diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 0f20abd2f6d90..f7f407252989f 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -1,24 +1,28 @@ - + - ## Motivation + - ## Changes - - +## Tests + -What's left to do: +## Related -- [ ] ... -- [ ] ... + diff --git a/.github/actions/build-image/action.yml b/.github/actions/build-image/action.yml index eeb8832cb4494..ec17d18e80a25 100644 --- a/.github/actions/build-image/action.yml +++ b/.github/actions/build-image/action.yml @@ -19,7 +19,7 @@ runs: # This GH Action requires localstack repo in 'localstack' dir + full git history (fetch-depth: 0) steps: - name: Set up Python - uses: actions/setup-python@v5 + uses: actions/setup-python@v6 with: python-version-file: 'localstack/.python-version' diff --git a/.github/actions/load-localstack-docker-from-artifacts/action.yml b/.github/actions/load-localstack-docker-from-artifacts/action.yml index cb22c52682734..a86352b786a43 100644 --- a/.github/actions/load-localstack-docker-from-artifacts/action.yml +++ b/.github/actions/load-localstack-docker-from-artifacts/action.yml @@ -9,12 +9,12 @@ runs: using: "composite" steps: - name: Download Docker Image - uses: actions/download-artifact@v4 + uses: actions/download-artifact@v5 with: name: localstack-docker-image-${{ inputs.platform }} - name: Set up Python - uses: actions/setup-python@v5 + uses: actions/setup-python@v6 with: python-version-file: '.python-version' cache: 'pip' diff --git a/.github/actions/setup-tests-env/action.yml b/.github/actions/setup-tests-env/action.yml index 95cd7fe359787..f33279972c9f2 100644 --- a/.github/actions/setup-tests-env/action.yml +++ b/.github/actions/setup-tests-env/action.yml @@ -4,7 +4,7 @@ runs: using: "composite" steps: - name: Set up Python - uses: actions/setup-python@v5 + uses: actions/setup-python@v6 with: python-version-file: '.python-version' cache: 'pip' diff --git a/.github/dependabot.yml b/.github/dependabot.yml index c585cd1f754bc..21c4e338fd3ce 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -7,12 +7,11 @@ updates: ignore: - dependency-name: "python" update-types: ["version-update:semver-major", "version-update:semver-minor"] - - dependency-name: "eclipse-temurin" - update-types: ["version-update:semver-major"] labels: - "area: dependencies" - "semver: patch" - - "skip-docs" + - "docs: skip" + - "notes: skip" groups: docker-base-images: patterns: @@ -24,7 +23,8 @@ updates: labels: - "area: dependencies" - "semver: patch" - - "skip-docs" + - "docs: skip" + - "notes: skip" groups: github-actions: patterns: diff --git a/.github/workflows/asf-updates.yml b/.github/workflows/asf-updates.yml index 45d20e220dab0..b378158091348 100644 --- a/.github/workflows/asf-updates.yml +++ b/.github/workflows/asf-updates.yml @@ -10,7 +10,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout Open Source - uses: actions/checkout@v5 + uses: actions/checkout@v6 with: fetch-depth: 0 @@ -22,12 +22,14 @@ jobs: - name: Set up Python id: setup-python uses: actions/setup-python@v6 + with: + python-version-file: '.python-version' - name: Install release helper dependencies - run: pip install --upgrade setuptools setuptools_scm uv + run: python3 -m pip install --upgrade setuptools setuptools_scm uv - name: Cache LocalStack community dependencies (venv) - uses: actions/cache@v4 + uses: actions/cache@v5 with: path: .venv key: ${{ runner.os }}-python-${{ steps.setup-python.outputs.python-version }}-venv-${{ hashFiles('requirements-dev.txt') }} @@ -42,15 +44,7 @@ jobs: - name: Update ASF APIs run: | - source .venv/bin/activate - python3 -m localstack.aws.scaffold upgrade - - - name: Format code - run: | - source .venv/bin/activate - # explicitly perform an unsafe fix to remove unused imports in the generated ASF APIs - ruff check --select F401 --unsafe-fixes --fix . --config "lint.preview = true" - make format-modified + make asf-regenerate - name: Check for changes id: check-for-changes @@ -74,9 +68,20 @@ jobs: source .venv/bin/activate # determine botocore version in venv BOTOCORE_VERSION=$(python -c "import botocore; print(botocore.__version__)"); - echo "Pinning botocore, boto3, and boto3-stubs to version $BOTOCORE_VERSION" + echo "Pinning botocore to version $BOTOCORE_VERSION" bin/release-helper.sh set-dep-ver botocore "==$BOTOCORE_VERSION" - bin/release-helper.sh set-dep-ver boto3 "==$BOTOCORE_VERSION" + + # determine boto3 version that works with $BOTOCORE_VERSION + uv venv /tmp/boto3-ver-venv + source /tmp/boto3-ver-venv/bin/activate + uv pip install "botocore==$BOTOCORE_VERSION" boto3 + export BOTO3_VERSION=$(uv pip list --format=json | jq -r '.[] | select(.name=="boto3") | .version') + deactivate + + # pin boto3 to that predetermined version + source .venv/bin/activate + echo "Pinning boto3 to version $BOTO3_VERSION" + bin/release-helper.sh set-dep-ver boto3 "==$BOTO3_VERSION" # determine awscli version that works with $BOTOCORE_VERSION uv venv /tmp/awscli-ver-venv @@ -91,13 +96,12 @@ jobs: bin/release-helper.sh set-dep-ver awscli "==$AWSCLI_VERSION" # upgrade the requirements files only for the botocore package - # FIXME remove pin on pip-tools when https://github.com/jazzband/pip-tools/issues/2215 us resolved - pip install "pip-tools<7.5.0" - pip-compile --strip-extras --upgrade-package "botocore==$BOTOCORE_VERSION" --upgrade-package "boto3==$BOTOCORE_VERSION" --extra base-runtime -o requirements-base-runtime.txt pyproject.toml - pip-compile --strip-extras --upgrade-package "botocore==$BOTOCORE_VERSION" --upgrade-package "boto3==$BOTOCORE_VERSION" --upgrade-package "awscli==$AWSCLI_VERSION" --extra runtime -o requirements-runtime.txt pyproject.toml - pip-compile --strip-extras --upgrade-package "botocore==$BOTOCORE_VERSION" --upgrade-package "boto3==$BOTOCORE_VERSION" --upgrade-package "awscli==$AWSCLI_VERSION" --extra test -o requirements-test.txt pyproject.toml - pip-compile --strip-extras --upgrade-package "botocore==$BOTOCORE_VERSION" --upgrade-package "boto3==$BOTOCORE_VERSION" --upgrade-package "awscli==$AWSCLI_VERSION" --extra dev -o requirements-dev.txt pyproject.toml - pip-compile --strip-extras --upgrade-package "botocore==$BOTOCORE_VERSION" --upgrade-package "boto3==$BOTOCORE_VERSION" --upgrade-package "awscli==$AWSCLI_VERSION" --extra typehint -o requirements-typehint.txt pyproject.toml + python3 -m pip install --upgrade "pip<26.0" pip-tools + pip-compile --strip-extras --upgrade-package "botocore==$BOTOCORE_VERSION" --upgrade-package "boto3==$BOTO3_VERSION" --extra base-runtime -o requirements-base-runtime.txt pyproject.toml + pip-compile --strip-extras --upgrade-package "botocore==$BOTOCORE_VERSION" --upgrade-package "boto3==$BOTO3_VERSION" --upgrade-package "awscli==$AWSCLI_VERSION" --extra runtime -o requirements-runtime.txt pyproject.toml + pip-compile --strip-extras --upgrade-package "botocore==$BOTOCORE_VERSION" --upgrade-package "boto3==$BOTO3_VERSION" --upgrade-package "awscli==$AWSCLI_VERSION" --extra test -o requirements-test.txt pyproject.toml + pip-compile --strip-extras --upgrade-package "botocore==$BOTOCORE_VERSION" --upgrade-package "boto3==$BOTO3_VERSION" --upgrade-package "awscli==$AWSCLI_VERSION" --extra dev -o requirements-dev.txt pyproject.toml + pip-compile --strip-extras --upgrade-package "botocore==$BOTOCORE_VERSION" --upgrade-package "boto3==$BOTO3_VERSION" --upgrade-package "awscli==$AWSCLI_VERSION" --extra typehint -o requirements-typehint.txt pyproject.toml - name: Read PR markdown template if: ${{ success() && steps.check-for-changes.outputs.diff-count != '0' && steps.check-for-changes.outputs.diff-count != '' }} @@ -116,7 +120,7 @@ jobs: replace: ${{ steps.check-for-changes.outputs.changed-services }} - name: Create PR - uses: peter-evans/create-pull-request@v7 + uses: peter-evans/create-pull-request@v8 if: ${{ success() && steps.check-for-changes.outputs.diff-count != '0' && steps.check-for-changes.outputs.diff-count != '' }} with: title: "Update ASF APIs" diff --git a/.github/workflows/aws-main.yml b/.github/workflows/aws-main.yml index f948790bdb46b..9b65946d4332a 100644 --- a/.github/workflows/aws-main.yml +++ b/.github/workflows/aws-main.yml @@ -100,11 +100,12 @@ jobs: if: ${{ !(inputs.onlyAcceptanceTests == true || inputs.enableTestSelection == true || github.event_name == 'push') && !failure() && !cancelled() && github.repository == 'localstack/localstack' }} steps: - name: Checkout - uses: actions/checkout@v5 + uses: actions/checkout@v6 - name: Set up Python uses: actions/setup-python@v6 with: + python-version-file: '.python-version' cache: 'pip' cache-dependency-path: 'requirements-dev.txt' @@ -113,7 +114,7 @@ jobs: run: make install-dev - name: Load all test results - uses: actions/download-artifact@v5 + uses: actions/download-artifact@v8 with: pattern: test-results-* path: target/coverage/ @@ -174,7 +175,7 @@ jobs: python -m scripts.metrics_coverage.diff_metrics_coverage - name: Archive coverage and parity metrics - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v7 with: name: coverage-and-parity-metrics path: | @@ -198,7 +199,7 @@ jobs: - test steps: - name: Checkout - uses: actions/checkout@v5 + uses: actions/checkout@v6 with: # setuptools_scm requires the git history (at least until the last tag) to determine the version fetch-depth: 0 @@ -209,7 +210,7 @@ jobs: platform: ${{ env.PLATFORM_NAME_AMD64 }} - name: Configure AWS credentials - uses: aws-actions/configure-aws-credentials@v5 + uses: aws-actions/configure-aws-credentials@v6 with: aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }} aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} diff --git a/.github/workflows/aws-tests-s3-image.yml b/.github/workflows/aws-tests-s3-image.yml index 1adc43f049685..8af6dcc13d65b 100644 --- a/.github/workflows/aws-tests-s3-image.yml +++ b/.github/workflows/aws-tests-s3-image.yml @@ -95,7 +95,7 @@ jobs: runs-on: ${{ matrix.runner }} steps: - name: Checkout - uses: actions/checkout@v5 + uses: actions/checkout@v6 with: # setuptools_scm requires the git history (at least until the last tag) to determine the version fetch-depth: 0 @@ -115,6 +115,8 @@ jobs: - name: Set up Python uses: actions/setup-python@v6 + with: + python-version-file: '.python-version' - name: Install docker build dependencies run: pip install --upgrade setuptools setuptools_scm @@ -135,7 +137,7 @@ jobs: make docker-run-tests-s3-only - name: Archive Test Results - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v7 if: success() || failure() with: name: test-results-s3-image-${{ matrix.arch }} @@ -147,7 +149,7 @@ jobs: run: ./bin/docker-helper.sh save - name: Store Docker image as artifact - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v7 with: name: localstack-s3-image-${{ matrix.arch }} path: ${{ steps.save-image.outputs.IMAGE_FILENAME }} @@ -171,12 +173,12 @@ jobs: ) steps: - name: Download AMD64 Results - uses: actions/download-artifact@v5 + uses: actions/download-artifact@v8 with: name: test-results-s3-image-amd64 - name: Download ARM64 Results - uses: actions/download-artifact@v5 + uses: actions/download-artifact@v8 with: name: test-results-s3-image-arm64 @@ -204,23 +206,23 @@ jobs: password: ${{ secrets.DOCKERHUB_PASSWORD }} - name: Checkout - uses: actions/checkout@v5 + uses: actions/checkout@v6 - name: Set up Python uses: actions/setup-python@v6 with: - python-version: '3.11' + python-version-file: '.python-version' - name: Install docker build dependencies run: pip install --upgrade setuptools setuptools_scm - name: Download AMD64 image - uses: actions/download-artifact@v5 + uses: actions/download-artifact@v8 with: name: localstack-s3-image-amd64 - name: Download ARM64 image - uses: actions/download-artifact@v5 + uses: actions/download-artifact@v8 with: name: localstack-s3-image-arm64 diff --git a/.github/workflows/aws-tests.yml b/.github/workflows/aws-tests.yml index 98cf8fc61c84f..c47daa1c79e23 100644 --- a/.github/workflows/aws-tests.yml +++ b/.github/workflows/aws-tests.yml @@ -163,7 +163,7 @@ jobs: run: echo "PLATFORM=${{ (runner.arch == 'X64' && 'amd64') || (runner.arch == 'ARM64' && 'arm64') || '' }}" >> $GITHUB_ENV - name: Checkout - uses: actions/checkout@v5 + uses: actions/checkout@v6 with: path: localstack # setuptools_scm requires the git history (at least until the last tag) to determine the version @@ -179,7 +179,7 @@ jobs: - name: Restore Lambda common runtime packages id: cached-lambda-common-restore if: inputs.disableCaching != true - uses: actions/cache/restore@v4 + uses: actions/cache/restore@v5 with: path: localstack/tests/aws/services/lambda_/functions/common key: common-it-${{ runner.os }}-${{ runner.arch }}-lambda-common-${{ hashFiles('localstack/tests/aws/services/lambda_/functions/common/**/src/*', 'localstack/tests/aws/services/lambda_/functions/common/**/Makefile') }} @@ -189,13 +189,13 @@ jobs: - name: Save Lambda common runtime packages if: inputs.disableCaching != true - uses: actions/cache/save@v4 + uses: actions/cache/save@v5 with: path: localstack/tests/aws/services/lambda_/functions/common key: ${{ steps.cached-lambda-common-restore.outputs.cache-primary-key }} - name: Archive Lambda common packages - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v7 with: name: lambda-common-${{ env.PLATFORM }} path: | @@ -211,10 +211,9 @@ jobs: dynamodb-v2: ${{ steps.changes.outputs.dynamodb-v2 }} events-v1: ${{ steps.changes.outputs.events-v1 }} cloudformation-legacy: ${{ steps.changes.outputs.cloudformation-legacy }} - sns-v2: ${{ steps.changes.outputs.sns-v2 }} steps: - name: Checkout - uses: actions/checkout@v5 + uses: actions/checkout@v6 with: # setuptools_scm requires the git history (at least until the last tag) to determine the version fetch-depth: 0 @@ -225,6 +224,9 @@ jobs: - name: Linting run: make lint + - name: Verify Plux Entrypoints + run: make entrypoints && git diff --exit-code plux.ini + - name: Check AWS compatibility markers run: make check-aws-markers @@ -245,7 +247,7 @@ jobs: - name: Archive Test Selection if: ${{ env.TESTSELECTION_PYTEST_ARGS }} - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v7 with: name: test-selection path: | @@ -277,8 +279,6 @@ jobs: cloudformation-legacy: - 'localstack-core/localstack/services/cloudformation/**' - 'tests/aws/services/cloudformation/**' - sns-v2: - - 'tests/aws/services/sns/**' # todo: potentially add more locations (lambda/sqs tests?) - name: Run Unit Tests timeout-minutes: 20 @@ -296,7 +296,7 @@ jobs: run: make test-coverage - name: Archive Test Results - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v7 if: success() || failure() with: name: test-results-preflight @@ -319,7 +319,7 @@ jobs: if: always() && !cancelled() && !contains(needs.*.result, 'skipped') steps: - name: Download Artifacts - uses: actions/download-artifact@v5 + uses: actions/download-artifact@v8 with: pattern: test-results-preflight @@ -376,13 +376,13 @@ jobs: echo "${{ inputs.testEnvironmentVariables }}" | sed "s/;/\n/" >> $GITHUB_ENV - name: Checkout - uses: actions/checkout@v5 + uses: actions/checkout@v6 with: # setuptools_scm requires the git history (at least until the last tag) to determine the version fetch-depth: 0 - name: Download Lambda Common packages - uses: actions/download-artifact@v5 + uses: actions/download-artifact@v8 with: name: lambda-common-${{ env.PLATFORM }} path: | @@ -395,7 +395,7 @@ jobs: - name: Download Test Selection if: ${{ env.TESTSELECTION_PYTEST_ARGS }} - uses: actions/download-artifact@v5 + uses: actions/download-artifact@v8 with: name: test-selection path: dist/testselection/ @@ -421,7 +421,7 @@ jobs: mv .test_durations .test_durations-${{ env.PLATFORM }}-${{ matrix.group }} - name: Archive Test Durations - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v7 if: success() || failure() with: name: pytest-split-durations-${{ env.PLATFORM }}-${{ matrix.group }} @@ -430,7 +430,7 @@ jobs: retention-days: 5 - name: Archive Test Results - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v7 if: success() || failure() with: name: test-results-integration-${{ env.PLATFORM }}-${{ matrix.group }} @@ -442,7 +442,7 @@ jobs: - name: Archive Parity Metric Results if: success() - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v7 with: name: parity-metric-raw-${{ env.PLATFORM }}-${{ matrix.group }} path: target/metric_reports @@ -463,7 +463,7 @@ jobs: CI_JOB_ID: ${{ github.job }} steps: - name: Checkout - uses: actions/checkout@v5 + uses: actions/checkout@v6 with: # setuptools_scm requires the git history (at least until the last tag) to determine the version fetch-depth: 0 @@ -488,7 +488,7 @@ jobs: run: make test-coverage - name: Archive Test Results - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v7 if: success() || failure() with: name: test-results-bootstrap @@ -522,13 +522,13 @@ jobs: if: always() && !cancelled() && !contains(needs.*.result, 'skipped') steps: - name: Download Bootstrap Artifacts - uses: actions/download-artifact@v5 + uses: actions/download-artifact@v8 if: ${{ matrix.arch == 'amd64' }} with: pattern: test-results-bootstrap - name: Download Integration Artifacts - uses: actions/download-artifact@v5 + uses: actions/download-artifact@v8 with: pattern: test-results-integration-${{ matrix.arch }}-* @@ -583,7 +583,7 @@ jobs: echo "${{ inputs.testEnvironmentVariables }}" | sed "s/;/\n/" >> $GITHUB_ENV - name: Checkout - uses: actions/checkout@v5 + uses: actions/checkout@v6 with: # setuptools_scm requires the git history (at least until the last tag) to determine the version fetch-depth: 0 @@ -609,7 +609,7 @@ jobs: run: make docker-run-tests - name: Archive Test Results - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v7 if: success() || failure() with: name: test-results-acceptance-${{ env.PLATFORM }} @@ -642,7 +642,7 @@ jobs: if: always() && !cancelled() && !contains(needs.*.result, 'skipped') steps: - name: Download Acceptance Artifacts - uses: actions/download-artifact@v5 + uses: actions/download-artifact@v8 with: pattern: test-results-acceptance-${{ matrix.arch }} @@ -673,14 +673,14 @@ jobs: job_status: "executed" steps: - name: Checkout - uses: actions/checkout@v5 + uses: actions/checkout@v6 - name: Prepare Local Test Environment uses: ./.github/actions/setup-tests-env - name: Download Test Selection if: ${{ env.TESTSELECTION_PYTEST_ARGS }} - uses: actions/download-artifact@v5 + uses: actions/download-artifact@v8 with: name: test-selection path: dist/testselection/ @@ -699,7 +699,7 @@ jobs: run: make test-coverage - name: Archive Test Results - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v7 if: success() || failure() with: name: test-results-cloudwatch-v1 @@ -726,14 +726,14 @@ jobs: job_status: "executed" steps: - name: Checkout - uses: actions/checkout@v5 + uses: actions/checkout@v6 - name: Prepare Local Test Environment uses: ./.github/actions/setup-tests-env - name: Download Test Selection if: ${{ env.TESTSELECTION_PYTEST_ARGS }} - uses: actions/download-artifact@v5 + uses: actions/download-artifact@v8 with: name: test-selection path: dist/testselection/ @@ -751,7 +751,7 @@ jobs: run: make test-coverage - name: Archive Test Results - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v7 if: success() || failure() with: name: test-results-dynamodb-v2 @@ -778,14 +778,14 @@ jobs: job_status: "executed" steps: - name: Checkout - uses: actions/checkout@v5 + uses: actions/checkout@v6 - name: Prepare Local Test Environment uses: ./.github/actions/setup-tests-env - name: Download Test Selection if: ${{ env.TESTSELECTION_PYTEST_ARGS }} - uses: actions/download-artifact@v5 + uses: actions/download-artifact@v8 with: name: test-selection path: dist/testselection/ @@ -804,7 +804,7 @@ jobs: run: make test-coverage - name: Archive Test Results - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v7 if: success() || failure() with: name: test-results-events-v1 @@ -832,14 +832,14 @@ jobs: job_status: "executed" steps: - name: Checkout - uses: actions/checkout@v5 + uses: actions/checkout@v6 - name: Prepare Local Test Environment uses: ./.github/actions/setup-tests-env - name: Download Test Selection if: ${{ env.TESTSELECTION_PYTEST_ARGS }} - uses: actions/download-artifact@v5 + uses: actions/download-artifact@v8 with: name: test-selection path: dist/testselection/ @@ -855,7 +855,7 @@ jobs: run: make test-coverage - name: Archive Test Results - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v7 if: success() || failure() with: name: test-results-cloudformation-legacy @@ -865,59 +865,6 @@ jobs: ${{ env.JUNIT_REPORTS_FILE }} retention-days: 30 - test-sns-v2: - name: Test SNS V2 - if: ${{ !inputs.onlyAcceptanceTests && (github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/tags/v') || needs.test-preflight.outputs.sns-v2 == 'true') }} - runs-on: ubuntu-latest - needs: - - test-preflight - - build - timeout-minutes: 60 - env: - # Set job-specific environment variables for pytest-tinybird - CI_JOB_NAME: ${{ github.job }} - CI_JOB_ID: ${{ github.job }} - outputs: - # we need this output to conditionally execute the Publishing step - job_status: "executed" - steps: - - name: Checkout - uses: actions/checkout@v5 - - - name: Prepare Local Test Environment - uses: ./.github/actions/setup-tests-env - - - name: Download Test Selection - if: ${{ env.TESTSELECTION_PYTEST_ARGS }} - uses: actions/download-artifact@v5 - with: - name: test-selection - path: dist/testselection/ - - - name: Run SNS v2 Provider Tests - timeout-minutes: 30 - env: - # add the GitHub API token to avoid rate limit issues - GITHUB_API_TOKEN: ${{ secrets.GITHUB_TOKEN }} - DEBUG: 1 - COVERAGE_FILE: ".coverage.sns_v2" - TEST_PATH: "tests/aws/services/sns/" - JUNIT_REPORTS_FILE: "pytest-junit-sns-v2.xml" - PYTEST_ARGS: "${{ env.TINYBIRD_PYTEST_ARGS }}${{ env.TESTSELECTION_PYTEST_ARGS }} --reruns 3 -o junit_suite_name=sns_v2" - PROVIDER_OVERRIDE_SNS: "v2" - run: make test-coverage - - - name: Archive Test Results - uses: actions/upload-artifact@v4 - if: success() || failure() - with: - name: test-results-sns-v2 - include-hidden-files: true - path: | - pytest-junit-sns-v2.xml - .coverage.sns_v2 - retention-days: 30 - publish-alternative-provider-test-results: name: Publish Alternative Provider Test Results # execute on success or failure, but not if the workflow is cancelled or all of the dependencies has been skipped @@ -927,7 +874,6 @@ jobs: - test-events-v1 - test-ddb-v2 - test-cloudwatch-v1 - - test-sns-v2 runs-on: ubuntu-latest permissions: checks: write @@ -936,30 +882,25 @@ jobs: issues: read steps: - name: Download Cloudformation legacy Artifacts - uses: actions/download-artifact@v5 + uses: actions/download-artifact@v8 with: pattern: test-results-cloudformation-legacy - name: Download EventBridge v1 Artifacts - uses: actions/download-artifact@v5 + uses: actions/download-artifact@v8 with: pattern: test-results-events-v1 - name: Download DynamoDB v2 Artifacts - uses: actions/download-artifact@v5 + uses: actions/download-artifact@v8 with: pattern: test-results-dynamodb-v2 - name: Download CloudWatch v1 Artifacts - uses: actions/download-artifact@v5 + uses: actions/download-artifact@v8 with: pattern: test-results-cloudwatch-v1 - - name: Download SNS v2 Artifacts - uses: actions/download-artifact@v5 - with: - pattern: test-results-sns-v2 - - name: Publish Bootstrap and Integration Test Results uses: EnricoMi/publish-unit-test-result-action@v2 if: success() || failure() @@ -972,7 +913,7 @@ jobs: capture-not-implemented: name: "Capture Not Implemented" - if: ${{ !inputs.onlyAcceptanceTests && ( github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/tags/v') ) }} + if: ${{ (!inputs.onlyAcceptanceTests && github.ref == 'refs/heads/main') || startsWith(github.ref, 'refs/tags/v') }} runs-on: ubuntu-latest needs: build env: @@ -987,7 +928,7 @@ jobs: password: ${{ secrets.DOCKERHUB_PULL_TOKEN }} - name: Checkout - uses: actions/checkout@v5 + uses: actions/checkout@v6 with: # setuptools_scm requires the git history (at least until the last tag) to determine the version fetch-depth: 0 @@ -1009,6 +950,7 @@ jobs: IMAGE_NAME: "localstack/localstack:latest" run: | source .venv/bin/activate + pip install --pre localstack localstack start -d localstack wait -t 120 || (localstack logs && false) @@ -1030,7 +972,7 @@ jobs: localstack stop - name: Archive Capture-Not-Implemented Results - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v7 with: name: capture-notimplemented path: results/ diff --git a/.github/workflows/dockerhub-description.yml b/.github/workflows/dockerhub-description.yml index 2ffcb0cbfa4c7..81c002d21daac 100644 --- a/.github/workflows/dockerhub-description.yml +++ b/.github/workflows/dockerhub-description.yml @@ -13,10 +13,10 @@ jobs: name: Sync DockerHub Description runs-on: ubuntu-latest steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 - name: Docker Hub Description - uses: peter-evans/dockerhub-description@v4 + uses: peter-evans/dockerhub-description@v5 with: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_PASSWORD }} diff --git a/.github/workflows/marker-report.yml b/.github/workflows/marker-report.yml index d978bb31f966d..0b89c8dabe800 100644 --- a/.github/workflows/marker-report.yml +++ b/.github/workflows/marker-report.yml @@ -38,16 +38,18 @@ jobs: timeout-minutes: 10 steps: - name: Checkout - uses: actions/checkout@v5 + uses: actions/checkout@v6 with: fetch-depth: 0 - name: Set up Python id: setup-python uses: actions/setup-python@v6 + with: + python-version-file: '.python-version' - name: Cache LocalStack community dependencies (venv) - uses: actions/cache@v4 + uses: actions/cache@v5 with: path: .venv key: ${{ runner.os }}-python-${{ steps.setup-python.outputs.python-version }}-venv-${{ hashFiles('requirements-dev.txt') }} @@ -99,7 +101,7 @@ jobs: - name: Upload generated markdown if: ${{ inputs.createIssue }} - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v7 with: path: ./target/MARKER_REPORT_ISSUE.md diff --git a/.github/workflows/pr-enforce-pr-labels.yml b/.github/workflows/pr-enforce-pr-labels.yml index 8ccbf1e8321ab..81f3eb8a73359 100644 --- a/.github/workflows/pr-enforce-pr-labels.yml +++ b/.github/workflows/pr-enforce-pr-labels.yml @@ -1,7 +1,7 @@ name: Enforce Labels on: pull_request_target: - types: [labeled, unlabeled, opened] + types: [labeled, unlabeled, opened, synchronize] jobs: labels: diff --git a/.github/workflows/rebase-release-prs.yml b/.github/workflows/rebase-release-prs.yml index 1675a68567833..81f1f50333f76 100644 --- a/.github/workflows/rebase-release-prs.yml +++ b/.github/workflows/rebase-release-prs.yml @@ -28,7 +28,7 @@ jobs: matrix: head: ${{ fromJson(needs.find-release-branches.outputs.matrix) }} steps: - - uses: peter-evans/rebase@v3 + - uses: peter-evans/rebase@v4 with: token: ${{ secrets.PRO_ACCESS_TOKEN }} head: ${{ matrix.head }} diff --git a/.github/workflows/rebase-release-targeting-prs.yml b/.github/workflows/rebase-release-targeting-prs.yml index b52262837293f..37387dbaba1ad 100644 --- a/.github/workflows/rebase-release-targeting-prs.yml +++ b/.github/workflows/rebase-release-targeting-prs.yml @@ -15,7 +15,7 @@ jobs: script: | // remove the ref prefx "refs/heads/" return context.payload.ref.substr(11) - - uses: peter-evans/rebase@v3 + - uses: peter-evans/rebase@v4 with: token: ${{ secrets.PRO_ACCESS_TOKEN }} base: ${{steps.determine-base-ref.outputs.result}} diff --git a/.github/workflows/tests-bin.yml b/.github/workflows/tests-bin.yml index 1e207b372dca6..1c9886019933c 100644 --- a/.github/workflows/tests-bin.yml +++ b/.github/workflows/tests-bin.yml @@ -20,7 +20,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v5 + uses: actions/checkout@v6 - name: Setup BATS run: | @@ -30,6 +30,9 @@ jobs: - name: Set up Python uses: actions/setup-python@v6 + with: + python-version-file: '.python-version' + - name: Install helper script dependencies run: pip install --upgrade setuptools setuptools_scm @@ -40,7 +43,7 @@ jobs: mv report.xml tests-junit-base.xml - name: Archive Test Results - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v7 if: success() || failure() with: name: test-results-tests-bin diff --git a/.github/workflows/tests-cli.yml b/.github/workflows/tests-cli.yml deleted file mode 100644 index e072500284d94..0000000000000 --- a/.github/workflows/tests-cli.yml +++ /dev/null @@ -1,118 +0,0 @@ -name: CLI Tests -on: - workflow_dispatch: - inputs: - PYTEST_LOGLEVEL: - type: choice - description: Loglevel for PyTest - options: - - DEBUG - - INFO - - WARNING - - ERROR - - CRITICAL - default: WARNING - pull_request: - paths: - - '**' - - '!.github/**' - - '.github/workflows/tests-cli.yml' - - '!docs/**' - - '!scripts/**' - - '!.dockerignore' - - '!.git-blame-ignore-revs' - - '!CODE_OF_CONDUCT.md' - - '!CODEOWNERS' - - '!CONTRIBUTING.md' - - '!docker-compose.yml' - - '!docker-compose-pro.yml' - - '!Dockerfile*' - - '!LICENSE.txt' - - '!README.md' - push: - paths: - - '**' - - '!.github/**' - - '.github/workflows/tests-cli.yml' - - '!docs/**' - - '!scripts/**' - - '!.dockerignore' - - '!.git-blame-ignore-revs' - - '!CODE_OF_CONDUCT.md' - - '!CODEOWNERS' - - '!CONTRIBUTING.md' - - '!docker-compose.yml' - - '!docker-compose-pro.yml' - - '!Dockerfile*' - - '!LICENSE.txt' - - '!README.md' - branches: - - main - - release/* - -concurrency: - group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} - cancel-in-progress: true - -env: - # Configure PyTest log level - PYTEST_LOGLEVEL: "${{ inputs.PYTEST_LOGLEVEL || 'WARNING' }}" - # Set non-job-specific environment variables for pytest-tinybird - TINYBIRD_URL: https://api.tinybird.co - TINYBIRD_DATASOURCE: community_tests_cli - TINYBIRD_TOKEN: ${{ secrets.TINYBIRD_CI_TOKEN }} - CI_COMMIT_BRANCH: ${{ github.head_ref || github.ref_name }} - CI_COMMIT_SHA: ${{ github.sha }} - CI_JOB_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}/attempts/${{ github.run_attempt }} - # report to tinybird if executed on main - TINYBIRD_PYTEST_ARGS: "${{ github.repository == 'localstack/localstack' && github.ref == 'refs/heads/main' && '--report-to-tinybird ' || '' }}" - -permissions: - contents: read # checkout the repository - -jobs: - cli-tests: - runs-on: ubuntu-latest - strategy: - fail-fast: false - matrix: - python-version: [ "3.9", "3.10", "3.11", "3.12", "3.13" ] - timeout-minutes: 10 - env: - # Set job-specific environment variables for pytest-tinybird - CI_JOB_NAME: ${{ github.job }}-${{ matrix.python-version }} - CI_JOB_ID: ${{ github.job }}-${{ matrix.python-version }} - steps: - - name: Checkout - uses: actions/checkout@v5 - - name: Set up Python - id: setup-python - uses: actions/setup-python@v6 - with: - python-version: ${{ matrix.python-version }} - - name: Install CLI test dependencies - run: | - make venv - source .venv/bin/activate - pip install -e . - pip install pytest pytest-tinybird - - name: Run CLI tests - env: - PYTEST_ADDOPTS: "${{ env.TINYBIRD_PYTEST_ARGS }}-p no:localstack.testing.pytest.fixtures -p no:localstack_snapshot.pytest.snapshot -p no:localstack.testing.pytest.filters -p no:localstack.testing.pytest.fixture_conflicts -p no:localstack.testing.pytest.validation_tracking -p no:localstack.testing.pytest.path_filter -p no:tests.fixtures -p no:localstack.testing.pytest.stepfunctions.fixtures -p no:localstack.testing.pytest.cloudformation.fixtures -s" - TEST_PATH: "tests/cli/" - run: make test - - push-to-tinybird: - if: always() && github.ref == 'refs/heads/main' && github.repository == 'localstack/localstack' - runs-on: ubuntu-latest - needs: cli-tests - permissions: - actions: read - steps: - - name: Push to Tinybird - uses: localstack/tinybird-workflow-push@v3 - with: - workflow_id: "tests_cli" - tinybird_token: ${{ secrets.TINYBIRD_CI_TOKEN }} - github_token: ${{ secrets.GITHUB_TOKEN }} - tinybird_datasource: "ci_workflows" diff --git a/.github/workflows/tests-podman.yml b/.github/workflows/tests-podman.yml index a12f6f11493e1..c384fcc4b486e 100644 --- a/.github/workflows/tests-podman.yml +++ b/.github/workflows/tests-podman.yml @@ -37,10 +37,12 @@ jobs: CI_JOB_ID: ${{ github.job }} steps: - name: Checkout - uses: actions/checkout@v5 + uses: actions/checkout@v6 - name: Set up Python uses: actions/setup-python@v6 + with: + python-version-file: '.python-version' - name: Install podman and test dependencies run: | diff --git a/.github/workflows/tests-pro-integration.yml b/.github/workflows/tests-pro-integration.yml index a428f76cd8ad2..ea21c9101de22 100644 --- a/.github/workflows/tests-pro-integration.yml +++ b/.github/workflows/tests-pro-integration.yml @@ -135,7 +135,7 @@ jobs: docker-images: false - name: Checkout Community - uses: actions/checkout@v5 + uses: actions/checkout@v6 with: path: localstack fetch-depth: 0 # we need the additional commits to figure out the merge base for test selection @@ -198,21 +198,15 @@ jobs: return DEFAULT_REF - name: Checkout Pro - uses: actions/checkout@v5 + uses: actions/checkout@v6 with: repository: localstack/localstack-pro ref: ${{steps.determine-companion-ref.outputs.result}} token: ${{ secrets.PRO_ACCESS_TOKEN }} path: localstack-pro - - name: Set up Python 3.11 - id: setup-python - uses: actions/setup-python@v6 - with: - python-version-file: 'localstack/.python-version' - - name: Set up Node 22.x - uses: actions/setup-node@v5 + uses: actions/setup-node@v6 with: node-version: 22.x @@ -227,20 +221,9 @@ jobs: sudo apt-get update sudo apt-get install -y --allow-downgrades libsnappy-dev jq libvirt-dev - - name: Cache Pro Dependencies (venv) - if: inputs.disableCaching != true - uses: actions/cache@v4 - with: - path: | - localstack-pro/.venv - # include the matrix group (to re-use the venv) - key: community-it-${{ runner.os }}-python-${{ steps.setup-python.outputs.python-version }}-venv-${{ hashFiles('localstack-pro/localstack-pro-core/requirements-test.txt') }}-${{steps.determine-companion-ref.outputs.result}} - restore-keys: | - community-it-${{ runner.os }}-python-${{ steps.setup-python.outputs.python-version }}-venv-${{ hashFiles('localstack-pro/localstack-pro-core/requirements-test.txt') }}-refs/heads/main - - name: Cache Pro Dependencies (libs) if: inputs.disableCaching != true - uses: actions/cache@v4 + uses: actions/cache@v5 with: path: | localstack/localstack-core/.filesystem/var/lib/localstack @@ -252,7 +235,7 @@ jobs: - name: Restore Lambda common runtime packages id: cached-lambda-common-restore if: inputs.disableCaching != true - uses: actions/cache/restore@v4 + uses: actions/cache/restore@v5 with: path: | localstack/tests/aws/services/lambda_/functions/common @@ -264,37 +247,21 @@ jobs: - name: Save Lambda common runtime packages if: inputs.disableCaching != true - uses: actions/cache/save@v4 + uses: actions/cache/save@v5 with: path: | localstack/tests/aws/services/lambda_/functions/common key: ${{ steps.cached-lambda-common-restore.outputs.cache-primary-key }} + - name: Set up uv + uses: astral-sh/setup-uv@v7 + with: + enable-cache: ${{ inputs.disableCaching != true }} + - name: Install Python Dependencies for Pro working-directory: localstack-pro run: make install-ci - - name: Link Community into Pro venv - working-directory: localstack-pro - run: | - source .venv/bin/activate - pip install -e ../localstack[runtime,test] - - - name: Create Community Entrypoints - working-directory: localstack - # Entrypoints need to be generated _after_ the community edition has been linked into the venv - run: | - VENV_DIR="../localstack-pro/.venv" make entrypoints - ../localstack-pro/.venv/bin/python -m plux show - - - name: Create Pro Entrypoints - working-directory: localstack-pro - # Entrypoints need to be generated _after_ the community edition has been linked into the venv - run: | - make entrypoints - cd localstack-pro-core - ../.venv/bin/python -m plux show - - name: Test Pro Startup env: DEBUG: 1 @@ -302,7 +269,7 @@ jobs: LOCALSTACK_AUTH_TOKEN: "test" working-directory: localstack-pro run: | - source .venv/bin/activate + source localstack-pro-core/.venv/bin/activate bin/test_localstack_pro.sh - name: Determine Test Selection @@ -315,7 +282,7 @@ jobs: echo "Do test selection based on Pull Request event" SCRIPT_OPTS="--base-commit-sha ${{ github.event.pull_request.base.sha }} --head-commit-sha ${{ github.event.pull_request.head.sha }}" fi - . ../localstack-pro/.venv/bin/activate + . ../localstack-pro/localstack-pro-core/.venv/bin/activate python -m localstack.testing.testselection.scripts.generate_test_selection $(pwd) target/testselection/test-selection.txt $SCRIPT_OPTS || (mkdir -p target/testselection && echo "SENTINEL_ALL_TESTS" >> target/testselection/test-selection.txt) echo "Resulting Test Selection file:" cat target/testselection/test-selection.txt @@ -342,7 +309,7 @@ jobs: make test - name: Archive Test Durations - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v7 if: success() || failure() with: name: pytest-split-durations-community-${{ matrix.group }} @@ -351,7 +318,7 @@ jobs: retention-days: 5 - name: Archive Test Results - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v7 if: success() || failure() with: name: test-results-community-${{ matrix.group }} @@ -377,12 +344,12 @@ jobs: ) steps: - name: Download Artifacts 1 - uses: actions/download-artifact@v5 + uses: actions/download-artifact@v8 with: name: test-results-community-1 - name: Download Artifacts 2 - uses: actions/download-artifact@v5 + uses: actions/download-artifact@v8 with: name: test-results-community-2 diff --git a/.github/workflows/update-cfn-resources.yml b/.github/workflows/update-cfn-resources.yml index 91957da968339..67ed3fbfb1560 100644 --- a/.github/workflows/update-cfn-resources.yml +++ b/.github/workflows/update-cfn-resources.yml @@ -3,6 +3,10 @@ name: Update CloudFormation Resources on: schedule: - cron: '0 6 * * TUE' + pull_request: + paths: + - '.github/workflows/update-cfn-resources.yml' + - 'scripts/update_cfn_resources.py' workflow_dispatch: jobs: @@ -14,7 +18,7 @@ jobs: pull-requests: write steps: - name: Checkout repository - uses: actions/checkout@v5 + uses: actions/checkout@v6 with: fetch-depth: 0 @@ -24,7 +28,7 @@ jobs: python-version-file: '.python-version' - name: Install uv - uses: astral-sh/setup-uv@v6 + uses: astral-sh/setup-uv@v7 - name: Determine boto dependency pins id: boto_versions @@ -47,7 +51,8 @@ jobs: python scripts/update_cfn_resources.py --resource-file localstack-core/localstack/services/cloudformation/resources.py - name: Create Pull Request - uses: peter-evans/create-pull-request@v7 + if: ${{ github.event_name != 'pull_request' }} + uses: peter-evans/create-pull-request@v8 with: title: "Update CloudFormation resource availability" body: "Automated update of CloudFormation resource metadata." diff --git a/.github/workflows/update-openapi-spec.yml b/.github/workflows/update-openapi-spec.yml index 8c8f2cc1dbb17..781fd02cace2d 100644 --- a/.github/workflows/update-openapi-spec.yml +++ b/.github/workflows/update-openapi-spec.yml @@ -16,7 +16,7 @@ jobs: steps: # This step dispatches a workflow in the OpenAPI repo, updating the spec and opening a PR. - name: Dispatch update spec workflow - uses: peter-evans/repository-dispatch@v3 + uses: peter-evans/repository-dispatch@v4 with: token: ${{ secrets.PRO_ACCESS_TOKEN }} repository: localstack/openapi diff --git a/.github/workflows/update-test-durations.yml b/.github/workflows/update-test-durations.yml index e8a4a52b06508..8f349dd64e3d6 100644 --- a/.github/workflows/update-test-durations.yml +++ b/.github/workflows/update-test-durations.yml @@ -6,71 +6,21 @@ on: - cron: 0 4 5 * * workflow_dispatch: inputs: - publishMethod: - description: 'Select how to publish the workflow result' + publish-method: + description: "Method to publish the test duration update results" type: choice options: - UPLOAD_ARTIFACT - CREATE_PR default: UPLOAD_ARTIFACT -env: - # Take test durations only for this platform - PLATFORM: "amd64" - jobs: - report: - name: "Download, merge and create PR with test durations" - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v5 - with: - path: localstack - - - name: Latest run-id from community repository - run: | - latest_workflow_id=$(curl -s https://api.github.com/repos/localstack/localstack/actions/workflows \ - | jq '.workflows[] | select(.path==".github/workflows/aws-main.yml").id') - latest_run_id=$(curl -s \ - "https://api.github.com/repos/localstack/localstack/actions/workflows/${latest_workflow_id}/runs?branch=main&status=success&per_page=30" \ - | jq '[.workflow_runs[] | select(.event == "schedule")][0].id') - echo "Latest run: https://github.com/localstack/localstack/actions/runs/${latest_run_id}" - echo "AWS_MAIN_LATEST_SCHEDULED_RUN_ID=${latest_run_id}" >> $GITHUB_ENV - - - name: Load test durations - uses: actions/download-artifact@v5 - with: - pattern: pytest-split-durations-${{ env.PLATFORM }}-* - path: artifacts-test-durations - merge-multiple: true - run-id: ${{ env.AWS_MAIN_LATEST_SCHEDULED_RUN_ID }} - github-token: ${{ secrets.GITHUB_TOKEN }} # PAT with access to artifacts from GH Actions - - - name: Merge test durations files - shell: bash - run: | - jq -s 'add | to_entries | sort_by(.key) | from_entries' artifacts-test-durations/.test_durations-${{ env.PLATFORM }}* > localstack/.test_durations || echo "::warning::Test durations were not merged" - - - name: Upload artifact with merged test durations - uses: actions/upload-artifact@v4 - if: ${{ success() && inputs.publishMethod == 'UPLOAD_ARTIFACT' }} - with: - name: merged-test-durations - path: localstack/.test_durations - include-hidden-files: true - if-no-files-found: error - - - name: Create PR - uses: peter-evans/create-pull-request@v7 - if: ${{ success() && inputs.publishMethod != 'UPLOAD_ARTIFACT' }} - with: - title: "[Testing] Update test durations" - body: "This PR includes an updated `.test_durations` file, generated based on latest test durations from main" - branch: "test-durations-auto-updates" - author: "LocalStack Bot " - committer: "LocalStack Bot " - commit-message: "CI: update .test_durations to latest version" - path: localstack - add-paths: .test_durations - labels: "semver: patch, area: testing, area: ci, docs: skip, notes: skip" - token: ${{ secrets.PRO_ACCESS_TOKEN }} + update-test-durations: + uses: localstack/meta/.github/workflows/update-test-durations.yml@main + with: + repository-name: localstack + test-durations-file-path: .test_durations + publish-method: ${{ inputs.publish-method || 'CREATE_PR' }} + secrets: + gh-token: ${{ secrets.GITHUB_TOKEN }} + pr-token: ${{ secrets.PRO_ACCESS_TOKEN }} diff --git a/.github/workflows/validate-codeowners.yml b/.github/workflows/validate-codeowners.yml index 55cd6483b1951..5209f23e9376a 100644 --- a/.github/workflows/validate-codeowners.yml +++ b/.github/workflows/validate-codeowners.yml @@ -13,7 +13,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout repo - uses: actions/checkout@v5 + uses: actions/checkout@v6 - name: Validate codeowners uses: mszostok/codeowners-validator@v0.7.4 diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index b2c5d9d556d3c..ef4ba8830d397 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,9 +1,10 @@ # See https://pre-commit.com for more information # See https://pre-commit.com/hooks.html for more hooks +# TODO add pre-commit hook for plux entrypoints reconciliation on changed files repos: - repo: https://github.com/astral-sh/ruff-pre-commit # Ruff version. - rev: v0.13.2 + rev: v0.15.4 hooks: - id: ruff args: [--fix, --exit-non-zero-on-fix] @@ -11,16 +12,18 @@ repos: - id: ruff-format - repo: https://github.com/pre-commit/mirrors-mypy - rev: v1.18.2 + rev: v1.19.1 hooks: - id: mypy entry: bash -c 'cd localstack-core && mypy --install-types --non-interactive' - additional_dependencies: ['botocore-stubs', 'rolo'] + additional_dependencies: ['botocore-stubs', 'rolo', 'moto-ext'] - repo: https://github.com/pre-commit/pre-commit-hooks rev: v6.0.0 hooks: + - id: no-commit-to-branch - id: end-of-file-fixer + exclude: "plux.ini" - id: trailing-whitespace - id: check-json files: .*\.(snapshot|validation)\.json @@ -31,7 +34,7 @@ repos: - id: check-pinned-deps-for-needed-upgrade - repo: https://github.com/python-openapi/openapi-spec-validator - rev: 0.8.0b1 + rev: 0.8.4 hooks: - id: openapi-spec-validator files: .*openapi.*\.(json|yaml|yml) diff --git a/.test_durations b/.test_durations index e4797f3b37307..084ea1f360468 100644 --- a/.test_durations +++ b/.test_durations @@ -1,4986 +1,5145 @@ { - "tests/aws/scenario/bookstore/test_bookstore.py::TestBookstoreApplication::test_lambda_dynamodb": 1.8670082820000005, - "tests/aws/scenario/bookstore/test_bookstore.py::TestBookstoreApplication::test_opensearch_crud": 3.362478288000034, - "tests/aws/scenario/bookstore/test_bookstore.py::TestBookstoreApplication::test_search_books": 60.64676492600006, - "tests/aws/scenario/bookstore/test_bookstore.py::TestBookstoreApplication::test_setup": 90.49064857799996, - "tests/aws/scenario/kinesis_firehose/test_kinesis_firehose.py::TestKinesisFirehoseScenario::test_kinesis_firehose_s3": 0.0026975989999868943, - "tests/aws/scenario/lambda_destination/test_lambda_destination_scenario.py::TestLambdaDestinationScenario::test_destination_sns": 5.617425776000005, - "tests/aws/scenario/lambda_destination/test_lambda_destination_scenario.py::TestLambdaDestinationScenario::test_infra": 12.838282334000041, - "tests/aws/scenario/loan_broker/test_loan_broker.py::TestLoanBrokerScenario::test_prefill_dynamodb_table": 30.082416248000015, - "tests/aws/scenario/loan_broker/test_loan_broker.py::TestLoanBrokerScenario::test_stepfunctions_input_recipient_list[step_function_input0-SUCCEEDED]": 3.849898365999991, - "tests/aws/scenario/loan_broker/test_loan_broker.py::TestLoanBrokerScenario::test_stepfunctions_input_recipient_list[step_function_input1-SUCCEEDED]": 2.880593910000016, - "tests/aws/scenario/loan_broker/test_loan_broker.py::TestLoanBrokerScenario::test_stepfunctions_input_recipient_list[step_function_input2-FAILED]": 0.9082103150000194, - "tests/aws/scenario/loan_broker/test_loan_broker.py::TestLoanBrokerScenario::test_stepfunctions_input_recipient_list[step_function_input3-FAILED]": 0.6722328980000043, - "tests/aws/scenario/loan_broker/test_loan_broker.py::TestLoanBrokerScenario::test_stepfunctions_input_recipient_list[step_function_input4-FAILED]": 1.169786477999935, - "tests/aws/scenario/mythical_mysfits/test_mythical_misfits.py::TestMythicalMisfitsScenario::test_deployed_infra_state": 0.0020200559999921097, - "tests/aws/scenario/mythical_mysfits/test_mythical_misfits.py::TestMythicalMisfitsScenario::test_populate_data": 0.0017880340000147044, - "tests/aws/scenario/mythical_mysfits/test_mythical_misfits.py::TestMythicalMisfitsScenario::test_user_clicks_are_stored": 0.0016162950000193632, - "tests/aws/scenario/note_taking/test_note_taking.py::TestNoteTakingScenario::test_notes_rest_api": 4.706982269999969, - "tests/aws/scenario/note_taking/test_note_taking.py::TestNoteTakingScenario::test_validate_infra_setup": 32.70136145800001, - "tests/aws/services/acm/test_acm.py::TestACM::test_boto_wait_for_certificate_validation": 1.138923955999985, - "tests/aws/services/acm/test_acm.py::TestACM::test_certificate_for_subdomain_wildcard": 2.2516514609999945, - "tests/aws/services/acm/test_acm.py::TestACM::test_create_certificate_for_multiple_alternative_domains": 11.139171326000053, - "tests/aws/services/acm/test_acm.py::TestACM::test_domain_validation": 0.26356249899993145, - "tests/aws/services/acm/test_acm.py::TestACM::test_import_certificate": 0.9437043010000252, - "tests/aws/services/apigateway/test_apigateway_api.py::TestApiGatewayApiAuthorizer::test_authorizer_crud_no_api": 0.03202481599998919, - "tests/aws/services/apigateway/test_apigateway_api.py::TestApiGatewayApiDocumentationPart::test_doc_parts_crud_no_api": 0.03290076100006445, - "tests/aws/services/apigateway/test_apigateway_api.py::TestApiGatewayApiDocumentationPart::test_documentation_part_lifecycle": 0.06852134299998625, - "tests/aws/services/apigateway/test_apigateway_api.py::TestApiGatewayApiDocumentationPart::test_import_documentation_parts": 0.1231469930000344, - "tests/aws/services/apigateway/test_apigateway_api.py::TestApiGatewayApiDocumentationPart::test_invalid_create_documentation_part_operations": 0.03844012099995098, - "tests/aws/services/apigateway/test_apigateway_api.py::TestApiGatewayApiDocumentationPart::test_invalid_delete_documentation_part": 0.050741658999982064, - "tests/aws/services/apigateway/test_apigateway_api.py::TestApiGatewayApiDocumentationPart::test_invalid_get_documentation_part": 0.04354593499999737, - "tests/aws/services/apigateway/test_apigateway_api.py::TestApiGatewayApiDocumentationPart::test_invalid_get_documentation_parts": 0.01455840899990335, - "tests/aws/services/apigateway/test_apigateway_api.py::TestApiGatewayApiDocumentationPart::test_invalid_update_documentation_part": 0.05275836799995659, - "tests/aws/services/apigateway/test_apigateway_api.py::TestApiGatewayApiMethod::test_method_lifecycle": 0.0721238390000849, - "tests/aws/services/apigateway/test_apigateway_api.py::TestApiGatewayApiMethod::test_method_request_parameters": 0.04763634000005368, - "tests/aws/services/apigateway/test_apigateway_api.py::TestApiGatewayApiMethod::test_put_method_model": 0.26902770600003123, - "tests/aws/services/apigateway/test_apigateway_api.py::TestApiGatewayApiMethod::test_put_method_validation": 0.06719570299998168, - "tests/aws/services/apigateway/test_apigateway_api.py::TestApiGatewayApiMethod::test_update_method": 0.06831357900000512, - "tests/aws/services/apigateway/test_apigateway_api.py::TestApiGatewayApiMethod::test_update_method_validation": 0.12667047800005093, - "tests/aws/services/apigateway/test_apigateway_api.py::TestApiGatewayApiModels::test_model_lifecycle": 0.07122208300006605, - "tests/aws/services/apigateway/test_apigateway_api.py::TestApiGatewayApiModels::test_model_validation": 0.09952942699999312, - "tests/aws/services/apigateway/test_apigateway_api.py::TestApiGatewayApiModels::test_update_model": 0.07243091800000911, - "tests/aws/services/apigateway/test_apigateway_api.py::TestApiGatewayApiRequestValidator::test_create_request_validator_invalid_api_id": 0.015537496000035844, - "tests/aws/services/apigateway/test_apigateway_api.py::TestApiGatewayApiRequestValidator::test_invalid_delete_request_validator": 0.04428208799993172, - "tests/aws/services/apigateway/test_apigateway_api.py::TestApiGatewayApiRequestValidator::test_invalid_get_request_validator": 0.04397758600003954, - "tests/aws/services/apigateway/test_apigateway_api.py::TestApiGatewayApiRequestValidator::test_invalid_get_request_validators": 0.015106426999977884, - "tests/aws/services/apigateway/test_apigateway_api.py::TestApiGatewayApiRequestValidator::test_invalid_update_request_validator_operations": 0.06196059400002696, - "tests/aws/services/apigateway/test_apigateway_api.py::TestApiGatewayApiRequestValidator::test_request_validator_lifecycle": 0.09111270500000046, - "tests/aws/services/apigateway/test_apigateway_api.py::TestApiGatewayApiRequestValidator::test_validators_crud_no_api": 0.03295066999999108, - "tests/aws/services/apigateway/test_apigateway_api.py::TestApiGatewayApiResource::test_create_proxy_resource": 0.1184646170000292, - "tests/aws/services/apigateway/test_apigateway_api.py::TestApiGatewayApiResource::test_create_proxy_resource_validation": 0.07660090600001013, - "tests/aws/services/apigateway/test_apigateway_api.py::TestApiGatewayApiResource::test_create_resource_parent_invalid": 0.03149854699995558, - "tests/aws/services/apigateway/test_apigateway_api.py::TestApiGatewayApiResource::test_delete_resource": 0.06793381699998235, - "tests/aws/services/apigateway/test_apigateway_api.py::TestApiGatewayApiResource::test_resource_lifecycle": 0.1077680679999844, - "tests/aws/services/apigateway/test_apigateway_api.py::TestApiGatewayApiResource::test_update_resource_behaviour": 0.14418074999997543, - "tests/aws/services/apigateway/test_apigateway_api.py::TestApiGatewayApiResource::test_update_resource_on_root": 0.03804404999999633, - "tests/aws/services/apigateway/test_apigateway_api.py::TestApiGatewayApiRestApi::test_create_rest_api_private_type": 0.029450368000027538, - "tests/aws/services/apigateway/test_apigateway_api.py::TestApiGatewayApiRestApi::test_create_rest_api_verify_defaults": 0.08110502099998484, - "tests/aws/services/apigateway/test_apigateway_api.py::TestApiGatewayApiRestApi::test_create_rest_api_with_binary_media_types": 0.02529124199998023, - "tests/aws/services/apigateway/test_apigateway_api.py::TestApiGatewayApiRestApi::test_create_rest_api_with_endpoint_configuration": 0.09951339100007317, - "tests/aws/services/apigateway/test_apigateway_api.py::TestApiGatewayApiRestApi::test_create_rest_api_with_optional_params": 0.0728459620000308, - "tests/aws/services/apigateway/test_apigateway_api.py::TestApiGatewayApiRestApi::test_create_rest_api_with_tags": 0.04323054199994658, - "tests/aws/services/apigateway/test_apigateway_api.py::TestApiGatewayApiRestApi::test_get_api_case_insensitive": 0.0018258729999161005, - "tests/aws/services/apigateway/test_apigateway_api.py::TestApiGatewayApiRestApi::test_list_and_delete_apis": 0.0858430159999557, - "tests/aws/services/apigateway/test_apigateway_api.py::TestApiGatewayApiRestApi::test_update_rest_api_behaviour": 0.05441999500004613, - "tests/aws/services/apigateway/test_apigateway_api.py::TestApiGatewayApiRestApi::test_update_rest_api_compression": 0.0927859720000015, - "tests/aws/services/apigateway/test_apigateway_api.py::TestApiGatewayApiRestApi::test_update_rest_api_concatenation_of_errors": 0.0018410610000501038, - "tests/aws/services/apigateway/test_apigateway_api.py::TestApiGatewayApiRestApi::test_update_rest_api_invalid_api_id": 0.014867815999934919, - "tests/aws/services/apigateway/test_apigateway_api.py::TestApiGatewayApiRestApi::test_update_rest_api_ip_address_type": 0.07566078000002108, - "tests/aws/services/apigateway/test_apigateway_api.py::TestApiGatewayApiRestApi::test_update_rest_api_operation_add_remove": 0.049946316999978535, - "tests/aws/services/apigateway/test_apigateway_api.py::TestApiGatewayGatewayResponse::test_gateway_response_crud": 0.09968896000003724, - "tests/aws/services/apigateway/test_apigateway_api.py::TestApiGatewayGatewayResponse::test_gateway_response_put": 0.09890570400000342, - "tests/aws/services/apigateway/test_apigateway_api.py::TestApiGatewayGatewayResponse::test_gateway_response_validation": 0.10342863599998964, - "tests/aws/services/apigateway/test_apigateway_api.py::TestApiGatewayGatewayResponse::test_update_gateway_response": 0.12568825099998548, - "tests/aws/services/apigateway/test_apigateway_api.py::TestApigatewayIntegration::test_delete_integration_response_errors": 0.08963522099998045, - "tests/aws/services/apigateway/test_apigateway_api.py::TestApigatewayIntegration::test_integration_response_invalid_integration": 0.038528208999991875, - "tests/aws/services/apigateway/test_apigateway_api.py::TestApigatewayIntegration::test_integration_response_invalid_responsetemplates": 0.0019366310000350495, - "tests/aws/services/apigateway/test_apigateway_api.py::TestApigatewayIntegration::test_integration_response_invalid_statuscode": 0.03999469699999736, - "tests/aws/services/apigateway/test_apigateway_api.py::TestApigatewayIntegration::test_integration_response_wrong_api": 0.024184810000008383, - "tests/aws/services/apigateway/test_apigateway_api.py::TestApigatewayIntegration::test_integration_response_wrong_method": 0.03831690599997728, - "tests/aws/services/apigateway/test_apigateway_api.py::TestApigatewayIntegration::test_integration_response_wrong_resource": 0.038120466000066244, - "tests/aws/services/apigateway/test_apigateway_api.py::TestApigatewayIntegration::test_integration_response_wrong_status_code": 0.04890177100003257, - "tests/aws/services/apigateway/test_apigateway_api.py::TestApigatewayIntegration::test_lifecycle_integration_response": 0.09245742600000995, - "tests/aws/services/apigateway/test_apigateway_api.py::TestApigatewayIntegration::test_lifecycle_method_response": 0.09105790899997146, - "tests/aws/services/apigateway/test_apigateway_api.py::TestApigatewayIntegration::test_put_integration_request_parameter_bool_type": 0.001794055000004846, - "tests/aws/services/apigateway/test_apigateway_api.py::TestApigatewayIntegration::test_put_integration_response_validation": 0.07534427300004154, - "tests/aws/services/apigateway/test_apigateway_api.py::TestApigatewayIntegration::test_put_integration_wrong_type": 0.04192926700005728, - "tests/aws/services/apigateway/test_apigateway_api.py::TestApigatewayIntegration::test_update_method_lack_response_parameters_and_models": 0.07127148000000716, - "tests/aws/services/apigateway/test_apigateway_api.py::TestApigatewayIntegration::test_update_method_response": 0.06291254900003196, - "tests/aws/services/apigateway/test_apigateway_api.py::TestApigatewayIntegration::test_update_method_response_negative_tests": 0.0867831209999963, - "tests/aws/services/apigateway/test_apigateway_api.py::TestApigatewayIntegration::test_update_method_response_wrong_operations": 0.08694727300002114, - "tests/aws/services/apigateway/test_apigateway_api.py::TestApigatewayIntegration::test_update_method_wrong_param_names": 0.08106724900005702, - "tests/aws/services/apigateway/test_apigateway_api.py::TestApigatewayTestInvoke::test_invoke_test_method": 0.34063664199999266, - "tests/aws/services/apigateway/test_apigateway_basic.py::TestAPIGateway::test_api_account": 0.04299754400000211, - "tests/aws/services/apigateway/test_apigateway_basic.py::TestAPIGateway::test_api_gateway_authorizer_crud": 0.002030987000011919, - "tests/aws/services/apigateway/test_apigateway_basic.py::TestAPIGateway::test_api_gateway_handle_domain_name": 0.24774540900000375, - "tests/aws/services/apigateway/test_apigateway_basic.py::TestAPIGateway::test_api_gateway_http_integration_with_path_request_parameter": 0.001875577000021167, - "tests/aws/services/apigateway/test_apigateway_basic.py::TestAPIGateway::test_api_gateway_lambda_asynchronous_invocation": 1.2947123230000557, - "tests/aws/services/apigateway/test_apigateway_basic.py::TestAPIGateway::test_api_gateway_lambda_integration_aws_type": 7.7259803179999835, - "tests/aws/services/apigateway/test_apigateway_basic.py::TestAPIGateway::test_api_gateway_lambda_proxy_integration[/lambda/foo1]": 0.0018571029999634447, - "tests/aws/services/apigateway/test_apigateway_basic.py::TestAPIGateway::test_api_gateway_lambda_proxy_integration[/lambda/{test_param1}]": 0.00183804699997836, - "tests/aws/services/apigateway/test_apigateway_basic.py::TestAPIGateway::test_api_gateway_lambda_proxy_integration_any_method": 0.001716210000040519, - "tests/aws/services/apigateway/test_apigateway_basic.py::TestAPIGateway::test_api_gateway_lambda_proxy_integration_any_method_with_path_param": 0.0017177640000340944, - "tests/aws/services/apigateway/test_apigateway_basic.py::TestAPIGateway::test_api_gateway_lambda_proxy_integration_with_is_base_64_encoded": 0.0018061790000274414, - "tests/aws/services/apigateway/test_apigateway_basic.py::TestAPIGateway::test_api_gateway_mock_integration": 0.06632037400004265, - "tests/aws/services/apigateway/test_apigateway_basic.py::TestAPIGateway::test_api_mock_integration_response_params": 0.0018231189999369235, - "tests/aws/services/apigateway/test_apigateway_basic.py::TestAPIGateway::test_apigateway_with_custom_authorization_method": 15.357801319999965, - "tests/aws/services/apigateway/test_apigateway_basic.py::TestAPIGateway::test_apigw_stage_variables[dev]": 1.6238911270000358, - "tests/aws/services/apigateway/test_apigateway_basic.py::TestAPIGateway::test_apigw_stage_variables[local]": 1.6210875059999807, - "tests/aws/services/apigateway/test_apigateway_basic.py::TestAPIGateway::test_apigw_test_invoke_method_api": 2.149522372999968, - "tests/aws/services/apigateway/test_apigateway_basic.py::TestAPIGateway::test_base_path_mapping": 0.1866234640000357, - "tests/aws/services/apigateway/test_apigateway_basic.py::TestAPIGateway::test_base_path_mapping_root": 0.16445774000004576, - "tests/aws/services/apigateway/test_apigateway_basic.py::TestAPIGateway::test_create_rest_api_with_custom_id[host_based_url]": 0.06365975699998216, - "tests/aws/services/apigateway/test_apigateway_basic.py::TestAPIGateway::test_create_rest_api_with_custom_id[localstack_path_based_url]": 0.06444183400003567, - "tests/aws/services/apigateway/test_apigateway_basic.py::TestAPIGateway::test_create_rest_api_with_custom_id[path_based_url]": 0.06773922700000412, - "tests/aws/services/apigateway/test_apigateway_basic.py::TestAPIGateway::test_delete_rest_api_with_invalid_id": 0.01293300000003228, - "tests/aws/services/apigateway/test_apigateway_basic.py::TestAPIGateway::test_invoke_endpoint_cors_headers[http://allowed-False-UrlType.HOST_BASED]": 0.07326340699995626, - "tests/aws/services/apigateway/test_apigateway_basic.py::TestAPIGateway::test_invoke_endpoint_cors_headers[http://allowed-False-UrlType.LS_PATH_BASED]": 0.07395422200005441, - "tests/aws/services/apigateway/test_apigateway_basic.py::TestAPIGateway::test_invoke_endpoint_cors_headers[http://allowed-False-UrlType.PATH_BASED]": 0.07583491099995854, - "tests/aws/services/apigateway/test_apigateway_basic.py::TestAPIGateway::test_invoke_endpoint_cors_headers[http://allowed-True-UrlType.HOST_BASED]": 0.09224523000006002, - "tests/aws/services/apigateway/test_apigateway_basic.py::TestAPIGateway::test_invoke_endpoint_cors_headers[http://allowed-True-UrlType.LS_PATH_BASED]": 0.07063509400001067, - "tests/aws/services/apigateway/test_apigateway_basic.py::TestAPIGateway::test_invoke_endpoint_cors_headers[http://allowed-True-UrlType.PATH_BASED]": 0.06801908899996079, - "tests/aws/services/apigateway/test_apigateway_basic.py::TestAPIGateway::test_invoke_endpoint_cors_headers[http://denied-False-UrlType.HOST_BASED]": 0.07119906500003026, - "tests/aws/services/apigateway/test_apigateway_basic.py::TestAPIGateway::test_invoke_endpoint_cors_headers[http://denied-False-UrlType.LS_PATH_BASED]": 0.07066423099996655, - "tests/aws/services/apigateway/test_apigateway_basic.py::TestAPIGateway::test_invoke_endpoint_cors_headers[http://denied-False-UrlType.PATH_BASED]": 0.0710325719999787, - "tests/aws/services/apigateway/test_apigateway_basic.py::TestAPIGateway::test_invoke_endpoint_cors_headers[http://denied-True-UrlType.HOST_BASED]": 0.06958176099999491, - "tests/aws/services/apigateway/test_apigateway_basic.py::TestAPIGateway::test_invoke_endpoint_cors_headers[http://denied-True-UrlType.LS_PATH_BASED]": 0.06782055900004025, - "tests/aws/services/apigateway/test_apigateway_basic.py::TestAPIGateway::test_invoke_endpoint_cors_headers[http://denied-True-UrlType.PATH_BASED]": 0.06980735300004426, - "tests/aws/services/apigateway/test_apigateway_basic.py::TestAPIGateway::test_multiple_api_keys_validate": 0.4419366609999429, - "tests/aws/services/apigateway/test_apigateway_basic.py::TestAPIGateway::test_put_integration_dynamodb_proxy_validation_with_request_template": 0.0018105149999882997, - "tests/aws/services/apigateway/test_apigateway_basic.py::TestAPIGateway::test_put_integration_dynamodb_proxy_validation_without_request_template": 0.0017636480000078336, - "tests/aws/services/apigateway/test_apigateway_basic.py::TestAPIGateway::test_response_headers_invocation_with_apigw": 1.7545271530000264, - "tests/aws/services/apigateway/test_apigateway_basic.py::TestAPIGateway::test_update_rest_api_deployment": 0.07518845500004545, - "tests/aws/services/apigateway/test_apigateway_basic.py::TestIntegrations::test_api_gateway_http_integrations[custom]": 0.003215114999989055, - "tests/aws/services/apigateway/test_apigateway_basic.py::TestIntegrations::test_api_gateway_http_integrations[proxy]": 0.0031166709999865816, - "tests/aws/services/apigateway/test_apigateway_basic.py::TestIntegrations::test_mock_integration_response[NEVER-UrlType.HOST_BASED-GET]": 0.0951533210000548, - "tests/aws/services/apigateway/test_apigateway_basic.py::TestIntegrations::test_mock_integration_response[NEVER-UrlType.HOST_BASED-POST]": 0.095306712000081, - "tests/aws/services/apigateway/test_apigateway_basic.py::TestIntegrations::test_mock_integration_response[NEVER-UrlType.PATH_BASED-GET]": 0.0956167929999765, - "tests/aws/services/apigateway/test_apigateway_basic.py::TestIntegrations::test_mock_integration_response[NEVER-UrlType.PATH_BASED-POST]": 0.0942956139999751, - "tests/aws/services/apigateway/test_apigateway_basic.py::TestIntegrations::test_mock_integration_response[WHEN_NO_MATCH-UrlType.HOST_BASED-GET]": 0.09300150600006418, - "tests/aws/services/apigateway/test_apigateway_basic.py::TestIntegrations::test_mock_integration_response[WHEN_NO_MATCH-UrlType.HOST_BASED-POST]": 0.09162137800001346, - "tests/aws/services/apigateway/test_apigateway_basic.py::TestIntegrations::test_mock_integration_response[WHEN_NO_MATCH-UrlType.PATH_BASED-GET]": 0.09984427000000551, - "tests/aws/services/apigateway/test_apigateway_basic.py::TestIntegrations::test_mock_integration_response[WHEN_NO_MATCH-UrlType.PATH_BASED-POST]": 0.0945887909999783, - "tests/aws/services/apigateway/test_apigateway_basic.py::TestIntegrations::test_mock_integration_response[WHEN_NO_TEMPLATES-UrlType.HOST_BASED-GET]": 0.10660883299999568, - "tests/aws/services/apigateway/test_apigateway_basic.py::TestIntegrations::test_mock_integration_response[WHEN_NO_TEMPLATES-UrlType.HOST_BASED-POST]": 0.10707337599995981, - "tests/aws/services/apigateway/test_apigateway_basic.py::TestIntegrations::test_mock_integration_response[WHEN_NO_TEMPLATES-UrlType.PATH_BASED-GET]": 0.09548922600004062, - "tests/aws/services/apigateway/test_apigateway_basic.py::TestIntegrations::test_mock_integration_response[WHEN_NO_TEMPLATES-UrlType.PATH_BASED-POST]": 0.09591352299992195, - "tests/aws/services/apigateway/test_apigateway_basic.py::TestTagging::test_tag_api": 0.06510670500000515, - "tests/aws/services/apigateway/test_apigateway_basic.py::test_apigw_call_api_with_aws_endpoint_url": 0.012966818000052172, - "tests/aws/services/apigateway/test_apigateway_basic.py::test_rest_api_multi_region[UrlType.HOST_BASED-ANY]": 3.3844965429999547, - "tests/aws/services/apigateway/test_apigateway_basic.py::test_rest_api_multi_region[UrlType.HOST_BASED-GET]": 3.344784027000003, - "tests/aws/services/apigateway/test_apigateway_basic.py::test_rest_api_multi_region[path_based_url-ANY]": 3.3402703029999543, - "tests/aws/services/apigateway/test_apigateway_basic.py::test_rest_api_multi_region[path_based_url-GET]": 10.313434229999984, - "tests/aws/services/apigateway/test_apigateway_canary.py::TestCanaryDeployments::test_invoking_canary_deployment": 0.11994048000002522, - "tests/aws/services/apigateway/test_apigateway_canary.py::TestStageCrudCanary::test_create_canary_deployment": 0.12586864100001094, - "tests/aws/services/apigateway/test_apigateway_canary.py::TestStageCrudCanary::test_create_canary_deployment_by_stage_update": 0.12964749999997593, - "tests/aws/services/apigateway/test_apigateway_canary.py::TestStageCrudCanary::test_create_canary_deployment_validation": 0.08967582699995091, - "tests/aws/services/apigateway/test_apigateway_canary.py::TestStageCrudCanary::test_create_canary_deployment_with_stage": 0.12494947400000456, - "tests/aws/services/apigateway/test_apigateway_canary.py::TestStageCrudCanary::test_create_update_stages": 0.1892432209999697, - "tests/aws/services/apigateway/test_apigateway_canary.py::TestStageCrudCanary::test_update_stage_canary_deployment_validation": 0.14493211000001338, - "tests/aws/services/apigateway/test_apigateway_canary.py::TestStageCrudCanary::test_update_stage_with_copy_ops": 0.12532194700008858, - "tests/aws/services/apigateway/test_apigateway_common.py::TestApiGatewayCommon::test_api_gateway_request_validator": 2.369182744999989, - "tests/aws/services/apigateway/test_apigateway_common.py::TestApiGatewayCommon::test_api_gateway_request_validator_with_ref_models": 0.16779883299994935, - "tests/aws/services/apigateway/test_apigateway_common.py::TestApiGatewayCommon::test_api_gateway_request_validator_with_ref_one_ofmodels": 0.18109446900001558, - "tests/aws/services/apigateway/test_apigateway_common.py::TestApiGatewayCommon::test_input_body_formatting": 3.4257875330000047, - "tests/aws/services/apigateway/test_apigateway_common.py::TestApiGatewayCommon::test_input_path_template_formatting": 0.6206764249999424, - "tests/aws/services/apigateway/test_apigateway_common.py::TestApiGatewayCommon::test_integration_request_parameters_mapping": 0.10669579500000737, - "tests/aws/services/apigateway/test_apigateway_common.py::TestApiGatewayCommon::test_invocation_trace_id": 2.2790580330000125, - "tests/aws/services/apigateway/test_apigateway_common.py::TestApigatewayRouting::test_api_not_existing": 0.023771072999977605, - "tests/aws/services/apigateway/test_apigateway_common.py::TestApigatewayRouting::test_proxy_routing_with_hardcoded_resource_sibling": 0.20966303699998434, - "tests/aws/services/apigateway/test_apigateway_common.py::TestApigatewayRouting::test_routing_not_found": 0.1122947910001244, - "tests/aws/services/apigateway/test_apigateway_common.py::TestApigatewayRouting::test_routing_with_custom_api_id": 0.0963815259999592, - "tests/aws/services/apigateway/test_apigateway_common.py::TestApigatewayRouting::test_routing_with_hardcoded_resource_sibling_order": 0.19896665599998187, - "tests/aws/services/apigateway/test_apigateway_common.py::TestDeployments::test_create_delete_deployments[False]": 0.40259461300007615, - "tests/aws/services/apigateway/test_apigateway_common.py::TestDeployments::test_create_delete_deployments[True]": 0.44589573599995447, - "tests/aws/services/apigateway/test_apigateway_common.py::TestDeployments::test_create_update_deployments": 0.32251260900000034, - "tests/aws/services/apigateway/test_apigateway_common.py::TestDocumentations::test_documentation_parts_and_versions": 0.1269586989999425, - "tests/aws/services/apigateway/test_apigateway_common.py::TestStages::test_create_update_stages": 0.32544009000002916, - "tests/aws/services/apigateway/test_apigateway_common.py::TestStages::test_update_stage_remove_wildcard": 0.3097793360000196, - "tests/aws/services/apigateway/test_apigateway_common.py::TestUsagePlans::test_api_key_required_for_methods": 0.2120183259999635, - "tests/aws/services/apigateway/test_apigateway_common.py::TestUsagePlans::test_usage_plan_crud": 0.20204061199996204, - "tests/aws/services/apigateway/test_apigateway_custom_ids.py::test_apigateway_custom_ids": 0.0613407250000364, - "tests/aws/services/apigateway/test_apigateway_dynamodb.py::test_error_aws_proxy_not_supported": 0.14632652099999177, - "tests/aws/services/apigateway/test_apigateway_dynamodb.py::test_rest_api_to_dynamodb_integration[PutItem]": 0.36369988099994544, - "tests/aws/services/apigateway/test_apigateway_dynamodb.py::test_rest_api_to_dynamodb_integration[Query]": 0.43507004200000665, - "tests/aws/services/apigateway/test_apigateway_dynamodb.py::test_rest_api_to_dynamodb_integration[Scan]": 0.3508443639999541, - "tests/aws/services/apigateway/test_apigateway_eventbridge.py::test_apigateway_to_eventbridge": 0.20453114299999697, - "tests/aws/services/apigateway/test_apigateway_extended.py::TestApigatewayApiKeysCrud::test_get_api_keys": 0.1600852430000259, - "tests/aws/services/apigateway/test_apigateway_extended.py::TestApigatewayApiKeysCrud::test_get_usage_plan_api_keys": 0.15761589400000275, - "tests/aws/services/apigateway/test_apigateway_extended.py::test_create_domain_names": 0.07397223999998914, - "tests/aws/services/apigateway/test_apigateway_extended.py::test_export_oas30_openapi[TEST_IMPORT_PETSTORE_SWAGGER]": 0.3960102219999726, - "tests/aws/services/apigateway/test_apigateway_extended.py::test_export_oas30_openapi[TEST_IMPORT_PETS]": 0.3034263380000084, - "tests/aws/services/apigateway/test_apigateway_extended.py::test_export_swagger_openapi[TEST_IMPORT_PETSTORE_SWAGGER]": 0.39968100900000536, - "tests/aws/services/apigateway/test_apigateway_extended.py::test_export_swagger_openapi[TEST_IMPORT_PETS]": 0.30155930800003716, - "tests/aws/services/apigateway/test_apigateway_extended.py::test_get_domain_name": 0.07133830599997282, - "tests/aws/services/apigateway/test_apigateway_extended.py::test_get_domain_names": 0.07373854200000096, - "tests/aws/services/apigateway/test_apigateway_http.py::test_http_integration_invoke_status_code_passthrough[HTTP]": 1.750751168000022, - "tests/aws/services/apigateway/test_apigateway_http.py::test_http_integration_invoke_status_code_passthrough[HTTP_PROXY]": 1.733307332000038, - "tests/aws/services/apigateway/test_apigateway_http.py::test_http_integration_method[HTTP]": 2.0365871269999616, - "tests/aws/services/apigateway/test_apigateway_http.py::test_http_integration_method[HTTP_PROXY]": 2.0259965890000444, - "tests/aws/services/apigateway/test_apigateway_http.py::test_http_integration_with_lambda[HTTP]": 2.157333338000001, - "tests/aws/services/apigateway/test_apigateway_http.py::test_http_integration_with_lambda[HTTP_PROXY]": 2.1933360780000157, - "tests/aws/services/apigateway/test_apigateway_http.py::test_http_proxy_integration_request_data_mappings": 1.980334250999988, - "tests/aws/services/apigateway/test_apigateway_import.py::TestApiGatewayImportRestApi::test_import_and_validate_rest_api[openapi.spec.tf.json]": 0.4006580900000358, - "tests/aws/services/apigateway/test_apigateway_import.py::TestApiGatewayImportRestApi::test_import_and_validate_rest_api[swagger-mock-cors.json]": 0.42534966999994595, - "tests/aws/services/apigateway/test_apigateway_import.py::TestApiGatewayImportRestApi::test_import_rest_api": 0.06661004600005072, - "tests/aws/services/apigateway/test_apigateway_import.py::TestApiGatewayImportRestApi::test_import_rest_api_with_base_path_oas30[ignore]": 0.8582959510000023, - "tests/aws/services/apigateway/test_apigateway_import.py::TestApiGatewayImportRestApi::test_import_rest_api_with_base_path_oas30[prepend]": 0.8669431350000423, - "tests/aws/services/apigateway/test_apigateway_import.py::TestApiGatewayImportRestApi::test_import_rest_api_with_base_path_oas30[split]": 0.8648593880000703, - "tests/aws/services/apigateway/test_apigateway_import.py::TestApiGatewayImportRestApi::test_import_rest_apis_with_base_path_swagger[ignore]": 0.6002547779999645, - "tests/aws/services/apigateway/test_apigateway_import.py::TestApiGatewayImportRestApi::test_import_rest_apis_with_base_path_swagger[prepend]": 1.3876511489999643, - "tests/aws/services/apigateway/test_apigateway_import.py::TestApiGatewayImportRestApi::test_import_rest_apis_with_base_path_swagger[split]": 0.5871150119999129, - "tests/aws/services/apigateway/test_apigateway_import.py::TestApiGatewayImportRestApi::test_import_swagger_api": 0.7689230470000439, - "tests/aws/services/apigateway/test_apigateway_import.py::TestApiGatewayImportRestApi::test_import_with_circular_models": 0.2758043549999343, - "tests/aws/services/apigateway/test_apigateway_import.py::TestApiGatewayImportRestApi::test_import_with_circular_models_and_request_validation": 0.4032421319998889, - "tests/aws/services/apigateway/test_apigateway_import.py::TestApiGatewayImportRestApi::test_import_with_cognito_auth_identity_source": 0.37745503999997254, - "tests/aws/services/apigateway/test_apigateway_import.py::TestApiGatewayImportRestApi::test_import_with_global_api_key_authorizer": 0.27706075399993324, - "tests/aws/services/apigateway/test_apigateway_import.py::TestApiGatewayImportRestApi::test_import_with_http_method_integration": 0.28544169700006705, - "tests/aws/services/apigateway/test_apigateway_import.py::TestApiGatewayImportRestApi::test_import_with_integer_http_status_code": 0.17469523199997639, - "tests/aws/services/apigateway/test_apigateway_import.py::TestApiGatewayImportRestApi::test_import_with_stage_variables": 1.6642305639999222, - "tests/aws/services/apigateway/test_apigateway_import.py::TestApiGatewayImportRestApi::test_put_rest_api_mode_binary_media_types[merge]": 0.33256700199996203, - "tests/aws/services/apigateway/test_apigateway_import.py::TestApiGatewayImportRestApi::test_put_rest_api_mode_binary_media_types[overwrite]": 0.3312144569999873, - "tests/aws/services/apigateway/test_apigateway_integrations.py::TestApiGatewayHeaderRemapping::test_apigateway_header_remapping_aws[AWS]": 2.4490121410001393, - "tests/aws/services/apigateway/test_apigateway_integrations.py::TestApiGatewayHeaderRemapping::test_apigateway_header_remapping_aws[AWS_PROXY]": 3.2597750340000857, - "tests/aws/services/apigateway/test_apigateway_integrations.py::TestApiGatewayHeaderRemapping::test_apigateway_header_remapping_http[HTTP]": 0.8110359870000821, - "tests/aws/services/apigateway/test_apigateway_integrations.py::TestApiGatewayHeaderRemapping::test_apigateway_header_remapping_http[HTTP_PROXY]": 0.7855166699999927, - "tests/aws/services/apigateway/test_apigateway_integrations.py::test_create_execute_api_vpc_endpoint": 5.407402619000038, - "tests/aws/services/apigateway/test_apigateway_integrations.py::test_http_integration_status_code_selection": 0.12213966600006643, - "tests/aws/services/apigateway/test_apigateway_integrations.py::test_integration_mock_with_path_param": 0.09625298599996768, - "tests/aws/services/apigateway/test_apigateway_integrations.py::test_integration_mock_with_request_overrides_in_response_template": 0.11548494499999151, - "tests/aws/services/apigateway/test_apigateway_integrations.py::test_integration_mock_with_response_override_in_request_template[False]": 0.08445540100001381, - "tests/aws/services/apigateway/test_apigateway_integrations.py::test_integration_mock_with_response_override_in_request_template[True]": 0.08515770199994677, - "tests/aws/services/apigateway/test_apigateway_integrations.py::test_integration_mock_with_vtl_map_assignation": 0.08523168200002829, - "tests/aws/services/apigateway/test_apigateway_integrations.py::test_put_integration_response_with_response_template": 1.2117569019999337, - "tests/aws/services/apigateway/test_apigateway_integrations.py::test_put_integration_responses": 0.18961181700007046, - "tests/aws/services/apigateway/test_apigateway_integrations.py::test_put_integration_validation": 0.20210301200000913, - "tests/aws/services/apigateway/test_apigateway_kinesis.py::test_apigateway_to_kinesis[PutRecord]": 1.0785970039999029, - "tests/aws/services/apigateway/test_apigateway_kinesis.py::test_apigateway_to_kinesis[PutRecords]": 1.0759147869999879, - "tests/aws/services/apigateway/test_apigateway_lambda.py::test_aws_proxy_binary_response": 3.6993263710000974, - "tests/aws/services/apigateway/test_apigateway_lambda.py::test_aws_proxy_response_payload_format_validation": 3.9657204440001124, - "tests/aws/services/apigateway/test_apigateway_lambda.py::test_lambda_aws_integration": 1.6796207849999973, - "tests/aws/services/apigateway/test_apigateway_lambda.py::test_lambda_aws_integration_response_with_mapping_templates": 1.8658529949999547, - "tests/aws/services/apigateway/test_apigateway_lambda.py::test_lambda_aws_integration_with_request_template": 1.814130223999996, - "tests/aws/services/apigateway/test_apigateway_lambda.py::test_lambda_aws_proxy_integration": 3.973228559000063, - "tests/aws/services/apigateway/test_apigateway_lambda.py::test_lambda_aws_proxy_integration_non_post_method": 1.272139908999975, - "tests/aws/services/apigateway/test_apigateway_lambda.py::test_lambda_aws_proxy_integration_request_data_mapping": 2.833532599000023, - "tests/aws/services/apigateway/test_apigateway_lambda.py::test_lambda_aws_proxy_response_format": 1.9675056880000739, - "tests/aws/services/apigateway/test_apigateway_lambda.py::test_lambda_rust_proxy_integration": 3.7251584169999887, - "tests/aws/services/apigateway/test_apigateway_lambda.py::test_lambda_selection_patterns": 1.9472248480001326, - "tests/aws/services/apigateway/test_apigateway_lambda.py::test_put_integration_aws_proxy_uri": 1.3009587189999365, - "tests/aws/services/apigateway/test_apigateway_lambda_cfn.py::TestApigatewayLambdaIntegration::test_scenario_validate_infra": 7.633159453999951, - "tests/aws/services/apigateway/test_apigateway_s3.py::TestApiGatewayS3BinarySupport::test_apigw_s3_binary_support_request[CONVERT_TO_TEXT]": 0.4920630040001015, - "tests/aws/services/apigateway/test_apigateway_s3.py::TestApiGatewayS3BinarySupport::test_apigw_s3_binary_support_request[None]": 0.5146514919999845, - "tests/aws/services/apigateway/test_apigateway_s3.py::TestApiGatewayS3BinarySupport::test_apigw_s3_binary_support_request_convert_to_binary": 0.4438411429998723, - "tests/aws/services/apigateway/test_apigateway_s3.py::TestApiGatewayS3BinarySupport::test_apigw_s3_binary_support_request_convert_to_binary_with_request_template": 0.2753280999999106, - "tests/aws/services/apigateway/test_apigateway_s3.py::TestApiGatewayS3BinarySupport::test_apigw_s3_binary_support_response_convert_to_binary": 0.5105983089999881, - "tests/aws/services/apigateway/test_apigateway_s3.py::TestApiGatewayS3BinarySupport::test_apigw_s3_binary_support_response_convert_to_binary_with_request_template": 0.3267231410000022, - "tests/aws/services/apigateway/test_apigateway_s3.py::TestApiGatewayS3BinarySupport::test_apigw_s3_binary_support_response_convert_to_text": 0.5117456020001327, - "tests/aws/services/apigateway/test_apigateway_s3.py::TestApiGatewayS3BinarySupport::test_apigw_s3_binary_support_response_no_content_handling": 0.5240489669998851, - "tests/aws/services/apigateway/test_apigateway_s3.py::test_apigateway_s3_any": 0.407860219999975, - "tests/aws/services/apigateway/test_apigateway_s3.py::test_apigateway_s3_method_mapping": 0.4505493500000739, - "tests/aws/services/apigateway/test_apigateway_sqs.py::test_sqs_amz_json_protocol": 0.9394801540000799, - "tests/aws/services/apigateway/test_apigateway_sqs.py::test_sqs_aws_integration": 1.1737576619999572, - "tests/aws/services/apigateway/test_apigateway_sqs.py::test_sqs_aws_integration_with_message_attribute[MessageAttribute]": 0.2444269439999971, - "tests/aws/services/apigateway/test_apigateway_sqs.py::test_sqs_aws_integration_with_message_attribute[MessageAttributes]": 0.2404195100001516, - "tests/aws/services/apigateway/test_apigateway_sqs.py::test_sqs_request_and_response_xml_templates_integration": 0.3305063650000193, - "tests/aws/services/apigateway/test_apigateway_ssm.py::test_get_parameter_query_protocol": 0.00192461800008914, - "tests/aws/services/apigateway/test_apigateway_ssm.py::test_ssm_aws_integration": 0.2153708480000205, - "tests/aws/services/apigateway/test_apigateway_stepfunctions.py::TestApigatewayStepfunctions::test_apigateway_with_step_function_integration[DeleteStateMachine]": 1.331796572999906, - "tests/aws/services/apigateway/test_apigateway_stepfunctions.py::TestApigatewayStepfunctions::test_apigateway_with_step_function_integration[StartExecution]": 1.4284064429999717, - "tests/aws/services/cloudcontrol/test_cloudcontrol_api.py::TestCloudControlResourceApi::test_api_exceptions": 0.0017795590000559969, - "tests/aws/services/cloudcontrol/test_cloudcontrol_api.py::TestCloudControlResourceApi::test_create_exceptions": 0.001734674999966046, - "tests/aws/services/cloudcontrol/test_cloudcontrol_api.py::TestCloudControlResourceApi::test_create_invalid_desiredstate": 0.0017110309998997764, - "tests/aws/services/cloudcontrol/test_cloudcontrol_api.py::TestCloudControlResourceApi::test_double_create_with_client_token": 0.00173207000000275, - "tests/aws/services/cloudcontrol/test_cloudcontrol_api.py::TestCloudControlResourceApi::test_lifecycle": 0.001910692000024028, - "tests/aws/services/cloudcontrol/test_cloudcontrol_api.py::TestCloudControlResourceApi::test_list_resources": 0.0018423369999709394, - "tests/aws/services/cloudcontrol/test_cloudcontrol_api.py::TestCloudControlResourceApi::test_list_resources_with_resource_model": 0.0018460530000083963, - "tests/aws/services/cloudcontrol/test_cloudcontrol_api.py::TestCloudControlResourceApi::test_update": 0.0018466040000930661, - "tests/aws/services/cloudcontrol/test_cloudcontrol_api.py::TestCloudControlResourceRequestApi::test_cancel_edge_cases[FAIL]": 0.0017173729999058196, - "tests/aws/services/cloudcontrol/test_cloudcontrol_api.py::TestCloudControlResourceRequestApi::test_cancel_edge_cases[SUCCESS]": 0.001741438000067319, - "tests/aws/services/cloudcontrol/test_cloudcontrol_api.py::TestCloudControlResourceRequestApi::test_cancel_request": 0.0017427910000833435, - "tests/aws/services/cloudcontrol/test_cloudcontrol_api.py::TestCloudControlResourceRequestApi::test_get_request_status": 0.0017382620000034876, - "tests/aws/services/cloudcontrol/test_cloudcontrol_api.py::TestCloudControlResourceRequestApi::test_invalid_request_token_exc": 0.001999750000095446, - "tests/aws/services/cloudcontrol/test_cloudcontrol_api.py::TestCloudControlResourceRequestApi::test_list_request_status": 0.001737270000035096, - "tests/aws/services/cloudformation/api/test_changesets.py::TestUpdates::test_deleting_resource": 24.388806261000013, - "tests/aws/services/cloudformation/api/test_changesets.py::TestUpdates::test_simple_update_single_resource": 4.193955933999973, - "tests/aws/services/cloudformation/api/test_changesets.py::TestUpdates::test_simple_update_two_resources": 4.241496714999926, - "tests/aws/services/cloudformation/api/test_changesets.py::test_autoexpand_capability_requirement": 0.08518068699993364, - "tests/aws/services/cloudformation/api/test_changesets.py::test_create_and_then_remove_non_supported_resource_change_set": 19.959580676999963, - "tests/aws/services/cloudformation/api/test_changesets.py::test_create_and_then_remove_supported_resource_change_set": 11.464060142000108, - "tests/aws/services/cloudformation/api/test_changesets.py::test_create_and_then_update_refreshes_template_metadata": 0.0019537030000265077, - "tests/aws/services/cloudformation/api/test_changesets.py::test_create_change_set_create_existing": 1.0824051119999467, - "tests/aws/services/cloudformation/api/test_changesets.py::test_create_change_set_invalid_params": 0.015684477999911905, - "tests/aws/services/cloudformation/api/test_changesets.py::test_create_change_set_missing_stackname": 0.021494500999892807, - "tests/aws/services/cloudformation/api/test_changesets.py::test_create_change_set_update_nonexisting": 0.015555899999981193, - "tests/aws/services/cloudformation/api/test_changesets.py::test_create_change_set_update_without_parameters": 0.0019441160000042146, - "tests/aws/services/cloudformation/api/test_changesets.py::test_create_change_set_with_ssm_parameter": 1.1505652240000472, - "tests/aws/services/cloudformation/api/test_changesets.py::test_create_change_set_without_parameters": 0.07426999299991621, - "tests/aws/services/cloudformation/api/test_changesets.py::test_create_changeset_with_stack_id": 0.2436181419999457, - "tests/aws/services/cloudformation/api/test_changesets.py::test_create_delete_create": 2.1492938129999857, - "tests/aws/services/cloudformation/api/test_changesets.py::test_create_while_in_review": 0.001776922999965791, - "tests/aws/services/cloudformation/api/test_changesets.py::test_delete_change_set_exception": 0.021389935000115656, - "tests/aws/services/cloudformation/api/test_changesets.py::test_deleted_changeset": 0.04805059000000256, - "tests/aws/services/cloudformation/api/test_changesets.py::test_describe_change_set_nonexisting": 0.013220300999932988, - "tests/aws/services/cloudformation/api/test_changesets.py::test_describe_change_set_with_similarly_named_stacks": 0.04852886599996964, - "tests/aws/services/cloudformation/api/test_changesets.py::test_empty_changeset": 1.3194248869999683, - "tests/aws/services/cloudformation/api/test_changesets.py::test_execute_change_set": 0.001725828000076035, - "tests/aws/services/cloudformation/api/test_changesets.py::test_multiple_create_changeset": 0.3481784550001521, - "tests/aws/services/cloudformation/api/test_changesets.py::test_name_conflicts": 1.8846580859999449, - "tests/aws/services/cloudformation/api/test_drift_detection.py::test_drift_detection_on_lambda": 0.001770471999975598, - "tests/aws/services/cloudformation/api/test_extensions_api.py::TestExtensionsApi::test_crud_extension[HOOK-LocalStack::Testing::TestHook-hooks/localstack-testing-testhook.zip]": 0.0017605829999638445, - "tests/aws/services/cloudformation/api/test_extensions_api.py::TestExtensionsApi::test_crud_extension[MODULE-LocalStack::Testing::TestModule::MODULE-modules/localstack-testing-testmodule-module.zip]": 0.001754833000063627, - "tests/aws/services/cloudformation/api/test_extensions_api.py::TestExtensionsApi::test_crud_extension[RESOURCE-LocalStack::Testing::TestResource-resourcetypes/localstack-testing-testresource.zip]": 0.0017863610000858898, - "tests/aws/services/cloudformation/api/test_extensions_api.py::TestExtensionsApi::test_extension_not_complete": 0.0017415669999536476, - "tests/aws/services/cloudformation/api/test_extensions_api.py::TestExtensionsApi::test_extension_type_configuration": 0.0017941060000339348, - "tests/aws/services/cloudformation/api/test_extensions_api.py::TestExtensionsApi::test_extension_versioning": 0.0017465659999515992, - "tests/aws/services/cloudformation/api/test_extensions_hooks.py::TestExtensionsHooks::test_hook_deployment[FAIL]": 0.001764150999974845, - "tests/aws/services/cloudformation/api/test_extensions_hooks.py::TestExtensionsHooks::test_hook_deployment[WARN]": 0.0017740980000553463, - "tests/aws/services/cloudformation/api/test_extensions_modules.py::TestExtensionsModules::test_module_usage": 0.0017879439999433089, - "tests/aws/services/cloudformation/api/test_extensions_resourcetypes.py::TestExtensionsResourceTypes::test_deploy_resource_type": 0.0018285600000353952, - "tests/aws/services/cloudformation/api/test_nested_stacks.py::test_deletion_of_failed_nested_stack": 6.272398151999937, - "tests/aws/services/cloudformation/api/test_nested_stacks.py::test_lifecycle_nested_stack": 0.002318803999969532, - "tests/aws/services/cloudformation/api/test_nested_stacks.py::test_nested_output_in_params": 12.614482294000027, - "tests/aws/services/cloudformation/api/test_nested_stacks.py::test_nested_stack": 6.210287766000079, - "tests/aws/services/cloudformation/api/test_nested_stacks.py::test_nested_stack_output_refs": 6.2195832670000755, - "tests/aws/services/cloudformation/api/test_nested_stacks.py::test_nested_stacks_conditions": 6.228385151000111, - "tests/aws/services/cloudformation/api/test_nested_stacks.py::test_nested_with_nested_stack": 12.307145999999989, - "tests/aws/services/cloudformation/api/test_reference_resolving.py::test_nested_getatt_ref[TopicArn]": 2.10084282899993, - "tests/aws/services/cloudformation/api/test_reference_resolving.py::test_nested_getatt_ref[TopicName]": 2.1182811420000007, - "tests/aws/services/cloudformation/api/test_reference_resolving.py::test_reference_unsupported_resource": 2.097733647000041, - "tests/aws/services/cloudformation/api/test_reference_resolving.py::test_sub_resolving": 2.103290293999976, - "tests/aws/services/cloudformation/api/test_resources.py::test_describe_non_existent_resource": 2.122872568000048, - "tests/aws/services/cloudformation/api/test_resources.py::test_describe_non_existent_stack": 0.0018273480000061681, - "tests/aws/services/cloudformation/api/test_resources.py::test_invalid_logical_resource_id": 0.0019162350000669903, - "tests/aws/services/cloudformation/api/test_stack_policies.py::TestStackPolicy::test_create_stack_with_policy": 0.0017998459999262195, - "tests/aws/services/cloudformation/api/test_stack_policies.py::TestStackPolicy::test_different_action_attribute": 0.0018924299999980576, - "tests/aws/services/cloudformation/api/test_stack_policies.py::TestStackPolicy::test_different_principal_attribute": 0.002029043999982605, - "tests/aws/services/cloudformation/api/test_stack_policies.py::TestStackPolicy::test_empty_policy": 0.0018636350000633684, - "tests/aws/services/cloudformation/api/test_stack_policies.py::TestStackPolicy::test_not_json_policy": 0.0017586899999741945, - "tests/aws/services/cloudformation/api/test_stack_policies.py::TestStackPolicy::test_policy_during_update": 0.0017677579999144655, - "tests/aws/services/cloudformation/api/test_stack_policies.py::TestStackPolicy::test_policy_lifecycle": 0.0017955989999336452, - "tests/aws/services/cloudformation/api/test_stack_policies.py::TestStackPolicy::test_prevent_deletion[resource0]": 0.0018241029998762315, - "tests/aws/services/cloudformation/api/test_stack_policies.py::TestStackPolicy::test_prevent_deletion[resource1]": 0.001851254000030167, - "tests/aws/services/cloudformation/api/test_stack_policies.py::TestStackPolicy::test_prevent_modifying_with_policy_specifying_resource_id": 0.0018270480001092437, - "tests/aws/services/cloudformation/api/test_stack_policies.py::TestStackPolicy::test_prevent_replacement": 0.0017674160000069605, - "tests/aws/services/cloudformation/api/test_stack_policies.py::TestStackPolicy::test_prevent_resource_deletion": 0.0017788369999607312, - "tests/aws/services/cloudformation/api/test_stack_policies.py::TestStackPolicy::test_prevent_stack_update": 0.0018809690000125556, - "tests/aws/services/cloudformation/api/test_stack_policies.py::TestStackPolicy::test_prevent_update[AWS::S3::Bucket]": 0.0018582960000230742, - "tests/aws/services/cloudformation/api/test_stack_policies.py::TestStackPolicy::test_prevent_update[AWS::SNS::Topic]": 0.0019299899998941328, - "tests/aws/services/cloudformation/api/test_stack_policies.py::TestStackPolicy::test_set_empty_policy_with_url": 0.0018457719999105393, - "tests/aws/services/cloudformation/api/test_stack_policies.py::TestStackPolicy::test_set_invalid_policy_with_url": 0.0017822140001726439, - "tests/aws/services/cloudformation/api/test_stack_policies.py::TestStackPolicy::test_set_policy_both_policy_and_url": 0.0017512659999283642, - "tests/aws/services/cloudformation/api/test_stack_policies.py::TestStackPolicy::test_set_policy_with_update_operation": 0.0019902120000097057, - "tests/aws/services/cloudformation/api/test_stack_policies.py::TestStackPolicy::test_set_policy_with_url": 0.00178779400005169, - "tests/aws/services/cloudformation/api/test_stack_policies.py::TestStackPolicy::test_update_with_empty_policy": 0.0018075600000884151, - "tests/aws/services/cloudformation/api/test_stack_policies.py::TestStackPolicy::test_update_with_overlapping_policies[False]": 0.0018832730000895026, - "tests/aws/services/cloudformation/api/test_stack_policies.py::TestStackPolicy::test_update_with_overlapping_policies[True]": 0.0019083700000237513, - "tests/aws/services/cloudformation/api/test_stack_policies.py::TestStackPolicy::test_update_with_policy": 0.001779577999968751, - "tests/aws/services/cloudformation/api/test_stacks.py::TestStacksApi::test_create_stack_with_custom_id": 1.0564707060000273, - "tests/aws/services/cloudformation/api/test_stacks.py::TestStacksApi::test_failure_options_for_stack_creation[False-0]": 0.001856701999940924, - "tests/aws/services/cloudformation/api/test_stacks.py::TestStacksApi::test_failure_options_for_stack_creation[True-1]": 0.001723986000001787, - "tests/aws/services/cloudformation/api/test_stacks.py::TestStacksApi::test_failure_options_for_stack_update[False-2]": 0.001796321000028911, - "tests/aws/services/cloudformation/api/test_stacks.py::TestStacksApi::test_failure_options_for_stack_update[True-1]": 0.0017401849999032493, - "tests/aws/services/cloudformation/api/test_stacks.py::TestStacksApi::test_get_template_using_changesets[json]": 2.106455037999922, - "tests/aws/services/cloudformation/api/test_stacks.py::TestStacksApi::test_get_template_using_changesets[yaml]": 2.1042961470001273, - "tests/aws/services/cloudformation/api/test_stacks.py::TestStacksApi::test_get_template_using_create_stack[json]": 1.0534392220000655, - "tests/aws/services/cloudformation/api/test_stacks.py::TestStacksApi::test_get_template_using_create_stack[yaml]": 1.0557331520000162, - "tests/aws/services/cloudformation/api/test_stacks.py::TestStacksApi::test_list_events_after_deployment": 2.1754690669999945, - "tests/aws/services/cloudformation/api/test_stacks.py::TestStacksApi::test_stack_description_lifecycle": 0.002089416999979221, - "tests/aws/services/cloudformation/api/test_stacks.py::TestStacksApi::test_stack_description_special_chars": 2.293484792999948, - "tests/aws/services/cloudformation/api/test_stacks.py::TestStacksApi::test_stack_lifecycle": 4.359698218000176, - "tests/aws/services/cloudformation/api/test_stacks.py::TestStacksApi::test_stack_name_creation": 0.07879569000010633, - "tests/aws/services/cloudformation/api/test_stacks.py::TestStacksApi::test_stack_update_resources": 4.423436992000006, - "tests/aws/services/cloudformation/api/test_stacks.py::TestStacksApi::test_update_stack_actual_update": 4.180976362000024, - "tests/aws/services/cloudformation/api/test_stacks.py::TestStacksApi::test_update_stack_with_same_template_withoutchange": 2.088754483000116, - "tests/aws/services/cloudformation/api/test_stacks.py::TestStacksApi::test_update_stack_with_same_template_withoutchange_transformation": 2.2526486210000485, - "tests/aws/services/cloudformation/api/test_stacks.py::test_blocked_stack_deletion": 0.0018228100000214909, - "tests/aws/services/cloudformation/api/test_stacks.py::test_describe_stack_events_errors": 0.023439608000103362, - "tests/aws/services/cloudformation/api/test_stacks.py::test_events_resource_types": 2.144624126999929, - "tests/aws/services/cloudformation/api/test_stacks.py::test_linting_error_during_creation": 0.0019566789999316825, - "tests/aws/services/cloudformation/api/test_stacks.py::test_list_parameter_type": 2.1054978240000537, - "tests/aws/services/cloudformation/api/test_stacks.py::test_name_conflicts": 2.3853568660001656, - "tests/aws/services/cloudformation/api/test_stacks.py::test_no_echo_parameter": 3.9561243029999105, - "tests/aws/services/cloudformation/api/test_stacks.py::test_no_parameters_given": 0.0018603260000418231, - "tests/aws/services/cloudformation/api/test_stacks.py::test_non_existing_stack_message": 0.015553941000007399, - "tests/aws/services/cloudformation/api/test_stacks.py::test_notifications": 0.001896195999961492, - "tests/aws/services/cloudformation/api/test_stacks.py::test_stack_deletion_order[A-B-C]": 0.0017353859999502674, - "tests/aws/services/cloudformation/api/test_stacks.py::test_stack_deletion_order[B-C]": 0.00176358800001708, - "tests/aws/services/cloudformation/api/test_stacks.py::test_stack_deletion_order[C]": 0.0018466040000930661, - "tests/aws/services/cloudformation/api/test_stacks.py::test_stack_deploy_order[A-B-C]": 2.374774640000055, - "tests/aws/services/cloudformation/api/test_stacks.py::test_stack_deploy_order[A-C-B]": 2.3760651929998176, - "tests/aws/services/cloudformation/api/test_stacks.py::test_stack_deploy_order[B-A-C]": 2.379135040000051, - "tests/aws/services/cloudformation/api/test_stacks.py::test_stack_deploy_order[B-C-A]": 2.3819516979998525, - "tests/aws/services/cloudformation/api/test_stacks.py::test_stack_deploy_order[C-A-B]": 2.381166539999981, - "tests/aws/services/cloudformation/api/test_stacks.py::test_stack_deploy_order[C-B-A]": 2.3824239229999193, - "tests/aws/services/cloudformation/api/test_stacks.py::test_stack_resource_not_found": 2.0997310719999405, - "tests/aws/services/cloudformation/api/test_stacks.py::test_update_termination_protection": 2.127637490000211, - "tests/aws/services/cloudformation/api/test_stacks.py::test_updating_an_updated_stack_sets_status": 6.426303193000194, - "tests/aws/services/cloudformation/api/test_templates.py::test_create_stack_from_s3_template_url[http_host]": 1.1367357619999439, - "tests/aws/services/cloudformation/api/test_templates.py::test_create_stack_from_s3_template_url[http_invalid]": 0.09227992399996765, - "tests/aws/services/cloudformation/api/test_templates.py::test_create_stack_from_s3_template_url[http_path]": 1.1375577229999863, - "tests/aws/services/cloudformation/api/test_templates.py::test_create_stack_from_s3_template_url[s3_url]": 0.10424774099999468, - "tests/aws/services/cloudformation/api/test_templates.py::test_get_template_summary": 2.2483909580000727, - "tests/aws/services/cloudformation/api/test_templates.py::test_validate_invalid_json_template_should_fail": 0.08912486999997782, - "tests/aws/services/cloudformation/api/test_templates.py::test_validate_template": 0.08934587900000679, - "tests/aws/services/cloudformation/api/test_transformers.py::TestLanguageExtensionsTransform::test_transform_foreach": 1.2805926229999613, - "tests/aws/services/cloudformation/api/test_transformers.py::TestLanguageExtensionsTransform::test_transform_foreach_multiple_resources": 1.3765966720000051, - "tests/aws/services/cloudformation/api/test_transformers.py::TestLanguageExtensionsTransform::test_transform_foreach_use_case": 1.5537835469999663, - "tests/aws/services/cloudformation/api/test_transformers.py::TestLanguageExtensionsTransform::test_transform_length": 1.2618158409999296, - "tests/aws/services/cloudformation/api/test_transformers.py::TestLanguageExtensionsTransform::test_transform_to_json_string": 1.3235084890000053, - "tests/aws/services/cloudformation/api/test_transformers.py::test_duplicate_resources": 2.34670231899986, - "tests/aws/services/cloudformation/api/test_transformers.py::test_transformer_individual_resource_level": 2.2386659269999427, - "tests/aws/services/cloudformation/api/test_transformers.py::test_transformer_property_level": 2.2886131000000205, - "tests/aws/services/cloudformation/api/test_update_stack.py::test_basic_update": 3.1384845669999777, - "tests/aws/services/cloudformation/api/test_update_stack.py::test_diff_after_update": 3.144493639000075, - "tests/aws/services/cloudformation/api/test_update_stack.py::test_no_parameters_update": 3.1244980489999534, - "tests/aws/services/cloudformation/api/test_update_stack.py::test_no_template_error": 0.0017634590000170647, - "tests/aws/services/cloudformation/api/test_update_stack.py::test_set_notification_arn_with_update": 0.0016889400000081878, - "tests/aws/services/cloudformation/api/test_update_stack.py::test_update_tags": 0.0018514619999905335, - "tests/aws/services/cloudformation/api/test_update_stack.py::test_update_using_template_url": 3.19734141299989, - "tests/aws/services/cloudformation/api/test_update_stack.py::test_update_with_capabilities[capability0]": 0.0018111769999222815, - "tests/aws/services/cloudformation/api/test_update_stack.py::test_update_with_capabilities[capability1]": 0.0017483910000919423, - "tests/aws/services/cloudformation/api/test_update_stack.py::test_update_with_invalid_rollback_configuration_errors": 0.0017264909999994416, - "tests/aws/services/cloudformation/api/test_update_stack.py::test_update_with_previous_parameter_value": 3.131199115000072, - "tests/aws/services/cloudformation/api/test_update_stack.py::test_update_with_previous_template": 0.0020163500000762724, - "tests/aws/services/cloudformation/api/test_update_stack.py::test_update_with_resource_types": 0.0017724350000207778, - "tests/aws/services/cloudformation/api/test_update_stack.py::test_update_with_role_without_permissions": 0.0018398599999045473, - "tests/aws/services/cloudformation/api/test_update_stack.py::test_update_with_rollback_configuration": 0.0017500629999176454, - "tests/aws/services/cloudformation/api/test_validations.py::test_invalid_output_structure[missing-def]": 0.0018233209999607425, - "tests/aws/services/cloudformation/api/test_validations.py::test_invalid_output_structure[multiple-nones]": 0.001776121999910174, - "tests/aws/services/cloudformation/api/test_validations.py::test_invalid_output_structure[none-value]": 0.001876638999988245, - "tests/aws/services/cloudformation/api/test_validations.py::test_missing_resources_block": 0.0017175119999137678, - "tests/aws/services/cloudformation/api/test_validations.py::test_resources_blocks[invalid-key]": 0.001771104000113155, - "tests/aws/services/cloudformation/api/test_validations.py::test_resources_blocks[missing-type]": 0.0017661639999460021, - "tests/aws/services/cloudformation/engine/test_attributes.py::TestResourceAttributes::test_dependency_on_attribute_with_dot_notation": 2.115954352000017, - "tests/aws/services/cloudformation/engine/test_attributes.py::TestResourceAttributes::test_invalid_getatt_fails": 0.001745496000012281, - "tests/aws/services/cloudformation/engine/test_conditions.py::TestCloudFormationConditions::test_condition_on_outputs": 2.1124120240000366, - "tests/aws/services/cloudformation/engine/test_conditions.py::TestCloudFormationConditions::test_conditional_att_to_conditional_resources[create]": 2.1383879650001063, - "tests/aws/services/cloudformation/engine/test_conditions.py::TestCloudFormationConditions::test_conditional_att_to_conditional_resources[no-create]": 2.1253189760001305, - "tests/aws/services/cloudformation/engine/test_conditions.py::TestCloudFormationConditions::test_conditional_in_conditional[dev-us-west-2]": 2.1022814059999746, - "tests/aws/services/cloudformation/engine/test_conditions.py::TestCloudFormationConditions::test_conditional_in_conditional[production-us-east-1]": 2.1030590190000567, - "tests/aws/services/cloudformation/engine/test_conditions.py::TestCloudFormationConditions::test_conditional_with_select": 2.1122508649999645, - "tests/aws/services/cloudformation/engine/test_conditions.py::TestCloudFormationConditions::test_dependency_in_non_evaluated_if_branch[None-FallbackParamValue]": 2.1299162660000093, - "tests/aws/services/cloudformation/engine/test_conditions.py::TestCloudFormationConditions::test_dependency_in_non_evaluated_if_branch[false-DefaultParamValue]": 2.131908502999977, - "tests/aws/services/cloudformation/engine/test_conditions.py::TestCloudFormationConditions::test_dependency_in_non_evaluated_if_branch[true-FallbackParamValue]": 2.134932886999991, - "tests/aws/services/cloudformation/engine/test_conditions.py::TestCloudFormationConditions::test_dependent_ref": 0.0018300919999774123, - "tests/aws/services/cloudformation/engine/test_conditions.py::TestCloudFormationConditions::test_dependent_ref_intrinsic_fn_condition": 0.0017098990000476988, - "tests/aws/services/cloudformation/engine/test_conditions.py::TestCloudFormationConditions::test_dependent_ref_with_macro": 0.0018350320000308784, - "tests/aws/services/cloudformation/engine/test_conditions.py::TestCloudFormationConditions::test_nested_conditions[prod-bucket-policy]": 0.001825984999868524, - "tests/aws/services/cloudformation/engine/test_conditions.py::TestCloudFormationConditions::test_nested_conditions[prod-nobucket-nopolicy]": 0.0017991150000398193, - "tests/aws/services/cloudformation/engine/test_conditions.py::TestCloudFormationConditions::test_nested_conditions[test-bucket-nopolicy]": 0.0018173689999230191, - "tests/aws/services/cloudformation/engine/test_conditions.py::TestCloudFormationConditions::test_nested_conditions[test-nobucket-nopolicy]": 0.0018108180000808716, - "tests/aws/services/cloudformation/engine/test_conditions.py::TestCloudFormationConditions::test_output_reference_to_skipped_resource": 0.0017813009999372298, - "tests/aws/services/cloudformation/engine/test_conditions.py::TestCloudFormationConditions::test_simple_condition_evaluation_deploys_resource": 2.1107950370001163, - "tests/aws/services/cloudformation/engine/test_conditions.py::TestCloudFormationConditions::test_simple_condition_evaluation_doesnt_deploy_resource": 0.08636257199998454, - "tests/aws/services/cloudformation/engine/test_conditions.py::TestCloudFormationConditions::test_simple_intrinsic_fn_condition_evaluation[nope]": 2.0920290889999933, - "tests/aws/services/cloudformation/engine/test_conditions.py::TestCloudFormationConditions::test_simple_intrinsic_fn_condition_evaluation[yep]": 2.0923519699999815, - "tests/aws/services/cloudformation/engine/test_conditions.py::TestCloudFormationConditions::test_sub_in_conditions": 2.126984724999943, - "tests/aws/services/cloudformation/engine/test_conditions.py::TestCloudFormationConditions::test_update_conditions": 4.219379247000006, - "tests/aws/services/cloudformation/engine/test_mappings.py::TestCloudFormationMappings::test_async_mapping_error_first_level_v2": 0.0018722720000141635, - "tests/aws/services/cloudformation/engine/test_mappings.py::TestCloudFormationMappings::test_async_mapping_error_second_level_v2": 0.001864608000005319, - "tests/aws/services/cloudformation/engine/test_mappings.py::TestCloudFormationMappings::test_aws_refs_in_mappings": 2.0968204040000273, - "tests/aws/services/cloudformation/engine/test_mappings.py::TestCloudFormationMappings::test_mapping_maximum_nesting_depth": 0.0017621460000327716, - "tests/aws/services/cloudformation/engine/test_mappings.py::TestCloudFormationMappings::test_mapping_minimum_nesting_depth": 0.0017830559999083562, - "tests/aws/services/cloudformation/engine/test_mappings.py::TestCloudFormationMappings::test_mapping_ref_map_key[should-deploy]": 2.117570846000035, - "tests/aws/services/cloudformation/engine/test_mappings.py::TestCloudFormationMappings::test_mapping_ref_map_key[should-not-deploy]": 2.0952545689998487, - "tests/aws/services/cloudformation/engine/test_mappings.py::TestCloudFormationMappings::test_mapping_with_invalid_refs": 0.0018820489999598067, - "tests/aws/services/cloudformation/engine/test_mappings.py::TestCloudFormationMappings::test_mapping_with_nonexisting_key": 0.0019205420001071616, - "tests/aws/services/cloudformation/engine/test_mappings.py::TestCloudFormationMappings::test_simple_mapping_working": 2.114810788999989, - "tests/aws/services/cloudformation/engine/test_references.py::TestDependsOn::test_depends_on_with_missing_reference": 0.0017936450000206605, - "tests/aws/services/cloudformation/engine/test_references.py::TestFnSub::test_fn_sub_cases": 2.116787725999984, - "tests/aws/services/cloudformation/engine/test_references.py::TestFnSub::test_non_string_parameter_in_sub": 2.1144851959999187, - "tests/aws/services/cloudformation/engine/test_references.py::test_aws_novalue[no]": 2.105223894999881, - "tests/aws/services/cloudformation/engine/test_references.py::test_aws_novalue[yes]": 2.102389591000133, - "tests/aws/services/cloudformation/engine/test_references.py::test_resolve_transitive_placeholders_in_strings": 2.131904114000008, - "tests/aws/services/cloudformation/engine/test_references.py::test_useful_error_when_invalid_ref": 0.018532472000060807, - "tests/aws/services/cloudformation/resource_providers/ec2/aws_ec2_networkacl/test_basic.py::TestBasicCRD::test_black_box": 2.561271474000023, - "tests/aws/services/cloudformation/resource_providers/ec2/test_ec2_resource_provider.py::test_deploy_instance_with_key_pair": 2.3982268630001045, - "tests/aws/services/cloudformation/resource_providers/ec2/test_ec2_resource_provider.py::test_deploy_prefix_list": 7.163684359000058, - "tests/aws/services/cloudformation/resource_providers/ec2/test_ec2_resource_provider.py::test_deploy_security_group_with_tags": 2.1153754520000803, - "tests/aws/services/cloudformation/resource_providers/ec2/test_ec2_resource_provider.py::test_deploy_vpc_endpoint": 2.5215625869999485, - "tests/aws/services/cloudformation/resource_providers/iam/aws_iam_user/test_basic_user.py::TestBasicCRD::test_autogenerated_values": 2.1005540159999327, - "tests/aws/services/cloudformation/resource_providers/iam/aws_iam_user/test_basic_user.py::TestBasicCRD::test_black_box": 2.1419907070001045, - "tests/aws/services/cloudformation/resource_providers/iam/aws_iam_user/test_basic_user.py::TestBasicCRD::test_getatt": 2.135787167000103, - "tests/aws/services/cloudformation/resource_providers/iam/aws_iam_user/test_basic_user.py::TestUpdates::test_update_without_replacement": 0.0019106419999843638, - "tests/aws/services/cloudformation/resource_providers/iam/aws_iam_user/test_exploration.py::TestAttributeAccess::test_getatt[Arn]": 0.0018572630000335266, - "tests/aws/services/cloudformation/resource_providers/iam/aws_iam_user/test_exploration.py::TestAttributeAccess::test_getatt[Id]": 0.001849117999995542, - "tests/aws/services/cloudformation/resource_providers/iam/aws_iam_user/test_exploration.py::TestAttributeAccess::test_getatt[Path]": 0.0018510920000380793, - "tests/aws/services/cloudformation/resource_providers/iam/aws_iam_user/test_exploration.py::TestAttributeAccess::test_getatt[PermissionsBoundary]": 0.001781090999998014, - "tests/aws/services/cloudformation/resource_providers/iam/aws_iam_user/test_exploration.py::TestAttributeAccess::test_getatt[UserName]": 0.0018790139999964595, - "tests/aws/services/cloudformation/resource_providers/iam/aws_iam_user/test_parity.py::TestParity::test_create_with_full_properties": 2.2481812959998706, - "tests/aws/services/cloudformation/resource_providers/iam/test_iam.py::test_cfn_handle_iam_role_resource_no_role_name": 2.1360537670000213, - "tests/aws/services/cloudformation/resource_providers/iam/test_iam.py::test_delete_role_detaches_role_policy": 4.21022870999991, - "tests/aws/services/cloudformation/resource_providers/iam/test_iam.py::test_iam_user_access_key": 4.210896816000172, - "tests/aws/services/cloudformation/resource_providers/iam/test_iam.py::test_iam_username_defaultname": 2.1697872929998994, - "tests/aws/services/cloudformation/resource_providers/iam/test_iam.py::test_managed_policy_with_empty_resource": 2.45452981599999, - "tests/aws/services/cloudformation/resource_providers/iam/test_iam.py::test_policy_attachments": 2.280067052999925, - "tests/aws/services/cloudformation/resource_providers/iam/test_iam.py::test_server_certificate": 2.235336026999903, - "tests/aws/services/cloudformation/resource_providers/iam/test_iam.py::test_update_inline_policy": 4.276489126999991, - "tests/aws/services/cloudformation/resource_providers/iam/test_iam.py::test_updating_stack_with_iam_role": 12.254183667999996, - "tests/aws/services/cloudformation/resource_providers/opensearch/test_domain.py::TestAttributeAccess::test_getattr[Arn]": 0.0018663810000134617, - "tests/aws/services/cloudformation/resource_providers/opensearch/test_domain.py::TestAttributeAccess::test_getattr[DomainArn]": 0.0018707689999928334, - "tests/aws/services/cloudformation/resource_providers/opensearch/test_domain.py::TestAttributeAccess::test_getattr[DomainEndpoint]": 0.0017590899999504472, - "tests/aws/services/cloudformation/resource_providers/opensearch/test_domain.py::TestAttributeAccess::test_getattr[DomainName]": 0.002028074000008928, - "tests/aws/services/cloudformation/resource_providers/opensearch/test_domain.py::TestAttributeAccess::test_getattr[EngineVersion]": 0.0018688750000137588, - "tests/aws/services/cloudformation/resource_providers/opensearch/test_domain.py::TestAttributeAccess::test_getattr[Id]": 0.0018576040000652938, - "tests/aws/services/cloudformation/resource_providers/scheduler/test_scheduler.py::test_schedule_and_group": 2.4955905909999956, - "tests/aws/services/cloudformation/resource_providers/ssm/test_parameter.py::TestBasicCRD::test_black_box": 0.0019830479999427553, - "tests/aws/services/cloudformation/resource_providers/ssm/test_parameter.py::TestUpdates::test_update_without_replacement": 0.0017549120000239782, - "tests/aws/services/cloudformation/resource_providers/ssm/test_parameter_getatt_exploration.py::TestAttributeAccess::test_getattr[AllowedPattern]": 0.0017155890000140062, - "tests/aws/services/cloudformation/resource_providers/ssm/test_parameter_getatt_exploration.py::TestAttributeAccess::test_getattr[DataType]": 0.002063869000039631, - "tests/aws/services/cloudformation/resource_providers/ssm/test_parameter_getatt_exploration.py::TestAttributeAccess::test_getattr[Description]": 0.0016947710000749794, - "tests/aws/services/cloudformation/resource_providers/ssm/test_parameter_getatt_exploration.py::TestAttributeAccess::test_getattr[Id]": 0.0016698150000138412, - "tests/aws/services/cloudformation/resource_providers/ssm/test_parameter_getatt_exploration.py::TestAttributeAccess::test_getattr[Name]": 0.001846272999955545, - "tests/aws/services/cloudformation/resource_providers/ssm/test_parameter_getatt_exploration.py::TestAttributeAccess::test_getattr[Policies]": 0.0017858709999245548, - "tests/aws/services/cloudformation/resource_providers/ssm/test_parameter_getatt_exploration.py::TestAttributeAccess::test_getattr[Tier]": 0.0017473290000680208, - "tests/aws/services/cloudformation/resource_providers/ssm/test_parameter_getatt_exploration.py::TestAttributeAccess::test_getattr[Type]": 0.001742970999885074, - "tests/aws/services/cloudformation/resource_providers/ssm/test_parameter_getatt_exploration.py::TestAttributeAccess::test_getattr[Value]": 0.0018230600001061248, - "tests/aws/services/cloudformation/resources/test_acm.py::test_cfn_acm_certificate": 2.1040202629999385, - "tests/aws/services/cloudformation/resources/test_apigateway.py::TestServerlessApigwLambda::test_serverless_like_deployment_with_update": 11.456122028999971, - "tests/aws/services/cloudformation/resources/test_apigateway.py::test_account": 2.153713201999949, - "tests/aws/services/cloudformation/resources/test_apigateway.py::test_api_gateway_with_policy_as_dict": 2.112438879999786, - "tests/aws/services/cloudformation/resources/test_apigateway.py::test_apigateway_deployment_canary_settings": 2.2550029129999984, - "tests/aws/services/cloudformation/resources/test_apigateway.py::test_cfn_apigateway_aws_integration": 2.34467025999993, - "tests/aws/services/cloudformation/resources/test_apigateway.py::test_cfn_apigateway_rest_api": 2.2914523079999753, - "tests/aws/services/cloudformation/resources/test_apigateway.py::test_cfn_apigateway_swagger_import": 2.3250083689999883, - "tests/aws/services/cloudformation/resources/test_apigateway.py::test_cfn_deploy_apigateway_from_s3_swagger": 2.450892336000038, - "tests/aws/services/cloudformation/resources/test_apigateway.py::test_cfn_deploy_apigateway_integration": 2.224595433999866, - "tests/aws/services/cloudformation/resources/test_apigateway.py::test_cfn_deploy_apigateway_models": 2.298949776000086, - "tests/aws/services/cloudformation/resources/test_apigateway.py::test_cfn_with_apigateway_resources": 2.3177373849999867, - "tests/aws/services/cloudformation/resources/test_apigateway.py::test_rest_api_serverless_ref_resolving": 9.91959432200008, - "tests/aws/services/cloudformation/resources/test_apigateway.py::test_update_apigateway_stage": 4.521591209000007, - "tests/aws/services/cloudformation/resources/test_apigateway.py::test_update_usage_plan": 4.471114585000123, - "tests/aws/services/cloudformation/resources/test_apigateway.py::test_url_output": 2.1902847230001043, - "tests/aws/services/cloudformation/resources/test_cdk.py::TestCdkInit::test_cdk_bootstrap[10]": 8.619151675000012, - "tests/aws/services/cloudformation/resources/test_cdk.py::TestCdkInit::test_cdk_bootstrap[11]": 8.624980868999955, - "tests/aws/services/cloudformation/resources/test_cdk.py::TestCdkInit::test_cdk_bootstrap[12]": 8.633268866000094, - "tests/aws/services/cloudformation/resources/test_cdk.py::TestCdkInit::test_cdk_bootstrap[28]": 9.537424839999971, - "tests/aws/services/cloudformation/resources/test_cdk.py::TestCdkInit::test_cdk_bootstrap_redeploy[v20]": 0.0022837950000393903, - "tests/aws/services/cloudformation/resources/test_cdk.py::TestCdkInit::test_cdk_bootstrap_redeploy[v28]": 0.0018582449998802986, - "tests/aws/services/cloudformation/resources/test_cdk.py::TestCdkSampleApp::test_cdk_sample": 2.4136869110000134, - "tests/aws/services/cloudformation/resources/test_cloudformation.py::test_create_macro": 3.195927155999925, - "tests/aws/services/cloudformation/resources/test_cloudformation.py::test_waitcondition": 2.1949850559998367, - "tests/aws/services/cloudformation/resources/test_cloudwatch.py::test_alarm_creation": 2.0934355749998304, - "tests/aws/services/cloudformation/resources/test_cloudwatch.py::test_alarm_ext_statistic": 2.1488341570002376, - "tests/aws/services/cloudformation/resources/test_cloudwatch.py::test_composite_alarm_creation": 2.403309019000062, - "tests/aws/services/cloudformation/resources/test_dynamodb.py::test_billing_mode_as_conditional[PAY_PER_REQUEST]": 2.47679626199988, - "tests/aws/services/cloudformation/resources/test_dynamodb.py::test_billing_mode_as_conditional[PROVISIONED]": 2.453243833999977, - "tests/aws/services/cloudformation/resources/test_dynamodb.py::test_default_name_for_table": 2.4546785339996404, - "tests/aws/services/cloudformation/resources/test_dynamodb.py::test_deploy_stack_with_dynamodb_table": 2.238734013999874, - "tests/aws/services/cloudformation/resources/test_dynamodb.py::test_global_table": 2.4713035080003465, - "tests/aws/services/cloudformation/resources/test_dynamodb.py::test_global_table_with_ttl_and_sse": 2.147203770000033, - "tests/aws/services/cloudformation/resources/test_dynamodb.py::test_globalindex_read_write_provisioned_throughput_dynamodb_table": 2.180918844999951, - "tests/aws/services/cloudformation/resources/test_dynamodb.py::test_table_with_ttl_and_sse": 2.133766440999807, - "tests/aws/services/cloudformation/resources/test_dynamodb.py::test_ttl_cdk": 1.254938354999922, - "tests/aws/services/cloudformation/resources/test_ec2.py::test_cfn_update_ec2_instance_type": 0.0018589859998883185, - "tests/aws/services/cloudformation/resources/test_ec2.py::test_cfn_with_multiple_route_table_associations": 2.5207858480000596, - "tests/aws/services/cloudformation/resources/test_ec2.py::test_cfn_with_multiple_route_tables": 2.201491333999911, - "tests/aws/services/cloudformation/resources/test_ec2.py::test_dhcp_options": 2.3163980740000625, - "tests/aws/services/cloudformation/resources/test_ec2.py::test_ec2_security_group_id_with_vpc": 2.149344286000087, - "tests/aws/services/cloudformation/resources/test_ec2.py::test_internet_gateway_ref_and_attr": 2.2946035310001207, - "tests/aws/services/cloudformation/resources/test_ec2.py::test_keypair_create_import": 2.2224704399998245, - "tests/aws/services/cloudformation/resources/test_ec2.py::test_simple_route_table_creation": 2.2261164089998147, - "tests/aws/services/cloudformation/resources/test_ec2.py::test_simple_route_table_creation_without_vpc": 2.231269534999683, - "tests/aws/services/cloudformation/resources/test_ec2.py::test_transit_gateway_attachment": 2.7519266720000815, - "tests/aws/services/cloudformation/resources/test_ec2.py::test_vpc_creates_default_sg": 2.4032517550001558, - "tests/aws/services/cloudformation/resources/test_ec2.py::test_vpc_gateway_attachment": 2.142192072000171, - "tests/aws/services/cloudformation/resources/test_ec2.py::test_vpc_with_route_table": 2.308793625999897, - "tests/aws/services/cloudformation/resources/test_elasticsearch.py::test_cfn_handle_elasticsearch_domain": 4.120628340000394, - "tests/aws/services/cloudformation/resources/test_events.py::test_cfn_event_api_destination_resource": 16.398843493999948, - "tests/aws/services/cloudformation/resources/test_events.py::test_cfn_event_bus_resource": 2.163815144999944, - "tests/aws/services/cloudformation/resources/test_events.py::test_event_rule_creation_without_target": 2.1127887259999625, - "tests/aws/services/cloudformation/resources/test_events.py::test_event_rule_to_logs": 2.2312000990002616, - "tests/aws/services/cloudformation/resources/test_events.py::test_eventbus_policies": 18.09359948899987, - "tests/aws/services/cloudformation/resources/test_events.py::test_eventbus_policy_statement": 2.111095416000353, - "tests/aws/services/cloudformation/resources/test_events.py::test_rule_pattern_transformation": 2.1299995379999928, - "tests/aws/services/cloudformation/resources/test_events.py::test_rule_properties": 2.136368421000043, - "tests/aws/services/cloudformation/resources/test_firehose.py::test_firehose_stack_with_kinesis_as_source": 31.57632070500017, - "tests/aws/services/cloudformation/resources/test_integration.py::test_events_sqs_sns_lambda": 13.585630660999868, - "tests/aws/services/cloudformation/resources/test_kinesis.py::test_cfn_handle_kinesis_firehose_resources": 11.389484808999896, - "tests/aws/services/cloudformation/resources/test_kinesis.py::test_default_parameters_kinesis": 11.304980787999739, - "tests/aws/services/cloudformation/resources/test_kinesis.py::test_describe_template": 0.13745309600017208, - "tests/aws/services/cloudformation/resources/test_kinesis.py::test_dynamodb_stream_response_with_cf": 11.35050941999998, - "tests/aws/services/cloudformation/resources/test_kinesis.py::test_kinesis_stream_consumer_creations": 17.275620743999525, - "tests/aws/services/cloudformation/resources/test_kinesis.py::test_stream_creation": 11.352783157000204, - "tests/aws/services/cloudformation/resources/test_kms.py::test_cfn_with_kms_resources": 2.136435848000019, - "tests/aws/services/cloudformation/resources/test_kms.py::test_deploy_stack_with_kms": 2.118403941999759, - "tests/aws/services/cloudformation/resources/test_kms.py::test_kms_key_disabled": 2.116259284999842, - "tests/aws/services/cloudformation/resources/test_lambda.py::TestCfnLambdaDestinations::test_generic_destination_routing[sqs-sqs]": 19.609054054000126, - "tests/aws/services/cloudformation/resources/test_lambda.py::TestCfnLambdaIntegrations::test_cfn_lambda_dynamodb_source": 10.623809937000033, - "tests/aws/services/cloudformation/resources/test_lambda.py::TestCfnLambdaIntegrations::test_cfn_lambda_kinesis_source": 21.34107489100029, - "tests/aws/services/cloudformation/resources/test_lambda.py::TestCfnLambdaIntegrations::test_cfn_lambda_permissions": 7.869721406000281, - "tests/aws/services/cloudformation/resources/test_lambda.py::TestCfnLambdaIntegrations::test_cfn_lambda_sqs_source": 8.126616325999748, - "tests/aws/services/cloudformation/resources/test_lambda.py::TestCfnLambdaIntegrations::test_lambda_dynamodb_event_filter": 9.437106496999832, - "tests/aws/services/cloudformation/resources/test_lambda.py::test_cfn_function_url": 7.5073507969998445, - "tests/aws/services/cloudformation/resources/test_lambda.py::test_event_invoke_config": 6.263453008999932, - "tests/aws/services/cloudformation/resources/test_lambda.py::test_lambda_alias": 12.48930604599991, - "tests/aws/services/cloudformation/resources/test_lambda.py::test_lambda_cfn_dead_letter_config_async_invocation": 11.041775531999974, - "tests/aws/services/cloudformation/resources/test_lambda.py::test_lambda_cfn_run": 6.577679215999979, - "tests/aws/services/cloudformation/resources/test_lambda.py::test_lambda_cfn_run_with_empty_string_replacement_deny_list": 8.269521201000089, - "tests/aws/services/cloudformation/resources/test_lambda.py::test_lambda_cfn_run_with_non_empty_string_replacement_deny_list": 8.271505955000066, - "tests/aws/services/cloudformation/resources/test_lambda.py::test_lambda_code_signing_config": 2.19243990200016, - "tests/aws/services/cloudformation/resources/test_lambda.py::test_lambda_function_tags": 6.533933949999891, - "tests/aws/services/cloudformation/resources/test_lambda.py::test_lambda_layer_crud": 6.258498285000087, - "tests/aws/services/cloudformation/resources/test_lambda.py::test_lambda_logging_config": 6.206309785000258, - "tests/aws/services/cloudformation/resources/test_lambda.py::test_lambda_version": 7.85057591299983, - "tests/aws/services/cloudformation/resources/test_lambda.py::test_lambda_version_provisioned_concurrency": 12.590261787000145, - "tests/aws/services/cloudformation/resources/test_lambda.py::test_lambda_vpc": 0.00199910599985742, - "tests/aws/services/cloudformation/resources/test_lambda.py::test_lambda_w_dynamodb_event_filter": 11.462079829999993, - "tests/aws/services/cloudformation/resources/test_lambda.py::test_lambda_w_dynamodb_event_filter_update": 12.694598585999756, - "tests/aws/services/cloudformation/resources/test_lambda.py::test_multiple_lambda_permissions_for_singlefn": 6.198462717999746, - "tests/aws/services/cloudformation/resources/test_lambda.py::test_python_lambda_code_deployed_via_s3": 6.638660150000305, - "tests/aws/services/cloudformation/resources/test_lambda.py::test_update_lambda_function": 8.285099514999956, - "tests/aws/services/cloudformation/resources/test_lambda.py::test_update_lambda_function_name": 12.301476525999988, - "tests/aws/services/cloudformation/resources/test_lambda.py::test_update_lambda_permissions": 8.281485180000118, - "tests/aws/services/cloudformation/resources/test_logs.py::test_cfn_handle_log_group_resource": 2.381928750999805, - "tests/aws/services/cloudformation/resources/test_logs.py::test_logstream": 2.121040460999893, - "tests/aws/services/cloudformation/resources/test_opensearch.py::test_domain": 0.0018494980001833028, - "tests/aws/services/cloudformation/resources/test_opensearch.py::test_domain_with_alternative_types": 17.286957237999786, - "tests/aws/services/cloudformation/resources/test_redshift.py::test_redshift_cluster": 2.1237814190001245, - "tests/aws/services/cloudformation/resources/test_resource_groups.py::test_group_defaults": 2.248774507999997, - "tests/aws/services/cloudformation/resources/test_route53.py::test_create_health_check": 2.2445089400000597, - "tests/aws/services/cloudformation/resources/test_route53.py::test_create_record_set_via_id": 2.191833394000014, - "tests/aws/services/cloudformation/resources/test_route53.py::test_create_record_set_via_name": 2.2039887739999813, - "tests/aws/services/cloudformation/resources/test_route53.py::test_create_record_set_without_resource_record": 2.1682614169997123, - "tests/aws/services/cloudformation/resources/test_s3.py::test_bucket_autoname": 2.1058889400001135, - "tests/aws/services/cloudformation/resources/test_s3.py::test_bucket_versioning": 2.1104673779998393, - "tests/aws/services/cloudformation/resources/test_s3.py::test_bucketpolicy": 19.69074199700026, - "tests/aws/services/cloudformation/resources/test_s3.py::test_cfn_handle_s3_notification_configuration": 2.167335867000247, - "tests/aws/services/cloudformation/resources/test_s3.py::test_cors_configuration": 2.5096333410001535, - "tests/aws/services/cloudformation/resources/test_s3.py::test_object_lock_configuration": 2.5005309719999786, - "tests/aws/services/cloudformation/resources/test_s3.py::test_website_configuration": 2.474074587000132, - "tests/aws/services/cloudformation/resources/test_sam.py::test_cfn_handle_serverless_api_resource": 6.609246298000016, - "tests/aws/services/cloudformation/resources/test_sam.py::test_sam_policies": 6.320508195000002, - "tests/aws/services/cloudformation/resources/test_sam.py::test_sam_sqs_event": 13.507857382999873, - "tests/aws/services/cloudformation/resources/test_sam.py::test_sam_template": 6.619006457999831, - "tests/aws/services/cloudformation/resources/test_secretsmanager.py::test_cdk_deployment_generates_secret_value_if_no_value_is_provided": 1.2609551410000677, - "tests/aws/services/cloudformation/resources/test_secretsmanager.py::test_cfn_handle_secretsmanager_secret": 2.2754093250002825, - "tests/aws/services/cloudformation/resources/test_secretsmanager.py::test_cfn_secret_policy[default]": 2.1154665609999483, - "tests/aws/services/cloudformation/resources/test_secretsmanager.py::test_cfn_secret_policy[true]": 2.121079998000141, - "tests/aws/services/cloudformation/resources/test_secretsmanager.py::test_cfn_secretsmanager_gen_secret": 2.2672296149999056, - "tests/aws/services/cloudformation/resources/test_sns.py::test_deploy_stack_with_sns_topic": 2.1396387850002156, - "tests/aws/services/cloudformation/resources/test_sns.py::test_sns_subscription": 2.1214921069999946, - "tests/aws/services/cloudformation/resources/test_sns.py::test_sns_subscription_region": 2.15327206500001, - "tests/aws/services/cloudformation/resources/test_sns.py::test_sns_topic_fifo_with_deduplication": 2.3359575399999812, - "tests/aws/services/cloudformation/resources/test_sns.py::test_sns_topic_fifo_without_suffix_fails": 0.0018975879997924494, - "tests/aws/services/cloudformation/resources/test_sns.py::test_sns_topic_policy_resets_to_default": 1.3531555710003431, - "tests/aws/services/cloudformation/resources/test_sns.py::test_sns_topic_update_attributes": 5.592643722000048, - "tests/aws/services/cloudformation/resources/test_sns.py::test_sns_topic_update_name": 4.4755441639999844, - "tests/aws/services/cloudformation/resources/test_sns.py::test_sns_topic_with_attributes": 1.2226003279999986, - "tests/aws/services/cloudformation/resources/test_sns.py::test_update_subscription": 4.24345005400005, - "tests/aws/services/cloudformation/resources/test_sqs.py::test_cfn_handle_sqs_resource": 2.140179775999968, - "tests/aws/services/cloudformation/resources/test_sqs.py::test_sqs_fifo_queue_generates_valid_name": 2.1098932309998872, - "tests/aws/services/cloudformation/resources/test_sqs.py::test_sqs_non_fifo_queue_generates_valid_name": 2.1007713100000274, - "tests/aws/services/cloudformation/resources/test_sqs.py::test_sqs_queue_policy": 2.1179973060000066, - "tests/aws/services/cloudformation/resources/test_sqs.py::test_update_queue_no_change": 4.203165025000089, - "tests/aws/services/cloudformation/resources/test_sqs.py::test_update_sqs_queuepolicy": 4.210548076000123, - "tests/aws/services/cloudformation/resources/test_ssm.py::test_deploy_patch_baseline": 2.2772580950002066, - "tests/aws/services/cloudformation/resources/test_ssm.py::test_maintenance_window": 2.1780762680000407, - "tests/aws/services/cloudformation/resources/test_ssm.py::test_parameter_defaults": 2.299136754000074, - "tests/aws/services/cloudformation/resources/test_ssm.py::test_update_ssm_parameter_tag": 4.195717675000196, - "tests/aws/services/cloudformation/resources/test_ssm.py::test_update_ssm_parameters": 4.194131180999875, - "tests/aws/services/cloudformation/resources/test_stack_sets.py::test_create_stack_set_with_stack_instances": 1.129772057999844, - "tests/aws/services/cloudformation/resources/test_stack_sets.py::test_delete_nonexistent_stack_set": 0.0017760020000423538, - "tests/aws/services/cloudformation/resources/test_stack_sets.py::test_fetch_non_existent_stack_set_instances": 0.0018006269999659708, - "tests/aws/services/cloudformation/resources/test_stepfunctions.py::test_apigateway_invoke": 9.548837025000012, - "tests/aws/services/cloudformation/resources/test_stepfunctions.py::test_apigateway_invoke_localhost": 9.576773857000035, - "tests/aws/services/cloudformation/resources/test_stepfunctions.py::test_apigateway_invoke_localhost_with_path": 15.658925686999964, - "tests/aws/services/cloudformation/resources/test_stepfunctions.py::test_apigateway_invoke_with_path": 15.63246081400007, - "tests/aws/services/cloudformation/resources/test_stepfunctions.py::test_cfn_statemachine_default_s3_location": 4.8222565149999355, - "tests/aws/services/cloudformation/resources/test_stepfunctions.py::test_cfn_statemachine_with_dependencies": 2.1733314429998245, - "tests/aws/services/cloudformation/resources/test_stepfunctions.py::test_nested_statemachine_with_sync2": 15.472821554999882, - "tests/aws/services/cloudformation/resources/test_stepfunctions.py::test_retry_and_catch": 0.0024880500002382178, - "tests/aws/services/cloudformation/resources/test_stepfunctions.py::test_statemachine_create_with_logging_configuration": 2.674407751999979, - "tests/aws/services/cloudformation/resources/test_stepfunctions.py::test_statemachine_definitionsubstitution": 7.340351221000219, - "tests/aws/services/cloudformation/test_change_set_conditions.py::TestChangeSetConditions::test_condition_add_new_negative_condition_to_existent_resource": 0.001822367999693597, - "tests/aws/services/cloudformation/test_change_set_conditions.py::TestChangeSetConditions::test_condition_add_new_positive_condition_to_existent_resource": 0.0017898979999699804, - "tests/aws/services/cloudformation/test_change_set_conditions.py::TestChangeSetConditions::test_condition_update_adds_resource": 0.0018112679999831016, - "tests/aws/services/cloudformation/test_change_set_conditions.py::TestChangeSetConditions::test_condition_update_removes_resource": 0.0018129210000097373, - "tests/aws/services/cloudformation/test_change_set_depends_on.py::TestChangeSetDependsOn::test_multiple_dependencies_addition": 0.0017375190000166185, - "tests/aws/services/cloudformation/test_change_set_depends_on.py::TestChangeSetDependsOn::test_multiple_dependencies_deletion": 0.0016096909998850606, - "tests/aws/services/cloudformation/test_change_set_depends_on.py::TestChangeSetDependsOn::test_update_depended_resource": 0.0017790169999898353, - "tests/aws/services/cloudformation/test_change_set_depends_on.py::TestChangeSetDependsOn::test_update_depended_resource_list": 0.001650426999958654, - "tests/aws/services/cloudformation/test_change_set_exports_imports.py::TestChangeSetImportExport::test_describe_change_set_import": 0.0018162860001211811, - "tests/aws/services/cloudformation/test_change_set_exports_imports.py::TestChangeSetImportExport::test_describe_change_set_import_non_existent_export": 0.0016531129999748373, - "tests/aws/services/cloudformation/test_change_set_exports_imports.py::TestChangeSetImportExport::test_describe_change_set_import_non_existent_export_then_create": 0.00178933600000164, - "tests/aws/services/cloudformation/test_change_set_fn_base64.py::TestChangeSetFnBase64::test_fn_base64_add_to_static_property": 0.001709917999960453, - "tests/aws/services/cloudformation/test_change_set_fn_base64.py::TestChangeSetFnBase64::test_fn_base64_change_input_string": 0.0017662540001310845, - "tests/aws/services/cloudformation/test_change_set_fn_base64.py::TestChangeSetFnBase64::test_fn_base64_remove_from_static_property": 0.0016784109998297936, - "tests/aws/services/cloudformation/test_change_set_fn_get_attr.py::TestChangeSetFnGetAttr::test_direct_attribute_value_change": 0.0016354299998511124, - "tests/aws/services/cloudformation/test_change_set_fn_get_attr.py::TestChangeSetFnGetAttr::test_direct_attribute_value_change_in_get_attr_chain": 0.0016587730001447198, - "tests/aws/services/cloudformation/test_change_set_fn_get_attr.py::TestChangeSetFnGetAttr::test_direct_attribute_value_change_with_dependent_addition": 0.0016689819999555766, - "tests/aws/services/cloudformation/test_change_set_fn_get_attr.py::TestChangeSetFnGetAttr::test_immutable_property_update_causes_resource_replacement": 0.001692405999847324, - "tests/aws/services/cloudformation/test_change_set_fn_get_attr.py::TestChangeSetFnGetAttr::test_resource_addition": 0.0017559959999289276, - "tests/aws/services/cloudformation/test_change_set_fn_get_attr.py::TestChangeSetFnGetAttr::test_resource_deletion": 0.001834852000229148, - "tests/aws/services/cloudformation/test_change_set_fn_join.py::TestChangeSetFnJoin::test_indirect_update_refence_argument": 0.0017867730000489246, - "tests/aws/services/cloudformation/test_change_set_fn_join.py::TestChangeSetFnJoin::test_update_refence_argument": 0.0016681299996434973, - "tests/aws/services/cloudformation/test_change_set_fn_join.py::TestChangeSetFnJoin::test_update_string_literal_argument": 0.0016671180001139874, - "tests/aws/services/cloudformation/test_change_set_fn_join.py::TestChangeSetFnJoin::test_update_string_literal_arguments_empty": 0.001816146999999546, - "tests/aws/services/cloudformation/test_change_set_fn_join.py::TestChangeSetFnJoin::test_update_string_literal_delimiter": 0.001743509999869275, - "tests/aws/services/cloudformation/test_change_set_fn_join.py::TestChangeSetFnJoin::test_update_string_literal_delimiter_empty": 0.0017501130000709963, - "tests/aws/services/cloudformation/test_change_set_fn_select.py::TestChangeSetFnSelect::test_fn_select_add_to_static_property": 0.0016399490000367223, - "tests/aws/services/cloudformation/test_change_set_fn_select.py::TestChangeSetFnSelect::test_fn_select_change_get_att_reference": 0.0016319020000992168, - "tests/aws/services/cloudformation/test_change_set_fn_select.py::TestChangeSetFnSelect::test_fn_select_change_in_selected_element_type_ref": 0.0016598859999703564, - "tests/aws/services/cloudformation/test_change_set_fn_select.py::TestChangeSetFnSelect::test_fn_select_change_in_selection_index_only": 0.0016356609999093052, - "tests/aws/services/cloudformation/test_change_set_fn_select.py::TestChangeSetFnSelect::test_fn_select_change_in_selection_list": 0.0016376640000999032, - "tests/aws/services/cloudformation/test_change_set_fn_select.py::TestChangeSetFnSelect::test_fn_select_remove_from_static_property": 0.0016563780000069528, - "tests/aws/services/cloudformation/test_change_set_fn_split.py::TestChangeSetFnSplit::test_fn_split_add_to_static_property": 0.0016725689999930182, - "tests/aws/services/cloudformation/test_change_set_fn_split.py::TestChangeSetFnSplit::test_fn_split_change_delimiter": 0.001737811000111833, - "tests/aws/services/cloudformation/test_change_set_fn_split.py::TestChangeSetFnSplit::test_fn_split_change_source_string_only": 0.0016444160003175057, - "tests/aws/services/cloudformation/test_change_set_fn_split.py::TestChangeSetFnSplit::test_fn_split_remove_from_static_property": 0.0016440259998944384, - "tests/aws/services/cloudformation/test_change_set_fn_split.py::TestChangeSetFnSplit::test_fn_split_with_get_att": 0.0017855089997738105, - "tests/aws/services/cloudformation/test_change_set_fn_split.py::TestChangeSetFnSplit::test_fn_split_with_ref_as_string_source": 0.0016722389998449216, - "tests/aws/services/cloudformation/test_change_set_fn_sub.py::TestChangeSetFnSub::test_fn_sub_addition_parameter": 0.001750183000240213, - "tests/aws/services/cloudformation/test_change_set_fn_sub.py::TestChangeSetFnSub::test_fn_sub_addition_parameter_literal": 0.0017519969999284513, - "tests/aws/services/cloudformation/test_change_set_fn_sub.py::TestChangeSetFnSub::test_fn_sub_addition_parameter_ref": 0.001731649000021207, - "tests/aws/services/cloudformation/test_change_set_fn_sub.py::TestChangeSetFnSub::test_fn_sub_addition_string_pseudo": 0.0015976790000422625, - "tests/aws/services/cloudformation/test_change_set_fn_sub.py::TestChangeSetFnSub::test_fn_sub_delete_parameter_literal": 0.0017490520001501864, - "tests/aws/services/cloudformation/test_change_set_fn_sub.py::TestChangeSetFnSub::test_fn_sub_delete_string_pseudo": 0.0017404249999799504, - "tests/aws/services/cloudformation/test_change_set_fn_sub.py::TestChangeSetFnSub::test_fn_sub_update_parameter_literal": 0.0017595099998288788, - "tests/aws/services/cloudformation/test_change_set_fn_sub.py::TestChangeSetFnSub::test_fn_sub_update_parameter_type": 0.0017304780003541964, - "tests/aws/services/cloudformation/test_change_set_fn_sub.py::TestChangeSetFnSub::test_fn_sub_update_string_pseudo": 0.0015830429999823536, - "tests/aws/services/cloudformation/test_change_set_fn_transform.py::TestChangeSetFnTransform::test_conditional_transform[false]": 0.001798853999844141, - "tests/aws/services/cloudformation/test_change_set_fn_transform.py::TestChangeSetFnTransform::test_conditional_transform[true]": 0.0017723349999414495, - "tests/aws/services/cloudformation/test_change_set_fn_transform.py::TestChangeSetFnTransform::test_embedded_fn_transform_include[json]": 0.0016545459998269507, - "tests/aws/services/cloudformation/test_change_set_fn_transform.py::TestChangeSetFnTransform::test_embedded_fn_transform_include[yml]": 0.001867772999958106, - "tests/aws/services/cloudformation/test_change_set_fn_transform.py::TestChangeSetFnTransform::test_embedded_macro_fn_transform": 0.0018372469999121677, - "tests/aws/services/cloudformation/test_change_set_fn_transform.py::TestChangeSetFnTransform::test_embedded_macro_for_attribute_fn_transform": 0.0017410370001016418, - "tests/aws/services/cloudformation/test_change_set_fn_transform.py::TestChangeSetFnTransform::test_global_fn_transform_include[json]": 0.001757938999844555, - "tests/aws/services/cloudformation/test_change_set_fn_transform.py::TestChangeSetFnTransform::test_global_fn_transform_include[yml]": 0.0018378059999122343, - "tests/aws/services/cloudformation/test_change_set_fn_transform.py::TestChangeSetFnTransform::test_global_macro_fn_transform": 0.0016640930000448861, - "tests/aws/services/cloudformation/test_change_set_fn_transform.py::TestChangeSetFnTransform::test_macro_with_intrinsic_function": 0.0016207219998705114, - "tests/aws/services/cloudformation/test_change_set_fn_transform.py::TestChangeSetFnTransform::test_multiple_fn_transform_order": 0.001776071999756823, - "tests/aws/services/cloudformation/test_change_set_fn_transform.py::TestChangeSetFnTransform::test_remove_transform_in_update_change_set": 0.00162859700003537, - "tests/aws/services/cloudformation/test_change_set_fn_transform.py::TestChangeSetFnTransform::test_serverless_fn_transform": 0.00176313800011485, - "tests/aws/services/cloudformation/test_change_set_fn_transform.py::TestChangeSetFnTransform::test_update_parameter_transform_in_update_change_set": 0.0018860879999920144, - "tests/aws/services/cloudformation/test_change_set_global_macros.py::TestChangeSetGlobalMacros::test_base_global_macro": 0.0017442529999698309, - "tests/aws/services/cloudformation/test_change_set_global_macros.py::TestChangeSetGlobalMacros::test_update_after_macro_for_before_version_is_deleted": 0.001771203000089372, - "tests/aws/services/cloudformation/test_change_set_mappings.py::TestChangeSetMappings::test_mapping_addition_with_resource": 0.0017699009999887494, - "tests/aws/services/cloudformation/test_change_set_mappings.py::TestChangeSetMappings::test_mapping_deletion_with_resource_remap": 0.0017707710001104715, - "tests/aws/services/cloudformation/test_change_set_mappings.py::TestChangeSetMappings::test_mapping_key_addition_with_resource": 0.0018065579999984038, - "tests/aws/services/cloudformation/test_change_set_mappings.py::TestChangeSetMappings::test_mapping_key_deletion_with_resource_remap": 0.0017845869999746355, - "tests/aws/services/cloudformation/test_change_set_mappings.py::TestChangeSetMappings::test_mapping_key_update": 0.0017662130001099285, - "tests/aws/services/cloudformation/test_change_set_mappings.py::TestChangeSetMappings::test_mapping_leaf_update": 0.0017881740000120772, - "tests/aws/services/cloudformation/test_change_set_parameters.py::TestChangeSetParameters::test_update_parameter_default_value": 0.0018066000000089844, - "tests/aws/services/cloudformation/test_change_set_parameters.py::TestChangeSetParameters::test_update_parameter_default_value_with_dynamic_overrides": 0.001706904000002396, - "tests/aws/services/cloudformation/test_change_set_parameters.py::TestChangeSetParameters::test_update_parameter_with_added_default_value": 0.0016482440000800125, - "tests/aws/services/cloudformation/test_change_set_parameters.py::TestChangeSetParameters::test_update_parameter_with_removed_default_value": 0.001635610999983328, - "tests/aws/services/cloudformation/test_change_set_ref.py::TestChangeSetRef::test_direct_attribute_value_change": 0.0016664680001667875, - "tests/aws/services/cloudformation/test_change_set_ref.py::TestChangeSetRef::test_direct_attribute_value_change_in_ref_chain": 0.0016374330000417103, - "tests/aws/services/cloudformation/test_change_set_ref.py::TestChangeSetRef::test_direct_attribute_value_change_with_dependent_addition": 0.0016536040002392838, - "tests/aws/services/cloudformation/test_change_set_ref.py::TestChangeSetRef::test_immutable_property_update_causes_resource_replacement": 0.0016828989998884936, - "tests/aws/services/cloudformation/test_change_set_ref.py::TestChangeSetRef::test_resource_addition": 0.0017828939999162685, - "tests/aws/services/cloudformation/test_change_set_ref.py::TestChangeSetRef::test_supported_pseudo_parameter": 0.0016740010000830807, - "tests/aws/services/cloudformation/test_change_set_values.py::TestChangeSetValues::test_property_empy_list": 0.0016602850000708713, - "tests/aws/services/cloudformation/test_change_sets.py::TestCaptureUpdateProcess::test_base_dynamic_parameter_scenarios[change_dynamic]": 0.0017865010001969495, - "tests/aws/services/cloudformation/test_change_sets.py::TestCaptureUpdateProcess::test_base_dynamic_parameter_scenarios[change_parameter_for_condition_create_resource]": 0.0016630109998914122, - "tests/aws/services/cloudformation/test_change_sets.py::TestCaptureUpdateProcess::test_base_dynamic_parameter_scenarios[change_unrelated_property]": 0.0033303309999155317, - "tests/aws/services/cloudformation/test_change_sets.py::TestCaptureUpdateProcess::test_base_dynamic_parameter_scenarios[change_unrelated_property_not_create_only]": 0.0022787099999277416, - "tests/aws/services/cloudformation/test_change_sets.py::TestCaptureUpdateProcess::test_base_mapping_scenarios[update_string_referencing_resource]": 0.001729123999894, - "tests/aws/services/cloudformation/test_change_sets.py::TestCaptureUpdateProcess::test_conditions": 0.0016790210002000094, - "tests/aws/services/cloudformation/test_change_sets.py::TestCaptureUpdateProcess::test_direct_update": 0.0016940880000220204, - "tests/aws/services/cloudformation/test_change_sets.py::TestCaptureUpdateProcess::test_dynamic_update": 0.0034579279999888968, - "tests/aws/services/cloudformation/test_change_sets.py::TestCaptureUpdateProcess::test_execute_with_ref": 0.0017641699998875993, - "tests/aws/services/cloudformation/test_change_sets.py::TestCaptureUpdateProcess::test_mappings_with_parameter_lookup": 0.00225976299998365, - "tests/aws/services/cloudformation/test_change_sets.py::TestCaptureUpdateProcess::test_mappings_with_static_fields": 0.0016156919998593366, - "tests/aws/services/cloudformation/test_change_sets.py::TestCaptureUpdateProcess::test_parameter_changes": 0.001633006000020032, - "tests/aws/services/cloudformation/test_change_sets.py::TestCaptureUpdateProcess::test_single_resource_static_update": 0.001664584000081959, - "tests/aws/services/cloudformation/test_change_sets.py::TestCaptureUpdateProcess::test_unrelated_changes_requires_replacement": 0.0017834759999004746, - "tests/aws/services/cloudformation/test_change_sets.py::TestCaptureUpdateProcess::test_unrelated_changes_update_propagation": 0.0017856889999166015, - "tests/aws/services/cloudformation/test_change_sets.py::test_dynamic_ssm_parameter_lookup": 0.0016673400000399852, - "tests/aws/services/cloudformation/test_change_sets.py::test_dynamic_ssm_parameter_lookup_no_change": 0.0016635920001135673, - "tests/aws/services/cloudformation/test_cloudformation_ui.py::TestCloudFormationUi::test_get_cloudformation_ui": 0.06836410599998999, - "tests/aws/services/cloudformation/test_cloudtrail_trace.py::test_cloudtrail_trace_example": 0.0016901220001273032, - "tests/aws/services/cloudformation/test_list_stacks.py::test_listing_stacks": 0.0016677510000135953, - "tests/aws/services/cloudformation/test_template_engine.py::TestImportValues::test_cfn_with_exports": 2.113261981000278, - "tests/aws/services/cloudformation/test_template_engine.py::TestImportValues::test_import_values_across_stacks": 4.207732727000121, - "tests/aws/services/cloudformation/test_template_engine.py::TestImports::test_stack_imports": 4.252758235999863, - "tests/aws/services/cloudformation/test_template_engine.py::TestIntrinsicFunctions::test_and_or_functions[Fn::And-0-0-False]": 0.08223201500004507, - "tests/aws/services/cloudformation/test_template_engine.py::TestIntrinsicFunctions::test_and_or_functions[Fn::And-0-1-False]": 0.08187495299989678, - "tests/aws/services/cloudformation/test_template_engine.py::TestIntrinsicFunctions::test_and_or_functions[Fn::And-1-0-False]": 0.08406428799980858, - "tests/aws/services/cloudformation/test_template_engine.py::TestIntrinsicFunctions::test_and_or_functions[Fn::And-1-1-True]": 2.1164270920000945, - "tests/aws/services/cloudformation/test_template_engine.py::TestIntrinsicFunctions::test_and_or_functions[Fn::Or-0-0-False]": 0.08172030900004756, - "tests/aws/services/cloudformation/test_template_engine.py::TestIntrinsicFunctions::test_and_or_functions[Fn::Or-0-1-True]": 2.117028476999849, - "tests/aws/services/cloudformation/test_template_engine.py::TestIntrinsicFunctions::test_and_or_functions[Fn::Or-1-0-True]": 2.116593284999908, - "tests/aws/services/cloudformation/test_template_engine.py::TestIntrinsicFunctions::test_and_or_functions[Fn::Or-1-1-True]": 2.118483641000239, - "tests/aws/services/cloudformation/test_template_engine.py::TestIntrinsicFunctions::test_base64_sub_and_getatt_functions": 2.099411565000082, - "tests/aws/services/cloudformation/test_template_engine.py::TestIntrinsicFunctions::test_cfn_template_with_short_form_fn_sub": 2.116229532000034, - "tests/aws/services/cloudformation/test_template_engine.py::TestIntrinsicFunctions::test_cidr_function": 0.0017985050001243508, - "tests/aws/services/cloudformation/test_template_engine.py::TestIntrinsicFunctions::test_find_map_function": 2.1020343480001884, - "tests/aws/services/cloudformation/test_template_engine.py::TestIntrinsicFunctions::test_fn_select_has_intrinsic_function": 2.103982804999987, - "tests/aws/services/cloudformation/test_template_engine.py::TestIntrinsicFunctions::test_get_azs_function[ap-northeast-1]": 2.128924009000002, - "tests/aws/services/cloudformation/test_template_engine.py::TestIntrinsicFunctions::test_get_azs_function[ap-southeast-2]": 2.1198981009997624, - "tests/aws/services/cloudformation/test_template_engine.py::TestIntrinsicFunctions::test_get_azs_function[eu-central-1]": 2.108724976000076, - "tests/aws/services/cloudformation/test_template_engine.py::TestIntrinsicFunctions::test_get_azs_function[eu-west-1]": 2.1090527239998664, - "tests/aws/services/cloudformation/test_template_engine.py::TestIntrinsicFunctions::test_get_azs_function[us-east-1]": 2.1021581320001133, - "tests/aws/services/cloudformation/test_template_engine.py::TestIntrinsicFunctions::test_get_azs_function[us-east-2]": 2.1153248849998363, - "tests/aws/services/cloudformation/test_template_engine.py::TestIntrinsicFunctions::test_get_azs_function[us-west-1]": 2.1123693890001505, - "tests/aws/services/cloudformation/test_template_engine.py::TestIntrinsicFunctions::test_get_azs_function[us-west-2]": 2.109521115000007, - "tests/aws/services/cloudformation/test_template_engine.py::TestIntrinsicFunctions::test_join_no_value_construct": 2.1039111120001053, - "tests/aws/services/cloudformation/test_template_engine.py::TestIntrinsicFunctions::test_split_length_and_join_functions": 2.169721877000029, - "tests/aws/services/cloudformation/test_template_engine.py::TestIntrinsicFunctions::test_sub_not_ready": 2.115556091999906, - "tests/aws/services/cloudformation/test_template_engine.py::TestIntrinsicFunctions::test_sub_number_type": 2.1224265929997728, - "tests/aws/services/cloudformation/test_template_engine.py::TestIntrinsicFunctions::test_to_json_functions": 0.0018662810000478203, - "tests/aws/services/cloudformation/test_template_engine.py::TestMacros::test_attribute_uses_macro": 5.704152959999874, - "tests/aws/services/cloudformation/test_template_engine.py::TestMacros::test_capabilities_requirements": 5.277847000999827, - "tests/aws/services/cloudformation/test_template_engine.py::TestMacros::test_error_pass_macro_as_reference": 0.025228104999996503, - "tests/aws/services/cloudformation/test_template_engine.py::TestMacros::test_failed_state[raise_error.py]": 3.667072912000094, - "tests/aws/services/cloudformation/test_template_engine.py::TestMacros::test_failed_state[return_invalid_template.py]": 3.6405673749998186, - "tests/aws/services/cloudformation/test_template_engine.py::TestMacros::test_failed_state[return_unsuccessful_with_message.py]": 3.644520244999967, - "tests/aws/services/cloudformation/test_template_engine.py::TestMacros::test_failed_state[return_unsuccessful_without_message.py]": 3.627837337000301, - "tests/aws/services/cloudformation/test_template_engine.py::TestMacros::test_functions_and_references_during_transformation": 4.696238694999693, - "tests/aws/services/cloudformation/test_template_engine.py::TestMacros::test_global_scope": 5.056988393999973, - "tests/aws/services/cloudformation/test_template_engine.py::TestMacros::test_macro_deployment": 3.224468907999835, - "tests/aws/services/cloudformation/test_template_engine.py::TestMacros::test_pyplate_param_type_list": 8.725061247999975, - "tests/aws/services/cloudformation/test_template_engine.py::TestMacros::test_scope_order_and_parameters": 0.002878237999993871, - "tests/aws/services/cloudformation/test_template_engine.py::TestMacros::test_snipped_scope[transformation_snippet_topic.json]": 5.720063072000357, - "tests/aws/services/cloudformation/test_template_engine.py::TestMacros::test_snipped_scope[transformation_snippet_topic.yml]": 5.725092254000174, - "tests/aws/services/cloudformation/test_template_engine.py::TestMacros::test_to_validate_template_limit_for_macro": 3.7043981480001094, - "tests/aws/services/cloudformation/test_template_engine.py::TestMacros::test_validate_lambda_internals": 5.159423854000124, - "tests/aws/services/cloudformation/test_template_engine.py::TestPreviousValues::test_parameter_usepreviousvalue_behavior": 0.0018244030002279032, - "tests/aws/services/cloudformation/test_template_engine.py::TestPseudoParameters::test_stack_id": 2.102794342000152, - "tests/aws/services/cloudformation/test_template_engine.py::TestSecretsManagerParameters::test_resolve_secretsmanager[resolve_secretsmanager.yaml]": 2.1122559179996188, - "tests/aws/services/cloudformation/test_template_engine.py::TestSecretsManagerParameters::test_resolve_secretsmanager[resolve_secretsmanager_full.yaml]": 2.111850857000263, - "tests/aws/services/cloudformation/test_template_engine.py::TestSecretsManagerParameters::test_resolve_secretsmanager[resolve_secretsmanager_partial.yaml]": 2.114289095999993, - "tests/aws/services/cloudformation/test_template_engine.py::TestSsmParameters::test_create_change_set_with_ssm_parameter_list": 2.161117554999919, - "tests/aws/services/cloudformation/test_template_engine.py::TestSsmParameters::test_create_stack_with_ssm_parameters": 2.189509571999679, - "tests/aws/services/cloudformation/test_template_engine.py::TestSsmParameters::test_resolve_ssm": 2.1251206609997553, - "tests/aws/services/cloudformation/test_template_engine.py::TestSsmParameters::test_resolve_ssm_missing_parameter": 0.001763097999855745, - "tests/aws/services/cloudformation/test_template_engine.py::TestSsmParameters::test_resolve_ssm_secure": 2.1222365940000145, - "tests/aws/services/cloudformation/test_template_engine.py::TestSsmParameters::test_resolve_ssm_with_version": 2.149189340000021, - "tests/aws/services/cloudformation/test_template_engine.py::TestSsmParameters::test_ssm_nested_with_nested_stack": 6.23664764199998, - "tests/aws/services/cloudformation/test_template_engine.py::TestStackEvents::test_invalid_stack_deploy": 2.35994549499992, - "tests/aws/services/cloudformation/test_template_engine.py::TestTypes::test_implicit_type_conversion": 2.1536559710000347, - "tests/aws/services/cloudformation/test_unsupported.py::test_unsupported": 2.090701301999843, - "tests/aws/services/cloudformation/v2/test_dynamic_resolving.py::TestSSMParameterValues::test_change_parameter_type": 0.00171569099984481, - "tests/aws/services/cloudformation/v2/test_dynamic_resolving.py::TestSSMParameterValues::test_update_parameter_between_deployments": 0.0017341029999897728, - "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_alarm_lambda_target": 2.664252599000065, - "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_anomaly_detector_lifecycle": 0.0017436529999486083, - "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_aws_sqs_metrics_created": 2.3894865419997586, - "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_breaching_alarm_actions": 5.308697712999901, - "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_create_metric_stream": 0.0017488719997800217, - "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_dashboard_lifecycle": 0.13474256100016646, - "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_default_ordering": 0.11789695399988886, - "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_delete_alarm": 0.09009371299998747, - "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_describe_alarms_converts_date_format_correctly": 0.07161725399987517, - "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_describe_minimal_metric_alarm": 0.08111960399992313, - "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_enable_disable_alarm_actions": 10.258978127000091, - "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_get_metric_data": 2.073345738999933, - "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_get_metric_data_different_units_no_unit_in_query[metric_data0]": 0.0017307779996826866, - "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_get_metric_data_different_units_no_unit_in_query[metric_data1]": 0.0017166510001516144, - "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_get_metric_data_different_units_no_unit_in_query[metric_data2]": 0.0017760920000000624, - "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_get_metric_data_for_multiple_metrics": 1.0480518280003253, - "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_get_metric_data_pagination": 2.184240346999559, - "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_get_metric_data_stats[Average]": 0.03375484399975903, - "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_get_metric_data_stats[Maximum]": 0.03202621300010833, - "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_get_metric_data_stats[Minimum]": 0.032385803999886775, - "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_get_metric_data_stats[SampleCount]": 0.031982662000018536, - "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_get_metric_data_stats[Sum]": 0.034568162000141456, - "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_get_metric_data_with_different_units": 0.02676298999995197, - "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_get_metric_data_with_dimensions": 0.045874368000113463, - "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_get_metric_data_with_zero_and_labels": 0.04006236099985472, - "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_get_metric_statistics": 1.3393033829997876, - "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_get_metric_with_no_results": 0.04898750600000312, - "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_get_metric_with_null_dimensions": 0.0316510699999526, - "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_handle_different_units": 0.030689416000086567, - "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_insight_rule": 0.0017241949999515782, - "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_invalid_amount_of_datapoints": 0.5506184980001763, - "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_invalid_dashboard_name": 0.017020241000182068, - "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_label_generation[input_pairs0]": 0.031136372999981177, - "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_label_generation[input_pairs1]": 0.030661034999639014, - "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_label_generation[input_pairs2]": 0.030187051999973846, - "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_label_generation[input_pairs3]": 0.03163030299992897, - "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_label_generation[input_pairs4]": 0.03011418899995988, - "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_label_generation[input_pairs5]": 0.030574638999951276, - "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_label_generation[input_pairs6]": 0.029782300000078976, - "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_list_metrics_pagination": 5.321698635999837, - "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_list_metrics_uniqueness": 2.0587860519999595, - "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_list_metrics_with_filters": 4.091751484999804, - "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_metric_widget": 0.0017422290000013163, - "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_multiple_dimensions": 2.1105188480000834, - "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_multiple_dimensions_statistics": 0.051538889000084964, - "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_parallel_put_metric_data_list_metrics": 0.2606073590000051, - "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_put_composite_alarm_describe_alarms": 0.08500402300001042, - "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_put_metric_alarm": 10.608368557999938, - "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_put_metric_alarm_escape_character": 0.07244708700022784, - "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_put_metric_data_gzip": 0.027645863000088866, - "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_put_metric_data_validation": 0.05039969200015548, - "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_put_metric_data_values_list": 0.031178279999949154, - "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_put_metric_uses_utc": 0.029517067000369934, - "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_raw_metric_data": 0.022691722999979902, - "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_set_alarm": 2.3017572609999206, - "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_set_alarm_invalid_input": 0.08114245000001574, - "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_store_tags": 0.11373796599991692, - "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_trigger_composite_alarm": 4.619815449000043, - "tests/aws/services/cloudwatch/test_cloudwatch_metrics.py::TestCloudWatchLambdaMetrics::test_lambda_invoke_error": 2.5423004469998887, - "tests/aws/services/cloudwatch/test_cloudwatch_metrics.py::TestCloudWatchLambdaMetrics::test_lambda_invoke_successful": 2.494149310000239, - "tests/aws/services/cloudwatch/test_cloudwatch_metrics.py::TestSQSMetrics::test_alarm_number_of_messages_sent": 61.22336387600012, - "tests/aws/services/cloudwatch/test_cloudwatch_metrics.py::TestSqsApproximateMetrics::test_sqs_approximate_metrics": 46.81945070399979, - "tests/aws/services/dynamodb/test_dynamodb.py::TestDynamoDB::test_batch_write_binary": 0.10532534000049054, - "tests/aws/services/dynamodb/test_dynamodb.py::TestDynamoDB::test_batch_write_items": 0.09721737300014865, - "tests/aws/services/dynamodb/test_dynamodb.py::TestDynamoDB::test_batch_write_items_streaming": 1.1487118669997471, - "tests/aws/services/dynamodb/test_dynamodb.py::TestDynamoDB::test_batch_write_not_existing_table": 0.20398678999998765, - "tests/aws/services/dynamodb/test_dynamodb.py::TestDynamoDB::test_batch_write_not_matching_schema": 0.17316224999999008, - "tests/aws/services/dynamodb/test_dynamodb.py::TestDynamoDB::test_binary_data_with_stream": 0.7434904800006734, - "tests/aws/services/dynamodb/test_dynamodb.py::TestDynamoDB::test_continuous_backup_update": 0.3054484009999783, - "tests/aws/services/dynamodb/test_dynamodb.py::TestDynamoDB::test_create_duplicate_table": 0.09765635500025382, - "tests/aws/services/dynamodb/test_dynamodb.py::TestDynamoDB::test_data_encoding_consistency": 3.429004185999986, - "tests/aws/services/dynamodb/test_dynamodb.py::TestDynamoDB::test_delete_table": 0.11296037400052228, - "tests/aws/services/dynamodb/test_dynamodb.py::TestDynamoDB::test_dynamodb_batch_execute_statement": 0.14039276699986658, - "tests/aws/services/dynamodb/test_dynamodb.py::TestDynamoDB::test_dynamodb_create_table_with_class": 0.1587409150001804, - "tests/aws/services/dynamodb/test_dynamodb.py::TestDynamoDB::test_dynamodb_create_table_with_partial_sse_specification": 0.11297631500019634, - "tests/aws/services/dynamodb/test_dynamodb.py::TestDynamoDB::test_dynamodb_create_table_with_sse_specification": 0.06657633700024235, - "tests/aws/services/dynamodb/test_dynamodb.py::TestDynamoDB::test_dynamodb_execute_statement_empy_parameter": 0.10414262400036023, - "tests/aws/services/dynamodb/test_dynamodb.py::TestDynamoDB::test_dynamodb_execute_transaction": 0.2712550890005332, - "tests/aws/services/dynamodb/test_dynamodb.py::TestDynamoDB::test_dynamodb_get_batch_items": 0.07894495200071106, - "tests/aws/services/dynamodb/test_dynamodb.py::TestDynamoDB::test_dynamodb_idempotent_writing": 6.6942361429999835, - "tests/aws/services/dynamodb/test_dynamodb.py::TestDynamoDB::test_dynamodb_partiql_missing": 0.1313779400002204, - "tests/aws/services/dynamodb/test_dynamodb.py::TestDynamoDB::test_dynamodb_pay_per_request": 0.038812498000424966, - "tests/aws/services/dynamodb/test_dynamodb.py::TestDynamoDB::test_dynamodb_stream_records_with_update_item": 0.001858133000041562, - "tests/aws/services/dynamodb/test_dynamodb.py::TestDynamoDB::test_dynamodb_stream_shard_iterator": 0.8204532219997418, - "tests/aws/services/dynamodb/test_dynamodb.py::TestDynamoDB::test_dynamodb_stream_stream_view_type": 1.29120860500052, - "tests/aws/services/dynamodb/test_dynamodb.py::TestDynamoDB::test_dynamodb_streams_describe_with_exclusive_start_shard_id": 0.7604718490001687, - "tests/aws/services/dynamodb/test_dynamodb.py::TestDynamoDB::test_dynamodb_streams_shard_iterator_format": 3.2715799500001594, - "tests/aws/services/dynamodb/test_dynamodb.py::TestDynamoDB::test_dynamodb_update_table_without_sse_specification_change": 0.10222767699951874, - "tests/aws/services/dynamodb/test_dynamodb.py::TestDynamoDB::test_dynamodb_with_kinesis_stream": 1.3814438699992024, - "tests/aws/services/dynamodb/test_dynamodb.py::TestDynamoDB::test_empty_and_binary_values": 0.0862211059998117, - "tests/aws/services/dynamodb/test_dynamodb.py::TestDynamoDB::test_global_tables": 0.09600912700034314, - "tests/aws/services/dynamodb/test_dynamodb.py::TestDynamoDB::test_global_tables_version_2019": 0.4569072760000381, - "tests/aws/services/dynamodb/test_dynamodb.py::TestDynamoDB::test_gsi_with_billing_mode[PAY_PER_REQUEST]": 0.7768409940000538, - "tests/aws/services/dynamodb/test_dynamodb.py::TestDynamoDB::test_gsi_with_billing_mode[PROVISIONED]": 0.5610281149999992, - "tests/aws/services/dynamodb/test_dynamodb.py::TestDynamoDB::test_invalid_query_index": 0.06447553599991807, - "tests/aws/services/dynamodb/test_dynamodb.py::TestDynamoDB::test_kinesis_streaming_destination_crud": 0.4477163599999585, - "tests/aws/services/dynamodb/test_dynamodb.py::TestDynamoDB::test_large_data_download": 0.34343749400022716, - "tests/aws/services/dynamodb/test_dynamodb.py::TestDynamoDB::test_list_tags_of_resource": 0.07902702299998055, - "tests/aws/services/dynamodb/test_dynamodb.py::TestDynamoDB::test_more_than_20_global_secondary_indexes": 0.2669182749996253, - "tests/aws/services/dynamodb/test_dynamodb.py::TestDynamoDB::test_multiple_update_expressions": 0.1368395400004374, - "tests/aws/services/dynamodb/test_dynamodb.py::TestDynamoDB::test_non_ascii_chars": 0.13370978700049818, - "tests/aws/services/dynamodb/test_dynamodb.py::TestDynamoDB::test_nosql_workbench_localhost_region": 0.0999395320000076, - "tests/aws/services/dynamodb/test_dynamodb.py::TestDynamoDB::test_query_on_deleted_resource": 0.12480377600013526, - "tests/aws/services/dynamodb/test_dynamodb.py::TestDynamoDB::test_return_values_in_put_item": 0.12486595799964562, - "tests/aws/services/dynamodb/test_dynamodb.py::TestDynamoDB::test_return_values_on_conditions_check_failure": 0.4687871910000183, - "tests/aws/services/dynamodb/test_dynamodb.py::TestDynamoDB::test_stream_destination_records": 12.412725176999999, - "tests/aws/services/dynamodb/test_dynamodb.py::TestDynamoDB::test_streams_on_global_tables": 1.1817989070000294, - "tests/aws/services/dynamodb/test_dynamodb.py::TestDynamoDB::test_time_to_live": 0.23207391000005373, - "tests/aws/services/dynamodb/test_dynamodb.py::TestDynamoDB::test_time_to_live_deletion": 0.40664513499996247, - "tests/aws/services/dynamodb/test_dynamodb.py::TestDynamoDB::test_transact_get_items": 0.10511154100004205, - "tests/aws/services/dynamodb/test_dynamodb.py::TestDynamoDB::test_transact_write_items_streaming": 2.3793528340000023, - "tests/aws/services/dynamodb/test_dynamodb.py::TestDynamoDB::test_transact_write_items_streaming_for_different_tables": 2.11002747400002, - "tests/aws/services/dynamodb/test_dynamodb.py::TestDynamoDB::test_transaction_write_binary_data": 0.09241240099981951, - "tests/aws/services/dynamodb/test_dynamodb.py::TestDynamoDB::test_transaction_write_canceled": 0.10009460499986744, - "tests/aws/services/dynamodb/test_dynamodb.py::TestDynamoDB::test_transaction_write_items": 0.11125708899999154, - "tests/aws/services/dynamodb/test_dynamodb.py::TestDynamoDB::test_valid_local_secondary_index": 0.1353748730002735, - "tests/aws/services/dynamodb/test_dynamodb.py::TestDynamoDB::test_valid_query_index": 0.07504215400058456, - "tests/aws/services/dynamodbstreams/test_dynamodb_streams.py::TestDynamoDBStreams::test_enable_kinesis_streaming_destination": 0.00296503700002404, - "tests/aws/services/dynamodbstreams/test_dynamodb_streams.py::TestDynamoDBStreams::test_non_existent_stream": 0.036550365000039164, - "tests/aws/services/dynamodbstreams/test_dynamodb_streams.py::TestDynamoDBStreams::test_stream_spec_and_region_replacement": 2.4279423950000023, - "tests/aws/services/dynamodbstreams/test_dynamodb_streams.py::TestDynamoDBStreams::test_table_v2_stream": 5.108910831999992, - "tests/aws/services/ec2/test_ec2.py::TestEc2FlowLogs::test_ec2_flow_logs_s3": 0.9285317810000038, - "tests/aws/services/ec2/test_ec2.py::TestEc2FlowLogs::test_ec2_flow_logs_s3_validation": 0.31585144100006346, - "tests/aws/services/ec2/test_ec2.py::TestEc2Integrations::test_create_route_table_association": 1.1225951850000229, - "tests/aws/services/ec2/test_ec2.py::TestEc2Integrations::test_create_security_group_with_custom_id[False-id_manager]": 0.0842122319999703, - "tests/aws/services/ec2/test_ec2.py::TestEc2Integrations::test_create_security_group_with_custom_id[False-tag]": 0.08725922200000014, - "tests/aws/services/ec2/test_ec2.py::TestEc2Integrations::test_create_security_group_with_custom_id[True-id_manager]": 0.07614575000002333, - "tests/aws/services/ec2/test_ec2.py::TestEc2Integrations::test_create_security_group_with_custom_id[True-tag]": 0.1033924779999893, - "tests/aws/services/ec2/test_ec2.py::TestEc2Integrations::test_create_subnet_with_custom_id": 0.10105127899998934, - "tests/aws/services/ec2/test_ec2.py::TestEc2Integrations::test_create_subnet_with_custom_id_and_vpc_id": 0.09971426000004158, - "tests/aws/services/ec2/test_ec2.py::TestEc2Integrations::test_create_subnet_with_tags": 0.09170143799997277, - "tests/aws/services/ec2/test_ec2.py::TestEc2Integrations::test_create_vpc_endpoint": 0.16613450099998772, - "tests/aws/services/ec2/test_ec2.py::TestEc2Integrations::test_create_vpc_with_custom_id": 0.08163153200001716, - "tests/aws/services/ec2/test_ec2.py::TestEc2Integrations::test_describe_vpc_endpoints_with_filter": 0.8269666680000114, - "tests/aws/services/ec2/test_ec2.py::TestEc2Integrations::test_describe_vpn_gateways_filter_by_vpc": 0.5050934620000476, - "tests/aws/services/ec2/test_ec2.py::TestEc2Integrations::test_get_security_groups_for_vpc": 0.481200685000033, - "tests/aws/services/ec2/test_ec2.py::TestEc2Integrations::test_modify_launch_template[id]": 0.11791328500004283, - "tests/aws/services/ec2/test_ec2.py::TestEc2Integrations::test_modify_launch_template[name]": 0.07181487400004016, - "tests/aws/services/ec2/test_ec2.py::TestEc2Integrations::test_reserved_instance_api": 0.03797306199999184, - "tests/aws/services/ec2/test_ec2.py::TestEc2Integrations::test_vcp_peering_difference_regions": 1.5004515449999758, - "tests/aws/services/ec2/test_ec2.py::TestEc2Integrations::test_vpc_endpoint_dns_names": 0.4490368540000418, - "tests/aws/services/ec2/test_ec2.py::test_create_specific_vpc_id": 0.04525607799996578, - "tests/aws/services/ec2/test_ec2.py::test_describe_availability_zones_filter_with_zone_ids": 0.454399627999976, - "tests/aws/services/ec2/test_ec2.py::test_describe_availability_zones_filter_with_zone_names": 0.3643228029999932, - "tests/aws/services/ec2/test_ec2.py::test_describe_availability_zones_filters": 0.48436624599997913, - "tests/aws/services/ec2/test_ec2.py::test_pickle_ec2_backend": 3.5770779460000313, - "tests/aws/services/ec2/test_ec2.py::test_raise_create_volume_without_size": 0.03366665699996929, - "tests/aws/services/ec2/test_ec2.py::test_raise_duplicate_launch_template_name": 0.03486189899990677, - "tests/aws/services/ec2/test_ec2.py::test_raise_invalid_launch_template_name": 0.012183980999907362, - "tests/aws/services/ec2/test_ec2.py::test_raise_modify_to_invalid_default_version": 0.03799415000008821, - "tests/aws/services/ec2/test_ec2.py::test_raise_when_launch_template_data_missing": 0.012681310999994366, - "tests/aws/services/es/test_es.py::TestElasticsearchProvider::test_create_domain": 0.0017290499999944586, - "tests/aws/services/es/test_es.py::TestElasticsearchProvider::test_create_existing_domain_causes_exception": 0.0023625809999430203, - "tests/aws/services/es/test_es.py::TestElasticsearchProvider::test_describe_domains": 0.0027754239999921992, - "tests/aws/services/es/test_es.py::TestElasticsearchProvider::test_domain_version": 0.002800920999959544, - "tests/aws/services/es/test_es.py::TestElasticsearchProvider::test_get_compatible_version_for_domain": 0.002515266999978394, - "tests/aws/services/es/test_es.py::TestElasticsearchProvider::test_get_compatible_versions": 0.002418997000006584, - "tests/aws/services/es/test_es.py::TestElasticsearchProvider::test_list_versions": 0.001831570999968335, - "tests/aws/services/es/test_es.py::TestElasticsearchProvider::test_path_endpoint_strategy": 0.0025020410000138327, - "tests/aws/services/es/test_es.py::TestElasticsearchProvider::test_update_domain_config": 0.0022780539999871507, - "tests/aws/services/events/test_api_destinations_and_connection.py::TestEventBridgeApiDestinations::test_api_destinations[auth0]": 0.22544585199995026, - "tests/aws/services/events/test_api_destinations_and_connection.py::TestEventBridgeApiDestinations::test_api_destinations[auth1]": 0.1640961639999432, - "tests/aws/services/events/test_api_destinations_and_connection.py::TestEventBridgeApiDestinations::test_api_destinations[auth2]": 0.1763999100000433, - "tests/aws/services/events/test_api_destinations_and_connection.py::TestEventBridgeApiDestinations::test_create_api_destination_invalid_parameters": 0.03141908900005319, - "tests/aws/services/events/test_api_destinations_and_connection.py::TestEventBridgeApiDestinations::test_create_api_destination_name_validation": 0.08002206800000522, - "tests/aws/services/events/test_api_destinations_and_connection.py::TestEventBridgeConnections::test_connection_secrets[api-key]": 0.07169257300000709, - "tests/aws/services/events/test_api_destinations_and_connection.py::TestEventBridgeConnections::test_connection_secrets[basic]": 0.07674272399998472, - "tests/aws/services/events/test_api_destinations_and_connection.py::TestEventBridgeConnections::test_connection_secrets[oauth]": 0.0868850159999397, - "tests/aws/services/events/test_api_destinations_and_connection.py::TestEventBridgeConnections::test_create_connection": 0.08707221200000959, - "tests/aws/services/events/test_api_destinations_and_connection.py::TestEventBridgeConnections::test_create_connection_invalid_parameters": 0.019305661000032615, - "tests/aws/services/events/test_api_destinations_and_connection.py::TestEventBridgeConnections::test_create_connection_name_validation": 0.021575135999967188, - "tests/aws/services/events/test_api_destinations_and_connection.py::TestEventBridgeConnections::test_create_connection_with_auth[auth_params0]": 0.10816632500001333, - "tests/aws/services/events/test_api_destinations_and_connection.py::TestEventBridgeConnections::test_create_connection_with_auth[auth_params1]": 0.09187064200011719, - "tests/aws/services/events/test_api_destinations_and_connection.py::TestEventBridgeConnections::test_create_connection_with_auth[auth_params2]": 0.06692732599992723, - "tests/aws/services/events/test_api_destinations_and_connection.py::TestEventBridgeConnections::test_delete_connection": 0.1398493750000398, - "tests/aws/services/events/test_api_destinations_and_connection.py::TestEventBridgeConnections::test_list_connections": 0.06641648299995495, - "tests/aws/services/events/test_api_destinations_and_connection.py::TestEventBridgeConnections::test_update_connection": 0.11920198100006019, - "tests/aws/services/events/test_archive_and_replay.py::TestArchive::test_create_archive_error_duplicate[custom]": 0.27983969600001046, - "tests/aws/services/events/test_archive_and_replay.py::TestArchive::test_create_archive_error_duplicate[default]": 0.06118509200001654, - "tests/aws/services/events/test_archive_and_replay.py::TestArchive::test_create_archive_error_unknown_event_bus": 0.015323013000056562, - "tests/aws/services/events/test_archive_and_replay.py::TestArchive::test_create_list_describe_update_delete_archive[custom]": 0.12724652099996092, - "tests/aws/services/events/test_archive_and_replay.py::TestArchive::test_create_list_describe_update_delete_archive[default]": 0.11368044099998542, - "tests/aws/services/events/test_archive_and_replay.py::TestArchive::test_delete_archive_error_unknown_archive": 0.013928601000031904, - "tests/aws/services/events/test_archive_and_replay.py::TestArchive::test_describe_archive_error_unknown_archive": 0.01454933700000538, - "tests/aws/services/events/test_archive_and_replay.py::TestArchive::test_list_archive_error_unknown_source_arn": 0.014182995000055598, - "tests/aws/services/events/test_archive_and_replay.py::TestArchive::test_list_archive_state_enabled[custom]": 0.08915911000002552, - "tests/aws/services/events/test_archive_and_replay.py::TestArchive::test_list_archive_state_enabled[default]": 0.05987369599995418, - "tests/aws/services/events/test_archive_and_replay.py::TestArchive::test_list_archive_with_events[False-custom]": 0.6201001140000244, - "tests/aws/services/events/test_archive_and_replay.py::TestArchive::test_list_archive_with_events[False-default]": 0.5288107970000056, - "tests/aws/services/events/test_archive_and_replay.py::TestArchive::test_list_archive_with_events[True-custom]": 0.6424519220000207, - "tests/aws/services/events/test_archive_and_replay.py::TestArchive::test_list_archive_with_events[True-default]": 0.6915066249999882, - "tests/aws/services/events/test_archive_and_replay.py::TestArchive::test_list_archive_with_name_prefix[custom]": 0.10465452400006825, - "tests/aws/services/events/test_archive_and_replay.py::TestArchive::test_list_archive_with_name_prefix[default]": 0.07662941199993156, - "tests/aws/services/events/test_archive_and_replay.py::TestArchive::test_list_archive_with_source_arn[custom]": 0.09000428799998872, - "tests/aws/services/events/test_archive_and_replay.py::TestArchive::test_list_archive_with_source_arn[default]": 0.06057838999998921, - "tests/aws/services/events/test_archive_and_replay.py::TestArchive::test_update_archive_error_unknown_archive": 0.001785143999995853, - "tests/aws/services/events/test_archive_and_replay.py::TestReplay::test_describe_replay_error_unknown_replay": 0.01460820700003751, - "tests/aws/services/events/test_archive_and_replay.py::TestReplay::test_list_replay_with_limit": 0.21887782700002845, - "tests/aws/services/events/test_archive_and_replay.py::TestReplay::test_list_replays_with_event_source_arn": 0.0992391749999797, - "tests/aws/services/events/test_archive_and_replay.py::TestReplay::test_list_replays_with_prefix": 0.1533863640000277, - "tests/aws/services/events/test_archive_and_replay.py::TestReplay::test_start_list_describe_canceled_replay[custom]": 0.0016786339999725897, - "tests/aws/services/events/test_archive_and_replay.py::TestReplay::test_start_list_describe_canceled_replay[default]": 0.001697068999988005, - "tests/aws/services/events/test_archive_and_replay.py::TestReplay::test_start_replay_error_duplicate_different_archive": 0.1203478509999627, - "tests/aws/services/events/test_archive_and_replay.py::TestReplay::test_start_replay_error_duplicate_name_same_archive": 0.06995067299999391, - "tests/aws/services/events/test_archive_and_replay.py::TestReplay::test_start_replay_error_invalid_end_time[0]": 0.0639523879999615, - "tests/aws/services/events/test_archive_and_replay.py::TestReplay::test_start_replay_error_invalid_end_time[10]": 0.06830694100000301, - "tests/aws/services/events/test_archive_and_replay.py::TestReplay::test_start_replay_error_unknown_archive": 0.014219009000044025, - "tests/aws/services/events/test_archive_and_replay.py::TestReplay::test_start_replay_error_unknown_event_bus": 0.09613163199992414, - "tests/aws/services/events/test_archive_and_replay.py::TestReplay::tests_concurrency_error_too_many_active_replays": 0.0018024849999846992, - "tests/aws/services/events/test_events.py::TestEventBus::test_create_list_describe_delete_custom_event_buses[False-regions0]": 0.04229384600000685, - "tests/aws/services/events/test_events.py::TestEventBus::test_create_list_describe_delete_custom_event_buses[False-regions1]": 0.11444910500006245, - "tests/aws/services/events/test_events.py::TestEventBus::test_create_list_describe_delete_custom_event_buses[True-regions0]": 0.0474705030000564, - "tests/aws/services/events/test_events.py::TestEventBus::test_create_list_describe_delete_custom_event_buses[True-regions1]": 0.13536005100002058, - "tests/aws/services/events/test_events.py::TestEventBus::test_create_multiple_event_buses_same_name": 0.04247449399997549, - "tests/aws/services/events/test_events.py::TestEventBus::test_delete_default_event_bus": 0.013098669999976664, - "tests/aws/services/events/test_events.py::TestEventBus::test_describe_delete_not_existing_event_bus": 0.021948995999991894, - "tests/aws/services/events/test_events.py::TestEventBus::test_list_event_buses_with_limit": 0.23349231700001383, - "tests/aws/services/events/test_events.py::TestEventBus::test_list_event_buses_with_prefix": 0.07710066200002075, - "tests/aws/services/events/test_events.py::TestEventBus::test_put_events_bus_to_bus[domain]": 0.2969921529999624, - "tests/aws/services/events/test_events.py::TestEventBus::test_put_events_bus_to_bus[path]": 0.2888524529999472, - "tests/aws/services/events/test_events.py::TestEventBus::test_put_events_bus_to_bus[standard]": 0.4282841280000298, - "tests/aws/services/events/test_events.py::TestEventBus::test_put_events_nonexistent_event_bus": 0.1612869449999721, - "tests/aws/services/events/test_events.py::TestEventBus::test_put_events_to_default_eventbus_for_custom_eventbus": 1.1278460569999993, - "tests/aws/services/events/test_events.py::TestEventBus::test_put_permission[custom]": 0.2952241379999805, - "tests/aws/services/events/test_events.py::TestEventBus::test_put_permission[default]": 0.09317721299993309, - "tests/aws/services/events/test_events.py::TestEventBus::test_put_permission_non_existing_event_bus": 0.014117620999968494, - "tests/aws/services/events/test_events.py::TestEventBus::test_remove_permission[custom]": 0.08369777899997644, - "tests/aws/services/events/test_events.py::TestEventBus::test_remove_permission[default]": 0.06305409299994835, - "tests/aws/services/events/test_events.py::TestEventBus::test_remove_permission_non_existing_sid[False-custom]": 0.041969042000005174, - "tests/aws/services/events/test_events.py::TestEventBus::test_remove_permission_non_existing_sid[False-default]": 0.021687365999980557, - "tests/aws/services/events/test_events.py::TestEventBus::test_remove_permission_non_existing_sid[True-custom]": 0.04958729499998071, - "tests/aws/services/events/test_events.py::TestEventBus::test_remove_permission_non_existing_sid[True-default]": 0.027575492999972084, - "tests/aws/services/events/test_events.py::TestEventPattern::test_put_events_pattern_nested": 10.238697456999944, - "tests/aws/services/events/test_events.py::TestEventPattern::test_put_events_pattern_with_values_in_array": 5.290066859000035, - "tests/aws/services/events/test_events.py::TestEventRule::test_delete_rule_with_targets": 0.07460850600000413, - "tests/aws/services/events/test_events.py::TestEventRule::test_describe_nonexistent_rule": 0.015511756999956106, - "tests/aws/services/events/test_events.py::TestEventRule::test_disable_re_enable_rule[custom]": 0.09204931600004329, - "tests/aws/services/events/test_events.py::TestEventRule::test_disable_re_enable_rule[default]": 0.06258120200004669, - "tests/aws/services/events/test_events.py::TestEventRule::test_list_rule_names_by_target[custom]": 0.22639593399992464, - "tests/aws/services/events/test_events.py::TestEventRule::test_list_rule_names_by_target[default]": 0.1654168679999657, - "tests/aws/services/events/test_events.py::TestEventRule::test_list_rule_names_by_target_no_matches[custom]": 0.1246281040000099, - "tests/aws/services/events/test_events.py::TestEventRule::test_list_rule_names_by_target_no_matches[default]": 0.09486482900001647, - "tests/aws/services/events/test_events.py::TestEventRule::test_list_rule_names_by_target_with_limit[custom]": 1.0568789740000284, - "tests/aws/services/events/test_events.py::TestEventRule::test_list_rule_names_by_target_with_limit[default]": 0.27260409499996285, - "tests/aws/services/events/test_events.py::TestEventRule::test_list_rule_with_limit": 0.23340641700002607, - "tests/aws/services/events/test_events.py::TestEventRule::test_process_pattern_to_single_matching_rules_single_target": 7.406426767000028, - "tests/aws/services/events/test_events.py::TestEventRule::test_process_to_multiple_matching_rules_different_targets": 0.5244049059999725, - "tests/aws/services/events/test_events.py::TestEventRule::test_process_to_multiple_matching_rules_single_target": 18.656392557999993, - "tests/aws/services/events/test_events.py::TestEventRule::test_process_to_single_matching_rules_single_target": 10.56372984699999, - "tests/aws/services/events/test_events.py::TestEventRule::test_put_list_with_prefix_describe_delete_rule[custom]": 0.08393164000005982, - "tests/aws/services/events/test_events.py::TestEventRule::test_put_list_with_prefix_describe_delete_rule[default]": 0.05714358700004141, - "tests/aws/services/events/test_events.py::TestEventRule::test_put_multiple_rules_with_same_name": 0.08051177000004373, - "tests/aws/services/events/test_events.py::TestEventRule::test_update_rule_with_targets": 0.0963120760000038, - "tests/aws/services/events/test_events.py::TestEventTarget::test_add_exceed_fife_targets_per_rule": 0.09855078699996511, - "tests/aws/services/events/test_events.py::TestEventTarget::test_list_target_by_rule_limit": 0.14595909599995593, - "tests/aws/services/events/test_events.py::TestEventTarget::test_put_list_remove_target[custom]": 0.11020815700004505, - "tests/aws/services/events/test_events.py::TestEventTarget::test_put_list_remove_target[default]": 0.08190674000002218, - "tests/aws/services/events/test_events.py::TestEventTarget::test_put_multiple_targets_with_same_arn_across_different_rules": 0.11326305000000048, - "tests/aws/services/events/test_events.py::TestEventTarget::test_put_multiple_targets_with_same_arn_single_rule": 0.07993727999996736, - "tests/aws/services/events/test_events.py::TestEventTarget::test_put_multiple_targets_with_same_id_across_different_rules": 0.11538664399995469, - "tests/aws/services/events/test_events.py::TestEventTarget::test_put_multiple_targets_with_same_id_single_rule": 0.08502090300004284, - "tests/aws/services/events/test_events.py::TestEventTarget::test_put_target_id_validation": 0.0966581860000133, - "tests/aws/services/events/test_events.py::TestEvents::test_create_connection_validations": 0.01587946400002238, - "tests/aws/services/events/test_events.py::TestEvents::test_events_written_to_disk_are_timestamp_prefixed_for_chronological_ordering": 0.0017141810000111946, - "tests/aws/services/events/test_events.py::TestEvents::test_put_event_malformed_detail[ARRAY]": 0.014073110000026645, - "tests/aws/services/events/test_events.py::TestEvents::test_put_event_malformed_detail[MALFORMED_JSON]": 0.014033607999976994, - "tests/aws/services/events/test_events.py::TestEvents::test_put_event_malformed_detail[SERIALIZED_STRING]": 0.013801451999995606, - "tests/aws/services/events/test_events.py::TestEvents::test_put_event_malformed_detail[STRING]": 0.013702326000043286, - "tests/aws/services/events/test_events.py::TestEvents::test_put_event_with_too_big_detail": 0.018788636000010683, - "tests/aws/services/events/test_events.py::TestEvents::test_put_event_without_detail": 0.01409746499996345, - "tests/aws/services/events/test_events.py::TestEvents::test_put_event_without_detail_type": 0.014066975999924125, - "tests/aws/services/events/test_events.py::TestEvents::test_put_events_exceed_limit_ten_entries[custom]": 0.046565864000058355, - "tests/aws/services/events/test_events.py::TestEvents::test_put_events_exceed_limit_ten_entries[default]": 0.017337193000003026, - "tests/aws/services/events/test_events.py::TestEvents::test_put_events_response_entries_order": 0.3081288839999843, - "tests/aws/services/events/test_events.py::TestEvents::test_put_events_time": 0.30878564300002154, - "tests/aws/services/events/test_events.py::TestEvents::test_put_events_with_target_delivery_failure": 1.1633123759999648, - "tests/aws/services/events/test_events.py::TestEvents::test_put_events_with_time_field": 0.19398479299997007, - "tests/aws/services/events/test_events.py::TestEvents::test_put_events_without_source": 0.014491060000011657, - "tests/aws/services/events/test_events_cross_account_region.py::TestEventsCrossAccountRegion::test_put_events[custom-account]": 0.1587168650000308, - "tests/aws/services/events/test_events_cross_account_region.py::test_event_bus_to_event_bus_cross_account_region[custom-account]": 0.44384268099997826, - "tests/aws/services/events/test_events_cross_account_region.py::test_event_bus_to_event_bus_cross_account_region[custom-region]": 0.4418718729999682, - "tests/aws/services/events/test_events_cross_account_region.py::test_event_bus_to_event_bus_cross_account_region[custom-region_account]": 0.4417133770000419, - "tests/aws/services/events/test_events_cross_account_region.py::test_event_bus_to_event_bus_cross_account_region[default-account]": 0.47764287399996874, - "tests/aws/services/events/test_events_cross_account_region.py::test_event_bus_to_event_bus_cross_account_region[default-region]": 0.4823256110000216, - "tests/aws/services/events/test_events_cross_account_region.py::test_event_bus_to_event_bus_cross_account_region[default-region_account]": 0.47187553399993476, - "tests/aws/services/events/test_events_inputs.py::TestInputPath::test_put_events_with_input_path": 0.18881940699998268, - "tests/aws/services/events/test_events_inputs.py::TestInputPath::test_put_events_with_input_path_max_level_depth": 0.1893413619999933, - "tests/aws/services/events/test_events_inputs.py::TestInputPath::test_put_events_with_input_path_multiple_targets": 0.2954343339999923, - "tests/aws/services/events/test_events_inputs.py::TestInputPath::test_put_events_with_input_path_nested[event_detail0]": 0.19167966699995986, - "tests/aws/services/events/test_events_inputs.py::TestInputPath::test_put_events_with_input_path_nested[event_detail1]": 0.18948708300001726, - "tests/aws/services/events/test_events_inputs.py::TestInputTransformer::test_input_transformer_nested_keys_replacement[\" multiple list items\"]": 0.2310215090000156, - "tests/aws/services/events/test_events_inputs.py::TestInputTransformer::test_input_transformer_nested_keys_replacement[\" single list item multiple list items system account id payload user id\"]": 0.23154693800000814, - "tests/aws/services/events/test_events_inputs.py::TestInputTransformer::test_input_transformer_nested_keys_replacement[\" single list item\"]": 0.2310114999999655, - "tests/aws/services/events/test_events_inputs.py::TestInputTransformer::test_input_transformer_nested_keys_replacement[\"Payload of with path users-service/users/ and \"]": 0.2313445290000118, - "tests/aws/services/events/test_events_inputs.py::TestInputTransformer::test_input_transformer_nested_keys_replacement[{\"id\" : \"\"}]": 0.23059472399995684, - "tests/aws/services/events/test_events_inputs.py::TestInputTransformer::test_input_transformer_nested_keys_replacement[{\"id\" : }]": 0.2323904439999751, - "tests/aws/services/events/test_events_inputs.py::TestInputTransformer::test_input_transformer_nested_keys_replacement[{\"method\": \"PUT\", \"nested\": {\"level1\": {\"level2\": {\"level3\": \"users-service/users/\"} } }, \"bod\": \"\"}]": 0.23368044299996882, - "tests/aws/services/events/test_events_inputs.py::TestInputTransformer::test_input_transformer_nested_keys_replacement[{\"method\": \"PUT\", \"path\": \"users-service/users/\", \"bod\": }]": 0.22850762499996335, - "tests/aws/services/events/test_events_inputs.py::TestInputTransformer::test_input_transformer_nested_keys_replacement[{\"method\": \"PUT\", \"path\": \"users-service/users/\", \"bod\": [, \"hardcoded\"]}]": 0.2338139720000072, - "tests/aws/services/events/test_events_inputs.py::TestInputTransformer::test_input_transformer_nested_keys_replacement[{\"method\": \"PUT\", \"path\": \"users-service/users/\", \"id\": , \"body\": }]": 0.23711606599999868, - "tests/aws/services/events/test_events_inputs.py::TestInputTransformer::test_input_transformer_nested_keys_replacement[{\"multi_replacement\": \"users//second/\"}]": 0.23157514199994012, - "tests/aws/services/events/test_events_inputs.py::TestInputTransformer::test_input_transformer_nested_keys_replacement[{\"singlelistitem\": }]": 0.23393226299992875, - "tests/aws/services/events/test_events_inputs.py::TestInputTransformer::test_input_transformer_nested_keys_replacement_not_valid[{\"not_valid\": \"users-service/users/\", \"bod\": }]": 5.152485646000002, - "tests/aws/services/events/test_events_inputs.py::TestInputTransformer::test_input_transformer_nested_keys_replacement_not_valid[{\"payload\": \"\"}]": 5.153228604999981, - "tests/aws/services/events/test_events_inputs.py::TestInputTransformer::test_input_transformer_nested_keys_replacement_not_valid[{\"singlelistitem\": \"\"}]": 5.15386825500002, - "tests/aws/services/events/test_events_inputs.py::TestInputTransformer::test_input_transformer_predefined_variables[\"Message containing all pre defined variables \"]": 0.27212004900002285, - "tests/aws/services/events/test_events_inputs.py::TestInputTransformer::test_input_transformer_predefined_variables[{\"originalEvent\": , \"originalEventJson\": }]": 0.22147957799995766, - "tests/aws/services/events/test_events_inputs.py::TestInputTransformer::test_put_events_with_input_transformer_input_template_json": 0.4461141919999818, - "tests/aws/services/events/test_events_inputs.py::TestInputTransformer::test_put_events_with_input_transformer_input_template_string[\"Event of type, at time , info extracted from detail \"]": 0.41128382199997304, - "tests/aws/services/events/test_events_inputs.py::TestInputTransformer::test_put_events_with_input_transformer_input_template_string[\"{[/Check with special starting characters for event of type\"]": 0.42507793400005767, - "tests/aws/services/events/test_events_inputs.py::TestInputTransformer::test_put_events_with_input_transformer_missing_keys": 0.1288414820000412, - "tests/aws/services/events/test_events_inputs.py::test_put_event_input_path_and_input_transformer": 0.10179580799996302, - "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_array_event_payload": 0.015113321999990603, - "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[arrays]": 0.01472416099994689, - "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[arrays_NEG]": 0.014086314000053335, - "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[arrays_empty_EXC]": 0.0887092149999944, - "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[arrays_empty_null_NEG]": 0.014655783000023348, - "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[boolean]": 0.013856715000031272, - "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[boolean_NEG]": 0.017198102999998355, - "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[complex_many_rules]": 0.014683052000009411, - "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[complex_multi_match]": 0.014279822999924363, - "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[complex_multi_match_NEG]": 0.015493452000043817, - "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[complex_or]": 0.01925428100003046, - "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[complex_or_NEG]": 0.015824634000011883, - "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_but_ignorecase]": 0.014334324000003562, - "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_but_ignorecase_EXC]": 0.08700571100001753, - "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_but_ignorecase_NEG]": 0.014133340000057615, - "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_but_ignorecase_list]": 0.014936758999965605, - "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_but_ignorecase_list_EXC]": 0.08765818599999875, - "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_but_ignorecase_list_NEG]": 0.014730636999956914, - "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_but_number]": 0.014331980999997995, - "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_but_number_NEG]": 0.014004330000034315, - "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_but_number_list]": 0.014411902000063037, - "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_but_number_list_NEG]": 0.01812051900003553, - "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_but_number_zero]": 0.014268364999963978, - "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_but_string]": 0.015774366999949052, - "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_but_string_NEG]": 0.018697422999991886, - "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_but_string_list]": 0.014283128999977635, - "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_but_string_list_NEG]": 0.014164687000004506, - "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_but_string_null]": 0.01570062199999711, - "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_prefix]": 0.014706550999960655, - "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_prefix_NEG]": 0.01408385799993539, - "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_prefix_empty_EXC]": 0.08976828699996986, - "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_prefix_ignorecase_EXC]": 0.10375606700000617, - "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_prefix_int_EXC]": 0.08777062499996191, - "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_prefix_list]": 0.01557448400001249, - "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_prefix_list_NEG]": 0.01462951600001361, - "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_prefix_list_type_EXC]": 0.08885766100002002, - "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_suffix]": 0.01428968100003658, - "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_suffix_NEG]": 0.014921021000020573, - "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_suffix_empty_EXC]": 0.0927351549999571, - "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_suffix_ignorecase_EXC]": 0.0884962670000391, - "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_suffix_int_EXC]": 0.09150582600005919, - "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_suffix_list]": 0.01404225400000314, - "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_suffix_list_NEG]": 0.014248785000006592, - "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_suffix_list_type_EXC]": 0.08950610999994524, - "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_wildcard]": 0.016145499999993262, - "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_wildcard_NEG]": 0.014640514999996412, - "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_wildcard_empty]": 0.014903184000047531, - "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_wildcard_list]": 0.015155535000019427, - "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_wildcard_list_NEG]": 0.01454540000003135, - "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_wildcard_list_type_EXC]": 0.08945834300004663, - "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_wildcard_type_EXC]": 0.08904192099993224, - "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_exists]": 0.015459362000058263, - "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_exists_NEG]": 0.014451004000022749, - "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_exists_false]": 0.022642694000012398, - "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_exists_false_NEG]": 0.01435165799995275, - "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_ignorecase]": 0.014184897000006913, - "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_ignorecase_EXC]": 0.0881684459999974, - "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_ignorecase_NEG]": 0.015013680000038221, - "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_ignorecase_empty]": 0.014723632000084308, - "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_ignorecase_empty_NEG]": 0.014705776000027981, - "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_ignorecase_list_EXC]": 0.08747247100001232, - "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_ip_address]": 0.014393385999994734, - "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_ip_address_EXC]": 0.08795043000003488, - "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_ip_address_NEG]": 0.014572217000022647, - "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_ip_address_bad_ip_EXC]": 0.08901414300004262, - "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_ip_address_bad_mask_EXC]": 0.08721073599997453, - "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_ip_address_type_EXC]": 0.08752350099990736, - "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_ip_address_v6]": 0.0164247600000067, - "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_ip_address_v6_NEG]": 0.014624474000072496, - "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_ip_address_v6_bad_ip_EXC]": 0.08832862500003102, - "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_numeric_EXC]": 0.08671135299994148, - "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_numeric_and]": 0.015509810999958518, - "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_numeric_and_NEG]": 0.020812545000012506, - "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_numeric_number_EXC]": 0.1093417530000238, - "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_numeric_operatorcasing_EXC]": 0.08850719899999149, - "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_numeric_syntax_EXC]": 0.10884408700002268, - "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_prefix]": 0.014145874000007552, - "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_prefix_NEG]": 0.014543286999980864, - "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_prefix_empty]": 0.015431489000036436, - "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_prefix_ignorecase]": 0.014815723000026537, - "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_prefix_int_EXC]": 0.08901537700000972, - "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_prefix_list_EXC]": 0.08868156299996599, - "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_suffix]": 0.014582116999974915, - "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_suffix_NEG]": 0.014042954999979429, - "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_suffix_empty]": 0.01462662800003045, - "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_suffix_ignorecase]": 0.014379550999990443, - "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_suffix_ignorecase_NEG]": 0.015225629000042318, - "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_suffix_int_EXC]": 0.08863398299996561, - "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_suffix_list_EXC]": 0.0880058510000481, - "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_wildcard_complex_EXC]": 0.08976001199999928, - "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_wildcard_empty_NEG]": 0.01554524099998389, - "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_wildcard_int_EXC]": 0.08842698900002688, - "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_wildcard_list_EXC]": 0.08819067700000005, - "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_wildcard_nonrepeating]": 0.014926217999970959, - "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_wildcard_nonrepeating_NEG]": 0.01537354200002028, - "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_wildcard_repeating]": 0.014944391000028645, - "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_wildcard_repeating_NEG]": 0.014949928000021373, - "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_wildcard_repeating_star_EXC]": 0.0876666799999839, - "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_wildcard_simplified]": 0.015956097000014324, - "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[dot_joining_event]": 0.014737656999955107, - "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[dot_joining_event_NEG]": 0.01420581599995785, - "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[dot_joining_pattern]": 0.014526713000009295, - "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[dot_joining_pattern_NEG]": 0.01455587899999955, - "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[dynamodb]": 0.014281274000040867, - "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[exists_dynamodb]": 0.014047760000039489, - "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[exists_dynamodb_NEG]": 0.013983741000060945, - "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[exists_list_empty_NEG]": 0.015198675000021922, - "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[int_nolist_EXC]": 0.08832306499999731, - "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[key_case_sensitive_NEG]": 0.014314477999960218, - "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[list_within_dict]": 0.01575416999992285, - "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[minimal]": 0.014330438000001777, - "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[nested_json_NEG]": 0.014308545000005779, - "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[null_value]": 0.01486818300008963, - "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[null_value_NEG]": 0.014670650000027763, - "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[number_comparison_float]": 0.014353660999972817, - "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[numeric-int-float]": 0.014028404999976374, - "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[numeric-null_NEG]": 0.02147796200006269, - "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[numeric-string_NEG]": 0.014482720999978937, - "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[operator_case_sensitive_EXC]": 0.09035089899998638, - "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[operator_multiple_list]": 0.01503944800009549, - "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[or-anything-but]": 0.014879029999974591, - "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[or-exists-parent]": 0.014192400000013095, - "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[or-exists]": 0.020539245000009032, - "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[or-numeric-anything-but]": 0.016102747999923395, - "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[or-numeric-anything-but_NEG]": 0.015270850000035807, - "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[prefix]": 0.013907378999988396, - "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[sample1]": 0.013989784999978383, - "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[string]": 0.014126818999955049, - "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[string_empty]": 0.014698172999999315, - "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[string_nolist_EXC]": 0.08775445599991372, - "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern_source": 0.025079028999925868, - "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern_with_escape_characters": 0.012931937999951515, - "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern_with_multi_key": 0.01310423699999319, - "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_with_large_and_complex_payload": 0.028149313999961123, - "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_invalid_event_payload": 0.014841723000017737, - "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_invalid_json_event_pattern[[\"not\", \"a\", \"dict\", \"but valid json\"]]": 0.08865607500001715, - "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_invalid_json_event_pattern[this is valid json but not a dict]": 0.08752079599997842, - "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_invalid_json_event_pattern[{\"not\": closed mark\"]": 0.08815595299995493, - "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_invalid_json_event_pattern[{'bad': 'quotation'}]": 0.08692419099998006, - "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_plain_string_payload": 0.016004205000001548, - "tests/aws/services/events/test_events_patterns.py::TestRuleWithPattern::test_put_event_with_content_base_rule_in_pattern": 0.20267552800004296, - "tests/aws/services/events/test_events_patterns.py::TestRuleWithPattern::test_put_events_with_rule_pattern_anything_but": 5.319287192000047, - "tests/aws/services/events/test_events_patterns.py::TestRuleWithPattern::test_put_events_with_rule_pattern_exists_false": 5.247686407999936, - "tests/aws/services/events/test_events_patterns.py::TestRuleWithPattern::test_put_events_with_rule_pattern_exists_true": 5.241712358000029, - "tests/aws/services/events/test_events_schedule.py::TestScheduleCron::test_schedule_cron_target_sqs": 0.0017541759999630813, - "tests/aws/services/events/test_events_schedule.py::TestScheduleCron::tests_put_rule_with_invalid_schedule_cron[cron(0 1 * * * *)]": 0.0138636190000625, - "tests/aws/services/events/test_events_schedule.py::TestScheduleCron::tests_put_rule_with_invalid_schedule_cron[cron(0 dummy ? * MON-FRI *)]": 0.013489698999990196, - "tests/aws/services/events/test_events_schedule.py::TestScheduleCron::tests_put_rule_with_invalid_schedule_cron[cron(7 20 * * NOT *)]": 0.013791243000071063, - "tests/aws/services/events/test_events_schedule.py::TestScheduleCron::tests_put_rule_with_invalid_schedule_cron[cron(71 8 1 * ? *)]": 0.01377911899993478, - "tests/aws/services/events/test_events_schedule.py::TestScheduleCron::tests_put_rule_with_invalid_schedule_cron[cron(INVALID)]": 0.013324482000030002, - "tests/aws/services/events/test_events_schedule.py::TestScheduleCron::tests_put_rule_with_schedule_cron[cron(* * ? * SAT#3 *)]": 0.036257400000010875, - "tests/aws/services/events/test_events_schedule.py::TestScheduleCron::tests_put_rule_with_schedule_cron[cron(0 10 * * ? *)]": 0.03641163100007816, - "tests/aws/services/events/test_events_schedule.py::TestScheduleCron::tests_put_rule_with_schedule_cron[cron(0 12 * * ? *)]": 0.03637429999997721, - "tests/aws/services/events/test_events_schedule.py::TestScheduleCron::tests_put_rule_with_schedule_cron[cron(0 18 ? * MON-FRI *)]": 0.03675758500003212, - "tests/aws/services/events/test_events_schedule.py::TestScheduleCron::tests_put_rule_with_schedule_cron[cron(0 2 ? * SAT *)]": 0.03704613399997925, - "tests/aws/services/events/test_events_schedule.py::TestScheduleCron::tests_put_rule_with_schedule_cron[cron(0 2 ? * SAT#3 *)]": 0.03619096699998181, - "tests/aws/services/events/test_events_schedule.py::TestScheduleCron::tests_put_rule_with_schedule_cron[cron(0 8 1 * ? *)]": 0.03614960900006281, - "tests/aws/services/events/test_events_schedule.py::TestScheduleCron::tests_put_rule_with_schedule_cron[cron(0/10 * ? * MON-FRI *)]": 0.03645134200002076, - "tests/aws/services/events/test_events_schedule.py::TestScheduleCron::tests_put_rule_with_schedule_cron[cron(0/15 * * * ? *)]": 0.036018283999965206, - "tests/aws/services/events/test_events_schedule.py::TestScheduleCron::tests_put_rule_with_schedule_cron[cron(0/30 0-2 ? * MON-FRI *)]": 0.037929793999978756, - "tests/aws/services/events/test_events_schedule.py::TestScheduleCron::tests_put_rule_with_schedule_cron[cron(0/30 20-23 ? * MON-FRI *)]": 0.03628623700001299, - "tests/aws/services/events/test_events_schedule.py::TestScheduleCron::tests_put_rule_with_schedule_cron[cron(0/5 5 ? JAN 1-5 2022)]": 0.036780057999976634, - "tests/aws/services/events/test_events_schedule.py::TestScheduleCron::tests_put_rule_with_schedule_cron[cron(0/5 8-17 ? * MON-FRI *)]": 0.0375571769999965, - "tests/aws/services/events/test_events_schedule.py::TestScheduleCron::tests_put_rule_with_schedule_cron[cron(15 10 ? * 6L 2002-2005)]": 0.03643190699989418, - "tests/aws/services/events/test_events_schedule.py::TestScheduleCron::tests_put_rule_with_schedule_cron[cron(15 12 * * ? *)]": 0.036412568999992345, - "tests/aws/services/events/test_events_schedule.py::TestScheduleCron::tests_put_rule_with_schedule_cron[cron(5,35 14 * * ? *)]": 0.037075668999989375, - "tests/aws/services/events/test_events_schedule.py::TestScheduleCron::tests_scheduled_rule_does_not_trigger_on_put_events": 3.107090512999946, - "tests/aws/services/events/test_events_schedule.py::TestScheduleRate::test_put_rule_with_invalid_schedule_rate[ rate(10 minutes)]": 0.011326027999984944, - "tests/aws/services/events/test_events_schedule.py::TestScheduleRate::test_put_rule_with_invalid_schedule_rate[rate( 10 minutes )]": 0.01197573100006366, - "tests/aws/services/events/test_events_schedule.py::TestScheduleRate::test_put_rule_with_invalid_schedule_rate[rate()]": 0.011375600000064878, - "tests/aws/services/events/test_events_schedule.py::TestScheduleRate::test_put_rule_with_invalid_schedule_rate[rate(-10 minutes)]": 0.011623443999951633, - "tests/aws/services/events/test_events_schedule.py::TestScheduleRate::test_put_rule_with_invalid_schedule_rate[rate(0 minutes)]": 0.011445470999944973, - "tests/aws/services/events/test_events_schedule.py::TestScheduleRate::test_put_rule_with_invalid_schedule_rate[rate(1 days)]": 0.011311691000059909, - "tests/aws/services/events/test_events_schedule.py::TestScheduleRate::test_put_rule_with_invalid_schedule_rate[rate(1 hours)]": 0.011592897000070934, - "tests/aws/services/events/test_events_schedule.py::TestScheduleRate::test_put_rule_with_invalid_schedule_rate[rate(1 minutes)]": 0.0110591399999862, - "tests/aws/services/events/test_events_schedule.py::TestScheduleRate::test_put_rule_with_invalid_schedule_rate[rate(10 MINUTES)]": 0.011063919000037004, - "tests/aws/services/events/test_events_schedule.py::TestScheduleRate::test_put_rule_with_invalid_schedule_rate[rate(10 day)]": 0.011329534999958923, - "tests/aws/services/events/test_events_schedule.py::TestScheduleRate::test_put_rule_with_invalid_schedule_rate[rate(10 hour)]": 0.011296202000039557, - "tests/aws/services/events/test_events_schedule.py::TestScheduleRate::test_put_rule_with_invalid_schedule_rate[rate(10 minute)]": 0.011663659000021198, - "tests/aws/services/events/test_events_schedule.py::TestScheduleRate::test_put_rule_with_invalid_schedule_rate[rate(10 minutess)]": 0.011299618000066403, - "tests/aws/services/events/test_events_schedule.py::TestScheduleRate::test_put_rule_with_invalid_schedule_rate[rate(10 seconds)]": 0.012233932000015102, - "tests/aws/services/events/test_events_schedule.py::TestScheduleRate::test_put_rule_with_invalid_schedule_rate[rate(10 years)]": 0.011565085999961866, - "tests/aws/services/events/test_events_schedule.py::TestScheduleRate::test_put_rule_with_invalid_schedule_rate[rate(10)]": 0.011480204999998023, - "tests/aws/services/events/test_events_schedule.py::TestScheduleRate::test_put_rule_with_invalid_schedule_rate[rate(foo minutes)]": 0.011452113000018471, - "tests/aws/services/events/test_events_schedule.py::TestScheduleRate::test_put_rule_with_schedule_rate": 0.03848467799997479, - "tests/aws/services/events/test_events_schedule.py::TestScheduleRate::test_scheduled_rule_logs": 0.0017789230000175849, - "tests/aws/services/events/test_events_schedule.py::TestScheduleRate::tests_put_rule_with_schedule_custom_event_bus": 0.04329292700009546, - "tests/aws/services/events/test_events_schedule.py::TestScheduleRate::tests_schedule_rate_custom_input_target_sqs": 60.11316494799996, - "tests/aws/services/events/test_events_schedule.py::TestScheduleRate::tests_schedule_rate_target_sqs": 0.0016661210000279425, - "tests/aws/services/events/test_events_tags.py::TestEventBusTags::test_create_event_bus_with_tags": 0.043308523000007426, - "tests/aws/services/events/test_events_tags.py::TestEventBusTags::test_list_tags_for_deleted_event_bus": 0.03517673300001434, - "tests/aws/services/events/test_events_tags.py::TestRuleTags::test_list_tags_for_deleted_rule": 0.06290706599997975, - "tests/aws/services/events/test_events_tags.py::TestRuleTags::test_put_rule_with_tags": 0.0640861640000594, - "tests/aws/services/events/test_events_tags.py::test_recreate_tagged_resource_without_tags[event_bus-event_bus_custom]": 0.06819020800003273, - "tests/aws/services/events/test_events_tags.py::test_recreate_tagged_resource_without_tags[event_bus-event_bus_default]": 0.024023224000018217, - "tests/aws/services/events/test_events_tags.py::test_recreate_tagged_resource_without_tags[rule-event_bus_custom]": 0.09002800000001798, - "tests/aws/services/events/test_events_tags.py::test_recreate_tagged_resource_without_tags[rule-event_bus_default]": 0.06358971900004917, - "tests/aws/services/events/test_events_tags.py::tests_tag_list_untag_not_existing_resource[not_existing_event_bus]": 0.033246797999993305, - "tests/aws/services/events/test_events_tags.py::tests_tag_list_untag_not_existing_resource[not_existing_rule]": 0.04546945700008109, - "tests/aws/services/events/test_events_tags.py::tests_tag_untag_resource[event_bus-event_bus_custom]": 0.10112773999998126, - "tests/aws/services/events/test_events_tags.py::tests_tag_untag_resource[event_bus-event_bus_default]": 0.06256318300000885, - "tests/aws/services/events/test_events_tags.py::tests_tag_untag_resource[rule-event_bus_custom]": 0.12388960800001314, - "tests/aws/services/events/test_events_tags.py::tests_tag_untag_resource[rule-event_bus_default]": 0.08162563700000192, - "tests/aws/services/events/test_events_targets.py::TestEventsTargetApiDestination::test_put_events_to_target_api_destinations[auth0]": 0.12098597700003211, - "tests/aws/services/events/test_events_targets.py::TestEventsTargetApiDestination::test_put_events_to_target_api_destinations[auth1]": 0.10929798100005428, - "tests/aws/services/events/test_events_targets.py::TestEventsTargetApiDestination::test_put_events_to_target_api_destinations[auth2]": 0.11308590299995558, - "tests/aws/services/events/test_events_targets.py::TestEventsTargetApiGateway::test_put_events_with_target_api_gateway": 8.254187989000002, - "tests/aws/services/events/test_events_targets.py::TestEventsTargetCloudWatchLogs::test_put_events_with_target_cloudwatch_logs": 0.21024522099997967, - "tests/aws/services/events/test_events_targets.py::TestEventsTargetEvents::test_put_events_with_target_events[bus_combination0]": 0.2954862220000223, - "tests/aws/services/events/test_events_targets.py::TestEventsTargetEvents::test_put_events_with_target_events[bus_combination1]": 1.175521931999981, - "tests/aws/services/events/test_events_targets.py::TestEventsTargetEvents::test_put_events_with_target_events[bus_combination2]": 0.29325240200000735, - "tests/aws/services/events/test_events_targets.py::TestEventsTargetFirehose::test_put_events_with_target_firehose": 1.0068901259999734, - "tests/aws/services/events/test_events_targets.py::TestEventsTargetKinesis::test_put_events_with_target_kinesis": 0.9027345099999593, - "tests/aws/services/events/test_events_targets.py::TestEventsTargetLambda::test_put_events_with_target_lambda": 4.239377536000006, - "tests/aws/services/events/test_events_targets.py::TestEventsTargetLambda::test_put_events_with_target_lambda_list_entries_partial_match": 4.27545645400005, - "tests/aws/services/events/test_events_targets.py::TestEventsTargetLambda::test_put_events_with_target_lambda_list_entry": 4.285332672999971, - "tests/aws/services/events/test_events_targets.py::TestEventsTargetSns::test_put_events_with_target_sns[domain]": 0.2269364820000419, - "tests/aws/services/events/test_events_targets.py::TestEventsTargetSns::test_put_events_with_target_sns[path]": 0.22617281500004083, - "tests/aws/services/events/test_events_targets.py::TestEventsTargetSns::test_put_events_with_target_sns[standard]": 0.5673225400000206, - "tests/aws/services/events/test_events_targets.py::TestEventsTargetSqs::test_put_events_with_target_sqs": 0.18582966400003897, - "tests/aws/services/events/test_events_targets.py::TestEventsTargetSqs::test_put_events_with_target_sqs_event_detail_match": 5.236169262999965, - "tests/aws/services/events/test_events_targets.py::TestEventsTargetStepFunctions::test_put_events_with_target_statefunction_machine": 2.077924687999996, - "tests/aws/services/events/test_x_ray_trace_propagation.py::test_xray_trace_propagation_events_api_gateway": 5.737344499000017, - "tests/aws/services/events/test_x_ray_trace_propagation.py::test_xray_trace_propagation_events_events[bus_combination0]": 4.39111324199996, - "tests/aws/services/events/test_x_ray_trace_propagation.py::test_xray_trace_propagation_events_events[bus_combination1]": 4.410297857999922, - "tests/aws/services/events/test_x_ray_trace_propagation.py::test_xray_trace_propagation_events_events[bus_combination2]": 4.377339905000042, - "tests/aws/services/events/test_x_ray_trace_propagation.py::test_xray_trace_propagation_events_lambda": 4.255771364000054, - "tests/aws/services/firehose/test_firehose.py::TestFirehoseIntegration::test_kinesis_firehose_elasticsearch_s3_backup": 0.0018826959999387327, - "tests/aws/services/firehose/test_firehose.py::TestFirehoseIntegration::test_kinesis_firehose_kinesis_as_source": 33.262779428000044, - "tests/aws/services/firehose/test_firehose.py::TestFirehoseIntegration::test_kinesis_firehose_kinesis_as_source_multiple_delivery_streams": 50.56226439399995, - "tests/aws/services/firehose/test_firehose.py::TestFirehoseIntegration::test_kinesis_firehose_opensearch_s3_backup[domain]": 0.0018425590001243108, - "tests/aws/services/firehose/test_firehose.py::TestFirehoseIntegration::test_kinesis_firehose_opensearch_s3_backup[path]": 0.00172167400012313, - "tests/aws/services/firehose/test_firehose.py::TestFirehoseIntegration::test_kinesis_firehose_opensearch_s3_backup[port]": 0.0017401880000988967, - "tests/aws/services/firehose/test_firehose.py::TestFirehoseIntegration::test_kinesis_firehose_s3_as_destination_with_file_extension": 1.1778381269999727, - "tests/aws/services/firehose/test_firehose.py::test_kinesis_firehose_http[False]": 0.08602945300003739, - "tests/aws/services/firehose/test_firehose.py::test_kinesis_firehose_http[True]": 1.59980154699997, - "tests/aws/services/iam/test_iam.py::TestIAMExtensions::test_create_role_with_malformed_assume_role_policy_document": 0.020238150999944082, - "tests/aws/services/iam/test_iam.py::TestIAMExtensions::test_create_user_add_permission_boundary_afterwards": 0.11170138799991491, - "tests/aws/services/iam/test_iam.py::TestIAMExtensions::test_create_user_with_permission_boundary": 0.09908693000011226, - "tests/aws/services/iam/test_iam.py::TestIAMExtensions::test_get_user_without_username_as_role": 0.11496437999994669, - "tests/aws/services/iam/test_iam.py::TestIAMExtensions::test_get_user_without_username_as_root": 0.041012554999952044, - "tests/aws/services/iam/test_iam.py::TestIAMExtensions::test_get_user_without_username_as_user": 0.15396861300018827, - "tests/aws/services/iam/test_iam.py::TestIAMExtensions::test_role_with_path_lifecycle": 0.11612076800008708, - "tests/aws/services/iam/test_iam.py::TestIAMIntegrations::test_attach_detach_role_policy": 0.08162928900003408, - "tests/aws/services/iam/test_iam.py::TestIAMIntegrations::test_attach_iam_role_to_new_iam_user": 0.10243673699994815, - "tests/aws/services/iam/test_iam.py::TestIAMIntegrations::test_create_describe_role": 0.15616835100013304, - "tests/aws/services/iam/test_iam.py::TestIAMIntegrations::test_create_role_with_assume_role_policy": 0.12831676800010428, - "tests/aws/services/iam/test_iam.py::TestIAMIntegrations::test_create_user_with_tags": 0.03143530500005909, - "tests/aws/services/iam/test_iam.py::TestIAMIntegrations::test_delete_non_existent_policy_returns_no_such_entity": 0.01624942499995541, - "tests/aws/services/iam/test_iam.py::TestIAMIntegrations::test_instance_profile_tags": 0.14609278300008555, - "tests/aws/services/iam/test_iam.py::TestIAMIntegrations::test_list_roles_with_permission_boundary": 0.19820658200001162, - "tests/aws/services/iam/test_iam.py::TestIAMIntegrations::test_recreate_iam_role": 0.050619607999919936, - "tests/aws/services/iam/test_iam.py::TestIAMIntegrations::test_role_attach_policy": 0.4058686719999969, - "tests/aws/services/iam/test_iam.py::TestIAMIntegrations::test_service_linked_role_name_should_match_aws[ecs.amazonaws.com-AWSServiceRoleForECS]": 0.002275940000004084, - "tests/aws/services/iam/test_iam.py::TestIAMIntegrations::test_service_linked_role_name_should_match_aws[eks.amazonaws.com-AWSServiceRoleForAmazonEKS]": 0.002890896999929282, - "tests/aws/services/iam/test_iam.py::TestIAMIntegrations::test_simulate_principle_policy[group]": 0.18886847700002818, - "tests/aws/services/iam/test_iam.py::TestIAMIntegrations::test_simulate_principle_policy[role]": 0.21745809799995186, - "tests/aws/services/iam/test_iam.py::TestIAMIntegrations::test_simulate_principle_policy[user]": 0.22570226899983936, - "tests/aws/services/iam/test_iam.py::TestIAMIntegrations::test_update_assume_role_policy": 0.13201091300004464, - "tests/aws/services/iam/test_iam.py::TestIAMIntegrations::test_user_attach_policy": 0.41616205699995135, - "tests/aws/services/iam/test_iam.py::TestIAMPolicyEncoding::test_put_group_policy_encoding": 0.055763372000001254, - "tests/aws/services/iam/test_iam.py::TestIAMPolicyEncoding::test_put_role_policy_encoding": 0.17728442099985386, - "tests/aws/services/iam/test_iam.py::TestIAMPolicyEncoding::test_put_user_policy_encoding": 0.0804576719999659, - "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_already_exists": 0.036425126000153796, - "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_deletion": 3.347165705000066, - "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle[accountdiscovery.ssm.amazonaws.com]": 0.2766924499999277, - "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle[acm.amazonaws.com]": 0.2749733319998313, - "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle[appmesh.amazonaws.com]": 0.28009624599997096, - "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle[autoscaling-plans.amazonaws.com]": 0.2787364669999306, - "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle[autoscaling.amazonaws.com]": 0.2805499929999087, - "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle[backup.amazonaws.com]": 0.2793444220000083, - "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle[batch.amazonaws.com]": 0.28120590799994716, - "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle[cassandra.application-autoscaling.amazonaws.com]": 0.27860010200004126, - "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle[cks.kms.amazonaws.com]": 0.27600945699998647, - "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle[cloudtrail.amazonaws.com]": 0.2843315509999229, - "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle[codestar-notifications.amazonaws.com]": 1.1657402020000518, - "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle[config.amazonaws.com]": 0.2736242519999905, - "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle[connect.amazonaws.com]": 0.27350013299997045, - "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle[dms-fleet-advisor.amazonaws.com]": 0.2739157759999671, - "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle[dms.amazonaws.com]": 0.27327498200008904, - "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle[docdb-elastic.amazonaws.com]": 0.27467426499993053, - "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle[ec2-instance-connect.amazonaws.com]": 0.2727547320000667, - "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle[ec2.application-autoscaling.amazonaws.com]": 0.2756869930000221, - "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle[ecr.amazonaws.com]": 0.27324617700003273, - "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle[ecs.amazonaws.com]": 0.27654629999994995, - "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle[eks-connector.amazonaws.com]": 0.28057046400010677, - "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle[eks-fargate.amazonaws.com]": 0.2842796369999405, - "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle[eks-nodegroup.amazonaws.com]": 0.28169082400006573, - "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle[eks.amazonaws.com]": 0.28091033799989873, - "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle[elasticache.amazonaws.com]": 0.2830041380001376, - "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle[elasticbeanstalk.amazonaws.com]": 0.28812132300004123, - "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle[elasticfilesystem.amazonaws.com]": 0.3050036939999927, - "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle[elasticloadbalancing.amazonaws.com]": 0.27974474100005864, - "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle[email.cognito-idp.amazonaws.com]": 0.27838823399997636, - "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle[emr-containers.amazonaws.com]": 0.28264105999994626, - "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle[emrwal.amazonaws.com]": 0.284902860000102, - "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle[fis.amazonaws.com]": 0.286014924999904, - "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle[grafana.amazonaws.com]": 0.28556717999993, - "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle[imagebuilder.amazonaws.com]": 0.2910752740000362, - "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle[iotmanagedintegrations.amazonaws.com]": 0.35293678099992576, - "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle[kafka.amazonaws.com]": 0.28086574399992514, - "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle[kafkaconnect.amazonaws.com]": 0.2836343950000355, - "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle[lakeformation.amazonaws.com]": 0.28101746200002253, - "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle[lex.amazonaws.com]": 0.3560131270000966, - "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle[lexv2.amazonaws.com]": 0.2844557600000144, - "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle[lightsail.amazonaws.com]": 0.27781867899989265, - "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle[m2.amazonaws.com]": 0.2848953210001355, - "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle[memorydb.amazonaws.com]": 0.2814740139999685, - "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle[mq.amazonaws.com]": 0.2845015450000119, - "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle[mrk.kms.amazonaws.com]": 0.28171004599994376, - "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle[notifications.amazonaws.com]": 0.2764323810000633, - "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle[observability.aoss.amazonaws.com]": 0.2812617770000543, - "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle[opensearchservice.amazonaws.com]": 0.2832174610000493, - "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle[ops.apigateway.amazonaws.com]": 0.2784232469999779, - "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle[ops.emr-serverless.amazonaws.com]": 0.27751762199989116, - "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle[opsdatasync.ssm.amazonaws.com]": 0.2780138169999873, - "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle[opsinsights.ssm.amazonaws.com]": 0.278777780999917, - "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle[pullthroughcache.ecr.amazonaws.com]": 0.2787828319998198, - "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle[ram.amazonaws.com]": 0.2799963619999062, - "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle[rds.amazonaws.com]": 0.2885942679999971, - "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle[redshift.amazonaws.com]": 0.28336435899996104, - "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle[replication.cassandra.amazonaws.com]": 0.2797796649999782, - "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle[replication.ecr.amazonaws.com]": 0.2833604520000108, - "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle[repository.sync.codeconnections.amazonaws.com]": 0.2807044459998451, - "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle[resource-explorer-2.amazonaws.com]": 0.28120385799991254, - "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle[rolesanywhere.amazonaws.com]": 0.2763864119999653, - "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle[s3-outposts.amazonaws.com]": 0.2886157899999944, - "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle[ses.amazonaws.com]": 0.30230607200007853, - "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle[shield.amazonaws.com]": 0.28968889600002967, - "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle[ssm-incidents.amazonaws.com]": 0.27701686800003245, - "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle[ssm-quicksetup.amazonaws.com]": 0.27459572799989473, - "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle[ssm.amazonaws.com]": 0.27885161399979097, - "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle[sso.amazonaws.com]": 0.2816540379999424, - "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle[vpcorigin.cloudfront.amazonaws.com]": 1.234145570999999, - "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle[waf.amazonaws.com]": 0.27824756600000455, - "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle[wafv2.amazonaws.com]": 0.27714035999997577, - "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle_custom_suffix[autoscaling.amazonaws.com]": 0.1350413430000117, - "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle_custom_suffix[connect.amazonaws.com]": 0.13369623900007355, - "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle_custom_suffix[lexv2.amazonaws.com]": 0.13070805400002428, - "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle_custom_suffix_not_allowed[accountdiscovery.ssm.amazonaws.com]": 0.015846935000126905, - "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle_custom_suffix_not_allowed[acm.amazonaws.com]": 0.018798661999994692, - "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle_custom_suffix_not_allowed[appmesh.amazonaws.com]": 0.01583665500004372, - "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle_custom_suffix_not_allowed[autoscaling-plans.amazonaws.com]": 0.01757402299995192, - "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle_custom_suffix_not_allowed[backup.amazonaws.com]": 0.01787395899987132, - "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle_custom_suffix_not_allowed[batch.amazonaws.com]": 0.01741507899998851, - "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle_custom_suffix_not_allowed[cassandra.application-autoscaling.amazonaws.com]": 0.01913997000008294, - "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle_custom_suffix_not_allowed[cks.kms.amazonaws.com]": 0.01750638400005755, - "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle_custom_suffix_not_allowed[cloudtrail.amazonaws.com]": 0.01534577400013859, - "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle_custom_suffix_not_allowed[codestar-notifications.amazonaws.com]": 0.015939282999966053, - "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle_custom_suffix_not_allowed[config.amazonaws.com]": 0.015963531999886982, - "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle_custom_suffix_not_allowed[dms-fleet-advisor.amazonaws.com]": 0.015537873999960539, - "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle_custom_suffix_not_allowed[dms.amazonaws.com]": 0.016161301000011008, - "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle_custom_suffix_not_allowed[docdb-elastic.amazonaws.com]": 0.018825020000008408, - "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle_custom_suffix_not_allowed[ec2-instance-connect.amazonaws.com]": 0.015494579999881353, - "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle_custom_suffix_not_allowed[ec2.application-autoscaling.amazonaws.com]": 0.01580329199987318, - "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle_custom_suffix_not_allowed[ecr.amazonaws.com]": 0.019116355000051044, - "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle_custom_suffix_not_allowed[ecs.amazonaws.com]": 0.019194541000160825, - "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle_custom_suffix_not_allowed[eks-connector.amazonaws.com]": 0.016729203000068082, - "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle_custom_suffix_not_allowed[eks-fargate.amazonaws.com]": 0.015719992999947863, - "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle_custom_suffix_not_allowed[eks-nodegroup.amazonaws.com]": 0.020124088999864398, - "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle_custom_suffix_not_allowed[eks.amazonaws.com]": 0.016589470999974765, - "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle_custom_suffix_not_allowed[elasticache.amazonaws.com]": 0.01570969800002331, - "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle_custom_suffix_not_allowed[elasticbeanstalk.amazonaws.com]": 0.018982694999976957, - "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle_custom_suffix_not_allowed[elasticfilesystem.amazonaws.com]": 0.019079249000014897, - "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle_custom_suffix_not_allowed[elasticloadbalancing.amazonaws.com]": 0.01957289899985426, - "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle_custom_suffix_not_allowed[email.cognito-idp.amazonaws.com]": 0.020254665999914323, - "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle_custom_suffix_not_allowed[emr-containers.amazonaws.com]": 0.016851802000019234, - "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle_custom_suffix_not_allowed[emrwal.amazonaws.com]": 0.01828211899987764, - "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle_custom_suffix_not_allowed[fis.amazonaws.com]": 0.01659646400003112, - "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle_custom_suffix_not_allowed[grafana.amazonaws.com]": 0.017188783000051444, - "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle_custom_suffix_not_allowed[imagebuilder.amazonaws.com]": 0.01604831000008744, - "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle_custom_suffix_not_allowed[iotmanagedintegrations.amazonaws.com]": 0.01750041200011765, - "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle_custom_suffix_not_allowed[kafka.amazonaws.com]": 0.01739921300008973, - "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle_custom_suffix_not_allowed[kafkaconnect.amazonaws.com]": 0.01595814699987841, - "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle_custom_suffix_not_allowed[lakeformation.amazonaws.com]": 0.01891131200000018, - "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle_custom_suffix_not_allowed[lex.amazonaws.com]": 0.017822223000052873, - "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle_custom_suffix_not_allowed[lightsail.amazonaws.com]": 0.015448092999918117, - "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle_custom_suffix_not_allowed[m2.amazonaws.com]": 0.019197820000044885, - "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle_custom_suffix_not_allowed[memorydb.amazonaws.com]": 0.01864186900002096, - "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle_custom_suffix_not_allowed[mq.amazonaws.com]": 0.019161322000059045, - "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle_custom_suffix_not_allowed[mrk.kms.amazonaws.com]": 0.017574210000020685, - "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle_custom_suffix_not_allowed[notifications.amazonaws.com]": 0.01917378199993891, - "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle_custom_suffix_not_allowed[observability.aoss.amazonaws.com]": 0.01667927200014674, - "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle_custom_suffix_not_allowed[opensearchservice.amazonaws.com]": 0.017764463999924374, - "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle_custom_suffix_not_allowed[ops.apigateway.amazonaws.com]": 0.015871385999957965, - "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle_custom_suffix_not_allowed[ops.emr-serverless.amazonaws.com]": 0.015799622000031377, - "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle_custom_suffix_not_allowed[opsdatasync.ssm.amazonaws.com]": 0.018350207999901613, - "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle_custom_suffix_not_allowed[opsinsights.ssm.amazonaws.com]": 0.015695702000016354, - "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle_custom_suffix_not_allowed[pullthroughcache.ecr.amazonaws.com]": 0.016318997000098534, - "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle_custom_suffix_not_allowed[ram.amazonaws.com]": 0.016216579999991154, - "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle_custom_suffix_not_allowed[rds.amazonaws.com]": 0.01952866199997061, - "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle_custom_suffix_not_allowed[redshift.amazonaws.com]": 0.018552985999917837, - "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle_custom_suffix_not_allowed[replication.cassandra.amazonaws.com]": 0.01617598999985148, - "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle_custom_suffix_not_allowed[replication.ecr.amazonaws.com]": 0.019434859000170945, - "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle_custom_suffix_not_allowed[repository.sync.codeconnections.amazonaws.com]": 0.015493882999862763, - "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle_custom_suffix_not_allowed[resource-explorer-2.amazonaws.com]": 0.019263448999936372, - "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle_custom_suffix_not_allowed[rolesanywhere.amazonaws.com]": 0.016731364999941434, - "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle_custom_suffix_not_allowed[s3-outposts.amazonaws.com]": 0.020736628999884488, - "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle_custom_suffix_not_allowed[ses.amazonaws.com]": 0.015308204000007208, - "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle_custom_suffix_not_allowed[shield.amazonaws.com]": 0.015980089999857228, - "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle_custom_suffix_not_allowed[ssm-incidents.amazonaws.com]": 0.018654228000173134, - "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle_custom_suffix_not_allowed[ssm-quicksetup.amazonaws.com]": 0.017625003999910405, - "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle_custom_suffix_not_allowed[ssm.amazonaws.com]": 0.019063491000110844, - "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle_custom_suffix_not_allowed[sso.amazonaws.com]": 0.01953008899999986, - "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle_custom_suffix_not_allowed[vpcorigin.cloudfront.amazonaws.com]": 0.0193398569999772, - "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle_custom_suffix_not_allowed[waf.amazonaws.com]": 0.01594744900000933, - "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle_custom_suffix_not_allowed[wafv2.amazonaws.com]": 0.016703574999951343, - "tests/aws/services/iam/test_iam.py::TestIAMServiceSpecificCredentials::test_create_service_specific_credential_invalid_service": 0.07965666300003704, - "tests/aws/services/iam/test_iam.py::TestIAMServiceSpecificCredentials::test_create_service_specific_credential_invalid_user": 0.02389655300009963, - "tests/aws/services/iam/test_iam.py::TestIAMServiceSpecificCredentials::test_delete_user_after_service_credential_created": 0.07797472200002176, - "tests/aws/services/iam/test_iam.py::TestIAMServiceSpecificCredentials::test_id_match_user_mismatch": 0.09613285200009614, - "tests/aws/services/iam/test_iam.py::TestIAMServiceSpecificCredentials::test_invalid_update_parameters": 0.07904687399991417, - "tests/aws/services/iam/test_iam.py::TestIAMServiceSpecificCredentials::test_list_service_specific_credential_different_service": 0.08015360899992174, - "tests/aws/services/iam/test_iam.py::TestIAMServiceSpecificCredentials::test_service_specific_credential_lifecycle[cassandra.amazonaws.com]": 0.10484987600011664, - "tests/aws/services/iam/test_iam.py::TestIAMServiceSpecificCredentials::test_service_specific_credential_lifecycle[codecommit.amazonaws.com]": 0.11063168100008625, - "tests/aws/services/iam/test_iam.py::TestIAMServiceSpecificCredentials::test_user_match_id_mismatch[satisfiesregexbutstillinvalid]": 0.09853819400007069, - "tests/aws/services/iam/test_iam.py::TestIAMServiceSpecificCredentials::test_user_match_id_mismatch[totally-wrong-credential-id-with-hyphens]": 0.09713208800008033, - "tests/aws/services/iam/test_iam.py::TestRoles::test_role_with_tags": 0.07963118200007102, - "tests/aws/services/kinesis/test_kinesis.py::TestKinesis::test_add_tags_to_stream": 0.6860903659999167, - "tests/aws/services/kinesis/test_kinesis.py::TestKinesis::test_cbor_blob_handling": 0.6623435109999036, - "tests/aws/services/kinesis/test_kinesis.py::TestKinesis::test_create_stream_without_shard_count": 0.6623489200001131, - "tests/aws/services/kinesis/test_kinesis.py::TestKinesis::test_create_stream_without_stream_name_raises": 0.03977176299997609, - "tests/aws/services/kinesis/test_kinesis.py::TestKinesis::test_get_records": 0.7473333049999837, - "tests/aws/services/kinesis/test_kinesis.py::TestKinesis::test_get_records_empty_stream": 0.6666298560000996, - "tests/aws/services/kinesis/test_kinesis.py::TestKinesis::test_get_records_next_shard_iterator": 0.6728014100000337, - "tests/aws/services/kinesis/test_kinesis.py::TestKinesis::test_get_records_shard_iterator_with_surrounding_quotes": 0.6809222170001021, - "tests/aws/services/kinesis/test_kinesis.py::TestKinesis::test_record_lifecycle_data_integrity": 0.856099008000001, - "tests/aws/services/kinesis/test_kinesis.py::TestKinesis::test_stream_consumers": 1.331015351000019, - "tests/aws/services/kinesis/test_kinesis.py::TestKinesis::test_subscribe_to_shard": 4.538219553999966, - "tests/aws/services/kinesis/test_kinesis.py::TestKinesis::test_subscribe_to_shard_cbor_at_timestamp": 1.3612051229999906, - "tests/aws/services/kinesis/test_kinesis.py::TestKinesis::test_subscribe_to_shard_timeout": 6.339550297000073, - "tests/aws/services/kinesis/test_kinesis.py::TestKinesis::test_subscribe_to_shard_with_at_timestamp": 4.504024748999882, - "tests/aws/services/kinesis/test_kinesis.py::TestKinesis::test_subscribe_to_shard_with_at_timestamp_cbor": 0.6523684630001299, - "tests/aws/services/kinesis/test_kinesis.py::TestKinesis::test_subscribe_to_shard_with_sequence_number_as_iterator": 4.544286493000072, - "tests/aws/services/kinesis/test_kinesis.py::TestKinesisJavaSDK::test_subscribe_to_shard_with_java_sdk_v2_lambda": 9.59929229599993, - "tests/aws/services/kinesis/test_kinesis.py::TestKinesisMockScala::test_add_tags_to_stream": 0.6775734999998804, - "tests/aws/services/kinesis/test_kinesis.py::TestKinesisMockScala::test_cbor_blob_handling": 0.6801028940000151, - "tests/aws/services/kinesis/test_kinesis.py::TestKinesisMockScala::test_create_stream_without_shard_count": 0.665633289000084, - "tests/aws/services/kinesis/test_kinesis.py::TestKinesisMockScala::test_create_stream_without_stream_name_raises": 0.04570791799994822, - "tests/aws/services/kinesis/test_kinesis.py::TestKinesisMockScala::test_get_records": 0.721093101000065, - "tests/aws/services/kinesis/test_kinesis.py::TestKinesisMockScala::test_get_records_empty_stream": 0.6674658529999533, - "tests/aws/services/kinesis/test_kinesis.py::TestKinesisMockScala::test_get_records_next_shard_iterator": 0.6645175659999722, - "tests/aws/services/kinesis/test_kinesis.py::TestKinesisMockScala::test_get_records_shard_iterator_with_surrounding_quotes": 0.6597587969998813, - "tests/aws/services/kinesis/test_kinesis.py::TestKinesisMockScala::test_record_lifecycle_data_integrity": 0.8699330260000124, - "tests/aws/services/kinesis/test_kinesis.py::TestKinesisMockScala::test_stream_consumers": 1.315080956000088, - "tests/aws/services/kinesis/test_kinesis.py::TestKinesisMockScala::test_subscribe_to_shard": 1.6306881760001488, - "tests/aws/services/kinesis/test_kinesis.py::TestKinesisMockScala::test_subscribe_to_shard_cbor_at_timestamp": 4.340954697000029, - "tests/aws/services/kinesis/test_kinesis.py::TestKinesisMockScala::test_subscribe_to_shard_timeout": 6.3159185140001455, - "tests/aws/services/kinesis/test_kinesis.py::TestKinesisMockScala::test_subscribe_to_shard_with_at_timestamp": 4.496381154000005, - "tests/aws/services/kinesis/test_kinesis.py::TestKinesisMockScala::test_subscribe_to_shard_with_at_timestamp_cbor": 0.6425933909999912, - "tests/aws/services/kinesis/test_kinesis.py::TestKinesisMockScala::test_subscribe_to_shard_with_sequence_number_as_iterator": 1.6495877830000154, - "tests/aws/services/kinesis/test_kinesis.py::TestKinesisPythonClient::test_run_kcl": 39.1048678169999, - "tests/aws/services/kms/test_kms.py::TestKMS::test_all_types_of_key_id_can_be_used_for_encryption": 0.06716262099996584, - "tests/aws/services/kms/test_kms.py::TestKMS::test_cant_delete_deleted_key": 0.03381922599999143, - "tests/aws/services/kms/test_kms.py::TestKMS::test_cant_use_disabled_or_deleted_keys": 0.05426699500003451, - "tests/aws/services/kms/test_kms.py::TestKMS::test_create_alias": 0.1936062250000532, - "tests/aws/services/kms/test_kms.py::TestKMS::test_create_custom_key_asymmetric": 0.038813034999861884, - "tests/aws/services/kms/test_kms.py::TestKMS::test_create_grant_with_invalid_key": 0.02443966900000305, - "tests/aws/services/kms/test_kms.py::TestKMS::test_create_grant_with_same_name_two_keys": 0.0620267369999965, - "tests/aws/services/kms/test_kms.py::TestKMS::test_create_grant_with_valid_key": 0.042606399000078454, - "tests/aws/services/kms/test_kms.py::TestKMS::test_create_key": 0.11698813400005292, - "tests/aws/services/kms/test_kms.py::TestKMS::test_create_key_custom_id": 0.02838077800015526, - "tests/aws/services/kms/test_kms.py::TestKMS::test_create_key_custom_key_material_hmac": 0.037949292999883255, - "tests/aws/services/kms/test_kms.py::TestKMS::test_create_key_custom_key_material_symmetric_decrypt": 0.03038753499993163, - "tests/aws/services/kms/test_kms.py::TestKMS::test_create_key_with_invalid_tag_key[lowercase_prefix]": 0.0891195299999481, - "tests/aws/services/kms/test_kms.py::TestKMS::test_create_key_with_invalid_tag_key[too_long_key]": 0.08834731000013107, - "tests/aws/services/kms/test_kms.py::TestKMS::test_create_key_with_invalid_tag_key[uppercase_prefix]": 0.08933281099996293, - "tests/aws/services/kms/test_kms.py::TestKMS::test_create_key_with_tag_and_untag": 0.11319700500007457, - "tests/aws/services/kms/test_kms.py::TestKMS::test_create_key_with_too_many_tags_raises_error": 0.09022377300004791, - "tests/aws/services/kms/test_kms.py::TestKMS::test_create_list_delete_alias": 0.05876891999980671, - "tests/aws/services/kms/test_kms.py::TestKMS::test_create_multi_region_key": 0.16889600500007873, - "tests/aws/services/kms/test_kms.py::TestKMS::test_derive_shared_secret": 0.20275388699997166, - "tests/aws/services/kms/test_kms.py::TestKMS::test_describe_and_list_sign_key": 0.03454873900000166, - "tests/aws/services/kms/test_kms.py::TestKMS::test_describe_with_alias_arn": 0.1907706629999666, - "tests/aws/services/kms/test_kms.py::TestKMS::test_disable_and_enable_key": 0.05570538199992825, - "tests/aws/services/kms/test_kms.py::TestKMS::test_encrypt_decrypt[RSA_2048-RSAES_OAEP_SHA_256]": 0.058896708000020226, - "tests/aws/services/kms/test_kms.py::TestKMS::test_encrypt_decrypt[SYMMETRIC_DEFAULT-SYMMETRIC_DEFAULT]": 0.03400140400003693, - "tests/aws/services/kms/test_kms.py::TestKMS::test_encrypt_decrypt_encryption_context": 0.2693628419998504, - "tests/aws/services/kms/test_kms.py::TestKMS::test_encrypt_validate_plaintext_size_per_key_type[RSA_2048-RSAES_OAEP_SHA_1]": 0.13375360400004865, - "tests/aws/services/kms/test_kms.py::TestKMS::test_encrypt_validate_plaintext_size_per_key_type[RSA_2048-RSAES_OAEP_SHA_256]": 0.13697323899998537, - "tests/aws/services/kms/test_kms.py::TestKMS::test_encrypt_validate_plaintext_size_per_key_type[RSA_3072-RSAES_OAEP_SHA_1]": 0.2980154820000962, - "tests/aws/services/kms/test_kms.py::TestKMS::test_encrypt_validate_plaintext_size_per_key_type[RSA_3072-RSAES_OAEP_SHA_256]": 0.2642861410001842, - "tests/aws/services/kms/test_kms.py::TestKMS::test_encrypt_validate_plaintext_size_per_key_type[RSA_4096-RSAES_OAEP_SHA_1]": 0.5318752520000771, - "tests/aws/services/kms/test_kms.py::TestKMS::test_encrypt_validate_plaintext_size_per_key_type[RSA_4096-RSAES_OAEP_SHA_256]": 0.5822761880000371, - "tests/aws/services/kms/test_kms.py::TestKMS::test_error_messaging_for_invalid_keys": 0.19633737200001633, - "tests/aws/services/kms/test_kms.py::TestKMS::test_generate_and_verify_mac[HMAC_224-HMAC_SHA_224]": 1.08429158499996, - "tests/aws/services/kms/test_kms.py::TestKMS::test_generate_and_verify_mac[HMAC_256-HMAC_SHA_256]": 0.12669558399989, - "tests/aws/services/kms/test_kms.py::TestKMS::test_generate_and_verify_mac[HMAC_384-HMAC_SHA_384]": 0.12381018600001426, - "tests/aws/services/kms/test_kms.py::TestKMS::test_generate_and_verify_mac[HMAC_512-HMAC_SHA_512]": 0.12440696900000603, - "tests/aws/services/kms/test_kms.py::TestKMS::test_generate_random[1024]": 0.0996383289999585, - "tests/aws/services/kms/test_kms.py::TestKMS::test_generate_random[12]": 0.09132048000003579, - "tests/aws/services/kms/test_kms.py::TestKMS::test_generate_random[1]": 0.09926554399999077, - "tests/aws/services/kms/test_kms.py::TestKMS::test_generate_random[44]": 0.09174029399991923, - "tests/aws/services/kms/test_kms.py::TestKMS::test_generate_random[91]": 0.09035692000009021, - "tests/aws/services/kms/test_kms.py::TestKMS::test_generate_random_invalid_number_of_bytes[0]": 0.08687029199995777, - "tests/aws/services/kms/test_kms.py::TestKMS::test_generate_random_invalid_number_of_bytes[1025]": 0.08689028000003418, - "tests/aws/services/kms/test_kms.py::TestKMS::test_generate_random_invalid_number_of_bytes[None]": 0.10561329699999078, - "tests/aws/services/kms/test_kms.py::TestKMS::test_get_key_does_not_exist": 0.1174776989998918, - "tests/aws/services/kms/test_kms.py::TestKMS::test_get_key_in_different_region": 0.13603615499994248, - "tests/aws/services/kms/test_kms.py::TestKMS::test_get_key_invalid_uuid": 0.10368899299999157, - "tests/aws/services/kms/test_kms.py::TestKMS::test_get_parameters_for_import": 0.3218431720000581, - "tests/aws/services/kms/test_kms.py::TestKMS::test_get_public_key": 0.04970806400001493, - "tests/aws/services/kms/test_kms.py::TestKMS::test_get_put_list_key_policies": 0.048341661999870666, - "tests/aws/services/kms/test_kms.py::TestKMS::test_hmac_create_key": 0.11911891200008995, - "tests/aws/services/kms/test_kms.py::TestKMS::test_hmac_create_key_invalid_operations": 0.10067290299991782, - "tests/aws/services/kms/test_kms.py::TestKMS::test_import_key_asymmetric": 0.3057153869998501, - "tests/aws/services/kms/test_kms.py::TestKMS::test_import_key_ecc_keys[ECC_NIST_P256]": 0.23233523400006106, - "tests/aws/services/kms/test_kms.py::TestKMS::test_import_key_ecc_keys[ECC_NIST_P384]": 0.27058119099979194, - "tests/aws/services/kms/test_kms.py::TestKMS::test_import_key_ecc_keys[ECC_NIST_P521]": 1.174245754000026, - "tests/aws/services/kms/test_kms.py::TestKMS::test_import_key_ecc_keys[ECC_SECG_P256K1]": 0.24309395000000222, - "tests/aws/services/kms/test_kms.py::TestKMS::test_import_key_hmac_keys[HMAC_224]": 0.7381110840000247, - "tests/aws/services/kms/test_kms.py::TestKMS::test_import_key_hmac_keys[HMAC_256]": 1.0678955849998601, - "tests/aws/services/kms/test_kms.py::TestKMS::test_import_key_hmac_keys[HMAC_384]": 0.7582589209998787, - "tests/aws/services/kms/test_kms.py::TestKMS::test_import_key_hmac_keys[HMAC_512]": 0.9174179699998604, - "tests/aws/services/kms/test_kms.py::TestKMS::test_import_key_rsa_aes_wrap_sha256": 1.6386584730000777, - "tests/aws/services/kms/test_kms.py::TestKMS::test_import_key_symmetric": 0.27750495400005093, - "tests/aws/services/kms/test_kms.py::TestKMS::test_invalid_generate_mac[HMAC_224-HMAC_SHA_256]": 0.10079854299999624, - "tests/aws/services/kms/test_kms.py::TestKMS::test_invalid_generate_mac[HMAC_256-INVALID]": 0.10167644800003472, - "tests/aws/services/kms/test_kms.py::TestKMS::test_invalid_key_usage": 0.6728558320000957, - "tests/aws/services/kms/test_kms.py::TestKMS::test_invalid_verify_mac[HMAC_256-HMAC_SHA_256-some different important message]": 0.18559989500010943, - "tests/aws/services/kms/test_kms.py::TestKMS::test_invalid_verify_mac[HMAC_256-HMAC_SHA_512-some important message]": 0.18567176800002017, - "tests/aws/services/kms/test_kms.py::TestKMS::test_invalid_verify_mac[HMAC_256-INVALID-some important message]": 0.18439888800014614, - "tests/aws/services/kms/test_kms.py::TestKMS::test_key_enable_rotation_status[180]": 0.10737989599999764, - "tests/aws/services/kms/test_kms.py::TestKMS::test_key_enable_rotation_status[90]": 0.10857957499990789, - "tests/aws/services/kms/test_kms.py::TestKMS::test_key_rotation_status": 0.07201187700002265, - "tests/aws/services/kms/test_kms.py::TestKMS::test_key_rotations_encryption_decryption": 0.16545787499990183, - "tests/aws/services/kms/test_kms.py::TestKMS::test_key_rotations_limits": 0.22999294900000677, - "tests/aws/services/kms/test_kms.py::TestKMS::test_key_with_long_tag_value_raises_error": 0.08943705199988017, - "tests/aws/services/kms/test_kms.py::TestKMS::test_list_aliases_of_key": 0.0655324000000519, - "tests/aws/services/kms/test_kms.py::TestKMS::test_list_grants_with_invalid_key": 0.013774266999917018, - "tests/aws/services/kms/test_kms.py::TestKMS::test_list_keys": 0.027745378999952663, - "tests/aws/services/kms/test_kms.py::TestKMS::test_list_retirable_grants": 0.07157103800000186, - "tests/aws/services/kms/test_kms.py::TestKMS::test_non_multi_region_keys_should_not_have_multi_region_properties": 0.16601549899985457, - "tests/aws/services/kms/test_kms.py::TestKMS::test_plaintext_size_for_encrypt": 0.10368295700016006, - "tests/aws/services/kms/test_kms.py::TestKMS::test_re_encrypt[RSA_2048-RSAES_OAEP_SHA_256]": 0.2804587239999137, - "tests/aws/services/kms/test_kms.py::TestKMS::test_re_encrypt[SYMMETRIC_DEFAULT-SYMMETRIC_DEFAULT]": 0.13531915300018227, - "tests/aws/services/kms/test_kms.py::TestKMS::test_re_encrypt_incorrect_source_key": 0.12365546800003813, - "tests/aws/services/kms/test_kms.py::TestKMS::test_re_encrypt_invalid_destination_key": 0.04866335899987462, - "tests/aws/services/kms/test_kms.py::TestKMS::test_replicate_key": 0.5180274849999478, - "tests/aws/services/kms/test_kms.py::TestKMS::test_retire_grant_with_grant_id_and_key_id": 0.059325762999947074, - "tests/aws/services/kms/test_kms.py::TestKMS::test_retire_grant_with_grant_token": 0.06090419399993152, - "tests/aws/services/kms/test_kms.py::TestKMS::test_revoke_grant": 0.06254979099992397, - "tests/aws/services/kms/test_kms.py::TestKMS::test_rotate_key_on_demand_modifies_key_material": 0.11332300200001555, - "tests/aws/services/kms/test_kms.py::TestKMS::test_rotate_key_on_demand_raises_error_given_key_is_disabled": 0.5664265539999178, - "tests/aws/services/kms/test_kms.py::TestKMS::test_rotate_key_on_demand_raises_error_given_key_that_does_not_exist": 0.0864451969999891, - "tests/aws/services/kms/test_kms.py::TestKMS::test_rotate_key_on_demand_raises_error_given_key_with_imported_key_material": 0.0017990689999578535, - "tests/aws/services/kms/test_kms.py::TestKMS::test_rotate_key_on_demand_raises_error_given_non_symmetric_key": 0.5849426839998841, - "tests/aws/services/kms/test_kms.py::TestKMS::test_rotate_key_on_demand_with_symmetric_key_and_automatic_rotation_disabled": 0.1153067430000192, - "tests/aws/services/kms/test_kms.py::TestKMS::test_rotate_key_on_demand_with_symmetric_key_and_automatic_rotation_enabled": 0.13785008700006074, - "tests/aws/services/kms/test_kms.py::TestKMS::test_schedule_and_cancel_key_deletion": 0.04960705100006635, - "tests/aws/services/kms/test_kms.py::TestKMS::test_sign_verify[ECC_NIST_P256-ECDSA_SHA_256]": 0.3084969579999779, - "tests/aws/services/kms/test_kms.py::TestKMS::test_sign_verify[ECC_NIST_P384-ECDSA_SHA_384]": 0.3226419039999655, - "tests/aws/services/kms/test_kms.py::TestKMS::test_sign_verify[ECC_SECG_P256K1-ECDSA_SHA_256]": 0.3502272489999996, - "tests/aws/services/kms/test_kms.py::TestKMS::test_sign_verify[RSA_2048-RSASSA_PSS_SHA_256]": 0.7342729570000301, - "tests/aws/services/kms/test_kms.py::TestKMS::test_sign_verify[RSA_2048-RSASSA_PSS_SHA_384]": 0.7803146109999943, - "tests/aws/services/kms/test_kms.py::TestKMS::test_sign_verify[RSA_2048-RSASSA_PSS_SHA_512]": 0.7256653949999645, - "tests/aws/services/kms/test_kms.py::TestKMS::test_sign_verify[RSA_4096-RSASSA_PKCS1_V1_5_SHA_256]": 3.3532967489999237, - "tests/aws/services/kms/test_kms.py::TestKMS::test_sign_verify[RSA_4096-RSASSA_PKCS1_V1_5_SHA_512]": 3.5970434040001464, - "tests/aws/services/kms/test_kms.py::TestKMS::test_symmetric_encrypt_offline_decrypt_online[RSA_2048-RSAES_OAEP_SHA_1]": 0.12813328799995816, - "tests/aws/services/kms/test_kms.py::TestKMS::test_symmetric_encrypt_offline_decrypt_online[RSA_2048-RSAES_OAEP_SHA_256]": 0.09058831800007283, - "tests/aws/services/kms/test_kms.py::TestKMS::test_symmetric_encrypt_offline_decrypt_online[RSA_3072-RSAES_OAEP_SHA_1]": 0.3442894550000801, - "tests/aws/services/kms/test_kms.py::TestKMS::test_symmetric_encrypt_offline_decrypt_online[RSA_3072-RSAES_OAEP_SHA_256]": 0.2646071879998999, - "tests/aws/services/kms/test_kms.py::TestKMS::test_symmetric_encrypt_offline_decrypt_online[RSA_4096-RSAES_OAEP_SHA_1]": 0.7939000520000263, - "tests/aws/services/kms/test_kms.py::TestKMS::test_symmetric_encrypt_offline_decrypt_online[RSA_4096-RSAES_OAEP_SHA_256]": 0.6086602380000841, - "tests/aws/services/kms/test_kms.py::TestKMS::test_tag_existing_key_and_untag": 0.12257197899998573, - "tests/aws/services/kms/test_kms.py::TestKMS::test_tag_existing_key_with_invalid_tag_key": 0.10421535600005427, - "tests/aws/services/kms/test_kms.py::TestKMS::test_tag_key_with_duplicate_tag_keys_raises_error": 0.10347335099982047, - "tests/aws/services/kms/test_kms.py::TestKMS::test_unsupported_rotate_key_on_demand_with_imported_key_material": 0.02872415000001638, - "tests/aws/services/kms/test_kms.py::TestKMS::test_untag_key_partially": 0.11565662700002122, - "tests/aws/services/kms/test_kms.py::TestKMS::test_update_alias": 0.06754520499998762, - "tests/aws/services/kms/test_kms.py::TestKMS::test_update_and_add_tags_on_tagged_key": 0.11862838599995484, - "tests/aws/services/kms/test_kms.py::TestKMS::test_update_key_description": 0.048149922999982664, - "tests/aws/services/kms/test_kms.py::TestKMS::test_verify_salt_length[ECC_NIST_P256-ECDSA_SHA_256]": 0.04296925799997098, - "tests/aws/services/kms/test_kms.py::TestKMS::test_verify_salt_length[ECC_NIST_P384-ECDSA_SHA_384]": 0.044260059000066576, - "tests/aws/services/kms/test_kms.py::TestKMS::test_verify_salt_length[ECC_SECG_P256K1-ECDSA_SHA_256]": 0.04383642600009807, - "tests/aws/services/kms/test_kms.py::TestKMS::test_verify_salt_length[RSA_2048-RSASSA_PSS_SHA_256]": 0.16822119699986615, - "tests/aws/services/kms/test_kms.py::TestKMS::test_verify_salt_length[RSA_2048-RSASSA_PSS_SHA_384]": 0.1611335519999102, - "tests/aws/services/kms/test_kms.py::TestKMS::test_verify_salt_length[RSA_2048-RSASSA_PSS_SHA_512]": 0.16607341700000688, - "tests/aws/services/kms/test_kms.py::TestKMS::test_verify_salt_length[RSA_4096-RSASSA_PKCS1_V1_5_SHA_256]": 1.0148265640000318, - "tests/aws/services/kms/test_kms.py::TestKMS::test_verify_salt_length[RSA_4096-RSASSA_PKCS1_V1_5_SHA_512]": 1.380871506000176, - "tests/aws/services/kms/test_kms.py::TestKMSGenerateKeys::test_encryption_context_generate_data_key": 0.18266957799994543, - "tests/aws/services/kms/test_kms.py::TestKMSGenerateKeys::test_encryption_context_generate_data_key_pair": 0.18865451100009523, - "tests/aws/services/kms/test_kms.py::TestKMSGenerateKeys::test_encryption_context_generate_data_key_pair_without_plaintext": 0.14129084800003966, - "tests/aws/services/kms/test_kms.py::TestKMSGenerateKeys::test_encryption_context_generate_data_key_without_plaintext": 0.1807960499999126, - "tests/aws/services/kms/test_kms.py::TestKMSGenerateKeys::test_generate_data_key": 0.03744241899994449, - "tests/aws/services/kms/test_kms.py::TestKMSGenerateKeys::test_generate_data_key_pair": 0.06829658900005597, - "tests/aws/services/kms/test_kms.py::TestKMSGenerateKeys::test_generate_data_key_pair_dry_run": 0.03220412899997882, - "tests/aws/services/kms/test_kms.py::TestKMSGenerateKeys::test_generate_data_key_pair_without_plaintext": 0.04889024400006292, - "tests/aws/services/kms/test_kms.py::TestKMSGenerateKeys::test_generate_data_key_pair_without_plaintext_dry_run": 0.08191053699988515, - "tests/aws/services/kms/test_kms.py::TestKMSGenerateKeys::test_generate_data_key_without_plaintext": 0.0314207849999093, - "tests/aws/services/kms/test_kms.py::TestKMSMultiAccounts::test_cross_accounts_access": 1.7503523690000975, - "tests/aws/services/lambda_/event_source_mapping/test_cfn_resource.py::test_adding_tags": 17.624486023999907, - "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_dynamodbstreams.py::TestDynamoDBEventSourceMapping::test_deletion_event_source_mapping_with_dynamodb": 6.19299654800011, - "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_dynamodbstreams.py::TestDynamoDBEventSourceMapping::test_disabled_dynamodb_event_source_mapping": 12.275834105000058, - "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_dynamodbstreams.py::TestDynamoDBEventSourceMapping::test_duplicate_event_source_mappings": 5.662659266999981, - "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_dynamodbstreams.py::TestDynamoDBEventSourceMapping::test_dynamodb_event_filter[content_filter_type]": 13.802188496999975, - "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_dynamodbstreams.py::TestDynamoDBEventSourceMapping::test_dynamodb_event_filter[content_multiple_filters]": 0.004389595999896301, - "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_dynamodbstreams.py::TestDynamoDBEventSourceMapping::test_dynamodb_event_filter[content_or_filter]": 12.838126037999928, - "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_dynamodbstreams.py::TestDynamoDBEventSourceMapping::test_dynamodb_event_filter[date_time_conversion]": 12.804712613000106, - "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_dynamodbstreams.py::TestDynamoDBEventSourceMapping::test_dynamodb_event_filter[exists_false_filter]": 12.776339392999944, - "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_dynamodbstreams.py::TestDynamoDBEventSourceMapping::test_dynamodb_event_filter[exists_filter_type]": 12.808232432000068, - "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_dynamodbstreams.py::TestDynamoDBEventSourceMapping::test_dynamodb_event_filter[insert_same_entry_twice]": 12.745544434999942, - "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_dynamodbstreams.py::TestDynamoDBEventSourceMapping::test_dynamodb_event_filter[numeric_filter]": 12.79569215299989, - "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_dynamodbstreams.py::TestDynamoDBEventSourceMapping::test_dynamodb_event_filter[prefix_filter]": 12.877754073999995, - "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_dynamodbstreams.py::TestDynamoDBEventSourceMapping::test_dynamodb_event_source_mapping": 14.808580451999887, - "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_dynamodbstreams.py::TestDynamoDBEventSourceMapping::test_dynamodb_event_source_mapping_with_on_failure_destination_config": 11.370671504000029, - "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_dynamodbstreams.py::TestDynamoDBEventSourceMapping::test_dynamodb_event_source_mapping_with_s3_on_failure_destination": 11.519753707000064, - "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_dynamodbstreams.py::TestDynamoDBEventSourceMapping::test_dynamodb_event_source_mapping_with_sns_on_failure_destination_config": 11.36489800400011, - "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_dynamodbstreams.py::TestDynamoDBEventSourceMapping::test_dynamodb_invalid_event_filter[[{\"eventName\": [\"INSERT\"=123}]]": 4.546579078000036, - "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_dynamodbstreams.py::TestDynamoDBEventSourceMapping::test_dynamodb_invalid_event_filter[single-string]": 4.567929847000073, - "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_dynamodbstreams.py::TestDynamoDBEventSourceMapping::test_dynamodb_report_batch_item_failure_scenarios[empty_string_item_identifier_failure]": 14.801936470999976, - "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_dynamodbstreams.py::TestDynamoDBEventSourceMapping::test_dynamodb_report_batch_item_failure_scenarios[invalid_key_foo_failure]": 14.824406479000572, - "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_dynamodbstreams.py::TestDynamoDBEventSourceMapping::test_dynamodb_report_batch_item_failure_scenarios[invalid_key_foo_null_value_failure]": 14.79767732099981, - "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_dynamodbstreams.py::TestDynamoDBEventSourceMapping::test_dynamodb_report_batch_item_failure_scenarios[item_identifier_not_present_failure]": 14.923005761000127, - "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_dynamodbstreams.py::TestDynamoDBEventSourceMapping::test_dynamodb_report_batch_item_failure_scenarios[null_item_identifier_failure]": 14.7953780429998, - "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_dynamodbstreams.py::TestDynamoDBEventSourceMapping::test_dynamodb_report_batch_item_failure_scenarios[unhandled_exception_in_function]": 15.828741327999978, - "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_dynamodbstreams.py::TestDynamoDBEventSourceMapping::test_dynamodb_report_batch_item_failures": 15.131787730000042, - "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_dynamodbstreams.py::TestDynamoDBEventSourceMapping::test_dynamodb_report_batch_item_success_scenarios[empty_batch_item_failure_success]": 9.826323532000288, - "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_dynamodbstreams.py::TestDynamoDBEventSourceMapping::test_dynamodb_report_batch_item_success_scenarios[empty_dict_success]": 9.824114839999993, - "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_dynamodbstreams.py::TestDynamoDBEventSourceMapping::test_dynamodb_report_batch_item_success_scenarios[empty_list_success]": 9.797083228999782, - "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_dynamodbstreams.py::TestDynamoDBEventSourceMapping::test_dynamodb_report_batch_item_success_scenarios[null_batch_item_failure_success]": 9.800503420000041, - "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_dynamodbstreams.py::TestDynamoDBEventSourceMapping::test_dynamodb_report_batch_item_success_scenarios[null_success]": 9.780069302999891, - "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_dynamodbstreams.py::TestDynamoDBEventSourceMapping::test_esm_with_not_existing_dynamodb_stream": 1.8316574250001167, - "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_kinesis.py::TestKinesisEventFiltering::test_kinesis_event_filtering_json_pattern": 9.283777827999756, - "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_kinesis.py::TestKinesisSource::test_create_kinesis_event_source_mapping": 12.115603054000303, - "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_kinesis.py::TestKinesisSource::test_create_kinesis_event_source_mapping_multiple_lambdas_single_kinesis_event_stream": 19.454714443000057, - "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_kinesis.py::TestKinesisSource::test_disable_kinesis_event_source_mapping": 29.285736556999836, - "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_kinesis.py::TestKinesisSource::test_duplicate_event_source_mappings": 3.424139316999799, - "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_kinesis.py::TestKinesisSource::test_esm_with_not_existing_kinesis_stream": 1.4152245800000856, - "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_kinesis.py::TestKinesisSource::test_kinesis_empty_provided": 11.273842872999921, - "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_kinesis.py::TestKinesisSource::test_kinesis_event_source_mapping_with_async_invocation": 20.17905410200001, - "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_kinesis.py::TestKinesisSource::test_kinesis_event_source_mapping_with_on_failure_destination_config": 9.21085841199988, - "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_kinesis.py::TestKinesisSource::test_kinesis_event_source_mapping_with_s3_on_failure_destination": 9.257189130000143, - "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_kinesis.py::TestKinesisSource::test_kinesis_event_source_mapping_with_sns_on_failure_destination_config": 9.251956784000186, - "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_kinesis.py::TestKinesisSource::test_kinesis_event_source_trim_horizon": 26.293055673000026, - "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_kinesis.py::TestKinesisSource::test_kinesis_maximum_record_age_exceeded[expire-before-ingestion]": 14.34083868100015, - "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_kinesis.py::TestKinesisSource::test_kinesis_maximum_record_age_exceeded[expire-while-retrying]": 9.365708785999914, - "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_kinesis.py::TestKinesisSource::test_kinesis_maximum_record_age_exceeded_discard_records": 19.38347986200006, - "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_kinesis.py::TestKinesisSource::test_kinesis_report_batch_item_failure_scenarios[empty_string_item_identifier_failure]": 12.2159465000002, - "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_kinesis.py::TestKinesisSource::test_kinesis_report_batch_item_failure_scenarios[invalid_key_foo_failure]": 12.18609163300016, - "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_kinesis.py::TestKinesisSource::test_kinesis_report_batch_item_failure_scenarios[invalid_key_foo_null_value_failure]": 13.217594300999963, - "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_kinesis.py::TestKinesisSource::test_kinesis_report_batch_item_failure_scenarios[item_identifier_not_present_failure]": 12.16656018100025, - "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_kinesis.py::TestKinesisSource::test_kinesis_report_batch_item_failure_scenarios[null_item_identifier_failure]": 12.17546643500009, - "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_kinesis.py::TestKinesisSource::test_kinesis_report_batch_item_failure_scenarios[unhandled_exception_in_function]": 12.17608245400038, - "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_kinesis.py::TestKinesisSource::test_kinesis_report_batch_item_failures": 12.298094092999918, - "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_kinesis.py::TestKinesisSource::test_kinesis_report_batch_item_success_scenarios[empty_batch_item_failure_success]": 7.15046417900021, - "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_kinesis.py::TestKinesisSource::test_kinesis_report_batch_item_success_scenarios[empty_dict_success]": 7.134511203000102, - "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_kinesis.py::TestKinesisSource::test_kinesis_report_batch_item_success_scenarios[empty_list_success]": 7.153358449000052, - "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_kinesis.py::TestKinesisSource::test_kinesis_report_batch_item_success_scenarios[empty_string_success]": 7.1324555740002324, - "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_kinesis.py::TestKinesisSource::test_kinesis_report_batch_item_success_scenarios[null_batch_item_failure_success]": 7.14277735099995, - "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_kinesis.py::TestKinesisSource::test_kinesis_report_batch_item_success_scenarios[null_success]": 7.152563771000359, - "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_sqs.py::TestSQSEventSourceMapping::test_duplicate_event_source_mappings": 2.6862398719999874, - "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_sqs.py::TestSQSEventSourceMapping::test_event_source_mapping_default_batch_size": 3.50781076699991, - "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_sqs.py::TestSQSEventSourceMapping::test_sqs_event_filter[and]": 6.468163141000105, - "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_sqs.py::TestSQSEventSourceMapping::test_sqs_event_filter[exists]": 6.469832829000097, - "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_sqs.py::TestSQSEventSourceMapping::test_sqs_event_filter[numeric-bigger]": 6.465654663999885, - "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_sqs.py::TestSQSEventSourceMapping::test_sqs_event_filter[numeric-range]": 6.4638559949999035, - "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_sqs.py::TestSQSEventSourceMapping::test_sqs_event_filter[numeric-smaller]": 6.472548658000051, - "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_sqs.py::TestSQSEventSourceMapping::test_sqs_event_filter[or]": 6.446740188999911, - "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_sqs.py::TestSQSEventSourceMapping::test_sqs_event_filter[plain-string-filter]": 0.0023833000002468907, - "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_sqs.py::TestSQSEventSourceMapping::test_sqs_event_filter[plain-string-matching]": 0.00274867300004189, - "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_sqs.py::TestSQSEventSourceMapping::test_sqs_event_filter[prefix]": 6.458606656999564, - "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_sqs.py::TestSQSEventSourceMapping::test_sqs_event_filter[single]": 6.472418349999998, - "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_sqs.py::TestSQSEventSourceMapping::test_sqs_event_filter[valid-json-filter]": 6.47676031900005, - "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_sqs.py::TestSQSEventSourceMapping::test_sqs_event_source_mapping": 6.434796558000016, - "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_sqs.py::TestSQSEventSourceMapping::test_sqs_event_source_mapping_batch_size[10000]": 9.6722657790001, - "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_sqs.py::TestSQSEventSourceMapping::test_sqs_event_source_mapping_batch_size[1000]": 10.78993156599995, - "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_sqs.py::TestSQSEventSourceMapping::test_sqs_event_source_mapping_batch_size[100]": 9.609503067999867, - "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_sqs.py::TestSQSEventSourceMapping::test_sqs_event_source_mapping_batch_size[15]": 9.604970559999856, - "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_sqs.py::TestSQSEventSourceMapping::test_sqs_event_source_mapping_batch_size_override[10000]": 0.020502711000062845, - "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_sqs.py::TestSQSEventSourceMapping::test_sqs_event_source_mapping_batch_size_override[1000]": 9.166082406000214, - "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_sqs.py::TestSQSEventSourceMapping::test_sqs_event_source_mapping_batch_size_override[100]": 6.749473818000297, - "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_sqs.py::TestSQSEventSourceMapping::test_sqs_event_source_mapping_batch_size_override[20]": 6.554918944000292, - "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_sqs.py::TestSQSEventSourceMapping::test_sqs_event_source_mapping_batching_reserved_concurrency": 8.711148799000057, - "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_sqs.py::TestSQSEventSourceMapping::test_sqs_event_source_mapping_batching_window_size_override": 27.959545613999808, - "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_sqs.py::TestSQSEventSourceMapping::test_sqs_event_source_mapping_update": 11.760441669999864, - "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_sqs.py::TestSQSEventSourceMapping::test_sqs_invalid_event_filter[None]": 1.2588273389999358, - "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_sqs.py::TestSQSEventSourceMapping::test_sqs_invalid_event_filter[invalid_filter2]": 1.2571155830000862, - "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_sqs.py::TestSQSEventSourceMapping::test_sqs_invalid_event_filter[invalid_filter3]": 1.2630294319999393, - "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_sqs.py::TestSQSEventSourceMapping::test_sqs_invalid_event_filter[simple string]": 1.2291774210000312, - "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_sqs.py::test_esm_with_not_existing_sqs_queue": 1.2083949099996971, - "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_sqs.py::test_failing_lambda_retries_after_visibility_timeout": 18.318848712999852, - "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_sqs.py::test_fifo_message_group_parallelism": 63.555022905000214, - "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_sqs.py::test_message_body_and_attributes_passed_correctly": 4.878457930999957, - "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_sqs.py::test_redrive_policy_with_failing_lambda": 21.185542614999804, - "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_sqs.py::test_report_batch_item_failures": 0.0033532509999076865, - "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_sqs.py::test_report_batch_item_failures_empty_json_batch_succeeds": 10.423626042000024, - "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_sqs.py::test_report_batch_item_failures_invalid_result_json_batch_fails": 14.558000567999898, - "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_sqs.py::test_report_batch_item_failures_on_lambda_error": 8.386975298000152, - "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_sqs.py::test_sqs_queue_as_lambda_dead_letter_queue": 6.302318438000157, - "tests/aws/services/lambda_/test_lambda.py::TestLambdaAliases::test_alias_routingconfig": 3.4572980980001375, - "tests/aws/services/lambda_/test_lambda.py::TestLambdaAliases::test_lambda_alias_moving": 3.4241600319996905, - "tests/aws/services/lambda_/test_lambda.py::TestLambdaBaseFeatures::test_assume_role[1]": 1.7310953989997415, - "tests/aws/services/lambda_/test_lambda.py::TestLambdaBaseFeatures::test_assume_role[2]": 1.7636844140001813, - "tests/aws/services/lambda_/test_lambda.py::TestLambdaBaseFeatures::test_function_state": 1.2475779830001557, - "tests/aws/services/lambda_/test_lambda.py::TestLambdaBaseFeatures::test_lambda_different_iam_keys_environment": 3.817614532999869, - "tests/aws/services/lambda_/test_lambda.py::TestLambdaBaseFeatures::test_lambda_large_response": 1.6518399650001356, - "tests/aws/services/lambda_/test_lambda.py::TestLambdaBaseFeatures::test_lambda_too_large_response": 1.8778853839999101, - "tests/aws/services/lambda_/test_lambda.py::TestLambdaBaseFeatures::test_lambda_too_large_response_but_with_custom_limit": 1.6020009239998672, - "tests/aws/services/lambda_/test_lambda.py::TestLambdaBaseFeatures::test_large_payloads": 1.9492293410000912, - "tests/aws/services/lambda_/test_lambda.py::TestLambdaBehavior::test_ignore_architecture": 1.567431039000212, - "tests/aws/services/lambda_/test_lambda.py::TestLambdaBehavior::test_lambda_cache_local[nodejs]": 7.720558855000263, - "tests/aws/services/lambda_/test_lambda.py::TestLambdaBehavior::test_lambda_cache_local[python]": 1.7015508580000187, - "tests/aws/services/lambda_/test_lambda.py::TestLambdaBehavior::test_lambda_host_prefix_api_operation": 12.493829206999862, - "tests/aws/services/lambda_/test_lambda.py::TestLambdaBehavior::test_lambda_init_environment": 3.7518186830000104, - "tests/aws/services/lambda_/test_lambda.py::TestLambdaBehavior::test_lambda_invoke_no_timeout": 3.6618932820001646, - "tests/aws/services/lambda_/test_lambda.py::TestLambdaBehavior::test_lambda_invoke_timed_out_environment_reuse": 0.0027936359999785054, - "tests/aws/services/lambda_/test_lambda.py::TestLambdaBehavior::test_lambda_invoke_with_timeout": 3.653631373000053, - "tests/aws/services/lambda_/test_lambda.py::TestLambdaBehavior::test_mixed_architecture": 0.0030195399999684014, - "tests/aws/services/lambda_/test_lambda.py::TestLambdaBehavior::test_runtime_introspection_arm": 0.002470183000241377, - "tests/aws/services/lambda_/test_lambda.py::TestLambdaBehavior::test_runtime_introspection_x86": 1.8399834310000642, - "tests/aws/services/lambda_/test_lambda.py::TestLambdaBehavior::test_runtime_ulimits": 1.6055801300001349, - "tests/aws/services/lambda_/test_lambda.py::TestLambdaCleanup::test_delete_lambda_during_sync_invoke": 0.0018091669999193982, - "tests/aws/services/lambda_/test_lambda.py::TestLambdaCleanup::test_recreate_function": 3.4136111319999145, - "tests/aws/services/lambda_/test_lambda.py::TestLambdaConcurrency::test_lambda_concurrency_block": 22.976070697999603, - "tests/aws/services/lambda_/test_lambda.py::TestLambdaConcurrency::test_lambda_concurrency_crud": 1.238109943000154, - "tests/aws/services/lambda_/test_lambda.py::TestLambdaConcurrency::test_lambda_concurrency_update": 1.3820693510001547, - "tests/aws/services/lambda_/test_lambda.py::TestLambdaConcurrency::test_lambda_provisioned_concurrency_moves_with_alias": 0.002998658000251453, - "tests/aws/services/lambda_/test_lambda.py::TestLambdaConcurrency::test_lambda_provisioned_concurrency_scheduling": 8.519994414999474, - "tests/aws/services/lambda_/test_lambda.py::TestLambdaConcurrency::test_provisioned_concurrency": 2.9477010430005066, - "tests/aws/services/lambda_/test_lambda.py::TestLambdaConcurrency::test_provisioned_concurrency_on_alias": 2.949256795999645, - "tests/aws/services/lambda_/test_lambda.py::TestLambdaConcurrency::test_reserved_concurrency": 12.184792133999963, - "tests/aws/services/lambda_/test_lambda.py::TestLambdaConcurrency::test_reserved_concurrency_async_queue": 3.102242474000377, - "tests/aws/services/lambda_/test_lambda.py::TestLambdaConcurrency::test_reserved_provisioned_overlap": 10.54315867699961, - "tests/aws/services/lambda_/test_lambda.py::TestLambdaErrors::test_lambda_handler_error": 1.5845099570001366, - "tests/aws/services/lambda_/test_lambda.py::TestLambdaErrors::test_lambda_handler_exit": 0.002975837000121828, - "tests/aws/services/lambda_/test_lambda.py::TestLambdaErrors::test_lambda_invoke_payload_encoding_error[body-n\\x87r\\x9e\\xe9\\xb5\\xd7I\\xee\\x9bmt]": 1.3619020150001688, - "tests/aws/services/lambda_/test_lambda.py::TestLambdaErrors::test_lambda_invoke_payload_encoding_error[message-\\x99\\xeb,j\\x07\\xa1zYh]": 1.3654869970000618, - "tests/aws/services/lambda_/test_lambda.py::TestLambdaErrors::test_lambda_runtime_error": 15.688763144999939, - "tests/aws/services/lambda_/test_lambda.py::TestLambdaErrors::test_lambda_runtime_exit": 0.001797015999954965, - "tests/aws/services/lambda_/test_lambda.py::TestLambdaErrors::test_lambda_runtime_exit_segfault": 0.001712428000246291, - "tests/aws/services/lambda_/test_lambda.py::TestLambdaErrors::test_lambda_runtime_startup_error": 1.8712039270001242, - "tests/aws/services/lambda_/test_lambda.py::TestLambdaErrors::test_lambda_runtime_startup_timeout": 42.04348754800003, - "tests/aws/services/lambda_/test_lambda.py::TestLambdaErrors::test_lambda_runtime_wrapper_not_found": 0.0024339050000889983, - "tests/aws/services/lambda_/test_lambda.py::TestLambdaFeatures::test_invocation_type_dry_run[nodejs16.x]": 0.00248174100011056, - "tests/aws/services/lambda_/test_lambda.py::TestLambdaFeatures::test_invocation_type_dry_run[python3.10]": 0.002342932999908953, - "tests/aws/services/lambda_/test_lambda.py::TestLambdaFeatures::test_invocation_type_event[nodejs16.x]": 3.437340162999817, - "tests/aws/services/lambda_/test_lambda.py::TestLambdaFeatures::test_invocation_type_event[python3.10]": 2.2943164299999808, - "tests/aws/services/lambda_/test_lambda.py::TestLambdaFeatures::test_invocation_type_event_error": 0.0021061410002403136, - "tests/aws/services/lambda_/test_lambda.py::TestLambdaFeatures::test_invocation_type_no_return_payload[nodejs-Event]": 2.2956115510000927, - "tests/aws/services/lambda_/test_lambda.py::TestLambdaFeatures::test_invocation_type_no_return_payload[nodejs-RequestResponse]": 2.6535891129997253, - "tests/aws/services/lambda_/test_lambda.py::TestLambdaFeatures::test_invocation_type_no_return_payload[python-Event]": 2.2909321780000482, - "tests/aws/services/lambda_/test_lambda.py::TestLambdaFeatures::test_invocation_type_no_return_payload[python-RequestResponse]": 2.5988212780000595, - "tests/aws/services/lambda_/test_lambda.py::TestLambdaFeatures::test_invocation_type_request_response[nodejs16.x]": 1.6183011689997784, - "tests/aws/services/lambda_/test_lambda.py::TestLambdaFeatures::test_invocation_type_request_response[python3.10]": 1.598229647000153, - "tests/aws/services/lambda_/test_lambda.py::TestLambdaFeatures::test_invocation_with_logs[nodejs16.x]": 15.757359547000078, - "tests/aws/services/lambda_/test_lambda.py::TestLambdaFeatures::test_invocation_with_logs[python3.10]": 7.703464147999966, - "tests/aws/services/lambda_/test_lambda.py::TestLambdaFeatures::test_invocation_with_qualifier": 1.865727361000154, - "tests/aws/services/lambda_/test_lambda.py::TestLambdaFeatures::test_invoke_exceptions": 0.11396346200012886, - "tests/aws/services/lambda_/test_lambda.py::TestLambdaFeatures::test_lambda_with_context": 0.0043954749999102205, - "tests/aws/services/lambda_/test_lambda.py::TestLambdaFeatures::test_upload_lambda_from_s3": 2.1748799169999984, - "tests/aws/services/lambda_/test_lambda.py::TestLambdaMultiAccounts::test_delete_function": 1.146606324000004, - "tests/aws/services/lambda_/test_lambda.py::TestLambdaMultiAccounts::test_function_alias": 1.182883647999688, - "tests/aws/services/lambda_/test_lambda.py::TestLambdaMultiAccounts::test_function_concurrency": 1.136422722999896, - "tests/aws/services/lambda_/test_lambda.py::TestLambdaMultiAccounts::test_function_invocation": 1.5348097480000433, - "tests/aws/services/lambda_/test_lambda.py::TestLambdaMultiAccounts::test_function_tags": 1.1615051050000602, - "tests/aws/services/lambda_/test_lambda.py::TestLambdaMultiAccounts::test_get_function": 1.1606004329998996, - "tests/aws/services/lambda_/test_lambda.py::TestLambdaMultiAccounts::test_get_function_configuration": 1.1497980789997655, - "tests/aws/services/lambda_/test_lambda.py::TestLambdaMultiAccounts::test_get_lambda_layer": 0.10919015900003615, - "tests/aws/services/lambda_/test_lambda.py::TestLambdaMultiAccounts::test_list_versions_by_function": 1.1475857409998298, - "tests/aws/services/lambda_/test_lambda.py::TestLambdaMultiAccounts::test_publish_version": 1.2170958679996602, - "tests/aws/services/lambda_/test_lambda.py::TestLambdaPermissions::test_lambda_permission_url_invocation": 0.0030424709998442268, - "tests/aws/services/lambda_/test_lambda.py::TestLambdaURL::test_function_url_with_response_streaming": 7.94717510800001, - "tests/aws/services/lambda_/test_lambda.py::TestLambdaURL::test_lambda_update_function_url_config": 1.5272616319998633, - "tests/aws/services/lambda_/test_lambda.py::TestLambdaURL::test_lambda_url_echo_http_fixture_default": 2.1435976480001955, - "tests/aws/services/lambda_/test_lambda.py::TestLambdaURL::test_lambda_url_echo_http_fixture_trim_x_headers": 1.9750401030003104, - "tests/aws/services/lambda_/test_lambda.py::TestLambdaURL::test_lambda_url_echo_invoke[BUFFERED]": 1.9550992150000184, - "tests/aws/services/lambda_/test_lambda.py::TestLambdaURL::test_lambda_url_echo_invoke[None]": 1.9509504599998309, - "tests/aws/services/lambda_/test_lambda.py::TestLambdaURL::test_lambda_url_echo_invoke[RESPONSE_STREAM]": 0.01313979599990489, - "tests/aws/services/lambda_/test_lambda.py::TestLambdaURL::test_lambda_url_form_payload": 1.9323509879998255, - "tests/aws/services/lambda_/test_lambda.py::TestLambdaURL::test_lambda_url_headers_and_status": 1.6303213359999518, - "tests/aws/services/lambda_/test_lambda.py::TestLambdaURL::test_lambda_url_invalid_invoke_mode": 1.4328448290002598, - "tests/aws/services/lambda_/test_lambda.py::TestLambdaURL::test_lambda_url_invocation[boolean]": 1.864371162999987, - "tests/aws/services/lambda_/test_lambda.py::TestLambdaURL::test_lambda_url_invocation[dict]": 1.893594500000063, - "tests/aws/services/lambda_/test_lambda.py::TestLambdaURL::test_lambda_url_invocation[float]": 1.883184361000076, - "tests/aws/services/lambda_/test_lambda.py::TestLambdaURL::test_lambda_url_invocation[http-response-json]": 1.8972898930001065, - "tests/aws/services/lambda_/test_lambda.py::TestLambdaURL::test_lambda_url_invocation[http-response]": 1.8530431639999279, - "tests/aws/services/lambda_/test_lambda.py::TestLambdaURL::test_lambda_url_invocation[integer]": 1.9129134770000746, - "tests/aws/services/lambda_/test_lambda.py::TestLambdaURL::test_lambda_url_invocation[list-mixed]": 1.8692261449998568, - "tests/aws/services/lambda_/test_lambda.py::TestLambdaURL::test_lambda_url_invocation[string]": 1.84680275300002, - "tests/aws/services/lambda_/test_lambda.py::TestLambdaURL::test_lambda_url_invocation_custom_id": 1.5701736870000786, - "tests/aws/services/lambda_/test_lambda.py::TestLambdaURL::test_lambda_url_invocation_custom_id_aliased": 1.5773605409997344, - "tests/aws/services/lambda_/test_lambda.py::TestLambdaURL::test_lambda_url_invocation_exception": 1.8793250620001345, - "tests/aws/services/lambda_/test_lambda.py::TestLambdaURL::test_lambda_url_non_existing_url": 0.01757739300001049, - "tests/aws/services/lambda_/test_lambda.py::TestLambdaURL::test_lambda_url_persists_after_alias_delete": 3.9361692420000054, - "tests/aws/services/lambda_/test_lambda.py::TestLambdaVersions::test_async_invoke_queue_upon_function_update": 98.77122390400018, - "tests/aws/services/lambda_/test_lambda.py::TestLambdaVersions::test_function_update_during_invoke": 0.0019901869995919697, - "tests/aws/services/lambda_/test_lambda.py::TestLambdaVersions::test_lambda_handler_update": 3.20468677900044, - "tests/aws/services/lambda_/test_lambda.py::TestLambdaVersions::test_lambda_versions_with_code_changes": 5.606115082000088, - "tests/aws/services/lambda_/test_lambda.py::TestRequestIdHandling::test_request_id_async_invoke_with_retry": 11.272501723000005, - "tests/aws/services/lambda_/test_lambda.py::TestRequestIdHandling::test_request_id_format": 0.027963573999841174, - "tests/aws/services/lambda_/test_lambda.py::TestRequestIdHandling::test_request_id_invoke": 3.6793288550002217, - "tests/aws/services/lambda_/test_lambda.py::TestRequestIdHandling::test_request_id_invoke_url": 3.616814756000622, - "tests/aws/services/lambda_/test_lambda_api.py::TestCodeSigningConfig::test_code_signing_not_found_excs": 1.3061497739998913, - "tests/aws/services/lambda_/test_lambda_api.py::TestCodeSigningConfig::test_function_code_signing_config": 1.2563717190000716, - "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaAccountSettings::test_account_settings": 0.08970905899991521, - "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaAccountSettings::test_account_settings_total_code_size": 1.4085385680001536, - "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaAccountSettings::test_account_settings_total_code_size_config_update": 7.32372354000006, - "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaAlias::test_alias_lifecycle": 1.523759345999963, - "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaAlias::test_alias_naming": 1.7061809749999952, - "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaAlias::test_non_existent_alias_deletion": 1.200611078999998, - "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaAlias::test_non_existent_alias_update": 1.2085146880000366, - "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaAlias::test_notfound_and_invalid_routingconfigs": 2.451714157000083, - "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaEventInvokeConfig::test_lambda_eventinvokeconfig_exceptions": 2.836638260999962, - "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaEventInvokeConfig::test_lambda_eventinvokeconfig_lifecycle": 1.3517520640000384, - "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaEventSourceMappings::test_create_event_filter_criteria_validation": 3.5264511290000655, - "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaEventSourceMappings::test_create_event_source_self_managed": 0.0018381280000312472, - "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaEventSourceMappings::test_create_event_source_validation": 4.217728222000005, - "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaEventSourceMappings::test_create_event_source_validation_kinesis": 1.911500480000086, - "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaEventSourceMappings::test_event_source_mapping_exceptions": 0.15138667999985955, - "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaEventSourceMappings::test_event_source_mapping_lifecycle": 7.796639526000035, - "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaEventSourceMappings::test_event_source_mapping_lifecycle_delete_function": 6.02754504699999, - "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaEventSourceMappings::test_function_name_variations": 16.014797429000055, - "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_create_lambda_exceptions": 0.1596831090000137, - "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_delete_on_nonexisting_version": 1.2210613949999356, - "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_arns": 2.568747512000016, - "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_lifecycle": 15.738491228000044, - "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[full_arn_and_qualifier_too_long_and_invalid_region-create_function]": 0.13796671500000457, - "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[full_arn_and_qualifier_too_long_and_invalid_region-delete_function]": 0.09183042699999078, - "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[full_arn_and_qualifier_too_long_and_invalid_region-get_function]": 0.09075254599997606, - "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[full_arn_and_qualifier_too_long_and_invalid_region-invoke]": 0.09152159499990375, - "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[full_arn_with_multiple_qualifiers-create_function]": 0.10128022900005362, - "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[full_arn_with_multiple_qualifiers-delete_function]": 0.08736447799992675, - "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[full_arn_with_multiple_qualifiers-get_function]": 0.09032097300007536, - "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[full_arn_with_multiple_qualifiers-invoke]": 0.08853915399998868, - "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[function_name_is_single_invalid-create_function]": 0.10267945600008943, - "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[function_name_is_single_invalid-delete_function]": 0.0877376730000492, - "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[function_name_is_single_invalid-get_function]": 0.08978101399998195, - "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[function_name_is_single_invalid-invoke]": 0.08828658700002734, - "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[function_name_too_long-create_function]": 0.10183979299995372, - "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[function_name_too_long-delete_function]": 0.08728489200007061, - "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[function_name_too_long-get_function]": 0.08644357099996114, - "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[function_name_too_long-invoke]": 0.009277565999980197, - "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[function_name_too_long_and_invalid_region-create_function]": 0.10747597799996811, - "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[function_name_too_long_and_invalid_region-delete_function]": 0.08880810100004055, - "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[function_name_too_long_and_invalid_region-get_function]": 0.0889470230000029, - "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[function_name_too_long_and_invalid_region-invoke]": 0.08675469999997176, - "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[incomplete_arn-create_function]": 0.007790023999973528, - "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[incomplete_arn-delete_function]": 0.08740113900000779, - "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[incomplete_arn-get_function]": 0.08771685300001764, - "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[incomplete_arn-invoke]": 0.00795375199999171, - "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[invalid_account_id_in_partial_arn-create_function]": 0.1017994700001168, - "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[invalid_account_id_in_partial_arn-delete_function]": 0.08797367999994776, - "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[invalid_account_id_in_partial_arn-get_function]": 0.09235578700003089, - "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[invalid_account_id_in_partial_arn-invoke]": 0.08871920999996519, - "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[invalid_characters_in_function_name-create_function]": 0.10300910699999122, - "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[invalid_characters_in_function_name-delete_function]": 0.08900231600000552, - "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[invalid_characters_in_function_name-get_function]": 0.09121417799997289, - "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[invalid_characters_in_function_name-invoke]": 0.08870917500001951, - "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[invalid_characters_in_qualifier-create_function]": 0.1040246530000104, - "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[invalid_characters_in_qualifier-delete_function]": 0.09547861300001159, - "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[invalid_characters_in_qualifier-get_function]": 0.09860413499995957, - "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[invalid_characters_in_qualifier-invoke]": 0.08771648199996207, - "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[invalid_region_in_arn-create_function]": 0.10192171599993571, - "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[invalid_region_in_arn-delete_function]": 0.08745871800005034, - "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[invalid_region_in_arn-get_function]": 0.08738793300000225, - "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[invalid_region_in_arn-invoke]": 0.08589146399998526, - "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[latest_version_with_additional_qualifier-create_function]": 0.10210876500002541, - "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[latest_version_with_additional_qualifier-delete_function]": 0.08911866800002599, - "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[latest_version_with_additional_qualifier-get_function]": 0.0912930959999585, - "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[latest_version_with_additional_qualifier-invoke]": 0.08747870300004479, - "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[lowercase_latest_qualifier-create_function]": 0.10076577400002407, - "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[lowercase_latest_qualifier-delete_function]": 0.008273526999914793, - "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[lowercase_latest_qualifier-get_function]": 0.08793017499993994, - "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[lowercase_latest_qualifier-invoke]": 0.08759324100003596, - "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[missing_account_id_in_arn-create_function]": 0.10213792000001831, - "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[missing_account_id_in_arn-delete_function]": 0.08701931100000593, - "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[missing_account_id_in_arn-get_function]": 0.08774798200005307, - "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[missing_account_id_in_arn-invoke]": 0.08760468199994875, - "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[missing_region_in_arn-create_function]": 0.10068653000007544, - "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[missing_region_in_arn-delete_function]": 0.08705265500003634, - "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[missing_region_in_arn-get_function]": 0.0875016079999682, - "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[missing_region_in_arn-invoke]": 0.08712593799998558, - "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[misspelled_latest_in_arn-create_function]": 0.10234733400000096, - "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[misspelled_latest_in_arn-delete_function]": 0.08722702099998969, - "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[misspelled_latest_in_arn-get_function]": 0.6772322780000195, - "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[misspelled_latest_in_arn-invoke]": 0.0868125819999932, - "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[non_lambda_arn-create_function]": 0.1024180230000411, - "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[non_lambda_arn-delete_function]": 0.08753101300004573, - "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[non_lambda_arn-get_function]": 0.08674007499996605, - "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[non_lambda_arn-invoke]": 0.08765202099993985, - "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[partial_arn_with_extra_qualifier-create_function]": 0.10154634200006285, - "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[partial_arn_with_extra_qualifier-delete_function]": 0.08721292699999594, - "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[partial_arn_with_extra_qualifier-get_function]": 0.08703962700002421, - "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[partial_arn_with_extra_qualifier-invoke]": 0.08829831799999965, - "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[qualifier_too_long-create_function]": 0.10325023899997632, - "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[qualifier_too_long-delete_function]": 0.08828476400003638, - "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[qualifier_too_long-get_function]": 0.08914916399999129, - "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[qualifier_too_long-invoke]": 0.08887090200005332, - "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_get_function_wrong_region[delete_function]": 1.2025383700000702, - "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_get_function_wrong_region[get_function]": 1.2021825880000279, - "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_get_function_wrong_region[get_function_code_signing_config]": 1.2165737960000342, - "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_get_function_wrong_region[get_function_concurrency]": 1.20363404699998, - "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_get_function_wrong_region[get_function_configuration]": 1.2057842730000061, - "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_get_function_wrong_region[get_function_event_invoke_config]": 1.2080122129999609, - "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_get_function_wrong_region[get_function_url_config]": 1.203973942999994, - "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_get_function_wrong_region[invoke]": 1.8041730110000458, - "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_invalid_invoke": 0.08885061299997687, - "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_invalid_vpc_config_security_group": 0.0016173340000023018, - "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_invalid_vpc_config_subnet": 0.24566771700000345, - "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_lambda_code_location_s3": 1.4567815089999954, - "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_lambda_code_location_s3_errors": 1.38319081100002, - "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_lambda_code_location_zipfile": 1.442674831999966, - "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_lambda_concurrent_code_updates": 2.297117648999972, - "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_lambda_concurrent_config_updates": 1.2489967429999638, - "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_list_functions": 2.4823874560000263, - "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_ops_on_nonexisting_fn[delete_function]": 0.08961188099993933, - "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_ops_on_nonexisting_fn[get_function]": 0.09630579700001363, - "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_ops_on_nonexisting_fn[get_function_code_signing_config]": 0.09171030800001745, - "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_ops_on_nonexisting_fn[get_function_concurrency]": 0.0913664610000069, - "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_ops_on_nonexisting_fn[get_function_configuration]": 0.09075401700005159, - "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_ops_on_nonexisting_fn[get_function_event_invoke_config]": 0.1036931890000119, - "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_ops_on_nonexisting_fn[get_function_url_config]": 0.09237404700002116, - "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_ops_on_nonexisting_version[get_function]": 1.207268943000031, - "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_ops_on_nonexisting_version[get_function_configuration]": 1.2098784739999928, - "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_ops_on_nonexisting_version[get_function_event_invoke_config]": 1.2044673819999616, - "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_ops_with_arn_qualifier_mismatch[delete_function]": 0.09732612700003074, - "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_ops_with_arn_qualifier_mismatch[get_function]": 0.09647406599998476, - "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_ops_with_arn_qualifier_mismatch[get_function_configuration]": 0.09567596900001263, - "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_redundant_updates": 2.3438119970000457, - "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_update_lambda_exceptions": 1.2247326879999605, - "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_vpc_config": 1.9344681819999892, - "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaImages::test_lambda_image_and_image_config_crud": 3.000206000999981, - "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaImages::test_lambda_image_crud": 8.038654770999983, - "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaImages::test_lambda_image_versions": 1.9863592709999693, - "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaImages::test_lambda_zip_file_to_image": 1.9385231020000333, - "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaLayer::test_layer_compatibilities[runtimes0]": 0.12789975099997264, - "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaLayer::test_layer_compatibilities[runtimes1]": 0.1260016620000215, - "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaLayer::test_layer_deterministic_version": 0.06057911499988222, - "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaLayer::test_layer_exceptions": 0.3034632280000551, - "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaLayer::test_layer_function_exceptions": 17.535242658000016, - "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaLayer::test_layer_function_quota_exception": 16.373621979000177, - "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaLayer::test_layer_lifecycle": 1.4680982890001815, - "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaLayer::test_layer_policy_exceptions": 0.23036473000001934, - "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaLayer::test_layer_policy_lifecycle": 0.17455461399993055, - "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaLayer::test_layer_s3_content": 0.20859303199995338, - "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaPermissions::test_add_lambda_permission_aws": 1.2136114770000859, - "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaPermissions::test_add_lambda_permission_fields": 1.3106665069999508, - "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaPermissions::test_create_multiple_lambda_permissions": 1.2187757980000242, - "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaPermissions::test_lambda_permission_fn_versioning": 1.3698691650000683, - "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaPermissions::test_permission_exceptions": 1.3399448650000636, - "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaPermissions::test_remove_multi_permissions": 1.2711173390001704, - "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaProvisionedConcurrency::test_lambda_provisioned_lifecycle": 2.4218703610000603, - "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaProvisionedConcurrency::test_provisioned_concurrency_exceptions": 1.3848505119999572, - "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaProvisionedConcurrency::test_provisioned_concurrency_limits": 1.256252685999982, - "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaRecursion::test_put_function_recursion_config_allow": 1.2029196920000231, - "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaRecursion::test_put_function_recursion_config_default_terminate": 1.203574303000039, - "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaRecursion::test_put_function_recursion_config_invalid_value": 1.2070249020000006, - "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaReservedConcurrency::test_function_concurrency": 1.247766162000005, - "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaReservedConcurrency::test_function_concurrency_exceptions": 1.2313621310000258, - "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaReservedConcurrency::test_function_concurrency_limits": 1.2198339589999705, - "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaRevisions::test_function_revisions_basic": 13.658809851000001, - "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaRevisions::test_function_revisions_permissions": 1.277166186000045, - "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaRevisions::test_function_revisions_version_and_alias": 1.3626976650000415, - "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaSizeLimits::test_lambda_envvars_near_limit_succeeds": 1.2996289490000663, - "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaSizeLimits::test_large_environment_fails_multiple_keys": 16.214497700999914, - "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaSizeLimits::test_large_environment_variables_fails": 16.213187984, - "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaSizeLimits::test_large_lambda": 12.63104160699993, - "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaSizeLimits::test_oversized_request_create_lambda": 2.0709809439999844, - "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaSizeLimits::test_oversized_unzipped_lambda": 4.7972113040000295, - "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaSizeLimits::test_oversized_zipped_create_lambda": 1.5870521069999768, - "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaSnapStart::test_snapstart_exceptions": 0.1034387649999644, - "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaSnapStart::test_snapstart_lifecycle[dotnet8]": 5.3036204719999205, - "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaSnapStart::test_snapstart_lifecycle[java11]": 3.291683068999987, - "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaSnapStart::test_snapstart_lifecycle[java17]": 3.291274256999941, - "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaSnapStart::test_snapstart_lifecycle[java21]": 3.288094304000083, - "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaSnapStart::test_snapstart_lifecycle[python3.12]": 1.2683686780000016, - "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaSnapStart::test_snapstart_lifecycle[python3.13]": 8.35663805999991, - "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaSnapStart::test_snapstart_update_function_configuration[dotnet8]": 1.2212683439998955, - "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaSnapStart::test_snapstart_update_function_configuration[java11]": 1.2356044389999852, - "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaSnapStart::test_snapstart_update_function_configuration[java17]": 1.2201755690000482, - "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaSnapStart::test_snapstart_update_function_configuration[java21]": 1.223450064000076, - "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaSnapStart::test_snapstart_update_function_configuration[python3.12]": 1.231877786000041, - "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaSnapStart::test_snapstart_update_function_configuration[python3.13]": 1.2185638760000757, - "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaTag::test_create_tag_on_esm_create": 1.5169849950000298, - "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaTag::test_create_tag_on_fn_create": 1.224696147999964, - "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaTag::test_tag_exceptions[event_source_mapping]": 0.12085182199996325, - "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaTag::test_tag_exceptions[lambda_function]": 0.12177883099997189, - "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaTag::test_tag_lifecycle[event_source_mapping]": 1.4089942709999832, - "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaTag::test_tag_lifecycle[lambda_function]": 1.3040425949999985, - "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaTag::test_tag_nonexisting_resource": 1.2586507119999624, - "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaTags::test_tag_exceptions": 1.2856605839999702, - "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaTags::test_tag_lifecycle": 1.345155380000051, - "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaTags::test_tag_limits": 1.3460433499998317, - "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaTags::test_tag_versions": 1.2544126360000973, - "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaUrl::test_create_url_config_custom_id_tag": 1.135956573000044, - "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaUrl::test_create_url_config_custom_id_tag_alias": 3.4202659489999405, - "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaUrl::test_create_url_config_custom_id_tag_invalid_id": 1.1430195550000235, - "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaUrl::test_url_config_deletion_without_qualifier": 1.3394973819999905, - "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaUrl::test_url_config_exceptions": 7.583454181999969, - "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaUrl::test_url_config_lifecycle": 1.308546868999997, - "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaUrl::test_url_config_list_paging": 2.0934607950000554, - "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaVersions::test_publish_version_on_create": 1.3101214320000167, - "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaVersions::test_publish_with_update": 1.3633353519999787, - "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaVersions::test_publish_with_wrong_sha256": 1.8999667619999627, - "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaVersions::test_version_lifecycle": 1.4330941810000013, - "tests/aws/services/lambda_/test_lambda_api.py::TestLoggingConfig::test_advanced_logging_configuration_format_switch": 34.19383840699999, - "tests/aws/services/lambda_/test_lambda_api.py::TestLoggingConfig::test_function_advanced_logging_configuration": 1.6953149279997888, - "tests/aws/services/lambda_/test_lambda_api.py::TestLoggingConfig::test_function_partial_advanced_logging_configuration_update[partial_config0]": 2.4344517450000467, - "tests/aws/services/lambda_/test_lambda_api.py::TestLoggingConfig::test_function_partial_advanced_logging_configuration_update[partial_config1]": 1.5132957820000001, - "tests/aws/services/lambda_/test_lambda_api.py::TestLoggingConfig::test_function_partial_advanced_logging_configuration_update[partial_config2]": 2.399479500000041, - "tests/aws/services/lambda_/test_lambda_api.py::TestLoggingConfig::test_function_partial_advanced_logging_configuration_update[partial_config3]": 1.458000425000023, - "tests/aws/services/lambda_/test_lambda_api.py::TestPartialARNMatching::test_cross_region_arn_function_access": 1.1458451000003151, - "tests/aws/services/lambda_/test_lambda_api.py::TestPartialARNMatching::test_update_function_configuration_full_arn": 3.279671763999886, - "tests/aws/services/lambda_/test_lambda_api.py::TestRuntimeValidation::test_create_deprecated_function_runtime_with_validation_disabled": 15.200714220000009, - "tests/aws/services/lambda_/test_lambda_api.py::TestRuntimeValidation::test_create_deprecated_function_runtime_with_validation_enabled[dotnetcore3.1]": 0.10698821100049827, - "tests/aws/services/lambda_/test_lambda_api.py::TestRuntimeValidation::test_create_deprecated_function_runtime_with_validation_enabled[go1.x]": 0.10453728499987847, - "tests/aws/services/lambda_/test_lambda_api.py::TestRuntimeValidation::test_create_deprecated_function_runtime_with_validation_enabled[java8]": 0.11119141999915882, - "tests/aws/services/lambda_/test_lambda_api.py::TestRuntimeValidation::test_create_deprecated_function_runtime_with_validation_enabled[nodejs12.x]": 0.10520928899995852, - "tests/aws/services/lambda_/test_lambda_api.py::TestRuntimeValidation::test_create_deprecated_function_runtime_with_validation_enabled[nodejs14.x]": 0.10405401399975744, - "tests/aws/services/lambda_/test_lambda_api.py::TestRuntimeValidation::test_create_deprecated_function_runtime_with_validation_enabled[provided]": 0.10536200699971232, - "tests/aws/services/lambda_/test_lambda_api.py::TestRuntimeValidation::test_create_deprecated_function_runtime_with_validation_enabled[python3.7]": 0.10518955300040034, - "tests/aws/services/lambda_/test_lambda_api.py::TestRuntimeValidation::test_create_deprecated_function_runtime_with_validation_enabled[ruby2.7]": 0.10413180500017916, - "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaCallingLocalstack::test_manual_endpoint_injection[dotnet6]": 1.940515935999997, - "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaCallingLocalstack::test_manual_endpoint_injection[dotnet8]": 1.8483189780000657, - "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaCallingLocalstack::test_manual_endpoint_injection[java11]": 5.057523948000039, - "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaCallingLocalstack::test_manual_endpoint_injection[java17]": 4.066212115999974, - "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaCallingLocalstack::test_manual_endpoint_injection[java21]": 4.062991565000061, - "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaCallingLocalstack::test_manual_endpoint_injection[java8.al2]": 5.840247148999879, - "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaCallingLocalstack::test_manual_endpoint_injection[nodejs16.x]": 1.7518210519999684, - "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaCallingLocalstack::test_manual_endpoint_injection[nodejs18.x]": 1.7185140189999402, - "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaCallingLocalstack::test_manual_endpoint_injection[nodejs20.x]": 1.685918559999891, - "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaCallingLocalstack::test_manual_endpoint_injection[nodejs22.x]": 1.6890931390001924, - "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaCallingLocalstack::test_manual_endpoint_injection[python3.10]": 1.7142178049999757, - "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaCallingLocalstack::test_manual_endpoint_injection[python3.11]": 1.785097816000075, - "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaCallingLocalstack::test_manual_endpoint_injection[python3.12]": 1.8158967589999975, - "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaCallingLocalstack::test_manual_endpoint_injection[python3.13]": 2.6719970629999352, - "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaCallingLocalstack::test_manual_endpoint_injection[python3.8]": 1.7403457869999102, - "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaCallingLocalstack::test_manual_endpoint_injection[python3.9]": 1.7167516480000131, - "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaCallingLocalstack::test_manual_endpoint_injection[ruby3.2]": 2.500828103000117, - "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaCallingLocalstack::test_manual_endpoint_injection[ruby3.3]": 2.4253834619998997, - "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaCallingLocalstack::test_manual_endpoint_injection[ruby3.4]": 2.0181292380000286, - "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_echo_invoke[dotnet6]": 4.570371820999981, - "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_echo_invoke[dotnet8]": 2.485369917000071, - "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_echo_invoke[java11]": 2.4866471749999164, - "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_echo_invoke[java17]": 2.4098411919999307, - "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_echo_invoke[java21]": 2.447252754000033, - "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_echo_invoke[java8.al2]": 4.476212925000027, - "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_echo_invoke[nodejs16.x]": 9.517288011000005, - "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_echo_invoke[nodejs18.x]": 2.4376595970001063, - "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_echo_invoke[nodejs20.x]": 2.3753294340000366, - "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_echo_invoke[nodejs22.x]": 8.44394050699998, - "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_echo_invoke[provided.al2023]": 4.283162178999987, - "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_echo_invoke[provided.al2]": 5.191805498999884, - "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_echo_invoke[python3.10]": 7.598927744999855, - "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_echo_invoke[python3.11]": 2.4800609709999435, - "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_echo_invoke[python3.12]": 2.5191315039999154, - "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_echo_invoke[python3.13]": 2.5496555760000774, - "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_echo_invoke[python3.8]": 2.788154823000127, - "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_echo_invoke[python3.9]": 7.589429095000128, - "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_echo_invoke[ruby3.2]": 9.566578197999888, - "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_echo_invoke[ruby3.3]": 9.615837706000093, - "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_echo_invoke[ruby3.4]": 9.58227202699993, - "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_introspection_invoke[dotnet6]": 3.595586573999981, - "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_introspection_invoke[dotnet8]": 3.617642324999906, - "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_introspection_invoke[java11]": 3.7500011370000266, - "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_introspection_invoke[java17]": 3.6108471800000643, - "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_introspection_invoke[java21]": 3.6455265700000155, - "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_introspection_invoke[java8.al2]": 3.832800919999954, - "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_introspection_invoke[nodejs16.x]": 3.527603951999822, - "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_introspection_invoke[nodejs18.x]": 3.5308301850000134, - "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_introspection_invoke[nodejs20.x]": 3.5102839049999375, - "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_introspection_invoke[nodejs22.x]": 4.2608065919999945, - "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_introspection_invoke[provided.al2023]": 3.520529318000058, - "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_introspection_invoke[provided.al2]": 3.481673457999932, - "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_introspection_invoke[python3.10]": 4.408989338000083, - "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_introspection_invoke[python3.11]": 3.5109056549999877, - "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_introspection_invoke[python3.12]": 3.4728782709998995, - "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_introspection_invoke[python3.13]": 3.5024601760001133, - "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_introspection_invoke[python3.8]": 3.5151679509999667, - "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_introspection_invoke[python3.9]": 3.469181532999869, - "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_introspection_invoke[ruby3.2]": 4.544715743999973, - "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_introspection_invoke[ruby3.3]": 3.576005337999959, - "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_introspection_invoke[ruby3.4]": 3.555493278999961, - "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_runtime_wrapper_invoke[dotnet6]": 1.7945582070000228, - "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_runtime_wrapper_invoke[dotnet8]": 1.7825248460000012, - "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_runtime_wrapper_invoke[java11]": 1.9007800450001469, - "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_runtime_wrapper_invoke[java17]": 1.8125411580000446, - "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_runtime_wrapper_invoke[java21]": 1.836274216999982, - "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_runtime_wrapper_invoke[java8.al2]": 2.037897940999983, - "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_runtime_wrapper_invoke[nodejs16.x]": 1.68559797599994, - "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_runtime_wrapper_invoke[nodejs18.x]": 1.7226869600000327, - "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_runtime_wrapper_invoke[nodejs20.x]": 1.7140155110000705, - "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_runtime_wrapper_invoke[nodejs22.x]": 1.6764306750001197, - "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_runtime_wrapper_invoke[python3.10]": 1.6563427900000534, - "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_runtime_wrapper_invoke[python3.11]": 1.6699255880000692, - "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_runtime_wrapper_invoke[python3.12]": 1.668662859000051, - "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_runtime_wrapper_invoke[python3.13]": 1.6831216119999226, - "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_runtime_wrapper_invoke[python3.8]": 1.6942434009998806, - "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_runtime_wrapper_invoke[python3.9]": 1.6563428749999503, - "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_runtime_wrapper_invoke[ruby3.2]": 1.7480983280000828, - "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_runtime_wrapper_invoke[ruby3.3]": 1.7285584649998782, - "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_runtime_wrapper_invoke[ruby3.4]": 1.7419065100000353, - "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_uncaught_exception_invoke[dotnet6]": 1.8292223430000831, - "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_uncaught_exception_invoke[dotnet8]": 1.8031123220000609, - "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_uncaught_exception_invoke[java11]": 1.9313765720000902, - "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_uncaught_exception_invoke[java17]": 1.867813741999953, - "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_uncaught_exception_invoke[java21]": 1.8530176130001337, - "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_uncaught_exception_invoke[java8.al2]": 2.0841088390000095, - "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_uncaught_exception_invoke[nodejs16.x]": 1.695230524999829, - "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_uncaught_exception_invoke[nodejs18.x]": 1.736664137000048, - "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_uncaught_exception_invoke[nodejs20.x]": 1.6866871729999957, - "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_uncaught_exception_invoke[nodejs22.x]": 1.729889091999894, - "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_uncaught_exception_invoke[provided.al2023]": 1.728769765999914, - "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_uncaught_exception_invoke[provided.al2]": 1.7310044799999105, - "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_uncaught_exception_invoke[python3.10]": 1.6788734549999162, - "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_uncaught_exception_invoke[python3.11]": 1.6549409680000053, - "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_uncaught_exception_invoke[python3.12]": 1.6973042679999253, - "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_uncaught_exception_invoke[python3.13]": 2.6806229779998603, - "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_uncaught_exception_invoke[python3.8]": 1.6968117979999988, - "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_uncaught_exception_invoke[python3.9]": 1.6787491240000918, - "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_uncaught_exception_invoke[ruby3.2]": 1.7787483680000378, - "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_uncaught_exception_invoke[ruby3.3]": 1.7682174569999916, - "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_uncaught_exception_invoke[ruby3.4]": 1.7597682100000611, - "tests/aws/services/lambda_/test_lambda_destinations.py::TestLambdaDLQ::test_dead_letter_queue": 21.19505796199985, - "tests/aws/services/lambda_/test_lambda_destinations.py::TestLambdaDestinationEventbridge::test_invoke_lambda_eventbridge": 15.617724874000032, - "tests/aws/services/lambda_/test_lambda_destinations.py::TestLambdaDestinationSqs::test_assess_lambda_destination_invocation[payload0]": 1.861485969000114, - "tests/aws/services/lambda_/test_lambda_destinations.py::TestLambdaDestinationSqs::test_assess_lambda_destination_invocation[payload1]": 1.876781630999858, - "tests/aws/services/lambda_/test_lambda_destinations.py::TestLambdaDestinationSqs::test_lambda_destination_default_retries": 17.973375596000324, - "tests/aws/services/lambda_/test_lambda_destinations.py::TestLambdaDestinationSqs::test_maxeventage": 63.6716803339998, - "tests/aws/services/lambda_/test_lambda_destinations.py::TestLambdaDestinationSqs::test_retries": 22.489727678999998, - "tests/aws/services/lambda_/test_lambda_developer_tools.py::TestDockerFlags::test_additional_docker_flags": 1.5254168600001776, - "tests/aws/services/lambda_/test_lambda_developer_tools.py::TestDockerFlags::test_lambda_docker_networks": 8.035310697000114, - "tests/aws/services/lambda_/test_lambda_developer_tools.py::TestHotReloading::test_hot_reloading[nodejs20.x]": 3.3995004969999627, - "tests/aws/services/lambda_/test_lambda_developer_tools.py::TestHotReloading::test_hot_reloading[python3.12]": 3.361364144999925, - "tests/aws/services/lambda_/test_lambda_developer_tools.py::TestHotReloading::test_hot_reloading_environment_placeholder": 0.4790896279998833, - "tests/aws/services/lambda_/test_lambda_developer_tools.py::TestHotReloading::test_hot_reloading_error_path_not_absolute": 0.0288076069998624, - "tests/aws/services/lambda_/test_lambda_developer_tools.py::TestHotReloading::test_hot_reloading_publish_version": 0.1250124410000808, - "tests/aws/services/lambda_/test_lambda_developer_tools.py::TestLambdaDNS::test_lambda_localhost_localstack_cloud_connectivity": 1.5520349830001123, - "tests/aws/services/lambda_/test_lambda_integration_xray.py::test_traceid_outside_handler[Active]": 2.557148595000399, - "tests/aws/services/lambda_/test_lambda_integration_xray.py::test_traceid_outside_handler[PassThrough]": 2.573391881999896, - "tests/aws/services/lambda_/test_lambda_integration_xray.py::test_xray_trace_propagation": 1.5235557620001146, - "tests/aws/services/lambda_/test_lambda_runtimes.py::TestCloudwatchLogs::test_multi_line_prints": 3.6154539359999944, - "tests/aws/services/lambda_/test_lambda_runtimes.py::TestGoProvidedRuntimes::test_manual_endpoint_injection[provided.al2023]": 1.8232869839998784, - "tests/aws/services/lambda_/test_lambda_runtimes.py::TestGoProvidedRuntimes::test_manual_endpoint_injection[provided.al2]": 1.819350077000081, - "tests/aws/services/lambda_/test_lambda_runtimes.py::TestGoProvidedRuntimes::test_uncaught_exception_invoke[provided.al2023]": 1.9541263440000876, - "tests/aws/services/lambda_/test_lambda_runtimes.py::TestGoProvidedRuntimes::test_uncaught_exception_invoke[provided.al2]": 1.9681317840002066, - "tests/aws/services/lambda_/test_lambda_runtimes.py::TestJavaRuntimes::test_java_custom_handler_method_specification[cloud.localstack.sample.LambdaHandlerWithInterfaceAndCustom-INTERFACE]": 2.997921412000096, - "tests/aws/services/lambda_/test_lambda_runtimes.py::TestJavaRuntimes::test_java_custom_handler_method_specification[cloud.localstack.sample.LambdaHandlerWithInterfaceAndCustom::handleRequest-INTERFACE]": 3.015320607000149, - "tests/aws/services/lambda_/test_lambda_runtimes.py::TestJavaRuntimes::test_java_custom_handler_method_specification[cloud.localstack.sample.LambdaHandlerWithInterfaceAndCustom::handleRequestCustom-CUSTOM]": 3.033118175000027, - "tests/aws/services/lambda_/test_lambda_runtimes.py::TestJavaRuntimes::test_java_lambda_subscribe_sns_topic": 8.789926172999913, - "tests/aws/services/lambda_/test_lambda_runtimes.py::TestJavaRuntimes::test_java_runtime_with_lib": 5.639377521000142, - "tests/aws/services/lambda_/test_lambda_runtimes.py::TestJavaRuntimes::test_serializable_input_object[java11]": 2.6262549600000966, - "tests/aws/services/lambda_/test_lambda_runtimes.py::TestJavaRuntimes::test_serializable_input_object[java17]": 3.5414807550002934, - "tests/aws/services/lambda_/test_lambda_runtimes.py::TestJavaRuntimes::test_serializable_input_object[java21]": 2.8697879289998127, - "tests/aws/services/lambda_/test_lambda_runtimes.py::TestJavaRuntimes::test_serializable_input_object[java8.al2]": 2.7600957790002667, - "tests/aws/services/lambda_/test_lambda_runtimes.py::TestJavaRuntimes::test_stream_handler[java11]": 1.7271167919998334, - "tests/aws/services/lambda_/test_lambda_runtimes.py::TestJavaRuntimes::test_stream_handler[java17]": 1.685842408000326, - "tests/aws/services/lambda_/test_lambda_runtimes.py::TestJavaRuntimes::test_stream_handler[java21]": 1.76785106300008, - "tests/aws/services/lambda_/test_lambda_runtimes.py::TestJavaRuntimes::test_stream_handler[java8.al2]": 1.7076826909999454, - "tests/aws/services/lambda_/test_lambda_runtimes.py::TestNodeJSRuntimes::test_invoke_nodejs_es6_lambda[nodejs16.x]": 4.677916545000016, - "tests/aws/services/lambda_/test_lambda_runtimes.py::TestNodeJSRuntimes::test_invoke_nodejs_es6_lambda[nodejs18.x]": 4.695796156999904, - "tests/aws/services/lambda_/test_lambda_runtimes.py::TestNodeJSRuntimes::test_invoke_nodejs_es6_lambda[nodejs20.x]": 4.66037436900001, - "tests/aws/services/lambda_/test_lambda_runtimes.py::TestNodeJSRuntimes::test_invoke_nodejs_es6_lambda[nodejs22.x]": 4.6520932529999754, - "tests/aws/services/lambda_/test_lambda_runtimes.py::TestPythonRuntimes::test_handler_in_submodule[python3.10]": 1.6482172390001324, - "tests/aws/services/lambda_/test_lambda_runtimes.py::TestPythonRuntimes::test_handler_in_submodule[python3.11]": 1.759423778999917, - "tests/aws/services/lambda_/test_lambda_runtimes.py::TestPythonRuntimes::test_handler_in_submodule[python3.12]": 1.6466268470001069, - "tests/aws/services/lambda_/test_lambda_runtimes.py::TestPythonRuntimes::test_handler_in_submodule[python3.13]": 1.6339802530003453, - "tests/aws/services/lambda_/test_lambda_runtimes.py::TestPythonRuntimes::test_handler_in_submodule[python3.8]": 1.6641135099998792, - "tests/aws/services/lambda_/test_lambda_runtimes.py::TestPythonRuntimes::test_handler_in_submodule[python3.9]": 1.6565522190001047, - "tests/aws/services/lambda_/test_lambda_runtimes.py::TestPythonRuntimes::test_python_runtime_correct_versions[python3.10]": 1.5233122840004398, - "tests/aws/services/lambda_/test_lambda_runtimes.py::TestPythonRuntimes::test_python_runtime_correct_versions[python3.11]": 1.5363878990001467, - "tests/aws/services/lambda_/test_lambda_runtimes.py::TestPythonRuntimes::test_python_runtime_correct_versions[python3.12]": 1.5337551380000605, - "tests/aws/services/lambda_/test_lambda_runtimes.py::TestPythonRuntimes::test_python_runtime_correct_versions[python3.13]": 1.5480532149999817, - "tests/aws/services/lambda_/test_lambda_runtimes.py::TestPythonRuntimes::test_python_runtime_correct_versions[python3.8]": 1.5486009560002003, - "tests/aws/services/lambda_/test_lambda_runtimes.py::TestPythonRuntimes::test_python_runtime_correct_versions[python3.9]": 1.52726694900025, - "tests/aws/services/logs/test_logs.py::TestCloudWatchLogs::test_create_and_delete_log_group": 0.21055121299991697, - "tests/aws/services/logs/test_logs.py::TestCloudWatchLogs::test_create_and_delete_log_stream": 0.47235682499990617, - "tests/aws/services/logs/test_logs.py::TestCloudWatchLogs::test_delivery_logs_for_sns": 1.0846007459999782, - "tests/aws/services/logs/test_logs.py::TestCloudWatchLogs::test_filter_log_events_response_header": 0.05314520899992203, - "tests/aws/services/logs/test_logs.py::TestCloudWatchLogs::test_list_tags_log_group": 0.22261226199998418, - "tests/aws/services/logs/test_logs.py::TestCloudWatchLogs::test_metric_filters": 0.0017339959999844723, - "tests/aws/services/logs/test_logs.py::TestCloudWatchLogs::test_put_events_multi_bytes_msg": 0.05553510599975198, - "tests/aws/services/logs/test_logs.py::TestCloudWatchLogs::test_put_subscription_filter_firehose": 0.6463777770002253, - "tests/aws/services/logs/test_logs.py::TestCloudWatchLogs::test_put_subscription_filter_kinesis": 2.3657529579998027, - "tests/aws/services/logs/test_logs.py::TestCloudWatchLogs::test_put_subscription_filter_lambda": 1.9594695610001054, - "tests/aws/services/logs/test_logs.py::TestCloudWatchLogs::test_resource_does_not_exist": 0.042111875000045984, - "tests/aws/services/opensearch/test_opensearch.py::TestCustomBackendManager::test_custom_backend": 0.1413162150001881, - "tests/aws/services/opensearch/test_opensearch.py::TestCustomBackendManager::test_custom_backend_with_custom_endpoint": 0.1644230280001011, - "tests/aws/services/opensearch/test_opensearch.py::TestEdgeProxiedOpensearchCluster::test_custom_endpoint": 10.45616812000003, - "tests/aws/services/opensearch/test_opensearch.py::TestEdgeProxiedOpensearchCluster::test_custom_endpoint_disabled": 10.453594161999945, - "tests/aws/services/opensearch/test_opensearch.py::TestEdgeProxiedOpensearchCluster::test_route_through_edge": 10.250165735999872, - "tests/aws/services/opensearch/test_opensearch.py::TestMultiClusterManager::test_multi_cluster": 18.84970671799988, - "tests/aws/services/opensearch/test_opensearch.py::TestMultiplexingClusterManager::test_multiplexing_cluster": 10.780765774999963, - "tests/aws/services/opensearch/test_opensearch.py::TestOpensearchProvider::test_cloudformation_deployment": 12.24712424900008, - "tests/aws/services/opensearch/test_opensearch.py::TestOpensearchProvider::test_create_domain_with_invalid_custom_endpoint": 0.020343288000049142, - "tests/aws/services/opensearch/test_opensearch.py::TestOpensearchProvider::test_create_domain_with_invalid_name": 0.02326645799985272, - "tests/aws/services/opensearch/test_opensearch.py::TestOpensearchProvider::test_create_existing_domain_causes_exception": 10.404662447000192, - "tests/aws/services/opensearch/test_opensearch.py::TestOpensearchProvider::test_create_indices": 11.38163922099966, - "tests/aws/services/opensearch/test_opensearch.py::TestOpensearchProvider::test_describe_domains": 10.498993944999938, - "tests/aws/services/opensearch/test_opensearch.py::TestOpensearchProvider::test_domain_lifecycle": 13.019392021000158, - "tests/aws/services/opensearch/test_opensearch.py::TestOpensearchProvider::test_domain_version": 9.890409955999985, - "tests/aws/services/opensearch/test_opensearch.py::TestOpensearchProvider::test_endpoint_strategy_path": 9.871911239999918, - "tests/aws/services/opensearch/test_opensearch.py::TestOpensearchProvider::test_endpoint_strategy_port": 9.885178396000128, - "tests/aws/services/opensearch/test_opensearch.py::TestOpensearchProvider::test_exception_header_field": 0.011882924000019557, - "tests/aws/services/opensearch/test_opensearch.py::TestOpensearchProvider::test_get_compatible_version_for_domain": 9.4175214039999, - "tests/aws/services/opensearch/test_opensearch.py::TestOpensearchProvider::test_get_compatible_versions": 0.021683797000150662, - "tests/aws/services/opensearch/test_opensearch.py::TestOpensearchProvider::test_get_document": 10.960264581999809, - "tests/aws/services/opensearch/test_opensearch.py::TestOpensearchProvider::test_gzip_responses": 10.58600595400003, - "tests/aws/services/opensearch/test_opensearch.py::TestOpensearchProvider::test_list_versions": 0.09888970099996186, - "tests/aws/services/opensearch/test_opensearch.py::TestOpensearchProvider::test_search": 11.1162568499999, - "tests/aws/services/opensearch/test_opensearch.py::TestOpensearchProvider::test_security_plugin": 16.02584580000007, - "tests/aws/services/opensearch/test_opensearch.py::TestOpensearchProvider::test_sql_plugin": 14.697879579000073, - "tests/aws/services/opensearch/test_opensearch.py::TestOpensearchProvider::test_update_domain_config": 10.544090847000007, - "tests/aws/services/opensearch/test_opensearch.py::TestSingletonClusterManager::test_endpoint_strategy_port_singleton_cluster": 10.25005351599998, - "tests/aws/services/redshift/test_redshift.py::TestRedshift::test_cluster_security_groups": 0.03374767700006487, - "tests/aws/services/redshift/test_redshift.py::TestRedshift::test_create_clusters": 0.20164425500001926, - "tests/aws/services/resource_groups/test_resource_groups.py::TestResourceGroups::test_cloudformation_query": 0.001621080000177244, - "tests/aws/services/resource_groups/test_resource_groups.py::TestResourceGroups::test_create_group": 0.41981817999999294, - "tests/aws/services/resource_groups/test_resource_groups.py::TestResourceGroups::test_resource_groups_different_region": 0.0016340849999778584, - "tests/aws/services/resource_groups/test_resource_groups.py::TestResourceGroups::test_resource_groups_tag_query": 0.0016949890000432788, - "tests/aws/services/resource_groups/test_resource_groups.py::TestResourceGroups::test_resource_type_filters": 0.0015955119999944145, - "tests/aws/services/resource_groups/test_resource_groups.py::TestResourceGroups::test_search_resources": 0.0016001799999685318, - "tests/aws/services/resourcegroupstaggingapi/test_rgsa.py::TestRGSAIntegrations::test_get_resources": 0.5810307079998438, - "tests/aws/services/route53/test_route53.py::TestRoute53::test_associate_vpc_with_hosted_zone": 0.5172743079999691, - "tests/aws/services/route53/test_route53.py::TestRoute53::test_create_hosted_zone": 0.6357233109999925, - "tests/aws/services/route53/test_route53.py::TestRoute53::test_create_hosted_zone_in_non_existent_vpc": 0.19109624799989433, - "tests/aws/services/route53/test_route53.py::TestRoute53::test_create_private_hosted_zone": 0.6751821010002459, - "tests/aws/services/route53/test_route53.py::TestRoute53::test_crud_health_check": 0.19370732700008375, - "tests/aws/services/route53/test_route53.py::TestRoute53::test_reusable_delegation_sets": 0.14788720500041563, - "tests/aws/services/route53resolver/test_route53resolver.py::TestRoute53Resolver::test_associate_and_disassociate_resolver_rule": 0.4948159589998795, - "tests/aws/services/route53resolver/test_route53resolver.py::TestRoute53Resolver::test_create_resolver_endpoint[INBOUND-5]": 0.3453339849997974, - "tests/aws/services/route53resolver/test_route53resolver.py::TestRoute53Resolver::test_create_resolver_endpoint[OUTBOUND-10]": 0.29440933199998653, - "tests/aws/services/route53resolver/test_route53resolver.py::TestRoute53Resolver::test_create_resolver_query_log_config": 0.3110715849998087, - "tests/aws/services/route53resolver/test_route53resolver.py::TestRoute53Resolver::test_create_resolver_rule": 0.38222297800007254, - "tests/aws/services/route53resolver/test_route53resolver.py::TestRoute53Resolver::test_create_resolver_rule_with_invalid_direction": 0.2933018470002935, - "tests/aws/services/route53resolver/test_route53resolver.py::TestRoute53Resolver::test_delete_non_existent_resolver_endpoint": 0.08713285400017412, - "tests/aws/services/route53resolver/test_route53resolver.py::TestRoute53Resolver::test_delete_non_existent_resolver_query_log_config": 0.1575363010001638, - "tests/aws/services/route53resolver/test_route53resolver.py::TestRoute53Resolver::test_delete_non_existent_resolver_rule": 0.08761765799999921, - "tests/aws/services/route53resolver/test_route53resolver.py::TestRoute53Resolver::test_delete_resolver_endpoint": 0.293988329000058, - "tests/aws/services/route53resolver/test_route53resolver.py::TestRoute53Resolver::test_disassociate_non_existent_association": 0.08812268699989545, - "tests/aws/services/route53resolver/test_route53resolver.py::TestRoute53Resolver::test_list_firewall_domain_lists": 0.18860889799998404, - "tests/aws/services/route53resolver/test_route53resolver.py::TestRoute53Resolver::test_list_firewall_rules": 0.3253538149999713, - "tests/aws/services/route53resolver/test_route53resolver.py::TestRoute53Resolver::test_list_firewall_rules_for_empty_rule_group": 0.10462003099974027, - "tests/aws/services/route53resolver/test_route53resolver.py::TestRoute53Resolver::test_list_firewall_rules_for_missing_rule_group": 0.1571065529999487, - "tests/aws/services/route53resolver/test_route53resolver.py::TestRoute53Resolver::test_multipe_create_resolver_rule": 0.42004981599984603, - "tests/aws/services/route53resolver/test_route53resolver.py::TestRoute53Resolver::test_multiple_create_resolver_endpoint_with_same_req_id": 0.3002360240004691, - "tests/aws/services/route53resolver/test_route53resolver.py::TestRoute53Resolver::test_route53resolver_bad_create_endpoint_security_groups": 0.19657931700021436, - "tests/aws/services/route53resolver/test_route53resolver.py::TestRoute53Resolver::test_update_resolver_endpoint": 0.30695322599990504, - "tests/aws/services/s3/test_s3.py::TestS3::test_access_bucket_different_region": 0.0017486310000549565, - "tests/aws/services/s3/test_s3.py::TestS3::test_bucket_availability": 0.03185725100024683, - "tests/aws/services/s3/test_s3.py::TestS3::test_bucket_does_not_exist": 0.442995412999835, - "tests/aws/services/s3/test_s3.py::TestS3::test_bucket_exists": 0.2364959850001469, - "tests/aws/services/s3/test_s3.py::TestS3::test_bucket_name_with_dots": 0.5560770519998641, - "tests/aws/services/s3/test_s3.py::TestS3::test_bucket_operation_between_regions": 0.464305233999994, - "tests/aws/services/s3/test_s3.py::TestS3::test_complete_multipart_parts_order": 0.5005493390001448, - "tests/aws/services/s3/test_s3.py::TestS3::test_copy_in_place_with_bucket_encryption": 0.1380110060001698, - "tests/aws/services/s3/test_s3.py::TestS3::test_copy_object_kms": 1.8048277220000273, - "tests/aws/services/s3/test_s3.py::TestS3::test_copy_object_special_character": 0.6493775710000591, - "tests/aws/services/s3/test_s3.py::TestS3::test_copy_object_special_character_plus_for_space": 0.09627962400008983, - "tests/aws/services/s3/test_s3.py::TestS3::test_create_bucket_head_bucket": 0.6483825300001627, - "tests/aws/services/s3/test_s3.py::TestS3::test_create_bucket_via_host_name": 0.039435483999795906, - "tests/aws/services/s3/test_s3.py::TestS3::test_create_bucket_with_existing_name": 0.4312836250003329, - "tests/aws/services/s3/test_s3.py::TestS3::test_delete_bucket_no_such_bucket": 0.01865536099990095, - "tests/aws/services/s3/test_s3.py::TestS3::test_delete_bucket_policy": 0.09831160800013095, - "tests/aws/services/s3/test_s3.py::TestS3::test_delete_bucket_policy_expected_bucket_owner": 0.10454281299985269, - "tests/aws/services/s3/test_s3.py::TestS3::test_delete_bucket_with_content": 0.7339347790000375, - "tests/aws/services/s3/test_s3.py::TestS3::test_delete_keys_in_versioned_bucket": 0.5232512129998668, - "tests/aws/services/s3/test_s3.py::TestS3::test_delete_non_existing_keys": 0.07548407600006612, - "tests/aws/services/s3/test_s3.py::TestS3::test_delete_non_existing_keys_in_non_existing_bucket": 0.02218930999993063, - "tests/aws/services/s3/test_s3.py::TestS3::test_delete_non_existing_keys_quiet": 0.07762034400002449, - "tests/aws/services/s3/test_s3.py::TestS3::test_delete_object_tagging": 0.105366852999623, - "tests/aws/services/s3/test_s3.py::TestS3::test_delete_objects_encoding": 0.10751101699997889, - "tests/aws/services/s3/test_s3.py::TestS3::test_different_location_constraint": 0.5964242960001229, - "tests/aws/services/s3/test_s3.py::TestS3::test_download_fileobj_multiple_range_requests": 1.1946407820000786, - "tests/aws/services/s3/test_s3.py::TestS3::test_empty_bucket_fixture": 0.14566269300007662, - "tests/aws/services/s3/test_s3.py::TestS3::test_etag_on_get_object_call": 0.474348831000043, - "tests/aws/services/s3/test_s3.py::TestS3::test_get_bucket_notification_configuration_no_such_bucket": 0.021005033999699663, - "tests/aws/services/s3/test_s3.py::TestS3::test_get_bucket_policy": 0.12237438299985115, - "tests/aws/services/s3/test_s3.py::TestS3::test_get_bucket_policy_invalid_account_id[0000000000020]": 0.06638687400004528, - "tests/aws/services/s3/test_s3.py::TestS3::test_get_bucket_policy_invalid_account_id[0000]": 0.06762299200022426, - "tests/aws/services/s3/test_s3.py::TestS3::test_get_bucket_policy_invalid_account_id[aa000000000$]": 0.06769106799993097, - "tests/aws/services/s3/test_s3.py::TestS3::test_get_bucket_policy_invalid_account_id[abcd]": 0.06730336200007514, - "tests/aws/services/s3/test_s3.py::TestS3::test_get_bucket_versioning_order": 0.5165583049997622, - "tests/aws/services/s3/test_s3.py::TestS3::test_get_obj_attrs_multi_headers_behavior": 0.08574432099976548, - "tests/aws/services/s3/test_s3.py::TestS3::test_get_object_after_deleted_in_versioned_bucket": 0.11993233900011546, - "tests/aws/services/s3/test_s3.py::TestS3::test_get_object_attributes": 0.30183377800017297, - "tests/aws/services/s3/test_s3.py::TestS3::test_get_object_attributes_versioned": 0.5053713419999895, - "tests/aws/services/s3/test_s3.py::TestS3::test_get_object_attributes_with_space": 0.0939985410002464, - "tests/aws/services/s3/test_s3.py::TestS3::test_get_object_content_length_with_virtual_host[False]": 0.09042158199986261, - "tests/aws/services/s3/test_s3.py::TestS3::test_get_object_content_length_with_virtual_host[True]": 0.09290480399999979, - "tests/aws/services/s3/test_s3.py::TestS3::test_get_object_no_such_bucket": 0.02057481699989694, - "tests/aws/services/s3/test_s3.py::TestS3::test_get_object_part": 0.2248842770002284, - "tests/aws/services/s3/test_s3.py::TestS3::test_get_object_part_checksum[COMPOSITE]": 0.11894790100018326, - "tests/aws/services/s3/test_s3.py::TestS3::test_get_object_part_checksum[FULL_OBJECT]": 0.11922658299999966, - "tests/aws/services/s3/test_s3.py::TestS3::test_get_object_with_anon_credentials": 0.49216677500021433, - "tests/aws/services/s3/test_s3.py::TestS3::test_get_range_object_headers": 0.0864914480000607, - "tests/aws/services/s3/test_s3.py::TestS3::test_head_object_fields": 0.10146788700012621, - "tests/aws/services/s3/test_s3.py::TestS3::test_invalid_range_error": 0.08767392099980498, - "tests/aws/services/s3/test_s3.py::TestS3::test_metadata_header_character_decoding": 0.4466715529999874, - "tests/aws/services/s3/test_s3.py::TestS3::test_multipart_and_list_parts": 0.185659412999712, - "tests/aws/services/s3/test_s3.py::TestS3::test_multipart_complete_multipart_too_small": 0.10430765999990399, - "tests/aws/services/s3/test_s3.py::TestS3::test_multipart_complete_multipart_wrong_part": 0.09496989799981748, - "tests/aws/services/s3/test_s3.py::TestS3::test_multipart_copy_object_etag": 0.127891155000043, - "tests/aws/services/s3/test_s3.py::TestS3::test_multipart_no_such_upload": 0.08794897699999638, - "tests/aws/services/s3/test_s3.py::TestS3::test_multipart_overwrite_key": 0.11405904100001862, - "tests/aws/services/s3/test_s3.py::TestS3::test_object_with_slashes_in_key[False]": 0.183374122000032, - "tests/aws/services/s3/test_s3.py::TestS3::test_object_with_slashes_in_key[True]": 0.18533284699969954, - "tests/aws/services/s3/test_s3.py::TestS3::test_precondition_failed_error": 0.09441950099972019, - "tests/aws/services/s3/test_s3.py::TestS3::test_put_and_get_object_with_content_language_disposition": 0.9461152449998735, - "tests/aws/services/s3/test_s3.py::TestS3::test_put_and_get_object_with_hash_prefix": 0.4468810759999542, - "tests/aws/services/s3/test_s3.py::TestS3::test_put_and_get_object_with_utf8_key": 0.44406913700004225, - "tests/aws/services/s3/test_s3.py::TestS3::test_put_bucket_inventory_config_order": 0.15632010600006652, - "tests/aws/services/s3/test_s3.py::TestS3::test_put_bucket_policy": 0.08910065499981101, - "tests/aws/services/s3/test_s3.py::TestS3::test_put_bucket_policy_expected_bucket_owner": 0.2555534179998631, - "tests/aws/services/s3/test_s3.py::TestS3::test_put_bucket_policy_invalid_account_id[0000000000020]": 0.06673398900011307, - "tests/aws/services/s3/test_s3.py::TestS3::test_put_bucket_policy_invalid_account_id[0000]": 0.06593606600017665, - "tests/aws/services/s3/test_s3.py::TestS3::test_put_bucket_policy_invalid_account_id[aa000000000$]": 0.064963766000119, - "tests/aws/services/s3/test_s3.py::TestS3::test_put_bucket_policy_invalid_account_id[abcd]": 0.0651437789999818, - "tests/aws/services/s3/test_s3.py::TestS3::test_put_get_object_single_character_trailing_slash": 0.14988147899998694, - "tests/aws/services/s3/test_s3.py::TestS3::test_put_get_object_special_character[a/%F0%9F%98%80/]": 0.45739597099986895, - "tests/aws/services/s3/test_s3.py::TestS3::test_put_get_object_special_character[file%2Fname]": 0.46246084400036125, - "tests/aws/services/s3/test_s3.py::TestS3::test_put_get_object_special_character[test key//]": 0.45868333299995356, - "tests/aws/services/s3/test_s3.py::TestS3::test_put_get_object_special_character[test key/]": 0.45826679900028466, - "tests/aws/services/s3/test_s3.py::TestS3::test_put_get_object_special_character[test%123/]": 0.460787074000109, - "tests/aws/services/s3/test_s3.py::TestS3::test_put_get_object_special_character[test%123]": 0.46762348399988696, - "tests/aws/services/s3/test_s3.py::TestS3::test_put_get_object_special_character[test%percent]": 0.4596633020000809, - "tests/aws/services/s3/test_s3.py::TestS3::test_put_get_object_special_character[test@key/]": 0.4557526539997525, - "tests/aws/services/s3/test_s3.py::TestS3::test_put_object_acl_on_delete_marker": 0.5163291420001315, - "tests/aws/services/s3/test_s3.py::TestS3::test_put_object_chunked_checksum": 0.10019167799987372, - "tests/aws/services/s3/test_s3.py::TestS3::test_put_object_chunked_content_encoding": 0.09516154200014171, - "tests/aws/services/s3/test_s3.py::TestS3::test_put_object_chunked_newlines": 0.07836589099997582, - "tests/aws/services/s3/test_s3.py::TestS3::test_put_object_chunked_newlines_no_sig": 0.07827823200000239, - "tests/aws/services/s3/test_s3.py::TestS3::test_put_object_chunked_newlines_no_sig_empty_body": 0.07769726199967408, - "tests/aws/services/s3/test_s3.py::TestS3::test_put_object_chunked_newlines_with_trailing_checksum": 0.10001367699987895, - "tests/aws/services/s3/test_s3.py::TestS3::test_put_object_storage_class[DEEP_ARCHIVE-False]": 0.09442486300008568, - "tests/aws/services/s3/test_s3.py::TestS3::test_put_object_storage_class[GLACIER-False]": 0.09736629899975924, - "tests/aws/services/s3/test_s3.py::TestS3::test_put_object_storage_class[GLACIER_IR-True]": 0.09885233299996798, - "tests/aws/services/s3/test_s3.py::TestS3::test_put_object_storage_class[INTELLIGENT_TIERING-True]": 0.09609571699979824, - "tests/aws/services/s3/test_s3.py::TestS3::test_put_object_storage_class[ONEZONE_IA-True]": 0.09924948000025324, - "tests/aws/services/s3/test_s3.py::TestS3::test_put_object_storage_class[REDUCED_REDUNDANCY-True]": 0.09991598099986732, - "tests/aws/services/s3/test_s3.py::TestS3::test_put_object_storage_class[STANDARD-True]": 0.09842562300013924, - "tests/aws/services/s3/test_s3.py::TestS3::test_put_object_storage_class[STANDARD_IA-True]": 0.09687286799976391, - "tests/aws/services/s3/test_s3.py::TestS3::test_put_object_storage_class_outposts": 0.07778246800012312, - "tests/aws/services/s3/test_s3.py::TestS3::test_put_object_tagging_empty_list": 0.12670672400008698, - "tests/aws/services/s3/test_s3.py::TestS3::test_put_object_with_md5_and_chunk_signature": 0.07696479600008388, - "tests/aws/services/s3/test_s3.py::TestS3::test_putobject_with_multiple_keys": 0.44356828500008305, - "tests/aws/services/s3/test_s3.py::TestS3::test_range_header_body_length": 0.10370441500003835, - "tests/aws/services/s3/test_s3.py::TestS3::test_range_key_not_exists": 0.06697710699995696, - "tests/aws/services/s3/test_s3.py::TestS3::test_region_header_exists_outside_us_east_1": 0.5508536620000086, - "tests/aws/services/s3/test_s3.py::TestS3::test_response_structure": 0.15892569399989043, - "tests/aws/services/s3/test_s3.py::TestS3::test_response_structure_get_obj_attrs": 0.11748295100005635, - "tests/aws/services/s3/test_s3.py::TestS3::test_s3_analytics_configurations": 0.215329526000005, - "tests/aws/services/s3/test_s3.py::TestS3::test_s3_batch_delete_objects": 0.48501359599981697, - "tests/aws/services/s3/test_s3.py::TestS3::test_s3_batch_delete_objects_using_requests_with_acl": 0.001871371000106592, - "tests/aws/services/s3/test_s3.py::TestS3::test_s3_batch_delete_public_objects_using_requests": 0.47506025199982105, - "tests/aws/services/s3/test_s3.py::TestS3::test_s3_bucket_acl": 0.15009417999976904, - "tests/aws/services/s3/test_s3.py::TestS3::test_s3_bucket_acl_exceptions": 0.1881077020000248, - "tests/aws/services/s3/test_s3.py::TestS3::test_s3_copy_content_type_and_metadata": 0.503202827999985, - "tests/aws/services/s3/test_s3.py::TestS3::test_s3_copy_metadata_directive_copy": 0.47129754899970067, - "tests/aws/services/s3/test_s3.py::TestS3::test_s3_copy_metadata_replace": 0.5013368309998896, - "tests/aws/services/s3/test_s3.py::TestS3::test_s3_copy_object_in_place": 1.7242066599994814, - "tests/aws/services/s3/test_s3.py::TestS3::test_s3_copy_object_in_place_metadata_directive": 0.549518634999913, - "tests/aws/services/s3/test_s3.py::TestS3::test_s3_copy_object_in_place_storage_class": 0.48520705500004624, - "tests/aws/services/s3/test_s3.py::TestS3::test_s3_copy_object_in_place_suspended_only": 0.5668245330000445, - "tests/aws/services/s3/test_s3.py::TestS3::test_s3_copy_object_in_place_versioned": 0.6097379250002177, - "tests/aws/services/s3/test_s3.py::TestS3::test_s3_copy_object_in_place_website_redirect_location": 0.4698999760000788, - "tests/aws/services/s3/test_s3.py::TestS3::test_s3_copy_object_in_place_with_encryption": 0.7784620590000486, - "tests/aws/services/s3/test_s3.py::TestS3::test_s3_copy_object_preconditions": 3.5279547219997767, - "tests/aws/services/s3/test_s3.py::TestS3::test_s3_copy_object_storage_class": 0.5087955059998421, - "tests/aws/services/s3/test_s3.py::TestS3::test_s3_copy_object_with_checksum[CRC32C]": 0.48330212700011543, - "tests/aws/services/s3/test_s3.py::TestS3::test_s3_copy_object_with_checksum[CRC32]": 0.5031673990001764, - "tests/aws/services/s3/test_s3.py::TestS3::test_s3_copy_object_with_checksum[CRC64NVME]": 0.482303279000007, - "tests/aws/services/s3/test_s3.py::TestS3::test_s3_copy_object_with_checksum[SHA1]": 0.4804120570001942, - "tests/aws/services/s3/test_s3.py::TestS3::test_s3_copy_object_with_checksum[SHA256]": 0.4918038920000072, - "tests/aws/services/s3/test_s3.py::TestS3::test_s3_copy_object_with_default_checksum[CRC32C]": 0.4949420430002647, - "tests/aws/services/s3/test_s3.py::TestS3::test_s3_copy_object_with_default_checksum[CRC32]": 0.4927352129998326, - "tests/aws/services/s3/test_s3.py::TestS3::test_s3_copy_object_with_default_checksum[CRC64NVME]": 0.5042494779997924, - "tests/aws/services/s3/test_s3.py::TestS3::test_s3_copy_object_with_default_checksum[SHA1]": 0.4941799700000047, - "tests/aws/services/s3/test_s3.py::TestS3::test_s3_copy_object_with_default_checksum[SHA256]": 0.49631447599995226, - "tests/aws/services/s3/test_s3.py::TestS3::test_s3_copy_object_wrong_format": 0.4249260090000462, - "tests/aws/services/s3/test_s3.py::TestS3::test_s3_copy_tagging_directive[COPY]": 0.48999527100022533, - "tests/aws/services/s3/test_s3.py::TestS3::test_s3_copy_tagging_directive[None]": 0.49378738499967767, - "tests/aws/services/s3/test_s3.py::TestS3::test_s3_copy_tagging_directive[REPLACE]": 0.49470431700001427, - "tests/aws/services/s3/test_s3.py::TestS3::test_s3_copy_tagging_directive_versioned[COPY]": 0.584358347000034, - "tests/aws/services/s3/test_s3.py::TestS3::test_s3_copy_tagging_directive_versioned[None]": 0.5843989630000124, - "tests/aws/services/s3/test_s3.py::TestS3::test_s3_copy_tagging_directive_versioned[REPLACE]": 0.5868629950002742, - "tests/aws/services/s3/test_s3.py::TestS3::test_s3_delete_object_with_version_id": 0.5145600200000899, - "tests/aws/services/s3/test_s3.py::TestS3::test_s3_delete_objects_trailing_slash": 0.07335199200019815, - "tests/aws/services/s3/test_s3.py::TestS3::test_s3_download_object_with_lambda": 4.231990113999927, - "tests/aws/services/s3/test_s3.py::TestS3::test_s3_get_object_header_overrides": 0.0895324600001004, - "tests/aws/services/s3/test_s3.py::TestS3::test_s3_get_object_headers": 0.1548024380001607, - "tests/aws/services/s3/test_s3.py::TestS3::test_s3_get_object_preconditions[get_object]": 3.5428688559998136, - "tests/aws/services/s3/test_s3.py::TestS3::test_s3_get_object_preconditions[head_object]": 3.5346619550002742, - "tests/aws/services/s3/test_s3.py::TestS3::test_s3_hostname_with_subdomain": 0.01983521500005736, - "tests/aws/services/s3/test_s3.py::TestS3::test_s3_intelligent_tier_config": 0.15954671299982692, - "tests/aws/services/s3/test_s3.py::TestS3::test_s3_invalid_content_md5": 16.293808780000063, - "tests/aws/services/s3/test_s3.py::TestS3::test_s3_inventory_report_crud": 0.16477751499996884, - "tests/aws/services/s3/test_s3.py::TestS3::test_s3_lambda_integration": 13.413261745, - "tests/aws/services/s3/test_s3.py::TestS3::test_s3_multipart_upload_acls": 0.20195804799982398, - "tests/aws/services/s3/test_s3.py::TestS3::test_s3_multipart_upload_sse": 0.20202871100013908, - "tests/aws/services/s3/test_s3.py::TestS3::test_s3_object_acl": 0.1634360029997879, - "tests/aws/services/s3/test_s3.py::TestS3::test_s3_object_acl_exceptions": 0.21919641499994214, - "tests/aws/services/s3/test_s3.py::TestS3::test_s3_object_expires": 0.49763248699969154, - "tests/aws/services/s3/test_s3.py::TestS3::test_s3_put_inventory_report_exceptions": 0.1587675539999509, - "tests/aws/services/s3/test_s3.py::TestS3::test_s3_put_more_than_1000_items": 12.836510378999947, - "tests/aws/services/s3/test_s3.py::TestS3::test_s3_put_object_versioned": 0.6401859249999688, - "tests/aws/services/s3/test_s3.py::TestS3::test_s3_raw_request_routing": 0.10220866500003467, - "tests/aws/services/s3/test_s3.py::TestS3::test_s3_request_payer": 0.07483815199998389, - "tests/aws/services/s3/test_s3.py::TestS3::test_s3_request_payer_exceptions": 0.07642289200020969, - "tests/aws/services/s3/test_s3.py::TestS3::test_s3_sse_bucket_key_default": 0.2345016869999199, - "tests/aws/services/s3/test_s3.py::TestS3::test_s3_sse_default_kms_key": 0.0018906969999079593, - "tests/aws/services/s3/test_s3.py::TestS3::test_s3_sse_validate_kms_key": 0.26955343799977527, - "tests/aws/services/s3/test_s3.py::TestS3::test_s3_sse_validate_kms_key_state": 0.2921022160003304, - "tests/aws/services/s3/test_s3.py::TestS3::test_s3_timestamp_precision": 0.10708111299959455, - "tests/aws/services/s3/test_s3.py::TestS3::test_s3_upload_download_gzip": 0.09241045499993561, - "tests/aws/services/s3/test_s3.py::TestS3::test_s3_uppercase_bucket_name": 0.377141213999721, - "tests/aws/services/s3/test_s3.py::TestS3::test_s3_uppercase_key_names": 0.09480276099998264, - "tests/aws/services/s3/test_s3.py::TestS3::test_set_external_hostname": 0.12955527399981293, - "tests/aws/services/s3/test_s3.py::TestS3::test_upload_big_file": 0.6076621139998224, - "tests/aws/services/s3/test_s3.py::TestS3::test_upload_file_multipart": 0.47794107999993685, - "tests/aws/services/s3/test_s3.py::TestS3::test_upload_file_with_xml_preamble": 0.4447776929998781, - "tests/aws/services/s3/test_s3.py::TestS3::test_upload_part_chunked_cancelled_valid_etag": 0.10952665200011324, - "tests/aws/services/s3/test_s3.py::TestS3::test_upload_part_chunked_newlines_valid_etag": 0.095215681000127, - "tests/aws/services/s3/test_s3.py::TestS3::test_url_encoded_key[False]": 0.13744821400018736, - "tests/aws/services/s3/test_s3.py::TestS3::test_url_encoded_key[True]": 0.14140231800024594, - "tests/aws/services/s3/test_s3.py::TestS3::test_virtual_host_proxy_does_not_decode_gzip": 0.08088519800026006, - "tests/aws/services/s3/test_s3.py::TestS3::test_virtual_host_proxying_headers": 0.09308547500017994, - "tests/aws/services/s3/test_s3.py::TestS3BucketLifecycle::test_bucket_lifecycle_configuration_date": 0.07556624800008649, - "tests/aws/services/s3/test_s3.py::TestS3BucketLifecycle::test_bucket_lifecycle_configuration_object_expiry": 0.11511457500000688, - "tests/aws/services/s3/test_s3.py::TestS3BucketLifecycle::test_bucket_lifecycle_configuration_object_expiry_versioned": 0.16264005399966663, - "tests/aws/services/s3/test_s3.py::TestS3BucketLifecycle::test_bucket_lifecycle_multiple_rules": 0.12373508300038338, - "tests/aws/services/s3/test_s3.py::TestS3BucketLifecycle::test_bucket_lifecycle_object_size_rules": 0.12103660599973409, - "tests/aws/services/s3/test_s3.py::TestS3BucketLifecycle::test_bucket_lifecycle_tag_rules": 0.1864694339997186, - "tests/aws/services/s3/test_s3.py::TestS3BucketLifecycle::test_delete_bucket_lifecycle_configuration": 0.10909918199990898, - "tests/aws/services/s3/test_s3.py::TestS3BucketLifecycle::test_delete_lifecycle_configuration_on_bucket_deletion": 0.11447274999977708, - "tests/aws/services/s3/test_s3.py::TestS3BucketLifecycle::test_lifecycle_expired_object_delete_marker": 0.10766789400008747, - "tests/aws/services/s3/test_s3.py::TestS3BucketLifecycle::test_object_expiry_after_bucket_lifecycle_configuration": 0.12545405899982143, - "tests/aws/services/s3/test_s3.py::TestS3BucketLifecycle::test_put_bucket_lifecycle_conf_exc": 0.13621729500027868, - "tests/aws/services/s3/test_s3.py::TestS3BucketLifecycle::test_s3_transition_default_minimum_object_size": 0.12344293799992556, - "tests/aws/services/s3/test_s3.py::TestS3BucketLogging::test_put_bucket_logging": 0.14712272800011306, - "tests/aws/services/s3/test_s3.py::TestS3BucketLogging::test_put_bucket_logging_accept_wrong_grants": 0.12814029600008325, - "tests/aws/services/s3/test_s3.py::TestS3BucketLogging::test_put_bucket_logging_cross_locations": 0.16679735099978643, - "tests/aws/services/s3/test_s3.py::TestS3BucketLogging::test_put_bucket_logging_wrong_target": 0.12091947999988406, - "tests/aws/services/s3/test_s3.py::TestS3BucketReplication::test_replication_config": 0.6489285249999739, - "tests/aws/services/s3/test_s3.py::TestS3BucketReplication::test_replication_config_without_filter": 0.6253546460000052, - "tests/aws/services/s3/test_s3.py::TestS3DeepArchive::test_s3_get_deep_archive_object_restore": 0.5476258169996981, - "tests/aws/services/s3/test_s3.py::TestS3DeepArchive::test_storage_class_deep_archive": 0.16768664100027308, - "tests/aws/services/s3/test_s3.py::TestS3MultiAccounts::test_cross_account_access": 0.12797023200005242, - "tests/aws/services/s3/test_s3.py::TestS3MultiAccounts::test_cross_account_copy_object": 0.09101696399989123, - "tests/aws/services/s3/test_s3.py::TestS3MultiAccounts::test_shared_bucket_namespace": 0.06650550199992722, - "tests/aws/services/s3/test_s3.py::TestS3MultipartUploadChecksum::test_complete_multipart_parts_checksum_composite[CRC32C]": 0.4924921930000892, - "tests/aws/services/s3/test_s3.py::TestS3MultipartUploadChecksum::test_complete_multipart_parts_checksum_composite[CRC32]": 0.4872010119997867, - "tests/aws/services/s3/test_s3.py::TestS3MultipartUploadChecksum::test_complete_multipart_parts_checksum_composite[SHA1]": 1.703371787000151, - "tests/aws/services/s3/test_s3.py::TestS3MultipartUploadChecksum::test_complete_multipart_parts_checksum_composite[SHA256]": 0.4968547049998051, - "tests/aws/services/s3/test_s3.py::TestS3MultipartUploadChecksum::test_complete_multipart_parts_checksum_default": 0.20930307599974185, - "tests/aws/services/s3/test_s3.py::TestS3MultipartUploadChecksum::test_complete_multipart_parts_checksum_full_object[CRC32C]": 0.5267858390000129, - "tests/aws/services/s3/test_s3.py::TestS3MultipartUploadChecksum::test_complete_multipart_parts_checksum_full_object[CRC32]": 0.51732115599998, - "tests/aws/services/s3/test_s3.py::TestS3MultipartUploadChecksum::test_complete_multipart_parts_checksum_full_object[CRC64NVME]": 0.5810182650002389, - "tests/aws/services/s3/test_s3.py::TestS3MultipartUploadChecksum::test_complete_multipart_parts_checksum_full_object_default": 0.12582673300016722, - "tests/aws/services/s3/test_s3.py::TestS3MultipartUploadChecksum::test_multipart_checksum_type_compatibility[COMPOSITE-CRC32C]": 0.0678138199998557, - "tests/aws/services/s3/test_s3.py::TestS3MultipartUploadChecksum::test_multipart_checksum_type_compatibility[COMPOSITE-CRC32]": 0.07099052600005962, - "tests/aws/services/s3/test_s3.py::TestS3MultipartUploadChecksum::test_multipart_checksum_type_compatibility[COMPOSITE-CRC64NVME]": 0.06987649799998508, - "tests/aws/services/s3/test_s3.py::TestS3MultipartUploadChecksum::test_multipart_checksum_type_compatibility[COMPOSITE-SHA1]": 0.06779095599995344, - "tests/aws/services/s3/test_s3.py::TestS3MultipartUploadChecksum::test_multipart_checksum_type_compatibility[COMPOSITE-SHA256]": 0.06717508799988536, - "tests/aws/services/s3/test_s3.py::TestS3MultipartUploadChecksum::test_multipart_checksum_type_compatibility[FULL_OBJECT-CRC32C]": 0.06883174099993994, - "tests/aws/services/s3/test_s3.py::TestS3MultipartUploadChecksum::test_multipart_checksum_type_compatibility[FULL_OBJECT-CRC32]": 0.06701414700000896, - "tests/aws/services/s3/test_s3.py::TestS3MultipartUploadChecksum::test_multipart_checksum_type_compatibility[FULL_OBJECT-CRC64NVME]": 0.07285982200005492, - "tests/aws/services/s3/test_s3.py::TestS3MultipartUploadChecksum::test_multipart_checksum_type_compatibility[FULL_OBJECT-SHA1]": 0.06858481399990524, - "tests/aws/services/s3/test_s3.py::TestS3MultipartUploadChecksum::test_multipart_checksum_type_compatibility[FULL_OBJECT-SHA256]": 0.07112180200010698, - "tests/aws/services/s3/test_s3.py::TestS3MultipartUploadChecksum::test_multipart_checksum_type_default_for_checksum[CRC32C]": 0.07341224199990393, - "tests/aws/services/s3/test_s3.py::TestS3MultipartUploadChecksum::test_multipart_checksum_type_default_for_checksum[CRC32]": 0.06681469099999049, - "tests/aws/services/s3/test_s3.py::TestS3MultipartUploadChecksum::test_multipart_checksum_type_default_for_checksum[CRC64NVME]": 0.09842143099990608, - "tests/aws/services/s3/test_s3.py::TestS3MultipartUploadChecksum::test_multipart_checksum_type_default_for_checksum[SHA1]": 0.08208724399992207, - "tests/aws/services/s3/test_s3.py::TestS3MultipartUploadChecksum::test_multipart_checksum_type_default_for_checksum[SHA256]": 0.08854464099999859, - "tests/aws/services/s3/test_s3.py::TestS3MultipartUploadChecksum::test_multipart_parts_checksum_exceptions_composite": 5.995401754999875, - "tests/aws/services/s3/test_s3.py::TestS3MultipartUploadChecksum::test_multipart_parts_checksum_exceptions_full_object": 44.126159716000075, - "tests/aws/services/s3/test_s3.py::TestS3MultipartUploadChecksum::test_multipart_size_validation": 0.11377745500021774, - "tests/aws/services/s3/test_s3.py::TestS3MultipartUploadChecksum::test_multipart_upload_part_checksum_exception[CRC32C]": 6.645884354999907, - "tests/aws/services/s3/test_s3.py::TestS3MultipartUploadChecksum::test_multipart_upload_part_checksum_exception[CRC32]": 9.78470028799984, - "tests/aws/services/s3/test_s3.py::TestS3MultipartUploadChecksum::test_multipart_upload_part_checksum_exception[CRC64NVME]": 9.880132203999892, - "tests/aws/services/s3/test_s3.py::TestS3MultipartUploadChecksum::test_multipart_upload_part_checksum_exception[SHA1]": 6.455737881000232, - "tests/aws/services/s3/test_s3.py::TestS3MultipartUploadChecksum::test_multipart_upload_part_checksum_exception[SHA256]": 3.4859419279998747, - "tests/aws/services/s3/test_s3.py::TestS3MultipartUploadChecksum::test_multipart_upload_part_copy_checksum[COMPOSITE]": 0.15403546099992127, - "tests/aws/services/s3/test_s3.py::TestS3MultipartUploadChecksum::test_multipart_upload_part_copy_checksum[FULL_OBJECT]": 0.15049404900014451, - "tests/aws/services/s3/test_s3.py::TestS3ObjectLockLegalHold::test_delete_locked_object": 0.12456764200010184, - "tests/aws/services/s3/test_s3.py::TestS3ObjectLockLegalHold::test_put_get_object_legal_hold": 0.13135895799996433, - "tests/aws/services/s3/test_s3.py::TestS3ObjectLockLegalHold::test_put_object_legal_hold_exc": 0.16820367800005442, - "tests/aws/services/s3/test_s3.py::TestS3ObjectLockLegalHold::test_put_object_with_legal_hold": 0.10578436700006932, - "tests/aws/services/s3/test_s3.py::TestS3ObjectLockLegalHold::test_s3_copy_object_legal_hold": 0.5001171900000827, - "tests/aws/services/s3/test_s3.py::TestS3ObjectLockLegalHold::test_s3_legal_hold_lock_versioned": 0.5354722340000535, - "tests/aws/services/s3/test_s3.py::TestS3ObjectLockRetention::test_bucket_config_default_retention": 0.13977304100012589, - "tests/aws/services/s3/test_s3.py::TestS3ObjectLockRetention::test_object_lock_delete_markers": 0.12150426799985325, - "tests/aws/services/s3/test_s3.py::TestS3ObjectLockRetention::test_object_lock_extend_duration": 0.1252291459998105, - "tests/aws/services/s3/test_s3.py::TestS3ObjectLockRetention::test_s3_copy_object_retention_lock": 0.4871093750000455, - "tests/aws/services/s3/test_s3.py::TestS3ObjectLockRetention::test_s3_object_lock_mode_validation": 0.10240302600004725, - "tests/aws/services/s3/test_s3.py::TestS3ObjectLockRetention::test_s3_object_retention": 6.167359015000102, - "tests/aws/services/s3/test_s3.py::TestS3ObjectLockRetention::test_s3_object_retention_compliance_mode": 6.143150704999925, - "tests/aws/services/s3/test_s3.py::TestS3ObjectLockRetention::test_s3_object_retention_exc": 0.25584264499980236, - "tests/aws/services/s3/test_s3.py::TestS3PresignedPost::test_post_object_default_checksum": 0.08964415400009784, - "tests/aws/services/s3/test_s3.py::TestS3PresignedPost::test_post_object_policy_casing[s3]": 0.09737008900015098, - "tests/aws/services/s3/test_s3.py::TestS3PresignedPost::test_post_object_policy_casing[s3v4]": 0.09765324900013184, - "tests/aws/services/s3/test_s3.py::TestS3PresignedPost::test_post_object_policy_conditions_validation_eq": 0.33423685400020986, - "tests/aws/services/s3/test_s3.py::TestS3PresignedPost::test_post_object_policy_conditions_validation_starts_with": 0.2863945550000153, - "tests/aws/services/s3/test_s3.py::TestS3PresignedPost::test_post_object_policy_validation_size": 0.225660150000067, - "tests/aws/services/s3/test_s3.py::TestS3PresignedPost::test_post_object_with_file_as_string": 0.33441127000014603, - "tests/aws/services/s3/test_s3.py::TestS3PresignedPost::test_post_object_with_files": 0.1310648549999769, - "tests/aws/services/s3/test_s3.py::TestS3PresignedPost::test_post_object_with_metadata": 0.09244160699995518, - "tests/aws/services/s3/test_s3.py::TestS3PresignedPost::test_post_object_with_storage_class": 0.31854475299974183, - "tests/aws/services/s3/test_s3.py::TestS3PresignedPost::test_post_object_with_tags[invalid]": 0.16174729999988813, - "tests/aws/services/s3/test_s3.py::TestS3PresignedPost::test_post_object_with_tags[list]": 0.16247338700009095, - "tests/aws/services/s3/test_s3.py::TestS3PresignedPost::test_post_object_with_tags[notxml]": 0.15113466499974493, - "tests/aws/services/s3/test_s3.py::TestS3PresignedPost::test_post_object_with_tags[single]": 0.1644751809999434, - "tests/aws/services/s3/test_s3.py::TestS3PresignedPost::test_post_object_with_wrong_content_type": 0.1412795940000251, - "tests/aws/services/s3/test_s3.py::TestS3PresignedPost::test_post_request_expires": 3.1496385340001325, - "tests/aws/services/s3/test_s3.py::TestS3PresignedPost::test_post_request_malformed_policy[s3]": 0.15481132399986564, - "tests/aws/services/s3/test_s3.py::TestS3PresignedPost::test_post_request_malformed_policy[s3v4]": 0.15611405300023762, - "tests/aws/services/s3/test_s3.py::TestS3PresignedPost::test_post_request_missing_fields[s3]": 0.16445087699980832, - "tests/aws/services/s3/test_s3.py::TestS3PresignedPost::test_post_request_missing_fields[s3v4]": 0.1629994150002858, - "tests/aws/services/s3/test_s3.py::TestS3PresignedPost::test_post_request_missing_signature[s3]": 0.15336242799980937, - "tests/aws/services/s3/test_s3.py::TestS3PresignedPost::test_post_request_missing_signature[s3v4]": 0.1569561880000947, - "tests/aws/services/s3/test_s3.py::TestS3PresignedPost::test_presigned_post_with_different_user_credentials": 0.1868553190001876, - "tests/aws/services/s3/test_s3.py::TestS3PresignedPost::test_s3_presigned_post_success_action_redirect": 0.08866975199998706, - "tests/aws/services/s3/test_s3.py::TestS3PresignedPost::test_s3_presigned_post_success_action_status_201_response": 0.07820224200008852, - "tests/aws/services/s3/test_s3.py::TestS3PresignedUrl::test_delete_has_empty_content_length_header": 0.09265035800012811, - "tests/aws/services/s3/test_s3.py::TestS3PresignedUrl::test_get_object_ignores_request_body": 0.08648766899978, - "tests/aws/services/s3/test_s3.py::TestS3PresignedUrl::test_get_request_expires_ignored_if_validation_disabled": 3.109025590999863, - "tests/aws/services/s3/test_s3.py::TestS3PresignedUrl::test_head_has_correct_content_length_header": 0.08327757000029123, - "tests/aws/services/s3/test_s3.py::TestS3PresignedUrl::test_pre_signed_url_forward_slash_bucket": 0.09578064700008326, - "tests/aws/services/s3/test_s3.py::TestS3PresignedUrl::test_pre_signed_url_if_match": 0.10110482899995077, - "tests/aws/services/s3/test_s3.py::TestS3PresignedUrl::test_pre_signed_url_if_none_match": 0.09951126800001475, - "tests/aws/services/s3/test_s3.py::TestS3PresignedUrl::test_presign_check_signature_validation_for_port_permutation": 0.11306825900010153, - "tests/aws/services/s3/test_s3.py::TestS3PresignedUrl::test_presign_with_additional_query_params": 0.11148853300005612, - "tests/aws/services/s3/test_s3.py::TestS3PresignedUrl::test_presigned_double_encoded_credentials": 0.17418193900016377, - "tests/aws/services/s3/test_s3.py::TestS3PresignedUrl::test_presigned_url_signature_authentication[s3-False]": 0.2228159900000719, - "tests/aws/services/s3/test_s3.py::TestS3PresignedUrl::test_presigned_url_signature_authentication[s3-True]": 0.2214356219999445, - "tests/aws/services/s3/test_s3.py::TestS3PresignedUrl::test_presigned_url_signature_authentication[s3v4-False]": 0.22835048299975824, - "tests/aws/services/s3/test_s3.py::TestS3PresignedUrl::test_presigned_url_signature_authentication[s3v4-True]": 0.22568844299985358, - "tests/aws/services/s3/test_s3.py::TestS3PresignedUrl::test_presigned_url_signature_authentication_expired[s3-False]": 2.1717648670000926, - "tests/aws/services/s3/test_s3.py::TestS3PresignedUrl::test_presigned_url_signature_authentication_expired[s3-True]": 2.173695236999947, - "tests/aws/services/s3/test_s3.py::TestS3PresignedUrl::test_presigned_url_signature_authentication_expired[s3v4-False]": 2.1736832009999034, - "tests/aws/services/s3/test_s3.py::TestS3PresignedUrl::test_presigned_url_signature_authentication_expired[s3v4-True]": 2.1713889339998786, - "tests/aws/services/s3/test_s3.py::TestS3PresignedUrl::test_presigned_url_signature_authentication_multi_part[s3-False]": 0.11522889000002579, - "tests/aws/services/s3/test_s3.py::TestS3PresignedUrl::test_presigned_url_signature_authentication_multi_part[s3-True]": 0.11730858400005673, - "tests/aws/services/s3/test_s3.py::TestS3PresignedUrl::test_presigned_url_signature_authentication_multi_part[s3v4-False]": 0.11764146600012282, - "tests/aws/services/s3/test_s3.py::TestS3PresignedUrl::test_presigned_url_signature_authentication_multi_part[s3v4-True]": 0.11754028900031699, - "tests/aws/services/s3/test_s3.py::TestS3PresignedUrl::test_presigned_url_v4_signed_headers_in_qs": 1.9072212909998143, - "tests/aws/services/s3/test_s3.py::TestS3PresignedUrl::test_presigned_url_v4_x_amz_in_qs": 8.019245741000077, - "tests/aws/services/s3/test_s3.py::TestS3PresignedUrl::test_presigned_url_with_different_user_credentials": 0.18860384600020552, - "tests/aws/services/s3/test_s3.py::TestS3PresignedUrl::test_presigned_url_with_session_token": 0.1129452449999917, - "tests/aws/services/s3/test_s3.py::TestS3PresignedUrl::test_put_object": 0.48203289000025507, - "tests/aws/services/s3/test_s3.py::TestS3PresignedUrl::test_put_object_with_md5_and_chunk_signature_bad_headers[s3-False]": 0.0940135979999468, - "tests/aws/services/s3/test_s3.py::TestS3PresignedUrl::test_put_object_with_md5_and_chunk_signature_bad_headers[s3-True]": 0.16985056200019244, - "tests/aws/services/s3/test_s3.py::TestS3PresignedUrl::test_put_object_with_md5_and_chunk_signature_bad_headers[s3v4-False]": 0.09099461800019526, - "tests/aws/services/s3/test_s3.py::TestS3PresignedUrl::test_put_object_with_md5_and_chunk_signature_bad_headers[s3v4-True]": 0.16457293199982814, - "tests/aws/services/s3/test_s3.py::TestS3PresignedUrl::test_put_url_metadata_with_sig_s3[False]": 0.5480833710003026, - "tests/aws/services/s3/test_s3.py::TestS3PresignedUrl::test_put_url_metadata_with_sig_s3[True]": 0.5458836749999136, - "tests/aws/services/s3/test_s3.py::TestS3PresignedUrl::test_put_url_metadata_with_sig_s3v4[False]": 1.7052311170000394, - "tests/aws/services/s3/test_s3.py::TestS3PresignedUrl::test_put_url_metadata_with_sig_s3v4[True]": 0.5647740000001704, - "tests/aws/services/s3/test_s3.py::TestS3PresignedUrl::test_s3_copy_md5": 0.11310218299990993, - "tests/aws/services/s3/test_s3.py::TestS3PresignedUrl::test_s3_get_response_case_sensitive_headers": 0.08377304500004357, - "tests/aws/services/s3/test_s3.py::TestS3PresignedUrl::test_s3_get_response_content_type_same_as_upload_and_range": 0.09609183399993526, - "tests/aws/services/s3/test_s3.py::TestS3PresignedUrl::test_s3_get_response_default_content_type": 0.08504755399985697, - "tests/aws/services/s3/test_s3.py::TestS3PresignedUrl::test_s3_get_response_header_overrides[s3]": 0.09542536000003565, - "tests/aws/services/s3/test_s3.py::TestS3PresignedUrl::test_s3_get_response_header_overrides[s3v4]": 0.09687690800024029, - "tests/aws/services/s3/test_s3.py::TestS3PresignedUrl::test_s3_ignored_special_headers": 0.13168041500011896, - "tests/aws/services/s3/test_s3.py::TestS3PresignedUrl::test_s3_presign_url_encoding[s3]": 0.09419521700033329, - "tests/aws/services/s3/test_s3.py::TestS3PresignedUrl::test_s3_presign_url_encoding[s3v4]": 0.10866914199982602, - "tests/aws/services/s3/test_s3.py::TestS3PresignedUrl::test_s3_presigned_url_expired[s3]": 3.197364440000001, - "tests/aws/services/s3/test_s3.py::TestS3PresignedUrl::test_s3_presigned_url_expired[s3v4]": 3.195593658000007, - "tests/aws/services/s3/test_s3.py::TestS3PresignedUrl::test_s3_put_presigned_url_missing_sig_param[s3]": 0.17181701300000896, - "tests/aws/services/s3/test_s3.py::TestS3PresignedUrl::test_s3_put_presigned_url_missing_sig_param[s3v4]": 0.17292209400011416, - "tests/aws/services/s3/test_s3.py::TestS3PresignedUrl::test_s3_put_presigned_url_same_header_and_qs_parameter": 0.1886692419998326, - "tests/aws/services/s3/test_s3.py::TestS3PresignedUrl::test_s3_put_presigned_url_with_different_headers[s3]": 1.3132659729999432, - "tests/aws/services/s3/test_s3.py::TestS3PresignedUrl::test_s3_put_presigned_url_with_different_headers[s3v4]": 0.21828577500014035, - "tests/aws/services/s3/test_s3.py::TestS3PutObjectChecksum::test_put_object_checksum[CRC32C]": 8.932304074000058, - "tests/aws/services/s3/test_s3.py::TestS3PutObjectChecksum::test_put_object_checksum[CRC32]": 9.319452923999961, - "tests/aws/services/s3/test_s3.py::TestS3PutObjectChecksum::test_put_object_checksum[CRC64NVME]": 8.379377974999898, - "tests/aws/services/s3/test_s3.py::TestS3PutObjectChecksum::test_put_object_checksum[SHA1]": 9.80005773899984, - "tests/aws/services/s3/test_s3.py::TestS3PutObjectChecksum::test_put_object_checksum[SHA256]": 2.522417633999794, - "tests/aws/services/s3/test_s3.py::TestS3PutObjectChecksum::test_s3_checksum_no_algorithm": 0.10919821699985732, - "tests/aws/services/s3/test_s3.py::TestS3PutObjectChecksum::test_s3_checksum_no_automatic_sdk_calculation": 0.24834114000009322, - "tests/aws/services/s3/test_s3.py::TestS3PutObjectChecksum::test_s3_checksum_with_content_encoding": 0.10795666199987863, - "tests/aws/services/s3/test_s3.py::TestS3PutObjectChecksum::test_s3_get_object_checksum[CRC32C]": 0.11676444999989144, - "tests/aws/services/s3/test_s3.py::TestS3PutObjectChecksum::test_s3_get_object_checksum[CRC32]": 0.12319164199971055, - "tests/aws/services/s3/test_s3.py::TestS3PutObjectChecksum::test_s3_get_object_checksum[CRC64NVME]": 0.11668438800006697, - "tests/aws/services/s3/test_s3.py::TestS3PutObjectChecksum::test_s3_get_object_checksum[None]": 0.11696784499963542, - "tests/aws/services/s3/test_s3.py::TestS3PutObjectChecksum::test_s3_get_object_checksum[SHA1]": 0.12171969400014859, - "tests/aws/services/s3/test_s3.py::TestS3PutObjectChecksum::test_s3_get_object_checksum[SHA256]": 0.11798366700008955, - "tests/aws/services/s3/test_s3.py::TestS3Routing::test_access_favicon_via_aws_endpoints[s3.amazonaws.com-False]": 0.0971813750002184, - "tests/aws/services/s3/test_s3.py::TestS3Routing::test_access_favicon_via_aws_endpoints[s3.amazonaws.com-True]": 0.09137503800002378, - "tests/aws/services/s3/test_s3.py::TestS3Routing::test_access_favicon_via_aws_endpoints[s3.us-west-2.amazonaws.com-False]": 0.09005470500005686, - "tests/aws/services/s3/test_s3.py::TestS3Routing::test_access_favicon_via_aws_endpoints[s3.us-west-2.amazonaws.com-True]": 0.09333476700021492, - "tests/aws/services/s3/test_s3.py::TestS3SSECEncryption::test_copy_object_with_sse_c": 0.22744315900013135, - "tests/aws/services/s3/test_s3.py::TestS3SSECEncryption::test_multipart_upload_sse_c": 0.46468152700003884, - "tests/aws/services/s3/test_s3.py::TestS3SSECEncryption::test_multipart_upload_sse_c_validation": 0.19172914499995386, - "tests/aws/services/s3/test_s3.py::TestS3SSECEncryption::test_object_retrieval_sse_c": 0.24756637799987402, - "tests/aws/services/s3/test_s3.py::TestS3SSECEncryption::test_put_object_default_checksum_with_sse_c": 0.1834542720000627, - "tests/aws/services/s3/test_s3.py::TestS3SSECEncryption::test_put_object_lifecycle_with_sse_c": 0.17973785000003772, - "tests/aws/services/s3/test_s3.py::TestS3SSECEncryption::test_put_object_validation_sse_c": 0.2096024360002957, - "tests/aws/services/s3/test_s3.py::TestS3SSECEncryption::test_sse_c_with_versioning": 0.2255204099999446, - "tests/aws/services/s3/test_s3.py::TestS3StaticWebsiteHosting::test_crud_website_configuration": 0.1348569429997042, - "tests/aws/services/s3/test_s3.py::TestS3StaticWebsiteHosting::test_object_website_redirect_location": 0.2632792670001436, - "tests/aws/services/s3/test_s3.py::TestS3StaticWebsiteHosting::test_routing_rules_conditions": 0.52639506599985, - "tests/aws/services/s3/test_s3.py::TestS3StaticWebsiteHosting::test_routing_rules_empty_replace_prefix": 0.416377175000207, - "tests/aws/services/s3/test_s3.py::TestS3StaticWebsiteHosting::test_routing_rules_order": 0.24217604599994047, - "tests/aws/services/s3/test_s3.py::TestS3StaticWebsiteHosting::test_routing_rules_redirects": 0.14829959699977735, - "tests/aws/services/s3/test_s3.py::TestS3StaticWebsiteHosting::test_s3_static_website_hosting": 0.5323913270001412, - "tests/aws/services/s3/test_s3.py::TestS3StaticWebsiteHosting::test_s3_static_website_index": 0.14434141200013073, - "tests/aws/services/s3/test_s3.py::TestS3StaticWebsiteHosting::test_validate_website_configuration": 0.23589379899976848, - "tests/aws/services/s3/test_s3.py::TestS3StaticWebsiteHosting::test_website_hosting_404": 0.21473044800018215, - "tests/aws/services/s3/test_s3.py::TestS3StaticWebsiteHosting::test_website_hosting_http_methods": 0.1471398159999353, - "tests/aws/services/s3/test_s3.py::TestS3StaticWebsiteHosting::test_website_hosting_index_lookup": 0.26823874100023204, - "tests/aws/services/s3/test_s3.py::TestS3StaticWebsiteHosting::test_website_hosting_no_such_website": 0.13154439799995998, - "tests/aws/services/s3/test_s3.py::TestS3StaticWebsiteHosting::test_website_hosting_redirect_all": 0.33585309700015387, - "tests/aws/services/s3/test_s3.py::TestS3TerraformRawRequests::test_terraform_request_sequence": 0.05717769500006398, - "tests/aws/services/s3/test_s3_api.py::TestS3BucketAccelerateConfiguration::test_bucket_acceleration_configuration_crud": 0.09692792099986036, - "tests/aws/services/s3/test_s3_api.py::TestS3BucketAccelerateConfiguration::test_bucket_acceleration_configuration_exc": 0.12453588200014565, - "tests/aws/services/s3/test_s3_api.py::TestS3BucketCRUD::test_delete_bucket_with_objects": 0.430555153999876, - "tests/aws/services/s3/test_s3_api.py::TestS3BucketCRUD::test_delete_versioned_bucket_with_objects": 0.4677492540001822, - "tests/aws/services/s3/test_s3_api.py::TestS3BucketEncryption::test_s3_bucket_encryption_sse_kms": 0.22394202499981475, - "tests/aws/services/s3/test_s3_api.py::TestS3BucketEncryption::test_s3_bucket_encryption_sse_kms_aws_managed_key": 0.2674113179998585, - "tests/aws/services/s3/test_s3_api.py::TestS3BucketEncryption::test_s3_bucket_encryption_sse_s3": 0.10482472499984397, - "tests/aws/services/s3/test_s3_api.py::TestS3BucketEncryption::test_s3_default_bucket_encryption": 0.08774058700009846, - "tests/aws/services/s3/test_s3_api.py::TestS3BucketEncryption::test_s3_default_bucket_encryption_exc": 0.47203817400031767, - "tests/aws/services/s3/test_s3_api.py::TestS3BucketNotificationConfiguration::test_bucket_notification_with_invalid_filter_rules": 0.11899933900008364, - "tests/aws/services/s3/test_s3_api.py::TestS3BucketNotificationConfiguration::test_bucket_notification_with_missing_values_in_rule": 0.21586082000021634, - "tests/aws/services/s3/test_s3_api.py::TestS3BucketObjectTagging::test_bucket_tagging_crud": 0.13555040099981852, - "tests/aws/services/s3/test_s3_api.py::TestS3BucketObjectTagging::test_bucket_tagging_exc": 0.08274651000010635, - "tests/aws/services/s3/test_s3_api.py::TestS3BucketObjectTagging::test_object_tagging_crud": 0.15301349399965147, - "tests/aws/services/s3/test_s3_api.py::TestS3BucketObjectTagging::test_object_tagging_exc": 0.20528559099989252, - "tests/aws/services/s3/test_s3_api.py::TestS3BucketObjectTagging::test_object_tagging_versioned": 0.1986481349999849, - "tests/aws/services/s3/test_s3_api.py::TestS3BucketObjectTagging::test_object_tags_delete_or_overwrite_object": 0.13517855300005976, - "tests/aws/services/s3/test_s3_api.py::TestS3BucketObjectTagging::test_put_bucket_tagging_none_value": 0.08500250500014772, - "tests/aws/services/s3/test_s3_api.py::TestS3BucketObjectTagging::test_put_object_tagging_none_value": 0.09442092499966748, - "tests/aws/services/s3/test_s3_api.py::TestS3BucketObjectTagging::test_put_object_with_tags": 0.19512392299975545, - "tests/aws/services/s3/test_s3_api.py::TestS3BucketObjectTagging::test_tagging_validation": 0.17709817400009342, - "tests/aws/services/s3/test_s3_api.py::TestS3BucketOwnershipControls::test_bucket_ownership_controls_exc": 0.10845528499999091, - "tests/aws/services/s3/test_s3_api.py::TestS3BucketOwnershipControls::test_crud_bucket_ownership_controls": 0.15815052800007834, - "tests/aws/services/s3/test_s3_api.py::TestS3BucketPolicy::test_bucket_policy_crud": 0.11518049899973448, - "tests/aws/services/s3/test_s3_api.py::TestS3BucketPolicy::test_bucket_policy_exc": 0.09438143100010166, - "tests/aws/services/s3/test_s3_api.py::TestS3BucketVersioning::test_bucket_versioning_crud": 0.18286976000035793, - "tests/aws/services/s3/test_s3_api.py::TestS3BucketVersioning::test_object_version_id_format": 0.09867107100012618, - "tests/aws/services/s3/test_s3_api.py::TestS3DeletePrecondition::test_delete_object_if_match_all_non_express": 0.0869366470001296, - "tests/aws/services/s3/test_s3_api.py::TestS3DeletePrecondition::test_delete_object_if_match_modified_non_express": 0.08247515399989425, - "tests/aws/services/s3/test_s3_api.py::TestS3DeletePrecondition::test_delete_object_if_match_non_express": 0.08132224700011648, - "tests/aws/services/s3/test_s3_api.py::TestS3DeletePrecondition::test_delete_object_if_match_size_non_express": 0.08338450299993383, - "tests/aws/services/s3/test_s3_api.py::TestS3MetricsConfiguration::test_delete_metrics_configuration": 0.07831027000020185, - "tests/aws/services/s3/test_s3_api.py::TestS3MetricsConfiguration::test_delete_metrics_configuration_twice": 0.07694640300019273, - "tests/aws/services/s3/test_s3_api.py::TestS3MetricsConfiguration::test_get_bucket_metrics_configuration": 0.07255867999992915, - "tests/aws/services/s3/test_s3_api.py::TestS3MetricsConfiguration::test_get_bucket_metrics_configuration_not_exist": 0.062028752000060194, - "tests/aws/services/s3/test_s3_api.py::TestS3MetricsConfiguration::test_list_bucket_metrics_configurations": 0.08398023600011584, - "tests/aws/services/s3/test_s3_api.py::TestS3MetricsConfiguration::test_list_bucket_metrics_configurations_paginated": 0.804146024000147, - "tests/aws/services/s3/test_s3_api.py::TestS3MetricsConfiguration::test_overwrite_bucket_metrics_configuration": 0.1490443210000194, - "tests/aws/services/s3/test_s3_api.py::TestS3MetricsConfiguration::test_put_bucket_metrics_configuration": 0.144050340999911, - "tests/aws/services/s3/test_s3_api.py::TestS3Multipart::test_upload_part_copy_no_copy_source_range": 0.18995913999992808, - "tests/aws/services/s3/test_s3_api.py::TestS3Multipart::test_upload_part_copy_range": 0.3329674110000269, - "tests/aws/services/s3/test_s3_api.py::TestS3ObjectCRUD::test_delete_object": 0.0896751249999852, - "tests/aws/services/s3/test_s3_api.py::TestS3ObjectCRUD::test_delete_object_on_suspended_bucket": 0.5676705789996959, - "tests/aws/services/s3/test_s3_api.py::TestS3ObjectCRUD::test_delete_object_versioned": 0.5557337689997439, - "tests/aws/services/s3/test_s3_api.py::TestS3ObjectCRUD::test_delete_objects": 0.08326828200006275, - "tests/aws/services/s3/test_s3_api.py::TestS3ObjectCRUD::test_delete_objects_versioned": 0.4871213310002531, - "tests/aws/services/s3/test_s3_api.py::TestS3ObjectCRUD::test_get_object_range": 0.2903472170000896, - "tests/aws/services/s3/test_s3_api.py::TestS3ObjectCRUD::test_get_object_with_version_unversioned_bucket": 0.4540507639999305, - "tests/aws/services/s3/test_s3_api.py::TestS3ObjectCRUD::test_list_object_versions_order_unversioned": 0.48733022200008236, - "tests/aws/services/s3/test_s3_api.py::TestS3ObjectCRUD::test_put_object_on_suspended_bucket": 0.6066525740002362, - "tests/aws/services/s3/test_s3_api.py::TestS3ObjectLock::test_delete_object_with_no_locking": 0.10338458999990507, - "tests/aws/services/s3/test_s3_api.py::TestS3ObjectLock::test_disable_versioning_on_locked_bucket": 0.06950114100027349, - "tests/aws/services/s3/test_s3_api.py::TestS3ObjectLock::test_get_object_lock_configuration_exc": 0.07537019400001554, - "tests/aws/services/s3/test_s3_api.py::TestS3ObjectLock::test_get_put_object_lock_configuration": 0.09338006699977086, - "tests/aws/services/s3/test_s3_api.py::TestS3ObjectLock::test_put_object_lock_configuration_exc": 0.11578802300005009, - "tests/aws/services/s3/test_s3_api.py::TestS3ObjectLock::test_put_object_lock_configuration_on_existing_bucket": 0.11305954899967219, - "tests/aws/services/s3/test_s3_api.py::TestS3ObjectWritePrecondition::test_multipart_if_match_etag": 0.14361462500005473, - "tests/aws/services/s3/test_s3_api.py::TestS3ObjectWritePrecondition::test_multipart_if_match_with_delete": 0.13218484299977717, - "tests/aws/services/s3/test_s3_api.py::TestS3ObjectWritePrecondition::test_multipart_if_match_with_put": 0.15121932099987134, - "tests/aws/services/s3/test_s3_api.py::TestS3ObjectWritePrecondition::test_multipart_if_match_with_put_identical": 0.14828275399986524, - "tests/aws/services/s3/test_s3_api.py::TestS3ObjectWritePrecondition::test_multipart_if_none_match_with_delete": 0.1479143829997156, - "tests/aws/services/s3/test_s3_api.py::TestS3ObjectWritePrecondition::test_multipart_if_none_match_with_put": 0.10418069799993646, - "tests/aws/services/s3/test_s3_api.py::TestS3ObjectWritePrecondition::test_put_object_if_match": 0.11997570700009419, - "tests/aws/services/s3/test_s3_api.py::TestS3ObjectWritePrecondition::test_put_object_if_match_and_if_none_match_validation": 0.0656151680000221, - "tests/aws/services/s3/test_s3_api.py::TestS3ObjectWritePrecondition::test_put_object_if_match_validation": 0.08544134399994618, - "tests/aws/services/s3/test_s3_api.py::TestS3ObjectWritePrecondition::test_put_object_if_match_versioned_bucket": 0.1618645840001136, - "tests/aws/services/s3/test_s3_api.py::TestS3ObjectWritePrecondition::test_put_object_if_none_match": 0.101328599999988, - "tests/aws/services/s3/test_s3_api.py::TestS3ObjectWritePrecondition::test_put_object_if_none_match_validation": 0.08542143600016061, - "tests/aws/services/s3/test_s3_api.py::TestS3ObjectWritePrecondition::test_put_object_if_none_match_versioned_bucket": 0.13587557400023798, - "tests/aws/services/s3/test_s3_api.py::TestS3PublicAccessBlock::test_crud_public_access_block": 0.10271814199995788, - "tests/aws/services/s3/test_s3_concurrency.py::TestParallelBucketCreation::test_parallel_bucket_creation": 0.4086462410000422, - "tests/aws/services/s3/test_s3_concurrency.py::TestParallelBucketCreation::test_parallel_object_creation_and_listing": 0.3208219509997434, - "tests/aws/services/s3/test_s3_concurrency.py::TestParallelBucketCreation::test_parallel_object_creation_and_read": 1.5664092970000638, - "tests/aws/services/s3/test_s3_concurrency.py::TestParallelBucketCreation::test_parallel_object_read_range": 1.5201945429998887, - "tests/aws/services/s3/test_s3_cors.py::TestS3Cors::test_cors_expose_headers": 0.2580052009996052, - "tests/aws/services/s3/test_s3_cors.py::TestS3Cors::test_cors_http_get_no_config": 0.10862903299994286, - "tests/aws/services/s3/test_s3_cors.py::TestS3Cors::test_cors_http_options_no_config": 0.19429473999980473, - "tests/aws/services/s3/test_s3_cors.py::TestS3Cors::test_cors_http_options_non_existent_bucket": 0.1599479760000122, - "tests/aws/services/s3/test_s3_cors.py::TestS3Cors::test_cors_http_options_non_existent_bucket_ls_allowed": 0.07636123199995382, - "tests/aws/services/s3/test_s3_cors.py::TestS3Cors::test_cors_list_buckets": 0.0809284340002705, - "tests/aws/services/s3/test_s3_cors.py::TestS3Cors::test_cors_match_headers": 0.7830458790001558, - "tests/aws/services/s3/test_s3_cors.py::TestS3Cors::test_cors_match_methods": 0.7289546599999994, - "tests/aws/services/s3/test_s3_cors.py::TestS3Cors::test_cors_match_origins": 0.6465525720000187, - "tests/aws/services/s3/test_s3_cors.py::TestS3Cors::test_cors_no_config_localstack_allowed": 0.10428626199973223, - "tests/aws/services/s3/test_s3_cors.py::TestS3Cors::test_cors_options_fails_partial_origin": 0.4438154899999063, - "tests/aws/services/s3/test_s3_cors.py::TestS3Cors::test_cors_options_match_partial_origin": 0.16056654999965758, - "tests/aws/services/s3/test_s3_cors.py::TestS3Cors::test_delete_cors": 0.18236880100016606, - "tests/aws/services/s3/test_s3_cors.py::TestS3Cors::test_get_cors": 0.17368339799986643, - "tests/aws/services/s3/test_s3_cors.py::TestS3Cors::test_put_cors": 0.16123790500000723, - "tests/aws/services/s3/test_s3_cors.py::TestS3Cors::test_put_cors_default_values": 0.4801126809998095, - "tests/aws/services/s3/test_s3_cors.py::TestS3Cors::test_put_cors_empty_origin": 0.1586530730000959, - "tests/aws/services/s3/test_s3_cors.py::TestS3Cors::test_put_cors_invalid_rules": 0.1637530660000266, - "tests/aws/services/s3/test_s3_cors.py::TestS3Cors::test_s3_cors_disabled": 0.09879665300013585, - "tests/aws/services/s3/test_s3_list_operations.py::TestS3ListBuckets::test_list_buckets_by_bucket_region": 0.5640392170000723, - "tests/aws/services/s3/test_s3_list_operations.py::TestS3ListBuckets::test_list_buckets_by_prefix_with_case_sensitivity": 0.49322199399989586, - "tests/aws/services/s3/test_s3_list_operations.py::TestS3ListBuckets::test_list_buckets_when_continuation_token_is_empty": 0.47131836300013674, - "tests/aws/services/s3/test_s3_list_operations.py::TestS3ListBuckets::test_list_buckets_with_continuation_token": 1.785249937999879, - "tests/aws/services/s3/test_s3_list_operations.py::TestS3ListBuckets::test_list_buckets_with_max_buckets": 0.4767437190000692, - "tests/aws/services/s3/test_s3_list_operations.py::TestS3ListMultipartUploads::test_list_multipart_uploads_marker_common_prefixes": 0.5056741320001947, - "tests/aws/services/s3/test_s3_list_operations.py::TestS3ListMultipartUploads::test_list_multiparts_next_marker": 0.6095032189998619, - "tests/aws/services/s3/test_s3_list_operations.py::TestS3ListMultipartUploads::test_list_multiparts_with_prefix_and_delimiter": 0.4887859299999491, - "tests/aws/services/s3/test_s3_list_operations.py::TestS3ListMultipartUploads::test_s3_list_multiparts_timestamp_precision": 0.08695454000007885, - "tests/aws/services/s3/test_s3_list_operations.py::TestS3ListObjectVersions::test_list_object_versions_pagination_common_prefixes": 0.5713050939998539, - "tests/aws/services/s3/test_s3_list_operations.py::TestS3ListObjectVersions::test_list_objects_versions_markers": 0.6667225959999996, - "tests/aws/services/s3/test_s3_list_operations.py::TestS3ListObjectVersions::test_list_objects_versions_with_prefix": 0.5893735680003829, - "tests/aws/services/s3/test_s3_list_operations.py::TestS3ListObjectVersions::test_list_objects_versions_with_prefix_only_and_pagination": 0.6118816759997117, - "tests/aws/services/s3/test_s3_list_operations.py::TestS3ListObjectVersions::test_list_objects_versions_with_prefix_only_and_pagination_many_versions": 1.0268015760000253, - "tests/aws/services/s3/test_s3_list_operations.py::TestS3ListObjectVersions::test_s3_list_object_versions_timestamp_precision": 0.10087905500017769, - "tests/aws/services/s3/test_s3_list_operations.py::TestS3ListObjects::test_list_objects_marker_common_prefixes": 0.5379581480001434, - "tests/aws/services/s3/test_s3_list_operations.py::TestS3ListObjects::test_list_objects_next_marker": 0.5200094809999882, - "tests/aws/services/s3/test_s3_list_operations.py::TestS3ListObjects::test_list_objects_with_prefix[%2F]": 0.4593089060001603, - "tests/aws/services/s3/test_s3_list_operations.py::TestS3ListObjects::test_list_objects_with_prefix[/]": 0.44486234200007857, - "tests/aws/services/s3/test_s3_list_operations.py::TestS3ListObjects::test_list_objects_with_prefix[]": 0.46920532299986917, - "tests/aws/services/s3/test_s3_list_operations.py::TestS3ListObjects::test_s3_list_objects_empty_marker": 0.42311132899999393, - "tests/aws/services/s3/test_s3_list_operations.py::TestS3ListObjects::test_s3_list_objects_timestamp_precision[ListObjectsV2]": 0.08247500100014804, - "tests/aws/services/s3/test_s3_list_operations.py::TestS3ListObjects::test_s3_list_objects_timestamp_precision[ListObjects]": 0.0829959250002048, - "tests/aws/services/s3/test_s3_list_operations.py::TestS3ListObjectsV2::test_list_objects_v2_continuation_common_prefixes": 0.5282242759999463, - "tests/aws/services/s3/test_s3_list_operations.py::TestS3ListObjectsV2::test_list_objects_v2_continuation_start_after": 0.6478527269998722, - "tests/aws/services/s3/test_s3_list_operations.py::TestS3ListObjectsV2::test_list_objects_v2_with_prefix": 0.5217973469998469, - "tests/aws/services/s3/test_s3_list_operations.py::TestS3ListObjectsV2::test_list_objects_v2_with_prefix_and_delimiter": 0.49832782900011807, - "tests/aws/services/s3/test_s3_list_operations.py::TestS3ListParts::test_list_parts_empty_part_number_marker": 0.09977889699985099, - "tests/aws/services/s3/test_s3_list_operations.py::TestS3ListParts::test_list_parts_pagination": 0.18187721100025556, - "tests/aws/services/s3/test_s3_list_operations.py::TestS3ListParts::test_list_parts_via_object_attrs_pagination": 0.24332552699979715, - "tests/aws/services/s3/test_s3_list_operations.py::TestS3ListParts::test_s3_list_parts_timestamp_precision": 0.08486619400036943, - "tests/aws/services/s3/test_s3_notifications_eventbridge.py::TestS3NotificationsToEventBridge::test_object_created_put": 1.8290181819997997, - "tests/aws/services/s3/test_s3_notifications_eventbridge.py::TestS3NotificationsToEventBridge::test_object_created_put_in_different_region": 1.8464647990003868, - "tests/aws/services/s3/test_s3_notifications_eventbridge.py::TestS3NotificationsToEventBridge::test_object_created_put_versioned": 5.169409443000177, - "tests/aws/services/s3/test_s3_notifications_eventbridge.py::TestS3NotificationsToEventBridge::test_object_put_acl": 1.2597912699998233, - "tests/aws/services/s3/test_s3_notifications_eventbridge.py::TestS3NotificationsToEventBridge::test_restore_object": 1.1393131209999865, - "tests/aws/services/s3/test_s3_notifications_lambda.py::TestS3NotificationsToLambda::test_create_object_by_presigned_request_via_dynamodb": 6.121388472000035, - "tests/aws/services/s3/test_s3_notifications_lambda.py::TestS3NotificationsToLambda::test_create_object_put_via_dynamodb": 2.9223176129999047, - "tests/aws/services/s3/test_s3_notifications_lambda.py::TestS3NotificationsToLambda::test_invalid_lambda_arn": 0.4670466950001355, - "tests/aws/services/s3/test_s3_notifications_sns.py::TestS3NotificationsToSns::test_bucket_not_exist": 0.3720970290000878, - "tests/aws/services/s3/test_s3_notifications_sns.py::TestS3NotificationsToSns::test_bucket_notifications_with_filter": 1.639867225999751, - "tests/aws/services/s3/test_s3_notifications_sns.py::TestS3NotificationsToSns::test_invalid_topic_arn": 0.2564062289998219, - "tests/aws/services/s3/test_s3_notifications_sns.py::TestS3NotificationsToSns::test_object_created_put": 1.7354050070002813, - "tests/aws/services/s3/test_s3_notifications_sqs.py::TestS3NotificationsToSQS::test_delete_objects": 2.1130127350002113, - "tests/aws/services/s3/test_s3_notifications_sqs.py::TestS3NotificationsToSQS::test_filter_rules_case_insensitive": 0.09786906299973452, - "tests/aws/services/s3/test_s3_notifications_sqs.py::TestS3NotificationsToSQS::test_filter_rules_empty_value": 0.09579953699994803, - "tests/aws/services/s3/test_s3_notifications_sqs.py::TestS3NotificationsToSQS::test_invalid_sqs_arn": 0.3946767309998904, - "tests/aws/services/s3/test_s3_notifications_sqs.py::TestS3NotificationsToSQS::test_key_encoding": 0.6170223779995467, - "tests/aws/services/s3/test_s3_notifications_sqs.py::TestS3NotificationsToSQS::test_multiple_invalid_sqs_arns": 0.6035256159998426, - "tests/aws/services/s3/test_s3_notifications_sqs.py::TestS3NotificationsToSQS::test_notifications_with_filter": 0.7268186389997027, - "tests/aws/services/s3/test_s3_notifications_sqs.py::TestS3NotificationsToSQS::test_object_created_and_object_removed": 0.8150645170001098, - "tests/aws/services/s3/test_s3_notifications_sqs.py::TestS3NotificationsToSQS::test_object_created_complete_multipart_upload": 0.6490185440000005, - "tests/aws/services/s3/test_s3_notifications_sqs.py::TestS3NotificationsToSQS::test_object_created_copy": 0.6737095329997373, - "tests/aws/services/s3/test_s3_notifications_sqs.py::TestS3NotificationsToSQS::test_object_created_put": 0.7064704859999438, - "tests/aws/services/s3/test_s3_notifications_sqs.py::TestS3NotificationsToSQS::test_object_created_put_versioned": 1.050106935000258, - "tests/aws/services/s3/test_s3_notifications_sqs.py::TestS3NotificationsToSQS::test_object_created_put_with_presigned_url_upload": 0.9729781389999062, - "tests/aws/services/s3/test_s3_notifications_sqs.py::TestS3NotificationsToSQS::test_object_put_acl": 0.8146149649996914, - "tests/aws/services/s3/test_s3_notifications_sqs.py::TestS3NotificationsToSQS::test_object_tagging_delete_event": 0.6701595160000124, - "tests/aws/services/s3/test_s3_notifications_sqs.py::TestS3NotificationsToSQS::test_object_tagging_put_event": 0.6663031409998439, - "tests/aws/services/s3/test_s3_notifications_sqs.py::TestS3NotificationsToSQS::test_restore_object": 0.791535835999639, - "tests/aws/services/s3/test_s3_notifications_sqs.py::TestS3NotificationsToSQS::test_xray_header": 1.6236199169998144, - "tests/aws/services/s3control/test_s3control.py::TestLegacyS3Control::test_lifecycle_public_access_block": 0.290692621000062, - "tests/aws/services/s3control/test_s3control.py::TestLegacyS3Control::test_public_access_block_validations": 0.079995967999821, - "tests/aws/services/s3control/test_s3control.py::TestS3ControlAccessPoint::test_access_point_already_exists": 0.0017862400000012713, - "tests/aws/services/s3control/test_s3control.py::TestS3ControlAccessPoint::test_access_point_bucket_not_exists": 0.0016378820000682026, - "tests/aws/services/s3control/test_s3control.py::TestS3ControlAccessPoint::test_access_point_lifecycle": 0.0016344859998298489, - "tests/aws/services/s3control/test_s3control.py::TestS3ControlAccessPoint::test_access_point_name_validation": 0.00165614699994876, - "tests/aws/services/s3control/test_s3control.py::TestS3ControlAccessPoint::test_access_point_pagination": 0.0016500649999215966, - "tests/aws/services/s3control/test_s3control.py::TestS3ControlAccessPoint::test_access_point_public_access_block_configuration": 0.0019419120001202828, - "tests/aws/services/s3control/test_s3control.py::TestS3ControlPublicAccessBlock::test_crud_public_access_block": 0.0016446439999526774, - "tests/aws/services/s3control/test_s3control.py::TestS3ControlPublicAccessBlock::test_empty_public_access_block": 0.0016484120001223346, - "tests/aws/services/scheduler/test_scheduler.py::test_list_schedules": 0.06771351999987019, - "tests/aws/services/scheduler/test_scheduler.py::test_tag_resource": 0.03495724299978065, - "tests/aws/services/scheduler/test_scheduler.py::test_untag_resource": 0.03190283399999316, - "tests/aws/services/scheduler/test_scheduler.py::tests_create_schedule_with_invalid_schedule_expression[ rate(10 minutes)]": 0.015788234999945416, - "tests/aws/services/scheduler/test_scheduler.py::tests_create_schedule_with_invalid_schedule_expression[at(2021-12-31)]": 0.01453659100002369, - "tests/aws/services/scheduler/test_scheduler.py::tests_create_schedule_with_invalid_schedule_expression[at(2021-12-31T23:59:59Z)]": 0.014657716999863624, - "tests/aws/services/scheduler/test_scheduler.py::tests_create_schedule_with_invalid_schedule_expression[cron()]": 0.014834773000075074, - "tests/aws/services/scheduler/test_scheduler.py::tests_create_schedule_with_invalid_schedule_expression[cron(0 1 * * * *)]": 0.017347879999988436, - "tests/aws/services/scheduler/test_scheduler.py::tests_create_schedule_with_invalid_schedule_expression[cron(0 dummy ? * MON-FRI *)]": 0.014268076000234942, - "tests/aws/services/scheduler/test_scheduler.py::tests_create_schedule_with_invalid_schedule_expression[cron(7 20 * * NOT *)]": 0.014256783999599065, - "tests/aws/services/scheduler/test_scheduler.py::tests_create_schedule_with_invalid_schedule_expression[cron(71 8 1 * ? *)]": 0.014431191000085164, - "tests/aws/services/scheduler/test_scheduler.py::tests_create_schedule_with_invalid_schedule_expression[cron(INVALID)]": 0.01440470199986521, - "tests/aws/services/scheduler/test_scheduler.py::tests_create_schedule_with_invalid_schedule_expression[rate( 10 minutes )]": 0.014504429999988133, - "tests/aws/services/scheduler/test_scheduler.py::tests_create_schedule_with_invalid_schedule_expression[rate()]": 0.014371730999982901, - "tests/aws/services/scheduler/test_scheduler.py::tests_create_schedule_with_invalid_schedule_expression[rate(-10 minutes)]": 0.014964273000259709, - "tests/aws/services/scheduler/test_scheduler.py::tests_create_schedule_with_invalid_schedule_expression[rate(10 minutess)]": 0.014749952000101985, - "tests/aws/services/scheduler/test_scheduler.py::tests_create_schedule_with_invalid_schedule_expression[rate(10 seconds)]": 0.01455244999988281, - "tests/aws/services/scheduler/test_scheduler.py::tests_create_schedule_with_invalid_schedule_expression[rate(10 years)]": 0.0144369029999325, - "tests/aws/services/scheduler/test_scheduler.py::tests_create_schedule_with_invalid_schedule_expression[rate(10)]": 0.014650024000047779, - "tests/aws/services/scheduler/test_scheduler.py::tests_create_schedule_with_invalid_schedule_expression[rate(foo minutes)]": 0.015195298999969964, - "tests/aws/services/scheduler/test_scheduler.py::tests_create_schedule_with_valid_schedule_expression": 0.07595148699988385, - "tests/aws/services/secretsmanager/test_secretsmanager.py::TestSecretsManager::test_call_lists_secrets_multiple_times": 0.052387088000159565, - "tests/aws/services/secretsmanager/test_secretsmanager.py::TestSecretsManager::test_call_lists_secrets_multiple_times_snapshots": 0.001728300999957355, - "tests/aws/services/secretsmanager/test_secretsmanager.py::TestSecretsManager::test_can_recreate_delete_secret": 0.05307403400001931, - "tests/aws/services/secretsmanager/test_secretsmanager.py::TestSecretsManager::test_create_and_update_secret[Valid/_+=.@-Name-a1b2]": 0.08269824300032269, - "tests/aws/services/secretsmanager/test_secretsmanager.py::TestSecretsManager::test_create_and_update_secret[Valid/_+=.@-Name-a1b2c3-]": 0.0851624219999394, - "tests/aws/services/secretsmanager/test_secretsmanager.py::TestSecretsManager::test_create_and_update_secret[Valid/_+=.@-Name]": 0.08463696399985565, - "tests/aws/services/secretsmanager/test_secretsmanager.py::TestSecretsManager::test_create_and_update_secret[s-c64bdc03]": 0.1104962549998163, - "tests/aws/services/secretsmanager/test_secretsmanager.py::TestSecretsManager::test_create_multi_secrets": 0.09866346000012527, - "tests/aws/services/secretsmanager/test_secretsmanager.py::TestSecretsManager::test_create_multi_secrets_snapshot": 0.0018365349999385217, - "tests/aws/services/secretsmanager/test_secretsmanager.py::TestSecretsManager::test_create_secret_version_from_empty_secret": 0.038822351999897364, - "tests/aws/services/secretsmanager/test_secretsmanager.py::TestSecretsManager::test_create_secret_with_custom_id": 0.021634814999742957, - "tests/aws/services/secretsmanager/test_secretsmanager.py::TestSecretsManager::test_delete_non_existent_secret_returns_as_if_secret_exists": 0.0197105240001747, - "tests/aws/services/secretsmanager/test_secretsmanager.py::TestSecretsManager::test_deprecated_secret_version": 0.8732994049998979, - "tests/aws/services/secretsmanager/test_secretsmanager.py::TestSecretsManager::test_deprecated_secret_version_stage": 0.18953710499999943, - "tests/aws/services/secretsmanager/test_secretsmanager.py::TestSecretsManager::test_exp_raised_on_creation_of_secret_scheduled_for_deletion": 0.03902704699999049, - "tests/aws/services/secretsmanager/test_secretsmanager.py::TestSecretsManager::test_first_rotate_secret_with_missing_lambda_arn": 0.03482661699968048, - "tests/aws/services/secretsmanager/test_secretsmanager.py::TestSecretsManager::test_force_delete_deleted_secret": 0.05401985399998921, - "tests/aws/services/secretsmanager/test_secretsmanager.py::TestSecretsManager::test_get_random_exclude_characters_and_symbols": 0.015315013999952498, - "tests/aws/services/secretsmanager/test_secretsmanager.py::TestSecretsManager::test_get_secret_value": 0.07467376299996431, - "tests/aws/services/secretsmanager/test_secretsmanager.py::TestSecretsManager::test_get_secret_value_errors": 0.03980020000017248, - "tests/aws/services/secretsmanager/test_secretsmanager.py::TestSecretsManager::test_http_put_secret_value_custom_client_request_token_new_version_stages": 0.05471878199978164, - "tests/aws/services/secretsmanager/test_secretsmanager.py::TestSecretsManager::test_http_put_secret_value_duplicate_req": 0.04883952000000136, - "tests/aws/services/secretsmanager/test_secretsmanager.py::TestSecretsManager::test_http_put_secret_value_null_client_request_token_new_version_stages": 0.056616047999568764, - "tests/aws/services/secretsmanager/test_secretsmanager.py::TestSecretsManager::test_http_put_secret_value_with_duplicate_client_request_token": 0.0017108480001297721, - "tests/aws/services/secretsmanager/test_secretsmanager.py::TestSecretsManager::test_http_put_secret_value_with_non_provided_client_request_token": 0.04911438299996007, - "tests/aws/services/secretsmanager/test_secretsmanager.py::TestSecretsManager::test_invalid_secret_name[ Inv *?!]Name\\\\-]": 0.08972729199990681, - "tests/aws/services/secretsmanager/test_secretsmanager.py::TestSecretsManager::test_invalid_secret_name[ Inv Name]": 0.093645085000162, - "tests/aws/services/secretsmanager/test_secretsmanager.py::TestSecretsManager::test_invalid_secret_name[ Inv*Name? ]": 0.0897607459999108, - "tests/aws/services/secretsmanager/test_secretsmanager.py::TestSecretsManager::test_invalid_secret_name[Inv Name]": 0.09399775799988674, - "tests/aws/services/secretsmanager/test_secretsmanager.py::TestSecretsManager::test_last_accessed_date": 0.05353804099991066, - "tests/aws/services/secretsmanager/test_secretsmanager.py::TestSecretsManager::test_last_updated_date": 0.0795668069997646, - "tests/aws/services/secretsmanager/test_secretsmanager.py::TestSecretsManager::test_list_secrets_filtering": 0.18667275000007066, - "tests/aws/services/secretsmanager/test_secretsmanager.py::TestSecretsManager::test_no_client_request_token[CreateSecret]": 0.02421970700015663, - "tests/aws/services/secretsmanager/test_secretsmanager.py::TestSecretsManager::test_no_client_request_token[PutSecretValue]": 0.02259224600015841, - "tests/aws/services/secretsmanager/test_secretsmanager.py::TestSecretsManager::test_no_client_request_token[RotateSecret]": 0.023020433000056073, - "tests/aws/services/secretsmanager/test_secretsmanager.py::TestSecretsManager::test_no_client_request_token[UpdateSecret]": 0.02326623799990557, - "tests/aws/services/secretsmanager/test_secretsmanager.py::TestSecretsManager::test_non_versioning_version_stages_no_replacement": 0.21306338399972446, - "tests/aws/services/secretsmanager/test_secretsmanager.py::TestSecretsManager::test_non_versioning_version_stages_replacement": 0.21911012300006405, - "tests/aws/services/secretsmanager/test_secretsmanager.py::TestSecretsManager::test_put_secret_value_with_new_custom_client_request_token": 0.047913905999848794, - "tests/aws/services/secretsmanager/test_secretsmanager.py::TestSecretsManager::test_put_secret_value_with_version_stages": 0.09823606999998447, - "tests/aws/services/secretsmanager/test_secretsmanager.py::TestSecretsManager::test_resource_policy": 0.04961883599980865, - "tests/aws/services/secretsmanager/test_secretsmanager.py::TestSecretsManager::test_rotate_secret_invalid_lambda_arn": 0.2184524879996843, - "tests/aws/services/secretsmanager/test_secretsmanager.py::TestSecretsManager::test_rotate_secret_multiple_times_with_lambda_success": 2.7987577470000815, - "tests/aws/services/secretsmanager/test_secretsmanager.py::TestSecretsManager::test_rotate_secret_with_lambda_success[None]": 2.315677043000278, - "tests/aws/services/secretsmanager/test_secretsmanager.py::TestSecretsManager::test_rotate_secret_with_lambda_success[True]": 2.321850237000035, - "tests/aws/services/secretsmanager/test_secretsmanager.py::TestSecretsManager::test_secret_exists": 0.047544925000238436, - "tests/aws/services/secretsmanager/test_secretsmanager.py::TestSecretsManager::test_secret_exists_snapshots": 0.04895267100005185, - "tests/aws/services/secretsmanager/test_secretsmanager.py::TestSecretsManager::test_secret_not_found": 0.026118589999896358, - "tests/aws/services/secretsmanager/test_secretsmanager.py::TestSecretsManager::test_secret_restore": 0.0458494139998038, - "tests/aws/services/secretsmanager/test_secretsmanager.py::TestSecretsManager::test_secret_tags": 0.11790869100013879, - "tests/aws/services/secretsmanager/test_secretsmanager.py::TestSecretsManager::test_secret_version_not_found": 0.041815284999984215, - "tests/aws/services/secretsmanager/test_secretsmanager.py::TestSecretsManager::test_update_secret_description": 0.09861709799997698, - "tests/aws/services/secretsmanager/test_secretsmanager.py::TestSecretsManager::test_update_secret_version_stages_current_pending": 0.2255201179998494, - "tests/aws/services/secretsmanager/test_secretsmanager.py::TestSecretsManager::test_update_secret_version_stages_current_pending_cycle": 0.275437188000069, - "tests/aws/services/secretsmanager/test_secretsmanager.py::TestSecretsManager::test_update_secret_version_stages_current_pending_cycle_custom_stages_1": 0.27688063300001886, - "tests/aws/services/secretsmanager/test_secretsmanager.py::TestSecretsManager::test_update_secret_version_stages_current_pending_cycle_custom_stages_2": 0.30303368399995634, - "tests/aws/services/secretsmanager/test_secretsmanager.py::TestSecretsManager::test_update_secret_version_stages_current_pending_cycle_custom_stages_3": 0.28328418900014185, - "tests/aws/services/secretsmanager/test_secretsmanager.py::TestSecretsManager::test_update_secret_version_stages_current_previous": 0.20825201699994977, - "tests/aws/services/secretsmanager/test_secretsmanager.py::TestSecretsManager::test_update_secret_version_stages_return_type": 0.04829878199984705, - "tests/aws/services/secretsmanager/test_secretsmanager.py::TestSecretsManager::test_update_secret_with_non_provided_client_request_token": 0.04561908100004075, - "tests/aws/services/secretsmanager/test_secretsmanager.py::TestSecretsManagerMultiAccounts::test_cross_account_access": 0.1335344049998639, - "tests/aws/services/secretsmanager/test_secretsmanager.py::TestSecretsManagerMultiAccounts::test_cross_account_access_non_default_key": 0.10505230899957496, - "tests/aws/services/ses/test_ses.py::TestSES::test_cannot_create_event_for_no_topic": 0.04012856700001066, - "tests/aws/services/ses/test_ses.py::TestSES::test_clone_receipt_rule_set": 0.5255924880000293, - "tests/aws/services/ses/test_ses.py::TestSES::test_creating_event_destination_without_configuration_set": 0.06660561800003961, - "tests/aws/services/ses/test_ses.py::TestSES::test_delete_template": 0.057691092000141, - "tests/aws/services/ses/test_ses.py::TestSES::test_deleting_non_existent_configuration_set": 0.014957654999989245, - "tests/aws/services/ses/test_ses.py::TestSES::test_deleting_non_existent_configuration_set_event_destination": 0.03063342400014335, - "tests/aws/services/ses/test_ses.py::TestSES::test_get_identity_verification_attributes_for_domain": 0.011340406000044823, - "tests/aws/services/ses/test_ses.py::TestSES::test_get_identity_verification_attributes_for_email": 0.024419333999958326, - "tests/aws/services/ses/test_ses.py::TestSES::test_invalid_tags_send_email[-]": 0.01452147499981038, - "tests/aws/services/ses/test_ses.py::TestSES::test_invalid_tags_send_email[-test]": 0.015365202000111822, - "tests/aws/services/ses/test_ses.py::TestSES::test_invalid_tags_send_email[test-]": 0.014679070000056527, - "tests/aws/services/ses/test_ses.py::TestSES::test_invalid_tags_send_email[test-test_invalid_value:123]": 0.015020153000023129, - "tests/aws/services/ses/test_ses.py::TestSES::test_invalid_tags_send_email[test_invalid_name:123-test]": 0.015674794999995356, - "tests/aws/services/ses/test_ses.py::TestSES::test_invalid_tags_send_email[test_invalid_name:123-test_invalid_value:123]": 0.01498320399991826, - "tests/aws/services/ses/test_ses.py::TestSES::test_invalid_tags_send_email[test_invalid_name_len]": 0.014515171999846643, - "tests/aws/services/ses/test_ses.py::TestSES::test_invalid_tags_send_email[test_invalid_value_len]": 0.014947578000374051, - "tests/aws/services/ses/test_ses.py::TestSES::test_invalid_tags_send_email[test_priority_name_value]": 0.014893363999817666, - "tests/aws/services/ses/test_ses.py::TestSES::test_list_templates": 0.13140169300004345, - "tests/aws/services/ses/test_ses.py::TestSES::test_sending_to_deleted_topic": 0.4460734849997152, - "tests/aws/services/ses/test_ses.py::TestSES::test_sent_message_counter": 0.10043530400025702, - "tests/aws/services/ses/test_ses.py::TestSES::test_ses_sns_topic_integration_send_email": 1.4988454109998202, - "tests/aws/services/ses/test_ses.py::TestSES::test_ses_sns_topic_integration_send_email_ses_destination": 0.6674744039999041, - "tests/aws/services/ses/test_ses.py::TestSES::test_ses_sns_topic_integration_send_raw_email": 1.4710158230002435, - "tests/aws/services/ses/test_ses.py::TestSES::test_ses_sns_topic_integration_send_templated_email": 1.4880803620001188, - "tests/aws/services/ses/test_ses.py::TestSES::test_set_identity_headers_in_notifications_enabled_failure_invalid_type": 0.030015942000090945, - "tests/aws/services/ses/test_ses.py::TestSES::test_set_identity_headers_in_notifications_enabled_failure_unknown_identity[Bounce]": 0.013700004999918747, - "tests/aws/services/ses/test_ses.py::TestSES::test_set_identity_headers_in_notifications_enabled_failure_unknown_identity[Complaint]": 0.014056956999866088, - "tests/aws/services/ses/test_ses.py::TestSES::test_set_identity_headers_in_notifications_enabled_failure_unknown_identity[Delivery]": 0.014189798999950654, - "tests/aws/services/ses/test_ses.py::TestSES::test_set_identity_headers_in_notifications_enabled_success[False-Bounce]": 0.03928198599987809, - "tests/aws/services/ses/test_ses.py::TestSES::test_set_identity_headers_in_notifications_enabled_success[False-Complaint]": 0.0376285459999508, - "tests/aws/services/ses/test_ses.py::TestSES::test_set_identity_headers_in_notifications_enabled_success[False-Delivery]": 0.03799354300008417, - "tests/aws/services/ses/test_ses.py::TestSES::test_set_identity_headers_in_notifications_enabled_success[True-Bounce]": 0.03952267100021345, - "tests/aws/services/ses/test_ses.py::TestSES::test_set_identity_headers_in_notifications_enabled_success[True-Complaint]": 0.03761888700000782, - "tests/aws/services/ses/test_ses.py::TestSES::test_set_identity_headers_in_notifications_enabled_success[True-Delivery]": 0.03807909299985113, - "tests/aws/services/ses/test_ses.py::TestSES::test_special_tags_send_email[ses:feedback-id-a-this-marketing-campaign]": 0.014989154999966559, - "tests/aws/services/ses/test_ses.py::TestSES::test_special_tags_send_email[ses:feedback-id-b-that-campaign]": 0.014768991999972059, - "tests/aws/services/ses/test_ses.py::TestSES::test_trying_to_delete_event_destination_from_non_existent_configuration_set": 0.09128266500033533, - "tests/aws/services/ses/test_ses.py::TestSESRetrospection::test_send_email_can_retrospect": 2.2090475510001397, - "tests/aws/services/ses/test_ses.py::TestSESRetrospection::test_send_templated_email_can_retrospect": 0.07655426000019361, - "tests/aws/services/sns/test_sns.py::TestSNSCertEndpoint::test_cert_endpoint_host[]": 0.18562184100005652, - "tests/aws/services/sns/test_sns.py::TestSNSCertEndpoint::test_cert_endpoint_host[sns.us-east-1.amazonaws.com]": 0.13506798899993555, - "tests/aws/services/sns/test_sns.py::TestSNSMultiAccounts::test_cross_account_access": 0.12198841000008542, - "tests/aws/services/sns/test_sns.py::TestSNSMultiAccounts::test_cross_account_publish_to_sqs": 0.5193080809999628, - "tests/aws/services/sns/test_sns.py::TestSNSMultiRegions::test_cross_region_access": 0.07806229599987091, - "tests/aws/services/sns/test_sns.py::TestSNSMultiRegions::test_cross_region_delivery_sqs": 0.14475707099995816, - "tests/aws/services/sns/test_sns.py::TestSNSPlatformEndpoint::test_create_platform_endpoint_check_idempotency": 0.0017336329999579903, - "tests/aws/services/sns/test_sns.py::TestSNSPlatformEndpoint::test_publish_disabled_endpoint": 0.08177784500003327, - "tests/aws/services/sns/test_sns.py::TestSNSPlatformEndpoint::test_publish_to_gcm": 0.0017530789996271778, - "tests/aws/services/sns/test_sns.py::TestSNSPlatformEndpoint::test_publish_to_platform_endpoint_is_dispatched": 0.14022246399986216, - "tests/aws/services/sns/test_sns.py::TestSNSPlatformEndpoint::test_subscribe_platform_endpoint": 0.09440210599996135, - "tests/aws/services/sns/test_sns.py::TestSNSPublishCrud::test_empty_sns_message": 0.09115962199962269, - "tests/aws/services/sns/test_sns.py::TestSNSPublishCrud::test_message_structure_json_exc": 0.05744053700027507, - "tests/aws/services/sns/test_sns.py::TestSNSPublishCrud::test_publish_batch_too_long_message": 0.07677045400009774, - "tests/aws/services/sns/test_sns.py::TestSNSPublishCrud::test_publish_by_path_parameters": 0.13785550999978113, - "tests/aws/services/sns/test_sns.py::TestSNSPublishCrud::test_publish_message_before_subscribe_topic": 0.14095311699998092, - "tests/aws/services/sns/test_sns.py::TestSNSPublishCrud::test_publish_message_by_target_arn": 0.19723490499995933, - "tests/aws/services/sns/test_sns.py::TestSNSPublishCrud::test_publish_non_existent_target": 0.03484550899997885, - "tests/aws/services/sns/test_sns.py::TestSNSPublishCrud::test_publish_too_long_message": 0.07418403399992712, - "tests/aws/services/sns/test_sns.py::TestSNSPublishCrud::test_publish_with_empty_subject": 0.04277783499992438, - "tests/aws/services/sns/test_sns.py::TestSNSPublishCrud::test_publish_wrong_arn_format": 0.03361490300017067, - "tests/aws/services/sns/test_sns.py::TestSNSPublishCrud::test_topic_publish_another_region": 0.06000161100018886, - "tests/aws/services/sns/test_sns.py::TestSNSPublishCrud::test_unknown_topic_publish": 0.04116441899986967, - "tests/aws/services/sns/test_sns.py::TestSNSPublishDelivery::test_delivery_lambda": 2.0666338589999214, - "tests/aws/services/sns/test_sns.py::TestSNSRetrospectionEndpoints::test_publish_sms_can_retrospect": 0.24685640200004855, - "tests/aws/services/sns/test_sns.py::TestSNSRetrospectionEndpoints::test_publish_to_platform_endpoint_can_retrospect": 0.19842587699986325, - "tests/aws/services/sns/test_sns.py::TestSNSRetrospectionEndpoints::test_subscription_tokens_can_retrospect": 1.0975598890001947, - "tests/aws/services/sns/test_sns.py::TestSNSSMS::test_publish_sms": 0.01632371100004093, - "tests/aws/services/sns/test_sns.py::TestSNSSMS::test_publish_sms_endpoint": 0.15564476600002308, - "tests/aws/services/sns/test_sns.py::TestSNSSMS::test_publish_wrong_phone_format": 0.04828788400004669, - "tests/aws/services/sns/test_sns.py::TestSNSSMS::test_subscribe_sms_endpoint": 0.04675748800013935, - "tests/aws/services/sns/test_sns.py::TestSNSSubscriptionCrud::test_create_subscriptions_with_attributes": 0.08469658299986804, - "tests/aws/services/sns/test_sns.py::TestSNSSubscriptionCrud::test_list_subscriptions": 0.337860696000007, - "tests/aws/services/sns/test_sns.py::TestSNSSubscriptionCrud::test_list_subscriptions_by_topic_pagination": 1.4880172289999791, - "tests/aws/services/sns/test_sns.py::TestSNSSubscriptionCrud::test_not_found_error_on_set_subscription_attributes": 0.303426201000093, - "tests/aws/services/sns/test_sns.py::TestSNSSubscriptionCrud::test_sns_confirm_subscription_wrong_token": 0.1207714419997501, - "tests/aws/services/sns/test_sns.py::TestSNSSubscriptionCrud::test_subscribe_idempotency": 0.11445740400017712, - "tests/aws/services/sns/test_sns.py::TestSNSSubscriptionCrud::test_subscribe_with_invalid_protocol": 0.03512422099993273, - "tests/aws/services/sns/test_sns.py::TestSNSSubscriptionCrud::test_subscribe_with_invalid_topic": 0.04974733199992443, - "tests/aws/services/sns/test_sns.py::TestSNSSubscriptionCrud::test_unsubscribe_from_non_existing_subscription": 0.08934858499992515, - "tests/aws/services/sns/test_sns.py::TestSNSSubscriptionCrud::test_unsubscribe_idempotency": 0.0888220659999206, - "tests/aws/services/sns/test_sns.py::TestSNSSubscriptionCrud::test_unsubscribe_wrong_arn_format": 0.049142788000153814, - "tests/aws/services/sns/test_sns.py::TestSNSSubscriptionCrud::test_validate_set_sub_attributes": 0.26452466199998526, - "tests/aws/services/sns/test_sns.py::TestSNSSubscriptionFirehose::test_publish_to_firehose_with_s3": 1.334460216999787, - "tests/aws/services/sns/test_sns.py::TestSNSSubscriptionHttp::test_dlq_external_http_endpoint[False]": 2.670084366999845, - "tests/aws/services/sns/test_sns.py::TestSNSSubscriptionHttp::test_dlq_external_http_endpoint[True]": 2.667428155999687, - "tests/aws/services/sns/test_sns.py::TestSNSSubscriptionHttp::test_http_subscription_response": 0.07180522399994516, - "tests/aws/services/sns/test_sns.py::TestSNSSubscriptionHttp::test_multiple_subscriptions_http_endpoint": 1.7081203160000769, - "tests/aws/services/sns/test_sns.py::TestSNSSubscriptionHttp::test_redrive_policy_http_subscription": 0.6562755689999449, - "tests/aws/services/sns/test_sns.py::TestSNSSubscriptionHttp::test_subscribe_external_http_endpoint[False]": 1.6256464600003255, - "tests/aws/services/sns/test_sns.py::TestSNSSubscriptionHttp::test_subscribe_external_http_endpoint[True]": 1.6490506940001524, - "tests/aws/services/sns/test_sns.py::TestSNSSubscriptionHttp::test_subscribe_external_http_endpoint_content_type[False]": 1.604136013000243, - "tests/aws/services/sns/test_sns.py::TestSNSSubscriptionHttp::test_subscribe_external_http_endpoint_content_type[True]": 1.614706673000228, - "tests/aws/services/sns/test_sns.py::TestSNSSubscriptionHttp::test_subscribe_external_http_endpoint_lambda_url_sig_validation": 2.4766274500000236, - "tests/aws/services/sns/test_sns.py::TestSNSSubscriptionLambda::test_publish_lambda_verify_signature[1]": 4.220732281999972, - "tests/aws/services/sns/test_sns.py::TestSNSSubscriptionLambda::test_publish_lambda_verify_signature[2]": 4.237253577000047, - "tests/aws/services/sns/test_sns.py::TestSNSSubscriptionLambda::test_python_lambda_subscribe_sns_topic": 4.214978799999699, - "tests/aws/services/sns/test_sns.py::TestSNSSubscriptionLambda::test_redrive_policy_lambda_subscription": 1.288097308000033, - "tests/aws/services/sns/test_sns.py::TestSNSSubscriptionLambda::test_sns_topic_as_lambda_dead_letter_queue": 2.362218845000143, - "tests/aws/services/sns/test_sns.py::TestSNSSubscriptionSES::test_email_sender": 2.123875246000125, - "tests/aws/services/sns/test_sns.py::TestSNSSubscriptionSES::test_topic_email_subscription_confirmation": 0.06725021299985201, - "tests/aws/services/sns/test_sns.py::TestSNSSubscriptionSQS::test_attribute_raw_subscribe": 0.14040596699987873, - "tests/aws/services/sns/test_sns.py::TestSNSSubscriptionSQS::test_empty_or_wrong_message_attributes": 0.28807338599972354, - "tests/aws/services/sns/test_sns.py::TestSNSSubscriptionSQS::test_message_attributes_not_missing": 0.21917864800002462, - "tests/aws/services/sns/test_sns.py::TestSNSSubscriptionSQS::test_message_attributes_prefixes": 0.16827880499999992, - "tests/aws/services/sns/test_sns.py::TestSNSSubscriptionSQS::test_message_structure_json_to_sqs": 0.1994814210002005, - "tests/aws/services/sns/test_sns.py::TestSNSSubscriptionSQS::test_publish_batch_exceptions": 0.06817198699991422, - "tests/aws/services/sns/test_sns.py::TestSNSSubscriptionSQS::test_publish_batch_messages_from_sns_to_sqs": 0.6758122609999191, - "tests/aws/services/sns/test_sns.py::TestSNSSubscriptionSQS::test_publish_batch_messages_without_topic": 0.03426606600010018, - "tests/aws/services/sns/test_sns.py::TestSNSSubscriptionSQS::test_publish_message_group_id": 0.14833124699998734, - "tests/aws/services/sns/test_sns.py::TestSNSSubscriptionSQS::test_publish_sqs_from_sns": 0.2314720470001248, - "tests/aws/services/sns/test_sns.py::TestSNSSubscriptionSQS::test_publish_sqs_from_sns_with_xray_propagation": 0.13270936300000358, - "tests/aws/services/sns/test_sns.py::TestSNSSubscriptionSQS::test_publish_sqs_verify_signature[1]": 0.14713790499990864, - "tests/aws/services/sns/test_sns.py::TestSNSSubscriptionSQS::test_publish_sqs_verify_signature[2]": 0.1439967210001214, - "tests/aws/services/sns/test_sns.py::TestSNSSubscriptionSQS::test_publish_unicode_chars": 0.13449563799986208, - "tests/aws/services/sns/test_sns.py::TestSNSSubscriptionSQS::test_redrive_policy_sqs_queue_subscription[False]": 0.1931517520001762, - "tests/aws/services/sns/test_sns.py::TestSNSSubscriptionSQS::test_redrive_policy_sqs_queue_subscription[True]": 0.20614289500008454, - "tests/aws/services/sns/test_sns.py::TestSNSSubscriptionSQS::test_sqs_topic_subscription_confirmation": 0.07446472800006632, - "tests/aws/services/sns/test_sns.py::TestSNSSubscriptionSQS::test_subscribe_sqs_queue": 0.17803836899975067, - "tests/aws/services/sns/test_sns.py::TestSNSSubscriptionSQS::test_subscribe_to_sqs_with_queue_url": 0.046725146999961, - "tests/aws/services/sns/test_sns.py::TestSNSSubscriptionSQS::test_subscription_after_failure_to_deliver": 1.5082588679999844, - "tests/aws/services/sns/test_sns.py::TestSNSSubscriptionSQSFifo::test_fifo_topic_to_regular_sqs[False]": 0.2831567160001214, - "tests/aws/services/sns/test_sns.py::TestSNSSubscriptionSQSFifo::test_fifo_topic_to_regular_sqs[True]": 0.27511420999962866, - "tests/aws/services/sns/test_sns.py::TestSNSSubscriptionSQSFifo::test_message_to_fifo_sqs[False]": 1.1887850529999469, - "tests/aws/services/sns/test_sns.py::TestSNSSubscriptionSQSFifo::test_message_to_fifo_sqs[True]": 1.18136820299992, - "tests/aws/services/sns/test_sns.py::TestSNSSubscriptionSQSFifo::test_message_to_fifo_sqs_ordering": 2.6735750650000227, - "tests/aws/services/sns/test_sns.py::TestSNSSubscriptionSQSFifo::test_publish_batch_messages_from_fifo_topic_to_fifo_queue[False]": 3.6345381679998354, - "tests/aws/services/sns/test_sns.py::TestSNSSubscriptionSQSFifo::test_publish_batch_messages_from_fifo_topic_to_fifo_queue[True]": 3.60771889800003, - "tests/aws/services/sns/test_sns.py::TestSNSSubscriptionSQSFifo::test_publish_fifo_messages_to_dlq[False]": 1.5717391200000748, - "tests/aws/services/sns/test_sns.py::TestSNSSubscriptionSQSFifo::test_publish_fifo_messages_to_dlq[True]": 1.6048512400000163, - "tests/aws/services/sns/test_sns.py::TestSNSSubscriptionSQSFifo::test_publish_to_fifo_topic_deduplication_on_topic_level": 1.6800883400001112, - "tests/aws/services/sns/test_sns.py::TestSNSSubscriptionSQSFifo::test_publish_to_fifo_topic_to_sqs_queue_no_content_dedup[False]": 0.27068375100020603, - "tests/aws/services/sns/test_sns.py::TestSNSSubscriptionSQSFifo::test_publish_to_fifo_topic_to_sqs_queue_no_content_dedup[True]": 0.32960470200009695, - "tests/aws/services/sns/test_sns.py::TestSNSSubscriptionSQSFifo::test_publish_to_fifo_with_target_arn": 0.03302396200001567, - "tests/aws/services/sns/test_sns.py::TestSNSSubscriptionSQSFifo::test_validations_for_fifo": 0.27844209399995634, - "tests/aws/services/sns/test_sns.py::TestSNSTopicCrud::test_create_duplicate_topic_check_idempotency": 0.08045791600011398, - "tests/aws/services/sns/test_sns.py::TestSNSTopicCrud::test_create_duplicate_topic_with_more_tags": 0.03747153899985278, - "tests/aws/services/sns/test_sns.py::TestSNSTopicCrud::test_create_topic_after_delete_with_new_tags": 0.05274963800002297, - "tests/aws/services/sns/test_sns.py::TestSNSTopicCrud::test_create_topic_test_arn": 0.2991935069999272, - "tests/aws/services/sns/test_sns.py::TestSNSTopicCrud::test_create_topic_with_attributes": 1.613240603000122, - "tests/aws/services/sns/test_sns.py::TestSNSTopicCrud::test_delete_topic_idempotency": 0.0486821030003739, - "tests/aws/services/sns/test_sns.py::TestSNSTopicCrud::test_tags": 0.0826896260000467, - "tests/aws/services/sns/test_sns.py::TestSNSTopicCrud::test_topic_delivery_policy_crud": 0.001722963000247546, - "tests/aws/services/sns/test_sns_filter_policy.py::TestSNSFilterPolicyAttributes::test_exists_filter_policy": 0.3075258149999627, - "tests/aws/services/sns/test_sns_filter_policy.py::TestSNSFilterPolicyAttributes::test_exists_filter_policy_attributes_array": 4.271013519999769, - "tests/aws/services/sns/test_sns_filter_policy.py::TestSNSFilterPolicyAttributes::test_filter_policy": 5.327803620000168, - "tests/aws/services/sns/test_sns_filter_policy.py::TestSNSFilterPolicyBody::test_filter_policy_empty_array_payload": 0.21646415699979116, - "tests/aws/services/sns/test_sns_filter_policy.py::TestSNSFilterPolicyBody::test_filter_policy_for_batch": 3.376312719999987, - "tests/aws/services/sns/test_sns_filter_policy.py::TestSNSFilterPolicyBody::test_filter_policy_ip_address_condition": 0.36901238999962516, - "tests/aws/services/sns/test_sns_filter_policy.py::TestSNSFilterPolicyBody::test_filter_policy_large_complex_payload": 0.2526597689998198, - "tests/aws/services/sns/test_sns_filter_policy.py::TestSNSFilterPolicyBody::test_filter_policy_on_message_body[False]": 5.332613958000138, - "tests/aws/services/sns/test_sns_filter_policy.py::TestSNSFilterPolicyBody::test_filter_policy_on_message_body[True]": 5.336485484000377, - "tests/aws/services/sns/test_sns_filter_policy.py::TestSNSFilterPolicyBody::test_filter_policy_on_message_body_array_attributes": 0.5863878790005401, - "tests/aws/services/sns/test_sns_filter_policy.py::TestSNSFilterPolicyBody::test_filter_policy_on_message_body_array_of_object_attributes": 0.3389585890008675, - "tests/aws/services/sns/test_sns_filter_policy.py::TestSNSFilterPolicyBody::test_filter_policy_on_message_body_dot_attribute": 5.585881613999845, - "tests/aws/services/sns/test_sns_filter_policy.py::TestSNSFilterPolicyBody::test_filter_policy_on_message_body_or_attribute": 0.802502762000131, - "tests/aws/services/sns/test_sns_filter_policy.py::TestSNSFilterPolicyConditions::test_policy_complexity": 0.05704831799994281, - "tests/aws/services/sns/test_sns_filter_policy.py::TestSNSFilterPolicyConditions::test_policy_complexity_with_or": 0.061687785999765765, - "tests/aws/services/sns/test_sns_filter_policy.py::TestSNSFilterPolicyConditions::test_validate_policy": 0.12780784800042966, - "tests/aws/services/sns/test_sns_filter_policy.py::TestSNSFilterPolicyConditions::test_validate_policy_exists_operator": 0.11901884599956247, - "tests/aws/services/sns/test_sns_filter_policy.py::TestSNSFilterPolicyConditions::test_validate_policy_nested_anything_but_operator": 0.1669969589993343, - "tests/aws/services/sns/test_sns_filter_policy.py::TestSNSFilterPolicyConditions::test_validate_policy_numeric_operator": 0.22958641200057173, - "tests/aws/services/sns/test_sns_filter_policy.py::TestSNSFilterPolicyConditions::test_validate_policy_string_operators": 0.22630362800009607, - "tests/aws/services/sns/test_sns_filter_policy.py::TestSNSFilterPolicyCrud::test_set_subscription_filter_policy_scope": 0.12318625599982624, - "tests/aws/services/sns/test_sns_filter_policy.py::TestSNSFilterPolicyCrud::test_sub_filter_policy_nested_property": 0.10398051599986502, - "tests/aws/services/sns/test_sns_filter_policy.py::TestSNSFilterPolicyCrud::test_sub_filter_policy_nested_property_constraints": 0.17596749399990586, - "tests/aws/services/sqs/test_sqs.py::TestSQSMultiAccounts::test_cross_account_access[domain]": 0.09171066199996858, - "tests/aws/services/sqs/test_sqs.py::TestSQSMultiAccounts::test_cross_account_access[path]": 0.09306953299937959, - "tests/aws/services/sqs/test_sqs.py::TestSQSMultiAccounts::test_cross_account_access[standard]": 0.09457075199998144, - "tests/aws/services/sqs/test_sqs.py::TestSQSMultiAccounts::test_cross_account_get_queue_url[domain]": 0.029731766000168136, - "tests/aws/services/sqs/test_sqs.py::TestSQSMultiAccounts::test_cross_account_get_queue_url[path]": 0.028707730999940395, - "tests/aws/services/sqs/test_sqs.py::TestSQSMultiAccounts::test_cross_account_get_queue_url[standard]": 0.03054050900027505, - "tests/aws/services/sqs/test_sqs.py::TestSQSMultiAccounts::test_delete_queue_multi_account[sqs]": 0.08911048100026164, - "tests/aws/services/sqs/test_sqs.py::TestSQSMultiAccounts::test_delete_queue_multi_account[sqs_query]": 0.09207044699996914, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_approximate_number_of_messages_delayed[sqs]": 3.128558417000022, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_approximate_number_of_messages_delayed[sqs_query]": 3.134042230999512, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_aws_trace_header_propagation[sqs]": 0.10310001800053215, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_aws_trace_header_propagation[sqs_query]": 0.1048458010000104, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_batch_send_with_invalid_char_should_succeed[sqs]": 0.12736164199986888, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_batch_send_with_invalid_char_should_succeed[sqs_query]": 0.22410616500019387, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_change_message_visibility_after_visibility_timeout_expiration[sqs]": 2.105905055999756, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_change_message_visibility_after_visibility_timeout_expiration[sqs_query]": 2.1103136680003445, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_change_message_visibility_batch_with_too_large_batch[sqs]": 0.6503453999994235, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_change_message_visibility_batch_with_too_large_batch[sqs_query]": 0.6642018659999849, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_change_message_visibility_not_permanent[sqs]": 0.10093698700029563, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_change_message_visibility_not_permanent[sqs_query]": 0.10091473499960557, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_change_visibility_on_deleted_message_raises_invalid_parameter_value[sqs]": 0.09199947600018277, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_change_visibility_on_deleted_message_raises_invalid_parameter_value[sqs_query]": 0.09318265499996414, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_create_and_send_to_fifo_queue[sqs]": 0.06218304700041699, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_create_and_send_to_fifo_queue[sqs_query]": 0.06354388699946867, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_create_and_update_queue_attributes[sqs]": 0.08238437299951329, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_create_and_update_queue_attributes[sqs_query]": 0.08456936299990048, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_create_fifo_queue_with_different_attributes_raises_error[sqs]": 0.13995697899963488, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_create_fifo_queue_with_different_attributes_raises_error[sqs_query]": 0.14256099700014602, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_create_fifo_queue_with_same_attributes_is_idempotent": 0.03557277299978523, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_create_queue_after_internal_attributes_changes_works[sqs]": 0.08454333400004543, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_create_queue_after_internal_attributes_changes_works[sqs_query]": 0.08609922999949049, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_create_queue_after_modified_attributes[sqs]": 0.00166755700001886, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_create_queue_after_modified_attributes[sqs_query]": 0.0016021349997572543, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_create_queue_after_send[sqs]": 0.11327558300035889, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_create_queue_after_send[sqs_query]": 0.11727117800046472, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_create_queue_and_get_attributes[sqs]": 0.03181285099935849, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_create_queue_and_get_attributes[sqs_query]": 0.031771512999966944, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_create_queue_recently_deleted[sqs]": 0.035984428000119806, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_create_queue_recently_deleted[sqs_query]": 0.03730651699970622, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_create_queue_recently_deleted_cache[sqs]": 1.5518857229994865, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_create_queue_recently_deleted_cache[sqs_query]": 1.5518903189995399, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_create_queue_recently_deleted_can_be_disabled[sqs]": 0.04207713200003127, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_create_queue_recently_deleted_can_be_disabled[sqs_query]": 0.043365485000322224, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_create_queue_with_default_arguments_works_with_modified_attributes[sqs]": 0.0018205960004706867, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_create_queue_with_default_arguments_works_with_modified_attributes[sqs_query]": 0.0017785959998946055, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_create_queue_with_default_attributes_is_idempotent": 0.03569263899998987, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_create_queue_with_different_attributes_raises_exception[sqs]": 0.19802580800069336, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_create_queue_with_different_attributes_raises_exception[sqs_query]": 0.19657736099998147, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_create_queue_with_same_attributes_is_idempotent": 0.03713740700004564, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_create_queue_with_tags[sqs]": 0.028338184999938676, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_create_queue_with_tags[sqs_query]": 0.02910332199962795, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_create_queue_without_attributes_is_idempotent": 0.036244148000150744, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_create_standard_queue_with_fifo_attribute_raises_error[sqs]": 0.08224480199987738, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_create_standard_queue_with_fifo_attribute_raises_error[sqs_query]": 0.08004530200014415, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_dead_letter_queue_chain[sqs]": 0.0016766339995228918, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_dead_letter_queue_chain[sqs_query]": 0.0017121309997492062, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_dead_letter_queue_config": 0.03702626100039197, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_dead_letter_queue_execution_lambda_mapping_preserves_id[sqs]": 0.0018784439998853486, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_dead_letter_queue_execution_lambda_mapping_preserves_id[sqs_query]": 0.0017548220002936432, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_dead_letter_queue_list_sources[sqs]": 0.05898568099928525, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_dead_letter_queue_list_sources[sqs_query]": 0.060930569999527506, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_dead_letter_queue_max_receive_count[sqs]": 0.12606582399939725, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_dead_letter_queue_max_receive_count[sqs_query]": 0.1307278039994344, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_dead_letter_queue_message_attributes": 0.7590886240000145, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_dead_letter_queue_with_fifo_and_content_based_deduplication[sqs]": 0.16818712000031155, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_dead_letter_queue_with_fifo_and_content_based_deduplication[sqs_query]": 0.17264950600065276, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_deduplication_interval[sqs]": 0.0018175209997934871, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_deduplication_interval[sqs_query]": 0.0017524170002616302, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_delete_after_visibility_timeout[sqs]": 1.1269590530000642, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_delete_after_visibility_timeout[sqs_query]": 1.1216539769998235, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_delete_message_batch_from_lambda[sqs]": 0.0018187019995821174, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_delete_message_batch_from_lambda[sqs_query]": 0.0016257079996648827, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_delete_message_batch_invalid_msg_id[sqs-]": 0.16111618499962788, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_delete_message_batch_invalid_msg_id[sqs-invalid:id]": 0.06843527000000904, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_delete_message_batch_invalid_msg_id[sqs-testLongIdtestLongIdtestLongIdtestLongIdtestLongIdtestLongIdtestLongIdtestLongIdtestLongIdtestLongId]": 0.06804211300004681, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_delete_message_batch_invalid_msg_id[sqs_query-]": 0.06767656200008787, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_delete_message_batch_invalid_msg_id[sqs_query-invalid:id]": 0.0686336630005826, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_delete_message_batch_invalid_msg_id[sqs_query-testLongIdtestLongIdtestLongIdtestLongIdtestLongIdtestLongIdtestLongIdtestLongIdtestLongIdtestLongId]": 0.06680168699995193, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_delete_message_batch_with_too_large_batch[sqs]": 0.650429368999994, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_delete_message_batch_with_too_large_batch[sqs_query]": 0.6592376640005568, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_delete_message_deletes_with_change_visibility_timeout[sqs]": 0.15566150099994047, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_delete_message_deletes_with_change_visibility_timeout[sqs_query]": 0.16125100700037365, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_delete_message_with_deleted_receipt_handle[sqs]": 0.11168961900011709, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_delete_message_with_deleted_receipt_handle[sqs_query]": 0.1113002819997746, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_delete_message_with_illegal_receipt_handle[sqs]": 0.031248368000433402, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_delete_message_with_illegal_receipt_handle[sqs_query]": 0.030361220999566285, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_disallow_queue_name_with_slashes": 0.0016644820002511551, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_extend_message_visibility_timeout_set_in_queue[sqs]": 6.2014863039999, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_extend_message_visibility_timeout_set_in_queue[sqs_query]": 6.99739885200006, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_external_endpoint[sqs]": 0.12769941600026868, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_external_endpoint[sqs_query]": 0.06296750199999224, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_external_host_via_header_complete_message_lifecycle": 0.08851900299987392, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_external_hostname_via_host_header": 0.031140615999902366, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_fair_queue_with_message_group_id[sqs]": 0.1099126289996093, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_fair_queue_with_message_group_id[sqs_query]": 0.11015329899964854, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_fifo_approx_number_of_messages[sqs]": 0.24401193199992122, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_fifo_approx_number_of_messages[sqs_query]": 0.25022980699986874, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_fifo_change_to_high_throughput_after_creation[sqs]": 0.3247484989997247, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_fifo_change_to_high_throughput_after_creation[sqs_query]": 0.331621551999433, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_fifo_change_to_regular_throughput_after_creation[sqs]": 0.23039284100013901, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_fifo_change_to_regular_throughput_after_creation[sqs_query]": 0.23107431699963854, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_fifo_content_based_message_deduplication_arrives_once[sqs]": 1.099846222999986, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_fifo_content_based_message_deduplication_arrives_once[sqs_query]": 1.0966737980002108, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_fifo_deduplication_arrives_once_after_delete[sqs-False]": 1.1526321309997911, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_fifo_deduplication_arrives_once_after_delete[sqs-True]": 1.1533366930002558, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_fifo_deduplication_arrives_once_after_delete[sqs_query-False]": 1.1541765150000174, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_fifo_deduplication_arrives_once_after_delete[sqs_query-True]": 1.152375399000448, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_fifo_deduplication_not_on_message_group_id[sqs-False]": 1.1326651649997075, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_fifo_deduplication_not_on_message_group_id[sqs-True]": 1.1421040669997637, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_fifo_deduplication_not_on_message_group_id[sqs_query-False]": 1.1331876439999178, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_fifo_deduplication_not_on_message_group_id[sqs_query-True]": 1.1337827420002213, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_fifo_delete_after_visibility_timeout[sqs]": 1.1741387530000793, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_fifo_delete_after_visibility_timeout[sqs_query]": 1.1754018540000288, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_fifo_delete_message_with_expired_receipt_handle[sqs]": 0.0016986760001600487, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_fifo_delete_message_with_expired_receipt_handle[sqs_query]": 0.0016785980001259304, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_fifo_empty_message_groups_added_back_to_queue[sqs]": 0.1729638330002672, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_fifo_empty_message_groups_added_back_to_queue[sqs_query]": 0.17420778200039422, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_fifo_high_throughput_ordering[sqs]": 0.15755012800036639, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_fifo_high_throughput_ordering[sqs_query]": 0.15861618200005978, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_fifo_message_attributes[sqs]": 0.1584494380003889, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_fifo_message_attributes[sqs_query]": 0.16035061300090092, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_fifo_message_group_visibility": 2.1103680240003087, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_fifo_message_group_visibility_after_change_message_visibility[sqs]": 2.1277779400002146, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_fifo_message_group_visibility_after_change_message_visibility[sqs_query]": 2.138380918999701, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_fifo_message_group_visibility_after_delete[sqs]": 0.2489430660002654, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_fifo_message_group_visibility_after_delete[sqs_query]": 0.2953905260001193, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_fifo_message_group_visibility_after_partial_delete[sqs]": 0.2693313719996695, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_fifo_message_group_visibility_after_partial_delete[sqs_query]": 0.25982725800031403, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_fifo_message_group_visibility_after_terminate_visibility_timeout[sqs]": 0.13222443199992995, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_fifo_message_group_visibility_after_terminate_visibility_timeout[sqs_query]": 0.13386045400011426, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_fifo_messages_in_order_after_timeout[sqs]": 2.1127299689997017, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_fifo_messages_in_order_after_timeout[sqs_query]": 2.103939007000008, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_fifo_queue_requires_suffix": 0.015542102999916096, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_fifo_queue_send_message_with_delay_on_queue_works[sqs]": 4.097345731999667, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_fifo_queue_send_message_with_delay_on_queue_works[sqs_query]": 4.102351711999745, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_fifo_queue_send_message_with_delay_seconds_fails[sqs]": 0.1753669469999295, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_fifo_queue_send_message_with_delay_seconds_fails[sqs_query]": 0.1567316320001737, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_fifo_queue_send_message_with_zero_delay_defaults_to_queue_delay[sqs]": 4.1139525119997415, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_fifo_queue_send_message_with_zero_delay_defaults_to_queue_delay[sqs_query]": 4.116017885000474, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_fifo_queue_send_multiple_messages_multiple_single_receives[sqs]": 0.24349559700021928, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_fifo_queue_send_multiple_messages_multiple_single_receives[sqs_query]": 0.24529998799971509, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_fifo_receive_message_group_id_ordering[sqs]": 0.133232097000473, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_fifo_receive_message_group_id_ordering[sqs_query]": 0.1360965369999576, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_fifo_receive_message_visibility_timeout_shared_in_group[sqs]": 3.51453093300006, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_fifo_receive_message_visibility_timeout_shared_in_group[sqs_query]": 2.183627208999951, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_fifo_receive_message_with_zero_visibility_timeout[sqs]": 0.173259046000112, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_fifo_receive_message_with_zero_visibility_timeout[sqs_query]": 0.1745205470001565, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_fifo_sequence_number_increases[sqs]": 0.09627180900042731, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_fifo_sequence_number_increases[sqs_query]": 0.09720894400015823, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_fifo_set_content_based_deduplication_strategy[sqs]": 0.08743548599932183, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_fifo_set_content_based_deduplication_strategy[sqs_query]": 0.09082197400039149, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_get_list_queues_with_query_auth": 0.02063423000026887, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_get_queue_url_contains_localstack_host[sqs]": 0.03151709399980973, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_get_queue_url_contains_localstack_host[sqs_query]": 0.037768634999792994, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_get_queue_url_multi_region[domain]": 0.0501409499993315, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_get_queue_url_multi_region[path]": 0.05052785899988521, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_get_queue_url_multi_region[standard]": 0.05223175399987667, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_get_specific_queue_attribute_response[sqs]": 0.05556147700008296, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_get_specific_queue_attribute_response[sqs_query]": 0.0562368629998673, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_inflight_message_requeue": 4.591975752999588, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_invalid_batch_id[sqs]": 0.14061046999950122, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_invalid_batch_id[sqs_query]": 0.14152612899988526, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_invalid_dead_letter_arn_rejected_before_lookup": 0.0017886750001707696, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_invalid_receipt_handle_should_return_error_message[sqs]": 0.030726125999990472, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_invalid_receipt_handle_should_return_error_message[sqs_query]": 0.02969768099956127, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_invalid_string_attributes_cause_invalid_parameter_value_error[sqs]": 0.029280717000347067, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_invalid_string_attributes_cause_invalid_parameter_value_error[sqs_query]": 0.030286392999641976, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_list_queue_tags[sqs]": 0.03592263200016532, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_list_queue_tags[sqs_query]": 0.036748064999756025, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_list_queues": 0.09460090500033402, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_list_queues_multi_region_with_endpoint_strategy_domain": 0.06175906799990116, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_list_queues_multi_region_with_endpoint_strategy_standard": 0.06093758599990906, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_list_queues_multi_region_without_endpoint_strategy": 0.07127442499995595, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_list_queues_pagination": 0.2737448000002587, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_marker_serialization_json_protocol[\"{\\\\\"foo\\\\\": \\\\\"ba\\\\rr\\\\\"}\"]": 0.0780517839998538, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_marker_serialization_json_protocol[{\"foo\": \"ba\\rr\", \"foo2\": \"ba"r"\"}]": 0.07958451399963451, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_message_deduplication_id_invalid[empty]": 0.06988805300034073, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_message_deduplication_id_invalid[spaces]": 0.07553387500001918, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_message_deduplication_id_invalid[too_long]": 0.07103944000027695, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_message_deduplication_id_success": 0.04942994499970155, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_message_retention": 3.0724374320006973, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_message_retention_fifo": 3.069914592999339, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_message_retention_with_inflight": 5.611137737000263, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_message_system_attribute_names_with_attribute_names[sqs]": 0.12038098499988337, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_message_system_attribute_names_with_attribute_names[sqs_query]": 0.12299935700002607, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_message_with_attributes_should_be_enqueued[sqs]": 0.06328487200016752, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_message_with_attributes_should_be_enqueued[sqs_query]": 0.06224406900037138, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_message_with_carriage_return[sqs]": 0.0646157929995752, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_message_with_carriage_return[sqs_query]": 0.06543127099985213, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_non_existent_queue": 0.17442676499968002, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_posting_to_fifo_requires_deduplicationid_group_id[sqs]": 0.23369672499939043, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_posting_to_fifo_requires_deduplicationid_group_id[sqs_query]": 0.23857155899986537, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_posting_to_queue_via_queue_name[sqs]": 0.04830609699956767, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_posting_to_queue_via_queue_name[sqs_query]": 0.047336096000435646, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_publish_get_delete_message[sqs]": 0.09411348900039229, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_publish_get_delete_message[sqs_query]": 0.10670459000039045, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_publish_get_delete_message_batch[sqs]": 0.17130787900032374, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_publish_get_delete_message_batch[sqs_query]": 0.25190582000004724, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_purge_queue[sqs]": 1.2430703159998302, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_purge_queue[sqs_query]": 1.2281092699995497, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_purge_queue_clears_fifo_deduplication_cache[sqs]": 0.09483639099971697, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_purge_queue_clears_fifo_deduplication_cache[sqs_query]": 0.09492801199985479, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_purge_queue_deletes_delayed_messages[sqs]": 3.1442317320002076, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_purge_queue_deletes_delayed_messages[sqs_query]": 3.1827820369999245, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_purge_queue_deletes_inflight_messages[sqs]": 4.271089804999974, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_purge_queue_deletes_inflight_messages[sqs_query]": 4.243241520000083, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_queue_list_nonexistent_tags[sqs]": 0.02991932899976746, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_queue_list_nonexistent_tags[sqs_query]": 0.02977304300020478, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_receive_after_visibility_timeout[sqs]": 1.7320383700002822, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_receive_after_visibility_timeout[sqs_query]": 1.9986299779998262, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_receive_empty_queue[sqs]": 1.0928865470000346, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_receive_empty_queue[sqs_query]": 1.0942731529999037, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_receive_message_attribute_names_filters[sqs]": 0.23095086800003628, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_receive_message_attribute_names_filters[sqs_query]": 0.23162340199996834, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_receive_message_attributes_timestamp_types[sqs]": 0.06510562599987679, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_receive_message_attributes_timestamp_types[sqs_query]": 0.06603301099949022, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_receive_message_message_attribute_names_filters[sqs]": 0.3136305579996588, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_receive_message_message_attribute_names_filters[sqs_query]": 0.2743147179994594, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_receive_message_message_system_attribute_names_filters[sqs]": 0.15683063000051334, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_receive_message_message_system_attribute_names_filters[sqs_query]": 0.1607661520001784, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_receive_message_wait_time_seconds_and_max_number_of_messages_does_not_block[sqs]": 0.09214720199952353, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_receive_message_wait_time_seconds_and_max_number_of_messages_does_not_block[sqs_query]": 0.09266177699964828, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_receive_message_with_visibility_timeout_updates_timeout[sqs]": 0.09130136200064953, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_receive_message_with_visibility_timeout_updates_timeout[sqs_query]": 0.0935833260000436, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_receive_terminate_visibility_timeout[sqs]": 0.0944745090005199, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_receive_terminate_visibility_timeout[sqs_query]": 0.09502814099960233, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_redrive_policy_attribute_validity[sqs]": 0.0016114209993247641, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_redrive_policy_attribute_validity[sqs_query]": 0.001655124000080832, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_remove_message_with_old_receipt_handle[sqs]": 2.082770313999845, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_remove_message_with_old_receipt_handle[sqs_query]": 2.0825161759994444, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_send_batch_message_size": 0.22913828799983094, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_send_batch_missing_deduplication_id_for_fifo_queue[sqs]": 0.13843160599981275, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_send_batch_missing_deduplication_id_for_fifo_queue[sqs_query]": 0.13834223300000303, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_send_batch_missing_message_group_id_for_fifo_queue[sqs]": 0.14008727200007343, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_send_batch_missing_message_group_id_for_fifo_queue[sqs_query]": 0.1419680910007628, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_send_batch_receive_multiple[sqs]": 0.10630998499982525, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_send_batch_receive_multiple[sqs_query]": 0.10471424200022739, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_send_delay_and_wait_time[sqs]": 1.891099313000268, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_send_delay_and_wait_time[sqs_query]": 1.9983066989998406, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_send_empty_message[sqs]": 0.1386241360000895, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_send_empty_message[sqs_query]": 0.1412056469998788, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_send_message_batch[sqs]": 0.11203167899975597, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_send_message_batch[sqs_query]": 0.1123158059999696, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_send_message_batch_with_empty_list[sqs]": 0.02854230799994184, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_send_message_batch_with_empty_list[sqs_query]": 0.02837475500018627, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_send_message_batch_with_oversized_contents[sqs]": 0.16517723599963574, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_send_message_batch_with_oversized_contents[sqs_query]": 0.18917780899982972, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_send_message_batch_with_oversized_contents_with_updated_maximum_message_size[sqs]": 0.12158126699978311, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_send_message_batch_with_oversized_contents_with_updated_maximum_message_size[sqs_query]": 0.11249407999957839, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_send_message_to_standard_queue_with_invalid_message_group_id[empty]": 0.0689861630003179, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_send_message_to_standard_queue_with_invalid_message_group_id[spaces]": 0.06711958600044454, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_send_message_to_standard_queue_with_invalid_message_group_id[too_long]": 0.06728861500005223, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_send_message_with_attributes[sqs]": 0.06327127899976404, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_send_message_with_attributes[sqs_query]": 0.06448416800003542, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_send_message_with_binary_attributes[sqs]": 0.10177787800012084, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_send_message_with_binary_attributes[sqs_query]": 0.10328755100044873, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_send_message_with_delay_0_works_for_fifo[sqs]": 0.06436044500060234, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_send_message_with_delay_0_works_for_fifo[sqs_query]": 0.06800741500001095, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_send_message_with_empty_string_attribute[sqs]": 0.14019934400039347, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_send_message_with_empty_string_attribute[sqs_query]": 0.14088930399975652, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_send_message_with_invalid_fifo_parameters[sqs]": 0.001710207999622071, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_send_message_with_invalid_fifo_parameters[sqs_query]": 0.0016695710000931285, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_send_message_with_invalid_payload_characters[sqs]": 0.031060184999660123, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_send_message_with_invalid_payload_characters[sqs_query]": 0.029390652000074624, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_send_message_with_invalid_string_attributes[sqs]": 0.13662768200038045, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_send_message_with_invalid_string_attributes[sqs_query]": 0.13909167000019806, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_send_message_with_updated_maximum_message_size[sqs]": 0.17420626200009792, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_send_message_with_updated_maximum_message_size[sqs_query]": 0.1809897250004724, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_send_oversized_message[sqs]": 0.15744854499962457, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_send_oversized_message[sqs_query]": 0.17516290099956677, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_send_receive_max_number_of_messages[sqs]": 0.16660516000001735, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_send_receive_max_number_of_messages[sqs_query]": 0.16470996500038382, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_send_receive_message[sqs]": 0.06344469300029232, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_send_receive_message[sqs_query]": 0.06508383499976844, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_send_receive_message_encoded_content[sqs]": 0.06323592199942141, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_send_receive_message_encoded_content[sqs_query]": 0.06257514499975514, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_send_receive_message_multiple_queues": 0.09121103799998309, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_send_receive_wait_time_seconds[sqs]": 0.23123057600014363, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_send_receive_wait_time_seconds[sqs_query]": 0.2324497970007542, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_sent_message_retains_attributes_after_receive[sqs]": 0.07927461599956587, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_sent_message_retains_attributes_after_receive[sqs_query]": 0.07979416900070646, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_sequence_number[sqs]": 0.08591220099970087, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_sequence_number[sqs_query]": 0.08533837199956906, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_set_empty_queue_policy[sqs]": 0.06461305800075934, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_set_empty_queue_policy[sqs_query]": 0.0667832020003516, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_set_empty_redrive_policy[sqs]": 0.06935097199993834, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_set_empty_redrive_policy[sqs_query]": 0.07248741400053405, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_set_queue_policy[sqs]": 0.04327207999949678, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_set_queue_policy[sqs_query]": 0.04506629600018641, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_set_unsupported_attribute_fifo[sqs]": 0.23907012300014685, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_set_unsupported_attribute_fifo[sqs_query]": 0.24284137099948566, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_set_unsupported_attribute_standard[sqs]": 0.21782245100030195, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_set_unsupported_attribute_standard[sqs_query]": 0.21794867800053908, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_sqs_fifo_message_group_scope_no_throughput_setting[sqs]": 0.15686796199997843, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_sqs_fifo_message_group_scope_no_throughput_setting[sqs_query]": 0.16145112700041864, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_sqs_fifo_same_dedup_id_different_message_groups[sqs]": 0.1562969689998681, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_sqs_fifo_same_dedup_id_different_message_groups[sqs_query]": 0.1574976480001169, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_sqs_permission_lifecycle[sqs]": 0.24814269900025465, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_sqs_permission_lifecycle[sqs_query]": 0.25360768500013364, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_sse_kms_and_sqs_are_mutually_exclusive[sqs]": 0.0019274979999863717, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_sse_kms_and_sqs_are_mutually_exclusive[sqs_query]": 0.0018197639997197257, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_sse_queue_attributes[sqs]": 0.11774222500025644, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_sse_queue_attributes[sqs_query]": 0.11684915900013948, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_standard_queue_cannot_have_fifo_suffix": 0.013654519999818149, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_successive_purge_calls_fail[sqs]": 0.1478715759994884, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_successive_purge_calls_fail[sqs_query]": 0.1475501279992386, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_system_attributes_have_no_effect_on_attr_md5[sqs]": 0.07071330500048134, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_system_attributes_have_no_effect_on_attr_md5[sqs_query]": 0.07325852599979044, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_tag_queue_overwrites_existing_tag[sqs]": 0.04210079599988603, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_tag_queue_overwrites_existing_tag[sqs_query]": 0.041884308000135206, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_tag_untag_queue[sqs]": 0.10382654399973035, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_tag_untag_queue[sqs_query]": 0.10478324199993949, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_tags_case_sensitive[sqs]": 0.03571180699964316, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_tags_case_sensitive[sqs_query]": 0.0356310250003844, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_terminate_visibility_timeout_after_receive[sqs]": 0.09999785499985592, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_terminate_visibility_timeout_after_receive[sqs_query]": 0.10100725199981753, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_too_many_entries_in_batch_request[sqs]": 0.15887959900010173, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_too_many_entries_in_batch_request[sqs_query]": 0.14472964300057356, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_untag_queue_ignores_non_existing_tag[sqs]": 0.04223948700018809, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_untag_queue_ignores_non_existing_tag[sqs_query]": 0.04204073299979427, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_wait_time_seconds_queue_attribute_waits_correctly[sqs]": 1.0614358009997886, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_wait_time_seconds_queue_attribute_waits_correctly[sqs_query]": 1.061825212999338, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_wait_time_seconds_waits_correctly[sqs]": 1.0632243830004882, - "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_wait_time_seconds_waits_correctly[sqs_query]": 1.0652233630003138, - "tests/aws/services/sqs/test_sqs.py::TestSqsQueryApi::test_endpoint_strategy_with_multi_region[domain]": 0.11968226900035006, - "tests/aws/services/sqs/test_sqs.py::TestSqsQueryApi::test_endpoint_strategy_with_multi_region[off]": 0.12290964099975099, - "tests/aws/services/sqs/test_sqs.py::TestSqsQueryApi::test_endpoint_strategy_with_multi_region[path]": 0.12052798000013354, - "tests/aws/services/sqs/test_sqs.py::TestSqsQueryApi::test_endpoint_strategy_with_multi_region[standard]": 0.17919661999985692, - "tests/aws/services/sqs/test_sqs.py::TestSqsQueryApi::test_get_create_queue_fails": 0.030921356999897398, - "tests/aws/services/sqs/test_sqs.py::TestSqsQueryApi::test_get_delete_queue[domain]": 0.04753043400023671, - "tests/aws/services/sqs/test_sqs.py::TestSqsQueryApi::test_get_delete_queue[path]": 0.04983613000013065, - "tests/aws/services/sqs/test_sqs.py::TestSqsQueryApi::test_get_delete_queue[standard]": 0.04798130199969819, - "tests/aws/services/sqs/test_sqs.py::TestSqsQueryApi::test_get_list_queues_fails": 0.03030665599999338, - "tests/aws/services/sqs/test_sqs.py::TestSqsQueryApi::test_get_list_queues_fails_json_format": 0.0021299469999576104, - "tests/aws/services/sqs/test_sqs.py::TestSqsQueryApi::test_get_on_deleted_queue_fails[sqs]": 0.05209615300009318, - "tests/aws/services/sqs/test_sqs.py::TestSqsQueryApi::test_get_on_deleted_queue_fails[sqs_query]": 0.0530535159991814, - "tests/aws/services/sqs/test_sqs.py::TestSqsQueryApi::test_get_queue_attributes_all": 0.05365280100068048, - "tests/aws/services/sqs/test_sqs.py::TestSqsQueryApi::test_get_queue_attributes_json_format": 0.001683426999989024, - "tests/aws/services/sqs/test_sqs.py::TestSqsQueryApi::test_get_queue_attributes_of_fifo_queue": 0.04218928499994945, - "tests/aws/services/sqs/test_sqs.py::TestSqsQueryApi::test_get_queue_attributes_with_invalid_arg_returns_error": 0.041859642999952484, - "tests/aws/services/sqs/test_sqs.py::TestSqsQueryApi::test_get_queue_attributes_with_query_args": 0.04095209500019337, - "tests/aws/services/sqs/test_sqs.py::TestSqsQueryApi::test_get_queue_attributes_works_without_authparams[domain]": 0.03949042699969141, - "tests/aws/services/sqs/test_sqs.py::TestSqsQueryApi::test_get_queue_attributes_works_without_authparams[path]": 0.03969356000015978, - "tests/aws/services/sqs/test_sqs.py::TestSqsQueryApi::test_get_queue_attributes_works_without_authparams[standard]": 0.04001950299971213, - "tests/aws/services/sqs/test_sqs.py::TestSqsQueryApi::test_get_queue_url_work_for_different_queue[domain]": 0.052826099000412796, - "tests/aws/services/sqs/test_sqs.py::TestSqsQueryApi::test_get_queue_url_work_for_different_queue[path]": 0.0531616150001355, - "tests/aws/services/sqs/test_sqs.py::TestSqsQueryApi::test_get_queue_url_work_for_different_queue[standard]": 0.051506020000488206, - "tests/aws/services/sqs/test_sqs.py::TestSqsQueryApi::test_get_queue_url_works_for_same_queue[domain]": 0.03775020300008691, - "tests/aws/services/sqs/test_sqs.py::TestSqsQueryApi::test_get_queue_url_works_for_same_queue[path]": 0.03797753099979673, - "tests/aws/services/sqs/test_sqs.py::TestSqsQueryApi::test_get_queue_url_works_for_same_queue[standard]": 0.0397369429997525, - "tests/aws/services/sqs/test_sqs.py::TestSqsQueryApi::test_get_send_and_receive_messages": 0.11650032199986526, - "tests/aws/services/sqs/test_sqs.py::TestSqsQueryApi::test_get_without_query_json_format_returns_returns_xml": 0.035407485000177985, - "tests/aws/services/sqs/test_sqs.py::TestSqsQueryApi::test_get_without_query_returns_unknown_operation": 0.03038080600072135, - "tests/aws/services/sqs/test_sqs.py::TestSqsQueryApi::test_invalid_action_raises_exception": 0.03459618999977465, - "tests/aws/services/sqs/test_sqs.py::TestSqsQueryApi::test_overwrite_queue_url_in_params": 0.05822564599930047, - "tests/aws/services/sqs/test_sqs.py::TestSqsQueryApi::test_queue_url_format_path_strategy": 0.02491899899996497, - "tests/aws/services/sqs/test_sqs.py::TestSqsQueryApi::test_send_message_via_queue_url_with_json_protocol": 1.0921735780002564, - "tests/aws/services/sqs/test_sqs.py::TestSqsQueryApi::test_valid_action_with_missing_parameter_raises_exception": 0.03293820700037031, - "tests/aws/services/sqs/test_sqs_backdoor.py::TestSqsDeveloperEndpoints::test_fifo_list_messages_as_botocore_endpoint_url[json-domain]": 0.0998748050001268, - "tests/aws/services/sqs/test_sqs_backdoor.py::TestSqsDeveloperEndpoints::test_fifo_list_messages_as_botocore_endpoint_url[json-path]": 0.10332748700011507, - "tests/aws/services/sqs/test_sqs_backdoor.py::TestSqsDeveloperEndpoints::test_fifo_list_messages_as_botocore_endpoint_url[json-standard]": 0.1035803559998385, - "tests/aws/services/sqs/test_sqs_backdoor.py::TestSqsDeveloperEndpoints::test_fifo_list_messages_as_botocore_endpoint_url[query-domain]": 0.10283490099982373, - "tests/aws/services/sqs/test_sqs_backdoor.py::TestSqsDeveloperEndpoints::test_fifo_list_messages_as_botocore_endpoint_url[query-path]": 0.103557381000428, - "tests/aws/services/sqs/test_sqs_backdoor.py::TestSqsDeveloperEndpoints::test_fifo_list_messages_as_botocore_endpoint_url[query-standard]": 0.10184545099946263, - "tests/aws/services/sqs/test_sqs_backdoor.py::TestSqsDeveloperEndpoints::test_list_messages_as_botocore_endpoint_url[json-domain]": 0.07665739099957136, - "tests/aws/services/sqs/test_sqs_backdoor.py::TestSqsDeveloperEndpoints::test_list_messages_as_botocore_endpoint_url[json-path]": 0.07743556900049953, - "tests/aws/services/sqs/test_sqs_backdoor.py::TestSqsDeveloperEndpoints::test_list_messages_as_botocore_endpoint_url[json-standard]": 0.08386818900044091, - "tests/aws/services/sqs/test_sqs_backdoor.py::TestSqsDeveloperEndpoints::test_list_messages_as_botocore_endpoint_url[query-domain]": 0.07901557600007436, - "tests/aws/services/sqs/test_sqs_backdoor.py::TestSqsDeveloperEndpoints::test_list_messages_as_botocore_endpoint_url[query-path]": 0.07811237800024173, - "tests/aws/services/sqs/test_sqs_backdoor.py::TestSqsDeveloperEndpoints::test_list_messages_as_botocore_endpoint_url[query-standard]": 0.08533873500027767, - "tests/aws/services/sqs/test_sqs_backdoor.py::TestSqsDeveloperEndpoints::test_list_messages_as_json[domain]": 0.07742602000007537, - "tests/aws/services/sqs/test_sqs_backdoor.py::TestSqsDeveloperEndpoints::test_list_messages_as_json[path]": 0.07662527200000113, - "tests/aws/services/sqs/test_sqs_backdoor.py::TestSqsDeveloperEndpoints::test_list_messages_as_json[standard]": 0.07526774799998748, - "tests/aws/services/sqs/test_sqs_backdoor.py::TestSqsDeveloperEndpoints::test_list_messages_has_no_side_effects[domain]": 0.10202377700034049, - "tests/aws/services/sqs/test_sqs_backdoor.py::TestSqsDeveloperEndpoints::test_list_messages_has_no_side_effects[path]": 0.09735905100023956, - "tests/aws/services/sqs/test_sqs_backdoor.py::TestSqsDeveloperEndpoints::test_list_messages_has_no_side_effects[standard]": 0.09862147500007268, - "tests/aws/services/sqs/test_sqs_backdoor.py::TestSqsDeveloperEndpoints::test_list_messages_with_delayed_messages[domain]": 0.10784124999963751, - "tests/aws/services/sqs/test_sqs_backdoor.py::TestSqsDeveloperEndpoints::test_list_messages_with_delayed_messages[path]": 0.10666101200013145, - "tests/aws/services/sqs/test_sqs_backdoor.py::TestSqsDeveloperEndpoints::test_list_messages_with_delayed_messages[standard]": 0.10556806700014931, - "tests/aws/services/sqs/test_sqs_backdoor.py::TestSqsDeveloperEndpoints::test_list_messages_with_invalid_action_raises_error[json-domain]": 0.02795011300031547, - "tests/aws/services/sqs/test_sqs_backdoor.py::TestSqsDeveloperEndpoints::test_list_messages_with_invalid_action_raises_error[json-path]": 0.028435900999738806, - "tests/aws/services/sqs/test_sqs_backdoor.py::TestSqsDeveloperEndpoints::test_list_messages_with_invalid_action_raises_error[json-standard]": 0.029448012999637285, - "tests/aws/services/sqs/test_sqs_backdoor.py::TestSqsDeveloperEndpoints::test_list_messages_with_invalid_action_raises_error[query-domain]": 0.027917863999846304, - "tests/aws/services/sqs/test_sqs_backdoor.py::TestSqsDeveloperEndpoints::test_list_messages_with_invalid_action_raises_error[query-path]": 0.028134264000073017, - "tests/aws/services/sqs/test_sqs_backdoor.py::TestSqsDeveloperEndpoints::test_list_messages_with_invalid_action_raises_error[query-standard]": 0.030351603999861254, - "tests/aws/services/sqs/test_sqs_backdoor.py::TestSqsDeveloperEndpoints::test_list_messages_with_invalid_queue_url[domain]": 0.018530885000473063, - "tests/aws/services/sqs/test_sqs_backdoor.py::TestSqsDeveloperEndpoints::test_list_messages_with_invalid_queue_url[path]": 0.018971997999869927, - "tests/aws/services/sqs/test_sqs_backdoor.py::TestSqsDeveloperEndpoints::test_list_messages_with_invalid_queue_url[standard]": 0.020208605999869178, - "tests/aws/services/sqs/test_sqs_backdoor.py::TestSqsDeveloperEndpoints::test_list_messages_with_invisible_messages[domain]": 0.12001916400049595, - "tests/aws/services/sqs/test_sqs_backdoor.py::TestSqsDeveloperEndpoints::test_list_messages_with_invisible_messages[path]": 0.11997474400050123, - "tests/aws/services/sqs/test_sqs_backdoor.py::TestSqsDeveloperEndpoints::test_list_messages_with_invisible_messages[standard]": 0.12154465199955666, - "tests/aws/services/sqs/test_sqs_backdoor.py::TestSqsDeveloperEndpoints::test_list_messages_with_non_existent_queue[domain]": 0.02374641300048097, - "tests/aws/services/sqs/test_sqs_backdoor.py::TestSqsDeveloperEndpoints::test_list_messages_with_non_existent_queue[path]": 0.024543470999560668, - "tests/aws/services/sqs/test_sqs_backdoor.py::TestSqsDeveloperEndpoints::test_list_messages_with_non_existent_queue[standard]": 0.023681767999732983, - "tests/aws/services/sqs/test_sqs_backdoor.py::TestSqsDeveloperEndpoints::test_list_messages_with_queue_url_in_path[domain]": 0.08313034799994057, - "tests/aws/services/sqs/test_sqs_backdoor.py::TestSqsDeveloperEndpoints::test_list_messages_with_queue_url_in_path[path]": 0.0808979379999073, - "tests/aws/services/sqs/test_sqs_backdoor.py::TestSqsDeveloperEndpoints::test_list_messages_with_queue_url_in_path[standard]": 0.08227417399984915, - "tests/aws/services/sqs/test_sqs_backdoor.py::TestSqsDeveloperEndpoints::test_list_messages_without_queue_url[domain]": 0.017859042000054615, - "tests/aws/services/sqs/test_sqs_backdoor.py::TestSqsDeveloperEndpoints::test_list_messages_without_queue_url[path]": 0.017803216000629618, - "tests/aws/services/sqs/test_sqs_backdoor.py::TestSqsDeveloperEndpoints::test_list_messages_without_queue_url[standard]": 0.018665594000140118, - "tests/aws/services/sqs/test_sqs_backdoor.py::TestSqsOverrideHeaders::test_receive_message_override_max_number_of_messages": 0.4022043740001209, - "tests/aws/services/sqs/test_sqs_backdoor.py::TestSqsOverrideHeaders::test_receive_message_override_message_wait_time_seconds": 25.254882433000148, - "tests/aws/services/sqs/test_sqs_move_task.py::test_basic_move_task_workflow": 1.812901002000217, - "tests/aws/services/sqs/test_sqs_move_task.py::test_cancel_with_invalid_source_arn_in_task_handle": 0.05002891699996326, - "tests/aws/services/sqs/test_sqs_move_task.py::test_cancel_with_invalid_task_handle": 0.053238316000260966, - "tests/aws/services/sqs/test_sqs_move_task.py::test_cancel_with_invalid_task_id_in_task_handle": 0.07462972800021817, - "tests/aws/services/sqs/test_sqs_move_task.py::test_destination_needs_to_exist": 0.10616784200010443, - "tests/aws/services/sqs/test_sqs_move_task.py::test_move_task_cancel": 1.8198730029998842, - "tests/aws/services/sqs/test_sqs_move_task.py::test_move_task_delete_destination_queue_while_running": 1.8638139340000635, - "tests/aws/services/sqs/test_sqs_move_task.py::test_move_task_with_throughput_limit": 3.438102752999839, - "tests/aws/services/sqs/test_sqs_move_task.py::test_move_task_workflow_with_default_destination": 1.8024598409992905, - "tests/aws/services/sqs/test_sqs_move_task.py::test_move_task_workflow_with_multiple_sources_as_default_destination": 2.5151042010006677, - "tests/aws/services/sqs/test_sqs_move_task.py::test_source_needs_redrive_policy": 0.0929697080000551, - "tests/aws/services/sqs/test_sqs_move_task.py::test_start_multiple_move_tasks": 0.693305464000332, - "tests/aws/services/ssm/test_ssm.py::TestSSM::test_describe_parameters": 0.016372535999835236, - "tests/aws/services/ssm/test_ssm.py::TestSSM::test_get_inexistent_maintenance_window": 0.014912380000168923, - "tests/aws/services/ssm/test_ssm.py::TestSSM::test_get_inexistent_secret": 0.03365872299946204, - "tests/aws/services/ssm/test_ssm.py::TestSSM::test_get_parameter_by_arn": 0.058861824000359775, - "tests/aws/services/ssm/test_ssm.py::TestSSM::test_get_parameters_and_secrets": 0.12255885599915928, - "tests/aws/services/ssm/test_ssm.py::TestSSM::test_get_parameters_by_path_and_filter_by_labels": 0.06163508599956913, - "tests/aws/services/ssm/test_ssm.py::TestSSM::test_get_secret_parameter": 0.0672592630003237, - "tests/aws/services/ssm/test_ssm.py::TestSSM::test_hierarchical_parameter[///b//c]": 0.0627855460002138, - "tests/aws/services/ssm/test_ssm.py::TestSSM::test_hierarchical_parameter[/b/c]": 0.06518010499985394, - "tests/aws/services/ssm/test_ssm.py::TestSSM::test_parameters_with_path": 0.15750458699949377, - "tests/aws/services/ssm/test_ssm.py::TestSSM::test_put_parameters": 0.07713579699975526, - "tests/aws/services/ssm/test_ssm.py::TestSSM::test_trigger_event_on_systems_manager_change[domain]": 0.11714157599999453, - "tests/aws/services/ssm/test_ssm.py::TestSSM::test_trigger_event_on_systems_manager_change[path]": 0.11676867199957996, - "tests/aws/services/ssm/test_ssm.py::TestSSM::test_trigger_event_on_systems_manager_change[standard]": 0.11916159199972753, - "tests/aws/services/stepfunctions/v2/activities/test_activities.py::TestActivities::test_activity_task": 1.1168161549994693, - "tests/aws/services/stepfunctions/v2/activities/test_activities.py::TestActivities::test_activity_task_failure": 1.9444928799998706, - "tests/aws/services/stepfunctions/v2/activities/test_activities.py::TestActivities::test_activity_task_no_worker_name": 1.9210892710002554, - "tests/aws/services/stepfunctions/v2/activities/test_activities.py::TestActivities::test_activity_task_on_deleted": 0.4191553410000779, - "tests/aws/services/stepfunctions/v2/activities/test_activities.py::TestActivities::test_activity_task_start_timeout": 5.71799353599954, - "tests/aws/services/stepfunctions/v2/activities/test_activities.py::TestActivities::test_activity_task_with_heartbeat": 6.171868001999883, - "tests/aws/services/stepfunctions/v2/arguments/test_arguments.py::TestArgumentsBase::test_base_cases[BASE_LAMBDA_EMPTY]": 2.217100918000142, - "tests/aws/services/stepfunctions/v2/arguments/test_arguments.py::TestArgumentsBase::test_base_cases[BASE_LAMBDA_EMPTY_GLOBAL_QL_JSONATA]": 2.3246185100006187, - "tests/aws/services/stepfunctions/v2/arguments/test_arguments.py::TestArgumentsBase::test_base_cases[BASE_LAMBDA_EXPRESSION]": 6.6142288830001235, - "tests/aws/services/stepfunctions/v2/arguments/test_arguments.py::TestArgumentsBase::test_base_cases[BASE_LAMBDA_LITERALS]": 2.374330598000597, - "tests/aws/services/stepfunctions/v2/assign/test_assign_base.py::TestAssignBase::test_assign_in_choice[CONDITION_FALSE]": 0.905710438999904, - "tests/aws/services/stepfunctions/v2/assign/test_assign_base.py::TestAssignBase::test_assign_in_choice[CONDITION_TRUE]": 0.9543315939995409, - "tests/aws/services/stepfunctions/v2/assign/test_assign_base.py::TestAssignBase::test_base_cases[BASE_CONSTANT_LITERALS]": 1.1422240450001482, - "tests/aws/services/stepfunctions/v2/assign/test_assign_base.py::TestAssignBase::test_base_cases[BASE_EMPTY]": 0.9213784559997293, - "tests/aws/services/stepfunctions/v2/assign/test_assign_base.py::TestAssignBase::test_base_cases[BASE_PATHS]": 0.980946885999856, - "tests/aws/services/stepfunctions/v2/assign/test_assign_base.py::TestAssignBase::test_base_cases[BASE_SCOPE_MAP]": 1.0445470709996698, - "tests/aws/services/stepfunctions/v2/assign/test_assign_base.py::TestAssignBase::test_base_cases[BASE_VAR]": 1.2938416659999348, - "tests/aws/services/stepfunctions/v2/assign/test_assign_base.py::TestAssignBase::test_base_parallel_cases[BASE_SCOPE_PARALLEL]": 1.0799630930000603, - "tests/aws/services/stepfunctions/v2/assign/test_assign_reference_variables.py::TestAssignReferenceVariables::test_assign_from_value[BASE_ASSIGN_FROM_INTRINSIC_FUNCTION]": 1.9545369699994808, - "tests/aws/services/stepfunctions/v2/assign/test_assign_reference_variables.py::TestAssignReferenceVariables::test_assign_from_value[BASE_ASSIGN_FROM_PARAMETERS]": 1.0214464030000272, - "tests/aws/services/stepfunctions/v2/assign/test_assign_reference_variables.py::TestAssignReferenceVariables::test_assign_from_value[BASE_ASSIGN_FROM_RESULT]": 0.9358108220003487, - "tests/aws/services/stepfunctions/v2/assign/test_assign_reference_variables.py::TestAssignReferenceVariables::test_assign_in_catch_state": 2.3644887440000275, - "tests/aws/services/stepfunctions/v2/assign/test_assign_reference_variables.py::TestAssignReferenceVariables::test_assign_in_choice_state[CORRECT]": 0.9777698339999006, - "tests/aws/services/stepfunctions/v2/assign/test_assign_reference_variables.py::TestAssignReferenceVariables::test_assign_in_choice_state[INCORRECT]": 0.9370865670002786, - "tests/aws/services/stepfunctions/v2/assign/test_assign_reference_variables.py::TestAssignReferenceVariables::test_assign_in_wait_state": 0.689651627999865, - "tests/aws/services/stepfunctions/v2/assign/test_assign_reference_variables.py::TestAssignReferenceVariables::test_reference_assign[BASE_REFERENCE_IN_CHOICE]": 1.0035225410001658, - "tests/aws/services/stepfunctions/v2/assign/test_assign_reference_variables.py::TestAssignReferenceVariables::test_reference_assign[BASE_REFERENCE_IN_FAIL]": 0.9252612020000015, - "tests/aws/services/stepfunctions/v2/assign/test_assign_reference_variables.py::TestAssignReferenceVariables::test_reference_assign[BASE_REFERENCE_IN_INPUTPATH]": 0.9290166300002056, - "tests/aws/services/stepfunctions/v2/assign/test_assign_reference_variables.py::TestAssignReferenceVariables::test_reference_assign[BASE_REFERENCE_IN_INTRINSIC_FUNCTION]": 1.1988384149999547, - "tests/aws/services/stepfunctions/v2/assign/test_assign_reference_variables.py::TestAssignReferenceVariables::test_reference_assign[BASE_REFERENCE_IN_ITERATOR_OUTER_SCOPE]": 1.974173786999927, - "tests/aws/services/stepfunctions/v2/assign/test_assign_reference_variables.py::TestAssignReferenceVariables::test_reference_assign[BASE_REFERENCE_IN_OUTPUTPATH]": 0.9508830970003146, - "tests/aws/services/stepfunctions/v2/assign/test_assign_reference_variables.py::TestAssignReferenceVariables::test_reference_assign[BASE_REFERENCE_IN_PARAMETERS]": 0.9637395670001752, - "tests/aws/services/stepfunctions/v2/assign/test_assign_reference_variables.py::TestAssignReferenceVariables::test_reference_assign[BASE_REFERENCE_IN_WAIT]": 0.9518863929997678, - "tests/aws/services/stepfunctions/v2/assign/test_assign_reference_variables.py::TestAssignReferenceVariables::test_reference_in_map_state[MAP_STATE_REFERENCE_IN_INTRINSIC_FUNCTION]": 1.2684681340006136, - "tests/aws/services/stepfunctions/v2/assign/test_assign_reference_variables.py::TestAssignReferenceVariables::test_reference_in_map_state[MAP_STATE_REFERENCE_IN_ITEMS_PATH]": 2.4565484839999954, - "tests/aws/services/stepfunctions/v2/assign/test_assign_reference_variables.py::TestAssignReferenceVariables::test_reference_in_map_state[MAP_STATE_REFERENCE_IN_ITEM_SELECTOR]": 1.07062692000045, - "tests/aws/services/stepfunctions/v2/assign/test_assign_reference_variables.py::TestAssignReferenceVariables::test_reference_in_map_state[MAP_STATE_REFERENCE_IN_MAX_CONCURRENCY_PATH]": 0.9838218740001139, - "tests/aws/services/stepfunctions/v2/assign/test_assign_reference_variables.py::TestAssignReferenceVariables::test_reference_in_map_state[MAP_STATE_REFERENCE_IN_TOLERATED_FAILURE_PATH]": 1.0875372050008991, - "tests/aws/services/stepfunctions/v2/assign/test_assign_reference_variables.py::TestAssignReferenceVariables::test_reference_in_map_state_max_items_path[MAP_STATE_REFERENCE_IN_MAX_ITEMS_PATH]": 1.1290897360004237, - "tests/aws/services/stepfunctions/v2/assign/test_assign_reference_variables.py::TestAssignReferenceVariables::test_reference_in_map_state_max_items_path[MAP_STATE_REFERENCE_IN_MAX_PER_BATCH_PATH]": 0.0020746449999933247, - "tests/aws/services/stepfunctions/v2/assign/test_assign_reference_variables.py::TestAssignReferenceVariables::test_state_assign_evaluation_order[BASE_EVALUATION_ORDER_PASS_STATE]": 0.0018767229998957191, - "tests/aws/services/stepfunctions/v2/assign/test_assign_reference_variables.py::TestAssignReferenceVariables::test_undefined_reference[BASE_UNDEFINED_ARGUMENTS]": 0.0018649839998943207, - "tests/aws/services/stepfunctions/v2/assign/test_assign_reference_variables.py::TestAssignReferenceVariables::test_undefined_reference[BASE_UNDEFINED_ARGUMENTS_FIELD]": 0.0016956009994828491, - "tests/aws/services/stepfunctions/v2/assign/test_assign_reference_variables.py::TestAssignReferenceVariables::test_undefined_reference[BASE_UNDEFINED_ASSIGN]": 1.2027564380000513, - "tests/aws/services/stepfunctions/v2/assign/test_assign_reference_variables.py::TestAssignReferenceVariables::test_undefined_reference[BASE_UNDEFINED_OUTPUT]": 1.207406495000214, - "tests/aws/services/stepfunctions/v2/assign/test_assign_reference_variables.py::TestAssignReferenceVariables::test_undefined_reference[BASE_UNDEFINED_OUTPUT_FIELD]": 1.2151864009997553, - "tests/aws/services/stepfunctions/v2/assign/test_assign_reference_variables.py::TestAssignReferenceVariables::test_undefined_reference[BASE_UNDEFINED_OUTPUT_MULTIPLE_STATES]": 1.2513221570002315, - "tests/aws/services/stepfunctions/v2/assign/test_assign_reference_variables.py::TestAssignReferenceVariables::test_variables_in_lambda_task[BASE_ASSIGN_FROM_LAMBDA_TASK_RESULT]": 4.215223109999897, - "tests/aws/services/stepfunctions/v2/base/test_base.py::TestSnfBase::test_decl_version_1_0": 0.4582681970005069, - "tests/aws/services/stepfunctions/v2/base/test_base.py::TestSnfBase::test_event_bridge_events_base": 2.5780720019997716, - "tests/aws/services/stepfunctions/v2/base/test_base.py::TestSnfBase::test_event_bridge_events_failure": 0.0019004470000254514, - "tests/aws/services/stepfunctions/v2/base/test_base.py::TestSnfBase::test_execution_dateformat": 0.46892110900000716, - "tests/aws/services/stepfunctions/v2/base/test_base.py::TestSnfBase::test_json_path_array_access[$.items[0]]": 0.7612496419999957, - "tests/aws/services/stepfunctions/v2/base/test_base.py::TestSnfBase::test_json_path_array_access[$.items[10]]": 0.7366658389999827, - "tests/aws/services/stepfunctions/v2/base/test_base.py::TestSnfBase::test_json_path_array_wildcard_or_slice_with_no_input[$.item.items[*]]": 0.7540416409999864, - "tests/aws/services/stepfunctions/v2/base/test_base.py::TestSnfBase::test_json_path_array_wildcard_or_slice_with_no_input[$.item.items[1:5].itemValue]": 0.6772155329999805, - "tests/aws/services/stepfunctions/v2/base/test_base.py::TestSnfBase::test_json_path_array_wildcard_or_slice_with_no_input[$.item.items[1:5]]": 0.7728841050000312, - "tests/aws/services/stepfunctions/v2/base/test_base.py::TestSnfBase::test_json_path_array_wildcard_or_slice_with_no_input[$.item.items[1:]]": 0.7398954379999907, - "tests/aws/services/stepfunctions/v2/base/test_base.py::TestSnfBase::test_json_path_array_wildcard_or_slice_with_no_input[$.item.items[:1]]": 0.7132555250000223, - "tests/aws/services/stepfunctions/v2/base/test_base.py::TestSnfBase::test_json_path_array_wildcard_or_slice_with_no_input[$.items[*].itemValue]": 0.717057576000002, - "tests/aws/services/stepfunctions/v2/base/test_base.py::TestSnfBase::test_json_path_array_wildcard_or_slice_with_no_input[$.items[*]]": 0.680644559000001, - "tests/aws/services/stepfunctions/v2/base/test_base.py::TestSnfBase::test_json_path_array_wildcard_or_slice_with_no_input[$.items[1:].itemValue]": 0.6726525850000087, - "tests/aws/services/stepfunctions/v2/base/test_base.py::TestSnfBase::test_json_path_array_wildcard_or_slice_with_no_input[$.items[1:]]": 0.6688912840000114, - "tests/aws/services/stepfunctions/v2/base/test_base.py::TestSnfBase::test_json_path_array_wildcard_or_slice_with_no_input[$.items[:1].itemValue]": 0.6921230660000219, - "tests/aws/services/stepfunctions/v2/base/test_base.py::TestSnfBase::test_json_path_array_wildcard_or_slice_with_no_input[$.items[:1]]": 0.684466714999985, - "tests/aws/services/stepfunctions/v2/base/test_base.py::TestSnfBase::test_json_path_array_wildcard_or_slice_with_no_input[$[*]]": 0.7024947139999824, - "tests/aws/services/stepfunctions/v2/base/test_base.py::TestSnfBase::test_query_context_object_values": 1.8435361319998265, - "tests/aws/services/stepfunctions/v2/base/test_base.py::TestSnfBase::test_state_fail": 0.6207512959995256, - "tests/aws/services/stepfunctions/v2/base/test_base.py::TestSnfBase::test_state_fail_empty": 0.6008635729999696, - "tests/aws/services/stepfunctions/v2/base/test_base.py::TestSnfBase::test_state_fail_intrinsic": 0.7037108790004822, - "tests/aws/services/stepfunctions/v2/base/test_base.py::TestSnfBase::test_state_fail_path": 0.7216695219999565, - "tests/aws/services/stepfunctions/v2/base/test_base.py::TestSnfBase::test_state_pass_regex_json_path": 0.002679120999971474, - "tests/aws/services/stepfunctions/v2/base/test_base.py::TestSnfBase::test_state_pass_regex_json_path_base": 0.772332734999992, - "tests/aws/services/stepfunctions/v2/base/test_base.py::TestSnfBase::test_state_pass_result": 0.6621131960000639, - "tests/aws/services/stepfunctions/v2/base/test_base.py::TestSnfBase::test_state_pass_result_jsonpaths": 0.46321089299999585, - "tests/aws/services/stepfunctions/v2/base/test_base.py::TestSnfBase::test_state_pass_result_null_input_output_paths": 3.575502916000005, - "tests/aws/services/stepfunctions/v2/base/test_wait.py::TestSfnWait::test_base_wait_seconds_path[-1.5]": 0.6559803320000128, - "tests/aws/services/stepfunctions/v2/base/test_wait.py::TestSfnWait::test_base_wait_seconds_path[-1]": 0.6588003049999713, - "tests/aws/services/stepfunctions/v2/base/test_wait.py::TestSfnWait::test_base_wait_seconds_path[0]": 0.6730968650000193, - "tests/aws/services/stepfunctions/v2/base/test_wait.py::TestSfnWait::test_base_wait_seconds_path[1.5]": 0.6290465050000194, - "tests/aws/services/stepfunctions/v2/base/test_wait.py::TestSfnWait::test_base_wait_seconds_path[1]": 1.5005784930000061, - "tests/aws/services/stepfunctions/v2/base/test_wait.py::TestSfnWait::test_timestamp_too_far_in_future_boundary[24855]": 0.002992375000019365, - "tests/aws/services/stepfunctions/v2/base/test_wait.py::TestSfnWait::test_timestamp_too_far_in_future_boundary[24856]": 0.002536086999981535, - "tests/aws/services/stepfunctions/v2/base/test_wait.py::TestSfnWait::test_wait_timestamppath[.000000Z]": 0.6328637409999942, - "tests/aws/services/stepfunctions/v2/base/test_wait.py::TestSfnWait::test_wait_timestamppath[.000000]": 0.6748895540000035, - "tests/aws/services/stepfunctions/v2/base/test_wait.py::TestSfnWait::test_wait_timestamppath[.00Z]": 0.652859651, - "tests/aws/services/stepfunctions/v2/base/test_wait.py::TestSfnWait::test_wait_timestamppath[Z]": 0.6534698549999973, - "tests/aws/services/stepfunctions/v2/base/test_wait.py::TestSfnWait::test_wait_timestamppath[]": 0.6247316060000117, - "tests/aws/services/stepfunctions/v2/callback/test_callback.py::TestCallback::test_multiple_executions_and_heartbeat_notifications": 0.0048321090000058575, - "tests/aws/services/stepfunctions/v2/callback/test_callback.py::TestCallback::test_multiple_heartbeat_notifications": 0.004340895999973782, - "tests/aws/services/stepfunctions/v2/callback/test_callback.py::TestCallback::test_sns_publish_wait_for_task_token": 1.2501086759999964, - "tests/aws/services/stepfunctions/v2/callback/test_callback.py::TestCallback::test_sqs_failure_in_wait_for_task_tok_no_error_field[SQS_PARALLEL_WAIT_FOR_TASK_TOKEN]": 0.007708252999975684, - "tests/aws/services/stepfunctions/v2/callback/test_callback.py::TestCallback::test_sqs_failure_in_wait_for_task_tok_no_error_field[SQS_WAIT_FOR_TASK_TOKEN_CATCH]": 1.6860366569999883, - "tests/aws/services/stepfunctions/v2/callback/test_callback.py::TestCallback::test_sqs_failure_in_wait_for_task_token": 3.012376878999987, - "tests/aws/services/stepfunctions/v2/callback/test_callback.py::TestCallback::test_sqs_wait_for_task_tok_with_heartbeat": 7.946099410000016, - "tests/aws/services/stepfunctions/v2/callback/test_callback.py::TestCallback::test_sqs_wait_for_task_token": 3.318648837000012, - "tests/aws/services/stepfunctions/v2/callback/test_callback.py::TestCallback::test_sqs_wait_for_task_token_call_chain": 4.053217168999964, - "tests/aws/services/stepfunctions/v2/callback/test_callback.py::TestCallback::test_sqs_wait_for_task_token_no_token_parameter": 5.66885970300001, - "tests/aws/services/stepfunctions/v2/callback/test_callback.py::TestCallback::test_sqs_wait_for_task_token_timeout": 6.052140242000007, - "tests/aws/services/stepfunctions/v2/callback/test_callback.py::TestCallback::test_start_execution_sync": 1.653952626000006, - "tests/aws/services/stepfunctions/v2/callback/test_callback.py::TestCallback::test_start_execution_sync2": 0.9920613630000048, - "tests/aws/services/stepfunctions/v2/callback/test_callback.py::TestCallback::test_start_execution_sync_delegate_failure": 1.0236996900000008, - "tests/aws/services/stepfunctions/v2/callback/test_callback.py::TestCallback::test_start_execution_sync_delegate_timeout": 22.042162022000014, - "tests/aws/services/stepfunctions/v2/callback/test_callback.py::TestCallback::test_sync_with_task_token": 2.6001658109999823, - "tests/aws/services/stepfunctions/v2/choice_operators/test_boolean_equals.py::TestBooleanEquals::test_boolean_equals": 13.484966773000025, - "tests/aws/services/stepfunctions/v2/choice_operators/test_boolean_equals.py::TestBooleanEquals::test_boolean_equals_path": 14.241450587000003, - "tests/aws/services/stepfunctions/v2/choice_operators/test_is_operators.py::TestIsOperators::test_is_boolean": 13.60962005700003, - "tests/aws/services/stepfunctions/v2/choice_operators/test_is_operators.py::TestIsOperators::test_is_null": 13.59974115099999, - "tests/aws/services/stepfunctions/v2/choice_operators/test_is_operators.py::TestIsOperators::test_is_numeric": 13.708412799000087, - "tests/aws/services/stepfunctions/v2/choice_operators/test_is_operators.py::TestIsOperators::test_is_present": 13.09261541899997, - "tests/aws/services/stepfunctions/v2/choice_operators/test_is_operators.py::TestIsOperators::test_is_string": 14.361840322000035, - "tests/aws/services/stepfunctions/v2/choice_operators/test_is_operators.py::TestIsOperators::test_is_timestamp": 0.003644869000027029, - "tests/aws/services/stepfunctions/v2/choice_operators/test_numeric.py::TestNumerics::test_numeric_equals": 20.03233487800003, - "tests/aws/services/stepfunctions/v2/choice_operators/test_numeric.py::TestNumerics::test_numeric_equals_path": 21.304556371000047, - "tests/aws/services/stepfunctions/v2/choice_operators/test_numeric.py::TestNumerics::test_numeric_greater_than": 2.5472927709999453, - "tests/aws/services/stepfunctions/v2/choice_operators/test_numeric.py::TestNumerics::test_numeric_greater_than_equals": 2.501973032999956, - "tests/aws/services/stepfunctions/v2/choice_operators/test_numeric.py::TestNumerics::test_numeric_greater_than_equals_path": 2.4943378739999957, - "tests/aws/services/stepfunctions/v2/choice_operators/test_numeric.py::TestNumerics::test_numeric_greater_than_path": 2.53231708200002, - "tests/aws/services/stepfunctions/v2/choice_operators/test_numeric.py::TestNumerics::test_numeric_less_than": 2.489934106000021, - "tests/aws/services/stepfunctions/v2/choice_operators/test_numeric.py::TestNumerics::test_numeric_less_than_equals": 2.2901119069999822, - "tests/aws/services/stepfunctions/v2/choice_operators/test_numeric.py::TestNumerics::test_numeric_less_than_equals_path": 2.4709666420000076, - "tests/aws/services/stepfunctions/v2/choice_operators/test_numeric.py::TestNumerics::test_numeric_less_than_path": 3.200514356000042, - "tests/aws/services/stepfunctions/v2/choice_operators/test_string_operators.py::TestStrings::test_string_equals": 6.012022827999999, - "tests/aws/services/stepfunctions/v2/choice_operators/test_string_operators.py::TestStrings::test_string_equals_path": 1.3905608239999765, - "tests/aws/services/stepfunctions/v2/choice_operators/test_string_operators.py::TestStrings::test_string_greater_than": 1.7788098349999473, - "tests/aws/services/stepfunctions/v2/choice_operators/test_string_operators.py::TestStrings::test_string_greater_than_equals": 1.3853067110000552, - "tests/aws/services/stepfunctions/v2/choice_operators/test_string_operators.py::TestStrings::test_string_greater_than_equals_path": 1.3789173819999974, - "tests/aws/services/stepfunctions/v2/choice_operators/test_string_operators.py::TestStrings::test_string_greater_than_path": 1.7936637039999823, - "tests/aws/services/stepfunctions/v2/choice_operators/test_string_operators.py::TestStrings::test_string_less_than": 1.33373969999991, - "tests/aws/services/stepfunctions/v2/choice_operators/test_string_operators.py::TestStrings::test_string_less_than_equals": 1.3777810210000325, - "tests/aws/services/stepfunctions/v2/choice_operators/test_string_operators.py::TestStrings::test_string_less_than_equals_path": 1.368481491999944, - "tests/aws/services/stepfunctions/v2/choice_operators/test_string_operators.py::TestStrings::test_string_less_than_path": 1.3576828000000205, - "tests/aws/services/stepfunctions/v2/choice_operators/test_timestamp_operators.py::TestTimestamps::test_timestamp_equals": 7.305440130000022, - "tests/aws/services/stepfunctions/v2/choice_operators/test_timestamp_operators.py::TestTimestamps::test_timestamp_equals_path": 1.4106758899999932, - "tests/aws/services/stepfunctions/v2/choice_operators/test_timestamp_operators.py::TestTimestamps::test_timestamp_greater_than": 1.3817891250000116, - "tests/aws/services/stepfunctions/v2/choice_operators/test_timestamp_operators.py::TestTimestamps::test_timestamp_greater_than_equals": 1.3494255580000072, - "tests/aws/services/stepfunctions/v2/choice_operators/test_timestamp_operators.py::TestTimestamps::test_timestamp_greater_than_equals_path": 0.649524308000025, - "tests/aws/services/stepfunctions/v2/choice_operators/test_timestamp_operators.py::TestTimestamps::test_timestamp_greater_than_path": 0.6115854629999262, - "tests/aws/services/stepfunctions/v2/choice_operators/test_timestamp_operators.py::TestTimestamps::test_timestamp_less_than": 1.4140616889999933, - "tests/aws/services/stepfunctions/v2/choice_operators/test_timestamp_operators.py::TestTimestamps::test_timestamp_less_than_equals": 1.376828025000009, - "tests/aws/services/stepfunctions/v2/choice_operators/test_timestamp_operators.py::TestTimestamps::test_timestamp_less_than_equals_path": 0.6571255389999351, - "tests/aws/services/stepfunctions/v2/choice_operators/test_timestamp_operators.py::TestTimestamps::test_timestamp_less_than_path": 0.617958883999961, - "tests/aws/services/stepfunctions/v2/comments/test_comments.py::TestComments::test_comment_in_parameters": 0.650220121000018, - "tests/aws/services/stepfunctions/v2/comments/test_comments.py::TestComments::test_comments_as_per_docs": 7.520571644000086, - "tests/aws/services/stepfunctions/v2/context_object/test_context_object.py::TestSnfBase::test_error_cause_path": 1.6216759950000323, - "tests/aws/services/stepfunctions/v2/context_object/test_context_object.py::TestSnfBase::test_input_path[$$.Execution.Input]": 0.9097204430000261, - "tests/aws/services/stepfunctions/v2/context_object/test_context_object.py::TestSnfBase::test_input_path[$$]": 0.7065717840000048, - "tests/aws/services/stepfunctions/v2/context_object/test_context_object.py::TestSnfBase::test_output_path[$$.Execution.Input]": 0.9203614239999638, - "tests/aws/services/stepfunctions/v2/context_object/test_context_object.py::TestSnfBase::test_output_path[$$]": 0.7044107099999337, - "tests/aws/services/stepfunctions/v2/context_object/test_context_object.py::TestSnfBase::test_result_selector": 2.365984641999944, - "tests/aws/services/stepfunctions/v2/context_object/test_context_object.py::TestSnfBase::test_variable": 0.9806597049999937, - "tests/aws/services/stepfunctions/v2/credentials/test_credentials_base.py::TestCredentialsBase::test_cross_account_lambda_task": 2.408269206, - "tests/aws/services/stepfunctions/v2/credentials/test_credentials_base.py::TestCredentialsBase::test_cross_account_service_lambda_invoke": 2.4498044079999204, - "tests/aws/services/stepfunctions/v2/credentials/test_credentials_base.py::TestCredentialsBase::test_cross_account_service_lambda_invoke_retry": 5.883398347999957, - "tests/aws/services/stepfunctions/v2/credentials/test_credentials_base.py::TestCredentialsBase::test_cross_account_states_start_sync_execution[SFN_START_EXECUTION_SYNC_ROLE_ARN_INTRINSIC]": 1.571537816999978, - "tests/aws/services/stepfunctions/v2/credentials/test_credentials_base.py::TestCredentialsBase::test_cross_account_states_start_sync_execution[SFN_START_EXECUTION_SYNC_ROLE_ARN_JSONATA]": 4.040797937000036, - "tests/aws/services/stepfunctions/v2/credentials/test_credentials_base.py::TestCredentialsBase::test_cross_account_states_start_sync_execution[SFN_START_EXECUTION_SYNC_ROLE_ARN_PATH]": 1.5015257750000046, - "tests/aws/services/stepfunctions/v2/credentials/test_credentials_base.py::TestCredentialsBase::test_cross_account_states_start_sync_execution[SFN_START_EXECUTION_SYNC_ROLE_ARN_PATH_CONTEXT]": 1.5761168070000622, - "tests/aws/services/stepfunctions/v2/credentials/test_credentials_base.py::TestCredentialsBase::test_cross_account_states_start_sync_execution[SFN_START_EXECUTION_SYNC_ROLE_ARN_VARIABLE]": 1.541909051999994, - "tests/aws/services/stepfunctions/v2/credentials/test_credentials_base.py::TestCredentialsBase::test_invalid_credentials_field[EMPTY_CREDENTIALS]": 0.8121427749999839, - "tests/aws/services/stepfunctions/v2/credentials/test_credentials_base.py::TestCredentialsBase::test_invalid_credentials_field[INVALID_CREDENTIALS_FIELD]": 0.8231579220000071, - "tests/aws/services/stepfunctions/v2/error_handling/test_aws_sdk.py::TestAwsSdk::test_dynamodb_invalid_param": 0.002008613000043624, - "tests/aws/services/stepfunctions/v2/error_handling/test_aws_sdk.py::TestAwsSdk::test_dynamodb_put_item_no_such_table": 3.7347847110000316, - "tests/aws/services/stepfunctions/v2/error_handling/test_aws_sdk.py::TestAwsSdk::test_invalid_secret_name": 0.7691631119999442, - "tests/aws/services/stepfunctions/v2/error_handling/test_aws_sdk.py::TestAwsSdk::test_no_such_bucket": 0.7202973029999953, - "tests/aws/services/stepfunctions/v2/error_handling/test_aws_sdk.py::TestAwsSdk::test_s3_no_such_key": 0.7576843970000482, - "tests/aws/services/stepfunctions/v2/error_handling/test_states_errors.py::TestStatesErrors::test_service_task_lambada_catch_state_all_data_limit_exceeded_on_large_utf8_response": 2.3955673639999873, - "tests/aws/services/stepfunctions/v2/error_handling/test_states_errors.py::TestStatesErrors::test_service_task_lambada_data_limit_exceeded_on_large_utf8_response": 2.36321328300005, - "tests/aws/services/stepfunctions/v2/error_handling/test_states_errors.py::TestStatesErrors::test_start_large_input": 4.983195223000109, - "tests/aws/services/stepfunctions/v2/error_handling/test_states_errors.py::TestStatesErrors::test_task_lambda_catch_state_all_data_limit_exceeded_on_large_utf8_response": 2.292653930999961, - "tests/aws/services/stepfunctions/v2/error_handling/test_states_errors.py::TestStatesErrors::test_task_lambda_data_limit_exceeded_on_large_utf8_response": 2.137981687999968, - "tests/aws/services/stepfunctions/v2/error_handling/test_task_lambda.py::TestTaskLambda::test_no_such_function": 2.338225831999978, - "tests/aws/services/stepfunctions/v2/error_handling/test_task_lambda.py::TestTaskLambda::test_no_such_function_catch": 2.69013791499998, - "tests/aws/services/stepfunctions/v2/error_handling/test_task_lambda.py::TestTaskLambda::test_raise_custom_exception": 2.208499805000031, - "tests/aws/services/stepfunctions/v2/error_handling/test_task_lambda.py::TestTaskLambda::test_raise_exception": 2.3602144889999295, - "tests/aws/services/stepfunctions/v2/error_handling/test_task_lambda.py::TestTaskLambda::test_raise_exception_catch": 2.424196576999975, - "tests/aws/services/stepfunctions/v2/error_handling/test_task_service_dynamodb.py::TestTaskServiceDynamoDB::test_invalid_param": 0.7942669940000542, - "tests/aws/services/stepfunctions/v2/error_handling/test_task_service_dynamodb.py::TestTaskServiceDynamoDB::test_put_item_invalid_table_name": 0.8318051530000048, - "tests/aws/services/stepfunctions/v2/error_handling/test_task_service_dynamodb.py::TestTaskServiceDynamoDB::test_put_item_no_such_table": 0.7741142419999392, - "tests/aws/services/stepfunctions/v2/error_handling/test_task_service_lambda.py::TestTaskServiceLambda::test_invoke_timeout": 6.745099793999941, - "tests/aws/services/stepfunctions/v2/error_handling/test_task_service_lambda.py::TestTaskServiceLambda::test_no_such_function": 1.852827927000078, - "tests/aws/services/stepfunctions/v2/error_handling/test_task_service_lambda.py::TestTaskServiceLambda::test_no_such_function_catch": 2.046467093999979, - "tests/aws/services/stepfunctions/v2/error_handling/test_task_service_lambda.py::TestTaskServiceLambda::test_raise_custom_exception": 2.334131422999974, - "tests/aws/services/stepfunctions/v2/error_handling/test_task_service_lambda.py::TestTaskServiceLambda::test_raise_exception": 2.2807600890000117, - "tests/aws/services/stepfunctions/v2/error_handling/test_task_service_lambda.py::TestTaskServiceLambda::test_raise_exception_catch": 2.4412453349999623, - "tests/aws/services/stepfunctions/v2/error_handling/test_task_service_lambda.py::TestTaskServiceLambda::test_raise_exception_catch_output_path[$.Payload]": 2.3615314250000097, - "tests/aws/services/stepfunctions/v2/error_handling/test_task_service_lambda.py::TestTaskServiceLambda::test_raise_exception_catch_output_path[$.no.such.path]": 2.3279361170000357, - "tests/aws/services/stepfunctions/v2/error_handling/test_task_service_lambda.py::TestTaskServiceLambda::test_raise_exception_catch_output_path[None]": 2.3775994759999435, - "tests/aws/services/stepfunctions/v2/error_handling/test_task_service_sfn.py::TestTaskServiceSfn::test_start_execution_no_such_arn": 1.0553041589998884, - "tests/aws/services/stepfunctions/v2/error_handling/test_task_service_sqs.py::TestTaskServiceSqs::test_send_message_empty_body": 0.002722884999911912, - "tests/aws/services/stepfunctions/v2/error_handling/test_task_service_sqs.py::TestTaskServiceSqs::test_send_message_no_such_queue": 1.095249185000057, - "tests/aws/services/stepfunctions/v2/error_handling/test_task_service_sqs.py::TestTaskServiceSqs::test_send_message_no_such_queue_no_catch": 1.2005389619998823, - "tests/aws/services/stepfunctions/v2/error_handling/test_task_service_sqs.py::TestTaskServiceSqs::test_sqs_failure_in_wait_for_task_tok": 2.8374841229999674, - "tests/aws/services/stepfunctions/v2/evaluate_jsonata/test_base_evaluate_expressions.py::TestBaseEvaluateJsonata::test_base_jsonata_regular_expressions[BASE]": 1.0764377629999444, - "tests/aws/services/stepfunctions/v2/evaluate_jsonata/test_base_evaluate_expressions.py::TestBaseEvaluateJsonata::test_base_jsonata_regular_expressions[BASE_FALSE]": 1.8875332229999913, - "tests/aws/services/stepfunctions/v2/evaluate_jsonata/test_base_evaluate_expressions.py::TestBaseEvaluateJsonata::test_base_jsonata_regular_expressions[BASE_SINGLE_QUOTE]": 1.0282470150001473, - "tests/aws/services/stepfunctions/v2/evaluate_jsonata/test_base_evaluate_expressions.py::TestBaseEvaluateJsonata::test_base_jsonata_regular_expressions[BASE_SINGLE_QUOTE_FALSE]": 1.0505732990001206, - "tests/aws/services/stepfunctions/v2/evaluate_jsonata/test_base_evaluate_expressions.py::TestBaseEvaluateJsonata::test_base_map[ITEMS]": 1.137420352999925, - "tests/aws/services/stepfunctions/v2/evaluate_jsonata/test_base_evaluate_expressions.py::TestBaseEvaluateJsonata::test_base_map[ITEMS_DOUBLE_QUOTES]": 1.1271247090000998, - "tests/aws/services/stepfunctions/v2/evaluate_jsonata/test_base_evaluate_expressions.py::TestBaseEvaluateJsonata::test_base_map[MAX_CONCURRENCY]": 1.108239173000129, - "tests/aws/services/stepfunctions/v2/evaluate_jsonata/test_base_evaluate_expressions.py::TestBaseEvaluateJsonata::test_base_map[TOLERATED_FAILURE_COUNT]": 1.3865658250000479, - "tests/aws/services/stepfunctions/v2/evaluate_jsonata/test_base_evaluate_expressions.py::TestBaseEvaluateJsonata::test_base_map[TOLERATED_FAILURE_PERCENTAGE]": 1.0997710979999056, - "tests/aws/services/stepfunctions/v2/evaluate_jsonata/test_base_evaluate_expressions.py::TestBaseEvaluateJsonata::test_base_map_from_input[ITEMS]": 2.317380731000071, - "tests/aws/services/stepfunctions/v2/evaluate_jsonata/test_base_evaluate_expressions.py::TestBaseEvaluateJsonata::test_base_map_from_input[MAX_CONCURRENCY]": 2.2799345269999094, - "tests/aws/services/stepfunctions/v2/evaluate_jsonata/test_base_evaluate_expressions.py::TestBaseEvaluateJsonata::test_base_map_from_input[TOLERATED_FAILURE_COUNT]": 2.2233104619998585, - "tests/aws/services/stepfunctions/v2/evaluate_jsonata/test_base_evaluate_expressions.py::TestBaseEvaluateJsonata::test_base_map_from_input[TOLERATED_FAILURE_PERCENTAGE]": 2.183234010999854, - "tests/aws/services/stepfunctions/v2/evaluate_jsonata/test_base_evaluate_expressions.py::TestBaseEvaluateJsonata::test_base_task[HEARTBEAT_SECONDS]": 2.5311129329999176, - "tests/aws/services/stepfunctions/v2/evaluate_jsonata/test_base_evaluate_expressions.py::TestBaseEvaluateJsonata::test_base_task[TIMEOUT_SECONDS]": 0.002977442000087649, - "tests/aws/services/stepfunctions/v2/evaluate_jsonata/test_base_evaluate_expressions.py::TestBaseEvaluateJsonata::test_base_task_from_input[HEARTBEAT_SECONDS]": 2.468189680999899, - "tests/aws/services/stepfunctions/v2/evaluate_jsonata/test_base_evaluate_expressions.py::TestBaseEvaluateJsonata::test_base_task_from_input[TIMEOUT_SECONDS]": 0.002011588999948799, - "tests/aws/services/stepfunctions/v2/express/test_express_async.py::TestExpressAsync::test_base[BASE_PASS_RESULT]": 1.3234646180001164, - "tests/aws/services/stepfunctions/v2/express/test_express_async.py::TestExpressAsync::test_base[BASE_RAISE_FAILURE]": 1.2710044039999957, - "tests/aws/services/stepfunctions/v2/express/test_express_async.py::TestExpressAsync::test_catch": 3.0478755639999235, - "tests/aws/services/stepfunctions/v2/express/test_express_async.py::TestExpressAsync::test_query_runtime_memory": 2.2810306940000373, - "tests/aws/services/stepfunctions/v2/express/test_express_async.py::TestExpressAsync::test_retry": 10.198184513999877, - "tests/aws/services/stepfunctions/v2/express/test_express_sync.py::TestExpressSync::test_base[BASE_PASS_RESULT]": 0.5675902429999269, - "tests/aws/services/stepfunctions/v2/express/test_express_sync.py::TestExpressSync::test_base[BASE_RAISE_FAILURE]": 0.5390118299999358, - "tests/aws/services/stepfunctions/v2/express/test_express_sync.py::TestExpressSync::test_catch": 2.2561434699999836, - "tests/aws/services/stepfunctions/v2/express/test_express_sync.py::TestExpressSync::test_query_runtime_memory": 1.3748141940001233, - "tests/aws/services/stepfunctions/v2/express/test_express_sync.py::TestExpressSync::test_retry": 10.4532806200001, - "tests/aws/services/stepfunctions/v2/intrinsic_functions/test_array.py::TestArray::test_array_0": 0.4719735270000456, - "tests/aws/services/stepfunctions/v2/intrinsic_functions/test_array.py::TestArray::test_array_2": 2.974943678000045, - "tests/aws/services/stepfunctions/v2/intrinsic_functions/test_array.py::TestArray::test_array_contains": 3.327804766999975, - "tests/aws/services/stepfunctions/v2/intrinsic_functions/test_array.py::TestArray::test_array_get_item": 0.7178049189999456, - "tests/aws/services/stepfunctions/v2/intrinsic_functions/test_array.py::TestArray::test_array_length": 0.7146909389999792, - "tests/aws/services/stepfunctions/v2/intrinsic_functions/test_array.py::TestArray::test_array_partition": 8.358665209999913, - "tests/aws/services/stepfunctions/v2/intrinsic_functions/test_array.py::TestArray::test_array_range": 1.6222079350000058, - "tests/aws/services/stepfunctions/v2/intrinsic_functions/test_array.py::TestArray::test_array_unique": 0.6751301960000546, - "tests/aws/services/stepfunctions/v2/intrinsic_functions/test_array_jsonata.py::TestArrayJSONata::test_array_partition": 5.590240679999965, - "tests/aws/services/stepfunctions/v2/intrinsic_functions/test_array_jsonata.py::TestArrayJSONata::test_array_range": 2.317583291000119, - "tests/aws/services/stepfunctions/v2/intrinsic_functions/test_encode_decode.py::TestEncodeDecode::test_base_64_decode": 0.9948151869998583, - "tests/aws/services/stepfunctions/v2/intrinsic_functions/test_encode_decode.py::TestEncodeDecode::test_base_64_encode": 0.9975545619998911, - "tests/aws/services/stepfunctions/v2/intrinsic_functions/test_generic.py::TestGeneric::test_context_json_path": 0.690121481999995, - "tests/aws/services/stepfunctions/v2/intrinsic_functions/test_generic.py::TestGeneric::test_escape_sequence": 0.4476204410000264, - "tests/aws/services/stepfunctions/v2/intrinsic_functions/test_generic.py::TestGeneric::test_format_1": 2.5653156049999097, - "tests/aws/services/stepfunctions/v2/intrinsic_functions/test_generic.py::TestGeneric::test_format_2": 2.8304680759999883, - "tests/aws/services/stepfunctions/v2/intrinsic_functions/test_generic.py::TestGeneric::test_nested_calls_1": 0.6693506780000007, - "tests/aws/services/stepfunctions/v2/intrinsic_functions/test_generic.py::TestGeneric::test_nested_calls_2": 0.6929975919999833, - "tests/aws/services/stepfunctions/v2/intrinsic_functions/test_hash_calculations.py::TestHashCalculations::test_hash": 1.950865340000064, - "tests/aws/services/stepfunctions/v2/intrinsic_functions/test_json_manipulation.py::TestJsonManipulation::test_json_merge": 0.7164912190000905, - "tests/aws/services/stepfunctions/v2/intrinsic_functions/test_json_manipulation.py::TestJsonManipulation::test_json_merge_escaped_argument": 0.7721051909999233, - "tests/aws/services/stepfunctions/v2/intrinsic_functions/test_json_manipulation.py::TestJsonManipulation::test_json_to_string": 2.8749569840000504, - "tests/aws/services/stepfunctions/v2/intrinsic_functions/test_json_manipulation.py::TestJsonManipulation::test_string_to_json": 3.5033315319998337, - "tests/aws/services/stepfunctions/v2/intrinsic_functions/test_json_manipulation_jsonata.py::TestJsonManipulationJSONata::test_parse": 2.3297101350000275, - "tests/aws/services/stepfunctions/v2/intrinsic_functions/test_math_operations.py::TestMathOperations::test_math_add": 6.985881412000026, - "tests/aws/services/stepfunctions/v2/intrinsic_functions/test_math_operations.py::TestMathOperations::test_math_random": 1.3638761509998858, - "tests/aws/services/stepfunctions/v2/intrinsic_functions/test_math_operations.py::TestMathOperations::test_math_random_seeded": 0.7513313229999312, - "tests/aws/services/stepfunctions/v2/intrinsic_functions/test_math_operations_jsonata.py::TestMathOperationsJSONata::test_math_random_seeded": 0.0022781189999250273, - "tests/aws/services/stepfunctions/v2/intrinsic_functions/test_string_operations.py::TestStringOperations::test_string_split": 2.567135013999973, - "tests/aws/services/stepfunctions/v2/intrinsic_functions/test_string_operations.py::TestStringOperations::test_string_split_context_object": 0.6801806150000402, - "tests/aws/services/stepfunctions/v2/intrinsic_functions/test_unique_id_generation.py::TestUniqueIdGeneration::test_uuid": 0.4763178340001559, - "tests/aws/services/stepfunctions/v2/logs/test_logs.py::TestLogs::test_base[pass_result.json5_ALL_False]": 1.0064512580000837, - "tests/aws/services/stepfunctions/v2/logs/test_logs.py::TestLogs::test_base[pass_result.json5_ALL_True]": 1.0109792099999595, - "tests/aws/services/stepfunctions/v2/logs/test_logs.py::TestLogs::test_base[raise_failure.json5_ALL_False]": 1.931796597000016, - "tests/aws/services/stepfunctions/v2/logs/test_logs.py::TestLogs::test_base[raise_failure.json5_ALL_True]": 0.997943882000186, - "tests/aws/services/stepfunctions/v2/logs/test_logs.py::TestLogs::test_base[wait_seconds_path.json5_ALL_False]": 0.9973998729999494, - "tests/aws/services/stepfunctions/v2/logs/test_logs.py::TestLogs::test_base[wait_seconds_path.json5_ALL_True]": 0.999766808000004, - "tests/aws/services/stepfunctions/v2/logs/test_logs.py::TestLogs::test_deleted_log_group": 1.0149676370000407, - "tests/aws/services/stepfunctions/v2/logs/test_logs.py::TestLogs::test_log_group_with_multiple_runs": 2.5932846470000186, - "tests/aws/services/stepfunctions/v2/logs/test_logs.py::TestLogs::test_partial_log_levels[pass_result.json5_ERROR_False]": 0.7334108710000464, - "tests/aws/services/stepfunctions/v2/logs/test_logs.py::TestLogs::test_partial_log_levels[pass_result.json5_ERROR_True]": 0.7211367460000702, - "tests/aws/services/stepfunctions/v2/logs/test_logs.py::TestLogs::test_partial_log_levels[pass_result.json5_FATAL_False]": 0.7128884319999997, - "tests/aws/services/stepfunctions/v2/logs/test_logs.py::TestLogs::test_partial_log_levels[pass_result.json5_FATAL_True]": 0.7226381290001882, - "tests/aws/services/stepfunctions/v2/logs/test_logs.py::TestLogs::test_partial_log_levels[pass_result.json5_OFF_False]": 0.9145405130000199, - "tests/aws/services/stepfunctions/v2/logs/test_logs.py::TestLogs::test_partial_log_levels[pass_result.json5_OFF_True]": 0.7196668420000378, - "tests/aws/services/stepfunctions/v2/logs/test_logs.py::TestLogs::test_partial_log_levels[raise_failure.json5_ERROR_False]": 1.0001883600000383, - "tests/aws/services/stepfunctions/v2/logs/test_logs.py::TestLogs::test_partial_log_levels[raise_failure.json5_ERROR_True]": 1.0684611070000756, - "tests/aws/services/stepfunctions/v2/logs/test_logs.py::TestLogs::test_partial_log_levels[raise_failure.json5_FATAL_False]": 0.8624058679999962, - "tests/aws/services/stepfunctions/v2/logs/test_logs.py::TestLogs::test_partial_log_levels[raise_failure.json5_FATAL_True]": 0.8046666419999156, - "tests/aws/services/stepfunctions/v2/logs/test_logs.py::TestLogs::test_partial_log_levels[raise_failure.json5_OFF_False]": 0.695719396999948, - "tests/aws/services/stepfunctions/v2/logs/test_logs.py::TestLogs::test_partial_log_levels[raise_failure.json5_OFF_True]": 0.710016729999893, - "tests/aws/services/stepfunctions/v2/logs/test_logs.py::TestLogs::test_partial_log_levels[wait_seconds_path.json5_ERROR_False]": 1.0030170480000606, - "tests/aws/services/stepfunctions/v2/logs/test_logs.py::TestLogs::test_partial_log_levels[wait_seconds_path.json5_ERROR_True]": 1.0045465079999758, - "tests/aws/services/stepfunctions/v2/logs/test_logs.py::TestLogs::test_partial_log_levels[wait_seconds_path.json5_FATAL_False]": 1.0176653520001082, - "tests/aws/services/stepfunctions/v2/logs/test_logs.py::TestLogs::test_partial_log_levels[wait_seconds_path.json5_FATAL_True]": 1.0281921910000165, - "tests/aws/services/stepfunctions/v2/logs/test_logs.py::TestLogs::test_partial_log_levels[wait_seconds_path.json5_OFF_False]": 0.9638481649999449, - "tests/aws/services/stepfunctions/v2/logs/test_logs.py::TestLogs::test_partial_log_levels[wait_seconds_path.json5_OFF_True]": 0.9393942900001093, - "tests/aws/services/stepfunctions/v2/mocking/test_aws_scenarios.py::TestBaseScenarios::test_lambda_sqs_integration_happy_path": 0.43143782399999964, - "tests/aws/services/stepfunctions/v2/mocking/test_aws_scenarios.py::TestBaseScenarios::test_lambda_sqs_integration_hybrid_path": 0.4176190799998949, - "tests/aws/services/stepfunctions/v2/mocking/test_aws_scenarios.py::TestBaseScenarios::test_lambda_sqs_integration_retry_path": 7.250187080999922, - "tests/aws/services/stepfunctions/v2/mocking/test_base_callbacks.py::TestBaseScenarios::test_sfn_start_execution_sync[SFN_SYNC2]": 1.6668908030000011, - "tests/aws/services/stepfunctions/v2/mocking/test_base_callbacks.py::TestBaseScenarios::test_sfn_start_execution_sync[SFN_SYNC]": 1.7785411730000078, - "tests/aws/services/stepfunctions/v2/mocking/test_base_callbacks.py::TestBaseScenarios::test_sqs_wait_for_task_token": 1.6420342549999987, - "tests/aws/services/stepfunctions/v2/mocking/test_base_callbacks.py::TestBaseScenarios::test_sqs_wait_for_task_token_task_failure": 1.6950897160000977, - "tests/aws/services/stepfunctions/v2/mocking/test_base_scenarios.py::TestBaseScenarios::test_dynamodb_put_get_item": 1.0408044920001203, - "tests/aws/services/stepfunctions/v2/mocking/test_base_scenarios.py::TestBaseScenarios::test_events_put_events": 0.9992221999999629, - "tests/aws/services/stepfunctions/v2/mocking/test_base_scenarios.py::TestBaseScenarios::test_lambda_invoke": 0.949037604999944, - "tests/aws/services/stepfunctions/v2/mocking/test_base_scenarios.py::TestBaseScenarios::test_lambda_invoke_retries": 3.37047364700004, - "tests/aws/services/stepfunctions/v2/mocking/test_base_scenarios.py::TestBaseScenarios::test_lambda_service_invoke": 1.0218771670000706, - "tests/aws/services/stepfunctions/v2/mocking/test_base_scenarios.py::TestBaseScenarios::test_lambda_service_invoke_sync_execution": 0.824501908000002, - "tests/aws/services/stepfunctions/v2/mocking/test_base_scenarios.py::TestBaseScenarios::test_map_state_lambda": 1.51103318700018, - "tests/aws/services/stepfunctions/v2/mocking/test_base_scenarios.py::TestBaseScenarios::test_parallel_state_lambda": 1.2504425910000236, - "tests/aws/services/stepfunctions/v2/mocking/test_base_scenarios.py::TestBaseScenarios::test_sns_publish_base": 1.0055854910000335, - "tests/aws/services/stepfunctions/v2/mocking/test_base_scenarios.py::TestBaseScenarios::test_sqs_send_message": 1.018653077999943, - "tests/aws/services/stepfunctions/v2/mocking/test_mock_config_file.py::TestMockConfigFile::test_is_mock_config_flag_detected_set": 0.004803519999995842, - "tests/aws/services/stepfunctions/v2/mocking/test_mock_config_file.py::TestMockConfigFile::test_is_mock_config_flag_detected_unset": 0.006809499999917534, - "tests/aws/services/stepfunctions/v2/outputdecl/test_output.py::TestArgumentsBase::test_base_cases[BASE_DIRECT_EXPR]": 0.9709705660000054, - "tests/aws/services/stepfunctions/v2/outputdecl/test_output.py::TestArgumentsBase::test_base_cases[BASE_EMPTY]": 0.7311016869999776, - "tests/aws/services/stepfunctions/v2/outputdecl/test_output.py::TestArgumentsBase::test_base_cases[BASE_EXPR]": 2.0711628260000907, - "tests/aws/services/stepfunctions/v2/outputdecl/test_output.py::TestArgumentsBase::test_base_cases[BASE_LITERALS]": 0.9006169479999926, - "tests/aws/services/stepfunctions/v2/outputdecl/test_output.py::TestArgumentsBase::test_base_lambda[BASE_LAMBDA]": 2.6762608550001232, - "tests/aws/services/stepfunctions/v2/outputdecl/test_output.py::TestArgumentsBase::test_base_output_any_non_dict[BOOL]": 0.6885860060000368, - "tests/aws/services/stepfunctions/v2/outputdecl/test_output.py::TestArgumentsBase::test_base_output_any_non_dict[FLOAT]": 0.6901550210000096, - "tests/aws/services/stepfunctions/v2/outputdecl/test_output.py::TestArgumentsBase::test_base_output_any_non_dict[INT]": 0.6935377169999128, - "tests/aws/services/stepfunctions/v2/outputdecl/test_output.py::TestArgumentsBase::test_base_output_any_non_dict[JSONATA_EXPR]": 0.6971945020000021, - "tests/aws/services/stepfunctions/v2/outputdecl/test_output.py::TestArgumentsBase::test_base_output_any_non_dict[LIST_EMPY]": 0.6913591420001239, - "tests/aws/services/stepfunctions/v2/outputdecl/test_output.py::TestArgumentsBase::test_base_output_any_non_dict[LIST_RICH]": 0.9166983230002188, - "tests/aws/services/stepfunctions/v2/outputdecl/test_output.py::TestArgumentsBase::test_base_output_any_non_dict[NULL]": 0.6999276409999311, - "tests/aws/services/stepfunctions/v2/outputdecl/test_output.py::TestArgumentsBase::test_base_output_any_non_dict[STR_LIT]": 0.9382916250000335, - "tests/aws/services/stepfunctions/v2/outputdecl/test_output.py::TestArgumentsBase::test_base_task_lambda[BASE_TASK_LAMBDA]": 2.364997995000067, - "tests/aws/services/stepfunctions/v2/outputdecl/test_output.py::TestArgumentsBase::test_output_in_choice[CONDITION_FALSE]": 0.6989295990000528, - "tests/aws/services/stepfunctions/v2/outputdecl/test_output.py::TestArgumentsBase::test_output_in_choice[CONDITION_TRUE]": 0.9458662750000713, - "tests/aws/services/stepfunctions/v2/query_language/test_base_query_language.py::TestBaseQueryLanguage::test_base_query_language_field[JSONATA]": 0.456503069000064, - "tests/aws/services/stepfunctions/v2/query_language/test_base_query_language.py::TestBaseQueryLanguage::test_base_query_language_field[JSON_PATH]": 0.4602720570001111, - "tests/aws/services/stepfunctions/v2/query_language/test_base_query_language.py::TestBaseQueryLanguage::test_jsonata_query_language_field_downgrade_exception": 0.0018397439999944254, - "tests/aws/services/stepfunctions/v2/query_language/test_base_query_language.py::TestBaseQueryLanguage::test_query_language_field_override[JSONATA_OVERRIDE]": 0.4644246849999263, - "tests/aws/services/stepfunctions/v2/query_language/test_base_query_language.py::TestBaseQueryLanguage::test_query_language_field_override[JSONATA_OVERRIDE_DEFAULT]": 0.4634456459999683, - "tests/aws/services/stepfunctions/v2/query_language/test_mixed_query_language.py::TestMixedQueryLanguageFlow::test_lambda_task_resource_data_flow[TASK_LAMBDA_LEGACY_RESOURCE_JSONATA_TO_JSONPATH]": 2.251297844000078, - "tests/aws/services/stepfunctions/v2/query_language/test_mixed_query_language.py::TestMixedQueryLanguageFlow::test_lambda_task_resource_data_flow[TASK_LAMBDA_LEGACY_RESOURCE_JSONPATH_TO_JSONATA]": 3.1732842559998744, - "tests/aws/services/stepfunctions/v2/query_language/test_mixed_query_language.py::TestMixedQueryLanguageFlow::test_lambda_task_resource_data_flow[TASK_LAMBDA_SDK_RESOURCE_JSONATA_TO_JSONPATH]": 2.2831871050000245, - "tests/aws/services/stepfunctions/v2/query_language/test_mixed_query_language.py::TestMixedQueryLanguageFlow::test_lambda_task_resource_data_flow[TASK_LAMBDA_SDK_RESOURCE_JSONPATH_TO_JSONATA]": 2.4778235790000736, - "tests/aws/services/stepfunctions/v2/query_language/test_mixed_query_language.py::TestMixedQueryLanguageFlow::test_output_to_state[JSONATA_OUTPUT_TO_JSONPATH]": 0.8438328299999966, - "tests/aws/services/stepfunctions/v2/query_language/test_mixed_query_language.py::TestMixedQueryLanguageFlow::test_output_to_state[JSONPATH_OUTPUT_TO_JSONATA]": 0.8569128880000108, - "tests/aws/services/stepfunctions/v2/query_language/test_mixed_query_language.py::TestMixedQueryLanguageFlow::test_task_dataflow_to_state": 2.33241466100003, - "tests/aws/services/stepfunctions/v2/query_language/test_mixed_query_language.py::TestMixedQueryLanguageFlow::test_variable_sampling[JSONATA_ASSIGN_JSONPATH_REF]": 0.8683233809998683, - "tests/aws/services/stepfunctions/v2/query_language/test_mixed_query_language.py::TestMixedQueryLanguageFlow::test_variable_sampling[JSONPATH_ASSIGN_JSONATA_REF]": 0.8554616469999701, - "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_catch_empty": 2.085155384000018, - "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_catch_states_runtime": 2.4115200500000356, - "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_choice_aws_docs_scenario[CHOICE_STATE_AWS_SCENARIO]": 0.7827204520001487, - "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_choice_aws_docs_scenario[CHOICE_STATE_AWS_SCENARIO_JSONATA]": 0.729039389000036, - "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_choice_condition_constant_jsonata": 0.6871617199999491, - "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_choice_singleton_composite[CHOICE_STATE_SINGLETON_COMPOSITE]": 0.7328589759999886, - "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_choice_singleton_composite[CHOICE_STATE_SINGLETON_COMPOSITE_JSONATA]": 0.7056804160001775, - "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_choice_singleton_composite[CHOICE_STATE_SINGLETON_COMPOSITE_LITERAL_JSONATA]": 0.535036343999991, - "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_choice_unsorted_parameters_negative[CHOICE_STATE_UNSORTED_CHOICE_PARAMETERS]": 0.7216938860000255, - "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_choice_unsorted_parameters_negative[CHOICE_STATE_UNSORTED_CHOICE_PARAMETERS_JSONATA]": 0.6889233440000453, - "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_choice_unsorted_parameters_positive[CHOICE_STATE_UNSORTED_CHOICE_PARAMETERS]": 0.9377796749998879, - "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_choice_unsorted_parameters_positive[CHOICE_STATE_UNSORTED_CHOICE_PARAMETERS_JSONATA]": 0.8377261210000597, - "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_escape_sequence_parsing[ESCAPE_SEQUENCES_JSONATA_COMPARISON_ASSIGN]": 0.7397900719998916, - "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_escape_sequence_parsing[ESCAPE_SEQUENCES_JSONATA_COMPARISON_OUTPUT]": 0.7380053079998561, - "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_escape_sequence_parsing[ESCAPE_SEQUENCES_JSONPATH]": 0.7777985369998532, - "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_escape_sequence_parsing[ESCAPE_SEQUENCES_STRING_LITERALS]": 0.8433357969998951, - "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_fail_cause_jsonata": 0.7281641490000084, - "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_fail_error_jsonata": 0.7261092060000465, - "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_illegal_escapes[ESCAPE_SEQUENCES_ILLEGAL_INTRINSIC_FUNCTION]": 0.001862505999952191, - "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_illegal_escapes[ESCAPE_SEQUENCES_ILLEGAL_INTRINSIC_FUNCTION_2]": 0.0016050109999241613, - "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_invalid_jsonpath[INVALID_JSONPATH_IN_ERRORPATH]": 0.72779299299998, - "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_invalid_jsonpath[INVALID_JSONPATH_IN_STRING_EXPR_CONTEXTPATH]": 0.7349078279997912, - "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_invalid_jsonpath[INVALID_JSONPATH_IN_STRING_EXPR_JSONPATH]": 0.7226904249999961, - "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_invalid_jsonpath[ST.INVALID_JSONPATH_IN_CAUSEPATH]": 0.7230260630000203, - "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_invalid_jsonpath[ST.INVALID_JSONPATH_IN_HEARTBEATSECONDSPATH]": 0.0017750120000528113, - "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_invalid_jsonpath[ST.INVALID_JSONPATH_IN_INPUTPATH]": 0.7353255519998356, - "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_invalid_jsonpath[ST.INVALID_JSONPATH_IN_OUTPUTPATH]": 0.7118375400000332, - "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_invalid_jsonpath[ST.INVALID_JSONPATH_IN_TIMEOUTSECONDSPATH]": 0.0018947960001014508, - "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_lambda_empty_retry": 2.178776689000074, - "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_lambda_invoke_with_retry_base": 9.582366787999945, - "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_lambda_invoke_with_retry_extended_input": 9.773223481999821, - "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_lambda_service_invoke_with_retry_extended_input": 10.125822578000111, - "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_map_item_batching_base_json_max_per_batch_jsonata": 0.002150519000110762, - "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_map_item_reader_base_csv_headers_decl": 0.8329759239999248, - "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_map_item_reader_base_csv_headers_first_line": 0.863840509000056, - "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_map_item_reader_base_json": 0.8558835040000758, - "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_map_item_reader_base_json_max_items": 0.8216619050000418, - "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_map_item_reader_base_json_max_items_jsonata": 0.8805157620001864, - "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_map_item_reader_base_json_with_items_path[INVALID_ITEMS_PATH]": 1.1701102430000674, - "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_map_item_reader_base_json_with_items_path[VALID_ITEMS_PATH_FROM_ITEM_READER]": 0.9536110290000579, - "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_map_item_reader_base_json_with_items_path[VALID_ITEMS_PATH_FROM_PREVIOUS]": 0.9770698419999917, - "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_map_item_reader_base_list_objects_v2": 0.8653175489999967, - "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_map_item_reader_csv_first_row_extra_fields": 0.8295850399999836, - "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_map_item_reader_csv_headers_decl_duplicate_headers": 0.7795593439999493, - "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_map_item_reader_csv_headers_decl_extra_fields": 0.8246902909999108, - "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_map_item_reader_csv_headers_first_row_typed_headers": 1.7791383530000076, - "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_map_item_reader_csv_max_items[0]": 0.8446134050000182, - "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_map_item_reader_csv_max_items[100000000]": 0.8589766650000001, - "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_map_item_reader_csv_max_items[2]": 0.7946388980000165, - "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_map_item_reader_csv_max_items_paths[-1]": 0.8240817669999387, - "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_map_item_reader_csv_max_items_paths[0]": 0.8121206490000077, - "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_map_item_reader_csv_max_items_paths[1.5]": 0.02541291199997886, - "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_map_item_reader_csv_max_items_paths[100000000]": 0.8150512359999311, - "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_map_item_reader_csv_max_items_paths[100000001]": 0.9996710460001168, - "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_map_item_reader_csv_max_items_paths[2]": 0.7712751000000253, - "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_map_item_reader_json_no_json_list_object": 0.8283716050000294, - "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_map_state": 0.8444968139999673, - "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_map_state_break_condition": 0.8902682330000289, - "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_map_state_break_condition_legacy": 0.8870563490000904, - "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_map_state_catch": 0.7796279320000394, - "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_map_state_catch_empty_fail": 0.7722267050000937, - "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_map_state_catch_legacy": 0.7906642530000454, - "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_map_state_config_distributed_item_selector": 0.8486774229999128, - "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_map_state_config_distributed_item_selector_parameters": 2.040947114000005, - "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_map_state_config_distributed_items_path_from_previous": 0.7944217140001228, - "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_map_state_config_distributed_parameters": 0.8454475570000568, - "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_map_state_config_distributed_reentrant": 1.6684453059999669, - "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_map_state_config_distributed_reentrant_lambda": 2.9226285920000237, - "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_map_state_config_inline_item_selector": 0.7965402459999495, - "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_map_state_config_inline_parameters": 0.8447900290000234, - "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_map_state_item_selector[MAP_STATE_ITEM_SELECTOR]": 1.9258302579999054, - "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_map_state_item_selector[MAP_STATE_ITEM_SELECTOR_JSONATA]": 0.7610728889999336, - "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_map_state_item_selector_parameters": 1.0971931630000427, - "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_map_state_item_selector_singleton": 1.3783061340000131, - "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_map_state_items_eval_jsonata[empty]": 0.7007744449998654, - "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_map_state_items_eval_jsonata[mixed]": 0.731389011000033, - "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_map_state_items_eval_jsonata[singleton]": 0.692354375999912, - "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_map_state_items_eval_jsonata_fail[boolean]": 0.5635425380000925, - "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_map_state_items_eval_jsonata_fail[function]": 0.001959921999969083, - "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_map_state_items_eval_jsonata_fail[null]": 0.757488440999964, - "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_map_state_items_eval_jsonata_fail[number]": 0.7685829239998156, - "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_map_state_items_eval_jsonata_fail[object]": 0.7636609790000648, - "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_map_state_items_eval_jsonata_fail[string]": 0.7922561279999627, - "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_map_state_items_eval_jsonata_variable_sampling_fail[boolean]": 0.7919999410000855, - "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_map_state_items_eval_jsonata_variable_sampling_fail[null]": 0.8067847309999934, - "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_map_state_items_eval_jsonata_variable_sampling_fail[number]": 0.8460545629999388, - "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_map_state_items_eval_jsonata_variable_sampling_fail[object]": 0.793258346000016, - "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_map_state_items_eval_jsonata_variable_sampling_fail[string]": 0.7906878889999689, - "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_map_state_items_input_array[empty]": 0.7382802619999893, - "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_map_state_items_input_array[mixed]": 0.7471226579999666, - "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_map_state_items_input_array[singleton]": 0.7253165199999785, - "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_map_state_items_input_types[boolean]": 0.9725378839999621, - "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_map_state_items_input_types[null]": 0.9697936290000371, - "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_map_state_items_input_types[number]": 0.9637028899999223, - "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_map_state_items_input_types[object]": 1.0091036750000058, - "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_map_state_items_input_types[string]": 1.9865200229999118, - "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_map_state_items_variable_sampling[boolean]": 0.7892047609999508, - "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_map_state_items_variable_sampling[null]": 0.8007275880000861, - "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_map_state_items_variable_sampling[number]": 0.7926594289999684, - "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_map_state_items_variable_sampling[object]": 0.8129251550000163, - "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_map_state_items_variable_sampling[string]": 0.7960197080000171, - "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_map_state_label": 0.7207149699999036, - "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_map_state_legacy": 0.8533941719999802, - "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_map_state_legacy_config_distributed": 0.8374351189999061, - "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_map_state_legacy_config_distributed_item_selector": 0.8285732929999767, - "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_map_state_legacy_config_distributed_parameters": 0.8666238749999593, - "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_map_state_legacy_config_inline": 0.8375670959999297, - "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_map_state_legacy_config_inline_item_selector": 0.9045657709999659, - "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_map_state_legacy_config_inline_parameters": 0.8831339999999273, - "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_map_state_legacy_reentrant": 1.7170074059999934, - "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_map_state_nested": 0.9055983299999752, - "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_map_state_nested_config_distributed": 0.8951309100000344, - "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_map_state_nested_config_distributed_no_max_max_concurrency": 11.82652010300012, - "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_map_state_no_processor_config": 0.7920000479999771, - "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_map_state_parameters_legacy": 1.9205570819999593, - "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_map_state_parameters_singleton_legacy": 1.3497504229999322, - "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_map_state_result_writer": 1.0598449290000644, - "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_map_state_retry": 3.7737085020000904, - "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_map_state_retry_legacy": 3.7239946850000933, - "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_map_state_retry_multiple_retriers": 7.745122001000141, - "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_map_state_tolerated_failure_count_path[-1]": 1.7463539440000204, - "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_map_state_tolerated_failure_count_path[0]": 0.7409196099999917, - "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_map_state_tolerated_failure_count_path[1]": 0.7506307830000196, - "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_map_state_tolerated_failure_count_path[NoNumber]": 0.7336356849999675, - "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_map_state_tolerated_failure_count_path[tolerated_failure_count_value0]": 0.7089711159999297, - "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_map_state_tolerated_failure_percentage_path[-1.1]": 0.6983877399999301, - "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_map_state_tolerated_failure_percentage_path[-1]": 0.7245411840000315, - "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_map_state_tolerated_failure_percentage_path[0]": 0.7325046479999173, - "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_map_state_tolerated_failure_percentage_path[1.1]": 0.7359668540001394, - "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_map_state_tolerated_failure_percentage_path[100.1]": 0.7423665920000531, - "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_map_state_tolerated_failure_percentage_path[100]": 0.6920672810001633, - "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_map_state_tolerated_failure_percentage_path[1]": 0.7343963239999312, - "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_map_state_tolerated_failure_percentage_path[NoNumber]": 0.7772465949999514, - "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_map_state_tolerated_failure_percentage_path[tolerated_failure_percentage_value0]": 0.710652266000011, - "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_map_state_tolerated_failure_values[count_literal]": 0.7361985430000004, - "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_map_state_tolerated_failure_values[percentage_literal]": 0.7227380450000283, - "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_max_concurrency_path[0]": 0.7353126439999187, - "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_max_concurrency_path[1]": 0.7347101620001695, - "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_max_concurrency_path[NoNumber]": 0.7038180610001064, - "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_max_concurrency_path[max_concurrency_value0]": 0.7333686929999885, - "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_max_concurrency_path_negative": 0.8123167730000205, - "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_parallel_state[PARALLEL_STATE]": 0.8260669659999849, - "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_parallel_state[PARALLEL_STATE_PARAMETERS]": 0.7713098120001405, - "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_parallel_state_catch": 0.7277399690000266, - "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_parallel_state_fail": 0.4889550270000882, - "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_parallel_state_nested": 1.027833651999913, - "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_parallel_state_order": 0.8778534119999222, - "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_parallel_state_retry": 3.6409979969999995, - "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_retry_interval_features": 7.6651363350000565, - "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_retry_interval_features_jitter_none": 4.477856412000051, - "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_retry_interval_features_max_attempts_zero": 2.443326243999877, - "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_wait_seconds_jsonata": 0.5380795259999331, - "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_wait_timestamp[NANOSECONDS]": 0.49585486299986314, - "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_wait_timestamp[SECONDS]": 0.5404079129999673, - "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_wait_timestamp_invalid[INVALID_DATE]": 0.4511147240000355, - "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_wait_timestamp_invalid[INVALID_ISO]": 0.43314240099994095, - "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_wait_timestamp_invalid[INVALID_TIME]": 1.5260780940000132, - "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_wait_timestamp_invalid[JSONATA]": 0.4652012310000373, - "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_wait_timestamp_invalid[NO_T]": 0.477208138999913, - "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_wait_timestamp_invalid[NO_Z]": 0.46036755400007223, - "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_wait_timestamp_jsonata[INVALID_DATE]": 0.0016621639999812032, - "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_wait_timestamp_jsonata[INVALID_ISO]": 0.0016141650000918162, - "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_wait_timestamp_jsonata[INVALID_TIME]": 0.0015985549999868454, - "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_wait_timestamp_jsonata[NANOSECONDS]": 0.5225769819999186, - "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_wait_timestamp_jsonata[NO_T]": 0.002111410000111391, - "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_wait_timestamp_jsonata[NO_Z]": 0.0016722229999004412, - "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_wait_timestamp_jsonata[SECONDS]": 0.7817547029999332, - "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_wait_timestamp_path[INVALID_DATE]": 0.7395124640000859, - "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_wait_timestamp_path[INVALID_ISO]": 0.7542089889998351, - "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_wait_timestamp_path[INVALID_TIME]": 0.7390341740000395, - "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_wait_timestamp_path[NANOSECONDS]": 0.7406559490001428, - "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_wait_timestamp_path[NO_T]": 0.7285236049999639, - "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_wait_timestamp_path[NO_Z]": 0.6775337689998651, - "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_wait_timestamp_path[SECONDS]": 0.7517397279999614, - "tests/aws/services/stepfunctions/v2/scenarios/test_sfn_scenarios.py::TestFundamental::test_path_based_on_data": 6.515040790999933, - "tests/aws/services/stepfunctions/v2/scenarios/test_sfn_scenarios.py::TestFundamental::test_step_functions_calling_api_gateway": 13.51390416899983, - "tests/aws/services/stepfunctions/v2/scenarios/test_sfn_scenarios.py::TestFundamental::test_wait_for_callback": 24.90752669699998, - "tests/aws/services/stepfunctions/v2/services/test_apigetway_task_service.py::TestTaskApiGateway::test_invoke_base": 3.2300784520000434, - "tests/aws/services/stepfunctions/v2/services/test_apigetway_task_service.py::TestTaskApiGateway::test_invoke_error": 4.144616982999992, - "tests/aws/services/stepfunctions/v2/services/test_apigetway_task_service.py::TestTaskApiGateway::test_invoke_with_body_post[HelloWorld]": 3.0350359119998984, - "tests/aws/services/stepfunctions/v2/services/test_apigetway_task_service.py::TestTaskApiGateway::test_invoke_with_body_post[None]": 3.15953809500013, - "tests/aws/services/stepfunctions/v2/services/test_apigetway_task_service.py::TestTaskApiGateway::test_invoke_with_body_post[]": 3.1680163870000797, - "tests/aws/services/stepfunctions/v2/services/test_apigetway_task_service.py::TestTaskApiGateway::test_invoke_with_body_post[request_body3]": 3.071213769999872, - "tests/aws/services/stepfunctions/v2/services/test_apigetway_task_service.py::TestTaskApiGateway::test_invoke_with_headers[custom_header1]": 3.2412031669999806, - "tests/aws/services/stepfunctions/v2/services/test_apigetway_task_service.py::TestTaskApiGateway::test_invoke_with_headers[custom_header2]": 3.141181649000032, - "tests/aws/services/stepfunctions/v2/services/test_apigetway_task_service.py::TestTaskApiGateway::test_invoke_with_headers[singleStringHeader]": 0.003596696999920823, - "tests/aws/services/stepfunctions/v2/services/test_apigetway_task_service.py::TestTaskApiGateway::test_invoke_with_query_parameters": 3.2622026540000206, - "tests/aws/services/stepfunctions/v2/services/test_aws_sdk_task_service.py::TestTaskServiceAwsSdk::test_dynamodb_put_delete_item": 0.9878333939999493, - "tests/aws/services/stepfunctions/v2/services/test_aws_sdk_task_service.py::TestTaskServiceAwsSdk::test_dynamodb_put_get_item": 1.224536444000023, - "tests/aws/services/stepfunctions/v2/services/test_aws_sdk_task_service.py::TestTaskServiceAwsSdk::test_dynamodb_put_update_get_item": 1.3166626920000226, - "tests/aws/services/stepfunctions/v2/services/test_aws_sdk_task_service.py::TestTaskServiceAwsSdk::test_list_secrets": 0.9407182740000053, - "tests/aws/services/stepfunctions/v2/services/test_aws_sdk_task_service.py::TestTaskServiceAwsSdk::test_s3_get_object[binary]": 1.2061503959999982, - "tests/aws/services/stepfunctions/v2/services/test_aws_sdk_task_service.py::TestTaskServiceAwsSdk::test_s3_get_object[bytearray]": 1.1741687530000036, - "tests/aws/services/stepfunctions/v2/services/test_aws_sdk_task_service.py::TestTaskServiceAwsSdk::test_s3_get_object[empty_binary]": 1.202543040999899, - "tests/aws/services/stepfunctions/v2/services/test_aws_sdk_task_service.py::TestTaskServiceAwsSdk::test_s3_get_object[empty_str]": 1.3281440880000446, - "tests/aws/services/stepfunctions/v2/services/test_aws_sdk_task_service.py::TestTaskServiceAwsSdk::test_s3_get_object[str]": 1.1582684939999126, - "tests/aws/services/stepfunctions/v2/services/test_aws_sdk_task_service.py::TestTaskServiceAwsSdk::test_s3_put_object[bool]": 1.2239369110000098, - "tests/aws/services/stepfunctions/v2/services/test_aws_sdk_task_service.py::TestTaskServiceAwsSdk::test_s3_put_object[dict]": 1.2396237320001546, - "tests/aws/services/stepfunctions/v2/services/test_aws_sdk_task_service.py::TestTaskServiceAwsSdk::test_s3_put_object[list]": 1.21901220799964, - "tests/aws/services/stepfunctions/v2/services/test_aws_sdk_task_service.py::TestTaskServiceAwsSdk::test_s3_put_object[num]": 1.2398692769997979, - "tests/aws/services/stepfunctions/v2/services/test_aws_sdk_task_service.py::TestTaskServiceAwsSdk::test_s3_put_object[str]": 1.285098894000157, - "tests/aws/services/stepfunctions/v2/services/test_aws_sdk_task_service.py::TestTaskServiceAwsSdk::test_sfn_send_task_outcome_with_no_such_token[state_machine_template0]": 0.9589244410000219, - "tests/aws/services/stepfunctions/v2/services/test_aws_sdk_task_service.py::TestTaskServiceAwsSdk::test_sfn_send_task_outcome_with_no_such_token[state_machine_template1]": 0.9459211219998451, - "tests/aws/services/stepfunctions/v2/services/test_aws_sdk_task_service.py::TestTaskServiceAwsSdk::test_sfn_start_execution": 1.0677741019999303, - "tests/aws/services/stepfunctions/v2/services/test_aws_sdk_task_service.py::TestTaskServiceAwsSdk::test_sfn_start_execution_implicit_json_serialisation": 1.064668519999941, - "tests/aws/services/stepfunctions/v2/services/test_dynamodb_task_service.py::TestTaskServiceDynamoDB::test_base_integrations[DYNAMODB_PUT_DELETE_ITEM]": 1.2643489039999167, - "tests/aws/services/stepfunctions/v2/services/test_dynamodb_task_service.py::TestTaskServiceDynamoDB::test_base_integrations[DYNAMODB_PUT_GET_ITEM]": 2.3571081239999785, - "tests/aws/services/stepfunctions/v2/services/test_dynamodb_task_service.py::TestTaskServiceDynamoDB::test_base_integrations[DYNAMODB_PUT_QUERY]": 1.2752469179999935, - "tests/aws/services/stepfunctions/v2/services/test_dynamodb_task_service.py::TestTaskServiceDynamoDB::test_base_integrations[DYNAMODB_PUT_UPDATE_GET_ITEM]": 1.574297729999671, - "tests/aws/services/stepfunctions/v2/services/test_dynamodb_task_service.py::TestTaskServiceDynamoDB::test_invalid_integration": 0.6107315669999025, - "tests/aws/services/stepfunctions/v2/services/test_ecs_task_service.py::TestTaskServiceECS::test_run_task": 0.0019121049999739625, - "tests/aws/services/stepfunctions/v2/services/test_ecs_task_service.py::TestTaskServiceECS::test_run_task_raise_failure": 0.0017512040001292917, - "tests/aws/services/stepfunctions/v2/services/test_ecs_task_service.py::TestTaskServiceECS::test_run_task_sync": 0.0017839360000380111, - "tests/aws/services/stepfunctions/v2/services/test_ecs_task_service.py::TestTaskServiceECS::test_run_task_sync_raise_failure": 0.001714064000225335, - "tests/aws/services/stepfunctions/v2/services/test_events_task_service.py::TestTaskServiceEvents::test_put_events_base": 2.074626114000239, - "tests/aws/services/stepfunctions/v2/services/test_events_task_service.py::TestTaskServiceEvents::test_put_events_malformed_detail": 0.9173915610001586, - "tests/aws/services/stepfunctions/v2/services/test_events_task_service.py::TestTaskServiceEvents::test_put_events_mixed_malformed_detail": 0.9683261530001346, - "tests/aws/services/stepfunctions/v2/services/test_events_task_service.py::TestTaskServiceEvents::test_put_events_no_source": 31.847579116999896, - "tests/aws/services/stepfunctions/v2/services/test_lambda_task.py::TestTaskLambda::test_invoke_bytes_payload": 2.098497137000095, - "tests/aws/services/stepfunctions/v2/services/test_lambda_task.py::TestTaskLambda::test_invoke_json_values[0.0]": 2.0871536050001396, - "tests/aws/services/stepfunctions/v2/services/test_lambda_task.py::TestTaskLambda::test_invoke_json_values[0_0]": 2.0397723590001533, - "tests/aws/services/stepfunctions/v2/services/test_lambda_task.py::TestTaskLambda::test_invoke_json_values[0_1]": 2.112506535999728, - "tests/aws/services/stepfunctions/v2/services/test_lambda_task.py::TestTaskLambda::test_invoke_json_values[HelloWorld]": 2.0669484160000593, - "tests/aws/services/stepfunctions/v2/services/test_lambda_task.py::TestTaskLambda::test_invoke_json_values[True]": 2.042214845999979, - "tests/aws/services/stepfunctions/v2/services/test_lambda_task.py::TestTaskLambda::test_invoke_json_values[json_value5]": 2.07549958699974, - "tests/aws/services/stepfunctions/v2/services/test_lambda_task.py::TestTaskLambda::test_invoke_json_values[json_value6]": 2.0707641640001384, - "tests/aws/services/stepfunctions/v2/services/test_lambda_task.py::TestTaskLambda::test_invoke_pipe": 3.7057476210000004, - "tests/aws/services/stepfunctions/v2/services/test_lambda_task.py::TestTaskLambda::test_invoke_string_payload": 2.071693748999678, - "tests/aws/services/stepfunctions/v2/services/test_lambda_task.py::TestTaskLambda::test_lambda_task_filter_parameters_input": 2.365063409000186, - "tests/aws/services/stepfunctions/v2/services/test_lambda_task_service.py::TestTaskServiceLambda::test_invoke": 2.50888240900008, - "tests/aws/services/stepfunctions/v2/services/test_lambda_task_service.py::TestTaskServiceLambda::test_invoke_bytes_payload": 2.553564919000337, - "tests/aws/services/stepfunctions/v2/services/test_lambda_task_service.py::TestTaskServiceLambda::test_invoke_json_values[0.0]": 3.8049633420000646, - "tests/aws/services/stepfunctions/v2/services/test_lambda_task_service.py::TestTaskServiceLambda::test_invoke_json_values[0_0]": 2.516325176999999, - "tests/aws/services/stepfunctions/v2/services/test_lambda_task_service.py::TestTaskServiceLambda::test_invoke_json_values[0_1]": 2.570751803000121, - "tests/aws/services/stepfunctions/v2/services/test_lambda_task_service.py::TestTaskServiceLambda::test_invoke_json_values[HelloWorld]": 2.5478850209999564, - "tests/aws/services/stepfunctions/v2/services/test_lambda_task_service.py::TestTaskServiceLambda::test_invoke_json_values[True]": 2.5680829189996075, - "tests/aws/services/stepfunctions/v2/services/test_lambda_task_service.py::TestTaskServiceLambda::test_invoke_json_values[json_value5]": 2.568544728000006, - "tests/aws/services/stepfunctions/v2/services/test_lambda_task_service.py::TestTaskServiceLambda::test_invoke_json_values[json_value6]": 2.579568038999696, - "tests/aws/services/stepfunctions/v2/services/test_lambda_task_service.py::TestTaskServiceLambda::test_invoke_unsupported_param": 2.5853561700002956, - "tests/aws/services/stepfunctions/v2/services/test_lambda_task_service.py::TestTaskServiceLambda::test_list_functions": 0.002785517000120308, - "tests/aws/services/stepfunctions/v2/services/test_sfn_task_service.py::TestTaskServiceSfn::test_start_execution": 1.0399065839997093, - "tests/aws/services/stepfunctions/v2/services/test_sfn_task_service.py::TestTaskServiceSfn::test_start_execution_input_json": 1.0636126649997095, - "tests/aws/services/stepfunctions/v2/services/test_sns_task_service.py::TestTaskServiceSns::test_fifo_message_attribute[input_params0-True]": 0.9598540689999027, - "tests/aws/services/stepfunctions/v2/services/test_sns_task_service.py::TestTaskServiceSns::test_fifo_message_attribute[input_params1-False]": 0.9619632710002861, - "tests/aws/services/stepfunctions/v2/services/test_sns_task_service.py::TestTaskServiceSns::test_publish_base[1]": 0.9182333589999416, - "tests/aws/services/stepfunctions/v2/services/test_sns_task_service.py::TestTaskServiceSns::test_publish_base[HelloWorld]": 0.9700923899999907, - "tests/aws/services/stepfunctions/v2/services/test_sns_task_service.py::TestTaskServiceSns::test_publish_base[None]": 0.9281373110000004, - "tests/aws/services/stepfunctions/v2/services/test_sns_task_service.py::TestTaskServiceSns::test_publish_base[True]": 0.9671137209998051, - "tests/aws/services/stepfunctions/v2/services/test_sns_task_service.py::TestTaskServiceSns::test_publish_base[]": 0.955548927999871, - "tests/aws/services/stepfunctions/v2/services/test_sns_task_service.py::TestTaskServiceSns::test_publish_base[message1]": 0.9604566049999903, - "tests/aws/services/stepfunctions/v2/services/test_sns_task_service.py::TestTaskServiceSns::test_publish_base_error_topic_arn": 0.956729267000128, - "tests/aws/services/stepfunctions/v2/services/test_sns_task_service.py::TestTaskServiceSns::test_publish_message_attributes[\"HelloWorld\"]": 1.1036731110000346, - "tests/aws/services/stepfunctions/v2/services/test_sns_task_service.py::TestTaskServiceSns::test_publish_message_attributes[HelloWorld]": 1.1922653200001605, - "tests/aws/services/stepfunctions/v2/services/test_sns_task_service.py::TestTaskServiceSns::test_publish_message_attributes[message_value3]": 1.0762557450000259, - "tests/aws/services/stepfunctions/v2/services/test_sns_task_service.py::TestTaskServiceSns::test_publish_message_attributes[{}]": 1.0877511720000257, - "tests/aws/services/stepfunctions/v2/services/test_sqs_task_service.py::TestTaskServiceSqs::test_send_message": 1.1070415340002455, - "tests/aws/services/stepfunctions/v2/services/test_sqs_task_service.py::TestTaskServiceSqs::test_send_message_attributes": 1.1338697029998457, - "tests/aws/services/stepfunctions/v2/services/test_sqs_task_service.py::TestTaskServiceSqs::test_send_message_unsupported_parameters": 2.3035207080001783, - "tests/aws/services/stepfunctions/v2/states_variables/test_error_output.py::TestStateVariablesTemplate::test_catch_error_variable_sampling[TASK_CATCH_ERROR_VARIABLE_SAMPLING]": 2.299582399000201, - "tests/aws/services/stepfunctions/v2/states_variables/test_error_output.py::TestStateVariablesTemplate::test_catch_error_variable_sampling[TASK_CATCH_ERROR_VARIABLE_SAMPLING_TO_JSONPATH]": 2.2702975289998903, - "tests/aws/services/stepfunctions/v2/states_variables/test_error_output.py::TestStateVariablesTemplate::test_map_catch_error[MAP_CATCH_ERROR_OUTPUT]": 0.002081313999951817, - "tests/aws/services/stepfunctions/v2/states_variables/test_error_output.py::TestStateVariablesTemplate::test_map_catch_error[MAP_CATCH_ERROR_OUTPUT_WITH_RETRY]": 0.0017759090001163713, - "tests/aws/services/stepfunctions/v2/states_variables/test_error_output.py::TestStateVariablesTemplate::test_map_catch_error[MAP_CATCH_ERROR_VARIABLE_SAMPLING]": 0.0017594190001091192, - "tests/aws/services/stepfunctions/v2/states_variables/test_error_output.py::TestStateVariablesTemplate::test_parallel_catch_error[PARALLEL_CATCH_ERROR_OUTPUT]": 0.0019076270000368822, - "tests/aws/services/stepfunctions/v2/states_variables/test_error_output.py::TestStateVariablesTemplate::test_parallel_catch_error[PARALLEL_CATCH_ERROR_OUTPUT_WITH_RETRY]": 0.0017486369999915041, - "tests/aws/services/stepfunctions/v2/states_variables/test_error_output.py::TestStateVariablesTemplate::test_parallel_catch_error[PARALLEL_CATCH_ERROR_VARIABLE_SAMPLING]": 0.0016791369998827577, - "tests/aws/services/stepfunctions/v2/states_variables/test_error_output.py::TestStateVariablesTemplate::test_task_catch_error_output[TASK_CATCH_ERROR_OUTPUT]": 2.254408301000012, - "tests/aws/services/stepfunctions/v2/states_variables/test_error_output.py::TestStateVariablesTemplate::test_task_catch_error_output[TASK_CATCH_ERROR_OUTPUT_TO_JSONPATH]": 2.257188072999952, - "tests/aws/services/stepfunctions/v2/states_variables/test_error_output.py::TestStateVariablesTemplate::test_task_catch_error_with_retry[TASK_CATCH_ERROR_OUTPUT_WITH_RETRY]": 3.5448578140001246, - "tests/aws/services/stepfunctions/v2/states_variables/test_error_output.py::TestStateVariablesTemplate::test_task_catch_error_with_retry[TASK_CATCH_ERROR_OUTPUT_WITH_RETRY_TO_JSONPATH]": 3.543735295000033, - "tests/aws/services/stepfunctions/v2/test_sfn_api.py::TestSnfApi::test_cloudformation_definition_create_describe[dump]": 1.4942089139999553, - "tests/aws/services/stepfunctions/v2/test_sfn_api.py::TestSnfApi::test_cloudformation_definition_create_describe[dumps]": 1.5000608709999597, - "tests/aws/services/stepfunctions/v2/test_sfn_api.py::TestSnfApi::test_cloudformation_definition_string_create_describe[dump]": 1.4929037609999796, - "tests/aws/services/stepfunctions/v2/test_sfn_api.py::TestSnfApi::test_cloudformation_definition_string_create_describe[dumps]": 1.4775933860000805, - "tests/aws/services/stepfunctions/v2/test_sfn_api.py::TestSnfApi::test_create_delete_invalid_sm": 0.5655073879997872, - "tests/aws/services/stepfunctions/v2/test_sfn_api.py::TestSnfApi::test_create_delete_valid_sm": 1.5922535100003188, - "tests/aws/services/stepfunctions/v2/test_sfn_api.py::TestSnfApi::test_create_duplicate_definition_format_sm": 0.48470228699989093, - "tests/aws/services/stepfunctions/v2/test_sfn_api.py::TestSnfApi::test_create_duplicate_sm_name": 0.49213495499998317, - "tests/aws/services/stepfunctions/v2/test_sfn_api.py::TestSnfApi::test_create_exact_duplicate_sm": 0.5007961379999415, - "tests/aws/services/stepfunctions/v2/test_sfn_api.py::TestSnfApi::test_create_update_state_machine_base_definition": 0.5243735989997731, - "tests/aws/services/stepfunctions/v2/test_sfn_api.py::TestSnfApi::test_create_update_state_machine_base_definition_and_role": 0.6359160189999784, - "tests/aws/services/stepfunctions/v2/test_sfn_api.py::TestSnfApi::test_create_update_state_machine_base_role_arn": 0.6261817409997548, - "tests/aws/services/stepfunctions/v2/test_sfn_api.py::TestSnfApi::test_create_update_state_machine_base_update_none": 0.46803113400005714, - "tests/aws/services/stepfunctions/v2/test_sfn_api.py::TestSnfApi::test_create_update_state_machine_same_parameters": 0.584257473000207, - "tests/aws/services/stepfunctions/v2/test_sfn_api.py::TestSnfApi::test_delete_nonexistent_sm": 0.4491524150002988, - "tests/aws/services/stepfunctions/v2/test_sfn_api.py::TestSnfApi::test_describe_execution": 0.9353172789999462, - "tests/aws/services/stepfunctions/v2/test_sfn_api.py::TestSnfApi::test_describe_execution_arn_containing_punctuation": 0.7255512169999747, - "tests/aws/services/stepfunctions/v2/test_sfn_api.py::TestSnfApi::test_describe_execution_invalid_arn": 0.41392919300005815, - "tests/aws/services/stepfunctions/v2/test_sfn_api.py::TestSnfApi::test_describe_execution_no_such_state_machine": 0.7025119230002019, - "tests/aws/services/stepfunctions/v2/test_sfn_api.py::TestSnfApi::test_describe_invalid_arn_sm": 0.44535319600004186, - "tests/aws/services/stepfunctions/v2/test_sfn_api.py::TestSnfApi::test_describe_nonexistent_sm": 0.4652641489999496, - "tests/aws/services/stepfunctions/v2/test_sfn_api.py::TestSnfApi::test_describe_sm_arn_containing_punctuation": 0.47888841899998624, - "tests/aws/services/stepfunctions/v2/test_sfn_api.py::TestSnfApi::test_describe_state_machine_for_execution": 1.7956825849996676, - "tests/aws/services/stepfunctions/v2/test_sfn_api.py::TestSnfApi::test_get_execution_history_invalid_arn": 0.41367401699972106, - "tests/aws/services/stepfunctions/v2/test_sfn_api.py::TestSnfApi::test_get_execution_history_no_such_execution": 0.48731828499990115, - "tests/aws/services/stepfunctions/v2/test_sfn_api.py::TestSnfApi::test_get_execution_history_reversed": 0.5634053109999968, - "tests/aws/services/stepfunctions/v2/test_sfn_api.py::TestSnfApi::test_invalid_start_execution_arn": 0.467231356999946, - "tests/aws/services/stepfunctions/v2/test_sfn_api.py::TestSnfApi::test_invalid_start_execution_input": 0.9122592710002664, - "tests/aws/services/stepfunctions/v2/test_sfn_api.py::TestSnfApi::test_list_execution_invalid_arn": 0.4478047219997734, - "tests/aws/services/stepfunctions/v2/test_sfn_api.py::TestSnfApi::test_list_execution_no_such_state_machine": 0.4828595309998036, - "tests/aws/services/stepfunctions/v2/test_sfn_api.py::TestSnfApi::test_list_executions_pagination": 2.0988020770003004, - "tests/aws/services/stepfunctions/v2/test_sfn_api.py::TestSnfApi::test_list_executions_versions_pagination": 2.3603436959999726, - "tests/aws/services/stepfunctions/v2/test_sfn_api.py::TestSnfApi::test_list_sms": 0.5586011709999639, - "tests/aws/services/stepfunctions/v2/test_sfn_api.py::TestSnfApi::test_list_sms_pagination": 0.9192100730001584, - "tests/aws/services/stepfunctions/v2/test_sfn_api.py::TestSnfApi::test_start_execution": 0.8344150440002522, - "tests/aws/services/stepfunctions/v2/test_sfn_api.py::TestSnfApi::test_start_execution_idempotent": 1.2253997150003215, - "tests/aws/services/stepfunctions/v2/test_sfn_api.py::TestSnfApi::test_start_sync_execution": 0.45616784499998175, - "tests/aws/services/stepfunctions/v2/test_sfn_api.py::TestSnfApi::test_state_machine_status_filter": 0.6021724470001573, - "tests/aws/services/stepfunctions/v2/test_sfn_api.py::TestSnfApi::test_stop_execution": 0.5560624060003647, - "tests/aws/services/stepfunctions/v2/test_sfn_api_activities.py::TestSnfApiActivities::test_create_activity_invalid_name[\\x00activity]": 0.3427738999998837, - "tests/aws/services/stepfunctions/v2/test_sfn_api_activities.py::TestSnfApiActivities::test_create_activity_invalid_name[activity name]": 0.3401654500000859, - "tests/aws/services/stepfunctions/v2/test_sfn_api_activities.py::TestSnfApiActivities::test_create_activity_invalid_name[activity\"name]": 0.33292296199988414, - "tests/aws/services/stepfunctions/v2/test_sfn_api_activities.py::TestSnfApiActivities::test_create_activity_invalid_name[activity#name]": 0.3342200490003506, - "tests/aws/services/stepfunctions/v2/test_sfn_api_activities.py::TestSnfApiActivities::test_create_activity_invalid_name[activity$name]": 0.3320176120000724, - "tests/aws/services/stepfunctions/v2/test_sfn_api_activities.py::TestSnfApiActivities::test_create_activity_invalid_name[activity%name]": 0.33228586800009907, - "tests/aws/services/stepfunctions/v2/test_sfn_api_activities.py::TestSnfApiActivities::test_create_activity_invalid_name[activity&name]": 0.33390630199983207, - "tests/aws/services/stepfunctions/v2/test_sfn_api_activities.py::TestSnfApiActivities::test_create_activity_invalid_name[activity*name]": 0.3329733870000382, - "tests/aws/services/stepfunctions/v2/test_sfn_api_activities.py::TestSnfApiActivities::test_create_activity_invalid_name[activity,name]": 0.3326470690001315, - "tests/aws/services/stepfunctions/v2/test_sfn_api_activities.py::TestSnfApiActivities::test_create_activity_invalid_name[activity/name]": 0.33193533799999386, - "tests/aws/services/stepfunctions/v2/test_sfn_api_activities.py::TestSnfApiActivities::test_create_activity_invalid_name[activity:name]": 0.32995179700014887, - "tests/aws/services/stepfunctions/v2/test_sfn_api_activities.py::TestSnfApiActivities::test_create_activity_invalid_name[activity;name]": 0.33480446899989147, - "tests/aws/services/stepfunctions/v2/test_sfn_api_activities.py::TestSnfApiActivities::test_create_activity_invalid_name[activityname]": 0.38074219700024514, - "tests/aws/services/stepfunctions/v2/test_sfn_api_activities.py::TestSnfApiActivities::test_create_activity_invalid_name[activity?name]": 0.329119270000092, - "tests/aws/services/stepfunctions/v2/test_sfn_api_activities.py::TestSnfApiActivities::test_create_activity_invalid_name[activity[name]": 0.35547309000003224, - "tests/aws/services/stepfunctions/v2/test_sfn_api_activities.py::TestSnfApiActivities::test_create_activity_invalid_name[activity\\\\name]": 0.3343720430000303, - "tests/aws/services/stepfunctions/v2/test_sfn_api_activities.py::TestSnfApiActivities::test_create_activity_invalid_name[activity\\x1f]": 0.3535064519999196, - "tests/aws/services/stepfunctions/v2/test_sfn_api_activities.py::TestSnfApiActivities::test_create_activity_invalid_name[activity\\x7f]": 0.35023538500013274, - "tests/aws/services/stepfunctions/v2/test_sfn_api_activities.py::TestSnfApiActivities::test_create_activity_invalid_name[activity]name]": 0.3413873859999512, - "tests/aws/services/stepfunctions/v2/test_sfn_api_activities.py::TestSnfApiActivities::test_create_activity_invalid_name[activity^name]": 0.3353727820001495, - "tests/aws/services/stepfunctions/v2/test_sfn_api_activities.py::TestSnfApiActivities::test_create_activity_invalid_name[activity`name]": 0.3392902820000927, - "tests/aws/services/stepfunctions/v2/test_sfn_api_activities.py::TestSnfApiActivities::test_create_activity_invalid_name[activity{name]": 0.33873932099982085, - "tests/aws/services/stepfunctions/v2/test_sfn_api_activities.py::TestSnfApiActivities::test_create_activity_invalid_name[activity|name]": 0.3357664479999585, - "tests/aws/services/stepfunctions/v2/test_sfn_api_activities.py::TestSnfApiActivities::test_create_activity_invalid_name[activity}name]": 0.33691126700000495, - "tests/aws/services/stepfunctions/v2/test_sfn_api_activities.py::TestSnfApiActivities::test_create_activity_invalid_name[activity~name]": 0.3396549970002525, - "tests/aws/services/stepfunctions/v2/test_sfn_api_activities.py::TestSnfApiActivities::test_create_describe_delete_activity[ACTIVITY_NAME_ABC]": 0.4092617579997295, - "tests/aws/services/stepfunctions/v2/test_sfn_api_activities.py::TestSnfApiActivities::test_create_describe_delete_activity[Activity1]": 0.4131242140001632, - "tests/aws/services/stepfunctions/v2/test_sfn_api_activities.py::TestSnfApiActivities::test_create_describe_delete_activity[aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa]": 0.415010428999949, - "tests/aws/services/stepfunctions/v2/test_sfn_api_activities.py::TestSnfApiActivities::test_create_describe_delete_activity[activity-name.1]": 0.4126788779999515, - "tests/aws/services/stepfunctions/v2/test_sfn_api_activities.py::TestSnfApiActivities::test_create_describe_delete_activity[activity-name_123]": 0.40830769600006533, - "tests/aws/services/stepfunctions/v2/test_sfn_api_activities.py::TestSnfApiActivities::test_create_describe_delete_activity[activity.name.v2]": 0.41453634800018335, - "tests/aws/services/stepfunctions/v2/test_sfn_api_activities.py::TestSnfApiActivities::test_create_describe_delete_activity[activity.name]": 0.4210997990001033, - "tests/aws/services/stepfunctions/v2/test_sfn_api_activities.py::TestSnfApiActivities::test_create_describe_delete_activity[activityName.with.dots]": 0.4100436969999919, - "tests/aws/services/stepfunctions/v2/test_sfn_api_activities.py::TestSnfApiActivities::test_create_describe_delete_activity[activity_123.name]": 0.4112813410001763, - "tests/aws/services/stepfunctions/v2/test_sfn_api_activities.py::TestSnfApiActivities::test_describe_activity_invalid_arn": 0.41676634899999954, - "tests/aws/services/stepfunctions/v2/test_sfn_api_activities.py::TestSnfApiActivities::test_describe_deleted_activity": 0.3511059759998716, - "tests/aws/services/stepfunctions/v2/test_sfn_api_activities.py::TestSnfApiActivities::test_get_activity_task_deleted": 1.6308452780001517, - "tests/aws/services/stepfunctions/v2/test_sfn_api_activities.py::TestSnfApiActivities::test_get_activity_task_invalid_arn": 0.44076093700005003, - "tests/aws/services/stepfunctions/v2/test_sfn_api_activities.py::TestSnfApiActivities::test_list_activities": 0.3547720640001444, - "tests/aws/services/stepfunctions/v2/test_sfn_api_aliasing.py::TestSfnApiAliasing::test_base_create_alias_single_router_config": 0.6674574529999973, - "tests/aws/services/stepfunctions/v2/test_sfn_api_aliasing.py::TestSfnApiAliasing::test_base_lifecycle_create_delete_list": 0.8403365169997414, - "tests/aws/services/stepfunctions/v2/test_sfn_api_aliasing.py::TestSfnApiAliasing::test_base_lifecycle_create_invoke_describe_list": 0.8702253650001239, - "tests/aws/services/stepfunctions/v2/test_sfn_api_aliasing.py::TestSfnApiAliasing::test_base_lifecycle_create_update_describe": 0.7692747669998425, - "tests/aws/services/stepfunctions/v2/test_sfn_api_aliasing.py::TestSfnApiAliasing::test_delete_no_such_alias_arn": 0.7603849460001584, - "tests/aws/services/stepfunctions/v2/test_sfn_api_aliasing.py::TestSfnApiAliasing::test_delete_revision_with_alias": 0.7212421550000272, - "tests/aws/services/stepfunctions/v2/test_sfn_api_aliasing.py::TestSfnApiAliasing::test_delete_version_with_alias": 0.7949866930000553, - "tests/aws/services/stepfunctions/v2/test_sfn_api_aliasing.py::TestSfnApiAliasing::test_error_create_alias_invalid_name": 0.7057614810005362, - "tests/aws/services/stepfunctions/v2/test_sfn_api_aliasing.py::TestSfnApiAliasing::test_error_create_alias_invalid_router_configs": 0.7245579170000838, - "tests/aws/services/stepfunctions/v2/test_sfn_api_aliasing.py::TestSfnApiAliasing::test_error_create_alias_not_idempotent": 0.7122576169999775, - "tests/aws/services/stepfunctions/v2/test_sfn_api_aliasing.py::TestSfnApiAliasing::test_error_create_alias_with_state_machine_arn": 0.6727614500000527, - "tests/aws/services/stepfunctions/v2/test_sfn_api_aliasing.py::TestSfnApiAliasing::test_idempotent_create_alias": 0.7062792300000638, - "tests/aws/services/stepfunctions/v2/test_sfn_api_aliasing.py::TestSfnApiAliasing::test_list_state_machine_aliases_pagination_invalid_next_token": 0.7331792079996831, - "tests/aws/services/stepfunctions/v2/test_sfn_api_aliasing.py::TestSfnApiAliasing::test_list_state_machine_aliases_pagination_max_results[0]": 0.7920723940001153, - "tests/aws/services/stepfunctions/v2/test_sfn_api_aliasing.py::TestSfnApiAliasing::test_list_state_machine_aliases_pagination_max_results[1]": 0.7909708570002749, - "tests/aws/services/stepfunctions/v2/test_sfn_api_aliasing.py::TestSfnApiAliasing::test_update_no_such_alias_arn": 0.7123539889998938, - "tests/aws/services/stepfunctions/v2/test_sfn_api_express.py::TestSfnApiExpress::test_create_describe_delete": 0.767442007000227, - "tests/aws/services/stepfunctions/v2/test_sfn_api_express.py::TestSfnApiExpress::test_illegal_activity_task": 0.9067802230001689, - "tests/aws/services/stepfunctions/v2/test_sfn_api_express.py::TestSfnApiExpress::test_illegal_callbacks[SYNC]": 0.884126717999834, - "tests/aws/services/stepfunctions/v2/test_sfn_api_express.py::TestSfnApiExpress::test_illegal_callbacks[WAIT_FOR_TASK_TOKEN]": 0.8999284460001036, - "tests/aws/services/stepfunctions/v2/test_sfn_api_express.py::TestSfnApiExpress::test_start_async_describe_history_execution": 1.3968983409999964, - "tests/aws/services/stepfunctions/v2/test_sfn_api_express.py::TestSfnApiExpress::test_start_sync_execution": 0.7922089680000681, - "tests/aws/services/stepfunctions/v2/test_sfn_api_logs.py::TestSnfApiLogs::test_deleted_log_group": 0.5007051979998778, - "tests/aws/services/stepfunctions/v2/test_sfn_api_logs.py::TestSnfApiLogs::test_incomplete_logging_configuration[logging_configuration0]": 0.4338179429998945, - "tests/aws/services/stepfunctions/v2/test_sfn_api_logs.py::TestSnfApiLogs::test_incomplete_logging_configuration[logging_configuration1]": 1.7049880449999364, - "tests/aws/services/stepfunctions/v2/test_sfn_api_logs.py::TestSnfApiLogs::test_invalid_logging_configuration[logging_configuration0]": 0.3916126659996735, - "tests/aws/services/stepfunctions/v2/test_sfn_api_logs.py::TestSnfApiLogs::test_invalid_logging_configuration[logging_configuration1]": 0.38704498199990667, - "tests/aws/services/stepfunctions/v2/test_sfn_api_logs.py::TestSnfApiLogs::test_invalid_logging_configuration[logging_configuration2]": 0.385842349999848, - "tests/aws/services/stepfunctions/v2/test_sfn_api_logs.py::TestSnfApiLogs::test_logging_configuration[ALL-False]": 0.47479075600017495, - "tests/aws/services/stepfunctions/v2/test_sfn_api_logs.py::TestSnfApiLogs::test_logging_configuration[ALL-True]": 0.4814130939998904, - "tests/aws/services/stepfunctions/v2/test_sfn_api_logs.py::TestSnfApiLogs::test_logging_configuration[ERROR-False]": 0.4950442720000865, - "tests/aws/services/stepfunctions/v2/test_sfn_api_logs.py::TestSnfApiLogs::test_logging_configuration[ERROR-True]": 0.5248022030000357, - "tests/aws/services/stepfunctions/v2/test_sfn_api_logs.py::TestSnfApiLogs::test_logging_configuration[FATAL-False]": 0.47284831800016036, - "tests/aws/services/stepfunctions/v2/test_sfn_api_logs.py::TestSnfApiLogs::test_logging_configuration[FATAL-True]": 0.48037774500016894, - "tests/aws/services/stepfunctions/v2/test_sfn_api_logs.py::TestSnfApiLogs::test_logging_configuration[OFF-False]": 0.4685586450000301, - "tests/aws/services/stepfunctions/v2/test_sfn_api_logs.py::TestSnfApiLogs::test_logging_configuration[OFF-True]": 0.4666896930000348, - "tests/aws/services/stepfunctions/v2/test_sfn_api_logs.py::TestSnfApiLogs::test_multiple_destinations": 0.4465438670001731, - "tests/aws/services/stepfunctions/v2/test_sfn_api_logs.py::TestSnfApiLogs::test_update_logging_configuration": 0.6018903909998699, - "tests/aws/services/stepfunctions/v2/test_sfn_api_map_run.py::TestSnfApiMapRun::test_list_map_runs_and_describe_map_run": 0.8172584460000962, - "tests/aws/services/stepfunctions/v2/test_sfn_api_map_run.py::TestSnfApiMapRun::test_map_state_label_empty_fail": 0.34224575600023854, - "tests/aws/services/stepfunctions/v2/test_sfn_api_map_run.py::TestSnfApiMapRun::test_map_state_label_invalid_char_fail[ ]": 0.33599627199964743, - "tests/aws/services/stepfunctions/v2/test_sfn_api_map_run.py::TestSnfApiMapRun::test_map_state_label_invalid_char_fail[\"]": 0.3147075430001678, - "tests/aws/services/stepfunctions/v2/test_sfn_api_map_run.py::TestSnfApiMapRun::test_map_state_label_invalid_char_fail[#]": 0.31807868700002473, - "tests/aws/services/stepfunctions/v2/test_sfn_api_map_run.py::TestSnfApiMapRun::test_map_state_label_invalid_char_fail[$]": 0.3199303310000232, - "tests/aws/services/stepfunctions/v2/test_sfn_api_map_run.py::TestSnfApiMapRun::test_map_state_label_invalid_char_fail[%]": 0.31969616400010636, - "tests/aws/services/stepfunctions/v2/test_sfn_api_map_run.py::TestSnfApiMapRun::test_map_state_label_invalid_char_fail[&]": 0.317973130999917, - "tests/aws/services/stepfunctions/v2/test_sfn_api_map_run.py::TestSnfApiMapRun::test_map_state_label_invalid_char_fail[*]": 0.3181168579999394, - "tests/aws/services/stepfunctions/v2/test_sfn_api_map_run.py::TestSnfApiMapRun::test_map_state_label_invalid_char_fail[,]": 0.32019413200009694, - "tests/aws/services/stepfunctions/v2/test_sfn_api_map_run.py::TestSnfApiMapRun::test_map_state_label_invalid_char_fail[:]": 0.33235933800006023, - "tests/aws/services/stepfunctions/v2/test_sfn_api_map_run.py::TestSnfApiMapRun::test_map_state_label_invalid_char_fail[;]": 0.3734093099999427, - "tests/aws/services/stepfunctions/v2/test_sfn_api_map_run.py::TestSnfApiMapRun::test_map_state_label_invalid_char_fail[<]": 0.3191923790000146, - "tests/aws/services/stepfunctions/v2/test_sfn_api_map_run.py::TestSnfApiMapRun::test_map_state_label_invalid_char_fail[>]": 0.3212069359999532, - "tests/aws/services/stepfunctions/v2/test_sfn_api_map_run.py::TestSnfApiMapRun::test_map_state_label_invalid_char_fail[?]": 0.32188577099987015, - "tests/aws/services/stepfunctions/v2/test_sfn_api_map_run.py::TestSnfApiMapRun::test_map_state_label_invalid_char_fail[[]": 0.3191273550000915, - "tests/aws/services/stepfunctions/v2/test_sfn_api_map_run.py::TestSnfApiMapRun::test_map_state_label_invalid_char_fail[\\\\]": 0.319752371000277, - "tests/aws/services/stepfunctions/v2/test_sfn_api_map_run.py::TestSnfApiMapRun::test_map_state_label_invalid_char_fail[\\n]": 0.33163048200003686, - "tests/aws/services/stepfunctions/v2/test_sfn_api_map_run.py::TestSnfApiMapRun::test_map_state_label_invalid_char_fail[\\r]": 0.31736187299998164, - "tests/aws/services/stepfunctions/v2/test_sfn_api_map_run.py::TestSnfApiMapRun::test_map_state_label_invalid_char_fail[\\t]": 0.32499775000019326, - "tests/aws/services/stepfunctions/v2/test_sfn_api_map_run.py::TestSnfApiMapRun::test_map_state_label_invalid_char_fail[\\x00]": 0.3216016740000214, - "tests/aws/services/stepfunctions/v2/test_sfn_api_map_run.py::TestSnfApiMapRun::test_map_state_label_invalid_char_fail[\\x01]": 0.3181631580002886, - "tests/aws/services/stepfunctions/v2/test_sfn_api_map_run.py::TestSnfApiMapRun::test_map_state_label_invalid_char_fail[\\x02]": 0.32178536399987934, - "tests/aws/services/stepfunctions/v2/test_sfn_api_map_run.py::TestSnfApiMapRun::test_map_state_label_invalid_char_fail[\\x03]": 0.3197625310001513, - "tests/aws/services/stepfunctions/v2/test_sfn_api_map_run.py::TestSnfApiMapRun::test_map_state_label_invalid_char_fail[\\x04]": 0.32057485899963467, - "tests/aws/services/stepfunctions/v2/test_sfn_api_map_run.py::TestSnfApiMapRun::test_map_state_label_invalid_char_fail[\\x05]": 0.3190663750001477, - "tests/aws/services/stepfunctions/v2/test_sfn_api_map_run.py::TestSnfApiMapRun::test_map_state_label_invalid_char_fail[\\x06]": 0.32645328799981144, - "tests/aws/services/stepfunctions/v2/test_sfn_api_map_run.py::TestSnfApiMapRun::test_map_state_label_invalid_char_fail[\\x07]": 0.31864898699996047, - "tests/aws/services/stepfunctions/v2/test_sfn_api_map_run.py::TestSnfApiMapRun::test_map_state_label_invalid_char_fail[\\x08]": 0.3215774370003146, - "tests/aws/services/stepfunctions/v2/test_sfn_api_map_run.py::TestSnfApiMapRun::test_map_state_label_invalid_char_fail[\\x0b]": 0.32906424400016476, - "tests/aws/services/stepfunctions/v2/test_sfn_api_map_run.py::TestSnfApiMapRun::test_map_state_label_invalid_char_fail[\\x0c]": 0.3212587349999012, - "tests/aws/services/stepfunctions/v2/test_sfn_api_map_run.py::TestSnfApiMapRun::test_map_state_label_invalid_char_fail[\\x0e]": 0.3176488069998413, - "tests/aws/services/stepfunctions/v2/test_sfn_api_map_run.py::TestSnfApiMapRun::test_map_state_label_invalid_char_fail[\\x0f]": 0.3230384580001555, - "tests/aws/services/stepfunctions/v2/test_sfn_api_map_run.py::TestSnfApiMapRun::test_map_state_label_invalid_char_fail[\\x10]": 0.3197475239999221, - "tests/aws/services/stepfunctions/v2/test_sfn_api_map_run.py::TestSnfApiMapRun::test_map_state_label_invalid_char_fail[\\x11]": 0.3231373830001303, - "tests/aws/services/stepfunctions/v2/test_sfn_api_map_run.py::TestSnfApiMapRun::test_map_state_label_invalid_char_fail[\\x12]": 0.328151650999871, - "tests/aws/services/stepfunctions/v2/test_sfn_api_map_run.py::TestSnfApiMapRun::test_map_state_label_invalid_char_fail[\\x13]": 0.3335529270000279, - "tests/aws/services/stepfunctions/v2/test_sfn_api_map_run.py::TestSnfApiMapRun::test_map_state_label_invalid_char_fail[\\x14]": 0.36047392400018907, - "tests/aws/services/stepfunctions/v2/test_sfn_api_map_run.py::TestSnfApiMapRun::test_map_state_label_invalid_char_fail[\\x15]": 0.33417355899996437, - "tests/aws/services/stepfunctions/v2/test_sfn_api_map_run.py::TestSnfApiMapRun::test_map_state_label_invalid_char_fail[\\x16]": 0.32934819100000823, - "tests/aws/services/stepfunctions/v2/test_sfn_api_map_run.py::TestSnfApiMapRun::test_map_state_label_invalid_char_fail[\\x17]": 0.3229090949998863, - "tests/aws/services/stepfunctions/v2/test_sfn_api_map_run.py::TestSnfApiMapRun::test_map_state_label_invalid_char_fail[\\x18]": 0.32682242100008807, - "tests/aws/services/stepfunctions/v2/test_sfn_api_map_run.py::TestSnfApiMapRun::test_map_state_label_invalid_char_fail[\\x19]": 0.3247671059998538, - "tests/aws/services/stepfunctions/v2/test_sfn_api_map_run.py::TestSnfApiMapRun::test_map_state_label_invalid_char_fail[\\x1a]": 0.3242768949996844, - "tests/aws/services/stepfunctions/v2/test_sfn_api_map_run.py::TestSnfApiMapRun::test_map_state_label_invalid_char_fail[\\x1b]": 0.3352842609999698, - "tests/aws/services/stepfunctions/v2/test_sfn_api_map_run.py::TestSnfApiMapRun::test_map_state_label_invalid_char_fail[\\x1c]": 0.33657303299992236, - "tests/aws/services/stepfunctions/v2/test_sfn_api_map_run.py::TestSnfApiMapRun::test_map_state_label_invalid_char_fail[\\x1d]": 0.3400762910000594, - "tests/aws/services/stepfunctions/v2/test_sfn_api_map_run.py::TestSnfApiMapRun::test_map_state_label_invalid_char_fail[\\x1e]": 0.32265769300011016, - "tests/aws/services/stepfunctions/v2/test_sfn_api_map_run.py::TestSnfApiMapRun::test_map_state_label_invalid_char_fail[\\x1f]": 0.3286651470000379, - "tests/aws/services/stepfunctions/v2/test_sfn_api_map_run.py::TestSnfApiMapRun::test_map_state_label_invalid_char_fail[\\x7f]": 0.32971409700030563, - "tests/aws/services/stepfunctions/v2/test_sfn_api_map_run.py::TestSnfApiMapRun::test_map_state_label_invalid_char_fail[\\x80]": 0.33243248999997377, - "tests/aws/services/stepfunctions/v2/test_sfn_api_map_run.py::TestSnfApiMapRun::test_map_state_label_invalid_char_fail[\\x81]": 0.33152016899975933, - "tests/aws/services/stepfunctions/v2/test_sfn_api_map_run.py::TestSnfApiMapRun::test_map_state_label_invalid_char_fail[\\x82]": 1.5752667159999874, - "tests/aws/services/stepfunctions/v2/test_sfn_api_map_run.py::TestSnfApiMapRun::test_map_state_label_invalid_char_fail[\\x83]": 0.32147927599976356, - "tests/aws/services/stepfunctions/v2/test_sfn_api_map_run.py::TestSnfApiMapRun::test_map_state_label_invalid_char_fail[\\x84]": 0.3175085849995867, - "tests/aws/services/stepfunctions/v2/test_sfn_api_map_run.py::TestSnfApiMapRun::test_map_state_label_invalid_char_fail[\\x85]": 0.3170626529999936, - "tests/aws/services/stepfunctions/v2/test_sfn_api_map_run.py::TestSnfApiMapRun::test_map_state_label_invalid_char_fail[\\x86]": 0.31784548399991763, - "tests/aws/services/stepfunctions/v2/test_sfn_api_map_run.py::TestSnfApiMapRun::test_map_state_label_invalid_char_fail[\\x87]": 0.31798663099971236, - "tests/aws/services/stepfunctions/v2/test_sfn_api_map_run.py::TestSnfApiMapRun::test_map_state_label_invalid_char_fail[\\x88]": 0.3301548360002471, - "tests/aws/services/stepfunctions/v2/test_sfn_api_map_run.py::TestSnfApiMapRun::test_map_state_label_invalid_char_fail[\\x89]": 0.3343969580000703, - "tests/aws/services/stepfunctions/v2/test_sfn_api_map_run.py::TestSnfApiMapRun::test_map_state_label_invalid_char_fail[\\x8a]": 0.33202437000022655, - "tests/aws/services/stepfunctions/v2/test_sfn_api_map_run.py::TestSnfApiMapRun::test_map_state_label_invalid_char_fail[\\x8b]": 0.3305926399998498, - "tests/aws/services/stepfunctions/v2/test_sfn_api_map_run.py::TestSnfApiMapRun::test_map_state_label_invalid_char_fail[\\x8c]": 0.3328532489999816, - "tests/aws/services/stepfunctions/v2/test_sfn_api_map_run.py::TestSnfApiMapRun::test_map_state_label_invalid_char_fail[\\x8d]": 0.32718840200004706, - "tests/aws/services/stepfunctions/v2/test_sfn_api_map_run.py::TestSnfApiMapRun::test_map_state_label_invalid_char_fail[\\x8e]": 0.34414952900010576, - "tests/aws/services/stepfunctions/v2/test_sfn_api_map_run.py::TestSnfApiMapRun::test_map_state_label_invalid_char_fail[\\x8f]": 0.36109037999995053, - "tests/aws/services/stepfunctions/v2/test_sfn_api_map_run.py::TestSnfApiMapRun::test_map_state_label_invalid_char_fail[\\x90]": 0.34024818700027026, - "tests/aws/services/stepfunctions/v2/test_sfn_api_map_run.py::TestSnfApiMapRun::test_map_state_label_invalid_char_fail[\\x91]": 0.3300847570001224, - "tests/aws/services/stepfunctions/v2/test_sfn_api_map_run.py::TestSnfApiMapRun::test_map_state_label_invalid_char_fail[\\x92]": 0.3328804179996041, - "tests/aws/services/stepfunctions/v2/test_sfn_api_map_run.py::TestSnfApiMapRun::test_map_state_label_invalid_char_fail[\\x93]": 0.32556065299968395, - "tests/aws/services/stepfunctions/v2/test_sfn_api_map_run.py::TestSnfApiMapRun::test_map_state_label_invalid_char_fail[\\x94]": 0.3253238169997985, - "tests/aws/services/stepfunctions/v2/test_sfn_api_map_run.py::TestSnfApiMapRun::test_map_state_label_invalid_char_fail[\\x95]": 0.31959310699994603, - "tests/aws/services/stepfunctions/v2/test_sfn_api_map_run.py::TestSnfApiMapRun::test_map_state_label_invalid_char_fail[\\x96]": 0.3205726900000627, - "tests/aws/services/stepfunctions/v2/test_sfn_api_map_run.py::TestSnfApiMapRun::test_map_state_label_invalid_char_fail[\\x97]": 0.32372824799995215, - "tests/aws/services/stepfunctions/v2/test_sfn_api_map_run.py::TestSnfApiMapRun::test_map_state_label_invalid_char_fail[\\x98]": 0.3187929450000411, - "tests/aws/services/stepfunctions/v2/test_sfn_api_map_run.py::TestSnfApiMapRun::test_map_state_label_invalid_char_fail[\\x99]": 0.3205008549998638, - "tests/aws/services/stepfunctions/v2/test_sfn_api_map_run.py::TestSnfApiMapRun::test_map_state_label_invalid_char_fail[\\x9a]": 0.32446663800010356, - "tests/aws/services/stepfunctions/v2/test_sfn_api_map_run.py::TestSnfApiMapRun::test_map_state_label_invalid_char_fail[\\x9b]": 0.32070611899985124, - "tests/aws/services/stepfunctions/v2/test_sfn_api_map_run.py::TestSnfApiMapRun::test_map_state_label_invalid_char_fail[\\x9c]": 0.31861087299989777, - "tests/aws/services/stepfunctions/v2/test_sfn_api_map_run.py::TestSnfApiMapRun::test_map_state_label_invalid_char_fail[\\x9d]": 0.3213036629997532, - "tests/aws/services/stepfunctions/v2/test_sfn_api_map_run.py::TestSnfApiMapRun::test_map_state_label_invalid_char_fail[\\x9e]": 0.31846855900016635, - "tests/aws/services/stepfunctions/v2/test_sfn_api_map_run.py::TestSnfApiMapRun::test_map_state_label_invalid_char_fail[\\x9f]": 0.3187743139999384, - "tests/aws/services/stepfunctions/v2/test_sfn_api_map_run.py::TestSnfApiMapRun::test_map_state_label_invalid_char_fail[]]": 0.3357276860001548, - "tests/aws/services/stepfunctions/v2/test_sfn_api_map_run.py::TestSnfApiMapRun::test_map_state_label_invalid_char_fail[^]": 0.31803543199998785, - "tests/aws/services/stepfunctions/v2/test_sfn_api_map_run.py::TestSnfApiMapRun::test_map_state_label_invalid_char_fail[`]": 0.32267680700010715, - "tests/aws/services/stepfunctions/v2/test_sfn_api_map_run.py::TestSnfApiMapRun::test_map_state_label_invalid_char_fail[{]": 0.3210628040001211, - "tests/aws/services/stepfunctions/v2/test_sfn_api_map_run.py::TestSnfApiMapRun::test_map_state_label_invalid_char_fail[|]": 0.3255849049999142, - "tests/aws/services/stepfunctions/v2/test_sfn_api_map_run.py::TestSnfApiMapRun::test_map_state_label_invalid_char_fail[}]": 0.31836248999979944, - "tests/aws/services/stepfunctions/v2/test_sfn_api_map_run.py::TestSnfApiMapRun::test_map_state_label_invalid_char_fail[~]": 0.319656643999906, - "tests/aws/services/stepfunctions/v2/test_sfn_api_map_run.py::TestSnfApiMapRun::test_map_state_label_too_long_fail": 0.3396349110000756, - "tests/aws/services/stepfunctions/v2/test_sfn_api_tagging.py::TestSnfApiTagging::test_create_state_machine": 0.3470180970000456, - "tests/aws/services/stepfunctions/v2/test_sfn_api_tagging.py::TestSnfApiTagging::test_tag_invalid_state_machine[None]": 0.3526295710003069, - "tests/aws/services/stepfunctions/v2/test_sfn_api_tagging.py::TestSnfApiTagging::test_tag_invalid_state_machine[tag_list1]": 0.33766252299983535, - "tests/aws/services/stepfunctions/v2/test_sfn_api_tagging.py::TestSnfApiTagging::test_tag_invalid_state_machine[tag_list2]": 0.34399084999995466, - "tests/aws/services/stepfunctions/v2/test_sfn_api_tagging.py::TestSnfApiTagging::test_tag_invalid_state_machine[tag_list3]": 0.3376532230001885, - "tests/aws/services/stepfunctions/v2/test_sfn_api_tagging.py::TestSnfApiTagging::test_tag_state_machine[tag_list0]": 0.3556462719998308, - "tests/aws/services/stepfunctions/v2/test_sfn_api_tagging.py::TestSnfApiTagging::test_tag_state_machine[tag_list1]": 0.36207118699985585, - "tests/aws/services/stepfunctions/v2/test_sfn_api_tagging.py::TestSnfApiTagging::test_tag_state_machine[tag_list2]": 0.3560073419998844, - "tests/aws/services/stepfunctions/v2/test_sfn_api_tagging.py::TestSnfApiTagging::test_tag_state_machine[tag_list3]": 0.35975916100005634, - "tests/aws/services/stepfunctions/v2/test_sfn_api_tagging.py::TestSnfApiTagging::test_tag_state_machine[tag_list4]": 0.3639771599998767, - "tests/aws/services/stepfunctions/v2/test_sfn_api_tagging.py::TestSnfApiTagging::test_tag_state_machine_version": 0.3656141850001404, - "tests/aws/services/stepfunctions/v2/test_sfn_api_tagging.py::TestSnfApiTagging::test_untag_state_machine[tag_keys0]": 0.3693061999999827, - "tests/aws/services/stepfunctions/v2/test_sfn_api_tagging.py::TestSnfApiTagging::test_untag_state_machine[tag_keys1]": 0.3885031910001544, - "tests/aws/services/stepfunctions/v2/test_sfn_api_tagging.py::TestSnfApiTagging::test_untag_state_machine[tag_keys2]": 0.4273158280000189, - "tests/aws/services/stepfunctions/v2/test_sfn_api_tagging.py::TestSnfApiTagging::test_untag_state_machine[tag_keys3]": 0.4003797640000357, - "tests/aws/services/stepfunctions/v2/test_sfn_api_validation.py::TestSfnApiValidation::test_validate_state_machine_definition_not_a_definition[EMPTY_DICT]": 0.34080210599995553, - "tests/aws/services/stepfunctions/v2/test_sfn_api_validation.py::TestSfnApiValidation::test_validate_state_machine_definition_not_a_definition[EMPTY_STRING]": 0.3372792230002233, - "tests/aws/services/stepfunctions/v2/test_sfn_api_validation.py::TestSfnApiValidation::test_validate_state_machine_definition_not_a_definition[NOT_A_DEF]": 0.33886078499995165, - "tests/aws/services/stepfunctions/v2/test_sfn_api_validation.py::TestSfnApiValidation::test_validate_state_machine_definition_type_express[ILLEGAL_WFTT]": 0.3514097950001087, - "tests/aws/services/stepfunctions/v2/test_sfn_api_validation.py::TestSfnApiValidation::test_validate_state_machine_definition_type_express[INVALID_BASE_NO_STARTAT]": 0.3390016100001958, - "tests/aws/services/stepfunctions/v2/test_sfn_api_validation.py::TestSfnApiValidation::test_validate_state_machine_definition_type_express[VALID_BASE_PASS]": 0.33905046199993194, - "tests/aws/services/stepfunctions/v2/test_sfn_api_validation.py::TestSfnApiValidation::test_validate_state_machine_definition_type_standard[INVALID_BASE_NO_STARTAT]": 0.34413774099994043, - "tests/aws/services/stepfunctions/v2/test_sfn_api_validation.py::TestSfnApiValidation::test_validate_state_machine_definition_type_standard[VALID_BASE_PASS]": 0.3429384989999562, - "tests/aws/services/stepfunctions/v2/test_sfn_api_variable_references.py::TestSfnApiVariableReferences::test_base_variable_references_in_assign_templates[BASE_ASSIGN_FROM_INTRINSIC_FUNCTION]": 1.8461829610000677, - "tests/aws/services/stepfunctions/v2/test_sfn_api_variable_references.py::TestSfnApiVariableReferences::test_base_variable_references_in_assign_templates[BASE_ASSIGN_FROM_PARAMETERS]": 0.9168926499996815, - "tests/aws/services/stepfunctions/v2/test_sfn_api_variable_references.py::TestSfnApiVariableReferences::test_base_variable_references_in_assign_templates[BASE_ASSIGN_FROM_RESULT]": 0.8853773229998296, - "tests/aws/services/stepfunctions/v2/test_sfn_api_variable_references.py::TestSfnApiVariableReferences::test_base_variable_references_in_assign_templates[BASE_EVALUATION_ORDER_PASS_STATE]": 0.9271738390000337, - "tests/aws/services/stepfunctions/v2/test_sfn_api_variable_references.py::TestSfnApiVariableReferences::test_base_variable_references_in_assign_templates[BASE_REFERENCE_IN_CHOICE]": 0.9918052009998064, - "tests/aws/services/stepfunctions/v2/test_sfn_api_variable_references.py::TestSfnApiVariableReferences::test_base_variable_references_in_assign_templates[BASE_REFERENCE_IN_FAIL]": 0.8677277950000644, - "tests/aws/services/stepfunctions/v2/test_sfn_api_variable_references.py::TestSfnApiVariableReferences::test_base_variable_references_in_assign_templates[BASE_REFERENCE_IN_INPUTPATH]": 2.098608432000219, - "tests/aws/services/stepfunctions/v2/test_sfn_api_variable_references.py::TestSfnApiVariableReferences::test_base_variable_references_in_assign_templates[BASE_REFERENCE_IN_INTRINSIC_FUNCTION]": 1.2159542619999684, - "tests/aws/services/stepfunctions/v2/test_sfn_api_variable_references.py::TestSfnApiVariableReferences::test_base_variable_references_in_assign_templates[BASE_REFERENCE_IN_ITERATOR_OUTER_SCOPE]": 1.7824523900001168, - "tests/aws/services/stepfunctions/v2/test_sfn_api_variable_references.py::TestSfnApiVariableReferences::test_base_variable_references_in_assign_templates[BASE_REFERENCE_IN_OUTPUTPATH]": 0.9221236250000402, - "tests/aws/services/stepfunctions/v2/test_sfn_api_variable_references.py::TestSfnApiVariableReferences::test_base_variable_references_in_assign_templates[BASE_REFERENCE_IN_PARAMETERS]": 0.903036449999945, - "tests/aws/services/stepfunctions/v2/test_sfn_api_variable_references.py::TestSfnApiVariableReferences::test_base_variable_references_in_assign_templates[BASE_REFERENCE_IN_WAIT]": 0.9030166409995672, - "tests/aws/services/stepfunctions/v2/test_sfn_api_variable_references.py::TestSfnApiVariableReferences::test_base_variable_references_in_assign_templates[MAP_STATE_REFERENCE_IN_INTRINSIC_FUNCTION]": 1.196199321999984, - "tests/aws/services/stepfunctions/v2/test_sfn_api_variable_references.py::TestSfnApiVariableReferences::test_base_variable_references_in_assign_templates[MAP_STATE_REFERENCE_IN_ITEMS_PATH]": 1.2087361839999176, - "tests/aws/services/stepfunctions/v2/test_sfn_api_variable_references.py::TestSfnApiVariableReferences::test_base_variable_references_in_assign_templates[MAP_STATE_REFERENCE_IN_ITEM_SELECTOR]": 0.9338066450000042, - "tests/aws/services/stepfunctions/v2/test_sfn_api_variable_references.py::TestSfnApiVariableReferences::test_base_variable_references_in_assign_templates[MAP_STATE_REFERENCE_IN_MAX_CONCURRENCY_PATH]": 0.9454423090001001, - "tests/aws/services/stepfunctions/v2/test_sfn_api_variable_references.py::TestSfnApiVariableReferences::test_base_variable_references_in_assign_templates[MAP_STATE_REFERENCE_IN_MAX_ITEMS_PATH]": 0.9326582870000948, - "tests/aws/services/stepfunctions/v2/test_sfn_api_variable_references.py::TestSfnApiVariableReferences::test_base_variable_references_in_assign_templates[MAP_STATE_REFERENCE_IN_TOLERATED_FAILURE_PATH]": 0.9207860220001294, - "tests/aws/services/stepfunctions/v2/test_sfn_api_variable_references.py::TestSfnApiVariableReferences::test_base_variable_references_in_jsonata_template[CHOICE_CONDITION_CONSTANT_JSONATA]": 0.5294505080003091, - "tests/aws/services/stepfunctions/v2/test_sfn_api_variable_references.py::TestSfnApiVariableReferences::test_base_variable_references_in_jsonata_template[CHOICE_STATE_UNSORTED_CHOICE_PARAMETERS_JSONATA]": 0.5273196739999548, - "tests/aws/services/stepfunctions/v2/test_sfn_api_versioning.py::TestSnfApiVersioning::test_create_express_with_publish": 0.40785704400013856, - "tests/aws/services/stepfunctions/v2/test_sfn_api_versioning.py::TestSnfApiVersioning::test_create_publish_describe_no_version_description": 0.4490623700003198, - "tests/aws/services/stepfunctions/v2/test_sfn_api_versioning.py::TestSnfApiVersioning::test_create_publish_describe_with_version_description": 0.4507894570001554, - "tests/aws/services/stepfunctions/v2/test_sfn_api_versioning.py::TestSnfApiVersioning::test_create_with_publish": 0.4193968619997577, - "tests/aws/services/stepfunctions/v2/test_sfn_api_versioning.py::TestSnfApiVersioning::test_create_with_version_description_no_publish": 0.39719076999995195, - "tests/aws/services/stepfunctions/v2/test_sfn_api_versioning.py::TestSnfApiVersioning::test_describe_state_machine_for_execution_of_version": 0.5038561109997772, - "tests/aws/services/stepfunctions/v2/test_sfn_api_versioning.py::TestSnfApiVersioning::test_describe_state_machine_for_execution_of_version_with_revision": 0.534412020000218, - "tests/aws/services/stepfunctions/v2/test_sfn_api_versioning.py::TestSnfApiVersioning::test_empty_revision_with_publish_and_no_publish_on_creation": 0.46021958799997265, - "tests/aws/services/stepfunctions/v2/test_sfn_api_versioning.py::TestSnfApiVersioning::test_empty_revision_with_publish_and_publish_on_creation": 0.47673828799997864, - "tests/aws/services/stepfunctions/v2/test_sfn_api_versioning.py::TestSnfApiVersioning::test_idempotent_publish": 0.4758321680001245, - "tests/aws/services/stepfunctions/v2/test_sfn_api_versioning.py::TestSnfApiVersioning::test_list_delete_version": 0.49565171700032806, - "tests/aws/services/stepfunctions/v2/test_sfn_api_versioning.py::TestSnfApiVersioning::test_list_state_machine_versions_pagination": 0.8833165639998697, - "tests/aws/services/stepfunctions/v2/test_sfn_api_versioning.py::TestSnfApiVersioning::test_publish_state_machine_version": 0.563326565999887, - "tests/aws/services/stepfunctions/v2/test_sfn_api_versioning.py::TestSnfApiVersioning::test_publish_state_machine_version_invalid_arn": 0.42281138699968324, - "tests/aws/services/stepfunctions/v2/test_sfn_api_versioning.py::TestSnfApiVersioning::test_publish_state_machine_version_no_such_machine": 0.47811249600022165, - "tests/aws/services/stepfunctions/v2/test_sfn_api_versioning.py::TestSnfApiVersioning::test_start_version_execution": 0.590223025999876, - "tests/aws/services/stepfunctions/v2/test_sfn_api_versioning.py::TestSnfApiVersioning::test_update_state_machine": 0.5149608490000901, - "tests/aws/services/stepfunctions/v2/test_sfn_api_versioning.py::TestSnfApiVersioning::test_version_ids_between_deletions": 0.468229731999827, - "tests/aws/services/stepfunctions/v2/test_state/test_test_state_scenarios.py::TestStateCaseScenarios::test_base_inspection_level_debug[BASE_CHOICE_STATE]": 0.97095853299993, - "tests/aws/services/stepfunctions/v2/test_state/test_test_state_scenarios.py::TestStateCaseScenarios::test_base_inspection_level_debug[BASE_FAIL_STATE]": 0.8523967129999619, - "tests/aws/services/stepfunctions/v2/test_state/test_test_state_scenarios.py::TestStateCaseScenarios::test_base_inspection_level_debug[BASE_PASS_STATE]": 0.8030079060001754, - "tests/aws/services/stepfunctions/v2/test_state/test_test_state_scenarios.py::TestStateCaseScenarios::test_base_inspection_level_debug[BASE_RESULT_PASS_STATE]": 0.8278763379998964, - "tests/aws/services/stepfunctions/v2/test_state/test_test_state_scenarios.py::TestStateCaseScenarios::test_base_inspection_level_debug[BASE_SUCCEED_STATE]": 0.8229462590002186, - "tests/aws/services/stepfunctions/v2/test_state/test_test_state_scenarios.py::TestStateCaseScenarios::test_base_inspection_level_debug[IO_PASS_STATE]": 1.0723797429998285, - "tests/aws/services/stepfunctions/v2/test_state/test_test_state_scenarios.py::TestStateCaseScenarios::test_base_inspection_level_debug[IO_RESULT_PASS_STATE]": 0.9868564170001264, - "tests/aws/services/stepfunctions/v2/test_state/test_test_state_scenarios.py::TestStateCaseScenarios::test_base_inspection_level_info[BASE_CHOICE_STATE]": 0.6883763659998294, - "tests/aws/services/stepfunctions/v2/test_state/test_test_state_scenarios.py::TestStateCaseScenarios::test_base_inspection_level_info[BASE_FAIL_STATE]": 0.48844512399978157, - "tests/aws/services/stepfunctions/v2/test_state/test_test_state_scenarios.py::TestStateCaseScenarios::test_base_inspection_level_info[BASE_PASS_STATE]": 0.5403738149998389, - "tests/aws/services/stepfunctions/v2/test_state/test_test_state_scenarios.py::TestStateCaseScenarios::test_base_inspection_level_info[BASE_RESULT_PASS_STATE]": 0.5144165650001469, - "tests/aws/services/stepfunctions/v2/test_state/test_test_state_scenarios.py::TestStateCaseScenarios::test_base_inspection_level_info[BASE_SUCCEED_STATE]": 0.47719492700002775, - "tests/aws/services/stepfunctions/v2/test_state/test_test_state_scenarios.py::TestStateCaseScenarios::test_base_inspection_level_info[IO_PASS_STATE]": 0.6137947429997439, - "tests/aws/services/stepfunctions/v2/test_state/test_test_state_scenarios.py::TestStateCaseScenarios::test_base_inspection_level_info[IO_RESULT_PASS_STATE]": 1.9048892890000388, - "tests/aws/services/stepfunctions/v2/test_state/test_test_state_scenarios.py::TestStateCaseScenarios::test_base_inspection_level_trace[BASE_CHOICE_STATE]": 0.9741826849999597, - "tests/aws/services/stepfunctions/v2/test_state/test_test_state_scenarios.py::TestStateCaseScenarios::test_base_inspection_level_trace[BASE_FAIL_STATE]": 0.7918365520001771, - "tests/aws/services/stepfunctions/v2/test_state/test_test_state_scenarios.py::TestStateCaseScenarios::test_base_inspection_level_trace[BASE_PASS_STATE]": 0.8063024369998857, - "tests/aws/services/stepfunctions/v2/test_state/test_test_state_scenarios.py::TestStateCaseScenarios::test_base_inspection_level_trace[BASE_RESULT_PASS_STATE]": 0.8041035010000996, - "tests/aws/services/stepfunctions/v2/test_state/test_test_state_scenarios.py::TestStateCaseScenarios::test_base_inspection_level_trace[BASE_SUCCEED_STATE]": 0.8000236520003909, - "tests/aws/services/stepfunctions/v2/test_state/test_test_state_scenarios.py::TestStateCaseScenarios::test_base_inspection_level_trace[IO_PASS_STATE]": 0.9060771189999741, - "tests/aws/services/stepfunctions/v2/test_state/test_test_state_scenarios.py::TestStateCaseScenarios::test_base_inspection_level_trace[IO_RESULT_PASS_STATE]": 0.9023305120001623, - "tests/aws/services/stepfunctions/v2/test_state/test_test_state_scenarios.py::TestStateCaseScenarios::test_base_lambda_service_task_state[DEBUG]": 2.4460459030001402, - "tests/aws/services/stepfunctions/v2/test_state/test_test_state_scenarios.py::TestStateCaseScenarios::test_base_lambda_service_task_state[INFO]": 2.4313038240002243, - "tests/aws/services/stepfunctions/v2/test_state/test_test_state_scenarios.py::TestStateCaseScenarios::test_base_lambda_service_task_state[TRACE]": 3.63481498200008, - "tests/aws/services/stepfunctions/v2/test_state/test_test_state_scenarios.py::TestStateCaseScenarios::test_base_lambda_task_state[DEBUG]": 2.403900856999826, - "tests/aws/services/stepfunctions/v2/test_state/test_test_state_scenarios.py::TestStateCaseScenarios::test_base_lambda_task_state[INFO]": 2.40422769099996, - "tests/aws/services/stepfunctions/v2/test_state/test_test_state_scenarios.py::TestStateCaseScenarios::test_base_lambda_task_state[TRACE]": 2.4119036229999438, - "tests/aws/services/stepfunctions/v2/test_stepfunctions_v2.py::TestStateMachine::test_create_choice_state_machine": 2.746007924999958, - "tests/aws/services/stepfunctions/v2/test_stepfunctions_v2.py::TestStateMachine::test_create_run_map_state_machine": 1.2022042279998004, - "tests/aws/services/stepfunctions/v2/test_stepfunctions_v2.py::TestStateMachine::test_create_run_state_machine": 1.5926095690001603, - "tests/aws/services/stepfunctions/v2/test_stepfunctions_v2.py::TestStateMachine::test_create_state_machines_in_parallel": 1.8965862820002712, - "tests/aws/services/stepfunctions/v2/test_stepfunctions_v2.py::TestStateMachine::test_events_state_machine": 0.0017587660001936456, - "tests/aws/services/stepfunctions/v2/test_stepfunctions_v2.py::TestStateMachine::test_intrinsic_functions": 1.2507996840001852, - "tests/aws/services/stepfunctions/v2/test_stepfunctions_v2.py::TestStateMachine::test_try_catch_state_machine": 10.223142363000079, - "tests/aws/services/stepfunctions/v2/test_stepfunctions_v2.py::test_aws_sdk_task": 1.2067861089997223, - "tests/aws/services/stepfunctions/v2/test_stepfunctions_v2.py::test_default_logging_configuration": 0.07023639999988518, - "tests/aws/services/stepfunctions/v2/test_stepfunctions_v2.py::test_multiregion_nested[statemachine_definition0-eu-central-1]": 0.0016847550000420597, - "tests/aws/services/stepfunctions/v2/test_stepfunctions_v2.py::test_multiregion_nested[statemachine_definition0-eu-west-1]": 0.0018171840001741657, - "tests/aws/services/stepfunctions/v2/test_stepfunctions_v2.py::test_multiregion_nested[statemachine_definition0-us-east-1]": 0.0023082770001110475, - "tests/aws/services/stepfunctions/v2/test_stepfunctions_v2.py::test_multiregion_nested[statemachine_definition0-us-east-2]": 0.0018707859999267384, - "tests/aws/services/stepfunctions/v2/test_stepfunctions_v2.py::test_run_aws_sdk_secrets_manager": 3.372649372000069, - "tests/aws/services/stepfunctions/v2/timeouts/test_heartbeats.py::TestHeartbeats::test_heartbeat_no_timeout": 5.979815277999705, - "tests/aws/services/stepfunctions/v2/timeouts/test_heartbeats.py::TestHeartbeats::test_heartbeat_path_timeout": 6.205156815999771, - "tests/aws/services/stepfunctions/v2/timeouts/test_heartbeats.py::TestHeartbeats::test_heartbeat_timeout": 6.080503753999665, - "tests/aws/services/stepfunctions/v2/timeouts/test_timeouts.py::TestTimeouts::test_fixed_timeout_lambda": 6.882398013000056, - "tests/aws/services/stepfunctions/v2/timeouts/test_timeouts.py::TestTimeouts::test_fixed_timeout_service_lambda": 6.863181847000305, - "tests/aws/services/stepfunctions/v2/timeouts/test_timeouts.py::TestTimeouts::test_fixed_timeout_service_lambda_with_path": 7.04602010099984, - "tests/aws/services/stepfunctions/v2/timeouts/test_timeouts.py::TestTimeouts::test_global_timeout": 5.7850999799998135, - "tests/aws/services/stepfunctions/v2/timeouts/test_timeouts.py::TestTimeouts::test_service_lambda_map_timeout": 0.013617140999940602, - "tests/aws/services/sts/test_sts.py::TestSTSAssumeRoleTagging::test_assume_role_tag_validation": 0.17200373199989372, - "tests/aws/services/sts/test_sts.py::TestSTSAssumeRoleTagging::test_iam_role_chaining_override_transitive_tags": 0.22284225899988996, - "tests/aws/services/sts/test_sts.py::TestSTSIntegrations::test_assume_non_existent_role": 0.0159679270000197, - "tests/aws/services/sts/test_sts.py::TestSTSIntegrations::test_assume_role": 0.2577328239999588, - "tests/aws/services/sts/test_sts.py::TestSTSIntegrations::test_assume_role_with_saml": 0.016638936999925136, - "tests/aws/services/sts/test_sts.py::TestSTSIntegrations::test_assume_role_with_web_identity": 0.016354262999811908, - "tests/aws/services/sts/test_sts.py::TestSTSIntegrations::test_expiration_date_format": 0.012769000000162123, - "tests/aws/services/sts/test_sts.py::TestSTSIntegrations::test_get_caller_identity_role_access_key[False]": 0.0948868739997124, - "tests/aws/services/sts/test_sts.py::TestSTSIntegrations::test_get_caller_identity_role_access_key[True]": 0.09716478099994674, - "tests/aws/services/sts/test_sts.py::TestSTSIntegrations::test_get_caller_identity_root": 0.014967177000016818, - "tests/aws/services/sts/test_sts.py::TestSTSIntegrations::test_get_caller_identity_user_access_key[False]": 0.07402870300006725, - "tests/aws/services/sts/test_sts.py::TestSTSIntegrations::test_get_caller_identity_user_access_key[True]": 0.22009088899972085, - "tests/aws/services/sts/test_sts.py::TestSTSIntegrations::test_get_federation_token": 0.10057894200008377, - "tests/aws/services/sts/test_sts.py::TestSTSIntegrations::test_sts_invalid_parameters": 0.06598328800009767, - "tests/aws/services/support/test_support.py::TestConfigService::test_support_case_lifecycle": 0.07017940400010048, - "tests/aws/services/swf/test_swf.py::TestSwf::test_run_workflow": 0.19333217900020827, - "tests/aws/services/transcribe/test_transcribe.py::TestTranscribe::test_failing_deletion": 0.2224877619999006, - "tests/aws/services/transcribe/test_transcribe.py::TestTranscribe::test_failing_start_transcription_job": 0.3547704470001918, - "tests/aws/services/transcribe/test_transcribe.py::TestTranscribe::test_get_transcription_job": 2.505678846999899, - "tests/aws/services/transcribe/test_transcribe.py::TestTranscribe::test_list_transcription_jobs": 2.6001187649999338, - "tests/aws/services/transcribe/test_transcribe.py::TestTranscribe::test_transcribe_error_invalid_length": 33.82959738900013, - "tests/aws/services/transcribe/test_transcribe.py::TestTranscribe::test_transcribe_error_speaker_labels": 0.0018284550001226307, - "tests/aws/services/transcribe/test_transcribe.py::TestTranscribe::test_transcribe_happy_path": 5.743826325999862, - "tests/aws/services/transcribe/test_transcribe.py::TestTranscribe::test_transcribe_speaker_diarization": 0.001978947999987213, - "tests/aws/services/transcribe/test_transcribe.py::TestTranscribe::test_transcribe_start_job[None-None]": 2.364126481000085, - "tests/aws/services/transcribe/test_transcribe.py::TestTranscribe::test_transcribe_start_job[test-output-bucket-2-None]": 4.875826905999929, - "tests/aws/services/transcribe/test_transcribe.py::TestTranscribe::test_transcribe_start_job[test-output-bucket-3-test-output]": 2.434742079999978, - "tests/aws/services/transcribe/test_transcribe.py::TestTranscribe::test_transcribe_start_job[test-output-bucket-4-test-output.json]": 5.01166304000003, - "tests/aws/services/transcribe/test_transcribe.py::TestTranscribe::test_transcribe_start_job[test-output-bucket-5-test-files/test-output.json]": 4.923937976999923, - "tests/aws/services/transcribe/test_transcribe.py::TestTranscribe::test_transcribe_start_job[test-output-bucket-6-test-files/test-output]": 5.041204063000123, - "tests/aws/services/transcribe/test_transcribe.py::TestTranscribe::test_transcribe_start_job_same_name": 2.3000981349996437, - "tests/aws/services/transcribe/test_transcribe.py::TestTranscribe::test_transcribe_supported_media_formats[../../files/en-gb.amr-hello my name is]": 2.1498029070003213, - "tests/aws/services/transcribe/test_transcribe.py::TestTranscribe::test_transcribe_supported_media_formats[../../files/en-gb.flac-hello my name is]": 2.161026948000199, - "tests/aws/services/transcribe/test_transcribe.py::TestTranscribe::test_transcribe_supported_media_formats[../../files/en-gb.mp3-hello my name is]": 2.6656668889997945, - "tests/aws/services/transcribe/test_transcribe.py::TestTranscribe::test_transcribe_supported_media_formats[../../files/en-gb.mp4-hello my name is]": 2.149582750000036, - "tests/aws/services/transcribe/test_transcribe.py::TestTranscribe::test_transcribe_supported_media_formats[../../files/en-gb.ogg-hello my name is]": 2.1607256680001683, - "tests/aws/services/transcribe/test_transcribe.py::TestTranscribe::test_transcribe_supported_media_formats[../../files/en-gb.webm-hello my name is]": 2.2004391760001454, - "tests/aws/services/transcribe/test_transcribe.py::TestTranscribe::test_transcribe_supported_media_formats[../../files/en-us_video.mkv-one of the most vital]": 2.1828872999999476, - "tests/aws/services/transcribe/test_transcribe.py::TestTranscribe::test_transcribe_supported_media_formats[../../files/en-us_video.mp4-one of the most vital]": 2.1689076149998527, - "tests/aws/services/transcribe/test_transcribe.py::TestTranscribe::test_transcribe_unsupported_media_format_failure": 3.1822730469998532, - "tests/aws/test_error_injection.py::TestErrorInjection::test_dynamodb_error_injection": 25.73627931599981, - "tests/aws/test_error_injection.py::TestErrorInjection::test_dynamodb_read_error_injection": 25.72157277300016, - "tests/aws/test_error_injection.py::TestErrorInjection::test_dynamodb_write_error_injection": 51.36769465899988, - "tests/aws/test_error_injection.py::TestErrorInjection::test_kinesis_error_injection": 1.9875396530001126, - "tests/aws/test_integration.py::TestIntegration::test_firehose_extended_s3": 0.19942273200013005, - "tests/aws/test_integration.py::TestIntegration::test_firehose_kinesis_to_s3": 29.317069991000153, - "tests/aws/test_integration.py::TestIntegration::test_firehose_s3": 0.3644186750002518, - "tests/aws/test_integration.py::TestIntegration::test_lambda_streams_batch_and_transactions": 38.77845093500014, - "tests/aws/test_integration.py::TestIntegration::test_scheduled_lambda": 21.265727374000335, - "tests/aws/test_integration.py::TestLambdaOutgoingSdkCalls::test_lambda_put_item_to_dynamodb[python3.10]": 1.9354925630002526, - "tests/aws/test_integration.py::TestLambdaOutgoingSdkCalls::test_lambda_put_item_to_dynamodb[python3.11]": 1.845265918999985, - "tests/aws/test_integration.py::TestLambdaOutgoingSdkCalls::test_lambda_put_item_to_dynamodb[python3.12]": 1.907205273000045, - "tests/aws/test_integration.py::TestLambdaOutgoingSdkCalls::test_lambda_put_item_to_dynamodb[python3.13]": 1.9004043400000228, - "tests/aws/test_integration.py::TestLambdaOutgoingSdkCalls::test_lambda_put_item_to_dynamodb[python3.8]": 1.8779100689998813, - "tests/aws/test_integration.py::TestLambdaOutgoingSdkCalls::test_lambda_put_item_to_dynamodb[python3.9]": 1.879783677000205, - "tests/aws/test_integration.py::TestLambdaOutgoingSdkCalls::test_lambda_send_message_to_sqs[python3.10]": 7.832932153000002, - "tests/aws/test_integration.py::TestLambdaOutgoingSdkCalls::test_lambda_send_message_to_sqs[python3.11]": 7.842683968000074, - "tests/aws/test_integration.py::TestLambdaOutgoingSdkCalls::test_lambda_send_message_to_sqs[python3.12]": 1.7903260399998544, - "tests/aws/test_integration.py::TestLambdaOutgoingSdkCalls::test_lambda_send_message_to_sqs[python3.13]": 15.840038560999801, - "tests/aws/test_integration.py::TestLambdaOutgoingSdkCalls::test_lambda_send_message_to_sqs[python3.8]": 15.83787988600011, - "tests/aws/test_integration.py::TestLambdaOutgoingSdkCalls::test_lambda_send_message_to_sqs[python3.9]": 1.808880344000272, - "tests/aws/test_integration.py::TestLambdaOutgoingSdkCalls::test_lambda_start_stepfunctions_execution[python3.10]": 3.9497499940002854, - "tests/aws/test_integration.py::TestLambdaOutgoingSdkCalls::test_lambda_start_stepfunctions_execution[python3.11]": 3.9111201400000937, - "tests/aws/test_integration.py::TestLambdaOutgoingSdkCalls::test_lambda_start_stepfunctions_execution[python3.12]": 3.969492998000078, - "tests/aws/test_integration.py::TestLambdaOutgoingSdkCalls::test_lambda_start_stepfunctions_execution[python3.13]": 3.919767772000114, - "tests/aws/test_integration.py::TestLambdaOutgoingSdkCalls::test_lambda_start_stepfunctions_execution[python3.8]": 3.9055871569999, - "tests/aws/test_integration.py::TestLambdaOutgoingSdkCalls::test_lambda_start_stepfunctions_execution[python3.9]": 3.9486829499999203, - "tests/aws/test_integration.py::test_kinesis_lambda_forward_chain": 0.0022935880001568876, - "tests/aws/test_moto.py::test_call_include_response_metadata": 0.00773474100014937, - "tests/aws/test_moto.py::test_call_multi_region_backends": 0.018870426000148655, - "tests/aws/test_moto.py::test_call_non_implemented_operation": 0.04619014500008234, - "tests/aws/test_moto.py::test_call_s3_with_streaming_trait[IO[bytes]]": 0.02158672099994874, - "tests/aws/test_moto.py::test_call_s3_with_streaming_trait[bytes]": 0.024414928999931362, - "tests/aws/test_moto.py::test_call_s3_with_streaming_trait[str]": 0.05679193500009205, - "tests/aws/test_moto.py::test_call_sqs_invalid_call_raises_http_exception": 0.013475553000034779, - "tests/aws/test_moto.py::test_call_with_es_creates_state_correctly": 0.07558004700013043, - "tests/aws/test_moto.py::test_call_with_modified_request": 0.01109310499964522, - "tests/aws/test_moto.py::test_call_with_sns_with_full_uri": 0.005496982999829925, - "tests/aws/test_moto.py::test_call_with_sqs_creates_state_correctly": 4.069256727000038, - "tests/aws/test_moto.py::test_call_with_sqs_invalid_call_raises_exception": 0.007603874999858817, - "tests/aws/test_moto.py::test_call_with_sqs_modifies_state_in_moto_backend": 0.010129342000027464, - "tests/aws/test_moto.py::test_call_with_sqs_returns_service_response": 0.007244469999704961, - "tests/aws/test_moto.py::test_moto_fallback_dispatcher": 0.016081462999864016, - "tests/aws/test_moto.py::test_moto_fallback_dispatcher_error_handling": 0.03662133599982553, - "tests/aws/test_moto.py::test_request_with_response_header_location_fields": 0.10947979699994903, - "tests/aws/test_multi_accounts.py::TestMultiAccounts::test_account_id_namespacing_for_localstack_backends": 0.1675915549999445, - "tests/aws/test_multi_accounts.py::TestMultiAccounts::test_account_id_namespacing_for_moto_backends": 1.6200137989999348, - "tests/aws/test_multi_accounts.py::TestMultiAccounts::test_multi_accounts_dynamodb": 0.3183115390002058, - "tests/aws/test_multi_accounts.py::TestMultiAccounts::test_multi_accounts_kinesis": 1.442821757000047, - "tests/aws/test_multiregion.py::TestMultiRegion::test_multi_region_api_gateway": 0.47113804099990375, - "tests/aws/test_multiregion.py::TestMultiRegion::test_multi_region_sns": 0.07742174999998497, - "tests/aws/test_network_configuration.py::TestLambda::test_function_url": 1.1530643439998585, - "tests/aws/test_network_configuration.py::TestLambda::test_http_api_for_function_url": 0.0017585140001301625, - "tests/aws/test_network_configuration.py::TestOpenSearch::test_default_strategy": 10.787745600000108, - "tests/aws/test_network_configuration.py::TestOpenSearch::test_path_strategy": 10.568777215000182, - "tests/aws/test_network_configuration.py::TestOpenSearch::test_port_strategy": 10.450559125999916, - "tests/aws/test_network_configuration.py::TestS3::test_201_response": 0.08312962800005153, - "tests/aws/test_network_configuration.py::TestS3::test_multipart_upload": 0.09692923099987638, - "tests/aws/test_network_configuration.py::TestS3::test_non_us_east_1_location": 0.0647773480000069, - "tests/aws/test_network_configuration.py::TestSQS::test_domain_based_strategies[domain]": 0.026799158000130774, - "tests/aws/test_network_configuration.py::TestSQS::test_domain_based_strategies[standard]": 0.02089506400011487, - "tests/aws/test_network_configuration.py::TestSQS::test_off_strategy_with_external_port": 0.021500440999716375, - "tests/aws/test_network_configuration.py::TestSQS::test_off_strategy_without_external_port": 0.023045820999868738, - "tests/aws/test_network_configuration.py::TestSQS::test_path_strategy": 0.021057657999790536, - "tests/aws/test_notifications.py::TestNotifications::test_sns_to_sqs": 0.15289965800002392, - "tests/aws/test_notifications.py::TestNotifications::test_sqs_queue_names": 0.021350830000073984, - "tests/aws/test_serverless.py::TestServerless::test_apigateway_deployed": 0.03922961800003577, - "tests/aws/test_serverless.py::TestServerless::test_dynamodb_stream_handler_deployed": 0.04738897799984443, - "tests/aws/test_serverless.py::TestServerless::test_event_rules_deployed": 101.49392449700008, - "tests/aws/test_serverless.py::TestServerless::test_kinesis_stream_handler_deployed": 0.0017196230000990909, - "tests/aws/test_serverless.py::TestServerless::test_lambda_with_configs_deployed": 0.02240639699971325, - "tests/aws/test_serverless.py::TestServerless::test_queue_handler_deployed": 0.045775997999726314, - "tests/aws/test_serverless.py::TestServerless::test_s3_bucket_deployed": 25.25264016899996, - "tests/aws/test_terraform.py::TestTerraform::test_acm": 0.0016936550000536954, - "tests/aws/test_terraform.py::TestTerraform::test_apigateway": 0.0016561649999857764, - "tests/aws/test_terraform.py::TestTerraform::test_apigateway_escaped_policy": 0.0016748109997024585, - "tests/aws/test_terraform.py::TestTerraform::test_bucket_exists": 0.004947396000034132, - "tests/aws/test_terraform.py::TestTerraform::test_dynamodb": 0.0016847389999838924, - "tests/aws/test_terraform.py::TestTerraform::test_event_source_mapping": 0.0016680959997756872, - "tests/aws/test_terraform.py::TestTerraform::test_lambda": 0.0016846390001319378, - "tests/aws/test_terraform.py::TestTerraform::test_route53": 0.0017090539997752785, - "tests/aws/test_terraform.py::TestTerraform::test_security_groups": 0.0018684439999105962, - "tests/aws/test_terraform.py::TestTerraform::test_sqs": 0.0016620359999706125, - "tests/aws/test_validate.py::TestMissingParameter::test_elasticache": 0.001669170000241138, - "tests/aws/test_validate.py::TestMissingParameter::test_opensearch": 0.001637419000189766, - "tests/aws/test_validate.py::TestMissingParameter::test_sns": 0.0017006179998588777, - "tests/aws/test_validate.py::TestMissingParameter::test_sqs_create_queue": 0.002135275000000547, - "tests/aws/test_validate.py::TestMissingParameter::test_sqs_send_message": 0.0026249370000641647, - "tests/cli/test_cli.py::TestCliContainerLifecycle::test_container_starts_non_root": 0.001682743999936065, - "tests/cli/test_cli.py::TestCliContainerLifecycle::test_custom_docker_flags": 0.0017804090000481665, - "tests/cli/test_cli.py::TestCliContainerLifecycle::test_logs": 0.0016466970000692527, - "tests/cli/test_cli.py::TestCliContainerLifecycle::test_pulling_image_message": 0.0016621350000605162, - "tests/cli/test_cli.py::TestCliContainerLifecycle::test_restart": 0.0016358359998775995, - "tests/cli/test_cli.py::TestCliContainerLifecycle::test_start_already_running": 0.0016510349998952734, - "tests/cli/test_cli.py::TestCliContainerLifecycle::test_start_cli_within_container": 0.0016707419999875128, - "tests/cli/test_cli.py::TestCliContainerLifecycle::test_start_wait_stop": 0.003806418000067424, - "tests/cli/test_cli.py::TestCliContainerLifecycle::test_status_services": 0.003140747000088595, - "tests/cli/test_cli.py::TestCliContainerLifecycle::test_volume_dir_mounted_correctly": 0.0017281000000366475, - "tests/cli/test_cli.py::TestCliContainerLifecycle::test_wait_timeout_raises_exception": 0.001661844999944151, - "tests/cli/test_cli.py::TestDNSServer::test_dns_port_not_published_by_default": 0.0026389029997062607, - "tests/cli/test_cli.py::TestDNSServer::test_dns_port_published_with_flag": 0.0016688680002516776, - "tests/cli/test_cli.py::TestHooks::test_prepare_host_hook_called_with_correct_dirs": 0.561031928000375, - "tests/cli/test_cli.py::TestImports::test_import_venv": 0.006514511999966999, - "tests/integration/aws/test_app.py::TestExceptionHandlers::test_404_unfortunately_detected_as_s3_request": 0.03486860299994987, - "tests/integration/aws/test_app.py::TestExceptionHandlers::test_internal_failure_handler_http_errors": 0.01842189699982555, - "tests/integration/aws/test_app.py::TestExceptionHandlers::test_router_handler_get_http_errors": 0.0017513730001610384, - "tests/integration/aws/test_app.py::TestExceptionHandlers::test_router_handler_get_unexpected_errors": 0.001851602999977331, - "tests/integration/aws/test_app.py::TestExceptionHandlers::test_router_handler_patch_http_errors": 0.11723553899992112, - "tests/integration/aws/test_app.py::TestHTTP2Support::test_http2_http": 0.09203284699970027, - "tests/integration/aws/test_app.py::TestHTTP2Support::test_http2_https": 0.09654304800005775, - "tests/integration/aws/test_app.py::TestHTTP2Support::test_http2_https_localhost": 0.06060117600009107, - "tests/integration/aws/test_app.py::TestHttps::test_default_cert_works": 0.08900233499980459, - "tests/integration/aws/test_app.py::TestWebSocketIntegration::test_return_response": 0.0016491910000695498, - "tests/integration/aws/test_app.py::TestWebSocketIntegration::test_ssl_websockets": 0.0017172599998502847, - "tests/integration/aws/test_app.py::TestWebSocketIntegration::test_websocket_reject_through_edge_router": 0.001692432000027111, - "tests/integration/aws/test_app.py::TestWebSocketIntegration::test_websockets_served_through_edge_router": 0.0017790960000638734, - "tests/integration/aws/test_app.py::TestWerkzeugIntegration::test_chunked_request_streaming": 0.10957294100012405, - "tests/integration/aws/test_app.py::TestWerkzeugIntegration::test_chunked_response_streaming": 0.13529009400008363, - "tests/integration/aws/test_app.py::TestWerkzeugIntegration::test_raw_header_handling": 0.11216934600020068, - "tests/integration/aws/test_app.py::TestWerkzeugIntegration::test_response_close_handlers_called_with_router": 0.10540180400016652, - "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_build_image[CmdDockerClient-False-False]": 0.0018907369999396906, - "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_build_image[CmdDockerClient-False-True]": 0.003432191999991119, - "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_build_image[CmdDockerClient-True-False]": 0.0018329070001072978, - "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_build_image[CmdDockerClient-True-True]": 0.001876628999980312, - "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_build_image[SdkDockerClient-False-False]": 3.0025729499996032, - "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_build_image[SdkDockerClient-False-True]": 2.998004886999979, - "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_build_image[SdkDockerClient-True-False]": 2.9986524549997284, - "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_build_image[SdkDockerClient-True-True]": 2.39176013600013, - "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_container_lifecycle_commands[CmdDockerClient]": 0.001841943000044921, - "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_container_lifecycle_commands[SdkDockerClient]": 21.7543395900002, - "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_copy_directory_content_into_container[CmdDockerClient]": 0.0019807549999768526, - "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_copy_directory_content_into_container[SdkDockerClient]": 0.28634493200002, - "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_copy_directory_into_container[CmdDockerClient]": 0.001887609000050361, - "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_copy_directory_into_container[SdkDockerClient]": 0.19659978200002115, - "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_copy_directory_structure_into_container[CmdDockerClient]": 0.0020098100001177954, - "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_copy_directory_structure_into_container[SdkDockerClient]": 0.25695561600014116, - "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_copy_from_container[CmdDockerClient]": 0.0036603329999707057, - "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_copy_from_container[SdkDockerClient]": 0.2449425329996302, - "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_copy_from_container_into_directory[CmdDockerClient]": 0.0019598369999584975, - "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_copy_from_container_into_directory[SdkDockerClient]": 0.2356086229997345, - "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_copy_from_container_to_different_file[CmdDockerClient]": 0.0019507590000102937, - "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_copy_from_container_to_different_file[SdkDockerClient]": 0.2750249810001151, - "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_copy_from_non_existent_container[CmdDockerClient]": 0.0018776620001972333, - "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_copy_from_non_existent_container[SdkDockerClient]": 0.008594453000569047, - "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_copy_into_container[CmdDockerClient]": 0.0037159979999614734, - "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_copy_into_container[SdkDockerClient]": 0.19646144200009985, - "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_copy_into_container_with_existing_target[CmdDockerClient]": 0.0018630829997619003, - "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_copy_into_container_with_existing_target[SdkDockerClient]": 0.31593800699988606, - "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_copy_into_container_without_target_filename[CmdDockerClient]": 0.0018992929999512853, - "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_copy_into_container_without_target_filename[SdkDockerClient]": 0.1929504330000782, - "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_copy_into_non_existent_container[CmdDockerClient]": 0.0018448089999765216, - "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_copy_into_non_existent_container[SdkDockerClient]": 0.00782935800020823, - "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_create_container_non_existing_image[CmdDockerClient]": 0.0019595450000906567, - "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_create_container_non_existing_image[SdkDockerClient]": 0.39209873799995876, - "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_create_container_remove_removes_container[CmdDockerClient]": 0.001975825999807057, - "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_create_container_remove_removes_container[SdkDockerClient]": 1.1839495090000582, - "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_create_container_with_init[CmdDockerClient]": 0.0018061979999401956, - "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_create_container_with_init[SdkDockerClient]": 0.02444257800016203, - "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_create_container_with_max_env_vars[CmdDockerClient]": 0.0018023690001882642, - "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_create_container_with_max_env_vars[SdkDockerClient]": 0.20775628799970036, - "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_create_file_in_container[CmdDockerClient]": 0.0018960360000619403, - "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_create_file_in_container[SdkDockerClient]": 0.21266746500009504, - "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_create_start_container_with_stdin_to_file[CmdDockerClient-False]": 0.0018603490002533363, - "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_create_start_container_with_stdin_to_file[CmdDockerClient-True]": 0.0018390289999388187, - "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_create_start_container_with_stdin_to_file[SdkDockerClient-False]": 0.19050280199985536, - "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_create_start_container_with_stdin_to_file[SdkDockerClient-True]": 0.19039050200012753, - "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_create_start_container_with_stdin_to_stdout[CmdDockerClient-False]": 0.0017948760000763286, - "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_create_start_container_with_stdin_to_stdout[CmdDockerClient-True]": 0.001814973000136888, - "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_create_start_container_with_stdin_to_stdout[SdkDockerClient-False]": 0.17688418500006264, - "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_create_start_container_with_stdin_to_stdout[SdkDockerClient-True]": 0.18367180400036887, - "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_create_with_exposed_ports[CmdDockerClient]": 0.0018222460000743013, - "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_create_with_exposed_ports[SdkDockerClient]": 0.0045089179998285545, - "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_create_with_host_network[CmdDockerClient]": 0.0034513709997554542, - "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_create_with_host_network[SdkDockerClient]": 0.026210579999997208, - "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_create_with_port_mapping[CmdDockerClient]": 0.0018637749999470543, - "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_create_with_port_mapping[SdkDockerClient]": 0.025427523000189467, - "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_create_with_volume[CmdDockerClient]": 0.001692953000201669, - "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_create_with_volume[SdkDockerClient]": 0.001805309000019406, - "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_docker_image_names[CmdDockerClient]": 0.0019508000000314496, - "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_docker_image_names[SdkDockerClient]": 1.0397348119995513, - "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_docker_not_available[CmdDockerClient]": 0.006732510999881924, - "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_docker_not_available[SdkDockerClient]": 0.005980066000120132, - "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_exec_error_in_container[CmdDockerClient]": 0.001844350000283157, - "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_exec_error_in_container[SdkDockerClient]": 0.24787273799984177, - "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_exec_in_container[CmdDockerClient]": 0.0018153239998355275, - "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_exec_in_container[SdkDockerClient]": 0.2397898469998836, - "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_exec_in_container_not_running_raises_exception[CmdDockerClient]": 0.0018199819999153988, - "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_exec_in_container_not_running_raises_exception[SdkDockerClient]": 0.02919394699983968, - "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_exec_in_container_with_env[CmdDockerClient]": 0.0034903240000403457, - "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_exec_in_container_with_env[SdkDockerClient]": 0.2329532610001479, - "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_exec_in_container_with_env_deletion[CmdDockerClient]": 0.001854287000014665, - "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_exec_in_container_with_env_deletion[SdkDockerClient]": 0.2646545310001329, - "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_exec_in_container_with_stdin[CmdDockerClient]": 0.003413219999856665, - "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_exec_in_container_with_stdin[SdkDockerClient]": 0.25070386199990935, - "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_exec_in_container_with_stdin_stdout_stderr[CmdDockerClient]": 0.0018058859998291155, - "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_exec_in_container_with_stdin_stdout_stderr[SdkDockerClient]": 0.22933067899998605, - "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_exec_in_container_with_workdir[CmdDockerClient]": 0.0018672209998840117, - "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_exec_in_container_with_workdir[SdkDockerClient]": 0.23115679099987574, - "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_get_all_container_names_should_include_even_stopped_containers[CmdDockerClient]": 0.0018619019997458963, - "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_get_all_container_names_should_include_even_stopped_containers[SdkDockerClient]": 0.3964399730000423, - "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_get_container_command[CmdDockerClient]": 0.0019425030002366839, - "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_get_container_command[SdkDockerClient]": 0.0058856849998392136, - "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_get_container_command_non_existing_image[CmdDockerClient]": 0.0019120260001272982, - "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_get_container_command_non_existing_image[SdkDockerClient]": 0.3634315770000285, - "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_get_container_command_not_pulled_image[CmdDockerClient]": 0.001914910999857966, - "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_get_container_command_not_pulled_image[SdkDockerClient]": 1.0492240630001106, - "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_get_container_entrypoint[CmdDockerClient]": 0.001997607000021162, - "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_get_container_entrypoint[SdkDockerClient]": 0.007400682000024972, - "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_get_container_entrypoint_non_existing_image[CmdDockerClient]": 0.0019157530000484257, - "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_get_container_entrypoint_non_existing_image[SdkDockerClient]": 0.40128003199993145, - "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_get_container_entrypoint_not_pulled_image[CmdDockerClient]": 0.0019163639999533189, - "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_get_container_entrypoint_not_pulled_image[SdkDockerClient]": 1.0072322700000313, - "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_get_container_id[CmdDockerClient]": 0.0019344889999501902, - "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_get_container_id[SdkDockerClient]": 0.18694931600020936, - "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_get_container_id_not_existing[CmdDockerClient]": 0.003463139999894338, - "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_get_container_id_not_existing[SdkDockerClient]": 0.0069276259996513545, - "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_get_container_ip[CmdDockerClient]": 0.004311364000159301, - "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_get_container_ip[SdkDockerClient]": 0.19218424899963793, - "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_get_container_ip_for_host_network[CmdDockerClient]": 0.0019155719996888365, - "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_get_container_ip_for_host_network[SdkDockerClient]": 0.03546328500033269, - "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_get_container_ip_for_network[CmdDockerClient]": 0.0019436050001786498, - "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_get_container_ip_for_network[SdkDockerClient]": 0.4336426429999847, - "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_get_container_ip_for_network_non_existent_network[CmdDockerClient]": 0.0018439980001403455, - "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_get_container_ip_for_network_non_existent_network[SdkDockerClient]": 0.19338688700008788, - "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_get_container_ip_for_network_wrong_network[CmdDockerClient]": 0.001964383999847996, - "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_get_container_ip_for_network_wrong_network[SdkDockerClient]": 0.35800931299991134, - "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_get_container_ip_non_existing_container[CmdDockerClient]": 0.001865208000253915, - "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_get_container_ip_non_existing_container[SdkDockerClient]": 0.006048121999810974, - "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_get_container_name[CmdDockerClient]": 0.0019101539999155648, - "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_get_container_name[SdkDockerClient]": 0.19664995499988436, - "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_get_container_name_not_existing[CmdDockerClient]": 0.0019036099999993894, - "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_get_container_name_not_existing[SdkDockerClient]": 0.0071747520000826626, - "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_get_logs[CmdDockerClient]": 0.0019497459998092381, - "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_get_logs[SdkDockerClient]": 0.1751782799999546, - "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_get_logs_non_existent_container[CmdDockerClient]": 0.0018219860000954213, - "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_get_logs_non_existent_container[SdkDockerClient]": 0.007083109999939552, - "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_get_network[CmdDockerClient]": 0.0017886239998006204, - "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_get_network[SdkDockerClient]": 0.02927024599989636, - "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_get_network_multiple_networks[CmdDockerClient]": 0.001902117000099679, - "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_get_network_multiple_networks[SdkDockerClient]": 0.44305470900008004, - "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_get_network_non_existing_container[CmdDockerClient]": 0.0018044640000880463, - "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_get_network_non_existing_container[SdkDockerClient]": 0.006504183000060948, - "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_get_running_container_names_should_ignore_stopped_containers[CmdDockerClient]": 0.0018299920000117709, - "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_get_running_container_names_should_ignore_stopped_containers[SdkDockerClient]": 0.39478177300020434, - "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_get_system_id[CmdDockerClient]": 0.0018012170000929473, - "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_get_system_id[SdkDockerClient]": 0.02122631100041872, - "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_get_system_info[CmdDockerClient]": 0.0036586909998277406, - "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_get_system_info[SdkDockerClient]": 0.021708249999846885, - "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_inspect_container[CmdDockerClient]": 0.0019068060000790865, - "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_inspect_container[SdkDockerClient]": 0.1878730479998012, - "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_inspect_container_volumes[CmdDockerClient]": 0.0017160970000986708, - "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_inspect_container_volumes[SdkDockerClient]": 0.0018262980001964024, - "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_inspect_container_volumes_with_no_volumes[CmdDockerClient]": 0.0019096109999736655, - "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_inspect_container_volumes_with_no_volumes[SdkDockerClient]": 0.18758480200017402, - "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_inspect_image[CmdDockerClient]": 0.0018467440002041258, - "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_inspect_image[SdkDockerClient]": 0.03227794000031281, - "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_inspect_network[CmdDockerClient]": 0.0019149719998949877, - "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_inspect_network[SdkDockerClient]": 0.15711732899990238, - "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_inspect_network_non_existent_network[CmdDockerClient]": 0.0019214750002447545, - "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_inspect_network_non_existent_network[SdkDockerClient]": 0.007160813999689708, - "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_is_container_running[CmdDockerClient]": 0.0034024950000457466, - "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_is_container_running[SdkDockerClient]": 20.38816804699991, - "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_list_containers[CmdDockerClient]": 0.001819461999957639, - "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_list_containers[SdkDockerClient]": 0.07847281500016834, - "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_list_containers_filter[CmdDockerClient]": 0.001959534000206986, - "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_list_containers_filter[SdkDockerClient]": 0.07592941700022493, - "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_list_containers_filter_illegal_filter[CmdDockerClient]": 0.0018196309999893856, - "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_list_containers_filter_illegal_filter[SdkDockerClient]": 0.006063343999812787, - "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_list_containers_filter_non_existing[CmdDockerClient]": 0.0018799150000177178, - "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_list_containers_filter_non_existing[SdkDockerClient]": 0.006614680000211592, - "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_list_containers_with_podman_image_ref_format[CmdDockerClient]": 0.0019589850001011655, - "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_list_containers_with_podman_image_ref_format[SdkDockerClient]": 0.2417650769998545, - "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_pause_non_existing_container[CmdDockerClient]": 0.0018683540001802612, - "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_pause_non_existing_container[SdkDockerClient]": 0.005609638000123596, - "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_pull_docker_image[CmdDockerClient]": 0.001862683999888759, - "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_pull_docker_image[SdkDockerClient]": 1.0259307540000009, - "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_pull_docker_image_with_hash[CmdDockerClient]": 0.0034434149999924557, - "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_pull_docker_image_with_hash[SdkDockerClient]": 0.7713214140001128, - "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_pull_docker_image_with_log_handler[CmdDockerClient]": 0.001867102000005616, - "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_pull_docker_image_with_log_handler[SdkDockerClient]": 1.191311427999608, - "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_pull_docker_image_with_tag[CmdDockerClient]": 0.0019432550000146875, - "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_pull_docker_image_with_tag[SdkDockerClient]": 0.9745696099998895, - "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_pull_non_existent_docker_image[CmdDockerClient]": 0.001954004000253917, - "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_pull_non_existent_docker_image[SdkDockerClient]": 0.33080683100001806, - "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_push_access_denied[CmdDockerClient]": 0.0018237100000533246, - "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_push_access_denied[SdkDockerClient]": 1.5648311530001138, - "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_push_invalid_registry[CmdDockerClient]": 0.0034765759999118018, - "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_push_invalid_registry[SdkDockerClient]": 0.0151932730000226, - "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_push_non_existent_docker_image[CmdDockerClient]": 0.0018180889999257488, - "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_push_non_existent_docker_image[SdkDockerClient]": 0.006710667999868747, - "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_remove_anonymous_volumes[CmdDockerClient]": 0.0018359620000865107, - "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_remove_anonymous_volumes[SdkDockerClient]": 3.9995173160000377, - "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_remove_container_should_throw_exception_when_container_doesnt_exist_and_not_forcing[CmdDockerClient]": 0.0035904229998777737, - "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_remove_container_should_throw_exception_when_container_doesnt_exist_and_not_forcing[SdkDockerClient]": 0.006189019000203189, - "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_remove_container_should_work_even_when_container_doesnt_exist_because_of_forcing[CmdDockerClient]": 0.0019848629999614786, - "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_remove_container_should_work_even_when_container_doesnt_exist_because_of_forcing[SdkDockerClient]": 0.005604519000144137, - "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_remove_container_should_work_when_container_is_running_and_checking_container_existence[CmdDockerClient]": 0.0019741620001241245, - "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_remove_container_should_work_when_container_is_running_and_checking_container_existence[SdkDockerClient]": 0.20887429699996574, - "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_remove_container_should_work_when_container_is_stopped_and_checking_container_existence[CmdDockerClient]": 0.0019919150001896924, - "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_remove_container_should_work_when_container_is_stopped_and_checking_container_existence[SdkDockerClient]": 0.03834988900030112, - "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_remove_non_existing_container[CmdDockerClient]": 0.004743531000030998, - "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_remove_non_existing_container[SdkDockerClient]": 0.005501985000137211, - "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_restart_non_existing_container[CmdDockerClient]": 0.0019841010000618553, - "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_restart_non_existing_container[SdkDockerClient]": 0.005536281999866333, - "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_run_container[CmdDockerClient]": 0.001827466000122513, - "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_run_container[SdkDockerClient]": 0.18278778300009435, - "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_run_container_automatic_pull[CmdDockerClient]": 0.0018568029997823032, - "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_run_container_automatic_pull[SdkDockerClient]": 1.1960610769999676, - "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_run_container_error[CmdDockerClient]": 0.0035532720000901463, - "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_run_container_error[SdkDockerClient]": 0.11389222799994059, - "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_run_container_non_existent_image[CmdDockerClient]": 0.0019473440002002462, - "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_run_container_non_existent_image[SdkDockerClient]": 0.41870576000019355, - "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_run_container_with_init[CmdDockerClient]": 0.001823899000100937, - "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_run_container_with_init[SdkDockerClient]": 0.1840458919998582, - "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_run_container_with_stdin[CmdDockerClient]": 0.0018250519999583048, - "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_run_container_with_stdin[SdkDockerClient]": 0.1863204350001979, - "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_run_detached_with_logs[CmdDockerClient]": 0.001825243999974191, - "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_run_detached_with_logs[SdkDockerClient]": 0.19206718999998884, - "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_running_container_names[CmdDockerClient]": 0.0018588960001579835, - "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_running_container_names[SdkDockerClient]": 13.247916171000043, - "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_set_container_entrypoint[CmdDockerClient-echo]": 0.001957310000079815, - "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_set_container_entrypoint[CmdDockerClient-entrypoint1]": 0.0019530419999682636, - "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_set_container_entrypoint[SdkDockerClient-echo]": 0.18090288299981694, - "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_set_container_entrypoint[SdkDockerClient-entrypoint1]": 0.18462804299997515, - "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_start_non_existing_container[CmdDockerClient]": 0.0018251829997097957, - "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_start_non_existing_container[SdkDockerClient]": 0.0055681220001133624, - "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_stop_non_existing_container[CmdDockerClient]": 0.0019321439999657741, - "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_stop_non_existing_container[SdkDockerClient]": 0.006305047000296327, - "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_stream_logs[CmdDockerClient]": 0.0018295800000487361, - "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_stream_logs[SdkDockerClient]": 0.17235441900015758, - "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_stream_logs_non_existent_container[CmdDockerClient]": 0.0035851319998982945, - "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_stream_logs_non_existent_container[SdkDockerClient]": 0.005851541000083671, - "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_tag_image[CmdDockerClient]": 0.001900154999930237, - "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_tag_image[SdkDockerClient]": 0.14691330200025732, - "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_tag_non_existing_image[CmdDockerClient]": 0.0018289990000539547, - "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_tag_non_existing_image[SdkDockerClient]": 0.006161852000104773, - "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_unpause_non_existing_container[CmdDockerClient]": 0.002031018999787193, - "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_unpause_non_existing_container[SdkDockerClient]": 0.005611693999981071, - "tests/integration/docker_utils/test_docker.py::TestDockerImages::test_commit_creates_image_from_running_container[CmdDockerClient]": 0.00329361100011738, - "tests/integration/docker_utils/test_docker.py::TestDockerImages::test_commit_creates_image_from_running_container[SdkDockerClient]": 1.0838862909995441, - "tests/integration/docker_utils/test_docker.py::TestDockerImages::test_commit_image_raises_for_nonexistent_container[CmdDockerClient]": 0.0020097330002499803, - "tests/integration/docker_utils/test_docker.py::TestDockerImages::test_commit_image_raises_for_nonexistent_container[SdkDockerClient]": 0.006058896000467939, - "tests/integration/docker_utils/test_docker.py::TestDockerImages::test_remove_image_raises_for_nonexistent_image[CmdDockerClient]": 0.0019544399997357687, - "tests/integration/docker_utils/test_docker.py::TestDockerImages::test_remove_image_raises_for_nonexistent_image[SdkDockerClient]": 0.006238433999897097, - "tests/integration/docker_utils/test_docker.py::TestDockerLabels::test_create_container_with_labels[CmdDockerClient]": 0.0033903569997164595, - "tests/integration/docker_utils/test_docker.py::TestDockerLabels::test_create_container_with_labels[SdkDockerClient]": 0.041286813000169786, - "tests/integration/docker_utils/test_docker.py::TestDockerLabels::test_get_container_stats[CmdDockerClient]": 0.001864227000169194, - "tests/integration/docker_utils/test_docker.py::TestDockerLabels::test_get_container_stats[SdkDockerClient]": 1.207755213999917, - "tests/integration/docker_utils/test_docker.py::TestDockerLabels::test_list_containers_with_labels[CmdDockerClient]": 0.0019621300002654607, - "tests/integration/docker_utils/test_docker.py::TestDockerLabels::test_list_containers_with_labels[SdkDockerClient]": 0.19751195500020913, - "tests/integration/docker_utils/test_docker.py::TestDockerLabels::test_run_container_with_labels[CmdDockerClient]": 0.001848506999976962, - "tests/integration/docker_utils/test_docker.py::TestDockerLabels::test_run_container_with_labels[SdkDockerClient]": 0.18387068299944076, - "tests/integration/docker_utils/test_docker.py::TestDockerLogging::test_docker_logging_fluentbit[CmdDockerClient]": 0.0019358229997124, - "tests/integration/docker_utils/test_docker.py::TestDockerLogging::test_docker_logging_fluentbit[SdkDockerClient]": 3.6858822449999025, - "tests/integration/docker_utils/test_docker.py::TestDockerLogging::test_docker_logging_none_disables_logs[CmdDockerClient]": 0.0033373530004610075, - "tests/integration/docker_utils/test_docker.py::TestDockerLogging::test_docker_logging_none_disables_logs[SdkDockerClient]": 0.20142116600027293, - "tests/integration/docker_utils/test_docker.py::TestDockerNetworking::test_connect_container_to_network[CmdDockerClient]": 0.0019400220003262802, - "tests/integration/docker_utils/test_docker.py::TestDockerNetworking::test_connect_container_to_network[SdkDockerClient]": 0.40952345800042167, - "tests/integration/docker_utils/test_docker.py::TestDockerNetworking::test_connect_container_to_network_with_alias_and_disconnect[CmdDockerClient]": 0.0018460649998814915, - "tests/integration/docker_utils/test_docker.py::TestDockerNetworking::test_connect_container_to_network_with_alias_and_disconnect[SdkDockerClient]": 0.7773572860005515, - "tests/integration/docker_utils/test_docker.py::TestDockerNetworking::test_connect_container_to_network_with_link_local_address[CmdDockerClient]": 0.0019620940001914278, - "tests/integration/docker_utils/test_docker.py::TestDockerNetworking::test_connect_container_to_network_with_link_local_address[SdkDockerClient]": 0.177972716000113, - "tests/integration/docker_utils/test_docker.py::TestDockerNetworking::test_connect_container_to_nonexistent_network[CmdDockerClient]": 0.0021626419998028723, - "tests/integration/docker_utils/test_docker.py::TestDockerNetworking::test_connect_container_to_nonexistent_network[SdkDockerClient]": 0.1818538890001946, - "tests/integration/docker_utils/test_docker.py::TestDockerNetworking::test_connect_nonexistent_container_to_network[CmdDockerClient]": 0.0018375290001131361, - "tests/integration/docker_utils/test_docker.py::TestDockerNetworking::test_connect_nonexistent_container_to_network[SdkDockerClient]": 0.18356062899965764, - "tests/integration/docker_utils/test_docker.py::TestDockerNetworking::test_disconnect_container_from_nonexistent_network[CmdDockerClient]": 0.0018404550000923336, - "tests/integration/docker_utils/test_docker.py::TestDockerNetworking::test_disconnect_container_from_nonexistent_network[SdkDockerClient]": 0.1817452089994731, - "tests/integration/docker_utils/test_docker.py::TestDockerNetworking::test_disconnect_nonexistent_container_from_network[CmdDockerClient]": 0.004560656000194285, - "tests/integration/docker_utils/test_docker.py::TestDockerNetworking::test_disconnect_nonexistent_container_from_network[SdkDockerClient]": 0.17011205600010726, - "tests/integration/docker_utils/test_docker.py::TestDockerNetworking::test_docker_sdk_no_retries": 0.0592845779997333, - "tests/integration/docker_utils/test_docker.py::TestDockerNetworking::test_docker_sdk_retries_after_init": 1.1239115560001665, - "tests/integration/docker_utils/test_docker.py::TestDockerNetworking::test_docker_sdk_retries_on_init": 1.0416192700004103, - "tests/integration/docker_utils/test_docker.py::TestDockerNetworking::test_docker_sdk_timeout_seconds": 0.01916970999991463, - "tests/integration/docker_utils/test_docker.py::TestDockerNetworking::test_get_container_ip_with_network[CmdDockerClient]": 0.0019204550003451004, - "tests/integration/docker_utils/test_docker.py::TestDockerNetworking::test_get_container_ip_with_network[SdkDockerClient]": 0.33816589299931366, - "tests/integration/docker_utils/test_docker.py::TestDockerNetworking::test_network_lifecycle[CmdDockerClient]": 0.00320677700028682, - "tests/integration/docker_utils/test_docker.py::TestDockerNetworking::test_network_lifecycle[SdkDockerClient]": 0.16566963499963094, - "tests/integration/docker_utils/test_docker.py::TestDockerNetworking::test_set_container_workdir[CmdDockerClient]": 0.0018556639997768798, - "tests/integration/docker_utils/test_docker.py::TestDockerNetworking::test_set_container_workdir[SdkDockerClient]": 0.20524270300029457, - "tests/integration/docker_utils/test_docker.py::TestDockerPermissions::test_container_with_cap_add[CmdDockerClient]": 0.003435243999774684, - "tests/integration/docker_utils/test_docker.py::TestDockerPermissions::test_container_with_cap_add[SdkDockerClient]": 0.40678809099927093, - "tests/integration/docker_utils/test_docker.py::TestDockerPermissions::test_container_with_cap_drop[CmdDockerClient]": 0.0018439599998600897, - "tests/integration/docker_utils/test_docker.py::TestDockerPermissions::test_container_with_cap_drop[SdkDockerClient]": 0.3580145249998168, - "tests/integration/docker_utils/test_docker.py::TestDockerPermissions::test_container_with_sec_opt[CmdDockerClient]": 0.00187799500008623, - "tests/integration/docker_utils/test_docker.py::TestDockerPermissions::test_container_with_sec_opt[SdkDockerClient]": 0.0298093880005581, - "tests/integration/docker_utils/test_docker.py::TestDockerPorts::test_container_port_can_be_bound[CmdDockerClient-None]": 0.0018619249999574095, - "tests/integration/docker_utils/test_docker.py::TestDockerPorts::test_container_port_can_be_bound[CmdDockerClient-tcp]": 0.002041702000042278, - "tests/integration/docker_utils/test_docker.py::TestDockerPorts::test_container_port_can_be_bound[CmdDockerClient-udp]": 0.004201195999939955, - "tests/integration/docker_utils/test_docker.py::TestDockerPorts::test_container_port_can_be_bound[SdkDockerClient-None]": 1.4504015960001198, - "tests/integration/docker_utils/test_docker.py::TestDockerPorts::test_container_port_can_be_bound[SdkDockerClient-tcp]": 1.4648564710000755, - "tests/integration/docker_utils/test_docker.py::TestDockerPorts::test_container_port_can_be_bound[SdkDockerClient-udp]": 1.4744425889998638, - "tests/integration/docker_utils/test_docker.py::TestDockerPorts::test_reserve_container_port[CmdDockerClient-None]": 0.0032527309999750287, - "tests/integration/docker_utils/test_docker.py::TestDockerPorts::test_reserve_container_port[CmdDockerClient-tcp]": 0.0018175089994656446, - "tests/integration/docker_utils/test_docker.py::TestDockerPorts::test_reserve_container_port[CmdDockerClient-udp]": 0.0019571439997889684, - "tests/integration/docker_utils/test_docker.py::TestDockerPorts::test_reserve_container_port[SdkDockerClient-None]": 2.5949652300000707, - "tests/integration/docker_utils/test_docker.py::TestDockerPorts::test_reserve_container_port[SdkDockerClient-tcp]": 2.5344584220001707, - "tests/integration/docker_utils/test_docker.py::TestDockerPorts::test_reserve_container_port[SdkDockerClient-udp]": 2.8175860130004367, - "tests/integration/docker_utils/test_docker.py::TestRunWithAdditionalArgs::test_run_with_additional_arguments[CmdDockerClient]": 0.0035283399997751985, - "tests/integration/docker_utils/test_docker.py::TestRunWithAdditionalArgs::test_run_with_additional_arguments[SdkDockerClient]": 0.37075025200010714, - "tests/integration/docker_utils/test_docker.py::TestRunWithAdditionalArgs::test_run_with_additional_arguments_add_dns[CmdDockerClient-False]": 0.0018449530002726533, - "tests/integration/docker_utils/test_docker.py::TestRunWithAdditionalArgs::test_run_with_additional_arguments_add_dns[CmdDockerClient-True]": 0.001859068000158004, - "tests/integration/docker_utils/test_docker.py::TestRunWithAdditionalArgs::test_run_with_additional_arguments_add_dns[SdkDockerClient-False]": 0.12216389299965158, - "tests/integration/docker_utils/test_docker.py::TestRunWithAdditionalArgs::test_run_with_additional_arguments_add_dns[SdkDockerClient-True]": 0.12426050799967925, - "tests/integration/docker_utils/test_docker.py::TestRunWithAdditionalArgs::test_run_with_additional_arguments_add_host[CmdDockerClient]": 0.0019610300000749703, - "tests/integration/docker_utils/test_docker.py::TestRunWithAdditionalArgs::test_run_with_additional_arguments_add_host[SdkDockerClient]": 0.1804531620000489, - "tests/integration/docker_utils/test_docker.py::TestRunWithAdditionalArgs::test_run_with_additional_arguments_env_files[CmdDockerClient]": 0.001879858000393142, - "tests/integration/docker_utils/test_docker.py::TestRunWithAdditionalArgs::test_run_with_additional_arguments_env_files[SdkDockerClient]": 0.6799926750004488, - "tests/integration/docker_utils/test_docker.py::TestRunWithAdditionalArgs::test_run_with_additional_arguments_random_port[CmdDockerClient]": 0.0018823929999598477, - "tests/integration/docker_utils/test_docker.py::TestRunWithAdditionalArgs::test_run_with_additional_arguments_random_port[SdkDockerClient]": 0.4030868269992425, - "tests/integration/docker_utils/test_docker.py::TestRunWithAdditionalArgs::test_run_with_ulimit[CmdDockerClient]": 0.006580743000085931, - "tests/integration/docker_utils/test_docker.py::TestRunWithAdditionalArgs::test_run_with_ulimit[SdkDockerClient]": 0.1785221269997237, - "tests/integration/services/test_internal.py::TestHealthResource::test_get": 0.01665641499994308, - "tests/integration/services/test_internal.py::TestHealthResource::test_head": 0.013989630999276415, - "tests/integration/services/test_internal.py::TestInfoEndpoint::test_get": 0.043870152000181406, - "tests/integration/services/test_internal.py::TestInitScriptsResource::test_query_individual_stage_completed[boot-True]": 0.025979217999974935, - "tests/integration/services/test_internal.py::TestInitScriptsResource::test_query_individual_stage_completed[ready-True]": 0.017750073000115663, - "tests/integration/services/test_internal.py::TestInitScriptsResource::test_query_individual_stage_completed[shutdown-False]": 0.0175051130004249, - "tests/integration/services/test_internal.py::TestInitScriptsResource::test_query_individual_stage_completed[start-True]": 0.01792768600034833, - "tests/integration/services/test_internal.py::TestInitScriptsResource::test_query_nonexisting_stage": 0.02098415800037401, - "tests/integration/services/test_internal.py::TestInitScriptsResource::test_stages_have_completed": 1.5136780140001065, - "tests/integration/test_config_endpoint.py::test_config_endpoint": 0.04038789700007328, - "tests/integration/test_config_service.py::TestConfigService::test_put_configuration_recorder": 0.1978645350000079, - "tests/integration/test_config_service.py::TestConfigService::test_put_delivery_channel": 0.1579211039997972, - "tests/integration/test_forwarder.py::test_forwarding_fallback_dispatcher": 0.00662201399973128, - "tests/integration/test_forwarder.py::test_forwarding_fallback_dispatcher_avoid_fallback": 0.004390065999359649, - "tests/integration/test_security.py::TestCSRF::test_CSRF": 0.09075563700025668, - "tests/integration/test_security.py::TestCSRF::test_additional_allowed_origins": 0.01682337100010045, - "tests/integration/test_security.py::TestCSRF::test_cors_apigw_not_applied": 0.04655876300057571, - "tests/integration/test_security.py::TestCSRF::test_cors_s3_override": 0.08051944799990451, - "tests/integration/test_security.py::TestCSRF::test_default_cors_headers": 0.012934133999806363, - "tests/integration/test_security.py::TestCSRF::test_disable_cors_checks": 0.01686208399996758, - "tests/integration/test_security.py::TestCSRF::test_disable_cors_headers": 0.01989701000002242, - "tests/integration/test_security.py::TestCSRF::test_internal_route_cors_headers[/_localstack/health]": 0.010912391000147181, - "tests/integration/test_security.py::TestCSRF::test_no_cors_without_origin_header": 0.014040980000117997, - "tests/integration/test_stores.py::test_nonstandard_regions": 0.13407453099989652, - "tests/integration/utils/test_diagnose.py::test_diagnose_resource": 0.27933176700025797 + "tests/aws/scenario/bookstore/test_bookstore.py::TestBookstoreApplication::test_lambda_dynamodb": 2.6456269580000367, + "tests/aws/scenario/bookstore/test_bookstore.py::TestBookstoreApplication::test_opensearch_crud": 3.8196625279999807, + "tests/aws/scenario/bookstore/test_bookstore.py::TestBookstoreApplication::test_search_books": 63.172157873, + "tests/aws/scenario/bookstore/test_bookstore.py::TestBookstoreApplication::test_setup": 100.94292506599996, + "tests/aws/scenario/kinesis_firehose/test_kinesis_firehose.py::TestKinesisFirehoseScenario::test_kinesis_firehose_s3": 0.0024516159999734555, + "tests/aws/scenario/lambda_destination/test_lambda_destination_scenario.py::TestLambdaDestinationScenario::test_destination_sns": 6.336545428000022, + "tests/aws/scenario/lambda_destination/test_lambda_destination_scenario.py::TestLambdaDestinationScenario::test_infra": 12.118331920999992, + "tests/aws/scenario/loan_broker/test_loan_broker.py::TestLoanBrokerScenario::test_prefill_dynamodb_table": 23.143875615000013, + "tests/aws/scenario/loan_broker/test_loan_broker.py::TestLoanBrokerScenario::test_stepfunctions_input_recipient_list[step_function_input0-SUCCEEDED]": 3.7690518139999654, + "tests/aws/scenario/loan_broker/test_loan_broker.py::TestLoanBrokerScenario::test_stepfunctions_input_recipient_list[step_function_input1-SUCCEEDED]": 2.5610185580000575, + "tests/aws/scenario/loan_broker/test_loan_broker.py::TestLoanBrokerScenario::test_stepfunctions_input_recipient_list[step_function_input2-FAILED]": 0.8786274600000183, + "tests/aws/scenario/loan_broker/test_loan_broker.py::TestLoanBrokerScenario::test_stepfunctions_input_recipient_list[step_function_input3-FAILED]": 0.6337569899999949, + "tests/aws/scenario/loan_broker/test_loan_broker.py::TestLoanBrokerScenario::test_stepfunctions_input_recipient_list[step_function_input4-FAILED]": 1.2380335299999956, + "tests/aws/scenario/mythical_mysfits/test_mythical_misfits.py::TestMythicalMisfitsScenario::test_deployed_infra_state": 0.002696966000030443, + "tests/aws/scenario/mythical_mysfits/test_mythical_misfits.py::TestMythicalMisfitsScenario::test_populate_data": 0.0013323470000159432, + "tests/aws/scenario/mythical_mysfits/test_mythical_misfits.py::TestMythicalMisfitsScenario::test_user_clicks_are_stored": 0.0013318549999894458, + "tests/aws/scenario/note_taking/test_note_taking.py::TestNoteTakingScenario::test_notes_rest_api": 5.305738380999969, + "tests/aws/scenario/note_taking/test_note_taking.py::TestNoteTakingScenario::test_validate_infra_setup": 29.924309257999994, + "tests/aws/services/acm/test_acm.py::TestACM::test_boto_wait_for_certificate_validation": 1.1489508750000255, + "tests/aws/services/acm/test_acm.py::TestACM::test_certificate_for_subdomain_wildcard": 2.2340195770000264, + "tests/aws/services/acm/test_acm.py::TestACM::test_create_certificate_for_multiple_alternative_domains": 11.005133203000014, + "tests/aws/services/acm/test_acm.py::TestACM::test_domain_validation": 0.2472397850000334, + "tests/aws/services/acm/test_acm.py::TestACM::test_import_certificate": 0.817190614000026, + "tests/aws/services/apigateway/test_apigateway_api.py::TestApiGatewayApiAuthorizer::test_authorizer_crud_no_api": 0.04637266700001419, + "tests/aws/services/apigateway/test_apigateway_api.py::TestApiGatewayApiDocumentationPart::test_doc_parts_crud_no_api": 0.03568605899999966, + "tests/aws/services/apigateway/test_apigateway_api.py::TestApiGatewayApiDocumentationPart::test_documentation_part_lifecycle": 0.07663063499995815, + "tests/aws/services/apigateway/test_apigateway_api.py::TestApiGatewayApiDocumentationPart::test_import_documentation_parts": 0.1284634840000649, + "tests/aws/services/apigateway/test_apigateway_api.py::TestApiGatewayApiDocumentationPart::test_invalid_create_documentation_part_operations": 0.045668518000070435, + "tests/aws/services/apigateway/test_apigateway_api.py::TestApiGatewayApiDocumentationPart::test_invalid_delete_documentation_part": 0.05593114100003049, + "tests/aws/services/apigateway/test_apigateway_api.py::TestApiGatewayApiDocumentationPart::test_invalid_get_documentation_part": 0.048879558999942674, + "tests/aws/services/apigateway/test_apigateway_api.py::TestApiGatewayApiDocumentationPart::test_invalid_get_documentation_parts": 0.01651635399997531, + "tests/aws/services/apigateway/test_apigateway_api.py::TestApiGatewayApiDocumentationPart::test_invalid_update_documentation_part": 0.05875432800002045, + "tests/aws/services/apigateway/test_apigateway_api.py::TestApiGatewayApiMethod::test_method_lifecycle": 0.10627967199997101, + "tests/aws/services/apigateway/test_apigateway_api.py::TestApiGatewayApiMethod::test_method_request_parameters": 0.06528431500004217, + "tests/aws/services/apigateway/test_apigateway_api.py::TestApiGatewayApiMethod::test_put_method_model": 0.3300249609999355, + "tests/aws/services/apigateway/test_apigateway_api.py::TestApiGatewayApiMethod::test_put_method_validation": 0.08674511299994947, + "tests/aws/services/apigateway/test_apigateway_api.py::TestApiGatewayApiMethod::test_update_method": 0.08591561100001854, + "tests/aws/services/apigateway/test_apigateway_api.py::TestApiGatewayApiMethod::test_update_method_validation": 0.15129677699991362, + "tests/aws/services/apigateway/test_apigateway_api.py::TestApiGatewayApiModels::test_model_lifecycle": 0.07697661400004563, + "tests/aws/services/apigateway/test_apigateway_api.py::TestApiGatewayApiModels::test_model_validation": 0.1075453300000504, + "tests/aws/services/apigateway/test_apigateway_api.py::TestApiGatewayApiModels::test_update_model": 0.07755871699998806, + "tests/aws/services/apigateway/test_apigateway_api.py::TestApiGatewayApiRequestValidator::test_create_request_validator_invalid_api_id": 0.017583082999976796, + "tests/aws/services/apigateway/test_apigateway_api.py::TestApiGatewayApiRequestValidator::test_invalid_delete_request_validator": 0.04679665200001182, + "tests/aws/services/apigateway/test_apigateway_api.py::TestApiGatewayApiRequestValidator::test_invalid_get_request_validator": 0.047971775000064554, + "tests/aws/services/apigateway/test_apigateway_api.py::TestApiGatewayApiRequestValidator::test_invalid_get_request_validators": 0.0162609330000123, + "tests/aws/services/apigateway/test_apigateway_api.py::TestApiGatewayApiRequestValidator::test_invalid_update_request_validator_operations": 0.06894953899995926, + "tests/aws/services/apigateway/test_apigateway_api.py::TestApiGatewayApiRequestValidator::test_request_validator_lifecycle": 0.09952419999996209, + "tests/aws/services/apigateway/test_apigateway_api.py::TestApiGatewayApiRequestValidator::test_validators_crud_no_api": 0.034721441999920444, + "tests/aws/services/apigateway/test_apigateway_api.py::TestApiGatewayApiResource::test_create_proxy_resource": 0.14982810300000438, + "tests/aws/services/apigateway/test_apigateway_api.py::TestApiGatewayApiResource::test_create_proxy_resource_validation": 0.11104134399994336, + "tests/aws/services/apigateway/test_apigateway_api.py::TestApiGatewayApiResource::test_create_resource_parent_invalid": 0.03867284199992582, + "tests/aws/services/apigateway/test_apigateway_api.py::TestApiGatewayApiResource::test_delete_resource": 0.0820284310000261, + "tests/aws/services/apigateway/test_apigateway_api.py::TestApiGatewayApiResource::test_resource_lifecycle": 0.12337009500004115, + "tests/aws/services/apigateway/test_apigateway_api.py::TestApiGatewayApiResource::test_update_resource_behaviour": 0.18124320999993415, + "tests/aws/services/apigateway/test_apigateway_api.py::TestApiGatewayApiResource::test_update_resource_on_root": 0.046250127000007524, + "tests/aws/services/apigateway/test_apigateway_api.py::TestApiGatewayApiRestApi::test_create_rest_api_private_type": 0.03360670300003221, + "tests/aws/services/apigateway/test_apigateway_api.py::TestApiGatewayApiRestApi::test_create_rest_api_verify_defaults": 0.09124261400006617, + "tests/aws/services/apigateway/test_apigateway_api.py::TestApiGatewayApiRestApi::test_create_rest_api_with_binary_media_types": 0.026391756999942118, + "tests/aws/services/apigateway/test_apigateway_api.py::TestApiGatewayApiRestApi::test_create_rest_api_with_endpoint_configuration": 0.11478790700010677, + "tests/aws/services/apigateway/test_apigateway_api.py::TestApiGatewayApiRestApi::test_create_rest_api_with_optional_params": 0.08147438099996407, + "tests/aws/services/apigateway/test_apigateway_api.py::TestApiGatewayApiRestApi::test_create_rest_api_with_tags": 0.04802782199999456, + "tests/aws/services/apigateway/test_apigateway_api.py::TestApiGatewayApiRestApi::test_get_api_case_insensitive": 0.0013809680000917979, + "tests/aws/services/apigateway/test_apigateway_api.py::TestApiGatewayApiRestApi::test_list_and_delete_apis": 0.09562653300008606, + "tests/aws/services/apigateway/test_apigateway_api.py::TestApiGatewayApiRestApi::test_update_rest_api_behaviour": 0.061753654000028746, + "tests/aws/services/apigateway/test_apigateway_api.py::TestApiGatewayApiRestApi::test_update_rest_api_compression": 0.10118536500004893, + "tests/aws/services/apigateway/test_apigateway_api.py::TestApiGatewayApiRestApi::test_update_rest_api_concatenation_of_errors": 0.0012802589999978409, + "tests/aws/services/apigateway/test_apigateway_api.py::TestApiGatewayApiRestApi::test_update_rest_api_invalid_api_id": 0.016668700000025183, + "tests/aws/services/apigateway/test_apigateway_api.py::TestApiGatewayApiRestApi::test_update_rest_api_ip_address_type": 0.09125376000002916, + "tests/aws/services/apigateway/test_apigateway_api.py::TestApiGatewayApiRestApi::test_update_rest_api_operation_add_remove": 0.05485495099998161, + "tests/aws/services/apigateway/test_apigateway_api.py::TestApiGatewayGatewayResponse::test_gateway_response_crud": 0.10914063399997076, + "tests/aws/services/apigateway/test_apigateway_api.py::TestApiGatewayGatewayResponse::test_gateway_response_put": 0.10674725900003068, + "tests/aws/services/apigateway/test_apigateway_api.py::TestApiGatewayGatewayResponse::test_gateway_response_validation": 0.10924249300001065, + "tests/aws/services/apigateway/test_apigateway_api.py::TestApiGatewayGatewayResponse::test_update_gateway_response": 0.13462732799996502, + "tests/aws/services/apigateway/test_apigateway_api.py::TestApigatewayIntegration::test_delete_integration_response_errors": 0.0973584589999632, + "tests/aws/services/apigateway/test_apigateway_api.py::TestApigatewayIntegration::test_integration_response_invalid_integration": 0.0410652640000535, + "tests/aws/services/apigateway/test_apigateway_api.py::TestApigatewayIntegration::test_integration_response_invalid_responsetemplates": 0.0013634360000196466, + "tests/aws/services/apigateway/test_apigateway_api.py::TestApigatewayIntegration::test_integration_response_invalid_statuscode": 0.042483876999938275, + "tests/aws/services/apigateway/test_apigateway_api.py::TestApigatewayIntegration::test_integration_response_wrong_api": 0.025697712999999567, + "tests/aws/services/apigateway/test_apigateway_api.py::TestApigatewayIntegration::test_integration_response_wrong_method": 0.040934195000033924, + "tests/aws/services/apigateway/test_apigateway_api.py::TestApigatewayIntegration::test_integration_response_wrong_resource": 0.04118440400003465, + "tests/aws/services/apigateway/test_apigateway_api.py::TestApigatewayIntegration::test_integration_response_wrong_status_code": 0.05235487900000635, + "tests/aws/services/apigateway/test_apigateway_api.py::TestApigatewayIntegration::test_lifecycle_integration_response": 0.10124393299992107, + "tests/aws/services/apigateway/test_apigateway_api.py::TestApigatewayIntegration::test_lifecycle_method_response": 0.09978650199997219, + "tests/aws/services/apigateway/test_apigateway_api.py::TestApigatewayIntegration::test_put_integration_request_parameter_bool_type": 0.001287863000015932, + "tests/aws/services/apigateway/test_apigateway_api.py::TestApigatewayIntegration::test_put_integration_response_validation": 0.079560125999933, + "tests/aws/services/apigateway/test_apigateway_api.py::TestApigatewayIntegration::test_put_integration_wrong_type": 0.04337553199997046, + "tests/aws/services/apigateway/test_apigateway_api.py::TestApigatewayIntegration::test_update_method_lack_response_parameters_and_models": 0.07873504900004491, + "tests/aws/services/apigateway/test_apigateway_api.py::TestApigatewayIntegration::test_update_method_response": 0.06936705200001825, + "tests/aws/services/apigateway/test_apigateway_api.py::TestApigatewayIntegration::test_update_method_response_negative_tests": 0.0943478489999734, + "tests/aws/services/apigateway/test_apigateway_api.py::TestApigatewayIntegration::test_update_method_response_wrong_operations": 0.09541652200005046, + "tests/aws/services/apigateway/test_apigateway_api.py::TestApigatewayIntegration::test_update_method_wrong_param_names": 0.08857474900003126, + "tests/aws/services/apigateway/test_apigateway_api.py::TestApigatewayTestInvoke::test_failed_invoke_test_method": 0.1586982680000233, + "tests/aws/services/apigateway/test_apigateway_api.py::TestApigatewayTestInvoke::test_invoke_test_method": 0.37606985500002565, + "tests/aws/services/apigateway/test_apigateway_basic.py::TestAPIGateway::test_api_account": 0.04710929199995917, + "tests/aws/services/apigateway/test_apigateway_basic.py::TestAPIGateway::test_api_gateway_authorizer_crud": 0.001686710999990737, + "tests/aws/services/apigateway/test_apigateway_basic.py::TestAPIGateway::test_api_gateway_handle_domain_name": 0.2803978350000307, + "tests/aws/services/apigateway/test_apigateway_basic.py::TestAPIGateway::test_api_gateway_http_integration_with_path_request_parameter": 0.0015659879999248005, + "tests/aws/services/apigateway/test_apigateway_basic.py::TestAPIGateway::test_api_gateway_lambda_asynchronous_invocation": 1.361566460000006, + "tests/aws/services/apigateway/test_apigateway_basic.py::TestAPIGateway::test_api_gateway_lambda_integration_aws_type": 7.860705881000001, + "tests/aws/services/apigateway/test_apigateway_basic.py::TestAPIGateway::test_api_gateway_lambda_proxy_integration[/lambda/foo1]": 0.0012725959999784209, + "tests/aws/services/apigateway/test_apigateway_basic.py::TestAPIGateway::test_api_gateway_lambda_proxy_integration[/lambda/{test_param1}]": 0.0013139220000084606, + "tests/aws/services/apigateway/test_apigateway_basic.py::TestAPIGateway::test_api_gateway_lambda_proxy_integration_any_method": 0.0013322269999775926, + "tests/aws/services/apigateway/test_apigateway_basic.py::TestAPIGateway::test_api_gateway_lambda_proxy_integration_any_method_with_path_param": 0.001333619999968505, + "tests/aws/services/apigateway/test_apigateway_basic.py::TestAPIGateway::test_api_gateway_lambda_proxy_integration_with_is_base_64_encoded": 0.0013637549999998555, + "tests/aws/services/apigateway/test_apigateway_basic.py::TestAPIGateway::test_api_gateway_mock_integration": 0.07010537399997929, + "tests/aws/services/apigateway/test_apigateway_basic.py::TestAPIGateway::test_api_mock_integration_response_params": 0.0013196450000236837, + "tests/aws/services/apigateway/test_apigateway_basic.py::TestAPIGateway::test_apigateway_with_custom_authorization_method": 15.471587273000011, + "tests/aws/services/apigateway/test_apigateway_basic.py::TestAPIGateway::test_apigw_stage_variables[dev]": 1.7265479289999917, + "tests/aws/services/apigateway/test_apigateway_basic.py::TestAPIGateway::test_apigw_stage_variables[local]": 1.6964592960000004, + "tests/aws/services/apigateway/test_apigateway_basic.py::TestAPIGateway::test_apigw_test_invoke_method_api": 2.193996351999999, + "tests/aws/services/apigateway/test_apigateway_basic.py::TestAPIGateway::test_base_path_mapping": 0.2133842019999861, + "tests/aws/services/apigateway/test_apigateway_basic.py::TestAPIGateway::test_base_path_mapping_root": 0.18810665699999163, + "tests/aws/services/apigateway/test_apigateway_basic.py::TestAPIGateway::test_create_rest_api_with_custom_id[host_based_url]": 0.07115619400002515, + "tests/aws/services/apigateway/test_apigateway_basic.py::TestAPIGateway::test_create_rest_api_with_custom_id[localstack_path_based_url]": 0.06978841199997987, + "tests/aws/services/apigateway/test_apigateway_basic.py::TestAPIGateway::test_create_rest_api_with_custom_id[path_based_url]": 0.07084975799995163, + "tests/aws/services/apigateway/test_apigateway_basic.py::TestAPIGateway::test_delete_rest_api_with_invalid_id": 0.012866712999993979, + "tests/aws/services/apigateway/test_apigateway_basic.py::TestAPIGateway::test_invoke_endpoint_cors_headers[http://allowed-False-UrlType.HOST_BASED]": 0.0809882980000225, + "tests/aws/services/apigateway/test_apigateway_basic.py::TestAPIGateway::test_invoke_endpoint_cors_headers[http://allowed-False-UrlType.LS_PATH_BASED]": 0.07979475600001251, + "tests/aws/services/apigateway/test_apigateway_basic.py::TestAPIGateway::test_invoke_endpoint_cors_headers[http://allowed-False-UrlType.PATH_BASED]": 0.08190060800006904, + "tests/aws/services/apigateway/test_apigateway_basic.py::TestAPIGateway::test_invoke_endpoint_cors_headers[http://allowed-True-UrlType.HOST_BASED]": 0.10462854999997262, + "tests/aws/services/apigateway/test_apigateway_basic.py::TestAPIGateway::test_invoke_endpoint_cors_headers[http://allowed-True-UrlType.LS_PATH_BASED]": 0.07954306400000632, + "tests/aws/services/apigateway/test_apigateway_basic.py::TestAPIGateway::test_invoke_endpoint_cors_headers[http://allowed-True-UrlType.PATH_BASED]": 0.07887761400002091, + "tests/aws/services/apigateway/test_apigateway_basic.py::TestAPIGateway::test_invoke_endpoint_cors_headers[http://denied-False-UrlType.HOST_BASED]": 0.08149311500005751, + "tests/aws/services/apigateway/test_apigateway_basic.py::TestAPIGateway::test_invoke_endpoint_cors_headers[http://denied-False-UrlType.LS_PATH_BASED]": 0.07939165600004117, + "tests/aws/services/apigateway/test_apigateway_basic.py::TestAPIGateway::test_invoke_endpoint_cors_headers[http://denied-False-UrlType.PATH_BASED]": 0.08065985100000717, + "tests/aws/services/apigateway/test_apigateway_basic.py::TestAPIGateway::test_invoke_endpoint_cors_headers[http://denied-True-UrlType.HOST_BASED]": 0.07685778200004734, + "tests/aws/services/apigateway/test_apigateway_basic.py::TestAPIGateway::test_invoke_endpoint_cors_headers[http://denied-True-UrlType.LS_PATH_BASED]": 0.07367952599997807, + "tests/aws/services/apigateway/test_apigateway_basic.py::TestAPIGateway::test_invoke_endpoint_cors_headers[http://denied-True-UrlType.PATH_BASED]": 0.0745811909999361, + "tests/aws/services/apigateway/test_apigateway_basic.py::TestAPIGateway::test_multiple_api_keys_validate": 0.48899641799999927, + "tests/aws/services/apigateway/test_apigateway_basic.py::TestAPIGateway::test_put_integration_dynamodb_proxy_validation_with_request_template": 0.0013646300000118572, + "tests/aws/services/apigateway/test_apigateway_basic.py::TestAPIGateway::test_put_integration_dynamodb_proxy_validation_without_request_template": 0.0014124499999752516, + "tests/aws/services/apigateway/test_apigateway_basic.py::TestAPIGateway::test_response_headers_invocation_with_apigw": 1.8284203879999836, + "tests/aws/services/apigateway/test_apigateway_basic.py::TestAPIGateway::test_update_rest_api_deployment": 0.08179651199998261, + "tests/aws/services/apigateway/test_apigateway_basic.py::TestIntegrations::test_api_gateway_http_integrations[custom]": 0.0015519380000341698, + "tests/aws/services/apigateway/test_apigateway_basic.py::TestIntegrations::test_api_gateway_http_integrations[proxy]": 0.0013731010000128663, + "tests/aws/services/apigateway/test_apigateway_basic.py::TestIntegrations::test_mock_integration_response[NEVER-UrlType.HOST_BASED-GET]": 0.1083645309999497, + "tests/aws/services/apigateway/test_apigateway_basic.py::TestIntegrations::test_mock_integration_response[NEVER-UrlType.HOST_BASED-POST]": 0.10870774400001437, + "tests/aws/services/apigateway/test_apigateway_basic.py::TestIntegrations::test_mock_integration_response[NEVER-UrlType.PATH_BASED-GET]": 0.10920055999991973, + "tests/aws/services/apigateway/test_apigateway_basic.py::TestIntegrations::test_mock_integration_response[NEVER-UrlType.PATH_BASED-POST]": 0.1107898310000337, + "tests/aws/services/apigateway/test_apigateway_basic.py::TestIntegrations::test_mock_integration_response[WHEN_NO_MATCH-UrlType.HOST_BASED-GET]": 0.10944720500009453, + "tests/aws/services/apigateway/test_apigateway_basic.py::TestIntegrations::test_mock_integration_response[WHEN_NO_MATCH-UrlType.HOST_BASED-POST]": 0.11896505100003196, + "tests/aws/services/apigateway/test_apigateway_basic.py::TestIntegrations::test_mock_integration_response[WHEN_NO_MATCH-UrlType.PATH_BASED-GET]": 0.11953732599999967, + "tests/aws/services/apigateway/test_apigateway_basic.py::TestIntegrations::test_mock_integration_response[WHEN_NO_MATCH-UrlType.PATH_BASED-POST]": 0.11522686000000704, + "tests/aws/services/apigateway/test_apigateway_basic.py::TestIntegrations::test_mock_integration_response[WHEN_NO_TEMPLATES-UrlType.HOST_BASED-GET]": 0.1121500239999591, + "tests/aws/services/apigateway/test_apigateway_basic.py::TestIntegrations::test_mock_integration_response[WHEN_NO_TEMPLATES-UrlType.HOST_BASED-POST]": 0.11266086099999484, + "tests/aws/services/apigateway/test_apigateway_basic.py::TestIntegrations::test_mock_integration_response[WHEN_NO_TEMPLATES-UrlType.PATH_BASED-GET]": 0.10965637800001105, + "tests/aws/services/apigateway/test_apigateway_basic.py::TestIntegrations::test_mock_integration_response[WHEN_NO_TEMPLATES-UrlType.PATH_BASED-POST]": 0.11511425099996586, + "tests/aws/services/apigateway/test_apigateway_basic.py::TestTagging::test_tag_api": 0.07799319600002264, + "tests/aws/services/apigateway/test_apigateway_basic.py::test_apigw_call_api_with_aws_endpoint_url": 0.013762637999946037, + "tests/aws/services/apigateway/test_apigateway_basic.py::test_rest_api_multi_region[UrlType.HOST_BASED-ANY]": 3.5463964600000395, + "tests/aws/services/apigateway/test_apigateway_basic.py::test_rest_api_multi_region[UrlType.HOST_BASED-GET]": 3.541395850000015, + "tests/aws/services/apigateway/test_apigateway_basic.py::test_rest_api_multi_region[path_based_url-ANY]": 3.5451315570000475, + "tests/aws/services/apigateway/test_apigateway_basic.py::test_rest_api_multi_region[path_based_url-GET]": 9.751090780999903, + "tests/aws/services/apigateway/test_apigateway_canary.py::TestCanaryDeployments::test_invoking_canary_deployment": 0.13880184499998904, + "tests/aws/services/apigateway/test_apigateway_canary.py::TestStageCrudCanary::test_create_canary_deployment": 0.13779946799996878, + "tests/aws/services/apigateway/test_apigateway_canary.py::TestStageCrudCanary::test_create_canary_deployment_by_stage_update": 0.14376558899999736, + "tests/aws/services/apigateway/test_apigateway_canary.py::TestStageCrudCanary::test_create_canary_deployment_validation": 0.10003202500007546, + "tests/aws/services/apigateway/test_apigateway_canary.py::TestStageCrudCanary::test_create_canary_deployment_with_stage": 0.11599074100001872, + "tests/aws/services/apigateway/test_apigateway_canary.py::TestStageCrudCanary::test_create_update_stages": 0.16610740099997656, + "tests/aws/services/apigateway/test_apigateway_canary.py::TestStageCrudCanary::test_update_stage_canary_deployment_validation": 0.16833170599994673, + "tests/aws/services/apigateway/test_apigateway_canary.py::TestStageCrudCanary::test_update_stage_with_copy_ops": 0.14386649600004375, + "tests/aws/services/apigateway/test_apigateway_common.py::TestApiGatewayCommon::test_api_gateway_request_validator": 2.5303406539999855, + "tests/aws/services/apigateway/test_apigateway_common.py::TestApiGatewayCommon::test_api_gateway_request_validator_with_ref_models": 0.19166108199999599, + "tests/aws/services/apigateway/test_apigateway_common.py::TestApiGatewayCommon::test_api_gateway_request_validator_with_ref_one_ofmodels": 0.20112380299997312, + "tests/aws/services/apigateway/test_apigateway_common.py::TestApiGatewayCommon::test_input_body_formatting": 3.5986269530000072, + "tests/aws/services/apigateway/test_apigateway_common.py::TestApiGatewayCommon::test_input_path_template_formatting": 0.6584828619999712, + "tests/aws/services/apigateway/test_apigateway_common.py::TestApiGatewayCommon::test_integration_request_parameters_mapping": 0.11663483400002406, + "tests/aws/services/apigateway/test_apigateway_common.py::TestApiGatewayCommon::test_invocation_trace_id": 2.3271853149999515, + "tests/aws/services/apigateway/test_apigateway_common.py::TestApigatewayRouting::test_api_not_existing": 0.027123352999979033, + "tests/aws/services/apigateway/test_apigateway_common.py::TestApigatewayRouting::test_proxy_routing_with_hardcoded_resource_sibling": 0.278068807000011, + "tests/aws/services/apigateway/test_apigateway_common.py::TestApigatewayRouting::test_routing_not_found": 0.11751300899999251, + "tests/aws/services/apigateway/test_apigateway_common.py::TestApigatewayRouting::test_routing_with_custom_api_id": 0.1108844639999802, + "tests/aws/services/apigateway/test_apigateway_common.py::TestApigatewayRouting::test_routing_with_hardcoded_resource_sibling_order": 0.23728950700001405, + "tests/aws/services/apigateway/test_apigateway_common.py::TestDeployments::test_create_delete_deployments[False]": 0.39955931599996575, + "tests/aws/services/apigateway/test_apigateway_common.py::TestDeployments::test_create_delete_deployments[True]": 0.4354391549999832, + "tests/aws/services/apigateway/test_apigateway_common.py::TestDeployments::test_create_update_deployments": 0.32936303499997166, + "tests/aws/services/apigateway/test_apigateway_common.py::TestDocumentations::test_documentation_parts_and_versions": 0.1091472539999927, + "tests/aws/services/apigateway/test_apigateway_common.py::TestStages::test_create_update_stages": 0.29803537299994787, + "tests/aws/services/apigateway/test_apigateway_common.py::TestStages::test_update_stage_remove_wildcard": 0.28483423400001584, + "tests/aws/services/apigateway/test_apigateway_common.py::TestUsagePlans::test_api_key_required_for_methods": 0.21461681999994653, + "tests/aws/services/apigateway/test_apigateway_common.py::TestUsagePlans::test_usage_plan_crud": 0.2111040710000225, + "tests/aws/services/apigateway/test_apigateway_custom_ids.py::test_apigateway_custom_ids": 0.06435841899997286, + "tests/aws/services/apigateway/test_apigateway_dynamodb.py::test_error_aws_proxy_not_supported": 0.1581544699999995, + "tests/aws/services/apigateway/test_apigateway_dynamodb.py::test_rest_api_to_dynamodb_integration[PutItem]": 0.3884141519999389, + "tests/aws/services/apigateway/test_apigateway_dynamodb.py::test_rest_api_to_dynamodb_integration[Query]": 0.4693211480000059, + "tests/aws/services/apigateway/test_apigateway_dynamodb.py::test_rest_api_to_dynamodb_integration[Scan]": 0.3616664450000826, + "tests/aws/services/apigateway/test_apigateway_eventbridge.py::test_apigateway_to_eventbridge": 0.21977327600001217, + "tests/aws/services/apigateway/test_apigateway_extended.py::TestApigatewayApiKeysCrud::test_get_api_keys": 0.18066219599995748, + "tests/aws/services/apigateway/test_apigateway_extended.py::TestApigatewayApiKeysCrud::test_get_usage_plan_api_keys": 0.17354237999995803, + "tests/aws/services/apigateway/test_apigateway_extended.py::test_create_domain_names": 0.08563463299998375, + "tests/aws/services/apigateway/test_apigateway_extended.py::test_export_oas30_openapi[TEST_IMPORT_PETSTORE_SWAGGER]": 0.37870676500006084, + "tests/aws/services/apigateway/test_apigateway_extended.py::test_export_oas30_openapi[TEST_IMPORT_PETS]": 0.2890934869999455, + "tests/aws/services/apigateway/test_apigateway_extended.py::test_export_swagger_openapi[TEST_IMPORT_PETSTORE_SWAGGER]": 0.3853350519999026, + "tests/aws/services/apigateway/test_apigateway_extended.py::test_export_swagger_openapi[TEST_IMPORT_PETS]": 0.28761935200003563, + "tests/aws/services/apigateway/test_apigateway_extended.py::test_get_domain_name": 0.08182579400005352, + "tests/aws/services/apigateway/test_apigateway_extended.py::test_get_domain_names": 0.08371523999994679, + "tests/aws/services/apigateway/test_apigateway_http.py::test_http_integration_invoke_status_code_passthrough[HTTP]": 1.8550186850000046, + "tests/aws/services/apigateway/test_apigateway_http.py::test_http_integration_invoke_status_code_passthrough[HTTP_PROXY]": 1.8178027780001003, + "tests/aws/services/apigateway/test_apigateway_http.py::test_http_integration_method[HTTP]": 2.075905109999894, + "tests/aws/services/apigateway/test_apigateway_http.py::test_http_integration_method[HTTP_PROXY]": 2.072051518999956, + "tests/aws/services/apigateway/test_apigateway_http.py::test_http_integration_with_lambda[HTTP]": 2.131987229999993, + "tests/aws/services/apigateway/test_apigateway_http.py::test_http_integration_with_lambda[HTTP_PROXY]": 2.154788033999921, + "tests/aws/services/apigateway/test_apigateway_http.py::test_http_proxy_integration_request_data_mappings": 1.972163066000121, + "tests/aws/services/apigateway/test_apigateway_import.py::TestApiGatewayImportRestApi::test_import_and_validate_rest_api[openapi.spec.tf.json]": 0.3222264710000218, + "tests/aws/services/apigateway/test_apigateway_import.py::TestApiGatewayImportRestApi::test_import_and_validate_rest_api[swagger-mock-cors.json]": 0.4126889309998205, + "tests/aws/services/apigateway/test_apigateway_import.py::TestApiGatewayImportRestApi::test_import_rest_api": 0.06846491800001786, + "tests/aws/services/apigateway/test_apigateway_import.py::TestApiGatewayImportRestApi::test_import_rest_api_with_base_path_oas30[ignore]": 0.7914613269999791, + "tests/aws/services/apigateway/test_apigateway_import.py::TestApiGatewayImportRestApi::test_import_rest_api_with_base_path_oas30[prepend]": 0.7977636560000292, + "tests/aws/services/apigateway/test_apigateway_import.py::TestApiGatewayImportRestApi::test_import_rest_api_with_base_path_oas30[split]": 0.80010070000003, + "tests/aws/services/apigateway/test_apigateway_import.py::TestApiGatewayImportRestApi::test_import_rest_apis_with_base_path_swagger[ignore]": 0.5907906319999938, + "tests/aws/services/apigateway/test_apigateway_import.py::TestApiGatewayImportRestApi::test_import_rest_apis_with_base_path_swagger[prepend]": 0.5621962060000669, + "tests/aws/services/apigateway/test_apigateway_import.py::TestApiGatewayImportRestApi::test_import_rest_apis_with_base_path_swagger[split]": 0.5516925409999658, + "tests/aws/services/apigateway/test_apigateway_import.py::TestApiGatewayImportRestApi::test_import_swagger_api": 1.615986711000005, + "tests/aws/services/apigateway/test_apigateway_import.py::TestApiGatewayImportRestApi::test_import_with_circular_models": 0.26273103200003334, + "tests/aws/services/apigateway/test_apigateway_import.py::TestApiGatewayImportRestApi::test_import_with_circular_models_and_request_validation": 0.3703296430001046, + "tests/aws/services/apigateway/test_apigateway_import.py::TestApiGatewayImportRestApi::test_import_with_cognito_auth_identity_source": 0.37319118899995374, + "tests/aws/services/apigateway/test_apigateway_import.py::TestApiGatewayImportRestApi::test_import_with_global_api_key_authorizer": 0.26718424400007734, + "tests/aws/services/apigateway/test_apigateway_import.py::TestApiGatewayImportRestApi::test_import_with_http_method_integration": 0.2859772630001771, + "tests/aws/services/apigateway/test_apigateway_import.py::TestApiGatewayImportRestApi::test_import_with_integer_http_status_code": 0.177729103999809, + "tests/aws/services/apigateway/test_apigateway_import.py::TestApiGatewayImportRestApi::test_import_with_stage_variables": 1.7214130680000608, + "tests/aws/services/apigateway/test_apigateway_import.py::TestApiGatewayImportRestApi::test_put_rest_api_mode_binary_media_types[merge]": 0.28449716099999023, + "tests/aws/services/apigateway/test_apigateway_import.py::TestApiGatewayImportRestApi::test_put_rest_api_mode_binary_media_types[overwrite]": 0.2869662570000173, + "tests/aws/services/apigateway/test_apigateway_integrations.py::TestApiGatewayHeaderRemapping::test_apigateway_header_remapping_aws[AWS]": 2.464199117000021, + "tests/aws/services/apigateway/test_apigateway_integrations.py::TestApiGatewayHeaderRemapping::test_apigateway_header_remapping_aws[AWS_PROXY]": 2.5354477359999237, + "tests/aws/services/apigateway/test_apigateway_integrations.py::TestApiGatewayHeaderRemapping::test_apigateway_header_remapping_http[HTTP]": 0.744673705000082, + "tests/aws/services/apigateway/test_apigateway_integrations.py::TestApiGatewayHeaderRemapping::test_apigateway_header_remapping_http[HTTP_PROXY]": 0.7362165459999233, + "tests/aws/services/apigateway/test_apigateway_integrations.py::test_create_execute_api_vpc_endpoint": 5.7030561540000235, + "tests/aws/services/apigateway/test_apigateway_integrations.py::test_http_integration_status_code_selection": 0.13366499699998258, + "tests/aws/services/apigateway/test_apigateway_integrations.py::test_integration_mock_with_path_param": 0.10666246499999943, + "tests/aws/services/apigateway/test_apigateway_integrations.py::test_integration_mock_with_request_overrides_in_response_template": 0.130015960000037, + "tests/aws/services/apigateway/test_apigateway_integrations.py::test_integration_mock_with_response_override_in_request_template[False]": 0.09563170399985665, + "tests/aws/services/apigateway/test_apigateway_integrations.py::test_integration_mock_with_response_override_in_request_template[True]": 0.09545003699997778, + "tests/aws/services/apigateway/test_apigateway_integrations.py::test_integration_mock_with_vtl_map_assignation": 0.10569509699996615, + "tests/aws/services/apigateway/test_apigateway_integrations.py::test_put_integration_response_with_response_template": 1.2647721769999407, + "tests/aws/services/apigateway/test_apigateway_integrations.py::test_put_integration_responses": 0.1892761960000371, + "tests/aws/services/apigateway/test_apigateway_integrations.py::test_put_integration_validation": 0.2247657509999499, + "tests/aws/services/apigateway/test_apigateway_kinesis.py::test_apigateway_to_kinesis[PutRecord]": 1.104556083000034, + "tests/aws/services/apigateway/test_apigateway_kinesis.py::test_apigateway_to_kinesis[PutRecords]": 1.1078049389999478, + "tests/aws/services/apigateway/test_apigateway_lambda.py::test_aws_proxy_binary_response": 3.8748110579999775, + "tests/aws/services/apigateway/test_apigateway_lambda.py::test_aws_proxy_response_payload_format_validation": 3.9616266670000186, + "tests/aws/services/apigateway/test_apigateway_lambda.py::test_lambda_aws_integration": 1.7649456100000407, + "tests/aws/services/apigateway/test_apigateway_lambda.py::test_lambda_aws_integration_response_with_mapping_templates": 1.9408369819999507, + "tests/aws/services/apigateway/test_apigateway_lambda.py::test_lambda_aws_integration_with_request_template": 1.9131105740000294, + "tests/aws/services/apigateway/test_apigateway_lambda.py::test_lambda_aws_proxy_integration": 4.015105978000065, + "tests/aws/services/apigateway/test_apigateway_lambda.py::test_lambda_aws_proxy_integration_non_post_method": 1.3791511099999525, + "tests/aws/services/apigateway/test_apigateway_lambda.py::test_lambda_aws_proxy_integration_request_data_mapping": 2.697379294999905, + "tests/aws/services/apigateway/test_apigateway_lambda.py::test_lambda_aws_proxy_response_format": 2.0455601890000707, + "tests/aws/services/apigateway/test_apigateway_lambda.py::test_lambda_rust_proxy_integration": 3.8343832280000925, + "tests/aws/services/apigateway/test_apigateway_lambda.py::test_lambda_selection_patterns": 2.0280876619999617, + "tests/aws/services/apigateway/test_apigateway_lambda.py::test_put_integration_aws_proxy_uri": 1.3393577350000214, + "tests/aws/services/apigateway/test_apigateway_lambda_cfn.py::TestApigatewayLambdaIntegration::test_scenario_validate_infra": 7.600949304999972, + "tests/aws/services/apigateway/test_apigateway_s3.py::TestApiGatewayS3BinarySupport::test_apigw_s3_binary_support_request[CONVERT_TO_TEXT]": 0.5568799640000179, + "tests/aws/services/apigateway/test_apigateway_s3.py::TestApiGatewayS3BinarySupport::test_apigw_s3_binary_support_request[None]": 0.5543614330000537, + "tests/aws/services/apigateway/test_apigateway_s3.py::TestApiGatewayS3BinarySupport::test_apigw_s3_binary_support_request_convert_to_binary": 0.5010715759999584, + "tests/aws/services/apigateway/test_apigateway_s3.py::TestApiGatewayS3BinarySupport::test_apigw_s3_binary_support_request_convert_to_binary_with_request_template": 0.31180505199995423, + "tests/aws/services/apigateway/test_apigateway_s3.py::TestApiGatewayS3BinarySupport::test_apigw_s3_binary_support_response_convert_to_binary": 0.5640049149999413, + "tests/aws/services/apigateway/test_apigateway_s3.py::TestApiGatewayS3BinarySupport::test_apigw_s3_binary_support_response_convert_to_binary_with_request_template": 0.3463934539998945, + "tests/aws/services/apigateway/test_apigateway_s3.py::TestApiGatewayS3BinarySupport::test_apigw_s3_binary_support_response_convert_to_text": 0.5812749249998888, + "tests/aws/services/apigateway/test_apigateway_s3.py::TestApiGatewayS3BinarySupport::test_apigw_s3_binary_support_response_no_content_handling": 0.5713210280000567, + "tests/aws/services/apigateway/test_apigateway_s3.py::test_apigateway_s3_any": 0.43049775500003307, + "tests/aws/services/apigateway/test_apigateway_s3.py::test_apigateway_s3_method_mapping": 0.48674832099993637, + "tests/aws/services/apigateway/test_apigateway_sqs.py::test_sqs_amz_json_protocol": 0.8626181380000162, + "tests/aws/services/apigateway/test_apigateway_sqs.py::test_sqs_aws_integration": 1.3032076849999612, + "tests/aws/services/apigateway/test_apigateway_sqs.py::test_sqs_aws_integration_with_message_attribute[MessageAttribute]": 0.26291680799999995, + "tests/aws/services/apigateway/test_apigateway_sqs.py::test_sqs_aws_integration_with_message_attribute[MessageAttributes]": 0.26487768399988454, + "tests/aws/services/apigateway/test_apigateway_sqs.py::test_sqs_request_and_response_xml_templates_integration": 0.3606767649998801, + "tests/aws/services/apigateway/test_apigateway_ssm.py::test_get_parameter_query_protocol": 0.0015783369999553543, + "tests/aws/services/apigateway/test_apigateway_ssm.py::test_ssm_aws_integration": 0.23722017299996878, + "tests/aws/services/apigateway/test_apigateway_stepfunctions.py::TestApigatewayStepfunctions::test_apigateway_with_step_function_integration[DeleteStateMachine]": 2.433100842000158, + "tests/aws/services/apigateway/test_apigateway_stepfunctions.py::TestApigatewayStepfunctions::test_apigateway_with_step_function_integration[StartExecution]": 1.4970347130000619, + "tests/aws/services/cloudcontrol/test_cloudcontrol_api.py::TestCloudControlResourceApi::test_api_exceptions": 0.0012828729999228017, + "tests/aws/services/cloudcontrol/test_cloudcontrol_api.py::TestCloudControlResourceApi::test_create_exceptions": 0.0012778220000200236, + "tests/aws/services/cloudcontrol/test_cloudcontrol_api.py::TestCloudControlResourceApi::test_create_invalid_desiredstate": 0.001262093000036657, + "tests/aws/services/cloudcontrol/test_cloudcontrol_api.py::TestCloudControlResourceApi::test_double_create_with_client_token": 0.001291487999878882, + "tests/aws/services/cloudcontrol/test_cloudcontrol_api.py::TestCloudControlResourceApi::test_lifecycle": 0.0015637899998637295, + "tests/aws/services/cloudcontrol/test_cloudcontrol_api.py::TestCloudControlResourceApi::test_list_resources": 0.0013646459998426508, + "tests/aws/services/cloudcontrol/test_cloudcontrol_api.py::TestCloudControlResourceApi::test_list_resources_with_resource_model": 0.0012826419999782956, + "tests/aws/services/cloudcontrol/test_cloudcontrol_api.py::TestCloudControlResourceApi::test_update": 0.0012996839999459553, + "tests/aws/services/cloudcontrol/test_cloudcontrol_api.py::TestCloudControlResourceRequestApi::test_cancel_edge_cases[FAIL]": 0.0013915470000256391, + "tests/aws/services/cloudcontrol/test_cloudcontrol_api.py::TestCloudControlResourceRequestApi::test_cancel_edge_cases[SUCCESS]": 0.0014010439999765367, + "tests/aws/services/cloudcontrol/test_cloudcontrol_api.py::TestCloudControlResourceRequestApi::test_cancel_request": 0.0013400499998397208, + "tests/aws/services/cloudcontrol/test_cloudcontrol_api.py::TestCloudControlResourceRequestApi::test_get_request_status": 0.0013697960000627063, + "tests/aws/services/cloudcontrol/test_cloudcontrol_api.py::TestCloudControlResourceRequestApi::test_invalid_request_token_exc": 0.001311826000005567, + "tests/aws/services/cloudcontrol/test_cloudcontrol_api.py::TestCloudControlResourceRequestApi::test_list_request_status": 0.001352633000124115, + "tests/aws/services/cloudformation/api/test_changesets.py::TestUpdates::test_deleting_resource": 8.404162154000005, + "tests/aws/services/cloudformation/api/test_changesets.py::TestUpdates::test_simple_update_single_resource": 10.339746874999946, + "tests/aws/services/cloudformation/api/test_changesets.py::TestUpdates::test_simple_update_two_resources": 10.33777058599992, + "tests/aws/services/cloudformation/api/test_changesets.py::test_autoexpand_capability_requirement": 0.42268806100003076, + "tests/aws/services/cloudformation/api/test_changesets.py::test_create_and_then_remove_non_supported_resource_change_set": 6.51865665899993, + "tests/aws/services/cloudformation/api/test_changesets.py::test_create_and_then_remove_supported_resource_change_set": 8.31361275900008, + "tests/aws/services/cloudformation/api/test_changesets.py::test_create_and_then_update_refreshes_template_metadata": 2.144253931000094, + "tests/aws/services/cloudformation/api/test_changesets.py::test_create_change_set_create_existing": 2.14049316299986, + "tests/aws/services/cloudformation/api/test_changesets.py::test_create_change_set_invalid_params": 0.01632428599987179, + "tests/aws/services/cloudformation/api/test_changesets.py::test_create_change_set_missing_stackname": 0.024681855000039832, + "tests/aws/services/cloudformation/api/test_changesets.py::test_create_change_set_no_changes": 2.1330406629999743, + "tests/aws/services/cloudformation/api/test_changesets.py::test_create_change_set_update_nonexisting": 0.016597931000092103, + "tests/aws/services/cloudformation/api/test_changesets.py::test_create_change_set_update_without_parameters": 0.0018949560000010024, + "tests/aws/services/cloudformation/api/test_changesets.py::test_create_change_set_with_ssm_parameter": 1.1957698999999593, + "tests/aws/services/cloudformation/api/test_changesets.py::test_create_change_set_without_parameters": 0.094190215000026, + "tests/aws/services/cloudformation/api/test_changesets.py::test_create_changeset_with_stack_id": 0.2775503120000167, + "tests/aws/services/cloudformation/api/test_changesets.py::test_create_delete_create": 3.2038420780000934, + "tests/aws/services/cloudformation/api/test_changesets.py::test_create_while_in_review": 0.0013845860000856192, + "tests/aws/services/cloudformation/api/test_changesets.py::test_delete_change_set_exception": 0.024341292999906727, + "tests/aws/services/cloudformation/api/test_changesets.py::test_deleted_changeset": 0.05408272800002578, + "tests/aws/services/cloudformation/api/test_changesets.py::test_describe_change_set_nonexisting": 0.013788048999913372, + "tests/aws/services/cloudformation/api/test_changesets.py::test_describe_change_set_with_similarly_named_stacks": 0.059652244999938375, + "tests/aws/services/cloudformation/api/test_changesets.py::test_describe_changeset_after_delete": 1.3491826900000206, + "tests/aws/services/cloudformation/api/test_changesets.py::test_empty_changeset": 0.4026904029999514, + "tests/aws/services/cloudformation/api/test_changesets.py::test_execute_change_set": 0.001401807999968696, + "tests/aws/services/cloudformation/api/test_changesets.py::test_multiple_create_changeset": 0.42415508400017643, + "tests/aws/services/cloudformation/api/test_changesets.py::test_name_conflicts": 2.9426208600000336, + "tests/aws/services/cloudformation/api/test_changesets.py::test_update_change_set_with_aws_novalue_repro": 1.1511685609999631, + "tests/aws/services/cloudformation/api/test_changesets.py::test_using_pseudoparameters_in_places[condition]": 0.035923608999951284, + "tests/aws/services/cloudformation/api/test_changesets.py::test_using_pseudoparameters_in_places[parameter]": 0.026244636000001265, + "tests/aws/services/cloudformation/api/test_changesets.py::test_using_pseudoparameters_in_places[resource]": 0.026627414999893517, + "tests/aws/services/cloudformation/api/test_drift_detection.py::test_drift_detection_on_lambda": 0.0014843859999018605, + "tests/aws/services/cloudformation/api/test_extensions_api.py::TestExtensionsApi::test_crud_extension[HOOK-LocalStack::Testing::TestHook-hooks/localstack-testing-testhook.zip]": 0.0012884269999631215, + "tests/aws/services/cloudformation/api/test_extensions_api.py::TestExtensionsApi::test_crud_extension[MODULE-LocalStack::Testing::TestModule::MODULE-modules/localstack-testing-testmodule-module.zip]": 0.0013140459999476661, + "tests/aws/services/cloudformation/api/test_extensions_api.py::TestExtensionsApi::test_crud_extension[RESOURCE-LocalStack::Testing::TestResource-resourcetypes/localstack-testing-testresource.zip]": 0.001317321999977139, + "tests/aws/services/cloudformation/api/test_extensions_api.py::TestExtensionsApi::test_extension_not_complete": 0.0012937479999663992, + "tests/aws/services/cloudformation/api/test_extensions_api.py::TestExtensionsApi::test_extension_type_configuration": 0.0012758150000991009, + "tests/aws/services/cloudformation/api/test_extensions_api.py::TestExtensionsApi::test_extension_versioning": 0.0012699610000481698, + "tests/aws/services/cloudformation/api/test_extensions_hooks.py::TestExtensionsHooks::test_hook_deployment[FAIL]": 0.001265823999915483, + "tests/aws/services/cloudformation/api/test_extensions_hooks.py::TestExtensionsHooks::test_hook_deployment[WARN]": 0.0013062100001661747, + "tests/aws/services/cloudformation/api/test_extensions_modules.py::TestExtensionsModules::test_module_usage": 0.001257027999940874, + "tests/aws/services/cloudformation/api/test_extensions_resourcetypes.py::TestExtensionsResourceTypes::test_deploy_resource_type": 0.001323012999932871, + "tests/aws/services/cloudformation/api/test_nested_stacks.py::test_deletion_of_failed_nested_stack": 7.330610597999907, + "tests/aws/services/cloudformation/api/test_nested_stacks.py::test_lifecycle_nested_stack": 0.0020546960000729086, + "tests/aws/services/cloudformation/api/test_nested_stacks.py::test_nested_output_in_params": 14.60362346099987, + "tests/aws/services/cloudformation/api/test_nested_stacks.py::test_nested_stack": 8.262399467000137, + "tests/aws/services/cloudformation/api/test_nested_stacks.py::test_nested_stack_output_refs": 8.281446308999989, + "tests/aws/services/cloudformation/api/test_nested_stacks.py::test_nested_stacks_conditions": 8.316307896000012, + "tests/aws/services/cloudformation/api/test_nested_stacks.py::test_nested_with_nested_stack": 14.293170295999971, + "tests/aws/services/cloudformation/api/test_reference_resolving.py::test_nested_getatt_ref[TopicArn]": 2.1506889739999906, + "tests/aws/services/cloudformation/api/test_reference_resolving.py::test_nested_getatt_ref[TopicName]": 2.1516910290000624, + "tests/aws/services/cloudformation/api/test_reference_resolving.py::test_redeploy_cdk_with_reference": 24.494509819999962, + "tests/aws/services/cloudformation/api/test_reference_resolving.py::test_reference_unsupported_resource": 4.167485872999919, + "tests/aws/services/cloudformation/api/test_reference_resolving.py::test_sub_resolving": 0.1437111919998415, + "tests/aws/services/cloudformation/api/test_resources.py::test_describe_non_existent_resource": 4.164431039999954, + "tests/aws/services/cloudformation/api/test_resources.py::test_describe_non_existent_stack": 0.020557286999974167, + "tests/aws/services/cloudformation/api/test_resources.py::test_invalid_logical_resource_id": 0.019758518999879016, + "tests/aws/services/cloudformation/api/test_stack_policies.py::TestStackPolicy::test_create_stack_with_policy": 0.0012493589999849064, + "tests/aws/services/cloudformation/api/test_stack_policies.py::TestStackPolicy::test_different_action_attribute": 0.0012993219999088979, + "tests/aws/services/cloudformation/api/test_stack_policies.py::TestStackPolicy::test_different_principal_attribute": 0.001286689000039587, + "tests/aws/services/cloudformation/api/test_stack_policies.py::TestStackPolicy::test_empty_policy": 0.0012922900000376103, + "tests/aws/services/cloudformation/api/test_stack_policies.py::TestStackPolicy::test_not_json_policy": 0.001327837999951953, + "tests/aws/services/cloudformation/api/test_stack_policies.py::TestStackPolicy::test_policy_during_update": 0.0013621420000617945, + "tests/aws/services/cloudformation/api/test_stack_policies.py::TestStackPolicy::test_policy_lifecycle": 0.0013370649999160378, + "tests/aws/services/cloudformation/api/test_stack_policies.py::TestStackPolicy::test_prevent_deletion[resource0]": 0.0012736160000486052, + "tests/aws/services/cloudformation/api/test_stack_policies.py::TestStackPolicy::test_prevent_deletion[resource1]": 0.0012961170000380662, + "tests/aws/services/cloudformation/api/test_stack_policies.py::TestStackPolicy::test_prevent_modifying_with_policy_specifying_resource_id": 0.0012676930000452558, + "tests/aws/services/cloudformation/api/test_stack_policies.py::TestStackPolicy::test_prevent_replacement": 0.0013636340000857672, + "tests/aws/services/cloudformation/api/test_stack_policies.py::TestStackPolicy::test_prevent_resource_deletion": 0.0012412739999945188, + "tests/aws/services/cloudformation/api/test_stack_policies.py::TestStackPolicy::test_prevent_stack_update": 0.0012607610000259228, + "tests/aws/services/cloudformation/api/test_stack_policies.py::TestStackPolicy::test_prevent_update[AWS::S3::Bucket]": 0.001317547999974522, + "tests/aws/services/cloudformation/api/test_stack_policies.py::TestStackPolicy::test_prevent_update[AWS::SNS::Topic]": 0.0013644050000038987, + "tests/aws/services/cloudformation/api/test_stack_policies.py::TestStackPolicy::test_set_empty_policy_with_url": 0.00131176599995797, + "tests/aws/services/cloudformation/api/test_stack_policies.py::TestStackPolicy::test_set_invalid_policy_with_url": 0.0014152809999359306, + "tests/aws/services/cloudformation/api/test_stack_policies.py::TestStackPolicy::test_set_policy_both_policy_and_url": 0.0013307830000712784, + "tests/aws/services/cloudformation/api/test_stack_policies.py::TestStackPolicy::test_set_policy_with_update_operation": 0.001373472000068432, + "tests/aws/services/cloudformation/api/test_stack_policies.py::TestStackPolicy::test_set_policy_with_url": 0.0013158750000457076, + "tests/aws/services/cloudformation/api/test_stack_policies.py::TestStackPolicy::test_update_with_empty_policy": 0.0012688460000163104, + "tests/aws/services/cloudformation/api/test_stack_policies.py::TestStackPolicy::test_update_with_overlapping_policies[False]": 0.0012807390000943997, + "tests/aws/services/cloudformation/api/test_stack_policies.py::TestStackPolicy::test_update_with_overlapping_policies[True]": 0.0012595690000125614, + "tests/aws/services/cloudformation/api/test_stack_policies.py::TestStackPolicy::test_update_with_policy": 0.0012570939999250186, + "tests/aws/services/cloudformation/api/test_stacks.py::TestStacksApi::test_create_stack_with_custom_id": 1.081139306999944, + "tests/aws/services/cloudformation/api/test_stacks.py::TestStacksApi::test_failure_options_for_stack_creation[False-0]": 0.001523873999872194, + "tests/aws/services/cloudformation/api/test_stacks.py::TestStacksApi::test_failure_options_for_stack_creation[True-1]": 0.0012987500000463115, + "tests/aws/services/cloudformation/api/test_stacks.py::TestStacksApi::test_failure_options_for_stack_update[False-2]": 0.0012799439999753304, + "tests/aws/services/cloudformation/api/test_stacks.py::TestStacksApi::test_failure_options_for_stack_update[True-1]": 0.0012856550000606148, + "tests/aws/services/cloudformation/api/test_stacks.py::TestStacksApi::test_get_template_using_changesets[json]": 2.133162459999994, + "tests/aws/services/cloudformation/api/test_stacks.py::TestStacksApi::test_get_template_using_changesets[yaml]": 2.1307114629998978, + "tests/aws/services/cloudformation/api/test_stacks.py::TestStacksApi::test_get_template_using_create_stack[json]": 0.05945624800017413, + "tests/aws/services/cloudformation/api/test_stacks.py::TestStacksApi::test_get_template_using_create_stack[yaml]": 1.0784446300000354, + "tests/aws/services/cloudformation/api/test_stacks.py::TestStacksApi::test_list_events_after_deployment": 0.18756459200005793, + "tests/aws/services/cloudformation/api/test_stacks.py::TestStacksApi::test_stack_description_lifecycle[no-tags]": 1.350698270999942, + "tests/aws/services/cloudformation/api/test_stacks.py::TestStacksApi::test_stack_description_lifecycle[with-tags]": 1.3260699039999508, + "tests/aws/services/cloudformation/api/test_stacks.py::TestStacksApi::test_stack_description_special_chars": 4.1352001839999275, + "tests/aws/services/cloudformation/api/test_stacks.py::TestStacksApi::test_stack_lifecycle": 3.492257999000117, + "tests/aws/services/cloudformation/api/test_stacks.py::TestStacksApi::test_stack_name_creation": 0.06792954400009421, + "tests/aws/services/cloudformation/api/test_stacks.py::TestStacksApi::test_stack_update_resources": 8.515684383000007, + "tests/aws/services/cloudformation/api/test_stacks.py::TestStacksApi::test_update_stack_actual_update": 6.269330416999992, + "tests/aws/services/cloudformation/api/test_stacks.py::TestStacksApi::test_update_stack_with_same_template_withoutchange": 0.11370097400003942, + "tests/aws/services/cloudformation/api/test_stacks.py::TestStacksApi::test_update_stack_with_same_template_withoutchange_transformation": 2.3034133049999355, + "tests/aws/services/cloudformation/api/test_stacks.py::test_blank_parameter_value": 1.071889287999852, + "tests/aws/services/cloudformation/api/test_stacks.py::test_blocked_stack_deletion": 0.0014894900000399502, + "tests/aws/services/cloudformation/api/test_stacks.py::test_describe_stack_events_errors": 0.025344392000079097, + "tests/aws/services/cloudformation/api/test_stacks.py::test_events_resource_types": 4.182726062000029, + "tests/aws/services/cloudformation/api/test_stacks.py::test_linting_error_during_creation": 0.0014967969999588604, + "tests/aws/services/cloudformation/api/test_stacks.py::test_list_parameter_type": 11.034818866000023, + "tests/aws/services/cloudformation/api/test_stacks.py::test_name_conflicts": 4.507989442000053, + "tests/aws/services/cloudformation/api/test_stacks.py::test_no_echo_parameter": 5.060418283999979, + "tests/aws/services/cloudformation/api/test_stacks.py::test_no_parameters_given": 0.019058277999988604, + "tests/aws/services/cloudformation/api/test_stacks.py::test_non_existing_stack_message": 0.017700245000014547, + "tests/aws/services/cloudformation/api/test_stacks.py::test_notifications": 0.0013656060000357684, + "tests/aws/services/cloudformation/api/test_stacks.py::test_stack_deletion_order[A-B-C]": 4.303141054999969, + "tests/aws/services/cloudformation/api/test_stacks.py::test_stack_deletion_order[B-C]": 4.357745637999983, + "tests/aws/services/cloudformation/api/test_stacks.py::test_stack_deletion_order[C]": 4.36363145200005, + "tests/aws/services/cloudformation/api/test_stacks.py::test_stack_deploy_order[A-B-C]": 6.3941780439998865, + "tests/aws/services/cloudformation/api/test_stacks.py::test_stack_deploy_order[A-C-B]": 6.417384671999912, + "tests/aws/services/cloudformation/api/test_stacks.py::test_stack_deploy_order[B-A-C]": 6.406346469000027, + "tests/aws/services/cloudformation/api/test_stacks.py::test_stack_deploy_order[B-C-A]": 6.387385734999839, + "tests/aws/services/cloudformation/api/test_stacks.py::test_stack_deploy_order[C-A-B]": 6.401446863999922, + "tests/aws/services/cloudformation/api/test_stacks.py::test_stack_deploy_order[C-B-A]": 6.40824198700011, + "tests/aws/services/cloudformation/api/test_stacks.py::test_stack_resource_not_found": 2.1229699609998534, + "tests/aws/services/cloudformation/api/test_stacks.py::test_update_termination_protection": 2.1878578499998866, + "tests/aws/services/cloudformation/api/test_stacks.py::test_updating_an_updated_stack_sets_status": 10.54534160999981, + "tests/aws/services/cloudformation/api/test_templates.py::test_create_stack_from_s3_template_url[http_host]": 0.16516910999996526, + "tests/aws/services/cloudformation/api/test_templates.py::test_create_stack_from_s3_template_url[http_invalid]": 0.10127567199981513, + "tests/aws/services/cloudformation/api/test_templates.py::test_create_stack_from_s3_template_url[http_path]": 1.1671113730000116, + "tests/aws/services/cloudformation/api/test_templates.py::test_create_stack_from_s3_template_url[s3_url]": 0.10172859800002243, + "tests/aws/services/cloudformation/api/test_templates.py::test_get_template_missing_resources_change_set": 0.014019324999935634, + "tests/aws/services/cloudformation/api/test_templates.py::test_get_template_missing_resources_change_set_id": 0.014410829000098602, + "tests/aws/services/cloudformation/api/test_templates.py::test_get_template_missing_resources_stack": 0.014762304000100812, + "tests/aws/services/cloudformation/api/test_templates.py::test_get_template_summary": 4.25621017200001, + "tests/aws/services/cloudformation/api/test_templates.py::test_get_template_summary_non_executed_change_set": 0.04406099700008781, + "tests/aws/services/cloudformation/api/test_templates.py::test_validate_invalid_json_template_should_fail": 0.0811384389999148, + "tests/aws/services/cloudformation/api/test_templates.py::test_validate_template": 0.07756446200005485, + "tests/aws/services/cloudformation/api/test_transformers.py::TestLanguageExtensionsTransform::test_transform_foreach": 1.2765373019998378, + "tests/aws/services/cloudformation/api/test_transformers.py::TestLanguageExtensionsTransform::test_transform_foreach_multiple_resources": 1.287062479000042, + "tests/aws/services/cloudformation/api/test_transformers.py::TestLanguageExtensionsTransform::test_transform_foreach_use_case": 0.7187638440000228, + "tests/aws/services/cloudformation/api/test_transformers.py::TestLanguageExtensionsTransform::test_transform_length": 1.25983037900005, + "tests/aws/services/cloudformation/api/test_transformers.py::TestLanguageExtensionsTransform::test_transform_to_json_string": 1.2771336899999142, + "tests/aws/services/cloudformation/api/test_transformers.py::test_duplicate_resources": 2.337123980000001, + "tests/aws/services/cloudformation/api/test_transformers.py::test_redeployment_with_fn_include": 4.404611287999842, + "tests/aws/services/cloudformation/api/test_transformers.py::test_transformer_individual_resource_level": 0.22337059300002693, + "tests/aws/services/cloudformation/api/test_transformers.py::test_transformer_property_level": 4.3048543359999485, + "tests/aws/services/cloudformation/api/test_update_stack.py::test_basic_update": 3.1980818490001184, + "tests/aws/services/cloudformation/api/test_update_stack.py::test_diff_after_update": 5.236281359000145, + "tests/aws/services/cloudformation/api/test_update_stack.py::test_no_parameters_update": 3.1766320180000776, + "tests/aws/services/cloudformation/api/test_update_stack.py::test_no_template_error": 0.0012510779998819999, + "tests/aws/services/cloudformation/api/test_update_stack.py::test_set_notification_arn_with_update": 0.0013314389999550258, + "tests/aws/services/cloudformation/api/test_update_stack.py::test_update_tags": 0.0012567379999381956, + "tests/aws/services/cloudformation/api/test_update_stack.py::test_update_using_template_url": 3.253050607999967, + "tests/aws/services/cloudformation/api/test_update_stack.py::test_update_with_capabilities[capability0]": 0.0012752530000170736, + "tests/aws/services/cloudformation/api/test_update_stack.py::test_update_with_capabilities[capability1]": 0.0013630089999878692, + "tests/aws/services/cloudformation/api/test_update_stack.py::test_update_with_invalid_rollback_configuration_errors": 0.0013736480000261508, + "tests/aws/services/cloudformation/api/test_update_stack.py::test_update_with_previous_parameter_value": 0.14219253900000695, + "tests/aws/services/cloudformation/api/test_update_stack.py::test_update_with_previous_template": 0.0015657689999670765, + "tests/aws/services/cloudformation/api/test_update_stack.py::test_update_with_resource_types": 0.0013220510001019647, + "tests/aws/services/cloudformation/api/test_update_stack.py::test_update_with_role_without_permissions": 0.0014732760000697454, + "tests/aws/services/cloudformation/api/test_update_stack.py::test_update_with_rollback_configuration": 0.0013093370000660798, + "tests/aws/services/cloudformation/api/test_validations.py::test_invalid_output_structure[missing-def]": 0.0012777979999327727, + "tests/aws/services/cloudformation/api/test_validations.py::test_invalid_output_structure[multiple-nones]": 0.001243515000055595, + "tests/aws/services/cloudformation/api/test_validations.py::test_invalid_output_structure[none-value]": 0.0014904480001405318, + "tests/aws/services/cloudformation/api/test_validations.py::test_missing_resources_block": 0.0012547750000067026, + "tests/aws/services/cloudformation/api/test_validations.py::test_resources_blocks[invalid-key]": 0.0013734779998912927, + "tests/aws/services/cloudformation/api/test_validations.py::test_resources_blocks[missing-type]": 0.0013267199999518198, + "tests/aws/services/cloudformation/engine/test_attributes.py::TestResourceAttributes::test_dependency_on_attribute_with_dot_notation": 4.137238700000012, + "tests/aws/services/cloudformation/engine/test_attributes.py::TestResourceAttributes::test_invalid_getatt_fails": 0.001252722999879552, + "tests/aws/services/cloudformation/engine/test_conditions.py::TestCloudFormationConditions::test_condition_on_outputs": 4.165156610000054, + "tests/aws/services/cloudformation/engine/test_conditions.py::TestCloudFormationConditions::test_conditional_att_to_conditional_resources[create]": 4.1715636259999656, + "tests/aws/services/cloudformation/engine/test_conditions.py::TestCloudFormationConditions::test_conditional_att_to_conditional_resources[no-create]": 4.159586366999974, + "tests/aws/services/cloudformation/engine/test_conditions.py::TestCloudFormationConditions::test_conditional_in_conditional[dev-us-west-2]": 4.15645468699995, + "tests/aws/services/cloudformation/engine/test_conditions.py::TestCloudFormationConditions::test_conditional_in_conditional[production-us-east-1]": 4.1565657690000535, + "tests/aws/services/cloudformation/engine/test_conditions.py::TestCloudFormationConditions::test_conditional_with_select": 4.146686298999953, + "tests/aws/services/cloudformation/engine/test_conditions.py::TestCloudFormationConditions::test_dependency_in_non_evaluated_if_branch[None-FallbackParamValue]": 4.175571267999999, + "tests/aws/services/cloudformation/engine/test_conditions.py::TestCloudFormationConditions::test_dependency_in_non_evaluated_if_branch[false-DefaultParamValue]": 4.164219216999982, + "tests/aws/services/cloudformation/engine/test_conditions.py::TestCloudFormationConditions::test_dependent_ref": 0.0014985720000595393, + "tests/aws/services/cloudformation/engine/test_conditions.py::TestCloudFormationConditions::test_dependent_ref_intrinsic_fn_condition": 0.0012824169999703372, + "tests/aws/services/cloudformation/engine/test_conditions.py::TestCloudFormationConditions::test_dependent_ref_with_macro": 0.0012421309999126606, + "tests/aws/services/cloudformation/engine/test_conditions.py::TestCloudFormationConditions::test_nested_conditions[prod-bucket-policy]": 0.001226452000082645, + "tests/aws/services/cloudformation/engine/test_conditions.py::TestCloudFormationConditions::test_nested_conditions[prod-nobucket-nopolicy]": 0.00126094600000215, + "tests/aws/services/cloudformation/engine/test_conditions.py::TestCloudFormationConditions::test_nested_conditions[test-bucket-nopolicy]": 0.0013150480000376774, + "tests/aws/services/cloudformation/engine/test_conditions.py::TestCloudFormationConditions::test_nested_conditions[test-nobucket-nopolicy]": 0.001276625999935277, + "tests/aws/services/cloudformation/engine/test_conditions.py::TestCloudFormationConditions::test_output_reference_to_skipped_resource": 0.0012213420000080077, + "tests/aws/services/cloudformation/engine/test_conditions.py::TestCloudFormationConditions::test_simple_condition_evaluation_deploys_resource": 0.1266208590000133, + "tests/aws/services/cloudformation/engine/test_conditions.py::TestCloudFormationConditions::test_simple_condition_evaluation_doesnt_deploy_resource": 0.10141634600006455, + "tests/aws/services/cloudformation/engine/test_conditions.py::TestCloudFormationConditions::test_simple_intrinsic_fn_condition_evaluation[nope]": 4.136201971999981, + "tests/aws/services/cloudformation/engine/test_conditions.py::TestCloudFormationConditions::test_simple_intrinsic_fn_condition_evaluation[yep]": 2.1237331290000157, + "tests/aws/services/cloudformation/engine/test_conditions.py::TestCloudFormationConditions::test_sub_in_conditions": 4.189682816999948, + "tests/aws/services/cloudformation/engine/test_conditions.py::TestCloudFormationConditions::test_update_conditions": 8.354058769999938, + "tests/aws/services/cloudformation/engine/test_mappings.py::TestCloudFormationMappings::test_async_mapping_error_first_level_v2": 0.025360976000001756, + "tests/aws/services/cloudformation/engine/test_mappings.py::TestCloudFormationMappings::test_async_mapping_error_second_level_v2": 0.023679225000023507, + "tests/aws/services/cloudformation/engine/test_mappings.py::TestCloudFormationMappings::test_aws_refs_in_mappings": 2.133420092999927, + "tests/aws/services/cloudformation/engine/test_mappings.py::TestCloudFormationMappings::test_mapping_maximum_nesting_depth": 0.0014187719998517423, + "tests/aws/services/cloudformation/engine/test_mappings.py::TestCloudFormationMappings::test_mapping_minimum_nesting_depth": 0.001293928999871241, + "tests/aws/services/cloudformation/engine/test_mappings.py::TestCloudFormationMappings::test_mapping_ref_map_key[should-deploy]": 4.161171374999867, + "tests/aws/services/cloudformation/engine/test_mappings.py::TestCloudFormationMappings::test_mapping_ref_map_key[should-not-deploy]": 4.144934368000008, + "tests/aws/services/cloudformation/engine/test_mappings.py::TestCloudFormationMappings::test_mapping_with_invalid_refs": 0.001371194000057585, + "tests/aws/services/cloudformation/engine/test_mappings.py::TestCloudFormationMappings::test_mapping_with_nonexisting_key": 0.0014664020000054734, + "tests/aws/services/cloudformation/engine/test_mappings.py::TestCloudFormationMappings::test_simple_mapping_working": 0.1355105000001231, + "tests/aws/services/cloudformation/engine/test_references.py::TestDependsOn::test_depends_on_with_missing_reference": 0.001410466999914206, + "tests/aws/services/cloudformation/engine/test_references.py::TestFnSub::test_fn_sub_cases": 4.1788247969999475, + "tests/aws/services/cloudformation/engine/test_references.py::TestFnSub::test_non_string_parameter_in_sub": 4.152975798000057, + "tests/aws/services/cloudformation/engine/test_references.py::TestPseudoParameters::test_stack_id": 4.152600853999957, + "tests/aws/services/cloudformation/engine/test_references.py::test_aws_novalue[no]": 4.1535521920000065, + "tests/aws/services/cloudformation/engine/test_references.py::test_aws_novalue[yes]": 4.157548119999888, + "tests/aws/services/cloudformation/engine/test_references.py::test_resolve_transitive_placeholders_in_strings": 4.161505732000023, + "tests/aws/services/cloudformation/engine/test_references.py::test_useful_error_when_invalid_ref": 0.019521310000072845, + "tests/aws/services/cloudformation/resource_providers/ec2/aws_ec2_networkacl/test_basic.py::TestBasicCRD::test_black_box": 6.6140516240000125, + "tests/aws/services/cloudformation/resource_providers/ec2/test_ec2_resource_provider.py::test_deploy_instance_with_key_pair": 6.479124407000199, + "tests/aws/services/cloudformation/resource_providers/ec2/test_ec2_resource_provider.py::test_deploy_prefix_list": 8.20703760299989, + "tests/aws/services/cloudformation/resource_providers/ec2/test_ec2_resource_provider.py::test_deploy_security_group_with_tags": 2.1464800029998514, + "tests/aws/services/cloudformation/resource_providers/ec2/test_ec2_resource_provider.py::test_deploy_vpc_endpoint": 4.625849566999932, + "tests/aws/services/cloudformation/resource_providers/iam/aws_iam_user/test_basic_user.py::TestBasicCRD::test_autogenerated_values": 4.151636282000027, + "tests/aws/services/cloudformation/resource_providers/iam/aws_iam_user/test_basic_user.py::TestBasicCRD::test_black_box": 2.197229077999964, + "tests/aws/services/cloudformation/resource_providers/iam/aws_iam_user/test_basic_user.py::TestBasicCRD::test_getatt": 4.200119262000044, + "tests/aws/services/cloudformation/resource_providers/iam/aws_iam_user/test_basic_user.py::TestUpdates::test_update_without_replacement": 0.001651728000069852, + "tests/aws/services/cloudformation/resource_providers/iam/aws_iam_user/test_exploration.py::TestAttributeAccess::test_getatt[Arn]": 0.0013811910000640637, + "tests/aws/services/cloudformation/resource_providers/iam/aws_iam_user/test_exploration.py::TestAttributeAccess::test_getatt[Id]": 0.001353188000166483, + "tests/aws/services/cloudformation/resource_providers/iam/aws_iam_user/test_exploration.py::TestAttributeAccess::test_getatt[Path]": 0.0012658949997330637, + "tests/aws/services/cloudformation/resource_providers/iam/aws_iam_user/test_exploration.py::TestAttributeAccess::test_getatt[PermissionsBoundary]": 0.0012701129999186378, + "tests/aws/services/cloudformation/resource_providers/iam/aws_iam_user/test_exploration.py::TestAttributeAccess::test_getatt[UserName]": 0.00126517400008197, + "tests/aws/services/cloudformation/resource_providers/iam/aws_iam_user/test_parity.py::TestParity::test_create_with_full_properties": 2.3437178450003557, + "tests/aws/services/cloudformation/resource_providers/iam/test_iam.py::test_cfn_handle_iam_role_resource_no_role_name": 4.180303478999804, + "tests/aws/services/cloudformation/resource_providers/iam/test_iam.py::test_delete_role_detaches_role_policy": 8.319186326999898, + "tests/aws/services/cloudformation/resource_providers/iam/test_iam.py::test_iam_user_access_key": 8.340515252999694, + "tests/aws/services/cloudformation/resource_providers/iam/test_iam.py::test_iam_username_defaultname": 2.180155017000061, + "tests/aws/services/cloudformation/resource_providers/iam/test_iam.py::test_managed_policy_with_empty_resource": 4.4238964660000875, + "tests/aws/services/cloudformation/resource_providers/iam/test_iam.py::test_policy_attachments": 4.30654615599974, + "tests/aws/services/cloudformation/resource_providers/iam/test_iam.py::test_server_certificate": 2.2540401740000107, + "tests/aws/services/cloudformation/resource_providers/iam/test_iam.py::test_update_inline_policy": 8.421094074999928, + "tests/aws/services/cloudformation/resource_providers/iam/test_iam.py::test_updating_stack_with_iam_role": 16.363797130999956, + "tests/aws/services/cloudformation/resource_providers/opensearch/test_domain.py::TestAttributeAccess::test_getattr[Arn]": 0.001231880999966961, + "tests/aws/services/cloudformation/resource_providers/opensearch/test_domain.py::TestAttributeAccess::test_getattr[DomainArn]": 0.0013240129999303463, + "tests/aws/services/cloudformation/resource_providers/opensearch/test_domain.py::TestAttributeAccess::test_getattr[DomainEndpoint]": 0.001354239999955098, + "tests/aws/services/cloudformation/resource_providers/opensearch/test_domain.py::TestAttributeAccess::test_getattr[DomainName]": 0.0016851209998094419, + "tests/aws/services/cloudformation/resource_providers/opensearch/test_domain.py::TestAttributeAccess::test_getattr[EngineVersion]": 0.001278217999924891, + "tests/aws/services/cloudformation/resource_providers/opensearch/test_domain.py::TestAttributeAccess::test_getattr[Id]": 0.001330916000142679, + "tests/aws/services/cloudformation/resource_providers/scheduler/test_scheduler.py::test_schedule_and_group": 4.45412737200013, + "tests/aws/services/cloudformation/resource_providers/ssm/test_parameter.py::TestBasicCRD::test_black_box": 0.00172058700013622, + "tests/aws/services/cloudformation/resource_providers/ssm/test_parameter.py::TestUpdates::test_update_without_replacement": 0.0012627999999494932, + "tests/aws/services/cloudformation/resource_providers/ssm/test_parameter_getatt_exploration.py::TestAttributeAccess::test_getattr[AllowedPattern]": 0.0012639199999284756, + "tests/aws/services/cloudformation/resource_providers/ssm/test_parameter_getatt_exploration.py::TestAttributeAccess::test_getattr[DataType]": 0.0012954500000432745, + "tests/aws/services/cloudformation/resource_providers/ssm/test_parameter_getatt_exploration.py::TestAttributeAccess::test_getattr[Description]": 0.0012519689998953254, + "tests/aws/services/cloudformation/resource_providers/ssm/test_parameter_getatt_exploration.py::TestAttributeAccess::test_getattr[Id]": 0.0012483120001434145, + "tests/aws/services/cloudformation/resource_providers/ssm/test_parameter_getatt_exploration.py::TestAttributeAccess::test_getattr[Name]": 0.0012446750001799955, + "tests/aws/services/cloudformation/resource_providers/ssm/test_parameter_getatt_exploration.py::TestAttributeAccess::test_getattr[Policies]": 0.0012754919998769765, + "tests/aws/services/cloudformation/resource_providers/ssm/test_parameter_getatt_exploration.py::TestAttributeAccess::test_getattr[Tier]": 0.001262076999864803, + "tests/aws/services/cloudformation/resource_providers/ssm/test_parameter_getatt_exploration.py::TestAttributeAccess::test_getattr[Type]": 0.0012562859999434295, + "tests/aws/services/cloudformation/resource_providers/ssm/test_parameter_getatt_exploration.py::TestAttributeAccess::test_getattr[Value]": 0.001272166000035213, + "tests/aws/services/cloudformation/resources/test_acm.py::test_cfn_acm_certificate": 2.1173333429999275, + "tests/aws/services/cloudformation/resources/test_apigateway.py::TestServerlessApigwLambda::test_serverless_like_deployment_with_update": 9.4983547610002, + "tests/aws/services/cloudformation/resources/test_apigateway.py::test_account": 4.222376223000083, + "tests/aws/services/cloudformation/resources/test_apigateway.py::test_api_gateway_with_policy_as_dict": 2.1449203789998137, + "tests/aws/services/cloudformation/resources/test_apigateway.py::test_apigateway_deployment_canary_settings": 4.274206154000012, + "tests/aws/services/cloudformation/resources/test_apigateway.py::test_cfn_apigateway_aws_integration": 2.311353435999763, + "tests/aws/services/cloudformation/resources/test_apigateway.py::test_cfn_apigateway_rest_api": 4.41301292199978, + "tests/aws/services/cloudformation/resources/test_apigateway.py::test_cfn_apigateway_swagger_import": 4.494508205999864, + "tests/aws/services/cloudformation/resources/test_apigateway.py::test_cfn_deploy_apigateway_from_s3_swagger": 4.532676222999953, + "tests/aws/services/cloudformation/resources/test_apigateway.py::test_cfn_deploy_apigateway_integration": 4.238668605999692, + "tests/aws/services/cloudformation/resources/test_apigateway.py::test_cfn_deploy_apigateway_models": 4.3272567079998225, + "tests/aws/services/cloudformation/resources/test_apigateway.py::test_cfn_with_apigateway_resources": 6.418256917999997, + "tests/aws/services/cloudformation/resources/test_apigateway.py::test_rest_api_serverless_ref_resolving": 9.90875629900006, + "tests/aws/services/cloudformation/resources/test_apigateway.py::test_update_apigateway_stage": 8.606673580999995, + "tests/aws/services/cloudformation/resources/test_apigateway.py::test_update_usage_plan": 14.600022588999764, + "tests/aws/services/cloudformation/resources/test_apigateway.py::test_url_output": 4.18214868899986, + "tests/aws/services/cloudformation/resources/test_cdk.py::TestCdkInit::test_cdk_bootstrap[10]": 4.70298974100001, + "tests/aws/services/cloudformation/resources/test_cdk.py::TestCdkInit::test_cdk_bootstrap[11]": 4.705063898999924, + "tests/aws/services/cloudformation/resources/test_cdk.py::TestCdkInit::test_cdk_bootstrap[12]": 4.719372566000175, + "tests/aws/services/cloudformation/resources/test_cdk.py::TestCdkInit::test_cdk_bootstrap[28]": 4.825019957999984, + "tests/aws/services/cloudformation/resources/test_cdk.py::TestCdkInit::test_cdk_bootstrap_redeploy[v20]": 3.13943703599989, + "tests/aws/services/cloudformation/resources/test_cdk.py::TestCdkInit::test_cdk_bootstrap_redeploy[v28]": 3.20759565000003, + "tests/aws/services/cloudformation/resources/test_cdk.py::TestCdkSampleApp::test_cdk_sample": 4.433135898000046, + "tests/aws/services/cloudformation/resources/test_cloudformation.py::test_create_macro": 1.2475991829999202, + "tests/aws/services/cloudformation/resources/test_cloudformation.py::test_waitcondition": 4.247003953000103, + "tests/aws/services/cloudformation/resources/test_cloudwatch.py::test_alarm_creation": 4.11753443900011, + "tests/aws/services/cloudformation/resources/test_cloudwatch.py::test_alarm_ext_statistic": 4.192617946000155, + "tests/aws/services/cloudformation/resources/test_cloudwatch.py::test_composite_alarm_creation": 6.470381188999909, + "tests/aws/services/cloudformation/resources/test_dynamodb.py::test_billing_mode_as_conditional[PAY_PER_REQUEST]": 4.432689299000231, + "tests/aws/services/cloudformation/resources/test_dynamodb.py::test_billing_mode_as_conditional[PROVISIONED]": 4.425877864999848, + "tests/aws/services/cloudformation/resources/test_dynamodb.py::test_default_name_for_table": 4.416706745000056, + "tests/aws/services/cloudformation/resources/test_dynamodb.py::test_deploy_stack_with_dynamodb_table": 6.2831660369997735, + "tests/aws/services/cloudformation/resources/test_dynamodb.py::test_global_table": 6.477947327000038, + "tests/aws/services/cloudformation/resources/test_dynamodb.py::test_global_table_with_ttl_and_sse": 4.190461296999956, + "tests/aws/services/cloudformation/resources/test_dynamodb.py::test_globalindex_read_write_provisioned_throughput_dynamodb_table": 4.22975604699991, + "tests/aws/services/cloudformation/resources/test_dynamodb.py::test_table_with_ttl_and_sse": 4.16537280700004, + "tests/aws/services/cloudformation/resources/test_dynamodb.py::test_ttl_cdk": 2.299598031999949, + "tests/aws/services/cloudformation/resources/test_ec2.py::test_cfn_update_ec2_instance_type": 0.0014331259999380563, + "tests/aws/services/cloudformation/resources/test_ec2.py::test_cfn_with_multiple_route_table_associations": 4.588824819000138, + "tests/aws/services/cloudformation/resources/test_ec2.py::test_cfn_with_multiple_route_tables": 4.245242613000073, + "tests/aws/services/cloudformation/resources/test_ec2.py::test_dhcp_options": 2.330296950000047, + "tests/aws/services/cloudformation/resources/test_ec2.py::test_ec2_security_group_id_with_vpc": 4.1783281779999015, + "tests/aws/services/cloudformation/resources/test_ec2.py::test_internet_gateway_ref_and_attr": 4.31606573199997, + "tests/aws/services/cloudformation/resources/test_ec2.py::test_keypair_create_import": 4.250140030000239, + "tests/aws/services/cloudformation/resources/test_ec2.py::test_simple_route_table_creation": 6.313525779999964, + "tests/aws/services/cloudformation/resources/test_ec2.py::test_simple_route_table_creation_without_vpc": 6.293967880000309, + "tests/aws/services/cloudformation/resources/test_ec2.py::test_transit_gateway_attachment": 12.99227860699989, + "tests/aws/services/cloudformation/resources/test_ec2.py::test_vpc_creates_default_sg": 4.650551889999861, + "tests/aws/services/cloudformation/resources/test_ec2.py::test_vpc_gateway_attachment": 4.155121082000051, + "tests/aws/services/cloudformation/resources/test_ec2.py::test_vpc_with_route_table": 6.362862209000241, + "tests/aws/services/cloudformation/resources/test_elasticsearch.py::test_cfn_handle_elasticsearch_domain": 5.869054202999905, + "tests/aws/services/cloudformation/resources/test_events.py::test_cfn_event_api_destination_resource": 20.4463428680001, + "tests/aws/services/cloudformation/resources/test_events.py::test_cfn_event_bus_resource": 6.226091407000013, + "tests/aws/services/cloudformation/resources/test_events.py::test_event_rule_creation_without_target": 2.1473210199997084, + "tests/aws/services/cloudformation/resources/test_events.py::test_event_rule_to_logs": 4.307591508000087, + "tests/aws/services/cloudformation/resources/test_events.py::test_eventbus_policies": 8.31663774899971, + "tests/aws/services/cloudformation/resources/test_events.py::test_eventbus_policy_statement": 4.158356432999881, + "tests/aws/services/cloudformation/resources/test_events.py::test_rule_pattern_transformation": 4.174901840000075, + "tests/aws/services/cloudformation/resources/test_events.py::test_rule_properties": 4.184917601000052, + "tests/aws/services/cloudformation/resources/test_firehose.py::test_firehose_stack_with_kinesis_as_source": 32.506783354999925, + "tests/aws/services/cloudformation/resources/test_integration.py::test_events_sqs_sns_lambda": 15.593235349999986, + "tests/aws/services/cloudformation/resources/test_kinesis.py::test_cfn_handle_kinesis_firehose_resources": 14.345025411000051, + "tests/aws/services/cloudformation/resources/test_kinesis.py::test_default_parameters_kinesis": 12.262631130999807, + "tests/aws/services/cloudformation/resources/test_kinesis.py::test_describe_template": 0.14888456999983646, + "tests/aws/services/cloudformation/resources/test_kinesis.py::test_dynamodb_stream_response_with_cf": 12.273976467999773, + "tests/aws/services/cloudformation/resources/test_kinesis.py::test_kinesis_stream_consumer_creations": 18.282819819999986, + "tests/aws/services/cloudformation/resources/test_kinesis.py::test_stream_creation": 12.289271137999776, + "tests/aws/services/cloudformation/resources/test_kms.py::test_cfn_with_kms_resources": 6.232263468999918, + "tests/aws/services/cloudformation/resources/test_kms.py::test_deploy_stack_with_kms": 6.204588087999809, + "tests/aws/services/cloudformation/resources/test_kms.py::test_kms_key_disabled": 2.14332899899955, + "tests/aws/services/cloudformation/resources/test_lambda.py::TestCfnLambdaDestinations::test_generic_destination_routing[sqs-sqs]": 21.494629775999783, + "tests/aws/services/cloudformation/resources/test_lambda.py::TestCfnLambdaIntegrations::test_cfn_lambda_dynamodb_source": 12.452103505999958, + "tests/aws/services/cloudformation/resources/test_lambda.py::TestCfnLambdaIntegrations::test_cfn_lambda_kinesis_source": 23.42588423799998, + "tests/aws/services/cloudformation/resources/test_lambda.py::TestCfnLambdaIntegrations::test_cfn_lambda_permissions": 9.782929393999893, + "tests/aws/services/cloudformation/resources/test_lambda.py::TestCfnLambdaIntegrations::test_cfn_lambda_sqs_source": 12.05539659200008, + "tests/aws/services/cloudformation/resources/test_lambda.py::TestCfnLambdaIntegrations::test_lambda_dynamodb_event_filter": 9.370127350000303, + "tests/aws/services/cloudformation/resources/test_lambda.py::test_cfn_function_url": 9.367169862000083, + "tests/aws/services/cloudformation/resources/test_lambda.py::test_event_invoke_config": 8.262103927999988, + "tests/aws/services/cloudformation/resources/test_lambda.py::test_lambda_alias": 14.521502121999902, + "tests/aws/services/cloudformation/resources/test_lambda.py::test_lambda_cfn_dead_letter_config_async_invocation": 11.027221931000213, + "tests/aws/services/cloudformation/resources/test_lambda.py::test_lambda_cfn_run": 8.579829952999944, + "tests/aws/services/cloudformation/resources/test_lambda.py::test_lambda_cfn_run_with_empty_string_replacement_deny_list": 14.39437914899986, + "tests/aws/services/cloudformation/resources/test_lambda.py::test_lambda_cfn_run_with_non_empty_string_replacement_deny_list": 12.37610093599983, + "tests/aws/services/cloudformation/resources/test_lambda.py::test_lambda_code_signing_config": 2.2121260529997926, + "tests/aws/services/cloudformation/resources/test_lambda.py::test_lambda_function_tags": 8.535121148999906, + "tests/aws/services/cloudformation/resources/test_lambda.py::test_lambda_layer_crud": 8.304940178000379, + "tests/aws/services/cloudformation/resources/test_lambda.py::test_lambda_logging_config": 8.238738352000155, + "tests/aws/services/cloudformation/resources/test_lambda.py::test_lambda_version": 8.774578849999898, + "tests/aws/services/cloudformation/resources/test_lambda.py::test_lambda_version_provisioned_concurrency": 14.545320326000137, + "tests/aws/services/cloudformation/resources/test_lambda.py::test_lambda_vpc": 0.0017805810002755607, + "tests/aws/services/cloudformation/resources/test_lambda.py::test_lambda_w_dynamodb_event_filter": 11.386835117999908, + "tests/aws/services/cloudformation/resources/test_lambda.py::test_lambda_w_dynamodb_event_filter_update": 12.709736131000227, + "tests/aws/services/cloudformation/resources/test_lambda.py::test_multiple_lambda_permissions_for_singlefn": 8.21350188700012, + "tests/aws/services/cloudformation/resources/test_lambda.py::test_python_lambda_code_deployed_via_s3": 8.683106293000037, + "tests/aws/services/cloudformation/resources/test_lambda.py::test_update_lambda_function": 12.408234104999792, + "tests/aws/services/cloudformation/resources/test_lambda.py::test_update_lambda_function_name": 16.41772111099999, + "tests/aws/services/cloudformation/resources/test_lambda.py::test_update_lambda_permissions": 12.409125654999798, + "tests/aws/services/cloudformation/resources/test_logs.py::test_cfn_handle_log_group_resource": 4.481038537000131, + "tests/aws/services/cloudformation/resources/test_logs.py::test_logstream": 4.1918819790000725, + "tests/aws/services/cloudformation/resources/test_opensearch.py::test_domain": 0.0016306630002418387, + "tests/aws/services/cloudformation/resources/test_opensearch.py::test_domain_with_alternative_types": 19.285289068999873, + "tests/aws/services/cloudformation/resources/test_redshift.py::test_redshift_cluster": 4.143793640999775, + "tests/aws/services/cloudformation/resources/test_resource_groups.py::test_group_defaults": 2.2599653190000026, + "tests/aws/services/cloudformation/resources/test_route53.py::test_create_health_check": 2.2765954470000906, + "tests/aws/services/cloudformation/resources/test_route53.py::test_create_record_set_via_id": 2.2500844759999836, + "tests/aws/services/cloudformation/resources/test_route53.py::test_create_record_set_via_name": 4.2690334790002, + "tests/aws/services/cloudformation/resources/test_route53.py::test_create_record_set_without_resource_record": 4.2310036540000056, + "tests/aws/services/cloudformation/resources/test_s3.py::test_bucket_autoname": 4.16007450300026, + "tests/aws/services/cloudformation/resources/test_s3.py::test_bucket_versioning": 4.160953516000063, + "tests/aws/services/cloudformation/resources/test_s3.py::test_bucketpolicy": 4.30778638400011, + "tests/aws/services/cloudformation/resources/test_s3.py::test_cfn_handle_s3_notification_configuration": 6.235421530000167, + "tests/aws/services/cloudformation/resources/test_s3.py::test_cors_configuration": 4.4985221819997605, + "tests/aws/services/cloudformation/resources/test_s3.py::test_object_lock_configuration": 4.482574827999997, + "tests/aws/services/cloudformation/resources/test_s3.py::test_website_configuration": 2.4667444419999356, + "tests/aws/services/cloudformation/resources/test_sam.py::test_cfn_handle_serverless_api_resource": 8.555735732999892, + "tests/aws/services/cloudformation/resources/test_sam.py::test_sam_policies": 8.303682415999901, + "tests/aws/services/cloudformation/resources/test_sam.py::test_sam_sqs_event": 13.358245395999802, + "tests/aws/services/cloudformation/resources/test_sam.py::test_sam_template": 8.656946364000078, + "tests/aws/services/cloudformation/resources/test_secretsmanager.py::test_cdk_deployment_generates_secret_value_if_no_value_is_provided": 2.333561540000119, + "tests/aws/services/cloudformation/resources/test_secretsmanager.py::test_cfn_handle_secretsmanager_secret": 4.308154777999789, + "tests/aws/services/cloudformation/resources/test_secretsmanager.py::test_cfn_secret_policy[default]": 4.186568650000254, + "tests/aws/services/cloudformation/resources/test_secretsmanager.py::test_cfn_secret_policy[true]": 4.17600065900001, + "tests/aws/services/cloudformation/resources/test_secretsmanager.py::test_cfn_secretsmanager_gen_secret": 4.281105772000046, + "tests/aws/services/cloudformation/resources/test_sns.py::test_deploy_stack_with_sns_topic": 4.241079905000106, + "tests/aws/services/cloudformation/resources/test_sns.py::test_sns_subscription": 4.161976669999831, + "tests/aws/services/cloudformation/resources/test_sns.py::test_sns_subscription_region": 4.251499906999925, + "tests/aws/services/cloudformation/resources/test_sns.py::test_sns_topic_fifo_with_deduplication": 4.334394874000054, + "tests/aws/services/cloudformation/resources/test_sns.py::test_sns_topic_fifo_without_suffix_fails": 1.107051457000125, + "tests/aws/services/cloudformation/resources/test_sns.py::test_sns_topic_policy_resets_to_default": 1.4153283230000397, + "tests/aws/services/cloudformation/resources/test_sns.py::test_sns_topic_update_attributes": 8.565429712000196, + "tests/aws/services/cloudformation/resources/test_sns.py::test_sns_topic_update_name": 8.584190715999966, + "tests/aws/services/cloudformation/resources/test_sns.py::test_sns_topic_with_attributes": 2.2986846329999935, + "tests/aws/services/cloudformation/resources/test_sns.py::test_update_subscription": 8.336254971999779, + "tests/aws/services/cloudformation/resources/test_sqs.py::test_cfn_handle_sqs_resource": 4.1892736419995344, + "tests/aws/services/cloudformation/resources/test_sqs.py::test_sqs_fifo_queue_generates_valid_name": 4.1552736280004865, + "tests/aws/services/cloudformation/resources/test_sqs.py::test_sqs_non_fifo_queue_generates_valid_name": 4.150328796999929, + "tests/aws/services/cloudformation/resources/test_sqs.py::test_sqs_queue_policy": 4.158265520999748, + "tests/aws/services/cloudformation/resources/test_sqs.py::test_update_queue_no_change": 8.29441399300049, + "tests/aws/services/cloudformation/resources/test_sqs.py::test_update_sqs_queuepolicy": 8.313355954999679, + "tests/aws/services/cloudformation/resources/test_ssm.py::test_deploy_patch_baseline": 4.305539447999763, + "tests/aws/services/cloudformation/resources/test_ssm.py::test_maintenance_window": 4.245239149999634, + "tests/aws/services/cloudformation/resources/test_ssm.py::test_parameter_defaults": 6.338836783000261, + "tests/aws/services/cloudformation/resources/test_ssm.py::test_update_ssm_parameter_tag": 8.29931099300029, + "tests/aws/services/cloudformation/resources/test_ssm.py::test_update_ssm_parameters": 8.293914510999912, + "tests/aws/services/cloudformation/resources/test_stack_sets.py::test_create_stack_set_with_stack_instances": 2.290908089999448, + "tests/aws/services/cloudformation/resources/test_stack_sets.py::test_delete_nonexistent_stack_set": 0.023508513999786373, + "tests/aws/services/cloudformation/resources/test_stack_sets.py::test_fetch_non_existent_stack_set_instances": 0.024391292999553116, + "tests/aws/services/cloudformation/resources/test_stepfunctions.py::test_apigateway_invoke": 9.524535716000173, + "tests/aws/services/cloudformation/resources/test_stepfunctions.py::test_apigateway_invoke_localhost": 9.570091989999128, + "tests/aws/services/cloudformation/resources/test_stepfunctions.py::test_apigateway_invoke_localhost_with_path": 15.629601222999554, + "tests/aws/services/cloudformation/resources/test_stepfunctions.py::test_apigateway_invoke_with_path": 15.593536947999837, + "tests/aws/services/cloudformation/resources/test_stepfunctions.py::test_cfn_statemachine_default_s3_location": 8.837343675999819, + "tests/aws/services/cloudformation/resources/test_stepfunctions.py::test_cfn_statemachine_with_dependencies": 6.244419001999631, + "tests/aws/services/cloudformation/resources/test_stepfunctions.py::test_nested_statemachine_with_sync2": 17.424246233000304, + "tests/aws/services/cloudformation/resources/test_stepfunctions.py::test_retry_and_catch": 0.0023174980001385848, + "tests/aws/services/cloudformation/resources/test_stepfunctions.py::test_statemachine_create_with_logging_configuration": 4.57907960700004, + "tests/aws/services/cloudformation/resources/test_stepfunctions.py::test_statemachine_definitionsubstitution": 9.275738479999745, + "tests/aws/services/cloudformation/test_change_set_conditions.py::TestChangeSetConditions::test_condition_add_new_negative_condition_to_existent_resource": 3.852487669999846, + "tests/aws/services/cloudformation/test_change_set_conditions.py::TestChangeSetConditions::test_condition_add_new_positive_condition_to_existent_resource": 2.8825359309994383, + "tests/aws/services/cloudformation/test_change_set_conditions.py::TestChangeSetConditions::test_condition_update_adds_resource": 3.913376287999654, + "tests/aws/services/cloudformation/test_change_set_conditions.py::TestChangeSetConditions::test_condition_update_removes_resource": 2.8896183710003243, + "tests/aws/services/cloudformation/test_change_set_depends_on.py::TestChangeSetDependsOn::test_multiple_dependencies_addition": 3.9378374019993316, + "tests/aws/services/cloudformation/test_change_set_depends_on.py::TestChangeSetDependsOn::test_multiple_dependencies_deletion": 2.9164099049999095, + "tests/aws/services/cloudformation/test_change_set_depends_on.py::TestChangeSetDependsOn::test_update_depended_resource": 3.935985683999661, + "tests/aws/services/cloudformation/test_change_set_depends_on.py::TestChangeSetDependsOn::test_update_depended_resource_list": 3.901446407000094, + "tests/aws/services/cloudformation/test_change_set_exports_imports.py::TestChangeSetImportExport::test_describe_change_set_import": 10.501941236999755, + "tests/aws/services/cloudformation/test_change_set_exports_imports.py::TestChangeSetImportExport::test_describe_change_set_import_non_existent_export": 0.47280953899962697, + "tests/aws/services/cloudformation/test_change_set_exports_imports.py::TestChangeSetImportExport::test_describe_change_set_import_non_existent_export_then_create": 10.503031676999854, + "tests/aws/services/cloudformation/test_change_set_fn_base64.py::TestChangeSetFnBase64::test_fn_base64_add_to_static_property": 1.7679006319999644, + "tests/aws/services/cloudformation/test_change_set_fn_base64.py::TestChangeSetFnBase64::test_fn_base64_change_input_string": 3.816246033999505, + "tests/aws/services/cloudformation/test_change_set_fn_base64.py::TestChangeSetFnBase64::test_fn_base64_remove_from_static_property": 2.7898777150003298, + "tests/aws/services/cloudformation/test_change_set_fn_get_attr.py::TestChangeSetFnGetAttr::test_direct_attribute_value_change": 3.9874643329999344, + "tests/aws/services/cloudformation/test_change_set_fn_get_attr.py::TestChangeSetFnGetAttr::test_direct_attribute_value_change_in_get_attr_chain": 4.045227463000174, + "tests/aws/services/cloudformation/test_change_set_fn_get_attr.py::TestChangeSetFnGetAttr::test_direct_attribute_value_change_with_dependent_addition": 3.9940154119999534, + "tests/aws/services/cloudformation/test_change_set_fn_get_attr.py::TestChangeSetFnGetAttr::test_immutable_property_update_causes_resource_replacement": 3.9891151009996975, + "tests/aws/services/cloudformation/test_change_set_fn_get_attr.py::TestChangeSetFnGetAttr::test_resource_addition": 2.893346072999975, + "tests/aws/services/cloudformation/test_change_set_fn_get_attr.py::TestChangeSetFnGetAttr::test_resource_deletion": 0.0014976679999563203, + "tests/aws/services/cloudformation/test_change_set_fn_join.py::TestChangeSetFnJoin::test_indirect_update_refence_argument": 3.9784737679997306, + "tests/aws/services/cloudformation/test_change_set_fn_join.py::TestChangeSetFnJoin::test_update_refence_argument": 3.967565198000102, + "tests/aws/services/cloudformation/test_change_set_fn_join.py::TestChangeSetFnJoin::test_update_string_literal_argument": 2.8660770610003965, + "tests/aws/services/cloudformation/test_change_set_fn_join.py::TestChangeSetFnJoin::test_update_string_literal_arguments_empty": 1.9251459209995119, + "tests/aws/services/cloudformation/test_change_set_fn_join.py::TestChangeSetFnJoin::test_update_string_literal_delimiter": 2.8773825289999877, + "tests/aws/services/cloudformation/test_change_set_fn_join.py::TestChangeSetFnJoin::test_update_string_literal_delimiter_empty": 2.859027580000202, + "tests/aws/services/cloudformation/test_change_set_fn_select.py::TestChangeSetFnSelect::test_fn_select_add_to_static_property": 2.846093037999708, + "tests/aws/services/cloudformation/test_change_set_fn_select.py::TestChangeSetFnSelect::test_fn_select_change_get_att_reference": 3.963067651000074, + "tests/aws/services/cloudformation/test_change_set_fn_select.py::TestChangeSetFnSelect::test_fn_select_change_in_selected_element_type_ref": 2.8471507509998446, + "tests/aws/services/cloudformation/test_change_set_fn_select.py::TestChangeSetFnSelect::test_fn_select_change_in_selection_index_only": 1.8343889600000693, + "tests/aws/services/cloudformation/test_change_set_fn_select.py::TestChangeSetFnSelect::test_fn_select_change_in_selection_list": 5.271533923999868, + "tests/aws/services/cloudformation/test_change_set_fn_select.py::TestChangeSetFnSelect::test_fn_select_remove_from_static_property": 3.8580872649999947, + "tests/aws/services/cloudformation/test_change_set_fn_select.py::TestChangeSetFnSelect::test_invalid_select_index_type[index-out-of-range]": 0.5455008059998363, + "tests/aws/services/cloudformation/test_change_set_fn_select.py::TestChangeSetFnSelect::test_invalid_select_index_type[non-integer-index]": 0.5517491329997029, + "tests/aws/services/cloudformation/test_change_set_fn_select.py::TestChangeSetFnSelect::test_invalid_select_index_type[non-list-list]": 0.5451639419998173, + "tests/aws/services/cloudformation/test_change_set_fn_select.py::TestChangeSetFnSelect::test_nested_select_within_other_intrinsics": 4.672090331000163, + "tests/aws/services/cloudformation/test_change_set_fn_split.py::TestChangeSetFnSplit::test_fn_split_add_to_static_property": 3.911025702000188, + "tests/aws/services/cloudformation/test_change_set_fn_split.py::TestChangeSetFnSplit::test_fn_split_change_delimiter": 2.9090728539999873, + "tests/aws/services/cloudformation/test_change_set_fn_split.py::TestChangeSetFnSplit::test_fn_split_change_source_string_only": 2.923613397000281, + "tests/aws/services/cloudformation/test_change_set_fn_split.py::TestChangeSetFnSplit::test_fn_split_remove_from_static_property": 2.9566623000005166, + "tests/aws/services/cloudformation/test_change_set_fn_split.py::TestChangeSetFnSplit::test_fn_split_with_get_att": 4.071247751000101, + "tests/aws/services/cloudformation/test_change_set_fn_split.py::TestChangeSetFnSplit::test_fn_split_with_ref_as_string_source": 3.9328008679999584, + "tests/aws/services/cloudformation/test_change_set_fn_sub.py::TestChangeSetFnSub::test_fn_sub_addition_parameter": 1.842570403000991, + "tests/aws/services/cloudformation/test_change_set_fn_sub.py::TestChangeSetFnSub::test_fn_sub_addition_parameter_literal": 2.8529626509998707, + "tests/aws/services/cloudformation/test_change_set_fn_sub.py::TestChangeSetFnSub::test_fn_sub_addition_parameter_ref": 3.900861778000035, + "tests/aws/services/cloudformation/test_change_set_fn_sub.py::TestChangeSetFnSub::test_fn_sub_addition_string_pseudo": 2.852985227999852, + "tests/aws/services/cloudformation/test_change_set_fn_sub.py::TestChangeSetFnSub::test_fn_sub_delete_parameter_literal": 2.875126079000438, + "tests/aws/services/cloudformation/test_change_set_fn_sub.py::TestChangeSetFnSub::test_fn_sub_delete_string_pseudo": 2.858295843000178, + "tests/aws/services/cloudformation/test_change_set_fn_sub.py::TestChangeSetFnSub::test_fn_sub_update_parameter_literal": 0.8303112730000066, + "tests/aws/services/cloudformation/test_change_set_fn_sub.py::TestChangeSetFnSub::test_fn_sub_update_parameter_type": 0.8620797470002799, + "tests/aws/services/cloudformation/test_change_set_fn_sub.py::TestChangeSetFnSub::test_fn_sub_update_string_pseudo": 2.846744931000103, + "tests/aws/services/cloudformation/test_change_set_fn_transform.py::TestChangeSetFnTransform::test_conditional_transform[false]": 4.521830470000168, + "tests/aws/services/cloudformation/test_change_set_fn_transform.py::TestChangeSetFnTransform::test_conditional_transform[true]": 5.604272257000503, + "tests/aws/services/cloudformation/test_change_set_fn_transform.py::TestChangeSetFnTransform::test_embedded_fn_transform_include[json]": 4.109979316000135, + "tests/aws/services/cloudformation/test_change_set_fn_transform.py::TestChangeSetFnTransform::test_embedded_fn_transform_include[yml]": 4.126937362999797, + "tests/aws/services/cloudformation/test_change_set_fn_transform.py::TestChangeSetFnTransform::test_embedded_macro_fn_transform": 5.607566508000218, + "tests/aws/services/cloudformation/test_change_set_fn_transform.py::TestChangeSetFnTransform::test_embedded_macro_for_attribute_fn_transform": 5.691895460000524, + "tests/aws/services/cloudformation/test_change_set_fn_transform.py::TestChangeSetFnTransform::test_global_fn_transform_include[json]": 2.942868945999635, + "tests/aws/services/cloudformation/test_change_set_fn_transform.py::TestChangeSetFnTransform::test_global_fn_transform_include[yml]": 2.9560577960000955, + "tests/aws/services/cloudformation/test_change_set_fn_transform.py::TestChangeSetFnTransform::test_global_macro_fn_transform": 5.59008060799988, + "tests/aws/services/cloudformation/test_change_set_fn_transform.py::TestChangeSetFnTransform::test_macro_with_intrinsic_function": 5.5888923409997915, + "tests/aws/services/cloudformation/test_change_set_fn_transform.py::TestChangeSetFnTransform::test_multiple_fn_transform_order": 5.803185232000033, + "tests/aws/services/cloudformation/test_change_set_fn_transform.py::TestChangeSetFnTransform::test_remove_transform_in_update_change_set": 5.565634921999845, + "tests/aws/services/cloudformation/test_change_set_fn_transform.py::TestChangeSetFnTransform::test_serverless_fn_transform": 9.391267123999569, + "tests/aws/services/cloudformation/test_change_set_fn_transform.py::TestChangeSetFnTransform::test_update_parameter_transform_in_update_change_set": 5.748311000000285, + "tests/aws/services/cloudformation/test_change_set_global_macros.py::TestChangeSetGlobalMacros::test_base_global_macro": 5.670586058000026, + "tests/aws/services/cloudformation/test_change_set_global_macros.py::TestChangeSetGlobalMacros::test_update_after_macro_for_before_version_is_deleted": 7.249163078000038, + "tests/aws/services/cloudformation/test_change_set_mappings.py::TestChangeSetMappings::test_mapping_addition_with_resource": 3.8917238110002472, + "tests/aws/services/cloudformation/test_change_set_mappings.py::TestChangeSetMappings::test_mapping_deletion_with_resource_remap": 3.925201976000153, + "tests/aws/services/cloudformation/test_change_set_mappings.py::TestChangeSetMappings::test_mapping_key_addition_with_resource": 3.8973306469997624, + "tests/aws/services/cloudformation/test_change_set_mappings.py::TestChangeSetMappings::test_mapping_key_deletion_with_resource_remap": 3.90968757499968, + "tests/aws/services/cloudformation/test_change_set_mappings.py::TestChangeSetMappings::test_mapping_key_update": 0.8733115880004334, + "tests/aws/services/cloudformation/test_change_set_mappings.py::TestChangeSetMappings::test_mapping_leaf_update": 2.861294906999774, + "tests/aws/services/cloudformation/test_change_set_parameters.py::TestChangeSetParameters::test_update_parameter_default_value": 2.8603763579999395, + "tests/aws/services/cloudformation/test_change_set_parameters.py::TestChangeSetParameters::test_update_parameter_default_value_with_dynamic_overrides": 2.8625361350004823, + "tests/aws/services/cloudformation/test_change_set_parameters.py::TestChangeSetParameters::test_update_parameter_with_added_default_value": 2.886203063999801, + "tests/aws/services/cloudformation/test_change_set_parameters.py::TestChangeSetParameters::test_update_parameter_with_removed_default_value": 2.8602072319995386, + "tests/aws/services/cloudformation/test_change_set_ref.py::TestChangeSetRef::test_direct_attribute_value_change": 3.975856001000011, + "tests/aws/services/cloudformation/test_change_set_ref.py::TestChangeSetRef::test_direct_attribute_value_change_in_ref_chain": 2.998176204000174, + "tests/aws/services/cloudformation/test_change_set_ref.py::TestChangeSetRef::test_direct_attribute_value_change_with_dependent_addition": 3.9625589180000134, + "tests/aws/services/cloudformation/test_change_set_ref.py::TestChangeSetRef::test_immutable_property_update_causes_resource_replacement": 4.090353426000092, + "tests/aws/services/cloudformation/test_change_set_ref.py::TestChangeSetRef::test_resource_addition": 2.932191614999738, + "tests/aws/services/cloudformation/test_change_set_ref.py::TestChangeSetRef::test_supported_pseudo_parameter": 2.8810573279997698, + "tests/aws/services/cloudformation/test_change_set_values.py::TestChangeSetValues::test_property_empy_list": 1.9040150539999559, + "tests/aws/services/cloudformation/test_change_sets.py::TestCaptureUpdateProcess::test_base_dynamic_parameter_scenarios[change_dynamic]": 3.8773958419997143, + "tests/aws/services/cloudformation/test_change_sets.py::TestCaptureUpdateProcess::test_base_dynamic_parameter_scenarios[change_parameter_for_condition_create_resource]": 3.867533692000052, + "tests/aws/services/cloudformation/test_change_sets.py::TestCaptureUpdateProcess::test_base_dynamic_parameter_scenarios[change_unrelated_property]": 0.010046068000065134, + "tests/aws/services/cloudformation/test_change_sets.py::TestCaptureUpdateProcess::test_base_dynamic_parameter_scenarios[change_unrelated_property_not_create_only]": 0.006568897000306606, + "tests/aws/services/cloudformation/test_change_sets.py::TestCaptureUpdateProcess::test_base_mapping_scenarios[update_string_referencing_resource]": 3.855042411999875, + "tests/aws/services/cloudformation/test_change_sets.py::TestCaptureUpdateProcess::test_conditions": 3.902138038999965, + "tests/aws/services/cloudformation/test_change_sets.py::TestCaptureUpdateProcess::test_direct_update": 1.7902702559999852, + "tests/aws/services/cloudformation/test_change_sets.py::TestCaptureUpdateProcess::test_dynamic_update": 3.876543992999814, + "tests/aws/services/cloudformation/test_change_sets.py::TestCaptureUpdateProcess::test_execute_with_ref": 8.790120364000359, + "tests/aws/services/cloudformation/test_change_sets.py::TestCaptureUpdateProcess::test_mappings_with_parameter_lookup": 3.921563021000111, + "tests/aws/services/cloudformation/test_change_sets.py::TestCaptureUpdateProcess::test_mappings_with_static_fields": 3.935851475000163, + "tests/aws/services/cloudformation/test_change_sets.py::TestCaptureUpdateProcess::test_parameter_changes": 3.87846077399945, + "tests/aws/services/cloudformation/test_change_sets.py::TestCaptureUpdateProcess::test_single_resource_static_update": 2.7249994439998773, + "tests/aws/services/cloudformation/test_change_sets.py::TestCaptureUpdateProcess::test_unrelated_changes_requires_replacement": 0.0013544029998229234, + "tests/aws/services/cloudformation/test_change_sets.py::TestCaptureUpdateProcess::test_unrelated_changes_update_propagation": 0.001769887000136805, + "tests/aws/services/cloudformation/test_change_sets.py::test_describe_failed_change_set": 0.1490840589999607, + "tests/aws/services/cloudformation/test_change_sets.py::test_dynamic_ssm_parameter_lookup": 4.013374728999679, + "tests/aws/services/cloudformation/test_change_sets.py::test_dynamic_ssm_parameter_lookup_no_change": 4.0064011099998424, + "tests/aws/services/cloudformation/test_change_sets.py::test_list_change_sets": 4.2180569279994415, + "tests/aws/services/cloudformation/test_cloudformation_ui.py::TestCloudFormationUi::test_get_cloudformation_ui": 0.07812691099979929, + "tests/aws/services/cloudformation/test_cloudtrail_trace.py::test_cloudtrail_trace_example": 0.0013734250001107284, + "tests/aws/services/cloudformation/test_list_stacks.py::test_listing_stacks": 12.676702364000448, + "tests/aws/services/cloudformation/test_template_engine.py::TestImportValues::test_cfn_with_exports": 4.1592686249996405, + "tests/aws/services/cloudformation/test_template_engine.py::TestImportValues::test_import_values_across_stacks": 8.294583342999886, + "tests/aws/services/cloudformation/test_template_engine.py::TestImports::test_stack_imports": 8.314190620999852, + "tests/aws/services/cloudformation/test_template_engine.py::TestIntrinsicFunctions::test_and_or_functions[Fn::And-0-0-False]": 0.11508478399991873, + "tests/aws/services/cloudformation/test_template_engine.py::TestIntrinsicFunctions::test_and_or_functions[Fn::And-0-1-False]": 0.11171747000025789, + "tests/aws/services/cloudformation/test_template_engine.py::TestIntrinsicFunctions::test_and_or_functions[Fn::And-1-0-False]": 0.10837719500023013, + "tests/aws/services/cloudformation/test_template_engine.py::TestIntrinsicFunctions::test_and_or_functions[Fn::And-1-1-True]": 4.170756640999116, + "tests/aws/services/cloudformation/test_template_engine.py::TestIntrinsicFunctions::test_and_or_functions[Fn::Or-0-0-False]": 0.13980295300007128, + "tests/aws/services/cloudformation/test_template_engine.py::TestIntrinsicFunctions::test_and_or_functions[Fn::Or-0-1-True]": 4.204466807000244, + "tests/aws/services/cloudformation/test_template_engine.py::TestIntrinsicFunctions::test_and_or_functions[Fn::Or-1-0-True]": 4.172498845000064, + "tests/aws/services/cloudformation/test_template_engine.py::TestIntrinsicFunctions::test_and_or_functions[Fn::Or-1-1-True]": 4.175012408000839, + "tests/aws/services/cloudformation/test_template_engine.py::TestIntrinsicFunctions::test_base64_sub_and_getatt_functions": 4.152805059000002, + "tests/aws/services/cloudformation/test_template_engine.py::TestIntrinsicFunctions::test_cfn_template_with_short_form_fn_sub": 4.1480926160006675, + "tests/aws/services/cloudformation/test_template_engine.py::TestIntrinsicFunctions::test_cidr_function": 0.0014816659995631198, + "tests/aws/services/cloudformation/test_template_engine.py::TestIntrinsicFunctions::test_find_map_function": 4.144273777999842, + "tests/aws/services/cloudformation/test_template_engine.py::TestIntrinsicFunctions::test_fn_select_has_intrinsic_function": 4.1508775300003435, + "tests/aws/services/cloudformation/test_template_engine.py::TestIntrinsicFunctions::test_get_azs_function[ap-northeast-1]": 4.462874144000125, + "tests/aws/services/cloudformation/test_template_engine.py::TestIntrinsicFunctions::test_get_azs_function[ap-southeast-2]": 4.408131613999558, + "tests/aws/services/cloudformation/test_template_engine.py::TestIntrinsicFunctions::test_get_azs_function[eu-central-1]": 4.330762527000388, + "tests/aws/services/cloudformation/test_template_engine.py::TestIntrinsicFunctions::test_get_azs_function[eu-west-1]": 4.337723859999642, + "tests/aws/services/cloudformation/test_template_engine.py::TestIntrinsicFunctions::test_get_azs_function[us-east-1]": 4.2436663609996685, + "tests/aws/services/cloudformation/test_template_engine.py::TestIntrinsicFunctions::test_get_azs_function[us-east-2]": 4.329648599000393, + "tests/aws/services/cloudformation/test_template_engine.py::TestIntrinsicFunctions::test_get_azs_function[us-west-1]": 4.32769045699979, + "tests/aws/services/cloudformation/test_template_engine.py::TestIntrinsicFunctions::test_get_azs_function[us-west-2]": 4.342231078999703, + "tests/aws/services/cloudformation/test_template_engine.py::TestIntrinsicFunctions::test_join_no_value_construct": 4.159109832000468, + "tests/aws/services/cloudformation/test_template_engine.py::TestIntrinsicFunctions::test_split_length_and_join_functions": 4.198803694999697, + "tests/aws/services/cloudformation/test_template_engine.py::TestIntrinsicFunctions::test_sub_not_ready": 4.170443689999502, + "tests/aws/services/cloudformation/test_template_engine.py::TestIntrinsicFunctions::test_sub_number_type": 2.148120138000195, + "tests/aws/services/cloudformation/test_template_engine.py::TestIntrinsicFunctions::test_to_json_functions": 0.0015495689999625029, + "tests/aws/services/cloudformation/test_template_engine.py::TestMacros::test_attribute_uses_macro": 5.838179292999939, + "tests/aws/services/cloudformation/test_template_engine.py::TestMacros::test_capabilities_requirements": 3.3009925659994224, + "tests/aws/services/cloudformation/test_template_engine.py::TestMacros::test_error_pass_macro_as_reference": 0.025029328000073292, + "tests/aws/services/cloudformation/test_template_engine.py::TestMacros::test_failed_state[raise_error.py]": 1.7007004100000813, + "tests/aws/services/cloudformation/test_template_engine.py::TestMacros::test_failed_state[return_invalid_template.py]": 1.7204820869997093, + "tests/aws/services/cloudformation/test_template_engine.py::TestMacros::test_failed_state[return_unsuccessful_with_message.py]": 1.6783374040001036, + "tests/aws/services/cloudformation/test_template_engine.py::TestMacros::test_failed_state[return_unsuccessful_without_message.py]": 1.708822444999896, + "tests/aws/services/cloudformation/test_template_engine.py::TestMacros::test_functions_and_references_during_transformation": 2.755572017000304, + "tests/aws/services/cloudformation/test_template_engine.py::TestMacros::test_global_scope": 3.1048967510000693, + "tests/aws/services/cloudformation/test_template_engine.py::TestMacros::test_macro_deployment": 1.2637196189998576, + "tests/aws/services/cloudformation/test_template_engine.py::TestMacros::test_pyplate_param_type_list": 12.770031919999838, + "tests/aws/services/cloudformation/test_template_engine.py::TestMacros::test_scope_order_and_parameters": 6.046968432000085, + "tests/aws/services/cloudformation/test_template_engine.py::TestMacros::test_snipped_scope[transformation_snippet_topic.json]": 3.8285572659997342, + "tests/aws/services/cloudformation/test_template_engine.py::TestMacros::test_snipped_scope[transformation_snippet_topic.yml]": 3.8545056870002554, + "tests/aws/services/cloudformation/test_template_engine.py::TestMacros::test_to_validate_template_limit_for_macro": 2.8448701019997316, + "tests/aws/services/cloudformation/test_template_engine.py::TestMacros::test_validate_lambda_internals": 3.1655879940003615, + "tests/aws/services/cloudformation/test_template_engine.py::TestPreviousValues::test_parameter_usepreviousvalue_behavior": 0.0014985800003159966, + "tests/aws/services/cloudformation/test_template_engine.py::TestPseudoParameters::test_stack_id": 4.133407439000166, + "tests/aws/services/cloudformation/test_template_engine.py::TestSecretsManagerParameters::test_resolve_secretsmanager[resolve_secretsmanager.yaml]": 2.1821745890001694, + "tests/aws/services/cloudformation/test_template_engine.py::TestSecretsManagerParameters::test_resolve_secretsmanager[resolve_secretsmanager_full.yaml]": 4.229967042999306, + "tests/aws/services/cloudformation/test_template_engine.py::TestSecretsManagerParameters::test_resolve_secretsmanager[resolve_secretsmanager_partial.yaml]": 4.2149673580001945, + "tests/aws/services/cloudformation/test_template_engine.py::TestSecretsManagerParameters::test_resolve_secretsmanager_with_backslashes": 4.217401008000252, + "tests/aws/services/cloudformation/test_template_engine.py::TestSsmParameters::test_create_change_set_with_ssm_parameter_list": 4.198306694999701, + "tests/aws/services/cloudformation/test_template_engine.py::TestSsmParameters::test_create_stack_with_ssm_parameters": 2.2094691179995607, + "tests/aws/services/cloudformation/test_template_engine.py::TestSsmParameters::test_resolve_ssm": 4.345402657999784, + "tests/aws/services/cloudformation/test_template_engine.py::TestSsmParameters::test_resolve_ssm_missing_parameter": 0.03910567200000514, + "tests/aws/services/cloudformation/test_template_engine.py::TestSsmParameters::test_resolve_ssm_secure": 2.22037949200012, + "tests/aws/services/cloudformation/test_template_engine.py::TestSsmParameters::test_resolve_ssm_with_version": 4.35751766400017, + "tests/aws/services/cloudformation/test_template_engine.py::TestSsmParameters::test_ssm_nested_with_nested_stack": 8.26307751999957, + "tests/aws/services/cloudformation/test_template_engine.py::TestStackEvents::test_invalid_stack_deploy": 2.330583822000335, + "tests/aws/services/cloudformation/test_template_engine.py::TestTypes::test_implicit_type_conversion": 4.185254361000261, + "tests/aws/services/cloudformation/test_unsupported.py::test_unsupported": 4.123089965000418, + "tests/aws/services/cloudformation/v2/test_dynamic_resolving.py::TestSSMParameterValues::test_change_parameter_type": 3.9510530300003666, + "tests/aws/services/cloudformation/v2/test_dynamic_resolving.py::TestSSMParameterValues::test_update_parameter_between_deployments": 3.992286458000308, + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudWatchMultiProtocol::test_basic_operations_multiple_protocols[json]": 2.811158785999993, + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudWatchMultiProtocol::test_basic_operations_multiple_protocols[query]": 3.646497738999983, + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudWatchMultiProtocol::test_basic_operations_multiple_protocols[smithy-rpc-v2-cbor]": 2.210046028999983, + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudWatchMultiProtocol::test_exception_serializing_with_no_shape_in_spec[json]": 0.12727995499997746, + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudWatchMultiProtocol::test_exception_serializing_with_no_shape_in_spec[query]": 0.1065351610000107, + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudWatchMultiProtocol::test_exception_serializing_with_no_shape_in_spec[smithy-rpc-v2-cbor]": 0.07529961800000251, + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudWatchMultiProtocol::test_multi_protocol_client_fixture[json]": 0.01489379300028304, + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudWatchMultiProtocol::test_multi_protocol_client_fixture[query]": 0.015893451000010828, + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudWatchMultiProtocol::test_multi_protocol_client_fixture[smithy-rpc-v2-cbor]": 0.3700452079997376, + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_alarm_lambda_target": 2.773849946000155, + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_anomaly_detector_lifecycle[json]": 0.001240070000221749, + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_anomaly_detector_lifecycle[query]": 0.001256842000202596, + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_anomaly_detector_lifecycle[smithy-rpc-v2-cbor]": 0.0012104739998903824, + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_aws_sqs_metrics_created[json]": 2.4531310379993556, + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_aws_sqs_metrics_created[query]": 2.439698910000061, + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_aws_sqs_metrics_created[smithy-rpc-v2-cbor]": 2.456522087999474, + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_breaching_alarm_actions[json]": 0.8162297150001905, + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_breaching_alarm_actions[query]": 0.8383222089996707, + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_breaching_alarm_actions[smithy-rpc-v2-cbor]": 0.8420433880000928, + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_create_metric_stream[json]": 0.0013510169997061894, + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_create_metric_stream[query]": 0.0014976439997553825, + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_create_metric_stream[smithy-rpc-v2-cbor]": 0.0012795540001206973, + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_dashboard_lifecycle[json]": 0.1391789389999758, + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_dashboard_lifecycle[query]": 0.14652316299998347, + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_dashboard_lifecycle[smithy-rpc-v2-cbor]": 0.14883560900034354, + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_default_ordering[json]": 0.14334177599948816, + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_default_ordering[query]": 0.153504668000096, + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_default_ordering[smithy-rpc-v2-cbor]": 0.14818591000039305, + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_delete_alarm[json]": 0.10272551899970495, + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_delete_alarm[query]": 0.10795680499995797, + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_delete_alarm[smithy-rpc-v2-cbor]": 0.10678845900019951, + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_describe_alarms_converts_date_format_correctly[json]": 0.08555109799999627, + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_describe_alarms_converts_date_format_correctly[query]": 0.0944415680005477, + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_describe_alarms_converts_date_format_correctly[smithy-rpc-v2-cbor]": 0.08652517899963641, + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_describe_minimal_metric_alarm[json]": 0.10349636799992368, + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_describe_minimal_metric_alarm[query]": 0.10725478900030794, + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_describe_minimal_metric_alarm[smithy-rpc-v2-cbor]": 0.10654450599986376, + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_enable_disable_alarm_actions[json]": 1.3290069469999253, + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_enable_disable_alarm_actions[query]": 1.312179400000332, + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_enable_disable_alarm_actions[smithy-rpc-v2-cbor]": 1.3227914430003693, + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_get_metric_data[json]": 2.06617417400048, + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_get_metric_data[query]": 2.069872688000032, + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_get_metric_data[smithy-rpc-v2-cbor]": 2.068143334999604, + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_get_metric_data_different_units_no_unit_in_query[json-metric_data0]": 0.00129936799976349, + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_get_metric_data_different_units_no_unit_in_query[json-metric_data1]": 0.0012749919997077086, + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_get_metric_data_different_units_no_unit_in_query[json-metric_data2]": 0.0012466389998735394, + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_get_metric_data_different_units_no_unit_in_query[query-metric_data0]": 0.001352178000161075, + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_get_metric_data_different_units_no_unit_in_query[query-metric_data1]": 0.0012711340000350901, + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_get_metric_data_different_units_no_unit_in_query[query-metric_data2]": 0.0012878259999524744, + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_get_metric_data_different_units_no_unit_in_query[smithy-rpc-v2-cbor-metric_data0]": 0.0013461150001603528, + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_get_metric_data_different_units_no_unit_in_query[smithy-rpc-v2-cbor-metric_data1]": 0.0013232330002210801, + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_get_metric_data_different_units_no_unit_in_query[smithy-rpc-v2-cbor-metric_data2]": 0.0013275709998197271, + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_get_metric_data_for_multiple_metrics[json]": 1.055730331000177, + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_get_metric_data_for_multiple_metrics[query]": 1.0553739580000183, + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_get_metric_data_for_multiple_metrics[smithy-rpc-v2-cbor]": 1.053150887999891, + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_get_metric_data_pagination[json]": 2.226323171000331, + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_get_metric_data_pagination[query]": 2.2111825159995533, + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_get_metric_data_pagination[smithy-rpc-v2-cbor]": 2.209987622999961, + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_get_metric_data_stats[json-Average]": 0.037183048000315466, + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_get_metric_data_stats[json-Maximum]": 0.03699544000028254, + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_get_metric_data_stats[json-Minimum]": 0.038189097000213224, + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_get_metric_data_stats[json-SampleCount]": 0.040695109000353114, + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_get_metric_data_stats[json-Sum]": 0.04025375800028996, + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_get_metric_data_stats[query-Average]": 0.04390169600037552, + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_get_metric_data_stats[query-Maximum]": 0.04310377599995263, + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_get_metric_data_stats[query-Minimum]": 0.044400484000561846, + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_get_metric_data_stats[query-SampleCount]": 0.04270415900009539, + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_get_metric_data_stats[query-Sum]": 0.04833039700042718, + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_get_metric_data_stats[smithy-rpc-v2-cbor-Average]": 0.03712328499977957, + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_get_metric_data_stats[smithy-rpc-v2-cbor-Maximum]": 0.039108768999994936, + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_get_metric_data_stats[smithy-rpc-v2-cbor-Minimum]": 0.039448419000109425, + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_get_metric_data_stats[smithy-rpc-v2-cbor-SampleCount]": 0.036719717999403656, + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_get_metric_data_stats[smithy-rpc-v2-cbor-Sum]": 0.03708030100051474, + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_get_metric_data_with_different_units[json]": 0.03565284200021779, + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_get_metric_data_with_different_units[query]": 0.03555717800054481, + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_get_metric_data_with_different_units[smithy-rpc-v2-cbor]": 0.03643358099998295, + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_get_metric_data_with_dimensions[json]": 0.04660945300020103, + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_get_metric_data_with_dimensions[query]": 0.04776256500008458, + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_get_metric_data_with_dimensions[smithy-rpc-v2-cbor]": 0.047501840999757405, + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_get_metric_data_with_zero_and_labels[json]": 0.04687158900014765, + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_get_metric_data_with_zero_and_labels[query]": 0.05432309700017868, + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_get_metric_data_with_zero_and_labels[smithy-rpc-v2-cbor]": 0.04814306799971746, + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_get_metric_statistics[json]": 0.19508392699981414, + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_get_metric_statistics[query]": 0.20280797399982475, + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_get_metric_statistics[smithy-rpc-v2-cbor]": 0.18838516400001026, + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_get_metric_with_no_results[json]": 0.04242199799955415, + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_get_metric_with_no_results[query]": 0.06538496999974086, + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_get_metric_with_no_results[smithy-rpc-v2-cbor]": 0.03927711900041686, + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_get_metric_with_null_dimensions[json]": 0.04014669699972728, + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_get_metric_with_null_dimensions[query]": 0.0411520249995192, + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_get_metric_with_null_dimensions[smithy-rpc-v2-cbor]": 0.03782159899947146, + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_handle_different_units[json]": 0.038318341999911354, + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_handle_different_units[query]": 0.03865218799955983, + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_handle_different_units[smithy-rpc-v2-cbor]": 0.03630447300020023, + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_insight_rule[json]": 0.0012025480000374955, + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_insight_rule[query]": 0.0014056810000511177, + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_insight_rule[smithy-rpc-v2-cbor]": 0.001235279999946215, + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_invalid_amount_of_datapoints[json]": 0.5582274770004005, + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_invalid_amount_of_datapoints[query]": 0.5612579469998309, + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_invalid_amount_of_datapoints[smithy-rpc-v2-cbor]": 0.5885494449998987, + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_invalid_dashboard_name[json]": 0.02346306400022513, + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_invalid_dashboard_name[query]": 0.02722180799992202, + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_invalid_dashboard_name[smithy-rpc-v2-cbor]": 0.023649332000331924, + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_label_generation[json-input_pairs0]": 0.037828029000138486, + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_label_generation[json-input_pairs1]": 0.03448540099952879, + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_label_generation[json-input_pairs2]": 0.03442138899981728, + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_label_generation[json-input_pairs3]": 0.0363866370003052, + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_label_generation[json-input_pairs4]": 0.035258117000012135, + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_label_generation[json-input_pairs5]": 0.03389237800001865, + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_label_generation[json-input_pairs6]": 0.03263129200013282, + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_label_generation[query-input_pairs0]": 0.042508270000325865, + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_label_generation[query-input_pairs1]": 0.047804937999899266, + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_label_generation[query-input_pairs2]": 0.04514854000035484, + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_label_generation[query-input_pairs3]": 0.04422484699989582, + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_label_generation[query-input_pairs4]": 0.04235340399964116, + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_label_generation[query-input_pairs5]": 0.04260199800000919, + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_label_generation[query-input_pairs6]": 0.04090263300031438, + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_label_generation[smithy-rpc-v2-cbor-input_pairs0]": 0.04048827600081495, + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_label_generation[smithy-rpc-v2-cbor-input_pairs1]": 0.038895782999588846, + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_label_generation[smithy-rpc-v2-cbor-input_pairs2]": 0.03935646799982351, + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_label_generation[smithy-rpc-v2-cbor-input_pairs3]": 0.03927095900053246, + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_label_generation[smithy-rpc-v2-cbor-input_pairs4]": 0.03670974999977261, + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_label_generation[smithy-rpc-v2-cbor-input_pairs5]": 0.03743298900008085, + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_label_generation[smithy-rpc-v2-cbor-input_pairs6]": 0.03745755600039047, + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_list_metrics_pagination[json]": 6.148744980000174, + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_list_metrics_pagination[query]": 6.315771258000041, + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_list_metrics_pagination[smithy-rpc-v2-cbor]": 5.509591850000106, + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_list_metrics_uniqueness[json]": 2.060155138000482, + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_list_metrics_uniqueness[query]": 2.0651757139999063, + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_list_metrics_uniqueness[smithy-rpc-v2-cbor]": 2.078719511000145, + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_list_metrics_with_filters[json]": 4.077581975000157, + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_list_metrics_with_filters[query]": 4.095830658000068, + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_list_metrics_with_filters[smithy-rpc-v2-cbor]": 4.090703062000102, + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_metric_widget[json]": 0.0012425450004229788, + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_metric_widget[query]": 0.0012268250002307468, + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_metric_widget[smithy-rpc-v2-cbor]": 0.0012336770000729302, + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_multiple_dimensions[json]": 2.10566807000032, + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_multiple_dimensions[query]": 2.1217468469994856, + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_multiple_dimensions[smithy-rpc-v2-cbor]": 2.1227656890000617, + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_multiple_dimensions_statistics[json]": 0.057849103000080504, + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_multiple_dimensions_statistics[query]": 0.06389475800006039, + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_multiple_dimensions_statistics[smithy-rpc-v2-cbor]": 0.0660539560003599, + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_parallel_put_metric_data_list_metrics": 0.2721236060001502, + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_put_composite_alarm_describe_alarms[json]": 0.09896848900007171, + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_put_composite_alarm_describe_alarms[query]": 0.0959065849997387, + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_put_composite_alarm_describe_alarms[smithy-rpc-v2-cbor]": 0.09274994299948958, + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_put_metric_alarm[json]": 10.609439121999912, + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_put_metric_alarm[query]": 10.62192488599976, + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_put_metric_alarm[smithy-rpc-v2-cbor]": 10.610445672000424, + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_put_metric_alarm_escape_character[json]": 0.09014131399999314, + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_put_metric_alarm_escape_character[query]": 0.09353315600037604, + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_put_metric_alarm_escape_character[smithy-rpc-v2-cbor]": 0.08795375600038824, + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_put_metric_data_gzip_with_query_protocol": 0.031797112000276684, + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_put_metric_data_validation[json]": 0.04909554699997898, + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_put_metric_data_validation[query]": 0.05382173400039392, + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_put_metric_data_validation[smithy-rpc-v2-cbor]": 0.05160453600001347, + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_put_metric_data_values_list[json]": 0.030093587000010302, + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_put_metric_data_values_list[query]": 0.03787106000027052, + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_put_metric_data_values_list[smithy-rpc-v2-cbor]": 0.03352613399965776, + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_put_metric_uses_utc[json]": 0.03248876299994663, + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_put_metric_uses_utc[query]": 0.0360369059999357, + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_put_metric_uses_utc[smithy-rpc-v2-cbor]": 0.03371178100042016, + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_raw_metric_data_internal_endpoint": 0.027582355000049574, + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_set_alarm[json]": 2.3574861120000605, + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_set_alarm[query]": 2.351572683000086, + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_set_alarm[smithy-rpc-v2-cbor]": 2.36579844400012, + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_set_alarm_invalid_input[json]": 0.03498397199973624, + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_set_alarm_invalid_input[query]": 0.035157470000285684, + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_set_alarm_invalid_input[smithy-rpc-v2-cbor]": 0.04242645500016806, + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_store_tags[json]": 0.1270491889999903, + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_store_tags[query]": 0.13248689000010927, + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_store_tags[smithy-rpc-v2-cbor]": 0.1322659659999772, + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_trigger_composite_alarm[json]": 4.707727161999628, + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_trigger_composite_alarm[query]": 4.715214482999727, + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_trigger_composite_alarm[smithy-rpc-v2-cbor]": 4.7695376299998316, + "tests/aws/services/cloudwatch/test_cloudwatch_metrics.py::TestCloudWatchLambdaMetrics::test_lambda_invoke_error": 2.7700554059999547, + "tests/aws/services/cloudwatch/test_cloudwatch_metrics.py::TestCloudWatchLambdaMetrics::test_lambda_invoke_successful": 35.651009464, + "tests/aws/services/cloudwatch/test_cloudwatch_metrics.py::TestSQSMetrics::test_alarm_number_of_messages_sent": 61.39199581700001, + "tests/aws/services/cloudwatch/test_cloudwatch_metrics.py::TestSqsApproximateMetrics::test_sqs_approximate_metrics": 61.20439586499998, + "tests/aws/services/dynamodb/test_dynamodb.py::TestDynamoDB::test_batch_write_binary": 0.12465600800004495, + "tests/aws/services/dynamodb/test_dynamodb.py::TestDynamoDB::test_batch_write_items": 0.10691843899996911, + "tests/aws/services/dynamodb/test_dynamodb.py::TestDynamoDB::test_batch_write_items_streaming": 1.1594485540000505, + "tests/aws/services/dynamodb/test_dynamodb.py::TestDynamoDB::test_batch_write_not_existing_table": 0.1410978839999757, + "tests/aws/services/dynamodb/test_dynamodb.py::TestDynamoDB::test_batch_write_not_matching_schema": 0.10197668299991847, + "tests/aws/services/dynamodb/test_dynamodb.py::TestDynamoDB::test_binary_data_with_stream": 2.3523887780000337, + "tests/aws/services/dynamodb/test_dynamodb.py::TestDynamoDB::test_continuous_backup_update": 0.2767921720000004, + "tests/aws/services/dynamodb/test_dynamodb.py::TestDynamoDB::test_create_duplicate_table": 0.11419986199996401, + "tests/aws/services/dynamodb/test_dynamodb.py::TestDynamoDB::test_data_encoding_consistency": 0.968967919000022, + "tests/aws/services/dynamodb/test_dynamodb.py::TestDynamoDB::test_delete_table": 0.153080546999945, + "tests/aws/services/dynamodb/test_dynamodb.py::TestDynamoDB::test_dynamodb_batch_execute_statement": 0.1571138259999998, + "tests/aws/services/dynamodb/test_dynamodb.py::TestDynamoDB::test_dynamodb_create_table_with_class": 0.21218027400004758, + "tests/aws/services/dynamodb/test_dynamodb.py::TestDynamoDB::test_dynamodb_create_table_with_partial_sse_specification": 0.23494120700001986, + "tests/aws/services/dynamodb/test_dynamodb.py::TestDynamoDB::test_dynamodb_create_table_with_sse_specification": 0.07104855099998986, + "tests/aws/services/dynamodb/test_dynamodb.py::TestDynamoDB::test_dynamodb_execute_statement_empy_parameter": 0.10863066599995364, + "tests/aws/services/dynamodb/test_dynamodb.py::TestDynamoDB::test_dynamodb_execute_transaction": 0.3029588950000175, + "tests/aws/services/dynamodb/test_dynamodb.py::TestDynamoDB::test_dynamodb_get_batch_items": 0.09340237899999693, + "tests/aws/services/dynamodb/test_dynamodb.py::TestDynamoDB::test_dynamodb_idempotent_writing": 0.14373054300000376, + "tests/aws/services/dynamodb/test_dynamodb.py::TestDynamoDB::test_dynamodb_partiql_missing": 0.1282570770000575, + "tests/aws/services/dynamodb/test_dynamodb.py::TestDynamoDB::test_dynamodb_pay_per_request": 0.04085504099998616, + "tests/aws/services/dynamodb/test_dynamodb.py::TestDynamoDB::test_dynamodb_stream_records_with_update_item": 0.001584020999985114, + "tests/aws/services/dynamodb/test_dynamodb.py::TestDynamoDB::test_dynamodb_stream_shard_iterator": 0.9230693839999731, + "tests/aws/services/dynamodb/test_dynamodb.py::TestDynamoDB::test_dynamodb_stream_stream_view_type": 1.3593261270000312, + "tests/aws/services/dynamodb/test_dynamodb.py::TestDynamoDB::test_dynamodb_streams_describe_with_exclusive_start_shard_id": 0.8158256819999679, + "tests/aws/services/dynamodb/test_dynamodb.py::TestDynamoDB::test_dynamodb_streams_shard_iterator_format": 2.894835404000048, + "tests/aws/services/dynamodb/test_dynamodb.py::TestDynamoDB::test_dynamodb_update_table_without_sse_specification_change": 0.10831990900004485, + "tests/aws/services/dynamodb/test_dynamodb.py::TestDynamoDB::test_dynamodb_with_kinesis_stream": 1.5318924630000197, + "tests/aws/services/dynamodb/test_dynamodb.py::TestDynamoDB::test_empty_and_binary_values": 0.10278530099998306, + "tests/aws/services/dynamodb/test_dynamodb.py::TestDynamoDB::test_global_tables": 0.10346463299998732, + "tests/aws/services/dynamodb/test_dynamodb.py::TestDynamoDB::test_global_tables_version_2019": 0.5214963909999142, + "tests/aws/services/dynamodb/test_dynamodb.py::TestDynamoDB::test_gsi_with_billing_mode[PAY_PER_REQUEST]": 0.3132016199999157, + "tests/aws/services/dynamodb/test_dynamodb.py::TestDynamoDB::test_gsi_with_billing_mode[PROVISIONED]": 0.28893174500007035, + "tests/aws/services/dynamodb/test_dynamodb.py::TestDynamoDB::test_invalid_query_index": 0.08320743500001981, + "tests/aws/services/dynamodb/test_dynamodb.py::TestDynamoDB::test_kinesis_streaming_destination_crud": 0.5217216089999965, + "tests/aws/services/dynamodb/test_dynamodb.py::TestDynamoDB::test_large_data_download": 0.45255535199993346, + "tests/aws/services/dynamodb/test_dynamodb.py::TestDynamoDB::test_list_tags_of_resource": 0.10883556299995689, + "tests/aws/services/dynamodb/test_dynamodb.py::TestDynamoDB::test_more_than_20_global_secondary_indexes": 0.361744986999895, + "tests/aws/services/dynamodb/test_dynamodb.py::TestDynamoDB::test_multiple_update_expressions": 0.2422053500000061, + "tests/aws/services/dynamodb/test_dynamodb.py::TestDynamoDB::test_non_ascii_chars": 2.6268016579999767, + "tests/aws/services/dynamodb/test_dynamodb.py::TestDynamoDB::test_nosql_workbench_localhost_region": 0.07988597399997843, + "tests/aws/services/dynamodb/test_dynamodb.py::TestDynamoDB::test_query_on_deleted_resource": 0.14557529799998292, + "tests/aws/services/dynamodb/test_dynamodb.py::TestDynamoDB::test_return_values_in_put_item": 0.14289347799996222, + "tests/aws/services/dynamodb/test_dynamodb.py::TestDynamoDB::test_return_values_on_conditions_check_failure": 0.20717741000004253, + "tests/aws/services/dynamodb/test_dynamodb.py::TestDynamoDB::test_stream_destination_records": 14.016551161999985, + "tests/aws/services/dynamodb/test_dynamodb.py::TestDynamoDB::test_streams_on_global_tables": 1.2724665430000073, + "tests/aws/services/dynamodb/test_dynamodb.py::TestDynamoDB::test_time_to_live": 0.258387250999931, + "tests/aws/services/dynamodb/test_dynamodb.py::TestDynamoDB::test_time_to_live_deletion": 0.49361070999998446, + "tests/aws/services/dynamodb/test_dynamodb.py::TestDynamoDB::test_transact_get_items": 0.11351019199997836, + "tests/aws/services/dynamodb/test_dynamodb.py::TestDynamoDB::test_transact_write_items_streaming": 1.274445688999947, + "tests/aws/services/dynamodb/test_dynamodb.py::TestDynamoDB::test_transact_write_items_streaming_for_different_tables": 1.1865290610000443, + "tests/aws/services/dynamodb/test_dynamodb.py::TestDynamoDB::test_transaction_write_binary_data": 0.12717677700004515, + "tests/aws/services/dynamodb/test_dynamodb.py::TestDynamoDB::test_transaction_write_canceled": 0.11547195800005738, + "tests/aws/services/dynamodb/test_dynamodb.py::TestDynamoDB::test_transaction_write_items": 0.1473114740000483, + "tests/aws/services/dynamodb/test_dynamodb.py::TestDynamoDB::test_valid_local_secondary_index": 0.13604469900002414, + "tests/aws/services/dynamodb/test_dynamodb.py::TestDynamoDB::test_valid_query_index": 0.11391803400005074, + "tests/aws/services/dynamodbstreams/test_dynamodb_streams.py::TestDynamoDBStreams::test_enable_kinesis_streaming_destination": 0.0013837260000286733, + "tests/aws/services/dynamodbstreams/test_dynamodb_streams.py::TestDynamoDBStreams::test_non_existent_stream": 0.014922376000015447, + "tests/aws/services/dynamodbstreams/test_dynamodb_streams.py::TestDynamoDBStreams::test_stream_spec_and_region_replacement": 2.3438293310000518, + "tests/aws/services/dynamodbstreams/test_dynamodb_streams.py::TestDynamoDBStreams::test_table_v2_stream": 4.10500811199995, + "tests/aws/services/ec2/test_ec2.py::TestEc2FlowLogs::test_ec2_flow_logs_s3": 0.5140941900000371, + "tests/aws/services/ec2/test_ec2.py::TestEc2FlowLogs::test_ec2_flow_logs_s3_validation": 0.20375748300000396, + "tests/aws/services/ec2/test_ec2.py::TestEc2Integrations::test_create_route_table_association": 0.7572834110000031, + "tests/aws/services/ec2/test_ec2.py::TestEc2Integrations::test_create_security_group_with_custom_id[False-id_manager]": 0.0684490290000781, + "tests/aws/services/ec2/test_ec2.py::TestEc2Integrations::test_create_security_group_with_custom_id[False-tag]": 0.06992147099998647, + "tests/aws/services/ec2/test_ec2.py::TestEc2Integrations::test_create_security_group_with_custom_id[True-id_manager]": 0.05654805900002202, + "tests/aws/services/ec2/test_ec2.py::TestEc2Integrations::test_create_security_group_with_custom_id[True-tag]": 0.06451198099995281, + "tests/aws/services/ec2/test_ec2.py::TestEc2Integrations::test_create_subnet_with_custom_id": 0.06292141600005152, + "tests/aws/services/ec2/test_ec2.py::TestEc2Integrations::test_create_subnet_with_custom_id_and_vpc_id": 0.06391890999992711, + "tests/aws/services/ec2/test_ec2.py::TestEc2Integrations::test_create_subnet_with_tags": 0.055064076000007844, + "tests/aws/services/ec2/test_ec2.py::TestEc2Integrations::test_create_vpc_endpoint": 0.14662980899998956, + "tests/aws/services/ec2/test_ec2.py::TestEc2Integrations::test_create_vpc_with_custom_id": 0.051759314999969774, + "tests/aws/services/ec2/test_ec2.py::TestEc2Integrations::test_describe_vpc_endpoints_with_filter": 0.6982113179999487, + "tests/aws/services/ec2/test_ec2.py::TestEc2Integrations::test_describe_vpn_gateways_filter_by_vpc": 0.33465864499999043, + "tests/aws/services/ec2/test_ec2.py::TestEc2Integrations::test_get_security_groups_for_vpc": 0.3494684590000361, + "tests/aws/services/ec2/test_ec2.py::TestEc2Integrations::test_modify_launch_template[id]": 0.07722742999999355, + "tests/aws/services/ec2/test_ec2.py::TestEc2Integrations::test_modify_launch_template[name]": 0.05744512499995835, + "tests/aws/services/ec2/test_ec2.py::TestEc2Integrations::test_reserved_instance_api": 0.035505785999930595, + "tests/aws/services/ec2/test_ec2.py::TestEc2Integrations::test_vcp_peering_difference_regions": 0.8950329499999725, + "tests/aws/services/ec2/test_ec2.py::TestEc2Integrations::test_vpc_endpoint_dns_names": 0.2526122849999979, + "tests/aws/services/ec2/test_ec2.py::test_create_specific_vpc_id": 0.028391089000081138, + "tests/aws/services/ec2/test_ec2.py::test_describe_availability_zones_filter_with_zone_ids": 0.24859146099998952, + "tests/aws/services/ec2/test_ec2.py::test_describe_availability_zones_filter_with_zone_names": 0.24854252899996254, + "tests/aws/services/ec2/test_ec2.py::test_describe_availability_zones_filters": 0.2573725899999886, + "tests/aws/services/ec2/test_ec2.py::test_pickle_ec2_backend": 2.112566402000027, + "tests/aws/services/ec2/test_ec2.py::test_raise_create_volume_without_size": 0.01804233400002886, + "tests/aws/services/ec2/test_ec2.py::test_raise_duplicate_launch_template_name": 0.03537818300003437, + "tests/aws/services/ec2/test_ec2.py::test_raise_invalid_launch_template_name": 0.011758012999962375, + "tests/aws/services/ec2/test_ec2.py::test_raise_modify_to_invalid_default_version": 0.03596424500000239, + "tests/aws/services/ec2/test_ec2.py::test_raise_when_launch_template_data_missing": 0.012061418999962825, + "tests/aws/services/es/test_es.py::TestElasticsearchProvider::test_create_domain": 0.0012421010000593924, + "tests/aws/services/es/test_es.py::TestElasticsearchProvider::test_create_existing_domain_causes_exception": 0.001334154000005583, + "tests/aws/services/es/test_es.py::TestElasticsearchProvider::test_describe_domains": 0.001283448000037879, + "tests/aws/services/es/test_es.py::TestElasticsearchProvider::test_domain_version": 0.0012855030000196166, + "tests/aws/services/es/test_es.py::TestElasticsearchProvider::test_get_compatible_version_for_domain": 0.001325026000017715, + "tests/aws/services/es/test_es.py::TestElasticsearchProvider::test_get_compatible_versions": 0.00132579699999269, + "tests/aws/services/es/test_es.py::TestElasticsearchProvider::test_list_versions": 0.0014102340000476943, + "tests/aws/services/es/test_es.py::TestElasticsearchProvider::test_path_endpoint_strategy": 0.0013147859999662614, + "tests/aws/services/es/test_es.py::TestElasticsearchProvider::test_update_domain_config": 0.0012909220000096866, + "tests/aws/services/events/test_api_destinations_and_connection.py::TestEventBridgeApiDestinations::test_api_destinations[auth0]": 0.1949911010000278, + "tests/aws/services/events/test_api_destinations_and_connection.py::TestEventBridgeApiDestinations::test_api_destinations[auth1]": 0.1015455120000297, + "tests/aws/services/events/test_api_destinations_and_connection.py::TestEventBridgeApiDestinations::test_api_destinations[auth2]": 0.1020841179999934, + "tests/aws/services/events/test_api_destinations_and_connection.py::TestEventBridgeApiDestinations::test_create_api_destination_invalid_parameters": 0.014765839999995478, + "tests/aws/services/events/test_api_destinations_and_connection.py::TestEventBridgeApiDestinations::test_create_api_destination_name_validation": 0.046085833999995884, + "tests/aws/services/events/test_api_destinations_and_connection.py::TestEventBridgeConnections::test_connection_secrets[api-key]": 0.06025992699994731, + "tests/aws/services/events/test_api_destinations_and_connection.py::TestEventBridgeConnections::test_connection_secrets[basic]": 0.06161780299999009, + "tests/aws/services/events/test_api_destinations_and_connection.py::TestEventBridgeConnections::test_connection_secrets[oauth]": 0.060985553999955755, + "tests/aws/services/events/test_api_destinations_and_connection.py::TestEventBridgeConnections::test_create_connection": 0.05576436700005161, + "tests/aws/services/events/test_api_destinations_and_connection.py::TestEventBridgeConnections::test_create_connection_invalid_parameters": 0.015537031000008028, + "tests/aws/services/events/test_api_destinations_and_connection.py::TestEventBridgeConnections::test_create_connection_name_validation": 0.015239974999985861, + "tests/aws/services/events/test_api_destinations_and_connection.py::TestEventBridgeConnections::test_create_connection_with_auth[auth_params0]": 0.049214429000016935, + "tests/aws/services/events/test_api_destinations_and_connection.py::TestEventBridgeConnections::test_create_connection_with_auth[auth_params1]": 0.04953966600004378, + "tests/aws/services/events/test_api_destinations_and_connection.py::TestEventBridgeConnections::test_create_connection_with_auth[auth_params2]": 0.05122310799998786, + "tests/aws/services/events/test_api_destinations_and_connection.py::TestEventBridgeConnections::test_delete_connection": 0.10599839199988992, + "tests/aws/services/events/test_api_destinations_and_connection.py::TestEventBridgeConnections::test_list_connections": 0.04971785700007558, + "tests/aws/services/events/test_api_destinations_and_connection.py::TestEventBridgeConnections::test_update_connection": 0.10198837900003355, + "tests/aws/services/events/test_archive_and_replay.py::TestArchive::test_create_archive_error_duplicate[custom]": 0.09932487499992249, + "tests/aws/services/events/test_archive_and_replay.py::TestArchive::test_create_archive_error_duplicate[default]": 0.06459558099999185, + "tests/aws/services/events/test_archive_and_replay.py::TestArchive::test_create_archive_error_unknown_event_bus": 0.015450603000033425, + "tests/aws/services/events/test_archive_and_replay.py::TestArchive::test_create_list_describe_update_delete_archive[custom]": 0.12262453900007131, + "tests/aws/services/events/test_archive_and_replay.py::TestArchive::test_create_list_describe_update_delete_archive[default]": 0.10177178499998263, + "tests/aws/services/events/test_archive_and_replay.py::TestArchive::test_delete_archive_error_unknown_archive": 0.014466796000021986, + "tests/aws/services/events/test_archive_and_replay.py::TestArchive::test_describe_archive_error_unknown_archive": 0.014359471000034318, + "tests/aws/services/events/test_archive_and_replay.py::TestArchive::test_list_archive_error_unknown_source_arn": 0.015051336999931664, + "tests/aws/services/events/test_archive_and_replay.py::TestArchive::test_list_archive_state_enabled[custom]": 0.09812634000002163, + "tests/aws/services/events/test_archive_and_replay.py::TestArchive::test_list_archive_state_enabled[default]": 0.06349232700006269, + "tests/aws/services/events/test_archive_and_replay.py::TestArchive::test_list_archive_with_events[False-custom]": 0.5817773789999592, + "tests/aws/services/events/test_archive_and_replay.py::TestArchive::test_list_archive_with_events[False-default]": 0.5432251150000411, + "tests/aws/services/events/test_archive_and_replay.py::TestArchive::test_list_archive_with_events[True-custom]": 0.5777327320000154, + "tests/aws/services/events/test_archive_and_replay.py::TestArchive::test_list_archive_with_events[True-default]": 0.5601550719999864, + "tests/aws/services/events/test_archive_and_replay.py::TestArchive::test_list_archive_with_name_prefix[custom]": 0.1080779399999301, + "tests/aws/services/events/test_archive_and_replay.py::TestArchive::test_list_archive_with_name_prefix[default]": 0.08966450900004475, + "tests/aws/services/events/test_archive_and_replay.py::TestArchive::test_list_archive_with_source_arn[custom]": 0.09390853100001095, + "tests/aws/services/events/test_archive_and_replay.py::TestArchive::test_list_archive_with_source_arn[default]": 0.06468560600001183, + "tests/aws/services/events/test_archive_and_replay.py::TestArchive::test_update_archive_error_unknown_archive": 0.001308263999931114, + "tests/aws/services/events/test_archive_and_replay.py::TestReplay::test_describe_replay_error_unknown_replay": 0.014317768000012165, + "tests/aws/services/events/test_archive_and_replay.py::TestReplay::test_list_replay_with_limit": 0.21953543799997988, + "tests/aws/services/events/test_archive_and_replay.py::TestReplay::test_list_replays_with_event_source_arn": 0.1089656939999486, + "tests/aws/services/events/test_archive_and_replay.py::TestReplay::test_list_replays_with_prefix": 0.1656955880000055, + "tests/aws/services/events/test_archive_and_replay.py::TestReplay::test_start_list_describe_canceled_replay[custom]": 0.0012783880000029058, + "tests/aws/services/events/test_archive_and_replay.py::TestReplay::test_start_list_describe_canceled_replay[default]": 0.0012826750000272114, + "tests/aws/services/events/test_archive_and_replay.py::TestReplay::test_start_replay_error_duplicate_different_archive": 0.13541886500001965, + "tests/aws/services/events/test_archive_and_replay.py::TestReplay::test_start_replay_error_duplicate_name_same_archive": 0.07667484799998192, + "tests/aws/services/events/test_archive_and_replay.py::TestReplay::test_start_replay_error_invalid_end_time[0]": 0.07195342900001833, + "tests/aws/services/events/test_archive_and_replay.py::TestReplay::test_start_replay_error_invalid_end_time[10]": 0.0719420839999998, + "tests/aws/services/events/test_archive_and_replay.py::TestReplay::test_start_replay_error_unknown_archive": 0.01571794200003751, + "tests/aws/services/events/test_archive_and_replay.py::TestReplay::test_start_replay_error_unknown_event_bus": 0.09824061400001938, + "tests/aws/services/events/test_archive_and_replay.py::TestReplay::tests_concurrency_error_too_many_active_replays": 0.0013359960000229876, + "tests/aws/services/events/test_events.py::TestEventBus::test_create_list_describe_delete_custom_event_buses[False-regions0]": 0.045992018999982065, + "tests/aws/services/events/test_events.py::TestEventBus::test_create_list_describe_delete_custom_event_buses[False-regions1]": 0.12144351000000597, + "tests/aws/services/events/test_events.py::TestEventBus::test_create_list_describe_delete_custom_event_buses[True-regions0]": 0.04851487199999838, + "tests/aws/services/events/test_events.py::TestEventBus::test_create_list_describe_delete_custom_event_buses[True-regions1]": 0.15294600000004266, + "tests/aws/services/events/test_events.py::TestEventBus::test_create_multiple_event_buses_same_name": 0.046447419999935846, + "tests/aws/services/events/test_events.py::TestEventBus::test_delete_default_event_bus": 0.01436366600000838, + "tests/aws/services/events/test_events.py::TestEventBus::test_describe_delete_not_existing_event_bus": 0.02389642000002823, + "tests/aws/services/events/test_events.py::TestEventBus::test_list_event_buses_with_limit": 0.23957604200001015, + "tests/aws/services/events/test_events.py::TestEventBus::test_list_event_buses_with_prefix": 0.0806352260000267, + "tests/aws/services/events/test_events.py::TestEventBus::test_put_events_bus_to_bus[domain]": 0.3057911530000297, + "tests/aws/services/events/test_events.py::TestEventBus::test_put_events_bus_to_bus[path]": 0.30398104800002557, + "tests/aws/services/events/test_events.py::TestEventBus::test_put_events_bus_to_bus[standard]": 0.3098361229999682, + "tests/aws/services/events/test_events.py::TestEventBus::test_put_events_nonexistent_event_bus": 0.1733256360000155, + "tests/aws/services/events/test_events.py::TestEventBus::test_put_events_to_default_eventbus_for_custom_eventbus": 1.7498588950000453, + "tests/aws/services/events/test_events.py::TestEventBus::test_put_permission[custom]": 0.29645375900003046, + "tests/aws/services/events/test_events.py::TestEventBus::test_put_permission[default]": 0.0978406570000061, + "tests/aws/services/events/test_events.py::TestEventBus::test_put_permission_non_existing_event_bus": 0.013903725000034228, + "tests/aws/services/events/test_events.py::TestEventBus::test_remove_permission[custom]": 0.09485938899990742, + "tests/aws/services/events/test_events.py::TestEventBus::test_remove_permission[default]": 0.07049043400007804, + "tests/aws/services/events/test_events.py::TestEventBus::test_remove_permission_non_existing_sid[False-custom]": 0.04519672899999705, + "tests/aws/services/events/test_events.py::TestEventBus::test_remove_permission_non_existing_sid[False-default]": 0.02376618799996777, + "tests/aws/services/events/test_events.py::TestEventBus::test_remove_permission_non_existing_sid[True-custom]": 0.05251923399998759, + "tests/aws/services/events/test_events.py::TestEventBus::test_remove_permission_non_existing_sid[True-default]": 0.030126171000006252, + "tests/aws/services/events/test_events.py::TestEventPattern::test_put_events_pattern_nested": 10.245785126000044, + "tests/aws/services/events/test_events.py::TestEventPattern::test_put_events_pattern_with_values_in_array": 5.301240906999965, + "tests/aws/services/events/test_events.py::TestEventRule::test_delete_rule_with_targets": 0.08178058499993313, + "tests/aws/services/events/test_events.py::TestEventRule::test_describe_nonexistent_rule": 0.01584935700003598, + "tests/aws/services/events/test_events.py::TestEventRule::test_disable_re_enable_rule[custom]": 0.10050070899995944, + "tests/aws/services/events/test_events.py::TestEventRule::test_disable_re_enable_rule[default]": 0.06425877699996363, + "tests/aws/services/events/test_events.py::TestEventRule::test_list_rule_names_by_target[custom]": 0.23041737200003354, + "tests/aws/services/events/test_events.py::TestEventRule::test_list_rule_names_by_target[default]": 0.17001968300007775, + "tests/aws/services/events/test_events.py::TestEventRule::test_list_rule_names_by_target_no_matches[custom]": 0.12756943300001922, + "tests/aws/services/events/test_events.py::TestEventRule::test_list_rule_names_by_target_no_matches[default]": 0.09593197600003123, + "tests/aws/services/events/test_events.py::TestEventRule::test_list_rule_names_by_target_with_limit[custom]": 0.29425250799994274, + "tests/aws/services/events/test_events.py::TestEventRule::test_list_rule_names_by_target_with_limit[default]": 0.27394962799996847, + "tests/aws/services/events/test_events.py::TestEventRule::test_list_rule_with_limit": 0.23466879099999005, + "tests/aws/services/events/test_events.py::TestEventRule::test_process_pattern_to_single_matching_rules_single_target": 7.414126908000014, + "tests/aws/services/events/test_events.py::TestEventRule::test_process_to_multiple_matching_rules_different_targets": 0.5653955709999536, + "tests/aws/services/events/test_events.py::TestEventRule::test_process_to_multiple_matching_rules_single_target": 18.488806020000084, + "tests/aws/services/events/test_events.py::TestEventRule::test_process_to_single_matching_rules_single_target": 10.529319838999982, + "tests/aws/services/events/test_events.py::TestEventRule::test_put_list_with_prefix_describe_delete_rule[custom]": 0.08993537700007437, + "tests/aws/services/events/test_events.py::TestEventRule::test_put_list_with_prefix_describe_delete_rule[default]": 0.05956947600003559, + "tests/aws/services/events/test_events.py::TestEventRule::test_put_multiple_rules_with_same_name": 0.08798471199997948, + "tests/aws/services/events/test_events.py::TestEventRule::test_update_rule_with_targets": 0.10443374600004063, + "tests/aws/services/events/test_events.py::TestEventTarget::test_add_exceed_fife_targets_per_rule": 0.09960708600004864, + "tests/aws/services/events/test_events.py::TestEventTarget::test_list_target_by_rule_limit": 0.14575810500002717, + "tests/aws/services/events/test_events.py::TestEventTarget::test_put_list_remove_target[custom]": 0.11710008199997901, + "tests/aws/services/events/test_events.py::TestEventTarget::test_put_list_remove_target[default]": 0.08418482299998686, + "tests/aws/services/events/test_events.py::TestEventTarget::test_put_multiple_targets_with_same_arn_across_different_rules": 0.12715759500002832, + "tests/aws/services/events/test_events.py::TestEventTarget::test_put_multiple_targets_with_same_arn_single_rule": 0.0911191750000171, + "tests/aws/services/events/test_events.py::TestEventTarget::test_put_multiple_targets_with_same_id_across_different_rules": 0.1271466040000746, + "tests/aws/services/events/test_events.py::TestEventTarget::test_put_multiple_targets_with_same_id_single_rule": 0.08317755299998453, + "tests/aws/services/events/test_events.py::TestEventTarget::test_put_target_id_validation": 0.10300018500004171, + "tests/aws/services/events/test_events.py::TestEvents::test_create_connection_validations": 0.014047441000002436, + "tests/aws/services/events/test_events.py::TestEvents::test_events_written_to_disk_are_timestamp_prefixed_for_chronological_ordering": 0.0012524599999892416, + "tests/aws/services/events/test_events.py::TestEvents::test_put_event_malformed_detail[ARRAY]": 0.013905276999992111, + "tests/aws/services/events/test_events.py::TestEvents::test_put_event_malformed_detail[MALFORMED_JSON]": 0.014060126000003947, + "tests/aws/services/events/test_events.py::TestEvents::test_put_event_malformed_detail[SERIALIZED_STRING]": 0.013834785000085503, + "tests/aws/services/events/test_events.py::TestEvents::test_put_event_malformed_detail[STRING]": 0.014338255000097888, + "tests/aws/services/events/test_events.py::TestEvents::test_put_event_with_too_big_detail": 0.018754596999997375, + "tests/aws/services/events/test_events.py::TestEvents::test_put_event_without_detail": 0.013726813000005222, + "tests/aws/services/events/test_events.py::TestEvents::test_put_event_without_detail_type": 0.01585790500001849, + "tests/aws/services/events/test_events.py::TestEvents::test_put_events_exceed_limit_ten_entries[custom]": 0.04626658199998701, + "tests/aws/services/events/test_events.py::TestEvents::test_put_events_exceed_limit_ten_entries[default]": 0.016297244999918803, + "tests/aws/services/events/test_events.py::TestEvents::test_put_events_response_entries_order": 0.3081194439999422, + "tests/aws/services/events/test_events.py::TestEvents::test_put_events_time": 0.33147174300006554, + "tests/aws/services/events/test_events.py::TestEvents::test_put_events_with_target_delivery_failure": 1.1629077079999774, + "tests/aws/services/events/test_events.py::TestEvents::test_put_events_with_time_field": 0.19857749799996327, + "tests/aws/services/events/test_events.py::TestEvents::test_put_events_without_source": 0.013793427000052816, + "tests/aws/services/events/test_events_cross_account_region.py::TestEventsCrossAccountRegion::test_put_events[custom-account]": 0.1648213139999939, + "tests/aws/services/events/test_events_cross_account_region.py::test_event_bus_to_event_bus_cross_account_region[custom-account]": 0.4739626360000102, + "tests/aws/services/events/test_events_cross_account_region.py::test_event_bus_to_event_bus_cross_account_region[custom-region]": 0.4857943319999549, + "tests/aws/services/events/test_events_cross_account_region.py::test_event_bus_to_event_bus_cross_account_region[custom-region_account]": 0.4662358980000363, + "tests/aws/services/events/test_events_cross_account_region.py::test_event_bus_to_event_bus_cross_account_region[default-account]": 0.5073404420000429, + "tests/aws/services/events/test_events_cross_account_region.py::test_event_bus_to_event_bus_cross_account_region[default-region]": 0.5166387740000573, + "tests/aws/services/events/test_events_cross_account_region.py::test_event_bus_to_event_bus_cross_account_region[default-region_account]": 0.5149933709999459, + "tests/aws/services/events/test_events_inputs.py::TestInputPath::test_put_events_with_input_path": 0.19800168599994095, + "tests/aws/services/events/test_events_inputs.py::TestInputPath::test_put_events_with_input_path_max_level_depth": 0.19938683700002002, + "tests/aws/services/events/test_events_inputs.py::TestInputPath::test_put_events_with_input_path_multiple_targets": 0.31752255099996773, + "tests/aws/services/events/test_events_inputs.py::TestInputPath::test_put_events_with_input_path_nested[event_detail0]": 0.20137049299995624, + "tests/aws/services/events/test_events_inputs.py::TestInputPath::test_put_events_with_input_path_nested[event_detail1]": 0.1998306479999883, + "tests/aws/services/events/test_events_inputs.py::TestInputTransformer::test_input_transformer_nested_keys_replacement[\" multiple list items\"]": 0.23755233299999645, + "tests/aws/services/events/test_events_inputs.py::TestInputTransformer::test_input_transformer_nested_keys_replacement[\" single list item multiple list items system account id payload user id\"]": 0.23624025000009397, + "tests/aws/services/events/test_events_inputs.py::TestInputTransformer::test_input_transformer_nested_keys_replacement[\" single list item\"]": 0.23853842599999098, + "tests/aws/services/events/test_events_inputs.py::TestInputTransformer::test_input_transformer_nested_keys_replacement[\"Payload of with path users-service/users/ and \"]": 0.24032532399996853, + "tests/aws/services/events/test_events_inputs.py::TestInputTransformer::test_input_transformer_nested_keys_replacement[{\"id\" : \"\"}]": 0.23494661699999142, + "tests/aws/services/events/test_events_inputs.py::TestInputTransformer::test_input_transformer_nested_keys_replacement[{\"id\" : }]": 0.2391056989999356, + "tests/aws/services/events/test_events_inputs.py::TestInputTransformer::test_input_transformer_nested_keys_replacement[{\"method\": \"PUT\", \"nested\": {\"level1\": {\"level2\": {\"level3\": \"users-service/users/\"} } }, \"bod\": \"\"}]": 0.23673493699993742, + "tests/aws/services/events/test_events_inputs.py::TestInputTransformer::test_input_transformer_nested_keys_replacement[{\"method\": \"PUT\", \"path\": \"users-service/users/\", \"bod\": }]": 0.23582404200004703, + "tests/aws/services/events/test_events_inputs.py::TestInputTransformer::test_input_transformer_nested_keys_replacement[{\"method\": \"PUT\", \"path\": \"users-service/users/\", \"bod\": [, \"hardcoded\"]}]": 0.23271717299996908, + "tests/aws/services/events/test_events_inputs.py::TestInputTransformer::test_input_transformer_nested_keys_replacement[{\"method\": \"PUT\", \"path\": \"users-service/users/\", \"id\": , \"body\": }]": 0.23206338500000356, + "tests/aws/services/events/test_events_inputs.py::TestInputTransformer::test_input_transformer_nested_keys_replacement[{\"multi_replacement\": \"users//second/\"}]": 0.2382915410000237, + "tests/aws/services/events/test_events_inputs.py::TestInputTransformer::test_input_transformer_nested_keys_replacement[{\"singlelistitem\": }]": 0.2397499350000203, + "tests/aws/services/events/test_events_inputs.py::TestInputTransformer::test_input_transformer_nested_keys_replacement_not_valid[{\"not_valid\": \"users-service/users/\", \"bod\": }]": 5.1610035199999515, + "tests/aws/services/events/test_events_inputs.py::TestInputTransformer::test_input_transformer_nested_keys_replacement_not_valid[{\"payload\": \"\"}]": 5.165831165000043, + "tests/aws/services/events/test_events_inputs.py::TestInputTransformer::test_input_transformer_nested_keys_replacement_not_valid[{\"singlelistitem\": \"\"}]": 5.159927456000048, + "tests/aws/services/events/test_events_inputs.py::TestInputTransformer::test_input_transformer_predefined_variables[\"Message containing all pre defined variables \"]": 0.23050062699996943, + "tests/aws/services/events/test_events_inputs.py::TestInputTransformer::test_input_transformer_predefined_variables[{\"originalEvent\": , \"originalEventJson\": }]": 0.2217760959999282, + "tests/aws/services/events/test_events_inputs.py::TestInputTransformer::test_put_events_with_input_transformer_input_template_json": 0.4963251460000606, + "tests/aws/services/events/test_events_inputs.py::TestInputTransformer::test_put_events_with_input_transformer_input_template_string[\"Event of type, at time , info extracted from detail \"]": 0.4242710249999959, + "tests/aws/services/events/test_events_inputs.py::TestInputTransformer::test_put_events_with_input_transformer_input_template_string[\"{[/Check with special starting characters for event of type\"]": 0.4281432699999641, + "tests/aws/services/events/test_events_inputs.py::TestInputTransformer::test_put_events_with_input_transformer_missing_keys": 0.14151847699992004, + "tests/aws/services/events/test_events_inputs.py::test_put_event_input_path_and_input_transformer": 0.10300098599998364, + "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_array_event_payload": 0.014769224000019676, + "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[arrays]": 0.01473700399998279, + "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[arrays_NEG]": 0.016250972999955593, + "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[arrays_empty_EXC]": 0.07737650000001395, + "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[arrays_empty_null_NEG]": 0.01444279300000062, + "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[boolean]": 0.013766240999984802, + "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[boolean_NEG]": 0.014040590999911728, + "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[complex_many_rules]": 0.014392761000010523, + "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[complex_multi_match]": 0.015076067999984843, + "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[complex_multi_match_NEG]": 0.016463436999970327, + "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[complex_or]": 0.014643366999962382, + "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[complex_or_NEG]": 0.014216971999985617, + "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_but_ignorecase]": 0.013837410000007822, + "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_but_ignorecase_EXC]": 0.07429653500003042, + "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_but_ignorecase_NEG]": 0.013719434999984514, + "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_but_ignorecase_list]": 0.014650921000054495, + "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_but_ignorecase_list_EXC]": 0.07397402199995895, + "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_but_ignorecase_list_NEG]": 0.014319102999991173, + "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_but_number]": 0.014844083000014052, + "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_but_number_NEG]": 0.014242549000016425, + "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_but_number_list]": 0.01709955199999058, + "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_but_number_list_NEG]": 0.016098084999953244, + "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_but_number_zero]": 0.014260070999966956, + "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_but_string]": 0.015044487999944067, + "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_but_string_NEG]": 0.01476335500001369, + "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_but_string_list]": 0.02068115499992018, + "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_but_string_list_NEG]": 0.014804909999952542, + "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_but_string_null]": 0.014085175000104755, + "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_prefix]": 0.01426160599993409, + "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_prefix_NEG]": 0.015561771000022873, + "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_prefix_empty_EXC]": 0.07428485599996293, + "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_prefix_ignorecase_EXC]": 0.07523379399998475, + "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_prefix_int_EXC]": 0.07527784200004817, + "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_prefix_list]": 0.014898268000024473, + "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_prefix_list_NEG]": 0.021546038999986195, + "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_prefix_list_type_EXC]": 0.07689632799997526, + "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_suffix]": 0.014166528000032486, + "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_suffix_NEG]": 0.014248637000036979, + "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_suffix_empty_EXC]": 0.07367630100003453, + "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_suffix_ignorecase_EXC]": 0.07439290799999299, + "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_suffix_int_EXC]": 0.07423224000001483, + "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_suffix_list]": 0.014122725999982322, + "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_suffix_list_NEG]": 0.014761318000012125, + "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_suffix_list_type_EXC]": 0.07548682000003737, + "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_wildcard]": 0.015540506999968784, + "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_wildcard_NEG]": 0.014257317999977204, + "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_wildcard_empty]": 0.015672594999898593, + "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_wildcard_list]": 0.01434771399993906, + "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_wildcard_list_NEG]": 0.014598369999987426, + "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_wildcard_list_type_EXC]": 0.07524496899998212, + "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_wildcard_type_EXC]": 0.07373897399997986, + "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_exists]": 0.013918073000013464, + "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_exists_NEG]": 0.015583042999992358, + "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_exists_false]": 0.01442360800001552, + "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_exists_false_NEG]": 0.014009017000034873, + "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_ignorecase]": 0.016272308999987217, + "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_ignorecase_EXC]": 0.07391722899996012, + "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_ignorecase_NEG]": 0.014096141000038642, + "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_ignorecase_empty]": 0.014554510999971626, + "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_ignorecase_empty_NEG]": 0.013844446000064181, + "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_ignorecase_list_EXC]": 0.07682260000001406, + "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_ip_address]": 0.01576323999995566, + "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_ip_address_EXC]": 0.0740842169999496, + "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_ip_address_NEG]": 0.013829718000010871, + "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_ip_address_bad_ip_EXC]": 0.07894248399998105, + "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_ip_address_bad_mask_EXC]": 0.08115277199999582, + "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_ip_address_type_EXC]": 0.08098299499999939, + "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_ip_address_v6]": 0.014130528999999115, + "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_ip_address_v6_NEG]": 0.015380627999945773, + "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_ip_address_v6_bad_ip_EXC]": 0.07352327400002423, + "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_numeric_EXC]": 0.07549371899995094, + "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_numeric_and]": 0.01581395400000929, + "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_numeric_and_NEG]": 0.014268909000008989, + "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_numeric_number_EXC]": 0.07553367799994248, + "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_numeric_operatorcasing_EXC]": 0.07327252499999304, + "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_numeric_syntax_EXC]": 0.07728201899999476, + "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_prefix]": 0.014616998999997577, + "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_prefix_NEG]": 0.014207315000021481, + "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_prefix_empty]": 0.014223287000049822, + "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_prefix_ignorecase]": 0.019804637000049752, + "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_prefix_int_EXC]": 0.07477866399995037, + "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_prefix_list_EXC]": 0.07539189300001681, + "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_suffix]": 0.014445883000007598, + "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_suffix_NEG]": 0.014586162000057357, + "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_suffix_empty]": 0.014782528000012007, + "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_suffix_ignorecase]": 0.016062568000052124, + "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_suffix_ignorecase_NEG]": 0.016894706999948994, + "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_suffix_int_EXC]": 0.0773131610000064, + "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_suffix_list_EXC]": 0.072937990000014, + "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_wildcard_complex_EXC]": 0.07405863699995052, + "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_wildcard_empty_NEG]": 0.016804483999976583, + "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_wildcard_int_EXC]": 0.07473737900005517, + "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_wildcard_list_EXC]": 0.07462217499994495, + "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_wildcard_nonrepeating]": 0.01586677300002748, + "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_wildcard_nonrepeating_NEG]": 0.01380465099992989, + "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_wildcard_repeating]": 0.01468936699995993, + "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_wildcard_repeating_NEG]": 0.0151713839999843, + "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_wildcard_repeating_star_EXC]": 0.07884239999992815, + "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_wildcard_simplified]": 0.01608221300000423, + "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[dot_joining_event]": 0.0145057720000068, + "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[dot_joining_event_NEG]": 0.020375953999973717, + "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[dot_joining_pattern]": 0.014232584000069437, + "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[dot_joining_pattern_NEG]": 0.014172383999948579, + "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[dynamodb]": 0.013996119000012186, + "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[exists_dynamodb]": 0.014197158000001764, + "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[exists_dynamodb_NEG]": 0.014888713000004827, + "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[exists_list_empty_NEG]": 0.017250607999926615, + "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[int_nolist_EXC]": 0.07519569499999079, + "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[key_case_sensitive_NEG]": 0.0142199979999873, + "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[list_within_dict]": 0.014119761999950242, + "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[minimal]": 0.014175944999976764, + "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[nested_json_NEG]": 0.015284716000053322, + "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[null_value]": 0.0225036180000302, + "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[null_value_NEG]": 0.013955663999979606, + "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[number_comparison_float]": 0.01940911000002643, + "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[numeric-int-float]": 0.015657472999976108, + "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[numeric-null_NEG]": 0.01408340299997235, + "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[numeric-string_NEG]": 0.014332366000019192, + "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[operator_case_sensitive_EXC]": 0.07478767399999242, + "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[operator_multiple_list]": 0.013959129999989273, + "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[or-anything-but]": 0.014398189999951683, + "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[or-exists-parent]": 0.014966101000027265, + "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[or-exists]": 0.013758525000071131, + "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[or-numeric-anything-but]": 0.013881814999990638, + "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[or-numeric-anything-but_NEG]": 0.019981379999990168, + "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[prefix]": 0.014259040000013101, + "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[sample1]": 0.014815910000038457, + "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[string]": 0.01501801699993166, + "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[string_empty]": 0.015583773000059864, + "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[string_nolist_EXC]": 0.07485117599998148, + "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern_source": 0.024772417000008318, + "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern_with_escape_characters": 0.01334152700002278, + "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern_with_multi_key": 0.012596724000047743, + "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_with_large_and_complex_payload": 0.026840837999998257, + "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_invalid_event_payload": 0.014060612000037054, + "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_invalid_json_event_pattern[[\"not\", \"a\", \"dict\", \"but valid json\"]]": 0.07505024699997875, + "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_invalid_json_event_pattern[this is valid json but not a dict]": 0.07363387800000964, + "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_invalid_json_event_pattern[{\"not\": closed mark\"]": 0.07749024199995347, + "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_invalid_json_event_pattern[{'bad': 'quotation'}]": 0.07488740199994481, + "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_plain_string_payload": 0.01489648000000443, + "tests/aws/services/events/test_events_patterns.py::TestRuleWithPattern::test_put_event_with_content_base_rule_in_pattern": 0.2125037749999592, + "tests/aws/services/events/test_events_patterns.py::TestRuleWithPattern::test_put_events_with_rule_pattern_anything_but": 5.32403263599997, + "tests/aws/services/events/test_events_patterns.py::TestRuleWithPattern::test_put_events_with_rule_pattern_exists_false": 5.262978658999941, + "tests/aws/services/events/test_events_patterns.py::TestRuleWithPattern::test_put_events_with_rule_pattern_exists_true": 5.249971863000098, + "tests/aws/services/events/test_events_schedule.py::TestScheduleCron::test_schedule_cron_target_sqs": 0.0013403819999666666, + "tests/aws/services/events/test_events_schedule.py::TestScheduleCron::tests_put_rule_with_invalid_schedule_cron[cron(0 1 * * * *)]": 0.014249778000134938, + "tests/aws/services/events/test_events_schedule.py::TestScheduleCron::tests_put_rule_with_invalid_schedule_cron[cron(0 dummy ? * MON-FRI *)]": 0.015488572000094791, + "tests/aws/services/events/test_events_schedule.py::TestScheduleCron::tests_put_rule_with_invalid_schedule_cron[cron(7 20 * * NOT *)]": 0.013537992999886228, + "tests/aws/services/events/test_events_schedule.py::TestScheduleCron::tests_put_rule_with_invalid_schedule_cron[cron(71 8 1 * ? *)]": 0.01338709500009827, + "tests/aws/services/events/test_events_schedule.py::TestScheduleCron::tests_put_rule_with_invalid_schedule_cron[cron(INVALID)]": 0.013556583999957184, + "tests/aws/services/events/test_events_schedule.py::TestScheduleCron::tests_put_rule_with_schedule_cron[cron(* * ? * SAT#3 *)]": 0.039524867999944036, + "tests/aws/services/events/test_events_schedule.py::TestScheduleCron::tests_put_rule_with_schedule_cron[cron(0 10 * * ? *)]": 0.03902212600007715, + "tests/aws/services/events/test_events_schedule.py::TestScheduleCron::tests_put_rule_with_schedule_cron[cron(0 12 * * ? *)]": 0.039991844000041965, + "tests/aws/services/events/test_events_schedule.py::TestScheduleCron::tests_put_rule_with_schedule_cron[cron(0 18 ? * MON-FRI *)]": 0.03998815600004946, + "tests/aws/services/events/test_events_schedule.py::TestScheduleCron::tests_put_rule_with_schedule_cron[cron(0 2 ? * SAT *)]": 0.03945478699984051, + "tests/aws/services/events/test_events_schedule.py::TestScheduleCron::tests_put_rule_with_schedule_cron[cron(0 2 ? * SAT#3 *)]": 0.03811496100001932, + "tests/aws/services/events/test_events_schedule.py::TestScheduleCron::tests_put_rule_with_schedule_cron[cron(0 8 1 * ? *)]": 0.04056264700011525, + "tests/aws/services/events/test_events_schedule.py::TestScheduleCron::tests_put_rule_with_schedule_cron[cron(0/10 * ? * MON-FRI *)]": 0.039733622000085234, + "tests/aws/services/events/test_events_schedule.py::TestScheduleCron::tests_put_rule_with_schedule_cron[cron(0/15 * * * ? *)]": 0.039946852999946714, + "tests/aws/services/events/test_events_schedule.py::TestScheduleCron::tests_put_rule_with_schedule_cron[cron(0/30 0-2 ? * MON-FRI *)]": 0.038315744000101404, + "tests/aws/services/events/test_events_schedule.py::TestScheduleCron::tests_put_rule_with_schedule_cron[cron(0/30 20-23 ? * MON-FRI *)]": 0.039884855999957836, + "tests/aws/services/events/test_events_schedule.py::TestScheduleCron::tests_put_rule_with_schedule_cron[cron(0/5 5 ? JAN 1-5 2022)]": 0.03990890100010347, + "tests/aws/services/events/test_events_schedule.py::TestScheduleCron::tests_put_rule_with_schedule_cron[cron(0/5 8-17 ? * MON-FRI *)]": 0.04050064000000475, + "tests/aws/services/events/test_events_schedule.py::TestScheduleCron::tests_put_rule_with_schedule_cron[cron(15 10 ? * 6L 2002-2005)]": 0.03854088899993258, + "tests/aws/services/events/test_events_schedule.py::TestScheduleCron::tests_put_rule_with_schedule_cron[cron(15 12 * * ? *)]": 0.03912135500002023, + "tests/aws/services/events/test_events_schedule.py::TestScheduleCron::tests_put_rule_with_schedule_cron[cron(5,35 14 * * ? *)]": 0.040583050999998704, + "tests/aws/services/events/test_events_schedule.py::TestScheduleCron::tests_scheduled_rule_does_not_trigger_on_put_events": 3.098797039000033, + "tests/aws/services/events/test_events_schedule.py::TestScheduleRate::test_put_rule_with_invalid_schedule_rate[ rate(10 minutes)]": 0.011782736999862209, + "tests/aws/services/events/test_events_schedule.py::TestScheduleRate::test_put_rule_with_invalid_schedule_rate[rate( 10 minutes )]": 0.010935715999949025, + "tests/aws/services/events/test_events_schedule.py::TestScheduleRate::test_put_rule_with_invalid_schedule_rate[rate()]": 0.01272831400024188, + "tests/aws/services/events/test_events_schedule.py::TestScheduleRate::test_put_rule_with_invalid_schedule_rate[rate(-10 minutes)]": 0.011175413999922057, + "tests/aws/services/events/test_events_schedule.py::TestScheduleRate::test_put_rule_with_invalid_schedule_rate[rate(0 minutes)]": 0.01160866400005034, + "tests/aws/services/events/test_events_schedule.py::TestScheduleRate::test_put_rule_with_invalid_schedule_rate[rate(1 days)]": 0.011537399999951958, + "tests/aws/services/events/test_events_schedule.py::TestScheduleRate::test_put_rule_with_invalid_schedule_rate[rate(1 hours)]": 0.012079271999937191, + "tests/aws/services/events/test_events_schedule.py::TestScheduleRate::test_put_rule_with_invalid_schedule_rate[rate(1 minutes)]": 0.01229389299999184, + "tests/aws/services/events/test_events_schedule.py::TestScheduleRate::test_put_rule_with_invalid_schedule_rate[rate(10 MINUTES)]": 0.010918001999925764, + "tests/aws/services/events/test_events_schedule.py::TestScheduleRate::test_put_rule_with_invalid_schedule_rate[rate(10 day)]": 0.012779326999975638, + "tests/aws/services/events/test_events_schedule.py::TestScheduleRate::test_put_rule_with_invalid_schedule_rate[rate(10 hour)]": 0.012875576999931582, + "tests/aws/services/events/test_events_schedule.py::TestScheduleRate::test_put_rule_with_invalid_schedule_rate[rate(10 minute)]": 0.01221343200006686, + "tests/aws/services/events/test_events_schedule.py::TestScheduleRate::test_put_rule_with_invalid_schedule_rate[rate(10 minutess)]": 0.011718728000005285, + "tests/aws/services/events/test_events_schedule.py::TestScheduleRate::test_put_rule_with_invalid_schedule_rate[rate(10 seconds)]": 0.012360175000026175, + "tests/aws/services/events/test_events_schedule.py::TestScheduleRate::test_put_rule_with_invalid_schedule_rate[rate(10 years)]": 0.011161657000116065, + "tests/aws/services/events/test_events_schedule.py::TestScheduleRate::test_put_rule_with_invalid_schedule_rate[rate(10)]": 0.013167574000021887, + "tests/aws/services/events/test_events_schedule.py::TestScheduleRate::test_put_rule_with_invalid_schedule_rate[rate(foo minutes)]": 0.011234874999900057, + "tests/aws/services/events/test_events_schedule.py::TestScheduleRate::test_put_rule_with_schedule_rate": 0.0402682519999189, + "tests/aws/services/events/test_events_schedule.py::TestScheduleRate::test_scheduled_rule_logs": 0.0014579930000309105, + "tests/aws/services/events/test_events_schedule.py::TestScheduleRate::tests_put_rule_with_schedule_custom_event_bus": 0.04621812400012004, + "tests/aws/services/events/test_events_schedule.py::TestScheduleRate::tests_schedule_rate_custom_input_target_sqs": 60.11986226500005, + "tests/aws/services/events/test_events_schedule.py::TestScheduleRate::tests_schedule_rate_target_sqs": 0.001341576000072564, + "tests/aws/services/events/test_events_tags.py::TestEventBusTags::test_create_event_bus_with_tags": 0.04632428599995819, + "tests/aws/services/events/test_events_tags.py::TestEventBusTags::test_list_tags_for_deleted_event_bus": 0.03768204900006822, + "tests/aws/services/events/test_events_tags.py::TestRuleTags::test_list_tags_for_deleted_rule": 0.06985411400000885, + "tests/aws/services/events/test_events_tags.py::TestRuleTags::test_put_rule_with_tags": 0.07012072900010935, + "tests/aws/services/events/test_events_tags.py::test_recreate_tagged_resource_without_tags[event_bus-event_bus_custom]": 0.08043061799980933, + "tests/aws/services/events/test_events_tags.py::test_recreate_tagged_resource_without_tags[event_bus-event_bus_default]": 0.025659442999995008, + "tests/aws/services/events/test_events_tags.py::test_recreate_tagged_resource_without_tags[rule-event_bus_custom]": 0.1144373380000161, + "tests/aws/services/events/test_events_tags.py::test_recreate_tagged_resource_without_tags[rule-event_bus_default]": 0.0837225559999979, + "tests/aws/services/events/test_events_tags.py::tests_tag_list_untag_not_existing_resource[not_existing_event_bus]": 0.04150798400007716, + "tests/aws/services/events/test_events_tags.py::tests_tag_list_untag_not_existing_resource[not_existing_rule]": 0.039595980999934, + "tests/aws/services/events/test_events_tags.py::tests_tag_untag_resource[event_bus-event_bus_custom]": 0.07899769299990567, + "tests/aws/services/events/test_events_tags.py::tests_tag_untag_resource[event_bus-event_bus_default]": 0.05171345799988103, + "tests/aws/services/events/test_events_tags.py::tests_tag_untag_resource[rule-event_bus_custom]": 0.1268474440000773, + "tests/aws/services/events/test_events_tags.py::tests_tag_untag_resource[rule-event_bus_default]": 0.07706992899989018, + "tests/aws/services/events/test_events_targets.py::TestEventsTargetApiDestination::test_put_events_to_target_api_destinations[auth0]": 0.12711244299998725, + "tests/aws/services/events/test_events_targets.py::TestEventsTargetApiDestination::test_put_events_to_target_api_destinations[auth1]": 0.11765732699996079, + "tests/aws/services/events/test_events_targets.py::TestEventsTargetApiDestination::test_put_events_to_target_api_destinations[auth2]": 0.11986999599992032, + "tests/aws/services/events/test_events_targets.py::TestEventsTargetApiGateway::test_put_events_with_target_api_gateway": 8.15067134700007, + "tests/aws/services/events/test_events_targets.py::TestEventsTargetCloudWatchLogs::test_put_events_with_target_cloudwatch_logs": 0.22258106499998576, + "tests/aws/services/events/test_events_targets.py::TestEventsTargetEvents::test_put_events_with_target_events[bus_combination0]": 0.3131844029999229, + "tests/aws/services/events/test_events_targets.py::TestEventsTargetEvents::test_put_events_with_target_events[bus_combination1]": 0.3492358979999608, + "tests/aws/services/events/test_events_targets.py::TestEventsTargetEvents::test_put_events_with_target_events[bus_combination2]": 0.3262127779998991, + "tests/aws/services/events/test_events_targets.py::TestEventsTargetFirehose::test_put_events_with_target_firehose": 1.1573409640001273, + "tests/aws/services/events/test_events_targets.py::TestEventsTargetKinesis::test_put_events_with_target_kinesis": 0.9200141759999951, + "tests/aws/services/events/test_events_targets.py::TestEventsTargetLambda::test_put_events_with_target_lambda": 4.2721585279998635, + "tests/aws/services/events/test_events_targets.py::TestEventsTargetLambda::test_put_events_with_target_lambda_list_entries_partial_match": 4.3310349420000875, + "tests/aws/services/events/test_events_targets.py::TestEventsTargetLambda::test_put_events_with_target_lambda_list_entry": 4.34329892400001, + "tests/aws/services/events/test_events_targets.py::TestEventsTargetSns::test_put_events_with_target_sns[domain]": 0.25569314500012297, + "tests/aws/services/events/test_events_targets.py::TestEventsTargetSns::test_put_events_with_target_sns[path]": 0.25889670999993086, + "tests/aws/services/events/test_events_targets.py::TestEventsTargetSns::test_put_events_with_target_sns[standard]": 0.27803015000006326, + "tests/aws/services/events/test_events_targets.py::TestEventsTargetSqs::test_put_events_with_target_sqs": 0.2082200599998032, + "tests/aws/services/events/test_events_targets.py::TestEventsTargetSqs::test_put_events_with_target_sqs_event_detail_match": 5.265115494999918, + "tests/aws/services/events/test_events_targets.py::TestEventsTargetStepFunctions::test_put_events_with_target_statefunction_machine": 3.082819936000078, + "tests/aws/services/events/test_x_ray_trace_propagation.py::test_xray_trace_propagation_events_api_gateway": 5.745362673999921, + "tests/aws/services/events/test_x_ray_trace_propagation.py::test_xray_trace_propagation_events_events[bus_combination0]": 4.408676894999985, + "tests/aws/services/events/test_x_ray_trace_propagation.py::test_xray_trace_propagation_events_events[bus_combination1]": 4.452466942000115, + "tests/aws/services/events/test_x_ray_trace_propagation.py::test_xray_trace_propagation_events_events[bus_combination2]": 4.427357289000042, + "tests/aws/services/events/test_x_ray_trace_propagation.py::test_xray_trace_propagation_events_lambda": 4.293536941999946, + "tests/aws/services/firehose/test_firehose.py::TestFirehoseIntegration::test_kinesis_firehose_elasticsearch_s3_backup": 0.0014430450000872952, + "tests/aws/services/firehose/test_firehose.py::TestFirehoseIntegration::test_kinesis_firehose_kinesis_as_source": 35.28502605099993, + "tests/aws/services/firehose/test_firehose.py::TestFirehoseIntegration::test_kinesis_firehose_kinesis_as_source_multiple_delivery_streams": 41.521515327999964, + "tests/aws/services/firehose/test_firehose.py::TestFirehoseIntegration::test_kinesis_firehose_opensearch_s3_backup[domain]": 0.0013686949998827913, + "tests/aws/services/firehose/test_firehose.py::TestFirehoseIntegration::test_kinesis_firehose_opensearch_s3_backup[path]": 0.0013377169999557736, + "tests/aws/services/firehose/test_firehose.py::TestFirehoseIntegration::test_kinesis_firehose_opensearch_s3_backup[port]": 0.00134457100000418, + "tests/aws/services/firehose/test_firehose.py::TestFirehoseIntegration::test_kinesis_firehose_s3_as_destination_with_file_extension": 1.1944170269999859, + "tests/aws/services/firehose/test_firehose.py::test_kinesis_firehose_http[False]": 0.07698860999994395, + "tests/aws/services/firehose/test_firehose.py::test_kinesis_firehose_http[True]": 1.6312629699998524, + "tests/aws/services/iam/test_iam.py::TestIAMExtensions::test_create_role_with_malformed_assume_role_policy_document": 0.020012918000020363, + "tests/aws/services/iam/test_iam.py::TestIAMExtensions::test_create_user_add_permission_boundary_afterwards": 0.11537089899991315, + "tests/aws/services/iam/test_iam.py::TestIAMExtensions::test_create_user_with_permission_boundary": 0.09831113200004893, + "tests/aws/services/iam/test_iam.py::TestIAMExtensions::test_get_user_without_username_as_role": 0.12178350900001078, + "tests/aws/services/iam/test_iam.py::TestIAMExtensions::test_get_user_without_username_as_root": 0.04201659000000291, + "tests/aws/services/iam/test_iam.py::TestIAMExtensions::test_get_user_without_username_as_user": 0.15553203299998586, + "tests/aws/services/iam/test_iam.py::TestIAMExtensions::test_role_with_path_lifecycle": 0.1076197659999707, + "tests/aws/services/iam/test_iam.py::TestIAMIntegrations::test_attach_detach_role_policy": 0.08618333200024608, + "tests/aws/services/iam/test_iam.py::TestIAMIntegrations::test_attach_iam_role_to_new_iam_user": 0.1061101380000764, + "tests/aws/services/iam/test_iam.py::TestIAMIntegrations::test_create_describe_role": 0.13644321700007822, + "tests/aws/services/iam/test_iam.py::TestIAMIntegrations::test_create_role_with_assume_role_policy": 0.1310539549999703, + "tests/aws/services/iam/test_iam.py::TestIAMIntegrations::test_create_user_with_tags": 0.033444476999875405, + "tests/aws/services/iam/test_iam.py::TestIAMIntegrations::test_delete_non_existent_policy_returns_no_such_entity": 0.016811741000083202, + "tests/aws/services/iam/test_iam.py::TestIAMIntegrations::test_instance_profile_tags": 0.15954212899998765, + "tests/aws/services/iam/test_iam.py::TestIAMIntegrations::test_list_roles_with_permission_boundary": 0.15987779299996419, + "tests/aws/services/iam/test_iam.py::TestIAMIntegrations::test_recreate_iam_role": 0.053607905000149, + "tests/aws/services/iam/test_iam.py::TestIAMIntegrations::test_role_attach_policy": 0.3554823359999091, + "tests/aws/services/iam/test_iam.py::TestIAMIntegrations::test_service_linked_role_name_should_match_aws[ecs.amazonaws.com-AWSServiceRoleForECS]": 0.0013373570000112522, + "tests/aws/services/iam/test_iam.py::TestIAMIntegrations::test_service_linked_role_name_should_match_aws[eks.amazonaws.com-AWSServiceRoleForAmazonEKS]": 0.0012612750000471351, + "tests/aws/services/iam/test_iam.py::TestIAMIntegrations::test_simulate_principle_policy[group]": 0.18022979400018357, + "tests/aws/services/iam/test_iam.py::TestIAMIntegrations::test_simulate_principle_policy[role]": 0.20425840000018525, + "tests/aws/services/iam/test_iam.py::TestIAMIntegrations::test_simulate_principle_policy[user]": 0.21684722600002715, + "tests/aws/services/iam/test_iam.py::TestIAMIntegrations::test_update_assume_role_policy": 0.10182629000007637, + "tests/aws/services/iam/test_iam.py::TestIAMIntegrations::test_user_attach_policy": 0.36940406000007897, + "tests/aws/services/iam/test_iam.py::TestIAMPolicyEncoding::test_put_group_policy_encoding": 0.06031510100001469, + "tests/aws/services/iam/test_iam.py::TestIAMPolicyEncoding::test_put_role_policy_encoding": 0.16878935800002637, + "tests/aws/services/iam/test_iam.py::TestIAMPolicyEncoding::test_put_user_policy_encoding": 0.08903085299982649, + "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_already_exists": 0.0377422529999194, + "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_deletion": 9.443803702999958, + "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle[accountdiscovery.ssm.amazonaws.com]": 0.23752084800003104, + "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle[acm.amazonaws.com]": 0.236425152000038, + "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle[appmesh.amazonaws.com]": 0.23591932500005441, + "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle[autoscaling-plans.amazonaws.com]": 0.23790745099995547, + "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle[autoscaling.amazonaws.com]": 0.23586615700003222, + "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle[backup.amazonaws.com]": 0.23452704400006041, + "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle[batch.amazonaws.com]": 0.23536637499989865, + "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle[cassandra.application-autoscaling.amazonaws.com]": 0.233326347000002, + "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle[cks.kms.amazonaws.com]": 0.24218515699988075, + "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle[cloudtrail.amazonaws.com]": 0.24111946700008957, + "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle[codestar-notifications.amazonaws.com]": 0.24057556000013847, + "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle[config.amazonaws.com]": 0.24120188299991696, + "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle[connect.amazonaws.com]": 0.2400878799999191, + "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle[dms-fleet-advisor.amazonaws.com]": 0.23661605099982808, + "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle[dms.amazonaws.com]": 0.23681608600008985, + "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle[docdb-elastic.amazonaws.com]": 0.23472724700013714, + "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle[ec2-instance-connect.amazonaws.com]": 0.23839326400002392, + "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle[ec2.application-autoscaling.amazonaws.com]": 0.23708535100001882, + "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle[ecr.amazonaws.com]": 0.23807324699998844, + "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle[ecs.amazonaws.com]": 0.25053279400003703, + "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle[eks-connector.amazonaws.com]": 0.24353402600002028, + "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle[eks-fargate.amazonaws.com]": 0.2515816410000298, + "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle[eks-nodegroup.amazonaws.com]": 0.23389030799989996, + "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle[eks.amazonaws.com]": 0.24098162399991452, + "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle[elasticache.amazonaws.com]": 0.2377574040001491, + "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle[elasticbeanstalk.amazonaws.com]": 0.23510221300011835, + "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle[elasticfilesystem.amazonaws.com]": 1.1003349629999093, + "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle[elasticloadbalancing.amazonaws.com]": 0.2334998760001099, + "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle[email.cognito-idp.amazonaws.com]": 0.23660922200008372, + "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle[emr-containers.amazonaws.com]": 0.23703105900005994, + "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle[emrwal.amazonaws.com]": 0.23604983900008847, + "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle[fis.amazonaws.com]": 0.23631183300005887, + "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle[grafana.amazonaws.com]": 0.23927999699992597, + "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle[imagebuilder.amazonaws.com]": 0.23719040599996788, + "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle[iotmanagedintegrations.amazonaws.com]": 0.2949682710000161, + "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle[kafka.amazonaws.com]": 0.23562907000007272, + "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle[kafkaconnect.amazonaws.com]": 0.2383439750000207, + "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle[lakeformation.amazonaws.com]": 0.23927425899989885, + "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle[lex.amazonaws.com]": 0.29387328500013155, + "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle[lexv2.amazonaws.com]": 0.23612717700018493, + "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle[lightsail.amazonaws.com]": 0.23766957700001967, + "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle[m2.amazonaws.com]": 0.2365146619999905, + "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle[memorydb.amazonaws.com]": 0.2364069699999618, + "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle[mq.amazonaws.com]": 0.23722694399998545, + "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle[mrk.kms.amazonaws.com]": 0.23770990200000597, + "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle[notifications.amazonaws.com]": 0.23669516200004637, + "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle[observability.aoss.amazonaws.com]": 0.23399929600009273, + "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle[opensearchservice.amazonaws.com]": 0.23962439000013092, + "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle[ops.apigateway.amazonaws.com]": 0.236731825999982, + "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle[ops.emr-serverless.amazonaws.com]": 0.24132388399993943, + "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle[opsdatasync.ssm.amazonaws.com]": 0.24263866400008283, + "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle[opsinsights.ssm.amazonaws.com]": 0.235813844000063, + "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle[pullthroughcache.ecr.amazonaws.com]": 0.24081646599995565, + "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle[ram.amazonaws.com]": 0.23659848799991323, + "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle[rds.amazonaws.com]": 0.2377248420000342, + "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle[redshift.amazonaws.com]": 0.23671476699996674, + "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle[replication.cassandra.amazonaws.com]": 0.2380671699999084, + "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle[replication.ecr.amazonaws.com]": 0.24236964600004285, + "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle[repository.sync.codeconnections.amazonaws.com]": 0.23834563999992042, + "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle[resource-explorer-2.amazonaws.com]": 0.2555888670000286, + "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle[rolesanywhere.amazonaws.com]": 0.2742257720000225, + "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle[s3-outposts.amazonaws.com]": 0.24921174299993254, + "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle[ses.amazonaws.com]": 0.2401779000000488, + "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle[shield.amazonaws.com]": 0.23697912300008284, + "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle[ssm-incidents.amazonaws.com]": 0.24215020600013304, + "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle[ssm-quicksetup.amazonaws.com]": 0.24041808099991613, + "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle[ssm.amazonaws.com]": 0.2410428270001148, + "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle[sso.amazonaws.com]": 0.24290620599992963, + "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle[vpcorigin.cloudfront.amazonaws.com]": 0.2394068729998935, + "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle[waf.amazonaws.com]": 0.24088652500006447, + "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle[wafv2.amazonaws.com]": 0.24069265299988274, + "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle_custom_suffix[autoscaling.amazonaws.com]": 0.12000415299996803, + "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle_custom_suffix[connect.amazonaws.com]": 0.12024076499994862, + "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle_custom_suffix[lexv2.amazonaws.com]": 0.12027017900015835, + "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle_custom_suffix_not_allowed[accountdiscovery.ssm.amazonaws.com]": 0.015942614000096, + "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle_custom_suffix_not_allowed[acm.amazonaws.com]": 0.015669434999949772, + "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle_custom_suffix_not_allowed[appmesh.amazonaws.com]": 0.016091824000000088, + "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle_custom_suffix_not_allowed[autoscaling-plans.amazonaws.com]": 0.016057498999998643, + "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle_custom_suffix_not_allowed[backup.amazonaws.com]": 0.015736869000079423, + "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle_custom_suffix_not_allowed[batch.amazonaws.com]": 0.015662854000083826, + "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle_custom_suffix_not_allowed[cassandra.application-autoscaling.amazonaws.com]": 0.01547597500007214, + "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle_custom_suffix_not_allowed[cks.kms.amazonaws.com]": 0.015872153999907823, + "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle_custom_suffix_not_allowed[cloudtrail.amazonaws.com]": 0.015592650000030517, + "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle_custom_suffix_not_allowed[codestar-notifications.amazonaws.com]": 0.01605762999986382, + "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle_custom_suffix_not_allowed[config.amazonaws.com]": 0.015653174000021863, + "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle_custom_suffix_not_allowed[dms-fleet-advisor.amazonaws.com]": 0.015661089999980504, + "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle_custom_suffix_not_allowed[dms.amazonaws.com]": 0.015666529999975864, + "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle_custom_suffix_not_allowed[docdb-elastic.amazonaws.com]": 0.01591199700010293, + "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle_custom_suffix_not_allowed[ec2-instance-connect.amazonaws.com]": 0.015887482999914937, + "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle_custom_suffix_not_allowed[ec2.application-autoscaling.amazonaws.com]": 0.015860381000038615, + "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle_custom_suffix_not_allowed[ecr.amazonaws.com]": 0.01583890400013388, + "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle_custom_suffix_not_allowed[ecs.amazonaws.com]": 0.015879390000009153, + "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle_custom_suffix_not_allowed[eks-connector.amazonaws.com]": 0.015888621000044623, + "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle_custom_suffix_not_allowed[eks-fargate.amazonaws.com]": 0.015840406999927836, + "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle_custom_suffix_not_allowed[eks-nodegroup.amazonaws.com]": 0.01621942199994919, + "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle_custom_suffix_not_allowed[eks.amazonaws.com]": 0.016415623999932905, + "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle_custom_suffix_not_allowed[elasticache.amazonaws.com]": 0.015674152999963553, + "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle_custom_suffix_not_allowed[elasticbeanstalk.amazonaws.com]": 0.015953566000007413, + "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle_custom_suffix_not_allowed[elasticfilesystem.amazonaws.com]": 0.015871371999992334, + "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle_custom_suffix_not_allowed[elasticloadbalancing.amazonaws.com]": 0.015740872000037598, + "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle_custom_suffix_not_allowed[email.cognito-idp.amazonaws.com]": 0.015461296999887963, + "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle_custom_suffix_not_allowed[emr-containers.amazonaws.com]": 0.015745907000109582, + "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle_custom_suffix_not_allowed[emrwal.amazonaws.com]": 0.016825304000008146, + "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle_custom_suffix_not_allowed[fis.amazonaws.com]": 0.01658694100001412, + "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle_custom_suffix_not_allowed[grafana.amazonaws.com]": 0.015877273999990393, + "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle_custom_suffix_not_allowed[imagebuilder.amazonaws.com]": 0.016222252000034132, + "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle_custom_suffix_not_allowed[iotmanagedintegrations.amazonaws.com]": 0.015717454999958136, + "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle_custom_suffix_not_allowed[kafka.amazonaws.com]": 0.015922987000067224, + "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle_custom_suffix_not_allowed[kafkaconnect.amazonaws.com]": 0.016659343999890552, + "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle_custom_suffix_not_allowed[lakeformation.amazonaws.com]": 0.015837504000160152, + "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle_custom_suffix_not_allowed[lex.amazonaws.com]": 0.01560044600000765, + "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle_custom_suffix_not_allowed[lightsail.amazonaws.com]": 0.016531686000121226, + "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle_custom_suffix_not_allowed[m2.amazonaws.com]": 0.0158204779999096, + "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle_custom_suffix_not_allowed[memorydb.amazonaws.com]": 0.015830616000016562, + "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle_custom_suffix_not_allowed[mq.amazonaws.com]": 0.015739126999960718, + "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle_custom_suffix_not_allowed[mrk.kms.amazonaws.com]": 0.015962194999929125, + "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle_custom_suffix_not_allowed[notifications.amazonaws.com]": 0.015920342999947934, + "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle_custom_suffix_not_allowed[observability.aoss.amazonaws.com]": 0.01599846899989643, + "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle_custom_suffix_not_allowed[opensearchservice.amazonaws.com]": 0.015627758000050562, + "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle_custom_suffix_not_allowed[ops.apigateway.amazonaws.com]": 0.015717695999796888, + "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle_custom_suffix_not_allowed[ops.emr-serverless.amazonaws.com]": 0.01593316200001027, + "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle_custom_suffix_not_allowed[opsdatasync.ssm.amazonaws.com]": 0.015808354000114377, + "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle_custom_suffix_not_allowed[opsinsights.ssm.amazonaws.com]": 0.015787648000014087, + "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle_custom_suffix_not_allowed[pullthroughcache.ecr.amazonaws.com]": 0.01600118599981215, + "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle_custom_suffix_not_allowed[ram.amazonaws.com]": 0.015932376999899134, + "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle_custom_suffix_not_allowed[rds.amazonaws.com]": 0.016099087000043255, + "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle_custom_suffix_not_allowed[redshift.amazonaws.com]": 0.015897878000032506, + "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle_custom_suffix_not_allowed[replication.cassandra.amazonaws.com]": 0.018563428000106796, + "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle_custom_suffix_not_allowed[replication.ecr.amazonaws.com]": 0.015469245999952363, + "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle_custom_suffix_not_allowed[repository.sync.codeconnections.amazonaws.com]": 0.015649419000169473, + "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle_custom_suffix_not_allowed[resource-explorer-2.amazonaws.com]": 0.015772808000065197, + "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle_custom_suffix_not_allowed[rolesanywhere.amazonaws.com]": 0.015615754000009474, + "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle_custom_suffix_not_allowed[s3-outposts.amazonaws.com]": 0.01741100800006734, + "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle_custom_suffix_not_allowed[ses.amazonaws.com]": 0.016188385000191374, + "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle_custom_suffix_not_allowed[shield.amazonaws.com]": 0.015915174000042498, + "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle_custom_suffix_not_allowed[ssm-incidents.amazonaws.com]": 0.015603532000000087, + "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle_custom_suffix_not_allowed[ssm-quicksetup.amazonaws.com]": 0.015793776000123216, + "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle_custom_suffix_not_allowed[ssm.amazonaws.com]": 0.01594392499987407, + "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle_custom_suffix_not_allowed[sso.amazonaws.com]": 0.015998808999938774, + "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle_custom_suffix_not_allowed[vpcorigin.cloudfront.amazonaws.com]": 0.016663566000033825, + "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle_custom_suffix_not_allowed[waf.amazonaws.com]": 0.015498996999895098, + "tests/aws/services/iam/test_iam.py::TestIAMServiceRoles::test_service_role_lifecycle_custom_suffix_not_allowed[wafv2.amazonaws.com]": 0.01619244999994862, + "tests/aws/services/iam/test_iam.py::TestIAMServiceSpecificCredentials::test_create_service_specific_credential_invalid_service": 0.08443130000000565, + "tests/aws/services/iam/test_iam.py::TestIAMServiceSpecificCredentials::test_create_service_specific_credential_invalid_user": 0.025679559999957746, + "tests/aws/services/iam/test_iam.py::TestIAMServiceSpecificCredentials::test_delete_user_after_service_credential_created": 0.08533676000001833, + "tests/aws/services/iam/test_iam.py::TestIAMServiceSpecificCredentials::test_id_match_user_mismatch": 0.10496085199997651, + "tests/aws/services/iam/test_iam.py::TestIAMServiceSpecificCredentials::test_invalid_update_parameters": 0.08476566499996352, + "tests/aws/services/iam/test_iam.py::TestIAMServiceSpecificCredentials::test_list_service_specific_credential_different_service": 0.08514647499998773, + "tests/aws/services/iam/test_iam.py::TestIAMServiceSpecificCredentials::test_service_specific_credential_lifecycle[cassandra.amazonaws.com]": 0.11508663900008287, + "tests/aws/services/iam/test_iam.py::TestIAMServiceSpecificCredentials::test_service_specific_credential_lifecycle[codecommit.amazonaws.com]": 0.11812451799994506, + "tests/aws/services/iam/test_iam.py::TestIAMServiceSpecificCredentials::test_user_match_id_mismatch[satisfiesregexbutstillinvalid]": 0.10094686800005093, + "tests/aws/services/iam/test_iam.py::TestIAMServiceSpecificCredentials::test_user_match_id_mismatch[totally-wrong-credential-id-with-hyphens]": 0.10170176799999808, + "tests/aws/services/iam/test_iam.py::TestRoles::test_role_with_tags": 0.07751543900008073, + "tests/aws/services/kinesis/test_kinesis.py::TestKinesis::test_add_tags_to_stream": 0.6662428759999557, + "tests/aws/services/kinesis/test_kinesis.py::TestKinesis::test_cbor_blob_handling": 0.6631036759999915, + "tests/aws/services/kinesis/test_kinesis.py::TestKinesis::test_cbor_exceptions": 0.11803236399998696, + "tests/aws/services/kinesis/test_kinesis.py::TestKinesis::test_create_stream_without_shard_count": 0.6587421030001224, + "tests/aws/services/kinesis/test_kinesis.py::TestKinesis::test_create_stream_without_stream_name_raises": 0.03923553300012372, + "tests/aws/services/kinesis/test_kinesis.py::TestKinesis::test_get_records": 0.7337191930000699, + "tests/aws/services/kinesis/test_kinesis.py::TestKinesis::test_get_records_empty_stream": 0.6706727120000551, + "tests/aws/services/kinesis/test_kinesis.py::TestKinesis::test_get_records_next_shard_iterator": 0.6840778329999466, + "tests/aws/services/kinesis/test_kinesis.py::TestKinesis::test_get_records_shard_iterator_with_surrounding_quotes": 0.6891836749999811, + "tests/aws/services/kinesis/test_kinesis.py::TestKinesis::test_record_lifecycle_data_integrity": 0.8482045110000627, + "tests/aws/services/kinesis/test_kinesis.py::TestKinesis::test_resource_policy_crud": 0.9541065870000693, + "tests/aws/services/kinesis/test_kinesis.py::TestKinesis::test_stream_consumers": 1.3269096259998605, + "tests/aws/services/kinesis/test_kinesis.py::TestKinesis::test_subscribe_to_shard": 4.585791513999993, + "tests/aws/services/kinesis/test_kinesis.py::TestKinesis::test_subscribe_to_shard_cbor_at_timestamp": 1.3565622189998976, + "tests/aws/services/kinesis/test_kinesis.py::TestKinesis::test_subscribe_to_shard_timeout": 6.335671786000148, + "tests/aws/services/kinesis/test_kinesis.py::TestKinesis::test_subscribe_to_shard_with_at_timestamp": 4.48483409500011, + "tests/aws/services/kinesis/test_kinesis.py::TestKinesis::test_subscribe_to_shard_with_at_timestamp_cbor": 0.650991071000135, + "tests/aws/services/kinesis/test_kinesis.py::TestKinesis::test_subscribe_to_shard_with_sequence_number_as_iterator": 4.540457367000158, + "tests/aws/services/kinesis/test_kinesis.py::TestKinesisJavaSDK::test_subscribe_to_shard_with_java_sdk_v2_lambda": 9.73590450600011, + "tests/aws/services/kinesis/test_kinesis.py::TestKinesisMockScala::test_add_tags_to_stream": 0.6691482530001167, + "tests/aws/services/kinesis/test_kinesis.py::TestKinesisMockScala::test_cbor_blob_handling": 0.6684586760000002, + "tests/aws/services/kinesis/test_kinesis.py::TestKinesisMockScala::test_cbor_exceptions": 0.12082172099997024, + "tests/aws/services/kinesis/test_kinesis.py::TestKinesisMockScala::test_create_stream_without_shard_count": 0.6557085149999011, + "tests/aws/services/kinesis/test_kinesis.py::TestKinesisMockScala::test_create_stream_without_stream_name_raises": 0.039067087000148604, + "tests/aws/services/kinesis/test_kinesis.py::TestKinesisMockScala::test_get_records": 0.740460434000056, + "tests/aws/services/kinesis/test_kinesis.py::TestKinesisMockScala::test_get_records_empty_stream": 0.6674212169999691, + "tests/aws/services/kinesis/test_kinesis.py::TestKinesisMockScala::test_get_records_next_shard_iterator": 0.6775948690000178, + "tests/aws/services/kinesis/test_kinesis.py::TestKinesisMockScala::test_get_records_shard_iterator_with_surrounding_quotes": 0.6706075799999098, + "tests/aws/services/kinesis/test_kinesis.py::TestKinesisMockScala::test_record_lifecycle_data_integrity": 0.8466757350000762, + "tests/aws/services/kinesis/test_kinesis.py::TestKinesisMockScala::test_resource_policy_crud": 0.8628125239999918, + "tests/aws/services/kinesis/test_kinesis.py::TestKinesisMockScala::test_stream_consumers": 1.2878686159999688, + "tests/aws/services/kinesis/test_kinesis.py::TestKinesisMockScala::test_subscribe_to_shard": 4.541976765000072, + "tests/aws/services/kinesis/test_kinesis.py::TestKinesisMockScala::test_subscribe_to_shard_cbor_at_timestamp": 4.376442415000042, + "tests/aws/services/kinesis/test_kinesis.py::TestKinesisMockScala::test_subscribe_to_shard_timeout": 6.331846114999962, + "tests/aws/services/kinesis/test_kinesis.py::TestKinesisMockScala::test_subscribe_to_shard_with_at_timestamp": 4.470410651999941, + "tests/aws/services/kinesis/test_kinesis.py::TestKinesisMockScala::test_subscribe_to_shard_with_at_timestamp_cbor": 0.644519783000078, + "tests/aws/services/kinesis/test_kinesis.py::TestKinesisMockScala::test_subscribe_to_shard_with_sequence_number_as_iterator": 4.482200308000074, + "tests/aws/services/kinesis/test_kinesis.py::TestKinesisPythonClient::test_run_kcl": 37.146918579000044, + "tests/aws/services/kms/test_kms.py::TestKMS::test_all_types_of_key_id_can_be_used_for_encryption": 0.07525084500014145, + "tests/aws/services/kms/test_kms.py::TestKMS::test_cant_delete_deleted_key": 0.03903651800010266, + "tests/aws/services/kms/test_kms.py::TestKMS::test_cant_use_disabled_or_deleted_keys": 0.0624945370000205, + "tests/aws/services/kms/test_kms.py::TestKMS::test_create_alias": 0.09774945000003754, + "tests/aws/services/kms/test_kms.py::TestKMS::test_create_custom_key_asymmetric": 0.04301571399992099, + "tests/aws/services/kms/test_kms.py::TestKMS::test_create_grant_with_invalid_key": 0.035128239999949074, + "tests/aws/services/kms/test_kms.py::TestKMS::test_create_grant_with_same_name_two_keys": 0.09220739500005948, + "tests/aws/services/kms/test_kms.py::TestKMS::test_create_grant_with_valid_key": 0.05784264400006123, + "tests/aws/services/kms/test_kms.py::TestKMS::test_create_key": 0.10303081600000041, + "tests/aws/services/kms/test_kms.py::TestKMS::test_create_key_custom_id": 0.030442850999861548, + "tests/aws/services/kms/test_kms.py::TestKMS::test_create_key_custom_key_material_hmac": 0.04035968599987427, + "tests/aws/services/kms/test_kms.py::TestKMS::test_create_key_custom_key_material_symmetric_decrypt": 0.03237497000009171, + "tests/aws/services/kms/test_kms.py::TestKMS::test_create_key_with_invalid_tag_key[lowercase_prefix]": 0.0717702270000018, + "tests/aws/services/kms/test_kms.py::TestKMS::test_create_key_with_invalid_tag_key[too_long_key]": 0.07411716600017826, + "tests/aws/services/kms/test_kms.py::TestKMS::test_create_key_with_invalid_tag_key[uppercase_prefix]": 0.07402220799986026, + "tests/aws/services/kms/test_kms.py::TestKMS::test_create_key_with_tag_and_untag": 0.10435492299995985, + "tests/aws/services/kms/test_kms.py::TestKMS::test_create_key_with_too_many_tags_raises_error": 0.07368844599989188, + "tests/aws/services/kms/test_kms.py::TestKMS::test_create_list_delete_alias": 0.07131185199989432, + "tests/aws/services/kms/test_kms.py::TestKMS::test_create_multi_region_key": 0.1471205140002212, + "tests/aws/services/kms/test_kms.py::TestKMS::test_derive_shared_secret": 0.19598962299994582, + "tests/aws/services/kms/test_kms.py::TestKMS::test_describe_and_list_sign_key": 0.038187810999943395, + "tests/aws/services/kms/test_kms.py::TestKMS::test_describe_with_alias_arn": 0.17071232100011002, + "tests/aws/services/kms/test_kms.py::TestKMS::test_disable_and_enable_key": 0.07048132900001747, + "tests/aws/services/kms/test_kms.py::TestKMS::test_encrypt_decrypt[RSA_2048-RSAES_OAEP_SHA_256]": 0.12224947100003192, + "tests/aws/services/kms/test_kms.py::TestKMS::test_encrypt_decrypt[SYMMETRIC_DEFAULT-SYMMETRIC_DEFAULT]": 0.03639782900006594, + "tests/aws/services/kms/test_kms.py::TestKMS::test_encrypt_decrypt_encryption_context": 0.1925487860000885, + "tests/aws/services/kms/test_kms.py::TestKMS::test_encrypt_validate_plaintext_size_per_key_type[RSA_2048-RSAES_OAEP_SHA_1]": 0.12749303900000086, + "tests/aws/services/kms/test_kms.py::TestKMS::test_encrypt_validate_plaintext_size_per_key_type[RSA_2048-RSAES_OAEP_SHA_256]": 0.10915568300003997, + "tests/aws/services/kms/test_kms.py::TestKMS::test_encrypt_validate_plaintext_size_per_key_type[RSA_3072-RSAES_OAEP_SHA_1]": 0.34787258199992266, + "tests/aws/services/kms/test_kms.py::TestKMS::test_encrypt_validate_plaintext_size_per_key_type[RSA_3072-RSAES_OAEP_SHA_256]": 0.4810007600001427, + "tests/aws/services/kms/test_kms.py::TestKMS::test_encrypt_validate_plaintext_size_per_key_type[RSA_4096-RSAES_OAEP_SHA_1]": 0.18832249400009005, + "tests/aws/services/kms/test_kms.py::TestKMS::test_encrypt_validate_plaintext_size_per_key_type[RSA_4096-RSAES_OAEP_SHA_256]": 0.5718246609999369, + "tests/aws/services/kms/test_kms.py::TestKMS::test_error_messaging_for_invalid_keys": 0.284109568999952, + "tests/aws/services/kms/test_kms.py::TestKMS::test_generate_and_verify_mac[HMAC_224-HMAC_SHA_224]": 0.11275924299991402, + "tests/aws/services/kms/test_kms.py::TestKMS::test_generate_and_verify_mac[HMAC_256-HMAC_SHA_256]": 0.11804133400005412, + "tests/aws/services/kms/test_kms.py::TestKMS::test_generate_and_verify_mac[HMAC_384-HMAC_SHA_384]": 0.1258368580000706, + "tests/aws/services/kms/test_kms.py::TestKMS::test_generate_and_verify_mac[HMAC_512-HMAC_SHA_512]": 0.11688147899985779, + "tests/aws/services/kms/test_kms.py::TestKMS::test_generate_random[1024]": 0.07222964099992168, + "tests/aws/services/kms/test_kms.py::TestKMS::test_generate_random[12]": 0.07562730200004353, + "tests/aws/services/kms/test_kms.py::TestKMS::test_generate_random[1]": 0.0746975490000068, + "tests/aws/services/kms/test_kms.py::TestKMS::test_generate_random[44]": 0.07282145599992873, + "tests/aws/services/kms/test_kms.py::TestKMS::test_generate_random[91]": 0.07248519300003409, + "tests/aws/services/kms/test_kms.py::TestKMS::test_generate_random_invalid_number_of_bytes[0]": 0.07411540199996125, + "tests/aws/services/kms/test_kms.py::TestKMS::test_generate_random_invalid_number_of_bytes[1025]": 0.07348865300002672, + "tests/aws/services/kms/test_kms.py::TestKMS::test_generate_random_invalid_number_of_bytes[None]": 0.08255926600008934, + "tests/aws/services/kms/test_kms.py::TestKMS::test_get_key_does_not_exist": 0.10782286599987856, + "tests/aws/services/kms/test_kms.py::TestKMS::test_get_key_in_different_region": 0.129439634000164, + "tests/aws/services/kms/test_kms.py::TestKMS::test_get_key_invalid_uuid": 0.09389854699998068, + "tests/aws/services/kms/test_kms.py::TestKMS::test_get_parameters_for_import": 0.21449805000008837, + "tests/aws/services/kms/test_kms.py::TestKMS::test_get_public_key": 0.08615242999997008, + "tests/aws/services/kms/test_kms.py::TestKMS::test_get_put_list_key_policies": 0.057031250999898475, + "tests/aws/services/kms/test_kms.py::TestKMS::test_hmac_create_key": 0.10917485100003432, + "tests/aws/services/kms/test_kms.py::TestKMS::test_hmac_create_key_invalid_operations": 0.08925669500001732, + "tests/aws/services/kms/test_kms.py::TestKMS::test_import_key_asymmetric": 0.2378090910001447, + "tests/aws/services/kms/test_kms.py::TestKMS::test_import_key_ecc_keys[ECC_NIST_P256]": 0.2829033510000727, + "tests/aws/services/kms/test_kms.py::TestKMS::test_import_key_ecc_keys[ECC_NIST_P384]": 0.21776286699991942, + "tests/aws/services/kms/test_kms.py::TestKMS::test_import_key_ecc_keys[ECC_NIST_P521]": 0.8178569530000459, + "tests/aws/services/kms/test_kms.py::TestKMS::test_import_key_ecc_keys[ECC_SECG_P256K1]": 0.25918438600001537, + "tests/aws/services/kms/test_kms.py::TestKMS::test_import_key_hmac_keys[HMAC_224]": 0.5572874010000533, + "tests/aws/services/kms/test_kms.py::TestKMS::test_import_key_hmac_keys[HMAC_256]": 1.0659213359998603, + "tests/aws/services/kms/test_kms.py::TestKMS::test_import_key_hmac_keys[HMAC_384]": 0.6776559990000806, + "tests/aws/services/kms/test_kms.py::TestKMS::test_import_key_hmac_keys[HMAC_512]": 0.7964541060000556, + "tests/aws/services/kms/test_kms.py::TestKMS::test_import_key_rsa_aes_wrap_sha256": 2.1396233709999706, + "tests/aws/services/kms/test_kms.py::TestKMS::test_import_key_symmetric": 0.2876078530000541, + "tests/aws/services/kms/test_kms.py::TestKMS::test_invalid_generate_mac[HMAC_224-HMAC_SHA_256]": 0.09140849200002776, + "tests/aws/services/kms/test_kms.py::TestKMS::test_invalid_generate_mac[HMAC_256-INVALID]": 0.0921107710000797, + "tests/aws/services/kms/test_kms.py::TestKMS::test_invalid_key_usage": 0.9693602549999696, + "tests/aws/services/kms/test_kms.py::TestKMS::test_invalid_verify_mac[HMAC_256-HMAC_SHA_256-some different important message]": 0.10348100199996679, + "tests/aws/services/kms/test_kms.py::TestKMS::test_invalid_verify_mac[HMAC_256-HMAC_SHA_512-some important message]": 0.09858694600006856, + "tests/aws/services/kms/test_kms.py::TestKMS::test_invalid_verify_mac[HMAC_256-INVALID-some important message]": 0.09800494100011292, + "tests/aws/services/kms/test_kms.py::TestKMS::test_key_enable_rotation_status[180]": 0.10370539900009135, + "tests/aws/services/kms/test_kms.py::TestKMS::test_key_enable_rotation_status[90]": 0.10208782999995947, + "tests/aws/services/kms/test_kms.py::TestKMS::test_key_rotation_status": 0.06748645199991188, + "tests/aws/services/kms/test_kms.py::TestKMS::test_key_rotations_encryption_decryption": 0.12994205799998326, + "tests/aws/services/kms/test_kms.py::TestKMS::test_key_rotations_limits": 0.2638635890000387, + "tests/aws/services/kms/test_kms.py::TestKMS::test_key_with_long_tag_value_raises_error": 0.07826206200002161, + "tests/aws/services/kms/test_kms.py::TestKMS::test_list_aliases_of_key": 0.07070787499992548, + "tests/aws/services/kms/test_kms.py::TestKMS::test_list_grants_with_invalid_key": 0.015868654999962928, + "tests/aws/services/kms/test_kms.py::TestKMS::test_list_keys": 0.029751414999964254, + "tests/aws/services/kms/test_kms.py::TestKMS::test_list_retirable_grants": 0.07939735200011455, + "tests/aws/services/kms/test_kms.py::TestKMS::test_non_multi_region_keys_should_not_have_multi_region_properties": 0.14488045799998872, + "tests/aws/services/kms/test_kms.py::TestKMS::test_plaintext_size_for_encrypt": 0.09962549800002307, + "tests/aws/services/kms/test_kms.py::TestKMS::test_re_encrypt[RSA_2048-RSAES_OAEP_SHA_256]": 0.2120501609999792, + "tests/aws/services/kms/test_kms.py::TestKMS::test_re_encrypt[SYMMETRIC_DEFAULT-SYMMETRIC_DEFAULT]": 0.1245167820000006, + "tests/aws/services/kms/test_kms.py::TestKMS::test_re_encrypt_incorrect_source_key": 0.11213603900000635, + "tests/aws/services/kms/test_kms.py::TestKMS::test_re_encrypt_invalid_destination_key": 0.05133242400006566, + "tests/aws/services/kms/test_kms.py::TestKMS::test_replicate_key": 0.4439463340000884, + "tests/aws/services/kms/test_kms.py::TestKMS::test_replicate_replica_key_should_fail": 0.11052289999997811, + "tests/aws/services/kms/test_kms.py::TestKMS::test_retire_grant_with_grant_id_and_key_id": 0.07566096199991534, + "tests/aws/services/kms/test_kms.py::TestKMS::test_retire_grant_with_grant_token": 0.0842235669999809, + "tests/aws/services/kms/test_kms.py::TestKMS::test_revoke_grant": 0.07561201099997561, + "tests/aws/services/kms/test_kms.py::TestKMS::test_rotate_key_on_demand_modifies_key_material": 0.10420845999999528, + "tests/aws/services/kms/test_kms.py::TestKMS::test_rotate_key_on_demand_raises_error_given_key_is_disabled": 0.5604534330000206, + "tests/aws/services/kms/test_kms.py::TestKMS::test_rotate_key_on_demand_raises_error_given_key_that_does_not_exist": 0.07832112000005509, + "tests/aws/services/kms/test_kms.py::TestKMS::test_rotate_key_on_demand_raises_error_given_key_with_imported_key_material": 0.001314804000003278, + "tests/aws/services/kms/test_kms.py::TestKMS::test_rotate_key_on_demand_raises_error_given_non_symmetric_key": 0.25958028499997, + "tests/aws/services/kms/test_kms.py::TestKMS::test_rotate_key_on_demand_with_symmetric_key_and_automatic_rotation_disabled": 0.10646822699993663, + "tests/aws/services/kms/test_kms.py::TestKMS::test_rotate_key_on_demand_with_symmetric_key_and_automatic_rotation_enabled": 0.1269322310000689, + "tests/aws/services/kms/test_kms.py::TestKMS::test_schedule_and_cancel_key_deletion": 0.05642230199998721, + "tests/aws/services/kms/test_kms.py::TestKMS::test_sign_verify[ECC_NIST_P256-ECDSA_SHA_256]": 0.23560709900004895, + "tests/aws/services/kms/test_kms.py::TestKMS::test_sign_verify[ECC_NIST_P384-ECDSA_SHA_384]": 0.2543413729999884, + "tests/aws/services/kms/test_kms.py::TestKMS::test_sign_verify[ECC_SECG_P256K1-ECDSA_SHA_256]": 0.2250775210000029, + "tests/aws/services/kms/test_kms.py::TestKMS::test_sign_verify[RSA_2048-RSASSA_PSS_SHA_256]": 0.6319831090000889, + "tests/aws/services/kms/test_kms.py::TestKMS::test_sign_verify[RSA_2048-RSASSA_PSS_SHA_384]": 0.6755214449998448, + "tests/aws/services/kms/test_kms.py::TestKMS::test_sign_verify[RSA_2048-RSASSA_PSS_SHA_512]": 0.6329130750000331, + "tests/aws/services/kms/test_kms.py::TestKMS::test_sign_verify[RSA_4096-RSASSA_PKCS1_V1_5_SHA_256]": 3.959218524999983, + "tests/aws/services/kms/test_kms.py::TestKMS::test_sign_verify[RSA_4096-RSASSA_PKCS1_V1_5_SHA_512]": 3.4174300860000812, + "tests/aws/services/kms/test_kms.py::TestKMS::test_symmetric_encrypt_offline_decrypt_online[RSA_2048-RSAES_OAEP_SHA_1]": 0.10718424400010917, + "tests/aws/services/kms/test_kms.py::TestKMS::test_symmetric_encrypt_offline_decrypt_online[RSA_2048-RSAES_OAEP_SHA_256]": 0.15189806000000772, + "tests/aws/services/kms/test_kms.py::TestKMS::test_symmetric_encrypt_offline_decrypt_online[RSA_3072-RSAES_OAEP_SHA_1]": 0.2191987370000561, + "tests/aws/services/kms/test_kms.py::TestKMS::test_symmetric_encrypt_offline_decrypt_online[RSA_3072-RSAES_OAEP_SHA_256]": 0.24307868800008237, + "tests/aws/services/kms/test_kms.py::TestKMS::test_symmetric_encrypt_offline_decrypt_online[RSA_4096-RSAES_OAEP_SHA_1]": 0.8285668670001769, + "tests/aws/services/kms/test_kms.py::TestKMS::test_symmetric_encrypt_offline_decrypt_online[RSA_4096-RSAES_OAEP_SHA_256]": 0.5098453329999302, + "tests/aws/services/kms/test_kms.py::TestKMS::test_tag_existing_key_and_untag": 0.11473213700003271, + "tests/aws/services/kms/test_kms.py::TestKMS::test_tag_existing_key_with_invalid_tag_key": 0.08985565799991946, + "tests/aws/services/kms/test_kms.py::TestKMS::test_tag_key_with_duplicate_tag_keys_raises_error": 0.08984834199986835, + "tests/aws/services/kms/test_kms.py::TestKMS::test_unsupported_rotate_key_on_demand_with_imported_key_material": 0.029957978999959778, + "tests/aws/services/kms/test_kms.py::TestKMS::test_untag_key_partially": 0.10400753700002952, + "tests/aws/services/kms/test_kms.py::TestKMS::test_update_alias": 0.07822793599996203, + "tests/aws/services/kms/test_kms.py::TestKMS::test_update_and_add_tags_on_tagged_key": 0.10498147600003449, + "tests/aws/services/kms/test_kms.py::TestKMS::test_update_key_description": 0.06104831400000421, + "tests/aws/services/kms/test_kms.py::TestKMS::test_verify_salt_length[ECC_NIST_P256-ECDSA_SHA_256]": 0.048955079999927875, + "tests/aws/services/kms/test_kms.py::TestKMS::test_verify_salt_length[ECC_NIST_P384-ECDSA_SHA_384]": 0.05165268600001127, + "tests/aws/services/kms/test_kms.py::TestKMS::test_verify_salt_length[ECC_SECG_P256K1-ECDSA_SHA_256]": 0.04865010700007133, + "tests/aws/services/kms/test_kms.py::TestKMS::test_verify_salt_length[RSA_2048-RSASSA_PSS_SHA_256]": 0.3070599669999865, + "tests/aws/services/kms/test_kms.py::TestKMS::test_verify_salt_length[RSA_2048-RSASSA_PSS_SHA_384]": 0.14540169199995034, + "tests/aws/services/kms/test_kms.py::TestKMS::test_verify_salt_length[RSA_2048-RSASSA_PSS_SHA_512]": 0.1956617160000178, + "tests/aws/services/kms/test_kms.py::TestKMS::test_verify_salt_length[RSA_4096-RSASSA_PKCS1_V1_5_SHA_256]": 0.7498778799999855, + "tests/aws/services/kms/test_kms.py::TestKMS::test_verify_salt_length[RSA_4096-RSASSA_PKCS1_V1_5_SHA_512]": 1.282845500999997, + "tests/aws/services/kms/test_kms.py::TestKMSGenerateKeys::test_encryption_context_generate_data_key": 0.03913119200001347, + "tests/aws/services/kms/test_kms.py::TestKMSGenerateKeys::test_encryption_context_generate_data_key_pair": 0.10479268699998556, + "tests/aws/services/kms/test_kms.py::TestKMSGenerateKeys::test_encryption_context_generate_data_key_pair_without_plaintext": 0.049937314999965565, + "tests/aws/services/kms/test_kms.py::TestKMSGenerateKeys::test_encryption_context_generate_data_key_without_plaintext": 0.03728065300003891, + "tests/aws/services/kms/test_kms.py::TestKMSGenerateKeys::test_generate_data_key": 0.03846625300002415, + "tests/aws/services/kms/test_kms.py::TestKMSGenerateKeys::test_generate_data_key_pair": 0.09385802199994941, + "tests/aws/services/kms/test_kms.py::TestKMSGenerateKeys::test_generate_data_key_pair_dry_run": 0.03170913299993572, + "tests/aws/services/kms/test_kms.py::TestKMSGenerateKeys::test_generate_data_key_pair_without_plaintext": 0.051331244999914816, + "tests/aws/services/kms/test_kms.py::TestKMSGenerateKeys::test_generate_data_key_pair_without_plaintext_dry_run": 0.0531491949999463, + "tests/aws/services/kms/test_kms.py::TestKMSGenerateKeys::test_generate_data_key_without_plaintext": 0.031767131000151494, + "tests/aws/services/kms/test_kms.py::TestKMSMultiAccounts::test_cross_accounts_access": 1.0834142170000405, + "tests/aws/services/lambda_/event_source_mapping/test_cfn_resource.py::test_adding_tags": 19.539093563999927, + "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_dynamodbstreams.py::TestDynamoDBEventSourceMapping::test_deletion_event_source_mapping_with_dynamodb": 6.102337664000061, + "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_dynamodbstreams.py::TestDynamoDBEventSourceMapping::test_disabled_dynamodb_event_source_mapping": 12.171949401000006, + "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_dynamodbstreams.py::TestDynamoDBEventSourceMapping::test_duplicate_event_source_mappings": 5.566545625000117, + "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_dynamodbstreams.py::TestDynamoDBEventSourceMapping::test_dynamodb_event_filter[content_filter_type]": 13.738606785000002, + "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_dynamodbstreams.py::TestDynamoDBEventSourceMapping::test_dynamodb_event_filter[content_multiple_filters]": 0.0068561899998940135, + "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_dynamodbstreams.py::TestDynamoDBEventSourceMapping::test_dynamodb_event_filter[content_or_filter]": 12.770586773999867, + "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_dynamodbstreams.py::TestDynamoDBEventSourceMapping::test_dynamodb_event_filter[date_time_conversion]": 12.769140345999858, + "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_dynamodbstreams.py::TestDynamoDBEventSourceMapping::test_dynamodb_event_filter[exists_false_filter]": 12.759619010000051, + "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_dynamodbstreams.py::TestDynamoDBEventSourceMapping::test_dynamodb_event_filter[exists_filter_type]": 12.673679355000104, + "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_dynamodbstreams.py::TestDynamoDBEventSourceMapping::test_dynamodb_event_filter[insert_same_entry_twice]": 12.675613689999977, + "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_dynamodbstreams.py::TestDynamoDBEventSourceMapping::test_dynamodb_event_filter[numeric_filter]": 12.712465871000177, + "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_dynamodbstreams.py::TestDynamoDBEventSourceMapping::test_dynamodb_event_filter[prefix_filter]": 12.671311755000033, + "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_dynamodbstreams.py::TestDynamoDBEventSourceMapping::test_dynamodb_event_source_mapping": 14.70439154600001, + "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_dynamodbstreams.py::TestDynamoDBEventSourceMapping::test_dynamodb_event_source_mapping_with_on_failure_destination_config": 11.222816751999972, + "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_dynamodbstreams.py::TestDynamoDBEventSourceMapping::test_dynamodb_event_source_mapping_with_s3_on_failure_destination": 11.386065805000044, + "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_dynamodbstreams.py::TestDynamoDBEventSourceMapping::test_dynamodb_event_source_mapping_with_sns_on_failure_destination_config": 11.340038573999891, + "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_dynamodbstreams.py::TestDynamoDBEventSourceMapping::test_dynamodb_invalid_event_filter[[{\"eventName\": [\"INSERT\"=123}]]": 4.473603445000435, + "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_dynamodbstreams.py::TestDynamoDBEventSourceMapping::test_dynamodb_invalid_event_filter[single-string]": 4.467117740000049, + "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_dynamodbstreams.py::TestDynamoDBEventSourceMapping::test_dynamodb_report_batch_item_failure_scenarios[empty_string_item_identifier_failure]": 14.734696914000097, + "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_dynamodbstreams.py::TestDynamoDBEventSourceMapping::test_dynamodb_report_batch_item_failure_scenarios[invalid_key_foo_failure]": 14.766616272999954, + "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_dynamodbstreams.py::TestDynamoDBEventSourceMapping::test_dynamodb_report_batch_item_failure_scenarios[invalid_key_foo_null_value_failure]": 14.813051587000018, + "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_dynamodbstreams.py::TestDynamoDBEventSourceMapping::test_dynamodb_report_batch_item_failure_scenarios[item_identifier_not_present_failure]": 14.76264406600012, + "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_dynamodbstreams.py::TestDynamoDBEventSourceMapping::test_dynamodb_report_batch_item_failure_scenarios[null_item_identifier_failure]": 14.7334870520001, + "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_dynamodbstreams.py::TestDynamoDBEventSourceMapping::test_dynamodb_report_batch_item_failure_scenarios[unhandled_exception_in_function]": 14.7123200179999, + "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_dynamodbstreams.py::TestDynamoDBEventSourceMapping::test_dynamodb_report_batch_item_failures": 15.036972384999899, + "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_dynamodbstreams.py::TestDynamoDBEventSourceMapping::test_dynamodb_report_batch_item_success_scenarios[empty_batch_item_failure_success]": 9.697935729999926, + "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_dynamodbstreams.py::TestDynamoDBEventSourceMapping::test_dynamodb_report_batch_item_success_scenarios[empty_dict_success]": 9.710972550999713, + "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_dynamodbstreams.py::TestDynamoDBEventSourceMapping::test_dynamodb_report_batch_item_success_scenarios[empty_list_success]": 9.687635306999937, + "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_dynamodbstreams.py::TestDynamoDBEventSourceMapping::test_dynamodb_report_batch_item_success_scenarios[null_batch_item_failure_success]": 9.658695268000201, + "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_dynamodbstreams.py::TestDynamoDBEventSourceMapping::test_dynamodb_report_batch_item_success_scenarios[null_success]": 9.712800831999857, + "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_dynamodbstreams.py::TestDynamoDBEventSourceMapping::test_esm_with_not_existing_dynamodb_stream": 1.7379020909999099, + "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_kinesis.py::TestKinesisEventFiltering::test_kinesis_event_filtering_json_pattern": 9.351899654000363, + "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_kinesis.py::TestKinesisSource::test_create_kinesis_event_source_mapping": 12.123220716000333, + "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_kinesis.py::TestKinesisSource::test_create_kinesis_event_source_mapping_multiple_lambdas_single_kinesis_event_stream": 19.481662102999962, + "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_kinesis.py::TestKinesisSource::test_disable_kinesis_event_source_mapping": 29.27592052700038, + "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_kinesis.py::TestKinesisSource::test_duplicate_event_source_mappings": 3.447744527000168, + "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_kinesis.py::TestKinesisSource::test_esm_with_not_existing_kinesis_stream": 1.4251973599998564, + "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_kinesis.py::TestKinesisSource::test_kinesis_empty_provided": 11.22090860299977, + "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_kinesis.py::TestKinesisSource::test_kinesis_event_source_mapping_with_async_invocation": 20.196567155000366, + "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_kinesis.py::TestKinesisSource::test_kinesis_event_source_mapping_with_on_failure_destination_config": 9.207921322000175, + "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_kinesis.py::TestKinesisSource::test_kinesis_event_source_mapping_with_s3_on_failure_destination": 9.291112459000033, + "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_kinesis.py::TestKinesisSource::test_kinesis_event_source_mapping_with_sns_on_failure_destination_config": 9.223555858000054, + "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_kinesis.py::TestKinesisSource::test_kinesis_event_source_trim_horizon": 26.318767419000324, + "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_kinesis.py::TestKinesisSource::test_kinesis_maximum_record_age_exceeded[expire-before-ingestion]": 14.269330664000108, + "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_kinesis.py::TestKinesisSource::test_kinesis_maximum_record_age_exceeded[expire-while-retrying]": 9.279857612000114, + "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_kinesis.py::TestKinesisSource::test_kinesis_maximum_record_age_exceeded_discard_records": 19.338719025999808, + "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_kinesis.py::TestKinesisSource::test_kinesis_report_batch_item_failure_scenarios[empty_string_item_identifier_failure]": 12.22695027099985, + "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_kinesis.py::TestKinesisSource::test_kinesis_report_batch_item_failure_scenarios[invalid_key_foo_failure]": 12.251495277000004, + "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_kinesis.py::TestKinesisSource::test_kinesis_report_batch_item_failure_scenarios[invalid_key_foo_null_value_failure]": 12.201116766000041, + "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_kinesis.py::TestKinesisSource::test_kinesis_report_batch_item_failure_scenarios[item_identifier_not_present_failure]": 13.21624410100003, + "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_kinesis.py::TestKinesisSource::test_kinesis_report_batch_item_failure_scenarios[null_item_identifier_failure]": 12.179542127000332, + "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_kinesis.py::TestKinesisSource::test_kinesis_report_batch_item_failure_scenarios[unhandled_exception_in_function]": 12.199320246000298, + "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_kinesis.py::TestKinesisSource::test_kinesis_report_batch_item_failures": 12.264598445000047, + "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_kinesis.py::TestKinesisSource::test_kinesis_report_batch_item_success_scenarios[empty_batch_item_failure_success]": 7.125527097000031, + "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_kinesis.py::TestKinesisSource::test_kinesis_report_batch_item_success_scenarios[empty_dict_success]": 7.1570520139998735, + "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_kinesis.py::TestKinesisSource::test_kinesis_report_batch_item_success_scenarios[empty_list_success]": 7.157303230000025, + "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_kinesis.py::TestKinesisSource::test_kinesis_report_batch_item_success_scenarios[empty_string_success]": 7.104275113999847, + "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_kinesis.py::TestKinesisSource::test_kinesis_report_batch_item_success_scenarios[null_batch_item_failure_success]": 7.143257565999875, + "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_kinesis.py::TestKinesisSource::test_kinesis_report_batch_item_success_scenarios[null_success]": 7.137574090000044, + "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_sqs.py::TestSQSEventSourceMapping::test_duplicate_event_source_mappings": 2.671776353000041, + "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_sqs.py::TestSQSEventSourceMapping::test_event_source_mapping_default_batch_size": 3.487495602000081, + "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_sqs.py::TestSQSEventSourceMapping::test_sqs_event_filter[and]": 6.462416768000139, + "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_sqs.py::TestSQSEventSourceMapping::test_sqs_event_filter[exists]": 6.462338854999871, + "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_sqs.py::TestSQSEventSourceMapping::test_sqs_event_filter[numeric-bigger]": 6.484703498000272, + "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_sqs.py::TestSQSEventSourceMapping::test_sqs_event_filter[numeric-range]": 6.469228887000099, + "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_sqs.py::TestSQSEventSourceMapping::test_sqs_event_filter[numeric-smaller]": 6.469964993000076, + "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_sqs.py::TestSQSEventSourceMapping::test_sqs_event_filter[or]": 6.469548430000032, + "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_sqs.py::TestSQSEventSourceMapping::test_sqs_event_filter[plain-string-filter]": 0.0016606720000709174, + "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_sqs.py::TestSQSEventSourceMapping::test_sqs_event_filter[plain-string-matching]": 0.0019218679999539745, + "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_sqs.py::TestSQSEventSourceMapping::test_sqs_event_filter[prefix]": 6.473829879000277, + "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_sqs.py::TestSQSEventSourceMapping::test_sqs_event_filter[single]": 6.448515857999837, + "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_sqs.py::TestSQSEventSourceMapping::test_sqs_event_filter[valid-json-filter]": 6.4730131060002805, + "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_sqs.py::TestSQSEventSourceMapping::test_sqs_event_source_mapping": 6.448754007000161, + "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_sqs.py::TestSQSEventSourceMapping::test_sqs_event_source_mapping_batch_size[10000]": 9.586044279000134, + "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_sqs.py::TestSQSEventSourceMapping::test_sqs_event_source_mapping_batch_size[1000]": 9.61095664200002, + "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_sqs.py::TestSQSEventSourceMapping::test_sqs_event_source_mapping_batch_size[100]": 9.602327203000186, + "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_sqs.py::TestSQSEventSourceMapping::test_sqs_event_source_mapping_batch_size[15]": 9.589174010000079, + "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_sqs.py::TestSQSEventSourceMapping::test_sqs_event_source_mapping_batch_size_override[10000]": 0.013637287999927139, + "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_sqs.py::TestSQSEventSourceMapping::test_sqs_event_source_mapping_batch_size_override[1000]": 9.058388519000118, + "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_sqs.py::TestSQSEventSourceMapping::test_sqs_event_source_mapping_batch_size_override[100]": 6.773113706999766, + "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_sqs.py::TestSQSEventSourceMapping::test_sqs_event_source_mapping_batch_size_override[20]": 6.453428181999925, + "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_sqs.py::TestSQSEventSourceMapping::test_sqs_event_source_mapping_batching_reserved_concurrency": 8.71703872199987, + "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_sqs.py::TestSQSEventSourceMapping::test_sqs_event_source_mapping_batching_window_size_override": 26.87101008699983, + "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_sqs.py::TestSQSEventSourceMapping::test_sqs_event_source_mapping_update": 11.810413368000127, + "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_sqs.py::TestSQSEventSourceMapping::test_sqs_invalid_event_filter[None]": 1.2844043700001748, + "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_sqs.py::TestSQSEventSourceMapping::test_sqs_invalid_event_filter[invalid_filter2]": 2.385117679000359, + "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_sqs.py::TestSQSEventSourceMapping::test_sqs_invalid_event_filter[invalid_filter3]": 1.2578402739998182, + "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_sqs.py::TestSQSEventSourceMapping::test_sqs_invalid_event_filter[simple string]": 1.256579775000091, + "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_sqs.py::test_esm_with_not_existing_sqs_queue": 1.2381455900001583, + "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_sqs.py::test_failing_lambda_retries_after_visibility_timeout": 19.38961928499998, + "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_sqs.py::test_fifo_message_group_parallelism": 63.55886172500004, + "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_sqs.py::test_message_body_and_attributes_passed_correctly": 5.2326157200000125, + "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_sqs.py::test_redrive_policy_with_failing_lambda": 16.33036967399994, + "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_sqs.py::test_report_batch_item_failures": 0.0019617919999745936, + "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_sqs.py::test_report_batch_item_failures_empty_json_batch_succeeds": 9.600262870000051, + "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_sqs.py::test_report_batch_item_failures_invalid_result_json_batch_fails": 15.944293937999873, + "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_sqs.py::test_report_batch_item_failures_on_lambda_error": 10.46249874199998, + "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_sqs.py::test_sqs_queue_as_lambda_dead_letter_queue": 6.306468979999863, + "tests/aws/services/lambda_/test_lambda.py::TestLambdaAliases::test_alias_routingconfig": 3.774854516000005, + "tests/aws/services/lambda_/test_lambda.py::TestLambdaAliases::test_lambda_alias_moving": 37.80165147300022, + "tests/aws/services/lambda_/test_lambda.py::TestLambdaBaseFeatures::test_assume_role[1]": 1.7769432549998783, + "tests/aws/services/lambda_/test_lambda.py::TestLambdaBaseFeatures::test_assume_role[2]": 1.7747804759999326, + "tests/aws/services/lambda_/test_lambda.py::TestLambdaBaseFeatures::test_function_state": 1.2700841830001082, + "tests/aws/services/lambda_/test_lambda.py::TestLambdaBaseFeatures::test_lambda_different_iam_keys_environment": 3.807665930999974, + "tests/aws/services/lambda_/test_lambda.py::TestLambdaBaseFeatures::test_lambda_large_response": 1.6255023819999224, + "tests/aws/services/lambda_/test_lambda.py::TestLambdaBaseFeatures::test_lambda_too_large_response": 1.9005019910000556, + "tests/aws/services/lambda_/test_lambda.py::TestLambdaBaseFeatures::test_lambda_too_large_response_but_with_custom_limit": 1.6431831930001408, + "tests/aws/services/lambda_/test_lambda.py::TestLambdaBaseFeatures::test_large_payloads": 1.863566577000256, + "tests/aws/services/lambda_/test_lambda.py::TestLambdaBehavior::test_ignore_architecture": 1.5904794219998166, + "tests/aws/services/lambda_/test_lambda.py::TestLambdaBehavior::test_lambda_cache_local[nodejs]": 7.727244825000071, + "tests/aws/services/lambda_/test_lambda.py::TestLambdaBehavior::test_lambda_cache_local[python]": 1.6967374900000323, + "tests/aws/services/lambda_/test_lambda.py::TestLambdaBehavior::test_lambda_host_prefix_api_operation": 13.969504820000111, + "tests/aws/services/lambda_/test_lambda.py::TestLambdaBehavior::test_lambda_init_environment": 3.3306744290002825, + "tests/aws/services/lambda_/test_lambda.py::TestLambdaBehavior::test_lambda_invoke_no_timeout": 3.658990530999972, + "tests/aws/services/lambda_/test_lambda.py::TestLambdaBehavior::test_lambda_invoke_timed_out_environment_reuse": 0.0018505350001305487, + "tests/aws/services/lambda_/test_lambda.py::TestLambdaBehavior::test_lambda_invoke_with_timeout": 3.6688465920001363, + "tests/aws/services/lambda_/test_lambda.py::TestLambdaBehavior::test_mixed_architecture": 0.0017290389998834144, + "tests/aws/services/lambda_/test_lambda.py::TestLambdaBehavior::test_runtime_introspection_arm": 0.0019343320000189124, + "tests/aws/services/lambda_/test_lambda.py::TestLambdaBehavior::test_runtime_introspection_x86": 1.849497695999844, + "tests/aws/services/lambda_/test_lambda.py::TestLambdaBehavior::test_runtime_ulimits": 1.6839137889999165, + "tests/aws/services/lambda_/test_lambda.py::TestLambdaCleanup::test_delete_lambda_during_sync_invoke": 0.00137293299940211, + "tests/aws/services/lambda_/test_lambda.py::TestLambdaCleanup::test_recreate_function": 3.453702032000365, + "tests/aws/services/lambda_/test_lambda.py::TestLambdaConcurrency::test_lambda_concurrency_block": 16.617687976999605, + "tests/aws/services/lambda_/test_lambda.py::TestLambdaConcurrency::test_lambda_concurrency_crud": 1.283731730000909, + "tests/aws/services/lambda_/test_lambda.py::TestLambdaConcurrency::test_lambda_concurrency_update": 1.3847263860002386, + "tests/aws/services/lambda_/test_lambda.py::TestLambdaConcurrency::test_lambda_provisioned_concurrency_moves_with_alias": 0.002060696000171447, + "tests/aws/services/lambda_/test_lambda.py::TestLambdaConcurrency::test_lambda_provisioned_concurrency_scheduling": 8.585584803000074, + "tests/aws/services/lambda_/test_lambda.py::TestLambdaConcurrency::test_provisioned_concurrency": 2.9287281410001924, + "tests/aws/services/lambda_/test_lambda.py::TestLambdaConcurrency::test_provisioned_concurrency_on_alias": 3.053905483000108, + "tests/aws/services/lambda_/test_lambda.py::TestLambdaConcurrency::test_reserved_concurrency": 8.642495405999853, + "tests/aws/services/lambda_/test_lambda.py::TestLambdaConcurrency::test_reserved_concurrency_async_queue": 3.6552346879998368, + "tests/aws/services/lambda_/test_lambda.py::TestLambdaConcurrency::test_reserved_provisioned_overlap": 9.618978092000816, + "tests/aws/services/lambda_/test_lambda.py::TestLambdaErrors::test_lambda_handler_error": 1.609167341000557, + "tests/aws/services/lambda_/test_lambda.py::TestLambdaErrors::test_lambda_handler_exit": 0.001988982000057149, + "tests/aws/services/lambda_/test_lambda.py::TestLambdaErrors::test_lambda_invoke_payload_encoding_error[body-n\\x87r\\x9e\\xe9\\xb5\\xd7I\\xee\\x9bmt]": 1.353904796000279, + "tests/aws/services/lambda_/test_lambda.py::TestLambdaErrors::test_lambda_invoke_payload_encoding_error[message-\\x99\\xeb,j\\x07\\xa1zYh]": 1.3548934179998469, + "tests/aws/services/lambda_/test_lambda.py::TestLambdaErrors::test_lambda_runtime_error": 7.800451548000183, + "tests/aws/services/lambda_/test_lambda.py::TestLambdaErrors::test_lambda_runtime_exit": 0.0013810180003019923, + "tests/aws/services/lambda_/test_lambda.py::TestLambdaErrors::test_lambda_runtime_exit_segfault": 0.0012109310005143925, + "tests/aws/services/lambda_/test_lambda.py::TestLambdaErrors::test_lambda_runtime_startup_error": 1.425636245000078, + "tests/aws/services/lambda_/test_lambda.py::TestLambdaErrors::test_lambda_runtime_startup_timeout": 41.968216714999926, + "tests/aws/services/lambda_/test_lambda.py::TestLambdaErrors::test_lambda_runtime_wrapper_not_found": 0.0016221579999182723, + "tests/aws/services/lambda_/test_lambda.py::TestLambdaFeatures::test_invocation_type_dry_run[nodejs16.x]": 0.0020073660002708493, + "tests/aws/services/lambda_/test_lambda.py::TestLambdaFeatures::test_invocation_type_dry_run[python3.10]": 0.0018761429996629886, + "tests/aws/services/lambda_/test_lambda.py::TestLambdaFeatures::test_invocation_type_event[nodejs16.x]": 2.317425625999931, + "tests/aws/services/lambda_/test_lambda.py::TestLambdaFeatures::test_invocation_type_event[python3.10]": 2.3033226069997, + "tests/aws/services/lambda_/test_lambda.py::TestLambdaFeatures::test_invocation_type_event_error": 0.0015690790000917332, + "tests/aws/services/lambda_/test_lambda.py::TestLambdaFeatures::test_invocation_type_no_return_payload[nodejs-Event]": 2.319506492000073, + "tests/aws/services/lambda_/test_lambda.py::TestLambdaFeatures::test_invocation_type_no_return_payload[nodejs-RequestResponse]": 2.6865782029999536, + "tests/aws/services/lambda_/test_lambda.py::TestLambdaFeatures::test_invocation_type_no_return_payload[python-Event]": 2.313405053999759, + "tests/aws/services/lambda_/test_lambda.py::TestLambdaFeatures::test_invocation_type_no_return_payload[python-RequestResponse]": 2.6387833010003305, + "tests/aws/services/lambda_/test_lambda.py::TestLambdaFeatures::test_invocation_type_request_response[nodejs16.x]": 1.6309119879997525, + "tests/aws/services/lambda_/test_lambda.py::TestLambdaFeatures::test_invocation_type_request_response[python3.10]": 1.623645045999183, + "tests/aws/services/lambda_/test_lambda.py::TestLambdaFeatures::test_invocation_with_logs[nodejs16.x]": 15.813433480000413, + "tests/aws/services/lambda_/test_lambda.py::TestLambdaFeatures::test_invocation_with_logs[python3.10]": 7.746435490000067, + "tests/aws/services/lambda_/test_lambda.py::TestLambdaFeatures::test_invocation_with_qualifier": 1.9019169160001184, + "tests/aws/services/lambda_/test_lambda.py::TestLambdaFeatures::test_invoke_exceptions": 0.10320941899999525, + "tests/aws/services/lambda_/test_lambda.py::TestLambdaFeatures::test_lambda_with_context": 0.0029127870002412237, + "tests/aws/services/lambda_/test_lambda.py::TestLambdaFeatures::test_upload_lambda_from_s3": 2.129957241000284, + "tests/aws/services/lambda_/test_lambda.py::TestLambdaMultiAccounts::test_delete_function": 1.1653334100001302, + "tests/aws/services/lambda_/test_lambda.py::TestLambdaMultiAccounts::test_function_alias": 1.2100018940000155, + "tests/aws/services/lambda_/test_lambda.py::TestLambdaMultiAccounts::test_function_concurrency": 1.1834457669997391, + "tests/aws/services/lambda_/test_lambda.py::TestLambdaMultiAccounts::test_function_invocation": 1.5702022199998282, + "tests/aws/services/lambda_/test_lambda.py::TestLambdaMultiAccounts::test_function_tags": 1.1938104490000114, + "tests/aws/services/lambda_/test_lambda.py::TestLambdaMultiAccounts::test_get_function": 1.1864973680003459, + "tests/aws/services/lambda_/test_lambda.py::TestLambdaMultiAccounts::test_get_function_configuration": 1.1722147360001145, + "tests/aws/services/lambda_/test_lambda.py::TestLambdaMultiAccounts::test_get_lambda_layer": 0.1427004250003847, + "tests/aws/services/lambda_/test_lambda.py::TestLambdaMultiAccounts::test_list_versions_by_function": 1.1817483820000234, + "tests/aws/services/lambda_/test_lambda.py::TestLambdaMultiAccounts::test_publish_version": 1.2331258129997877, + "tests/aws/services/lambda_/test_lambda.py::TestLambdaPermissions::test_lambda_permission_url_invocation": 0.0016648660000555537, + "tests/aws/services/lambda_/test_lambda.py::TestLambdaURL::test_function_url_with_response_streaming": 7.938405253000155, + "tests/aws/services/lambda_/test_lambda.py::TestLambdaURL::test_lambda_update_function_url_config": 1.4785447689998819, + "tests/aws/services/lambda_/test_lambda.py::TestLambdaURL::test_lambda_url_echo_http_fixture_default": 2.0410052570000516, + "tests/aws/services/lambda_/test_lambda.py::TestLambdaURL::test_lambda_url_echo_http_fixture_trim_x_headers": 2.9943600080002852, + "tests/aws/services/lambda_/test_lambda.py::TestLambdaURL::test_lambda_url_echo_invoke[BUFFERED]": 1.93905359900009, + "tests/aws/services/lambda_/test_lambda.py::TestLambdaURL::test_lambda_url_echo_invoke[None]": 1.9279683730001125, + "tests/aws/services/lambda_/test_lambda.py::TestLambdaURL::test_lambda_url_echo_invoke[RESPONSE_STREAM]": 0.012159704000168858, + "tests/aws/services/lambda_/test_lambda.py::TestLambdaURL::test_lambda_url_form_payload": 1.8806745419999515, + "tests/aws/services/lambda_/test_lambda.py::TestLambdaURL::test_lambda_url_headers_and_status": 1.6586140920001071, + "tests/aws/services/lambda_/test_lambda.py::TestLambdaURL::test_lambda_url_invalid_invoke_mode": 1.4352354319998994, + "tests/aws/services/lambda_/test_lambda.py::TestLambdaURL::test_lambda_url_invocation[boolean]": 1.8288806030002434, + "tests/aws/services/lambda_/test_lambda.py::TestLambdaURL::test_lambda_url_invocation[dict]": 1.8197115729997222, + "tests/aws/services/lambda_/test_lambda.py::TestLambdaURL::test_lambda_url_invocation[float]": 1.8417397279999932, + "tests/aws/services/lambda_/test_lambda.py::TestLambdaURL::test_lambda_url_invocation[http-response-json]": 1.8216079999999693, + "tests/aws/services/lambda_/test_lambda.py::TestLambdaURL::test_lambda_url_invocation[http-response]": 1.8228076079999482, + "tests/aws/services/lambda_/test_lambda.py::TestLambdaURL::test_lambda_url_invocation[integer]": 1.8499917349997759, + "tests/aws/services/lambda_/test_lambda.py::TestLambdaURL::test_lambda_url_invocation[list-mixed]": 1.8187581490003595, + "tests/aws/services/lambda_/test_lambda.py::TestLambdaURL::test_lambda_url_invocation[string]": 1.8320846260003236, + "tests/aws/services/lambda_/test_lambda.py::TestLambdaURL::test_lambda_url_invocation_custom_id": 1.5985798579999937, + "tests/aws/services/lambda_/test_lambda.py::TestLambdaURL::test_lambda_url_invocation_custom_id_aliased": 1.6077459610000915, + "tests/aws/services/lambda_/test_lambda.py::TestLambdaURL::test_lambda_url_invocation_exception": 1.8434158059997117, + "tests/aws/services/lambda_/test_lambda.py::TestLambdaURL::test_lambda_url_non_existing_url": 0.01706250300026113, + "tests/aws/services/lambda_/test_lambda.py::TestLambdaURL::test_lambda_url_persists_after_alias_delete": 3.9523542629997337, + "tests/aws/services/lambda_/test_lambda.py::TestLambdaVersions::test_async_invoke_queue_upon_function_update": 100.17100790900031, + "tests/aws/services/lambda_/test_lambda.py::TestLambdaVersions::test_function_update_during_invoke": 0.0016117479999593343, + "tests/aws/services/lambda_/test_lambda.py::TestLambdaVersions::test_lambda_handler_update": 3.339313079999556, + "tests/aws/services/lambda_/test_lambda.py::TestLambdaVersions::test_lambda_versions_with_code_changes": 5.744227653000053, + "tests/aws/services/lambda_/test_lambda.py::TestRequestIdHandling::test_request_id_async_invoke_with_retry": 11.320661913000095, + "tests/aws/services/lambda_/test_lambda.py::TestRequestIdHandling::test_request_id_format": 0.0337875189998158, + "tests/aws/services/lambda_/test_lambda.py::TestRequestIdHandling::test_request_id_invoke": 4.0056264960001045, + "tests/aws/services/lambda_/test_lambda.py::TestRequestIdHandling::test_request_id_invoke_url": 3.869290203999981, + "tests/aws/services/lambda_/test_lambda_api.py::TestCodeSigningConfig::test_code_signing_not_found_excs": 1.3611597699998583, + "tests/aws/services/lambda_/test_lambda_api.py::TestCodeSigningConfig::test_function_code_signing_config": 1.3207078299997193, + "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaAccountSettings::test_account_settings": 0.07984425700010434, + "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaAccountSettings::test_account_settings_total_code_size": 1.5261632329998065, + "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaAccountSettings::test_account_settings_total_code_size_config_update": 7.466087038000069, + "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaAlias::test_alias_lifecycle": 2.6898677359999965, + "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaAlias::test_alias_naming": 2.502068691000204, + "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaAlias::test_non_existent_alias_deletion": 1.2483986570000525, + "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaAlias::test_non_existent_alias_update": 1.2247517570001492, + "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaAlias::test_notfound_and_invalid_routingconfigs": 1.5069724289999158, + "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaEndpoints::test_s3_code_url[localstack_host0]": 1.1918762670002252, + "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaEndpoints::test_s3_code_url[localstack_host1]": 1.1855227149999337, + "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaEndpoints::test_s3_code_url[localstack_host2]": 1.193306714999835, + "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaEventInvokeConfig::test_lambda_eventinvokeconfig_exceptions": 2.9189557659999537, + "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaEventInvokeConfig::test_lambda_eventinvokeconfig_lifecycle": 1.4090530159999162, + "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaEventSourceMappings::test_create_event_filter_criteria_validation": 3.5983861900001557, + "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaEventSourceMappings::test_create_event_source_self_managed": 0.001569402000086484, + "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaEventSourceMappings::test_create_event_source_validation": 3.4591853359997913, + "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaEventSourceMappings::test_create_event_source_validation_kinesis": 1.9422431769999093, + "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaEventSourceMappings::test_event_source_mapping_exceptions": 0.14435250899987295, + "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaEventSourceMappings::test_event_source_mapping_lifecycle": 7.758359959000018, + "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaEventSourceMappings::test_event_source_mapping_lifecycle_delete_function": 6.0902301920000355, + "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaEventSourceMappings::test_function_name_variations": 16.181312729999945, + "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_create_lambda_exceptions": 0.1611859550000645, + "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_delete_on_nonexisting_version": 1.2679380070001116, + "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_arns": 2.611127668999643, + "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_lifecycle": 13.965233762000253, + "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[full_arn_and_qualifier_too_long_and_invalid_region-create_function]": 0.09690669999986312, + "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[full_arn_and_qualifier_too_long_and_invalid_region-delete_function]": 0.08042988499983039, + "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[full_arn_and_qualifier_too_long_and_invalid_region-get_function]": 0.07774769899970124, + "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[full_arn_and_qualifier_too_long_and_invalid_region-invoke]": 0.0795029760001853, + "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[full_arn_with_multiple_qualifiers-create_function]": 0.09718526399979055, + "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[full_arn_with_multiple_qualifiers-delete_function]": 0.08033341400005156, + "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[full_arn_with_multiple_qualifiers-get_function]": 0.0795279690003099, + "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[full_arn_with_multiple_qualifiers-invoke]": 0.08172547399976793, + "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[function_name_is_single_invalid-create_function]": 0.09317256000008456, + "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[function_name_is_single_invalid-delete_function]": 0.07956548699985433, + "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[function_name_is_single_invalid-get_function]": 0.07877618499992423, + "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[function_name_is_single_invalid-invoke]": 0.07728964300008556, + "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[function_name_too_long-create_function]": 0.0915923349998593, + "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[function_name_too_long-delete_function]": 0.07934115800003383, + "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[function_name_too_long-get_function]": 0.07854317499982244, + "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[function_name_too_long-invoke]": 0.00917423299983966, + "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[function_name_too_long_and_invalid_region-create_function]": 0.09439862599992921, + "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[function_name_too_long_and_invalid_region-delete_function]": 0.08110562799993204, + "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[function_name_too_long_and_invalid_region-get_function]": 0.07756306400005997, + "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[function_name_too_long_and_invalid_region-invoke]": 0.07784435799999301, + "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[incomplete_arn-create_function]": 0.00993420600002537, + "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[incomplete_arn-delete_function]": 0.08318418799990468, + "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[incomplete_arn-get_function]": 0.08172020100005284, + "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[incomplete_arn-invoke]": 0.010790625999788972, + "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[invalid_account_id_in_partial_arn-create_function]": 0.09322575300006974, + "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[invalid_account_id_in_partial_arn-delete_function]": 0.07974302499997066, + "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[invalid_account_id_in_partial_arn-get_function]": 0.07751704099973722, + "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[invalid_account_id_in_partial_arn-invoke]": 0.07814713799984929, + "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[invalid_characters_in_function_name-create_function]": 0.09295170800010055, + "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[invalid_characters_in_function_name-delete_function]": 0.0796517070000391, + "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[invalid_characters_in_function_name-get_function]": 0.07820801799971377, + "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[invalid_characters_in_function_name-invoke]": 0.07757854000010411, + "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[invalid_characters_in_qualifier-create_function]": 0.0928619889998572, + "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[invalid_characters_in_qualifier-delete_function]": 0.07933900099988023, + "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[invalid_characters_in_qualifier-get_function]": 0.07745431600028496, + "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[invalid_characters_in_qualifier-invoke]": 0.07640406599989547, + "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[invalid_region_in_arn-create_function]": 0.09523165099994912, + "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[invalid_region_in_arn-delete_function]": 0.07916874600027768, + "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[invalid_region_in_arn-get_function]": 0.07689634700022907, + "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[invalid_region_in_arn-invoke]": 0.07868826600019929, + "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[latest_version_with_additional_qualifier-create_function]": 0.1022781629999372, + "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[latest_version_with_additional_qualifier-delete_function]": 0.08555620499987526, + "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[latest_version_with_additional_qualifier-get_function]": 0.08123639200016441, + "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[latest_version_with_additional_qualifier-invoke]": 0.0925592080000115, + "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[lowercase_latest_qualifier-create_function]": 0.11940647500000523, + "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[lowercase_latest_qualifier-delete_function]": 0.009787160000314543, + "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[lowercase_latest_qualifier-get_function]": 0.07980758099984087, + "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[lowercase_latest_qualifier-invoke]": 0.08365348500001346, + "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[missing_account_id_in_arn-create_function]": 0.09505319999993844, + "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[missing_account_id_in_arn-delete_function]": 0.0790348489997541, + "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[missing_account_id_in_arn-get_function]": 0.07734486599974844, + "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[missing_account_id_in_arn-invoke]": 0.07819100699975934, + "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[missing_region_in_arn-create_function]": 0.09556850100011616, + "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[missing_region_in_arn-delete_function]": 0.07740989600029025, + "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[missing_region_in_arn-get_function]": 0.07705608400010533, + "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[missing_region_in_arn-invoke]": 0.07898846900025092, + "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[misspelled_latest_in_arn-create_function]": 0.09483925499966972, + "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[misspelled_latest_in_arn-delete_function]": 0.07741275300008965, + "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[misspelled_latest_in_arn-get_function]": 0.07684864799989555, + "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[misspelled_latest_in_arn-invoke]": 0.07655330200009303, + "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[non_lambda_arn-create_function]": 0.09553111899981559, + "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[non_lambda_arn-delete_function]": 0.08118155400006799, + "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[non_lambda_arn-get_function]": 0.07828541800017774, + "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[non_lambda_arn-invoke]": 0.0787381100001312, + "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[partial_arn_with_extra_qualifier-create_function]": 0.0998242919997665, + "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[partial_arn_with_extra_qualifier-delete_function]": 0.0825988699998561, + "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[partial_arn_with_extra_qualifier-get_function]": 0.08045580799989693, + "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[partial_arn_with_extra_qualifier-invoke]": 0.08186571900000672, + "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[qualifier_too_long-create_function]": 0.09258256500015705, + "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[qualifier_too_long-delete_function]": 0.07883430900028543, + "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[qualifier_too_long-get_function]": 0.07583370099973763, + "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[qualifier_too_long-invoke]": 0.07682908100014174, + "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_get_function_wrong_region[delete_function]": 1.2341862329999458, + "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_get_function_wrong_region[get_function]": 1.2357378359999984, + "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_get_function_wrong_region[get_function_code_signing_config]": 1.2447863419999976, + "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_get_function_wrong_region[get_function_concurrency]": 1.2331815660002121, + "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_get_function_wrong_region[get_function_configuration]": 1.2453651789996911, + "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_get_function_wrong_region[get_function_event_invoke_config]": 1.2484696559999975, + "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_get_function_wrong_region[get_function_url_config]": 1.2458108739999716, + "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_get_function_wrong_region[invoke]": 1.2478288480001538, + "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_invalid_invoke": 0.07864329400013048, + "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_invalid_vpc_config_security_group": 0.0012454470002012386, + "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_invalid_vpc_config_subnet": 0.24479987999984587, + "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_lambda_code_location_s3": 2.196056768000062, + "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_lambda_code_location_s3_errors": 1.4253174380000928, + "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_lambda_code_location_zipfile": 1.476975191000065, + "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_lambda_concurrent_code_updates": 2.357595589000084, + "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_lambda_concurrent_config_updates": 1.2862788170000385, + "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_list_functions": 2.5866544390000854, + "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_ops_on_nonexisting_fn[delete_function]": 0.07943708299967511, + "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_ops_on_nonexisting_fn[get_function]": 0.07946960399999625, + "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_ops_on_nonexisting_fn[get_function_code_signing_config]": 0.07917695700007243, + "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_ops_on_nonexisting_fn[get_function_concurrency]": 0.08024742699967646, + "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_ops_on_nonexisting_fn[get_function_configuration]": 0.07861296100031723, + "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_ops_on_nonexisting_fn[get_function_event_invoke_config]": 0.0787924070000372, + "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_ops_on_nonexisting_fn[get_function_url_config]": 0.08180243600008907, + "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_ops_on_nonexisting_version[get_function]": 1.237768461999849, + "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_ops_on_nonexisting_version[get_function_configuration]": 1.237413854000124, + "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_ops_on_nonexisting_version[get_function_event_invoke_config]": 1.2372900269999718, + "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_ops_with_arn_qualifier_mismatch[delete_function]": 0.09339908800006924, + "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_ops_with_arn_qualifier_mismatch[get_function]": 0.08950060300003315, + "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_ops_with_arn_qualifier_mismatch[get_function_configuration]": 0.09007958699999108, + "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_redundant_updates": 1.4294561499998508, + "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_update_lambda_exceptions": 1.2419897610000135, + "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_vpc_config": 2.099020168999914, + "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaImages::test_lambda_image_and_image_config_crud": 1.444914739000069, + "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaImages::test_lambda_image_crud": 3.6087379400000827, + "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaImages::test_lambda_image_versions": 1.5208672100000058, + "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaImages::test_lambda_zip_file_to_image": 1.4336479990001862, + "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaLayer::test_layer_compatibilities[runtimes0]": 0.13284665800006223, + "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaLayer::test_layer_compatibilities[runtimes1]": 0.1322108169999865, + "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaLayer::test_layer_deterministic_version": 0.09139648000018497, + "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaLayer::test_layer_exceptions": 0.3277695199999471, + "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaLayer::test_layer_function_exceptions": 17.59035748899987, + "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaLayer::test_layer_function_quota_exception": 16.458823675000076, + "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaLayer::test_layer_lifecycle": 2.643783758000154, + "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaLayer::test_layer_policy_exceptions": 0.2507123740001589, + "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaLayer::test_layer_policy_lifecycle": 0.18940312500012624, + "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaLayer::test_layer_s3_content": 0.22167809900020075, + "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaPermissions::test_add_lambda_permission_aws": 1.2566154129997358, + "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaPermissions::test_add_lambda_permission_fields": 1.3169450529999267, + "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaPermissions::test_create_multiple_lambda_permissions": 1.256923363000169, + "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaPermissions::test_lambda_permission_fn_versioning": 1.425892594999823, + "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaPermissions::test_permission_exceptions": 1.3610277620000488, + "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaPermissions::test_remove_multi_permissions": 1.3039002479999908, + "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaProvisionedConcurrency::test_lambda_provisioned_lifecycle": 2.5250874379999004, + "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaProvisionedConcurrency::test_provisioned_concurrency_exceptions": 1.4273166680000031, + "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaProvisionedConcurrency::test_provisioned_concurrency_limits": 1.2894245090001277, + "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaRecursion::test_put_function_recursion_config_allow": 1.2440557429997625, + "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaRecursion::test_put_function_recursion_config_default_terminate": 1.2329553540000688, + "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaRecursion::test_put_function_recursion_config_invalid_value": 1.2277464990002045, + "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaReservedConcurrency::test_function_concurrency": 1.2642305920001036, + "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaReservedConcurrency::test_function_concurrency_exceptions": 1.2732510029998139, + "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaReservedConcurrency::test_function_concurrency_limits": 1.2304744119999214, + "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaRevisions::test_function_revisions_basic": 13.959974920999912, + "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaRevisions::test_function_revisions_permissions": 1.350482189000104, + "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaRevisions::test_function_revisions_version_and_alias": 1.4652932850003708, + "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaSizeLimits::test_lambda_envvars_near_limit_succeeds": 1.310029866999912, + "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaSizeLimits::test_large_environment_fails_multiple_keys": 16.1882492740001, + "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaSizeLimits::test_large_environment_variables_fails": 16.197543932999906, + "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaSizeLimits::test_large_lambda": 12.048900620000268, + "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaSizeLimits::test_oversized_request_create_lambda": 2.1221904720000566, + "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaSizeLimits::test_oversized_unzipped_lambda": 4.7276464229998965, + "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaSizeLimits::test_oversized_zipped_create_lambda": 1.6450437239998337, + "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaSnapStart::test_snapstart_exceptions": 0.09433723300026031, + "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaSnapStart::test_snapstart_lifecycle[dotnet8]": 3.3995466389999365, + "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaSnapStart::test_snapstart_lifecycle[java11]": 2.3949374940000325, + "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaSnapStart::test_snapstart_lifecycle[java17]": 2.386287237000033, + "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaSnapStart::test_snapstart_lifecycle[java21]": 3.4900049850000414, + "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaSnapStart::test_snapstart_lifecycle[python3.12]": 1.31538473899991, + "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaSnapStart::test_snapstart_lifecycle[python3.13]": 7.51159045099962, + "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaSnapStart::test_snapstart_update_function_configuration[dotnet8]": 1.2749618470002133, + "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaSnapStart::test_snapstart_update_function_configuration[java11]": 1.296473209999931, + "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaSnapStart::test_snapstart_update_function_configuration[java17]": 1.2748645259998739, + "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaSnapStart::test_snapstart_update_function_configuration[java21]": 1.2906026549999297, + "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaSnapStart::test_snapstart_update_function_configuration[python3.12]": 1.2892904830000589, + "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaSnapStart::test_snapstart_update_function_configuration[python3.13]": 1.2684874850001506, + "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaTag::test_create_tag_on_esm_create": 1.618167000999847, + "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaTag::test_create_tag_on_fn_create": 1.2724506760000622, + "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaTag::test_tag_exceptions[event_source_mapping]": 0.1226704810001138, + "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaTag::test_tag_exceptions[lambda_function]": 0.11912567900026261, + "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaTag::test_tag_lifecycle[event_source_mapping]": 1.5263167329999305, + "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaTag::test_tag_lifecycle[lambda_function]": 1.3617147530003422, + "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaTag::test_tag_nonexisting_resource": 1.3167038249998768, + "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaTags::test_tag_exceptions": 1.3405402209998556, + "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaTags::test_tag_lifecycle": 1.517157499999712, + "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaTags::test_tag_limits": 1.4266448680002668, + "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaTags::test_tag_versions": 1.2881184849998135, + "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaUrl::test_create_url_config_custom_id_tag": 1.1742348219997893, + "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaUrl::test_create_url_config_custom_id_tag_alias": 3.515004801999794, + "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaUrl::test_create_url_config_custom_id_tag_invalid_id": 1.1654222020001725, + "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaUrl::test_url_config_deletion_without_qualifier": 1.3781419300000834, + "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaUrl::test_url_config_exceptions": 7.683597218999921, + "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaUrl::test_url_config_lifecycle": 1.336087761999579, + "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaUrl::test_url_config_list_paging": 1.4136182499996721, + "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaVersions::test_publish_version_on_create": 1.377443539999831, + "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaVersions::test_publish_with_update": 1.4418671279997852, + "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaVersions::test_publish_with_wrong_sha256": 1.2903443610000522, + "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaVersions::test_version_lifecycle": 1.5859621200002039, + "tests/aws/services/lambda_/test_lambda_api.py::TestLoggingConfig::test_advanced_logging_configuration_format_switch": 1.4260140040000806, + "tests/aws/services/lambda_/test_lambda_api.py::TestLoggingConfig::test_function_advanced_logging_configuration": 1.360485423, + "tests/aws/services/lambda_/test_lambda_api.py::TestLoggingConfig::test_function_partial_advanced_logging_configuration_update[partial_config0]": 1.346933853000337, + "tests/aws/services/lambda_/test_lambda_api.py::TestLoggingConfig::test_function_partial_advanced_logging_configuration_update[partial_config1]": 1.3544866539998566, + "tests/aws/services/lambda_/test_lambda_api.py::TestLoggingConfig::test_function_partial_advanced_logging_configuration_update[partial_config2]": 1.36505804300009, + "tests/aws/services/lambda_/test_lambda_api.py::TestLoggingConfig::test_function_partial_advanced_logging_configuration_update[partial_config3]": 1.3700794369999585, + "tests/aws/services/lambda_/test_lambda_api.py::TestPartialARNMatching::test_cross_region_arn_function_access": 1.2886335479997797, + "tests/aws/services/lambda_/test_lambda_api.py::TestPartialARNMatching::test_update_function_configuration_full_arn": 1.3511882110001352, + "tests/aws/services/lambda_/test_lambda_api.py::TestRuntimeValidation::test_create_deprecated_function_runtime_with_validation_disabled": 15.28985684600002, + "tests/aws/services/lambda_/test_lambda_api.py::TestRuntimeValidation::test_create_deprecated_function_runtime_with_validation_enabled[dotnetcore3.1]": 0.0932805739998912, + "tests/aws/services/lambda_/test_lambda_api.py::TestRuntimeValidation::test_create_deprecated_function_runtime_with_validation_enabled[go1.x]": 0.09605915799988907, + "tests/aws/services/lambda_/test_lambda_api.py::TestRuntimeValidation::test_create_deprecated_function_runtime_with_validation_enabled[java8]": 0.09706734199994571, + "tests/aws/services/lambda_/test_lambda_api.py::TestRuntimeValidation::test_create_deprecated_function_runtime_with_validation_enabled[nodejs12.x]": 0.09515151900018282, + "tests/aws/services/lambda_/test_lambda_api.py::TestRuntimeValidation::test_create_deprecated_function_runtime_with_validation_enabled[nodejs14.x]": 0.09513771200022347, + "tests/aws/services/lambda_/test_lambda_api.py::TestRuntimeValidation::test_create_deprecated_function_runtime_with_validation_enabled[provided]": 0.09448335899969607, + "tests/aws/services/lambda_/test_lambda_api.py::TestRuntimeValidation::test_create_deprecated_function_runtime_with_validation_enabled[python3.7]": 0.09420069199995851, + "tests/aws/services/lambda_/test_lambda_api.py::TestRuntimeValidation::test_create_deprecated_function_runtime_with_validation_enabled[ruby2.7]": 0.09718651699995462, + "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaCallingLocalstack::test_manual_endpoint_injection[dotnet6]": 1.9716081999999915, + "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaCallingLocalstack::test_manual_endpoint_injection[dotnet8]": 1.9185855260002427, + "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaCallingLocalstack::test_manual_endpoint_injection[java11]": 5.017611704000046, + "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaCallingLocalstack::test_manual_endpoint_injection[java17]": 4.330249219000052, + "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaCallingLocalstack::test_manual_endpoint_injection[java21]": 4.2266401210004005, + "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaCallingLocalstack::test_manual_endpoint_injection[java8.al2]": 5.9387268119999135, + "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaCallingLocalstack::test_manual_endpoint_injection[nodejs16.x]": 1.825586645000385, + "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaCallingLocalstack::test_manual_endpoint_injection[nodejs18.x]": 1.8509531779991448, + "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaCallingLocalstack::test_manual_endpoint_injection[nodejs20.x]": 1.7242943249998461, + "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaCallingLocalstack::test_manual_endpoint_injection[nodejs22.x]": 1.7350301700007549, + "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaCallingLocalstack::test_manual_endpoint_injection[python3.10]": 1.792552868000712, + "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaCallingLocalstack::test_manual_endpoint_injection[python3.11]": 1.7933644890003961, + "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaCallingLocalstack::test_manual_endpoint_injection[python3.12]": 1.864934016999996, + "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaCallingLocalstack::test_manual_endpoint_injection[python3.13]": 1.7974310790000345, + "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaCallingLocalstack::test_manual_endpoint_injection[python3.8]": 1.8028182590001052, + "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaCallingLocalstack::test_manual_endpoint_injection[python3.9]": 1.8059142080005586, + "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaCallingLocalstack::test_manual_endpoint_injection[ruby3.2]": 2.572872259000178, + "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaCallingLocalstack::test_manual_endpoint_injection[ruby3.3]": 2.529481393999504, + "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaCallingLocalstack::test_manual_endpoint_injection[ruby3.4]": 2.101305271000456, + "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_echo_invoke[dotnet6]": 3.6225527679998777, + "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_echo_invoke[dotnet8]": 2.639297213000191, + "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_echo_invoke[java11]": 2.5319848310005, + "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_echo_invoke[java17]": 2.4719371790001787, + "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_echo_invoke[java21]": 2.4938243340002373, + "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_echo_invoke[java8.al2]": 3.6080355789999885, + "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_echo_invoke[nodejs16.x]": 8.715589448999708, + "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_echo_invoke[nodejs18.x]": 2.539816198999233, + "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_echo_invoke[nodejs20.x]": 2.499069388999942, + "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_echo_invoke[nodejs22.x]": 6.613958327000091, + "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_echo_invoke[provided.al2023]": 3.3057297870000184, + "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_echo_invoke[provided.al2]": 4.16912358799982, + "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_echo_invoke[python3.10]": 6.785254965999684, + "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_echo_invoke[python3.11]": 2.5656174240007203, + "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_echo_invoke[python3.12]": 2.611587856999904, + "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_echo_invoke[python3.13]": 2.6600024239996856, + "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_echo_invoke[python3.8]": 2.8263475529997777, + "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_echo_invoke[python3.9]": 6.695624887000122, + "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_echo_invoke[ruby3.2]": 8.738416017999498, + "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_echo_invoke[ruby3.3]": 8.783033908999641, + "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_echo_invoke[ruby3.4]": 8.723920859999907, + "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_introspection_invoke[dotnet6]": 3.3738126379998903, + "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_introspection_invoke[dotnet8]": 3.4016650269995807, + "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_introspection_invoke[java11]": 3.5209068770009253, + "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_introspection_invoke[java17]": 3.4014341950005473, + "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_introspection_invoke[java21]": 3.437620197999422, + "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_introspection_invoke[java8.al2]": 3.6149094119996334, + "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_introspection_invoke[nodejs16.x]": 3.2864813969999886, + "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_introspection_invoke[nodejs18.x]": 3.284145179999996, + "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_introspection_invoke[nodejs20.x]": 3.2495486610005173, + "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_introspection_invoke[nodejs22.x]": 3.269801438000286, + "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_introspection_invoke[provided.al2023]": 3.314472888999717, + "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_introspection_invoke[provided.al2]": 3.2970753810000133, + "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_introspection_invoke[python3.10]": 3.243772856000305, + "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_introspection_invoke[python3.11]": 3.294916967000063, + "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_introspection_invoke[python3.12]": 4.340521111000271, + "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_introspection_invoke[python3.13]": 3.2525403920003555, + "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_introspection_invoke[python3.8]": 3.3282651060003445, + "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_introspection_invoke[python3.9]": 3.2451308449999487, + "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_introspection_invoke[ruby3.2]": 3.341104921999431, + "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_introspection_invoke[ruby3.3]": 3.3973708669996086, + "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_introspection_invoke[ruby3.4]": 3.3296546729998227, + "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_runtime_wrapper_invoke[dotnet6]": 1.8247581950004133, + "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_runtime_wrapper_invoke[dotnet8]": 1.8318357429998287, + "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_runtime_wrapper_invoke[java11]": 1.9657814089996464, + "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_runtime_wrapper_invoke[java17]": 1.8785884119997718, + "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_runtime_wrapper_invoke[java21]": 1.884928518000379, + "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_runtime_wrapper_invoke[java8.al2]": 2.119865010000467, + "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_runtime_wrapper_invoke[nodejs16.x]": 1.7884648880003624, + "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_runtime_wrapper_invoke[nodejs18.x]": 1.7396612669995193, + "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_runtime_wrapper_invoke[nodejs20.x]": 1.7238376770005743, + "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_runtime_wrapper_invoke[nodejs22.x]": 1.7107113060001211, + "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_runtime_wrapper_invoke[python3.10]": 1.7134672399997726, + "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_runtime_wrapper_invoke[python3.11]": 1.6952845929999967, + "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_runtime_wrapper_invoke[python3.12]": 1.7223263370001405, + "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_runtime_wrapper_invoke[python3.13]": 1.72885013000041, + "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_runtime_wrapper_invoke[python3.8]": 1.7236099300002934, + "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_runtime_wrapper_invoke[python3.9]": 2.8661994249996496, + "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_runtime_wrapper_invoke[ruby3.2]": 1.805479725999703, + "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_runtime_wrapper_invoke[ruby3.3]": 1.7763632480000524, + "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_runtime_wrapper_invoke[ruby3.4]": 1.7880888169997888, + "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_uncaught_exception_invoke[dotnet6]": 1.8496824189996914, + "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_uncaught_exception_invoke[dotnet8]": 1.8573296900003697, + "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_uncaught_exception_invoke[java11]": 2.0042793269994945, + "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_uncaught_exception_invoke[java17]": 1.8745346849996167, + "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_uncaught_exception_invoke[java21]": 1.8958454540002094, + "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_uncaught_exception_invoke[java8.al2]": 2.203468948999671, + "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_uncaught_exception_invoke[nodejs16.x]": 1.7734768069999518, + "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_uncaught_exception_invoke[nodejs18.x]": 1.792258034999577, + "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_uncaught_exception_invoke[nodejs20.x]": 1.7324157070002002, + "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_uncaught_exception_invoke[nodejs22.x]": 1.7448200240000915, + "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_uncaught_exception_invoke[provided.al2023]": 1.7763813739993566, + "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_uncaught_exception_invoke[provided.al2]": 1.7560374780005077, + "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_uncaught_exception_invoke[python3.10]": 1.7168397719997301, + "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_uncaught_exception_invoke[python3.11]": 1.6843507220000902, + "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_uncaught_exception_invoke[python3.12]": 1.6998135549997642, + "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_uncaught_exception_invoke[python3.13]": 1.737045353000667, + "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_uncaught_exception_invoke[python3.8]": 1.75836364099996, + "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_uncaught_exception_invoke[python3.9]": 1.698833084999933, + "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_uncaught_exception_invoke[ruby3.2]": 1.8076482559995384, + "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_uncaught_exception_invoke[ruby3.3]": 1.8046597690004091, + "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_uncaught_exception_invoke[ruby3.4]": 1.8075289510002222, + "tests/aws/services/lambda_/test_lambda_destinations.py::TestLambdaDLQ::test_dead_letter_queue": 21.237125565000497, + "tests/aws/services/lambda_/test_lambda_destinations.py::TestLambdaDestinationEventbridge::test_invoke_lambda_eventbridge": 15.81599990299992, + "tests/aws/services/lambda_/test_lambda_destinations.py::TestLambdaDestinationSqs::test_assess_lambda_destination_invocation[payload0]": 1.9076070959999925, + "tests/aws/services/lambda_/test_lambda_destinations.py::TestLambdaDestinationSqs::test_assess_lambda_destination_invocation[payload1]": 1.9321258869999838, + "tests/aws/services/lambda_/test_lambda_destinations.py::TestLambdaDestinationSqs::test_lambda_destination_default_retries": 21.43546591700033, + "tests/aws/services/lambda_/test_lambda_destinations.py::TestLambdaDestinationSqs::test_maxeventage": 63.099447291999695, + "tests/aws/services/lambda_/test_lambda_destinations.py::TestLambdaDestinationSqs::test_retries": 22.56642078599998, + "tests/aws/services/lambda_/test_lambda_developer_tools.py::TestDockerFlags::test_additional_docker_flags": 1.6250885770000423, + "tests/aws/services/lambda_/test_lambda_developer_tools.py::TestDockerFlags::test_lambda_docker_networks": 6.6112471249998634, + "tests/aws/services/lambda_/test_lambda_developer_tools.py::TestHotReloading::test_hot_reloading[nodejs20.x]": 3.4466891220004072, + "tests/aws/services/lambda_/test_lambda_developer_tools.py::TestHotReloading::test_hot_reloading[python3.12]": 3.388316873999429, + "tests/aws/services/lambda_/test_lambda_developer_tools.py::TestHotReloading::test_hot_reloading_environment_placeholder": 0.4880693270001757, + "tests/aws/services/lambda_/test_lambda_developer_tools.py::TestHotReloading::test_hot_reloading_error_path_not_absolute": 0.026937281000300572, + "tests/aws/services/lambda_/test_lambda_developer_tools.py::TestHotReloading::test_hot_reloading_publish_version": 0.1270180349997645, + "tests/aws/services/lambda_/test_lambda_developer_tools.py::TestLambdaDNS::test_lambda_localhost_localstack_cloud_connectivity": 1.6061296089997086, + "tests/aws/services/lambda_/test_lambda_integration_xray.py::test_traceid_outside_handler[Active]": 2.6318831680000585, + "tests/aws/services/lambda_/test_lambda_integration_xray.py::test_traceid_outside_handler[PassThrough]": 2.600750307999533, + "tests/aws/services/lambda_/test_lambda_integration_xray.py::test_xray_trace_propagation": 1.581187645999762, + "tests/aws/services/lambda_/test_lambda_runtimes.py::TestCloudwatchLogs::test_multi_line_prints": 3.632768229999783, + "tests/aws/services/lambda_/test_lambda_runtimes.py::TestGoProvidedRuntimes::test_manual_endpoint_injection[provided.al2023]": 1.92320860899963, + "tests/aws/services/lambda_/test_lambda_runtimes.py::TestGoProvidedRuntimes::test_manual_endpoint_injection[provided.al2]": 1.9065978130001895, + "tests/aws/services/lambda_/test_lambda_runtimes.py::TestGoProvidedRuntimes::test_uncaught_exception_invoke[provided.al2023]": 1.9773371139995106, + "tests/aws/services/lambda_/test_lambda_runtimes.py::TestGoProvidedRuntimes::test_uncaught_exception_invoke[provided.al2]": 1.9826536389996363, + "tests/aws/services/lambda_/test_lambda_runtimes.py::TestJavaRuntimes::test_java_custom_handler_method_specification[cloud.localstack.sample.LambdaHandlerWithInterfaceAndCustom-INTERFACE]": 3.0452167139997073, + "tests/aws/services/lambda_/test_lambda_runtimes.py::TestJavaRuntimes::test_java_custom_handler_method_specification[cloud.localstack.sample.LambdaHandlerWithInterfaceAndCustom::handleRequest-INTERFACE]": 3.046131130000049, + "tests/aws/services/lambda_/test_lambda_runtimes.py::TestJavaRuntimes::test_java_custom_handler_method_specification[cloud.localstack.sample.LambdaHandlerWithInterfaceAndCustom::handleRequestCustom-CUSTOM]": 3.0344581899998957, + "tests/aws/services/lambda_/test_lambda_runtimes.py::TestJavaRuntimes::test_java_lambda_subscribe_sns_topic": 9.902181085000848, + "tests/aws/services/lambda_/test_lambda_runtimes.py::TestJavaRuntimes::test_java_runtime_with_lib": 5.730901092999375, + "tests/aws/services/lambda_/test_lambda_runtimes.py::TestJavaRuntimes::test_serializable_input_object[java11]": 2.6918155740004295, + "tests/aws/services/lambda_/test_lambda_runtimes.py::TestJavaRuntimes::test_serializable_input_object[java17]": 2.5855882360001488, + "tests/aws/services/lambda_/test_lambda_runtimes.py::TestJavaRuntimes::test_serializable_input_object[java21]": 2.879764664999584, + "tests/aws/services/lambda_/test_lambda_runtimes.py::TestJavaRuntimes::test_serializable_input_object[java8.al2]": 2.815680366000379, + "tests/aws/services/lambda_/test_lambda_runtimes.py::TestJavaRuntimes::test_stream_handler[java11]": 1.7586527359999309, + "tests/aws/services/lambda_/test_lambda_runtimes.py::TestJavaRuntimes::test_stream_handler[java17]": 1.7304077270000562, + "tests/aws/services/lambda_/test_lambda_runtimes.py::TestJavaRuntimes::test_stream_handler[java21]": 1.854050210999958, + "tests/aws/services/lambda_/test_lambda_runtimes.py::TestJavaRuntimes::test_stream_handler[java8.al2]": 1.7436802410002201, + "tests/aws/services/lambda_/test_lambda_runtimes.py::TestNodeJSRuntimes::test_invoke_nodejs_es6_lambda[nodejs16.x]": 4.704460786000254, + "tests/aws/services/lambda_/test_lambda_runtimes.py::TestNodeJSRuntimes::test_invoke_nodejs_es6_lambda[nodejs18.x]": 4.735790853000253, + "tests/aws/services/lambda_/test_lambda_runtimes.py::TestNodeJSRuntimes::test_invoke_nodejs_es6_lambda[nodejs20.x]": 4.706063764000191, + "tests/aws/services/lambda_/test_lambda_runtimes.py::TestNodeJSRuntimes::test_invoke_nodejs_es6_lambda[nodejs22.x]": 4.679959966000297, + "tests/aws/services/lambda_/test_lambda_runtimes.py::TestPythonRuntimes::test_handler_in_submodule[python3.10]": 1.7396797089995744, + "tests/aws/services/lambda_/test_lambda_runtimes.py::TestPythonRuntimes::test_handler_in_submodule[python3.11]": 1.717828296999869, + "tests/aws/services/lambda_/test_lambda_runtimes.py::TestPythonRuntimes::test_handler_in_submodule[python3.12]": 1.712753490999603, + "tests/aws/services/lambda_/test_lambda_runtimes.py::TestPythonRuntimes::test_handler_in_submodule[python3.13]": 1.7002941840005406, + "tests/aws/services/lambda_/test_lambda_runtimes.py::TestPythonRuntimes::test_handler_in_submodule[python3.8]": 1.700418451000587, + "tests/aws/services/lambda_/test_lambda_runtimes.py::TestPythonRuntimes::test_handler_in_submodule[python3.9]": 1.7140749159993902, + "tests/aws/services/lambda_/test_lambda_runtimes.py::TestPythonRuntimes::test_python_runtime_correct_versions[python3.10]": 1.5784838829999899, + "tests/aws/services/lambda_/test_lambda_runtimes.py::TestPythonRuntimes::test_python_runtime_correct_versions[python3.11]": 1.5743654830002924, + "tests/aws/services/lambda_/test_lambda_runtimes.py::TestPythonRuntimes::test_python_runtime_correct_versions[python3.12]": 1.5789184179998301, + "tests/aws/services/lambda_/test_lambda_runtimes.py::TestPythonRuntimes::test_python_runtime_correct_versions[python3.13]": 1.5784883580004134, + "tests/aws/services/lambda_/test_lambda_runtimes.py::TestPythonRuntimes::test_python_runtime_correct_versions[python3.8]": 1.6151738119992842, + "tests/aws/services/lambda_/test_lambda_runtimes.py::TestPythonRuntimes::test_python_runtime_correct_versions[python3.9]": 1.613309997000215, + "tests/aws/services/logs/test_logs.py::TestCloudWatchLogs::test_create_and_delete_log_group": 0.22247289300003104, + "tests/aws/services/logs/test_logs.py::TestCloudWatchLogs::test_create_and_delete_log_stream": 0.4734315399996376, + "tests/aws/services/logs/test_logs.py::TestCloudWatchLogs::test_delivery_logs_for_sns": 1.094350631999987, + "tests/aws/services/logs/test_logs.py::TestCloudWatchLogs::test_filter_log_events_response_header": 0.058520929999758664, + "tests/aws/services/logs/test_logs.py::TestCloudWatchLogs::test_list_tags_log_group": 0.2528336170003058, + "tests/aws/services/logs/test_logs.py::TestCloudWatchLogs::test_metric_filters": 0.0014058539995858155, + "tests/aws/services/logs/test_logs.py::TestCloudWatchLogs::test_put_events_multi_bytes_msg": 0.06018758099980914, + "tests/aws/services/logs/test_logs.py::TestCloudWatchLogs::test_put_subscription_filter_firehose": 0.5290895489997638, + "tests/aws/services/logs/test_logs.py::TestCloudWatchLogs::test_put_subscription_filter_kinesis": 2.3642309579995526, + "tests/aws/services/logs/test_logs.py::TestCloudWatchLogs::test_put_subscription_filter_lambda": 1.9569745380003951, + "tests/aws/services/logs/test_logs.py::TestCloudWatchLogs::test_resource_does_not_exist": 0.042624362000879046, + "tests/aws/services/opensearch/test_opensearch.py::TestCustomBackendManager::test_custom_backend": 0.176206445999469, + "tests/aws/services/opensearch/test_opensearch.py::TestCustomBackendManager::test_custom_backend_with_custom_endpoint": 0.20220733599990126, + "tests/aws/services/opensearch/test_opensearch.py::TestEdgeProxiedOpensearchCluster::test_custom_endpoint": 16.69602467200002, + "tests/aws/services/opensearch/test_opensearch.py::TestEdgeProxiedOpensearchCluster::test_custom_endpoint_disabled": 17.15874823899958, + "tests/aws/services/opensearch/test_opensearch.py::TestEdgeProxiedOpensearchCluster::test_route_through_edge": 16.00811466399955, + "tests/aws/services/opensearch/test_opensearch.py::TestMultiClusterManager::test_multi_cluster": 28.98962941199943, + "tests/aws/services/opensearch/test_opensearch.py::TestMultiplexingClusterManager::test_multiplexing_cluster": 16.83103826000024, + "tests/aws/services/opensearch/test_opensearch.py::TestOpensearchProvider::test_cloudformation_deployment": 22.34181647100013, + "tests/aws/services/opensearch/test_opensearch.py::TestOpensearchProvider::test_create_domain_with_invalid_custom_endpoint": 0.025610988999687834, + "tests/aws/services/opensearch/test_opensearch.py::TestOpensearchProvider::test_create_domain_with_invalid_name": 0.02675696699998298, + "tests/aws/services/opensearch/test_opensearch.py::TestOpensearchProvider::test_create_existing_domain_causes_exception": 16.634077459999844, + "tests/aws/services/opensearch/test_opensearch.py::TestOpensearchProvider::test_create_indices": 18.10921287600013, + "tests/aws/services/opensearch/test_opensearch.py::TestOpensearchProvider::test_describe_domains": 16.676775760000055, + "tests/aws/services/opensearch/test_opensearch.py::TestOpensearchProvider::test_domain_lifecycle": 12.621857965000345, + "tests/aws/services/opensearch/test_opensearch.py::TestOpensearchProvider::test_domain_version": 16.654584985000383, + "tests/aws/services/opensearch/test_opensearch.py::TestOpensearchProvider::test_endpoint_strategy_path": 17.151445567000337, + "tests/aws/services/opensearch/test_opensearch.py::TestOpensearchProvider::test_endpoint_strategy_port": 16.599927720000323, + "tests/aws/services/opensearch/test_opensearch.py::TestOpensearchProvider::test_exception_header_field": 0.012853248999363132, + "tests/aws/services/opensearch/test_opensearch.py::TestOpensearchProvider::test_get_compatible_version_for_domain": 10.529920713000138, + "tests/aws/services/opensearch/test_opensearch.py::TestOpensearchProvider::test_get_compatible_versions": 0.023109229000056075, + "tests/aws/services/opensearch/test_opensearch.py::TestOpensearchProvider::test_get_document": 17.97161406899977, + "tests/aws/services/opensearch/test_opensearch.py::TestOpensearchProvider::test_gzip_responses": 16.75748987099996, + "tests/aws/services/opensearch/test_opensearch.py::TestOpensearchProvider::test_list_versions": 0.11356572900012907, + "tests/aws/services/opensearch/test_opensearch.py::TestOpensearchProvider::test_search": 17.485556370999802, + "tests/aws/services/opensearch/test_opensearch.py::TestOpensearchProvider::test_security_plugin": 24.56527201299923, + "tests/aws/services/opensearch/test_opensearch.py::TestOpensearchProvider::test_sql_plugin": 22.83707307600025, + "tests/aws/services/opensearch/test_opensearch.py::TestOpensearchProvider::test_update_domain_config": 16.724387572999603, + "tests/aws/services/opensearch/test_opensearch.py::TestSingletonClusterManager::test_endpoint_strategy_port_singleton_cluster": 16.398998222000046, + "tests/aws/services/redshift/test_redshift.py::TestRedshift::test_cluster_security_groups": 0.041280231000655476, + "tests/aws/services/redshift/test_redshift.py::TestRedshift::test_create_clusters": 0.23284682599978623, + "tests/aws/services/resource_groups/test_resource_groups.py::TestResourceGroups::test_cloudformation_query": 0.0013502040001185378, + "tests/aws/services/resource_groups/test_resource_groups.py::TestResourceGroups::test_create_group": 0.3328535460000239, + "tests/aws/services/resource_groups/test_resource_groups.py::TestResourceGroups::test_resource_groups_different_region": 0.0013102979996801878, + "tests/aws/services/resource_groups/test_resource_groups.py::TestResourceGroups::test_resource_groups_tag_query": 0.001366244000109873, + "tests/aws/services/resource_groups/test_resource_groups.py::TestResourceGroups::test_resource_type_filters": 0.0013516260000869806, + "tests/aws/services/resource_groups/test_resource_groups.py::TestResourceGroups::test_search_resources": 0.0012218939996273548, + "tests/aws/services/resourcegroupstaggingapi/test_rgsa.py::TestRGSAIntegrations::test_get_resources": 0.6554781960003311, + "tests/aws/services/route53/test_route53.py::TestRoute53::test_associate_vpc_with_hosted_zone": 0.5800650900000619, + "tests/aws/services/route53/test_route53.py::TestRoute53::test_create_hosted_zone": 0.6148777179996614, + "tests/aws/services/route53/test_route53.py::TestRoute53::test_create_hosted_zone_in_non_existent_vpc": 0.1649388499995439, + "tests/aws/services/route53/test_route53.py::TestRoute53::test_create_private_hosted_zone": 0.676643452999997, + "tests/aws/services/route53/test_route53.py::TestRoute53::test_crud_health_check": 0.21010402100000647, + "tests/aws/services/route53/test_route53.py::TestRoute53::test_reusable_delegation_sets": 0.16522129100030725, + "tests/aws/services/route53resolver/test_route53resolver.py::TestRoute53Resolver::test_associate_and_disassociate_resolver_rule": 0.5263741439998739, + "tests/aws/services/route53resolver/test_route53resolver.py::TestRoute53Resolver::test_create_resolver_endpoint[INBOUND-5]": 0.34117876099981004, + "tests/aws/services/route53resolver/test_route53resolver.py::TestRoute53Resolver::test_create_resolver_endpoint[OUTBOUND-10]": 0.2815388409994739, + "tests/aws/services/route53resolver/test_route53resolver.py::TestRoute53Resolver::test_create_resolver_query_log_config": 0.31460391900054674, + "tests/aws/services/route53resolver/test_route53resolver.py::TestRoute53Resolver::test_create_resolver_rule": 0.3680470630001764, + "tests/aws/services/route53resolver/test_route53resolver.py::TestRoute53Resolver::test_create_resolver_rule_with_invalid_direction": 0.30752149100044335, + "tests/aws/services/route53resolver/test_route53resolver.py::TestRoute53Resolver::test_delete_non_existent_resolver_endpoint": 0.0763859780004168, + "tests/aws/services/route53resolver/test_route53resolver.py::TestRoute53Resolver::test_delete_non_existent_resolver_query_log_config": 0.1337224500002776, + "tests/aws/services/route53resolver/test_route53resolver.py::TestRoute53Resolver::test_delete_non_existent_resolver_rule": 0.0802166789999319, + "tests/aws/services/route53resolver/test_route53resolver.py::TestRoute53Resolver::test_delete_resolver_endpoint": 0.29052185199952874, + "tests/aws/services/route53resolver/test_route53resolver.py::TestRoute53Resolver::test_disassociate_non_existent_association": 0.07675981900001716, + "tests/aws/services/route53resolver/test_route53resolver.py::TestRoute53Resolver::test_list_firewall_domain_lists": 0.1740745740003149, + "tests/aws/services/route53resolver/test_route53resolver.py::TestRoute53Resolver::test_list_firewall_rules": 0.3205631890004952, + "tests/aws/services/route53resolver/test_route53resolver.py::TestRoute53Resolver::test_list_firewall_rules_for_empty_rule_group": 0.09645334700053354, + "tests/aws/services/route53resolver/test_route53resolver.py::TestRoute53Resolver::test_list_firewall_rules_for_missing_rule_group": 0.1370423249995838, + "tests/aws/services/route53resolver/test_route53resolver.py::TestRoute53Resolver::test_multipe_create_resolver_rule": 0.41771281499904944, + "tests/aws/services/route53resolver/test_route53resolver.py::TestRoute53Resolver::test_multiple_create_resolver_endpoint_with_same_req_id": 0.2937225370001215, + "tests/aws/services/route53resolver/test_route53resolver.py::TestRoute53Resolver::test_route53resolver_bad_create_endpoint_security_groups": 0.1944827450001867, + "tests/aws/services/route53resolver/test_route53resolver.py::TestRoute53Resolver::test_update_resolver_endpoint": 0.3037835440004528, + "tests/aws/services/s3/test_s3.py::TestS3::test_access_bucket_different_region": 0.0014311149998320616, + "tests/aws/services/s3/test_s3.py::TestS3::test_bucket_availability": 0.03563191500006724, + "tests/aws/services/s3/test_s3.py::TestS3::test_bucket_does_not_exist": 0.39390743900003145, + "tests/aws/services/s3/test_s3.py::TestS3::test_bucket_exists": 0.22664170400048533, + "tests/aws/services/s3/test_s3.py::TestS3::test_bucket_name_with_dots": 0.49739670999997543, + "tests/aws/services/s3/test_s3.py::TestS3::test_bucket_operation_between_regions": 0.42815036800038797, + "tests/aws/services/s3/test_s3.py::TestS3::test_complete_multipart_parts_order": 0.5212038730001041, + "tests/aws/services/s3/test_s3.py::TestS3::test_copy_in_place_with_bucket_encryption": 0.15288744600002246, + "tests/aws/services/s3/test_s3.py::TestS3::test_copy_object_kms": 1.847800226000345, + "tests/aws/services/s3/test_s3.py::TestS3::test_copy_object_special_character": 0.6463883850001366, + "tests/aws/services/s3/test_s3.py::TestS3::test_copy_object_special_character_plus_for_space": 0.13492454400056886, + "tests/aws/services/s3/test_s3.py::TestS3::test_create_bucket_head_bucket": 0.556593446000079, + "tests/aws/services/s3/test_s3.py::TestS3::test_create_bucket_via_host_name": 0.04272206100040421, + "tests/aws/services/s3/test_s3.py::TestS3::test_create_bucket_with_existing_name": 0.3824714100001074, + "tests/aws/services/s3/test_s3.py::TestS3::test_delete_bucket_no_such_bucket": 0.020142577999649802, + "tests/aws/services/s3/test_s3.py::TestS3::test_delete_bucket_policy": 0.11007689100006246, + "tests/aws/services/s3/test_s3.py::TestS3::test_delete_bucket_policy_expected_bucket_owner": 0.12606886899993697, + "tests/aws/services/s3/test_s3.py::TestS3::test_delete_bucket_with_content": 0.6849047020000398, + "tests/aws/services/s3/test_s3.py::TestS3::test_delete_keys_in_versioned_bucket": 0.49424523799962117, + "tests/aws/services/s3/test_s3.py::TestS3::test_delete_non_existing_keys": 0.0922543770006996, + "tests/aws/services/s3/test_s3.py::TestS3::test_delete_non_existing_keys_in_non_existing_bucket": 0.024732660000154283, + "tests/aws/services/s3/test_s3.py::TestS3::test_delete_non_existing_keys_quiet": 0.0876091459995223, + "tests/aws/services/s3/test_s3.py::TestS3::test_delete_object_tagging": 0.12487830500003838, + "tests/aws/services/s3/test_s3.py::TestS3::test_delete_objects_encoding": 0.12122958699956143, + "tests/aws/services/s3/test_s3.py::TestS3::test_different_location_constraint": 0.5835461719993873, + "tests/aws/services/s3/test_s3.py::TestS3::test_download_fileobj_multiple_range_requests": 1.1113223829997878, + "tests/aws/services/s3/test_s3.py::TestS3::test_empty_bucket_fixture": 0.15848056699951485, + "tests/aws/services/s3/test_s3.py::TestS3::test_etag_on_get_object_call": 0.40174113200055217, + "tests/aws/services/s3/test_s3.py::TestS3::test_get_bucket_notification_configuration_no_such_bucket": 0.022182074999818724, + "tests/aws/services/s3/test_s3.py::TestS3::test_get_bucket_policy": 0.13108733300032327, + "tests/aws/services/s3/test_s3.py::TestS3::test_get_bucket_policy_invalid_account_id[0000000000020]": 0.07182867100027579, + "tests/aws/services/s3/test_s3.py::TestS3::test_get_bucket_policy_invalid_account_id[0000]": 0.07679088400027467, + "tests/aws/services/s3/test_s3.py::TestS3::test_get_bucket_policy_invalid_account_id[aa000000000$]": 0.07793785800049591, + "tests/aws/services/s3/test_s3.py::TestS3::test_get_bucket_policy_invalid_account_id[abcd]": 0.07478520699987712, + "tests/aws/services/s3/test_s3.py::TestS3::test_get_bucket_versioning_order": 0.4686067819998243, + "tests/aws/services/s3/test_s3.py::TestS3::test_get_obj_attrs_multi_headers_behavior": 0.0925742760000503, + "tests/aws/services/s3/test_s3.py::TestS3::test_get_object_after_deleted_in_versioned_bucket": 0.12754891599934126, + "tests/aws/services/s3/test_s3.py::TestS3::test_get_object_attributes": 0.3282333430001927, + "tests/aws/services/s3/test_s3.py::TestS3::test_get_object_attributes_versioned": 0.45207105499957834, + "tests/aws/services/s3/test_s3.py::TestS3::test_get_object_attributes_with_space": 0.10515536399998382, + "tests/aws/services/s3/test_s3.py::TestS3::test_get_object_content_length_with_virtual_host[False]": 0.09941725499948006, + "tests/aws/services/s3/test_s3.py::TestS3::test_get_object_content_length_with_virtual_host[True]": 0.10067110799991497, + "tests/aws/services/s3/test_s3.py::TestS3::test_get_object_no_such_bucket": 0.023855784999796015, + "tests/aws/services/s3/test_s3.py::TestS3::test_get_object_part": 0.26016301700065014, + "tests/aws/services/s3/test_s3.py::TestS3::test_get_object_part_checksum[COMPOSITE]": 0.138903663000292, + "tests/aws/services/s3/test_s3.py::TestS3::test_get_object_part_checksum[FULL_OBJECT]": 0.1394303349998154, + "tests/aws/services/s3/test_s3.py::TestS3::test_get_object_with_anon_credentials": 0.4789050100002896, + "tests/aws/services/s3/test_s3.py::TestS3::test_get_range_object_headers": 0.09739372199965146, + "tests/aws/services/s3/test_s3.py::TestS3::test_head_object_fields": 0.11071024700004273, + "tests/aws/services/s3/test_s3.py::TestS3::test_invalid_range_error": 0.09452628500002902, + "tests/aws/services/s3/test_s3.py::TestS3::test_metadata_header_character_decoding": 0.39177849699990475, + "tests/aws/services/s3/test_s3.py::TestS3::test_multipart_and_list_parts": 0.20196719600062352, + "tests/aws/services/s3/test_s3.py::TestS3::test_multipart_complete_multipart_too_small": 0.12305001000004268, + "tests/aws/services/s3/test_s3.py::TestS3::test_multipart_complete_multipart_wrong_part": 0.1110787149996213, + "tests/aws/services/s3/test_s3.py::TestS3::test_multipart_copy_object_etag": 0.14799262399992585, + "tests/aws/services/s3/test_s3.py::TestS3::test_multipart_no_such_upload": 0.10011023600009139, + "tests/aws/services/s3/test_s3.py::TestS3::test_multipart_overwrite_key": 0.13523088099964298, + "tests/aws/services/s3/test_s3.py::TestS3::test_object_with_slashes_in_key[False]": 0.19929717800005164, + "tests/aws/services/s3/test_s3.py::TestS3::test_object_with_slashes_in_key[True]": 0.20554226100011874, + "tests/aws/services/s3/test_s3.py::TestS3::test_precondition_failed_error": 0.1040177679997214, + "tests/aws/services/s3/test_s3.py::TestS3::test_put_and_get_object_with_content_language_disposition": 0.7872401259996877, + "tests/aws/services/s3/test_s3.py::TestS3::test_put_and_get_object_with_hash_prefix": 0.39535114900036206, + "tests/aws/services/s3/test_s3.py::TestS3::test_put_and_get_object_with_utf8_key": 0.39381614299963985, + "tests/aws/services/s3/test_s3.py::TestS3::test_put_bucket_inventory_config_order": 0.16949424399990676, + "tests/aws/services/s3/test_s3.py::TestS3::test_put_bucket_policy": 0.10412678300008338, + "tests/aws/services/s3/test_s3.py::TestS3::test_put_bucket_policy_expected_bucket_owner": 0.20948596700009148, + "tests/aws/services/s3/test_s3.py::TestS3::test_put_bucket_policy_invalid_account_id[0000000000020]": 0.07331882600010431, + "tests/aws/services/s3/test_s3.py::TestS3::test_put_bucket_policy_invalid_account_id[0000]": 0.07545868500028519, + "tests/aws/services/s3/test_s3.py::TestS3::test_put_bucket_policy_invalid_account_id[aa000000000$]": 0.07478237999976045, + "tests/aws/services/s3/test_s3.py::TestS3::test_put_bucket_policy_invalid_account_id[abcd]": 0.07716094500028703, + "tests/aws/services/s3/test_s3.py::TestS3::test_put_get_object_single_character_trailing_slash": 0.1645546140002807, + "tests/aws/services/s3/test_s3.py::TestS3::test_put_get_object_special_character[a/%F0%9F%98%80/]": 0.41125686199984557, + "tests/aws/services/s3/test_s3.py::TestS3::test_put_get_object_special_character[file%2Fname]": 0.4153871150001578, + "tests/aws/services/s3/test_s3.py::TestS3::test_put_get_object_special_character[test key//]": 0.4130967710002551, + "tests/aws/services/s3/test_s3.py::TestS3::test_put_get_object_special_character[test key/]": 0.41436055300027874, + "tests/aws/services/s3/test_s3.py::TestS3::test_put_get_object_special_character[test%123/]": 0.4141466330002004, + "tests/aws/services/s3/test_s3.py::TestS3::test_put_get_object_special_character[test%123]": 0.4131032929999492, + "tests/aws/services/s3/test_s3.py::TestS3::test_put_get_object_special_character[test%percent]": 0.4120161500004542, + "tests/aws/services/s3/test_s3.py::TestS3::test_put_get_object_special_character[test@key/]": 0.41264673900013804, + "tests/aws/services/s3/test_s3.py::TestS3::test_put_object_acl_on_delete_marker": 0.4920932769996398, + "tests/aws/services/s3/test_s3.py::TestS3::test_put_object_chunked_checksum": 0.11112109700070505, + "tests/aws/services/s3/test_s3.py::TestS3::test_put_object_chunked_content_encoding": 0.10936002100015685, + "tests/aws/services/s3/test_s3.py::TestS3::test_put_object_chunked_newlines": 0.09143400599987217, + "tests/aws/services/s3/test_s3.py::TestS3::test_put_object_chunked_newlines_no_sig": 0.08981792399981714, + "tests/aws/services/s3/test_s3.py::TestS3::test_put_object_chunked_newlines_no_sig_empty_body": 0.08639272300024459, + "tests/aws/services/s3/test_s3.py::TestS3::test_put_object_chunked_newlines_with_trailing_checksum": 0.1118749850002132, + "tests/aws/services/s3/test_s3.py::TestS3::test_put_object_storage_class[DEEP_ARCHIVE-False]": 0.10715643100002126, + "tests/aws/services/s3/test_s3.py::TestS3::test_put_object_storage_class[GLACIER-False]": 0.10769446699987384, + "tests/aws/services/s3/test_s3.py::TestS3::test_put_object_storage_class[GLACIER_IR-True]": 0.10819315800063123, + "tests/aws/services/s3/test_s3.py::TestS3::test_put_object_storage_class[INTELLIGENT_TIERING-True]": 0.10795182799984104, + "tests/aws/services/s3/test_s3.py::TestS3::test_put_object_storage_class[ONEZONE_IA-True]": 0.10705553300022075, + "tests/aws/services/s3/test_s3.py::TestS3::test_put_object_storage_class[REDUCED_REDUNDANCY-True]": 0.10436111500030165, + "tests/aws/services/s3/test_s3.py::TestS3::test_put_object_storage_class[STANDARD-True]": 0.1084896959996513, + "tests/aws/services/s3/test_s3.py::TestS3::test_put_object_storage_class[STANDARD_IA-True]": 0.10717642900044666, + "tests/aws/services/s3/test_s3.py::TestS3::test_put_object_storage_class_outposts": 0.08939534099954471, + "tests/aws/services/s3/test_s3.py::TestS3::test_put_object_tagging_empty_list": 0.13706755500015788, + "tests/aws/services/s3/test_s3.py::TestS3::test_put_object_with_md5_and_chunk_signature": 0.09201318699933836, + "tests/aws/services/s3/test_s3.py::TestS3::test_putobject_with_multiple_keys": 0.40017656700047155, + "tests/aws/services/s3/test_s3.py::TestS3::test_range_header_body_length": 0.1139273119997597, + "tests/aws/services/s3/test_s3.py::TestS3::test_range_key_not_exists": 0.07326382299925172, + "tests/aws/services/s3/test_s3.py::TestS3::test_region_header_exists_outside_us_east_1": 0.5012690190005742, + "tests/aws/services/s3/test_s3.py::TestS3::test_response_structure": 0.17830833900006837, + "tests/aws/services/s3/test_s3.py::TestS3::test_response_structure_get_obj_attrs": 0.13193758099987463, + "tests/aws/services/s3/test_s3.py::TestS3::test_s3_analytics_configurations": 0.24352889399960986, + "tests/aws/services/s3/test_s3.py::TestS3::test_s3_batch_delete_objects": 0.4378169190003973, + "tests/aws/services/s3/test_s3.py::TestS3::test_s3_batch_delete_objects_using_requests_with_acl": 0.0015288770000552176, + "tests/aws/services/s3/test_s3.py::TestS3::test_s3_batch_delete_public_objects_using_requests": 0.42677172799949403, + "tests/aws/services/s3/test_s3.py::TestS3::test_s3_bucket_acl": 0.18284208299974125, + "tests/aws/services/s3/test_s3.py::TestS3::test_s3_bucket_acl_exceptions": 0.24021505099972273, + "tests/aws/services/s3/test_s3.py::TestS3::test_s3_copy_content_type_and_metadata": 0.46338415399986843, + "tests/aws/services/s3/test_s3.py::TestS3::test_s3_copy_metadata_directive_copy": 0.42849802399996406, + "tests/aws/services/s3/test_s3.py::TestS3::test_s3_copy_metadata_replace": 0.42308678600056737, + "tests/aws/services/s3/test_s3.py::TestS3::test_s3_copy_object_in_place": 0.4935041349999665, + "tests/aws/services/s3/test_s3.py::TestS3::test_s3_copy_object_in_place_metadata_directive": 0.5231125850000353, + "tests/aws/services/s3/test_s3.py::TestS3::test_s3_copy_object_in_place_storage_class": 0.4659259210006894, + "tests/aws/services/s3/test_s3.py::TestS3::test_s3_copy_object_in_place_suspended_only": 0.5315309959996739, + "tests/aws/services/s3/test_s3.py::TestS3::test_s3_copy_object_in_place_versioned": 0.5878815990004114, + "tests/aws/services/s3/test_s3.py::TestS3::test_s3_copy_object_in_place_website_redirect_location": 0.43244674700008545, + "tests/aws/services/s3/test_s3.py::TestS3::test_s3_copy_object_in_place_with_encryption": 0.7005700240001715, + "tests/aws/services/s3/test_s3.py::TestS3::test_s3_copy_object_preconditions": 3.5161163590000797, + "tests/aws/services/s3/test_s3.py::TestS3::test_s3_copy_object_storage_class": 0.44215684400023747, + "tests/aws/services/s3/test_s3.py::TestS3::test_s3_copy_object_with_checksum[CRC32C]": 0.46307258800015916, + "tests/aws/services/s3/test_s3.py::TestS3::test_s3_copy_object_with_checksum[CRC32]": 0.43670690599947193, + "tests/aws/services/s3/test_s3.py::TestS3::test_s3_copy_object_with_checksum[CRC64NVME]": 0.43522463499994046, + "tests/aws/services/s3/test_s3.py::TestS3::test_s3_copy_object_with_checksum[SHA1]": 0.4629811559998416, + "tests/aws/services/s3/test_s3.py::TestS3::test_s3_copy_object_with_checksum[SHA256]": 0.45361405800031207, + "tests/aws/services/s3/test_s3.py::TestS3::test_s3_copy_object_with_default_checksum[CRC32C]": 0.45782711100036977, + "tests/aws/services/s3/test_s3.py::TestS3::test_s3_copy_object_with_default_checksum[CRC32]": 0.4506696240000565, + "tests/aws/services/s3/test_s3.py::TestS3::test_s3_copy_object_with_default_checksum[CRC64NVME]": 0.4695559570000114, + "tests/aws/services/s3/test_s3.py::TestS3::test_s3_copy_object_with_default_checksum[SHA1]": 0.4632878860006713, + "tests/aws/services/s3/test_s3.py::TestS3::test_s3_copy_object_with_default_checksum[SHA256]": 0.47252701700017496, + "tests/aws/services/s3/test_s3.py::TestS3::test_s3_copy_object_wrong_format": 0.43046842700050547, + "tests/aws/services/s3/test_s3.py::TestS3::test_s3_copy_tagging_directive[COPY]": 0.4443623770002887, + "tests/aws/services/s3/test_s3.py::TestS3::test_s3_copy_tagging_directive[None]": 0.4483863850000489, + "tests/aws/services/s3/test_s3.py::TestS3::test_s3_copy_tagging_directive[REPLACE]": 0.4429512090005119, + "tests/aws/services/s3/test_s3.py::TestS3::test_s3_copy_tagging_directive_versioned[COPY]": 0.5478163820002919, + "tests/aws/services/s3/test_s3.py::TestS3::test_s3_copy_tagging_directive_versioned[None]": 0.5594213089998448, + "tests/aws/services/s3/test_s3.py::TestS3::test_s3_copy_tagging_directive_versioned[REPLACE]": 0.5556130529998882, + "tests/aws/services/s3/test_s3.py::TestS3::test_s3_delete_object_with_version_id": 0.4649089200001981, + "tests/aws/services/s3/test_s3.py::TestS3::test_s3_delete_objects_trailing_slash": 0.07796578500028772, + "tests/aws/services/s3/test_s3.py::TestS3::test_s3_download_object_with_lambda": 4.313591648000056, + "tests/aws/services/s3/test_s3.py::TestS3::test_s3_get_object_header_overrides": 0.09946182699968631, + "tests/aws/services/s3/test_s3.py::TestS3::test_s3_get_object_headers": 0.1693278219995591, + "tests/aws/services/s3/test_s3.py::TestS3::test_s3_get_object_preconditions[get_object]": 3.5033547059997545, + "tests/aws/services/s3/test_s3.py::TestS3::test_s3_get_object_preconditions[head_object]": 3.502851503999864, + "tests/aws/services/s3/test_s3.py::TestS3::test_s3_hostname_with_subdomain": 0.022511846000270452, + "tests/aws/services/s3/test_s3.py::TestS3::test_s3_intelligent_tier_config": 0.1846471199996813, + "tests/aws/services/s3/test_s3.py::TestS3::test_s3_invalid_content_md5": 15.296445336000488, + "tests/aws/services/s3/test_s3.py::TestS3::test_s3_inventory_report_crud": 0.19139644499955466, + "tests/aws/services/s3/test_s3.py::TestS3::test_s3_lambda_integration": 10.575362100000348, + "tests/aws/services/s3/test_s3.py::TestS3::test_s3_multipart_upload_acls": 0.23343668800043815, + "tests/aws/services/s3/test_s3.py::TestS3::test_s3_multipart_upload_sse": 0.19904124500044418, + "tests/aws/services/s3/test_s3.py::TestS3::test_s3_object_acl": 0.19159279100040294, + "tests/aws/services/s3/test_s3.py::TestS3::test_s3_object_acl_exceptions": 0.2463385770001878, + "tests/aws/services/s3/test_s3.py::TestS3::test_s3_object_expires": 0.4554310200001055, + "tests/aws/services/s3/test_s3.py::TestS3::test_s3_put_inventory_report_exceptions": 0.16925571799993122, + "tests/aws/services/s3/test_s3.py::TestS3::test_s3_put_more_than_1000_items": 15.606845604999762, + "tests/aws/services/s3/test_s3.py::TestS3::test_s3_put_object_versioned": 0.6212042409997593, + "tests/aws/services/s3/test_s3.py::TestS3::test_s3_raw_request_routing": 0.10796410200009632, + "tests/aws/services/s3/test_s3.py::TestS3::test_s3_request_payer": 0.08487042099977771, + "tests/aws/services/s3/test_s3.py::TestS3::test_s3_request_payer_exceptions": 0.09342851100018379, + "tests/aws/services/s3/test_s3.py::TestS3::test_s3_sse_bucket_key_default": 0.23223016500060112, + "tests/aws/services/s3/test_s3.py::TestS3::test_s3_sse_default_kms_key": 0.0014406229997803166, + "tests/aws/services/s3/test_s3.py::TestS3::test_s3_sse_validate_kms_key": 0.28746081199960827, + "tests/aws/services/s3/test_s3.py::TestS3::test_s3_sse_validate_kms_key_state": 0.3022960130001593, + "tests/aws/services/s3/test_s3.py::TestS3::test_s3_timestamp_precision": 0.11780194800030586, + "tests/aws/services/s3/test_s3.py::TestS3::test_s3_upload_download_gzip": 0.10007102800000212, + "tests/aws/services/s3/test_s3.py::TestS3::test_s3_uppercase_bucket_name": 0.32407048499953817, + "tests/aws/services/s3/test_s3.py::TestS3::test_s3_uppercase_key_names": 0.10683470099957049, + "tests/aws/services/s3/test_s3.py::TestS3::test_set_external_hostname": 0.15591663500072173, + "tests/aws/services/s3/test_s3.py::TestS3::test_upload_big_file": 0.565452266000193, + "tests/aws/services/s3/test_s3.py::TestS3::test_upload_file_multipart": 0.42814722700040875, + "tests/aws/services/s3/test_s3.py::TestS3::test_upload_file_with_xml_preamble": 0.39353056199934144, + "tests/aws/services/s3/test_s3.py::TestS3::test_upload_part_chunked_cancelled_valid_etag": 0.13196516800007885, + "tests/aws/services/s3/test_s3.py::TestS3::test_upload_part_chunked_newlines_valid_etag": 0.10851035699988643, + "tests/aws/services/s3/test_s3.py::TestS3::test_url_encoded_key[False]": 0.15478296399942337, + "tests/aws/services/s3/test_s3.py::TestS3::test_url_encoded_key[True]": 0.18092323799965015, + "tests/aws/services/s3/test_s3.py::TestS3::test_virtual_host_proxy_does_not_decode_gzip": 0.09315321799977028, + "tests/aws/services/s3/test_s3.py::TestS3::test_virtual_host_proxying_headers": 0.09632514500026446, + "tests/aws/services/s3/test_s3.py::TestS3BucketLifecycle::test_bucket_lifecycle_configuration_date": 0.09270792400002392, + "tests/aws/services/s3/test_s3.py::TestS3BucketLifecycle::test_bucket_lifecycle_configuration_object_expiry": 0.14600835599958373, + "tests/aws/services/s3/test_s3.py::TestS3BucketLifecycle::test_bucket_lifecycle_configuration_object_expiry_versioned": 0.21530533000031937, + "tests/aws/services/s3/test_s3.py::TestS3BucketLifecycle::test_bucket_lifecycle_multiple_rules": 0.13150569300023562, + "tests/aws/services/s3/test_s3.py::TestS3BucketLifecycle::test_bucket_lifecycle_object_size_rules": 0.1312440750002679, + "tests/aws/services/s3/test_s3.py::TestS3BucketLifecycle::test_bucket_lifecycle_tag_rules": 0.20801253400031783, + "tests/aws/services/s3/test_s3.py::TestS3BucketLifecycle::test_delete_bucket_lifecycle_configuration": 0.1395693030003713, + "tests/aws/services/s3/test_s3.py::TestS3BucketLifecycle::test_delete_lifecycle_configuration_on_bucket_deletion": 0.13658051899983548, + "tests/aws/services/s3/test_s3.py::TestS3BucketLifecycle::test_lifecycle_expired_object_delete_marker": 0.11941938100017069, + "tests/aws/services/s3/test_s3.py::TestS3BucketLifecycle::test_object_expiry_after_bucket_lifecycle_configuration": 0.13655838799968478, + "tests/aws/services/s3/test_s3.py::TestS3BucketLifecycle::test_put_bucket_lifecycle_conf_exc": 0.17131165799946757, + "tests/aws/services/s3/test_s3.py::TestS3BucketLifecycle::test_s3_transition_default_minimum_object_size": 0.13363396300064778, + "tests/aws/services/s3/test_s3.py::TestS3BucketLogging::test_put_bucket_logging": 0.16345619000048828, + "tests/aws/services/s3/test_s3.py::TestS3BucketLogging::test_put_bucket_logging_accept_wrong_grants": 0.14004781700032254, + "tests/aws/services/s3/test_s3.py::TestS3BucketLogging::test_put_bucket_logging_cross_locations": 0.1824445220004236, + "tests/aws/services/s3/test_s3.py::TestS3BucketLogging::test_put_bucket_logging_wrong_target": 0.13133645800007798, + "tests/aws/services/s3/test_s3.py::TestS3BucketReplication::test_replication_config": 0.6151046270001643, + "tests/aws/services/s3/test_s3.py::TestS3BucketReplication::test_replication_config_without_filter": 0.5819036749999213, + "tests/aws/services/s3/test_s3.py::TestS3DeepArchive::test_s3_get_deep_archive_object_restore": 0.5024507419998372, + "tests/aws/services/s3/test_s3.py::TestS3DeepArchive::test_storage_class_deep_archive": 0.1737055439998585, + "tests/aws/services/s3/test_s3.py::TestS3MultiAccounts::test_cross_account_access": 0.14070701399941754, + "tests/aws/services/s3/test_s3.py::TestS3MultiAccounts::test_cross_account_copy_object": 0.10865801700037991, + "tests/aws/services/s3/test_s3.py::TestS3MultiAccounts::test_shared_bucket_namespace": 0.07728725700053474, + "tests/aws/services/s3/test_s3.py::TestS3MultipartUploadChecksum::test_complete_multipart_parts_checksum_composite[CRC32C]": 0.49061367899957986, + "tests/aws/services/s3/test_s3.py::TestS3MultipartUploadChecksum::test_complete_multipart_parts_checksum_composite[CRC32]": 0.5183371690000058, + "tests/aws/services/s3/test_s3.py::TestS3MultipartUploadChecksum::test_complete_multipart_parts_checksum_composite[SHA1]": 0.5104261149999729, + "tests/aws/services/s3/test_s3.py::TestS3MultipartUploadChecksum::test_complete_multipart_parts_checksum_composite[SHA256]": 0.5142565410005773, + "tests/aws/services/s3/test_s3.py::TestS3MultipartUploadChecksum::test_complete_multipart_parts_checksum_default": 0.24138455299998895, + "tests/aws/services/s3/test_s3.py::TestS3MultipartUploadChecksum::test_complete_multipart_parts_checksum_full_object[CRC32C]": 0.5554792799998722, + "tests/aws/services/s3/test_s3.py::TestS3MultipartUploadChecksum::test_complete_multipart_parts_checksum_full_object[CRC32]": 0.5744382820003011, + "tests/aws/services/s3/test_s3.py::TestS3MultipartUploadChecksum::test_complete_multipart_parts_checksum_full_object[CRC64NVME]": 0.5868915289997858, + "tests/aws/services/s3/test_s3.py::TestS3MultipartUploadChecksum::test_complete_multipart_parts_checksum_full_object_default": 0.16691302900017035, + "tests/aws/services/s3/test_s3.py::TestS3MultipartUploadChecksum::test_multipart_checksum_type_compatibility[COMPOSITE-CRC32C]": 0.07721510400051557, + "tests/aws/services/s3/test_s3.py::TestS3MultipartUploadChecksum::test_multipart_checksum_type_compatibility[COMPOSITE-CRC32]": 0.07729239699983737, + "tests/aws/services/s3/test_s3.py::TestS3MultipartUploadChecksum::test_multipart_checksum_type_compatibility[COMPOSITE-CRC64NVME]": 0.0751163820000329, + "tests/aws/services/s3/test_s3.py::TestS3MultipartUploadChecksum::test_multipart_checksum_type_compatibility[COMPOSITE-SHA1]": 0.07848550199969395, + "tests/aws/services/s3/test_s3.py::TestS3MultipartUploadChecksum::test_multipart_checksum_type_compatibility[COMPOSITE-SHA256]": 0.07600848200036125, + "tests/aws/services/s3/test_s3.py::TestS3MultipartUploadChecksum::test_multipart_checksum_type_compatibility[FULL_OBJECT-CRC32C]": 0.08024931499994636, + "tests/aws/services/s3/test_s3.py::TestS3MultipartUploadChecksum::test_multipart_checksum_type_compatibility[FULL_OBJECT-CRC32]": 0.07655595000005633, + "tests/aws/services/s3/test_s3.py::TestS3MultipartUploadChecksum::test_multipart_checksum_type_compatibility[FULL_OBJECT-CRC64NVME]": 0.0836652539996976, + "tests/aws/services/s3/test_s3.py::TestS3MultipartUploadChecksum::test_multipart_checksum_type_compatibility[FULL_OBJECT-SHA1]": 0.07511683099983202, + "tests/aws/services/s3/test_s3.py::TestS3MultipartUploadChecksum::test_multipart_checksum_type_compatibility[FULL_OBJECT-SHA256]": 0.07824184099990816, + "tests/aws/services/s3/test_s3.py::TestS3MultipartUploadChecksum::test_multipart_checksum_type_default_for_checksum[CRC32C]": 0.08213921300011862, + "tests/aws/services/s3/test_s3.py::TestS3MultipartUploadChecksum::test_multipart_checksum_type_default_for_checksum[CRC32]": 0.07730753299983917, + "tests/aws/services/s3/test_s3.py::TestS3MultipartUploadChecksum::test_multipart_checksum_type_default_for_checksum[CRC64NVME]": 0.08022365499982698, + "tests/aws/services/s3/test_s3.py::TestS3MultipartUploadChecksum::test_multipart_checksum_type_default_for_checksum[SHA1]": 0.08233737599994129, + "tests/aws/services/s3/test_s3.py::TestS3MultipartUploadChecksum::test_multipart_checksum_type_default_for_checksum[SHA256]": 0.07609371800026565, + "tests/aws/services/s3/test_s3.py::TestS3MultipartUploadChecksum::test_multipart_parts_checksum_exceptions_composite": 6.286937272999694, + "tests/aws/services/s3/test_s3.py::TestS3MultipartUploadChecksum::test_multipart_parts_checksum_exceptions_full_object": 35.723331452999446, + "tests/aws/services/s3/test_s3.py::TestS3MultipartUploadChecksum::test_multipart_size_validation": 0.13453836600046998, + "tests/aws/services/s3/test_s3.py::TestS3MultipartUploadChecksum::test_multipart_upload_part_checksum_exception[CRC32C]": 5.584607071000391, + "tests/aws/services/s3/test_s3.py::TestS3MultipartUploadChecksum::test_multipart_upload_part_checksum_exception[CRC32]": 7.920285199000318, + "tests/aws/services/s3/test_s3.py::TestS3MultipartUploadChecksum::test_multipart_upload_part_checksum_exception[CRC64NVME]": 7.211505239999951, + "tests/aws/services/s3/test_s3.py::TestS3MultipartUploadChecksum::test_multipart_upload_part_checksum_exception[SHA1]": 8.737606642999708, + "tests/aws/services/s3/test_s3.py::TestS3MultipartUploadChecksum::test_multipart_upload_part_checksum_exception[SHA256]": 6.218879280999772, + "tests/aws/services/s3/test_s3.py::TestS3MultipartUploadChecksum::test_multipart_upload_part_copy_checksum[COMPOSITE]": 0.20519400500006668, + "tests/aws/services/s3/test_s3.py::TestS3MultipartUploadChecksum::test_multipart_upload_part_copy_checksum[FULL_OBJECT]": 0.18588291800006118, + "tests/aws/services/s3/test_s3.py::TestS3ObjectLockLegalHold::test_delete_locked_object": 0.13641333399982614, + "tests/aws/services/s3/test_s3.py::TestS3ObjectLockLegalHold::test_put_get_object_legal_hold": 0.14958616700050698, + "tests/aws/services/s3/test_s3.py::TestS3ObjectLockLegalHold::test_put_object_legal_hold_exc": 0.1906691220005996, + "tests/aws/services/s3/test_s3.py::TestS3ObjectLockLegalHold::test_put_object_with_legal_hold": 0.11694607199979146, + "tests/aws/services/s3/test_s3.py::TestS3ObjectLockLegalHold::test_s3_copy_object_legal_hold": 0.4540782340000078, + "tests/aws/services/s3/test_s3.py::TestS3ObjectLockLegalHold::test_s3_legal_hold_lock_versioned": 0.4908959099993808, + "tests/aws/services/s3/test_s3.py::TestS3ObjectLockRetention::test_bucket_config_default_retention": 0.15427045799970074, + "tests/aws/services/s3/test_s3.py::TestS3ObjectLockRetention::test_object_lock_delete_markers": 0.1362130709999292, + "tests/aws/services/s3/test_s3.py::TestS3ObjectLockRetention::test_object_lock_extend_duration": 0.13868393100074172, + "tests/aws/services/s3/test_s3.py::TestS3ObjectLockRetention::test_s3_copy_object_retention_lock": 0.43457355000009557, + "tests/aws/services/s3/test_s3.py::TestS3ObjectLockRetention::test_s3_object_lock_mode_validation": 0.11411536699961289, + "tests/aws/services/s3/test_s3.py::TestS3ObjectLockRetention::test_s3_object_retention": 6.185806250999576, + "tests/aws/services/s3/test_s3.py::TestS3ObjectLockRetention::test_s3_object_retention_compliance_mode": 6.156663158999891, + "tests/aws/services/s3/test_s3.py::TestS3ObjectLockRetention::test_s3_object_retention_exc": 0.27757289999999557, + "tests/aws/services/s3/test_s3.py::TestS3PresignedPost::test_post_object_default_checksum": 0.10327428500022506, + "tests/aws/services/s3/test_s3.py::TestS3PresignedPost::test_post_object_policy_casing[s3]": 0.10859275999928286, + "tests/aws/services/s3/test_s3.py::TestS3PresignedPost::test_post_object_policy_casing[s3v4]": 0.11061208999990413, + "tests/aws/services/s3/test_s3.py::TestS3PresignedPost::test_post_object_policy_conditions_validation_eq": 0.3250650740005767, + "tests/aws/services/s3/test_s3.py::TestS3PresignedPost::test_post_object_policy_conditions_validation_starts_with": 0.2704991149998932, + "tests/aws/services/s3/test_s3.py::TestS3PresignedPost::test_post_object_policy_validation_size": 0.22965626800032624, + "tests/aws/services/s3/test_s3.py::TestS3PresignedPost::test_post_object_with_file_as_string": 0.31448510499967597, + "tests/aws/services/s3/test_s3.py::TestS3PresignedPost::test_post_object_with_files": 0.13720413400005782, + "tests/aws/services/s3/test_s3.py::TestS3PresignedPost::test_post_object_with_metadata": 0.10900799699993513, + "tests/aws/services/s3/test_s3.py::TestS3PresignedPost::test_post_object_with_storage_class": 0.2985897949997707, + "tests/aws/services/s3/test_s3.py::TestS3PresignedPost::test_post_object_with_tags[invalid]": 0.16037197400009973, + "tests/aws/services/s3/test_s3.py::TestS3PresignedPost::test_post_object_with_tags[list]": 0.16010879499981456, + "tests/aws/services/s3/test_s3.py::TestS3PresignedPost::test_post_object_with_tags[notxml]": 0.1499793220000356, + "tests/aws/services/s3/test_s3.py::TestS3PresignedPost::test_post_object_with_tags[single]": 0.15809975900037898, + "tests/aws/services/s3/test_s3.py::TestS3PresignedPost::test_post_object_with_wrong_content_type": 0.13462846799984618, + "tests/aws/services/s3/test_s3.py::TestS3PresignedPost::test_post_request_expires": 3.1407435760006592, + "tests/aws/services/s3/test_s3.py::TestS3PresignedPost::test_post_request_malformed_policy[s3]": 0.14976841299994703, + "tests/aws/services/s3/test_s3.py::TestS3PresignedPost::test_post_request_malformed_policy[s3v4]": 0.15522411199981434, + "tests/aws/services/s3/test_s3.py::TestS3PresignedPost::test_post_request_missing_fields[s3]": 0.1645636809998905, + "tests/aws/services/s3/test_s3.py::TestS3PresignedPost::test_post_request_missing_fields[s3v4]": 0.16584259899991594, + "tests/aws/services/s3/test_s3.py::TestS3PresignedPost::test_post_request_missing_signature[s3]": 0.1510694099997636, + "tests/aws/services/s3/test_s3.py::TestS3PresignedPost::test_post_request_missing_signature[s3v4]": 0.1481256309998571, + "tests/aws/services/s3/test_s3.py::TestS3PresignedPost::test_presigned_post_with_different_user_credentials": 0.208660676999898, + "tests/aws/services/s3/test_s3.py::TestS3PresignedPost::test_s3_presigned_post_success_action_redirect": 0.09429943499981164, + "tests/aws/services/s3/test_s3.py::TestS3PresignedPost::test_s3_presigned_post_success_action_status_201_response": 0.0833556900001895, + "tests/aws/services/s3/test_s3.py::TestS3PresignedUrl::test_delete_has_empty_content_length_header": 0.10368621899988284, + "tests/aws/services/s3/test_s3.py::TestS3PresignedUrl::test_get_object_ignores_request_body": 0.09564649499998268, + "tests/aws/services/s3/test_s3.py::TestS3PresignedUrl::test_get_request_expires_ignored_if_validation_disabled": 3.1234599349995733, + "tests/aws/services/s3/test_s3.py::TestS3PresignedUrl::test_head_has_correct_content_length_header": 0.09364780299983977, + "tests/aws/services/s3/test_s3.py::TestS3PresignedUrl::test_pre_signed_url_forward_slash_bucket": 0.1031929890000356, + "tests/aws/services/s3/test_s3.py::TestS3PresignedUrl::test_pre_signed_url_if_match": 0.10614787700023953, + "tests/aws/services/s3/test_s3.py::TestS3PresignedUrl::test_pre_signed_url_if_none_match": 0.1067344149996643, + "tests/aws/services/s3/test_s3.py::TestS3PresignedUrl::test_presign_check_signature_validation_for_port_permutation": 0.11240479299976869, + "tests/aws/services/s3/test_s3.py::TestS3PresignedUrl::test_presign_with_additional_query_params": 0.10323826500007272, + "tests/aws/services/s3/test_s3.py::TestS3PresignedUrl::test_presigned_double_encoded_credentials": 0.16756112699977166, + "tests/aws/services/s3/test_s3.py::TestS3PresignedUrl::test_presigned_url_signature_authentication[s3-False]": 0.22959763600010774, + "tests/aws/services/s3/test_s3.py::TestS3PresignedUrl::test_presigned_url_signature_authentication[s3-True]": 0.2227879780002695, + "tests/aws/services/s3/test_s3.py::TestS3PresignedUrl::test_presigned_url_signature_authentication[s3v4-False]": 0.23490470799970353, + "tests/aws/services/s3/test_s3.py::TestS3PresignedUrl::test_presigned_url_signature_authentication[s3v4-True]": 0.23447759100008625, + "tests/aws/services/s3/test_s3.py::TestS3PresignedUrl::test_presigned_url_signature_authentication_expired[s3-False]": 2.1714172289994167, + "tests/aws/services/s3/test_s3.py::TestS3PresignedUrl::test_presigned_url_signature_authentication_expired[s3-True]": 2.1746714870000687, + "tests/aws/services/s3/test_s3.py::TestS3PresignedUrl::test_presigned_url_signature_authentication_expired[s3v4-False]": 2.17273669899987, + "tests/aws/services/s3/test_s3.py::TestS3PresignedUrl::test_presigned_url_signature_authentication_expired[s3v4-True]": 2.1751660650002123, + "tests/aws/services/s3/test_s3.py::TestS3PresignedUrl::test_presigned_url_signature_authentication_multi_part[s3-False]": 0.1289737970000715, + "tests/aws/services/s3/test_s3.py::TestS3PresignedUrl::test_presigned_url_signature_authentication_multi_part[s3-True]": 0.12819696699989436, + "tests/aws/services/s3/test_s3.py::TestS3PresignedUrl::test_presigned_url_signature_authentication_multi_part[s3v4-False]": 0.12860915200008094, + "tests/aws/services/s3/test_s3.py::TestS3PresignedUrl::test_presigned_url_signature_authentication_multi_part[s3v4-True]": 0.13649179699950764, + "tests/aws/services/s3/test_s3.py::TestS3PresignedUrl::test_presigned_url_v4_signed_headers_in_qs": 1.9880414630001724, + "tests/aws/services/s3/test_s3.py::TestS3PresignedUrl::test_presigned_url_v4_x_amz_in_qs": 7.780856012000186, + "tests/aws/services/s3/test_s3.py::TestS3PresignedUrl::test_presigned_url_with_different_user_credentials": 0.2091497219998928, + "tests/aws/services/s3/test_s3.py::TestS3PresignedUrl::test_presigned_url_with_session_token": 0.12297336099936729, + "tests/aws/services/s3/test_s3.py::TestS3PresignedUrl::test_put_object": 0.4109487390005597, + "tests/aws/services/s3/test_s3.py::TestS3PresignedUrl::test_put_object_with_md5_and_chunk_signature_bad_headers[s3-False]": 0.10262192400023196, + "tests/aws/services/s3/test_s3.py::TestS3PresignedUrl::test_put_object_with_md5_and_chunk_signature_bad_headers[s3-True]": 0.16359939499989196, + "tests/aws/services/s3/test_s3.py::TestS3PresignedUrl::test_put_object_with_md5_and_chunk_signature_bad_headers[s3v4-False]": 0.09687508200022421, + "tests/aws/services/s3/test_s3.py::TestS3PresignedUrl::test_put_object_with_md5_and_chunk_signature_bad_headers[s3v4-True]": 0.1634062820003237, + "tests/aws/services/s3/test_s3.py::TestS3PresignedUrl::test_put_url_metadata_with_sig_s3[False]": 0.48472462199970323, + "tests/aws/services/s3/test_s3.py::TestS3PresignedUrl::test_put_url_metadata_with_sig_s3[True]": 0.48876628100015296, + "tests/aws/services/s3/test_s3.py::TestS3PresignedUrl::test_put_url_metadata_with_sig_s3v4[False]": 0.49413586499986195, + "tests/aws/services/s3/test_s3.py::TestS3PresignedUrl::test_put_url_metadata_with_sig_s3v4[True]": 0.5014092450005592, + "tests/aws/services/s3/test_s3.py::TestS3PresignedUrl::test_s3_copy_md5": 0.1214465149996613, + "tests/aws/services/s3/test_s3.py::TestS3PresignedUrl::test_s3_get_response_case_sensitive_headers": 0.09092272700036119, + "tests/aws/services/s3/test_s3.py::TestS3PresignedUrl::test_s3_get_response_content_type_same_as_upload_and_range": 0.10349502300005042, + "tests/aws/services/s3/test_s3.py::TestS3PresignedUrl::test_s3_get_response_default_content_type": 0.09431971200001499, + "tests/aws/services/s3/test_s3.py::TestS3PresignedUrl::test_s3_get_response_header_overrides[s3]": 0.10493481699995755, + "tests/aws/services/s3/test_s3.py::TestS3PresignedUrl::test_s3_get_response_header_overrides[s3v4]": 0.10706557699950281, + "tests/aws/services/s3/test_s3.py::TestS3PresignedUrl::test_s3_ignored_special_headers": 0.14242722899962246, + "tests/aws/services/s3/test_s3.py::TestS3PresignedUrl::test_s3_presign_url_encoding[s3]": 0.1049699730001521, + "tests/aws/services/s3/test_s3.py::TestS3PresignedUrl::test_s3_presign_url_encoding[s3v4]": 0.10709475000021484, + "tests/aws/services/s3/test_s3.py::TestS3PresignedUrl::test_s3_presigned_url_expired[s3]": 3.194650764000471, + "tests/aws/services/s3/test_s3.py::TestS3PresignedUrl::test_s3_presigned_url_expired[s3v4]": 3.199019183999553, + "tests/aws/services/s3/test_s3.py::TestS3PresignedUrl::test_s3_put_presigned_url_missing_sig_param[s3]": 0.17224334499996985, + "tests/aws/services/s3/test_s3.py::TestS3PresignedUrl::test_s3_put_presigned_url_missing_sig_param[s3v4]": 0.17293162100031623, + "tests/aws/services/s3/test_s3.py::TestS3PresignedUrl::test_s3_put_presigned_url_same_header_and_qs_parameter": 0.18512965099989742, + "tests/aws/services/s3/test_s3.py::TestS3PresignedUrl::test_s3_put_presigned_url_with_different_headers[s3]": 1.3196900310003912, + "tests/aws/services/s3/test_s3.py::TestS3PresignedUrl::test_s3_put_presigned_url_with_different_headers[s3v4]": 0.22145837699963522, + "tests/aws/services/s3/test_s3.py::TestS3PutObjectChecksum::test_put_object_checksum[CRC32C]": 8.668408091000401, + "tests/aws/services/s3/test_s3.py::TestS3PutObjectChecksum::test_put_object_checksum[CRC32]": 7.718041926000751, + "tests/aws/services/s3/test_s3.py::TestS3PutObjectChecksum::test_put_object_checksum[CRC64NVME]": 11.444973849000235, + "tests/aws/services/s3/test_s3.py::TestS3PutObjectChecksum::test_put_object_checksum[SHA1]": 7.202316345000327, + "tests/aws/services/s3/test_s3.py::TestS3PutObjectChecksum::test_put_object_checksum[SHA256]": 9.537320907999401, + "tests/aws/services/s3/test_s3.py::TestS3PutObjectChecksum::test_s3_checksum_no_algorithm": 0.13975593799978014, + "tests/aws/services/s3/test_s3.py::TestS3PutObjectChecksum::test_s3_checksum_no_automatic_sdk_calculation": 0.2877906730000177, + "tests/aws/services/s3/test_s3.py::TestS3PutObjectChecksum::test_s3_checksum_with_content_encoding": 0.12023025100006635, + "tests/aws/services/s3/test_s3.py::TestS3PutObjectChecksum::test_s3_get_object_checksum[CRC32C]": 0.13099604899980477, + "tests/aws/services/s3/test_s3.py::TestS3PutObjectChecksum::test_s3_get_object_checksum[CRC32]": 0.13697178400025223, + "tests/aws/services/s3/test_s3.py::TestS3PutObjectChecksum::test_s3_get_object_checksum[CRC64NVME]": 0.13177105999966443, + "tests/aws/services/s3/test_s3.py::TestS3PutObjectChecksum::test_s3_get_object_checksum[None]": 0.13150545300004524, + "tests/aws/services/s3/test_s3.py::TestS3PutObjectChecksum::test_s3_get_object_checksum[SHA1]": 0.13263240400010545, + "tests/aws/services/s3/test_s3.py::TestS3PutObjectChecksum::test_s3_get_object_checksum[SHA256]": 0.13207392300046195, + "tests/aws/services/s3/test_s3.py::TestS3Routing::test_access_favicon_via_aws_endpoints[s3.amazonaws.com-False]": 0.10959772200021689, + "tests/aws/services/s3/test_s3.py::TestS3Routing::test_access_favicon_via_aws_endpoints[s3.amazonaws.com-True]": 0.11074963300052332, + "tests/aws/services/s3/test_s3.py::TestS3Routing::test_access_favicon_via_aws_endpoints[s3.us-west-2.amazonaws.com-False]": 0.1077513270001873, + "tests/aws/services/s3/test_s3.py::TestS3Routing::test_access_favicon_via_aws_endpoints[s3.us-west-2.amazonaws.com-True]": 0.11479282299978877, + "tests/aws/services/s3/test_s3.py::TestS3SSECEncryption::test_copy_object_with_sse_c": 0.22657384400008596, + "tests/aws/services/s3/test_s3.py::TestS3SSECEncryption::test_multipart_upload_sse_c": 0.459652334999646, + "tests/aws/services/s3/test_s3.py::TestS3SSECEncryption::test_multipart_upload_sse_c_validation": 0.19472717500002545, + "tests/aws/services/s3/test_s3.py::TestS3SSECEncryption::test_object_retrieval_sse_c": 0.2647568060001504, + "tests/aws/services/s3/test_s3.py::TestS3SSECEncryption::test_put_object_default_checksum_with_sse_c": 0.1854524059999676, + "tests/aws/services/s3/test_s3.py::TestS3SSECEncryption::test_put_object_lifecycle_with_sse_c": 0.1850618140001643, + "tests/aws/services/s3/test_s3.py::TestS3SSECEncryption::test_put_object_validation_sse_c": 0.2141358100002435, + "tests/aws/services/s3/test_s3.py::TestS3SSECEncryption::test_sse_c_with_versioning": 0.2343968110003516, + "tests/aws/services/s3/test_s3.py::TestS3StaticWebsiteHosting::test_crud_website_configuration": 0.11852695500010668, + "tests/aws/services/s3/test_s3.py::TestS3StaticWebsiteHosting::test_object_website_redirect_location": 0.2808713979998174, + "tests/aws/services/s3/test_s3.py::TestS3StaticWebsiteHosting::test_routing_rules_conditions": 0.5735699169995314, + "tests/aws/services/s3/test_s3.py::TestS3StaticWebsiteHosting::test_routing_rules_empty_replace_prefix": 0.44932206800012864, + "tests/aws/services/s3/test_s3.py::TestS3StaticWebsiteHosting::test_routing_rules_order": 0.26814201400020465, + "tests/aws/services/s3/test_s3.py::TestS3StaticWebsiteHosting::test_routing_rules_redirects": 0.1648387980003463, + "tests/aws/services/s3/test_s3.py::TestS3StaticWebsiteHosting::test_s3_static_website_hosting": 0.5816639469999245, + "tests/aws/services/s3/test_s3.py::TestS3StaticWebsiteHosting::test_s3_static_website_index": 0.15312513600019884, + "tests/aws/services/s3/test_s3.py::TestS3StaticWebsiteHosting::test_validate_website_configuration": 0.21054697299996405, + "tests/aws/services/s3/test_s3.py::TestS3StaticWebsiteHosting::test_website_hosting_404": 0.2384250980003344, + "tests/aws/services/s3/test_s3.py::TestS3StaticWebsiteHosting::test_website_hosting_http_methods": 0.15633030999970288, + "tests/aws/services/s3/test_s3.py::TestS3StaticWebsiteHosting::test_website_hosting_index_lookup": 0.29542297499938286, + "tests/aws/services/s3/test_s3.py::TestS3StaticWebsiteHosting::test_website_hosting_no_such_website": 0.14624504300036278, + "tests/aws/services/s3/test_s3.py::TestS3StaticWebsiteHosting::test_website_hosting_redirect_all": 0.34026437099964824, + "tests/aws/services/s3/test_s3.py::TestS3TerraformRawRequests::test_terraform_request_sequence": 0.06260259999953632, + "tests/aws/services/s3/test_s3_api.py::TestS3BucketAccelerateConfiguration::test_bucket_acceleration_configuration_crud": 0.10982299600027545, + "tests/aws/services/s3/test_s3_api.py::TestS3BucketAccelerateConfiguration::test_bucket_acceleration_configuration_exc": 0.14696022900034222, + "tests/aws/services/s3/test_s3_api.py::TestS3BucketCRUD::test_delete_bucket_with_objects": 0.3941128729998127, + "tests/aws/services/s3/test_s3_api.py::TestS3BucketCRUD::test_delete_versioned_bucket_with_objects": 0.4229502299995147, + "tests/aws/services/s3/test_s3_api.py::TestS3BucketEncryption::test_s3_bucket_encryption_sse_kms": 0.22827332199994999, + "tests/aws/services/s3/test_s3_api.py::TestS3BucketEncryption::test_s3_bucket_encryption_sse_kms_aws_managed_key": 0.2615253520002625, + "tests/aws/services/s3/test_s3_api.py::TestS3BucketEncryption::test_s3_bucket_encryption_sse_s3": 0.11092375399994125, + "tests/aws/services/s3/test_s3_api.py::TestS3BucketEncryption::test_s3_default_bucket_encryption": 0.10381976999997278, + "tests/aws/services/s3/test_s3_api.py::TestS3BucketEncryption::test_s3_default_bucket_encryption_exc": 0.4336686700003156, + "tests/aws/services/s3/test_s3_api.py::TestS3BucketNotificationConfiguration::test_bucket_notification_with_invalid_filter_rules": 0.13241483599995263, + "tests/aws/services/s3/test_s3_api.py::TestS3BucketNotificationConfiguration::test_bucket_notification_with_missing_values_in_rule": 0.23791482499973426, + "tests/aws/services/s3/test_s3_api.py::TestS3BucketObjectTagging::test_bucket_tagging_crud": 0.1544599630005905, + "tests/aws/services/s3/test_s3_api.py::TestS3BucketObjectTagging::test_bucket_tagging_exc": 0.09137463099978049, + "tests/aws/services/s3/test_s3_api.py::TestS3BucketObjectTagging::test_object_tagging_crud": 0.1756744549998075, + "tests/aws/services/s3/test_s3_api.py::TestS3BucketObjectTagging::test_object_tagging_exc": 0.23216939000030834, + "tests/aws/services/s3/test_s3_api.py::TestS3BucketObjectTagging::test_object_tagging_versioned": 0.2726441039999372, + "tests/aws/services/s3/test_s3_api.py::TestS3BucketObjectTagging::test_object_tags_delete_or_overwrite_object": 0.2026069280000229, + "tests/aws/services/s3/test_s3_api.py::TestS3BucketObjectTagging::test_put_bucket_tagging_none_value": 0.09370453600013207, + "tests/aws/services/s3/test_s3_api.py::TestS3BucketObjectTagging::test_put_object_tagging_none_value": 0.10473509100029332, + "tests/aws/services/s3/test_s3_api.py::TestS3BucketObjectTagging::test_put_object_with_tags": 0.2814053910005896, + "tests/aws/services/s3/test_s3_api.py::TestS3BucketObjectTagging::test_tagging_validation": 0.2026951310003824, + "tests/aws/services/s3/test_s3_api.py::TestS3BucketOwnershipControls::test_bucket_ownership_controls_exc": 0.12461489399993297, + "tests/aws/services/s3/test_s3_api.py::TestS3BucketOwnershipControls::test_crud_bucket_ownership_controls": 0.17175685200027146, + "tests/aws/services/s3/test_s3_api.py::TestS3BucketPolicy::test_bucket_policy_crud": 0.13092497000025105, + "tests/aws/services/s3/test_s3_api.py::TestS3BucketPolicy::test_bucket_policy_exc": 0.10695187299961617, + "tests/aws/services/s3/test_s3_api.py::TestS3BucketVersioning::test_bucket_versioning_crud": 0.17091869500063694, + "tests/aws/services/s3/test_s3_api.py::TestS3BucketVersioning::test_object_version_id_format": 0.10824634100072217, + "tests/aws/services/s3/test_s3_api.py::TestS3DeletePrecondition::test_delete_object_if_match_all_non_express": 0.0968112329996984, + "tests/aws/services/s3/test_s3_api.py::TestS3DeletePrecondition::test_delete_object_if_match_modified_non_express": 0.09461589200009257, + "tests/aws/services/s3/test_s3_api.py::TestS3DeletePrecondition::test_delete_object_if_match_non_express": 0.09317315799989956, + "tests/aws/services/s3/test_s3_api.py::TestS3DeletePrecondition::test_delete_object_if_match_size_non_express": 0.09341186700021353, + "tests/aws/services/s3/test_s3_api.py::TestS3MetricsConfiguration::test_delete_metrics_configuration": 0.09342927999978201, + "tests/aws/services/s3/test_s3_api.py::TestS3MetricsConfiguration::test_delete_metrics_configuration_twice": 0.09086909599955106, + "tests/aws/services/s3/test_s3_api.py::TestS3MetricsConfiguration::test_get_bucket_metrics_configuration": 0.07911206200014931, + "tests/aws/services/s3/test_s3_api.py::TestS3MetricsConfiguration::test_get_bucket_metrics_configuration_not_exist": 0.07555175799961944, + "tests/aws/services/s3/test_s3_api.py::TestS3MetricsConfiguration::test_list_bucket_metrics_configurations": 0.09412855999971725, + "tests/aws/services/s3/test_s3_api.py::TestS3MetricsConfiguration::test_list_bucket_metrics_configurations_paginated": 0.939654075999897, + "tests/aws/services/s3/test_s3_api.py::TestS3MetricsConfiguration::test_overwrite_bucket_metrics_configuration": 0.1528091579998545, + "tests/aws/services/s3/test_s3_api.py::TestS3MetricsConfiguration::test_put_bucket_metrics_configuration": 0.142796668000301, + "tests/aws/services/s3/test_s3_api.py::TestS3Multipart::test_upload_part_copy_no_copy_source_range": 0.18737982299990108, + "tests/aws/services/s3/test_s3_api.py::TestS3Multipart::test_upload_part_copy_range": 0.3504060880004545, + "tests/aws/services/s3/test_s3_api.py::TestS3Multipart::test_upload_part_copy_with_copy_source_if_match_and_if_unmodified_since_match": 0.19703015999994022, + "tests/aws/services/s3/test_s3_api.py::TestS3Multipart::test_upload_part_copy_with_copy_source_if_match_failed": 0.11456609599963485, + "tests/aws/services/s3/test_s3_api.py::TestS3Multipart::test_upload_part_copy_with_copy_source_if_match_none_success": 0.18643513500046538, + "tests/aws/services/s3/test_s3_api.py::TestS3Multipart::test_upload_part_copy_with_copy_source_if_match_success": 0.1850737080003455, + "tests/aws/services/s3/test_s3_api.py::TestS3Multipart::test_upload_part_copy_with_copy_source_if_modified_since_in_future_success": 0.1890991949999261, + "tests/aws/services/s3/test_s3_api.py::TestS3Multipart::test_upload_part_copy_with_copy_source_if_modified_since_success": 0.1872147149997545, + "tests/aws/services/s3/test_s3_api.py::TestS3Multipart::test_upload_part_copy_with_copy_source_if_none_match_and_if_unmodified_since_match_failed": 0.11386610299996391, + "tests/aws/services/s3/test_s3_api.py::TestS3Multipart::test_upload_part_copy_with_copy_source_if_none_match_failed": 0.10887517499941168, + "tests/aws/services/s3/test_s3_api.py::TestS3Multipart::test_upload_part_copy_with_copy_source_if_unmodified_since_match_failed": 0.12030760700054088, + "tests/aws/services/s3/test_s3_api.py::TestS3Multipart::test_upload_part_copy_with_copy_source_if_unmodified_since_success": 0.18616978999943967, + "tests/aws/services/s3/test_s3_api.py::TestS3Multipart::test_upload_part_copy_with_if_modified_since_failed": 1.1087142629999107, + "tests/aws/services/s3/test_s3_api.py::TestS3ObjectCRUD::test_delete_object": 0.10280995400034953, + "tests/aws/services/s3/test_s3_api.py::TestS3ObjectCRUD::test_delete_object_on_suspended_bucket": 0.5449862370001028, + "tests/aws/services/s3/test_s3_api.py::TestS3ObjectCRUD::test_delete_object_versioned": 0.5375198740002816, + "tests/aws/services/s3/test_s3_api.py::TestS3ObjectCRUD::test_delete_objects": 0.09688189799953761, + "tests/aws/services/s3/test_s3_api.py::TestS3ObjectCRUD::test_delete_objects_versioned": 0.4391578390000177, + "tests/aws/services/s3/test_s3_api.py::TestS3ObjectCRUD::test_get_object_range": 0.34701741900016714, + "tests/aws/services/s3/test_s3_api.py::TestS3ObjectCRUD::test_get_object_with_version_unversioned_bucket": 0.41036094700029935, + "tests/aws/services/s3/test_s3_api.py::TestS3ObjectCRUD::test_list_object_versions_order_unversioned": 0.45761144200014314, + "tests/aws/services/s3/test_s3_api.py::TestS3ObjectCRUD::test_put_object_on_suspended_bucket": 0.5883510769999702, + "tests/aws/services/s3/test_s3_api.py::TestS3ObjectLock::test_delete_object_with_no_locking": 0.11582512600080008, + "tests/aws/services/s3/test_s3_api.py::TestS3ObjectLock::test_disable_versioning_on_locked_bucket": 0.0805648939999628, + "tests/aws/services/s3/test_s3_api.py::TestS3ObjectLock::test_get_object_lock_configuration_exc": 0.08353629100020044, + "tests/aws/services/s3/test_s3_api.py::TestS3ObjectLock::test_get_put_object_lock_configuration": 0.1064698469999712, + "tests/aws/services/s3/test_s3_api.py::TestS3ObjectLock::test_put_object_lock_configuration_exc": 0.12719455300020854, + "tests/aws/services/s3/test_s3_api.py::TestS3ObjectLock::test_put_object_lock_configuration_on_existing_bucket": 0.1348488809999253, + "tests/aws/services/s3/test_s3_api.py::TestS3ObjectWritePrecondition::test_multipart_if_match_etag": 0.1660244380000222, + "tests/aws/services/s3/test_s3_api.py::TestS3ObjectWritePrecondition::test_multipart_if_match_with_delete": 0.162616823999997, + "tests/aws/services/s3/test_s3_api.py::TestS3ObjectWritePrecondition::test_multipart_if_match_with_put": 0.17093302599960225, + "tests/aws/services/s3/test_s3_api.py::TestS3ObjectWritePrecondition::test_multipart_if_match_with_put_identical": 0.1609035319997929, + "tests/aws/services/s3/test_s3_api.py::TestS3ObjectWritePrecondition::test_multipart_if_none_match_with_delete": 0.17712965899954725, + "tests/aws/services/s3/test_s3_api.py::TestS3ObjectWritePrecondition::test_multipart_if_none_match_with_put": 0.11741415800042887, + "tests/aws/services/s3/test_s3_api.py::TestS3ObjectWritePrecondition::test_put_object_if_match": 0.1386633570000413, + "tests/aws/services/s3/test_s3_api.py::TestS3ObjectWritePrecondition::test_put_object_if_match_and_if_none_match_validation": 0.07768420599995807, + "tests/aws/services/s3/test_s3_api.py::TestS3ObjectWritePrecondition::test_put_object_if_match_validation": 0.10263288200030729, + "tests/aws/services/s3/test_s3_api.py::TestS3ObjectWritePrecondition::test_put_object_if_match_versioned_bucket": 0.19288842600008138, + "tests/aws/services/s3/test_s3_api.py::TestS3ObjectWritePrecondition::test_put_object_if_none_match": 0.11493544799986921, + "tests/aws/services/s3/test_s3_api.py::TestS3ObjectWritePrecondition::test_put_object_if_none_match_validation": 0.09484473399970739, + "tests/aws/services/s3/test_s3_api.py::TestS3ObjectWritePrecondition::test_put_object_if_none_match_versioned_bucket": 0.15365416400027243, + "tests/aws/services/s3/test_s3_api.py::TestS3PublicAccessBlock::test_crud_public_access_block": 0.11939993299984053, + "tests/aws/services/s3/test_s3_concurrency.py::TestParallelBucketCreation::test_parallel_bucket_creation": 0.44419600299988815, + "tests/aws/services/s3/test_s3_concurrency.py::TestParallelBucketCreation::test_parallel_object_creation_and_listing": 0.34020609800018065, + "tests/aws/services/s3/test_s3_concurrency.py::TestParallelBucketCreation::test_parallel_object_creation_and_read": 1.7606022869999833, + "tests/aws/services/s3/test_s3_concurrency.py::TestParallelBucketCreation::test_parallel_object_read_range": 1.6840314740002214, + "tests/aws/services/s3/test_s3_cors.py::TestS3Cors::test_cors_expose_headers": 0.26165130900017175, + "tests/aws/services/s3/test_s3_cors.py::TestS3Cors::test_cors_http_get_no_config": 0.1237979039997299, + "tests/aws/services/s3/test_s3_cors.py::TestS3Cors::test_cors_http_options_no_config": 0.2649947730005806, + "tests/aws/services/s3/test_s3_cors.py::TestS3Cors::test_cors_http_options_non_existent_bucket": 0.158071512999868, + "tests/aws/services/s3/test_s3_cors.py::TestS3Cors::test_cors_http_options_non_existent_bucket_ls_allowed": 0.09342131499988682, + "tests/aws/services/s3/test_s3_cors.py::TestS3Cors::test_cors_list_buckets": 0.08799382200004402, + "tests/aws/services/s3/test_s3_cors.py::TestS3Cors::test_cors_match_headers": 0.7237416950001716, + "tests/aws/services/s3/test_s3_cors.py::TestS3Cors::test_cors_match_methods": 0.6542369750000034, + "tests/aws/services/s3/test_s3_cors.py::TestS3Cors::test_cors_match_origins": 0.6157704550005292, + "tests/aws/services/s3/test_s3_cors.py::TestS3Cors::test_cors_no_config_localstack_allowed": 0.14757528599966463, + "tests/aws/services/s3/test_s3_cors.py::TestS3Cors::test_cors_options_fails_partial_origin": 0.42761956400045165, + "tests/aws/services/s3/test_s3_cors.py::TestS3Cors::test_cors_options_match_partial_origin": 0.1648472220003896, + "tests/aws/services/s3/test_s3_cors.py::TestS3Cors::test_delete_cors": 0.18427277499995398, + "tests/aws/services/s3/test_s3_cors.py::TestS3Cors::test_get_cors": 0.1765129350001189, + "tests/aws/services/s3/test_s3_cors.py::TestS3Cors::test_put_cors": 0.16653353199990306, + "tests/aws/services/s3/test_s3_cors.py::TestS3Cors::test_put_cors_default_values": 0.45658614000012676, + "tests/aws/services/s3/test_s3_cors.py::TestS3Cors::test_put_cors_empty_origin": 0.15943824600026346, + "tests/aws/services/s3/test_s3_cors.py::TestS3Cors::test_put_cors_invalid_rules": 0.1586085820003973, + "tests/aws/services/s3/test_s3_cors.py::TestS3Cors::test_s3_cors_disabled": 0.10856764600066526, + "tests/aws/services/s3/test_s3_list_operations.py::TestS3ListBuckets::test_list_buckets_by_bucket_region": 0.5025437939998483, + "tests/aws/services/s3/test_s3_list_operations.py::TestS3ListBuckets::test_list_buckets_by_prefix_with_case_sensitivity": 0.4287542929996562, + "tests/aws/services/s3/test_s3_list_operations.py::TestS3ListBuckets::test_list_buckets_when_continuation_token_is_empty": 0.4156340919998911, + "tests/aws/services/s3/test_s3_list_operations.py::TestS3ListBuckets::test_list_buckets_with_continuation_token": 0.4734223150003345, + "tests/aws/services/s3/test_s3_list_operations.py::TestS3ListBuckets::test_list_buckets_with_max_buckets": 0.41979768300052456, + "tests/aws/services/s3/test_s3_list_operations.py::TestS3ListMultipartUploads::test_list_multipart_uploads_marker_common_prefixes": 0.44186526700059403, + "tests/aws/services/s3/test_s3_list_operations.py::TestS3ListMultipartUploads::test_list_multiparts_next_marker": 0.5741249229995447, + "tests/aws/services/s3/test_s3_list_operations.py::TestS3ListMultipartUploads::test_list_multiparts_with_prefix_and_delimiter": 0.44451020699989385, + "tests/aws/services/s3/test_s3_list_operations.py::TestS3ListMultipartUploads::test_s3_list_multiparts_timestamp_precision": 0.07874003899951276, + "tests/aws/services/s3/test_s3_list_operations.py::TestS3ListObjectVersions::test_list_object_versions_pagination_common_prefixes": 0.5323521170003005, + "tests/aws/services/s3/test_s3_list_operations.py::TestS3ListObjectVersions::test_list_objects_versions_markers": 0.650325724999675, + "tests/aws/services/s3/test_s3_list_operations.py::TestS3ListObjectVersions::test_list_objects_versions_with_prefix": 0.5614163859995642, + "tests/aws/services/s3/test_s3_list_operations.py::TestS3ListObjectVersions::test_list_objects_versions_with_prefix_only_and_pagination": 0.5726779689994146, + "tests/aws/services/s3/test_s3_list_operations.py::TestS3ListObjectVersions::test_list_objects_versions_with_prefix_only_and_pagination_many_versions": 1.148513868000009, + "tests/aws/services/s3/test_s3_list_operations.py::TestS3ListObjectVersions::test_s3_list_object_versions_timestamp_precision": 0.10854225900038728, + "tests/aws/services/s3/test_s3_list_operations.py::TestS3ListObjects::test_list_objects_marker_common_prefixes": 0.5002471190000506, + "tests/aws/services/s3/test_s3_list_operations.py::TestS3ListObjects::test_list_objects_next_marker": 0.46824301200012997, + "tests/aws/services/s3/test_s3_list_operations.py::TestS3ListObjects::test_list_objects_with_prefix[%2F]": 0.4075148920001084, + "tests/aws/services/s3/test_s3_list_operations.py::TestS3ListObjects::test_list_objects_with_prefix[/]": 0.3915966960003061, + "tests/aws/services/s3/test_s3_list_operations.py::TestS3ListObjects::test_list_objects_with_prefix[]": 0.39615000300000247, + "tests/aws/services/s3/test_s3_list_operations.py::TestS3ListObjects::test_s3_list_objects_empty_marker": 0.36415216800014605, + "tests/aws/services/s3/test_s3_list_operations.py::TestS3ListObjects::test_s3_list_objects_timestamp_precision[ListObjectsV2]": 0.09150354199982758, + "tests/aws/services/s3/test_s3_list_operations.py::TestS3ListObjects::test_s3_list_objects_timestamp_precision[ListObjects]": 0.09405699999979333, + "tests/aws/services/s3/test_s3_list_operations.py::TestS3ListObjectsV2::test_list_objects_v2_continuation_common_prefixes": 0.48483639400092216, + "tests/aws/services/s3/test_s3_list_operations.py::TestS3ListObjectsV2::test_list_objects_v2_continuation_start_after": 0.6139321869995911, + "tests/aws/services/s3/test_s3_list_operations.py::TestS3ListObjectsV2::test_list_objects_v2_with_prefix": 0.4976965770001698, + "tests/aws/services/s3/test_s3_list_operations.py::TestS3ListObjectsV2::test_list_objects_v2_with_prefix_and_delimiter": 0.48009164900031465, + "tests/aws/services/s3/test_s3_list_operations.py::TestS3ListParts::test_list_parts_empty_part_number_marker": 0.10960839700010183, + "tests/aws/services/s3/test_s3_list_operations.py::TestS3ListParts::test_list_parts_pagination": 0.14938962200039896, + "tests/aws/services/s3/test_s3_list_operations.py::TestS3ListParts::test_list_parts_via_object_attrs_pagination": 0.27604011100038406, + "tests/aws/services/s3/test_s3_list_operations.py::TestS3ListParts::test_s3_list_parts_timestamp_precision": 0.0918357130003642, + "tests/aws/services/s3/test_s3_notifications_eventbridge.py::TestS3NotificationsToEventBridge::test_object_created_put": 1.7497640480000882, + "tests/aws/services/s3/test_s3_notifications_eventbridge.py::TestS3NotificationsToEventBridge::test_object_created_put_in_different_region": 1.8056461039996066, + "tests/aws/services/s3/test_s3_notifications_eventbridge.py::TestS3NotificationsToEventBridge::test_object_created_put_versioned": 5.169573362999927, + "tests/aws/services/s3/test_s3_notifications_eventbridge.py::TestS3NotificationsToEventBridge::test_object_put_acl": 1.2411078839995753, + "tests/aws/services/s3/test_s3_notifications_eventbridge.py::TestS3NotificationsToEventBridge::test_restore_object": 2.459640582999782, + "tests/aws/services/s3/test_s3_notifications_lambda.py::TestS3NotificationsToLambda::test_create_object_by_presigned_request_via_dynamodb": 6.084695994999947, + "tests/aws/services/s3/test_s3_notifications_lambda.py::TestS3NotificationsToLambda::test_create_object_put_via_dynamodb": 2.9978575180007283, + "tests/aws/services/s3/test_s3_notifications_lambda.py::TestS3NotificationsToLambda::test_invalid_lambda_arn": 0.4023626550001609, + "tests/aws/services/s3/test_s3_notifications_sns.py::TestS3NotificationsToSns::test_bucket_not_exist": 0.316588330999366, + "tests/aws/services/s3/test_s3_notifications_sns.py::TestS3NotificationsToSns::test_bucket_notifications_with_filter": 1.686299543000132, + "tests/aws/services/s3/test_s3_notifications_sns.py::TestS3NotificationsToSns::test_invalid_topic_arn": 0.2444576469997628, + "tests/aws/services/s3/test_s3_notifications_sns.py::TestS3NotificationsToSns::test_object_created_put": 1.7166392600001927, + "tests/aws/services/s3/test_s3_notifications_sqs.py::TestS3NotificationsToSQS::test_delete_objects": 0.7663217660006012, + "tests/aws/services/s3/test_s3_notifications_sqs.py::TestS3NotificationsToSQS::test_filter_rules_case_insensitive": 0.11862335300065752, + "tests/aws/services/s3/test_s3_notifications_sqs.py::TestS3NotificationsToSQS::test_filter_rules_empty_value": 0.11682704799977728, + "tests/aws/services/s3/test_s3_notifications_sqs.py::TestS3NotificationsToSQS::test_invalid_sqs_arn": 0.3851042200003576, + "tests/aws/services/s3/test_s3_notifications_sqs.py::TestS3NotificationsToSQS::test_key_encoding": 0.5812207869994381, + "tests/aws/services/s3/test_s3_notifications_sqs.py::TestS3NotificationsToSQS::test_multiple_invalid_sqs_arns": 0.5316138610000962, + "tests/aws/services/s3/test_s3_notifications_sqs.py::TestS3NotificationsToSQS::test_notifications_with_filter": 0.7331682329991054, + "tests/aws/services/s3/test_s3_notifications_sqs.py::TestS3NotificationsToSQS::test_object_created_and_object_removed": 0.7947303360006117, + "tests/aws/services/s3/test_s3_notifications_sqs.py::TestS3NotificationsToSQS::test_object_created_complete_multipart_upload": 0.6227922230000331, + "tests/aws/services/s3/test_s3_notifications_sqs.py::TestS3NotificationsToSQS::test_object_created_copy": 0.6257197920003819, + "tests/aws/services/s3/test_s3_notifications_sqs.py::TestS3NotificationsToSQS::test_object_created_put": 0.6785168999999769, + "tests/aws/services/s3/test_s3_notifications_sqs.py::TestS3NotificationsToSQS::test_object_created_put_versioned": 1.0693258129999776, + "tests/aws/services/s3/test_s3_notifications_sqs.py::TestS3NotificationsToSQS::test_object_created_put_with_presigned_url_upload": 0.908638627000073, + "tests/aws/services/s3/test_s3_notifications_sqs.py::TestS3NotificationsToSQS::test_object_put_acl": 0.785258634999991, + "tests/aws/services/s3/test_s3_notifications_sqs.py::TestS3NotificationsToSQS::test_object_tagging_delete_event": 0.6355096540005434, + "tests/aws/services/s3/test_s3_notifications_sqs.py::TestS3NotificationsToSQS::test_object_tagging_put_event": 0.6258236620001298, + "tests/aws/services/s3/test_s3_notifications_sqs.py::TestS3NotificationsToSQS::test_restore_object": 0.743333795000126, + "tests/aws/services/s3/test_s3_notifications_sqs.py::TestS3NotificationsToSQS::test_xray_header": 1.5719291640002666, + "tests/aws/services/s3control/test_s3control.py::TestLegacyS3Control::test_lifecycle_public_access_block": 0.3348778980002862, + "tests/aws/services/s3control/test_s3control.py::TestLegacyS3Control::test_public_access_block_validations": 0.07877420600016194, + "tests/aws/services/s3control/test_s3control.py::TestS3ControlAccessPoint::test_access_point_already_exists": 0.0012051980002070195, + "tests/aws/services/s3control/test_s3control.py::TestS3ControlAccessPoint::test_access_point_bucket_not_exists": 0.001295208000101411, + "tests/aws/services/s3control/test_s3control.py::TestS3ControlAccessPoint::test_access_point_lifecycle": 0.001303051999911986, + "tests/aws/services/s3control/test_s3control.py::TestS3ControlAccessPoint::test_access_point_name_validation": 0.001221819999955187, + "tests/aws/services/s3control/test_s3control.py::TestS3ControlAccessPoint::test_access_point_pagination": 0.0012014809999527643, + "tests/aws/services/s3control/test_s3control.py::TestS3ControlAccessPoint::test_access_point_public_access_block_configuration": 0.0012176219997854787, + "tests/aws/services/s3control/test_s3control.py::TestS3ControlPublicAccessBlock::test_crud_public_access_block": 0.0012201560002722545, + "tests/aws/services/s3control/test_s3control.py::TestS3ControlPublicAccessBlock::test_empty_public_access_block": 0.0011967120003646414, + "tests/aws/services/scheduler/test_scheduler.py::test_list_schedules": 0.07299728899988622, + "tests/aws/services/scheduler/test_scheduler.py::test_tag_resource": 0.0393742299997939, + "tests/aws/services/scheduler/test_scheduler.py::test_untag_resource": 0.03603147200010426, + "tests/aws/services/scheduler/test_scheduler.py::tests_create_schedule_with_invalid_schedule_expression[ rate(10 minutes)]": 0.01667461400029424, + "tests/aws/services/scheduler/test_scheduler.py::tests_create_schedule_with_invalid_schedule_expression[at(2021-12-31)]": 0.016262982000171178, + "tests/aws/services/scheduler/test_scheduler.py::tests_create_schedule_with_invalid_schedule_expression[at(2021-12-31T23:59:59Z)]": 0.016679671999554557, + "tests/aws/services/scheduler/test_scheduler.py::tests_create_schedule_with_invalid_schedule_expression[cron()]": 0.016257512000265706, + "tests/aws/services/scheduler/test_scheduler.py::tests_create_schedule_with_invalid_schedule_expression[cron(0 1 * * * *)]": 0.02792194300036499, + "tests/aws/services/scheduler/test_scheduler.py::tests_create_schedule_with_invalid_schedule_expression[cron(0 dummy ? * MON-FRI *)]": 0.01692124499959391, + "tests/aws/services/scheduler/test_scheduler.py::tests_create_schedule_with_invalid_schedule_expression[cron(7 20 * * NOT *)]": 0.017603984000743367, + "tests/aws/services/scheduler/test_scheduler.py::tests_create_schedule_with_invalid_schedule_expression[cron(71 8 1 * ? *)]": 0.017490922999513714, + "tests/aws/services/scheduler/test_scheduler.py::tests_create_schedule_with_invalid_schedule_expression[cron(INVALID)]": 0.017407185999672947, + "tests/aws/services/scheduler/test_scheduler.py::tests_create_schedule_with_invalid_schedule_expression[rate( 10 minutes )]": 0.01759665200006566, + "tests/aws/services/scheduler/test_scheduler.py::tests_create_schedule_with_invalid_schedule_expression[rate()]": 0.016625469999780762, + "tests/aws/services/scheduler/test_scheduler.py::tests_create_schedule_with_invalid_schedule_expression[rate(-10 minutes)]": 0.017929744999946706, + "tests/aws/services/scheduler/test_scheduler.py::tests_create_schedule_with_invalid_schedule_expression[rate(10 minutess)]": 0.016189273000236426, + "tests/aws/services/scheduler/test_scheduler.py::tests_create_schedule_with_invalid_schedule_expression[rate(10 seconds)]": 0.015897726999810402, + "tests/aws/services/scheduler/test_scheduler.py::tests_create_schedule_with_invalid_schedule_expression[rate(10 years)]": 0.016117690000100993, + "tests/aws/services/scheduler/test_scheduler.py::tests_create_schedule_with_invalid_schedule_expression[rate(10)]": 0.01668105499993544, + "tests/aws/services/scheduler/test_scheduler.py::tests_create_schedule_with_invalid_schedule_expression[rate(foo minutes)]": 0.017716748000111693, + "tests/aws/services/scheduler/test_scheduler.py::tests_create_schedule_with_valid_schedule_expression": 0.08329794499968557, + "tests/aws/services/secretsmanager/test_secretsmanager.py::TestSecretsManager::test_call_lists_secrets_multiple_times": 0.060524180000356864, + "tests/aws/services/secretsmanager/test_secretsmanager.py::TestSecretsManager::test_call_lists_secrets_multiple_times_snapshots": 0.001344991000223672, + "tests/aws/services/secretsmanager/test_secretsmanager.py::TestSecretsManager::test_can_recreate_delete_secret": 0.05819487500048126, + "tests/aws/services/secretsmanager/test_secretsmanager.py::TestSecretsManager::test_create_and_update_secret[Valid/_+=.@-Name-a1b2]": 0.0970788740005446, + "tests/aws/services/secretsmanager/test_secretsmanager.py::TestSecretsManager::test_create_and_update_secret[Valid/_+=.@-Name-a1b2c3-]": 0.0962901190005141, + "tests/aws/services/secretsmanager/test_secretsmanager.py::TestSecretsManager::test_create_and_update_secret[Valid/_+=.@-Name]": 0.09713370700001178, + "tests/aws/services/secretsmanager/test_secretsmanager.py::TestSecretsManager::test_create_and_update_secret[s-c64bdc03]": 0.1219062580003083, + "tests/aws/services/secretsmanager/test_secretsmanager.py::TestSecretsManager::test_create_multi_secrets": 0.11499769900001411, + "tests/aws/services/secretsmanager/test_secretsmanager.py::TestSecretsManager::test_create_multi_secrets_snapshot": 0.001355019000129687, + "tests/aws/services/secretsmanager/test_secretsmanager.py::TestSecretsManager::test_create_secret_version_from_empty_secret": 0.04289433300073142, + "tests/aws/services/secretsmanager/test_secretsmanager.py::TestSecretsManager::test_create_secret_with_custom_id": 0.023774842999500834, + "tests/aws/services/secretsmanager/test_secretsmanager.py::TestSecretsManager::test_delete_non_existent_secret_returns_as_if_secret_exists": 0.02117032900059712, + "tests/aws/services/secretsmanager/test_secretsmanager.py::TestSecretsManager::test_deprecated_secret_version": 0.9697656360003748, + "tests/aws/services/secretsmanager/test_secretsmanager.py::TestSecretsManager::test_deprecated_secret_version_stage": 0.1902340859992364, + "tests/aws/services/secretsmanager/test_secretsmanager.py::TestSecretsManager::test_exp_raised_on_creation_of_secret_scheduled_for_deletion": 0.042694821000168304, + "tests/aws/services/secretsmanager/test_secretsmanager.py::TestSecretsManager::test_first_rotate_secret_with_missing_lambda_arn": 0.03796356700013348, + "tests/aws/services/secretsmanager/test_secretsmanager.py::TestSecretsManager::test_force_delete_deleted_secret": 0.056402538000384084, + "tests/aws/services/secretsmanager/test_secretsmanager.py::TestSecretsManager::test_get_random_exclude_characters_and_symbols": 0.015931550000459538, + "tests/aws/services/secretsmanager/test_secretsmanager.py::TestSecretsManager::test_get_secret_value": 0.07407171400018342, + "tests/aws/services/secretsmanager/test_secretsmanager.py::TestSecretsManager::test_get_secret_value_errors": 0.04274879799959308, + "tests/aws/services/secretsmanager/test_secretsmanager.py::TestSecretsManager::test_http_put_secret_value_custom_client_request_token_new_version_stages": 0.05900952900037737, + "tests/aws/services/secretsmanager/test_secretsmanager.py::TestSecretsManager::test_http_put_secret_value_duplicate_req": 0.055132751999735774, + "tests/aws/services/secretsmanager/test_secretsmanager.py::TestSecretsManager::test_http_put_secret_value_null_client_request_token_new_version_stages": 0.06115131700016718, + "tests/aws/services/secretsmanager/test_secretsmanager.py::TestSecretsManager::test_http_put_secret_value_with_duplicate_client_request_token": 0.0012615509999704955, + "tests/aws/services/secretsmanager/test_secretsmanager.py::TestSecretsManager::test_http_put_secret_value_with_non_provided_client_request_token": 0.05515936099982355, + "tests/aws/services/secretsmanager/test_secretsmanager.py::TestSecretsManager::test_invalid_secret_name[ Inv *?!]Name\\\\-]": 0.10333742400007395, + "tests/aws/services/secretsmanager/test_secretsmanager.py::TestSecretsManager::test_invalid_secret_name[ Inv Name]": 0.10253145400020003, + "tests/aws/services/secretsmanager/test_secretsmanager.py::TestSecretsManager::test_invalid_secret_name[ Inv*Name? ]": 0.10472035199973107, + "tests/aws/services/secretsmanager/test_secretsmanager.py::TestSecretsManager::test_invalid_secret_name[Inv Name]": 0.10664760700001352, + "tests/aws/services/secretsmanager/test_secretsmanager.py::TestSecretsManager::test_last_accessed_date": 0.06172552599991832, + "tests/aws/services/secretsmanager/test_secretsmanager.py::TestSecretsManager::test_last_updated_date": 0.0938670849996015, + "tests/aws/services/secretsmanager/test_secretsmanager.py::TestSecretsManager::test_list_secrets_filtering": 0.21189353999943705, + "tests/aws/services/secretsmanager/test_secretsmanager.py::TestSecretsManager::test_no_client_request_token[CreateSecret]": 0.026468202999694768, + "tests/aws/services/secretsmanager/test_secretsmanager.py::TestSecretsManager::test_no_client_request_token[PutSecretValue]": 0.024789200999748573, + "tests/aws/services/secretsmanager/test_secretsmanager.py::TestSecretsManager::test_no_client_request_token[RotateSecret]": 0.02488346900054239, + "tests/aws/services/secretsmanager/test_secretsmanager.py::TestSecretsManager::test_no_client_request_token[UpdateSecret]": 0.02456495400019776, + "tests/aws/services/secretsmanager/test_secretsmanager.py::TestSecretsManager::test_non_versioning_version_stages_no_replacement": 0.19348553000008906, + "tests/aws/services/secretsmanager/test_secretsmanager.py::TestSecretsManager::test_non_versioning_version_stages_replacement": 0.1956941060002464, + "tests/aws/services/secretsmanager/test_secretsmanager.py::TestSecretsManager::test_put_secret_value_with_new_custom_client_request_token": 0.05355759199937893, + "tests/aws/services/secretsmanager/test_secretsmanager.py::TestSecretsManager::test_put_secret_value_with_version_stages": 0.11284068599979946, + "tests/aws/services/secretsmanager/test_secretsmanager.py::TestSecretsManager::test_resource_policy": 0.05343851099996755, + "tests/aws/services/secretsmanager/test_secretsmanager.py::TestSecretsManager::test_rotate_secret_invalid_lambda_arn": 0.2053501329996834, + "tests/aws/services/secretsmanager/test_secretsmanager.py::TestSecretsManager::test_rotate_secret_multiple_times_with_lambda_success": 2.970870883000771, + "tests/aws/services/secretsmanager/test_secretsmanager.py::TestSecretsManager::test_rotate_secret_with_lambda_success[None]": 2.4195715609998842, + "tests/aws/services/secretsmanager/test_secretsmanager.py::TestSecretsManager::test_rotate_secret_with_lambda_success[True]": 2.3823056310002357, + "tests/aws/services/secretsmanager/test_secretsmanager.py::TestSecretsManager::test_secret_exists": 0.05317210099974545, + "tests/aws/services/secretsmanager/test_secretsmanager.py::TestSecretsManager::test_secret_exists_snapshots": 0.05976463200022408, + "tests/aws/services/secretsmanager/test_secretsmanager.py::TestSecretsManager::test_secret_not_found": 0.02915526700007831, + "tests/aws/services/secretsmanager/test_secretsmanager.py::TestSecretsManager::test_secret_restore": 0.05126885299978312, + "tests/aws/services/secretsmanager/test_secretsmanager.py::TestSecretsManager::test_secret_tags": 0.13079450199984421, + "tests/aws/services/secretsmanager/test_secretsmanager.py::TestSecretsManager::test_secret_version_not_found": 0.04997145100014677, + "tests/aws/services/secretsmanager/test_secretsmanager.py::TestSecretsManager::test_update_secret_description": 0.1190105229998153, + "tests/aws/services/secretsmanager/test_secretsmanager.py::TestSecretsManager::test_update_secret_version_stages_current_pending": 0.2134648510000261, + "tests/aws/services/secretsmanager/test_secretsmanager.py::TestSecretsManager::test_update_secret_version_stages_current_pending_cycle": 0.2717740970001614, + "tests/aws/services/secretsmanager/test_secretsmanager.py::TestSecretsManager::test_update_secret_version_stages_current_pending_cycle_custom_stages_1": 0.267972109999846, + "tests/aws/services/secretsmanager/test_secretsmanager.py::TestSecretsManager::test_update_secret_version_stages_current_pending_cycle_custom_stages_2": 0.28774183499990613, + "tests/aws/services/secretsmanager/test_secretsmanager.py::TestSecretsManager::test_update_secret_version_stages_current_pending_cycle_custom_stages_3": 0.24272180299976753, + "tests/aws/services/secretsmanager/test_secretsmanager.py::TestSecretsManager::test_update_secret_version_stages_current_previous": 0.19378790600012508, + "tests/aws/services/secretsmanager/test_secretsmanager.py::TestSecretsManager::test_update_secret_version_stages_return_type": 0.05332573699979548, + "tests/aws/services/secretsmanager/test_secretsmanager.py::TestSecretsManager::test_update_secret_with_non_provided_client_request_token": 0.051447372999973595, + "tests/aws/services/secretsmanager/test_secretsmanager.py::TestSecretsManagerMultiAccounts::test_cross_account_access": 0.14516057200034993, + "tests/aws/services/secretsmanager/test_secretsmanager.py::TestSecretsManagerMultiAccounts::test_cross_account_access_non_default_key": 0.11362850800014712, + "tests/aws/services/ses/test_ses.py::TestSES::test_cannot_create_event_for_no_topic": 0.04614824600002976, + "tests/aws/services/ses/test_ses.py::TestSES::test_clone_receipt_rule_set": 0.4684116180001183, + "tests/aws/services/ses/test_ses.py::TestSES::test_creating_event_destination_without_configuration_set": 0.07094300000062503, + "tests/aws/services/ses/test_ses.py::TestSES::test_delete_template": 0.0650293950006926, + "tests/aws/services/ses/test_ses.py::TestSES::test_deleting_non_existent_configuration_set": 0.016092710000521038, + "tests/aws/services/ses/test_ses.py::TestSES::test_deleting_non_existent_configuration_set_event_destination": 0.03390313999943828, + "tests/aws/services/ses/test_ses.py::TestSES::test_describe_config_set_event_destinations": 0.11264441599996644, + "tests/aws/services/ses/test_ses.py::TestSES::test_get_identity_verification_attributes_for_domain": 0.011928948999866407, + "tests/aws/services/ses/test_ses.py::TestSES::test_get_identity_verification_attributes_for_email": 0.026058887999624858, + "tests/aws/services/ses/test_ses.py::TestSES::test_invalid_tags_send_email[-]": 0.016435322000688757, + "tests/aws/services/ses/test_ses.py::TestSES::test_invalid_tags_send_email[-test]": 0.01677301600057035, + "tests/aws/services/ses/test_ses.py::TestSES::test_invalid_tags_send_email[test-]": 0.016850944000452728, + "tests/aws/services/ses/test_ses.py::TestSES::test_invalid_tags_send_email[test-test_invalid_value:123]": 0.01733078100005514, + "tests/aws/services/ses/test_ses.py::TestSES::test_invalid_tags_send_email[test_invalid_name:123-test]": 0.01813305500036222, + "tests/aws/services/ses/test_ses.py::TestSES::test_invalid_tags_send_email[test_invalid_name:123-test_invalid_value:123]": 0.016496927999924083, + "tests/aws/services/ses/test_ses.py::TestSES::test_invalid_tags_send_email[test_invalid_name_len]": 0.014796482000292599, + "tests/aws/services/ses/test_ses.py::TestSES::test_invalid_tags_send_email[test_invalid_value_len]": 0.01504976699970939, + "tests/aws/services/ses/test_ses.py::TestSES::test_invalid_tags_send_email[test_priority_name_value]": 0.015447909999693366, + "tests/aws/services/ses/test_ses.py::TestSES::test_list_templates": 0.1486297859996739, + "tests/aws/services/ses/test_ses.py::TestSES::test_sending_to_deleted_topic": 0.455500868999934, + "tests/aws/services/ses/test_ses.py::TestSES::test_sent_message_counter": 0.1110661610000534, + "tests/aws/services/ses/test_ses.py::TestSES::test_ses_sns_topic_integration_send_email": 1.371585430000323, + "tests/aws/services/ses/test_ses.py::TestSES::test_ses_sns_topic_integration_send_email_ses_destination": 0.7114223890002904, + "tests/aws/services/ses/test_ses.py::TestSES::test_ses_sns_topic_integration_send_raw_email": 1.3488006019997556, + "tests/aws/services/ses/test_ses.py::TestSES::test_ses_sns_topic_integration_send_templated_email": 1.3497784619999038, + "tests/aws/services/ses/test_ses.py::TestSES::test_set_identity_headers_in_notifications_enabled_failure_invalid_type": 0.03581774599979326, + "tests/aws/services/ses/test_ses.py::TestSES::test_set_identity_headers_in_notifications_enabled_failure_unknown_identity[Bounce]": 0.01499329799980842, + "tests/aws/services/ses/test_ses.py::TestSES::test_set_identity_headers_in_notifications_enabled_failure_unknown_identity[Complaint]": 0.018143482000141375, + "tests/aws/services/ses/test_ses.py::TestSES::test_set_identity_headers_in_notifications_enabled_failure_unknown_identity[Delivery]": 0.01750189099993804, + "tests/aws/services/ses/test_ses.py::TestSES::test_set_identity_headers_in_notifications_enabled_success[False-Bounce]": 0.040550323999468674, + "tests/aws/services/ses/test_ses.py::TestSES::test_set_identity_headers_in_notifications_enabled_success[False-Complaint]": 0.044134042999758094, + "tests/aws/services/ses/test_ses.py::TestSES::test_set_identity_headers_in_notifications_enabled_success[False-Delivery]": 0.03981778300021688, + "tests/aws/services/ses/test_ses.py::TestSES::test_set_identity_headers_in_notifications_enabled_success[True-Bounce]": 0.043621854000321036, + "tests/aws/services/ses/test_ses.py::TestSES::test_set_identity_headers_in_notifications_enabled_success[True-Complaint]": 0.0404307009994227, + "tests/aws/services/ses/test_ses.py::TestSES::test_set_identity_headers_in_notifications_enabled_success[True-Delivery]": 0.040911843000230874, + "tests/aws/services/ses/test_ses.py::TestSES::test_special_tags_send_email[ses:feedback-id-a-this-marketing-campaign]": 0.017104346999985864, + "tests/aws/services/ses/test_ses.py::TestSES::test_special_tags_send_email[ses:feedback-id-b-that-campaign]": 0.01705299000013838, + "tests/aws/services/ses/test_ses.py::TestSES::test_trying_to_delete_event_destination_from_non_existent_configuration_set": 0.10231889400029104, + "tests/aws/services/ses/test_ses.py::TestSESRetrospection::test_send_email_can_retrospect": 1.786491496999588, + "tests/aws/services/ses/test_ses.py::TestSESRetrospection::test_send_email_raises_message_rejected": 0.015311477000068408, + "tests/aws/services/ses/test_ses.py::TestSESRetrospection::test_send_templated_email_can_retrospect": 0.08152223699926253, + "tests/aws/services/sns/test_sns.py::TestSNSCertEndpoint::test_cert_endpoint_host[]": 0.2077597239995157, + "tests/aws/services/sns/test_sns.py::TestSNSCertEndpoint::test_cert_endpoint_host[sns.us-east-1.amazonaws.com]": 0.15314737500011688, + "tests/aws/services/sns/test_sns.py::TestSNSMultiAccounts::test_cross_account_access": 0.13301658199952726, + "tests/aws/services/sns/test_sns.py::TestSNSMultiAccounts::test_cross_account_publish_to_sqs": 0.5403921259999152, + "tests/aws/services/sns/test_sns.py::TestSNSMultiRegions::test_cross_region_access": 0.11177230800058169, + "tests/aws/services/sns/test_sns.py::TestSNSMultiRegions::test_cross_region_delivery_sqs": 0.16662111300001925, + "tests/aws/services/sns/test_sns.py::TestSNSPlatformEndpoint::test_create_platform_endpoint_check_idempotency": 0.0014652239997303695, + "tests/aws/services/sns/test_sns.py::TestSNSPlatformEndpoint::test_publish_disabled_endpoint": 0.09585106099939367, + "tests/aws/services/sns/test_sns.py::TestSNSPlatformEndpoint::test_publish_to_gcm": 0.0013624409998556075, + "tests/aws/services/sns/test_sns.py::TestSNSPlatformEndpoint::test_publish_to_platform_endpoint_is_dispatched": 0.16705854700012424, + "tests/aws/services/sns/test_sns.py::TestSNSPlatformEndpoint::test_subscribe_platform_endpoint": 0.10476830099969447, + "tests/aws/services/sns/test_sns.py::TestSNSPublishCrud::test_empty_sns_message": 0.09867360199996256, + "tests/aws/services/sns/test_sns.py::TestSNSPublishCrud::test_message_structure_json_exc": 0.06433802100036701, + "tests/aws/services/sns/test_sns.py::TestSNSPublishCrud::test_publish_batch_too_long_message": 0.08060597899975619, + "tests/aws/services/sns/test_sns.py::TestSNSPublishCrud::test_publish_by_path_parameters": 0.1461495780004043, + "tests/aws/services/sns/test_sns.py::TestSNSPublishCrud::test_publish_message_before_subscribe_topic": 0.15925975200025277, + "tests/aws/services/sns/test_sns.py::TestSNSPublishCrud::test_publish_message_by_target_arn": 0.22601026400025148, + "tests/aws/services/sns/test_sns.py::TestSNSPublishCrud::test_publish_non_existent_target": 0.03739077799946244, + "tests/aws/services/sns/test_sns.py::TestSNSPublishCrud::test_publish_too_long_message": 0.0809699719998207, + "tests/aws/services/sns/test_sns.py::TestSNSPublishCrud::test_publish_with_empty_subject": 0.04663797799958047, + "tests/aws/services/sns/test_sns.py::TestSNSPublishCrud::test_publish_wrong_arn_format": 0.03485628599946722, + "tests/aws/services/sns/test_sns.py::TestSNSPublishCrud::test_topic_publish_another_region": 0.06687320099990757, + "tests/aws/services/sns/test_sns.py::TestSNSPublishCrud::test_unknown_topic_publish": 0.045796339999924385, + "tests/aws/services/sns/test_sns.py::TestSNSPublishDelivery::test_delivery_lambda": 2.1167528179998953, + "tests/aws/services/sns/test_sns.py::TestSNSRetrospectionEndpoints::test_publish_sms_can_retrospect": 0.2873195090005538, + "tests/aws/services/sns/test_sns.py::TestSNSRetrospectionEndpoints::test_publish_to_platform_endpoint_can_retrospect": 0.23784997600023416, + "tests/aws/services/sns/test_sns.py::TestSNSRetrospectionEndpoints::test_subscription_tokens_can_retrospect": 1.1083832460003578, + "tests/aws/services/sns/test_sns.py::TestSNSSMS::test_publish_sms": 0.01791694199982885, + "tests/aws/services/sns/test_sns.py::TestSNSSMS::test_publish_sms_endpoint": 0.17037757199977932, + "tests/aws/services/sns/test_sns.py::TestSNSSMS::test_publish_wrong_phone_format": 0.05527289400015434, + "tests/aws/services/sns/test_sns.py::TestSNSSMS::test_subscribe_sms_endpoint": 0.055267083999751776, + "tests/aws/services/sns/test_sns.py::TestSNSSubscriptionCrud::test_create_subscriptions_with_attributes": 0.10042560399961076, + "tests/aws/services/sns/test_sns.py::TestSNSSubscriptionCrud::test_list_subscriptions": 0.39171506200000294, + "tests/aws/services/sns/test_sns.py::TestSNSSubscriptionCrud::test_list_subscriptions_by_topic_pagination": 1.7541828180001175, + "tests/aws/services/sns/test_sns.py::TestSNSSubscriptionCrud::test_not_found_error_on_set_subscription_attributes": 0.3182221749998462, + "tests/aws/services/sns/test_sns.py::TestSNSSubscriptionCrud::test_sns_confirm_subscription_wrong_token": 0.11702473499963162, + "tests/aws/services/sns/test_sns.py::TestSNSSubscriptionCrud::test_subscribe_idempotency": 0.12186695800028247, + "tests/aws/services/sns/test_sns.py::TestSNSSubscriptionCrud::test_subscribe_with_invalid_protocol": 0.037314724999760074, + "tests/aws/services/sns/test_sns.py::TestSNSSubscriptionCrud::test_subscribe_with_invalid_topic": 0.05633284299983643, + "tests/aws/services/sns/test_sns.py::TestSNSSubscriptionCrud::test_unsubscribe_from_non_existing_subscription": 0.1014632609999353, + "tests/aws/services/sns/test_sns.py::TestSNSSubscriptionCrud::test_unsubscribe_idempotency": 0.09873567399972671, + "tests/aws/services/sns/test_sns.py::TestSNSSubscriptionCrud::test_unsubscribe_wrong_arn_format": 0.05327393100014888, + "tests/aws/services/sns/test_sns.py::TestSNSSubscriptionCrud::test_validate_set_sub_attributes": 0.2567477179995876, + "tests/aws/services/sns/test_sns.py::TestSNSSubscriptionFirehose::test_publish_to_firehose_with_s3": 1.3216375330002847, + "tests/aws/services/sns/test_sns.py::TestSNSSubscriptionHttp::test_dlq_external_http_endpoint[False]": 2.6919450569998844, + "tests/aws/services/sns/test_sns.py::TestSNSSubscriptionHttp::test_dlq_external_http_endpoint[True]": 2.6808424959999684, + "tests/aws/services/sns/test_sns.py::TestSNSSubscriptionHttp::test_http_subscription_response": 0.08456367600001613, + "tests/aws/services/sns/test_sns.py::TestSNSSubscriptionHttp::test_multiple_subscriptions_http_endpoint": 1.732501916000274, + "tests/aws/services/sns/test_sns.py::TestSNSSubscriptionHttp::test_redrive_policy_http_subscription": 0.666631757000232, + "tests/aws/services/sns/test_sns.py::TestSNSSubscriptionHttp::test_subscribe_external_http_endpoint[False]": 1.6364068699995187, + "tests/aws/services/sns/test_sns.py::TestSNSSubscriptionHttp::test_subscribe_external_http_endpoint[True]": 1.648674561000007, + "tests/aws/services/sns/test_sns.py::TestSNSSubscriptionHttp::test_subscribe_external_http_endpoint_content_type[False]": 1.6144298719996186, + "tests/aws/services/sns/test_sns.py::TestSNSSubscriptionHttp::test_subscribe_external_http_endpoint_content_type[True]": 1.6232071059998816, + "tests/aws/services/sns/test_sns.py::TestSNSSubscriptionHttp::test_subscribe_external_http_endpoint_lambda_url_sig_validation": 2.1434537009999985, + "tests/aws/services/sns/test_sns.py::TestSNSSubscriptionLambda::test_publish_lambda_verify_signature[1]": 4.266658207999626, + "tests/aws/services/sns/test_sns.py::TestSNSSubscriptionLambda::test_publish_lambda_verify_signature[2]": 4.262278340000194, + "tests/aws/services/sns/test_sns.py::TestSNSSubscriptionLambda::test_python_lambda_subscribe_sns_topic": 4.240641885999594, + "tests/aws/services/sns/test_sns.py::TestSNSSubscriptionLambda::test_redrive_policy_lambda_subscription": 1.3589285960006237, + "tests/aws/services/sns/test_sns.py::TestSNSSubscriptionLambda::test_sns_topic_as_lambda_dead_letter_queue": 2.3963951619998625, + "tests/aws/services/sns/test_sns.py::TestSNSSubscriptionSES::test_email_sender": 2.1245875639997394, + "tests/aws/services/sns/test_sns.py::TestSNSSubscriptionSES::test_topic_email_subscription_confirmation": 0.06959648700012622, + "tests/aws/services/sns/test_sns.py::TestSNSSubscriptionSQS::test_attribute_raw_subscribe": 0.16244819099983943, + "tests/aws/services/sns/test_sns.py::TestSNSSubscriptionSQS::test_empty_or_wrong_message_attributes": 0.32577201300046, + "tests/aws/services/sns/test_sns.py::TestSNSSubscriptionSQS::test_message_attributes_not_missing": 0.2804674609997164, + "tests/aws/services/sns/test_sns.py::TestSNSSubscriptionSQS::test_message_attributes_prefixes": 0.19570549099989876, + "tests/aws/services/sns/test_sns.py::TestSNSSubscriptionSQS::test_message_structure_json_to_sqs": 0.22378459700030362, + "tests/aws/services/sns/test_sns.py::TestSNSSubscriptionSQS::test_publish_batch_exceptions": 0.0742154020003909, + "tests/aws/services/sns/test_sns.py::TestSNSSubscriptionSQS::test_publish_batch_messages_from_sns_to_sqs": 0.7074655850001363, + "tests/aws/services/sns/test_sns.py::TestSNSSubscriptionSQS::test_publish_batch_messages_without_topic": 0.03691314100024101, + "tests/aws/services/sns/test_sns.py::TestSNSSubscriptionSQS::test_publish_message_group_id": 0.1615735760001371, + "tests/aws/services/sns/test_sns.py::TestSNSSubscriptionSQS::test_publish_sqs_from_sns": 0.262594810000337, + "tests/aws/services/sns/test_sns.py::TestSNSSubscriptionSQS::test_publish_sqs_from_sns_with_xray_propagation": 0.14839567000080933, + "tests/aws/services/sns/test_sns.py::TestSNSSubscriptionSQS::test_publish_sqs_verify_signature[1]": 0.1569465030001993, + "tests/aws/services/sns/test_sns.py::TestSNSSubscriptionSQS::test_publish_sqs_verify_signature[2]": 0.15702895699951114, + "tests/aws/services/sns/test_sns.py::TestSNSSubscriptionSQS::test_publish_unicode_chars": 0.1486039480000727, + "tests/aws/services/sns/test_sns.py::TestSNSSubscriptionSQS::test_redrive_policy_sqs_queue_subscription[False]": 0.2169683899996926, + "tests/aws/services/sns/test_sns.py::TestSNSSubscriptionSQS::test_redrive_policy_sqs_queue_subscription[True]": 0.22076564599910853, + "tests/aws/services/sns/test_sns.py::TestSNSSubscriptionSQS::test_sqs_topic_subscription_confirmation": 0.08497214600038205, + "tests/aws/services/sns/test_sns.py::TestSNSSubscriptionSQS::test_subscribe_sqs_queue": 0.19036628600042604, + "tests/aws/services/sns/test_sns.py::TestSNSSubscriptionSQS::test_subscribe_to_sqs_with_queue_url": 0.05177121299993814, + "tests/aws/services/sns/test_sns.py::TestSNSSubscriptionSQS::test_subscription_after_failure_to_deliver": 1.636144542999773, + "tests/aws/services/sns/test_sns.py::TestSNSSubscriptionSQSFifo::test_fifo_topic_to_regular_sqs[False]": 0.27768155000012484, + "tests/aws/services/sns/test_sns.py::TestSNSSubscriptionSQSFifo::test_fifo_topic_to_regular_sqs[True]": 0.28622776999964117, + "tests/aws/services/sns/test_sns.py::TestSNSSubscriptionSQSFifo::test_message_to_fifo_sqs[False]": 1.2042731639999147, + "tests/aws/services/sns/test_sns.py::TestSNSSubscriptionSQSFifo::test_message_to_fifo_sqs[True]": 1.1893723949997366, + "tests/aws/services/sns/test_sns.py::TestSNSSubscriptionSQSFifo::test_message_to_fifo_sqs_ordering": 2.96489732200007, + "tests/aws/services/sns/test_sns.py::TestSNSSubscriptionSQSFifo::test_publish_batch_messages_from_fifo_topic_to_fifo_queue[False]": 3.6084733509997022, + "tests/aws/services/sns/test_sns.py::TestSNSSubscriptionSQSFifo::test_publish_batch_messages_from_fifo_topic_to_fifo_queue[True]": 3.6020166119997157, + "tests/aws/services/sns/test_sns.py::TestSNSSubscriptionSQSFifo::test_publish_fifo_messages_to_dlq[False]": 1.5699765829999706, + "tests/aws/services/sns/test_sns.py::TestSNSSubscriptionSQSFifo::test_publish_fifo_messages_to_dlq[True]": 1.5721326249999947, + "tests/aws/services/sns/test_sns.py::TestSNSSubscriptionSQSFifo::test_publish_to_fifo_topic_deduplication_on_topic_level": 1.688049924999632, + "tests/aws/services/sns/test_sns.py::TestSNSSubscriptionSQSFifo::test_publish_to_fifo_topic_to_sqs_queue_no_content_dedup[False]": 0.3023276919998352, + "tests/aws/services/sns/test_sns.py::TestSNSSubscriptionSQSFifo::test_publish_to_fifo_topic_to_sqs_queue_no_content_dedup[True]": 0.3034509569997681, + "tests/aws/services/sns/test_sns.py::TestSNSSubscriptionSQSFifo::test_publish_to_fifo_with_target_arn": 0.03807672499988257, + "tests/aws/services/sns/test_sns.py::TestSNSSubscriptionSQSFifo::test_validations_for_fifo": 0.24380152599951543, + "tests/aws/services/sns/test_sns.py::TestSNSTopicCrud::test_create_duplicate_topic_check_idempotency": 0.09146287800012942, + "tests/aws/services/sns/test_sns.py::TestSNSTopicCrud::test_create_duplicate_topic_with_more_tags": 0.04258755699947869, + "tests/aws/services/sns/test_sns.py::TestSNSTopicCrud::test_create_topic_after_delete_with_new_tags": 0.059196254999733355, + "tests/aws/services/sns/test_sns.py::TestSNSTopicCrud::test_create_topic_test_arn": 0.2823058799995124, + "tests/aws/services/sns/test_sns.py::TestSNSTopicCrud::test_create_topic_with_attributes": 0.2362524459999804, + "tests/aws/services/sns/test_sns.py::TestSNSTopicCrud::test_delete_topic_idempotency": 0.05525595000017347, + "tests/aws/services/sns/test_sns.py::TestSNSTopicCrud::test_tags": 0.0980973420000737, + "tests/aws/services/sns/test_sns.py::TestSNSTopicCrud::test_topic_delivery_policy_crud": 0.001294577000408026, + "tests/aws/services/sns/test_sns_filter_policy.py::TestSNSFilterPolicyAttributes::test_exists_filter_policy": 0.3457501230000162, + "tests/aws/services/sns/test_sns_filter_policy.py::TestSNSFilterPolicyAttributes::test_exists_filter_policy_attributes_array": 4.30117979500028, + "tests/aws/services/sns/test_sns_filter_policy.py::TestSNSFilterPolicyAttributes::test_filter_policy": 5.357053337000252, + "tests/aws/services/sns/test_sns_filter_policy.py::TestSNSFilterPolicyBody::test_filter_policy_empty_array_payload": 0.188670130999526, + "tests/aws/services/sns/test_sns_filter_policy.py::TestSNSFilterPolicyBody::test_filter_policy_for_batch": 3.407110845999796, + "tests/aws/services/sns/test_sns_filter_policy.py::TestSNSFilterPolicyBody::test_filter_policy_ip_address_condition": 0.3716640169996026, + "tests/aws/services/sns/test_sns_filter_policy.py::TestSNSFilterPolicyBody::test_filter_policy_large_complex_payload": 0.19213371199975882, + "tests/aws/services/sns/test_sns_filter_policy.py::TestSNSFilterPolicyBody::test_filter_policy_on_message_body[False]": 5.372784816000149, + "tests/aws/services/sns/test_sns_filter_policy.py::TestSNSFilterPolicyBody::test_filter_policy_on_message_body[True]": 5.370167467000101, + "tests/aws/services/sns/test_sns_filter_policy.py::TestSNSFilterPolicyBody::test_filter_policy_on_message_body_array_attributes": 0.6174587310001698, + "tests/aws/services/sns/test_sns_filter_policy.py::TestSNSFilterPolicyBody::test_filter_policy_on_message_body_array_of_object_attributes": 0.377198276999934, + "tests/aws/services/sns/test_sns_filter_policy.py::TestSNSFilterPolicyBody::test_filter_policy_on_message_body_dot_attribute": 5.648212536999836, + "tests/aws/services/sns/test_sns_filter_policy.py::TestSNSFilterPolicyBody::test_filter_policy_on_message_body_or_attribute": 0.8674322130000292, + "tests/aws/services/sns/test_sns_filter_policy.py::TestSNSFilterPolicyConditions::test_policy_complexity": 0.05695097899979373, + "tests/aws/services/sns/test_sns_filter_policy.py::TestSNSFilterPolicyConditions::test_policy_complexity_with_or": 0.06360075699967638, + "tests/aws/services/sns/test_sns_filter_policy.py::TestSNSFilterPolicyConditions::test_validate_policy": 0.11692719999973633, + "tests/aws/services/sns/test_sns_filter_policy.py::TestSNSFilterPolicyConditions::test_validate_policy_exists_operator": 0.1073459570002342, + "tests/aws/services/sns/test_sns_filter_policy.py::TestSNSFilterPolicyConditions::test_validate_policy_nested_anything_but_operator": 0.16035512499956894, + "tests/aws/services/sns/test_sns_filter_policy.py::TestSNSFilterPolicyConditions::test_validate_policy_numeric_operator": 0.22322914300002594, + "tests/aws/services/sns/test_sns_filter_policy.py::TestSNSFilterPolicyConditions::test_validate_policy_string_operators": 0.2376109740002903, + "tests/aws/services/sns/test_sns_filter_policy.py::TestSNSFilterPolicyCrud::test_set_subscription_filter_policy_scope": 0.13561585500019646, + "tests/aws/services/sns/test_sns_filter_policy.py::TestSNSFilterPolicyCrud::test_sub_filter_policy_nested_property": 0.12530587599985665, + "tests/aws/services/sns/test_sns_filter_policy.py::TestSNSFilterPolicyCrud::test_sub_filter_policy_nested_property_constraints": 0.18985079500043867, + "tests/aws/services/sqs/test_sqs.py::TestSQSMultiAccounts::test_cross_account_access[domain]": 0.10049642200056041, + "tests/aws/services/sqs/test_sqs.py::TestSQSMultiAccounts::test_cross_account_access[path]": 0.10343805299999076, + "tests/aws/services/sqs/test_sqs.py::TestSQSMultiAccounts::test_cross_account_access[standard]": 0.10812272099974507, + "tests/aws/services/sqs/test_sqs.py::TestSQSMultiAccounts::test_cross_account_get_queue_url[domain]": 0.03428158699989581, + "tests/aws/services/sqs/test_sqs.py::TestSQSMultiAccounts::test_cross_account_get_queue_url[path]": 0.032497113000772515, + "tests/aws/services/sqs/test_sqs.py::TestSQSMultiAccounts::test_cross_account_get_queue_url[standard]": 0.035996762000195304, + "tests/aws/services/sqs/test_sqs.py::TestSQSMultiAccounts::test_delete_queue_multi_account[sqs]": 0.09775940100007574, + "tests/aws/services/sqs/test_sqs.py::TestSQSMultiAccounts::test_delete_queue_multi_account[sqs_query]": 0.10041708900007507, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_approximate_number_of_messages_delayed[sqs]": 3.153632347999519, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_approximate_number_of_messages_delayed[sqs_query]": 3.139560939000603, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_approximate_number_of_messages_not_visible[sqs]": 6.25618009200025, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_approximate_number_of_messages_not_visible[sqs_query]": 6.260902344999977, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_aws_trace_header_propagation[sqs]": 0.10181982299991432, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_aws_trace_header_propagation[sqs_query]": 0.10339828700034559, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_batch_send_with_invalid_char_should_succeed[sqs]": 0.1423902120004641, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_batch_send_with_invalid_char_should_succeed[sqs_query]": 0.18304358999967008, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_change_message_visibility_after_visibility_timeout_expiration[sqs]": 2.103396603999954, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_change_message_visibility_after_visibility_timeout_expiration[sqs_query]": 2.1052091229994403, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_change_message_visibility_batch_with_too_large_batch[sqs]": 0.6600071549996755, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_change_message_visibility_batch_with_too_large_batch[sqs_query]": 0.6615540099996906, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_change_message_visibility_not_permanent[sqs]": 0.11364824100019177, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_change_message_visibility_not_permanent[sqs_query]": 0.11191602300004888, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_change_visibility_on_deleted_message_raises_invalid_parameter_value[sqs]": 0.10148781700036125, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_change_visibility_on_deleted_message_raises_invalid_parameter_value[sqs_query]": 0.10294988099985858, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_create_and_send_to_fifo_queue[sqs]": 0.07273036499964292, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_create_and_send_to_fifo_queue[sqs_query]": 0.074890313999731, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_create_and_update_queue_attributes[sqs]": 0.08626171299920316, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_create_and_update_queue_attributes[sqs_query]": 0.08445831800008818, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_create_fifo_queue_with_different_attributes_raises_error[sqs]": 0.12333916099942144, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_create_fifo_queue_with_different_attributes_raises_error[sqs_query]": 0.12400173000014547, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_create_fifo_queue_with_same_attributes_is_idempotent": 0.04180613299968172, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_create_queue_after_internal_attributes_changes_works[sqs]": 0.09521035599982497, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_create_queue_after_internal_attributes_changes_works[sqs_query]": 0.09445160899986149, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_create_queue_after_modified_attributes[sqs]": 0.0012733220000882284, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_create_queue_after_modified_attributes[sqs_query]": 0.001234280000517174, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_create_queue_after_send[sqs]": 0.12481575400033762, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_create_queue_after_send[sqs_query]": 0.1263576279998233, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_create_queue_and_get_attributes[sqs]": 0.03761760699990191, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_create_queue_and_get_attributes[sqs_query]": 0.03952227300032973, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_create_queue_recently_deleted[sqs]": 0.04905982599984782, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_create_queue_recently_deleted[sqs_query]": 0.04786149399978967, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_create_queue_recently_deleted_cache[sqs]": 1.5646157940000194, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_create_queue_recently_deleted_cache[sqs_query]": 1.5640715179993094, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_create_queue_recently_deleted_can_be_disabled[sqs]": 0.047663233000093896, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_create_queue_recently_deleted_can_be_disabled[sqs_query]": 0.048129074000371475, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_create_queue_with_default_arguments_works_with_modified_attributes[sqs]": 0.0012503610000749177, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_create_queue_with_default_arguments_works_with_modified_attributes[sqs_query]": 0.0012596280002981075, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_create_queue_with_default_attributes_is_idempotent": 0.04219275600053152, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_create_queue_with_different_attributes_raises_exception[sqs]": 0.18869519100053367, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_create_queue_with_different_attributes_raises_exception[sqs_query]": 0.188720579999881, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_create_queue_with_same_attributes_is_idempotent": 0.03929368399985833, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_create_queue_with_tags[sqs]": 0.03237712999998621, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_create_queue_with_tags[sqs_query]": 0.031055229999765288, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_create_queue_without_attributes_is_idempotent": 0.03947538399961559, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_create_standard_queue_with_fifo_attribute_raises_error[sqs]": 0.07674356600000465, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_create_standard_queue_with_fifo_attribute_raises_error[sqs_query]": 0.07738451499972143, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_dead_letter_queue_chain[sqs]": 0.0012798050001947558, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_dead_letter_queue_chain[sqs_query]": 0.0011831239999082754, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_dead_letter_queue_config": 0.043210893999912514, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_dead_letter_queue_execution_lambda_mapping_preserves_id[sqs]": 0.0013766450001639896, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_dead_letter_queue_execution_lambda_mapping_preserves_id[sqs_query]": 0.001272791000246798, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_dead_letter_queue_list_sources[sqs]": 0.06819904899975882, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_dead_letter_queue_list_sources[sqs_query]": 0.0638062329994682, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_dead_letter_queue_max_receive_count[sqs]": 0.13685380899960364, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_dead_letter_queue_max_receive_count[sqs_query]": 0.1406112720001147, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_dead_letter_queue_message_attributes": 0.7790068139997857, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_dead_letter_queue_with_fifo_and_content_based_deduplication[sqs]": 0.18640956399985953, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_dead_letter_queue_with_fifo_and_content_based_deduplication[sqs_query]": 0.18998611400047594, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_deduplication_interval[sqs]": 0.0013708650003536604, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_deduplication_interval[sqs_query]": 0.0012137600001551618, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_delete_after_visibility_timeout[sqs]": 1.1235310360002586, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_delete_after_visibility_timeout[sqs_query]": 1.12840464699957, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_delete_message_batch_from_lambda[sqs]": 0.0013228150000941241, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_delete_message_batch_from_lambda[sqs_query]": 0.001222759000484075, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_delete_message_batch_invalid_msg_id[sqs-]": 0.19178459199974895, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_delete_message_batch_invalid_msg_id[sqs-invalid:id]": 0.06714789700026813, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_delete_message_batch_invalid_msg_id[sqs-testLongIdtestLongIdtestLongIdtestLongIdtestLongIdtestLongIdtestLongIdtestLongIdtestLongIdtestLongId]": 0.06700423600022987, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_delete_message_batch_invalid_msg_id[sqs_query-]": 0.06861306500013598, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_delete_message_batch_invalid_msg_id[sqs_query-invalid:id]": 0.06675896400020065, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_delete_message_batch_invalid_msg_id[sqs_query-testLongIdtestLongIdtestLongIdtestLongIdtestLongIdtestLongIdtestLongIdtestLongIdtestLongIdtestLongId]": 0.07032401800051957, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_delete_message_batch_with_too_large_batch[sqs]": 0.648133009999583, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_delete_message_batch_with_too_large_batch[sqs_query]": 0.6689296089998606, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_delete_message_deletes_with_change_visibility_timeout[sqs]": 0.14496617200029505, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_delete_message_deletes_with_change_visibility_timeout[sqs_query]": 0.14406387600001835, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_delete_message_with_deleted_receipt_handle[sqs]": 0.11965512100005071, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_delete_message_with_deleted_receipt_handle[sqs_query]": 0.12075262000053044, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_delete_message_with_illegal_receipt_handle[sqs]": 0.03561284399984288, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_delete_message_with_illegal_receipt_handle[sqs_query]": 0.03311309899982007, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_disallow_queue_name_with_slashes": 0.0013219229999776871, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_extend_message_visibility_timeout_set_in_queue[sqs]": 6.189328901999943, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_extend_message_visibility_timeout_set_in_queue[sqs_query]": 6.999780781000027, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_external_endpoint[sqs]": 0.20072038500074996, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_external_endpoint[sqs_query]": 0.0731942950001212, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_external_host_via_header_complete_message_lifecycle": 0.09929605400020591, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_external_hostname_via_host_header": 0.03352713699950982, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_fair_queue_with_message_group_id[sqs]": 0.11091738400000395, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_fair_queue_with_message_group_id[sqs_query]": 0.11552896600005624, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_fifo_approx_number_of_messages[sqs]": 0.2770632559995647, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_fifo_approx_number_of_messages[sqs_query]": 0.29076301099939883, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_fifo_approximate_number_of_messages_not_visible[sqs]": 5.23756682200019, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_fifo_approximate_number_of_messages_not_visible[sqs_query]": 6.292369363000034, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_fifo_change_to_high_throughput_after_creation[sqs]": 0.34713211799999044, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_fifo_change_to_high_throughput_after_creation[sqs_query]": 0.35337055000036344, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_fifo_change_to_regular_throughput_after_creation[sqs]": 0.24829099799990217, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_fifo_change_to_regular_throughput_after_creation[sqs_query]": 0.24655406100009714, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_fifo_content_based_message_deduplication_arrives_once[sqs]": 1.0999195519993918, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_fifo_content_based_message_deduplication_arrives_once[sqs_query]": 1.1404099500000484, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_fifo_deduplication_arrives_once_after_delete[sqs-False]": 1.1563005979996888, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_fifo_deduplication_arrives_once_after_delete[sqs-True]": 1.155783098000029, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_fifo_deduplication_arrives_once_after_delete[sqs_query-False]": 1.1550735129994791, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_fifo_deduplication_arrives_once_after_delete[sqs_query-True]": 1.155690826999944, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_fifo_deduplication_not_on_message_group_id[sqs-False]": 1.1473802900004557, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_fifo_deduplication_not_on_message_group_id[sqs-True]": 1.139292265000222, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_fifo_deduplication_not_on_message_group_id[sqs_query-False]": 1.1495068740000534, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_fifo_deduplication_not_on_message_group_id[sqs_query-True]": 1.138506810000763, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_fifo_delete_after_visibility_timeout[sqs]": 1.1626400260001901, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_fifo_delete_after_visibility_timeout[sqs_query]": 1.1684312290003618, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_fifo_delete_message_with_expired_receipt_handle[sqs]": 0.00130406900007074, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_fifo_delete_message_with_expired_receipt_handle[sqs_query]": 0.0012183799999547773, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_fifo_empty_message_groups_added_back_to_queue[sqs]": 0.18811560899985125, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_fifo_empty_message_groups_added_back_to_queue[sqs_query]": 0.19097158499971556, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_fifo_high_throughput_ordering[sqs]": 0.16637581400027557, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_fifo_high_throughput_ordering[sqs_query]": 0.1913700790000803, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_fifo_message_attributes[sqs]": 0.1577526529995339, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_fifo_message_attributes[sqs_query]": 0.158854625999993, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_fifo_message_group_visibility": 2.131139436000012, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_fifo_message_group_visibility_after_change_message_visibility[sqs]": 2.1414605550003216, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_fifo_message_group_visibility_after_change_message_visibility[sqs_query]": 2.1435724039997694, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_fifo_message_group_visibility_after_delete[sqs]": 0.3162583939997603, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_fifo_message_group_visibility_after_delete[sqs_query]": 0.29838431200050763, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_fifo_message_group_visibility_after_partial_delete[sqs]": 0.2626342650000879, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_fifo_message_group_visibility_after_partial_delete[sqs_query]": 0.332348266000281, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_fifo_message_group_visibility_after_terminate_visibility_timeout[sqs]": 0.1571287160004431, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_fifo_message_group_visibility_after_terminate_visibility_timeout[sqs_query]": 0.1497240700000475, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_fifo_messages_in_order_after_timeout[sqs]": 2.11512474500023, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_fifo_messages_in_order_after_timeout[sqs_query]": 2.117957320000187, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_fifo_queue_requires_suffix": 0.01869052499978352, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_fifo_queue_send_message_with_delay_on_queue_works[sqs]": 4.117708233000485, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_fifo_queue_send_message_with_delay_on_queue_works[sqs_query]": 4.127097821000007, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_fifo_queue_send_message_with_delay_seconds_fails[sqs]": 0.14256279200026256, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_fifo_queue_send_message_with_delay_seconds_fails[sqs_query]": 0.14419401899976947, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_fifo_queue_send_message_with_zero_delay_defaults_to_queue_delay[sqs]": 4.1206942059998255, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_fifo_queue_send_message_with_zero_delay_defaults_to_queue_delay[sqs_query]": 4.11692149000055, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_fifo_queue_send_multiple_messages_multiple_single_receives[sqs]": 0.26361298799974975, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_fifo_queue_send_multiple_messages_multiple_single_receives[sqs_query]": 0.27310130600017146, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_fifo_receive_message_group_id_ordering[sqs]": 0.14773580599967318, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_fifo_receive_message_group_id_ordering[sqs_query]": 0.15416444899983617, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_fifo_receive_message_visibility_timeout_shared_in_group[sqs]": 2.211526860000049, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_fifo_receive_message_visibility_timeout_shared_in_group[sqs_query]": 2.2017023070002324, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_fifo_receive_message_with_zero_visibility_timeout[sqs]": 0.18827871300027255, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_fifo_receive_message_with_zero_visibility_timeout[sqs_query]": 0.206288276000123, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_fifo_sequence_number_increases[sqs]": 0.10193211400019209, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_fifo_sequence_number_increases[sqs_query]": 0.11163119400043797, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_fifo_set_content_based_deduplication_strategy[sqs]": 0.08444457499945202, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_fifo_set_content_based_deduplication_strategy[sqs_query]": 0.08534739299966532, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_get_list_queues_with_query_auth": 0.023060615999838774, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_get_queue_url_contains_localstack_host[sqs]": 0.03278106399920944, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_get_queue_url_contains_localstack_host[sqs_query]": 0.04164392400025463, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_get_queue_url_multi_region[domain]": 0.056873033000101714, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_get_queue_url_multi_region[path]": 0.05586032900009741, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_get_queue_url_multi_region[standard]": 0.05558132900023338, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_get_specific_queue_attribute_response[sqs]": 0.06125742599988371, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_get_specific_queue_attribute_response[sqs_query]": 0.06280585900049118, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_inflight_message_requeue": 4.601648954999746, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_invalid_batch_id[sqs]": 0.1410071649997917, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_invalid_batch_id[sqs_query]": 0.15878042799977266, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_invalid_dead_letter_arn_rejected_before_lookup": 0.001326271999914752, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_invalid_receipt_handle_should_return_error_message[sqs]": 0.03531152999948972, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_invalid_receipt_handle_should_return_error_message[sqs_query]": 0.03424329100016621, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_invalid_string_attributes_cause_invalid_parameter_value_error[sqs]": 0.03493167899932814, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_invalid_string_attributes_cause_invalid_parameter_value_error[sqs_query]": 0.034451651999916066, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_list_queue_tags[sqs]": 0.03916435100018134, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_list_queue_tags[sqs_query]": 0.03983079799991174, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_list_queues": 0.10899360199982766, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_list_queues_multi_region_with_endpoint_strategy_domain": 0.06909792200031006, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_list_queues_multi_region_with_endpoint_strategy_standard": 0.06998386900067999, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_list_queues_multi_region_without_endpoint_strategy": 0.07816677600021649, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_list_queues_pagination": 0.3186461280001822, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_marker_serialization_json_protocol[\"{\\\\\"foo\\\\\": \\\\\"ba\\\\rr\\\\\"}\"]": 0.08674679599971569, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_marker_serialization_json_protocol[{\"foo\": \"ba\\rr\", \"foo2\": \"ba"r"\"}]": 0.08708712199995716, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_message_deduplication_id_invalid[empty]": 0.06634185700022499, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_message_deduplication_id_invalid[spaces]": 0.06959543400034818, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_message_deduplication_id_invalid[too_long]": 0.06517404199985322, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_message_deduplication_id_success": 0.05452824500025599, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_message_retention": 3.083256314999744, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_message_retention_fifo": 3.0810836329997073, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_message_retention_with_inflight": 5.624934372000098, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_message_system_attribute_names_with_attribute_names[sqs]": 0.1272934889998396, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_message_system_attribute_names_with_attribute_names[sqs_query]": 0.12491753800031802, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_message_with_attributes_should_be_enqueued[sqs]": 0.0693878870001754, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_message_with_attributes_should_be_enqueued[sqs_query]": 0.07659332200046265, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_message_with_carriage_return[sqs]": 0.07337673100028042, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_message_with_carriage_return[sqs_query]": 0.07565964800051006, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_non_existent_queue": 0.1635939990001134, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_posting_to_fifo_requires_deduplicationid_group_id[sqs]": 0.23862482800086582, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_posting_to_fifo_requires_deduplicationid_group_id[sqs_query]": 0.23575156099968808, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_posting_to_queue_via_queue_name[sqs]": 0.053543034000085754, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_posting_to_queue_via_queue_name[sqs_query]": 0.05567006799992669, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_publish_get_delete_message[sqs]": 0.1027016990001357, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_publish_get_delete_message[sqs_query]": 0.10493010100026368, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_publish_get_delete_message_batch[sqs]": 0.19760692799991375, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_publish_get_delete_message_batch[sqs_query]": 0.24620958399964366, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_purge_queue[sqs]": 1.2413372710002477, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_purge_queue[sqs_query]": 1.2462030489996323, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_purge_queue_clears_fifo_deduplication_cache[sqs]": 0.10154147999992347, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_purge_queue_clears_fifo_deduplication_cache[sqs_query]": 0.10409943299964652, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_purge_queue_deletes_delayed_messages[sqs]": 3.169302904000233, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_purge_queue_deletes_delayed_messages[sqs_query]": 3.1968623600000683, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_purge_queue_deletes_inflight_messages[sqs]": 4.254872518999491, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_purge_queue_deletes_inflight_messages[sqs_query]": 4.312629573000322, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_queue_list_nonexistent_tags[sqs]": 0.031208538000555563, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_queue_list_nonexistent_tags[sqs_query]": 0.03131818100064265, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_receive_after_visibility_timeout[sqs]": 1.644043079000312, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_receive_after_visibility_timeout[sqs_query]": 1.9991240360004667, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_receive_empty_queue[sqs]": 1.0925791180002307, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_receive_empty_queue[sqs_query]": 1.0931653999991795, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_receive_message_attribute_names_filters[sqs]": 0.22550998899987462, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_receive_message_attribute_names_filters[sqs_query]": 0.23038279000047623, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_receive_message_attributes_timestamp_types[sqs]": 0.0697768800000631, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_receive_message_attributes_timestamp_types[sqs_query]": 0.06897148999996716, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_receive_message_message_attribute_names_filters[sqs]": 0.31088079200026186, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_receive_message_message_attribute_names_filters[sqs_query]": 0.2897951340000873, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_receive_message_message_system_attribute_names_filters[sqs]": 0.1611026519999541, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_receive_message_message_system_attribute_names_filters[sqs_query]": 0.1648235650004608, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_receive_message_wait_time_seconds_and_max_number_of_messages_does_not_block[sqs]": 0.10193476699987514, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_receive_message_wait_time_seconds_and_max_number_of_messages_does_not_block[sqs_query]": 0.10276156200052355, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_receive_message_with_visibility_timeout_updates_timeout[sqs]": 0.10088348499994026, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_receive_message_with_visibility_timeout_updates_timeout[sqs_query]": 0.10588759800020853, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_receive_terminate_visibility_timeout[sqs]": 0.10925697399943601, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_receive_terminate_visibility_timeout[sqs_query]": 0.10519987099996797, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_redrive_policy_attribute_validity[sqs]": 0.0012296199997763324, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_redrive_policy_attribute_validity[sqs_query]": 0.0011961670002165192, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_remove_message_with_old_receipt_handle[sqs]": 2.093612412999846, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_remove_message_with_old_receipt_handle[sqs_query]": 2.0894138689996, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_send_batch_message_size": 0.2031209729998409, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_send_batch_missing_deduplication_id_for_fifo_queue[sqs]": 0.14097454700004164, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_send_batch_missing_deduplication_id_for_fifo_queue[sqs_query]": 0.12441417099944374, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_send_batch_missing_message_group_id_for_fifo_queue[sqs]": 0.12818788200002018, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_send_batch_missing_message_group_id_for_fifo_queue[sqs_query]": 0.12309957399929772, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_send_batch_receive_multiple[sqs]": 0.1115640389998589, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_send_batch_receive_multiple[sqs_query]": 0.11734971400028371, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_send_delay_and_wait_time[sqs]": 1.7281163570005447, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_send_delay_and_wait_time[sqs_query]": 2.0005093529998703, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_send_empty_message[sqs]": 0.12300892700068289, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_send_empty_message[sqs_query]": 0.1280528869997397, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_send_message_batch[sqs]": 0.12097204199972111, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_send_message_batch[sqs_query]": 0.12744143500049177, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_send_message_batch_with_empty_list[sqs]": 0.03154163400040488, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_send_message_batch_with_empty_list[sqs_query]": 0.031107669999983045, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_send_message_batch_with_oversized_contents[sqs]": 0.14269334499931574, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_send_message_batch_with_oversized_contents[sqs_query]": 0.15955116100030864, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_send_message_batch_with_oversized_contents_with_updated_maximum_message_size[sqs]": 1.485583153999869, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_send_message_batch_with_oversized_contents_with_updated_maximum_message_size[sqs_query]": 0.11683631100049752, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_send_message_to_standard_queue_with_invalid_message_group_id[empty]": 0.06616047699981209, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_send_message_to_standard_queue_with_invalid_message_group_id[spaces]": 0.06520347599962406, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_send_message_to_standard_queue_with_invalid_message_group_id[too_long]": 0.06683580099979736, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_send_message_with_attributes[sqs]": 0.0718099939995227, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_send_message_with_attributes[sqs_query]": 0.07385412600069685, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_send_message_with_binary_attributes[sqs]": 0.10585860600031083, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_send_message_with_binary_attributes[sqs_query]": 0.10517945800029338, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_send_message_with_delay_0_works_for_fifo[sqs]": 0.06754333399976531, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_send_message_with_delay_0_works_for_fifo[sqs_query]": 0.07047336600044218, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_send_message_with_empty_string_attribute[sqs]": 0.12463757700061251, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_send_message_with_empty_string_attribute[sqs_query]": 0.13014763500041227, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_send_message_with_invalid_fifo_parameters[sqs]": 0.0012775000004694448, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_send_message_with_invalid_fifo_parameters[sqs_query]": 0.0012247019999449549, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_send_message_with_invalid_payload_characters[sqs]": 0.03571400999999241, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_send_message_with_invalid_payload_characters[sqs_query]": 0.035914516000048025, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_send_message_with_invalid_string_attributes[sqs]": 0.1541050739997445, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_send_message_with_invalid_string_attributes[sqs_query]": 0.15587192599969057, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_send_message_with_updated_maximum_message_size[sqs]": 0.16039722400000755, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_send_message_with_updated_maximum_message_size[sqs_query]": 0.15865042299992638, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_send_oversized_message[sqs]": 0.14089012900012676, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_send_oversized_message[sqs_query]": 0.15548399899989818, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_send_receive_max_number_of_messages[sqs]": 0.1517126260000623, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_send_receive_max_number_of_messages[sqs_query]": 0.1496052449997478, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_send_receive_message[sqs]": 0.06929818500020701, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_send_receive_message[sqs_query]": 0.072508020999976, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_send_receive_message_encoded_content[sqs]": 0.06913107100035631, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_send_receive_message_encoded_content[sqs_query]": 0.06973786700018536, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_send_receive_message_multiple_queues": 0.10032514199974685, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_send_receive_wait_time_seconds[sqs]": 0.22326395799973398, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_send_receive_wait_time_seconds[sqs_query]": 0.22534987200015166, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_sent_message_retains_attributes_after_receive[sqs]": 0.08921915099972466, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_sent_message_retains_attributes_after_receive[sqs_query]": 0.0904060190000564, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_sequence_number[sqs]": 0.09650424900019061, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_sequence_number[sqs_query]": 0.09526961099982145, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_set_empty_queue_policy[sqs]": 0.07252384899993558, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_set_empty_queue_policy[sqs_query]": 0.07584177499984435, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_set_empty_redrive_policy[sqs]": 0.07717880799964405, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_set_empty_redrive_policy[sqs_query]": 0.08030330200017488, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_set_queue_policy[sqs]": 0.0520587440005329, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_set_queue_policy[sqs_query]": 0.05129745200019897, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_set_unsupported_attribute_fifo[sqs]": 0.2178601090004122, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_set_unsupported_attribute_fifo[sqs_query]": 0.21859218600047825, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_set_unsupported_attribute_standard[sqs]": 0.1948529379997126, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_set_unsupported_attribute_standard[sqs_query]": 0.19947326100009377, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_sqs_fifo_message_group_scope_no_throughput_setting[sqs]": 0.16500942399989071, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_sqs_fifo_message_group_scope_no_throughput_setting[sqs_query]": 0.18200624700057233, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_sqs_fifo_same_dedup_id_different_message_groups[sqs]": 0.1679102459997921, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_sqs_fifo_same_dedup_id_different_message_groups[sqs_query]": 0.16596840499960308, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_sqs_permission_lifecycle[sqs]": 0.24300796200031982, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_sqs_permission_lifecycle[sqs_query]": 0.2445847680000952, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_sse_kms_and_sqs_are_mutually_exclusive[sqs]": 0.0013277819998620544, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_sse_kms_and_sqs_are_mutually_exclusive[sqs_query]": 0.0012621300002138014, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_sse_queue_attributes[sqs]": 0.13409459300009985, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_sse_queue_attributes[sqs_query]": 0.11681415799966999, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_standard_queue_cannot_have_fifo_suffix": 0.016181481000330677, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_successive_purge_calls_fail[sqs]": 0.13845254500029114, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_successive_purge_calls_fail[sqs_query]": 0.13553655900022932, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_system_attributes_have_no_effect_on_attr_md5[sqs]": 0.0904525509999985, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_system_attributes_have_no_effect_on_attr_md5[sqs_query]": 0.10283761600021535, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_tag_queue_overwrites_existing_tag[sqs]": 0.04456064699934359, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_tag_queue_overwrites_existing_tag[sqs_query]": 0.045628764999946725, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_tag_untag_queue[sqs]": 0.1051446329997816, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_tag_untag_queue[sqs_query]": 0.10784507999960624, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_tags_case_sensitive[sqs]": 0.03965188400070474, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_tags_case_sensitive[sqs_query]": 0.03942758299990601, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_terminate_visibility_timeout_after_receive[sqs]": 0.11068071499994403, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_terminate_visibility_timeout_after_receive[sqs_query]": 0.11317499799997677, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_too_many_entries_in_batch_request[sqs]": 0.13450034099969344, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_too_many_entries_in_batch_request[sqs_query]": 0.139476160999493, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_untag_queue_ignores_non_existing_tag[sqs]": 0.04694319599957453, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_untag_queue_ignores_non_existing_tag[sqs_query]": 0.0511181150000084, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_wait_time_seconds_queue_attribute_waits_correctly[sqs]": 1.0667736389996207, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_wait_time_seconds_queue_attribute_waits_correctly[sqs_query]": 1.0672898810003062, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_wait_time_seconds_waits_correctly[sqs]": 1.0789726599996357, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_wait_time_seconds_waits_correctly[sqs_query]": 1.0702264740002647, + "tests/aws/services/sqs/test_sqs.py::TestSqsQueryApi::test_endpoint_strategy_with_multi_region[domain]": 0.1357706059998236, + "tests/aws/services/sqs/test_sqs.py::TestSqsQueryApi::test_endpoint_strategy_with_multi_region[off]": 0.13112367900021127, + "tests/aws/services/sqs/test_sqs.py::TestSqsQueryApi::test_endpoint_strategy_with_multi_region[path]": 0.1349605110003722, + "tests/aws/services/sqs/test_sqs.py::TestSqsQueryApi::test_endpoint_strategy_with_multi_region[standard]": 0.1917628229998627, + "tests/aws/services/sqs/test_sqs.py::TestSqsQueryApi::test_get_create_queue_fails": 0.033321869999781484, + "tests/aws/services/sqs/test_sqs.py::TestSqsQueryApi::test_get_delete_queue[domain]": 0.05679991100078041, + "tests/aws/services/sqs/test_sqs.py::TestSqsQueryApi::test_get_delete_queue[path]": 0.05683004499951494, + "tests/aws/services/sqs/test_sqs.py::TestSqsQueryApi::test_get_delete_queue[standard]": 0.05375360600055501, + "tests/aws/services/sqs/test_sqs.py::TestSqsQueryApi::test_get_list_queues_fails": 0.03384233299993866, + "tests/aws/services/sqs/test_sqs.py::TestSqsQueryApi::test_get_list_queues_fails_json_format": 0.0015484040000046662, + "tests/aws/services/sqs/test_sqs.py::TestSqsQueryApi::test_get_on_deleted_queue_fails[sqs]": 0.05725436000011541, + "tests/aws/services/sqs/test_sqs.py::TestSqsQueryApi::test_get_on_deleted_queue_fails[sqs_query]": 0.0582559110002876, + "tests/aws/services/sqs/test_sqs.py::TestSqsQueryApi::test_get_queue_attributes_all": 0.06086819399979504, + "tests/aws/services/sqs/test_sqs.py::TestSqsQueryApi::test_get_queue_attributes_json_format": 0.0012619689996427041, + "tests/aws/services/sqs/test_sqs.py::TestSqsQueryApi::test_get_queue_attributes_of_fifo_queue": 0.04905103499959296, + "tests/aws/services/sqs/test_sqs.py::TestSqsQueryApi::test_get_queue_attributes_with_invalid_arg_returns_error": 0.04697998199981157, + "tests/aws/services/sqs/test_sqs.py::TestSqsQueryApi::test_get_queue_attributes_with_query_args": 0.04903073699961169, + "tests/aws/services/sqs/test_sqs.py::TestSqsQueryApi::test_get_queue_attributes_works_without_authparams[domain]": 0.049267259999851376, + "tests/aws/services/sqs/test_sqs.py::TestSqsQueryApi::test_get_queue_attributes_works_without_authparams[path]": 0.04740159000039057, + "tests/aws/services/sqs/test_sqs.py::TestSqsQueryApi::test_get_queue_attributes_works_without_authparams[standard]": 0.04987064699980692, + "tests/aws/services/sqs/test_sqs.py::TestSqsQueryApi::test_get_queue_url_work_for_different_queue[domain]": 0.061671164999552275, + "tests/aws/services/sqs/test_sqs.py::TestSqsQueryApi::test_get_queue_url_work_for_different_queue[path]": 0.060371527000370406, + "tests/aws/services/sqs/test_sqs.py::TestSqsQueryApi::test_get_queue_url_work_for_different_queue[standard]": 0.05892663500026174, + "tests/aws/services/sqs/test_sqs.py::TestSqsQueryApi::test_get_queue_url_works_for_same_queue[domain]": 0.04473431599944888, + "tests/aws/services/sqs/test_sqs.py::TestSqsQueryApi::test_get_queue_url_works_for_same_queue[path]": 0.04253435299960984, + "tests/aws/services/sqs/test_sqs.py::TestSqsQueryApi::test_get_queue_url_works_for_same_queue[standard]": 0.04293925899992246, + "tests/aws/services/sqs/test_sqs.py::TestSqsQueryApi::test_get_send_and_receive_messages": 0.1277562039995246, + "tests/aws/services/sqs/test_sqs.py::TestSqsQueryApi::test_get_without_query_json_format_returns_returns_xml": 0.03343292099998507, + "tests/aws/services/sqs/test_sqs.py::TestSqsQueryApi::test_get_without_query_returns_unknown_operation": 0.034057365000535356, + "tests/aws/services/sqs/test_sqs.py::TestSqsQueryApi::test_invalid_action_raises_exception": 0.04014072600057261, + "tests/aws/services/sqs/test_sqs.py::TestSqsQueryApi::test_overwrite_queue_url_in_params": 0.05718692300069961, + "tests/aws/services/sqs/test_sqs.py::TestSqsQueryApi::test_queue_url_format_path_strategy": 0.02453443399963362, + "tests/aws/services/sqs/test_sqs.py::TestSqsQueryApi::test_send_message_via_queue_url_with_json_protocol": 1.087111148000531, + "tests/aws/services/sqs/test_sqs.py::TestSqsQueryApi::test_valid_action_with_missing_parameter_raises_exception": 0.03583193500026027, + "tests/aws/services/sqs/test_sqs_developer_api.py::TestSqsDeveloperApi::test_fifo_list_messages_as_botocore_endpoint_url[json-domain]": 0.1097651790000782, + "tests/aws/services/sqs/test_sqs_developer_api.py::TestSqsDeveloperApi::test_fifo_list_messages_as_botocore_endpoint_url[json-path]": 0.11146125799950823, + "tests/aws/services/sqs/test_sqs_developer_api.py::TestSqsDeveloperApi::test_fifo_list_messages_as_botocore_endpoint_url[json-standard]": 0.11145034599985593, + "tests/aws/services/sqs/test_sqs_developer_api.py::TestSqsDeveloperApi::test_fifo_list_messages_as_botocore_endpoint_url[query-domain]": 0.11159369300003164, + "tests/aws/services/sqs/test_sqs_developer_api.py::TestSqsDeveloperApi::test_fifo_list_messages_as_botocore_endpoint_url[query-path]": 0.11324684300006993, + "tests/aws/services/sqs/test_sqs_developer_api.py::TestSqsDeveloperApi::test_fifo_list_messages_as_botocore_endpoint_url[query-standard]": 0.11648561899983179, + "tests/aws/services/sqs/test_sqs_developer_api.py::TestSqsDeveloperApi::test_fifo_list_messages_with_invisible_messages[domain]": 0.1669657010006631, + "tests/aws/services/sqs/test_sqs_developer_api.py::TestSqsDeveloperApi::test_fifo_list_messages_with_invisible_messages[path]": 0.16340134300025966, + "tests/aws/services/sqs/test_sqs_developer_api.py::TestSqsDeveloperApi::test_fifo_list_messages_with_invisible_messages[standard]": 0.1623430129998269, + "tests/aws/services/sqs/test_sqs_developer_api.py::TestSqsDeveloperApi::test_list_messages_as_botocore_endpoint_url[json-domain]": 0.08249273699993864, + "tests/aws/services/sqs/test_sqs_developer_api.py::TestSqsDeveloperApi::test_list_messages_as_botocore_endpoint_url[json-path]": 0.0850710060003621, + "tests/aws/services/sqs/test_sqs_developer_api.py::TestSqsDeveloperApi::test_list_messages_as_botocore_endpoint_url[json-standard]": 0.09328979800011439, + "tests/aws/services/sqs/test_sqs_developer_api.py::TestSqsDeveloperApi::test_list_messages_as_botocore_endpoint_url[query-domain]": 0.08467084599988084, + "tests/aws/services/sqs/test_sqs_developer_api.py::TestSqsDeveloperApi::test_list_messages_as_botocore_endpoint_url[query-path]": 0.08494456000016726, + "tests/aws/services/sqs/test_sqs_developer_api.py::TestSqsDeveloperApi::test_list_messages_as_botocore_endpoint_url[query-standard]": 0.09140686200044001, + "tests/aws/services/sqs/test_sqs_developer_api.py::TestSqsDeveloperApi::test_list_messages_as_json[domain]": 0.08335970999996789, + "tests/aws/services/sqs/test_sqs_developer_api.py::TestSqsDeveloperApi::test_list_messages_as_json[path]": 0.08517717599988828, + "tests/aws/services/sqs/test_sqs_developer_api.py::TestSqsDeveloperApi::test_list_messages_as_json[standard]": 0.08535895300019547, + "tests/aws/services/sqs/test_sqs_developer_api.py::TestSqsDeveloperApi::test_list_messages_has_no_side_effects[domain]": 0.10879557099997328, + "tests/aws/services/sqs/test_sqs_developer_api.py::TestSqsDeveloperApi::test_list_messages_has_no_side_effects[path]": 0.10569760099951964, + "tests/aws/services/sqs/test_sqs_developer_api.py::TestSqsDeveloperApi::test_list_messages_has_no_side_effects[standard]": 0.11174326600030327, + "tests/aws/services/sqs/test_sqs_developer_api.py::TestSqsDeveloperApi::test_list_messages_with_delayed_messages[domain]": 0.1166038779997507, + "tests/aws/services/sqs/test_sqs_developer_api.py::TestSqsDeveloperApi::test_list_messages_with_delayed_messages[path]": 0.116450602000441, + "tests/aws/services/sqs/test_sqs_developer_api.py::TestSqsDeveloperApi::test_list_messages_with_delayed_messages[standard]": 0.11907575900022493, + "tests/aws/services/sqs/test_sqs_developer_api.py::TestSqsDeveloperApi::test_list_messages_with_invalid_action_raises_error[json-domain]": 0.03126542400013932, + "tests/aws/services/sqs/test_sqs_developer_api.py::TestSqsDeveloperApi::test_list_messages_with_invalid_action_raises_error[json-path]": 0.029977559000144538, + "tests/aws/services/sqs/test_sqs_developer_api.py::TestSqsDeveloperApi::test_list_messages_with_invalid_action_raises_error[json-standard]": 0.033395923000171024, + "tests/aws/services/sqs/test_sqs_developer_api.py::TestSqsDeveloperApi::test_list_messages_with_invalid_action_raises_error[query-domain]": 0.030354399000316334, + "tests/aws/services/sqs/test_sqs_developer_api.py::TestSqsDeveloperApi::test_list_messages_with_invalid_action_raises_error[query-path]": 0.030636946000413445, + "tests/aws/services/sqs/test_sqs_developer_api.py::TestSqsDeveloperApi::test_list_messages_with_invalid_action_raises_error[query-standard]": 0.03371987899981832, + "tests/aws/services/sqs/test_sqs_developer_api.py::TestSqsDeveloperApi::test_list_messages_with_invalid_queue_url[domain]": 0.02182133399992381, + "tests/aws/services/sqs/test_sqs_developer_api.py::TestSqsDeveloperApi::test_list_messages_with_invalid_queue_url[path]": 0.027840345000186062, + "tests/aws/services/sqs/test_sqs_developer_api.py::TestSqsDeveloperApi::test_list_messages_with_invalid_queue_url[standard]": 0.020859860999735247, + "tests/aws/services/sqs/test_sqs_developer_api.py::TestSqsDeveloperApi::test_list_messages_with_invisible_messages[domain]": 0.13479989099914746, + "tests/aws/services/sqs/test_sqs_developer_api.py::TestSqsDeveloperApi::test_list_messages_with_invisible_messages[path]": 0.1328532050006288, + "tests/aws/services/sqs/test_sqs_developer_api.py::TestSqsDeveloperApi::test_list_messages_with_invisible_messages[standard]": 0.1335970200002521, + "tests/aws/services/sqs/test_sqs_developer_api.py::TestSqsDeveloperApi::test_list_messages_with_non_existent_queue[domain]": 0.034122012999887374, + "tests/aws/services/sqs/test_sqs_developer_api.py::TestSqsDeveloperApi::test_list_messages_with_non_existent_queue[path]": 0.034412899000017205, + "tests/aws/services/sqs/test_sqs_developer_api.py::TestSqsDeveloperApi::test_list_messages_with_non_existent_queue[standard]": 0.03447472500056392, + "tests/aws/services/sqs/test_sqs_developer_api.py::TestSqsDeveloperApi::test_list_messages_with_queue_url_in_path[domain]": 0.1063456730003054, + "tests/aws/services/sqs/test_sqs_developer_api.py::TestSqsDeveloperApi::test_list_messages_with_queue_url_in_path[path]": 0.12074981400019169, + "tests/aws/services/sqs/test_sqs_developer_api.py::TestSqsDeveloperApi::test_list_messages_with_queue_url_in_path[standard]": 0.11109597099994062, + "tests/aws/services/sqs/test_sqs_developer_api.py::TestSqsDeveloperApi::test_list_messages_without_queue_url[domain]": 0.021424468999612145, + "tests/aws/services/sqs/test_sqs_developer_api.py::TestSqsDeveloperApi::test_list_messages_without_queue_url[path]": 0.019053136000366067, + "tests/aws/services/sqs/test_sqs_developer_api.py::TestSqsDeveloperApi::test_list_messages_without_queue_url[standard]": 0.020732005999889225, + "tests/aws/services/sqs/test_sqs_developer_api.py::TestSqsOverrideHeaders::test_receive_message_override_max_number_of_messages": 0.5404043520002233, + "tests/aws/services/sqs/test_sqs_developer_api.py::TestSqsOverrideHeaders::test_receive_message_override_message_wait_time_seconds": 25.323759635999977, + "tests/aws/services/sqs/test_sqs_move_task.py::test_basic_move_task_workflow": 1.8399658890002684, + "tests/aws/services/sqs/test_sqs_move_task.py::test_cancel_with_invalid_source_arn_in_task_handle": 0.04808881700046186, + "tests/aws/services/sqs/test_sqs_move_task.py::test_cancel_with_invalid_task_handle": 0.05102502399995501, + "tests/aws/services/sqs/test_sqs_move_task.py::test_cancel_with_invalid_task_id_in_task_handle": 0.070766389000255, + "tests/aws/services/sqs/test_sqs_move_task.py::test_destination_needs_to_exist": 0.11300669000002017, + "tests/aws/services/sqs/test_sqs_move_task.py::test_move_task_cancel": 1.8807692529999258, + "tests/aws/services/sqs/test_sqs_move_task.py::test_move_task_delete_destination_queue_while_running": 1.9166870109997944, + "tests/aws/services/sqs/test_sqs_move_task.py::test_move_task_with_throughput_limit": 3.4144436009996753, + "tests/aws/services/sqs/test_sqs_move_task.py::test_move_task_workflow_with_default_destination": 1.8290882539999984, + "tests/aws/services/sqs/test_sqs_move_task.py::test_move_task_workflow_with_multiple_sources_as_default_destination": 2.5480937190000077, + "tests/aws/services/sqs/test_sqs_move_task.py::test_source_needs_redrive_policy": 0.09766449000017019, + "tests/aws/services/sqs/test_sqs_move_task.py::test_start_multiple_move_tasks": 0.759629496999878, + "tests/aws/services/ssm/test_ssm.py::TestSSM::test_describe_parameters": 0.01696661200003291, + "tests/aws/services/ssm/test_ssm.py::TestSSM::test_get_inexistent_maintenance_window": 0.01599292199989577, + "tests/aws/services/ssm/test_ssm.py::TestSSM::test_get_inexistent_secret": 0.03937400800032265, + "tests/aws/services/ssm/test_ssm.py::TestSSM::test_get_parameter_by_arn": 0.06356212399987271, + "tests/aws/services/ssm/test_ssm.py::TestSSM::test_get_parameters_and_secrets": 0.13389876500013997, + "tests/aws/services/ssm/test_ssm.py::TestSSM::test_get_parameters_by_path_and_filter_by_labels": 0.0694651720004913, + "tests/aws/services/ssm/test_ssm.py::TestSSM::test_get_secret_parameter": 0.07284651500003747, + "tests/aws/services/ssm/test_ssm.py::TestSSM::test_hierarchical_parameter[///b//c]": 0.06941538699993544, + "tests/aws/services/ssm/test_ssm.py::TestSSM::test_hierarchical_parameter[/b/c]": 0.06796022799971979, + "tests/aws/services/ssm/test_ssm.py::TestSSM::test_parameters_with_path": 0.1869178660003854, + "tests/aws/services/ssm/test_ssm.py::TestSSM::test_put_parameters": 0.08667811600025743, + "tests/aws/services/ssm/test_ssm.py::TestSSM::test_trigger_event_on_systems_manager_change[domain]": 0.12984959199957302, + "tests/aws/services/ssm/test_ssm.py::TestSSM::test_trigger_event_on_systems_manager_change[path]": 0.15758843000003253, + "tests/aws/services/ssm/test_ssm.py::TestSSM::test_trigger_event_on_systems_manager_change[standard]": 0.12951783500011516, + "tests/aws/services/stepfunctions/v2/activities/test_activities.py::TestActivities::test_activity_task": 1.1902226430001974, + "tests/aws/services/stepfunctions/v2/activities/test_activities.py::TestActivities::test_activity_task_failure": 1.9905185380002877, + "tests/aws/services/stepfunctions/v2/activities/test_activities.py::TestActivities::test_activity_task_no_worker_name": 1.9229628520001825, + "tests/aws/services/stepfunctions/v2/activities/test_activities.py::TestActivities::test_activity_task_on_deleted": 0.3948248350002359, + "tests/aws/services/stepfunctions/v2/activities/test_activities.py::TestActivities::test_activity_task_start_timeout": 5.6992578219997085, + "tests/aws/services/stepfunctions/v2/activities/test_activities.py::TestActivities::test_activity_task_with_heartbeat": 6.016608636000456, + "tests/aws/services/stepfunctions/v2/arguments/test_arguments.py::TestArgumentsBase::test_base_cases[BASE_LAMBDA_EMPTY]": 2.1970904680006242, + "tests/aws/services/stepfunctions/v2/arguments/test_arguments.py::TestArgumentsBase::test_base_cases[BASE_LAMBDA_EMPTY_GLOBAL_QL_JSONATA]": 2.269730731999971, + "tests/aws/services/stepfunctions/v2/arguments/test_arguments.py::TestArgumentsBase::test_base_cases[BASE_LAMBDA_EXPRESSION]": 38.73959147299999, + "tests/aws/services/stepfunctions/v2/arguments/test_arguments.py::TestArgumentsBase::test_base_cases[BASE_LAMBDA_LITERALS]": 2.9236314859999766, + "tests/aws/services/stepfunctions/v2/assign/test_assign_base.py::TestAssignBase::test_assign_in_choice[CONDITION_FALSE]": 0.831761723999989, + "tests/aws/services/stepfunctions/v2/assign/test_assign_base.py::TestAssignBase::test_assign_in_choice[CONDITION_TRUE]": 0.9164310640000508, + "tests/aws/services/stepfunctions/v2/assign/test_assign_base.py::TestAssignBase::test_base_cases[BASE_CONSTANT_LITERALS]": 1.081394017000008, + "tests/aws/services/stepfunctions/v2/assign/test_assign_base.py::TestAssignBase::test_base_cases[BASE_EMPTY]": 0.6063378830000374, + "tests/aws/services/stepfunctions/v2/assign/test_assign_base.py::TestAssignBase::test_base_cases[BASE_PATHS]": 0.90581906999995, + "tests/aws/services/stepfunctions/v2/assign/test_assign_base.py::TestAssignBase::test_base_cases[BASE_SCOPE_MAP]": 0.9807989779999673, + "tests/aws/services/stepfunctions/v2/assign/test_assign_base.py::TestAssignBase::test_base_cases[BASE_VAR]": 1.2517423759999815, + "tests/aws/services/stepfunctions/v2/assign/test_assign_base.py::TestAssignBase::test_base_parallel_cases[BASE_SCOPE_PARALLEL]": 1.0187616399999797, + "tests/aws/services/stepfunctions/v2/assign/test_assign_reference_variables.py::TestAssignReferenceVariables::test_assign_from_value[BASE_ASSIGN_FROM_INTRINSIC_FUNCTION]": 1.6956755220000161, + "tests/aws/services/stepfunctions/v2/assign/test_assign_reference_variables.py::TestAssignReferenceVariables::test_assign_from_value[BASE_ASSIGN_FROM_PARAMETERS]": 0.8940815749999729, + "tests/aws/services/stepfunctions/v2/assign/test_assign_reference_variables.py::TestAssignReferenceVariables::test_assign_from_value[BASE_ASSIGN_FROM_RESULT]": 0.8509992759999818, + "tests/aws/services/stepfunctions/v2/assign/test_assign_reference_variables.py::TestAssignReferenceVariables::test_assign_in_catch_state": 2.583142261000006, + "tests/aws/services/stepfunctions/v2/assign/test_assign_reference_variables.py::TestAssignReferenceVariables::test_assign_in_choice_state[CORRECT]": 0.9688652849999642, + "tests/aws/services/stepfunctions/v2/assign/test_assign_reference_variables.py::TestAssignReferenceVariables::test_assign_in_choice_state[INCORRECT]": 0.892965098000019, + "tests/aws/services/stepfunctions/v2/assign/test_assign_reference_variables.py::TestAssignReferenceVariables::test_assign_in_wait_state": 0.6046863589999987, + "tests/aws/services/stepfunctions/v2/assign/test_assign_reference_variables.py::TestAssignReferenceVariables::test_reference_assign[BASE_REFERENCE_IN_CHOICE]": 0.9596412810000174, + "tests/aws/services/stepfunctions/v2/assign/test_assign_reference_variables.py::TestAssignReferenceVariables::test_reference_assign[BASE_REFERENCE_IN_FAIL]": 0.854236850999996, + "tests/aws/services/stepfunctions/v2/assign/test_assign_reference_variables.py::TestAssignReferenceVariables::test_reference_assign[BASE_REFERENCE_IN_INPUTPATH]": 0.8470256509999956, + "tests/aws/services/stepfunctions/v2/assign/test_assign_reference_variables.py::TestAssignReferenceVariables::test_reference_assign[BASE_REFERENCE_IN_INTRINSIC_FUNCTION]": 1.1495041929999843, + "tests/aws/services/stepfunctions/v2/assign/test_assign_reference_variables.py::TestAssignReferenceVariables::test_reference_assign[BASE_REFERENCE_IN_ITERATOR_OUTER_SCOPE]": 1.7069828200000359, + "tests/aws/services/stepfunctions/v2/assign/test_assign_reference_variables.py::TestAssignReferenceVariables::test_reference_assign[BASE_REFERENCE_IN_OUTPUTPATH]": 0.8867560289999687, + "tests/aws/services/stepfunctions/v2/assign/test_assign_reference_variables.py::TestAssignReferenceVariables::test_reference_assign[BASE_REFERENCE_IN_PARAMETERS]": 0.9015212930000018, + "tests/aws/services/stepfunctions/v2/assign/test_assign_reference_variables.py::TestAssignReferenceVariables::test_reference_assign[BASE_REFERENCE_IN_WAIT]": 0.8696183989999895, + "tests/aws/services/stepfunctions/v2/assign/test_assign_reference_variables.py::TestAssignReferenceVariables::test_reference_in_map_state[MAP_STATE_REFERENCE_IN_INTRINSIC_FUNCTION]": 1.2011682459999804, + "tests/aws/services/stepfunctions/v2/assign/test_assign_reference_variables.py::TestAssignReferenceVariables::test_reference_in_map_state[MAP_STATE_REFERENCE_IN_ITEMS_PATH]": 1.1801570479999839, + "tests/aws/services/stepfunctions/v2/assign/test_assign_reference_variables.py::TestAssignReferenceVariables::test_reference_in_map_state[MAP_STATE_REFERENCE_IN_ITEM_SELECTOR]": 0.9761947770000177, + "tests/aws/services/stepfunctions/v2/assign/test_assign_reference_variables.py::TestAssignReferenceVariables::test_reference_in_map_state[MAP_STATE_REFERENCE_IN_MAX_CONCURRENCY_PATH]": 0.9095731889999854, + "tests/aws/services/stepfunctions/v2/assign/test_assign_reference_variables.py::TestAssignReferenceVariables::test_reference_in_map_state[MAP_STATE_REFERENCE_IN_TOLERATED_FAILURE_PATH]": 0.9782822240000257, + "tests/aws/services/stepfunctions/v2/assign/test_assign_reference_variables.py::TestAssignReferenceVariables::test_reference_in_map_state_max_items_path[MAP_STATE_REFERENCE_IN_MAX_ITEMS_PATH]": 1.114863506000006, + "tests/aws/services/stepfunctions/v2/assign/test_assign_reference_variables.py::TestAssignReferenceVariables::test_reference_in_map_state_max_items_path[MAP_STATE_REFERENCE_IN_MAX_PER_BATCH_PATH]": 0.0017311119999874336, + "tests/aws/services/stepfunctions/v2/assign/test_assign_reference_variables.py::TestAssignReferenceVariables::test_state_assign_evaluation_order[BASE_EVALUATION_ORDER_PASS_STATE]": 0.0014354920000130278, + "tests/aws/services/stepfunctions/v2/assign/test_assign_reference_variables.py::TestAssignReferenceVariables::test_undefined_reference[BASE_UNDEFINED_ARGUMENTS]": 0.001413132999971367, + "tests/aws/services/stepfunctions/v2/assign/test_assign_reference_variables.py::TestAssignReferenceVariables::test_undefined_reference[BASE_UNDEFINED_ARGUMENTS_FIELD]": 0.0013397250000082295, + "tests/aws/services/stepfunctions/v2/assign/test_assign_reference_variables.py::TestAssignReferenceVariables::test_undefined_reference[BASE_UNDEFINED_ASSIGN]": 1.0573789999999974, + "tests/aws/services/stepfunctions/v2/assign/test_assign_reference_variables.py::TestAssignReferenceVariables::test_undefined_reference[BASE_UNDEFINED_OUTPUT]": 1.0918045000000234, + "tests/aws/services/stepfunctions/v2/assign/test_assign_reference_variables.py::TestAssignReferenceVariables::test_undefined_reference[BASE_UNDEFINED_OUTPUT_FIELD]": 1.1082281000000194, + "tests/aws/services/stepfunctions/v2/assign/test_assign_reference_variables.py::TestAssignReferenceVariables::test_undefined_reference[BASE_UNDEFINED_OUTPUT_MULTIPLE_STATES]": 1.1118311109999865, + "tests/aws/services/stepfunctions/v2/assign/test_assign_reference_variables.py::TestAssignReferenceVariables::test_variables_in_lambda_task[BASE_ASSIGN_FROM_LAMBDA_TASK_RESULT]": 2.626794177000022, + "tests/aws/services/stepfunctions/v2/base/test_base.py::TestSnfBase::test_decl_version_1_0": 0.41370319699996116, + "tests/aws/services/stepfunctions/v2/base/test_base.py::TestSnfBase::test_event_bridge_events_base": 3.3917723430000137, + "tests/aws/services/stepfunctions/v2/base/test_base.py::TestSnfBase::test_event_bridge_events_failure": 0.00144323600000007, + "tests/aws/services/stepfunctions/v2/base/test_base.py::TestSnfBase::test_execution_dateformat": 0.4228336609999701, + "tests/aws/services/stepfunctions/v2/base/test_base.py::TestSnfBase::test_json_path_array_access[$.items[0]]": 0.6998179799999775, + "tests/aws/services/stepfunctions/v2/base/test_base.py::TestSnfBase::test_json_path_array_access[$.items[10]]": 0.6857794730000251, + "tests/aws/services/stepfunctions/v2/base/test_base.py::TestSnfBase::test_json_path_array_wildcard_or_slice_with_no_input[$.item.items[*]]": 0.6345928650000019, + "tests/aws/services/stepfunctions/v2/base/test_base.py::TestSnfBase::test_json_path_array_wildcard_or_slice_with_no_input[$.item.items[1:5].itemValue]": 0.6468369119999693, + "tests/aws/services/stepfunctions/v2/base/test_base.py::TestSnfBase::test_json_path_array_wildcard_or_slice_with_no_input[$.item.items[1:5]]": 0.6446173619999627, + "tests/aws/services/stepfunctions/v2/base/test_base.py::TestSnfBase::test_json_path_array_wildcard_or_slice_with_no_input[$.item.items[1:]]": 0.6458532130000663, + "tests/aws/services/stepfunctions/v2/base/test_base.py::TestSnfBase::test_json_path_array_wildcard_or_slice_with_no_input[$.item.items[:1]]": 0.6423487389999991, + "tests/aws/services/stepfunctions/v2/base/test_base.py::TestSnfBase::test_json_path_array_wildcard_or_slice_with_no_input[$.items[*].itemValue]": 0.6359501609999825, + "tests/aws/services/stepfunctions/v2/base/test_base.py::TestSnfBase::test_json_path_array_wildcard_or_slice_with_no_input[$.items[*]]": 0.6522063439999783, + "tests/aws/services/stepfunctions/v2/base/test_base.py::TestSnfBase::test_json_path_array_wildcard_or_slice_with_no_input[$.items[1:].itemValue]": 0.6586342680000143, + "tests/aws/services/stepfunctions/v2/base/test_base.py::TestSnfBase::test_json_path_array_wildcard_or_slice_with_no_input[$.items[1:]]": 0.6449029139999993, + "tests/aws/services/stepfunctions/v2/base/test_base.py::TestSnfBase::test_json_path_array_wildcard_or_slice_with_no_input[$.items[:1].itemValue]": 0.6582005239999944, + "tests/aws/services/stepfunctions/v2/base/test_base.py::TestSnfBase::test_json_path_array_wildcard_or_slice_with_no_input[$.items[:1]]": 0.6393883810000034, + "tests/aws/services/stepfunctions/v2/base/test_base.py::TestSnfBase::test_json_path_array_wildcard_or_slice_with_no_input[$[*]]": 0.6568717890000357, + "tests/aws/services/stepfunctions/v2/base/test_base.py::TestSnfBase::test_query_context_object_values": 1.2916421279999781, + "tests/aws/services/stepfunctions/v2/base/test_base.py::TestSnfBase::test_state_fail": 0.5852214169999854, + "tests/aws/services/stepfunctions/v2/base/test_base.py::TestSnfBase::test_state_fail_empty": 0.5319537329999662, + "tests/aws/services/stepfunctions/v2/base/test_base.py::TestSnfBase::test_state_fail_intrinsic": 0.6762413379999828, + "tests/aws/services/stepfunctions/v2/base/test_base.py::TestSnfBase::test_state_fail_path": 0.6827631160000465, + "tests/aws/services/stepfunctions/v2/base/test_base.py::TestSnfBase::test_state_pass_regex_json_path": 0.0013439820000371583, + "tests/aws/services/stepfunctions/v2/base/test_base.py::TestSnfBase::test_state_pass_regex_json_path_base": 0.6816353689999914, + "tests/aws/services/stepfunctions/v2/base/test_base.py::TestSnfBase::test_state_pass_result": 0.4235873330000004, + "tests/aws/services/stepfunctions/v2/base/test_base.py::TestSnfBase::test_state_pass_result_jsonpaths": 0.41356102299997133, + "tests/aws/services/stepfunctions/v2/base/test_base.py::TestSnfBase::test_state_pass_result_null_input_output_paths": 0.7048943690000158, + "tests/aws/services/stepfunctions/v2/base/test_wait.py::TestSfnWait::test_base_wait_seconds_path[-1.5]": 0.6362103999999817, + "tests/aws/services/stepfunctions/v2/base/test_wait.py::TestSfnWait::test_base_wait_seconds_path[-1]": 0.653885695999918, + "tests/aws/services/stepfunctions/v2/base/test_wait.py::TestSfnWait::test_base_wait_seconds_path[0]": 0.6373557690000098, + "tests/aws/services/stepfunctions/v2/base/test_wait.py::TestSfnWait::test_base_wait_seconds_path[1.5]": 0.6242134309999869, + "tests/aws/services/stepfunctions/v2/base/test_wait.py::TestSfnWait::test_base_wait_seconds_path[1]": 1.4701744660000031, + "tests/aws/services/stepfunctions/v2/base/test_wait.py::TestSfnWait::test_timestamp_too_far_in_future_boundary[24855]": 0.0014000569999552681, + "tests/aws/services/stepfunctions/v2/base/test_wait.py::TestSfnWait::test_timestamp_too_far_in_future_boundary[24856]": 0.0012547559999802615, + "tests/aws/services/stepfunctions/v2/base/test_wait.py::TestSfnWait::test_wait_timestamppath[.000000Z]": 0.4432489069999406, + "tests/aws/services/stepfunctions/v2/base/test_wait.py::TestSfnWait::test_wait_timestamppath[.000000]": 0.6479090140000494, + "tests/aws/services/stepfunctions/v2/base/test_wait.py::TestSfnWait::test_wait_timestamppath[.00Z]": 0.4354218989999481, + "tests/aws/services/stepfunctions/v2/base/test_wait.py::TestSfnWait::test_wait_timestamppath[Z]": 0.6408434479999983, + "tests/aws/services/stepfunctions/v2/base/test_wait.py::TestSfnWait::test_wait_timestamppath[]": 0.6595009390000541, + "tests/aws/services/stepfunctions/v2/callback/test_callback.py::TestCallback::test_multiple_executions_and_heartbeat_notifications": 0.0020032090000654534, + "tests/aws/services/stepfunctions/v2/callback/test_callback.py::TestCallback::test_multiple_heartbeat_notifications": 0.002602403000025788, + "tests/aws/services/stepfunctions/v2/callback/test_callback.py::TestCallback::test_sns_publish_wait_for_task_token": 1.2874683530000084, + "tests/aws/services/stepfunctions/v2/callback/test_callback.py::TestCallback::test_sqs_failure_in_wait_for_task_tok_no_error_field[SQS_PARALLEL_WAIT_FOR_TASK_TOKEN]": 0.007885615000020607, + "tests/aws/services/stepfunctions/v2/callback/test_callback.py::TestCallback::test_sqs_failure_in_wait_for_task_tok_no_error_field[SQS_WAIT_FOR_TASK_TOKEN_CATCH]": 1.6422235599999908, + "tests/aws/services/stepfunctions/v2/callback/test_callback.py::TestCallback::test_sqs_failure_in_wait_for_task_token": 2.361604681000017, + "tests/aws/services/stepfunctions/v2/callback/test_callback.py::TestCallback::test_sqs_wait_for_task_tok_with_heartbeat": 7.520997841999986, + "tests/aws/services/stepfunctions/v2/callback/test_callback.py::TestCallback::test_sqs_wait_for_task_token": 2.4310978919999684, + "tests/aws/services/stepfunctions/v2/callback/test_callback.py::TestCallback::test_sqs_wait_for_task_token_call_chain": 4.1590370370000755, + "tests/aws/services/stepfunctions/v2/callback/test_callback.py::TestCallback::test_sqs_wait_for_task_token_no_token_parameter": 5.711228739000035, + "tests/aws/services/stepfunctions/v2/callback/test_callback.py::TestCallback::test_sqs_wait_for_task_token_timeout": 5.746088063000002, + "tests/aws/services/stepfunctions/v2/callback/test_callback.py::TestCallback::test_start_execution_sync": 0.985175889000061, + "tests/aws/services/stepfunctions/v2/callback/test_callback.py::TestCallback::test_start_execution_sync2": 1.0051435839999385, + "tests/aws/services/stepfunctions/v2/callback/test_callback.py::TestCallback::test_start_execution_sync_delegate_failure": 1.002220452999893, + "tests/aws/services/stepfunctions/v2/callback/test_callback.py::TestCallback::test_start_execution_sync_delegate_timeout": 7.346532499000034, + "tests/aws/services/stepfunctions/v2/callback/test_callback.py::TestCallback::test_sync_with_task_token": 2.6560816090000117, + "tests/aws/services/stepfunctions/v2/choice_operators/test_boolean_equals.py::TestBooleanEquals::test_boolean_equals": 14.057533159000002, + "tests/aws/services/stepfunctions/v2/choice_operators/test_boolean_equals.py::TestBooleanEquals::test_boolean_equals_path": 14.54851601799993, + "tests/aws/services/stepfunctions/v2/choice_operators/test_is_operators.py::TestIsOperators::test_is_boolean": 14.07695680400002, + "tests/aws/services/stepfunctions/v2/choice_operators/test_is_operators.py::TestIsOperators::test_is_null": 14.779984507999984, + "tests/aws/services/stepfunctions/v2/choice_operators/test_is_operators.py::TestIsOperators::test_is_numeric": 13.76370995800005, + "tests/aws/services/stepfunctions/v2/choice_operators/test_is_operators.py::TestIsOperators::test_is_present": 14.124768061999987, + "tests/aws/services/stepfunctions/v2/choice_operators/test_is_operators.py::TestIsOperators::test_is_string": 14.412845747000063, + "tests/aws/services/stepfunctions/v2/choice_operators/test_is_operators.py::TestIsOperators::test_is_timestamp": 0.0037111560000084864, + "tests/aws/services/stepfunctions/v2/choice_operators/test_numeric.py::TestNumerics::test_numeric_equals": 22.392381779000004, + "tests/aws/services/stepfunctions/v2/choice_operators/test_numeric.py::TestNumerics::test_numeric_equals_path": 22.21474983300004, + "tests/aws/services/stepfunctions/v2/choice_operators/test_numeric.py::TestNumerics::test_numeric_greater_than": 2.6155413969999586, + "tests/aws/services/stepfunctions/v2/choice_operators/test_numeric.py::TestNumerics::test_numeric_greater_than_equals": 2.669106174000035, + "tests/aws/services/stepfunctions/v2/choice_operators/test_numeric.py::TestNumerics::test_numeric_greater_than_equals_path": 2.666449630000045, + "tests/aws/services/stepfunctions/v2/choice_operators/test_numeric.py::TestNumerics::test_numeric_greater_than_path": 2.703213990999984, + "tests/aws/services/stepfunctions/v2/choice_operators/test_numeric.py::TestNumerics::test_numeric_less_than": 2.6466921940000248, + "tests/aws/services/stepfunctions/v2/choice_operators/test_numeric.py::TestNumerics::test_numeric_less_than_equals": 2.6651008679999677, + "tests/aws/services/stepfunctions/v2/choice_operators/test_numeric.py::TestNumerics::test_numeric_less_than_equals_path": 2.6317249859999947, + "tests/aws/services/stepfunctions/v2/choice_operators/test_numeric.py::TestNumerics::test_numeric_less_than_path": 2.653719925999951, + "tests/aws/services/stepfunctions/v2/choice_operators/test_string_operators.py::TestStrings::test_string_equals": 6.472137256999929, + "tests/aws/services/stepfunctions/v2/choice_operators/test_string_operators.py::TestStrings::test_string_equals_path": 1.4613608579999209, + "tests/aws/services/stepfunctions/v2/choice_operators/test_string_operators.py::TestStrings::test_string_greater_than": 1.842500052000048, + "tests/aws/services/stepfunctions/v2/choice_operators/test_string_operators.py::TestStrings::test_string_greater_than_equals": 1.4563713000000007, + "tests/aws/services/stepfunctions/v2/choice_operators/test_string_operators.py::TestStrings::test_string_greater_than_equals_path": 1.4483059269999785, + "tests/aws/services/stepfunctions/v2/choice_operators/test_string_operators.py::TestStrings::test_string_greater_than_path": 1.9130369069999915, + "tests/aws/services/stepfunctions/v2/choice_operators/test_string_operators.py::TestStrings::test_string_less_than": 1.4525353939999377, + "tests/aws/services/stepfunctions/v2/choice_operators/test_string_operators.py::TestStrings::test_string_less_than_equals": 1.4552924789999793, + "tests/aws/services/stepfunctions/v2/choice_operators/test_string_operators.py::TestStrings::test_string_less_than_equals_path": 1.4574919890000047, + "tests/aws/services/stepfunctions/v2/choice_operators/test_string_operators.py::TestStrings::test_string_less_than_path": 1.4487556240000004, + "tests/aws/services/stepfunctions/v2/choice_operators/test_timestamp_operators.py::TestTimestamps::test_timestamp_equals": 7.7002068379999855, + "tests/aws/services/stepfunctions/v2/choice_operators/test_timestamp_operators.py::TestTimestamps::test_timestamp_equals_path": 1.475662836999959, + "tests/aws/services/stepfunctions/v2/choice_operators/test_timestamp_operators.py::TestTimestamps::test_timestamp_greater_than": 1.4585675130000482, + "tests/aws/services/stepfunctions/v2/choice_operators/test_timestamp_operators.py::TestTimestamps::test_timestamp_greater_than_equals": 1.454430554000055, + "tests/aws/services/stepfunctions/v2/choice_operators/test_timestamp_operators.py::TestTimestamps::test_timestamp_greater_than_equals_path": 0.6718609270000115, + "tests/aws/services/stepfunctions/v2/choice_operators/test_timestamp_operators.py::TestTimestamps::test_timestamp_greater_than_path": 0.6572580689999086, + "tests/aws/services/stepfunctions/v2/choice_operators/test_timestamp_operators.py::TestTimestamps::test_timestamp_less_than": 1.4511545530000376, + "tests/aws/services/stepfunctions/v2/choice_operators/test_timestamp_operators.py::TestTimestamps::test_timestamp_less_than_equals": 1.4367073509999955, + "tests/aws/services/stepfunctions/v2/choice_operators/test_timestamp_operators.py::TestTimestamps::test_timestamp_less_than_equals_path": 0.6968024349999951, + "tests/aws/services/stepfunctions/v2/choice_operators/test_timestamp_operators.py::TestTimestamps::test_timestamp_less_than_path": 0.6659636140001339, + "tests/aws/services/stepfunctions/v2/comments/test_comments.py::TestComments::test_comment_in_parameters": 0.44412617600005433, + "tests/aws/services/stepfunctions/v2/comments/test_comments.py::TestComments::test_comments_as_per_docs": 7.657039604999909, + "tests/aws/services/stepfunctions/v2/context_object/test_context_object.py::TestSnfBase::test_error_cause_path": 0.9207384970001158, + "tests/aws/services/stepfunctions/v2/context_object/test_context_object.py::TestSnfBase::test_input_path[$$.Execution.Input]": 0.9112104269999008, + "tests/aws/services/stepfunctions/v2/context_object/test_context_object.py::TestSnfBase::test_input_path[$$]": 0.6829352999999401, + "tests/aws/services/stepfunctions/v2/context_object/test_context_object.py::TestSnfBase::test_output_path[$$.Execution.Input]": 0.933717113000057, + "tests/aws/services/stepfunctions/v2/context_object/test_context_object.py::TestSnfBase::test_output_path[$$]": 0.7277401249999684, + "tests/aws/services/stepfunctions/v2/context_object/test_context_object.py::TestSnfBase::test_result_selector": 2.6493019079998703, + "tests/aws/services/stepfunctions/v2/context_object/test_context_object.py::TestSnfBase::test_variable": 0.9558019320000994, + "tests/aws/services/stepfunctions/v2/credentials/test_credentials_base.py::TestCredentialsBase::test_cross_account_lambda_task": 2.3808702039999616, + "tests/aws/services/stepfunctions/v2/credentials/test_credentials_base.py::TestCredentialsBase::test_cross_account_service_lambda_invoke": 2.4580215940001153, + "tests/aws/services/stepfunctions/v2/credentials/test_credentials_base.py::TestCredentialsBase::test_cross_account_service_lambda_invoke_retry": 6.599305754999932, + "tests/aws/services/stepfunctions/v2/credentials/test_credentials_base.py::TestCredentialsBase::test_cross_account_states_start_sync_execution[SFN_START_EXECUTION_SYNC_ROLE_ARN_INTRINSIC]": 1.4636050670000031, + "tests/aws/services/stepfunctions/v2/credentials/test_credentials_base.py::TestCredentialsBase::test_cross_account_states_start_sync_execution[SFN_START_EXECUTION_SYNC_ROLE_ARN_JSONATA]": 1.4210514220001187, + "tests/aws/services/stepfunctions/v2/credentials/test_credentials_base.py::TestCredentialsBase::test_cross_account_states_start_sync_execution[SFN_START_EXECUTION_SYNC_ROLE_ARN_PATH]": 1.2496084629999586, + "tests/aws/services/stepfunctions/v2/credentials/test_credentials_base.py::TestCredentialsBase::test_cross_account_states_start_sync_execution[SFN_START_EXECUTION_SYNC_ROLE_ARN_PATH_CONTEXT]": 1.548342931999855, + "tests/aws/services/stepfunctions/v2/credentials/test_credentials_base.py::TestCredentialsBase::test_cross_account_states_start_sync_execution[SFN_START_EXECUTION_SYNC_ROLE_ARN_VARIABLE]": 1.503167932999986, + "tests/aws/services/stepfunctions/v2/credentials/test_credentials_base.py::TestCredentialsBase::test_invalid_credentials_field[EMPTY_CREDENTIALS]": 0.7533891010000389, + "tests/aws/services/stepfunctions/v2/credentials/test_credentials_base.py::TestCredentialsBase::test_invalid_credentials_field[INVALID_CREDENTIALS_FIELD]": 0.744623630999854, + "tests/aws/services/stepfunctions/v2/error_handling/test_aws_sdk.py::TestAwsSdk::test_dynamodb_invalid_param": 0.0017897509999329486, + "tests/aws/services/stepfunctions/v2/error_handling/test_aws_sdk.py::TestAwsSdk::test_dynamodb_put_item_no_such_table": 2.91332757400005, + "tests/aws/services/stepfunctions/v2/error_handling/test_aws_sdk.py::TestAwsSdk::test_invalid_secret_name": 0.7360151300000553, + "tests/aws/services/stepfunctions/v2/error_handling/test_aws_sdk.py::TestAwsSdk::test_no_such_bucket": 0.7153032289999146, + "tests/aws/services/stepfunctions/v2/error_handling/test_aws_sdk.py::TestAwsSdk::test_s3_no_such_key": 0.7485641309999664, + "tests/aws/services/stepfunctions/v2/error_handling/test_states_errors.py::TestStatesErrors::test_service_task_lambada_catch_state_all_data_limit_exceeded_on_large_utf8_response": 2.372627464999937, + "tests/aws/services/stepfunctions/v2/error_handling/test_states_errors.py::TestStatesErrors::test_service_task_lambada_data_limit_exceeded_on_large_utf8_response": 2.429581538999969, + "tests/aws/services/stepfunctions/v2/error_handling/test_states_errors.py::TestStatesErrors::test_start_large_input": 5.0312700420001875, + "tests/aws/services/stepfunctions/v2/error_handling/test_states_errors.py::TestStatesErrors::test_task_lambda_catch_state_all_data_limit_exceeded_on_large_utf8_response": 2.335017616000073, + "tests/aws/services/stepfunctions/v2/error_handling/test_states_errors.py::TestStatesErrors::test_task_lambda_data_limit_exceeded_on_large_utf8_response": 2.3937545339999815, + "tests/aws/services/stepfunctions/v2/error_handling/test_task_lambda.py::TestTaskLambda::test_no_such_function": 2.4590246300000445, + "tests/aws/services/stepfunctions/v2/error_handling/test_task_lambda.py::TestTaskLambda::test_no_such_function_catch": 2.539929175999987, + "tests/aws/services/stepfunctions/v2/error_handling/test_task_lambda.py::TestTaskLambda::test_raise_custom_exception": 2.2798439900000176, + "tests/aws/services/stepfunctions/v2/error_handling/test_task_lambda.py::TestTaskLambda::test_raise_exception": 2.3246745269999565, + "tests/aws/services/stepfunctions/v2/error_handling/test_task_lambda.py::TestTaskLambda::test_raise_exception_catch": 2.591555625000069, + "tests/aws/services/stepfunctions/v2/error_handling/test_task_service_dynamodb.py::TestTaskServiceDynamoDB::test_invalid_param": 0.7621778620000441, + "tests/aws/services/stepfunctions/v2/error_handling/test_task_service_dynamodb.py::TestTaskServiceDynamoDB::test_put_item_invalid_table_name": 0.8126507149999043, + "tests/aws/services/stepfunctions/v2/error_handling/test_task_service_dynamodb.py::TestTaskServiceDynamoDB::test_put_item_no_such_table": 0.7501988669999946, + "tests/aws/services/stepfunctions/v2/error_handling/test_task_service_lambda.py::TestTaskServiceLambda::test_invoke_timeout": 6.849358958999915, + "tests/aws/services/stepfunctions/v2/error_handling/test_task_service_lambda.py::TestTaskServiceLambda::test_no_such_function": 1.8964083009999513, + "tests/aws/services/stepfunctions/v2/error_handling/test_task_service_lambda.py::TestTaskServiceLambda::test_no_such_function_catch": 1.951046455000096, + "tests/aws/services/stepfunctions/v2/error_handling/test_task_service_lambda.py::TestTaskServiceLambda::test_raise_custom_exception": 2.458397307999917, + "tests/aws/services/stepfunctions/v2/error_handling/test_task_service_lambda.py::TestTaskServiceLambda::test_raise_exception": 2.378047891000165, + "tests/aws/services/stepfunctions/v2/error_handling/test_task_service_lambda.py::TestTaskServiceLambda::test_raise_exception_catch": 2.4782958779999262, + "tests/aws/services/stepfunctions/v2/error_handling/test_task_service_lambda.py::TestTaskServiceLambda::test_raise_exception_catch_output_path[$.Payload]": 2.397692574999951, + "tests/aws/services/stepfunctions/v2/error_handling/test_task_service_lambda.py::TestTaskServiceLambda::test_raise_exception_catch_output_path[$.no.such.path]": 2.4630499229999714, + "tests/aws/services/stepfunctions/v2/error_handling/test_task_service_lambda.py::TestTaskServiceLambda::test_raise_exception_catch_output_path[None]": 2.4570057739998674, + "tests/aws/services/stepfunctions/v2/error_handling/test_task_service_sfn.py::TestTaskServiceSfn::test_start_execution_no_such_arn": 0.9991826439999159, + "tests/aws/services/stepfunctions/v2/error_handling/test_task_service_sqs.py::TestTaskServiceSqs::test_send_message_empty_body": 0.0018949269999666285, + "tests/aws/services/stepfunctions/v2/error_handling/test_task_service_sqs.py::TestTaskServiceSqs::test_send_message_no_such_queue": 1.0757080629999791, + "tests/aws/services/stepfunctions/v2/error_handling/test_task_service_sqs.py::TestTaskServiceSqs::test_send_message_no_such_queue_no_catch": 1.0083143620000783, + "tests/aws/services/stepfunctions/v2/error_handling/test_task_service_sqs.py::TestTaskServiceSqs::test_sqs_failure_in_wait_for_task_tok": 2.6103349509999134, + "tests/aws/services/stepfunctions/v2/evaluate_jsonata/test_base_evaluate_expressions.py::TestBaseEvaluateJsonata::test_base_jsonata_regular_expressions[BASE]": 0.956835559999945, + "tests/aws/services/stepfunctions/v2/evaluate_jsonata/test_base_evaluate_expressions.py::TestBaseEvaluateJsonata::test_base_jsonata_regular_expressions[BASE_FALSE]": 0.9651893970000174, + "tests/aws/services/stepfunctions/v2/evaluate_jsonata/test_base_evaluate_expressions.py::TestBaseEvaluateJsonata::test_base_jsonata_regular_expressions[BASE_SINGLE_QUOTE]": 0.7491998440000316, + "tests/aws/services/stepfunctions/v2/evaluate_jsonata/test_base_evaluate_expressions.py::TestBaseEvaluateJsonata::test_base_jsonata_regular_expressions[BASE_SINGLE_QUOTE_FALSE]": 0.969816650000098, + "tests/aws/services/stepfunctions/v2/evaluate_jsonata/test_base_evaluate_expressions.py::TestBaseEvaluateJsonata::test_base_map[ITEMS]": 1.190785837000135, + "tests/aws/services/stepfunctions/v2/evaluate_jsonata/test_base_evaluate_expressions.py::TestBaseEvaluateJsonata::test_base_map[ITEMS_DOUBLE_QUOTES]": 1.0532044139999925, + "tests/aws/services/stepfunctions/v2/evaluate_jsonata/test_base_evaluate_expressions.py::TestBaseEvaluateJsonata::test_base_map[MAX_CONCURRENCY]": 0.9969959499999277, + "tests/aws/services/stepfunctions/v2/evaluate_jsonata/test_base_evaluate_expressions.py::TestBaseEvaluateJsonata::test_base_map[TOLERATED_FAILURE_COUNT]": 1.8325543490001337, + "tests/aws/services/stepfunctions/v2/evaluate_jsonata/test_base_evaluate_expressions.py::TestBaseEvaluateJsonata::test_base_map[TOLERATED_FAILURE_PERCENTAGE]": 1.008905987999924, + "tests/aws/services/stepfunctions/v2/evaluate_jsonata/test_base_evaluate_expressions.py::TestBaseEvaluateJsonata::test_base_map_from_input[ITEMS]": 2.1931953509999857, + "tests/aws/services/stepfunctions/v2/evaluate_jsonata/test_base_evaluate_expressions.py::TestBaseEvaluateJsonata::test_base_map_from_input[MAX_CONCURRENCY]": 2.196262746000002, + "tests/aws/services/stepfunctions/v2/evaluate_jsonata/test_base_evaluate_expressions.py::TestBaseEvaluateJsonata::test_base_map_from_input[TOLERATED_FAILURE_COUNT]": 2.1719618609999998, + "tests/aws/services/stepfunctions/v2/evaluate_jsonata/test_base_evaluate_expressions.py::TestBaseEvaluateJsonata::test_base_map_from_input[TOLERATED_FAILURE_PERCENTAGE]": 2.1820168760000342, + "tests/aws/services/stepfunctions/v2/evaluate_jsonata/test_base_evaluate_expressions.py::TestBaseEvaluateJsonata::test_base_task[HEARTBEAT_SECONDS]": 2.4928617439999243, + "tests/aws/services/stepfunctions/v2/evaluate_jsonata/test_base_evaluate_expressions.py::TestBaseEvaluateJsonata::test_base_task[TIMEOUT_SECONDS]": 0.0015987750000476808, + "tests/aws/services/stepfunctions/v2/evaluate_jsonata/test_base_evaluate_expressions.py::TestBaseEvaluateJsonata::test_base_task_from_input[HEARTBEAT_SECONDS]": 2.717386970000234, + "tests/aws/services/stepfunctions/v2/evaluate_jsonata/test_base_evaluate_expressions.py::TestBaseEvaluateJsonata::test_base_task_from_input[TIMEOUT_SECONDS]": 0.0018364769999834607, + "tests/aws/services/stepfunctions/v2/express/test_express_async.py::TestExpressAsync::test_base[BASE_PASS_RESULT]": 1.2645768080000153, + "tests/aws/services/stepfunctions/v2/express/test_express_async.py::TestExpressAsync::test_base[BASE_RAISE_FAILURE]": 1.1962060049999081, + "tests/aws/services/stepfunctions/v2/express/test_express_async.py::TestExpressAsync::test_catch": 2.9381455080001615, + "tests/aws/services/stepfunctions/v2/express/test_express_async.py::TestExpressAsync::test_query_runtime_memory": 1.5153374610000583, + "tests/aws/services/stepfunctions/v2/express/test_express_async.py::TestExpressAsync::test_retry": 10.182059527999968, + "tests/aws/services/stepfunctions/v2/express/test_express_sync.py::TestExpressSync::test_base[BASE_PASS_RESULT]": 0.5391500019999285, + "tests/aws/services/stepfunctions/v2/express/test_express_sync.py::TestExpressSync::test_base[BASE_RAISE_FAILURE]": 0.4817176330000166, + "tests/aws/services/stepfunctions/v2/express/test_express_sync.py::TestExpressSync::test_catch": 2.2923866009999756, + "tests/aws/services/stepfunctions/v2/express/test_express_sync.py::TestExpressSync::test_query_runtime_memory": 1.2541421839999884, + "tests/aws/services/stepfunctions/v2/express/test_express_sync.py::TestExpressSync::test_retry": 9.542196978999982, + "tests/aws/services/stepfunctions/v2/intrinsic_functions/test_array.py::TestArray::test_array_0": 0.43521627600000556, + "tests/aws/services/stepfunctions/v2/intrinsic_functions/test_array.py::TestArray::test_array_2": 2.9940132640000456, + "tests/aws/services/stepfunctions/v2/intrinsic_functions/test_array.py::TestArray::test_array_contains": 3.3989766649999638, + "tests/aws/services/stepfunctions/v2/intrinsic_functions/test_array.py::TestArray::test_array_get_item": 0.6550304740001138, + "tests/aws/services/stepfunctions/v2/intrinsic_functions/test_array.py::TestArray::test_array_length": 0.46514351400003306, + "tests/aws/services/stepfunctions/v2/intrinsic_functions/test_array.py::TestArray::test_array_partition": 8.693146518000049, + "tests/aws/services/stepfunctions/v2/intrinsic_functions/test_array.py::TestArray::test_array_range": 1.653620493999938, + "tests/aws/services/stepfunctions/v2/intrinsic_functions/test_array.py::TestArray::test_array_unique": 0.6559421759999395, + "tests/aws/services/stepfunctions/v2/intrinsic_functions/test_array_jsonata.py::TestArrayJSONata::test_array_partition": 6.774616142000241, + "tests/aws/services/stepfunctions/v2/intrinsic_functions/test_array_jsonata.py::TestArrayJSONata::test_array_range": 1.5123225019999609, + "tests/aws/services/stepfunctions/v2/intrinsic_functions/test_encode_decode.py::TestEncodeDecode::test_base_64_decode": 0.9963757960000521, + "tests/aws/services/stepfunctions/v2/intrinsic_functions/test_encode_decode.py::TestEncodeDecode::test_base_64_encode": 0.9922024219999912, + "tests/aws/services/stepfunctions/v2/intrinsic_functions/test_generic.py::TestGeneric::test_context_json_path": 0.697502792999785, + "tests/aws/services/stepfunctions/v2/intrinsic_functions/test_generic.py::TestGeneric::test_escape_sequence": 0.42711766899992654, + "tests/aws/services/stepfunctions/v2/intrinsic_functions/test_generic.py::TestGeneric::test_format_1": 2.4217977819999987, + "tests/aws/services/stepfunctions/v2/intrinsic_functions/test_generic.py::TestGeneric::test_format_2": 2.973157241000081, + "tests/aws/services/stepfunctions/v2/intrinsic_functions/test_generic.py::TestGeneric::test_nested_calls_1": 0.6756444430001238, + "tests/aws/services/stepfunctions/v2/intrinsic_functions/test_generic.py::TestGeneric::test_nested_calls_2": 0.6829451959998778, + "tests/aws/services/stepfunctions/v2/intrinsic_functions/test_hash_calculations.py::TestHashCalculations::test_hash": 1.996756466000079, + "tests/aws/services/stepfunctions/v2/intrinsic_functions/test_json_manipulation.py::TestJsonManipulation::test_json_merge": 0.6632467730000826, + "tests/aws/services/stepfunctions/v2/intrinsic_functions/test_json_manipulation.py::TestJsonManipulation::test_json_merge_escaped_argument": 0.6983688580000944, + "tests/aws/services/stepfunctions/v2/intrinsic_functions/test_json_manipulation.py::TestJsonManipulation::test_json_to_string": 2.99752201900003, + "tests/aws/services/stepfunctions/v2/intrinsic_functions/test_json_manipulation.py::TestJsonManipulation::test_string_to_json": 3.378486374999966, + "tests/aws/services/stepfunctions/v2/intrinsic_functions/test_json_manipulation_jsonata.py::TestJsonManipulationJSONata::test_parse": 2.3657660589998386, + "tests/aws/services/stepfunctions/v2/intrinsic_functions/test_math_operations.py::TestMathOperations::test_math_add": 7.14482663199999, + "tests/aws/services/stepfunctions/v2/intrinsic_functions/test_math_operations.py::TestMathOperations::test_math_random": 1.4101467749999301, + "tests/aws/services/stepfunctions/v2/intrinsic_functions/test_math_operations.py::TestMathOperations::test_math_random_seeded": 0.7319624829998475, + "tests/aws/services/stepfunctions/v2/intrinsic_functions/test_math_operations_jsonata.py::TestMathOperationsJSONata::test_math_random_seeded": 0.0019245199999886609, + "tests/aws/services/stepfunctions/v2/intrinsic_functions/test_string_operations.py::TestStringOperations::test_string_split": 2.6798777819999486, + "tests/aws/services/stepfunctions/v2/intrinsic_functions/test_string_operations.py::TestStringOperations::test_string_split_context_object": 0.6670701240000199, + "tests/aws/services/stepfunctions/v2/intrinsic_functions/test_unique_id_generation.py::TestUniqueIdGeneration::test_uuid": 0.4465262699999357, + "tests/aws/services/stepfunctions/v2/logs/test_logs.py::TestLogs::test_base[pass_result.json5_ALL_False]": 0.9544782240001268, + "tests/aws/services/stepfunctions/v2/logs/test_logs.py::TestLogs::test_base[pass_result.json5_ALL_True]": 0.9576517719999629, + "tests/aws/services/stepfunctions/v2/logs/test_logs.py::TestLogs::test_base[raise_failure.json5_ALL_False]": 0.9996447399998942, + "tests/aws/services/stepfunctions/v2/logs/test_logs.py::TestLogs::test_base[raise_failure.json5_ALL_True]": 0.9510461510000141, + "tests/aws/services/stepfunctions/v2/logs/test_logs.py::TestLogs::test_base[wait_seconds_path.json5_ALL_False]": 0.9473354569998946, + "tests/aws/services/stepfunctions/v2/logs/test_logs.py::TestLogs::test_base[wait_seconds_path.json5_ALL_True]": 0.944271694999884, + "tests/aws/services/stepfunctions/v2/logs/test_logs.py::TestLogs::test_deleted_log_group": 0.9494689399999743, + "tests/aws/services/stepfunctions/v2/logs/test_logs.py::TestLogs::test_log_group_with_multiple_runs": 1.5385741449999841, + "tests/aws/services/stepfunctions/v2/logs/test_logs.py::TestLogs::test_partial_log_levels[pass_result.json5_ERROR_False]": 0.6671723279999924, + "tests/aws/services/stepfunctions/v2/logs/test_logs.py::TestLogs::test_partial_log_levels[pass_result.json5_ERROR_True]": 0.6575617329998522, + "tests/aws/services/stepfunctions/v2/logs/test_logs.py::TestLogs::test_partial_log_levels[pass_result.json5_FATAL_False]": 0.6525587200000018, + "tests/aws/services/stepfunctions/v2/logs/test_logs.py::TestLogs::test_partial_log_levels[pass_result.json5_FATAL_True]": 0.6636563000000706, + "tests/aws/services/stepfunctions/v2/logs/test_logs.py::TestLogs::test_partial_log_levels[pass_result.json5_OFF_False]": 0.6551389510000263, + "tests/aws/services/stepfunctions/v2/logs/test_logs.py::TestLogs::test_partial_log_levels[pass_result.json5_OFF_True]": 0.6468277180000541, + "tests/aws/services/stepfunctions/v2/logs/test_logs.py::TestLogs::test_partial_log_levels[raise_failure.json5_ERROR_False]": 0.9407028159999982, + "tests/aws/services/stepfunctions/v2/logs/test_logs.py::TestLogs::test_partial_log_levels[raise_failure.json5_ERROR_True]": 0.9425986719999173, + "tests/aws/services/stepfunctions/v2/logs/test_logs.py::TestLogs::test_partial_log_levels[raise_failure.json5_FATAL_False]": 0.7237593730000071, + "tests/aws/services/stepfunctions/v2/logs/test_logs.py::TestLogs::test_partial_log_levels[raise_failure.json5_FATAL_True]": 0.7704059490000645, + "tests/aws/services/stepfunctions/v2/logs/test_logs.py::TestLogs::test_partial_log_levels[raise_failure.json5_OFF_False]": 0.6410263470000928, + "tests/aws/services/stepfunctions/v2/logs/test_logs.py::TestLogs::test_partial_log_levels[raise_failure.json5_OFF_True]": 0.6389551490000258, + "tests/aws/services/stepfunctions/v2/logs/test_logs.py::TestLogs::test_partial_log_levels[wait_seconds_path.json5_ERROR_False]": 0.9350075799999331, + "tests/aws/services/stepfunctions/v2/logs/test_logs.py::TestLogs::test_partial_log_levels[wait_seconds_path.json5_ERROR_True]": 0.9356525670000337, + "tests/aws/services/stepfunctions/v2/logs/test_logs.py::TestLogs::test_partial_log_levels[wait_seconds_path.json5_FATAL_False]": 0.9295935559998725, + "tests/aws/services/stepfunctions/v2/logs/test_logs.py::TestLogs::test_partial_log_levels[wait_seconds_path.json5_FATAL_True]": 0.9365297639999426, + "tests/aws/services/stepfunctions/v2/logs/test_logs.py::TestLogs::test_partial_log_levels[wait_seconds_path.json5_OFF_False]": 0.85719275200006, + "tests/aws/services/stepfunctions/v2/logs/test_logs.py::TestLogs::test_partial_log_levels[wait_seconds_path.json5_OFF_True]": 0.8595070640000131, + "tests/aws/services/stepfunctions/v2/mocking/test_aws_scenarios.py::TestBaseScenarios::test_lambda_sqs_integration_happy_path": 0.4649218040000278, + "tests/aws/services/stepfunctions/v2/mocking/test_aws_scenarios.py::TestBaseScenarios::test_lambda_sqs_integration_hybrid_path": 0.3859992779999857, + "tests/aws/services/stepfunctions/v2/mocking/test_aws_scenarios.py::TestBaseScenarios::test_lambda_sqs_integration_retry_path": 7.287881313000071, + "tests/aws/services/stepfunctions/v2/mocking/test_base_callbacks.py::TestBaseScenarios::test_sfn_start_execution_sync[SFN_SYNC2]": 1.5104381679999506, + "tests/aws/services/stepfunctions/v2/mocking/test_base_callbacks.py::TestBaseScenarios::test_sfn_start_execution_sync[SFN_SYNC]": 1.478903124000226, + "tests/aws/services/stepfunctions/v2/mocking/test_base_callbacks.py::TestBaseScenarios::test_sqs_wait_for_task_token": 1.449284513999828, + "tests/aws/services/stepfunctions/v2/mocking/test_base_callbacks.py::TestBaseScenarios::test_sqs_wait_for_task_token_task_failure": 1.4797105509999255, + "tests/aws/services/stepfunctions/v2/mocking/test_base_scenarios.py::TestBaseScenarios::test_dynamodb_put_get_item": 0.9850285460001942, + "tests/aws/services/stepfunctions/v2/mocking/test_base_scenarios.py::TestBaseScenarios::test_events_put_events": 0.9213897380001299, + "tests/aws/services/stepfunctions/v2/mocking/test_base_scenarios.py::TestBaseScenarios::test_lambda_invoke": 0.6459490959998675, + "tests/aws/services/stepfunctions/v2/mocking/test_base_scenarios.py::TestBaseScenarios::test_lambda_invoke_retries": 3.3871937600000592, + "tests/aws/services/stepfunctions/v2/mocking/test_base_scenarios.py::TestBaseScenarios::test_lambda_service_invoke": 0.9611778510001159, + "tests/aws/services/stepfunctions/v2/mocking/test_base_scenarios.py::TestBaseScenarios::test_lambda_service_invoke_sync_execution": 0.7098648070000309, + "tests/aws/services/stepfunctions/v2/mocking/test_base_scenarios.py::TestBaseScenarios::test_map_state_lambda": 2.443971835999946, + "tests/aws/services/stepfunctions/v2/mocking/test_base_scenarios.py::TestBaseScenarios::test_parallel_state_lambda": 1.143267556000069, + "tests/aws/services/stepfunctions/v2/mocking/test_base_scenarios.py::TestBaseScenarios::test_sns_publish_base": 0.9000230139998848, + "tests/aws/services/stepfunctions/v2/mocking/test_base_scenarios.py::TestBaseScenarios::test_sqs_send_message": 0.8943130230001088, + "tests/aws/services/stepfunctions/v2/mocking/test_mock_config_file.py::TestMockConfigFile::test_is_mock_config_flag_detected_set": 0.004498179000052005, + "tests/aws/services/stepfunctions/v2/mocking/test_mock_config_file.py::TestMockConfigFile::test_is_mock_config_flag_detected_unset": 0.006515632999935406, + "tests/aws/services/stepfunctions/v2/outputdecl/test_output.py::TestArgumentsBase::test_base_cases[BASE_DIRECT_EXPR]": 0.8565157799999952, + "tests/aws/services/stepfunctions/v2/outputdecl/test_output.py::TestArgumentsBase::test_base_cases[BASE_EMPTY]": 0.6196766530000559, + "tests/aws/services/stepfunctions/v2/outputdecl/test_output.py::TestArgumentsBase::test_base_cases[BASE_EXPR]": 0.9278250759998627, + "tests/aws/services/stepfunctions/v2/outputdecl/test_output.py::TestArgumentsBase::test_base_cases[BASE_LITERALS]": 1.0117282930001466, + "tests/aws/services/stepfunctions/v2/outputdecl/test_output.py::TestArgumentsBase::test_base_lambda[BASE_LAMBDA]": 2.6625980130002063, + "tests/aws/services/stepfunctions/v2/outputdecl/test_output.py::TestArgumentsBase::test_base_output_any_non_dict[BOOL]": 0.5990962449999415, + "tests/aws/services/stepfunctions/v2/outputdecl/test_output.py::TestArgumentsBase::test_base_output_any_non_dict[FLOAT]": 0.599402044000044, + "tests/aws/services/stepfunctions/v2/outputdecl/test_output.py::TestArgumentsBase::test_base_output_any_non_dict[INT]": 0.6076174589999255, + "tests/aws/services/stepfunctions/v2/outputdecl/test_output.py::TestArgumentsBase::test_base_output_any_non_dict[JSONATA_EXPR]": 0.81654504800008, + "tests/aws/services/stepfunctions/v2/outputdecl/test_output.py::TestArgumentsBase::test_base_output_any_non_dict[LIST_EMPY]": 0.5982697069999858, + "tests/aws/services/stepfunctions/v2/outputdecl/test_output.py::TestArgumentsBase::test_base_output_any_non_dict[LIST_RICH]": 0.8333995429999277, + "tests/aws/services/stepfunctions/v2/outputdecl/test_output.py::TestArgumentsBase::test_base_output_any_non_dict[NULL]": 0.6059017470000754, + "tests/aws/services/stepfunctions/v2/outputdecl/test_output.py::TestArgumentsBase::test_base_output_any_non_dict[STR_LIT]": 0.6162246929998219, + "tests/aws/services/stepfunctions/v2/outputdecl/test_output.py::TestArgumentsBase::test_base_task_lambda[BASE_TASK_LAMBDA]": 2.51585411699989, + "tests/aws/services/stepfunctions/v2/outputdecl/test_output.py::TestArgumentsBase::test_output_in_choice[CONDITION_FALSE]": 0.8268836849998706, + "tests/aws/services/stepfunctions/v2/outputdecl/test_output.py::TestArgumentsBase::test_output_in_choice[CONDITION_TRUE]": 0.8622091830001182, + "tests/aws/services/stepfunctions/v2/query_language/test_base_query_language.py::TestBaseQueryLanguage::test_base_query_language_field[JSONATA]": 0.4352644950000695, + "tests/aws/services/stepfunctions/v2/query_language/test_base_query_language.py::TestBaseQueryLanguage::test_base_query_language_field[JSON_PATH]": 0.4342592240000158, + "tests/aws/services/stepfunctions/v2/query_language/test_base_query_language.py::TestBaseQueryLanguage::test_jsonata_query_language_field_downgrade_exception": 0.0014316729999563904, + "tests/aws/services/stepfunctions/v2/query_language/test_base_query_language.py::TestBaseQueryLanguage::test_query_language_field_override[JSONATA_OVERRIDE]": 0.41461808400003974, + "tests/aws/services/stepfunctions/v2/query_language/test_base_query_language.py::TestBaseQueryLanguage::test_query_language_field_override[JSONATA_OVERRIDE_DEFAULT]": 0.412078612000073, + "tests/aws/services/stepfunctions/v2/query_language/test_mixed_query_language.py::TestMixedQueryLanguageFlow::test_lambda_task_resource_data_flow[TASK_LAMBDA_LEGACY_RESOURCE_JSONATA_TO_JSONPATH]": 2.270800948000101, + "tests/aws/services/stepfunctions/v2/query_language/test_mixed_query_language.py::TestMixedQueryLanguageFlow::test_lambda_task_resource_data_flow[TASK_LAMBDA_LEGACY_RESOURCE_JSONPATH_TO_JSONATA]": 2.253996518999884, + "tests/aws/services/stepfunctions/v2/query_language/test_mixed_query_language.py::TestMixedQueryLanguageFlow::test_lambda_task_resource_data_flow[TASK_LAMBDA_SDK_RESOURCE_JSONATA_TO_JSONPATH]": 2.5104426620000595, + "tests/aws/services/stepfunctions/v2/query_language/test_mixed_query_language.py::TestMixedQueryLanguageFlow::test_lambda_task_resource_data_flow[TASK_LAMBDA_SDK_RESOURCE_JSONPATH_TO_JSONATA]": 2.262945189999982, + "tests/aws/services/stepfunctions/v2/query_language/test_mixed_query_language.py::TestMixedQueryLanguageFlow::test_output_to_state[JSONATA_OUTPUT_TO_JSONPATH]": 0.7825480929999458, + "tests/aws/services/stepfunctions/v2/query_language/test_mixed_query_language.py::TestMixedQueryLanguageFlow::test_output_to_state[JSONPATH_OUTPUT_TO_JSONATA]": 0.7908677289999559, + "tests/aws/services/stepfunctions/v2/query_language/test_mixed_query_language.py::TestMixedQueryLanguageFlow::test_task_dataflow_to_state": 2.331101700000204, + "tests/aws/services/stepfunctions/v2/query_language/test_mixed_query_language.py::TestMixedQueryLanguageFlow::test_variable_sampling[JSONATA_ASSIGN_JSONPATH_REF]": 0.7950797889999421, + "tests/aws/services/stepfunctions/v2/query_language/test_mixed_query_language.py::TestMixedQueryLanguageFlow::test_variable_sampling[JSONPATH_ASSIGN_JSONATA_REF]": 0.6084580100000494, + "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_catch_empty": 2.1258660859999736, + "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_catch_states_runtime": 2.4124591620000047, + "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_choice_aws_docs_scenario[CHOICE_STATE_AWS_SCENARIO]": 0.7537995860000137, + "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_choice_aws_docs_scenario[CHOICE_STATE_AWS_SCENARIO_JSONATA]": 0.7489256409999143, + "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_choice_condition_constant_jsonata": 0.4593965430000253, + "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_choice_singleton_composite[CHOICE_STATE_SINGLETON_COMPOSITE]": 0.682107487000053, + "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_choice_singleton_composite[CHOICE_STATE_SINGLETON_COMPOSITE_JSONATA]": 0.6685266570001431, + "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_choice_singleton_composite[CHOICE_STATE_SINGLETON_COMPOSITE_LITERAL_JSONATA]": 0.6940128429998822, + "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_choice_unsorted_parameters_negative[CHOICE_STATE_UNSORTED_CHOICE_PARAMETERS]": 0.6766513829999212, + "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_choice_unsorted_parameters_negative[CHOICE_STATE_UNSORTED_CHOICE_PARAMETERS_JSONATA]": 0.6692178070001091, + "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_choice_unsorted_parameters_positive[CHOICE_STATE_UNSORTED_CHOICE_PARAMETERS]": 0.8506772340000452, + "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_choice_unsorted_parameters_positive[CHOICE_STATE_UNSORTED_CHOICE_PARAMETERS_JSONATA]": 0.7641094570000178, + "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_escape_sequence_parsing[ESCAPE_SEQUENCES_JSONATA_COMPARISON_ASSIGN]": 0.6632465460000958, + "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_escape_sequence_parsing[ESCAPE_SEQUENCES_JSONATA_COMPARISON_OUTPUT]": 0.6539519860000382, + "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_escape_sequence_parsing[ESCAPE_SEQUENCES_JSONPATH]": 0.6570053609998467, + "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_escape_sequence_parsing[ESCAPE_SEQUENCES_STRING_LITERALS]": 1.774072488999991, + "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_fail_cause_jsonata": 0.6194552560000375, + "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_fail_error_jsonata": 0.616403478000052, + "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_illegal_escapes[ESCAPE_SEQUENCES_ILLEGAL_INTRINSIC_FUNCTION]": 0.0015169109999533248, + "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_illegal_escapes[ESCAPE_SEQUENCES_ILLEGAL_INTRINSIC_FUNCTION_2]": 0.001550564000012855, + "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_invalid_jsonpath[INVALID_JSONPATH_IN_ERRORPATH]": 0.6638188289999789, + "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_invalid_jsonpath[INVALID_JSONPATH_IN_STRING_EXPR_CONTEXTPATH]": 0.6409136470001613, + "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_invalid_jsonpath[INVALID_JSONPATH_IN_STRING_EXPR_JSONPATH]": 0.6394653449999623, + "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_invalid_jsonpath[ST.INVALID_JSONPATH_IN_CAUSEPATH]": 0.6666008660000671, + "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_invalid_jsonpath[ST.INVALID_JSONPATH_IN_HEARTBEATSECONDSPATH]": 0.0013240140000334577, + "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_invalid_jsonpath[ST.INVALID_JSONPATH_IN_INPUTPATH]": 0.6257105940001111, + "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_invalid_jsonpath[ST.INVALID_JSONPATH_IN_OUTPUTPATH]": 0.6468296749999354, + "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_invalid_jsonpath[ST.INVALID_JSONPATH_IN_TIMEOUTSECONDSPATH]": 0.001428806999911103, + "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_lambda_empty_retry": 2.183717161000004, + "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_lambda_invoke_with_retry_base": 9.596061772000098, + "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_lambda_invoke_with_retry_extended_input": 9.738075471999991, + "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_lambda_service_invoke_with_retry_extended_input": 10.0268381489999, + "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_map_item_batching_base_json_max_per_batch_jsonata": 0.0015926810000337355, + "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_map_item_reader_base_csv_headers_decl": 0.8257868880000387, + "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_map_item_reader_base_csv_headers_first_line": 0.8200754729999744, + "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_map_item_reader_base_json": 0.7974556520000533, + "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_map_item_reader_base_json_max_items": 0.8476931740001419, + "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_map_item_reader_base_json_max_items_jsonata": 0.8544814759999326, + "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_map_item_reader_base_json_with_items_path[INVALID_ITEMS_PATH]": 0.8671537670001044, + "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_map_item_reader_base_json_with_items_path[VALID_ITEMS_PATH_FROM_ITEM_READER]": 0.8629255779999312, + "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_map_item_reader_base_json_with_items_path[VALID_ITEMS_PATH_FROM_PREVIOUS]": 0.9118303869998954, + "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_map_item_reader_base_list_objects_v2": 0.8157886590001908, + "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_map_item_reader_csv_first_row_extra_fields": 0.7903731699999526, + "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_map_item_reader_csv_headers_decl_duplicate_headers": 0.787734238999974, + "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_map_item_reader_csv_headers_decl_extra_fields": 0.78771610900003, + "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_map_item_reader_csv_headers_first_row_typed_headers": 0.7958535290000555, + "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_map_item_reader_csv_max_items[0]": 0.8215810080000665, + "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_map_item_reader_csv_max_items[100000000]": 0.7811037609999403, + "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_map_item_reader_csv_max_items[2]": 0.8058885340000188, + "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_map_item_reader_csv_max_items_paths[-1]": 0.8069669940000495, + "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_map_item_reader_csv_max_items_paths[0]": 0.7741167209999276, + "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_map_item_reader_csv_max_items_paths[1.5]": 0.017960853999966275, + "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_map_item_reader_csv_max_items_paths[100000000]": 0.7788026140000284, + "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_map_item_reader_csv_max_items_paths[100000001]": 0.8154565490000323, + "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_map_item_reader_csv_max_items_paths[2]": 0.7794856959999379, + "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_map_item_reader_json_no_json_list_object": 0.770710294999958, + "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_map_state": 0.8432103449999886, + "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_map_state_break_condition": 0.8542080670000587, + "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_map_state_break_condition_legacy": 0.883681700000011, + "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_map_state_catch": 0.7658226830000103, + "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_map_state_catch_empty_fail": 0.7668815289999884, + "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_map_state_catch_legacy": 0.7522838859999865, + "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_map_state_config_distributed_item_selector": 0.8009209409999585, + "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_map_state_config_distributed_item_selector_parameters": 1.068085822999933, + "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_map_state_config_distributed_items_path_from_previous": 0.7889239700000417, + "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_map_state_config_distributed_parameters": 0.804703969000002, + "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_map_state_config_distributed_reentrant": 1.4406893600000785, + "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_map_state_config_distributed_reentrant_lambda": 2.724264208000136, + "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_map_state_config_inline_item_selector": 0.7860973200000672, + "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_map_state_config_inline_parameters": 0.8210414730000366, + "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_map_state_item_selector[MAP_STATE_ITEM_SELECTOR]": 1.7329706230000284, + "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_map_state_item_selector[MAP_STATE_ITEM_SELECTOR_JSONATA]": 0.7717198610000651, + "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_map_state_item_selector_parameters": 1.0853433269999186, + "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_map_state_item_selector_singleton": 1.09245502400006, + "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_map_state_items_eval_jsonata[empty]": 0.6417151849999527, + "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_map_state_items_eval_jsonata[mixed]": 0.6719161620000023, + "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_map_state_items_eval_jsonata[singleton]": 0.6590245690000529, + "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_map_state_items_eval_jsonata_fail[boolean]": 1.71658656600016, + "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_map_state_items_eval_jsonata_fail[function]": 0.001453363999985413, + "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_map_state_items_eval_jsonata_fail[null]": 0.7101921029999403, + "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_map_state_items_eval_jsonata_fail[number]": 0.5350459969999974, + "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_map_state_items_eval_jsonata_fail[object]": 0.7017062759999817, + "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_map_state_items_eval_jsonata_fail[string]": 0.6985786380000718, + "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_map_state_items_eval_jsonata_variable_sampling_fail[boolean]": 0.721392933000061, + "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_map_state_items_eval_jsonata_variable_sampling_fail[null]": 0.7271091640001259, + "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_map_state_items_eval_jsonata_variable_sampling_fail[number]": 0.7692483060000086, + "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_map_state_items_eval_jsonata_variable_sampling_fail[object]": 0.7306621269999596, + "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_map_state_items_eval_jsonata_variable_sampling_fail[string]": 0.7253498249998529, + "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_map_state_items_input_array[empty]": 0.6682329929999469, + "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_map_state_items_input_array[mixed]": 0.7091676700000562, + "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_map_state_items_input_array[singleton]": 0.679793241000084, + "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_map_state_items_input_types[boolean]": 0.6560907530000577, + "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_map_state_items_input_types[null]": 0.8575762380000924, + "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_map_state_items_input_types[number]": 0.9289312989999416, + "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_map_state_items_input_types[object]": 0.8803756029999477, + "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_map_state_items_input_types[string]": 0.8518144079999956, + "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_map_state_items_variable_sampling[boolean]": 0.7322244840001986, + "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_map_state_items_variable_sampling[null]": 0.7331614480000326, + "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_map_state_items_variable_sampling[number]": 0.7339278449999256, + "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_map_state_items_variable_sampling[object]": 0.5429761970001437, + "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_map_state_items_variable_sampling[string]": 0.7294905369999469, + "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_map_state_label": 0.6892345830001432, + "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_map_state_legacy": 0.8386783539999669, + "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_map_state_legacy_config_distributed": 0.7451264469999614, + "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_map_state_legacy_config_distributed_item_selector": 0.783849411999995, + "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_map_state_legacy_config_distributed_parameters": 0.766857765000168, + "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_map_state_legacy_config_inline": 0.7772348749999765, + "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_map_state_legacy_config_inline_item_selector": 0.8111688850000291, + "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_map_state_legacy_config_inline_parameters": 0.8147210529999711, + "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_map_state_legacy_reentrant": 1.5157979589998831, + "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_map_state_nested": 0.8582524990000593, + "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_map_state_nested_config_distributed": 0.8366607350000095, + "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_map_state_nested_config_distributed_no_max_max_concurrency": 11.096241853000038, + "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_map_state_no_processor_config": 0.7555171359999804, + "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_map_state_parameters_legacy": 1.7431363249999094, + "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_map_state_parameters_singleton_legacy": 1.0814228069999672, + "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_map_state_result_writer": 0.9679549370000586, + "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_map_state_retry": 3.715458570999999, + "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_map_state_retry_legacy": 3.7319825869999477, + "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_map_state_retry_multiple_retriers": 7.753578466000022, + "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_map_state_tolerated_failure_count_path[-1]": 0.6948851330000707, + "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_map_state_tolerated_failure_count_path[0]": 0.6937183109999978, + "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_map_state_tolerated_failure_count_path[1]": 0.7215072169998393, + "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_map_state_tolerated_failure_count_path[NoNumber]": 0.6976194980001083, + "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_map_state_tolerated_failure_count_path[tolerated_failure_count_value0]": 0.7462855730000229, + "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_map_state_tolerated_failure_percentage_path[-1.1]": 0.6778342559998691, + "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_map_state_tolerated_failure_percentage_path[-1]": 0.6689009859998123, + "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_map_state_tolerated_failure_percentage_path[0]": 0.7161152920000404, + "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_map_state_tolerated_failure_percentage_path[1.1]": 0.6882725750000418, + "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_map_state_tolerated_failure_percentage_path[100.1]": 0.6724968180000133, + "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_map_state_tolerated_failure_percentage_path[100]": 0.6807517970000845, + "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_map_state_tolerated_failure_percentage_path[1]": 0.7083904380000376, + "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_map_state_tolerated_failure_percentage_path[NoNumber]": 0.6740306050000981, + "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_map_state_tolerated_failure_percentage_path[tolerated_failure_percentage_value0]": 0.7043530979999559, + "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_map_state_tolerated_failure_values[count_literal]": 0.6787886369999114, + "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_map_state_tolerated_failure_values[percentage_literal]": 0.7028972760000443, + "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_max_concurrency_path[0]": 0.6920890930000496, + "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_max_concurrency_path[1]": 0.7022614250000743, + "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_max_concurrency_path[NoNumber]": 0.6619229799999857, + "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_max_concurrency_path[max_concurrency_value0]": 0.6895781929999885, + "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_max_concurrency_path_negative": 0.7260900409999067, + "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_parallel_state[PARALLEL_STATE]": 0.7991212970000561, + "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_parallel_state[PARALLEL_STATE_PARAMETERS]": 0.7141865920000328, + "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_parallel_state_catch": 0.6907764900000757, + "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_parallel_state_fail": 0.657077496999932, + "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_parallel_state_nested": 0.9090290560000085, + "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_parallel_state_order": 0.7898281930001758, + "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_parallel_state_retry": 3.631920515000047, + "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_retry_interval_features": 6.550807052999971, + "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_retry_interval_features_jitter_none": 4.455392958999937, + "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_retry_interval_features_max_attempts_zero": 2.205439081999998, + "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_wait_seconds_jsonata": 0.4220421500000384, + "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_wait_timestamp[NANOSECONDS]": 0.4080955399998629, + "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_wait_timestamp[SECONDS]": 0.4215188779999153, + "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_wait_timestamp_invalid[INVALID_DATE]": 0.354175750999957, + "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_wait_timestamp_invalid[INVALID_ISO]": 0.3457314120000774, + "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_wait_timestamp_invalid[INVALID_TIME]": 0.3449061699999447, + "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_wait_timestamp_invalid[JSONATA]": 0.35548078700003316, + "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_wait_timestamp_invalid[NO_T]": 0.36989638399995783, + "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_wait_timestamp_invalid[NO_Z]": 0.34718054300003587, + "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_wait_timestamp_jsonata[INVALID_DATE]": 0.001255134999951224, + "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_wait_timestamp_jsonata[INVALID_ISO]": 0.0012106130000120174, + "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_wait_timestamp_jsonata[INVALID_TIME]": 0.001335714999981974, + "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_wait_timestamp_jsonata[NANOSECONDS]": 0.6345200830000977, + "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_wait_timestamp_jsonata[NO_T]": 0.0014879689999816037, + "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_wait_timestamp_jsonata[NO_Z]": 0.0012779280000358995, + "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_wait_timestamp_jsonata[SECONDS]": 0.6811168309999402, + "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_wait_timestamp_path[INVALID_DATE]": 0.641259122000065, + "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_wait_timestamp_path[INVALID_ISO]": 0.6425941260000627, + "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_wait_timestamp_path[INVALID_TIME]": 0.44567078800002946, + "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_wait_timestamp_path[NANOSECONDS]": 0.6462392830001136, + "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_wait_timestamp_path[NO_T]": 0.6466972619999751, + "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_wait_timestamp_path[NO_Z]": 0.6373484059998873, + "tests/aws/services/stepfunctions/v2/scenarios/test_base_scenarios.py::TestBaseScenarios::test_wait_timestamp_path[SECONDS]": 0.655332493999822, + "tests/aws/services/stepfunctions/v2/scenarios/test_sfn_scenarios.py::TestFundamental::test_path_based_on_data": 8.525910078999914, + "tests/aws/services/stepfunctions/v2/scenarios/test_sfn_scenarios.py::TestFundamental::test_step_functions_calling_api_gateway": 13.399877156000002, + "tests/aws/services/stepfunctions/v2/scenarios/test_sfn_scenarios.py::TestFundamental::test_wait_for_callback": 21.502328047000105, + "tests/aws/services/stepfunctions/v2/services/test_apigetway_task_service.py::TestTaskApiGateway::test_invoke_base": 2.978728528000147, + "tests/aws/services/stepfunctions/v2/services/test_apigetway_task_service.py::TestTaskApiGateway::test_invoke_error": 2.6306461910000962, + "tests/aws/services/stepfunctions/v2/services/test_apigetway_task_service.py::TestTaskApiGateway::test_invoke_with_body_post[HelloWorld]": 2.977694278000172, + "tests/aws/services/stepfunctions/v2/services/test_apigetway_task_service.py::TestTaskApiGateway::test_invoke_with_body_post[None]": 2.973088604000168, + "tests/aws/services/stepfunctions/v2/services/test_apigetway_task_service.py::TestTaskApiGateway::test_invoke_with_body_post[]": 2.9838867619998837, + "tests/aws/services/stepfunctions/v2/services/test_apigetway_task_service.py::TestTaskApiGateway::test_invoke_with_body_post[request_body3]": 2.9643499080002584, + "tests/aws/services/stepfunctions/v2/services/test_apigetway_task_service.py::TestTaskApiGateway::test_invoke_with_headers[custom_header1]": 3.0003308660004677, + "tests/aws/services/stepfunctions/v2/services/test_apigetway_task_service.py::TestTaskApiGateway::test_invoke_with_headers[custom_header2]": 3.040210503000253, + "tests/aws/services/stepfunctions/v2/services/test_apigetway_task_service.py::TestTaskApiGateway::test_invoke_with_headers[singleStringHeader]": 0.002461710000034145, + "tests/aws/services/stepfunctions/v2/services/test_apigetway_task_service.py::TestTaskApiGateway::test_invoke_with_query_parameters": 3.1116020980000485, + "tests/aws/services/stepfunctions/v2/services/test_aws_sdk_task_service.py::TestTaskServiceAwsSdk::test_dynamodb_put_delete_item": 1.0046548470002108, + "tests/aws/services/stepfunctions/v2/services/test_aws_sdk_task_service.py::TestTaskServiceAwsSdk::test_dynamodb_put_get_item": 1.2152030489999106, + "tests/aws/services/stepfunctions/v2/services/test_aws_sdk_task_service.py::TestTaskServiceAwsSdk::test_dynamodb_put_update_get_item": 1.3682963510000263, + "tests/aws/services/stepfunctions/v2/services/test_aws_sdk_task_service.py::TestTaskServiceAwsSdk::test_list_secrets": 0.8629939989998547, + "tests/aws/services/stepfunctions/v2/services/test_aws_sdk_task_service.py::TestTaskServiceAwsSdk::test_s3_get_object[binary]": 1.015403847000016, + "tests/aws/services/stepfunctions/v2/services/test_aws_sdk_task_service.py::TestTaskServiceAwsSdk::test_s3_get_object[bytearray]": 2.2309794389998387, + "tests/aws/services/stepfunctions/v2/services/test_aws_sdk_task_service.py::TestTaskServiceAwsSdk::test_s3_get_object[empty_binary]": 1.056208166000033, + "tests/aws/services/stepfunctions/v2/services/test_aws_sdk_task_service.py::TestTaskServiceAwsSdk::test_s3_get_object[empty_str]": 1.0946390289998362, + "tests/aws/services/stepfunctions/v2/services/test_aws_sdk_task_service.py::TestTaskServiceAwsSdk::test_s3_get_object[str]": 1.0297221479995642, + "tests/aws/services/stepfunctions/v2/services/test_aws_sdk_task_service.py::TestTaskServiceAwsSdk::test_s3_put_object[bool]": 1.098107974999948, + "tests/aws/services/stepfunctions/v2/services/test_aws_sdk_task_service.py::TestTaskServiceAwsSdk::test_s3_put_object[dict]": 1.0846987019997414, + "tests/aws/services/stepfunctions/v2/services/test_aws_sdk_task_service.py::TestTaskServiceAwsSdk::test_s3_put_object[list]": 1.0825935170000776, + "tests/aws/services/stepfunctions/v2/services/test_aws_sdk_task_service.py::TestTaskServiceAwsSdk::test_s3_put_object[num]": 1.0818839270000353, + "tests/aws/services/stepfunctions/v2/services/test_aws_sdk_task_service.py::TestTaskServiceAwsSdk::test_s3_put_object[str]": 1.0930626490001032, + "tests/aws/services/stepfunctions/v2/services/test_aws_sdk_task_service.py::TestTaskServiceAwsSdk::test_sfn_send_task_outcome_with_no_such_token[state_machine_template0]": 0.8539934289997291, + "tests/aws/services/stepfunctions/v2/services/test_aws_sdk_task_service.py::TestTaskServiceAwsSdk::test_sfn_send_task_outcome_with_no_such_token[state_machine_template1]": 0.8465384029998404, + "tests/aws/services/stepfunctions/v2/services/test_aws_sdk_task_service.py::TestTaskServiceAwsSdk::test_sfn_start_execution": 0.915937920000033, + "tests/aws/services/stepfunctions/v2/services/test_aws_sdk_task_service.py::TestTaskServiceAwsSdk::test_sfn_start_execution_implicit_json_serialisation": 0.9958073200000399, + "tests/aws/services/stepfunctions/v2/services/test_dynamodb_task_service.py::TestTaskServiceDynamoDB::test_base_integrations[DYNAMODB_PUT_DELETE_ITEM]": 1.0037659009999516, + "tests/aws/services/stepfunctions/v2/services/test_dynamodb_task_service.py::TestTaskServiceDynamoDB::test_base_integrations[DYNAMODB_PUT_GET_ITEM]": 0.9714120390001426, + "tests/aws/services/stepfunctions/v2/services/test_dynamodb_task_service.py::TestTaskServiceDynamoDB::test_base_integrations[DYNAMODB_PUT_QUERY]": 1.2190684070001225, + "tests/aws/services/stepfunctions/v2/services/test_dynamodb_task_service.py::TestTaskServiceDynamoDB::test_base_integrations[DYNAMODB_PUT_UPDATE_GET_ITEM]": 1.3446013719999428, + "tests/aws/services/stepfunctions/v2/services/test_dynamodb_task_service.py::TestTaskServiceDynamoDB::test_invalid_integration": 0.5198966529999325, + "tests/aws/services/stepfunctions/v2/services/test_ecs_task_service.py::TestTaskServiceECS::test_run_task": 0.0014105239999935293, + "tests/aws/services/stepfunctions/v2/services/test_ecs_task_service.py::TestTaskServiceECS::test_run_task_raise_failure": 0.0013457939999170776, + "tests/aws/services/stepfunctions/v2/services/test_ecs_task_service.py::TestTaskServiceECS::test_run_task_sync": 0.0013249849998828722, + "tests/aws/services/stepfunctions/v2/services/test_ecs_task_service.py::TestTaskServiceECS::test_run_task_sync_raise_failure": 0.0012906510000902927, + "tests/aws/services/stepfunctions/v2/services/test_events_task_service.py::TestTaskServiceEvents::test_put_events_base": 1.9750714250001238, + "tests/aws/services/stepfunctions/v2/services/test_events_task_service.py::TestTaskServiceEvents::test_put_events_malformed_detail": 0.870598604999941, + "tests/aws/services/stepfunctions/v2/services/test_events_task_service.py::TestTaskServiceEvents::test_put_events_mixed_malformed_detail": 0.9015939409998737, + "tests/aws/services/stepfunctions/v2/services/test_events_task_service.py::TestTaskServiceEvents::test_put_events_no_source": 31.013957537999886, + "tests/aws/services/stepfunctions/v2/services/test_lambda_task.py::TestTaskLambda::test_invoke_bytes_payload": 2.0451227040000504, + "tests/aws/services/stepfunctions/v2/services/test_lambda_task.py::TestTaskLambda::test_invoke_json_values[0.0]": 2.077203504000181, + "tests/aws/services/stepfunctions/v2/services/test_lambda_task.py::TestTaskLambda::test_invoke_json_values[0_0]": 2.0493138610002006, + "tests/aws/services/stepfunctions/v2/services/test_lambda_task.py::TestTaskLambda::test_invoke_json_values[0_1]": 2.0530038009999316, + "tests/aws/services/stepfunctions/v2/services/test_lambda_task.py::TestTaskLambda::test_invoke_json_values[HelloWorld]": 2.0617401960000734, + "tests/aws/services/stepfunctions/v2/services/test_lambda_task.py::TestTaskLambda::test_invoke_json_values[True]": 2.0501758319999226, + "tests/aws/services/stepfunctions/v2/services/test_lambda_task.py::TestTaskLambda::test_invoke_json_values[json_value5]": 2.0835334739997506, + "tests/aws/services/stepfunctions/v2/services/test_lambda_task.py::TestTaskLambda::test_invoke_json_values[json_value6]": 2.045453359000021, + "tests/aws/services/stepfunctions/v2/services/test_lambda_task.py::TestTaskLambda::test_invoke_pipe": 3.7522378619999017, + "tests/aws/services/stepfunctions/v2/services/test_lambda_task.py::TestTaskLambda::test_invoke_string_payload": 2.0775800480000726, + "tests/aws/services/stepfunctions/v2/services/test_lambda_task.py::TestTaskLambda::test_lambda_task_filter_parameters_input": 2.146494283000038, + "tests/aws/services/stepfunctions/v2/services/test_lambda_task_service.py::TestTaskServiceLambda::test_invoke": 2.4905850289999307, + "tests/aws/services/stepfunctions/v2/services/test_lambda_task_service.py::TestTaskServiceLambda::test_invoke_bytes_payload": 2.2899421140000413, + "tests/aws/services/stepfunctions/v2/services/test_lambda_task_service.py::TestTaskServiceLambda::test_invoke_json_values[0.0]": 2.539797380999971, + "tests/aws/services/stepfunctions/v2/services/test_lambda_task_service.py::TestTaskServiceLambda::test_invoke_json_values[0_0]": 2.3666762539999127, + "tests/aws/services/stepfunctions/v2/services/test_lambda_task_service.py::TestTaskServiceLambda::test_invoke_json_values[0_1]": 2.521461226000156, + "tests/aws/services/stepfunctions/v2/services/test_lambda_task_service.py::TestTaskServiceLambda::test_invoke_json_values[HelloWorld]": 2.5336736459998974, + "tests/aws/services/stepfunctions/v2/services/test_lambda_task_service.py::TestTaskServiceLambda::test_invoke_json_values[True]": 2.320306366000068, + "tests/aws/services/stepfunctions/v2/services/test_lambda_task_service.py::TestTaskServiceLambda::test_invoke_json_values[json_value5]": 2.5070964139999887, + "tests/aws/services/stepfunctions/v2/services/test_lambda_task_service.py::TestTaskServiceLambda::test_invoke_json_values[json_value6]": 2.572920606000025, + "tests/aws/services/stepfunctions/v2/services/test_lambda_task_service.py::TestTaskServiceLambda::test_invoke_unsupported_param": 2.5388529829999698, + "tests/aws/services/stepfunctions/v2/services/test_lambda_task_service.py::TestTaskServiceLambda::test_list_functions": 0.0016159069998593623, + "tests/aws/services/stepfunctions/v2/services/test_sfn_task_service.py::TestTaskServiceSfn::test_start_execution": 0.9429495130000305, + "tests/aws/services/stepfunctions/v2/services/test_sfn_task_service.py::TestTaskServiceSfn::test_start_execution_input_json": 2.249640737000391, + "tests/aws/services/stepfunctions/v2/services/test_sns_task_service.py::TestTaskServiceSns::test_fifo_message_attribute[input_params0-True]": 0.8859050380001463, + "tests/aws/services/stepfunctions/v2/services/test_sns_task_service.py::TestTaskServiceSns::test_fifo_message_attribute[input_params1-False]": 0.9171690229998148, + "tests/aws/services/stepfunctions/v2/services/test_sns_task_service.py::TestTaskServiceSns::test_publish_base[1]": 0.8620628969999871, + "tests/aws/services/stepfunctions/v2/services/test_sns_task_service.py::TestTaskServiceSns::test_publish_base[HelloWorld]": 0.8498827190001066, + "tests/aws/services/stepfunctions/v2/services/test_sns_task_service.py::TestTaskServiceSns::test_publish_base[None]": 0.8872691839999334, + "tests/aws/services/stepfunctions/v2/services/test_sns_task_service.py::TestTaskServiceSns::test_publish_base[True]": 0.9035265850000087, + "tests/aws/services/stepfunctions/v2/services/test_sns_task_service.py::TestTaskServiceSns::test_publish_base[]": 0.895389631000171, + "tests/aws/services/stepfunctions/v2/services/test_sns_task_service.py::TestTaskServiceSns::test_publish_base[message1]": 0.8662667210001018, + "tests/aws/services/stepfunctions/v2/services/test_sns_task_service.py::TestTaskServiceSns::test_publish_base_error_topic_arn": 0.8711489669997263, + "tests/aws/services/stepfunctions/v2/services/test_sns_task_service.py::TestTaskServiceSns::test_publish_message_attributes[\"HelloWorld\"]": 0.9669459040001129, + "tests/aws/services/stepfunctions/v2/services/test_sns_task_service.py::TestTaskServiceSns::test_publish_message_attributes[HelloWorld]": 1.0336747189999187, + "tests/aws/services/stepfunctions/v2/services/test_sns_task_service.py::TestTaskServiceSns::test_publish_message_attributes[message_value3]": 0.9907786109999961, + "tests/aws/services/stepfunctions/v2/services/test_sns_task_service.py::TestTaskServiceSns::test_publish_message_attributes[{}]": 0.9722182850000536, + "tests/aws/services/stepfunctions/v2/services/test_sqs_task_service.py::TestTaskServiceSqs::test_send_message": 1.0059260650000397, + "tests/aws/services/stepfunctions/v2/services/test_sqs_task_service.py::TestTaskServiceSqs::test_send_message_attributes": 1.061620038000001, + "tests/aws/services/stepfunctions/v2/services/test_sqs_task_service.py::TestTaskServiceSqs::test_send_message_unsupported_parameters": 1.022527104999881, + "tests/aws/services/stepfunctions/v2/states_variables/test_error_output.py::TestStateVariablesTemplate::test_catch_error_variable_sampling[TASK_CATCH_ERROR_VARIABLE_SAMPLING]": 2.2851763609999125, + "tests/aws/services/stepfunctions/v2/states_variables/test_error_output.py::TestStateVariablesTemplate::test_catch_error_variable_sampling[TASK_CATCH_ERROR_VARIABLE_SAMPLING_TO_JSONPATH]": 2.2795353289998275, + "tests/aws/services/stepfunctions/v2/states_variables/test_error_output.py::TestStateVariablesTemplate::test_map_catch_error[MAP_CATCH_ERROR_OUTPUT]": 0.001723113000025478, + "tests/aws/services/stepfunctions/v2/states_variables/test_error_output.py::TestStateVariablesTemplate::test_map_catch_error[MAP_CATCH_ERROR_OUTPUT_WITH_RETRY]": 0.0013117160001456796, + "tests/aws/services/stepfunctions/v2/states_variables/test_error_output.py::TestStateVariablesTemplate::test_map_catch_error[MAP_CATCH_ERROR_VARIABLE_SAMPLING]": 0.0014117320001787448, + "tests/aws/services/stepfunctions/v2/states_variables/test_error_output.py::TestStateVariablesTemplate::test_parallel_catch_error[PARALLEL_CATCH_ERROR_OUTPUT]": 0.0014204189999418304, + "tests/aws/services/stepfunctions/v2/states_variables/test_error_output.py::TestStateVariablesTemplate::test_parallel_catch_error[PARALLEL_CATCH_ERROR_OUTPUT_WITH_RETRY]": 0.0012970069999482803, + "tests/aws/services/stepfunctions/v2/states_variables/test_error_output.py::TestStateVariablesTemplate::test_parallel_catch_error[PARALLEL_CATCH_ERROR_VARIABLE_SAMPLING]": 0.0013980779999656079, + "tests/aws/services/stepfunctions/v2/states_variables/test_error_output.py::TestStateVariablesTemplate::test_task_catch_error_output[TASK_CATCH_ERROR_OUTPUT]": 2.5425632550000046, + "tests/aws/services/stepfunctions/v2/states_variables/test_error_output.py::TestStateVariablesTemplate::test_task_catch_error_output[TASK_CATCH_ERROR_OUTPUT_TO_JSONPATH]": 2.286581460000207, + "tests/aws/services/stepfunctions/v2/states_variables/test_error_output.py::TestStateVariablesTemplate::test_task_catch_error_with_retry[TASK_CATCH_ERROR_OUTPUT_WITH_RETRY]": 3.6223718720000306, + "tests/aws/services/stepfunctions/v2/states_variables/test_error_output.py::TestStateVariablesTemplate::test_task_catch_error_with_retry[TASK_CATCH_ERROR_OUTPUT_WITH_RETRY_TO_JSONPATH]": 3.517191249000007, + "tests/aws/services/stepfunctions/v2/test_sfn_api.py::TestSnfApi::test_cloudformation_definition_create_describe[dump]": 1.455828449999899, + "tests/aws/services/stepfunctions/v2/test_sfn_api.py::TestSnfApi::test_cloudformation_definition_create_describe[dumps]": 1.5074513570000363, + "tests/aws/services/stepfunctions/v2/test_sfn_api.py::TestSnfApi::test_cloudformation_definition_string_create_describe[dump]": 1.447662697999931, + "tests/aws/services/stepfunctions/v2/test_sfn_api.py::TestSnfApi::test_cloudformation_definition_string_create_describe[dumps]": 2.4545108800000435, + "tests/aws/services/stepfunctions/v2/test_sfn_api.py::TestSnfApi::test_create_delete_invalid_sm": 0.4661109989999659, + "tests/aws/services/stepfunctions/v2/test_sfn_api.py::TestSnfApi::test_create_delete_valid_sm": 1.5502120230000855, + "tests/aws/services/stepfunctions/v2/test_sfn_api.py::TestSnfApi::test_create_duplicate_definition_format_sm": 0.40055327999994006, + "tests/aws/services/stepfunctions/v2/test_sfn_api.py::TestSnfApi::test_create_duplicate_sm_name": 0.3913319490000049, + "tests/aws/services/stepfunctions/v2/test_sfn_api.py::TestSnfApi::test_create_exact_duplicate_sm": 0.4290000799999234, + "tests/aws/services/stepfunctions/v2/test_sfn_api.py::TestSnfApi::test_create_update_state_machine_base_definition": 0.45521460700001626, + "tests/aws/services/stepfunctions/v2/test_sfn_api.py::TestSnfApi::test_create_update_state_machine_base_definition_and_role": 0.5969184049999967, + "tests/aws/services/stepfunctions/v2/test_sfn_api.py::TestSnfApi::test_create_update_state_machine_base_role_arn": 0.5777497849999236, + "tests/aws/services/stepfunctions/v2/test_sfn_api.py::TestSnfApi::test_create_update_state_machine_base_update_none": 0.4014350499999182, + "tests/aws/services/stepfunctions/v2/test_sfn_api.py::TestSnfApi::test_create_update_state_machine_same_parameters": 0.5165326989999812, + "tests/aws/services/stepfunctions/v2/test_sfn_api.py::TestSnfApi::test_delete_nonexistent_sm": 0.3715536020001764, + "tests/aws/services/stepfunctions/v2/test_sfn_api.py::TestSnfApi::test_describe_execution": 0.6318914969999696, + "tests/aws/services/stepfunctions/v2/test_sfn_api.py::TestSnfApi::test_describe_execution_arn_containing_punctuation": 0.6245696249998218, + "tests/aws/services/stepfunctions/v2/test_sfn_api.py::TestSnfApi::test_describe_execution_invalid_arn": 0.33634016199971484, + "tests/aws/services/stepfunctions/v2/test_sfn_api.py::TestSnfApi::test_describe_execution_no_such_state_machine": 0.6491895859999204, + "tests/aws/services/stepfunctions/v2/test_sfn_api.py::TestSnfApi::test_describe_invalid_arn_sm": 0.3349278539999432, + "tests/aws/services/stepfunctions/v2/test_sfn_api.py::TestSnfApi::test_describe_nonexistent_sm": 0.38232449099973564, + "tests/aws/services/stepfunctions/v2/test_sfn_api.py::TestSnfApi::test_describe_sm_arn_containing_punctuation": 0.3786171080002987, + "tests/aws/services/stepfunctions/v2/test_sfn_api.py::TestSnfApi::test_describe_state_machine_for_execution": 0.4436429790000602, + "tests/aws/services/stepfunctions/v2/test_sfn_api.py::TestSnfApi::test_get_execution_history_invalid_arn": 0.3221701039999516, + "tests/aws/services/stepfunctions/v2/test_sfn_api.py::TestSnfApi::test_get_execution_history_no_such_execution": 0.43469368700016275, + "tests/aws/services/stepfunctions/v2/test_sfn_api.py::TestSnfApi::test_get_execution_history_reversed": 0.47089356200012844, + "tests/aws/services/stepfunctions/v2/test_sfn_api.py::TestSnfApi::test_invalid_start_execution_arn": 0.37151989700009835, + "tests/aws/services/stepfunctions/v2/test_sfn_api.py::TestSnfApi::test_invalid_start_execution_input": 0.6884124250002515, + "tests/aws/services/stepfunctions/v2/test_sfn_api.py::TestSnfApi::test_list_execution_invalid_arn": 0.33663754499980314, + "tests/aws/services/stepfunctions/v2/test_sfn_api.py::TestSnfApi::test_list_execution_no_such_state_machine": 0.37454473200000393, + "tests/aws/services/stepfunctions/v2/test_sfn_api.py::TestSnfApi::test_list_executions_pagination": 1.2949013369998283, + "tests/aws/services/stepfunctions/v2/test_sfn_api.py::TestSnfApi::test_list_executions_versions_pagination": 1.4038130930002808, + "tests/aws/services/stepfunctions/v2/test_sfn_api.py::TestSnfApi::test_list_sms": 0.5269642559999284, + "tests/aws/services/stepfunctions/v2/test_sfn_api.py::TestSnfApi::test_list_sms_pagination": 0.870764551999855, + "tests/aws/services/stepfunctions/v2/test_sfn_api.py::TestSnfApi::test_start_execution": 0.5319297689995892, + "tests/aws/services/stepfunctions/v2/test_sfn_api.py::TestSnfApi::test_start_execution_idempotent": 1.1434892390000186, + "tests/aws/services/stepfunctions/v2/test_sfn_api.py::TestSnfApi::test_start_sync_execution": 0.41012675399997534, + "tests/aws/services/stepfunctions/v2/test_sfn_api.py::TestSnfApi::test_state_machine_status_filter": 0.5427347660001942, + "tests/aws/services/stepfunctions/v2/test_sfn_api.py::TestSnfApi::test_stop_execution": 0.45740701900012937, + "tests/aws/services/stepfunctions/v2/test_sfn_api_activities.py::TestSnfApiActivities::test_create_activity_invalid_name[\\x00activity]": 0.2694624930002192, + "tests/aws/services/stepfunctions/v2/test_sfn_api_activities.py::TestSnfApiActivities::test_create_activity_invalid_name[activity name]": 0.26439781300018694, + "tests/aws/services/stepfunctions/v2/test_sfn_api_activities.py::TestSnfApiActivities::test_create_activity_invalid_name[activity\"name]": 0.26594500999976844, + "tests/aws/services/stepfunctions/v2/test_sfn_api_activities.py::TestSnfApiActivities::test_create_activity_invalid_name[activity#name]": 0.26864252000018496, + "tests/aws/services/stepfunctions/v2/test_sfn_api_activities.py::TestSnfApiActivities::test_create_activity_invalid_name[activity$name]": 0.2727922680001029, + "tests/aws/services/stepfunctions/v2/test_sfn_api_activities.py::TestSnfApiActivities::test_create_activity_invalid_name[activity%name]": 0.2672791340000913, + "tests/aws/services/stepfunctions/v2/test_sfn_api_activities.py::TestSnfApiActivities::test_create_activity_invalid_name[activity&name]": 0.2652647369998249, + "tests/aws/services/stepfunctions/v2/test_sfn_api_activities.py::TestSnfApiActivities::test_create_activity_invalid_name[activity*name]": 0.2693485109998619, + "tests/aws/services/stepfunctions/v2/test_sfn_api_activities.py::TestSnfApiActivities::test_create_activity_invalid_name[activity,name]": 0.27638648100014507, + "tests/aws/services/stepfunctions/v2/test_sfn_api_activities.py::TestSnfApiActivities::test_create_activity_invalid_name[activity/name]": 0.2740626130000692, + "tests/aws/services/stepfunctions/v2/test_sfn_api_activities.py::TestSnfApiActivities::test_create_activity_invalid_name[activity:name]": 0.26993699500008006, + "tests/aws/services/stepfunctions/v2/test_sfn_api_activities.py::TestSnfApiActivities::test_create_activity_invalid_name[activity;name]": 0.27830236800014063, + "tests/aws/services/stepfunctions/v2/test_sfn_api_activities.py::TestSnfApiActivities::test_create_activity_invalid_name[activityname]": 0.26855861599983655, + "tests/aws/services/stepfunctions/v2/test_sfn_api_activities.py::TestSnfApiActivities::test_create_activity_invalid_name[activity?name]": 0.2712787440000284, + "tests/aws/services/stepfunctions/v2/test_sfn_api_activities.py::TestSnfApiActivities::test_create_activity_invalid_name[activity[name]": 0.26982070199983355, + "tests/aws/services/stepfunctions/v2/test_sfn_api_activities.py::TestSnfApiActivities::test_create_activity_invalid_name[activity\\\\name]": 0.26892137800018645, + "tests/aws/services/stepfunctions/v2/test_sfn_api_activities.py::TestSnfApiActivities::test_create_activity_invalid_name[activity\\x1f]": 0.26962413699993704, + "tests/aws/services/stepfunctions/v2/test_sfn_api_activities.py::TestSnfApiActivities::test_create_activity_invalid_name[activity\\x7f]": 0.2797547980001127, + "tests/aws/services/stepfunctions/v2/test_sfn_api_activities.py::TestSnfApiActivities::test_create_activity_invalid_name[activity]name]": 0.2645891119998396, + "tests/aws/services/stepfunctions/v2/test_sfn_api_activities.py::TestSnfApiActivities::test_create_activity_invalid_name[activity^name]": 0.27367608200006543, + "tests/aws/services/stepfunctions/v2/test_sfn_api_activities.py::TestSnfApiActivities::test_create_activity_invalid_name[activity`name]": 0.2742184400001406, + "tests/aws/services/stepfunctions/v2/test_sfn_api_activities.py::TestSnfApiActivities::test_create_activity_invalid_name[activity{name]": 0.26574337600004583, + "tests/aws/services/stepfunctions/v2/test_sfn_api_activities.py::TestSnfApiActivities::test_create_activity_invalid_name[activity|name]": 0.2732202839997626, + "tests/aws/services/stepfunctions/v2/test_sfn_api_activities.py::TestSnfApiActivities::test_create_activity_invalid_name[activity}name]": 0.2718794780000735, + "tests/aws/services/stepfunctions/v2/test_sfn_api_activities.py::TestSnfApiActivities::test_create_activity_invalid_name[activity~name]": 0.2812859360001312, + "tests/aws/services/stepfunctions/v2/test_sfn_api_activities.py::TestSnfApiActivities::test_create_describe_delete_activity[ACTIVITY_NAME_ABC]": 0.36404359900029704, + "tests/aws/services/stepfunctions/v2/test_sfn_api_activities.py::TestSnfApiActivities::test_create_describe_delete_activity[Activity1]": 0.3488405200002944, + "tests/aws/services/stepfunctions/v2/test_sfn_api_activities.py::TestSnfApiActivities::test_create_describe_delete_activity[aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa]": 0.3364496690001033, + "tests/aws/services/stepfunctions/v2/test_sfn_api_activities.py::TestSnfApiActivities::test_create_describe_delete_activity[activity-name.1]": 0.3446965629998431, + "tests/aws/services/stepfunctions/v2/test_sfn_api_activities.py::TestSnfApiActivities::test_create_describe_delete_activity[activity-name_123]": 0.3587593030001699, + "tests/aws/services/stepfunctions/v2/test_sfn_api_activities.py::TestSnfApiActivities::test_create_describe_delete_activity[activity.name.v2]": 0.34000516900005096, + "tests/aws/services/stepfunctions/v2/test_sfn_api_activities.py::TestSnfApiActivities::test_create_describe_delete_activity[activity.name]": 0.3358813890001784, + "tests/aws/services/stepfunctions/v2/test_sfn_api_activities.py::TestSnfApiActivities::test_create_describe_delete_activity[activityName.with.dots]": 0.34054381299984016, + "tests/aws/services/stepfunctions/v2/test_sfn_api_activities.py::TestSnfApiActivities::test_create_describe_delete_activity[activity_123.name]": 0.3461990840000908, + "tests/aws/services/stepfunctions/v2/test_sfn_api_activities.py::TestSnfApiActivities::test_describe_activity_invalid_arn": 0.34742549700013114, + "tests/aws/services/stepfunctions/v2/test_sfn_api_activities.py::TestSnfApiActivities::test_describe_deleted_activity": 0.3038433240001268, + "tests/aws/services/stepfunctions/v2/test_sfn_api_activities.py::TestSnfApiActivities::test_get_activity_task_deleted": 0.29910061999999016, + "tests/aws/services/stepfunctions/v2/test_sfn_api_activities.py::TestSnfApiActivities::test_get_activity_task_invalid_arn": 0.36540262600010465, + "tests/aws/services/stepfunctions/v2/test_sfn_api_activities.py::TestSnfApiActivities::test_list_activities": 0.30509806399982153, + "tests/aws/services/stepfunctions/v2/test_sfn_api_aliasing.py::TestSfnApiAliasing::test_base_create_alias_single_router_config": 0.5769438019997324, + "tests/aws/services/stepfunctions/v2/test_sfn_api_aliasing.py::TestSfnApiAliasing::test_base_lifecycle_create_delete_list": 0.766673055000183, + "tests/aws/services/stepfunctions/v2/test_sfn_api_aliasing.py::TestSfnApiAliasing::test_base_lifecycle_create_invoke_describe_list": 0.7660878160002085, + "tests/aws/services/stepfunctions/v2/test_sfn_api_aliasing.py::TestSfnApiAliasing::test_base_lifecycle_create_update_describe": 0.6879029660001379, + "tests/aws/services/stepfunctions/v2/test_sfn_api_aliasing.py::TestSfnApiAliasing::test_delete_no_such_alias_arn": 0.5915638789999775, + "tests/aws/services/stepfunctions/v2/test_sfn_api_aliasing.py::TestSfnApiAliasing::test_delete_revision_with_alias": 0.5749963620000926, + "tests/aws/services/stepfunctions/v2/test_sfn_api_aliasing.py::TestSfnApiAliasing::test_delete_version_with_alias": 1.8059554810001828, + "tests/aws/services/stepfunctions/v2/test_sfn_api_aliasing.py::TestSfnApiAliasing::test_error_create_alias_invalid_name": 0.6105705269997088, + "tests/aws/services/stepfunctions/v2/test_sfn_api_aliasing.py::TestSfnApiAliasing::test_error_create_alias_invalid_router_configs": 0.6439699699997163, + "tests/aws/services/stepfunctions/v2/test_sfn_api_aliasing.py::TestSfnApiAliasing::test_error_create_alias_not_idempotent": 0.6121604970001044, + "tests/aws/services/stepfunctions/v2/test_sfn_api_aliasing.py::TestSfnApiAliasing::test_error_create_alias_with_state_machine_arn": 0.5874254679999922, + "tests/aws/services/stepfunctions/v2/test_sfn_api_aliasing.py::TestSfnApiAliasing::test_idempotent_create_alias": 0.6202524850000373, + "tests/aws/services/stepfunctions/v2/test_sfn_api_aliasing.py::TestSfnApiAliasing::test_list_state_machine_aliases_pagination_invalid_next_token": 0.6192526289999023, + "tests/aws/services/stepfunctions/v2/test_sfn_api_aliasing.py::TestSfnApiAliasing::test_list_state_machine_aliases_pagination_max_results[0]": 0.7004264319998583, + "tests/aws/services/stepfunctions/v2/test_sfn_api_aliasing.py::TestSfnApiAliasing::test_list_state_machine_aliases_pagination_max_results[1]": 0.6940009019999707, + "tests/aws/services/stepfunctions/v2/test_sfn_api_aliasing.py::TestSfnApiAliasing::test_update_no_such_alias_arn": 0.6039409489999343, + "tests/aws/services/stepfunctions/v2/test_sfn_api_express.py::TestSfnApiExpress::test_create_describe_delete": 0.6420727930001249, + "tests/aws/services/stepfunctions/v2/test_sfn_api_express.py::TestSfnApiExpress::test_illegal_activity_task": 0.7679716450002161, + "tests/aws/services/stepfunctions/v2/test_sfn_api_express.py::TestSfnApiExpress::test_illegal_callbacks[SYNC]": 0.7271125379998011, + "tests/aws/services/stepfunctions/v2/test_sfn_api_express.py::TestSfnApiExpress::test_illegal_callbacks[WAIT_FOR_TASK_TOKEN]": 0.7341727190002985, + "tests/aws/services/stepfunctions/v2/test_sfn_api_express.py::TestSfnApiExpress::test_start_async_describe_history_execution": 1.2579329950001465, + "tests/aws/services/stepfunctions/v2/test_sfn_api_express.py::TestSfnApiExpress::test_start_sync_execution": 0.6730412439997053, + "tests/aws/services/stepfunctions/v2/test_sfn_api_logs.py::TestSnfApiLogs::test_deleted_log_group": 0.44795972099996106, + "tests/aws/services/stepfunctions/v2/test_sfn_api_logs.py::TestSnfApiLogs::test_incomplete_logging_configuration[logging_configuration0]": 0.38479956100013624, + "tests/aws/services/stepfunctions/v2/test_sfn_api_logs.py::TestSnfApiLogs::test_incomplete_logging_configuration[logging_configuration1]": 0.4176422549999188, + "tests/aws/services/stepfunctions/v2/test_sfn_api_logs.py::TestSnfApiLogs::test_invalid_logging_configuration[logging_configuration0]": 0.3614154100000633, + "tests/aws/services/stepfunctions/v2/test_sfn_api_logs.py::TestSnfApiLogs::test_invalid_logging_configuration[logging_configuration1]": 0.3367657810003948, + "tests/aws/services/stepfunctions/v2/test_sfn_api_logs.py::TestSnfApiLogs::test_invalid_logging_configuration[logging_configuration2]": 0.3353904710002098, + "tests/aws/services/stepfunctions/v2/test_sfn_api_logs.py::TestSnfApiLogs::test_logging_configuration[ALL-False]": 0.4431069149998166, + "tests/aws/services/stepfunctions/v2/test_sfn_api_logs.py::TestSnfApiLogs::test_logging_configuration[ALL-True]": 0.4275375019999501, + "tests/aws/services/stepfunctions/v2/test_sfn_api_logs.py::TestSnfApiLogs::test_logging_configuration[ERROR-False]": 0.4168814479999128, + "tests/aws/services/stepfunctions/v2/test_sfn_api_logs.py::TestSnfApiLogs::test_logging_configuration[ERROR-True]": 0.42266378800036364, + "tests/aws/services/stepfunctions/v2/test_sfn_api_logs.py::TestSnfApiLogs::test_logging_configuration[FATAL-False]": 0.4202333239998097, + "tests/aws/services/stepfunctions/v2/test_sfn_api_logs.py::TestSnfApiLogs::test_logging_configuration[FATAL-True]": 0.42434028499974374, + "tests/aws/services/stepfunctions/v2/test_sfn_api_logs.py::TestSnfApiLogs::test_logging_configuration[OFF-False]": 0.42655233799996495, + "tests/aws/services/stepfunctions/v2/test_sfn_api_logs.py::TestSnfApiLogs::test_logging_configuration[OFF-True]": 0.4253541029997905, + "tests/aws/services/stepfunctions/v2/test_sfn_api_logs.py::TestSnfApiLogs::test_multiple_destinations": 0.3820960430002742, + "tests/aws/services/stepfunctions/v2/test_sfn_api_logs.py::TestSnfApiLogs::test_update_logging_configuration": 0.5599695299999894, + "tests/aws/services/stepfunctions/v2/test_sfn_api_map_run.py::TestSnfApiMapRun::test_list_map_runs_and_describe_map_run": 0.8090661280000404, + "tests/aws/services/stepfunctions/v2/test_sfn_api_map_run.py::TestSnfApiMapRun::test_map_state_label_empty_fail": 0.2982047190002959, + "tests/aws/services/stepfunctions/v2/test_sfn_api_map_run.py::TestSnfApiMapRun::test_map_state_label_invalid_char_fail[ ]": 0.3096916599999986, + "tests/aws/services/stepfunctions/v2/test_sfn_api_map_run.py::TestSnfApiMapRun::test_map_state_label_invalid_char_fail[\"]": 0.28330881999977464, + "tests/aws/services/stepfunctions/v2/test_sfn_api_map_run.py::TestSnfApiMapRun::test_map_state_label_invalid_char_fail[#]": 0.2857859370001279, + "tests/aws/services/stepfunctions/v2/test_sfn_api_map_run.py::TestSnfApiMapRun::test_map_state_label_invalid_char_fail[$]": 0.2899813510000513, + "tests/aws/services/stepfunctions/v2/test_sfn_api_map_run.py::TestSnfApiMapRun::test_map_state_label_invalid_char_fail[%]": 0.27936332100011896, + "tests/aws/services/stepfunctions/v2/test_sfn_api_map_run.py::TestSnfApiMapRun::test_map_state_label_invalid_char_fail[&]": 0.2951200659999813, + "tests/aws/services/stepfunctions/v2/test_sfn_api_map_run.py::TestSnfApiMapRun::test_map_state_label_invalid_char_fail[*]": 0.2820116160000907, + "tests/aws/services/stepfunctions/v2/test_sfn_api_map_run.py::TestSnfApiMapRun::test_map_state_label_invalid_char_fail[,]": 0.28098302400007924, + "tests/aws/services/stepfunctions/v2/test_sfn_api_map_run.py::TestSnfApiMapRun::test_map_state_label_invalid_char_fail[:]": 0.28148987399981706, + "tests/aws/services/stepfunctions/v2/test_sfn_api_map_run.py::TestSnfApiMapRun::test_map_state_label_invalid_char_fail[;]": 0.28378896399999576, + "tests/aws/services/stepfunctions/v2/test_sfn_api_map_run.py::TestSnfApiMapRun::test_map_state_label_invalid_char_fail[<]": 0.2872835620000842, + "tests/aws/services/stepfunctions/v2/test_sfn_api_map_run.py::TestSnfApiMapRun::test_map_state_label_invalid_char_fail[>]": 0.2822845039997901, + "tests/aws/services/stepfunctions/v2/test_sfn_api_map_run.py::TestSnfApiMapRun::test_map_state_label_invalid_char_fail[?]": 0.2810987899999873, + "tests/aws/services/stepfunctions/v2/test_sfn_api_map_run.py::TestSnfApiMapRun::test_map_state_label_invalid_char_fail[[]": 0.2864168819999122, + "tests/aws/services/stepfunctions/v2/test_sfn_api_map_run.py::TestSnfApiMapRun::test_map_state_label_invalid_char_fail[\\\\]": 0.2911610559997371, + "tests/aws/services/stepfunctions/v2/test_sfn_api_map_run.py::TestSnfApiMapRun::test_map_state_label_invalid_char_fail[\\n]": 0.2840047610000056, + "tests/aws/services/stepfunctions/v2/test_sfn_api_map_run.py::TestSnfApiMapRun::test_map_state_label_invalid_char_fail[\\r]": 0.2732440819997919, + "tests/aws/services/stepfunctions/v2/test_sfn_api_map_run.py::TestSnfApiMapRun::test_map_state_label_invalid_char_fail[\\t]": 0.2913525949998075, + "tests/aws/services/stepfunctions/v2/test_sfn_api_map_run.py::TestSnfApiMapRun::test_map_state_label_invalid_char_fail[\\x00]": 0.2854353949999222, + "tests/aws/services/stepfunctions/v2/test_sfn_api_map_run.py::TestSnfApiMapRun::test_map_state_label_invalid_char_fail[\\x01]": 0.29611834599995746, + "tests/aws/services/stepfunctions/v2/test_sfn_api_map_run.py::TestSnfApiMapRun::test_map_state_label_invalid_char_fail[\\x02]": 0.3279465070002061, + "tests/aws/services/stepfunctions/v2/test_sfn_api_map_run.py::TestSnfApiMapRun::test_map_state_label_invalid_char_fail[\\x03]": 0.320164092999903, + "tests/aws/services/stepfunctions/v2/test_sfn_api_map_run.py::TestSnfApiMapRun::test_map_state_label_invalid_char_fail[\\x04]": 0.2817061470000226, + "tests/aws/services/stepfunctions/v2/test_sfn_api_map_run.py::TestSnfApiMapRun::test_map_state_label_invalid_char_fail[\\x05]": 0.28866665500004274, + "tests/aws/services/stepfunctions/v2/test_sfn_api_map_run.py::TestSnfApiMapRun::test_map_state_label_invalid_char_fail[\\x06]": 0.28059872400012864, + "tests/aws/services/stepfunctions/v2/test_sfn_api_map_run.py::TestSnfApiMapRun::test_map_state_label_invalid_char_fail[\\x07]": 0.2868114590000914, + "tests/aws/services/stepfunctions/v2/test_sfn_api_map_run.py::TestSnfApiMapRun::test_map_state_label_invalid_char_fail[\\x08]": 0.2802511180000238, + "tests/aws/services/stepfunctions/v2/test_sfn_api_map_run.py::TestSnfApiMapRun::test_map_state_label_invalid_char_fail[\\x0b]": 0.2878253639999002, + "tests/aws/services/stepfunctions/v2/test_sfn_api_map_run.py::TestSnfApiMapRun::test_map_state_label_invalid_char_fail[\\x0c]": 0.2874051059998237, + "tests/aws/services/stepfunctions/v2/test_sfn_api_map_run.py::TestSnfApiMapRun::test_map_state_label_invalid_char_fail[\\x0e]": 0.289644730000191, + "tests/aws/services/stepfunctions/v2/test_sfn_api_map_run.py::TestSnfApiMapRun::test_map_state_label_invalid_char_fail[\\x0f]": 0.2861423639997156, + "tests/aws/services/stepfunctions/v2/test_sfn_api_map_run.py::TestSnfApiMapRun::test_map_state_label_invalid_char_fail[\\x10]": 0.28188491700007035, + "tests/aws/services/stepfunctions/v2/test_sfn_api_map_run.py::TestSnfApiMapRun::test_map_state_label_invalid_char_fail[\\x11]": 0.2821781600000577, + "tests/aws/services/stepfunctions/v2/test_sfn_api_map_run.py::TestSnfApiMapRun::test_map_state_label_invalid_char_fail[\\x12]": 0.2896934630002761, + "tests/aws/services/stepfunctions/v2/test_sfn_api_map_run.py::TestSnfApiMapRun::test_map_state_label_invalid_char_fail[\\x13]": 0.30172197400020195, + "tests/aws/services/stepfunctions/v2/test_sfn_api_map_run.py::TestSnfApiMapRun::test_map_state_label_invalid_char_fail[\\x14]": 0.2858908870000505, + "tests/aws/services/stepfunctions/v2/test_sfn_api_map_run.py::TestSnfApiMapRun::test_map_state_label_invalid_char_fail[\\x15]": 0.295288919000086, + "tests/aws/services/stepfunctions/v2/test_sfn_api_map_run.py::TestSnfApiMapRun::test_map_state_label_invalid_char_fail[\\x16]": 0.2970946160003223, + "tests/aws/services/stepfunctions/v2/test_sfn_api_map_run.py::TestSnfApiMapRun::test_map_state_label_invalid_char_fail[\\x17]": 0.2854559299998982, + "tests/aws/services/stepfunctions/v2/test_sfn_api_map_run.py::TestSnfApiMapRun::test_map_state_label_invalid_char_fail[\\x18]": 0.2799820370000816, + "tests/aws/services/stepfunctions/v2/test_sfn_api_map_run.py::TestSnfApiMapRun::test_map_state_label_invalid_char_fail[\\x19]": 0.2822970520001036, + "tests/aws/services/stepfunctions/v2/test_sfn_api_map_run.py::TestSnfApiMapRun::test_map_state_label_invalid_char_fail[\\x1a]": 0.28592698300008124, + "tests/aws/services/stepfunctions/v2/test_sfn_api_map_run.py::TestSnfApiMapRun::test_map_state_label_invalid_char_fail[\\x1b]": 0.28291799999988143, + "tests/aws/services/stepfunctions/v2/test_sfn_api_map_run.py::TestSnfApiMapRun::test_map_state_label_invalid_char_fail[\\x1c]": 0.29178949000015564, + "tests/aws/services/stepfunctions/v2/test_sfn_api_map_run.py::TestSnfApiMapRun::test_map_state_label_invalid_char_fail[\\x1d]": 0.2956381480003074, + "tests/aws/services/stepfunctions/v2/test_sfn_api_map_run.py::TestSnfApiMapRun::test_map_state_label_invalid_char_fail[\\x1e]": 0.28228567099995416, + "tests/aws/services/stepfunctions/v2/test_sfn_api_map_run.py::TestSnfApiMapRun::test_map_state_label_invalid_char_fail[\\x1f]": 0.27987972599976274, + "tests/aws/services/stepfunctions/v2/test_sfn_api_map_run.py::TestSnfApiMapRun::test_map_state_label_invalid_char_fail[\\x7f]": 0.28626822799992624, + "tests/aws/services/stepfunctions/v2/test_sfn_api_map_run.py::TestSnfApiMapRun::test_map_state_label_invalid_char_fail[\\x80]": 0.2978710519996639, + "tests/aws/services/stepfunctions/v2/test_sfn_api_map_run.py::TestSnfApiMapRun::test_map_state_label_invalid_char_fail[\\x81]": 0.27896393499986516, + "tests/aws/services/stepfunctions/v2/test_sfn_api_map_run.py::TestSnfApiMapRun::test_map_state_label_invalid_char_fail[\\x82]": 0.28845693100015524, + "tests/aws/services/stepfunctions/v2/test_sfn_api_map_run.py::TestSnfApiMapRun::test_map_state_label_invalid_char_fail[\\x83]": 0.2881292319998465, + "tests/aws/services/stepfunctions/v2/test_sfn_api_map_run.py::TestSnfApiMapRun::test_map_state_label_invalid_char_fail[\\x84]": 0.28015330599987465, + "tests/aws/services/stepfunctions/v2/test_sfn_api_map_run.py::TestSnfApiMapRun::test_map_state_label_invalid_char_fail[\\x85]": 0.30609100100014075, + "tests/aws/services/stepfunctions/v2/test_sfn_api_map_run.py::TestSnfApiMapRun::test_map_state_label_invalid_char_fail[\\x86]": 0.3131425080000554, + "tests/aws/services/stepfunctions/v2/test_sfn_api_map_run.py::TestSnfApiMapRun::test_map_state_label_invalid_char_fail[\\x87]": 0.28532149900024706, + "tests/aws/services/stepfunctions/v2/test_sfn_api_map_run.py::TestSnfApiMapRun::test_map_state_label_invalid_char_fail[\\x88]": 0.28444473900003686, + "tests/aws/services/stepfunctions/v2/test_sfn_api_map_run.py::TestSnfApiMapRun::test_map_state_label_invalid_char_fail[\\x89]": 0.2914696660000118, + "tests/aws/services/stepfunctions/v2/test_sfn_api_map_run.py::TestSnfApiMapRun::test_map_state_label_invalid_char_fail[\\x8a]": 0.2906591659998412, + "tests/aws/services/stepfunctions/v2/test_sfn_api_map_run.py::TestSnfApiMapRun::test_map_state_label_invalid_char_fail[\\x8b]": 0.28784513400000833, + "tests/aws/services/stepfunctions/v2/test_sfn_api_map_run.py::TestSnfApiMapRun::test_map_state_label_invalid_char_fail[\\x8c]": 0.28578058299990516, + "tests/aws/services/stepfunctions/v2/test_sfn_api_map_run.py::TestSnfApiMapRun::test_map_state_label_invalid_char_fail[\\x8d]": 0.2958572559998629, + "tests/aws/services/stepfunctions/v2/test_sfn_api_map_run.py::TestSnfApiMapRun::test_map_state_label_invalid_char_fail[\\x8e]": 0.2884580959998857, + "tests/aws/services/stepfunctions/v2/test_sfn_api_map_run.py::TestSnfApiMapRun::test_map_state_label_invalid_char_fail[\\x8f]": 0.289518815999827, + "tests/aws/services/stepfunctions/v2/test_sfn_api_map_run.py::TestSnfApiMapRun::test_map_state_label_invalid_char_fail[\\x90]": 0.2830009819999759, + "tests/aws/services/stepfunctions/v2/test_sfn_api_map_run.py::TestSnfApiMapRun::test_map_state_label_invalid_char_fail[\\x91]": 0.28544497100006083, + "tests/aws/services/stepfunctions/v2/test_sfn_api_map_run.py::TestSnfApiMapRun::test_map_state_label_invalid_char_fail[\\x92]": 0.29064888699986113, + "tests/aws/services/stepfunctions/v2/test_sfn_api_map_run.py::TestSnfApiMapRun::test_map_state_label_invalid_char_fail[\\x93]": 0.2863837459997285, + "tests/aws/services/stepfunctions/v2/test_sfn_api_map_run.py::TestSnfApiMapRun::test_map_state_label_invalid_char_fail[\\x94]": 0.2909311329999582, + "tests/aws/services/stepfunctions/v2/test_sfn_api_map_run.py::TestSnfApiMapRun::test_map_state_label_invalid_char_fail[\\x95]": 0.28907287700008055, + "tests/aws/services/stepfunctions/v2/test_sfn_api_map_run.py::TestSnfApiMapRun::test_map_state_label_invalid_char_fail[\\x96]": 0.28387240299980476, + "tests/aws/services/stepfunctions/v2/test_sfn_api_map_run.py::TestSnfApiMapRun::test_map_state_label_invalid_char_fail[\\x97]": 0.2787383840000075, + "tests/aws/services/stepfunctions/v2/test_sfn_api_map_run.py::TestSnfApiMapRun::test_map_state_label_invalid_char_fail[\\x98]": 0.2830254379998678, + "tests/aws/services/stepfunctions/v2/test_sfn_api_map_run.py::TestSnfApiMapRun::test_map_state_label_invalid_char_fail[\\x99]": 0.2792593520000537, + "tests/aws/services/stepfunctions/v2/test_sfn_api_map_run.py::TestSnfApiMapRun::test_map_state_label_invalid_char_fail[\\x9a]": 0.28292196699999295, + "tests/aws/services/stepfunctions/v2/test_sfn_api_map_run.py::TestSnfApiMapRun::test_map_state_label_invalid_char_fail[\\x9b]": 0.2842076070003259, + "tests/aws/services/stepfunctions/v2/test_sfn_api_map_run.py::TestSnfApiMapRun::test_map_state_label_invalid_char_fail[\\x9c]": 0.29497174800007997, + "tests/aws/services/stepfunctions/v2/test_sfn_api_map_run.py::TestSnfApiMapRun::test_map_state_label_invalid_char_fail[\\x9d]": 0.29116712700010794, + "tests/aws/services/stepfunctions/v2/test_sfn_api_map_run.py::TestSnfApiMapRun::test_map_state_label_invalid_char_fail[\\x9e]": 0.280328786000382, + "tests/aws/services/stepfunctions/v2/test_sfn_api_map_run.py::TestSnfApiMapRun::test_map_state_label_invalid_char_fail[\\x9f]": 0.27714028700006565, + "tests/aws/services/stepfunctions/v2/test_sfn_api_map_run.py::TestSnfApiMapRun::test_map_state_label_invalid_char_fail[]]": 0.28107411300015883, + "tests/aws/services/stepfunctions/v2/test_sfn_api_map_run.py::TestSnfApiMapRun::test_map_state_label_invalid_char_fail[^]": 0.2800892999998723, + "tests/aws/services/stepfunctions/v2/test_sfn_api_map_run.py::TestSnfApiMapRun::test_map_state_label_invalid_char_fail[`]": 0.2933119759998135, + "tests/aws/services/stepfunctions/v2/test_sfn_api_map_run.py::TestSnfApiMapRun::test_map_state_label_invalid_char_fail[{]": 0.28501219700001457, + "tests/aws/services/stepfunctions/v2/test_sfn_api_map_run.py::TestSnfApiMapRun::test_map_state_label_invalid_char_fail[|]": 0.292037333999815, + "tests/aws/services/stepfunctions/v2/test_sfn_api_map_run.py::TestSnfApiMapRun::test_map_state_label_invalid_char_fail[}]": 0.2892943730000752, + "tests/aws/services/stepfunctions/v2/test_sfn_api_map_run.py::TestSnfApiMapRun::test_map_state_label_invalid_char_fail[~]": 0.29101467300006334, + "tests/aws/services/stepfunctions/v2/test_sfn_api_map_run.py::TestSnfApiMapRun::test_map_state_label_too_long_fail": 0.30246001200021055, + "tests/aws/services/stepfunctions/v2/test_sfn_api_tagging.py::TestSnfApiTagging::test_create_state_machine": 0.31471586999987267, + "tests/aws/services/stepfunctions/v2/test_sfn_api_tagging.py::TestSnfApiTagging::test_tag_invalid_state_machine[None]": 0.3115964069997972, + "tests/aws/services/stepfunctions/v2/test_sfn_api_tagging.py::TestSnfApiTagging::test_tag_invalid_state_machine[tag_list1]": 0.33941620500013414, + "tests/aws/services/stepfunctions/v2/test_sfn_api_tagging.py::TestSnfApiTagging::test_tag_invalid_state_machine[tag_list2]": 0.359933017000003, + "tests/aws/services/stepfunctions/v2/test_sfn_api_tagging.py::TestSnfApiTagging::test_tag_invalid_state_machine[tag_list3]": 0.30702289999999266, + "tests/aws/services/stepfunctions/v2/test_sfn_api_tagging.py::TestSnfApiTagging::test_tag_state_machine[tag_list0]": 0.3290532080002322, + "tests/aws/services/stepfunctions/v2/test_sfn_api_tagging.py::TestSnfApiTagging::test_tag_state_machine[tag_list1]": 0.32478021999986595, + "tests/aws/services/stepfunctions/v2/test_sfn_api_tagging.py::TestSnfApiTagging::test_tag_state_machine[tag_list2]": 0.33326286900000923, + "tests/aws/services/stepfunctions/v2/test_sfn_api_tagging.py::TestSnfApiTagging::test_tag_state_machine[tag_list3]": 0.3301218859999153, + "tests/aws/services/stepfunctions/v2/test_sfn_api_tagging.py::TestSnfApiTagging::test_tag_state_machine[tag_list4]": 0.32579951699995036, + "tests/aws/services/stepfunctions/v2/test_sfn_api_tagging.py::TestSnfApiTagging::test_tag_state_machine_version": 0.31691086200021346, + "tests/aws/services/stepfunctions/v2/test_sfn_api_tagging.py::TestSnfApiTagging::test_untag_state_machine[tag_keys0]": 0.33380092900006275, + "tests/aws/services/stepfunctions/v2/test_sfn_api_tagging.py::TestSnfApiTagging::test_untag_state_machine[tag_keys1]": 0.3244383249998464, + "tests/aws/services/stepfunctions/v2/test_sfn_api_tagging.py::TestSnfApiTagging::test_untag_state_machine[tag_keys2]": 0.3266782090001925, + "tests/aws/services/stepfunctions/v2/test_sfn_api_tagging.py::TestSnfApiTagging::test_untag_state_machine[tag_keys3]": 0.3265721630000371, + "tests/aws/services/stepfunctions/v2/test_sfn_api_validation.py::TestSfnApiValidation::test_validate_state_machine_definition_not_a_definition[EMPTY_DICT]": 0.27368374699995, + "tests/aws/services/stepfunctions/v2/test_sfn_api_validation.py::TestSfnApiValidation::test_validate_state_machine_definition_not_a_definition[EMPTY_STRING]": 0.2813416110000162, + "tests/aws/services/stepfunctions/v2/test_sfn_api_validation.py::TestSfnApiValidation::test_validate_state_machine_definition_not_a_definition[NOT_A_DEF]": 0.2711640030001945, + "tests/aws/services/stepfunctions/v2/test_sfn_api_validation.py::TestSfnApiValidation::test_validate_state_machine_definition_type_express[ILLEGAL_WFTT]": 0.29251751000015247, + "tests/aws/services/stepfunctions/v2/test_sfn_api_validation.py::TestSfnApiValidation::test_validate_state_machine_definition_type_express[INVALID_BASE_NO_STARTAT]": 0.2765057260000958, + "tests/aws/services/stepfunctions/v2/test_sfn_api_validation.py::TestSfnApiValidation::test_validate_state_machine_definition_type_express[VALID_BASE_PASS]": 0.28299971499973253, + "tests/aws/services/stepfunctions/v2/test_sfn_api_validation.py::TestSfnApiValidation::test_validate_state_machine_definition_type_standard[INVALID_BASE_NO_STARTAT]": 0.28795555199985756, + "tests/aws/services/stepfunctions/v2/test_sfn_api_validation.py::TestSfnApiValidation::test_validate_state_machine_definition_type_standard[VALID_BASE_PASS]": 0.2836752549999346, + "tests/aws/services/stepfunctions/v2/test_sfn_api_variable_references.py::TestSfnApiVariableReferences::test_base_variable_references_in_assign_templates[BASE_ASSIGN_FROM_INTRINSIC_FUNCTION]": 1.7557982299999821, + "tests/aws/services/stepfunctions/v2/test_sfn_api_variable_references.py::TestSfnApiVariableReferences::test_base_variable_references_in_assign_templates[BASE_ASSIGN_FROM_PARAMETERS]": 0.8613147079997816, + "tests/aws/services/stepfunctions/v2/test_sfn_api_variable_references.py::TestSfnApiVariableReferences::test_base_variable_references_in_assign_templates[BASE_ASSIGN_FROM_RESULT]": 0.8181745750000573, + "tests/aws/services/stepfunctions/v2/test_sfn_api_variable_references.py::TestSfnApiVariableReferences::test_base_variable_references_in_assign_templates[BASE_EVALUATION_ORDER_PASS_STATE]": 0.8697814649995053, + "tests/aws/services/stepfunctions/v2/test_sfn_api_variable_references.py::TestSfnApiVariableReferences::test_base_variable_references_in_assign_templates[BASE_REFERENCE_IN_CHOICE]": 0.898569481000095, + "tests/aws/services/stepfunctions/v2/test_sfn_api_variable_references.py::TestSfnApiVariableReferences::test_base_variable_references_in_assign_templates[BASE_REFERENCE_IN_FAIL]": 0.797702843000252, + "tests/aws/services/stepfunctions/v2/test_sfn_api_variable_references.py::TestSfnApiVariableReferences::test_base_variable_references_in_assign_templates[BASE_REFERENCE_IN_INPUTPATH]": 0.7858166719997826, + "tests/aws/services/stepfunctions/v2/test_sfn_api_variable_references.py::TestSfnApiVariableReferences::test_base_variable_references_in_assign_templates[BASE_REFERENCE_IN_INTRINSIC_FUNCTION]": 1.1834529559998828, + "tests/aws/services/stepfunctions/v2/test_sfn_api_variable_references.py::TestSfnApiVariableReferences::test_base_variable_references_in_assign_templates[BASE_REFERENCE_IN_ITERATOR_OUTER_SCOPE]": 1.5324656489999597, + "tests/aws/services/stepfunctions/v2/test_sfn_api_variable_references.py::TestSfnApiVariableReferences::test_base_variable_references_in_assign_templates[BASE_REFERENCE_IN_OUTPUTPATH]": 0.8493412809998517, + "tests/aws/services/stepfunctions/v2/test_sfn_api_variable_references.py::TestSfnApiVariableReferences::test_base_variable_references_in_assign_templates[BASE_REFERENCE_IN_PARAMETERS]": 0.8116150050000215, + "tests/aws/services/stepfunctions/v2/test_sfn_api_variable_references.py::TestSfnApiVariableReferences::test_base_variable_references_in_assign_templates[BASE_REFERENCE_IN_WAIT]": 0.6117544750002253, + "tests/aws/services/stepfunctions/v2/test_sfn_api_variable_references.py::TestSfnApiVariableReferences::test_base_variable_references_in_assign_templates[MAP_STATE_REFERENCE_IN_INTRINSIC_FUNCTION]": 1.14703382100015, + "tests/aws/services/stepfunctions/v2/test_sfn_api_variable_references.py::TestSfnApiVariableReferences::test_base_variable_references_in_assign_templates[MAP_STATE_REFERENCE_IN_ITEMS_PATH]": 1.1541426180001508, + "tests/aws/services/stepfunctions/v2/test_sfn_api_variable_references.py::TestSfnApiVariableReferences::test_base_variable_references_in_assign_templates[MAP_STATE_REFERENCE_IN_ITEM_SELECTOR]": 0.9435908350003501, + "tests/aws/services/stepfunctions/v2/test_sfn_api_variable_references.py::TestSfnApiVariableReferences::test_base_variable_references_in_assign_templates[MAP_STATE_REFERENCE_IN_MAX_CONCURRENCY_PATH]": 0.8425658740000017, + "tests/aws/services/stepfunctions/v2/test_sfn_api_variable_references.py::TestSfnApiVariableReferences::test_base_variable_references_in_assign_templates[MAP_STATE_REFERENCE_IN_MAX_ITEMS_PATH]": 0.8734228490002351, + "tests/aws/services/stepfunctions/v2/test_sfn_api_variable_references.py::TestSfnApiVariableReferences::test_base_variable_references_in_assign_templates[MAP_STATE_REFERENCE_IN_TOLERATED_FAILURE_PATH]": 0.8731554370001504, + "tests/aws/services/stepfunctions/v2/test_sfn_api_variable_references.py::TestSfnApiVariableReferences::test_base_variable_references_in_jsonata_template[CHOICE_CONDITION_CONSTANT_JSONATA]": 0.4598278770001798, + "tests/aws/services/stepfunctions/v2/test_sfn_api_variable_references.py::TestSfnApiVariableReferences::test_base_variable_references_in_jsonata_template[CHOICE_STATE_UNSORTED_CHOICE_PARAMETERS_JSONATA]": 0.47466705800002273, + "tests/aws/services/stepfunctions/v2/test_sfn_api_versioning.py::TestSnfApiVersioning::test_create_express_with_publish": 0.36909724599968285, + "tests/aws/services/stepfunctions/v2/test_sfn_api_versioning.py::TestSnfApiVersioning::test_create_publish_describe_no_version_description": 0.40268262400013555, + "tests/aws/services/stepfunctions/v2/test_sfn_api_versioning.py::TestSnfApiVersioning::test_create_publish_describe_with_version_description": 0.4028376249998473, + "tests/aws/services/stepfunctions/v2/test_sfn_api_versioning.py::TestSnfApiVersioning::test_create_with_publish": 0.36855261400000927, + "tests/aws/services/stepfunctions/v2/test_sfn_api_versioning.py::TestSnfApiVersioning::test_create_with_version_description_no_publish": 0.3396498659999452, + "tests/aws/services/stepfunctions/v2/test_sfn_api_versioning.py::TestSnfApiVersioning::test_describe_state_machine_for_execution_of_version": 0.46787771699996483, + "tests/aws/services/stepfunctions/v2/test_sfn_api_versioning.py::TestSnfApiVersioning::test_describe_state_machine_for_execution_of_version_with_revision": 1.7409699550000823, + "tests/aws/services/stepfunctions/v2/test_sfn_api_versioning.py::TestSnfApiVersioning::test_empty_revision_with_publish_and_no_publish_on_creation": 0.40766628199980914, + "tests/aws/services/stepfunctions/v2/test_sfn_api_versioning.py::TestSnfApiVersioning::test_empty_revision_with_publish_and_publish_on_creation": 0.3923105369997302, + "tests/aws/services/stepfunctions/v2/test_sfn_api_versioning.py::TestSnfApiVersioning::test_idempotent_publish": 0.4036295730002166, + "tests/aws/services/stepfunctions/v2/test_sfn_api_versioning.py::TestSnfApiVersioning::test_list_delete_version": 0.4318062539998664, + "tests/aws/services/stepfunctions/v2/test_sfn_api_versioning.py::TestSnfApiVersioning::test_list_state_machine_versions_pagination": 0.9050393189997976, + "tests/aws/services/stepfunctions/v2/test_sfn_api_versioning.py::TestSnfApiVersioning::test_publish_state_machine_version": 0.5158844940001472, + "tests/aws/services/stepfunctions/v2/test_sfn_api_versioning.py::TestSnfApiVersioning::test_publish_state_machine_version_invalid_arn": 0.34471958599988284, + "tests/aws/services/stepfunctions/v2/test_sfn_api_versioning.py::TestSnfApiVersioning::test_publish_state_machine_version_no_such_machine": 0.38646450399983223, + "tests/aws/services/stepfunctions/v2/test_sfn_api_versioning.py::TestSnfApiVersioning::test_start_version_execution": 0.540428036999856, + "tests/aws/services/stepfunctions/v2/test_sfn_api_versioning.py::TestSnfApiVersioning::test_update_state_machine": 0.45051492600009624, + "tests/aws/services/stepfunctions/v2/test_sfn_api_versioning.py::TestSnfApiVersioning::test_version_ids_between_deletions": 0.41504477700004827, + "tests/aws/services/stepfunctions/v2/test_state/test_test_state_scenarios.py::TestStateCaseScenarios::test_base_inspection_level_debug[BASE_CHOICE_STATE]": 0.815037688999837, + "tests/aws/services/stepfunctions/v2/test_state/test_test_state_scenarios.py::TestStateCaseScenarios::test_base_inspection_level_debug[BASE_FAIL_STATE]": 0.6514022169999407, + "tests/aws/services/stepfunctions/v2/test_state/test_test_state_scenarios.py::TestStateCaseScenarios::test_base_inspection_level_debug[BASE_PASS_STATE]": 0.6616980649998823, + "tests/aws/services/stepfunctions/v2/test_state/test_test_state_scenarios.py::TestStateCaseScenarios::test_base_inspection_level_debug[BASE_RESULT_PASS_STATE]": 0.6837199870001314, + "tests/aws/services/stepfunctions/v2/test_state/test_test_state_scenarios.py::TestStateCaseScenarios::test_base_inspection_level_debug[BASE_SUCCEED_STATE]": 0.6680279370000335, + "tests/aws/services/stepfunctions/v2/test_state/test_test_state_scenarios.py::TestStateCaseScenarios::test_base_inspection_level_debug[IO_PASS_STATE]": 0.7504055059998791, + "tests/aws/services/stepfunctions/v2/test_state/test_test_state_scenarios.py::TestStateCaseScenarios::test_base_inspection_level_debug[IO_RESULT_PASS_STATE]": 0.7632075980002355, + "tests/aws/services/stepfunctions/v2/test_state/test_test_state_scenarios.py::TestStateCaseScenarios::test_base_inspection_level_info[BASE_CHOICE_STATE]": 0.5718781839998428, + "tests/aws/services/stepfunctions/v2/test_state/test_test_state_scenarios.py::TestStateCaseScenarios::test_base_inspection_level_info[BASE_FAIL_STATE]": 0.41024080000011054, + "tests/aws/services/stepfunctions/v2/test_state/test_test_state_scenarios.py::TestStateCaseScenarios::test_base_inspection_level_info[BASE_PASS_STATE]": 0.41771617400013383, + "tests/aws/services/stepfunctions/v2/test_state/test_test_state_scenarios.py::TestStateCaseScenarios::test_base_inspection_level_info[BASE_RESULT_PASS_STATE]": 0.4196921899999779, + "tests/aws/services/stepfunctions/v2/test_state/test_test_state_scenarios.py::TestStateCaseScenarios::test_base_inspection_level_info[BASE_SUCCEED_STATE]": 0.40505238800005827, + "tests/aws/services/stepfunctions/v2/test_state/test_test_state_scenarios.py::TestStateCaseScenarios::test_base_inspection_level_info[IO_PASS_STATE]": 0.5008502449998105, + "tests/aws/services/stepfunctions/v2/test_state/test_test_state_scenarios.py::TestStateCaseScenarios::test_base_inspection_level_info[IO_RESULT_PASS_STATE]": 0.5093722219996835, + "tests/aws/services/stepfunctions/v2/test_state/test_test_state_scenarios.py::TestStateCaseScenarios::test_base_inspection_level_trace[BASE_CHOICE_STATE]": 0.8278172519999316, + "tests/aws/services/stepfunctions/v2/test_state/test_test_state_scenarios.py::TestStateCaseScenarios::test_base_inspection_level_trace[BASE_FAIL_STATE]": 0.6840251429996442, + "tests/aws/services/stepfunctions/v2/test_state/test_test_state_scenarios.py::TestStateCaseScenarios::test_base_inspection_level_trace[BASE_PASS_STATE]": 0.6622020620000058, + "tests/aws/services/stepfunctions/v2/test_state/test_test_state_scenarios.py::TestStateCaseScenarios::test_base_inspection_level_trace[BASE_RESULT_PASS_STATE]": 0.669345438000164, + "tests/aws/services/stepfunctions/v2/test_state/test_test_state_scenarios.py::TestStateCaseScenarios::test_base_inspection_level_trace[BASE_SUCCEED_STATE]": 0.658141373000035, + "tests/aws/services/stepfunctions/v2/test_state/test_test_state_scenarios.py::TestStateCaseScenarios::test_base_inspection_level_trace[IO_PASS_STATE]": 0.7942755189997115, + "tests/aws/services/stepfunctions/v2/test_state/test_test_state_scenarios.py::TestStateCaseScenarios::test_base_inspection_level_trace[IO_RESULT_PASS_STATE]": 0.7707484350003142, + "tests/aws/services/stepfunctions/v2/test_state/test_test_state_scenarios.py::TestStateCaseScenarios::test_base_lambda_service_task_state[DEBUG]": 2.3081441649999306, + "tests/aws/services/stepfunctions/v2/test_state/test_test_state_scenarios.py::TestStateCaseScenarios::test_base_lambda_service_task_state[INFO]": 2.3130773159998625, + "tests/aws/services/stepfunctions/v2/test_state/test_test_state_scenarios.py::TestStateCaseScenarios::test_base_lambda_service_task_state[TRACE]": 2.3286053139997875, + "tests/aws/services/stepfunctions/v2/test_state/test_test_state_scenarios.py::TestStateCaseScenarios::test_base_lambda_task_state[DEBUG]": 2.3062292409999827, + "tests/aws/services/stepfunctions/v2/test_state/test_test_state_scenarios.py::TestStateCaseScenarios::test_base_lambda_task_state[INFO]": 2.2913872240001183, + "tests/aws/services/stepfunctions/v2/test_state/test_test_state_scenarios.py::TestStateCaseScenarios::test_base_lambda_task_state[TRACE]": 2.318082245999676, + "tests/aws/services/stepfunctions/v2/test_stepfunctions_v2.py::TestStateMachine::test_create_choice_state_machine": 2.934022679999998, + "tests/aws/services/stepfunctions/v2/test_stepfunctions_v2.py::TestStateMachine::test_create_run_map_state_machine": 1.2224994480000078, + "tests/aws/services/stepfunctions/v2/test_stepfunctions_v2.py::TestStateMachine::test_create_run_state_machine": 1.5981542629999694, + "tests/aws/services/stepfunctions/v2/test_stepfunctions_v2.py::TestStateMachine::test_create_state_machines_in_parallel": 2.1759436429999823, + "tests/aws/services/stepfunctions/v2/test_stepfunctions_v2.py::TestStateMachine::test_events_state_machine": 0.0013729130000683654, + "tests/aws/services/stepfunctions/v2/test_stepfunctions_v2.py::TestStateMachine::test_intrinsic_functions": 1.279459959000178, + "tests/aws/services/stepfunctions/v2/test_stepfunctions_v2.py::TestStateMachine::test_try_catch_state_machine": 10.199330852000003, + "tests/aws/services/stepfunctions/v2/test_stepfunctions_v2.py::test_aws_sdk_task": 1.2237063790000775, + "tests/aws/services/stepfunctions/v2/test_stepfunctions_v2.py::test_default_logging_configuration": 0.07177152099984596, + "tests/aws/services/stepfunctions/v2/test_stepfunctions_v2.py::test_multiregion_nested[statemachine_definition0-eu-central-1]": 0.0012207409999973606, + "tests/aws/services/stepfunctions/v2/test_stepfunctions_v2.py::test_multiregion_nested[statemachine_definition0-eu-west-1]": 0.0012446759999420465, + "tests/aws/services/stepfunctions/v2/test_stepfunctions_v2.py::test_multiregion_nested[statemachine_definition0-us-east-1]": 0.0019506080000155634, + "tests/aws/services/stepfunctions/v2/test_stepfunctions_v2.py::test_multiregion_nested[statemachine_definition0-us-east-2]": 0.0012408879999838973, + "tests/aws/services/stepfunctions/v2/test_stepfunctions_v2.py::test_run_aws_sdk_secrets_manager": 3.403536338000322, + "tests/aws/services/stepfunctions/v2/timeouts/test_heartbeats.py::TestHeartbeats::test_heartbeat_no_timeout": 5.893610356999716, + "tests/aws/services/stepfunctions/v2/timeouts/test_heartbeats.py::TestHeartbeats::test_heartbeat_path_timeout": 5.95751552999991, + "tests/aws/services/stepfunctions/v2/timeouts/test_heartbeats.py::TestHeartbeats::test_heartbeat_timeout": 6.034737336000035, + "tests/aws/services/stepfunctions/v2/timeouts/test_timeouts.py::TestTimeouts::test_fixed_timeout_lambda": 6.851902800000062, + "tests/aws/services/stepfunctions/v2/timeouts/test_timeouts.py::TestTimeouts::test_fixed_timeout_service_lambda": 6.881835702000217, + "tests/aws/services/stepfunctions/v2/timeouts/test_timeouts.py::TestTimeouts::test_fixed_timeout_service_lambda_with_path": 6.840051506999771, + "tests/aws/services/stepfunctions/v2/timeouts/test_timeouts.py::TestTimeouts::test_global_timeout": 5.514187309000135, + "tests/aws/services/stepfunctions/v2/timeouts/test_timeouts.py::TestTimeouts::test_service_lambda_map_timeout": 0.0016153750000285072, + "tests/aws/services/sts/test_sts.py::TestSTSAssumeRoleTagging::test_assume_role_tag_validation": 0.16289301499978137, + "tests/aws/services/sts/test_sts.py::TestSTSAssumeRoleTagging::test_iam_role_chaining_override_transitive_tags": 0.2296982080001726, + "tests/aws/services/sts/test_sts.py::TestSTSIntegrations::test_assume_non_existent_role": 0.019445780000069135, + "tests/aws/services/sts/test_sts.py::TestSTSIntegrations::test_assume_role": 0.22107210400008626, + "tests/aws/services/sts/test_sts.py::TestSTSIntegrations::test_assume_role_with_saml": 0.020377013000370425, + "tests/aws/services/sts/test_sts.py::TestSTSIntegrations::test_assume_role_with_web_identity": 0.01884468200023548, + "tests/aws/services/sts/test_sts.py::TestSTSIntegrations::test_expiration_date_format": 0.01499617399986164, + "tests/aws/services/sts/test_sts.py::TestSTSIntegrations::test_get_caller_identity_role_access_key[False]": 0.11107185700006994, + "tests/aws/services/sts/test_sts.py::TestSTSIntegrations::test_get_caller_identity_role_access_key[True]": 0.10342340000011063, + "tests/aws/services/sts/test_sts.py::TestSTSIntegrations::test_get_caller_identity_root": 0.016750987999557765, + "tests/aws/services/sts/test_sts.py::TestSTSIntegrations::test_get_caller_identity_user_access_key[False]": 0.08004611699993802, + "tests/aws/services/sts/test_sts.py::TestSTSIntegrations::test_get_caller_identity_user_access_key[True]": 0.19875780800020948, + "tests/aws/services/sts/test_sts.py::TestSTSIntegrations::test_get_federation_token": 0.0937704450000183, + "tests/aws/services/sts/test_sts.py::TestSTSIntegrations::test_sts_invalid_parameters": 0.0730474309998499, + "tests/aws/services/support/test_support.py::TestConfigService::test_support_case_lifecycle": 0.07528906100014865, + "tests/aws/services/swf/test_swf.py::TestSwf::test_run_workflow": 0.2067564740002581, + "tests/aws/services/transcribe/test_transcribe.py::TestTranscribe::test_failing_deletion": 0.2104494590005288, + "tests/aws/services/transcribe/test_transcribe.py::TestTranscribe::test_failing_start_transcription_job": 0.35872204300017074, + "tests/aws/services/transcribe/test_transcribe.py::TestTranscribe::test_get_transcription_job": 2.608120640999914, + "tests/aws/services/transcribe/test_transcribe.py::TestTranscribe::test_list_transcription_jobs": 2.5435078090001753, + "tests/aws/services/transcribe/test_transcribe.py::TestTranscribe::test_transcribe_error_invalid_length": 32.44955604300003, + "tests/aws/services/transcribe/test_transcribe.py::TestTranscribe::test_transcribe_error_speaker_labels": 0.001341499999853113, + "tests/aws/services/transcribe/test_transcribe.py::TestTranscribe::test_transcribe_happy_path": 2.546047976999944, + "tests/aws/services/transcribe/test_transcribe.py::TestTranscribe::test_transcribe_speaker_diarization": 0.0016446969998469285, + "tests/aws/services/transcribe/test_transcribe.py::TestTranscribe::test_transcribe_start_job[None-None]": 2.3403817150001487, + "tests/aws/services/transcribe/test_transcribe.py::TestTranscribe::test_transcribe_start_job[test-output-bucket-2-None]": 2.5885377179999978, + "tests/aws/services/transcribe/test_transcribe.py::TestTranscribe::test_transcribe_start_job[test-output-bucket-3-test-output]": 2.4106673810001666, + "tests/aws/services/transcribe/test_transcribe.py::TestTranscribe::test_transcribe_start_job[test-output-bucket-4-test-output.json]": 5.06222421099983, + "tests/aws/services/transcribe/test_transcribe.py::TestTranscribe::test_transcribe_start_job[test-output-bucket-5-test-files/test-output.json]": 2.4235455749999346, + "tests/aws/services/transcribe/test_transcribe.py::TestTranscribe::test_transcribe_start_job[test-output-bucket-6-test-files/test-output]": 4.989362425999843, + "tests/aws/services/transcribe/test_transcribe.py::TestTranscribe::test_transcribe_start_job_same_name": 2.9120818119997693, + "tests/aws/services/transcribe/test_transcribe.py::TestTranscribe::test_transcribe_supported_media_formats[../../files/en-gb.amr-hello my name is]": 2.1762116109998715, + "tests/aws/services/transcribe/test_transcribe.py::TestTranscribe::test_transcribe_supported_media_formats[../../files/en-gb.flac-hello my name is]": 2.185134156999993, + "tests/aws/services/transcribe/test_transcribe.py::TestTranscribe::test_transcribe_supported_media_formats[../../files/en-gb.mp3-hello my name is]": 2.1810205020001376, + "tests/aws/services/transcribe/test_transcribe.py::TestTranscribe::test_transcribe_supported_media_formats[../../files/en-gb.mp4-hello my name is]": 2.189077824000151, + "tests/aws/services/transcribe/test_transcribe.py::TestTranscribe::test_transcribe_supported_media_formats[../../files/en-gb.ogg-hello my name is]": 2.171964302000106, + "tests/aws/services/transcribe/test_transcribe.py::TestTranscribe::test_transcribe_supported_media_formats[../../files/en-gb.webm-hello my name is]": 2.1757555570000022, + "tests/aws/services/transcribe/test_transcribe.py::TestTranscribe::test_transcribe_supported_media_formats[../../files/en-us_video.mkv-one of the most vital]": 2.197480847999941, + "tests/aws/services/transcribe/test_transcribe.py::TestTranscribe::test_transcribe_supported_media_formats[../../files/en-us_video.mp4-one of the most vital]": 2.1884996569999657, + "tests/aws/services/transcribe/test_transcribe.py::TestTranscribe::test_transcribe_unsupported_media_format_failure": 3.197422684000003, + "tests/aws/test_error_injection.py::TestErrorInjection::test_dynamodb_error_injection": 25.73564731400029, + "tests/aws/test_error_injection.py::TestErrorInjection::test_dynamodb_read_error_injection": 25.738237048999963, + "tests/aws/test_error_injection.py::TestErrorInjection::test_dynamodb_write_error_injection": 51.381935092000504, + "tests/aws/test_error_injection.py::TestErrorInjection::test_kinesis_error_injection": 2.02135969699998, + "tests/aws/test_integration.py::TestIntegration::test_firehose_extended_s3": 0.22325086300020303, + "tests/aws/test_integration.py::TestIntegration::test_firehose_kinesis_to_s3": 51.589191119999896, + "tests/aws/test_integration.py::TestIntegration::test_firehose_s3": 0.3558000069999707, + "tests/aws/test_integration.py::TestIntegration::test_lambda_streams_batch_and_transactions": 26.87984179299974, + "tests/aws/test_integration.py::TestIntegration::test_scheduled_lambda": 46.39182503899974, + "tests/aws/test_integration.py::TestLambdaOutgoingSdkCalls::test_lambda_put_item_to_dynamodb[python3.10]": 1.997800419999976, + "tests/aws/test_integration.py::TestLambdaOutgoingSdkCalls::test_lambda_put_item_to_dynamodb[python3.11]": 2.005218125999818, + "tests/aws/test_integration.py::TestLambdaOutgoingSdkCalls::test_lambda_put_item_to_dynamodb[python3.12]": 1.9817306749998806, + "tests/aws/test_integration.py::TestLambdaOutgoingSdkCalls::test_lambda_put_item_to_dynamodb[python3.13]": 1.9770219800000177, + "tests/aws/test_integration.py::TestLambdaOutgoingSdkCalls::test_lambda_put_item_to_dynamodb[python3.8]": 1.953781465999782, + "tests/aws/test_integration.py::TestLambdaOutgoingSdkCalls::test_lambda_put_item_to_dynamodb[python3.9]": 1.9604283910000504, + "tests/aws/test_integration.py::TestLambdaOutgoingSdkCalls::test_lambda_send_message_to_sqs[python3.10]": 7.985243243999776, + "tests/aws/test_integration.py::TestLambdaOutgoingSdkCalls::test_lambda_send_message_to_sqs[python3.11]": 7.92167346899987, + "tests/aws/test_integration.py::TestLambdaOutgoingSdkCalls::test_lambda_send_message_to_sqs[python3.12]": 1.8561595389999184, + "tests/aws/test_integration.py::TestLambdaOutgoingSdkCalls::test_lambda_send_message_to_sqs[python3.13]": 7.958425087000023, + "tests/aws/test_integration.py::TestLambdaOutgoingSdkCalls::test_lambda_send_message_to_sqs[python3.8]": 15.98100621499998, + "tests/aws/test_integration.py::TestLambdaOutgoingSdkCalls::test_lambda_send_message_to_sqs[python3.9]": 1.8654234789996735, + "tests/aws/test_integration.py::TestLambdaOutgoingSdkCalls::test_lambda_start_stepfunctions_execution[python3.10]": 4.0344607579997955, + "tests/aws/test_integration.py::TestLambdaOutgoingSdkCalls::test_lambda_start_stepfunctions_execution[python3.11]": 3.997534539999833, + "tests/aws/test_integration.py::TestLambdaOutgoingSdkCalls::test_lambda_start_stepfunctions_execution[python3.12]": 4.037196066999968, + "tests/aws/test_integration.py::TestLambdaOutgoingSdkCalls::test_lambda_start_stepfunctions_execution[python3.13]": 4.000019816000076, + "tests/aws/test_integration.py::TestLambdaOutgoingSdkCalls::test_lambda_start_stepfunctions_execution[python3.8]": 4.006171419999873, + "tests/aws/test_integration.py::TestLambdaOutgoingSdkCalls::test_lambda_start_stepfunctions_execution[python3.9]": 4.043954328999689, + "tests/aws/test_integration.py::test_kinesis_lambda_forward_chain": 0.002535214000090491, + "tests/aws/test_moto.py::test_call_include_response_metadata": 0.007765847000200665, + "tests/aws/test_moto.py::test_call_multi_region_backends": 0.017100282000001243, + "tests/aws/test_moto.py::test_call_non_implemented_operation": 0.04491914499999439, + "tests/aws/test_moto.py::test_call_s3_with_streaming_trait[IO[bytes]]": 0.023063054999738597, + "tests/aws/test_moto.py::test_call_s3_with_streaming_trait[bytes]": 0.028169944999945074, + "tests/aws/test_moto.py::test_call_s3_with_streaming_trait[str]": 0.06021391900026174, + "tests/aws/test_moto.py::test_call_sqs_invalid_call_raises_http_exception": 0.014636858000130815, + "tests/aws/test_moto.py::test_call_with_es_creates_state_correctly": 0.06320221699979811, + "tests/aws/test_moto.py::test_call_with_modified_request": 0.012074723000068843, + "tests/aws/test_moto.py::test_call_with_sns_with_full_uri": 0.005441130999770394, + "tests/aws/test_moto.py::test_call_with_sqs_creates_state_correctly": 2.095916200999909, + "tests/aws/test_moto.py::test_call_with_sqs_invalid_call_raises_exception": 0.007622338999908607, + "tests/aws/test_moto.py::test_call_with_sqs_modifies_state_in_moto_backend": 0.011041840999951091, + "tests/aws/test_moto.py::test_call_with_sqs_returns_service_response": 0.006905204999839043, + "tests/aws/test_moto.py::test_moto_fallback_dispatcher": 0.010007336999933614, + "tests/aws/test_moto.py::test_moto_fallback_dispatcher_error_handling": 0.0412454610000168, + "tests/aws/test_moto.py::test_request_with_multi_protocol_non_default_protocol": 0.0012680499999078165, + "tests/aws/test_moto.py::test_request_with_response_header_location_fields": 0.10339789200020277, + "tests/aws/test_multi_accounts.py::TestMultiAccounts::test_account_id_namespacing_for_localstack_backends": 0.17225311499987583, + "tests/aws/test_multi_accounts.py::TestMultiAccounts::test_account_id_namespacing_for_moto_backends": 1.348460455999657, + "tests/aws/test_multi_accounts.py::TestMultiAccounts::test_multi_accounts_dynamodb": 0.33413467900004434, + "tests/aws/test_multi_accounts.py::TestMultiAccounts::test_multi_accounts_kinesis": 1.4324311980001312, + "tests/aws/test_multiregion.py::TestMultiRegion::test_multi_region_api_gateway": 0.48391825599969707, + "tests/aws/test_multiregion.py::TestMultiRegion::test_multi_region_sns": 0.09833296300007532, + "tests/aws/test_network_configuration.py::TestLambda::test_function_url": 1.1771073680001791, + "tests/aws/test_network_configuration.py::TestLambda::test_http_api_for_function_url": 0.0014825279999968188, + "tests/aws/test_network_configuration.py::TestOpenSearch::test_default_strategy": 16.882774949000122, + "tests/aws/test_network_configuration.py::TestOpenSearch::test_path_strategy": 16.675977731000103, + "tests/aws/test_network_configuration.py::TestOpenSearch::test_port_strategy": 16.588410995000004, + "tests/aws/test_network_configuration.py::TestS3::test_201_response": 0.0851535489998696, + "tests/aws/test_network_configuration.py::TestS3::test_multipart_upload": 0.10855221899987555, + "tests/aws/test_network_configuration.py::TestS3::test_non_us_east_1_location": 0.07016762000012022, + "tests/aws/test_network_configuration.py::TestSQS::test_domain_based_strategies[domain]": 0.022150418999672183, + "tests/aws/test_network_configuration.py::TestSQS::test_domain_based_strategies[standard]": 0.023223933999815927, + "tests/aws/test_network_configuration.py::TestSQS::test_off_strategy_with_external_port": 0.023408800000197516, + "tests/aws/test_network_configuration.py::TestSQS::test_off_strategy_without_external_port": 0.024459554000031858, + "tests/aws/test_network_configuration.py::TestSQS::test_path_strategy": 0.022869075000016892, + "tests/aws/test_notifications.py::TestNotifications::test_sns_to_sqs": 0.16105597299997498, + "tests/aws/test_notifications.py::TestNotifications::test_sqs_queue_names": 0.022074117000101978, + "tests/aws/test_serverless.py::TestServerless::test_apigateway_deployed": 0.04375949000018409, + "tests/aws/test_serverless.py::TestServerless::test_dynamodb_stream_handler_deployed": 0.0433799730001283, + "tests/aws/test_serverless.py::TestServerless::test_event_rules_deployed": 98.67178473599984, + "tests/aws/test_serverless.py::TestServerless::test_kinesis_stream_handler_deployed": 0.001249244000064209, + "tests/aws/test_serverless.py::TestServerless::test_lambda_with_configs_deployed": 0.03782760599983703, + "tests/aws/test_serverless.py::TestServerless::test_queue_handler_deployed": 0.0444987549999496, + "tests/aws/test_serverless.py::TestServerless::test_s3_bucket_deployed": 27.794429918000105, + "tests/aws/test_validate.py::TestMissingParameter::test_elasticache": 0.0012768149997555156, + "tests/aws/test_validate.py::TestMissingParameter::test_opensearch": 0.005046037999818509, + "tests/aws/test_validate.py::TestMissingParameter::test_sns": 0.0013006589999804419, + "tests/aws/test_validate.py::TestMissingParameter::test_sqs_create_queue": 0.001211224000371658, + "tests/aws/test_validate.py::TestMissingParameter::test_sqs_send_message": 0.0012062939999850641, + "tests/cli/test_cli.py::TestCliContainerLifecycle::test_container_starts_non_root": 0.0013143759997547022, + "tests/cli/test_cli.py::TestCliContainerLifecycle::test_custom_docker_flags": 0.0012123960000280931, + "tests/cli/test_cli.py::TestCliContainerLifecycle::test_logs": 0.001262487999838413, + "tests/cli/test_cli.py::TestCliContainerLifecycle::test_pulling_image_message": 0.0012681890000294516, + "tests/cli/test_cli.py::TestCliContainerLifecycle::test_restart": 0.0012832470001740148, + "tests/cli/test_cli.py::TestCliContainerLifecycle::test_start_already_existing": 0.0013125120001404866, + "tests/cli/test_cli.py::TestCliContainerLifecycle::test_start_already_running": 0.0012694920001194987, + "tests/cli/test_cli.py::TestCliContainerLifecycle::test_start_cli_within_container": 0.001236159999962183, + "tests/cli/test_cli.py::TestCliContainerLifecycle::test_start_wait_stop": 0.001203850000138118, + "tests/cli/test_cli.py::TestCliContainerLifecycle::test_status_services": 0.0012125949999699515, + "tests/cli/test_cli.py::TestCliContainerLifecycle::test_volume_dir_mounted_correctly": 0.0016644059999180172, + "tests/cli/test_cli.py::TestCliContainerLifecycle::test_wait_timeout_raises_exception": 0.0012617869999758113, + "tests/cli/test_cli.py::TestDNSServer::test_dns_port_not_published_by_default": 0.0012203100000078848, + "tests/cli/test_cli.py::TestDNSServer::test_dns_port_published_with_flag": 0.0012254289999873436, + "tests/cli/test_cli.py::TestHooks::test_prepare_host_hook_called_with_correct_dirs": 0.5863296360000732, + "tests/cli/test_cli.py::TestImports::test_import_venv": 0.007570002999727876, + "tests/integration/aws/test_app.py::TestExceptionHandlers::test_404_unfortunately_detected_as_s3_request": 0.046189517000129854, + "tests/integration/aws/test_app.py::TestExceptionHandlers::test_internal_failure_handler_http_errors": 0.01835274199993364, + "tests/integration/aws/test_app.py::TestExceptionHandlers::test_router_handler_get_http_errors": 0.0015470180001102563, + "tests/integration/aws/test_app.py::TestExceptionHandlers::test_router_handler_get_unexpected_errors": 0.0014265639999848645, + "tests/integration/aws/test_app.py::TestExceptionHandlers::test_router_handler_patch_http_errors": 0.15189248000024236, + "tests/integration/aws/test_app.py::TestHTTP2Support::test_http2_http": 0.08159936800007017, + "tests/integration/aws/test_app.py::TestHTTP2Support::test_http2_https": 0.07610825300002944, + "tests/integration/aws/test_app.py::TestHTTP2Support::test_http2_https_localhost": 0.05950527600020905, + "tests/integration/aws/test_app.py::TestHttps::test_default_cert_works": 0.08117448699999841, + "tests/integration/aws/test_app.py::TestWebSocketIntegration::test_return_response": 0.0012781779998931597, + "tests/integration/aws/test_app.py::TestWebSocketIntegration::test_ssl_websockets": 0.0013071310002032988, + "tests/integration/aws/test_app.py::TestWebSocketIntegration::test_websocket_reject_through_edge_router": 0.0012996589998692798, + "tests/integration/aws/test_app.py::TestWebSocketIntegration::test_websockets_served_through_edge_router": 0.0016424240000105783, + "tests/integration/aws/test_app.py::TestWerkzeugIntegration::test_chunked_request_streaming": 0.13899842599994372, + "tests/integration/aws/test_app.py::TestWerkzeugIntegration::test_chunked_response_streaming": 0.1601849650000986, + "tests/integration/aws/test_app.py::TestWerkzeugIntegration::test_raw_header_handling": 0.18866339599981075, + "tests/integration/aws/test_app.py::TestWerkzeugIntegration::test_response_close_handlers_called_with_router": 0.13924651800016363, + "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_build_image[CmdDockerClient-False-False]": 0.0014136699999198754, + "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_build_image[CmdDockerClient-False-True]": 0.0014346090001708944, + "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_build_image[CmdDockerClient-True-False]": 0.0014065259997551038, + "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_build_image[CmdDockerClient-True-True]": 0.0014227870001377596, + "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_build_image[SdkDockerClient-False-False]": 2.9760576409998976, + "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_build_image[SdkDockerClient-False-True]": 2.9915073319998555, + "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_build_image[SdkDockerClient-True-False]": 3.0260625230002915, + "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_build_image[SdkDockerClient-True-True]": 2.240534951000427, + "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_container_lifecycle_commands[CmdDockerClient]": 0.0014071489997604658, + "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_container_lifecycle_commands[SdkDockerClient]": 22.27311114700001, + "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_copy_directory_content_into_container[CmdDockerClient]": 0.001536849999865808, + "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_copy_directory_content_into_container[SdkDockerClient]": 0.29455210600008286, + "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_copy_directory_into_container[CmdDockerClient]": 0.0014414809998015699, + "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_copy_directory_into_container[SdkDockerClient]": 0.203184224999859, + "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_copy_directory_structure_into_container[CmdDockerClient]": 0.0015370899998288223, + "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_copy_directory_structure_into_container[SdkDockerClient]": 0.24866048300009425, + "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_copy_from_container[CmdDockerClient]": 0.001421615000026577, + "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_copy_from_container[SdkDockerClient]": 0.2411842669998805, + "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_copy_from_container_into_directory[CmdDockerClient]": 0.001486154999838618, + "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_copy_from_container_into_directory[SdkDockerClient]": 0.24808871999994153, + "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_copy_from_container_to_different_file[CmdDockerClient]": 0.0014302899999165675, + "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_copy_from_container_to_different_file[SdkDockerClient]": 0.26957559099946593, + "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_copy_from_non_existent_container[CmdDockerClient]": 0.0014286070002071938, + "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_copy_from_non_existent_container[SdkDockerClient]": 0.00820101500085002, + "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_copy_into_container[CmdDockerClient]": 0.0017722769998727017, + "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_copy_into_container[SdkDockerClient]": 0.19508825600041746, + "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_copy_into_container_with_existing_target[CmdDockerClient]": 0.0015121530000214989, + "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_copy_into_container_with_existing_target[SdkDockerClient]": 0.3502553080002144, + "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_copy_into_container_without_target_filename[CmdDockerClient]": 0.0015219809999962308, + "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_copy_into_container_without_target_filename[SdkDockerClient]": 0.23179477100029544, + "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_copy_into_non_existent_container[CmdDockerClient]": 0.0015237949999118428, + "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_copy_into_non_existent_container[SdkDockerClient]": 0.007568006999917998, + "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_create_container_non_existing_image[CmdDockerClient]": 0.0014508280000882223, + "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_create_container_non_existing_image[SdkDockerClient]": 0.8921736500001316, + "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_create_container_remove_removes_container[CmdDockerClient]": 0.001425410999900123, + "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_create_container_remove_removes_container[SdkDockerClient]": 1.1906941550000738, + "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_create_container_with_init[CmdDockerClient]": 0.0014347889996315644, + "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_create_container_with_init[SdkDockerClient]": 0.026445284000146785, + "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_create_container_with_max_env_vars[CmdDockerClient]": 0.0013992530000450643, + "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_create_container_with_max_env_vars[SdkDockerClient]": 0.2277763529996264, + "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_create_file_in_container[CmdDockerClient]": 0.0015288440001768322, + "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_create_file_in_container[SdkDockerClient]": 0.2203259339999022, + "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_create_start_container_with_stdin_to_file[CmdDockerClient-False]": 0.0014168949999202596, + "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_create_start_container_with_stdin_to_file[CmdDockerClient-True]": 0.0014208030002009764, + "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_create_start_container_with_stdin_to_file[SdkDockerClient-False]": 0.19046954200030086, + "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_create_start_container_with_stdin_to_file[SdkDockerClient-True]": 0.2075875869995798, + "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_create_start_container_with_stdin_to_stdout[CmdDockerClient-False]": 0.0015032859998882486, + "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_create_start_container_with_stdin_to_stdout[CmdDockerClient-True]": 0.0014218850001270766, + "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_create_start_container_with_stdin_to_stdout[SdkDockerClient-False]": 0.2049280499991255, + "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_create_start_container_with_stdin_to_stdout[SdkDockerClient-True]": 0.19887853699992775, + "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_create_with_exposed_ports[CmdDockerClient]": 0.0014125979998880211, + "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_create_with_exposed_ports[SdkDockerClient]": 0.004677941999943869, + "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_create_with_host_network[CmdDockerClient]": 0.001400004000061017, + "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_create_with_host_network[SdkDockerClient]": 0.02971875400044155, + "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_create_with_port_mapping[CmdDockerClient]": 0.0014377550000972406, + "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_create_with_port_mapping[SdkDockerClient]": 0.028084823999506625, + "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_create_with_volume[CmdDockerClient]": 0.0012893489999896701, + "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_create_with_volume[SdkDockerClient]": 0.001277496000056999, + "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_docker_image_names[CmdDockerClient]": 0.0014047330000721558, + "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_docker_image_names[SdkDockerClient]": 2.1129838860001655, + "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_docker_not_available[CmdDockerClient]": 0.007719670000142287, + "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_docker_not_available[SdkDockerClient]": 0.005567737000546913, + "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_exec_error_in_container[CmdDockerClient]": 0.0014342080000915303, + "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_exec_error_in_container[SdkDockerClient]": 0.2565331099999639, + "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_exec_in_container[CmdDockerClient]": 0.0014478119999239425, + "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_exec_in_container[SdkDockerClient]": 0.25939388000006147, + "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_exec_in_container_not_running_raises_exception[CmdDockerClient]": 0.0014301809999324178, + "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_exec_in_container_not_running_raises_exception[SdkDockerClient]": 0.03279205299986643, + "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_exec_in_container_with_env[CmdDockerClient]": 0.0015190359999905922, + "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_exec_in_container_with_env[SdkDockerClient]": 0.2465640949999397, + "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_exec_in_container_with_env_deletion[CmdDockerClient]": 0.0014955530000406725, + "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_exec_in_container_with_env_deletion[SdkDockerClient]": 0.28799500600007377, + "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_exec_in_container_with_stdin[CmdDockerClient]": 0.0014816859998063592, + "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_exec_in_container_with_stdin[SdkDockerClient]": 0.24450984699979017, + "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_exec_in_container_with_stdin_stdout_stderr[CmdDockerClient]": 0.0013814900000852504, + "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_exec_in_container_with_stdin_stdout_stderr[SdkDockerClient]": 0.23804629499909424, + "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_exec_in_container_with_workdir[CmdDockerClient]": 0.009688152999842714, + "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_exec_in_container_with_workdir[SdkDockerClient]": 0.27905647699981273, + "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_get_all_container_names_should_include_even_stopped_containers[CmdDockerClient]": 0.0013947959996585269, + "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_get_all_container_names_should_include_even_stopped_containers[SdkDockerClient]": 0.43114839299960295, + "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_get_container_command[CmdDockerClient]": 0.0015033260001473536, + "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_get_container_command[SdkDockerClient]": 0.026059131000238267, + "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_get_container_command_non_existing_image[CmdDockerClient]": 0.001402349000045433, + "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_get_container_command_non_existing_image[SdkDockerClient]": 0.8397267449995525, + "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_get_container_command_not_pulled_image[CmdDockerClient]": 0.0014133600000150182, + "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_get_container_command_not_pulled_image[SdkDockerClient]": 1.6453665439998986, + "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_get_container_entrypoint[CmdDockerClient]": 0.001417405999973198, + "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_get_container_entrypoint[SdkDockerClient]": 0.006871675000184041, + "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_get_container_entrypoint_non_existing_image[CmdDockerClient]": 0.001536890000124913, + "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_get_container_entrypoint_non_existing_image[SdkDockerClient]": 0.8378609050000705, + "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_get_container_entrypoint_not_pulled_image[CmdDockerClient]": 0.0014113849997556827, + "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_get_container_entrypoint_not_pulled_image[SdkDockerClient]": 1.654897436000283, + "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_get_container_id[CmdDockerClient]": 0.0013954060000287427, + "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_get_container_id[SdkDockerClient]": 0.2121221589995912, + "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_get_container_id_not_existing[CmdDockerClient]": 0.001448224000114351, + "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_get_container_id_not_existing[SdkDockerClient]": 0.006564701000115747, + "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_get_container_ip[CmdDockerClient]": 0.0014009960000294086, + "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_get_container_ip[SdkDockerClient]": 0.2207406790003006, + "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_get_container_ip_for_host_network[CmdDockerClient]": 0.0014079889999720763, + "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_get_container_ip_for_host_network[SdkDockerClient]": 0.04228904799947486, + "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_get_container_ip_for_network[CmdDockerClient]": 0.0013942339999175601, + "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_get_container_ip_for_network[SdkDockerClient]": 0.4290057549997073, + "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_get_container_ip_for_network_non_existent_network[CmdDockerClient]": 0.001397399999859772, + "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_get_container_ip_for_network_non_existent_network[SdkDockerClient]": 0.20403712400002405, + "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_get_container_ip_for_network_wrong_network[CmdDockerClient]": 0.0014304410001386714, + "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_get_container_ip_for_network_wrong_network[SdkDockerClient]": 0.36810051600059523, + "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_get_container_ip_non_existing_container[CmdDockerClient]": 0.0014186099999733415, + "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_get_container_ip_non_existing_container[SdkDockerClient]": 0.005557447999763099, + "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_get_container_name[CmdDockerClient]": 0.001424970999778452, + "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_get_container_name[SdkDockerClient]": 0.2034879250004451, + "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_get_container_name_not_existing[CmdDockerClient]": 0.0014068059999772231, + "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_get_container_name_not_existing[SdkDockerClient]": 0.006777027000225644, + "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_get_logs[CmdDockerClient]": 0.0014090409999880649, + "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_get_logs[SdkDockerClient]": 0.1777478739995786, + "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_get_logs_non_existent_container[CmdDockerClient]": 0.0013837129999956232, + "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_get_logs_non_existent_container[SdkDockerClient]": 0.007043324000278517, + "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_get_network[CmdDockerClient]": 0.001435950999848501, + "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_get_network[SdkDockerClient]": 0.029575827999451576, + "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_get_network_multiple_networks[CmdDockerClient]": 0.0014576519999991433, + "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_get_network_multiple_networks[SdkDockerClient]": 0.4345225249999203, + "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_get_network_non_existing_container[CmdDockerClient]": 0.0014135999999780324, + "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_get_network_non_existing_container[SdkDockerClient]": 0.00681201300039902, + "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_get_running_container_names_should_ignore_stopped_containers[CmdDockerClient]": 0.001433768000197233, + "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_get_running_container_names_should_ignore_stopped_containers[SdkDockerClient]": 0.38895521499989627, + "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_get_system_id[CmdDockerClient]": 0.0015310979999867413, + "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_get_system_id[SdkDockerClient]": 0.02409923200002595, + "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_get_system_info[CmdDockerClient]": 0.0038493910001307086, + "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_get_system_info[SdkDockerClient]": 0.0287523969996073, + "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_inspect_container[CmdDockerClient]": 0.0014433149999604211, + "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_inspect_container[SdkDockerClient]": 0.21537140000009458, + "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_inspect_container_volumes[CmdDockerClient]": 0.0012763540000833018, + "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_inspect_container_volumes[SdkDockerClient]": 0.0012612669997906778, + "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_inspect_container_volumes_with_no_volumes[CmdDockerClient]": 0.0014136090001102275, + "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_inspect_container_volumes_with_no_volumes[SdkDockerClient]": 0.18625000499969246, + "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_inspect_image[CmdDockerClient]": 0.0014198409999153228, + "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_inspect_image[SdkDockerClient]": 0.03606343299998116, + "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_inspect_network[CmdDockerClient]": 0.0014843810001821112, + "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_inspect_network[SdkDockerClient]": 0.16143997000017407, + "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_inspect_network_non_existent_network[CmdDockerClient]": 0.0014543659999617375, + "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_inspect_network_non_existent_network[SdkDockerClient]": 0.007395306999569584, + "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_is_container_running[CmdDockerClient]": 0.0013839639998423081, + "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_is_container_running[SdkDockerClient]": 20.42964576300028, + "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_list_containers[CmdDockerClient]": 0.0013869409999642812, + "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_list_containers[SdkDockerClient]": 0.08077750999973432, + "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_list_containers_filter[CmdDockerClient]": 0.0014085589998558135, + "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_list_containers_filter[SdkDockerClient]": 0.08528943299961611, + "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_list_containers_filter_illegal_filter[CmdDockerClient]": 0.0013926110000284098, + "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_list_containers_filter_illegal_filter[SdkDockerClient]": 0.005855682999936107, + "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_list_containers_filter_non_existing[CmdDockerClient]": 0.0013891839998905198, + "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_list_containers_filter_non_existing[SdkDockerClient]": 0.006638671000018803, + "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_list_containers_with_podman_image_ref_format[CmdDockerClient]": 0.0015118930002699926, + "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_list_containers_with_podman_image_ref_format[SdkDockerClient]": 0.2408772379999391, + "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_pause_non_existing_container[CmdDockerClient]": 0.0015409160000672273, + "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_pause_non_existing_container[SdkDockerClient]": 0.005409332999988692, + "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_pull_docker_image[CmdDockerClient]": 0.0014396779999970022, + "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_pull_docker_image[SdkDockerClient]": 1.6896245600000839, + "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_pull_docker_image_with_hash[CmdDockerClient]": 0.001400254000145651, + "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_pull_docker_image_with_hash[SdkDockerClient]": 1.9145194080001602, + "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_pull_docker_image_with_log_handler[CmdDockerClient]": 0.0014061059998766723, + "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_pull_docker_image_with_log_handler[SdkDockerClient]": 2.056144004000089, + "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_pull_docker_image_with_tag[CmdDockerClient]": 0.0014196110000739282, + "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_pull_docker_image_with_tag[SdkDockerClient]": 1.6814630669996404, + "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_pull_non_existent_docker_image[CmdDockerClient]": 0.0014013270001669298, + "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_pull_non_existent_docker_image[SdkDockerClient]": 0.8287883560001319, + "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_push_access_denied[CmdDockerClient]": 0.0014628320000156236, + "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_push_access_denied[SdkDockerClient]": 2.652870971000084, + "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_push_invalid_registry[CmdDockerClient]": 0.0014011270000082732, + "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_push_invalid_registry[SdkDockerClient]": 0.015871176000473497, + "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_push_non_existent_docker_image[CmdDockerClient]": 0.0014079190000302333, + "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_push_non_existent_docker_image[SdkDockerClient]": 0.006878046000110771, + "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_remove_anonymous_volumes[CmdDockerClient]": 0.001412547000199993, + "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_remove_anonymous_volumes[SdkDockerClient]": 4.0073730350000005, + "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_remove_container_should_throw_exception_when_container_doesnt_exist_and_not_forcing[CmdDockerClient]": 0.0014181579999785754, + "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_remove_container_should_throw_exception_when_container_doesnt_exist_and_not_forcing[SdkDockerClient]": 0.005855182999766839, + "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_remove_container_should_work_even_when_container_doesnt_exist_because_of_forcing[CmdDockerClient]": 0.0014562700000624318, + "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_remove_container_should_work_even_when_container_doesnt_exist_because_of_forcing[SdkDockerClient]": 0.005137377000664856, + "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_remove_container_should_work_when_container_is_running_and_checking_container_existence[CmdDockerClient]": 0.0017905320000863867, + "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_remove_container_should_work_when_container_is_running_and_checking_container_existence[SdkDockerClient]": 0.21209447199953502, + "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_remove_container_should_work_when_container_is_stopped_and_checking_container_existence[CmdDockerClient]": 0.0015122030001748499, + "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_remove_container_should_work_when_container_is_stopped_and_checking_container_existence[SdkDockerClient]": 0.04503438100027779, + "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_remove_non_existing_container[CmdDockerClient]": 0.0015049199998884433, + "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_remove_non_existing_container[SdkDockerClient]": 0.005368405999888637, + "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_restart_non_existing_container[CmdDockerClient]": 0.004103630999907182, + "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_restart_non_existing_container[SdkDockerClient]": 0.005337657999916701, + "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_run_container[CmdDockerClient]": 0.014423642000110704, + "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_run_container[SdkDockerClient]": 0.1832504049993986, + "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_run_container_automatic_pull[CmdDockerClient]": 0.0014079089999086136, + "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_run_container_automatic_pull[SdkDockerClient]": 2.0021920860003775, + "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_run_container_error[CmdDockerClient]": 0.0021577840000190918, + "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_run_container_error[SdkDockerClient]": 0.11429065200036348, + "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_run_container_non_existent_image[CmdDockerClient]": 0.0014009460001034313, + "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_run_container_non_existent_image[SdkDockerClient]": 0.8514135099994746, + "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_run_container_with_init[CmdDockerClient]": 0.0015737879998596327, + "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_run_container_with_init[SdkDockerClient]": 0.20492800100009845, + "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_run_container_with_stdin[CmdDockerClient]": 0.0014318629998797405, + "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_run_container_with_stdin[SdkDockerClient]": 0.1872367970004234, + "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_run_detached_with_logs[CmdDockerClient]": 0.0014705460000641324, + "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_run_detached_with_logs[SdkDockerClient]": 0.19558967600005417, + "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_running_container_names[CmdDockerClient]": 0.0013927410000178497, + "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_running_container_names[SdkDockerClient]": 11.943760120999286, + "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_set_container_entrypoint[CmdDockerClient-echo]": 0.0014983979999669828, + "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_set_container_entrypoint[CmdDockerClient-entrypoint1]": 0.0014016079999237263, + "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_set_container_entrypoint[SdkDockerClient-echo]": 0.1836204030000772, + "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_set_container_entrypoint[SdkDockerClient-entrypoint1]": 0.1951503310001499, + "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_start_non_existing_container[CmdDockerClient]": 0.0014208729999154457, + "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_start_non_existing_container[SdkDockerClient]": 0.005221854999490461, + "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_stop_non_existing_container[CmdDockerClient]": 0.002254574999824399, + "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_stop_non_existing_container[SdkDockerClient]": 0.006226894000064931, + "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_stream_logs[CmdDockerClient]": 0.0014949510000406008, + "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_stream_logs[SdkDockerClient]": 0.1882260050001605, + "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_stream_logs_non_existent_container[CmdDockerClient]": 0.0013739350001742423, + "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_stream_logs_non_existent_container[SdkDockerClient]": 0.005472849999932805, + "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_tag_image[CmdDockerClient]": 0.0014379449999069038, + "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_tag_image[SdkDockerClient]": 0.15481095199947958, + "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_tag_non_existing_image[CmdDockerClient]": 0.0014174569998886, + "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_tag_non_existing_image[SdkDockerClient]": 0.0062288980002449534, + "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_unpause_non_existing_container[CmdDockerClient]": 0.0015062110001053952, + "tests/integration/docker_utils/test_docker.py::TestDockerClient::test_unpause_non_existing_container[SdkDockerClient]": 0.005317191000358434, + "tests/integration/docker_utils/test_docker.py::TestDockerImages::test_commit_creates_image_from_running_container[CmdDockerClient]": 0.0032817549995343143, + "tests/integration/docker_utils/test_docker.py::TestDockerImages::test_commit_creates_image_from_running_container[SdkDockerClient]": 0.6129665449998356, + "tests/integration/docker_utils/test_docker.py::TestDockerImages::test_commit_image_raises_for_nonexistent_container[CmdDockerClient]": 0.0014590129999305645, + "tests/integration/docker_utils/test_docker.py::TestDockerImages::test_commit_image_raises_for_nonexistent_container[SdkDockerClient]": 0.006213016999936372, + "tests/integration/docker_utils/test_docker.py::TestDockerImages::test_remove_image_raises_for_nonexistent_image[CmdDockerClient]": 0.0015389430000141147, + "tests/integration/docker_utils/test_docker.py::TestDockerImages::test_remove_image_raises_for_nonexistent_image[SdkDockerClient]": 0.005961730000763055, + "tests/integration/docker_utils/test_docker.py::TestDockerLabels::test_create_container_with_labels[CmdDockerClient]": 0.0034539109997240303, + "tests/integration/docker_utils/test_docker.py::TestDockerLabels::test_create_container_with_labels[SdkDockerClient]": 0.040319997000551666, + "tests/integration/docker_utils/test_docker.py::TestDockerLabels::test_get_container_stats[CmdDockerClient]": 0.0014096620002419513, + "tests/integration/docker_utils/test_docker.py::TestDockerLabels::test_get_container_stats[SdkDockerClient]": 1.2273794510001608, + "tests/integration/docker_utils/test_docker.py::TestDockerLabels::test_list_containers_with_labels[CmdDockerClient]": 0.0014256220001698239, + "tests/integration/docker_utils/test_docker.py::TestDockerLabels::test_list_containers_with_labels[SdkDockerClient]": 0.20573961799937024, + "tests/integration/docker_utils/test_docker.py::TestDockerLabels::test_run_container_with_labels[CmdDockerClient]": 0.0015288820000023406, + "tests/integration/docker_utils/test_docker.py::TestDockerLabels::test_run_container_with_labels[SdkDockerClient]": 0.20969910099938716, + "tests/integration/docker_utils/test_docker.py::TestDockerLogging::test_docker_logging_fluentbit[CmdDockerClient]": 0.0014608890000999963, + "tests/integration/docker_utils/test_docker.py::TestDockerLogging::test_docker_logging_fluentbit[SdkDockerClient]": 5.811885718999747, + "tests/integration/docker_utils/test_docker.py::TestDockerLogging::test_docker_logging_none_disables_logs[CmdDockerClient]": 0.0033854499997687526, + "tests/integration/docker_utils/test_docker.py::TestDockerLogging::test_docker_logging_none_disables_logs[SdkDockerClient]": 0.2022555979997378, + "tests/integration/docker_utils/test_docker.py::TestDockerNetworking::test_connect_container_to_network[CmdDockerClient]": 0.001530227000330342, + "tests/integration/docker_utils/test_docker.py::TestDockerNetworking::test_connect_container_to_network[SdkDockerClient]": 0.5343384399998286, + "tests/integration/docker_utils/test_docker.py::TestDockerNetworking::test_connect_container_to_network_with_alias_and_disconnect[CmdDockerClient]": 0.0071732639999027015, + "tests/integration/docker_utils/test_docker.py::TestDockerNetworking::test_connect_container_to_network_with_alias_and_disconnect[SdkDockerClient]": 0.814026749000277, + "tests/integration/docker_utils/test_docker.py::TestDockerNetworking::test_connect_container_to_network_with_link_local_address[CmdDockerClient]": 0.0014604560001316713, + "tests/integration/docker_utils/test_docker.py::TestDockerNetworking::test_connect_container_to_network_with_link_local_address[SdkDockerClient]": 0.17843500500021037, + "tests/integration/docker_utils/test_docker.py::TestDockerNetworking::test_connect_container_to_nonexistent_network[CmdDockerClient]": 0.0015080250004757545, + "tests/integration/docker_utils/test_docker.py::TestDockerNetworking::test_connect_container_to_nonexistent_network[SdkDockerClient]": 0.20054101499999888, + "tests/integration/docker_utils/test_docker.py::TestDockerNetworking::test_connect_nonexistent_container_to_network[CmdDockerClient]": 0.014571857000191812, + "tests/integration/docker_utils/test_docker.py::TestDockerNetworking::test_connect_nonexistent_container_to_network[SdkDockerClient]": 0.16719234900028823, + "tests/integration/docker_utils/test_docker.py::TestDockerNetworking::test_disconnect_container_from_nonexistent_network[CmdDockerClient]": 0.0015210900000965921, + "tests/integration/docker_utils/test_docker.py::TestDockerNetworking::test_disconnect_container_from_nonexistent_network[SdkDockerClient]": 0.23906621800051653, + "tests/integration/docker_utils/test_docker.py::TestDockerNetworking::test_disconnect_nonexistent_container_from_network[CmdDockerClient]": 0.002241689000129554, + "tests/integration/docker_utils/test_docker.py::TestDockerNetworking::test_disconnect_nonexistent_container_from_network[SdkDockerClient]": 0.1576368050000383, + "tests/integration/docker_utils/test_docker.py::TestDockerNetworking::test_docker_sdk_no_retries": 0.13170184200043877, + "tests/integration/docker_utils/test_docker.py::TestDockerNetworking::test_docker_sdk_retries_after_init": 1.2779327209996154, + "tests/integration/docker_utils/test_docker.py::TestDockerNetworking::test_docker_sdk_retries_on_init": 1.1406676540000262, + "tests/integration/docker_utils/test_docker.py::TestDockerNetworking::test_docker_sdk_timeout_seconds": 0.021520688999771664, + "tests/integration/docker_utils/test_docker.py::TestDockerNetworking::test_get_container_ip_with_network[CmdDockerClient]": 0.0015078350002113439, + "tests/integration/docker_utils/test_docker.py::TestDockerNetworking::test_get_container_ip_with_network[SdkDockerClient]": 0.37259845500057054, + "tests/integration/docker_utils/test_docker.py::TestDockerNetworking::test_network_lifecycle[CmdDockerClient]": 0.0033505329997751687, + "tests/integration/docker_utils/test_docker.py::TestDockerNetworking::test_network_lifecycle[SdkDockerClient]": 0.1867143410004246, + "tests/integration/docker_utils/test_docker.py::TestDockerNetworking::test_set_container_workdir[CmdDockerClient]": 0.0014463099996646633, + "tests/integration/docker_utils/test_docker.py::TestDockerNetworking::test_set_container_workdir[SdkDockerClient]": 0.23435144599989144, + "tests/integration/docker_utils/test_docker.py::TestDockerPermissions::test_container_with_cap_add[CmdDockerClient]": 0.004714934999810794, + "tests/integration/docker_utils/test_docker.py::TestDockerPermissions::test_container_with_cap_add[SdkDockerClient]": 0.41643684400014536, + "tests/integration/docker_utils/test_docker.py::TestDockerPermissions::test_container_with_cap_drop[CmdDockerClient]": 0.0019246319998273975, + "tests/integration/docker_utils/test_docker.py::TestDockerPermissions::test_container_with_cap_drop[SdkDockerClient]": 0.391863383999862, + "tests/integration/docker_utils/test_docker.py::TestDockerPermissions::test_container_with_sec_opt[CmdDockerClient]": 0.001962873000138643, + "tests/integration/docker_utils/test_docker.py::TestDockerPermissions::test_container_with_sec_opt[SdkDockerClient]": 0.032850023999799305, + "tests/integration/docker_utils/test_docker.py::TestDockerPorts::test_container_port_can_be_bound[CmdDockerClient-None]": 0.001393712999743002, + "tests/integration/docker_utils/test_docker.py::TestDockerPorts::test_container_port_can_be_bound[CmdDockerClient-tcp]": 0.0015041299998301838, + "tests/integration/docker_utils/test_docker.py::TestDockerPorts::test_container_port_can_be_bound[CmdDockerClient-udp]": 0.0014287780004451633, + "tests/integration/docker_utils/test_docker.py::TestDockerPorts::test_container_port_can_be_bound[SdkDockerClient-None]": 1.4859149109997816, + "tests/integration/docker_utils/test_docker.py::TestDockerPorts::test_container_port_can_be_bound[SdkDockerClient-tcp]": 1.498148060999938, + "tests/integration/docker_utils/test_docker.py::TestDockerPorts::test_container_port_can_be_bound[SdkDockerClient-udp]": 1.501350339000055, + "tests/integration/docker_utils/test_docker.py::TestDockerPorts::test_reserve_container_port[CmdDockerClient-None]": 0.0034080430004905793, + "tests/integration/docker_utils/test_docker.py::TestDockerPorts::test_reserve_container_port[CmdDockerClient-tcp]": 0.0014754959997844708, + "tests/integration/docker_utils/test_docker.py::TestDockerPorts::test_reserve_container_port[CmdDockerClient-udp]": 0.0014989800001785625, + "tests/integration/docker_utils/test_docker.py::TestDockerPorts::test_reserve_container_port[SdkDockerClient-None]": 2.7217243439999947, + "tests/integration/docker_utils/test_docker.py::TestDockerPorts::test_reserve_container_port[SdkDockerClient-tcp]": 2.6387296500001867, + "tests/integration/docker_utils/test_docker.py::TestDockerPorts::test_reserve_container_port[SdkDockerClient-udp]": 2.901062312999784, + "tests/integration/docker_utils/test_docker.py::TestRunWithAdditionalArgs::test_run_with_additional_arguments[CmdDockerClient]": 0.0033752079998521367, + "tests/integration/docker_utils/test_docker.py::TestRunWithAdditionalArgs::test_run_with_additional_arguments[SdkDockerClient]": 0.3787502280001718, + "tests/integration/docker_utils/test_docker.py::TestRunWithAdditionalArgs::test_run_with_additional_arguments_add_dns[CmdDockerClient-False]": 0.0015056309998726647, + "tests/integration/docker_utils/test_docker.py::TestRunWithAdditionalArgs::test_run_with_additional_arguments_add_dns[CmdDockerClient-True]": 0.0015315490004468302, + "tests/integration/docker_utils/test_docker.py::TestRunWithAdditionalArgs::test_run_with_additional_arguments_add_dns[SdkDockerClient-False]": 0.13489488100003655, + "tests/integration/docker_utils/test_docker.py::TestRunWithAdditionalArgs::test_run_with_additional_arguments_add_dns[SdkDockerClient-True]": 0.12092069500022262, + "tests/integration/docker_utils/test_docker.py::TestRunWithAdditionalArgs::test_run_with_additional_arguments_add_host[CmdDockerClient]": 0.0014564589996552968, + "tests/integration/docker_utils/test_docker.py::TestRunWithAdditionalArgs::test_run_with_additional_arguments_add_host[SdkDockerClient]": 0.20942816699971445, + "tests/integration/docker_utils/test_docker.py::TestRunWithAdditionalArgs::test_run_with_additional_arguments_env_files[CmdDockerClient]": 0.0014950600002521242, + "tests/integration/docker_utils/test_docker.py::TestRunWithAdditionalArgs::test_run_with_additional_arguments_env_files[SdkDockerClient]": 0.7517742690001796, + "tests/integration/docker_utils/test_docker.py::TestRunWithAdditionalArgs::test_run_with_additional_arguments_random_port[CmdDockerClient]": 0.0014962740001465136, + "tests/integration/docker_utils/test_docker.py::TestRunWithAdditionalArgs::test_run_with_additional_arguments_random_port[SdkDockerClient]": 0.42006964999973206, + "tests/integration/docker_utils/test_docker.py::TestRunWithAdditionalArgs::test_run_with_ulimit[CmdDockerClient]": 0.0015056209995236713, + "tests/integration/docker_utils/test_docker.py::TestRunWithAdditionalArgs::test_run_with_ulimit[SdkDockerClient]": 0.17939532899981714, + "tests/integration/services/test_internal.py::TestHealthResource::test_get": 0.019109316000140097, + "tests/integration/services/test_internal.py::TestHealthResource::test_head": 0.015374293999229849, + "tests/integration/services/test_internal.py::TestInfoEndpoint::test_get": 0.040711614999963786, + "tests/integration/services/test_internal.py::TestInitScriptsResource::test_query_individual_stage_completed[boot-True]": 0.023648329000025115, + "tests/integration/services/test_internal.py::TestInitScriptsResource::test_query_individual_stage_completed[ready-True]": 0.020980114999929356, + "tests/integration/services/test_internal.py::TestInitScriptsResource::test_query_individual_stage_completed[shutdown-False]": 0.020283478000237665, + "tests/integration/services/test_internal.py::TestInitScriptsResource::test_query_individual_stage_completed[start-True]": 0.020978761999685958, + "tests/integration/services/test_internal.py::TestInitScriptsResource::test_query_nonexisting_stage": 0.021183413000017026, + "tests/integration/services/test_internal.py::TestInitScriptsResource::test_stages_have_completed": 2.782768469000075, + "tests/integration/test_config_endpoint.py::test_config_endpoint": 0.039892633000363276, + "tests/integration/test_config_service.py::TestConfigService::test_put_configuration_recorder": 0.18140216099982354, + "tests/integration/test_config_service.py::TestConfigService::test_put_delivery_channel": 0.1813844190000964, + "tests/integration/test_forwarder.py::test_forwarding_fallback_dispatcher": 0.007053050999729749, + "tests/integration/test_forwarder.py::test_forwarding_fallback_dispatcher_avoid_fallback": 0.004772130000219477, + "tests/integration/test_security.py::TestCSRF::test_CSRF": 0.11712493000004542, + "tests/integration/test_security.py::TestCSRF::test_additional_allowed_origins": 0.020309886999712035, + "tests/integration/test_security.py::TestCSRF::test_cors_apigw_not_applied": 0.09949914299977536, + "tests/integration/test_security.py::TestCSRF::test_cors_s3_override": 0.13386974199966062, + "tests/integration/test_security.py::TestCSRF::test_default_cors_headers": 0.013950815000043804, + "tests/integration/test_security.py::TestCSRF::test_disable_cors_checks": 0.021486006999566598, + "tests/integration/test_security.py::TestCSRF::test_disable_cors_headers": 0.02481705400032297, + "tests/integration/test_security.py::TestCSRF::test_internal_route_cors_headers[/_localstack/health]": 0.012596867999945971, + "tests/integration/test_security.py::TestCSRF::test_no_cors_without_origin_header": 0.01330875300027401, + "tests/integration/test_stores.py::test_nonstandard_regions": 0.13026484700048968, + "tests/integration/utils/test_diagnose.py::test_diagnose_resource": 0.25306075800017425 } diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000000000..e5f81c35c2119 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,178 @@ +# AGENTS.md — LocalStack Pro + +LocalStack is a fully functional local AWS cloud stack that emulates AWS services (S3, Lambda, DynamoDB, etc.) for development and testing. It runs in Docker, provides AWS-like APIs locally, enabling offline workflows, integration testing, and CI without calling real AWS endpoints. + +This codebase contains both the AWS emulator in `localstack-core`. + +--- + +## ⚠️ Critical Hard Constraints + +**NEVER:** +- Modify `*.snapshot.json` or `*.validation.json` files manually — generated by running tests against AWS +- Use plain `assert` in validated tests — **ALWAYS** use `snapshot.match()` +- Create AWS resources directly in test bodies — **ALWAYS** use fixtures +- Hardcode account IDs or region names — use `account_id` and `region_name` fixtures +- Modify files in `aws/api/` — auto-generated from AWS API definitions +- Add new project dependencies without approval +- Run `git push` or modify repository history + +--- + +## Commands + +```bash +# Testing +pytest # Run test file +pytest -k # Run specific test +AWS_PROFILE=ls-sandbox TEST_TARGET=AWS_CLOUD SNAPSHOT_UPDATE=1 pytest # Run against AWS + +# Code quality +make lint # Lint check +make format # Format all +make format-modified # Format staged only +``` + +--- + +## Project Structure + +``` +localstack-core/ +├── localstack/core/ +│ ├── services// # Service implementations +│ │ ├── provider.py # API handlers +│ │ ├── models.py # State stores +│ │ └── resource_providers/ # CloudFormation resources +│ ├── aws/api// # Auto-generated API types (DO NOT EDIT) +│ └── providers.py # Service registration & Moto fallbacks +├── tests/aws/services// # Integration tests +├── tests/unit/ # Unit tests (prefer integration tests) +├── tests/bootstrap/ # Container startup tests +``` + +### Moto Fallback + +Moto is a library used to implement services not fully implemented in LocalStack. Requests can fall back to Moto operations, with the disadvantage that state is kept in Moto and Moto changes may break the implementation. Check `providers.py` for fallback configurations. + +--- + +## Implementing AWS Operations + +### Reference Implementation + +For a complete example of provider patterns, state management, and error handling, see the **CodeBuild** service: + +- **Provider:** `localstack-pro-core/localstack/pro/core/services/codebuild/provider.py` +- **Models (state store):** `localstack-pro-core/localstack/pro/core/services/codebuild/models.py` + +Refer to this implementation when: +- Creating a new service from scratch +- Understanding the `@handler` decorator pattern (with and without `expand=False`) +- Learning the `AccountRegionBundle` state management pattern +- Implementing service-specific exceptions +- Using helper functions like `get_store(context)` and utility functions outside the class + +### Key Conventions + +- **Types:** Import from `localstack.pro.core.aws.api.` (auto-generated, don't modify) +- **Errors:** Use service-specific exceptions from API module, or `CommonServiceException` +- **IDs:** Use `short_uid()` from `localstack.utils.strings` +- **ARNs:** Use helpers from `localstack.utils.aws.arns` +- **Logging:** `LOG = logging.getLogger(__name__)` at module top + +--- + +## Writing Parity Tests + +### Reference Implementation + +For complete examples of test patterns, fixtures, and snapshots, see the **Pipes** tests: + +- **Validation tests:** `localstack-pro-core/tests/aws/services/pipes/test_pipes_validation.py` +- **Integration tests:** `localstack-pro-core/tests/aws/services/pipes/test_pipes.py` +- **Fixtures (conftest):** `localstack-pro-core/tests/aws/services/pipes/conftest.py` + +Refer to these when: +- Writing `@markers.aws.validated` tests with snapshot matching +- Creating fixture factories with cleanup (see `pipes_create_pipe` in conftest) +- Understanding the `@pytest.mark.parametrize` pattern +- Testing error cases with `pytest.raises` and `snapshot.match` + +### Test Markers + +Use `@markers.aws.validated` for tests that run against AWS (preferred), or `@markers.aws.only_localstack` for implementation-specific assertions. + +### Core Patterns + +All test patterns are demonstrated in the reference files. Refer to: + +- **Validation tests with error handling:** `test_pipes_validation.py:9-35` — shows `@markers.aws.validated`, `pytest.raises`, and `snapshot.match` for error responses +- **Parametrized tests:** `test_pipes_validation.py:304-377` — shows `@pytest.mark.parametrize` with multiple test cases +- **Fixture with cleanup:** `conftest.py:55-76` — shows the `pipes_create_pipe` fixture factory pattern with `LOG.debug()` cleanup +- **Async resource handling:** `test_pipes.py:134-139` — shows `poll_condition` for waiting on resource state + +### Fixture Rules + +- **Return the entire response** from create operations +- **Store only names/ARNs** in cleanup list (not full responses) +- **Log cleanup errors** with `LOG.debug()` for debugging with `-s` + +### Transformers + +Add transformers **before** `snapshot.match()` for non-deterministic values: + +- **By key (preferred):** `snapshot.add_transformer(snapshot.transform.key_value("FooArn"))` +- **By regex:** `snapshot.add_transformer(snapshot.transform.regex(dynamic_value, ""))` +- **For sorting:** Use `SortingTransformer` from `localstack.testing.snapshots.transformer` + +### Key Fixtures + +- `aws_client` — Boto3 clients (e.g., `aws_client.s3`, `aws_client.lambda_`) +- `snapshot` — Snapshot matching and transformers +- `account_id`, `region_name` — Current account/region (never hardcode) +- `deploy_cfn_template` — Deploy CloudFormation with lifecycle management +- `cleanups` — Register arbitrary cleanup code for teardown + +For common resource fixtures (S3 buckets, KMS keys, etc.), check `localstack-core/localstack/testing/pytest/fixtures.py` + +--- + +## Development Process + +1. **Write a failing test first** — Capture AWS behavior with `TEST_TARGET=AWS_CLOUD SNAPSHOT_UPDATE=1` +2. **Find the provider** — Look in `services//provider.py` for the handler +3. **Check the store** — State issues often in `models.py` +4. **Compare with AWS docs** — Verify expected behavior +5. **Run test against LocalStack** — Ensure snapshot matches +6. **Iterate** — Run tests individually, see failures, fix, re-run + +**Important:** When developing tests for functionality that doesn't exist in LocalStack yet, run tests against AWS to ensure validity. Don't run with `TEST_TARGET=LOCALSTACK` until the functionality exists. + +--- + +## Best Practices + +### Always + +- Run new tests against AWS first +- Use fixtures for resource creation with cleanup +- Add transformers for dynamic values +- Follow patterns in nearby existing code +- Use simple, concise, Sphinx docstrings +- Use type hints +- Start simple (CRUD), then add edge cases, errors, pagination + +### Avoid + +- Over-commenting tests — test name and structure should be self-explanatory +- Adding comments for standard steps (transformers, snapshot matching) +- Creating new markers without discussion + +--- + +## Reference + +- **Testing Docs:** https://github.com/localstack/localstack/tree/main/docs/testing +- **Architecture:** https://github.com/localstack/localstack/blob/main/docs/localstack-concepts/README.md +- **Common Fixtures:** `localstack-core/localstack/testing/pytest/fixtures.py` diff --git a/CODEOWNERS b/CODEOWNERS index d82443a8c02f6..d7537da30a6a7 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -24,9 +24,9 @@ /bin/release-helper.sh @thrau @alexrashed # Python project, packaging, and dependencies -/pyproject.toml @alexrashed @silv-io @k-a-il @bentsku @sannya-singal -/requirements-*.txt @alexrashed @silv-io @k-a-il @bentsku @sannya-singal -/.pre-commit-config.yaml @alexrashed @silv-io @k-a-il @bentsku @sannya-singal +/pyproject.toml @alexrashed @silv-io @k-a-il @bentsku @aidehn +/requirements-*.txt @alexrashed @silv-io @k-a-il @bentsku @aidehn +/.pre-commit-config.yaml @alexrashed @silv-io @k-a-il @bentsku @aidehn # ASF /localstack-core/localstack/aws/ @thrau @@ -37,11 +37,6 @@ # you can overwrite this for single services afterwards /localstack-core/localstack/aws/api/ -# CLI -/localstack-core/localstack/cli/ @thrau @alexrashed -/tests/unit/cli/ @thrau @alexrashed -/tests/cli/ @thrau @alexrashed - # Plugins /localstack-core/localstack/plugins.py @thrau /localstack-core/localstack/config.py @thrau @@ -149,10 +144,10 @@ /tests/aws/services/es/ @alexrashed @silv-io # events -/localstack-core/localstack/aws/api/events/ @maxhoheiser @bentsku -/localstack-core/localstack/services/events/ @maxhoheiser @bentsku -/tests/aws/services/events/ @maxhoheiser @bentsku -/tests/unit/services/events/ @maxhoheiser @bentsku +/localstack-core/localstack/aws/api/events/ @bentsku +/localstack-core/localstack/services/events/ @bentsku +/tests/aws/services/events/ @bentsku +/tests/unit/services/events/ @bentsku # firehose /localstack-core/localstack/aws/api/firehose/ @pinzon @@ -165,16 +160,16 @@ /tests/aws/services/iam/ @dfangl @pinzon # kms -/localstack-core/localstack/aws/api/kms/ @sannya-singal -/localstack-core/localstack/services/kms/ @sannya-singal -/tests/aws/services/kms/ @sannya-singal -/tests/unit/services/kms/ @sannya-singal +/localstack-core/localstack/aws/api/kms/ @k-a-il +/localstack-core/localstack/services/kms/ @k-a-il +/tests/aws/services/kms/ @k-a-il +/tests/unit/services/kms/ @k-a-il # lambda -/localstack-core/localstack/aws/api/lambda_/ @joe4dev @dominikschubert @dfangl @gregfurman -/localstack-core/localstack/services/lambda_/ @joe4dev @dominikschubert @dfangl @gregfurman -/tests/aws/services/lambda_/ @joe4dev @dominikschubert @dfangl @gregfurman -/tests/unit/services/lambda_/ @joe4dev @dominikschubert @dfangl @gregfurman +/localstack-core/localstack/aws/api/lambda_/ @joe4dev @dfangl @gregfurman +/localstack-core/localstack/services/lambda_/ @joe4dev @dfangl @gregfurman +/tests/aws/services/lambda_/ @joe4dev @dfangl @gregfurman +/tests/unit/services/lambda_/ @joe4dev @dfangl @gregfurman # logs /localstack-core/localstack/aws/api/logs/ @pinzon @steffyP @@ -189,7 +184,12 @@ /tests/unit/services/opensearch/ @alexrashed @silv-io # pipes -/localstack-core/localstack/aws/api/pipes/ @tiurin @gregfurman @joe4dev +/localstack-core/localstack/aws/api/pipes/ @tiurin @gregfurman @joe4dev @carole-lavillonniere + +# resourcegroupstaggingapi +/localstack-core/localstack/aws/api/resourcegroupstaggingapi/ @aidehn +/localstack-core/localstack/services/resourcegroupstaggingapi/ @aidehn +/tests/aws/services/resourcegroupstaggingapi/ @aidehn # route53 /localstack-core/localstack/aws/api/route53/ @giograno @@ -197,15 +197,15 @@ /tests/aws/services/route53/ @giograno # route53resolver -/localstack-core/localstack/aws/api/route53resolver/ @macnev2013 @sannya-singal -/localstack-core/localstack/services/route53resolver/ @macnev2013 @sannya-singal -/tests/aws/services/route53resolver/ @macnev2013 @sannya-singal +/localstack-core/localstack/aws/api/route53resolver/ @macnev2013 +/localstack-core/localstack/services/route53resolver/ @macnev2013 +/tests/aws/services/route53resolver/ @macnev2013 # s3 -/localstack-core/localstack/aws/api/s3/ @bentsku @k-a-il -/localstack-core/localstack/services/s3/ @bentsku @k-a-il -/tests/aws/services/s3/ @bentsku @k-a-il -/tests/unit/services/s3/ @bentsku @k-a-il +/localstack-core/localstack/aws/api/s3/ @bentsku @k-a-il @aidehn +/localstack-core/localstack/services/s3/ @bentsku @k-a-il @aidehn +/tests/aws/services/s3/ @bentsku @k-a-il @aidehn +/tests/unit/services/s3/ @bentsku @k-a-il @aidehn # s3control /localstack-core/localstack/aws/api/s3control/ @bentsku @@ -213,9 +213,9 @@ /tests/aws/services/s3control/ @bentsku # secretsmanager -/localstack-core/localstack/aws/api/secretsmanager/ @dominikschubert @macnev2013 -/localstack-core/localstack/services/secretsmanager/ @dominikschubert @macnev2013 -/tests/aws/services/secretsmanager/ @dominikschubert @macnev2013 +/localstack-core/localstack/aws/api/secretsmanager/ @macnev2013 +/localstack-core/localstack/services/secretsmanager/ @macnev2013 +/tests/aws/services/secretsmanager/ @macnev2013 # ses /localstack-core/localstack/aws/api/ses/ @viren-nadkarni @@ -229,10 +229,10 @@ /tests/unit/services/sns/ @bentsku @baermat # sqs -/localstack-core/localstack/aws/api/sqs/ @thrau @baermat @gregfurman -/localstack-core/localstack/services/sqs/ @thrau @baermat @gregfurman -/tests/aws/services/sqs/ @thrau @baermat @gregfurman -/tests/unit/services/sqs/ @thrau @baermat @gregfurman +/localstack-core/localstack/aws/api/sqs/ @baermat @gregfurman @thrau +/localstack-core/localstack/services/sqs/ @baermat @gregfurman @thrau +/tests/aws/services/sqs/ @baermat @gregfurman @thrau +/tests/unit/services/sqs/ @baermat @gregfurman @thrau # ssm /localstack-core/localstack/aws/api/ssm/ @viren-nadkarni @dominikschubert @@ -240,10 +240,10 @@ /tests/aws/services/ssm/ @viren-nadkarni @dominikschubert # stepfunctions -/localstack-core/localstack/aws/api/stepfunctions/ @dominikschubert @joe4dev @gregfurman -/localstack-core/localstack/services/stepfunctions/ @dominikschubert @joe4dev @gregfurman -/tests/aws/services/stepfunctions/ @dominikschubert @joe4dev @gregfurman -/tests/unit/services/stepfunctions/ @dominikschubert @joe4dev @gregfurman +/localstack-core/localstack/aws/api/stepfunctions/ @tiurin @joe4dev @gregfurman +/localstack-core/localstack/services/stepfunctions/ @tiurin @joe4dev @gregfurman +/tests/aws/services/stepfunctions/ @tiurin @joe4dev @gregfurman +/tests/unit/services/stepfunctions/ @tiurin @joe4dev @gregfurman # sts /localstack-core/localstack/aws/api/sts/ @pinzon @dfangl @@ -251,6 +251,6 @@ /tests/aws/services/sts/ @pinzon @dfangl # transcribe -/localstack-core/localstack/aws/api/transcribe/ @sannya-singal -/localstack-core/localstack/services/transcribe/ @sannya-singal -/tests/aws/services/transcribe/ @sannya-singal +/localstack-core/localstack/aws/api/transcribe/ @silv-io @k-a-il +/localstack-core/localstack/services/transcribe/ @silv-io @k-a-il +/tests/aws/services/transcribe/ @silv-io @k-a-il diff --git a/DOCKER.md b/DOCKER.md index bebba9bdb24a8..5af3f0ab0a64d 100644 --- a/DOCKER.md +++ b/DOCKER.md @@ -1,3 +1,8 @@ +> # ℹ️ **Important** +> +> ## We’re moving toward a unified LocalStack for AWS image, updating how access works. +> ## For details on timing and impact please refer [to this blog post](https://localstack.cloud/2026-updates). +

LocalStack - A fully functional local cloud stack

diff --git a/Dockerfile b/Dockerfile index 58520b4fd97ca..8ae951ee1969a 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,7 +1,7 @@ # # base: Stage which installs necessary runtime dependencies (OS packages, etc.) # -FROM python:3.13.7-slim-trixie@sha256:58c30f5bfaa718b5803a53393190b9c68bd517c44c6c94c1b6c8c172bcfad040 AS base +FROM python:3.13.12-slim-trixie@sha256:8bc60ca09afaa8ea0d6d1220bde073bacfedd66a4bf8129cbdc8ef0e16c8a952 AS base ARG TARGETARCH # Install runtime OS package dependencies @@ -49,7 +49,7 @@ RUN ARCH= && dpkgArch="$(dpkg --print-architecture)" \ && rm "$LATEST_VERSION_FILENAME.tar.xz" SHASUMS256.txt.asc SHASUMS256.txt \ && ln -s /usr/local/bin/node /usr/local/bin/nodejs \ # upgrade npm to the latest version - && npm upgrade -g npm \ + && npm install -g npm@latest \ # smoke tests && node --version \ && npm --version \ @@ -78,7 +78,7 @@ RUN chmod 777 . && \ # install the entrypoint script ADD bin/docker-entrypoint.sh /usr/local/bin/ -# add the shipped hosts file to prevent performance degredation in windows container mode on windows +# add the shipped hosts file to prevent performance degradation in windows container mode on windows # (where hosts file is not mounted) See https://github.com/localstack/localstack/issues/5178 ADD bin/hosts /etc/hosts @@ -104,7 +104,7 @@ RUN --mount=type=cache,target=/var/cache/apt \ apt-get update && \ # Install dependencies to add additional repos # g++ is a workaround to fix the JPype1 compile error on ARM Linux "gcc: fatal error: cannot execute ‘cc1plus’" - apt-get install -y gcc g++ + apt-get install -y --no-install-recommends gcc g++ # upgrade python build tools RUN --mount=type=cache,target=/root/.cache \ @@ -113,7 +113,7 @@ RUN --mount=type=cache,target=/root/.cache \ # add files necessary to install runtime dependencies ADD Makefile pyproject.toml requirements-runtime.txt ./ # add the localstack start scripts (necessary for the installation of the runtime dependencies, i.e. `pip install -e .`) -ADD bin/localstack bin/localstack.bat bin/localstack-supervisor bin/ +ADD bin/localstack-supervisor bin/ # Install dependencies for running the LocalStack runtime RUN --mount=type=cache,target=/root/.cache\ @@ -129,9 +129,9 @@ COPY --from=builder /opt/code/localstack/.venv /opt/code/localstack/.venv ARG LOCALSTACK_BUILD_VERSION # add project files necessary to install all dependencies -ADD Makefile pyproject.toml ./ +ADD Makefile pyproject.toml plux.ini ./ # add the localstack start scripts (necessary for the installation of the runtime dependencies, i.e. `pip install -e .`) -ADD bin/localstack bin/localstack.bat bin/localstack-supervisor bin/ +ADD bin/localstack-supervisor bin/ # add the code as late as possible ADD localstack-core/ /opt/code/localstack/localstack-core @@ -142,9 +142,10 @@ RUN --mount=type=cache,target=/root/.cache \ SETUPTOOLS_SCM_PRETEND_VERSION_FOR_LOCALSTACK_CORE=${LOCALSTACK_BUILD_VERSION} \ pip install -e .[runtime] -# Generate the plugin entrypoints -RUN SETUPTOOLS_SCM_PRETEND_VERSION_FOR_LOCALSTACK_CORE=${LOCALSTACK_BUILD_VERSION} \ - make entrypoints +# Install standalone CLI package +RUN --mount=type=cache,target=/root/.cache \ + . .venv/bin/activate && \ + pip install --upgrade --pre localstack # Generate service catalog cache in static libs dir RUN . .venv/bin/activate && python3 -m localstack.aws.spec diff --git a/Dockerfile.s3 b/Dockerfile.s3 index 7292f13942686..6ae631419c6ec 100644 --- a/Dockerfile.s3 +++ b/Dockerfile.s3 @@ -1,5 +1,5 @@ # base: Stage which installs necessary runtime dependencies (OS packages, filesystem...) -FROM python:3.13.7-slim-trixie@sha256:58c30f5bfaa718b5803a53393190b9c68bd517c44c6c94c1b6c8c172bcfad040 AS base +FROM python:3.13.12-slim-trixie@sha256:8bc60ca09afaa8ea0d6d1220bde073bacfedd66a4bf8129cbdc8ef0e16c8a952 AS base ARG TARGETARCH # set workdir @@ -58,7 +58,7 @@ RUN --mount=type=cache,target=/root/.cache \ # add files necessary to install all dependencies ADD Makefile pyproject.toml requirements-base-runtime.txt ./ # add the localstack start scripts (necessary for the installation of the runtime dependencies, i.e. `pip install -e .`) -ADD bin/localstack bin/localstack.bat bin/localstack-supervisor bin/ +ADD bin/localstack-supervisor bin/ # Install dependencies for running the LocalStack base runtime (for S3) RUN --mount=type=cache,target=/root/.cache \ @@ -76,9 +76,9 @@ COPY --from=builder /opt/code/localstack/.venv /opt/code/localstack/.venv ARG LOCALSTACK_BUILD_VERSION # add project files necessary to install all dependencies -ADD Makefile pyproject.toml requirements-base-runtime.txt ./ +ADD Makefile pyproject.toml plux.ini requirements-base-runtime.txt ./ # add the localstack start scripts (necessary for the installation of the runtime dependencies, i.e. `pip install -e .`) -ADD bin/localstack bin/localstack.bat bin/localstack-supervisor bin/ +ADD bin/localstack-supervisor bin/ # add the code as late as possible ADD localstack-core/ /opt/code/localstack/localstack-core @@ -89,10 +89,6 @@ RUN --mount=type=cache,target=/root/.cache \ SETUPTOOLS_SCM_PRETEND_VERSION_FOR_LOCALSTACK_CORE=${LOCALSTACK_BUILD_VERSION} \ pip install -e .[base-runtime] -# Generate the plugin entrypoints -RUN SETUPTOOLS_SCM_PRETEND_VERSION_FOR_LOCALSTACK_CORE=${LOCALSTACK_BUILD_VERSION} \ - make entrypoints - # Generate service catalog cache in static libs dir RUN . .venv/bin/activate && python3 -m localstack.aws.spec diff --git a/MANIFEST.in b/MANIFEST.in index 07442c11a993f..53076cee97ece 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1,5 +1,4 @@ exclude .github/** -exclude .circleci/** exclude docs/** exclude tests/** exclude .test_durations diff --git a/Makefile b/Makefile index 58bbab9c7dda8..2bd6322186309 100644 --- a/Makefile +++ b/Makefile @@ -27,7 +27,7 @@ usage: ## Show this help $(VENV_ACTIVATE): pyproject.toml test -d $(VENV_DIR) || $(VENV_BIN) $(VENV_DIR) - $(VENV_RUN); $(PIP_CMD) install --upgrade pip setuptools wheel plux + $(VENV_RUN); $(PIP_CMD) install --upgrade pip setuptools wheel touch $(VENV_ACTIVATE) venv: $(VENV_ACTIVATE) ## Create a new (empty) virtual environment @@ -36,8 +36,8 @@ freeze: ## Run pip freeze -l in the virtual environment @$(VENV_RUN); pip freeze -l upgrade-pinned-dependencies: venv - # FIXME remove pin on pip-tools when https://github.com/jazzband/pip-tools/issues/2215 us resolved - $(VENV_RUN); $(PIP_CMD) install --upgrade "pip-tools<7.5.0" pre-commit + # TODO: Avoid pip 26.0 for now due to https://github.com/jazzband/pip-tools/issues/2319 + $(VENV_RUN); $(PIP_CMD) install --upgrade "pip<26.0" pip-tools pre-commit $(VENV_RUN); pip-compile --strip-extras --upgrade -o requirements-basic.txt pyproject.toml $(VENV_RUN); pip-compile --strip-extras --upgrade --extra runtime -o requirements-runtime.txt pyproject.toml $(VENV_RUN); pip-compile --strip-extras --upgrade --extra test -o requirements-test.txt pyproject.toml @@ -70,15 +70,15 @@ install-s3: venv ## Install dependencies for the localstack runtime for s3-o $(VENV_RUN); $(PIP_CMD) install -r requirements-base-runtime.txt $(VENV_RUN); $(PIP_CMD) install $(PIP_OPTS) -e ".[base-runtime]" -install: install-dev entrypoints ## Install full dependencies into venv +install: install-dev ## Install full dependencies into venv -entrypoints: ## Run plux to build entry points - $(VENV_RUN); python3 -c "from setuptools import setup; setup()" plugins egg_info - @# make sure that the entrypoints were correctly created and are non-empty - @test -s localstack-core/localstack_core.egg-info/entry_points.txt || (echo "Entrypoints were not correctly created! Aborting!" && exit 1) +entrypoints: install-dev + $(VENV_RUN); python -m plux entrypoints + @# make sure that the plux.ini file with the entrypoints has correctly been created + @test -s plux.ini || (echo "Entrypoints were not correctly created! Aborting!" && exit 1) -dist: entrypoints ## Build source and built (wheel) distributions of the current version - $(VENV_RUN); pip install --upgrade twine; python -m build +dist: ## Build source and built (wheel) distributions of the current version + $(VENV_RUN); pip install --upgrade build twine; python -m build publish: clean-dist dist ## Publish the library to the central PyPi repository # make sure the dist archive contains a non-empty entry_points.txt file before uploading @@ -89,10 +89,10 @@ coveralls: ## Publish coveralls metrics $(VENV_RUN); coveralls start: ## Manually start the local infrastructure for testing - ($(VENV_RUN); exec bin/localstack start --host) + ($(VENV_RUN); python3 -m localstack.runtime.main) docker-run-tests: ## Initializes the test environment and runs the tests in a docker container - docker run -e LOCALSTACK_INTERNAL_TEST_COLLECT_METRIC=1 --entrypoint= -v `pwd`/.git:/opt/code/localstack/.git -v `pwd`/requirements-test.txt:/opt/code/localstack/requirements-test.txt -v `pwd`/.test_durations:/opt/code/localstack/.test_durations -v `pwd`/tests/:/opt/code/localstack/tests/ -v `pwd`/dist/:/opt/code/localstack/dist/ -v `pwd`/target/:/opt/code/localstack/target/ -v /var/run/docker.sock:/var/run/docker.sock -v /tmp/localstack:/var/lib/localstack \ + docker run -e LOCALSTACK_INTERNAL_TEST_COLLECT_METRIC=1 -e DOCKERHUB_USERNAME -e DOCKERHUB_PASSWORD --entrypoint= -v `pwd`/.git:/opt/code/localstack/.git -v `pwd`/requirements-test.txt:/opt/code/localstack/requirements-test.txt -v `pwd`/.test_durations:/opt/code/localstack/.test_durations -v `pwd`/tests/:/opt/code/localstack/tests/ -v `pwd`/dist/:/opt/code/localstack/dist/ -v `pwd`/target/:/opt/code/localstack/target/ -v /var/run/docker.sock:/var/run/docker.sock -v /tmp/localstack:/var/lib/localstack \ $(IMAGE_NAME):$(DEFAULT_TAG) \ bash -c "make install-test && DEBUG=$(DEBUG) PYTEST_LOGLEVEL=$(PYTEST_LOGLEVEL) PYTEST_ARGS='$(PYTEST_ARGS)' COVERAGE_FILE='$(COVERAGE_FILE)' JUNIT_REPORTS_FILE=$(JUNIT_REPORTS_FILE) TEST_PATH='$(TEST_PATH)' LAMBDA_IGNORE_ARCHITECTURE=1 LAMBDA_INIT_POST_INVOKE_WAIT_MS=50 TINYBIRD_PYTEST_ARGS='$(TINYBIRD_PYTEST_ARGS)' TINYBIRD_DATASOURCE='$(TINYBIRD_DATASOURCE)' TINYBIRD_TOKEN='$(TINYBIRD_TOKEN)' TINYBIRD_URL='$(TINYBIRD_URL)' CI_REPOSITORY_NAME='$(CI_REPOSITORY_NAME)' CI_WORKFLOW_NAME='$(CI_WORKFLOW_NAME)' CI_COMMIT_BRANCH='$(CI_COMMIT_BRANCH)' CI_COMMIT_SHA='$(CI_COMMIT_SHA)' CI_JOB_URL='$(CI_JOB_URL)' CI_JOB_NAME='$(CI_JOB_NAME)' CI_JOB_ID='$(CI_JOB_ID)' CI='$(CI)' TEST_AWS_REGION_NAME='${TEST_AWS_REGION_NAME}' TEST_AWS_ACCESS_KEY_ID='${TEST_AWS_ACCESS_KEY_ID}' TEST_AWS_ACCOUNT_ID='${TEST_AWS_ACCOUNT_ID}' make test-coverage" @@ -123,6 +123,7 @@ lint: ## Run code linter to check code style, check if formatte $(VENV_RUN); pre-commit run check-pinned-deps-for-needed-upgrade --files pyproject.toml # run pre-commit hook manually here to ensure that this check runs in CI as well $(VENV_RUN); openapi-spec-validator localstack-core/localstack/openapi.yaml $(VENV_RUN); cd localstack-core && mypy --install-types --non-interactive + $(VENV_RUN); deptry . lint-modified: ## Run code linter to check code style, check if formatter would make changes on modified files, and check if dependency pins need to be updated because of modified files ($(VENV_RUN); python -m ruff check --output-format=full `git diff --diff-filter=d --name-only HEAD | grep '\.py$$' | xargs` && python -m ruff format --check `git diff --diff-filter=d --name-only HEAD | grep '\.py$$' | xargs`) @@ -139,6 +140,13 @@ format-modified: ## Run ruff to format only modified code python -m ruff check --output-format=full --fix `git diff --diff-filter=d --name-only HEAD | grep '\.py$$' | xargs`; \ python -m ruff format `git diff --diff-filter=d --name-only HEAD | grep '\.py$$' | xargs`) +asf-regenerate: ## Regenerate ASF APIs + $(VENV_RUN); python -m localstack.aws.scaffold upgrade + @echo 'Removing unused imports from generated modules' + $(VENV_RUN); python -m ruff check --select F401 --unsafe-fixes --fix localstack-core/localstack/aws/api/ --config "lint.preview = true" + $(VENV_RUN); python -m ruff check --output-format=full --fix localstack-core/localstack/aws/api/ + $(VENV_RUN); python -m ruff format localstack-core/localstack/aws/api/ + init-precommit: ## install te pre-commit hook into your local git repository ($(VENV_RUN); pre-commit install) @@ -157,4 +165,4 @@ clean-dist: ## Clean up python distribution directories rm -rf dist/ build/ rm -rf localstack-core/*.egg-info -.PHONY: usage freeze install-basic install-runtime install-test install-dev install entrypoints dist publish coveralls start docker-run-tests docker-cp-coverage test test-coverage lint lint-modified format format-modified init-precommit clean clean-dist upgrade-pinned-dependencies +.PHONY: usage freeze install-basic install-runtime install-test install-dev install entrypoints dist publish coveralls start docker-run-tests docker-cp-coverage test test-coverage lint lint-modified format format-modified asf-regenerate init-precommit clean clean-dist upgrade-pinned-dependencies diff --git a/README.md b/README.md index 2d3c9533e78f6..0d78c2be49085 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,16 @@ -

-:zap: We are thrilled to announce the release of LocalStack 4.9 :zap: -

+> [!IMPORTANT] +> **Project Update: Consolidation into the Unified LocalStack Image** +> +> To provide a more reliable and streamlined experience, we are consolidating our development into a single, unified image. As part of this transition, this repository is now **archived and read-only**. +> +> This decision reflects our commitment to reducing fragmentation and focusing our resources on building the most robust AWS emulation layer possible. We are deeply grateful to the contributors who helped make this project into what it is today–your work remains integral to the future of the LocalStack ecosystem. +> +> What this means for your workflow: +> +> - LocalStack for AWS offers a [range of options](https://www.localstack.cloud/pricing) including a free Hobby plan for non-commercial use with the same capabilities as this project. +> - Your input is still vital to us. Please continue to share [bug reports here](https://github.com/orgs/localstack/discussions/categories/bugs) and [submit feature requests here](https://github.com/orgs/localstack/discussions/categories/feature-requests) or join our [Slack Community](https://slack.localstack.cloud). +> +> Thank you for your continued support as we grow together.

LocalStack - The Leading Platform for Local Cloud Development @@ -12,8 +22,6 @@ PyPI Version Docker Pulls PyPi downloads - Backers on Open Collective - Sponsors on Open Collective PyPI License Code style: black Ruff @@ -34,7 +42,7 @@ Contributing
📖 Docs • - 💻 Pro version • + 💻 LocalStack for AWS☑️ LocalStack coverage

@@ -66,7 +74,7 @@ If Brew is not installed on your machine, you can download the pre-built LocalSt - Visit [localstack/localstack-cli](https://github.com/localstack/localstack-cli/releases/latest) and download the latest release for your platform. - Extract the downloaded archive to a directory included in your `PATH` variable: - - For macOS/Linux, use the command: `sudo tar xvzf ~/Downloads/localstack-cli-*-darwin-*-onefile.tar.gz -C /usr/local/bin` + - For macOS/Linux, use the command: `sudo tar xvzf ~/Downloads/localstack-cli-*-darwin-*-onefile.tar.gz -C /usr/local/bin` ### PyPI (macOS, Linux, Windows) @@ -153,9 +161,9 @@ To start using LocalStack, check out our [documentation](https://docs.localstack To use LocalStack with a graphical user interface, you can use the following UI clients: -* [LocalStack Web Application](https://app.localstack.cloud) -* [LocalStack Desktop](https://docs.localstack.cloud/user-guide/tools/localstack-desktop/) -* [LocalStack Docker Extension](https://docs.localstack.cloud/user-guide/tools/localstack-docker-extension/) +- [LocalStack Web Application](https://app.localstack.cloud) +- [LocalStack Desktop](https://docs.localstack.cloud/user-guide/tools/localstack-desktop/) +- [LocalStack Docker Extension](https://docs.localstack.cloud/user-guide/tools/localstack-docker-extension/) ## Releases @@ -211,7 +219,7 @@ You can also support this project by becoming a sponsor on [Open Collective](htt ## License -Copyright (c) 2017-2025 LocalStack maintainers and contributors. +Copyright (c) 2017-2026 LocalStack maintainers and contributors. Copyright (c) 2016 Atlassian and others. diff --git a/bin/docker-entrypoint.sh b/bin/docker-entrypoint.sh index 1c4a297fd1fa1..985d791907b61 100755 --- a/bin/docker-entrypoint.sh +++ b/bin/docker-entrypoint.sh @@ -3,17 +3,27 @@ set -eo pipefail shopt -s nullglob +if [ -z $LOCALSTACK_AUTH_TOKEN ]; then + echo "WARNING" + echo "================================================================================" + echo " You are starting the LocalStack Community Docker image." + echo " We move towards a unified LocalStack for AWS image in March 2026." + echo " Go to this page for more infos: https://localstack.cloud/2026-updates" + echo "================================================================================" + echo "" +fi + # When trying to activate pro features in the community version, raise a warning if [[ -n $LOCALSTACK_API_KEY || -n $LOCALSTACK_AUTH_TOKEN ]]; then echo "WARNING" - echo "============================================================================" - echo " It seems you are trying to use the LocalStack Pro version without using " - echo " the dedicated Pro image." + echo "================================================================================" + echo " It seems you are trying to use the LocalStack Pro version without using the" + echo " dedicated Pro image." echo " LocalStack will only start with community services enabled." echo " To fix this warning, use localstack/localstack-pro instead." echo "" echo " See: https://github.com/localstack/localstack/issues/7882" - echo "============================================================================" + echo "================================================================================" echo "" fi diff --git a/bin/docker-helper.sh b/bin/docker-helper.sh index 5c8cd0f52bfcd..58bf0736d2d9d 100755 --- a/bin/docker-helper.sh +++ b/bin/docker-helper.sh @@ -138,7 +138,11 @@ function cmd-build() { # --add-host: Fix for Centos host OS # --build-arg BUILDKIT_INLINE_CACHE=1: Instruct buildkit to inline the caching information into the image # --cache-from: Use the inlined caching information when building the image - DOCKER_BUILDKIT=1 docker buildx build --platform linux/$PLATFORM --pull --progress=plain \ + # BUILDX_NO_DEFAULT_ATTESTATIONS=1 buildkit attestation will lead to the image being a single-platform image index if built with buildkit and containerd image store. + # The docker manifest command we use to create multi platform manifests does not support doing this from those image indexes, failing with ` is a manifest list` + # We might want to revert this to use attestation, but for now this locks the old behavior of the image manifest being a `application/vnd.docker.distribution.manifest.v2+json` + # Before switching back we also need to make sure other registries like ECR support these single platform image indexes + DOCKER_BUILDKIT=1 BUILDX_NO_DEFAULT_ATTESTATIONS=1 docker buildx build --platform linux/$PLATFORM --pull --progress=plain \ --cache-from "$IMAGE_NAME" --build-arg BUILDKIT_INLINE_CACHE=1 \ --build-arg LOCALSTACK_PRE_RELEASE=$(_is_release_commit && echo "0" || echo "1") \ --build-arg LOCALSTACK_BUILD_GIT_HASH=$(git rev-parse --short HEAD) \ diff --git a/bin/localstack b/bin/localstack deleted file mode 100755 index 5cd199565d8bf..0000000000000 --- a/bin/localstack +++ /dev/null @@ -1,23 +0,0 @@ -#!/usr/bin/env python3 - -import glob -import os -import sys - -PARENT_FOLDER = os.path.realpath(os.path.join(os.path.dirname(os.path.realpath(__file__)), "..")) -venv_dir = os.path.join(PARENT_FOLDER, ".venv") -insert_pos = min(len(sys.path), 2) -if os.path.isdir(venv_dir): - for path in glob.glob(os.path.join(venv_dir, "lib/python*/site-packages")): - sys.path.insert(insert_pos, path) - sys.path.insert(insert_pos, PARENT_FOLDER) - - -def main(): - from localstack.cli import main - - main.main() - - -if __name__ == "__main__": - main() diff --git a/bin/localstack.bat b/bin/localstack.bat deleted file mode 100644 index 05370a69c42ef..0000000000000 --- a/bin/localstack.bat +++ /dev/null @@ -1 +0,0 @@ -python "%~dp0\localstack" %* diff --git a/docs/CONTRIBUTING.md b/docs/CONTRIBUTING.md index 35af4e8333b5d..57f575d8921ee 100644 --- a/docs/CONTRIBUTING.md +++ b/docs/CONTRIBUTING.md @@ -5,9 +5,9 @@ We welcome contributions to LocalStack! Please refer to the following sections t ## Sections - [Contribution Guidelines](#contribution-guidelines) -- [Development Environment Setup](development-environment-setup/README.md) -- [LocalStack Concepts](localstack-concepts/README.md) -- [Testing](testing/README.md) +- [Development Environment Setup](/docs/development-environment-setup/README.md) +- [LocalStack Concepts](/docs/localstack-concepts/README.md) +- [Testing](/docs/testing/README.md) ## Contribution Guidelines @@ -19,7 +19,7 @@ For pull requests (PRs), please stick to the following guidelines: * Fork localstack on your GitHub user account, make code changes there, and then create a PR against main localstack repository. * Add tests for any new features or bug fixes. Ideally, each PR increases the test coverage. Please read our [integration testing](testing/integration-tests/README.md) and [parity testing](testing/parity-testing/README.md) guides on how to write tests for AWS services. * Follow the existing code style. Run `make format` and `make lint` before checking in your code. - * Refer to [Development Environment Setup](development-environment-setup/README.md) if your local testing environment is not yet properly set up. + * Refer to [Development Environment Setup](/docs/development-environment-setup/README.md) if your local testing environment is not yet properly set up. * Document newly introduced methods and classes with pydoc, and add inline comments to code that is not self-documenting. * Separate unrelated changes into multiple PRs. * When creating a PR, classify the size of your change with setting a semver label: diff --git a/docs/development-environment-setup/README.md b/docs/development-environment-setup/README.md index f5342846143ad..6a9c82097df3b 100644 --- a/docs/development-environment-setup/README.md +++ b/docs/development-environment-setup/README.md @@ -1,7 +1,7 @@ # Development Environment Setup Before you get started with contributing to LocalStack, make sure you’ve familiarized yourself with LocalStack from the perspective of a user. -You can follow our [getting started guide](https://docs.localstack.cloud/get-started/). +You can follow our [getting started guide](https://docs.localstack.cloud/getting-started/). Once LocalStack runs in your Docker environment and you’ve played around with the LocalStack and `awslocal` CLI, you can move forward to set up your developer environment. ## Development requirements @@ -69,8 +69,7 @@ LocalStack runs its own [DNS server](https://docs.localstack.cloud/user-guide/to #### Python Dependencies * [JPype1](https://pypi.org/project/JPype1/) might require `g++` to fix a compile error on ARM Linux `gcc: fatal error: cannot execute ‘cc1plus’` - * Used in EventBridge, EventBridge Pipes, and Lambda Event Source Mapping for a Java-based event ruler via the opt-in configuration `EVENT_RULE_ENGINE=java` - * Introduced in [#10615](https://github.com/localstack/localstack/pull/10615) + * Used in StepFunctions for JSONata #### Test Dependencies diff --git a/docs/localstack-concepts/README.md b/docs/localstack-concepts/README.md index cee2227c14d75..4dbfccb9fb80d 100644 --- a/docs/localstack-concepts/README.md +++ b/docs/localstack-concepts/README.md @@ -143,9 +143,9 @@ Plugins provided by [https://github.com/localstack/plux](https://github.com/loca - Hooks - Extensions -Key points to understand are that plugins use [Python entry points, which are part of the PyPA specification](https://packaging.python.org/en/latest/specifications/entry-points/). Entry points are discovered from the code during a build step rather than defined manually (this is the main differentiator of Plux to other code loading tools). In LocalStack, the `make entrypoints` make target does that, which is also part of `make install`. +Key points to understand are that plugins use [Python entry points, which are part of the PyPA specification](https://packaging.python.org/en/latest/specifications/entry-points/). Entry points are discovered from the code and maintained in the `plux.ini` file, which is version-controlled. This file is used at build time to generate the entry points for the Python package. -When you add new hooks or service providers, or any other plugin, make sure to run `make entrypoints`. +When you add new hooks or service providers, or any other plugin, make sure to run `make entrypoints` to update the `plux.ini` file, and commit the changes to version control. When writing plugins, it is important to understand that any code that sits in the same module as the plugin, will be imported when the plugin is _resolved_. That is, _before_ it is loaded. Resolving a plugin simply means discovering the entry points and loading the code the underlying entry point points to. This is why many times you will see imports deferred to the actual loading of the plugin. diff --git a/localstack-core/localstack/aws/api/acm/__init__.py b/localstack-core/localstack/aws/api/acm/__init__.py index b62d3c2508d96..8d10782d79470 100644 --- a/localstack-core/localstack/aws/api/acm/__init__.py +++ b/localstack-core/localstack/aws/api/acm/__init__.py @@ -1,6 +1,6 @@ from datetime import datetime from enum import StrEnum -from typing import List, Optional, TypedDict +from typing import TypedDict from localstack.aws.api import RequestContext, ServiceException, ServiceRequest, handler @@ -261,10 +261,10 @@ class ValidationException(ServiceException): class Tag(TypedDict, total=False): Key: TagKey - Value: Optional[TagValue] + Value: TagValue | None -TagList = List[Tag] +TagList = list[Tag] class AddTagsToCertificateRequest(ServiceRequest): @@ -277,29 +277,29 @@ class AddTagsToCertificateRequest(ServiceRequest): class CertificateOptions(TypedDict, total=False): - CertificateTransparencyLoggingPreference: Optional[CertificateTransparencyLoggingPreference] - Export: Optional[CertificateExport] + CertificateTransparencyLoggingPreference: CertificateTransparencyLoggingPreference | None + Export: CertificateExport | None class ExtendedKeyUsage(TypedDict, total=False): - Name: Optional[ExtendedKeyUsageName] - OID: Optional[String] + Name: ExtendedKeyUsageName | None + OID: String | None -ExtendedKeyUsageList = List[ExtendedKeyUsage] +ExtendedKeyUsageList = list[ExtendedKeyUsage] class KeyUsage(TypedDict, total=False): - Name: Optional[KeyUsageName] + Name: KeyUsageName | None -KeyUsageList = List[KeyUsage] +KeyUsageList = list[KeyUsage] TStamp = datetime class HttpRedirect(TypedDict, total=False): - RedirectFrom: Optional[String] - RedirectTo: Optional[String] + RedirectFrom: String | None + RedirectTo: String | None class ResourceRecord(TypedDict, total=False): @@ -308,92 +308,92 @@ class ResourceRecord(TypedDict, total=False): Value: String -ValidationEmailList = List[String] +ValidationEmailList = list[String] class DomainValidation(TypedDict, total=False): DomainName: DomainNameString - ValidationEmails: Optional[ValidationEmailList] - ValidationDomain: Optional[DomainNameString] - ValidationStatus: Optional[DomainStatus] - ResourceRecord: Optional[ResourceRecord] - HttpRedirect: Optional[HttpRedirect] - ValidationMethod: Optional[ValidationMethod] + ValidationEmails: ValidationEmailList | None + ValidationDomain: DomainNameString | None + ValidationStatus: DomainStatus | None + ResourceRecord: ResourceRecord | None + HttpRedirect: HttpRedirect | None + ValidationMethod: ValidationMethod | None -DomainValidationList = List[DomainValidation] +DomainValidationList = list[DomainValidation] class RenewalSummary(TypedDict, total=False): RenewalStatus: RenewalStatus DomainValidationOptions: DomainValidationList - RenewalStatusReason: Optional[FailureReason] + RenewalStatusReason: FailureReason | None UpdatedAt: TStamp -InUseList = List[String] -DomainList = List[DomainNameString] +InUseList = list[String] +DomainList = list[DomainNameString] class CertificateDetail(TypedDict, total=False): - CertificateArn: Optional[Arn] - DomainName: Optional[DomainNameString] - SubjectAlternativeNames: Optional[DomainList] - ManagedBy: Optional[CertificateManagedBy] - DomainValidationOptions: Optional[DomainValidationList] - Serial: Optional[String] - Subject: Optional[String] - Issuer: Optional[String] - CreatedAt: Optional[TStamp] - IssuedAt: Optional[TStamp] - ImportedAt: Optional[TStamp] - Status: Optional[CertificateStatus] - RevokedAt: Optional[TStamp] - RevocationReason: Optional[RevocationReason] - NotBefore: Optional[TStamp] - NotAfter: Optional[TStamp] - KeyAlgorithm: Optional[KeyAlgorithm] - SignatureAlgorithm: Optional[String] - InUseBy: Optional[InUseList] - FailureReason: Optional[FailureReason] - Type: Optional[CertificateType] - RenewalSummary: Optional[RenewalSummary] - KeyUsages: Optional[KeyUsageList] - ExtendedKeyUsages: Optional[ExtendedKeyUsageList] - CertificateAuthorityArn: Optional[Arn] - RenewalEligibility: Optional[RenewalEligibility] - Options: Optional[CertificateOptions] - - -CertificateStatuses = List[CertificateStatus] -ExtendedKeyUsageNames = List[ExtendedKeyUsageName] -KeyUsageNames = List[KeyUsageName] + CertificateArn: Arn | None + DomainName: DomainNameString | None + SubjectAlternativeNames: DomainList | None + ManagedBy: CertificateManagedBy | None + DomainValidationOptions: DomainValidationList | None + Serial: String | None + Subject: String | None + Issuer: String | None + CreatedAt: TStamp | None + IssuedAt: TStamp | None + ImportedAt: TStamp | None + Status: CertificateStatus | None + RevokedAt: TStamp | None + RevocationReason: RevocationReason | None + NotBefore: TStamp | None + NotAfter: TStamp | None + KeyAlgorithm: KeyAlgorithm | None + SignatureAlgorithm: String | None + InUseBy: InUseList | None + FailureReason: FailureReason | None + Type: CertificateType | None + RenewalSummary: RenewalSummary | None + KeyUsages: KeyUsageList | None + ExtendedKeyUsages: ExtendedKeyUsageList | None + CertificateAuthorityArn: Arn | None + RenewalEligibility: RenewalEligibility | None + Options: CertificateOptions | None + + +CertificateStatuses = list[CertificateStatus] +ExtendedKeyUsageNames = list[ExtendedKeyUsageName] +KeyUsageNames = list[KeyUsageName] class CertificateSummary(TypedDict, total=False): - CertificateArn: Optional[Arn] - DomainName: Optional[DomainNameString] - SubjectAlternativeNameSummaries: Optional[DomainList] - HasAdditionalSubjectAlternativeNames: Optional[NullableBoolean] - Status: Optional[CertificateStatus] - Type: Optional[CertificateType] - KeyAlgorithm: Optional[KeyAlgorithm] - KeyUsages: Optional[KeyUsageNames] - ExtendedKeyUsages: Optional[ExtendedKeyUsageNames] - ExportOption: Optional[CertificateExport] - InUse: Optional[NullableBoolean] - Exported: Optional[NullableBoolean] - RenewalEligibility: Optional[RenewalEligibility] - NotBefore: Optional[TStamp] - NotAfter: Optional[TStamp] - CreatedAt: Optional[TStamp] - IssuedAt: Optional[TStamp] - ImportedAt: Optional[TStamp] - RevokedAt: Optional[TStamp] - ManagedBy: Optional[CertificateManagedBy] - - -CertificateSummaryList = List[CertificateSummary] + CertificateArn: Arn | None + DomainName: DomainNameString | None + SubjectAlternativeNameSummaries: DomainList | None + HasAdditionalSubjectAlternativeNames: NullableBoolean | None + Status: CertificateStatus | None + Type: CertificateType | None + KeyAlgorithm: KeyAlgorithm | None + KeyUsages: KeyUsageNames | None + ExtendedKeyUsages: ExtendedKeyUsageNames | None + ExportOption: CertificateExport | None + InUse: NullableBoolean | None + Exported: NullableBoolean | None + RenewalEligibility: RenewalEligibility | None + NotBefore: TStamp | None + NotAfter: TStamp | None + CreatedAt: TStamp | None + IssuedAt: TStamp | None + ImportedAt: TStamp | None + RevokedAt: TStamp | None + ManagedBy: CertificateManagedBy | None + + +CertificateSummaryList = list[CertificateSummary] class DeleteCertificateRequest(ServiceRequest): @@ -405,7 +405,7 @@ class DescribeCertificateRequest(ServiceRequest): class DescribeCertificateResponse(TypedDict, total=False): - Certificate: Optional[CertificateDetail] + Certificate: CertificateDetail | None class DomainValidationOption(TypedDict, total=False): @@ -413,11 +413,11 @@ class DomainValidationOption(TypedDict, total=False): ValidationDomain: DomainNameString -DomainValidationOptionList = List[DomainValidationOption] +DomainValidationOptionList = list[DomainValidationOption] class ExpiryEventsConfiguration(TypedDict, total=False): - DaysBeforeExpiry: Optional[PositiveInteger] + DaysBeforeExpiry: PositiveInteger | None PassphraseBlob = bytes @@ -429,26 +429,26 @@ class ExportCertificateRequest(ServiceRequest): class ExportCertificateResponse(TypedDict, total=False): - Certificate: Optional[CertificateBody] - CertificateChain: Optional[CertificateChain] - PrivateKey: Optional[PrivateKey] + Certificate: CertificateBody | None + CertificateChain: CertificateChain | None + PrivateKey: PrivateKey | None -ExtendedKeyUsageFilterList = List[ExtendedKeyUsageName] -KeyAlgorithmList = List[KeyAlgorithm] -KeyUsageFilterList = List[KeyUsageName] +ExtendedKeyUsageFilterList = list[ExtendedKeyUsageName] +KeyAlgorithmList = list[KeyAlgorithm] +KeyUsageFilterList = list[KeyUsageName] class Filters(TypedDict, total=False): - extendedKeyUsage: Optional[ExtendedKeyUsageFilterList] - keyUsage: Optional[KeyUsageFilterList] - keyTypes: Optional[KeyAlgorithmList] - exportOption: Optional[CertificateExport] - managedBy: Optional[CertificateManagedBy] + extendedKeyUsage: ExtendedKeyUsageFilterList | None + keyUsage: KeyUsageFilterList | None + keyTypes: KeyAlgorithmList | None + exportOption: CertificateExport | None + managedBy: CertificateManagedBy | None class GetAccountConfigurationResponse(TypedDict, total=False): - ExpiryEvents: Optional[ExpiryEventsConfiguration] + ExpiryEvents: ExpiryEventsConfiguration | None class GetCertificateRequest(ServiceRequest): @@ -456,37 +456,37 @@ class GetCertificateRequest(ServiceRequest): class GetCertificateResponse(TypedDict, total=False): - Certificate: Optional[CertificateBody] - CertificateChain: Optional[CertificateChain] + Certificate: CertificateBody | None + CertificateChain: CertificateChain | None PrivateKeyBlob = bytes class ImportCertificateRequest(ServiceRequest): - CertificateArn: Optional[Arn] + CertificateArn: Arn | None Certificate: CertificateBodyBlob PrivateKey: PrivateKeyBlob - CertificateChain: Optional[CertificateChainBlob] - Tags: Optional[TagList] + CertificateChain: CertificateChainBlob | None + Tags: TagList | None class ImportCertificateResponse(TypedDict, total=False): - CertificateArn: Optional[Arn] + CertificateArn: Arn | None class ListCertificatesRequest(ServiceRequest): - CertificateStatuses: Optional[CertificateStatuses] - Includes: Optional[Filters] - NextToken: Optional[NextToken] - MaxItems: Optional[MaxItems] - SortBy: Optional[SortBy] - SortOrder: Optional[SortOrder] + CertificateStatuses: CertificateStatuses | None + Includes: Filters | None + NextToken: NextToken | None + MaxItems: MaxItems | None + SortBy: SortBy | None + SortOrder: SortOrder | None class ListCertificatesResponse(TypedDict, total=False): - NextToken: Optional[NextToken] - CertificateSummaryList: Optional[CertificateSummaryList] + NextToken: NextToken | None + CertificateSummaryList: CertificateSummaryList | None class ListTagsForCertificateRequest(ServiceRequest): @@ -494,11 +494,11 @@ class ListTagsForCertificateRequest(ServiceRequest): class ListTagsForCertificateResponse(TypedDict, total=False): - Tags: Optional[TagList] + Tags: TagList | None class PutAccountConfigurationRequest(ServiceRequest): - ExpiryEvents: Optional[ExpiryEventsConfiguration] + ExpiryEvents: ExpiryEventsConfiguration | None IdempotencyToken: IdempotencyToken @@ -513,19 +513,19 @@ class RenewCertificateRequest(ServiceRequest): class RequestCertificateRequest(ServiceRequest): DomainName: DomainNameString - ValidationMethod: Optional[ValidationMethod] - SubjectAlternativeNames: Optional[DomainList] - IdempotencyToken: Optional[IdempotencyToken] - DomainValidationOptions: Optional[DomainValidationOptionList] - Options: Optional[CertificateOptions] - CertificateAuthorityArn: Optional[PcaArn] - Tags: Optional[TagList] - KeyAlgorithm: Optional[KeyAlgorithm] - ManagedBy: Optional[CertificateManagedBy] + ValidationMethod: ValidationMethod | None + SubjectAlternativeNames: DomainList | None + IdempotencyToken: IdempotencyToken | None + DomainValidationOptions: DomainValidationOptionList | None + Options: CertificateOptions | None + CertificateAuthorityArn: PcaArn | None + Tags: TagList | None + KeyAlgorithm: KeyAlgorithm | None + ManagedBy: CertificateManagedBy | None class RequestCertificateResponse(TypedDict, total=False): - CertificateArn: Optional[Arn] + CertificateArn: Arn | None class ResendValidationEmailRequest(ServiceRequest): @@ -540,7 +540,7 @@ class RevokeCertificateRequest(ServiceRequest): class RevokeCertificateResponse(TypedDict, total=False): - CertificateArn: Optional[Arn] + CertificateArn: Arn | None class UpdateCertificateOptionsRequest(ServiceRequest): @@ -549,8 +549,8 @@ class UpdateCertificateOptionsRequest(ServiceRequest): class AcmApi: - service = "acm" - version = "2015-12-08" + service: str = "acm" + version: str = "2015-12-08" @handler("AddTagsToCertificate") def add_tags_to_certificate( diff --git a/localstack-core/localstack/aws/api/apigateway/__init__.py b/localstack-core/localstack/aws/api/apigateway/__init__.py index ac90e9f542368..d47a5a760ea0d 100644 --- a/localstack-core/localstack/aws/api/apigateway/__init__.py +++ b/localstack-core/localstack/aws/api/apigateway/__init__.py @@ -1,6 +1,7 @@ +from collections.abc import Iterable from datetime import datetime from enum import StrEnum -from typing import IO, Dict, Iterable, List, Optional, TypedDict, Union +from typing import IO, TypedDict from localstack.aws.api import RequestContext, ServiceException, ServiceRequest, handler @@ -28,6 +29,13 @@ class ApiKeysFormat(StrEnum): csv = "csv" +class ApiStatus(StrEnum): + UPDATING = "UPDATING" + AVAILABLE = "AVAILABLE" + PENDING = "PENDING" + FAILED = "FAILED" + + class AuthorizerType(StrEnum): TOKEN = "TOKEN" REQUEST = "REQUEST" @@ -84,6 +92,12 @@ class DomainNameStatus(StrEnum): PENDING = "PENDING" PENDING_CERTIFICATE_REIMPORT = "PENDING_CERTIFICATE_REIMPORT" PENDING_OWNERSHIP_VERIFICATION = "PENDING_OWNERSHIP_VERIFICATION" + FAILED = "FAILED" + + +class EndpointAccessMode(StrEnum): + BASIC = "BASIC" + STRICT = "STRICT" class EndpointType(StrEnum): @@ -159,6 +173,11 @@ class ResourceOwner(StrEnum): OTHER_ACCOUNTS = "OTHER_ACCOUNTS" +class ResponseTransferMode(StrEnum): + BUFFERED = "BUFFERED" + STREAM = "STREAM" + + class RoutingMode(StrEnum): BASE_PATH_MAPPING_ONLY = "BASE_PATH_MAPPING_ONLY" ROUTING_RULE_ONLY = "ROUTING_RULE_ONLY" @@ -168,6 +187,15 @@ class RoutingMode(StrEnum): class SecurityPolicy(StrEnum): TLS_1_0 = "TLS_1_0" TLS_1_2 = "TLS_1_2" + SecurityPolicy_TLS13_1_3_2025_09 = "SecurityPolicy_TLS13_1_3_2025_09" + SecurityPolicy_TLS13_1_3_FIPS_2025_09 = "SecurityPolicy_TLS13_1_3_FIPS_2025_09" + SecurityPolicy_TLS13_1_2_PFS_PQ_2025_09 = "SecurityPolicy_TLS13_1_2_PFS_PQ_2025_09" + SecurityPolicy_TLS13_1_2_FIPS_PQ_2025_09 = "SecurityPolicy_TLS13_1_2_FIPS_PQ_2025_09" + SecurityPolicy_TLS13_1_2_PQ_2025_09 = "SecurityPolicy_TLS13_1_2_PQ_2025_09" + SecurityPolicy_TLS13_1_2_2021_06 = "SecurityPolicy_TLS13_1_2_2021_06" + SecurityPolicy_TLS13_2025_EDGE = "SecurityPolicy_TLS13_2025_EDGE" + SecurityPolicy_TLS12_PFS_2025_EDGE = "SecurityPolicy_TLS12_PFS_2025_EDGE" + SecurityPolicy_TLS12_2018_EDGE = "SecurityPolicy_TLS12_2018_EDGE" class UnauthorizedCacheControlHeaderStrategy(StrEnum): @@ -199,7 +227,7 @@ class LimitExceededException(ServiceException): code: str = "LimitExceededException" sender_fault: bool = False status_code: int = 429 - retryAfterSeconds: Optional[String] + retryAfterSeconds: String | None class NotFoundException(ServiceException): @@ -212,14 +240,14 @@ class ServiceUnavailableException(ServiceException): code: str = "ServiceUnavailableException" sender_fault: bool = False status_code: int = 503 - retryAfterSeconds: Optional[String] + retryAfterSeconds: String | None class TooManyRequestsException(ServiceException): code: str = "TooManyRequestsException" sender_fault: bool = False status_code: int = 429 - retryAfterSeconds: Optional[String] + retryAfterSeconds: String | None class UnauthorizedException(ServiceException): @@ -229,194 +257,194 @@ class UnauthorizedException(ServiceException): class AccessLogSettings(TypedDict, total=False): - format: Optional[String] - destinationArn: Optional[String] + format: String | None + destinationArn: String | None -ListOfString = List[String] +ListOfString = list[String] class ThrottleSettings(TypedDict, total=False): - burstLimit: Optional[Integer] - rateLimit: Optional[Double] + burstLimit: Integer | None + rateLimit: Double | None class Account(TypedDict, total=False): - cloudwatchRoleArn: Optional[String] - throttleSettings: Optional[ThrottleSettings] - features: Optional[ListOfString] - apiKeyVersion: Optional[String] + cloudwatchRoleArn: String | None + throttleSettings: ThrottleSettings | None + features: ListOfString | None + apiKeyVersion: String | None -MapOfStringToString = Dict[String, String] +MapOfStringToString = dict[String, String] Timestamp = datetime class ApiKey(TypedDict, total=False): - id: Optional[String] - value: Optional[String] - name: Optional[String] - customerId: Optional[String] - description: Optional[String] - enabled: Optional[Boolean] - createdDate: Optional[Timestamp] - lastUpdatedDate: Optional[Timestamp] - stageKeys: Optional[ListOfString] - tags: Optional[MapOfStringToString] + id: String | None + value: String | None + name: String | None + customerId: String | None + description: String | None + enabled: Boolean | None + createdDate: Timestamp | None + lastUpdatedDate: Timestamp | None + stageKeys: ListOfString | None + tags: MapOfStringToString | None class ApiKeyIds(TypedDict, total=False): - ids: Optional[ListOfString] - warnings: Optional[ListOfString] + ids: ListOfString | None + warnings: ListOfString | None -ListOfApiKey = List[ApiKey] +ListOfApiKey = list[ApiKey] class ApiKeys(TypedDict, total=False): - warnings: Optional[ListOfString] - position: Optional[String] - items: Optional[ListOfApiKey] + warnings: ListOfString | None + position: String | None + items: ListOfApiKey | None -MapOfApiStageThrottleSettings = Dict[String, ThrottleSettings] +MapOfApiStageThrottleSettings = dict[String, ThrottleSettings] class ApiStage(TypedDict, total=False): - apiId: Optional[String] - stage: Optional[String] - throttle: Optional[MapOfApiStageThrottleSettings] + apiId: String | None + stage: String | None + throttle: MapOfApiStageThrottleSettings | None -ListOfARNs = List[ProviderARN] +ListOfARNs = list[ProviderARN] class Authorizer(TypedDict, total=False): - id: Optional[String] - name: Optional[String] - type: Optional[AuthorizerType] - providerARNs: Optional[ListOfARNs] - authType: Optional[String] - authorizerUri: Optional[String] - authorizerCredentials: Optional[String] - identitySource: Optional[String] - identityValidationExpression: Optional[String] - authorizerResultTtlInSeconds: Optional[NullableInteger] + id: String | None + name: String | None + type: AuthorizerType | None + providerARNs: ListOfARNs | None + authType: String | None + authorizerUri: String | None + authorizerCredentials: String | None + identitySource: String | None + identityValidationExpression: String | None + authorizerResultTtlInSeconds: NullableInteger | None -ListOfAuthorizer = List[Authorizer] +ListOfAuthorizer = list[Authorizer] class Authorizers(TypedDict, total=False): - position: Optional[String] - items: Optional[ListOfAuthorizer] + position: String | None + items: ListOfAuthorizer | None class BasePathMapping(TypedDict, total=False): - basePath: Optional[String] - restApiId: Optional[String] - stage: Optional[String] + basePath: String | None + restApiId: String | None + stage: String | None -ListOfBasePathMapping = List[BasePathMapping] +ListOfBasePathMapping = list[BasePathMapping] class BasePathMappings(TypedDict, total=False): - position: Optional[String] - items: Optional[ListOfBasePathMapping] + position: String | None + items: ListOfBasePathMapping | None Blob = bytes class CanarySettings(TypedDict, total=False): - percentTraffic: Optional[Double] - deploymentId: Optional[String] - stageVariableOverrides: Optional[MapOfStringToString] - useStageCache: Optional[Boolean] + percentTraffic: Double | None + deploymentId: String | None + stageVariableOverrides: MapOfStringToString | None + useStageCache: Boolean | None class ClientCertificate(TypedDict, total=False): - clientCertificateId: Optional[String] - description: Optional[String] - pemEncodedCertificate: Optional[String] - createdDate: Optional[Timestamp] - expirationDate: Optional[Timestamp] - tags: Optional[MapOfStringToString] + clientCertificateId: String | None + description: String | None + pemEncodedCertificate: String | None + createdDate: Timestamp | None + expirationDate: Timestamp | None + tags: MapOfStringToString | None -ListOfClientCertificate = List[ClientCertificate] +ListOfClientCertificate = list[ClientCertificate] class ClientCertificates(TypedDict, total=False): - position: Optional[String] - items: Optional[ListOfClientCertificate] + position: String | None + items: ListOfClientCertificate | None class StageKey(TypedDict, total=False): - restApiId: Optional[String] - stageName: Optional[String] + restApiId: String | None + stageName: String | None -ListOfStageKeys = List[StageKey] +ListOfStageKeys = list[StageKey] class CreateApiKeyRequest(ServiceRequest): - name: Optional[String] - description: Optional[String] - enabled: Optional[Boolean] - generateDistinctId: Optional[Boolean] - value: Optional[String] - stageKeys: Optional[ListOfStageKeys] - customerId: Optional[String] - tags: Optional[MapOfStringToString] + name: String | None + description: String | None + enabled: Boolean | None + generateDistinctId: Boolean | None + value: String | None + stageKeys: ListOfStageKeys | None + customerId: String | None + tags: MapOfStringToString | None class CreateAuthorizerRequest(TypedDict, total=False): restApiId: String name: String type: AuthorizerType - providerARNs: Optional[ListOfARNs] - authType: Optional[String] - authorizerUri: Optional[String] - authorizerCredentials: Optional[String] - identitySource: Optional[String] - identityValidationExpression: Optional[String] - authorizerResultTtlInSeconds: Optional[NullableInteger] + providerARNs: ListOfARNs | None + authType: String | None + authorizerUri: String | None + authorizerCredentials: String | None + identitySource: String | None + identityValidationExpression: String | None + authorizerResultTtlInSeconds: NullableInteger | None class CreateBasePathMappingRequest(ServiceRequest): domainName: String - domainNameId: Optional[String] - basePath: Optional[String] + domainNameId: String | None + basePath: String | None restApiId: String - stage: Optional[String] + stage: String | None class DeploymentCanarySettings(TypedDict, total=False): - percentTraffic: Optional[Double] - stageVariableOverrides: Optional[MapOfStringToString] - useStageCache: Optional[Boolean] + percentTraffic: Double | None + stageVariableOverrides: MapOfStringToString | None + useStageCache: Boolean | None class CreateDeploymentRequest(ServiceRequest): restApiId: String - stageName: Optional[String] - stageDescription: Optional[String] - description: Optional[String] - cacheClusterEnabled: Optional[NullableBoolean] - cacheClusterSize: Optional[CacheClusterSize] - variables: Optional[MapOfStringToString] - canarySettings: Optional[DeploymentCanarySettings] - tracingEnabled: Optional[NullableBoolean] + stageName: String | None + stageDescription: String | None + description: String | None + cacheClusterEnabled: NullableBoolean | None + cacheClusterSize: CacheClusterSize | None + variables: MapOfStringToString | None + canarySettings: DeploymentCanarySettings | None + tracingEnabled: NullableBoolean | None class DocumentationPartLocation(TypedDict, total=False): type: DocumentationPartType - path: Optional[String] - method: Optional[String] - statusCode: Optional[DocumentationPartLocationStatusCode] - name: Optional[String] + path: String | None + method: String | None + statusCode: DocumentationPartLocationStatusCode | None + name: String | None class CreateDocumentationPartRequest(ServiceRequest): @@ -428,62 +456,63 @@ class CreateDocumentationPartRequest(ServiceRequest): class CreateDocumentationVersionRequest(ServiceRequest): restApiId: String documentationVersion: String - stageName: Optional[String] - description: Optional[String] + stageName: String | None + description: String | None class CreateDomainNameAccessAssociationRequest(ServiceRequest): domainNameArn: String accessAssociationSourceType: AccessAssociationSourceType accessAssociationSource: String - tags: Optional[MapOfStringToString] + tags: MapOfStringToString | None class MutualTlsAuthenticationInput(TypedDict, total=False): - truststoreUri: Optional[String] - truststoreVersion: Optional[String] + truststoreUri: String | None + truststoreVersion: String | None -ListOfEndpointType = List[EndpointType] +ListOfEndpointType = list[EndpointType] class EndpointConfiguration(TypedDict, total=False): - types: Optional[ListOfEndpointType] - ipAddressType: Optional[IpAddressType] - vpcEndpointIds: Optional[ListOfString] + types: ListOfEndpointType | None + ipAddressType: IpAddressType | None + vpcEndpointIds: ListOfString | None class CreateDomainNameRequest(ServiceRequest): domainName: String - certificateName: Optional[String] - certificateBody: Optional[String] - certificatePrivateKey: Optional[String] - certificateChain: Optional[String] - certificateArn: Optional[String] - regionalCertificateName: Optional[String] - regionalCertificateArn: Optional[String] - endpointConfiguration: Optional[EndpointConfiguration] - tags: Optional[MapOfStringToString] - securityPolicy: Optional[SecurityPolicy] - mutualTlsAuthentication: Optional[MutualTlsAuthenticationInput] - ownershipVerificationCertificateArn: Optional[String] - policy: Optional[String] - routingMode: Optional[RoutingMode] + certificateName: String | None + certificateBody: String | None + certificatePrivateKey: String | None + certificateChain: String | None + certificateArn: String | None + regionalCertificateName: String | None + regionalCertificateArn: String | None + endpointConfiguration: EndpointConfiguration | None + tags: MapOfStringToString | None + securityPolicy: SecurityPolicy | None + endpointAccessMode: EndpointAccessMode | None + mutualTlsAuthentication: MutualTlsAuthenticationInput | None + ownershipVerificationCertificateArn: String | None + policy: String | None + routingMode: RoutingMode | None class CreateModelRequest(ServiceRequest): restApiId: String name: String - description: Optional[String] - schema: Optional[String] + description: String | None + schema: String | None contentType: String class CreateRequestValidatorRequest(ServiceRequest): restApiId: String - name: Optional[String] - validateRequestBody: Optional[Boolean] - validateRequestParameters: Optional[Boolean] + name: String | None + validateRequestBody: Boolean | None + validateRequestParameters: Boolean | None class CreateResourceRequest(ServiceRequest): @@ -494,30 +523,32 @@ class CreateResourceRequest(ServiceRequest): class CreateRestApiRequest(ServiceRequest): name: String - description: Optional[String] - version: Optional[String] - cloneFrom: Optional[String] - binaryMediaTypes: Optional[ListOfString] - minimumCompressionSize: Optional[NullableInteger] - apiKeySource: Optional[ApiKeySourceType] - endpointConfiguration: Optional[EndpointConfiguration] - policy: Optional[String] - tags: Optional[MapOfStringToString] - disableExecuteApiEndpoint: Optional[Boolean] + description: String | None + version: String | None + cloneFrom: String | None + binaryMediaTypes: ListOfString | None + minimumCompressionSize: NullableInteger | None + apiKeySource: ApiKeySourceType | None + endpointConfiguration: EndpointConfiguration | None + policy: String | None + tags: MapOfStringToString | None + disableExecuteApiEndpoint: Boolean | None + securityPolicy: SecurityPolicy | None + endpointAccessMode: EndpointAccessMode | None class CreateStageRequest(ServiceRequest): restApiId: String stageName: String deploymentId: String - description: Optional[String] - cacheClusterEnabled: Optional[Boolean] - cacheClusterSize: Optional[CacheClusterSize] - variables: Optional[MapOfStringToString] - documentationVersion: Optional[String] - canarySettings: Optional[CanarySettings] - tracingEnabled: Optional[Boolean] - tags: Optional[MapOfStringToString] + description: String | None + cacheClusterEnabled: Boolean | None + cacheClusterSize: CacheClusterSize | None + variables: MapOfStringToString | None + documentationVersion: String | None + canarySettings: CanarySettings | None + tracingEnabled: Boolean | None + tags: MapOfStringToString | None class CreateUsagePlanKeyRequest(ServiceRequest): @@ -527,28 +558,28 @@ class CreateUsagePlanKeyRequest(ServiceRequest): class QuotaSettings(TypedDict, total=False): - limit: Optional[Integer] - offset: Optional[Integer] - period: Optional[QuotaPeriodType] + limit: Integer | None + offset: Integer | None + period: QuotaPeriodType | None -ListOfApiStage = List[ApiStage] +ListOfApiStage = list[ApiStage] class CreateUsagePlanRequest(ServiceRequest): name: String - description: Optional[String] - apiStages: Optional[ListOfApiStage] - throttle: Optional[ThrottleSettings] - quota: Optional[QuotaSettings] - tags: Optional[MapOfStringToString] + description: String | None + apiStages: ListOfApiStage | None + throttle: ThrottleSettings | None + quota: QuotaSettings | None + tags: MapOfStringToString | None class CreateVpcLinkRequest(ServiceRequest): name: String - description: Optional[String] + description: String | None targetArns: ListOfString - tags: Optional[MapOfStringToString] + tags: MapOfStringToString | None class DeleteApiKeyRequest(ServiceRequest): @@ -562,7 +593,7 @@ class DeleteAuthorizerRequest(ServiceRequest): class DeleteBasePathMappingRequest(ServiceRequest): domainName: String - domainNameId: Optional[String] + domainNameId: String | None basePath: String @@ -591,7 +622,7 @@ class DeleteDomainNameAccessAssociationRequest(ServiceRequest): class DeleteDomainNameRequest(ServiceRequest): domainName: String - domainNameId: Optional[String] + domainNameId: String | None class DeleteGatewayResponseRequest(ServiceRequest): @@ -663,121 +694,122 @@ class DeleteVpcLinkRequest(ServiceRequest): class MethodSnapshot(TypedDict, total=False): - authorizationType: Optional[String] - apiKeyRequired: Optional[Boolean] + authorizationType: String | None + apiKeyRequired: Boolean | None -MapOfMethodSnapshot = Dict[String, MethodSnapshot] -PathToMapOfMethodSnapshot = Dict[String, MapOfMethodSnapshot] +MapOfMethodSnapshot = dict[String, MethodSnapshot] +PathToMapOfMethodSnapshot = dict[String, MapOfMethodSnapshot] class Deployment(TypedDict, total=False): - id: Optional[String] - description: Optional[String] - createdDate: Optional[Timestamp] - apiSummary: Optional[PathToMapOfMethodSnapshot] + id: String | None + description: String | None + createdDate: Timestamp | None + apiSummary: PathToMapOfMethodSnapshot | None -ListOfDeployment = List[Deployment] +ListOfDeployment = list[Deployment] class Deployments(TypedDict, total=False): - position: Optional[String] - items: Optional[ListOfDeployment] + position: String | None + items: ListOfDeployment | None class DocumentationPart(TypedDict, total=False): - id: Optional[String] - location: Optional[DocumentationPartLocation] - properties: Optional[String] + id: String | None + location: DocumentationPartLocation | None + properties: String | None class DocumentationPartIds(TypedDict, total=False): - ids: Optional[ListOfString] - warnings: Optional[ListOfString] + ids: ListOfString | None + warnings: ListOfString | None -ListOfDocumentationPart = List[DocumentationPart] +ListOfDocumentationPart = list[DocumentationPart] class DocumentationParts(TypedDict, total=False): - position: Optional[String] - items: Optional[ListOfDocumentationPart] + position: String | None + items: ListOfDocumentationPart | None class DocumentationVersion(TypedDict, total=False): - version: Optional[String] - createdDate: Optional[Timestamp] - description: Optional[String] + version: String | None + createdDate: Timestamp | None + description: String | None -ListOfDocumentationVersion = List[DocumentationVersion] +ListOfDocumentationVersion = list[DocumentationVersion] class DocumentationVersions(TypedDict, total=False): - position: Optional[String] - items: Optional[ListOfDocumentationVersion] + position: String | None + items: ListOfDocumentationVersion | None class MutualTlsAuthentication(TypedDict, total=False): - truststoreUri: Optional[String] - truststoreVersion: Optional[String] - truststoreWarnings: Optional[ListOfString] + truststoreUri: String | None + truststoreVersion: String | None + truststoreWarnings: ListOfString | None class DomainName(TypedDict, total=False): - domainName: Optional[String] - domainNameId: Optional[String] - domainNameArn: Optional[String] - certificateName: Optional[String] - certificateArn: Optional[String] - certificateUploadDate: Optional[Timestamp] - regionalDomainName: Optional[String] - regionalHostedZoneId: Optional[String] - regionalCertificateName: Optional[String] - regionalCertificateArn: Optional[String] - distributionDomainName: Optional[String] - distributionHostedZoneId: Optional[String] - endpointConfiguration: Optional[EndpointConfiguration] - domainNameStatus: Optional[DomainNameStatus] - domainNameStatusMessage: Optional[String] - securityPolicy: Optional[SecurityPolicy] - tags: Optional[MapOfStringToString] - mutualTlsAuthentication: Optional[MutualTlsAuthentication] - ownershipVerificationCertificateArn: Optional[String] - managementPolicy: Optional[String] - policy: Optional[String] - routingMode: Optional[RoutingMode] + domainName: String | None + domainNameId: String | None + domainNameArn: String | None + certificateName: String | None + certificateArn: String | None + certificateUploadDate: Timestamp | None + regionalDomainName: String | None + regionalHostedZoneId: String | None + regionalCertificateName: String | None + regionalCertificateArn: String | None + distributionDomainName: String | None + distributionHostedZoneId: String | None + endpointConfiguration: EndpointConfiguration | None + domainNameStatus: DomainNameStatus | None + domainNameStatusMessage: String | None + securityPolicy: SecurityPolicy | None + endpointAccessMode: EndpointAccessMode | None + tags: MapOfStringToString | None + mutualTlsAuthentication: MutualTlsAuthentication | None + ownershipVerificationCertificateArn: String | None + managementPolicy: String | None + policy: String | None + routingMode: RoutingMode | None class DomainNameAccessAssociation(TypedDict, total=False): - domainNameAccessAssociationArn: Optional[String] - domainNameArn: Optional[String] - accessAssociationSourceType: Optional[AccessAssociationSourceType] - accessAssociationSource: Optional[String] - tags: Optional[MapOfStringToString] + domainNameAccessAssociationArn: String | None + domainNameArn: String | None + accessAssociationSourceType: AccessAssociationSourceType | None + accessAssociationSource: String | None + tags: MapOfStringToString | None -ListOfDomainNameAccessAssociation = List[DomainNameAccessAssociation] +ListOfDomainNameAccessAssociation = list[DomainNameAccessAssociation] class DomainNameAccessAssociations(TypedDict, total=False): - position: Optional[String] - items: Optional[ListOfDomainNameAccessAssociation] + position: String | None + items: ListOfDomainNameAccessAssociation | None -ListOfDomainName = List[DomainName] +ListOfDomainName = list[DomainName] class DomainNames(TypedDict, total=False): - position: Optional[String] - items: Optional[ListOfDomainName] + position: String | None + items: ListOfDomainName | None class ExportResponse(TypedDict, total=False): - body: Optional[Union[Blob, IO[Blob], Iterable[Blob]]] - contentType: Optional[String] - contentDisposition: Optional[String] + body: Blob | IO[Blob] | Iterable[Blob] | None + contentType: String | None + contentDisposition: String | None class FlushStageAuthorizersCacheRequest(ServiceRequest): @@ -791,24 +823,24 @@ class FlushStageCacheRequest(ServiceRequest): class GatewayResponse(TypedDict, total=False): - responseType: Optional[GatewayResponseType] - statusCode: Optional[StatusCode] - responseParameters: Optional[MapOfStringToString] - responseTemplates: Optional[MapOfStringToString] - defaultResponse: Optional[Boolean] + responseType: GatewayResponseType | None + statusCode: StatusCode | None + responseParameters: MapOfStringToString | None + responseTemplates: MapOfStringToString | None + defaultResponse: Boolean | None -ListOfGatewayResponse = List[GatewayResponse] +ListOfGatewayResponse = list[GatewayResponse] class GatewayResponses(TypedDict, total=False): - position: Optional[String] - items: Optional[ListOfGatewayResponse] + position: String | None + items: ListOfGatewayResponse | None class GenerateClientCertificateRequest(ServiceRequest): - description: Optional[String] - tags: Optional[MapOfStringToString] + description: String | None + tags: MapOfStringToString | None class GetAccountRequest(ServiceRequest): @@ -817,15 +849,15 @@ class GetAccountRequest(ServiceRequest): class GetApiKeyRequest(ServiceRequest): apiKey: String - includeValue: Optional[NullableBoolean] + includeValue: NullableBoolean | None class GetApiKeysRequest(ServiceRequest): - position: Optional[String] - limit: Optional[NullableInteger] - nameQuery: Optional[String] - customerId: Optional[String] - includeValues: Optional[NullableBoolean] + position: String | None + limit: NullableInteger | None + nameQuery: String | None + customerId: String | None + includeValues: NullableBoolean | None class GetAuthorizerRequest(ServiceRequest): @@ -835,21 +867,21 @@ class GetAuthorizerRequest(ServiceRequest): class GetAuthorizersRequest(ServiceRequest): restApiId: String - position: Optional[String] - limit: Optional[NullableInteger] + position: String | None + limit: NullableInteger | None class GetBasePathMappingRequest(ServiceRequest): domainName: String - domainNameId: Optional[String] + domainNameId: String | None basePath: String class GetBasePathMappingsRequest(ServiceRequest): domainName: String - domainNameId: Optional[String] - position: Optional[String] - limit: Optional[NullableInteger] + domainNameId: String | None + position: String | None + limit: NullableInteger | None class GetClientCertificateRequest(ServiceRequest): @@ -857,20 +889,20 @@ class GetClientCertificateRequest(ServiceRequest): class GetClientCertificatesRequest(ServiceRequest): - position: Optional[String] - limit: Optional[NullableInteger] + position: String | None + limit: NullableInteger | None class GetDeploymentRequest(ServiceRequest): restApiId: String deploymentId: String - embed: Optional[ListOfString] + embed: ListOfString | None class GetDeploymentsRequest(ServiceRequest): restApiId: String - position: Optional[String] - limit: Optional[NullableInteger] + position: String | None + limit: NullableInteger | None class GetDocumentationPartRequest(ServiceRequest): @@ -880,12 +912,12 @@ class GetDocumentationPartRequest(ServiceRequest): class GetDocumentationPartsRequest(TypedDict, total=False): restApiId: String - type: Optional[DocumentationPartType] - nameQuery: Optional[String] - path: Optional[String] - position: Optional[String] - limit: Optional[NullableInteger] - locationStatus: Optional[LocationStatusType] + type: DocumentationPartType | None + nameQuery: String | None + path: String | None + position: String | None + limit: NullableInteger | None + locationStatus: LocationStatusType | None class GetDocumentationVersionRequest(ServiceRequest): @@ -895,33 +927,33 @@ class GetDocumentationVersionRequest(ServiceRequest): class GetDocumentationVersionsRequest(ServiceRequest): restApiId: String - position: Optional[String] - limit: Optional[NullableInteger] + position: String | None + limit: NullableInteger | None class GetDomainNameAccessAssociationsRequest(ServiceRequest): - position: Optional[String] - limit: Optional[NullableInteger] - resourceOwner: Optional[ResourceOwner] + position: String | None + limit: NullableInteger | None + resourceOwner: ResourceOwner | None class GetDomainNameRequest(ServiceRequest): domainName: String - domainNameId: Optional[String] + domainNameId: String | None class GetDomainNamesRequest(ServiceRequest): - position: Optional[String] - limit: Optional[NullableInteger] - resourceOwner: Optional[ResourceOwner] + position: String | None + limit: NullableInteger | None + resourceOwner: ResourceOwner | None class GetExportRequest(ServiceRequest): restApiId: String stageName: String exportType: String - parameters: Optional[MapOfStringToString] - accepts: Optional[String] + parameters: MapOfStringToString | None + accepts: String | None class GetGatewayResponseRequest(ServiceRequest): @@ -931,8 +963,8 @@ class GetGatewayResponseRequest(ServiceRequest): class GetGatewayResponsesRequest(ServiceRequest): restApiId: String - position: Optional[String] - limit: Optional[NullableInteger] + position: String | None + limit: NullableInteger | None class GetIntegrationRequest(ServiceRequest): @@ -964,7 +996,7 @@ class GetMethodResponseRequest(ServiceRequest): class GetModelRequest(ServiceRequest): restApiId: String modelName: String - flatten: Optional[Boolean] + flatten: Boolean | None class GetModelTemplateRequest(ServiceRequest): @@ -974,8 +1006,8 @@ class GetModelTemplateRequest(ServiceRequest): class GetModelsRequest(ServiceRequest): restApiId: String - position: Optional[String] - limit: Optional[NullableInteger] + position: String | None + limit: NullableInteger | None class GetRequestValidatorRequest(ServiceRequest): @@ -985,21 +1017,21 @@ class GetRequestValidatorRequest(ServiceRequest): class GetRequestValidatorsRequest(ServiceRequest): restApiId: String - position: Optional[String] - limit: Optional[NullableInteger] + position: String | None + limit: NullableInteger | None class GetResourceRequest(ServiceRequest): restApiId: String resourceId: String - embed: Optional[ListOfString] + embed: ListOfString | None class GetResourcesRequest(ServiceRequest): restApiId: String - position: Optional[String] - limit: Optional[NullableInteger] - embed: Optional[ListOfString] + position: String | None + limit: NullableInteger | None + embed: ListOfString | None class GetRestApiRequest(ServiceRequest): @@ -1007,15 +1039,15 @@ class GetRestApiRequest(ServiceRequest): class GetRestApisRequest(ServiceRequest): - position: Optional[String] - limit: Optional[NullableInteger] + position: String | None + limit: NullableInteger | None class GetSdkRequest(ServiceRequest): restApiId: String stageName: String sdkType: String - parameters: Optional[MapOfStringToString] + parameters: MapOfStringToString | None class GetSdkTypeRequest(ServiceRequest): @@ -1023,8 +1055,8 @@ class GetSdkTypeRequest(ServiceRequest): class GetSdkTypesRequest(ServiceRequest): - position: Optional[String] - limit: Optional[NullableInteger] + position: String | None + limit: NullableInteger | None class GetStageRequest(ServiceRequest): @@ -1034,13 +1066,13 @@ class GetStageRequest(ServiceRequest): class GetStagesRequest(ServiceRequest): restApiId: String - deploymentId: Optional[String] + deploymentId: String | None class GetTagsRequest(ServiceRequest): resourceArn: String - position: Optional[String] - limit: Optional[NullableInteger] + position: String | None + limit: NullableInteger | None class GetUsagePlanKeyRequest(ServiceRequest): @@ -1050,9 +1082,9 @@ class GetUsagePlanKeyRequest(ServiceRequest): class GetUsagePlanKeysRequest(ServiceRequest): usagePlanId: String - position: Optional[String] - limit: Optional[NullableInteger] - nameQuery: Optional[String] + position: String | None + limit: NullableInteger | None + nameQuery: String | None class GetUsagePlanRequest(ServiceRequest): @@ -1060,18 +1092,18 @@ class GetUsagePlanRequest(ServiceRequest): class GetUsagePlansRequest(ServiceRequest): - position: Optional[String] - keyId: Optional[String] - limit: Optional[NullableInteger] + position: String | None + keyId: String | None + limit: NullableInteger | None class GetUsageRequest(ServiceRequest): usagePlanId: String - keyId: Optional[String] + keyId: String | None startDate: String endDate: String - position: Optional[String] - limit: Optional[NullableInteger] + position: String | None + limit: NullableInteger | None class GetVpcLinkRequest(ServiceRequest): @@ -1079,267 +1111,276 @@ class GetVpcLinkRequest(ServiceRequest): class GetVpcLinksRequest(ServiceRequest): - position: Optional[String] - limit: Optional[NullableInteger] + position: String | None + limit: NullableInteger | None class ImportApiKeysRequest(ServiceRequest): body: IO[Blob] format: ApiKeysFormat - failOnWarnings: Optional[Boolean] + failOnWarnings: Boolean | None class ImportDocumentationPartsRequest(ServiceRequest): body: IO[Blob] restApiId: String - mode: Optional[PutMode] - failOnWarnings: Optional[Boolean] + mode: PutMode | None + failOnWarnings: Boolean | None class ImportRestApiRequest(ServiceRequest): body: IO[Blob] - failOnWarnings: Optional[Boolean] - parameters: Optional[MapOfStringToString] + failOnWarnings: Boolean | None + parameters: MapOfStringToString | None class TlsConfig(TypedDict, total=False): - insecureSkipVerification: Optional[Boolean] + insecureSkipVerification: Boolean | None + + +MapOfStringToNullableString = dict[String, String | None] class IntegrationResponse(TypedDict, total=False): - statusCode: Optional[StatusCode] - selectionPattern: Optional[String] - responseParameters: Optional[MapOfStringToString] - responseTemplates: Optional[MapOfStringToString] - contentHandling: Optional[ContentHandlingStrategy] + statusCode: StatusCode | None + selectionPattern: String | None + responseParameters: MapOfStringToString | None + responseTemplates: MapOfStringToNullableString | None + contentHandling: ContentHandlingStrategy | None -MapOfIntegrationResponse = Dict[String, IntegrationResponse] +MapOfIntegrationResponse = dict[String, IntegrationResponse] class Integration(TypedDict, total=False): - type: Optional[IntegrationType] - httpMethod: Optional[String] - uri: Optional[String] - connectionType: Optional[ConnectionType] - connectionId: Optional[String] - credentials: Optional[String] - requestParameters: Optional[MapOfStringToString] - requestTemplates: Optional[MapOfStringToString] - passthroughBehavior: Optional[String] - contentHandling: Optional[ContentHandlingStrategy] - timeoutInMillis: Optional[Integer] - cacheNamespace: Optional[String] - cacheKeyParameters: Optional[ListOfString] - integrationResponses: Optional[MapOfIntegrationResponse] - tlsConfig: Optional[TlsConfig] + type: IntegrationType | None + httpMethod: String | None + uri: String | None + connectionType: ConnectionType | None + connectionId: String | None + credentials: String | None + requestParameters: MapOfStringToString | None + requestTemplates: MapOfStringToString | None + passthroughBehavior: String | None + contentHandling: ContentHandlingStrategy | None + timeoutInMillis: Integer | None + cacheNamespace: String | None + cacheKeyParameters: ListOfString | None + integrationResponses: MapOfIntegrationResponse | None + tlsConfig: TlsConfig | None + responseTransferMode: ResponseTransferMode | None + integrationTarget: String | None Long = int -ListOfLong = List[Long] +ListOfLong = list[Long] class Model(TypedDict, total=False): - id: Optional[String] - name: Optional[String] - description: Optional[String] - schema: Optional[String] - contentType: Optional[String] + id: String | None + name: String | None + description: String | None + schema: String | None + contentType: String | None -ListOfModel = List[Model] +ListOfModel = list[Model] PatchOperation = TypedDict( "PatchOperation", { - "op": Optional[Op], - "path": Optional[String], - "value": Optional[String], - "from": Optional[String], + "op": Op | None, + "path": String | None, + "value": String | None, + "from": String | None, }, total=False, ) -ListOfPatchOperation = List[PatchOperation] +ListOfPatchOperation = list[PatchOperation] class RequestValidator(TypedDict, total=False): - id: Optional[String] - name: Optional[String] - validateRequestBody: Optional[Boolean] - validateRequestParameters: Optional[Boolean] + id: String | None + name: String | None + validateRequestBody: Boolean | None + validateRequestParameters: Boolean | None -ListOfRequestValidator = List[RequestValidator] -MapOfStringToBoolean = Dict[String, NullableBoolean] +ListOfRequestValidator = list[RequestValidator] +MapOfStringToBoolean = dict[String, NullableBoolean] class MethodResponse(TypedDict, total=False): - statusCode: Optional[StatusCode] - responseParameters: Optional[MapOfStringToBoolean] - responseModels: Optional[MapOfStringToString] + statusCode: StatusCode | None + responseParameters: MapOfStringToBoolean | None + responseModels: MapOfStringToString | None -MapOfMethodResponse = Dict[String, MethodResponse] +MapOfMethodResponse = dict[String, MethodResponse] class Method(TypedDict, total=False): - httpMethod: Optional[String] - authorizationType: Optional[String] - authorizerId: Optional[String] - apiKeyRequired: Optional[NullableBoolean] - requestValidatorId: Optional[String] - operationName: Optional[String] - requestParameters: Optional[MapOfStringToBoolean] - requestModels: Optional[MapOfStringToString] - methodResponses: Optional[MapOfMethodResponse] - methodIntegration: Optional[Integration] - authorizationScopes: Optional[ListOfString] + httpMethod: String | None + authorizationType: String | None + authorizerId: String | None + apiKeyRequired: NullableBoolean | None + requestValidatorId: String | None + operationName: String | None + requestParameters: MapOfStringToBoolean | None + requestModels: MapOfStringToString | None + methodResponses: MapOfMethodResponse | None + methodIntegration: Integration | None + authorizationScopes: ListOfString | None -MapOfMethod = Dict[String, Method] +MapOfMethod = dict[String, Method] class Resource(TypedDict, total=False): - id: Optional[String] - parentId: Optional[String] - pathPart: Optional[String] - path: Optional[String] - resourceMethods: Optional[MapOfMethod] + id: String | None + parentId: String | None + pathPart: String | None + path: String | None + resourceMethods: MapOfMethod | None -ListOfResource = List[Resource] +ListOfResource = list[Resource] class RestApi(TypedDict, total=False): - id: Optional[String] - name: Optional[String] - description: Optional[String] - createdDate: Optional[Timestamp] - version: Optional[String] - warnings: Optional[ListOfString] - binaryMediaTypes: Optional[ListOfString] - minimumCompressionSize: Optional[NullableInteger] - apiKeySource: Optional[ApiKeySourceType] - endpointConfiguration: Optional[EndpointConfiguration] - policy: Optional[String] - tags: Optional[MapOfStringToString] - disableExecuteApiEndpoint: Optional[Boolean] - rootResourceId: Optional[String] - - -ListOfRestApi = List[RestApi] + id: String | None + name: String | None + description: String | None + createdDate: Timestamp | None + version: String | None + warnings: ListOfString | None + binaryMediaTypes: ListOfString | None + minimumCompressionSize: NullableInteger | None + apiKeySource: ApiKeySourceType | None + endpointConfiguration: EndpointConfiguration | None + policy: String | None + tags: MapOfStringToString | None + disableExecuteApiEndpoint: Boolean | None + rootResourceId: String | None + securityPolicy: SecurityPolicy | None + endpointAccessMode: EndpointAccessMode | None + apiStatus: ApiStatus | None + apiStatusMessage: String | None + + +ListOfRestApi = list[RestApi] class SdkConfigurationProperty(TypedDict, total=False): - name: Optional[String] - friendlyName: Optional[String] - description: Optional[String] - required: Optional[Boolean] - defaultValue: Optional[String] + name: String | None + friendlyName: String | None + description: String | None + required: Boolean | None + defaultValue: String | None -ListOfSdkConfigurationProperty = List[SdkConfigurationProperty] +ListOfSdkConfigurationProperty = list[SdkConfigurationProperty] class SdkType(TypedDict, total=False): - id: Optional[String] - friendlyName: Optional[String] - description: Optional[String] - configurationProperties: Optional[ListOfSdkConfigurationProperty] + id: String | None + friendlyName: String | None + description: String | None + configurationProperties: ListOfSdkConfigurationProperty | None -ListOfSdkType = List[SdkType] +ListOfSdkType = list[SdkType] class MethodSetting(TypedDict, total=False): - metricsEnabled: Optional[Boolean] - loggingLevel: Optional[String] - dataTraceEnabled: Optional[Boolean] - throttlingBurstLimit: Optional[Integer] - throttlingRateLimit: Optional[Double] - cachingEnabled: Optional[Boolean] - cacheTtlInSeconds: Optional[Integer] - cacheDataEncrypted: Optional[Boolean] - requireAuthorizationForCacheControl: Optional[Boolean] - unauthorizedCacheControlHeaderStrategy: Optional[UnauthorizedCacheControlHeaderStrategy] + metricsEnabled: Boolean | None + loggingLevel: String | None + dataTraceEnabled: Boolean | None + throttlingBurstLimit: Integer | None + throttlingRateLimit: Double | None + cachingEnabled: Boolean | None + cacheTtlInSeconds: Integer | None + cacheDataEncrypted: Boolean | None + requireAuthorizationForCacheControl: Boolean | None + unauthorizedCacheControlHeaderStrategy: UnauthorizedCacheControlHeaderStrategy | None -MapOfMethodSettings = Dict[String, MethodSetting] +MapOfMethodSettings = dict[String, MethodSetting] class Stage(TypedDict, total=False): - deploymentId: Optional[String] - clientCertificateId: Optional[String] - stageName: Optional[String] - description: Optional[String] - cacheClusterEnabled: Optional[Boolean] - cacheClusterSize: Optional[CacheClusterSize] - cacheClusterStatus: Optional[CacheClusterStatus] - methodSettings: Optional[MapOfMethodSettings] - variables: Optional[MapOfStringToString] - documentationVersion: Optional[String] - accessLogSettings: Optional[AccessLogSettings] - canarySettings: Optional[CanarySettings] - tracingEnabled: Optional[Boolean] - webAclArn: Optional[String] - tags: Optional[MapOfStringToString] - createdDate: Optional[Timestamp] - lastUpdatedDate: Optional[Timestamp] - - -ListOfStage = List[Stage] -ListOfUsage = List[ListOfLong] + deploymentId: String | None + clientCertificateId: String | None + stageName: String | None + description: String | None + cacheClusterEnabled: Boolean | None + cacheClusterSize: CacheClusterSize | None + cacheClusterStatus: CacheClusterStatus | None + methodSettings: MapOfMethodSettings | None + variables: MapOfStringToString | None + documentationVersion: String | None + accessLogSettings: AccessLogSettings | None + canarySettings: CanarySettings | None + tracingEnabled: Boolean | None + webAclArn: String | None + tags: MapOfStringToString | None + createdDate: Timestamp | None + lastUpdatedDate: Timestamp | None + + +ListOfStage = list[Stage] +ListOfUsage = list[ListOfLong] class UsagePlan(TypedDict, total=False): - id: Optional[String] - name: Optional[String] - description: Optional[String] - apiStages: Optional[ListOfApiStage] - throttle: Optional[ThrottleSettings] - quota: Optional[QuotaSettings] - productCode: Optional[String] - tags: Optional[MapOfStringToString] + id: String | None + name: String | None + description: String | None + apiStages: ListOfApiStage | None + throttle: ThrottleSettings | None + quota: QuotaSettings | None + productCode: String | None + tags: MapOfStringToString | None -ListOfUsagePlan = List[UsagePlan] +ListOfUsagePlan = list[UsagePlan] class UsagePlanKey(TypedDict, total=False): - id: Optional[String] - type: Optional[String] - value: Optional[String] - name: Optional[String] + id: String | None + type: String | None + value: String | None + name: String | None -ListOfUsagePlanKey = List[UsagePlanKey] +ListOfUsagePlanKey = list[UsagePlanKey] class VpcLink(TypedDict, total=False): - id: Optional[String] - name: Optional[String] - description: Optional[String] - targetArns: Optional[ListOfString] - status: Optional[VpcLinkStatus] - statusMessage: Optional[String] - tags: Optional[MapOfStringToString] + id: String | None + name: String | None + description: String | None + targetArns: ListOfString | None + status: VpcLinkStatus | None + statusMessage: String | None + tags: MapOfStringToString | None -ListOfVpcLink = List[VpcLink] -MapOfKeyUsages = Dict[String, ListOfUsage] -MapOfStringToList = Dict[String, ListOfString] +ListOfVpcLink = list[VpcLink] +MapOfKeyUsages = dict[String, ListOfUsage] +MapOfStringToList = dict[String, ListOfString] class Models(TypedDict, total=False): - position: Optional[String] - items: Optional[ListOfModel] + position: String | None + items: ListOfModel | None class PutGatewayResponseRequest(ServiceRequest): restApiId: String responseType: GatewayResponseType - statusCode: Optional[StatusCode] - responseParameters: Optional[MapOfStringToString] - responseTemplates: Optional[MapOfStringToString] + statusCode: StatusCode | None + responseParameters: MapOfStringToString | None + responseTemplates: MapOfStringToString | None class PutIntegrationRequest(TypedDict, total=False): @@ -1347,19 +1388,21 @@ class PutIntegrationRequest(TypedDict, total=False): resourceId: String httpMethod: String type: IntegrationType - integrationHttpMethod: Optional[String] - uri: Optional[String] - connectionType: Optional[ConnectionType] - connectionId: Optional[String] - credentials: Optional[String] - requestParameters: Optional[MapOfStringToString] - requestTemplates: Optional[MapOfStringToString] - passthroughBehavior: Optional[String] - cacheNamespace: Optional[String] - cacheKeyParameters: Optional[ListOfString] - contentHandling: Optional[ContentHandlingStrategy] - timeoutInMillis: Optional[NullableInteger] - tlsConfig: Optional[TlsConfig] + integrationHttpMethod: String | None + uri: String | None + connectionType: ConnectionType | None + connectionId: String | None + credentials: String | None + requestParameters: MapOfStringToString | None + requestTemplates: MapOfStringToString | None + passthroughBehavior: String | None + cacheNamespace: String | None + cacheKeyParameters: ListOfString | None + contentHandling: ContentHandlingStrategy | None + timeoutInMillis: NullableInteger | None + tlsConfig: TlsConfig | None + responseTransferMode: ResponseTransferMode | None + integrationTarget: String | None class PutIntegrationResponseRequest(ServiceRequest): @@ -1367,10 +1410,10 @@ class PutIntegrationResponseRequest(ServiceRequest): resourceId: String httpMethod: String statusCode: StatusCode - selectionPattern: Optional[String] - responseParameters: Optional[MapOfStringToString] - responseTemplates: Optional[MapOfStringToString] - contentHandling: Optional[ContentHandlingStrategy] + selectionPattern: String | None + responseParameters: MapOfStringToString | None + responseTemplates: MapOfStringToString | None + contentHandling: ContentHandlingStrategy | None class PutMethodRequest(ServiceRequest): @@ -1378,13 +1421,13 @@ class PutMethodRequest(ServiceRequest): resourceId: String httpMethod: String authorizationType: String - authorizerId: Optional[String] - apiKeyRequired: Optional[Boolean] - operationName: Optional[String] - requestParameters: Optional[MapOfStringToBoolean] - requestModels: Optional[MapOfStringToString] - requestValidatorId: Optional[String] - authorizationScopes: Optional[ListOfString] + authorizerId: String | None + apiKeyRequired: Boolean | None + operationName: String | None + requestParameters: MapOfStringToBoolean | None + requestModels: MapOfStringToString | None + requestValidatorId: String | None + authorizationScopes: ListOfString | None class PutMethodResponseRequest(ServiceRequest): @@ -1392,16 +1435,16 @@ class PutMethodResponseRequest(ServiceRequest): resourceId: String httpMethod: String statusCode: StatusCode - responseParameters: Optional[MapOfStringToBoolean] - responseModels: Optional[MapOfStringToString] + responseParameters: MapOfStringToBoolean | None + responseModels: MapOfStringToString | None class PutRestApiRequest(ServiceRequest): body: IO[Blob] restApiId: String - mode: Optional[PutMode] - failOnWarnings: Optional[Boolean] - parameters: Optional[MapOfStringToString] + mode: PutMode | None + failOnWarnings: Boolean | None + parameters: MapOfStringToString | None class RejectDomainNameAccessAssociationRequest(ServiceRequest): @@ -1410,33 +1453,33 @@ class RejectDomainNameAccessAssociationRequest(ServiceRequest): class RequestValidators(TypedDict, total=False): - position: Optional[String] - items: Optional[ListOfRequestValidator] + position: String | None + items: ListOfRequestValidator | None class Resources(TypedDict, total=False): - position: Optional[String] - items: Optional[ListOfResource] + position: String | None + items: ListOfResource | None class RestApis(TypedDict, total=False): - position: Optional[String] - items: Optional[ListOfRestApi] + position: String | None + items: ListOfRestApi | None class SdkResponse(TypedDict, total=False): - body: Optional[Union[Blob, IO[Blob], Iterable[Blob]]] - contentType: Optional[String] - contentDisposition: Optional[String] + body: Blob | IO[Blob] | Iterable[Blob] | None + contentType: String | None + contentDisposition: String | None class SdkTypes(TypedDict, total=False): - position: Optional[String] - items: Optional[ListOfSdkType] + position: String | None + items: ListOfSdkType | None class Stages(TypedDict, total=False): - item: Optional[ListOfStage] + item: ListOfStage | None class TagResourceRequest(ServiceRequest): @@ -1445,53 +1488,53 @@ class TagResourceRequest(ServiceRequest): class Tags(TypedDict, total=False): - tags: Optional[MapOfStringToString] + tags: MapOfStringToString | None class Template(TypedDict, total=False): - value: Optional[String] + value: String | None class TestInvokeAuthorizerRequest(ServiceRequest): restApiId: String authorizerId: String - headers: Optional[MapOfStringToString] - multiValueHeaders: Optional[MapOfStringToList] - pathWithQueryString: Optional[String] - body: Optional[String] - stageVariables: Optional[MapOfStringToString] - additionalContext: Optional[MapOfStringToString] + headers: MapOfStringToString | None + multiValueHeaders: MapOfStringToList | None + pathWithQueryString: String | None + body: String | None + stageVariables: MapOfStringToString | None + additionalContext: MapOfStringToString | None class TestInvokeAuthorizerResponse(TypedDict, total=False): - clientStatus: Optional[Integer] - log: Optional[String] - latency: Optional[Long] - principalId: Optional[String] - policy: Optional[String] - authorization: Optional[MapOfStringToList] - claims: Optional[MapOfStringToString] + clientStatus: Integer | None + log: String | None + latency: Long | None + principalId: String | None + policy: String | None + authorization: MapOfStringToList | None + claims: MapOfStringToString | None class TestInvokeMethodRequest(ServiceRequest): restApiId: String resourceId: String httpMethod: String - pathWithQueryString: Optional[String] - body: Optional[String] - headers: Optional[MapOfStringToString] - multiValueHeaders: Optional[MapOfStringToList] - clientCertificateId: Optional[String] - stageVariables: Optional[MapOfStringToString] + pathWithQueryString: String | None + body: String | None + headers: MapOfStringToString | None + multiValueHeaders: MapOfStringToList | None + clientCertificateId: String | None + stageVariables: MapOfStringToString | None class TestInvokeMethodResponse(TypedDict, total=False): - status: Optional[Integer] - body: Optional[String] - headers: Optional[MapOfStringToString] - multiValueHeaders: Optional[MapOfStringToList] - log: Optional[String] - latency: Optional[Long] + status: Integer | None + body: String | None + headers: MapOfStringToString | None + multiValueHeaders: MapOfStringToList | None + log: String | None + latency: Long | None class UntagResourceRequest(ServiceRequest): @@ -1500,67 +1543,67 @@ class UntagResourceRequest(ServiceRequest): class UpdateAccountRequest(ServiceRequest): - patchOperations: Optional[ListOfPatchOperation] + patchOperations: ListOfPatchOperation | None class UpdateApiKeyRequest(ServiceRequest): apiKey: String - patchOperations: Optional[ListOfPatchOperation] + patchOperations: ListOfPatchOperation | None class UpdateAuthorizerRequest(ServiceRequest): restApiId: String authorizerId: String - patchOperations: Optional[ListOfPatchOperation] + patchOperations: ListOfPatchOperation | None class UpdateBasePathMappingRequest(ServiceRequest): domainName: String - domainNameId: Optional[String] + domainNameId: String | None basePath: String - patchOperations: Optional[ListOfPatchOperation] + patchOperations: ListOfPatchOperation | None class UpdateClientCertificateRequest(ServiceRequest): clientCertificateId: String - patchOperations: Optional[ListOfPatchOperation] + patchOperations: ListOfPatchOperation | None class UpdateDeploymentRequest(ServiceRequest): restApiId: String deploymentId: String - patchOperations: Optional[ListOfPatchOperation] + patchOperations: ListOfPatchOperation | None class UpdateDocumentationPartRequest(ServiceRequest): restApiId: String documentationPartId: String - patchOperations: Optional[ListOfPatchOperation] + patchOperations: ListOfPatchOperation | None class UpdateDocumentationVersionRequest(ServiceRequest): restApiId: String documentationVersion: String - patchOperations: Optional[ListOfPatchOperation] + patchOperations: ListOfPatchOperation | None class UpdateDomainNameRequest(ServiceRequest): domainName: String - domainNameId: Optional[String] - patchOperations: Optional[ListOfPatchOperation] + domainNameId: String | None + patchOperations: ListOfPatchOperation | None class UpdateGatewayResponseRequest(ServiceRequest): restApiId: String responseType: GatewayResponseType - patchOperations: Optional[ListOfPatchOperation] + patchOperations: ListOfPatchOperation | None class UpdateIntegrationRequest(ServiceRequest): restApiId: String resourceId: String httpMethod: String - patchOperations: Optional[ListOfPatchOperation] + patchOperations: ListOfPatchOperation | None class UpdateIntegrationResponseRequest(ServiceRequest): @@ -1568,14 +1611,14 @@ class UpdateIntegrationResponseRequest(ServiceRequest): resourceId: String httpMethod: String statusCode: StatusCode - patchOperations: Optional[ListOfPatchOperation] + patchOperations: ListOfPatchOperation | None class UpdateMethodRequest(ServiceRequest): restApiId: String resourceId: String httpMethod: String - patchOperations: Optional[ListOfPatchOperation] + patchOperations: ListOfPatchOperation | None class UpdateMethodResponseRequest(ServiceRequest): @@ -1583,80 +1626,80 @@ class UpdateMethodResponseRequest(ServiceRequest): resourceId: String httpMethod: String statusCode: StatusCode - patchOperations: Optional[ListOfPatchOperation] + patchOperations: ListOfPatchOperation | None class UpdateModelRequest(ServiceRequest): restApiId: String modelName: String - patchOperations: Optional[ListOfPatchOperation] + patchOperations: ListOfPatchOperation | None class UpdateRequestValidatorRequest(ServiceRequest): restApiId: String requestValidatorId: String - patchOperations: Optional[ListOfPatchOperation] + patchOperations: ListOfPatchOperation | None class UpdateResourceRequest(ServiceRequest): restApiId: String resourceId: String - patchOperations: Optional[ListOfPatchOperation] + patchOperations: ListOfPatchOperation | None class UpdateRestApiRequest(ServiceRequest): restApiId: String - patchOperations: Optional[ListOfPatchOperation] + patchOperations: ListOfPatchOperation | None class UpdateStageRequest(ServiceRequest): restApiId: String stageName: String - patchOperations: Optional[ListOfPatchOperation] + patchOperations: ListOfPatchOperation | None class UpdateUsagePlanRequest(ServiceRequest): usagePlanId: String - patchOperations: Optional[ListOfPatchOperation] + patchOperations: ListOfPatchOperation | None class UpdateUsageRequest(ServiceRequest): usagePlanId: String keyId: String - patchOperations: Optional[ListOfPatchOperation] + patchOperations: ListOfPatchOperation | None class UpdateVpcLinkRequest(ServiceRequest): vpcLinkId: String - patchOperations: Optional[ListOfPatchOperation] + patchOperations: ListOfPatchOperation | None class Usage(TypedDict, total=False): - usagePlanId: Optional[String] - startDate: Optional[String] - endDate: Optional[String] - position: Optional[String] - items: Optional[MapOfKeyUsages] + usagePlanId: String | None + startDate: String | None + endDate: String | None + position: String | None + items: MapOfKeyUsages | None class UsagePlanKeys(TypedDict, total=False): - position: Optional[String] - items: Optional[ListOfUsagePlanKey] + position: String | None + items: ListOfUsagePlanKey | None class UsagePlans(TypedDict, total=False): - position: Optional[String] - items: Optional[ListOfUsagePlan] + position: String | None + items: ListOfUsagePlan | None class VpcLinks(TypedDict, total=False): - position: Optional[String] - items: Optional[ListOfVpcLink] + position: String | None + items: ListOfVpcLink | None class ApigatewayApi: - service = "apigateway" - version = "2015-07-09" + service: str = "apigateway" + version: str = "2015-07-09" @handler("CreateApiKey") def create_api_key( @@ -1748,6 +1791,7 @@ def create_domain_name( endpoint_configuration: EndpointConfiguration | None = None, tags: MapOfStringToString | None = None, security_policy: SecurityPolicy | None = None, + endpoint_access_mode: EndpointAccessMode | None = None, mutual_tls_authentication: MutualTlsAuthenticationInput | None = None, ownership_verification_certificate_arn: String | None = None, policy: String | None = None, @@ -1819,6 +1863,8 @@ def create_rest_api( policy: String | None = None, tags: MapOfStringToString | None = None, disable_execute_api_endpoint: Boolean | None = None, + security_policy: SecurityPolicy | None = None, + endpoint_access_mode: EndpointAccessMode | None = None, **kwargs, ) -> RestApi: raise NotImplementedError diff --git a/localstack-core/localstack/aws/api/cloudcontrol/__init__.py b/localstack-core/localstack/aws/api/cloudcontrol/__init__.py index 7420a35c50e8c..fdb07c98fed3e 100644 --- a/localstack-core/localstack/aws/api/cloudcontrol/__init__.py +++ b/localstack-core/localstack/aws/api/cloudcontrol/__init__.py @@ -1,6 +1,6 @@ from datetime import datetime from enum import StrEnum -from typing import List, Optional, TypedDict +from typing import TypedDict from localstack.aws.api import RequestContext, ServiceException, ServiceRequest, handler @@ -191,62 +191,62 @@ class CancelResourceRequestInput(ServiceRequest): class ProgressEvent(TypedDict, total=False): - TypeName: Optional[TypeName] - Identifier: Optional[Identifier] - RequestToken: Optional[RequestToken] - HooksRequestToken: Optional[RequestToken] - Operation: Optional[Operation] - OperationStatus: Optional[OperationStatus] - EventTime: Optional[Timestamp] - ResourceModel: Optional[Properties] - StatusMessage: Optional[StatusMessage] - ErrorCode: Optional[HandlerErrorCode] - RetryAfter: Optional[Timestamp] + TypeName: TypeName | None + Identifier: Identifier | None + RequestToken: RequestToken | None + HooksRequestToken: RequestToken | None + Operation: Operation | None + OperationStatus: OperationStatus | None + EventTime: Timestamp | None + ResourceModel: Properties | None + StatusMessage: StatusMessage | None + ErrorCode: HandlerErrorCode | None + RetryAfter: Timestamp | None class CancelResourceRequestOutput(TypedDict, total=False): - ProgressEvent: Optional[ProgressEvent] + ProgressEvent: ProgressEvent | None class CreateResourceInput(ServiceRequest): TypeName: TypeName - TypeVersionId: Optional[TypeVersionId] - RoleArn: Optional[RoleArn] - ClientToken: Optional[ClientToken] + TypeVersionId: TypeVersionId | None + RoleArn: RoleArn | None + ClientToken: ClientToken | None DesiredState: Properties class CreateResourceOutput(TypedDict, total=False): - ProgressEvent: Optional[ProgressEvent] + ProgressEvent: ProgressEvent | None class DeleteResourceInput(ServiceRequest): TypeName: TypeName - TypeVersionId: Optional[TypeVersionId] - RoleArn: Optional[RoleArn] - ClientToken: Optional[ClientToken] + TypeVersionId: TypeVersionId | None + RoleArn: RoleArn | None + ClientToken: ClientToken | None Identifier: Identifier class DeleteResourceOutput(TypedDict, total=False): - ProgressEvent: Optional[ProgressEvent] + ProgressEvent: ProgressEvent | None class GetResourceInput(ServiceRequest): TypeName: TypeName - TypeVersionId: Optional[TypeVersionId] - RoleArn: Optional[RoleArn] + TypeVersionId: TypeVersionId | None + RoleArn: RoleArn | None Identifier: Identifier class ResourceDescription(TypedDict, total=False): - Identifier: Optional[Identifier] - Properties: Optional[Properties] + Identifier: Identifier | None + Properties: Properties | None class GetResourceOutput(TypedDict, total=False): - TypeName: Optional[TypeName] - ResourceDescription: Optional[ResourceDescription] + TypeName: TypeName | None + ResourceDescription: ResourceDescription | None class GetResourceRequestStatusInput(ServiceRequest): @@ -254,81 +254,81 @@ class GetResourceRequestStatusInput(ServiceRequest): class HookProgressEvent(TypedDict, total=False): - HookTypeName: Optional[TypeName] - HookTypeVersionId: Optional[TypeVersionId] - HookTypeArn: Optional[HookTypeArn] - InvocationPoint: Optional[HookInvocationPoint] - HookStatus: Optional[HookStatus] - HookEventTime: Optional[Timestamp] - HookStatusMessage: Optional[StatusMessage] - FailureMode: Optional[HookFailureMode] + HookTypeName: TypeName | None + HookTypeVersionId: TypeVersionId | None + HookTypeArn: HookTypeArn | None + InvocationPoint: HookInvocationPoint | None + HookStatus: HookStatus | None + HookEventTime: Timestamp | None + HookStatusMessage: StatusMessage | None + FailureMode: HookFailureMode | None -HooksProgressEvent = List[HookProgressEvent] +HooksProgressEvent = list[HookProgressEvent] class GetResourceRequestStatusOutput(TypedDict, total=False): - ProgressEvent: Optional[ProgressEvent] - HooksProgressEvent: Optional[HooksProgressEvent] + ProgressEvent: ProgressEvent | None + HooksProgressEvent: HooksProgressEvent | None -OperationStatuses = List[OperationStatus] -Operations = List[Operation] +OperationStatuses = list[OperationStatus] +Operations = list[Operation] class ResourceRequestStatusFilter(TypedDict, total=False): - Operations: Optional[Operations] - OperationStatuses: Optional[OperationStatuses] + Operations: Operations | None + OperationStatuses: OperationStatuses | None class ListResourceRequestsInput(ServiceRequest): - MaxResults: Optional[MaxResults] - NextToken: Optional[NextToken] - ResourceRequestStatusFilter: Optional[ResourceRequestStatusFilter] + MaxResults: MaxResults | None + NextToken: NextToken | None + ResourceRequestStatusFilter: ResourceRequestStatusFilter | None -ResourceRequestStatusSummaries = List[ProgressEvent] +ResourceRequestStatusSummaries = list[ProgressEvent] class ListResourceRequestsOutput(TypedDict, total=False): - ResourceRequestStatusSummaries: Optional[ResourceRequestStatusSummaries] - NextToken: Optional[NextToken] + ResourceRequestStatusSummaries: ResourceRequestStatusSummaries | None + NextToken: NextToken | None class ListResourcesInput(ServiceRequest): TypeName: TypeName - TypeVersionId: Optional[TypeVersionId] - RoleArn: Optional[RoleArn] - NextToken: Optional[HandlerNextToken] - MaxResults: Optional[MaxResults] - ResourceModel: Optional[Properties] + TypeVersionId: TypeVersionId | None + RoleArn: RoleArn | None + NextToken: HandlerNextToken | None + MaxResults: MaxResults | None + ResourceModel: Properties | None -ResourceDescriptions = List[ResourceDescription] +ResourceDescriptions = list[ResourceDescription] class ListResourcesOutput(TypedDict, total=False): - TypeName: Optional[TypeName] - ResourceDescriptions: Optional[ResourceDescriptions] - NextToken: Optional[HandlerNextToken] + TypeName: TypeName | None + ResourceDescriptions: ResourceDescriptions | None + NextToken: HandlerNextToken | None class UpdateResourceInput(ServiceRequest): TypeName: TypeName - TypeVersionId: Optional[TypeVersionId] - RoleArn: Optional[RoleArn] - ClientToken: Optional[ClientToken] + TypeVersionId: TypeVersionId | None + RoleArn: RoleArn | None + ClientToken: ClientToken | None Identifier: Identifier PatchDocument: PatchDocument class UpdateResourceOutput(TypedDict, total=False): - ProgressEvent: Optional[ProgressEvent] + ProgressEvent: ProgressEvent | None class CloudcontrolApi: - service = "cloudcontrol" - version = "2021-09-30" + service: str = "cloudcontrol" + version: str = "2021-09-30" @handler("CancelResourceRequest") def cancel_resource_request( diff --git a/localstack-core/localstack/aws/api/cloudformation/__init__.py b/localstack-core/localstack/aws/api/cloudformation/__init__.py index 07defdde7f710..6888630444021 100644 --- a/localstack-core/localstack/aws/api/cloudformation/__init__.py +++ b/localstack-core/localstack/aws/api/cloudformation/__init__.py @@ -1,6 +1,6 @@ from datetime import datetime from enum import StrEnum -from typing import Dict, List, Optional, TypedDict +from typing import TypedDict from localstack.aws.api import RequestContext, ServiceException, ServiceRequest, handler @@ -11,6 +11,8 @@ AfterContext = str AfterValue = str AllowedValue = str +AnnotationName = str +AnnotationRemediationLink = str Arn = str AutoDeploymentNullable = bool AutoUpdate = bool @@ -41,6 +43,7 @@ ExecutionStatusReason = str ExportName = str ExportValue = str +FailedEventsFilter = bool FailedStackInstancesCount = int FailureToleranceCount = int FailureTolerancePercentage = int @@ -50,6 +53,7 @@ HookInvocationId = str HookResultId = str HookStatusReason = str +HookTargetId = str HookTargetTypeName = str HookType = str HookTypeArn = str @@ -83,6 +87,7 @@ NoEcho = bool NotificationARN = str NumberOfResources = int +OperationId = str OperationResultFilterValues = str OptionalSecureUrl = str OrganizationalUnitId = str @@ -93,6 +98,7 @@ ParameterValue = str PercentageCompleted = float PhysicalResourceId = str +PreviousDeploymentContext = str PrivateTypeArn = str Properties = str PropertyDescription = str @@ -107,8 +113,12 @@ RefreshAllResources = bool Region = str RegistrationToken = str +RemediationMessageRemediationMessage = str +RemediationMessageStatusMessage = str RequestToken = str RequiredProperty = bool +ResourceDriftActualValue = str +ResourceDriftPreviousValue = str ResourceIdentifier = str ResourceIdentifierPropertyKey = str ResourceIdentifierPropertyValue = str @@ -187,6 +197,9 @@ Url = str UsePreviousTemplate = bool UsePreviousValue = bool +ValidationName = str +ValidationPath = str +ValidationStatusReason = str Value = str Version = str @@ -204,10 +217,40 @@ class AccountGateStatus(StrEnum): SKIPPED = "SKIPPED" +class AfterValueFrom(StrEnum): + TEMPLATE = "TEMPLATE" + + +class AnnotationSeverityLevel(StrEnum): + INFORMATIONAL = "INFORMATIONAL" + LOW = "LOW" + MEDIUM = "MEDIUM" + HIGH = "HIGH" + CRITICAL = "CRITICAL" + + +class AnnotationStatus(StrEnum): + PASSED = "PASSED" + FAILED = "FAILED" + SKIPPED = "SKIPPED" + + class AttributeChangeType(StrEnum): Add = "Add" Remove = "Remove" Modify = "Modify" + SyncWithActual = "SyncWithActual" + + +class BeaconStackOperationStatus(StrEnum): + IN_PROGRESS = "IN_PROGRESS" + SUCCEEDED = "SUCCEEDED" + FAILED = "FAILED" + + +class BeforeValueFrom(StrEnum): + PREVIOUS_DEPLOYMENT_STATE = "PREVIOUS_DEPLOYMENT_STATE" + ACTUAL_STATE = "ACTUAL_STATE" class CallAs(StrEnum): @@ -234,6 +277,7 @@ class ChangeAction(StrEnum): Remove = "Remove" Import = "Import" Dynamic = "Dynamic" + SyncWithActual = "SyncWithActual" class ChangeSetHooksStatus(StrEnum): @@ -265,6 +309,7 @@ class ChangeSource(StrEnum): ResourceAttribute = "ResourceAttribute" DirectModification = "DirectModification" Automatic = "Automatic" + NoModification = "NoModification" class ChangeType(StrEnum): @@ -281,6 +326,10 @@ class DeletionMode(StrEnum): FORCE_DELETE_STACK = "FORCE_DELETE_STACK" +class DeploymentMode(StrEnum): + REVERT_DRIFT = "REVERT_DRIFT" + + class DeprecatedStatus(StrEnum): LIVE = "LIVE" DEPRECATED = "DEPRECATED" @@ -297,11 +346,24 @@ class DifferenceType(StrEnum): NOT_EQUAL = "NOT_EQUAL" +class DriftIgnoredReason(StrEnum): + MANAGED_BY_AWS = "MANAGED_BY_AWS" + WRITE_ONLY_PROPERTY = "WRITE_ONLY_PROPERTY" + + class EvaluationType(StrEnum): Static = "Static" Dynamic = "Dynamic" +class EventType(StrEnum): + STACK_EVENT = "STACK_EVENT" + PROGRESS_EVENT = "PROGRESS_EVENT" + VALIDATION_ERROR = "VALIDATION_ERROR" + PROVISIONING_ERROR = "PROVISIONING_ERROR" + HOOK_INVOCATION_ERROR = "HOOK_INVOCATION_ERROR" + + class ExecutionStatus(StrEnum): UNAVAILABLE = "UNAVAILABLE" AVAILABLE = "AVAILABLE" @@ -377,6 +439,13 @@ class HookStatus(StrEnum): HOOK_FAILED = "HOOK_FAILED" +class HookTargetAction(StrEnum): + CREATE = "CREATE" + UPDATE = "UPDATE" + DELETE = "DELETE" + IMPORT = "IMPORT" + + class HookTargetType(StrEnum): RESOURCE = "RESOURCE" @@ -417,6 +486,15 @@ class OperationStatus(StrEnum): FAILED = "FAILED" +class OperationType(StrEnum): + CREATE_STACK = "CREATE_STACK" + UPDATE_STACK = "UPDATE_STACK" + DELETE_STACK = "DELETE_STACK" + CONTINUE_ROLLBACK = "CONTINUE_ROLLBACK" + ROLLBACK = "ROLLBACK" + CREATE_CHANGESET = "CREATE_CHANGESET" + + class OrganizationStatus(StrEnum): ENABLED = "ENABLED" DISABLED = "DISABLED" @@ -613,6 +691,7 @@ class StackResourceDriftStatus(StrEnum): DELETED = "DELETED" NOT_CHECKED = "NOT_CHECKED" UNKNOWN = "UNKNOWN" + UNSUPPORTED = "UNSUPPORTED" class StackSetDriftDetectionStatus(StrEnum): @@ -707,6 +786,11 @@ class TypeTestsStatus(StrEnum): NOT_TESTED = "NOT_TESTED" +class ValidationStatus(StrEnum): + FAILED = "FAILED" + SKIPPED = "SKIPPED" + + class VersionBump(StrEnum): MAJOR = "MAJOR" MINOR = "MINOR" @@ -722,6 +806,7 @@ class WarningType(StrEnum): UNSUPPORTED_PROPERTIES = "UNSUPPORTED_PROPERTIES" MUTUALLY_EXCLUSIVE_TYPES = "MUTUALLY_EXCLUSIVE_TYPES" EXCLUDED_PROPERTIES = "EXCLUDED_PROPERTIES" + EXCLUDED_RESOURCES = "EXCLUDED_RESOURCES" class AlreadyExistsException(ServiceException): @@ -899,17 +984,17 @@ class TypeNotFoundException(ServiceException): class AccountGateResult(TypedDict, total=False): - Status: Optional[AccountGateStatus] - StatusReason: Optional[AccountGateStatusReason] + Status: AccountGateStatus | None + StatusReason: AccountGateStatusReason | None class AccountLimit(TypedDict, total=False): - Name: Optional[LimitName] - Value: Optional[LimitValue] + Name: LimitName | None + Value: LimitValue | None -AccountLimitList = List[AccountLimit] -AccountList = List[Account] +AccountLimitList = list[AccountLimit] +AccountList = list[Account] class ActivateOrganizationsAccessInput(ServiceRequest): @@ -929,46 +1014,60 @@ class LoggingConfig(TypedDict, total=False): class ActivateTypeInput(ServiceRequest): - Type: Optional[ThirdPartyType] - PublicTypeArn: Optional[ThirdPartyTypeArn] - PublisherId: Optional[PublisherId] - TypeName: Optional[TypeName] - TypeNameAlias: Optional[TypeName] - AutoUpdate: Optional[AutoUpdate] - LoggingConfig: Optional[LoggingConfig] - ExecutionRoleArn: Optional[RoleArn] - VersionBump: Optional[VersionBump] - MajorVersion: Optional[MajorVersion] + Type: ThirdPartyType | None + PublicTypeArn: ThirdPartyTypeArn | None + PublisherId: PublisherId | None + TypeName: TypeName | None + TypeNameAlias: TypeName | None + AutoUpdate: AutoUpdate | None + LoggingConfig: LoggingConfig | None + ExecutionRoleArn: RoleArn | None + VersionBump: VersionBump | None + MajorVersion: MajorVersion | None class ActivateTypeOutput(TypedDict, total=False): - Arn: Optional[PrivateTypeArn] + Arn: PrivateTypeArn | None + + +AllowedValues = list[AllowedValue] + + +class Annotation(TypedDict, total=False): + AnnotationName: AnnotationName | None + Status: AnnotationStatus | None + StatusMessage: RemediationMessageStatusMessage | None + RemediationMessage: RemediationMessageRemediationMessage | None + RemediationLink: AnnotationRemediationLink | None + SeverityLevel: AnnotationSeverityLevel | None -AllowedValues = List[AllowedValue] +AnnotationList = list[Annotation] +StackSetARNList = list[StackSetARN] class AutoDeployment(TypedDict, total=False): - Enabled: Optional[AutoDeploymentNullable] - RetainStacksOnAccountRemoval: Optional[RetainStacksOnAccountRemovalNullable] + Enabled: AutoDeploymentNullable | None + RetainStacksOnAccountRemoval: RetainStacksOnAccountRemovalNullable | None + DependsOn: StackSetARNList | None class TypeConfigurationIdentifier(TypedDict, total=False): - TypeArn: Optional[TypeArn] - TypeConfigurationAlias: Optional[TypeConfigurationAlias] - TypeConfigurationArn: Optional[TypeConfigurationArn] - Type: Optional[ThirdPartyType] - TypeName: Optional[TypeName] + TypeArn: TypeArn | None + TypeConfigurationAlias: TypeConfigurationAlias | None + TypeConfigurationArn: TypeConfigurationArn | None + Type: ThirdPartyType | None + TypeName: TypeName | None class BatchDescribeTypeConfigurationsError(TypedDict, total=False): - ErrorCode: Optional[ErrorCode] - ErrorMessage: Optional[ErrorMessage] - TypeConfigurationIdentifier: Optional[TypeConfigurationIdentifier] + ErrorCode: ErrorCode | None + ErrorMessage: ErrorMessage | None + TypeConfigurationIdentifier: TypeConfigurationIdentifier | None -BatchDescribeTypeConfigurationsErrors = List[BatchDescribeTypeConfigurationsError] -TypeConfigurationIdentifiers = List[TypeConfigurationIdentifier] +BatchDescribeTypeConfigurationsErrors = list[BatchDescribeTypeConfigurationsError] +TypeConfigurationIdentifiers = list[TypeConfigurationIdentifier] class BatchDescribeTypeConfigurationsInput(ServiceRequest): @@ -979,137 +1078,157 @@ class BatchDescribeTypeConfigurationsInput(ServiceRequest): class TypeConfigurationDetails(TypedDict, total=False): - Arn: Optional[TypeConfigurationArn] - Alias: Optional[TypeConfigurationAlias] - Configuration: Optional[TypeConfiguration] - LastUpdated: Optional[Timestamp] - TypeArn: Optional[TypeArn] - TypeName: Optional[TypeName] - IsDefaultConfiguration: Optional[IsDefaultConfiguration] + Arn: TypeConfigurationArn | None + Alias: TypeConfigurationAlias | None + Configuration: TypeConfiguration | None + LastUpdated: Timestamp | None + TypeArn: TypeArn | None + TypeName: TypeName | None + IsDefaultConfiguration: IsDefaultConfiguration | None -TypeConfigurationDetailsList = List[TypeConfigurationDetails] -UnprocessedTypeConfigurations = List[TypeConfigurationIdentifier] +TypeConfigurationDetailsList = list[TypeConfigurationDetails] +UnprocessedTypeConfigurations = list[TypeConfigurationIdentifier] class BatchDescribeTypeConfigurationsOutput(TypedDict, total=False): - Errors: Optional[BatchDescribeTypeConfigurationsErrors] - UnprocessedTypeConfigurations: Optional[UnprocessedTypeConfigurations] - TypeConfigurations: Optional[TypeConfigurationDetailsList] + Errors: BatchDescribeTypeConfigurationsErrors | None + UnprocessedTypeConfigurations: UnprocessedTypeConfigurations | None + TypeConfigurations: TypeConfigurationDetailsList | None class CancelUpdateStackInput(ServiceRequest): StackName: StackName - ClientRequestToken: Optional[ClientRequestToken] + ClientRequestToken: ClientRequestToken | None -Capabilities = List[Capability] +Capabilities = list[Capability] class ModuleInfo(TypedDict, total=False): - TypeHierarchy: Optional[TypeHierarchy] - LogicalIdHierarchy: Optional[LogicalIdHierarchy] + TypeHierarchy: TypeHierarchy | None + LogicalIdHierarchy: LogicalIdHierarchy | None + + +class LiveResourceDrift(TypedDict, total=False): + PreviousValue: ResourceDriftPreviousValue | None + ActualValue: ResourceDriftActualValue | None + DriftDetectionTimestamp: Timestamp | None class ResourceTargetDefinition(TypedDict, total=False): - Attribute: Optional[ResourceAttribute] - Name: Optional[PropertyName] - RequiresRecreation: Optional[RequiresRecreation] - Path: Optional[ResourcePropertyPath] - BeforeValue: Optional[BeforeValue] - AfterValue: Optional[AfterValue] - AttributeChangeType: Optional[AttributeChangeType] + Attribute: ResourceAttribute | None + Name: PropertyName | None + RequiresRecreation: RequiresRecreation | None + Path: ResourcePropertyPath | None + BeforeValue: BeforeValue | None + AfterValue: AfterValue | None + BeforeValueFrom: BeforeValueFrom | None + AfterValueFrom: AfterValueFrom | None + Drift: LiveResourceDrift | None + AttributeChangeType: AttributeChangeType | None class ResourceChangeDetail(TypedDict, total=False): - Target: Optional[ResourceTargetDefinition] - Evaluation: Optional[EvaluationType] - ChangeSource: Optional[ChangeSource] - CausingEntity: Optional[CausingEntity] + Target: ResourceTargetDefinition | None + Evaluation: EvaluationType | None + ChangeSource: ChangeSource | None + CausingEntity: CausingEntity | None + + +ResourceChangeDetails = list[ResourceChangeDetail] -ResourceChangeDetails = List[ResourceChangeDetail] -Scope = List[ResourceAttribute] +class ResourceDriftIgnoredAttribute(TypedDict, total=False): + Path: ResourcePropertyPath | None + Reason: DriftIgnoredReason | None + + +ResourceDriftIgnoredAttributes = list[ResourceDriftIgnoredAttribute] +Scope = list[ResourceAttribute] class ResourceChange(TypedDict, total=False): - PolicyAction: Optional[PolicyAction] - Action: Optional[ChangeAction] - LogicalResourceId: Optional[LogicalResourceId] - PhysicalResourceId: Optional[PhysicalResourceId] - ResourceType: Optional[ResourceType] - Replacement: Optional[Replacement] - Scope: Optional[Scope] - Details: Optional[ResourceChangeDetails] - ChangeSetId: Optional[ChangeSetId] - ModuleInfo: Optional[ModuleInfo] - BeforeContext: Optional[BeforeContext] - AfterContext: Optional[AfterContext] + PolicyAction: PolicyAction | None + Action: ChangeAction | None + LogicalResourceId: LogicalResourceId | None + PhysicalResourceId: PhysicalResourceId | None + ResourceType: ResourceType | None + Replacement: Replacement | None + Scope: Scope | None + ResourceDriftStatus: StackResourceDriftStatus | None + ResourceDriftIgnoredAttributes: ResourceDriftIgnoredAttributes | None + Details: ResourceChangeDetails | None + ChangeSetId: ChangeSetId | None + ModuleInfo: ModuleInfo | None + BeforeContext: BeforeContext | None + AfterContext: AfterContext | None + PreviousDeploymentContext: PreviousDeploymentContext | None class Change(TypedDict, total=False): - Type: Optional[ChangeType] - HookInvocationCount: Optional[HookInvocationCount] - ResourceChange: Optional[ResourceChange] + Type: ChangeType | None + HookInvocationCount: HookInvocationCount | None + ResourceChange: ResourceChange | None class ChangeSetHookResourceTargetDetails(TypedDict, total=False): - LogicalResourceId: Optional[LogicalResourceId] - ResourceType: Optional[HookTargetTypeName] - ResourceAction: Optional[ChangeAction] + LogicalResourceId: LogicalResourceId | None + ResourceType: HookTargetTypeName | None + ResourceAction: ChangeAction | None class ChangeSetHookTargetDetails(TypedDict, total=False): - TargetType: Optional[HookTargetType] - ResourceTargetDetails: Optional[ChangeSetHookResourceTargetDetails] + TargetType: HookTargetType | None + ResourceTargetDetails: ChangeSetHookResourceTargetDetails | None class ChangeSetHook(TypedDict, total=False): - InvocationPoint: Optional[HookInvocationPoint] - FailureMode: Optional[HookFailureMode] - TypeName: Optional[HookTypeName] - TypeVersionId: Optional[HookTypeVersionId] - TypeConfigurationVersionId: Optional[HookTypeConfigurationVersionId] - TargetDetails: Optional[ChangeSetHookTargetDetails] + InvocationPoint: HookInvocationPoint | None + FailureMode: HookFailureMode | None + TypeName: HookTypeName | None + TypeVersionId: HookTypeVersionId | None + TypeConfigurationVersionId: HookTypeConfigurationVersionId | None + TargetDetails: ChangeSetHookTargetDetails | None -ChangeSetHooks = List[ChangeSetHook] +ChangeSetHooks = list[ChangeSetHook] CreationTime = datetime class ChangeSetSummary(TypedDict, total=False): - StackId: Optional[StackId] - StackName: Optional[StackName] - ChangeSetId: Optional[ChangeSetId] - ChangeSetName: Optional[ChangeSetName] - ExecutionStatus: Optional[ExecutionStatus] - Status: Optional[ChangeSetStatus] - StatusReason: Optional[ChangeSetStatusReason] - CreationTime: Optional[CreationTime] - Description: Optional[Description] - IncludeNestedStacks: Optional[IncludeNestedStacks] - ParentChangeSetId: Optional[ChangeSetId] - RootChangeSetId: Optional[ChangeSetId] - ImportExistingResources: Optional[ImportExistingResources] - - -ChangeSetSummaries = List[ChangeSetSummary] -Changes = List[Change] -ResourcesToSkip = List[ResourceToSkip] + StackId: StackId | None + StackName: StackName | None + ChangeSetId: ChangeSetId | None + ChangeSetName: ChangeSetName | None + ExecutionStatus: ExecutionStatus | None + Status: ChangeSetStatus | None + StatusReason: ChangeSetStatusReason | None + CreationTime: CreationTime | None + Description: Description | None + IncludeNestedStacks: IncludeNestedStacks | None + ParentChangeSetId: ChangeSetId | None + RootChangeSetId: ChangeSetId | None + ImportExistingResources: ImportExistingResources | None + + +ChangeSetSummaries = list[ChangeSetSummary] +Changes = list[Change] +ResourcesToSkip = list[ResourceToSkip] class ContinueUpdateRollbackInput(ServiceRequest): StackName: StackNameOrId - RoleARN: Optional[RoleARN] - ResourcesToSkip: Optional[ResourcesToSkip] - ClientRequestToken: Optional[ClientRequestToken] + RoleARN: RoleARN | None + ResourcesToSkip: ResourcesToSkip | None + ClientRequestToken: ClientRequestToken | None class ContinueUpdateRollbackOutput(TypedDict, total=False): pass -ResourceIdentifierProperties = Dict[ResourceIdentifierPropertyKey, ResourceIdentifierPropertyValue] +ResourceIdentifierProperties = dict[ResourceIdentifierPropertyKey, ResourceIdentifierPropertyValue] class ResourceToImport(TypedDict, total=False): @@ -1118,7 +1237,7 @@ class ResourceToImport(TypedDict, total=False): ResourceIdentifier: ResourceIdentifierProperties -ResourcesToImport = List[ResourceToImport] +ResourcesToImport = list[ResourceToImport] class Tag(TypedDict, total=False): @@ -1126,8 +1245,8 @@ class Tag(TypedDict, total=False): Value: TagValue -Tags = List[Tag] -NotificationARNs = List[NotificationARN] +Tags = list[Tag] +NotificationARNs = list[NotificationARN] class RollbackTrigger(TypedDict, total=False): @@ -1135,149 +1254,151 @@ class RollbackTrigger(TypedDict, total=False): Type: Type -RollbackTriggers = List[RollbackTrigger] +RollbackTriggers = list[RollbackTrigger] class RollbackConfiguration(TypedDict, total=False): - RollbackTriggers: Optional[RollbackTriggers] - MonitoringTimeInMinutes: Optional[MonitoringTimeInMinutes] + RollbackTriggers: RollbackTriggers | None + MonitoringTimeInMinutes: MonitoringTimeInMinutes | None -ResourceTypes = List[ResourceType] +ResourceTypes = list[ResourceType] class Parameter(TypedDict, total=False): - ParameterKey: Optional[ParameterKey] - ParameterValue: Optional[ParameterValue] - UsePreviousValue: Optional[UsePreviousValue] - ResolvedValue: Optional[ParameterValue] + ParameterKey: ParameterKey | None + ParameterValue: ParameterValue | None + UsePreviousValue: UsePreviousValue | None + ResolvedValue: ParameterValue | None -Parameters = List[Parameter] +Parameters = list[Parameter] class CreateChangeSetInput(ServiceRequest): StackName: StackNameOrId - TemplateBody: Optional[TemplateBody] - TemplateURL: Optional[TemplateURL] - UsePreviousTemplate: Optional[UsePreviousTemplate] - Parameters: Optional[Parameters] - Capabilities: Optional[Capabilities] - ResourceTypes: Optional[ResourceTypes] - RoleARN: Optional[RoleARN] - RollbackConfiguration: Optional[RollbackConfiguration] - NotificationARNs: Optional[NotificationARNs] - Tags: Optional[Tags] + TemplateBody: TemplateBody | None + TemplateURL: TemplateURL | None + UsePreviousTemplate: UsePreviousTemplate | None + Parameters: Parameters | None + Capabilities: Capabilities | None + ResourceTypes: ResourceTypes | None + RoleARN: RoleARN | None + RollbackConfiguration: RollbackConfiguration | None + NotificationARNs: NotificationARNs | None + Tags: Tags | None ChangeSetName: ChangeSetName - ClientToken: Optional[ClientToken] - Description: Optional[Description] - ChangeSetType: Optional[ChangeSetType] - ResourcesToImport: Optional[ResourcesToImport] - IncludeNestedStacks: Optional[IncludeNestedStacks] - OnStackFailure: Optional[OnStackFailure] - ImportExistingResources: Optional[ImportExistingResources] + ClientToken: ClientToken | None + Description: Description | None + ChangeSetType: ChangeSetType | None + ResourcesToImport: ResourcesToImport | None + IncludeNestedStacks: IncludeNestedStacks | None + OnStackFailure: OnStackFailure | None + ImportExistingResources: ImportExistingResources | None + DeploymentMode: DeploymentMode | None class CreateChangeSetOutput(TypedDict, total=False): - Id: Optional[ChangeSetId] - StackId: Optional[StackId] + Id: ChangeSetId | None + StackId: StackId | None class TemplateConfiguration(TypedDict, total=False): - DeletionPolicy: Optional[GeneratedTemplateDeletionPolicy] - UpdateReplacePolicy: Optional[GeneratedTemplateUpdateReplacePolicy] + DeletionPolicy: GeneratedTemplateDeletionPolicy | None + UpdateReplacePolicy: GeneratedTemplateUpdateReplacePolicy | None class ResourceDefinition(TypedDict, total=False): ResourceType: ResourceType - LogicalResourceId: Optional[LogicalResourceId] + LogicalResourceId: LogicalResourceId | None ResourceIdentifier: ResourceIdentifierProperties -ResourceDefinitions = List[ResourceDefinition] +ResourceDefinitions = list[ResourceDefinition] class CreateGeneratedTemplateInput(ServiceRequest): - Resources: Optional[ResourceDefinitions] + Resources: ResourceDefinitions | None GeneratedTemplateName: GeneratedTemplateName - StackName: Optional[StackName] - TemplateConfiguration: Optional[TemplateConfiguration] + StackName: StackName | None + TemplateConfiguration: TemplateConfiguration | None class CreateGeneratedTemplateOutput(TypedDict, total=False): - GeneratedTemplateId: Optional[GeneratedTemplateId] + GeneratedTemplateId: GeneratedTemplateId | None class CreateStackInput(ServiceRequest): StackName: StackName - TemplateBody: Optional[TemplateBody] - TemplateURL: Optional[TemplateURL] - Parameters: Optional[Parameters] - DisableRollback: Optional[DisableRollback] - RollbackConfiguration: Optional[RollbackConfiguration] - TimeoutInMinutes: Optional[TimeoutMinutes] - NotificationARNs: Optional[NotificationARNs] - Capabilities: Optional[Capabilities] - ResourceTypes: Optional[ResourceTypes] - RoleARN: Optional[RoleARN] - OnFailure: Optional[OnFailure] - StackPolicyBody: Optional[StackPolicyBody] - StackPolicyURL: Optional[StackPolicyURL] - Tags: Optional[Tags] - ClientRequestToken: Optional[ClientRequestToken] - EnableTerminationProtection: Optional[EnableTerminationProtection] - RetainExceptOnCreate: Optional[RetainExceptOnCreate] - - -RegionList = List[Region] + TemplateBody: TemplateBody | None + TemplateURL: TemplateURL | None + Parameters: Parameters | None + DisableRollback: DisableRollback | None + RollbackConfiguration: RollbackConfiguration | None + TimeoutInMinutes: TimeoutMinutes | None + NotificationARNs: NotificationARNs | None + Capabilities: Capabilities | None + ResourceTypes: ResourceTypes | None + RoleARN: RoleARN | None + OnFailure: OnFailure | None + StackPolicyBody: StackPolicyBody | None + StackPolicyURL: StackPolicyURL | None + Tags: Tags | None + ClientRequestToken: ClientRequestToken | None + EnableTerminationProtection: EnableTerminationProtection | None + RetainExceptOnCreate: RetainExceptOnCreate | None + + +RegionList = list[Region] class StackSetOperationPreferences(TypedDict, total=False): - RegionConcurrencyType: Optional[RegionConcurrencyType] - RegionOrder: Optional[RegionList] - FailureToleranceCount: Optional[FailureToleranceCount] - FailureTolerancePercentage: Optional[FailureTolerancePercentage] - MaxConcurrentCount: Optional[MaxConcurrentCount] - MaxConcurrentPercentage: Optional[MaxConcurrentPercentage] - ConcurrencyMode: Optional[ConcurrencyMode] + RegionConcurrencyType: RegionConcurrencyType | None + RegionOrder: RegionList | None + FailureToleranceCount: FailureToleranceCount | None + FailureTolerancePercentage: FailureTolerancePercentage | None + MaxConcurrentCount: MaxConcurrentCount | None + MaxConcurrentPercentage: MaxConcurrentPercentage | None + ConcurrencyMode: ConcurrencyMode | None -OrganizationalUnitIdList = List[OrganizationalUnitId] +OrganizationalUnitIdList = list[OrganizationalUnitId] class DeploymentTargets(TypedDict, total=False): - Accounts: Optional[AccountList] - AccountsUrl: Optional[AccountsUrl] - OrganizationalUnitIds: Optional[OrganizationalUnitIdList] - AccountFilterType: Optional[AccountFilterType] + Accounts: AccountList | None + AccountsUrl: AccountsUrl | None + OrganizationalUnitIds: OrganizationalUnitIdList | None + AccountFilterType: AccountFilterType | None class CreateStackInstancesInput(ServiceRequest): StackSetName: StackSetName - Accounts: Optional[AccountList] - DeploymentTargets: Optional[DeploymentTargets] + Accounts: AccountList | None + DeploymentTargets: DeploymentTargets | None Regions: RegionList - ParameterOverrides: Optional[Parameters] - OperationPreferences: Optional[StackSetOperationPreferences] - OperationId: Optional[ClientRequestToken] - CallAs: Optional[CallAs] + ParameterOverrides: Parameters | None + OperationPreferences: StackSetOperationPreferences | None + OperationId: ClientRequestToken | None + CallAs: CallAs | None class CreateStackInstancesOutput(TypedDict, total=False): - OperationId: Optional[ClientRequestToken] + OperationId: ClientRequestToken | None class CreateStackOutput(TypedDict, total=False): - StackId: Optional[StackId] + StackId: StackId | None + OperationId: OperationId | None class StackDefinition(TypedDict, total=False): - StackName: Optional[StackName] - TemplateBody: Optional[TemplateBody] - TemplateURL: Optional[TemplateURL] + StackName: StackName | None + TemplateBody: TemplateBody | None + TemplateURL: TemplateURL | None -StackDefinitions = List[StackDefinition] +StackDefinitions = list[StackDefinition] class ResourceLocation(TypedDict, total=False): @@ -1290,13 +1411,13 @@ class ResourceMapping(TypedDict, total=False): Destination: ResourceLocation -ResourceMappings = List[ResourceMapping] +ResourceMappings = list[ResourceMapping] class CreateStackRefactorInput(ServiceRequest): - Description: Optional[Description] - EnableStackCreation: Optional[EnableStackCreation] - ResourceMappings: Optional[ResourceMappings] + Description: Description | None + EnableStackCreation: EnableStackCreation | None + ResourceMappings: ResourceMappings | None StackDefinitions: StackDefinitions @@ -1305,29 +1426,29 @@ class CreateStackRefactorOutput(TypedDict, total=False): class ManagedExecution(TypedDict, total=False): - Active: Optional[ManagedExecutionNullable] + Active: ManagedExecutionNullable | None class CreateStackSetInput(ServiceRequest): StackSetName: StackSetName - Description: Optional[Description] - TemplateBody: Optional[TemplateBody] - TemplateURL: Optional[TemplateURL] - StackId: Optional[StackId] - Parameters: Optional[Parameters] - Capabilities: Optional[Capabilities] - Tags: Optional[Tags] - AdministrationRoleARN: Optional[RoleARN] - ExecutionRoleName: Optional[ExecutionRoleName] - PermissionModel: Optional[PermissionModels] - AutoDeployment: Optional[AutoDeployment] - CallAs: Optional[CallAs] - ClientRequestToken: Optional[ClientRequestToken] - ManagedExecution: Optional[ManagedExecution] + Description: Description | None + TemplateBody: TemplateBody | None + TemplateURL: TemplateURL | None + StackId: StackId | None + Parameters: Parameters | None + Capabilities: Capabilities | None + Tags: Tags | None + AdministrationRoleARN: RoleARN | None + ExecutionRoleName: ExecutionRoleName | None + PermissionModel: PermissionModels | None + AutoDeployment: AutoDeployment | None + CallAs: CallAs | None + ClientRequestToken: ClientRequestToken | None + ManagedExecution: ManagedExecution | None class CreateStackSetOutput(TypedDict, total=False): - StackSetId: Optional[StackSetId] + StackSetId: StackSetId | None class DeactivateOrganizationsAccessInput(ServiceRequest): @@ -1339,9 +1460,9 @@ class DeactivateOrganizationsAccessOutput(TypedDict, total=False): class DeactivateTypeInput(ServiceRequest): - TypeName: Optional[TypeName] - Type: Optional[ThirdPartyType] - Arn: Optional[PrivateTypeArn] + TypeName: TypeName | None + Type: ThirdPartyType | None + Arn: PrivateTypeArn | None class DeactivateTypeOutput(TypedDict, total=False): @@ -1350,7 +1471,7 @@ class DeactivateTypeOutput(TypedDict, total=False): class DeleteChangeSetInput(ServiceRequest): ChangeSetName: ChangeSetNameOrId - StackName: Optional[StackNameOrId] + StackName: StackNameOrId | None class DeleteChangeSetOutput(TypedDict, total=False): @@ -1361,35 +1482,35 @@ class DeleteGeneratedTemplateInput(ServiceRequest): GeneratedTemplateName: GeneratedTemplateName -RetainResources = List[LogicalResourceId] +RetainResources = list[LogicalResourceId] class DeleteStackInput(ServiceRequest): StackName: StackName - RetainResources: Optional[RetainResources] - RoleARN: Optional[RoleARN] - ClientRequestToken: Optional[ClientRequestToken] - DeletionMode: Optional[DeletionMode] + RetainResources: RetainResources | None + RoleARN: RoleARN | None + ClientRequestToken: ClientRequestToken | None + DeletionMode: DeletionMode | None class DeleteStackInstancesInput(ServiceRequest): StackSetName: StackSetName - Accounts: Optional[AccountList] - DeploymentTargets: Optional[DeploymentTargets] + Accounts: AccountList | None + DeploymentTargets: DeploymentTargets | None Regions: RegionList - OperationPreferences: Optional[StackSetOperationPreferences] + OperationPreferences: StackSetOperationPreferences | None RetainStacks: RetainStacks - OperationId: Optional[ClientRequestToken] - CallAs: Optional[CallAs] + OperationId: ClientRequestToken | None + CallAs: CallAs | None class DeleteStackInstancesOutput(TypedDict, total=False): - OperationId: Optional[ClientRequestToken] + OperationId: ClientRequestToken | None class DeleteStackSetInput(ServiceRequest): StackSetName: StackSetName - CallAs: Optional[CallAs] + CallAs: CallAs | None class DeleteStackSetOutput(TypedDict, total=False): @@ -1400,10 +1521,10 @@ class DeleteStackSetOutput(TypedDict, total=False): class DeregisterTypeInput(ServiceRequest): - Arn: Optional[PrivateTypeArn] - Type: Optional[RegistryType] - TypeName: Optional[TypeName] - VersionId: Optional[TypeVersionId] + Arn: PrivateTypeArn | None + Type: RegistryType | None + TypeName: TypeName | None + VersionId: TypeVersionId | None class DeregisterTypeOutput(TypedDict, total=False): @@ -1411,60 +1532,112 @@ class DeregisterTypeOutput(TypedDict, total=False): class DescribeAccountLimitsInput(ServiceRequest): - NextToken: Optional[NextToken] + NextToken: NextToken | None class DescribeAccountLimitsOutput(TypedDict, total=False): - AccountLimits: Optional[AccountLimitList] - NextToken: Optional[NextToken] + AccountLimits: AccountLimitList | None + NextToken: NextToken | None class DescribeChangeSetHooksInput(ServiceRequest): ChangeSetName: ChangeSetNameOrId - StackName: Optional[StackNameOrId] - NextToken: Optional[NextToken] - LogicalResourceId: Optional[LogicalResourceId] + StackName: StackNameOrId | None + NextToken: NextToken | None + LogicalResourceId: LogicalResourceId | None class DescribeChangeSetHooksOutput(TypedDict, total=False): - ChangeSetId: Optional[ChangeSetId] - ChangeSetName: Optional[ChangeSetName] - Hooks: Optional[ChangeSetHooks] - Status: Optional[ChangeSetHooksStatus] - NextToken: Optional[NextToken] - StackId: Optional[StackId] - StackName: Optional[StackName] + ChangeSetId: ChangeSetId | None + ChangeSetName: ChangeSetName | None + Hooks: ChangeSetHooks | None + Status: ChangeSetHooksStatus | None + NextToken: NextToken | None + StackId: StackId | None + StackName: StackName | None class DescribeChangeSetInput(ServiceRequest): ChangeSetName: ChangeSetNameOrId - StackName: Optional[StackNameOrId] - NextToken: Optional[NextToken] - IncludePropertyValues: Optional[IncludePropertyValues] + StackName: StackNameOrId | None + NextToken: NextToken | None + IncludePropertyValues: IncludePropertyValues | None class DescribeChangeSetOutput(TypedDict, total=False): - ChangeSetName: Optional[ChangeSetName] - ChangeSetId: Optional[ChangeSetId] - StackId: Optional[StackId] - StackName: Optional[StackName] - Description: Optional[Description] - Parameters: Optional[Parameters] - CreationTime: Optional[CreationTime] - ExecutionStatus: Optional[ExecutionStatus] - Status: Optional[ChangeSetStatus] - StatusReason: Optional[ChangeSetStatusReason] - NotificationARNs: Optional[NotificationARNs] - RollbackConfiguration: Optional[RollbackConfiguration] - Capabilities: Optional[Capabilities] - Tags: Optional[Tags] - Changes: Optional[Changes] - NextToken: Optional[NextToken] - IncludeNestedStacks: Optional[IncludeNestedStacks] - ParentChangeSetId: Optional[ChangeSetId] - RootChangeSetId: Optional[ChangeSetId] - OnStackFailure: Optional[OnStackFailure] - ImportExistingResources: Optional[ImportExistingResources] + ChangeSetName: ChangeSetName | None + ChangeSetId: ChangeSetId | None + StackId: StackId | None + StackName: StackName | None + Description: Description | None + Parameters: Parameters | None + CreationTime: CreationTime | None + ExecutionStatus: ExecutionStatus | None + Status: ChangeSetStatus | None + StatusReason: ChangeSetStatusReason | None + StackDriftStatus: StackDriftStatus | None + NotificationARNs: NotificationARNs | None + RollbackConfiguration: RollbackConfiguration | None + Capabilities: Capabilities | None + Tags: Tags | None + Changes: Changes | None + NextToken: NextToken | None + IncludeNestedStacks: IncludeNestedStacks | None + ParentChangeSetId: ChangeSetId | None + RootChangeSetId: ChangeSetId | None + OnStackFailure: OnStackFailure | None + ImportExistingResources: ImportExistingResources | None + DeploymentMode: DeploymentMode | None + + +class EventFilter(TypedDict, total=False): + FailedEvents: FailedEventsFilter | None + + +class DescribeEventsInput(ServiceRequest): + StackName: StackNameOrId | None + ChangeSetName: ChangeSetNameOrId | None + OperationId: OperationId | None + Filters: EventFilter | None + NextToken: NextToken | None + + +class OperationEvent(TypedDict, total=False): + EventId: EventId | None + StackId: StackId | None + OperationId: OperationId | None + OperationType: OperationType | None + OperationStatus: BeaconStackOperationStatus | None + EventType: EventType | None + LogicalResourceId: LogicalResourceId | None + PhysicalResourceId: PhysicalResourceId | None + ResourceType: ResourceType | None + Timestamp: Timestamp | None + StartTime: Timestamp | None + EndTime: Timestamp | None + ResourceStatus: ResourceStatus | None + ResourceStatusReason: ResourceStatusReason | None + ResourceProperties: ResourceProperties | None + ClientRequestToken: ClientRequestToken | None + HookType: HookType | None + HookStatus: HookStatus | None + HookStatusReason: HookStatusReason | None + HookInvocationPoint: HookInvocationPoint | None + HookFailureMode: HookFailureMode | None + DetailedStatus: DetailedStatus | None + ValidationFailureMode: HookFailureMode | None + ValidationName: ValidationName | None + ValidationStatus: ValidationStatus | None + ValidationStatusReason: ValidationStatusReason | None + ValidationPath: ValidationPath | None + + +OperationEvents = list[OperationEvent] + + +class DescribeEventsOutput(TypedDict, total=False): + OperationEvents: OperationEvents | None + NextToken: NextToken | None class DescribeGeneratedTemplateInput(ServiceRequest): @@ -1472,102 +1645,102 @@ class DescribeGeneratedTemplateInput(ServiceRequest): class TemplateProgress(TypedDict, total=False): - ResourcesSucceeded: Optional[ResourcesSucceeded] - ResourcesFailed: Optional[ResourcesFailed] - ResourcesProcessing: Optional[ResourcesProcessing] - ResourcesPending: Optional[ResourcesPending] + ResourcesSucceeded: ResourcesSucceeded | None + ResourcesFailed: ResourcesFailed | None + ResourcesProcessing: ResourcesProcessing | None + ResourcesPending: ResourcesPending | None LastUpdatedTime = datetime class WarningProperty(TypedDict, total=False): - PropertyPath: Optional[PropertyPath] - Required: Optional[RequiredProperty] - Description: Optional[PropertyDescription] + PropertyPath: PropertyPath | None + Required: RequiredProperty | None + Description: PropertyDescription | None -WarningProperties = List[WarningProperty] +WarningProperties = list[WarningProperty] class WarningDetail(TypedDict, total=False): - Type: Optional[WarningType] - Properties: Optional[WarningProperties] + Type: WarningType | None + Properties: WarningProperties | None -WarningDetails = List[WarningDetail] +WarningDetails = list[WarningDetail] class ResourceDetail(TypedDict, total=False): - ResourceType: Optional[ResourceType] - LogicalResourceId: Optional[LogicalResourceId] - ResourceIdentifier: Optional[ResourceIdentifierProperties] - ResourceStatus: Optional[GeneratedTemplateResourceStatus] - ResourceStatusReason: Optional[ResourceStatusReason] - Warnings: Optional[WarningDetails] + ResourceType: ResourceType | None + LogicalResourceId: LogicalResourceId | None + ResourceIdentifier: ResourceIdentifierProperties | None + ResourceStatus: GeneratedTemplateResourceStatus | None + ResourceStatusReason: ResourceStatusReason | None + Warnings: WarningDetails | None -ResourceDetails = List[ResourceDetail] +ResourceDetails = list[ResourceDetail] class DescribeGeneratedTemplateOutput(TypedDict, total=False): - GeneratedTemplateId: Optional[GeneratedTemplateId] - GeneratedTemplateName: Optional[GeneratedTemplateName] - Resources: Optional[ResourceDetails] - Status: Optional[GeneratedTemplateStatus] - StatusReason: Optional[TemplateStatusReason] - CreationTime: Optional[CreationTime] - LastUpdatedTime: Optional[LastUpdatedTime] - Progress: Optional[TemplateProgress] - StackId: Optional[StackId] - TemplateConfiguration: Optional[TemplateConfiguration] - TotalWarnings: Optional[TotalWarnings] + GeneratedTemplateId: GeneratedTemplateId | None + GeneratedTemplateName: GeneratedTemplateName | None + Resources: ResourceDetails | None + Status: GeneratedTemplateStatus | None + StatusReason: TemplateStatusReason | None + CreationTime: CreationTime | None + LastUpdatedTime: LastUpdatedTime | None + Progress: TemplateProgress | None + StackId: StackId | None + TemplateConfiguration: TemplateConfiguration | None + TotalWarnings: TotalWarnings | None class DescribeOrganizationsAccessInput(ServiceRequest): - CallAs: Optional[CallAs] + CallAs: CallAs | None class DescribeOrganizationsAccessOutput(TypedDict, total=False): - Status: Optional[OrganizationStatus] + Status: OrganizationStatus | None class DescribePublisherInput(ServiceRequest): - PublisherId: Optional[PublisherId] + PublisherId: PublisherId | None class DescribePublisherOutput(TypedDict, total=False): - PublisherId: Optional[PublisherId] - PublisherStatus: Optional[PublisherStatus] - IdentityProvider: Optional[IdentityProvider] - PublisherProfile: Optional[PublisherProfile] + PublisherId: PublisherId | None + PublisherStatus: PublisherStatus | None + IdentityProvider: IdentityProvider | None + PublisherProfile: PublisherProfile | None class DescribeResourceScanInput(ServiceRequest): ResourceScanId: ResourceScanId -ResourceTypeFilters = List[ResourceTypeFilter] +ResourceTypeFilters = list[ResourceTypeFilter] class ScanFilter(TypedDict, total=False): - Types: Optional[ResourceTypeFilters] + Types: ResourceTypeFilters | None -ScanFilters = List[ScanFilter] +ScanFilters = list[ScanFilter] class DescribeResourceScanOutput(TypedDict, total=False): - ResourceScanId: Optional[ResourceScanId] - Status: Optional[ResourceScanStatus] - StatusReason: Optional[ResourceScanStatusReason] - StartTime: Optional[Timestamp] - EndTime: Optional[Timestamp] - PercentageCompleted: Optional[PercentageCompleted] - ResourceTypes: Optional[ResourceTypes] - ResourcesScanned: Optional[ResourcesScanned] - ResourcesRead: Optional[ResourcesRead] - ScanFilters: Optional[ScanFilters] + ResourceScanId: ResourceScanId | None + Status: ResourceScanStatus | None + StatusReason: ResourceScanStatusReason | None + StartTime: Timestamp | None + EndTime: Timestamp | None + PercentageCompleted: PercentageCompleted | None + ResourceTypes: ResourceTypes | None + ResourcesScanned: ResourcesScanned | None + ResourcesRead: ResourcesRead | None + ScanFilters: ScanFilters | None class DescribeStackDriftDetectionStatusInput(ServiceRequest): @@ -1577,102 +1750,103 @@ class DescribeStackDriftDetectionStatusInput(ServiceRequest): class DescribeStackDriftDetectionStatusOutput(TypedDict, total=False): StackId: StackId StackDriftDetectionId: StackDriftDetectionId - StackDriftStatus: Optional[StackDriftStatus] + StackDriftStatus: StackDriftStatus | None DetectionStatus: StackDriftDetectionStatus - DetectionStatusReason: Optional[StackDriftDetectionStatusReason] - DriftedStackResourceCount: Optional[BoxedInteger] + DetectionStatusReason: StackDriftDetectionStatusReason | None + DriftedStackResourceCount: BoxedInteger | None Timestamp: Timestamp class DescribeStackEventsInput(ServiceRequest): - StackName: Optional[StackName] - NextToken: Optional[NextToken] + StackName: StackName + NextToken: NextToken | None class StackEvent(TypedDict, total=False): StackId: StackId EventId: EventId StackName: StackName - LogicalResourceId: Optional[LogicalResourceId] - PhysicalResourceId: Optional[PhysicalResourceId] - ResourceType: Optional[ResourceType] + OperationId: OperationId | None + LogicalResourceId: LogicalResourceId | None + PhysicalResourceId: PhysicalResourceId | None + ResourceType: ResourceType | None Timestamp: Timestamp - ResourceStatus: Optional[ResourceStatus] - ResourceStatusReason: Optional[ResourceStatusReason] - ResourceProperties: Optional[ResourceProperties] - ClientRequestToken: Optional[ClientRequestToken] - HookType: Optional[HookType] - HookStatus: Optional[HookStatus] - HookStatusReason: Optional[HookStatusReason] - HookInvocationPoint: Optional[HookInvocationPoint] - HookInvocationId: Optional[HookInvocationId] - HookFailureMode: Optional[HookFailureMode] - DetailedStatus: Optional[DetailedStatus] + ResourceStatus: ResourceStatus | None + ResourceStatusReason: ResourceStatusReason | None + ResourceProperties: ResourceProperties | None + ClientRequestToken: ClientRequestToken | None + HookType: HookType | None + HookStatus: HookStatus | None + HookStatusReason: HookStatusReason | None + HookInvocationPoint: HookInvocationPoint | None + HookInvocationId: HookInvocationId | None + HookFailureMode: HookFailureMode | None + DetailedStatus: DetailedStatus | None -StackEvents = List[StackEvent] +StackEvents = list[StackEvent] class DescribeStackEventsOutput(TypedDict, total=False): - StackEvents: Optional[StackEvents] - NextToken: Optional[NextToken] + StackEvents: StackEvents | None + NextToken: NextToken | None class DescribeStackInstanceInput(ServiceRequest): StackSetName: StackSetName StackInstanceAccount: Account StackInstanceRegion: Region - CallAs: Optional[CallAs] + CallAs: CallAs | None class StackInstanceComprehensiveStatus(TypedDict, total=False): - DetailedStatus: Optional[StackInstanceDetailedStatus] + DetailedStatus: StackInstanceDetailedStatus | None class StackInstance(TypedDict, total=False): - StackSetId: Optional[StackSetId] - Region: Optional[Region] - Account: Optional[Account] - StackId: Optional[StackId] - ParameterOverrides: Optional[Parameters] - Status: Optional[StackInstanceStatus] - StackInstanceStatus: Optional[StackInstanceComprehensiveStatus] - StatusReason: Optional[Reason] - OrganizationalUnitId: Optional[OrganizationalUnitId] - DriftStatus: Optional[StackDriftStatus] - LastDriftCheckTimestamp: Optional[Timestamp] - LastOperationId: Optional[ClientRequestToken] + StackSetId: StackSetId | None + Region: Region | None + Account: Account | None + StackId: StackId | None + ParameterOverrides: Parameters | None + Status: StackInstanceStatus | None + StackInstanceStatus: StackInstanceComprehensiveStatus | None + StatusReason: Reason | None + OrganizationalUnitId: OrganizationalUnitId | None + DriftStatus: StackDriftStatus | None + LastDriftCheckTimestamp: Timestamp | None + LastOperationId: ClientRequestToken | None class DescribeStackInstanceOutput(TypedDict, total=False): - StackInstance: Optional[StackInstance] + StackInstance: StackInstance | None class DescribeStackRefactorInput(ServiceRequest): StackRefactorId: StackRefactorId -StackIds = List[StackId] +StackIds = list[StackId] class DescribeStackRefactorOutput(TypedDict, total=False): - Description: Optional[Description] - StackRefactorId: Optional[StackRefactorId] - StackIds: Optional[StackIds] - ExecutionStatus: Optional[StackRefactorExecutionStatus] - ExecutionStatusReason: Optional[ExecutionStatusReason] - Status: Optional[StackRefactorStatus] - StatusReason: Optional[StackRefactorStatusReason] + Description: Description | None + StackRefactorId: StackRefactorId | None + StackIds: StackIds | None + ExecutionStatus: StackRefactorExecutionStatus | None + ExecutionStatusReason: ExecutionStatusReason | None + Status: StackRefactorStatus | None + StatusReason: StackRefactorStatusReason | None -StackResourceDriftStatusFilters = List[StackResourceDriftStatus] +StackResourceDriftStatusFilters = list[StackResourceDriftStatus] class DescribeStackResourceDriftsInput(ServiceRequest): StackName: StackNameOrId - StackResourceDriftStatusFilters: Optional[StackResourceDriftStatusFilters] - NextToken: Optional[NextToken] - MaxResults: Optional[BoxedMaxResults] + StackResourceDriftStatusFilters: StackResourceDriftStatusFilters | None + NextToken: NextToken | None + MaxResults: BoxedMaxResults | None class PropertyDifference(TypedDict, total=False): @@ -1682,7 +1856,7 @@ class PropertyDifference(TypedDict, total=False): DifferenceType: DifferenceType -PropertyDifferences = List[PropertyDifference] +PropertyDifferences = list[PropertyDifference] class PhysicalResourceIdContextKeyValuePair(TypedDict, total=False): @@ -1690,30 +1864,30 @@ class PhysicalResourceIdContextKeyValuePair(TypedDict, total=False): Value: Value -PhysicalResourceIdContext = List[PhysicalResourceIdContextKeyValuePair] +PhysicalResourceIdContext = list[PhysicalResourceIdContextKeyValuePair] class StackResourceDrift(TypedDict, total=False): StackId: StackId LogicalResourceId: LogicalResourceId - PhysicalResourceId: Optional[PhysicalResourceId] - PhysicalResourceIdContext: Optional[PhysicalResourceIdContext] + PhysicalResourceId: PhysicalResourceId | None + PhysicalResourceIdContext: PhysicalResourceIdContext | None ResourceType: ResourceType - ExpectedProperties: Optional[Properties] - ActualProperties: Optional[Properties] - PropertyDifferences: Optional[PropertyDifferences] + ExpectedProperties: Properties | None + ActualProperties: Properties | None + PropertyDifferences: PropertyDifferences | None StackResourceDriftStatus: StackResourceDriftStatus Timestamp: Timestamp - ModuleInfo: Optional[ModuleInfo] - DriftStatusReason: Optional[StackResourceDriftStatusReason] + ModuleInfo: ModuleInfo | None + DriftStatusReason: StackResourceDriftStatusReason | None -StackResourceDrifts = List[StackResourceDrift] +StackResourceDrifts = list[StackResourceDrift] class DescribeStackResourceDriftsOutput(TypedDict, total=False): StackResourceDrifts: StackResourceDrifts - NextToken: Optional[NextToken] + NextToken: NextToken | None class DescribeStackResourceInput(ServiceRequest): @@ -1723,232 +1897,241 @@ class DescribeStackResourceInput(ServiceRequest): class StackResourceDriftInformation(TypedDict, total=False): StackResourceDriftStatus: StackResourceDriftStatus - LastCheckTimestamp: Optional[Timestamp] + LastCheckTimestamp: Timestamp | None class StackResourceDetail(TypedDict, total=False): - StackName: Optional[StackName] - StackId: Optional[StackId] + StackName: StackName | None + StackId: StackId | None LogicalResourceId: LogicalResourceId - PhysicalResourceId: Optional[PhysicalResourceId] + PhysicalResourceId: PhysicalResourceId | None ResourceType: ResourceType LastUpdatedTimestamp: Timestamp ResourceStatus: ResourceStatus - ResourceStatusReason: Optional[ResourceStatusReason] - Description: Optional[Description] - Metadata: Optional[Metadata] - DriftInformation: Optional[StackResourceDriftInformation] - ModuleInfo: Optional[ModuleInfo] + ResourceStatusReason: ResourceStatusReason | None + Description: Description | None + Metadata: Metadata | None + DriftInformation: StackResourceDriftInformation | None + ModuleInfo: ModuleInfo | None class DescribeStackResourceOutput(TypedDict, total=False): - StackResourceDetail: Optional[StackResourceDetail] + StackResourceDetail: StackResourceDetail | None class DescribeStackResourcesInput(ServiceRequest): - StackName: Optional[StackName] - LogicalResourceId: Optional[LogicalResourceId] - PhysicalResourceId: Optional[PhysicalResourceId] + StackName: StackName | None + LogicalResourceId: LogicalResourceId | None + PhysicalResourceId: PhysicalResourceId | None class StackResource(TypedDict, total=False): - StackName: Optional[StackName] - StackId: Optional[StackId] + StackName: StackName | None + StackId: StackId | None LogicalResourceId: LogicalResourceId - PhysicalResourceId: Optional[PhysicalResourceId] + PhysicalResourceId: PhysicalResourceId | None ResourceType: ResourceType Timestamp: Timestamp ResourceStatus: ResourceStatus - ResourceStatusReason: Optional[ResourceStatusReason] - Description: Optional[Description] - DriftInformation: Optional[StackResourceDriftInformation] - ModuleInfo: Optional[ModuleInfo] + ResourceStatusReason: ResourceStatusReason | None + Description: Description | None + DriftInformation: StackResourceDriftInformation | None + ModuleInfo: ModuleInfo | None -StackResources = List[StackResource] +StackResources = list[StackResource] class DescribeStackResourcesOutput(TypedDict, total=False): - StackResources: Optional[StackResources] + StackResources: StackResources | None class DescribeStackSetInput(ServiceRequest): StackSetName: StackSetName - CallAs: Optional[CallAs] + CallAs: CallAs | None class DescribeStackSetOperationInput(ServiceRequest): StackSetName: StackSetName OperationId: ClientRequestToken - CallAs: Optional[CallAs] + CallAs: CallAs | None class StackSetOperationStatusDetails(TypedDict, total=False): - FailedStackInstancesCount: Optional[FailedStackInstancesCount] + FailedStackInstancesCount: FailedStackInstancesCount | None class StackSetDriftDetectionDetails(TypedDict, total=False): - DriftStatus: Optional[StackSetDriftStatus] - DriftDetectionStatus: Optional[StackSetDriftDetectionStatus] - LastDriftCheckTimestamp: Optional[Timestamp] - TotalStackInstancesCount: Optional[TotalStackInstancesCount] - DriftedStackInstancesCount: Optional[DriftedStackInstancesCount] - InSyncStackInstancesCount: Optional[InSyncStackInstancesCount] - InProgressStackInstancesCount: Optional[InProgressStackInstancesCount] - FailedStackInstancesCount: Optional[FailedStackInstancesCount] + DriftStatus: StackSetDriftStatus | None + DriftDetectionStatus: StackSetDriftDetectionStatus | None + LastDriftCheckTimestamp: Timestamp | None + TotalStackInstancesCount: TotalStackInstancesCount | None + DriftedStackInstancesCount: DriftedStackInstancesCount | None + InSyncStackInstancesCount: InSyncStackInstancesCount | None + InProgressStackInstancesCount: InProgressStackInstancesCount | None + FailedStackInstancesCount: FailedStackInstancesCount | None class StackSetOperation(TypedDict, total=False): - OperationId: Optional[ClientRequestToken] - StackSetId: Optional[StackSetId] - Action: Optional[StackSetOperationAction] - Status: Optional[StackSetOperationStatus] - OperationPreferences: Optional[StackSetOperationPreferences] - RetainStacks: Optional[RetainStacksNullable] - AdministrationRoleARN: Optional[RoleARN] - ExecutionRoleName: Optional[ExecutionRoleName] - CreationTimestamp: Optional[Timestamp] - EndTimestamp: Optional[Timestamp] - DeploymentTargets: Optional[DeploymentTargets] - StackSetDriftDetectionDetails: Optional[StackSetDriftDetectionDetails] - StatusReason: Optional[StackSetOperationStatusReason] - StatusDetails: Optional[StackSetOperationStatusDetails] + OperationId: ClientRequestToken | None + StackSetId: StackSetId | None + Action: StackSetOperationAction | None + Status: StackSetOperationStatus | None + OperationPreferences: StackSetOperationPreferences | None + RetainStacks: RetainStacksNullable | None + AdministrationRoleARN: RoleARN | None + ExecutionRoleName: ExecutionRoleName | None + CreationTimestamp: Timestamp | None + EndTimestamp: Timestamp | None + DeploymentTargets: DeploymentTargets | None + StackSetDriftDetectionDetails: StackSetDriftDetectionDetails | None + StatusReason: StackSetOperationStatusReason | None + StatusDetails: StackSetOperationStatusDetails | None class DescribeStackSetOperationOutput(TypedDict, total=False): - StackSetOperation: Optional[StackSetOperation] + StackSetOperation: StackSetOperation | None class StackSet(TypedDict, total=False): - StackSetName: Optional[StackSetName] - StackSetId: Optional[StackSetId] - Description: Optional[Description] - Status: Optional[StackSetStatus] - TemplateBody: Optional[TemplateBody] - Parameters: Optional[Parameters] - Capabilities: Optional[Capabilities] - Tags: Optional[Tags] - StackSetARN: Optional[StackSetARN] - AdministrationRoleARN: Optional[RoleARN] - ExecutionRoleName: Optional[ExecutionRoleName] - StackSetDriftDetectionDetails: Optional[StackSetDriftDetectionDetails] - AutoDeployment: Optional[AutoDeployment] - PermissionModel: Optional[PermissionModels] - OrganizationalUnitIds: Optional[OrganizationalUnitIdList] - ManagedExecution: Optional[ManagedExecution] - Regions: Optional[RegionList] + StackSetName: StackSetName | None + StackSetId: StackSetId | None + Description: Description | None + Status: StackSetStatus | None + TemplateBody: TemplateBody | None + Parameters: Parameters | None + Capabilities: Capabilities | None + Tags: Tags | None + StackSetARN: StackSetARN | None + AdministrationRoleARN: RoleARN | None + ExecutionRoleName: ExecutionRoleName | None + StackSetDriftDetectionDetails: StackSetDriftDetectionDetails | None + AutoDeployment: AutoDeployment | None + PermissionModel: PermissionModels | None + OrganizationalUnitIds: OrganizationalUnitIdList | None + ManagedExecution: ManagedExecution | None + Regions: RegionList | None class DescribeStackSetOutput(TypedDict, total=False): - StackSet: Optional[StackSet] + StackSet: StackSet | None class DescribeStacksInput(ServiceRequest): - StackName: Optional[StackName] - NextToken: Optional[NextToken] + StackName: StackName | None + NextToken: NextToken | None + + +class OperationEntry(TypedDict, total=False): + OperationType: OperationType | None + OperationId: OperationId | None + + +LastOperations = list[OperationEntry] class StackDriftInformation(TypedDict, total=False): StackDriftStatus: StackDriftStatus - LastCheckTimestamp: Optional[Timestamp] + LastCheckTimestamp: Timestamp | None class Output(TypedDict, total=False): - OutputKey: Optional[OutputKey] - OutputValue: Optional[OutputValue] - Description: Optional[Description] - ExportName: Optional[ExportName] + OutputKey: OutputKey | None + OutputValue: OutputValue | None + Description: Description | None + ExportName: ExportName | None -Outputs = List[Output] +Outputs = list[Output] class Stack(TypedDict, total=False): - StackId: Optional[StackId] + StackId: StackId | None StackName: StackName - ChangeSetId: Optional[ChangeSetId] - Description: Optional[Description] - Parameters: Optional[Parameters] + ChangeSetId: ChangeSetId | None + Description: Description | None + Parameters: Parameters | None CreationTime: CreationTime - DeletionTime: Optional[DeletionTime] - LastUpdatedTime: Optional[LastUpdatedTime] - RollbackConfiguration: Optional[RollbackConfiguration] + DeletionTime: DeletionTime | None + LastUpdatedTime: LastUpdatedTime | None + RollbackConfiguration: RollbackConfiguration | None StackStatus: StackStatus - StackStatusReason: Optional[StackStatusReason] - DisableRollback: Optional[DisableRollback] - NotificationARNs: Optional[NotificationARNs] - TimeoutInMinutes: Optional[TimeoutMinutes] - Capabilities: Optional[Capabilities] - Outputs: Optional[Outputs] - RoleARN: Optional[RoleARN] - Tags: Optional[Tags] - EnableTerminationProtection: Optional[EnableTerminationProtection] - ParentId: Optional[StackId] - RootId: Optional[StackId] - DriftInformation: Optional[StackDriftInformation] - RetainExceptOnCreate: Optional[RetainExceptOnCreate] - DeletionMode: Optional[DeletionMode] - DetailedStatus: Optional[DetailedStatus] - - -Stacks = List[Stack] + StackStatusReason: StackStatusReason | None + DisableRollback: DisableRollback | None + NotificationARNs: NotificationARNs | None + TimeoutInMinutes: TimeoutMinutes | None + Capabilities: Capabilities | None + Outputs: Outputs | None + RoleARN: RoleARN | None + Tags: Tags | None + EnableTerminationProtection: EnableTerminationProtection | None + ParentId: StackId | None + RootId: StackId | None + DriftInformation: StackDriftInformation | None + RetainExceptOnCreate: RetainExceptOnCreate | None + DeletionMode: DeletionMode | None + DetailedStatus: DetailedStatus | None + LastOperations: LastOperations | None + + +Stacks = list[Stack] class DescribeStacksOutput(TypedDict, total=False): - Stacks: Optional[Stacks] - NextToken: Optional[NextToken] + Stacks: Stacks | None + NextToken: NextToken | None class DescribeTypeInput(ServiceRequest): - Type: Optional[RegistryType] - TypeName: Optional[TypeName] - Arn: Optional[TypeArn] - VersionId: Optional[TypeVersionId] - PublisherId: Optional[PublisherId] - PublicVersionNumber: Optional[PublicVersionNumber] + Type: RegistryType | None + TypeName: TypeName | None + Arn: TypeArn | None + VersionId: TypeVersionId | None + PublisherId: PublisherId | None + PublicVersionNumber: PublicVersionNumber | None -SupportedMajorVersions = List[SupportedMajorVersion] +SupportedMajorVersions = list[SupportedMajorVersion] class RequiredActivatedType(TypedDict, total=False): - TypeNameAlias: Optional[TypeName] - OriginalTypeName: Optional[TypeName] - PublisherId: Optional[PublisherId] - SupportedMajorVersions: Optional[SupportedMajorVersions] + TypeNameAlias: TypeName | None + OriginalTypeName: TypeName | None + PublisherId: PublisherId | None + SupportedMajorVersions: SupportedMajorVersions | None -RequiredActivatedTypes = List[RequiredActivatedType] +RequiredActivatedTypes = list[RequiredActivatedType] class DescribeTypeOutput(TypedDict, total=False): - Arn: Optional[TypeArn] - Type: Optional[RegistryType] - TypeName: Optional[TypeName] - DefaultVersionId: Optional[TypeVersionId] - IsDefaultVersion: Optional[IsDefaultVersion] - TypeTestsStatus: Optional[TypeTestsStatus] - TypeTestsStatusDescription: Optional[TypeTestsStatusDescription] - Description: Optional[Description] - Schema: Optional[TypeSchema] - ProvisioningType: Optional[ProvisioningType] - DeprecatedStatus: Optional[DeprecatedStatus] - LoggingConfig: Optional[LoggingConfig] - RequiredActivatedTypes: Optional[RequiredActivatedTypes] - ExecutionRoleArn: Optional[RoleArn] - Visibility: Optional[Visibility] - SourceUrl: Optional[OptionalSecureUrl] - DocumentationUrl: Optional[OptionalSecureUrl] - LastUpdated: Optional[Timestamp] - TimeCreated: Optional[Timestamp] - ConfigurationSchema: Optional[ConfigurationSchema] - PublisherId: Optional[PublisherId] - OriginalTypeName: Optional[TypeName] - OriginalTypeArn: Optional[TypeArn] - PublicVersionNumber: Optional[PublicVersionNumber] - LatestPublicVersion: Optional[PublicVersionNumber] - IsActivated: Optional[IsActivated] - AutoUpdate: Optional[AutoUpdate] + Arn: TypeArn | None + Type: RegistryType | None + TypeName: TypeName | None + DefaultVersionId: TypeVersionId | None + IsDefaultVersion: IsDefaultVersion | None + TypeTestsStatus: TypeTestsStatus | None + TypeTestsStatusDescription: TypeTestsStatusDescription | None + Description: Description | None + Schema: TypeSchema | None + ProvisioningType: ProvisioningType | None + DeprecatedStatus: DeprecatedStatus | None + LoggingConfig: LoggingConfig | None + RequiredActivatedTypes: RequiredActivatedTypes | None + ExecutionRoleArn: RoleArn | None + Visibility: Visibility | None + SourceUrl: OptionalSecureUrl | None + DocumentationUrl: OptionalSecureUrl | None + LastUpdated: Timestamp | None + TimeCreated: Timestamp | None + ConfigurationSchema: ConfigurationSchema | None + PublisherId: PublisherId | None + OriginalTypeName: TypeName | None + OriginalTypeArn: TypeArn | None + PublicVersionNumber: PublicVersionNumber | None + LatestPublicVersion: PublicVersionNumber | None + IsActivated: IsActivated | None + AutoUpdate: AutoUpdate | None class DescribeTypeRegistrationInput(ServiceRequest): @@ -1956,18 +2139,18 @@ class DescribeTypeRegistrationInput(ServiceRequest): class DescribeTypeRegistrationOutput(TypedDict, total=False): - ProgressStatus: Optional[RegistrationStatus] - Description: Optional[Description] - TypeArn: Optional[TypeArn] - TypeVersionArn: Optional[TypeArn] + ProgressStatus: RegistrationStatus | None + Description: Description | None + TypeArn: TypeArn | None + TypeVersionArn: TypeArn | None -LogicalResourceIds = List[LogicalResourceId] +LogicalResourceIds = list[LogicalResourceId] class DetectStackDriftInput(ServiceRequest): StackName: StackNameOrId - LogicalResourceIds: Optional[LogicalResourceIds] + LogicalResourceIds: LogicalResourceIds | None class DetectStackDriftOutput(TypedDict, total=False): @@ -1985,31 +2168,31 @@ class DetectStackResourceDriftOutput(TypedDict, total=False): class DetectStackSetDriftInput(ServiceRequest): StackSetName: StackSetNameOrId - OperationPreferences: Optional[StackSetOperationPreferences] - OperationId: Optional[ClientRequestToken] - CallAs: Optional[CallAs] + OperationPreferences: StackSetOperationPreferences | None + OperationId: ClientRequestToken | None + CallAs: CallAs | None class DetectStackSetDriftOutput(TypedDict, total=False): - OperationId: Optional[ClientRequestToken] + OperationId: ClientRequestToken | None class EstimateTemplateCostInput(ServiceRequest): - TemplateBody: Optional[TemplateBody] - TemplateURL: Optional[TemplateURL] - Parameters: Optional[Parameters] + TemplateBody: TemplateBody | None + TemplateURL: TemplateURL | None + Parameters: Parameters | None class EstimateTemplateCostOutput(TypedDict, total=False): - Url: Optional[Url] + Url: Url | None class ExecuteChangeSetInput(ServiceRequest): ChangeSetName: ChangeSetNameOrId - StackName: Optional[StackNameOrId] - ClientRequestToken: Optional[ClientRequestToken] - DisableRollback: Optional[DisableRollback] - RetainExceptOnCreate: Optional[RetainExceptOnCreate] + StackName: StackNameOrId | None + ClientRequestToken: ClientRequestToken | None + DisableRollback: DisableRollback | None + RetainExceptOnCreate: RetainExceptOnCreate | None class ExecuteChangeSetOutput(TypedDict, total=False): @@ -2021,22 +2204,49 @@ class ExecuteStackRefactorInput(ServiceRequest): class Export(TypedDict, total=False): - ExportingStackId: Optional[StackId] - Name: Optional[ExportName] - Value: Optional[ExportValue] + ExportingStackId: StackId | None + Name: ExportName | None + Value: ExportValue | None -Exports = List[Export] +Exports = list[Export] class GetGeneratedTemplateInput(ServiceRequest): - Format: Optional[TemplateFormat] + Format: TemplateFormat | None GeneratedTemplateName: GeneratedTemplateName class GetGeneratedTemplateOutput(TypedDict, total=False): - Status: Optional[GeneratedTemplateStatus] - TemplateBody: Optional[TemplateBody] + Status: GeneratedTemplateStatus | None + TemplateBody: TemplateBody | None + + +class GetHookResultInput(ServiceRequest): + HookResultId: HookInvocationId | None + + +class HookTarget(TypedDict, total=False): + TargetType: HookTargetType + TargetTypeName: HookTargetTypeName + TargetId: HookTargetId + Action: HookTargetAction + + +class GetHookResultOutput(TypedDict, total=False): + HookResultId: HookInvocationId | None + InvocationPoint: HookInvocationPoint | None + FailureMode: HookFailureMode | None + TypeName: HookTypeName | None + OriginalTypeName: HookTypeName | None + TypeVersionId: HookTypeVersionId | None + TypeConfigurationVersionId: HookTypeConfigurationVersionId | None + TypeArn: HookTypeArn | None + Status: HookStatus | None + HookStatusReason: HookStatusReason | None + InvokedAt: Timestamp | None + Target: HookTarget | None + Annotations: AnnotationList | None class GetStackPolicyInput(ServiceRequest): @@ -2044,188 +2254,188 @@ class GetStackPolicyInput(ServiceRequest): class GetStackPolicyOutput(TypedDict, total=False): - StackPolicyBody: Optional[StackPolicyBody] + StackPolicyBody: StackPolicyBody | None class GetTemplateInput(ServiceRequest): - StackName: Optional[StackName] - ChangeSetName: Optional[ChangeSetNameOrId] - TemplateStage: Optional[TemplateStage] + StackName: StackName | None + ChangeSetName: ChangeSetNameOrId | None + TemplateStage: TemplateStage | None -StageList = List[TemplateStage] +StageList = list[TemplateStage] class GetTemplateOutput(TypedDict, total=False): - TemplateBody: Optional[TemplateBody] - StagesAvailable: Optional[StageList] + TemplateBody: TemplateBody | None + StagesAvailable: StageList | None class TemplateSummaryConfig(TypedDict, total=False): - TreatUnrecognizedResourceTypesAsWarnings: Optional[TreatUnrecognizedResourceTypesAsWarnings] + TreatUnrecognizedResourceTypesAsWarnings: TreatUnrecognizedResourceTypesAsWarnings | None class GetTemplateSummaryInput(ServiceRequest): - TemplateBody: Optional[TemplateBody] - TemplateURL: Optional[TemplateURL] - StackName: Optional[StackNameOrId] - StackSetName: Optional[StackSetNameOrId] - CallAs: Optional[CallAs] - TemplateSummaryConfig: Optional[TemplateSummaryConfig] + TemplateBody: TemplateBody | None + TemplateURL: TemplateURL | None + StackName: StackNameOrId | None + StackSetName: StackSetNameOrId | None + CallAs: CallAs | None + TemplateSummaryConfig: TemplateSummaryConfig | None class Warnings(TypedDict, total=False): - UnrecognizedResourceTypes: Optional[ResourceTypes] + UnrecognizedResourceTypes: ResourceTypes | None -ResourceIdentifiers = List[ResourceIdentifierPropertyKey] +ResourceIdentifiers = list[ResourceIdentifierPropertyKey] class ResourceIdentifierSummary(TypedDict, total=False): - ResourceType: Optional[ResourceType] - LogicalResourceIds: Optional[LogicalResourceIds] - ResourceIdentifiers: Optional[ResourceIdentifiers] + ResourceType: ResourceType | None + LogicalResourceIds: LogicalResourceIds | None + ResourceIdentifiers: ResourceIdentifiers | None -ResourceIdentifierSummaries = List[ResourceIdentifierSummary] -TransformsList = List[TransformName] +ResourceIdentifierSummaries = list[ResourceIdentifierSummary] +TransformsList = list[TransformName] class ParameterConstraints(TypedDict, total=False): - AllowedValues: Optional[AllowedValues] + AllowedValues: AllowedValues | None class ParameterDeclaration(TypedDict, total=False): - ParameterKey: Optional[ParameterKey] - DefaultValue: Optional[ParameterValue] - ParameterType: Optional[ParameterType] - NoEcho: Optional[NoEcho] - Description: Optional[Description] - ParameterConstraints: Optional[ParameterConstraints] + ParameterKey: ParameterKey | None + DefaultValue: ParameterValue | None + ParameterType: ParameterType | None + NoEcho: NoEcho | None + Description: Description | None + ParameterConstraints: ParameterConstraints | None -ParameterDeclarations = List[ParameterDeclaration] +ParameterDeclarations = list[ParameterDeclaration] class GetTemplateSummaryOutput(TypedDict, total=False): - Parameters: Optional[ParameterDeclarations] - Description: Optional[Description] - Capabilities: Optional[Capabilities] - CapabilitiesReason: Optional[CapabilitiesReason] - ResourceTypes: Optional[ResourceTypes] - Version: Optional[Version] - Metadata: Optional[Metadata] - DeclaredTransforms: Optional[TransformsList] - ResourceIdentifierSummaries: Optional[ResourceIdentifierSummaries] - Warnings: Optional[Warnings] + Parameters: ParameterDeclarations | None + Description: Description | None + Capabilities: Capabilities | None + CapabilitiesReason: CapabilitiesReason | None + ResourceTypes: ResourceTypes | None + Version: Version | None + Metadata: Metadata | None + DeclaredTransforms: TransformsList | None + ResourceIdentifierSummaries: ResourceIdentifierSummaries | None + Warnings: Warnings | None class HookResultSummary(TypedDict, total=False): - HookResultId: Optional[HookInvocationId] - InvocationPoint: Optional[HookInvocationPoint] - FailureMode: Optional[HookFailureMode] - TypeName: Optional[HookTypeName] - TypeVersionId: Optional[HookTypeVersionId] - TypeConfigurationVersionId: Optional[HookTypeConfigurationVersionId] - Status: Optional[HookStatus] - HookStatusReason: Optional[HookStatusReason] - InvokedAt: Optional[Timestamp] - TargetType: Optional[ListHookResultsTargetType] - TargetId: Optional[HookResultId] - TypeArn: Optional[HookTypeArn] - HookExecutionTarget: Optional[HookResultId] + HookResultId: HookInvocationId | None + InvocationPoint: HookInvocationPoint | None + FailureMode: HookFailureMode | None + TypeName: HookTypeName | None + TypeVersionId: HookTypeVersionId | None + TypeConfigurationVersionId: HookTypeConfigurationVersionId | None + Status: HookStatus | None + HookStatusReason: HookStatusReason | None + InvokedAt: Timestamp | None + TargetType: ListHookResultsTargetType | None + TargetId: HookResultId | None + TypeArn: HookTypeArn | None + HookExecutionTarget: HookResultId | None -HookResultSummaries = List[HookResultSummary] -StackIdList = List[StackId] +HookResultSummaries = list[HookResultSummary] +StackIdList = list[StackId] class ImportStacksToStackSetInput(ServiceRequest): StackSetName: StackSetNameOrId - StackIds: Optional[StackIdList] - StackIdsUrl: Optional[StackIdsUrl] - OrganizationalUnitIds: Optional[OrganizationalUnitIdList] - OperationPreferences: Optional[StackSetOperationPreferences] - OperationId: Optional[ClientRequestToken] - CallAs: Optional[CallAs] + StackIds: StackIdList | None + StackIdsUrl: StackIdsUrl | None + OrganizationalUnitIds: OrganizationalUnitIdList | None + OperationPreferences: StackSetOperationPreferences | None + OperationId: ClientRequestToken | None + CallAs: CallAs | None class ImportStacksToStackSetOutput(TypedDict, total=False): - OperationId: Optional[ClientRequestToken] + OperationId: ClientRequestToken | None -Imports = List[StackName] -JazzLogicalResourceIds = List[LogicalResourceId] -JazzResourceIdentifierProperties = Dict[ +Imports = list[StackName] +JazzLogicalResourceIds = list[LogicalResourceId] +JazzResourceIdentifierProperties = dict[ JazzResourceIdentifierPropertyKey, JazzResourceIdentifierPropertyValue ] class ListChangeSetsInput(ServiceRequest): StackName: StackNameOrId - NextToken: Optional[NextToken] + NextToken: NextToken | None class ListChangeSetsOutput(TypedDict, total=False): - Summaries: Optional[ChangeSetSummaries] - NextToken: Optional[NextToken] + Summaries: ChangeSetSummaries | None + NextToken: NextToken | None class ListExportsInput(ServiceRequest): - NextToken: Optional[NextToken] + NextToken: NextToken | None class ListExportsOutput(TypedDict, total=False): - Exports: Optional[Exports] - NextToken: Optional[NextToken] + Exports: Exports | None + NextToken: NextToken | None class ListGeneratedTemplatesInput(ServiceRequest): - NextToken: Optional[NextToken] - MaxResults: Optional[MaxResults] + NextToken: NextToken | None + MaxResults: MaxResults | None class TemplateSummary(TypedDict, total=False): - GeneratedTemplateId: Optional[GeneratedTemplateId] - GeneratedTemplateName: Optional[GeneratedTemplateName] - Status: Optional[GeneratedTemplateStatus] - StatusReason: Optional[TemplateStatusReason] - CreationTime: Optional[CreationTime] - LastUpdatedTime: Optional[LastUpdatedTime] - NumberOfResources: Optional[NumberOfResources] + GeneratedTemplateId: GeneratedTemplateId | None + GeneratedTemplateName: GeneratedTemplateName | None + Status: GeneratedTemplateStatus | None + StatusReason: TemplateStatusReason | None + CreationTime: CreationTime | None + LastUpdatedTime: LastUpdatedTime | None + NumberOfResources: NumberOfResources | None -TemplateSummaries = List[TemplateSummary] +TemplateSummaries = list[TemplateSummary] class ListGeneratedTemplatesOutput(TypedDict, total=False): - Summaries: Optional[TemplateSummaries] - NextToken: Optional[NextToken] + Summaries: TemplateSummaries | None + NextToken: NextToken | None class ListHookResultsInput(ServiceRequest): - TargetType: Optional[ListHookResultsTargetType] - TargetId: Optional[HookResultId] - TypeArn: Optional[HookTypeArn] - Status: Optional[HookStatus] - NextToken: Optional[NextToken] + TargetType: ListHookResultsTargetType | None + TargetId: HookResultId | None + TypeArn: HookTypeArn | None + Status: HookStatus | None + NextToken: NextToken | None class ListHookResultsOutput(TypedDict, total=False): - TargetType: Optional[ListHookResultsTargetType] - TargetId: Optional[HookResultId] - HookResults: Optional[HookResultSummaries] - NextToken: Optional[NextToken] + TargetType: ListHookResultsTargetType | None + TargetId: HookResultId | None + HookResults: HookResultSummaries | None + NextToken: NextToken | None class ListImportsInput(ServiceRequest): ExportName: ExportName - NextToken: Optional[NextToken] + NextToken: NextToken | None class ListImportsOutput(TypedDict, total=False): - Imports: Optional[Imports] - NextToken: Optional[NextToken] + Imports: Imports | None + NextToken: NextToken | None class ScannedResourceIdentifier(TypedDict, total=False): @@ -2233,475 +2443,476 @@ class ScannedResourceIdentifier(TypedDict, total=False): ResourceIdentifier: JazzResourceIdentifierProperties -ScannedResourceIdentifiers = List[ScannedResourceIdentifier] +ScannedResourceIdentifiers = list[ScannedResourceIdentifier] class ListResourceScanRelatedResourcesInput(ServiceRequest): ResourceScanId: ResourceScanId Resources: ScannedResourceIdentifiers - NextToken: Optional[NextToken] - MaxResults: Optional[BoxedMaxResults] + NextToken: NextToken | None + MaxResults: BoxedMaxResults | None class ScannedResource(TypedDict, total=False): - ResourceType: Optional[ResourceType] - ResourceIdentifier: Optional[JazzResourceIdentifierProperties] - ManagedByStack: Optional[ManagedByStack] + ResourceType: ResourceType | None + ResourceIdentifier: JazzResourceIdentifierProperties | None + ManagedByStack: ManagedByStack | None -RelatedResources = List[ScannedResource] +RelatedResources = list[ScannedResource] class ListResourceScanRelatedResourcesOutput(TypedDict, total=False): - RelatedResources: Optional[RelatedResources] - NextToken: Optional[NextToken] + RelatedResources: RelatedResources | None + NextToken: NextToken | None class ListResourceScanResourcesInput(ServiceRequest): ResourceScanId: ResourceScanId - ResourceIdentifier: Optional[ResourceIdentifier] - ResourceTypePrefix: Optional[ResourceTypePrefix] - TagKey: Optional[TagKey] - TagValue: Optional[TagValue] - NextToken: Optional[NextToken] - MaxResults: Optional[ResourceScannerMaxResults] + ResourceIdentifier: ResourceIdentifier | None + ResourceTypePrefix: ResourceTypePrefix | None + TagKey: TagKey | None + TagValue: TagValue | None + NextToken: NextToken | None + MaxResults: ResourceScannerMaxResults | None -ScannedResources = List[ScannedResource] +ScannedResources = list[ScannedResource] class ListResourceScanResourcesOutput(TypedDict, total=False): - Resources: Optional[ScannedResources] - NextToken: Optional[NextToken] + Resources: ScannedResources | None + NextToken: NextToken | None class ListResourceScansInput(ServiceRequest): - NextToken: Optional[NextToken] - MaxResults: Optional[ResourceScannerMaxResults] - ScanTypeFilter: Optional[ScanType] + NextToken: NextToken | None + MaxResults: ResourceScannerMaxResults | None + ScanTypeFilter: ScanType | None class ResourceScanSummary(TypedDict, total=False): - ResourceScanId: Optional[ResourceScanId] - Status: Optional[ResourceScanStatus] - StatusReason: Optional[ResourceScanStatusReason] - StartTime: Optional[Timestamp] - EndTime: Optional[Timestamp] - PercentageCompleted: Optional[PercentageCompleted] - ScanType: Optional[ScanType] + ResourceScanId: ResourceScanId | None + Status: ResourceScanStatus | None + StatusReason: ResourceScanStatusReason | None + StartTime: Timestamp | None + EndTime: Timestamp | None + PercentageCompleted: PercentageCompleted | None + ScanType: ScanType | None -ResourceScanSummaries = List[ResourceScanSummary] +ResourceScanSummaries = list[ResourceScanSummary] class ListResourceScansOutput(TypedDict, total=False): - ResourceScanSummaries: Optional[ResourceScanSummaries] - NextToken: Optional[NextToken] + ResourceScanSummaries: ResourceScanSummaries | None + NextToken: NextToken | None class ListStackInstanceResourceDriftsInput(ServiceRequest): StackSetName: StackSetNameOrId - NextToken: Optional[NextToken] - MaxResults: Optional[MaxResults] - StackInstanceResourceDriftStatuses: Optional[StackResourceDriftStatusFilters] + NextToken: NextToken | None + MaxResults: MaxResults | None + StackInstanceResourceDriftStatuses: StackResourceDriftStatusFilters | None StackInstanceAccount: Account StackInstanceRegion: Region OperationId: ClientRequestToken - CallAs: Optional[CallAs] + CallAs: CallAs | None class StackInstanceResourceDriftsSummary(TypedDict, total=False): StackId: StackId LogicalResourceId: LogicalResourceId - PhysicalResourceId: Optional[PhysicalResourceId] - PhysicalResourceIdContext: Optional[PhysicalResourceIdContext] + PhysicalResourceId: PhysicalResourceId | None + PhysicalResourceIdContext: PhysicalResourceIdContext | None ResourceType: ResourceType - PropertyDifferences: Optional[PropertyDifferences] + PropertyDifferences: PropertyDifferences | None StackResourceDriftStatus: StackResourceDriftStatus Timestamp: Timestamp -StackInstanceResourceDriftsSummaries = List[StackInstanceResourceDriftsSummary] +StackInstanceResourceDriftsSummaries = list[StackInstanceResourceDriftsSummary] class ListStackInstanceResourceDriftsOutput(TypedDict, total=False): - Summaries: Optional[StackInstanceResourceDriftsSummaries] - NextToken: Optional[NextToken] + Summaries: StackInstanceResourceDriftsSummaries | None + NextToken: NextToken | None class StackInstanceFilter(TypedDict, total=False): - Name: Optional[StackInstanceFilterName] - Values: Optional[StackInstanceFilterValues] + Name: StackInstanceFilterName | None + Values: StackInstanceFilterValues | None -StackInstanceFilters = List[StackInstanceFilter] +StackInstanceFilters = list[StackInstanceFilter] class ListStackInstancesInput(ServiceRequest): StackSetName: StackSetName - NextToken: Optional[NextToken] - MaxResults: Optional[MaxResults] - Filters: Optional[StackInstanceFilters] - StackInstanceAccount: Optional[Account] - StackInstanceRegion: Optional[Region] - CallAs: Optional[CallAs] + NextToken: NextToken | None + MaxResults: MaxResults | None + Filters: StackInstanceFilters | None + StackInstanceAccount: Account | None + StackInstanceRegion: Region | None + CallAs: CallAs | None class StackInstanceSummary(TypedDict, total=False): - StackSetId: Optional[StackSetId] - Region: Optional[Region] - Account: Optional[Account] - StackId: Optional[StackId] - Status: Optional[StackInstanceStatus] - StatusReason: Optional[Reason] - StackInstanceStatus: Optional[StackInstanceComprehensiveStatus] - OrganizationalUnitId: Optional[OrganizationalUnitId] - DriftStatus: Optional[StackDriftStatus] - LastDriftCheckTimestamp: Optional[Timestamp] - LastOperationId: Optional[ClientRequestToken] + StackSetId: StackSetId | None + Region: Region | None + Account: Account | None + StackId: StackId | None + Status: StackInstanceStatus | None + StatusReason: Reason | None + StackInstanceStatus: StackInstanceComprehensiveStatus | None + OrganizationalUnitId: OrganizationalUnitId | None + DriftStatus: StackDriftStatus | None + LastDriftCheckTimestamp: Timestamp | None + LastOperationId: ClientRequestToken | None -StackInstanceSummaries = List[StackInstanceSummary] +StackInstanceSummaries = list[StackInstanceSummary] class ListStackInstancesOutput(TypedDict, total=False): - Summaries: Optional[StackInstanceSummaries] - NextToken: Optional[NextToken] + Summaries: StackInstanceSummaries | None + NextToken: NextToken | None class ListStackRefactorActionsInput(ServiceRequest): StackRefactorId: StackRefactorId - NextToken: Optional[NextToken] - MaxResults: Optional[MaxResults] + NextToken: NextToken | None + MaxResults: MaxResults | None -StackRefactorUntagResources = List[TagKey] -StackRefactorTagResources = List[Tag] +StackRefactorUntagResources = list[TagKey] +StackRefactorTagResources = list[Tag] class StackRefactorAction(TypedDict, total=False): - Action: Optional[StackRefactorActionType] - Entity: Optional[StackRefactorActionEntity] - PhysicalResourceId: Optional[PhysicalResourceId] - ResourceIdentifier: Optional[StackRefactorResourceIdentifier] - Description: Optional[Description] - Detection: Optional[StackRefactorDetection] - DetectionReason: Optional[DetectionReason] - TagResources: Optional[StackRefactorTagResources] - UntagResources: Optional[StackRefactorUntagResources] - ResourceMapping: Optional[ResourceMapping] + Action: StackRefactorActionType | None + Entity: StackRefactorActionEntity | None + PhysicalResourceId: PhysicalResourceId | None + ResourceIdentifier: StackRefactorResourceIdentifier | None + Description: Description | None + Detection: StackRefactorDetection | None + DetectionReason: DetectionReason | None + TagResources: StackRefactorTagResources | None + UntagResources: StackRefactorUntagResources | None + ResourceMapping: ResourceMapping | None -StackRefactorActions = List[StackRefactorAction] +StackRefactorActions = list[StackRefactorAction] class ListStackRefactorActionsOutput(TypedDict, total=False): StackRefactorActions: StackRefactorActions - NextToken: Optional[NextToken] + NextToken: NextToken | None -StackRefactorExecutionStatusFilter = List[StackRefactorExecutionStatus] +StackRefactorExecutionStatusFilter = list[StackRefactorExecutionStatus] class ListStackRefactorsInput(ServiceRequest): - ExecutionStatusFilter: Optional[StackRefactorExecutionStatusFilter] - NextToken: Optional[NextToken] - MaxResults: Optional[MaxResults] + ExecutionStatusFilter: StackRefactorExecutionStatusFilter | None + NextToken: NextToken | None + MaxResults: MaxResults | None class StackRefactorSummary(TypedDict, total=False): - StackRefactorId: Optional[StackRefactorId] - Description: Optional[Description] - ExecutionStatus: Optional[StackRefactorExecutionStatus] - ExecutionStatusReason: Optional[ExecutionStatusReason] - Status: Optional[StackRefactorStatus] - StatusReason: Optional[StackRefactorStatusReason] + StackRefactorId: StackRefactorId | None + Description: Description | None + ExecutionStatus: StackRefactorExecutionStatus | None + ExecutionStatusReason: ExecutionStatusReason | None + Status: StackRefactorStatus | None + StatusReason: StackRefactorStatusReason | None -StackRefactorSummaries = List[StackRefactorSummary] +StackRefactorSummaries = list[StackRefactorSummary] class ListStackRefactorsOutput(TypedDict, total=False): StackRefactorSummaries: StackRefactorSummaries - NextToken: Optional[NextToken] + NextToken: NextToken | None class ListStackResourcesInput(ServiceRequest): StackName: StackName - NextToken: Optional[NextToken] + NextToken: NextToken | None class StackResourceDriftInformationSummary(TypedDict, total=False): StackResourceDriftStatus: StackResourceDriftStatus - LastCheckTimestamp: Optional[Timestamp] + LastCheckTimestamp: Timestamp | None class StackResourceSummary(TypedDict, total=False): LogicalResourceId: LogicalResourceId - PhysicalResourceId: Optional[PhysicalResourceId] + PhysicalResourceId: PhysicalResourceId | None ResourceType: ResourceType LastUpdatedTimestamp: Timestamp ResourceStatus: ResourceStatus - ResourceStatusReason: Optional[ResourceStatusReason] - DriftInformation: Optional[StackResourceDriftInformationSummary] - ModuleInfo: Optional[ModuleInfo] + ResourceStatusReason: ResourceStatusReason | None + DriftInformation: StackResourceDriftInformationSummary | None + ModuleInfo: ModuleInfo | None -StackResourceSummaries = List[StackResourceSummary] +StackResourceSummaries = list[StackResourceSummary] class ListStackResourcesOutput(TypedDict, total=False): - StackResourceSummaries: Optional[StackResourceSummaries] - NextToken: Optional[NextToken] + StackResourceSummaries: StackResourceSummaries | None + NextToken: NextToken | None class ListStackSetAutoDeploymentTargetsInput(ServiceRequest): StackSetName: StackSetNameOrId - NextToken: Optional[NextToken] - MaxResults: Optional[MaxResults] - CallAs: Optional[CallAs] + NextToken: NextToken | None + MaxResults: MaxResults | None + CallAs: CallAs | None class StackSetAutoDeploymentTargetSummary(TypedDict, total=False): - OrganizationalUnitId: Optional[OrganizationalUnitId] - Regions: Optional[RegionList] + OrganizationalUnitId: OrganizationalUnitId | None + Regions: RegionList | None -StackSetAutoDeploymentTargetSummaries = List[StackSetAutoDeploymentTargetSummary] +StackSetAutoDeploymentTargetSummaries = list[StackSetAutoDeploymentTargetSummary] class ListStackSetAutoDeploymentTargetsOutput(TypedDict, total=False): - Summaries: Optional[StackSetAutoDeploymentTargetSummaries] - NextToken: Optional[NextToken] + Summaries: StackSetAutoDeploymentTargetSummaries | None + NextToken: NextToken | None class OperationResultFilter(TypedDict, total=False): - Name: Optional[OperationResultFilterName] - Values: Optional[OperationResultFilterValues] + Name: OperationResultFilterName | None + Values: OperationResultFilterValues | None -OperationResultFilters = List[OperationResultFilter] +OperationResultFilters = list[OperationResultFilter] class ListStackSetOperationResultsInput(ServiceRequest): StackSetName: StackSetName OperationId: ClientRequestToken - NextToken: Optional[NextToken] - MaxResults: Optional[MaxResults] - CallAs: Optional[CallAs] - Filters: Optional[OperationResultFilters] + NextToken: NextToken | None + MaxResults: MaxResults | None + CallAs: CallAs | None + Filters: OperationResultFilters | None class StackSetOperationResultSummary(TypedDict, total=False): - Account: Optional[Account] - Region: Optional[Region] - Status: Optional[StackSetOperationResultStatus] - StatusReason: Optional[Reason] - AccountGateResult: Optional[AccountGateResult] - OrganizationalUnitId: Optional[OrganizationalUnitId] + Account: Account | None + Region: Region | None + Status: StackSetOperationResultStatus | None + StatusReason: Reason | None + AccountGateResult: AccountGateResult | None + OrganizationalUnitId: OrganizationalUnitId | None -StackSetOperationResultSummaries = List[StackSetOperationResultSummary] +StackSetOperationResultSummaries = list[StackSetOperationResultSummary] class ListStackSetOperationResultsOutput(TypedDict, total=False): - Summaries: Optional[StackSetOperationResultSummaries] - NextToken: Optional[NextToken] + Summaries: StackSetOperationResultSummaries | None + NextToken: NextToken | None class ListStackSetOperationsInput(ServiceRequest): StackSetName: StackSetName - NextToken: Optional[NextToken] - MaxResults: Optional[MaxResults] - CallAs: Optional[CallAs] + NextToken: NextToken | None + MaxResults: MaxResults | None + CallAs: CallAs | None class StackSetOperationSummary(TypedDict, total=False): - OperationId: Optional[ClientRequestToken] - Action: Optional[StackSetOperationAction] - Status: Optional[StackSetOperationStatus] - CreationTimestamp: Optional[Timestamp] - EndTimestamp: Optional[Timestamp] - StatusReason: Optional[StackSetOperationStatusReason] - StatusDetails: Optional[StackSetOperationStatusDetails] - OperationPreferences: Optional[StackSetOperationPreferences] + OperationId: ClientRequestToken | None + Action: StackSetOperationAction | None + Status: StackSetOperationStatus | None + CreationTimestamp: Timestamp | None + EndTimestamp: Timestamp | None + StatusReason: StackSetOperationStatusReason | None + StatusDetails: StackSetOperationStatusDetails | None + OperationPreferences: StackSetOperationPreferences | None -StackSetOperationSummaries = List[StackSetOperationSummary] +StackSetOperationSummaries = list[StackSetOperationSummary] class ListStackSetOperationsOutput(TypedDict, total=False): - Summaries: Optional[StackSetOperationSummaries] - NextToken: Optional[NextToken] + Summaries: StackSetOperationSummaries | None + NextToken: NextToken | None class ListStackSetsInput(ServiceRequest): - NextToken: Optional[NextToken] - MaxResults: Optional[MaxResults] - Status: Optional[StackSetStatus] - CallAs: Optional[CallAs] + NextToken: NextToken | None + MaxResults: MaxResults | None + Status: StackSetStatus | None + CallAs: CallAs | None class StackSetSummary(TypedDict, total=False): - StackSetName: Optional[StackSetName] - StackSetId: Optional[StackSetId] - Description: Optional[Description] - Status: Optional[StackSetStatus] - AutoDeployment: Optional[AutoDeployment] - PermissionModel: Optional[PermissionModels] - DriftStatus: Optional[StackDriftStatus] - LastDriftCheckTimestamp: Optional[Timestamp] - ManagedExecution: Optional[ManagedExecution] + StackSetName: StackSetName | None + StackSetId: StackSetId | None + Description: Description | None + Status: StackSetStatus | None + AutoDeployment: AutoDeployment | None + PermissionModel: PermissionModels | None + DriftStatus: StackDriftStatus | None + LastDriftCheckTimestamp: Timestamp | None + ManagedExecution: ManagedExecution | None -StackSetSummaries = List[StackSetSummary] +StackSetSummaries = list[StackSetSummary] class ListStackSetsOutput(TypedDict, total=False): - Summaries: Optional[StackSetSummaries] - NextToken: Optional[NextToken] + Summaries: StackSetSummaries | None + NextToken: NextToken | None -StackStatusFilter = List[StackStatus] +StackStatusFilter = list[StackStatus] class ListStacksInput(ServiceRequest): - NextToken: Optional[NextToken] - StackStatusFilter: Optional[StackStatusFilter] + NextToken: NextToken | None + StackStatusFilter: StackStatusFilter | None class StackDriftInformationSummary(TypedDict, total=False): StackDriftStatus: StackDriftStatus - LastCheckTimestamp: Optional[Timestamp] + LastCheckTimestamp: Timestamp | None class StackSummary(TypedDict, total=False): - StackId: Optional[StackId] + StackId: StackId | None StackName: StackName - TemplateDescription: Optional[TemplateDescription] + TemplateDescription: TemplateDescription | None CreationTime: CreationTime - LastUpdatedTime: Optional[LastUpdatedTime] - DeletionTime: Optional[DeletionTime] + LastUpdatedTime: LastUpdatedTime | None + DeletionTime: DeletionTime | None StackStatus: StackStatus - StackStatusReason: Optional[StackStatusReason] - ParentId: Optional[StackId] - RootId: Optional[StackId] - DriftInformation: Optional[StackDriftInformationSummary] + StackStatusReason: StackStatusReason | None + ParentId: StackId | None + RootId: StackId | None + DriftInformation: StackDriftInformationSummary | None + LastOperations: LastOperations | None -StackSummaries = List[StackSummary] +StackSummaries = list[StackSummary] class ListStacksOutput(TypedDict, total=False): - StackSummaries: Optional[StackSummaries] - NextToken: Optional[NextToken] + StackSummaries: StackSummaries | None + NextToken: NextToken | None class ListTypeRegistrationsInput(ServiceRequest): - Type: Optional[RegistryType] - TypeName: Optional[TypeName] - TypeArn: Optional[TypeArn] - RegistrationStatusFilter: Optional[RegistrationStatus] - MaxResults: Optional[MaxResults] - NextToken: Optional[NextToken] + Type: RegistryType | None + TypeName: TypeName | None + TypeArn: TypeArn | None + RegistrationStatusFilter: RegistrationStatus | None + MaxResults: MaxResults | None + NextToken: NextToken | None -RegistrationTokenList = List[RegistrationToken] +RegistrationTokenList = list[RegistrationToken] class ListTypeRegistrationsOutput(TypedDict, total=False): - RegistrationTokenList: Optional[RegistrationTokenList] - NextToken: Optional[NextToken] + RegistrationTokenList: RegistrationTokenList | None + NextToken: NextToken | None class ListTypeVersionsInput(ServiceRequest): - Type: Optional[RegistryType] - TypeName: Optional[TypeName] - Arn: Optional[TypeArn] - MaxResults: Optional[MaxResults] - NextToken: Optional[NextToken] - DeprecatedStatus: Optional[DeprecatedStatus] - PublisherId: Optional[PublisherId] + Type: RegistryType | None + TypeName: TypeName | None + Arn: TypeArn | None + MaxResults: MaxResults | None + NextToken: NextToken | None + DeprecatedStatus: DeprecatedStatus | None + PublisherId: PublisherId | None class TypeVersionSummary(TypedDict, total=False): - Type: Optional[RegistryType] - TypeName: Optional[TypeName] - VersionId: Optional[TypeVersionId] - IsDefaultVersion: Optional[IsDefaultVersion] - Arn: Optional[TypeArn] - TimeCreated: Optional[Timestamp] - Description: Optional[Description] - PublicVersionNumber: Optional[PublicVersionNumber] + Type: RegistryType | None + TypeName: TypeName | None + VersionId: TypeVersionId | None + IsDefaultVersion: IsDefaultVersion | None + Arn: TypeArn | None + TimeCreated: Timestamp | None + Description: Description | None + PublicVersionNumber: PublicVersionNumber | None -TypeVersionSummaries = List[TypeVersionSummary] +TypeVersionSummaries = list[TypeVersionSummary] class ListTypeVersionsOutput(TypedDict, total=False): - TypeVersionSummaries: Optional[TypeVersionSummaries] - NextToken: Optional[NextToken] + TypeVersionSummaries: TypeVersionSummaries | None + NextToken: NextToken | None class TypeFilters(TypedDict, total=False): - Category: Optional[Category] - PublisherId: Optional[PublisherId] - TypeNamePrefix: Optional[TypeNamePrefix] + Category: Category | None + PublisherId: PublisherId | None + TypeNamePrefix: TypeNamePrefix | None class ListTypesInput(ServiceRequest): - Visibility: Optional[Visibility] - ProvisioningType: Optional[ProvisioningType] - DeprecatedStatus: Optional[DeprecatedStatus] - Type: Optional[RegistryType] - Filters: Optional[TypeFilters] - MaxResults: Optional[MaxResults] - NextToken: Optional[NextToken] + Visibility: Visibility | None + ProvisioningType: ProvisioningType | None + DeprecatedStatus: DeprecatedStatus | None + Type: RegistryType | None + Filters: TypeFilters | None + MaxResults: MaxResults | None + NextToken: NextToken | None class TypeSummary(TypedDict, total=False): - Type: Optional[RegistryType] - TypeName: Optional[TypeName] - DefaultVersionId: Optional[TypeVersionId] - TypeArn: Optional[TypeArn] - LastUpdated: Optional[Timestamp] - Description: Optional[Description] - PublisherId: Optional[PublisherId] - OriginalTypeName: Optional[TypeName] - PublicVersionNumber: Optional[PublicVersionNumber] - LatestPublicVersion: Optional[PublicVersionNumber] - PublisherIdentity: Optional[IdentityProvider] - PublisherName: Optional[PublisherName] - IsActivated: Optional[IsActivated] + Type: RegistryType | None + TypeName: TypeName | None + DefaultVersionId: TypeVersionId | None + TypeArn: TypeArn | None + LastUpdated: Timestamp | None + Description: Description | None + PublisherId: PublisherId | None + OriginalTypeName: TypeName | None + PublicVersionNumber: PublicVersionNumber | None + LatestPublicVersion: PublicVersionNumber | None + PublisherIdentity: IdentityProvider | None + PublisherName: PublisherName | None + IsActivated: IsActivated | None -TypeSummaries = List[TypeSummary] +TypeSummaries = list[TypeSummary] class ListTypesOutput(TypedDict, total=False): - TypeSummaries: Optional[TypeSummaries] - NextToken: Optional[NextToken] + TypeSummaries: TypeSummaries | None + NextToken: NextToken | None class PublishTypeInput(ServiceRequest): - Type: Optional[ThirdPartyType] - Arn: Optional[PrivateTypeArn] - TypeName: Optional[TypeName] - PublicVersionNumber: Optional[PublicVersionNumber] + Type: ThirdPartyType | None + Arn: PrivateTypeArn | None + TypeName: TypeName | None + PublicVersionNumber: PublicVersionNumber | None class PublishTypeOutput(TypedDict, total=False): - PublicTypeArn: Optional[TypeArn] + PublicTypeArn: TypeArn | None class RecordHandlerProgressInput(ServiceRequest): BearerToken: ClientToken OperationStatus: OperationStatus - CurrentOperationStatus: Optional[OperationStatus] - StatusMessage: Optional[StatusMessage] - ErrorCode: Optional[HandlerErrorCode] - ResourceModel: Optional[ResourceModel] - ClientRequestToken: Optional[ClientRequestToken] + CurrentOperationStatus: OperationStatus | None + StatusMessage: StatusMessage | None + ErrorCode: HandlerErrorCode | None + ResourceModel: ResourceModel | None + ClientRequestToken: ClientRequestToken | None class RecordHandlerProgressOutput(TypedDict, total=False): @@ -2709,61 +2920,62 @@ class RecordHandlerProgressOutput(TypedDict, total=False): class RegisterPublisherInput(ServiceRequest): - AcceptTermsAndConditions: Optional[AcceptTermsAndConditions] - ConnectionArn: Optional[ConnectionArn] + AcceptTermsAndConditions: AcceptTermsAndConditions | None + ConnectionArn: ConnectionArn | None class RegisterPublisherOutput(TypedDict, total=False): - PublisherId: Optional[PublisherId] + PublisherId: PublisherId | None class RegisterTypeInput(ServiceRequest): - Type: Optional[RegistryType] + Type: RegistryType | None TypeName: TypeName SchemaHandlerPackage: S3Url - LoggingConfig: Optional[LoggingConfig] - ExecutionRoleArn: Optional[RoleArn] - ClientRequestToken: Optional[RequestToken] + LoggingConfig: LoggingConfig | None + ExecutionRoleArn: RoleArn | None + ClientRequestToken: RequestToken | None class RegisterTypeOutput(TypedDict, total=False): - RegistrationToken: Optional[RegistrationToken] + RegistrationToken: RegistrationToken | None class RollbackStackInput(ServiceRequest): StackName: StackNameOrId - RoleARN: Optional[RoleARN] - ClientRequestToken: Optional[ClientRequestToken] - RetainExceptOnCreate: Optional[RetainExceptOnCreate] + RoleARN: RoleARN | None + ClientRequestToken: ClientRequestToken | None + RetainExceptOnCreate: RetainExceptOnCreate | None class RollbackStackOutput(TypedDict, total=False): - StackId: Optional[StackId] + StackId: StackId | None + OperationId: OperationId | None class SetStackPolicyInput(ServiceRequest): StackName: StackName - StackPolicyBody: Optional[StackPolicyBody] - StackPolicyURL: Optional[StackPolicyURL] + StackPolicyBody: StackPolicyBody | None + StackPolicyURL: StackPolicyURL | None class SetTypeConfigurationInput(ServiceRequest): - TypeArn: Optional[TypeArn] + TypeArn: TypeArn | None Configuration: TypeConfiguration - ConfigurationAlias: Optional[TypeConfigurationAlias] - TypeName: Optional[TypeName] - Type: Optional[ThirdPartyType] + ConfigurationAlias: TypeConfigurationAlias | None + TypeName: TypeName | None + Type: ThirdPartyType | None class SetTypeConfigurationOutput(TypedDict, total=False): - ConfigurationArn: Optional[TypeConfigurationArn] + ConfigurationArn: TypeConfigurationArn | None class SetTypeDefaultVersionInput(ServiceRequest): - Arn: Optional[PrivateTypeArn] - Type: Optional[RegistryType] - TypeName: Optional[TypeName] - VersionId: Optional[TypeVersionId] + Arn: PrivateTypeArn | None + Type: RegistryType | None + TypeName: TypeName | None + VersionId: TypeVersionId | None class SetTypeDefaultVersionOutput(TypedDict, total=False): @@ -2778,18 +2990,18 @@ class SignalResourceInput(ServiceRequest): class StartResourceScanInput(ServiceRequest): - ClientRequestToken: Optional[ClientRequestToken] - ScanFilters: Optional[ScanFilters] + ClientRequestToken: ClientRequestToken | None + ScanFilters: ScanFilters | None class StartResourceScanOutput(TypedDict, total=False): - ResourceScanId: Optional[ResourceScanId] + ResourceScanId: ResourceScanId | None class StopStackSetOperationInput(ServiceRequest): StackSetName: StackSetName OperationId: ClientRequestToken - CallAs: Optional[CallAs] + CallAs: CallAs | None class StopStackSetOperationOutput(TypedDict, total=False): @@ -2797,104 +3009,105 @@ class StopStackSetOperationOutput(TypedDict, total=False): class TemplateParameter(TypedDict, total=False): - ParameterKey: Optional[ParameterKey] - DefaultValue: Optional[ParameterValue] - NoEcho: Optional[NoEcho] - Description: Optional[Description] + ParameterKey: ParameterKey | None + DefaultValue: ParameterValue | None + NoEcho: NoEcho | None + Description: Description | None -TemplateParameters = List[TemplateParameter] +TemplateParameters = list[TemplateParameter] class TestTypeInput(ServiceRequest): - Arn: Optional[TypeArn] - Type: Optional[ThirdPartyType] - TypeName: Optional[TypeName] - VersionId: Optional[TypeVersionId] - LogDeliveryBucket: Optional[S3Bucket] + Arn: TypeArn | None + Type: ThirdPartyType | None + TypeName: TypeName | None + VersionId: TypeVersionId | None + LogDeliveryBucket: S3Bucket | None class TestTypeOutput(TypedDict, total=False): - TypeVersionArn: Optional[TypeArn] + TypeVersionArn: TypeArn | None class UpdateGeneratedTemplateInput(ServiceRequest): GeneratedTemplateName: GeneratedTemplateName - NewGeneratedTemplateName: Optional[GeneratedTemplateName] - AddResources: Optional[ResourceDefinitions] - RemoveResources: Optional[JazzLogicalResourceIds] - RefreshAllResources: Optional[RefreshAllResources] - TemplateConfiguration: Optional[TemplateConfiguration] + NewGeneratedTemplateName: GeneratedTemplateName | None + AddResources: ResourceDefinitions | None + RemoveResources: JazzLogicalResourceIds | None + RefreshAllResources: RefreshAllResources | None + TemplateConfiguration: TemplateConfiguration | None class UpdateGeneratedTemplateOutput(TypedDict, total=False): - GeneratedTemplateId: Optional[GeneratedTemplateId] + GeneratedTemplateId: GeneratedTemplateId | None class UpdateStackInput(ServiceRequest): StackName: StackName - TemplateBody: Optional[TemplateBody] - TemplateURL: Optional[TemplateURL] - UsePreviousTemplate: Optional[UsePreviousTemplate] - StackPolicyDuringUpdateBody: Optional[StackPolicyDuringUpdateBody] - StackPolicyDuringUpdateURL: Optional[StackPolicyDuringUpdateURL] - Parameters: Optional[Parameters] - Capabilities: Optional[Capabilities] - ResourceTypes: Optional[ResourceTypes] - RoleARN: Optional[RoleARN] - RollbackConfiguration: Optional[RollbackConfiguration] - StackPolicyBody: Optional[StackPolicyBody] - StackPolicyURL: Optional[StackPolicyURL] - NotificationARNs: Optional[NotificationARNs] - Tags: Optional[Tags] - DisableRollback: Optional[DisableRollback] - ClientRequestToken: Optional[ClientRequestToken] - RetainExceptOnCreate: Optional[RetainExceptOnCreate] + TemplateBody: TemplateBody | None + TemplateURL: TemplateURL | None + UsePreviousTemplate: UsePreviousTemplate | None + StackPolicyDuringUpdateBody: StackPolicyDuringUpdateBody | None + StackPolicyDuringUpdateURL: StackPolicyDuringUpdateURL | None + Parameters: Parameters | None + Capabilities: Capabilities | None + ResourceTypes: ResourceTypes | None + RoleARN: RoleARN | None + RollbackConfiguration: RollbackConfiguration | None + StackPolicyBody: StackPolicyBody | None + StackPolicyURL: StackPolicyURL | None + NotificationARNs: NotificationARNs | None + Tags: Tags | None + DisableRollback: DisableRollback | None + ClientRequestToken: ClientRequestToken | None + RetainExceptOnCreate: RetainExceptOnCreate | None class UpdateStackInstancesInput(ServiceRequest): StackSetName: StackSetNameOrId - Accounts: Optional[AccountList] - DeploymentTargets: Optional[DeploymentTargets] + Accounts: AccountList | None + DeploymentTargets: DeploymentTargets | None Regions: RegionList - ParameterOverrides: Optional[Parameters] - OperationPreferences: Optional[StackSetOperationPreferences] - OperationId: Optional[ClientRequestToken] - CallAs: Optional[CallAs] + ParameterOverrides: Parameters | None + OperationPreferences: StackSetOperationPreferences | None + OperationId: ClientRequestToken | None + CallAs: CallAs | None class UpdateStackInstancesOutput(TypedDict, total=False): - OperationId: Optional[ClientRequestToken] + OperationId: ClientRequestToken | None class UpdateStackOutput(TypedDict, total=False): - StackId: Optional[StackId] + StackId: StackId | None + OperationId: OperationId | None class UpdateStackSetInput(ServiceRequest): StackSetName: StackSetName - Description: Optional[Description] - TemplateBody: Optional[TemplateBody] - TemplateURL: Optional[TemplateURL] - UsePreviousTemplate: Optional[UsePreviousTemplate] - Parameters: Optional[Parameters] - Capabilities: Optional[Capabilities] - Tags: Optional[Tags] - OperationPreferences: Optional[StackSetOperationPreferences] - AdministrationRoleARN: Optional[RoleARN] - ExecutionRoleName: Optional[ExecutionRoleName] - DeploymentTargets: Optional[DeploymentTargets] - PermissionModel: Optional[PermissionModels] - AutoDeployment: Optional[AutoDeployment] - OperationId: Optional[ClientRequestToken] - Accounts: Optional[AccountList] - Regions: Optional[RegionList] - CallAs: Optional[CallAs] - ManagedExecution: Optional[ManagedExecution] + Description: Description | None + TemplateBody: TemplateBody | None + TemplateURL: TemplateURL | None + UsePreviousTemplate: UsePreviousTemplate | None + Parameters: Parameters | None + Capabilities: Capabilities | None + Tags: Tags | None + OperationPreferences: StackSetOperationPreferences | None + AdministrationRoleARN: RoleARN | None + ExecutionRoleName: ExecutionRoleName | None + DeploymentTargets: DeploymentTargets | None + PermissionModel: PermissionModels | None + AutoDeployment: AutoDeployment | None + OperationId: ClientRequestToken | None + Accounts: AccountList | None + Regions: RegionList | None + CallAs: CallAs | None + ManagedExecution: ManagedExecution | None class UpdateStackSetOutput(TypedDict, total=False): - OperationId: Optional[ClientRequestToken] + OperationId: ClientRequestToken | None class UpdateTerminationProtectionInput(ServiceRequest): @@ -2903,25 +3116,25 @@ class UpdateTerminationProtectionInput(ServiceRequest): class UpdateTerminationProtectionOutput(TypedDict, total=False): - StackId: Optional[StackId] + StackId: StackId | None class ValidateTemplateInput(ServiceRequest): - TemplateBody: Optional[TemplateBody] - TemplateURL: Optional[TemplateURL] + TemplateBody: TemplateBody | None + TemplateURL: TemplateURL | None class ValidateTemplateOutput(TypedDict, total=False): - Parameters: Optional[TemplateParameters] - Description: Optional[Description] - Capabilities: Optional[Capabilities] - CapabilitiesReason: Optional[CapabilitiesReason] - DeclaredTransforms: Optional[TransformsList] + Parameters: TemplateParameters | None + Description: Description | None + Capabilities: Capabilities | None + CapabilitiesReason: CapabilitiesReason | None + DeclaredTransforms: TransformsList | None class CloudformationApi: - service = "cloudformation" - version = "2010-05-15" + service: str = "cloudformation" + version: str = "2010-05-15" @handler("ActivateOrganizationsAccess") def activate_organizations_access( @@ -2989,6 +3202,7 @@ def create_change_set( include_nested_stacks: IncludeNestedStacks | None = None, on_stack_failure: OnStackFailure | None = None, import_existing_resources: ImportExistingResources | None = None, + deployment_mode: DeploymentMode | None = None, **kwargs, ) -> CreateChangeSetOutput: raise NotImplementedError @@ -3185,6 +3399,19 @@ def describe_change_set_hooks( ) -> DescribeChangeSetHooksOutput: raise NotImplementedError + @handler("DescribeEvents") + def describe_events( + self, + context: RequestContext, + stack_name: StackNameOrId | None = None, + change_set_name: ChangeSetNameOrId | None = None, + operation_id: OperationId | None = None, + filters: EventFilter | None = None, + next_token: NextToken | None = None, + **kwargs, + ) -> DescribeEventsOutput: + raise NotImplementedError + @handler("DescribeGeneratedTemplate") def describe_generated_template( self, context: RequestContext, generated_template_name: GeneratedTemplateName, **kwargs @@ -3219,7 +3446,7 @@ def describe_stack_drift_detection_status( def describe_stack_events( self, context: RequestContext, - stack_name: StackName | None = None, + stack_name: StackName, next_token: NextToken | None = None, **kwargs, ) -> DescribeStackEventsOutput: @@ -3391,6 +3618,12 @@ def get_generated_template( ) -> GetGeneratedTemplateOutput: raise NotImplementedError + @handler("GetHookResult") + def get_hook_result( + self, context: RequestContext, hook_result_id: HookInvocationId | None = None, **kwargs + ) -> GetHookResultOutput: + raise NotImplementedError + @handler("GetStackPolicy") def get_stack_policy( self, context: RequestContext, stack_name: StackName, **kwargs diff --git a/localstack-core/localstack/aws/api/cloudwatch/__init__.py b/localstack-core/localstack/aws/api/cloudwatch/__init__.py index 5739823f29805..cfbc60d767caf 100644 --- a/localstack-core/localstack/aws/api/cloudwatch/__init__.py +++ b/localstack-core/localstack/aws/api/cloudwatch/__init__.py @@ -1,6 +1,6 @@ from datetime import datetime from enum import StrEnum -from typing import Dict, List, Optional, TypedDict +from typing import TypedDict from localstack.aws.api import RequestContext, ServiceException, ServiceRequest, handler @@ -16,6 +16,7 @@ AmazonResourceName = str AnomalyDetectorMetricStat = str AnomalyDetectorMetricTimezone = str +Arn = str AttributeName = str AttributeValue = str AwsQueryErrorMessage = str @@ -30,6 +31,7 @@ DatapointsToAlarm = int DimensionName = str DimensionValue = str +Duration = str EntityAttributesMapKeyString = str EntityAttributesMapValueString = str EntityKeyAttributesMapKeyString = str @@ -38,6 +40,7 @@ EvaluateLowSampleCountPercentile = str EvaluationPeriods = int ExceptionType = str +Expression = str ExtendedStatistic = str FailureCode = str FailureDescription = str @@ -77,6 +80,8 @@ MetricStreamState = str MetricStreamStatistic = str MetricWidget = str +MuteType = str +Name = str Namespace = str NextToken = str OutputFormat = str @@ -96,6 +101,7 @@ TagValue = str TemplateName = str Threshold = float +Timezone = str TreatMissingData = str @@ -105,6 +111,12 @@ class ActionsSuppressedBy(StrEnum): Alarm = "Alarm" +class AlarmMuteRuleStatus(StrEnum): + SCHEDULED = "SCHEDULED" + ACTIVE = "ACTIVE" + EXPIRED = "EXPIRED" + + class AlarmType(StrEnum): CompositeAlarm = "CompositeAlarm" MetricAlarm = "MetricAlarm" @@ -133,6 +145,8 @@ class ComparisonOperator(StrEnum): class EvaluationState(StrEnum): PARTIAL_DATA = "PARTIAL_DATA" + EVALUATION_FAILURE = "EVALUATION_FAILURE" + EVALUATION_ERROR = "EVALUATION_ERROR" class HistoryItemType(StrEnum): @@ -222,18 +236,18 @@ class ConflictException(ServiceException): class DashboardValidationMessage(TypedDict, total=False): - DataPath: Optional[DataPath] - Message: Optional[Message] + DataPath: DataPath | None + Message: Message | None -DashboardValidationMessages = List[DashboardValidationMessage] +DashboardValidationMessages = list[DashboardValidationMessage] class DashboardInvalidInputError(ServiceException): code: str = "InvalidParameterInput" sender_fault: bool = True status_code: int = 400 - dashboardValidationMessages: Optional[DashboardValidationMessages] + dashboardValidationMessages: DashboardValidationMessages | None class DashboardNotFoundError(ServiceException): @@ -300,38 +314,50 @@ class ResourceNotFoundException(ServiceException): code: str = "ResourceNotFoundException" sender_fault: bool = True status_code: int = 404 - ResourceType: Optional[ResourceType] - ResourceId: Optional[ResourceId] + ResourceType: ResourceType | None + ResourceId: ResourceId | None Timestamp = datetime -ContributorAttributes = Dict[AttributeName, AttributeValue] +ContributorAttributes = dict[AttributeName, AttributeValue] class AlarmContributor(TypedDict, total=False): ContributorId: ContributorId ContributorAttributes: ContributorAttributes StateReason: StateReason - StateTransitionedTimestamp: Optional[Timestamp] + StateTransitionedTimestamp: Timestamp | None -AlarmContributors = List[AlarmContributor] +AlarmContributors = list[AlarmContributor] class AlarmHistoryItem(TypedDict, total=False): - AlarmName: Optional[AlarmName] - AlarmContributorId: Optional[ContributorId] - AlarmType: Optional[AlarmType] - Timestamp: Optional[Timestamp] - HistoryItemType: Optional[HistoryItemType] - HistorySummary: Optional[HistorySummary] - HistoryData: Optional[HistoryData] - AlarmContributorAttributes: Optional[ContributorAttributes] + AlarmName: AlarmName | None + AlarmContributorId: ContributorId | None + AlarmType: AlarmType | None + Timestamp: Timestamp | None + HistoryItemType: HistoryItemType | None + HistorySummary: HistorySummary | None + HistoryData: HistoryData | None + AlarmContributorAttributes: ContributorAttributes | None + + +AlarmHistoryItems = list[AlarmHistoryItem] +AlarmMuteRuleStatuses = list[AlarmMuteRuleStatus] + + +class AlarmMuteRuleSummary(TypedDict, total=False): + AlarmMuteRuleArn: Arn | None + ExpireDate: Timestamp | None + Status: AlarmMuteRuleStatus | None + MuteType: MuteType | None + LastUpdatedTimestamp: Timestamp | None -AlarmHistoryItems = List[AlarmHistoryItem] -AlarmNames = List[AlarmName] -AlarmTypes = List[AlarmType] +AlarmMuteRuleSummaries = list[AlarmMuteRuleSummary] +AlarmNames = list[AlarmName] +AlarmTypes = list[AlarmType] class Dimension(TypedDict, total=False): @@ -339,49 +365,49 @@ class Dimension(TypedDict, total=False): Value: DimensionValue -Dimensions = List[Dimension] +Dimensions = list[Dimension] class Metric(TypedDict, total=False): - Namespace: Optional[Namespace] - MetricName: Optional[MetricName] - Dimensions: Optional[Dimensions] + Namespace: Namespace | None + MetricName: MetricName | None + Dimensions: Dimensions | None class MetricStat(TypedDict, total=False): Metric: Metric Period: Period Stat: Stat - Unit: Optional[StandardUnit] + Unit: StandardUnit | None class MetricDataQuery(TypedDict, total=False): Id: MetricId - MetricStat: Optional[MetricStat] - Expression: Optional[MetricExpression] - Label: Optional[MetricLabel] - ReturnData: Optional[ReturnData] - Period: Optional[Period] - AccountId: Optional[AccountId] + MetricStat: MetricStat | None + Expression: MetricExpression | None + Label: MetricLabel | None + ReturnData: ReturnData | None + Period: Period | None + AccountId: AccountId | None -MetricDataQueries = List[MetricDataQuery] +MetricDataQueries = list[MetricDataQuery] class MetricMathAnomalyDetector(TypedDict, total=False): - MetricDataQueries: Optional[MetricDataQueries] + MetricDataQueries: MetricDataQueries | None class SingleMetricAnomalyDetector(TypedDict, total=False): - AccountId: Optional[AccountId] - Namespace: Optional[Namespace] - MetricName: Optional[MetricName] - Dimensions: Optional[Dimensions] - Stat: Optional[AnomalyDetectorMetricStat] + AccountId: AccountId | None + Namespace: Namespace | None + MetricName: MetricName | None + Dimensions: Dimensions | None + Stat: AnomalyDetectorMetricStat | None class MetricCharacteristics(TypedDict, total=False): - PeriodicSpikes: Optional[PeriodicSpikes] + PeriodicSpikes: PeriodicSpikes | None class Range(TypedDict, total=False): @@ -389,94 +415,98 @@ class Range(TypedDict, total=False): EndTime: Timestamp -AnomalyDetectorExcludedTimeRanges = List[Range] +AnomalyDetectorExcludedTimeRanges = list[Range] class AnomalyDetectorConfiguration(TypedDict, total=False): - ExcludedTimeRanges: Optional[AnomalyDetectorExcludedTimeRanges] - MetricTimezone: Optional[AnomalyDetectorMetricTimezone] + ExcludedTimeRanges: AnomalyDetectorExcludedTimeRanges | None + MetricTimezone: AnomalyDetectorMetricTimezone | None class AnomalyDetector(TypedDict, total=False): - Namespace: Optional[Namespace] - MetricName: Optional[MetricName] - Dimensions: Optional[Dimensions] - Stat: Optional[AnomalyDetectorMetricStat] - Configuration: Optional[AnomalyDetectorConfiguration] - StateValue: Optional[AnomalyDetectorStateValue] - MetricCharacteristics: Optional[MetricCharacteristics] - SingleMetricAnomalyDetector: Optional[SingleMetricAnomalyDetector] - MetricMathAnomalyDetector: Optional[MetricMathAnomalyDetector] + Namespace: Namespace | None + MetricName: MetricName | None + Dimensions: Dimensions | None + Stat: AnomalyDetectorMetricStat | None + Configuration: AnomalyDetectorConfiguration | None + StateValue: AnomalyDetectorStateValue | None + MetricCharacteristics: MetricCharacteristics | None + SingleMetricAnomalyDetector: SingleMetricAnomalyDetector | None + MetricMathAnomalyDetector: MetricMathAnomalyDetector | None -AnomalyDetectorTypes = List[AnomalyDetectorType] -AnomalyDetectors = List[AnomalyDetector] +AnomalyDetectorTypes = list[AnomalyDetectorType] +AnomalyDetectors = list[AnomalyDetector] class PartialFailure(TypedDict, total=False): - FailureResource: Optional[FailureResource] - ExceptionType: Optional[ExceptionType] - FailureCode: Optional[FailureCode] - FailureDescription: Optional[FailureDescription] + FailureResource: FailureResource | None + ExceptionType: ExceptionType | None + FailureCode: FailureCode | None + FailureDescription: FailureDescription | None -BatchFailures = List[PartialFailure] -ResourceList = List[ResourceName] +BatchFailures = list[PartialFailure] +ResourceList = list[ResourceName] class CompositeAlarm(TypedDict, total=False): - ActionsEnabled: Optional[ActionsEnabled] - AlarmActions: Optional[ResourceList] - AlarmArn: Optional[AlarmArn] - AlarmConfigurationUpdatedTimestamp: Optional[Timestamp] - AlarmDescription: Optional[AlarmDescription] - AlarmName: Optional[AlarmName] - AlarmRule: Optional[AlarmRule] - InsufficientDataActions: Optional[ResourceList] - OKActions: Optional[ResourceList] - StateReason: Optional[StateReason] - StateReasonData: Optional[StateReasonData] - StateUpdatedTimestamp: Optional[Timestamp] - StateValue: Optional[StateValue] - StateTransitionedTimestamp: Optional[Timestamp] - ActionsSuppressedBy: Optional[ActionsSuppressedBy] - ActionsSuppressedReason: Optional[ActionsSuppressedReason] - ActionsSuppressor: Optional[AlarmArn] - ActionsSuppressorWaitPeriod: Optional[SuppressorPeriod] - ActionsSuppressorExtensionPeriod: Optional[SuppressorPeriod] - - -CompositeAlarms = List[CompositeAlarm] -Counts = List[DatapointValue] + ActionsEnabled: ActionsEnabled | None + AlarmActions: ResourceList | None + AlarmArn: AlarmArn | None + AlarmConfigurationUpdatedTimestamp: Timestamp | None + AlarmDescription: AlarmDescription | None + AlarmName: AlarmName | None + AlarmRule: AlarmRule | None + InsufficientDataActions: ResourceList | None + OKActions: ResourceList | None + StateReason: StateReason | None + StateReasonData: StateReasonData | None + StateUpdatedTimestamp: Timestamp | None + StateValue: StateValue | None + StateTransitionedTimestamp: Timestamp | None + ActionsSuppressedBy: ActionsSuppressedBy | None + ActionsSuppressedReason: ActionsSuppressedReason | None + ActionsSuppressor: AlarmArn | None + ActionsSuppressorWaitPeriod: SuppressorPeriod | None + ActionsSuppressorExtensionPeriod: SuppressorPeriod | None + + +CompositeAlarms = list[CompositeAlarm] +Counts = list[DatapointValue] Size = int LastModified = datetime class DashboardEntry(TypedDict, total=False): - DashboardName: Optional[DashboardName] - DashboardArn: Optional[DashboardArn] - LastModified: Optional[LastModified] - Size: Optional[Size] + DashboardName: DashboardName | None + DashboardArn: DashboardArn | None + LastModified: LastModified | None + Size: Size | None -DashboardEntries = List[DashboardEntry] -DashboardNames = List[DashboardName] -DatapointValueMap = Dict[ExtendedStatistic, DatapointValue] +DashboardEntries = list[DashboardEntry] +DashboardNames = list[DashboardName] +DatapointValueMap = dict[ExtendedStatistic, DatapointValue] class Datapoint(TypedDict, total=False): - Timestamp: Optional[Timestamp] - SampleCount: Optional[DatapointValue] - Average: Optional[DatapointValue] - Sum: Optional[DatapointValue] - Minimum: Optional[DatapointValue] - Maximum: Optional[DatapointValue] - Unit: Optional[StandardUnit] - ExtendedStatistics: Optional[DatapointValueMap] + Timestamp: Timestamp | None + SampleCount: DatapointValue | None + Average: DatapointValue | None + Sum: DatapointValue | None + Minimum: DatapointValue | None + Maximum: DatapointValue | None + Unit: StandardUnit | None + ExtendedStatistics: DatapointValueMap | None -DatapointValues = List[DatapointValue] -Datapoints = List[Datapoint] +DatapointValues = list[DatapointValue] +Datapoints = list[Datapoint] + + +class DeleteAlarmMuteRuleInput(ServiceRequest): + AlarmMuteRuleName: Name class DeleteAlarmsInput(ServiceRequest): @@ -484,12 +514,12 @@ class DeleteAlarmsInput(ServiceRequest): class DeleteAnomalyDetectorInput(ServiceRequest): - Namespace: Optional[Namespace] - MetricName: Optional[MetricName] - Dimensions: Optional[Dimensions] - Stat: Optional[AnomalyDetectorMetricStat] - SingleMetricAnomalyDetector: Optional[SingleMetricAnomalyDetector] - MetricMathAnomalyDetector: Optional[MetricMathAnomalyDetector] + Namespace: Namespace | None + MetricName: MetricName | None + Dimensions: Dimensions | None + Stat: AnomalyDetectorMetricStat | None + SingleMetricAnomalyDetector: SingleMetricAnomalyDetector | None + MetricMathAnomalyDetector: MetricMathAnomalyDetector | None class DeleteAnomalyDetectorOutput(TypedDict, total=False): @@ -504,7 +534,7 @@ class DeleteDashboardsOutput(TypedDict, total=False): pass -InsightRuleNames = List[InsightRuleName] +InsightRuleNames = list[InsightRuleName] class DeleteInsightRulesInput(ServiceRequest): @@ -512,7 +542,7 @@ class DeleteInsightRulesInput(ServiceRequest): class DeleteInsightRulesOutput(TypedDict, total=False): - Failures: Optional[BatchFailures] + Failures: BatchFailures | None class DeleteMetricStreamInput(ServiceRequest): @@ -525,115 +555,115 @@ class DeleteMetricStreamOutput(TypedDict, total=False): class DescribeAlarmContributorsInput(ServiceRequest): AlarmName: AlarmName - NextToken: Optional[NextToken] + NextToken: NextToken | None class DescribeAlarmContributorsOutput(TypedDict, total=False): AlarmContributors: AlarmContributors - NextToken: Optional[NextToken] + NextToken: NextToken | None class DescribeAlarmHistoryInput(ServiceRequest): - AlarmName: Optional[AlarmName] - AlarmContributorId: Optional[ContributorId] - AlarmTypes: Optional[AlarmTypes] - HistoryItemType: Optional[HistoryItemType] - StartDate: Optional[Timestamp] - EndDate: Optional[Timestamp] - MaxRecords: Optional[MaxRecords] - NextToken: Optional[NextToken] - ScanBy: Optional[ScanBy] + AlarmName: AlarmName | None + AlarmContributorId: ContributorId | None + AlarmTypes: AlarmTypes | None + HistoryItemType: HistoryItemType | None + StartDate: Timestamp | None + EndDate: Timestamp | None + MaxRecords: MaxRecords | None + NextToken: NextToken | None + ScanBy: ScanBy | None class DescribeAlarmHistoryOutput(TypedDict, total=False): - AlarmHistoryItems: Optional[AlarmHistoryItems] - NextToken: Optional[NextToken] + AlarmHistoryItems: AlarmHistoryItems | None + NextToken: NextToken | None class DescribeAlarmsForMetricInput(ServiceRequest): MetricName: MetricName Namespace: Namespace - Statistic: Optional[Statistic] - ExtendedStatistic: Optional[ExtendedStatistic] - Dimensions: Optional[Dimensions] - Period: Optional[Period] - Unit: Optional[StandardUnit] + Statistic: Statistic | None + ExtendedStatistic: ExtendedStatistic | None + Dimensions: Dimensions | None + Period: Period | None + Unit: StandardUnit | None class MetricAlarm(TypedDict, total=False): - AlarmName: Optional[AlarmName] - AlarmArn: Optional[AlarmArn] - AlarmDescription: Optional[AlarmDescription] - AlarmConfigurationUpdatedTimestamp: Optional[Timestamp] - ActionsEnabled: Optional[ActionsEnabled] - OKActions: Optional[ResourceList] - AlarmActions: Optional[ResourceList] - InsufficientDataActions: Optional[ResourceList] - StateValue: Optional[StateValue] - StateReason: Optional[StateReason] - StateReasonData: Optional[StateReasonData] - StateUpdatedTimestamp: Optional[Timestamp] - MetricName: Optional[MetricName] - Namespace: Optional[Namespace] - Statistic: Optional[Statistic] - ExtendedStatistic: Optional[ExtendedStatistic] - Dimensions: Optional[Dimensions] - Period: Optional[Period] - Unit: Optional[StandardUnit] - EvaluationPeriods: Optional[EvaluationPeriods] - DatapointsToAlarm: Optional[DatapointsToAlarm] - Threshold: Optional[Threshold] - ComparisonOperator: Optional[ComparisonOperator] - TreatMissingData: Optional[TreatMissingData] - EvaluateLowSampleCountPercentile: Optional[EvaluateLowSampleCountPercentile] - Metrics: Optional[MetricDataQueries] - ThresholdMetricId: Optional[MetricId] - EvaluationState: Optional[EvaluationState] - StateTransitionedTimestamp: Optional[Timestamp] - - -MetricAlarms = List[MetricAlarm] + AlarmName: AlarmName | None + AlarmArn: AlarmArn | None + AlarmDescription: AlarmDescription | None + AlarmConfigurationUpdatedTimestamp: Timestamp | None + ActionsEnabled: ActionsEnabled | None + OKActions: ResourceList | None + AlarmActions: ResourceList | None + InsufficientDataActions: ResourceList | None + StateValue: StateValue | None + StateReason: StateReason | None + StateReasonData: StateReasonData | None + StateUpdatedTimestamp: Timestamp | None + MetricName: MetricName | None + Namespace: Namespace | None + Statistic: Statistic | None + ExtendedStatistic: ExtendedStatistic | None + Dimensions: Dimensions | None + Period: Period | None + Unit: StandardUnit | None + EvaluationPeriods: EvaluationPeriods | None + DatapointsToAlarm: DatapointsToAlarm | None + Threshold: Threshold | None + ComparisonOperator: ComparisonOperator | None + TreatMissingData: TreatMissingData | None + EvaluateLowSampleCountPercentile: EvaluateLowSampleCountPercentile | None + Metrics: MetricDataQueries | None + ThresholdMetricId: MetricId | None + EvaluationState: EvaluationState | None + StateTransitionedTimestamp: Timestamp | None + + +MetricAlarms = list[MetricAlarm] class DescribeAlarmsForMetricOutput(TypedDict, total=False): - MetricAlarms: Optional[MetricAlarms] + MetricAlarms: MetricAlarms | None class DescribeAlarmsInput(ServiceRequest): - AlarmNames: Optional[AlarmNames] - AlarmNamePrefix: Optional[AlarmNamePrefix] - AlarmTypes: Optional[AlarmTypes] - ChildrenOfAlarmName: Optional[AlarmName] - ParentsOfAlarmName: Optional[AlarmName] - StateValue: Optional[StateValue] - ActionPrefix: Optional[ActionPrefix] - MaxRecords: Optional[MaxRecords] - NextToken: Optional[NextToken] + AlarmNames: AlarmNames | None + AlarmNamePrefix: AlarmNamePrefix | None + AlarmTypes: AlarmTypes | None + ChildrenOfAlarmName: AlarmName | None + ParentsOfAlarmName: AlarmName | None + StateValue: StateValue | None + ActionPrefix: ActionPrefix | None + MaxRecords: MaxRecords | None + NextToken: NextToken | None class DescribeAlarmsOutput(TypedDict, total=False): - CompositeAlarms: Optional[CompositeAlarms] - MetricAlarms: Optional[MetricAlarms] - NextToken: Optional[NextToken] + CompositeAlarms: CompositeAlarms | None + MetricAlarms: MetricAlarms | None + NextToken: NextToken | None class DescribeAnomalyDetectorsInput(ServiceRequest): - NextToken: Optional[NextToken] - MaxResults: Optional[MaxReturnedResultsCount] - Namespace: Optional[Namespace] - MetricName: Optional[MetricName] - Dimensions: Optional[Dimensions] - AnomalyDetectorTypes: Optional[AnomalyDetectorTypes] + NextToken: NextToken | None + MaxResults: MaxReturnedResultsCount | None + Namespace: Namespace | None + MetricName: MetricName | None + Dimensions: Dimensions | None + AnomalyDetectorTypes: AnomalyDetectorTypes | None class DescribeAnomalyDetectorsOutput(TypedDict, total=False): - AnomalyDetectors: Optional[AnomalyDetectors] - NextToken: Optional[NextToken] + AnomalyDetectors: AnomalyDetectors | None + NextToken: NextToken | None class DescribeInsightRulesInput(ServiceRequest): - NextToken: Optional[NextToken] - MaxResults: Optional[InsightRuleMaxResults] + NextToken: NextToken | None + MaxResults: InsightRuleMaxResults | None class InsightRule(TypedDict, total=False): @@ -641,24 +671,24 @@ class InsightRule(TypedDict, total=False): State: InsightRuleState Schema: InsightRuleSchema Definition: InsightRuleDefinition - ManagedRule: Optional[InsightRuleIsManaged] - ApplyOnTransformedLogs: Optional[InsightRuleOnTransformedLogs] + ManagedRule: InsightRuleIsManaged | None + ApplyOnTransformedLogs: InsightRuleOnTransformedLogs | None -InsightRules = List[InsightRule] +InsightRules = list[InsightRule] class DescribeInsightRulesOutput(TypedDict, total=False): - NextToken: Optional[NextToken] - InsightRules: Optional[InsightRules] + NextToken: NextToken | None + InsightRules: InsightRules | None class DimensionFilter(TypedDict, total=False): Name: DimensionName - Value: Optional[DimensionValue] + Value: DimensionValue | None -DimensionFilters = List[DimensionFilter] +DimensionFilters = list[DimensionFilter] class DisableAlarmActionsInput(ServiceRequest): @@ -670,7 +700,7 @@ class DisableInsightRulesInput(ServiceRequest): class DisableInsightRulesOutput(TypedDict, total=False): - Failures: Optional[BatchFailures] + Failures: BatchFailures | None class EnableAlarmActionsInput(ServiceRequest): @@ -682,19 +712,19 @@ class EnableInsightRulesInput(ServiceRequest): class EnableInsightRulesOutput(TypedDict, total=False): - Failures: Optional[BatchFailures] + Failures: BatchFailures | None -EntityAttributesMap = Dict[EntityAttributesMapKeyString, EntityAttributesMapValueString] -EntityKeyAttributesMap = Dict[EntityKeyAttributesMapKeyString, EntityKeyAttributesMapValueString] +EntityAttributesMap = dict[EntityAttributesMapKeyString, EntityAttributesMapValueString] +EntityKeyAttributesMap = dict[EntityKeyAttributesMapKeyString, EntityKeyAttributesMapValueString] class Entity(TypedDict, total=False): - KeyAttributes: Optional[EntityKeyAttributesMap] - Attributes: Optional[EntityAttributesMap] + KeyAttributes: EntityKeyAttributesMap | None + Attributes: EntityAttributesMap | None -Values = List[DatapointValue] +Values = list[DatapointValue] class StatisticSet(TypedDict, total=False): @@ -706,26 +736,60 @@ class StatisticSet(TypedDict, total=False): class MetricDatum(TypedDict, total=False): MetricName: MetricName - Dimensions: Optional[Dimensions] - Timestamp: Optional[Timestamp] - Value: Optional[DatapointValue] - StatisticValues: Optional[StatisticSet] - Values: Optional[Values] - Counts: Optional[Counts] - Unit: Optional[StandardUnit] - StorageResolution: Optional[StorageResolution] + Dimensions: Dimensions | None + Timestamp: Timestamp | None + Value: DatapointValue | None + StatisticValues: StatisticSet | None + Values: Values | None + Counts: Counts | None + Unit: StandardUnit | None + StorageResolution: StorageResolution | None -MetricData = List[MetricDatum] +MetricData = list[MetricDatum] class EntityMetricData(TypedDict, total=False): - Entity: Optional[Entity] - MetricData: Optional[MetricData] + Entity: Entity | None + MetricData: MetricData | None + + +EntityMetricDataList = list[EntityMetricData] +ExtendedStatistics = list[ExtendedStatistic] + + +class GetAlarmMuteRuleInput(ServiceRequest): + AlarmMuteRuleName: Name -EntityMetricDataList = List[EntityMetricData] -ExtendedStatistics = List[ExtendedStatistic] +MuteTargetAlarmNameList = list[Name] + + +class MuteTargets(TypedDict, total=False): + AlarmNames: MuteTargetAlarmNameList + + +class Schedule(TypedDict, total=False): + Expression: Expression + Duration: Duration + Timezone: Timezone | None + + +class Rule(TypedDict, total=False): + Schedule: Schedule + + +class GetAlarmMuteRuleOutput(TypedDict, total=False): + Name: Name | None + AlarmMuteRuleArn: Arn | None + Description: AlarmDescription | None + Rule: Rule | None + MuteTargets: MuteTargets | None + StartDate: Timestamp | None + ExpireDate: Timestamp | None + Status: AlarmMuteRuleStatus | None + LastUpdatedTimestamp: Timestamp | None + MuteType: MuteType | None class GetDashboardInput(ServiceRequest): @@ -733,12 +797,12 @@ class GetDashboardInput(ServiceRequest): class GetDashboardOutput(TypedDict, total=False): - DashboardArn: Optional[DashboardArn] - DashboardBody: Optional[DashboardBody] - DashboardName: Optional[DashboardName] + DashboardArn: DashboardArn | None + DashboardBody: DashboardBody | None + DashboardName: DashboardName | None -InsightRuleMetricList = List[InsightRuleMetricName] +InsightRuleMetricList = list[InsightRuleMetricName] class GetInsightRuleReportInput(ServiceRequest): @@ -746,23 +810,23 @@ class GetInsightRuleReportInput(ServiceRequest): StartTime: Timestamp EndTime: Timestamp Period: Period - MaxContributorCount: Optional[InsightRuleUnboundInteger] - Metrics: Optional[InsightRuleMetricList] - OrderBy: Optional[InsightRuleOrderBy] + MaxContributorCount: InsightRuleUnboundInteger | None + Metrics: InsightRuleMetricList | None + OrderBy: InsightRuleOrderBy | None class InsightRuleMetricDatapoint(TypedDict, total=False): Timestamp: Timestamp - UniqueContributors: Optional[InsightRuleUnboundDouble] - MaxContributorValue: Optional[InsightRuleUnboundDouble] - SampleCount: Optional[InsightRuleUnboundDouble] - Average: Optional[InsightRuleUnboundDouble] - Sum: Optional[InsightRuleUnboundDouble] - Minimum: Optional[InsightRuleUnboundDouble] - Maximum: Optional[InsightRuleUnboundDouble] + UniqueContributors: InsightRuleUnboundDouble | None + MaxContributorValue: InsightRuleUnboundDouble | None + SampleCount: InsightRuleUnboundDouble | None + Average: InsightRuleUnboundDouble | None + Sum: InsightRuleUnboundDouble | None + Minimum: InsightRuleUnboundDouble | None + Maximum: InsightRuleUnboundDouble | None -InsightRuleMetricDatapoints = List[InsightRuleMetricDatapoint] +InsightRuleMetricDatapoints = list[InsightRuleMetricDatapoint] class InsightRuleContributorDatapoint(TypedDict, total=False): @@ -770,8 +834,8 @@ class InsightRuleContributorDatapoint(TypedDict, total=False): ApproximateValue: InsightRuleUnboundDouble -InsightRuleContributorDatapoints = List[InsightRuleContributorDatapoint] -InsightRuleContributorKeys = List[InsightRuleContributorKey] +InsightRuleContributorDatapoints = list[InsightRuleContributorDatapoint] +InsightRuleContributorKeys = list[InsightRuleContributorKey] class InsightRuleContributor(TypedDict, total=False): @@ -780,86 +844,86 @@ class InsightRuleContributor(TypedDict, total=False): Datapoints: InsightRuleContributorDatapoints -InsightRuleContributors = List[InsightRuleContributor] +InsightRuleContributors = list[InsightRuleContributor] InsightRuleUnboundLong = int -InsightRuleContributorKeyLabels = List[InsightRuleContributorKeyLabel] +InsightRuleContributorKeyLabels = list[InsightRuleContributorKeyLabel] class GetInsightRuleReportOutput(TypedDict, total=False): - KeyLabels: Optional[InsightRuleContributorKeyLabels] - AggregationStatistic: Optional[InsightRuleAggregationStatistic] - AggregateValue: Optional[InsightRuleUnboundDouble] - ApproximateUniqueCount: Optional[InsightRuleUnboundLong] - Contributors: Optional[InsightRuleContributors] - MetricDatapoints: Optional[InsightRuleMetricDatapoints] + KeyLabels: InsightRuleContributorKeyLabels | None + AggregationStatistic: InsightRuleAggregationStatistic | None + AggregateValue: InsightRuleUnboundDouble | None + ApproximateUniqueCount: InsightRuleUnboundLong | None + Contributors: InsightRuleContributors | None + MetricDatapoints: InsightRuleMetricDatapoints | None class LabelOptions(TypedDict, total=False): - Timezone: Optional[GetMetricDataLabelTimezone] + Timezone: GetMetricDataLabelTimezone | None class GetMetricDataInput(ServiceRequest): MetricDataQueries: MetricDataQueries StartTime: Timestamp EndTime: Timestamp - NextToken: Optional[NextToken] - ScanBy: Optional[ScanBy] - MaxDatapoints: Optional[GetMetricDataMaxDatapoints] - LabelOptions: Optional[LabelOptions] + NextToken: NextToken | None + ScanBy: ScanBy | None + MaxDatapoints: GetMetricDataMaxDatapoints | None + LabelOptions: LabelOptions | None class MessageData(TypedDict, total=False): - Code: Optional[MessageDataCode] - Value: Optional[MessageDataValue] + Code: MessageDataCode | None + Value: MessageDataValue | None -MetricDataResultMessages = List[MessageData] -Timestamps = List[Timestamp] +MetricDataResultMessages = list[MessageData] +Timestamps = list[Timestamp] class MetricDataResult(TypedDict, total=False): - Id: Optional[MetricId] - Label: Optional[MetricLabel] - Timestamps: Optional[Timestamps] - Values: Optional[DatapointValues] - StatusCode: Optional[StatusCode] - Messages: Optional[MetricDataResultMessages] + Id: MetricId | None + Label: MetricLabel | None + Timestamps: Timestamps | None + Values: DatapointValues | None + StatusCode: StatusCode | None + Messages: MetricDataResultMessages | None -MetricDataResults = List[MetricDataResult] +MetricDataResults = list[MetricDataResult] class GetMetricDataOutput(TypedDict, total=False): - MetricDataResults: Optional[MetricDataResults] - NextToken: Optional[NextToken] - Messages: Optional[MetricDataResultMessages] + MetricDataResults: MetricDataResults | None + NextToken: NextToken | None + Messages: MetricDataResultMessages | None -Statistics = List[Statistic] +Statistics = list[Statistic] class GetMetricStatisticsInput(ServiceRequest): Namespace: Namespace MetricName: MetricName - Dimensions: Optional[Dimensions] + Dimensions: Dimensions | None StartTime: Timestamp EndTime: Timestamp Period: Period - Statistics: Optional[Statistics] - ExtendedStatistics: Optional[ExtendedStatistics] - Unit: Optional[StandardUnit] + Statistics: Statistics | None + ExtendedStatistics: ExtendedStatistics | None + Unit: StandardUnit | None class GetMetricStatisticsOutput(TypedDict, total=False): - Label: Optional[MetricLabel] - Datapoints: Optional[Datapoints] + Label: MetricLabel | None + Datapoints: Datapoints | None class GetMetricStreamInput(ServiceRequest): Name: MetricStreamName -MetricStreamStatisticsAdditionalStatistics = List[MetricStreamStatistic] +MetricStreamStatisticsAdditionalStatistics = list[MetricStreamStatistic] class MetricStreamStatisticsMetric(TypedDict, total=False): @@ -867,7 +931,7 @@ class MetricStreamStatisticsMetric(TypedDict, total=False): MetricName: MetricName -MetricStreamStatisticsIncludeMetrics = List[MetricStreamStatisticsMetric] +MetricStreamStatisticsIncludeMetrics = list[MetricStreamStatisticsMetric] class MetricStreamStatisticsConfiguration(TypedDict, total=False): @@ -875,59 +939,71 @@ class MetricStreamStatisticsConfiguration(TypedDict, total=False): AdditionalStatistics: MetricStreamStatisticsAdditionalStatistics -MetricStreamStatisticsConfigurations = List[MetricStreamStatisticsConfiguration] -MetricStreamFilterMetricNames = List[MetricName] +MetricStreamStatisticsConfigurations = list[MetricStreamStatisticsConfiguration] +MetricStreamFilterMetricNames = list[MetricName] class MetricStreamFilter(TypedDict, total=False): - Namespace: Optional[Namespace] - MetricNames: Optional[MetricStreamFilterMetricNames] + Namespace: Namespace | None + MetricNames: MetricStreamFilterMetricNames | None -MetricStreamFilters = List[MetricStreamFilter] +MetricStreamFilters = list[MetricStreamFilter] class GetMetricStreamOutput(TypedDict, total=False): - Arn: Optional[AmazonResourceName] - Name: Optional[MetricStreamName] - IncludeFilters: Optional[MetricStreamFilters] - ExcludeFilters: Optional[MetricStreamFilters] - FirehoseArn: Optional[AmazonResourceName] - RoleArn: Optional[AmazonResourceName] - State: Optional[MetricStreamState] - CreationDate: Optional[Timestamp] - LastUpdateDate: Optional[Timestamp] - OutputFormat: Optional[MetricStreamOutputFormat] - StatisticsConfigurations: Optional[MetricStreamStatisticsConfigurations] - IncludeLinkedAccountsMetrics: Optional[IncludeLinkedAccountsMetrics] + Arn: AmazonResourceName | None + Name: MetricStreamName | None + IncludeFilters: MetricStreamFilters | None + ExcludeFilters: MetricStreamFilters | None + FirehoseArn: AmazonResourceName | None + RoleArn: AmazonResourceName | None + State: MetricStreamState | None + CreationDate: Timestamp | None + LastUpdateDate: Timestamp | None + OutputFormat: MetricStreamOutputFormat | None + StatisticsConfigurations: MetricStreamStatisticsConfigurations | None + IncludeLinkedAccountsMetrics: IncludeLinkedAccountsMetrics | None class GetMetricWidgetImageInput(ServiceRequest): MetricWidget: MetricWidget - OutputFormat: Optional[OutputFormat] + OutputFormat: OutputFormat | None MetricWidgetImage = bytes class GetMetricWidgetImageOutput(TypedDict, total=False): - MetricWidgetImage: Optional[MetricWidgetImage] + MetricWidgetImage: MetricWidgetImage | None + + +class ListAlarmMuteRulesInput(ServiceRequest): + AlarmName: Name | None + Statuses: AlarmMuteRuleStatuses | None + MaxRecords: MaxRecords | None + NextToken: NextToken | None + + +class ListAlarmMuteRulesOutput(TypedDict, total=False): + AlarmMuteRuleSummaries: AlarmMuteRuleSummaries | None + NextToken: NextToken | None class ListDashboardsInput(ServiceRequest): - DashboardNamePrefix: Optional[DashboardNamePrefix] - NextToken: Optional[NextToken] + DashboardNamePrefix: DashboardNamePrefix | None + NextToken: NextToken | None class ListDashboardsOutput(TypedDict, total=False): - DashboardEntries: Optional[DashboardEntries] - NextToken: Optional[NextToken] + DashboardEntries: DashboardEntries | None + NextToken: NextToken | None class ListManagedInsightRulesInput(ServiceRequest): ResourceARN: AmazonResourceName - NextToken: Optional[NextToken] - MaxResults: Optional[InsightRuleMaxResults] + NextToken: NextToken | None + MaxResults: InsightRuleMaxResults | None class ManagedRuleState(TypedDict, total=False): @@ -936,60 +1012,60 @@ class ManagedRuleState(TypedDict, total=False): class ManagedRuleDescription(TypedDict, total=False): - TemplateName: Optional[TemplateName] - ResourceARN: Optional[AmazonResourceName] - RuleState: Optional[ManagedRuleState] + TemplateName: TemplateName | None + ResourceARN: AmazonResourceName | None + RuleState: ManagedRuleState | None -ManagedRuleDescriptions = List[ManagedRuleDescription] +ManagedRuleDescriptions = list[ManagedRuleDescription] class ListManagedInsightRulesOutput(TypedDict, total=False): - ManagedRules: Optional[ManagedRuleDescriptions] - NextToken: Optional[NextToken] + ManagedRules: ManagedRuleDescriptions | None + NextToken: NextToken | None class ListMetricStreamsInput(ServiceRequest): - NextToken: Optional[NextToken] - MaxResults: Optional[ListMetricStreamsMaxResults] + NextToken: NextToken | None + MaxResults: ListMetricStreamsMaxResults | None class MetricStreamEntry(TypedDict, total=False): - Arn: Optional[AmazonResourceName] - CreationDate: Optional[Timestamp] - LastUpdateDate: Optional[Timestamp] - Name: Optional[MetricStreamName] - FirehoseArn: Optional[AmazonResourceName] - State: Optional[MetricStreamState] - OutputFormat: Optional[MetricStreamOutputFormat] + Arn: AmazonResourceName | None + CreationDate: Timestamp | None + LastUpdateDate: Timestamp | None + Name: MetricStreamName | None + FirehoseArn: AmazonResourceName | None + State: MetricStreamState | None + OutputFormat: MetricStreamOutputFormat | None -MetricStreamEntries = List[MetricStreamEntry] +MetricStreamEntries = list[MetricStreamEntry] class ListMetricStreamsOutput(TypedDict, total=False): - NextToken: Optional[NextToken] - Entries: Optional[MetricStreamEntries] + NextToken: NextToken | None + Entries: MetricStreamEntries | None class ListMetricsInput(ServiceRequest): - Namespace: Optional[Namespace] - MetricName: Optional[MetricName] - Dimensions: Optional[DimensionFilters] - NextToken: Optional[NextToken] - RecentlyActive: Optional[RecentlyActive] - IncludeLinkedAccounts: Optional[IncludeLinkedAccounts] - OwningAccount: Optional[AccountId] + Namespace: Namespace | None + MetricName: MetricName | None + Dimensions: DimensionFilters | None + NextToken: NextToken | None + RecentlyActive: RecentlyActive | None + IncludeLinkedAccounts: IncludeLinkedAccounts | None + OwningAccount: AccountId | None -OwningAccounts = List[AccountId] -Metrics = List[Metric] +OwningAccounts = list[AccountId] +Metrics = list[Metric] class ListMetricsOutput(TypedDict, total=False): - Metrics: Optional[Metrics] - NextToken: Optional[NextToken] - OwningAccounts: Optional[OwningAccounts] + Metrics: Metrics | None + NextToken: NextToken | None + OwningAccounts: OwningAccounts | None class ListTagsForResourceInput(ServiceRequest): @@ -1001,32 +1077,42 @@ class Tag(TypedDict, total=False): Value: TagValue -TagList = List[Tag] +TagList = list[Tag] class ListTagsForResourceOutput(TypedDict, total=False): - Tags: Optional[TagList] + Tags: TagList | None class ManagedRule(TypedDict, total=False): TemplateName: TemplateName ResourceARN: AmazonResourceName - Tags: Optional[TagList] + Tags: TagList | None + + +ManagedRules = list[ManagedRule] +MetricStreamNames = list[MetricStreamName] -ManagedRules = List[ManagedRule] -MetricStreamNames = List[MetricStreamName] +class PutAlarmMuteRuleInput(ServiceRequest): + Name: Name + Description: AlarmDescription | None + Rule: Rule + MuteTargets: MuteTargets | None + Tags: TagList | None + StartDate: Timestamp | None + ExpireDate: Timestamp | None class PutAnomalyDetectorInput(ServiceRequest): - Namespace: Optional[Namespace] - MetricName: Optional[MetricName] - Dimensions: Optional[Dimensions] - Stat: Optional[AnomalyDetectorMetricStat] - Configuration: Optional[AnomalyDetectorConfiguration] - MetricCharacteristics: Optional[MetricCharacteristics] - SingleMetricAnomalyDetector: Optional[SingleMetricAnomalyDetector] - MetricMathAnomalyDetector: Optional[MetricMathAnomalyDetector] + Namespace: Namespace | None + MetricName: MetricName | None + Dimensions: Dimensions | None + Stat: AnomalyDetectorMetricStat | None + Configuration: AnomalyDetectorConfiguration | None + MetricCharacteristics: MetricCharacteristics | None + SingleMetricAnomalyDetector: SingleMetricAnomalyDetector | None + MetricMathAnomalyDetector: MetricMathAnomalyDetector | None class PutAnomalyDetectorOutput(TypedDict, total=False): @@ -1034,17 +1120,17 @@ class PutAnomalyDetectorOutput(TypedDict, total=False): class PutCompositeAlarmInput(ServiceRequest): - ActionsEnabled: Optional[ActionsEnabled] - AlarmActions: Optional[ResourceList] - AlarmDescription: Optional[AlarmDescription] + ActionsEnabled: ActionsEnabled | None + AlarmActions: ResourceList | None + AlarmDescription: AlarmDescription | None AlarmName: AlarmName AlarmRule: AlarmRule - InsufficientDataActions: Optional[ResourceList] - OKActions: Optional[ResourceList] - Tags: Optional[TagList] - ActionsSuppressor: Optional[AlarmArn] - ActionsSuppressorWaitPeriod: Optional[SuppressorPeriod] - ActionsSuppressorExtensionPeriod: Optional[SuppressorPeriod] + InsufficientDataActions: ResourceList | None + OKActions: ResourceList | None + Tags: TagList | None + ActionsSuppressor: AlarmArn | None + ActionsSuppressorWaitPeriod: SuppressorPeriod | None + ActionsSuppressorExtensionPeriod: SuppressorPeriod | None class PutDashboardInput(ServiceRequest): @@ -1053,15 +1139,15 @@ class PutDashboardInput(ServiceRequest): class PutDashboardOutput(TypedDict, total=False): - DashboardValidationMessages: Optional[DashboardValidationMessages] + DashboardValidationMessages: DashboardValidationMessages | None class PutInsightRuleInput(ServiceRequest): RuleName: InsightRuleName - RuleState: Optional[InsightRuleState] + RuleState: InsightRuleState | None RuleDefinition: InsightRuleDefinition - Tags: Optional[TagList] - ApplyOnTransformedLogs: Optional[InsightRuleOnTransformedLogs] + Tags: TagList | None + ApplyOnTransformedLogs: InsightRuleOnTransformedLogs | None class PutInsightRuleOutput(TypedDict, total=False): @@ -1073,62 +1159,62 @@ class PutManagedInsightRulesInput(ServiceRequest): class PutManagedInsightRulesOutput(TypedDict, total=False): - Failures: Optional[BatchFailures] + Failures: BatchFailures | None class PutMetricAlarmInput(ServiceRequest): AlarmName: AlarmName - AlarmDescription: Optional[AlarmDescription] - ActionsEnabled: Optional[ActionsEnabled] - OKActions: Optional[ResourceList] - AlarmActions: Optional[ResourceList] - InsufficientDataActions: Optional[ResourceList] - MetricName: Optional[MetricName] - Namespace: Optional[Namespace] - Statistic: Optional[Statistic] - ExtendedStatistic: Optional[ExtendedStatistic] - Dimensions: Optional[Dimensions] - Period: Optional[Period] - Unit: Optional[StandardUnit] + AlarmDescription: AlarmDescription | None + ActionsEnabled: ActionsEnabled | None + OKActions: ResourceList | None + AlarmActions: ResourceList | None + InsufficientDataActions: ResourceList | None + MetricName: MetricName | None + Namespace: Namespace | None + Statistic: Statistic | None + ExtendedStatistic: ExtendedStatistic | None + Dimensions: Dimensions | None + Period: Period | None + Unit: StandardUnit | None EvaluationPeriods: EvaluationPeriods - DatapointsToAlarm: Optional[DatapointsToAlarm] - Threshold: Optional[Threshold] + DatapointsToAlarm: DatapointsToAlarm | None + Threshold: Threshold | None ComparisonOperator: ComparisonOperator - TreatMissingData: Optional[TreatMissingData] - EvaluateLowSampleCountPercentile: Optional[EvaluateLowSampleCountPercentile] - Metrics: Optional[MetricDataQueries] - Tags: Optional[TagList] - ThresholdMetricId: Optional[MetricId] + TreatMissingData: TreatMissingData | None + EvaluateLowSampleCountPercentile: EvaluateLowSampleCountPercentile | None + Metrics: MetricDataQueries | None + Tags: TagList | None + ThresholdMetricId: MetricId | None class PutMetricDataInput(ServiceRequest): Namespace: Namespace - MetricData: Optional[MetricData] - EntityMetricData: Optional[EntityMetricDataList] - StrictEntityValidation: Optional[StrictEntityValidation] + MetricData: MetricData | None + EntityMetricData: EntityMetricDataList | None + StrictEntityValidation: StrictEntityValidation | None class PutMetricStreamInput(ServiceRequest): Name: MetricStreamName - IncludeFilters: Optional[MetricStreamFilters] - ExcludeFilters: Optional[MetricStreamFilters] + IncludeFilters: MetricStreamFilters | None + ExcludeFilters: MetricStreamFilters | None FirehoseArn: AmazonResourceName RoleArn: AmazonResourceName OutputFormat: MetricStreamOutputFormat - Tags: Optional[TagList] - StatisticsConfigurations: Optional[MetricStreamStatisticsConfigurations] - IncludeLinkedAccountsMetrics: Optional[IncludeLinkedAccountsMetrics] + Tags: TagList | None + StatisticsConfigurations: MetricStreamStatisticsConfigurations | None + IncludeLinkedAccountsMetrics: IncludeLinkedAccountsMetrics | None class PutMetricStreamOutput(TypedDict, total=False): - Arn: Optional[AmazonResourceName] + Arn: AmazonResourceName | None class SetAlarmStateInput(ServiceRequest): AlarmName: AlarmName StateValue: StateValue StateReason: StateReason - StateReasonData: Optional[StateReasonData] + StateReasonData: StateReasonData | None class StartMetricStreamsInput(ServiceRequest): @@ -1147,7 +1233,7 @@ class StopMetricStreamsOutput(TypedDict, total=False): pass -TagKeyList = List[TagKey] +TagKeyList = list[TagKey] class TagResourceInput(ServiceRequest): @@ -1169,8 +1255,14 @@ class UntagResourceOutput(TypedDict, total=False): class CloudwatchApi: - service = "cloudwatch" - version = "2010-08-01" + service: str = "cloudwatch" + version: str = "2010-08-01" + + @handler("DeleteAlarmMuteRule") + def delete_alarm_mute_rule( + self, context: RequestContext, alarm_mute_rule_name: Name, **kwargs + ) -> None: + raise NotImplementedError @handler("DeleteAlarms") def delete_alarms(self, context: RequestContext, alarm_names: AlarmNames, **kwargs) -> None: @@ -1315,6 +1407,12 @@ def enable_insight_rules( ) -> EnableInsightRulesOutput: raise NotImplementedError + @handler("GetAlarmMuteRule") + def get_alarm_mute_rule( + self, context: RequestContext, alarm_mute_rule_name: Name, **kwargs + ) -> GetAlarmMuteRuleOutput: + raise NotImplementedError + @handler("GetDashboard") def get_dashboard( self, context: RequestContext, dashboard_name: DashboardName, **kwargs @@ -1384,6 +1482,18 @@ def get_metric_widget_image( ) -> GetMetricWidgetImageOutput: raise NotImplementedError + @handler("ListAlarmMuteRules") + def list_alarm_mute_rules( + self, + context: RequestContext, + alarm_name: Name | None = None, + statuses: AlarmMuteRuleStatuses | None = None, + max_records: MaxRecords | None = None, + next_token: NextToken | None = None, + **kwargs, + ) -> ListAlarmMuteRulesOutput: + raise NotImplementedError + @handler("ListDashboards") def list_dashboards( self, @@ -1436,6 +1546,21 @@ def list_tags_for_resource( ) -> ListTagsForResourceOutput: raise NotImplementedError + @handler("PutAlarmMuteRule") + def put_alarm_mute_rule( + self, + context: RequestContext, + name: Name, + rule: Rule, + description: AlarmDescription | None = None, + mute_targets: MuteTargets | None = None, + tags: TagList | None = None, + start_date: Timestamp | None = None, + expire_date: Timestamp | None = None, + **kwargs, + ) -> None: + raise NotImplementedError + @handler("PutAnomalyDetector") def put_anomaly_detector( self, diff --git a/localstack-core/localstack/aws/api/config/__init__.py b/localstack-core/localstack/aws/api/config/__init__.py index c4befd59cdab4..6e137a8b1ed42 100644 --- a/localstack-core/localstack/aws/api/config/__init__.py +++ b/localstack-core/localstack/aws/api/config/__init__.py @@ -1,6 +1,6 @@ from datetime import datetime from enum import StrEnum -from typing import Dict, List, Optional, TypedDict +from typing import TypedDict from localstack.aws.api import RequestContext, ServiceException, ServiceRequest, handler @@ -780,6 +780,99 @@ class ResourceType(StrEnum): AWS_SageMaker_InferenceExperiment = "AWS::SageMaker::InferenceExperiment" AWS_SecurityHub_Standard = "AWS::SecurityHub::Standard" AWS_Transfer_Profile = "AWS::Transfer::Profile" + AWS_CloudFormation_StackSet = "AWS::CloudFormation::StackSet" + AWS_MediaPackageV2_Channel = "AWS::MediaPackageV2::Channel" + AWS_S3_AccessGrantsLocation = "AWS::S3::AccessGrantsLocation" + AWS_S3_AccessGrant = "AWS::S3::AccessGrant" + AWS_S3_AccessGrantsInstance = "AWS::S3::AccessGrantsInstance" + AWS_EMRServerless_Application = "AWS::EMRServerless::Application" + AWS_Config_AggregationAuthorization = "AWS::Config::AggregationAuthorization" + AWS_Bedrock_ApplicationInferenceProfile = "AWS::Bedrock::ApplicationInferenceProfile" + AWS_ApiGatewayV2_Integration = "AWS::ApiGatewayV2::Integration" + AWS_SageMaker_MlflowTrackingServer = "AWS::SageMaker::MlflowTrackingServer" + AWS_SageMaker_ModelBiasJobDefinition = "AWS::SageMaker::ModelBiasJobDefinition" + AWS_SecretsManager_RotationSchedule = "AWS::SecretsManager::RotationSchedule" + AWS_Deadline_QueueFleetAssociation = "AWS::Deadline::QueueFleetAssociation" + AWS_ECR_RepositoryCreationTemplate = "AWS::ECR::RepositoryCreationTemplate" + AWS_CloudFormation_LambdaHook = "AWS::CloudFormation::LambdaHook" + AWS_EC2_SubnetNetworkAclAssociation = "AWS::EC2::SubnetNetworkAclAssociation" + AWS_ApiGateway_UsagePlan = "AWS::ApiGateway::UsagePlan" + AWS_AppConfig_Extension = "AWS::AppConfig::Extension" + AWS_Deadline_Fleet = "AWS::Deadline::Fleet" + AWS_EMR_Studio = "AWS::EMR::Studio" + AWS_S3Tables_TableBucket = "AWS::S3Tables::TableBucket" + AWS_CloudFront_RealtimeLogConfig = "AWS::CloudFront::RealtimeLogConfig" + AWS_BackupGateway_Hypervisor = "AWS::BackupGateway::Hypervisor" + AWS_BCMDataExports_Export = "AWS::BCMDataExports::Export" + AWS_CloudFormation_GuardHook = "AWS::CloudFormation::GuardHook" + AWS_CloudFront_PublicKey = "AWS::CloudFront::PublicKey" + AWS_CloudTrail_EventDataStore = "AWS::CloudTrail::EventDataStore" + AWS_EntityResolution_IdMappingWorkflow = "AWS::EntityResolution::IdMappingWorkflow" + AWS_EntityResolution_SchemaMapping = "AWS::EntityResolution::SchemaMapping" + AWS_IoT_DomainConfiguration = "AWS::IoT::DomainConfiguration" + AWS_PCAConnectorAD_DirectoryRegistration = "AWS::PCAConnectorAD::DirectoryRegistration" + AWS_RDS_Integration = "AWS::RDS::Integration" + AWS_Config_ConformancePack = "AWS::Config::ConformancePack" + AWS_RolesAnywhere_Profile = "AWS::RolesAnywhere::Profile" + AWS_CodeArtifact_Domain = "AWS::CodeArtifact::Domain" + AWS_Backup_RestoreTestingPlan = "AWS::Backup::RestoreTestingPlan" + AWS_Config_StoredQuery = "AWS::Config::StoredQuery" + AWS_SageMaker_DataQualityJobDefinition = "AWS::SageMaker::DataQualityJobDefinition" + AWS_SageMaker_ModelExplainabilityJobDefinition = ( + "AWS::SageMaker::ModelExplainabilityJobDefinition" + ) + AWS_SageMaker_ModelQualityJobDefinition = "AWS::SageMaker::ModelQualityJobDefinition" + AWS_SageMaker_StudioLifecycleConfig = "AWS::SageMaker::StudioLifecycleConfig" + AWS_SES_DedicatedIpPool = "AWS::SES::DedicatedIpPool" + AWS_SES_MailManagerTrafficPolicy = "AWS::SES::MailManagerTrafficPolicy" + AWS_SSM_ResourceDataSync = "AWS::SSM::ResourceDataSync" + AWS_BedrockAgentCore_Runtime = "AWS::BedrockAgentCore::Runtime" + AWS_BedrockAgentCore_BrowserCustom = "AWS::BedrockAgentCore::BrowserCustom" + AWS_ElasticLoadBalancingV2_TargetGroup = "AWS::ElasticLoadBalancingV2::TargetGroup" + AWS_EMRContainers_VirtualCluster = "AWS::EMRContainers::VirtualCluster" + AWS_EntityResolution_MatchingWorkflow = "AWS::EntityResolution::MatchingWorkflow" + AWS_IoTCoreDeviceAdvisor_SuiteDefinition = "AWS::IoTCoreDeviceAdvisor::SuiteDefinition" + AWS_EC2_SecurityGroupVpcAssociation = "AWS::EC2::SecurityGroupVpcAssociation" + AWS_EC2_VerifiedAccessInstance = "AWS::EC2::VerifiedAccessInstance" + AWS_KafkaConnect_CustomPlugin = "AWS::KafkaConnect::CustomPlugin" + AWS_NetworkManager_TransitGatewayPeering = "AWS::NetworkManager::TransitGatewayPeering" + AWS_OpenSearchServerless_SecurityConfig = "AWS::OpenSearchServerless::SecurityConfig" + AWS_Redshift_Integration = "AWS::Redshift::Integration" + AWS_RolesAnywhere_TrustAnchor = "AWS::RolesAnywhere::TrustAnchor" + AWS_Route53Profiles_ProfileAssociation = "AWS::Route53Profiles::ProfileAssociation" + AWS_SSMIncidents_ResponsePlan = "AWS::SSMIncidents::ResponsePlan" + AWS_Transfer_Server = "AWS::Transfer::Server" + AWS_Glue_Database = "AWS::Glue::Database" + AWS_Organizations_OrganizationalUnit = "AWS::Organizations::OrganizationalUnit" + AWS_EC2_IPAMPoolCidr = "AWS::EC2::IPAMPoolCidr" + AWS_EC2_VPCGatewayAttachment = "AWS::EC2::VPCGatewayAttachment" + AWS_Bedrock_Prompt = "AWS::Bedrock::Prompt" + AWS_Comprehend_Flywheel = "AWS::Comprehend::Flywheel" + AWS_DataSync_Agent = "AWS::DataSync::Agent" + AWS_MediaTailor_LiveSource = "AWS::MediaTailor::LiveSource" + AWS_MSK_ServerlessCluster = "AWS::MSK::ServerlessCluster" + AWS_IoTSiteWise_Asset = "AWS::IoTSiteWise::Asset" + AWS_B2BI_Capability = "AWS::B2BI::Capability" + AWS_CloudFront_KeyValueStore = "AWS::CloudFront::KeyValueStore" + AWS_Deadline_Monitor = "AWS::Deadline::Monitor" + AWS_GuardDuty_MalwareProtectionPlan = "AWS::GuardDuty::MalwareProtectionPlan" + AWS_Location_APIKey = "AWS::Location::APIKey" + AWS_MediaPackageV2_OriginEndpoint = "AWS::MediaPackageV2::OriginEndpoint" + AWS_PCAConnectorAD_Connector = "AWS::PCAConnectorAD::Connector" + AWS_S3Tables_TableBucketPolicy = "AWS::S3Tables::TableBucketPolicy" + AWS_SecretsManager_ResourcePolicy = "AWS::SecretsManager::ResourcePolicy" + AWS_SSMContacts_Contact = "AWS::SSMContacts::Contact" + AWS_IoT_ThingGroup = "AWS::IoT::ThingGroup" + AWS_ImageBuilder_LifecyclePolicy = "AWS::ImageBuilder::LifecyclePolicy" + AWS_GameLift_Build = "AWS::GameLift::Build" + AWS_ECR_ReplicationConfiguration = "AWS::ECR::ReplicationConfiguration" + AWS_EC2_SubnetCidrBlock = "AWS::EC2::SubnetCidrBlock" + AWS_Connect_SecurityProfile = "AWS::Connect::SecurityProfile" + AWS_CleanRoomsML_TrainingDataset = "AWS::CleanRoomsML::TrainingDataset" + AWS_AppStream_AppBlockBuilder = "AWS::AppStream::AppBlockBuilder" + AWS_Route53_DNSSEC = "AWS::Route53::DNSSEC" + AWS_SageMaker_UserProfile = "AWS::SageMaker::UserProfile" + AWS_ApiGateway_Method = "AWS::ApiGateway::Method" class ResourceValueType(StrEnum): @@ -1131,120 +1224,120 @@ class ValidationException(ServiceException): status_code: int = 400 -AggregatorRegionList = List[String] -AccountAggregationSourceAccountList = List[AccountId] +AggregatorRegionList = list[String] +AccountAggregationSourceAccountList = list[AccountId] class AccountAggregationSource(TypedDict, total=False): AccountIds: AccountAggregationSourceAccountList - AllAwsRegions: Optional[Boolean] - AwsRegions: Optional[AggregatorRegionList] + AllAwsRegions: Boolean | None + AwsRegions: AggregatorRegionList | None -AccountAggregationSourceList = List[AccountAggregationSource] +AccountAggregationSourceList = list[AccountAggregationSource] class ComplianceContributorCount(TypedDict, total=False): - CappedCount: Optional[Integer] - CapExceeded: Optional[Boolean] + CappedCount: Integer | None + CapExceeded: Boolean | None class Compliance(TypedDict, total=False): - ComplianceType: Optional[ComplianceType] - ComplianceContributorCount: Optional[ComplianceContributorCount] + ComplianceType: ComplianceType | None + ComplianceContributorCount: ComplianceContributorCount | None class AggregateComplianceByConfigRule(TypedDict, total=False): - ConfigRuleName: Optional[ConfigRuleName] - Compliance: Optional[Compliance] - AccountId: Optional[AccountId] - AwsRegion: Optional[AwsRegion] + ConfigRuleName: ConfigRuleName | None + Compliance: Compliance | None + AccountId: AccountId | None + AwsRegion: AwsRegion | None -AggregateComplianceByConfigRuleList = List[AggregateComplianceByConfigRule] +AggregateComplianceByConfigRuleList = list[AggregateComplianceByConfigRule] class AggregateConformancePackCompliance(TypedDict, total=False): - ComplianceType: Optional[ConformancePackComplianceType] - CompliantRuleCount: Optional[Integer] - NonCompliantRuleCount: Optional[Integer] - TotalRuleCount: Optional[Integer] + ComplianceType: ConformancePackComplianceType | None + CompliantRuleCount: Integer | None + NonCompliantRuleCount: Integer | None + TotalRuleCount: Integer | None class AggregateComplianceByConformancePack(TypedDict, total=False): - ConformancePackName: Optional[ConformancePackName] - Compliance: Optional[AggregateConformancePackCompliance] - AccountId: Optional[AccountId] - AwsRegion: Optional[AwsRegion] + ConformancePackName: ConformancePackName | None + Compliance: AggregateConformancePackCompliance | None + AccountId: AccountId | None + AwsRegion: AwsRegion | None -AggregateComplianceByConformancePackList = List[AggregateComplianceByConformancePack] +AggregateComplianceByConformancePackList = list[AggregateComplianceByConformancePack] Date = datetime class ComplianceSummary(TypedDict, total=False): - CompliantResourceCount: Optional[ComplianceContributorCount] - NonCompliantResourceCount: Optional[ComplianceContributorCount] - ComplianceSummaryTimestamp: Optional[Date] + CompliantResourceCount: ComplianceContributorCount | None + NonCompliantResourceCount: ComplianceContributorCount | None + ComplianceSummaryTimestamp: Date | None class AggregateComplianceCount(TypedDict, total=False): - GroupName: Optional[StringWithCharLimit256] - ComplianceSummary: Optional[ComplianceSummary] + GroupName: StringWithCharLimit256 | None + ComplianceSummary: ComplianceSummary | None -AggregateComplianceCountList = List[AggregateComplianceCount] +AggregateComplianceCountList = list[AggregateComplianceCount] class AggregateConformancePackComplianceCount(TypedDict, total=False): - CompliantConformancePackCount: Optional[Integer] - NonCompliantConformancePackCount: Optional[Integer] + CompliantConformancePackCount: Integer | None + NonCompliantConformancePackCount: Integer | None class AggregateConformancePackComplianceFilters(TypedDict, total=False): - ConformancePackName: Optional[ConformancePackName] - ComplianceType: Optional[ConformancePackComplianceType] - AccountId: Optional[AccountId] - AwsRegion: Optional[AwsRegion] + ConformancePackName: ConformancePackName | None + ComplianceType: ConformancePackComplianceType | None + AccountId: AccountId | None + AwsRegion: AwsRegion | None class AggregateConformancePackComplianceSummary(TypedDict, total=False): - ComplianceSummary: Optional[AggregateConformancePackComplianceCount] - GroupName: Optional[StringWithCharLimit256] + ComplianceSummary: AggregateConformancePackComplianceCount | None + GroupName: StringWithCharLimit256 | None class AggregateConformancePackComplianceSummaryFilters(TypedDict, total=False): - AccountId: Optional[AccountId] - AwsRegion: Optional[AwsRegion] + AccountId: AccountId | None + AwsRegion: AwsRegion | None -AggregateConformancePackComplianceSummaryList = List[AggregateConformancePackComplianceSummary] +AggregateConformancePackComplianceSummaryList = list[AggregateConformancePackComplianceSummary] class EvaluationResultQualifier(TypedDict, total=False): - ConfigRuleName: Optional[ConfigRuleName] - ResourceType: Optional[StringWithCharLimit256] - ResourceId: Optional[BaseResourceId] - EvaluationMode: Optional[EvaluationMode] + ConfigRuleName: ConfigRuleName | None + ResourceType: StringWithCharLimit256 | None + ResourceId: BaseResourceId | None + EvaluationMode: EvaluationMode | None class EvaluationResultIdentifier(TypedDict, total=False): - EvaluationResultQualifier: Optional[EvaluationResultQualifier] - OrderingTimestamp: Optional[Date] - ResourceEvaluationId: Optional[ResourceEvaluationId] + EvaluationResultQualifier: EvaluationResultQualifier | None + OrderingTimestamp: Date | None + ResourceEvaluationId: ResourceEvaluationId | None class AggregateEvaluationResult(TypedDict, total=False): - EvaluationResultIdentifier: Optional[EvaluationResultIdentifier] - ComplianceType: Optional[ComplianceType] - ResultRecordedTime: Optional[Date] - ConfigRuleInvokedTime: Optional[Date] - Annotation: Optional[StringWithCharLimit256] - AccountId: Optional[AccountId] - AwsRegion: Optional[AwsRegion] + EvaluationResultIdentifier: EvaluationResultIdentifier | None + ComplianceType: ComplianceType | None + ResultRecordedTime: Date | None + ConfigRuleInvokedTime: Date | None + Annotation: StringWithCharLimit256 | None + AccountId: AccountId | None + AwsRegion: AwsRegion | None -AggregateEvaluationResultList = List[AggregateEvaluationResult] +AggregateEvaluationResultList = list[AggregateEvaluationResult] class AggregateResourceIdentifier(TypedDict, total=False): @@ -1252,53 +1345,53 @@ class AggregateResourceIdentifier(TypedDict, total=False): SourceRegion: AwsRegion ResourceId: ResourceId ResourceType: ResourceType - ResourceName: Optional[ResourceName] + ResourceName: ResourceName | None class AggregatedSourceStatus(TypedDict, total=False): - SourceId: Optional[String] - SourceType: Optional[AggregatedSourceType] - AwsRegion: Optional[AwsRegion] - LastUpdateStatus: Optional[AggregatedSourceStatusType] - LastUpdateTime: Optional[Date] - LastErrorCode: Optional[String] - LastErrorMessage: Optional[String] + SourceId: String | None + SourceType: AggregatedSourceType | None + AwsRegion: AwsRegion | None + LastUpdateStatus: AggregatedSourceStatusType | None + LastUpdateTime: Date | None + LastErrorCode: String | None + LastErrorMessage: String | None -AggregatedSourceStatusList = List[AggregatedSourceStatus] -AggregatedSourceStatusTypeList = List[AggregatedSourceStatusType] +AggregatedSourceStatusList = list[AggregatedSourceStatus] +AggregatedSourceStatusTypeList = list[AggregatedSourceStatusType] class AggregationAuthorization(TypedDict, total=False): - AggregationAuthorizationArn: Optional[String] - AuthorizedAccountId: Optional[AccountId] - AuthorizedAwsRegion: Optional[AwsRegion] - CreationTime: Optional[Date] + AggregationAuthorizationArn: String | None + AuthorizedAccountId: AccountId | None + AuthorizedAwsRegion: AwsRegion | None + CreationTime: Date | None -AggregationAuthorizationList = List[AggregationAuthorization] -ResourceTypeValueList = List[ResourceTypeValue] +AggregationAuthorizationList = list[AggregationAuthorization] +ResourceTypeValueList = list[ResourceTypeValue] class AggregatorFilterResourceType(TypedDict, total=False): - Type: Optional[AggregatorFilterType] - Value: Optional[ResourceTypeValueList] + Type: AggregatorFilterType | None + Value: ResourceTypeValueList | None -ServicePrincipalValueList = List[ServicePrincipalValue] +ServicePrincipalValueList = list[ServicePrincipalValue] class AggregatorFilterServicePrincipal(TypedDict, total=False): - Type: Optional[AggregatorFilterType] - Value: Optional[ServicePrincipalValueList] + Type: AggregatorFilterType | None + Value: ServicePrincipalValueList | None class AggregatorFilters(TypedDict, total=False): - ResourceType: Optional[AggregatorFilterResourceType] - ServicePrincipal: Optional[AggregatorFilterServicePrincipal] + ResourceType: AggregatorFilterResourceType | None + ServicePrincipal: AggregatorFilterServicePrincipal | None -ResourceTypeList = List[ResourceType] +ResourceTypeList = list[ResourceType] class AssociateResourceTypesRequest(ServiceRequest): @@ -1306,47 +1399,47 @@ class AssociateResourceTypesRequest(ServiceRequest): ResourceTypes: ResourceTypeList -RecordingModeResourceTypesList = List[ResourceType] +RecordingModeResourceTypesList = list[ResourceType] class RecordingModeOverride(TypedDict, total=False): - description: Optional[Description] + description: Description | None resourceTypes: RecordingModeResourceTypesList recordingFrequency: RecordingFrequency -RecordingModeOverrides = List[RecordingModeOverride] +RecordingModeOverrides = list[RecordingModeOverride] class RecordingMode(TypedDict, total=False): recordingFrequency: RecordingFrequency - recordingModeOverrides: Optional[RecordingModeOverrides] + recordingModeOverrides: RecordingModeOverrides | None class RecordingStrategy(TypedDict, total=False): - useOnly: Optional[RecordingStrategyType] + useOnly: RecordingStrategyType | None class ExclusionByResourceTypes(TypedDict, total=False): - resourceTypes: Optional[ResourceTypeList] + resourceTypes: ResourceTypeList | None class RecordingGroup(TypedDict, total=False): - allSupported: Optional[AllSupported] - includeGlobalResourceTypes: Optional[IncludeGlobalResourceTypes] - resourceTypes: Optional[ResourceTypeList] - exclusionByResourceTypes: Optional[ExclusionByResourceTypes] - recordingStrategy: Optional[RecordingStrategy] + allSupported: AllSupported | None + includeGlobalResourceTypes: IncludeGlobalResourceTypes | None + resourceTypes: ResourceTypeList | None + exclusionByResourceTypes: ExclusionByResourceTypes | None + recordingStrategy: RecordingStrategy | None class ConfigurationRecorder(TypedDict, total=False): - arn: Optional[AmazonResourceName] - name: Optional[RecorderName] - roleARN: Optional[String] - recordingGroup: Optional[RecordingGroup] - recordingMode: Optional[RecordingMode] - recordingScope: Optional[RecordingScope] - servicePrincipal: Optional[ServicePrincipal] + arn: AmazonResourceName | None + name: RecorderName | None + roleARN: String | None + recordingGroup: RecordingGroup | None + recordingMode: RecordingMode | None + recordingScope: RecordingScope | None + servicePrincipal: ServicePrincipal | None class AssociateResourceTypesResponse(TypedDict, total=False): @@ -1355,32 +1448,32 @@ class AssociateResourceTypesResponse(TypedDict, total=False): AutoRemediationAttemptSeconds = int ConfigurationItemDeliveryTime = datetime -SupplementaryConfiguration = Dict[SupplementaryConfigurationName, SupplementaryConfigurationValue] +SupplementaryConfiguration = dict[SupplementaryConfigurationName, SupplementaryConfigurationValue] ResourceCreationTime = datetime ConfigurationItemCaptureTime = datetime class BaseConfigurationItem(TypedDict, total=False): - version: Optional[Version] - accountId: Optional[AccountId] - configurationItemCaptureTime: Optional[ConfigurationItemCaptureTime] - configurationItemStatus: Optional[ConfigurationItemStatus] - configurationStateId: Optional[ConfigurationStateId] - arn: Optional[ARN] - resourceType: Optional[ResourceType] - resourceId: Optional[ResourceId] - resourceName: Optional[ResourceName] - awsRegion: Optional[AwsRegion] - availabilityZone: Optional[AvailabilityZone] - resourceCreationTime: Optional[ResourceCreationTime] - configuration: Optional[Configuration] - supplementaryConfiguration: Optional[SupplementaryConfiguration] - recordingFrequency: Optional[RecordingFrequency] - configurationItemDeliveryTime: Optional[ConfigurationItemDeliveryTime] - - -BaseConfigurationItems = List[BaseConfigurationItem] -ResourceIdentifiersList = List[AggregateResourceIdentifier] + version: Version | None + accountId: AccountId | None + configurationItemCaptureTime: ConfigurationItemCaptureTime | None + configurationItemStatus: ConfigurationItemStatus | None + configurationStateId: ConfigurationStateId | None + arn: ARN | None + resourceType: ResourceType | None + resourceId: ResourceId | None + resourceName: ResourceName | None + awsRegion: AwsRegion | None + availabilityZone: AvailabilityZone | None + resourceCreationTime: ResourceCreationTime | None + configuration: Configuration | None + supplementaryConfiguration: SupplementaryConfiguration | None + recordingFrequency: RecordingFrequency | None + configurationItemDeliveryTime: ConfigurationItemDeliveryTime | None + + +BaseConfigurationItems = list[BaseConfigurationItem] +ResourceIdentifiersList = list[AggregateResourceIdentifier] class BatchGetAggregateResourceConfigRequest(ServiceRequest): @@ -1388,12 +1481,12 @@ class BatchGetAggregateResourceConfigRequest(ServiceRequest): ResourceIdentifiers: ResourceIdentifiersList -UnprocessedResourceIdentifierList = List[AggregateResourceIdentifier] +UnprocessedResourceIdentifierList = list[AggregateResourceIdentifier] class BatchGetAggregateResourceConfigResponse(TypedDict, total=False): - BaseConfigurationItems: Optional[BaseConfigurationItems] - UnprocessedResourceIdentifiers: Optional[UnprocessedResourceIdentifierList] + BaseConfigurationItems: BaseConfigurationItems | None + UnprocessedResourceIdentifiers: UnprocessedResourceIdentifierList | None class ResourceKey(TypedDict, total=False): @@ -1401,7 +1494,7 @@ class ResourceKey(TypedDict, total=False): resourceId: ResourceId -ResourceKeys = List[ResourceKey] +ResourceKeys = list[ResourceKey] class BatchGetResourceConfigRequest(ServiceRequest): @@ -1409,256 +1502,256 @@ class BatchGetResourceConfigRequest(ServiceRequest): class BatchGetResourceConfigResponse(TypedDict, total=False): - baseConfigurationItems: Optional[BaseConfigurationItems] - unprocessedResourceKeys: Optional[ResourceKeys] + baseConfigurationItems: BaseConfigurationItems | None + unprocessedResourceKeys: ResourceKeys | None class ComplianceByConfigRule(TypedDict, total=False): - ConfigRuleName: Optional[StringWithCharLimit64] - Compliance: Optional[Compliance] + ConfigRuleName: StringWithCharLimit64 | None + Compliance: Compliance | None -ComplianceByConfigRules = List[ComplianceByConfigRule] +ComplianceByConfigRules = list[ComplianceByConfigRule] class ComplianceByResource(TypedDict, total=False): - ResourceType: Optional[StringWithCharLimit256] - ResourceId: Optional[BaseResourceId] - Compliance: Optional[Compliance] + ResourceType: StringWithCharLimit256 | None + ResourceId: BaseResourceId | None + Compliance: Compliance | None -ComplianceByResources = List[ComplianceByResource] -ComplianceResourceTypes = List[StringWithCharLimit256] +ComplianceByResources = list[ComplianceByResource] +ComplianceResourceTypes = list[StringWithCharLimit256] class ComplianceSummaryByResourceType(TypedDict, total=False): - ResourceType: Optional[StringWithCharLimit256] - ComplianceSummary: Optional[ComplianceSummary] + ResourceType: StringWithCharLimit256 | None + ComplianceSummary: ComplianceSummary | None -ComplianceSummariesByResourceType = List[ComplianceSummaryByResourceType] -ComplianceTypes = List[ComplianceType] +ComplianceSummariesByResourceType = list[ComplianceSummaryByResourceType] +ComplianceTypes = list[ComplianceType] class ConfigExportDeliveryInfo(TypedDict, total=False): - lastStatus: Optional[DeliveryStatus] - lastErrorCode: Optional[String] - lastErrorMessage: Optional[String] - lastAttemptTime: Optional[Date] - lastSuccessfulTime: Optional[Date] - nextDeliveryTime: Optional[Date] + lastStatus: DeliveryStatus | None + lastErrorCode: String | None + lastErrorMessage: String | None + lastAttemptTime: Date | None + lastSuccessfulTime: Date | None + nextDeliveryTime: Date | None class EvaluationModeConfiguration(TypedDict, total=False): - Mode: Optional[EvaluationMode] + Mode: EvaluationMode | None -EvaluationModes = List[EvaluationModeConfiguration] +EvaluationModes = list[EvaluationModeConfiguration] class CustomPolicyDetails(TypedDict, total=False): PolicyRuntime: PolicyRuntime PolicyText: PolicyText - EnableDebugLogDelivery: Optional[Boolean] + EnableDebugLogDelivery: Boolean | None class SourceDetail(TypedDict, total=False): - EventSource: Optional[EventSource] - MessageType: Optional[MessageType] - MaximumExecutionFrequency: Optional[MaximumExecutionFrequency] + EventSource: EventSource | None + MessageType: MessageType | None + MaximumExecutionFrequency: MaximumExecutionFrequency | None -SourceDetails = List[SourceDetail] +SourceDetails = list[SourceDetail] class Source(TypedDict, total=False): Owner: Owner - SourceIdentifier: Optional[StringWithCharLimit256] - SourceDetails: Optional[SourceDetails] - CustomPolicyDetails: Optional[CustomPolicyDetails] + SourceIdentifier: StringWithCharLimit256 | None + SourceDetails: SourceDetails | None + CustomPolicyDetails: CustomPolicyDetails | None class Scope(TypedDict, total=False): - ComplianceResourceTypes: Optional[ComplianceResourceTypes] - TagKey: Optional[StringWithCharLimit128] - TagValue: Optional[StringWithCharLimit256] - ComplianceResourceId: Optional[BaseResourceId] + ComplianceResourceTypes: ComplianceResourceTypes | None + TagKey: StringWithCharLimit128 | None + TagValue: StringWithCharLimit256 | None + ComplianceResourceId: BaseResourceId | None class ConfigRule(TypedDict, total=False): - ConfigRuleName: Optional[ConfigRuleName] - ConfigRuleArn: Optional[StringWithCharLimit256] - ConfigRuleId: Optional[StringWithCharLimit64] - Description: Optional[EmptiableStringWithCharLimit256] - Scope: Optional[Scope] + ConfigRuleName: ConfigRuleName | None + ConfigRuleArn: StringWithCharLimit256 | None + ConfigRuleId: StringWithCharLimit64 | None + Description: EmptiableStringWithCharLimit256 | None + Scope: Scope | None Source: Source - InputParameters: Optional[StringWithCharLimit1024] - MaximumExecutionFrequency: Optional[MaximumExecutionFrequency] - ConfigRuleState: Optional[ConfigRuleState] - CreatedBy: Optional[StringWithCharLimit256] - EvaluationModes: Optional[EvaluationModes] + InputParameters: StringWithCharLimit1024 | None + MaximumExecutionFrequency: MaximumExecutionFrequency | None + ConfigRuleState: ConfigRuleState | None + CreatedBy: StringWithCharLimit256 | None + EvaluationModes: EvaluationModes | None class ConfigRuleComplianceFilters(TypedDict, total=False): - ConfigRuleName: Optional[ConfigRuleName] - ComplianceType: Optional[ComplianceType] - AccountId: Optional[AccountId] - AwsRegion: Optional[AwsRegion] + ConfigRuleName: ConfigRuleName | None + ComplianceType: ComplianceType | None + AccountId: AccountId | None + AwsRegion: AwsRegion | None class ConfigRuleComplianceSummaryFilters(TypedDict, total=False): - AccountId: Optional[AccountId] - AwsRegion: Optional[AwsRegion] + AccountId: AccountId | None + AwsRegion: AwsRegion | None class ConfigRuleEvaluationStatus(TypedDict, total=False): - ConfigRuleName: Optional[ConfigRuleName] - ConfigRuleArn: Optional[String] - ConfigRuleId: Optional[String] - LastSuccessfulInvocationTime: Optional[Date] - LastFailedInvocationTime: Optional[Date] - LastSuccessfulEvaluationTime: Optional[Date] - LastFailedEvaluationTime: Optional[Date] - FirstActivatedTime: Optional[Date] - LastDeactivatedTime: Optional[Date] - LastErrorCode: Optional[String] - LastErrorMessage: Optional[String] - FirstEvaluationStarted: Optional[Boolean] - LastDebugLogDeliveryStatus: Optional[String] - LastDebugLogDeliveryStatusReason: Optional[String] - LastDebugLogDeliveryTime: Optional[Date] - - -ConfigRuleEvaluationStatusList = List[ConfigRuleEvaluationStatus] -ConfigRuleNames = List[ConfigRuleName] -ConfigRules = List[ConfigRule] + ConfigRuleName: ConfigRuleName | None + ConfigRuleArn: String | None + ConfigRuleId: String | None + LastSuccessfulInvocationTime: Date | None + LastFailedInvocationTime: Date | None + LastSuccessfulEvaluationTime: Date | None + LastFailedEvaluationTime: Date | None + FirstActivatedTime: Date | None + LastDeactivatedTime: Date | None + LastErrorCode: String | None + LastErrorMessage: String | None + FirstEvaluationStarted: Boolean | None + LastDebugLogDeliveryStatus: String | None + LastDebugLogDeliveryStatusReason: String | None + LastDebugLogDeliveryTime: Date | None + + +ConfigRuleEvaluationStatusList = list[ConfigRuleEvaluationStatus] +ConfigRuleNames = list[ConfigRuleName] +ConfigRules = list[ConfigRule] class ConfigSnapshotDeliveryProperties(TypedDict, total=False): - deliveryFrequency: Optional[MaximumExecutionFrequency] + deliveryFrequency: MaximumExecutionFrequency | None class ConfigStreamDeliveryInfo(TypedDict, total=False): - lastStatus: Optional[DeliveryStatus] - lastErrorCode: Optional[String] - lastErrorMessage: Optional[String] - lastStatusChangeTime: Optional[Date] + lastStatus: DeliveryStatus | None + lastErrorCode: String | None + lastErrorMessage: String | None + lastStatusChangeTime: Date | None class OrganizationAggregationSource(TypedDict, total=False): RoleArn: String - AwsRegions: Optional[AggregatorRegionList] - AllAwsRegions: Optional[Boolean] + AwsRegions: AggregatorRegionList | None + AllAwsRegions: Boolean | None class ConfigurationAggregator(TypedDict, total=False): - ConfigurationAggregatorName: Optional[ConfigurationAggregatorName] - ConfigurationAggregatorArn: Optional[ConfigurationAggregatorArn] - AccountAggregationSources: Optional[AccountAggregationSourceList] - OrganizationAggregationSource: Optional[OrganizationAggregationSource] - CreationTime: Optional[Date] - LastUpdatedTime: Optional[Date] - CreatedBy: Optional[StringWithCharLimit256] - AggregatorFilters: Optional[AggregatorFilters] + ConfigurationAggregatorName: ConfigurationAggregatorName | None + ConfigurationAggregatorArn: ConfigurationAggregatorArn | None + AccountAggregationSources: AccountAggregationSourceList | None + OrganizationAggregationSource: OrganizationAggregationSource | None + CreationTime: Date | None + LastUpdatedTime: Date | None + CreatedBy: StringWithCharLimit256 | None + AggregatorFilters: AggregatorFilters | None -ConfigurationAggregatorList = List[ConfigurationAggregator] -ConfigurationAggregatorNameList = List[ConfigurationAggregatorName] +ConfigurationAggregatorList = list[ConfigurationAggregator] +ConfigurationAggregatorNameList = list[ConfigurationAggregatorName] class Relationship(TypedDict, total=False): - resourceType: Optional[ResourceType] - resourceId: Optional[ResourceId] - resourceName: Optional[ResourceName] - relationshipName: Optional[RelationshipName] + resourceType: ResourceType | None + resourceId: ResourceId | None + resourceName: ResourceName | None + relationshipName: RelationshipName | None -RelationshipList = List[Relationship] -RelatedEventList = List[RelatedEvent] -Tags = Dict[Name, Value] +RelationshipList = list[Relationship] +RelatedEventList = list[RelatedEvent] +Tags = dict[Name, Value] class ConfigurationItem(TypedDict, total=False): - version: Optional[Version] - accountId: Optional[AccountId] - configurationItemCaptureTime: Optional[ConfigurationItemCaptureTime] - configurationItemStatus: Optional[ConfigurationItemStatus] - configurationStateId: Optional[ConfigurationStateId] - configurationItemMD5Hash: Optional[ConfigurationItemMD5Hash] - arn: Optional[ARN] - resourceType: Optional[ResourceType] - resourceId: Optional[ResourceId] - resourceName: Optional[ResourceName] - awsRegion: Optional[AwsRegion] - availabilityZone: Optional[AvailabilityZone] - resourceCreationTime: Optional[ResourceCreationTime] - tags: Optional[Tags] - relatedEvents: Optional[RelatedEventList] - relationships: Optional[RelationshipList] - configuration: Optional[Configuration] - supplementaryConfiguration: Optional[SupplementaryConfiguration] - recordingFrequency: Optional[RecordingFrequency] - configurationItemDeliveryTime: Optional[ConfigurationItemDeliveryTime] - - -ConfigurationItemList = List[ConfigurationItem] -ConfigurationRecorderFilterValues = List[ConfigurationRecorderFilterValue] + version: Version | None + accountId: AccountId | None + configurationItemCaptureTime: ConfigurationItemCaptureTime | None + configurationItemStatus: ConfigurationItemStatus | None + configurationStateId: ConfigurationStateId | None + configurationItemMD5Hash: ConfigurationItemMD5Hash | None + arn: ARN | None + resourceType: ResourceType | None + resourceId: ResourceId | None + resourceName: ResourceName | None + awsRegion: AwsRegion | None + availabilityZone: AvailabilityZone | None + resourceCreationTime: ResourceCreationTime | None + tags: Tags | None + relatedEvents: RelatedEventList | None + relationships: RelationshipList | None + configuration: Configuration | None + supplementaryConfiguration: SupplementaryConfiguration | None + recordingFrequency: RecordingFrequency | None + configurationItemDeliveryTime: ConfigurationItemDeliveryTime | None + + +ConfigurationItemList = list[ConfigurationItem] +ConfigurationRecorderFilterValues = list[ConfigurationRecorderFilterValue] class ConfigurationRecorderFilter(TypedDict, total=False): - filterName: Optional[ConfigurationRecorderFilterName] - filterValue: Optional[ConfigurationRecorderFilterValues] + filterName: ConfigurationRecorderFilterName | None + filterValue: ConfigurationRecorderFilterValues | None -ConfigurationRecorderFilterList = List[ConfigurationRecorderFilter] -ConfigurationRecorderList = List[ConfigurationRecorder] -ConfigurationRecorderNameList = List[RecorderName] +ConfigurationRecorderFilterList = list[ConfigurationRecorderFilter] +ConfigurationRecorderList = list[ConfigurationRecorder] +ConfigurationRecorderNameList = list[RecorderName] class ConfigurationRecorderStatus(TypedDict, total=False): - arn: Optional[AmazonResourceName] - name: Optional[String] - lastStartTime: Optional[Date] - lastStopTime: Optional[Date] - recording: Optional[Boolean] - lastStatus: Optional[RecorderStatus] - lastErrorCode: Optional[String] - lastErrorMessage: Optional[String] - lastStatusChangeTime: Optional[Date] - servicePrincipal: Optional[ServicePrincipal] + arn: AmazonResourceName | None + name: String | None + lastStartTime: Date | None + lastStopTime: Date | None + recording: Boolean | None + lastStatus: RecorderStatus | None + lastErrorCode: String | None + lastErrorMessage: String | None + lastStatusChangeTime: Date | None + servicePrincipal: ServicePrincipal | None -ConfigurationRecorderStatusList = List[ConfigurationRecorderStatus] +ConfigurationRecorderStatusList = list[ConfigurationRecorderStatus] class ConfigurationRecorderSummary(TypedDict, total=False): arn: AmazonResourceName name: RecorderName - servicePrincipal: Optional[ServicePrincipal] + servicePrincipal: ServicePrincipal | None recordingScope: RecordingScope -ConfigurationRecorderSummaries = List[ConfigurationRecorderSummary] -ConformancePackConfigRuleNames = List[StringWithCharLimit64] +ConfigurationRecorderSummaries = list[ConfigurationRecorderSummary] +ConformancePackConfigRuleNames = list[StringWithCharLimit64] class ConformancePackComplianceFilters(TypedDict, total=False): - ConfigRuleNames: Optional[ConformancePackConfigRuleNames] - ComplianceType: Optional[ConformancePackComplianceType] + ConfigRuleNames: ConformancePackConfigRuleNames | None + ComplianceType: ConformancePackComplianceType | None -ConformancePackComplianceResourceIds = List[StringWithCharLimit256] +ConformancePackComplianceResourceIds = list[StringWithCharLimit256] LastUpdatedTime = datetime class ConformancePackComplianceScore(TypedDict, total=False): - Score: Optional[ComplianceScore] - ConformancePackName: Optional[ConformancePackName] - LastUpdatedTime: Optional[LastUpdatedTime] + Score: ComplianceScore | None + ConformancePackName: ConformancePackName | None + LastUpdatedTime: LastUpdatedTime | None -ConformancePackComplianceScores = List[ConformancePackComplianceScore] -ConformancePackNameFilter = List[ConformancePackName] +ConformancePackComplianceScores = list[ConformancePackComplianceScore] +ConformancePackNameFilter = list[ConformancePackName] class ConformancePackComplianceScoresFilters(TypedDict, total=False): @@ -1670,12 +1763,12 @@ class ConformancePackComplianceSummary(TypedDict, total=False): ConformancePackComplianceStatus: ConformancePackComplianceType -ConformancePackComplianceSummaryList = List[ConformancePackComplianceSummary] +ConformancePackComplianceSummaryList = list[ConformancePackComplianceSummary] class TemplateSSMDocumentDetails(TypedDict, total=False): DocumentName: SSMDocumentName - DocumentVersion: Optional[SSMDocumentVersion] + DocumentVersion: SSMDocumentVersion | None class ConformancePackInputParameter(TypedDict, total=False): @@ -1683,29 +1776,29 @@ class ConformancePackInputParameter(TypedDict, total=False): ParameterValue: ParameterValue -ConformancePackInputParameters = List[ConformancePackInputParameter] +ConformancePackInputParameters = list[ConformancePackInputParameter] class ConformancePackDetail(TypedDict, total=False): ConformancePackName: ConformancePackName ConformancePackArn: ConformancePackArn ConformancePackId: ConformancePackId - DeliveryS3Bucket: Optional[DeliveryS3Bucket] - DeliveryS3KeyPrefix: Optional[DeliveryS3KeyPrefix] - ConformancePackInputParameters: Optional[ConformancePackInputParameters] - LastUpdateRequestedTime: Optional[Date] - CreatedBy: Optional[StringWithCharLimit256] - TemplateSSMDocumentDetails: Optional[TemplateSSMDocumentDetails] + DeliveryS3Bucket: DeliveryS3Bucket | None + DeliveryS3KeyPrefix: DeliveryS3KeyPrefix | None + ConformancePackInputParameters: ConformancePackInputParameters | None + LastUpdateRequestedTime: Date | None + CreatedBy: StringWithCharLimit256 | None + TemplateSSMDocumentDetails: TemplateSSMDocumentDetails | None -ConformancePackDetailList = List[ConformancePackDetail] +ConformancePackDetailList = list[ConformancePackDetail] class ConformancePackEvaluationFilters(TypedDict, total=False): - ConfigRuleNames: Optional[ConformancePackConfigRuleNames] - ComplianceType: Optional[ConformancePackComplianceType] - ResourceType: Optional[StringWithCharLimit256] - ResourceIds: Optional[ConformancePackComplianceResourceIds] + ConfigRuleNames: ConformancePackConfigRuleNames | None + ComplianceType: ConformancePackComplianceType | None + ResourceType: StringWithCharLimit256 | None + ResourceIds: ConformancePackComplianceResourceIds | None class ConformancePackEvaluationResult(TypedDict, total=False): @@ -1713,22 +1806,22 @@ class ConformancePackEvaluationResult(TypedDict, total=False): EvaluationResultIdentifier: EvaluationResultIdentifier ConfigRuleInvokedTime: Date ResultRecordedTime: Date - Annotation: Optional[Annotation] + Annotation: Annotation | None -ConformancePackNamesList = List[ConformancePackName] -ConformancePackNamesToSummarizeList = List[ConformancePackName] -ControlsList = List[StringWithCharLimit128] +ConformancePackNamesList = list[ConformancePackName] +ConformancePackNamesToSummarizeList = list[ConformancePackName] +ControlsList = list[StringWithCharLimit128] class ConformancePackRuleCompliance(TypedDict, total=False): - ConfigRuleName: Optional[ConfigRuleName] - ComplianceType: Optional[ConformancePackComplianceType] - Controls: Optional[ControlsList] + ConfigRuleName: ConfigRuleName | None + ComplianceType: ConformancePackComplianceType | None + Controls: ControlsList | None -ConformancePackRuleComplianceList = List[ConformancePackRuleCompliance] -ConformancePackRuleEvaluationResultsList = List[ConformancePackEvaluationResult] +ConformancePackRuleComplianceList = list[ConformancePackRuleCompliance] +ConformancePackRuleEvaluationResultsList = list[ConformancePackEvaluationResult] class ConformancePackStatusDetail(TypedDict, total=False): @@ -1737,13 +1830,13 @@ class ConformancePackStatusDetail(TypedDict, total=False): ConformancePackArn: ConformancePackArn ConformancePackState: ConformancePackState StackArn: StackArn - ConformancePackStatusReason: Optional[ConformancePackStatusReason] + ConformancePackStatusReason: ConformancePackStatusReason | None LastUpdateRequestedTime: Date - LastUpdateCompletedTime: Optional[Date] + LastUpdateCompletedTime: Date | None -ConformancePackStatusDetailsList = List[ConformancePackStatusDetail] -DebugLogDeliveryAccounts = List[AccountId] +ConformancePackStatusDetailsList = list[ConformancePackStatusDetail] +DebugLogDeliveryAccounts = list[AccountId] class DeleteAggregationAuthorizationRequest(ServiceRequest): @@ -1794,7 +1887,7 @@ class DeletePendingAggregationRequestRequest(ServiceRequest): class DeleteRemediationConfigurationRequest(ServiceRequest): ConfigRuleName: ConfigRuleName - ResourceType: Optional[String] + ResourceType: String | None class DeleteRemediationConfigurationResponse(TypedDict, total=False): @@ -1802,11 +1895,11 @@ class DeleteRemediationConfigurationResponse(TypedDict, total=False): class RemediationExceptionResourceKey(TypedDict, total=False): - ResourceType: Optional[StringWithCharLimit256] - ResourceId: Optional[StringWithCharLimit1024] + ResourceType: StringWithCharLimit256 | None + ResourceId: StringWithCharLimit1024 | None -RemediationExceptionResourceKeys = List[RemediationExceptionResourceKey] +RemediationExceptionResourceKeys = list[RemediationExceptionResourceKey] class DeleteRemediationExceptionsRequest(ServiceRequest): @@ -1815,15 +1908,15 @@ class DeleteRemediationExceptionsRequest(ServiceRequest): class FailedDeleteRemediationExceptionsBatch(TypedDict, total=False): - FailureMessage: Optional[String] - FailedItems: Optional[RemediationExceptionResourceKeys] + FailureMessage: String | None + FailedItems: RemediationExceptionResourceKeys | None -FailedDeleteRemediationExceptionsBatches = List[FailedDeleteRemediationExceptionsBatch] +FailedDeleteRemediationExceptionsBatches = list[FailedDeleteRemediationExceptionsBatch] class DeleteRemediationExceptionsResponse(TypedDict, total=False): - FailedBatches: Optional[FailedDeleteRemediationExceptionsBatches] + FailedBatches: FailedDeleteRemediationExceptionsBatches | None class DeleteResourceConfigRequest(ServiceRequest): @@ -1857,368 +1950,368 @@ class DeliverConfigSnapshotRequest(ServiceRequest): class DeliverConfigSnapshotResponse(TypedDict, total=False): - configSnapshotId: Optional[String] + configSnapshotId: String | None class DeliveryChannel(TypedDict, total=False): - name: Optional[ChannelName] - s3BucketName: Optional[String] - s3KeyPrefix: Optional[String] - s3KmsKeyArn: Optional[String] - snsTopicARN: Optional[String] - configSnapshotDeliveryProperties: Optional[ConfigSnapshotDeliveryProperties] + name: ChannelName | None + s3BucketName: String | None + s3KeyPrefix: String | None + s3KmsKeyArn: String | None + snsTopicARN: String | None + configSnapshotDeliveryProperties: ConfigSnapshotDeliveryProperties | None -DeliveryChannelList = List[DeliveryChannel] -DeliveryChannelNameList = List[ChannelName] +DeliveryChannelList = list[DeliveryChannel] +DeliveryChannelNameList = list[ChannelName] class DeliveryChannelStatus(TypedDict, total=False): - name: Optional[String] - configSnapshotDeliveryInfo: Optional[ConfigExportDeliveryInfo] - configHistoryDeliveryInfo: Optional[ConfigExportDeliveryInfo] - configStreamDeliveryInfo: Optional[ConfigStreamDeliveryInfo] + name: String | None + configSnapshotDeliveryInfo: ConfigExportDeliveryInfo | None + configHistoryDeliveryInfo: ConfigExportDeliveryInfo | None + configStreamDeliveryInfo: ConfigStreamDeliveryInfo | None -DeliveryChannelStatusList = List[DeliveryChannelStatus] +DeliveryChannelStatusList = list[DeliveryChannelStatus] class DescribeAggregateComplianceByConfigRulesRequest(ServiceRequest): ConfigurationAggregatorName: ConfigurationAggregatorName - Filters: Optional[ConfigRuleComplianceFilters] - Limit: Optional[GroupByAPILimit] - NextToken: Optional[NextToken] + Filters: ConfigRuleComplianceFilters | None + Limit: GroupByAPILimit | None + NextToken: NextToken | None class DescribeAggregateComplianceByConfigRulesResponse(TypedDict, total=False): - AggregateComplianceByConfigRules: Optional[AggregateComplianceByConfigRuleList] - NextToken: Optional[NextToken] + AggregateComplianceByConfigRules: AggregateComplianceByConfigRuleList | None + NextToken: NextToken | None class DescribeAggregateComplianceByConformancePacksRequest(ServiceRequest): ConfigurationAggregatorName: ConfigurationAggregatorName - Filters: Optional[AggregateConformancePackComplianceFilters] - Limit: Optional[Limit] - NextToken: Optional[NextToken] + Filters: AggregateConformancePackComplianceFilters | None + Limit: Limit | None + NextToken: NextToken | None class DescribeAggregateComplianceByConformancePacksResponse(TypedDict, total=False): - AggregateComplianceByConformancePacks: Optional[AggregateComplianceByConformancePackList] - NextToken: Optional[NextToken] + AggregateComplianceByConformancePacks: AggregateComplianceByConformancePackList | None + NextToken: NextToken | None class DescribeAggregationAuthorizationsRequest(ServiceRequest): - Limit: Optional[Limit] - NextToken: Optional[String] + Limit: Limit | None + NextToken: String | None class DescribeAggregationAuthorizationsResponse(TypedDict, total=False): - AggregationAuthorizations: Optional[AggregationAuthorizationList] - NextToken: Optional[String] + AggregationAuthorizations: AggregationAuthorizationList | None + NextToken: String | None class DescribeComplianceByConfigRuleRequest(ServiceRequest): - ConfigRuleNames: Optional[ConfigRuleNames] - ComplianceTypes: Optional[ComplianceTypes] - NextToken: Optional[String] + ConfigRuleNames: ConfigRuleNames | None + ComplianceTypes: ComplianceTypes | None + NextToken: String | None class DescribeComplianceByConfigRuleResponse(TypedDict, total=False): - ComplianceByConfigRules: Optional[ComplianceByConfigRules] - NextToken: Optional[String] + ComplianceByConfigRules: ComplianceByConfigRules | None + NextToken: String | None class DescribeComplianceByResourceRequest(ServiceRequest): - ResourceType: Optional[StringWithCharLimit256] - ResourceId: Optional[BaseResourceId] - ComplianceTypes: Optional[ComplianceTypes] - Limit: Optional[Limit] - NextToken: Optional[NextToken] + ResourceType: StringWithCharLimit256 | None + ResourceId: BaseResourceId | None + ComplianceTypes: ComplianceTypes | None + Limit: Limit | None + NextToken: NextToken | None class DescribeComplianceByResourceResponse(TypedDict, total=False): - ComplianceByResources: Optional[ComplianceByResources] - NextToken: Optional[NextToken] + ComplianceByResources: ComplianceByResources | None + NextToken: NextToken | None class DescribeConfigRuleEvaluationStatusRequest(ServiceRequest): - ConfigRuleNames: Optional[ConfigRuleNames] - NextToken: Optional[String] - Limit: Optional[RuleLimit] + ConfigRuleNames: ConfigRuleNames | None + NextToken: String | None + Limit: RuleLimit | None class DescribeConfigRuleEvaluationStatusResponse(TypedDict, total=False): - ConfigRulesEvaluationStatus: Optional[ConfigRuleEvaluationStatusList] - NextToken: Optional[String] + ConfigRulesEvaluationStatus: ConfigRuleEvaluationStatusList | None + NextToken: String | None class DescribeConfigRulesFilters(TypedDict, total=False): - EvaluationMode: Optional[EvaluationMode] + EvaluationMode: EvaluationMode | None class DescribeConfigRulesRequest(ServiceRequest): - ConfigRuleNames: Optional[ConfigRuleNames] - NextToken: Optional[String] - Filters: Optional[DescribeConfigRulesFilters] + ConfigRuleNames: ConfigRuleNames | None + NextToken: String | None + Filters: DescribeConfigRulesFilters | None class DescribeConfigRulesResponse(TypedDict, total=False): - ConfigRules: Optional[ConfigRules] - NextToken: Optional[String] + ConfigRules: ConfigRules | None + NextToken: String | None class DescribeConfigurationAggregatorSourcesStatusRequest(ServiceRequest): ConfigurationAggregatorName: ConfigurationAggregatorName - UpdateStatus: Optional[AggregatedSourceStatusTypeList] - NextToken: Optional[String] - Limit: Optional[Limit] + UpdateStatus: AggregatedSourceStatusTypeList | None + NextToken: String | None + Limit: Limit | None class DescribeConfigurationAggregatorSourcesStatusResponse(TypedDict, total=False): - AggregatedSourceStatusList: Optional[AggregatedSourceStatusList] - NextToken: Optional[String] + AggregatedSourceStatusList: AggregatedSourceStatusList | None + NextToken: String | None class DescribeConfigurationAggregatorsRequest(ServiceRequest): - ConfigurationAggregatorNames: Optional[ConfigurationAggregatorNameList] - NextToken: Optional[String] - Limit: Optional[Limit] + ConfigurationAggregatorNames: ConfigurationAggregatorNameList | None + NextToken: String | None + Limit: Limit | None class DescribeConfigurationAggregatorsResponse(TypedDict, total=False): - ConfigurationAggregators: Optional[ConfigurationAggregatorList] - NextToken: Optional[String] + ConfigurationAggregators: ConfigurationAggregatorList | None + NextToken: String | None class DescribeConfigurationRecorderStatusRequest(ServiceRequest): - ConfigurationRecorderNames: Optional[ConfigurationRecorderNameList] - ServicePrincipal: Optional[ServicePrincipal] - Arn: Optional[AmazonResourceName] + ConfigurationRecorderNames: ConfigurationRecorderNameList | None + ServicePrincipal: ServicePrincipal | None + Arn: AmazonResourceName | None class DescribeConfigurationRecorderStatusResponse(TypedDict, total=False): - ConfigurationRecordersStatus: Optional[ConfigurationRecorderStatusList] + ConfigurationRecordersStatus: ConfigurationRecorderStatusList | None class DescribeConfigurationRecordersRequest(ServiceRequest): - ConfigurationRecorderNames: Optional[ConfigurationRecorderNameList] - ServicePrincipal: Optional[ServicePrincipal] - Arn: Optional[AmazonResourceName] + ConfigurationRecorderNames: ConfigurationRecorderNameList | None + ServicePrincipal: ServicePrincipal | None + Arn: AmazonResourceName | None class DescribeConfigurationRecordersResponse(TypedDict, total=False): - ConfigurationRecorders: Optional[ConfigurationRecorderList] + ConfigurationRecorders: ConfigurationRecorderList | None class DescribeConformancePackComplianceRequest(ServiceRequest): ConformancePackName: ConformancePackName - Filters: Optional[ConformancePackComplianceFilters] - Limit: Optional[DescribeConformancePackComplianceLimit] - NextToken: Optional[NextToken] + Filters: ConformancePackComplianceFilters | None + Limit: DescribeConformancePackComplianceLimit | None + NextToken: NextToken | None class DescribeConformancePackComplianceResponse(TypedDict, total=False): ConformancePackName: ConformancePackName ConformancePackRuleComplianceList: ConformancePackRuleComplianceList - NextToken: Optional[NextToken] + NextToken: NextToken | None class DescribeConformancePackStatusRequest(ServiceRequest): - ConformancePackNames: Optional[ConformancePackNamesList] - Limit: Optional[PageSizeLimit] - NextToken: Optional[NextToken] + ConformancePackNames: ConformancePackNamesList | None + Limit: PageSizeLimit | None + NextToken: NextToken | None class DescribeConformancePackStatusResponse(TypedDict, total=False): - ConformancePackStatusDetails: Optional[ConformancePackStatusDetailsList] - NextToken: Optional[NextToken] + ConformancePackStatusDetails: ConformancePackStatusDetailsList | None + NextToken: NextToken | None class DescribeConformancePacksRequest(ServiceRequest): - ConformancePackNames: Optional[ConformancePackNamesList] - Limit: Optional[PageSizeLimit] - NextToken: Optional[NextToken] + ConformancePackNames: ConformancePackNamesList | None + Limit: PageSizeLimit | None + NextToken: NextToken | None class DescribeConformancePacksResponse(TypedDict, total=False): - ConformancePackDetails: Optional[ConformancePackDetailList] - NextToken: Optional[NextToken] + ConformancePackDetails: ConformancePackDetailList | None + NextToken: NextToken | None class DescribeDeliveryChannelStatusRequest(ServiceRequest): - DeliveryChannelNames: Optional[DeliveryChannelNameList] + DeliveryChannelNames: DeliveryChannelNameList | None class DescribeDeliveryChannelStatusResponse(TypedDict, total=False): - DeliveryChannelsStatus: Optional[DeliveryChannelStatusList] + DeliveryChannelsStatus: DeliveryChannelStatusList | None class DescribeDeliveryChannelsRequest(ServiceRequest): - DeliveryChannelNames: Optional[DeliveryChannelNameList] + DeliveryChannelNames: DeliveryChannelNameList | None class DescribeDeliveryChannelsResponse(TypedDict, total=False): - DeliveryChannels: Optional[DeliveryChannelList] + DeliveryChannels: DeliveryChannelList | None -OrganizationConfigRuleNames = List[StringWithCharLimit64] +OrganizationConfigRuleNames = list[StringWithCharLimit64] class DescribeOrganizationConfigRuleStatusesRequest(ServiceRequest): - OrganizationConfigRuleNames: Optional[OrganizationConfigRuleNames] - Limit: Optional[CosmosPageLimit] - NextToken: Optional[String] + OrganizationConfigRuleNames: OrganizationConfigRuleNames | None + Limit: CosmosPageLimit | None + NextToken: String | None class OrganizationConfigRuleStatus(TypedDict, total=False): OrganizationConfigRuleName: OrganizationConfigRuleName OrganizationRuleStatus: OrganizationRuleStatus - ErrorCode: Optional[String] - ErrorMessage: Optional[String] - LastUpdateTime: Optional[Date] + ErrorCode: String | None + ErrorMessage: String | None + LastUpdateTime: Date | None -OrganizationConfigRuleStatuses = List[OrganizationConfigRuleStatus] +OrganizationConfigRuleStatuses = list[OrganizationConfigRuleStatus] class DescribeOrganizationConfigRuleStatusesResponse(TypedDict, total=False): - OrganizationConfigRuleStatuses: Optional[OrganizationConfigRuleStatuses] - NextToken: Optional[String] + OrganizationConfigRuleStatuses: OrganizationConfigRuleStatuses | None + NextToken: String | None class DescribeOrganizationConfigRulesRequest(ServiceRequest): - OrganizationConfigRuleNames: Optional[OrganizationConfigRuleNames] - Limit: Optional[CosmosPageLimit] - NextToken: Optional[String] + OrganizationConfigRuleNames: OrganizationConfigRuleNames | None + Limit: CosmosPageLimit | None + NextToken: String | None -ResourceTypesScope = List[StringWithCharLimit256] -OrganizationConfigRuleTriggerTypeNoSNs = List[OrganizationConfigRuleTriggerTypeNoSN] +ResourceTypesScope = list[StringWithCharLimit256] +OrganizationConfigRuleTriggerTypeNoSNs = list[OrganizationConfigRuleTriggerTypeNoSN] class OrganizationCustomPolicyRuleMetadataNoPolicy(TypedDict, total=False): - Description: Optional[StringWithCharLimit256Min0] - OrganizationConfigRuleTriggerTypes: Optional[OrganizationConfigRuleTriggerTypeNoSNs] - InputParameters: Optional[StringWithCharLimit2048] - MaximumExecutionFrequency: Optional[MaximumExecutionFrequency] - ResourceTypesScope: Optional[ResourceTypesScope] - ResourceIdScope: Optional[StringWithCharLimit768] - TagKeyScope: Optional[StringWithCharLimit128] - TagValueScope: Optional[StringWithCharLimit256] - PolicyRuntime: Optional[PolicyRuntime] - DebugLogDeliveryAccounts: Optional[DebugLogDeliveryAccounts] + Description: StringWithCharLimit256Min0 | None + OrganizationConfigRuleTriggerTypes: OrganizationConfigRuleTriggerTypeNoSNs | None + InputParameters: StringWithCharLimit2048 | None + MaximumExecutionFrequency: MaximumExecutionFrequency | None + ResourceTypesScope: ResourceTypesScope | None + ResourceIdScope: StringWithCharLimit768 | None + TagKeyScope: StringWithCharLimit128 | None + TagValueScope: StringWithCharLimit256 | None + PolicyRuntime: PolicyRuntime | None + DebugLogDeliveryAccounts: DebugLogDeliveryAccounts | None -ExcludedAccounts = List[AccountId] -OrganizationConfigRuleTriggerTypes = List[OrganizationConfigRuleTriggerType] +ExcludedAccounts = list[AccountId] +OrganizationConfigRuleTriggerTypes = list[OrganizationConfigRuleTriggerType] class OrganizationCustomRuleMetadata(TypedDict, total=False): - Description: Optional[StringWithCharLimit256Min0] + Description: StringWithCharLimit256Min0 | None LambdaFunctionArn: StringWithCharLimit256 OrganizationConfigRuleTriggerTypes: OrganizationConfigRuleTriggerTypes - InputParameters: Optional[StringWithCharLimit2048] - MaximumExecutionFrequency: Optional[MaximumExecutionFrequency] - ResourceTypesScope: Optional[ResourceTypesScope] - ResourceIdScope: Optional[StringWithCharLimit768] - TagKeyScope: Optional[StringWithCharLimit128] - TagValueScope: Optional[StringWithCharLimit256] + InputParameters: StringWithCharLimit2048 | None + MaximumExecutionFrequency: MaximumExecutionFrequency | None + ResourceTypesScope: ResourceTypesScope | None + ResourceIdScope: StringWithCharLimit768 | None + TagKeyScope: StringWithCharLimit128 | None + TagValueScope: StringWithCharLimit256 | None class OrganizationManagedRuleMetadata(TypedDict, total=False): - Description: Optional[StringWithCharLimit256Min0] + Description: StringWithCharLimit256Min0 | None RuleIdentifier: StringWithCharLimit256 - InputParameters: Optional[StringWithCharLimit2048] - MaximumExecutionFrequency: Optional[MaximumExecutionFrequency] - ResourceTypesScope: Optional[ResourceTypesScope] - ResourceIdScope: Optional[StringWithCharLimit768] - TagKeyScope: Optional[StringWithCharLimit128] - TagValueScope: Optional[StringWithCharLimit256] + InputParameters: StringWithCharLimit2048 | None + MaximumExecutionFrequency: MaximumExecutionFrequency | None + ResourceTypesScope: ResourceTypesScope | None + ResourceIdScope: StringWithCharLimit768 | None + TagKeyScope: StringWithCharLimit128 | None + TagValueScope: StringWithCharLimit256 | None class OrganizationConfigRule(TypedDict, total=False): OrganizationConfigRuleName: OrganizationConfigRuleName OrganizationConfigRuleArn: StringWithCharLimit256 - OrganizationManagedRuleMetadata: Optional[OrganizationManagedRuleMetadata] - OrganizationCustomRuleMetadata: Optional[OrganizationCustomRuleMetadata] - ExcludedAccounts: Optional[ExcludedAccounts] - LastUpdateTime: Optional[Date] - OrganizationCustomPolicyRuleMetadata: Optional[OrganizationCustomPolicyRuleMetadataNoPolicy] + OrganizationManagedRuleMetadata: OrganizationManagedRuleMetadata | None + OrganizationCustomRuleMetadata: OrganizationCustomRuleMetadata | None + ExcludedAccounts: ExcludedAccounts | None + LastUpdateTime: Date | None + OrganizationCustomPolicyRuleMetadata: OrganizationCustomPolicyRuleMetadataNoPolicy | None -OrganizationConfigRules = List[OrganizationConfigRule] +OrganizationConfigRules = list[OrganizationConfigRule] class DescribeOrganizationConfigRulesResponse(TypedDict, total=False): - OrganizationConfigRules: Optional[OrganizationConfigRules] - NextToken: Optional[String] + OrganizationConfigRules: OrganizationConfigRules | None + NextToken: String | None -OrganizationConformancePackNames = List[OrganizationConformancePackName] +OrganizationConformancePackNames = list[OrganizationConformancePackName] class DescribeOrganizationConformancePackStatusesRequest(ServiceRequest): - OrganizationConformancePackNames: Optional[OrganizationConformancePackNames] - Limit: Optional[CosmosPageLimit] - NextToken: Optional[String] + OrganizationConformancePackNames: OrganizationConformancePackNames | None + Limit: CosmosPageLimit | None + NextToken: String | None class OrganizationConformancePackStatus(TypedDict, total=False): OrganizationConformancePackName: OrganizationConformancePackName Status: OrganizationResourceStatus - ErrorCode: Optional[String] - ErrorMessage: Optional[String] - LastUpdateTime: Optional[Date] + ErrorCode: String | None + ErrorMessage: String | None + LastUpdateTime: Date | None -OrganizationConformancePackStatuses = List[OrganizationConformancePackStatus] +OrganizationConformancePackStatuses = list[OrganizationConformancePackStatus] class DescribeOrganizationConformancePackStatusesResponse(TypedDict, total=False): - OrganizationConformancePackStatuses: Optional[OrganizationConformancePackStatuses] - NextToken: Optional[String] + OrganizationConformancePackStatuses: OrganizationConformancePackStatuses | None + NextToken: String | None class DescribeOrganizationConformancePacksRequest(ServiceRequest): - OrganizationConformancePackNames: Optional[OrganizationConformancePackNames] - Limit: Optional[CosmosPageLimit] - NextToken: Optional[String] + OrganizationConformancePackNames: OrganizationConformancePackNames | None + Limit: CosmosPageLimit | None + NextToken: String | None class OrganizationConformancePack(TypedDict, total=False): OrganizationConformancePackName: OrganizationConformancePackName OrganizationConformancePackArn: StringWithCharLimit256 - DeliveryS3Bucket: Optional[DeliveryS3Bucket] - DeliveryS3KeyPrefix: Optional[DeliveryS3KeyPrefix] - ConformancePackInputParameters: Optional[ConformancePackInputParameters] - ExcludedAccounts: Optional[ExcludedAccounts] + DeliveryS3Bucket: DeliveryS3Bucket | None + DeliveryS3KeyPrefix: DeliveryS3KeyPrefix | None + ConformancePackInputParameters: ConformancePackInputParameters | None + ExcludedAccounts: ExcludedAccounts | None LastUpdateTime: Date -OrganizationConformancePacks = List[OrganizationConformancePack] +OrganizationConformancePacks = list[OrganizationConformancePack] class DescribeOrganizationConformancePacksResponse(TypedDict, total=False): - OrganizationConformancePacks: Optional[OrganizationConformancePacks] - NextToken: Optional[String] + OrganizationConformancePacks: OrganizationConformancePacks | None + NextToken: String | None class DescribePendingAggregationRequestsRequest(ServiceRequest): - Limit: Optional[DescribePendingAggregationRequestsLimit] - NextToken: Optional[String] + Limit: DescribePendingAggregationRequestsLimit | None + NextToken: String | None class PendingAggregationRequest(TypedDict, total=False): - RequesterAccountId: Optional[AccountId] - RequesterAwsRegion: Optional[AwsRegion] + RequesterAccountId: AccountId | None + RequesterAwsRegion: AwsRegion | None -PendingAggregationRequestList = List[PendingAggregationRequest] +PendingAggregationRequestList = list[PendingAggregationRequest] class DescribePendingAggregationRequestsResponse(TypedDict, total=False): - PendingAggregationRequests: Optional[PendingAggregationRequestList] - NextToken: Optional[String] + PendingAggregationRequests: PendingAggregationRequestList | None + NextToken: String | None class DescribeRemediationConfigurationsRequest(ServiceRequest): @@ -2226,15 +2319,15 @@ class DescribeRemediationConfigurationsRequest(ServiceRequest): class SsmControls(TypedDict, total=False): - ConcurrentExecutionRatePercentage: Optional[Percentage] - ErrorPercentage: Optional[Percentage] + ConcurrentExecutionRatePercentage: Percentage | None + ErrorPercentage: Percentage | None class ExecutionControls(TypedDict, total=False): - SsmControls: Optional[SsmControls] + SsmControls: SsmControls | None -StaticParameterValues = List[StringWithCharLimit256] +StaticParameterValues = list[StringWithCharLimit256] class StaticValue(TypedDict, total=False): @@ -2246,98 +2339,98 @@ class ResourceValue(TypedDict, total=False): class RemediationParameterValue(TypedDict, total=False): - ResourceValue: Optional[ResourceValue] - StaticValue: Optional[StaticValue] + ResourceValue: ResourceValue | None + StaticValue: StaticValue | None -RemediationParameters = Dict[StringWithCharLimit256, RemediationParameterValue] +RemediationParameters = dict[StringWithCharLimit256, RemediationParameterValue] class RemediationConfiguration(TypedDict, total=False): ConfigRuleName: ConfigRuleName TargetType: RemediationTargetType TargetId: StringWithCharLimit256 - TargetVersion: Optional[String] - Parameters: Optional[RemediationParameters] - ResourceType: Optional[String] - Automatic: Optional[Boolean] - ExecutionControls: Optional[ExecutionControls] - MaximumAutomaticAttempts: Optional[AutoRemediationAttempts] - RetryAttemptSeconds: Optional[AutoRemediationAttemptSeconds] - Arn: Optional[StringWithCharLimit1024] - CreatedByService: Optional[StringWithCharLimit1024] + TargetVersion: String | None + Parameters: RemediationParameters | None + ResourceType: String | None + Automatic: Boolean | None + ExecutionControls: ExecutionControls | None + MaximumAutomaticAttempts: AutoRemediationAttempts | None + RetryAttemptSeconds: AutoRemediationAttemptSeconds | None + Arn: StringWithCharLimit1024 | None + CreatedByService: StringWithCharLimit1024 | None -RemediationConfigurations = List[RemediationConfiguration] +RemediationConfigurations = list[RemediationConfiguration] class DescribeRemediationConfigurationsResponse(TypedDict, total=False): - RemediationConfigurations: Optional[RemediationConfigurations] + RemediationConfigurations: RemediationConfigurations | None class DescribeRemediationExceptionsRequest(ServiceRequest): ConfigRuleName: ConfigRuleName - ResourceKeys: Optional[RemediationExceptionResourceKeys] - Limit: Optional[Limit] - NextToken: Optional[String] + ResourceKeys: RemediationExceptionResourceKeys | None + Limit: Limit | None + NextToken: String | None class RemediationException(TypedDict, total=False): ConfigRuleName: ConfigRuleName ResourceType: StringWithCharLimit256 ResourceId: StringWithCharLimit1024 - Message: Optional[StringWithCharLimit1024] - ExpirationTime: Optional[Date] + Message: StringWithCharLimit1024 | None + ExpirationTime: Date | None -RemediationExceptions = List[RemediationException] +RemediationExceptions = list[RemediationException] class DescribeRemediationExceptionsResponse(TypedDict, total=False): - RemediationExceptions: Optional[RemediationExceptions] - NextToken: Optional[String] + RemediationExceptions: RemediationExceptions | None + NextToken: String | None class DescribeRemediationExecutionStatusRequest(ServiceRequest): ConfigRuleName: ConfigRuleName - ResourceKeys: Optional[ResourceKeys] - Limit: Optional[Limit] - NextToken: Optional[String] + ResourceKeys: ResourceKeys | None + Limit: Limit | None + NextToken: String | None class RemediationExecutionStep(TypedDict, total=False): - Name: Optional[String] - State: Optional[RemediationExecutionStepState] - ErrorMessage: Optional[String] - StartTime: Optional[Date] - StopTime: Optional[Date] + Name: String | None + State: RemediationExecutionStepState | None + ErrorMessage: String | None + StartTime: Date | None + StopTime: Date | None -RemediationExecutionSteps = List[RemediationExecutionStep] +RemediationExecutionSteps = list[RemediationExecutionStep] class RemediationExecutionStatus(TypedDict, total=False): - ResourceKey: Optional[ResourceKey] - State: Optional[RemediationExecutionState] - StepDetails: Optional[RemediationExecutionSteps] - InvocationTime: Optional[Date] - LastUpdatedTime: Optional[Date] + ResourceKey: ResourceKey | None + State: RemediationExecutionState | None + StepDetails: RemediationExecutionSteps | None + InvocationTime: Date | None + LastUpdatedTime: Date | None -RemediationExecutionStatuses = List[RemediationExecutionStatus] +RemediationExecutionStatuses = list[RemediationExecutionStatus] class DescribeRemediationExecutionStatusResponse(TypedDict, total=False): - RemediationExecutionStatuses: Optional[RemediationExecutionStatuses] - NextToken: Optional[String] + RemediationExecutionStatuses: RemediationExecutionStatuses | None + NextToken: String | None -RetentionConfigurationNameList = List[RetentionConfigurationName] +RetentionConfigurationNameList = list[RetentionConfigurationName] class DescribeRetentionConfigurationsRequest(ServiceRequest): - RetentionConfigurationNames: Optional[RetentionConfigurationNameList] - NextToken: Optional[NextToken] + RetentionConfigurationNames: RetentionConfigurationNameList | None + NextToken: NextToken | None class RetentionConfiguration(TypedDict, total=False): @@ -2345,12 +2438,12 @@ class RetentionConfiguration(TypedDict, total=False): RetentionPeriodInDays: RetentionPeriodInDays -RetentionConfigurationList = List[RetentionConfiguration] +RetentionConfigurationList = list[RetentionConfiguration] class DescribeRetentionConfigurationsResponse(TypedDict, total=False): - RetentionConfigurations: Optional[RetentionConfigurationList] - NextToken: Optional[NextToken] + RetentionConfigurations: RetentionConfigurationList | None + NextToken: NextToken | None class DisassociateResourceTypesRequest(ServiceRequest): @@ -2362,7 +2455,7 @@ class DisassociateResourceTypesResponse(TypedDict, total=False): ConfigurationRecorder: ConfigurationRecorder -DiscoveredResourceIdentifierList = List[AggregateResourceIdentifier] +DiscoveredResourceIdentifierList = list[AggregateResourceIdentifier] EarlierTime = datetime OrderingTimestamp = datetime @@ -2371,63 +2464,63 @@ class Evaluation(TypedDict, total=False): ComplianceResourceType: StringWithCharLimit256 ComplianceResourceId: BaseResourceId ComplianceType: ComplianceType - Annotation: Optional[StringWithCharLimit256] + Annotation: StringWithCharLimit256 | None OrderingTimestamp: OrderingTimestamp class EvaluationContext(TypedDict, total=False): - EvaluationContextIdentifier: Optional[EvaluationContextIdentifier] + EvaluationContextIdentifier: EvaluationContextIdentifier | None class EvaluationResult(TypedDict, total=False): - EvaluationResultIdentifier: Optional[EvaluationResultIdentifier] - ComplianceType: Optional[ComplianceType] - ResultRecordedTime: Optional[Date] - ConfigRuleInvokedTime: Optional[Date] - Annotation: Optional[StringWithCharLimit256] - ResultToken: Optional[String] + EvaluationResultIdentifier: EvaluationResultIdentifier | None + ComplianceType: ComplianceType | None + ResultRecordedTime: Date | None + ConfigRuleInvokedTime: Date | None + Annotation: StringWithCharLimit256 | None + ResultToken: String | None -EvaluationResults = List[EvaluationResult] +EvaluationResults = list[EvaluationResult] class EvaluationStatus(TypedDict, total=False): Status: ResourceEvaluationStatus - FailureReason: Optional[StringWithCharLimit1024] + FailureReason: StringWithCharLimit1024 | None -Evaluations = List[Evaluation] +Evaluations = list[Evaluation] class ExternalEvaluation(TypedDict, total=False): ComplianceResourceType: StringWithCharLimit256 ComplianceResourceId: BaseResourceId ComplianceType: ComplianceType - Annotation: Optional[StringWithCharLimit256] + Annotation: StringWithCharLimit256 | None OrderingTimestamp: OrderingTimestamp class FailedRemediationBatch(TypedDict, total=False): - FailureMessage: Optional[String] - FailedItems: Optional[RemediationConfigurations] + FailureMessage: String | None + FailedItems: RemediationConfigurations | None -FailedRemediationBatches = List[FailedRemediationBatch] +FailedRemediationBatches = list[FailedRemediationBatch] class FailedRemediationExceptionBatch(TypedDict, total=False): - FailureMessage: Optional[String] - FailedItems: Optional[RemediationExceptions] + FailureMessage: String | None + FailedItems: RemediationExceptions | None -FailedRemediationExceptionBatches = List[FailedRemediationExceptionBatch] +FailedRemediationExceptionBatches = list[FailedRemediationExceptionBatch] class FieldInfo(TypedDict, total=False): - Name: Optional[FieldName] + Name: FieldName | None -FieldInfoList = List[FieldInfo] +FieldInfoList = list[FieldInfo] class GetAggregateComplianceDetailsByConfigRuleRequest(ServiceRequest): @@ -2435,58 +2528,58 @@ class GetAggregateComplianceDetailsByConfigRuleRequest(ServiceRequest): ConfigRuleName: ConfigRuleName AccountId: AccountId AwsRegion: AwsRegion - ComplianceType: Optional[ComplianceType] - Limit: Optional[Limit] - NextToken: Optional[NextToken] + ComplianceType: ComplianceType | None + Limit: Limit | None + NextToken: NextToken | None class GetAggregateComplianceDetailsByConfigRuleResponse(TypedDict, total=False): - AggregateEvaluationResults: Optional[AggregateEvaluationResultList] - NextToken: Optional[NextToken] + AggregateEvaluationResults: AggregateEvaluationResultList | None + NextToken: NextToken | None class GetAggregateConfigRuleComplianceSummaryRequest(ServiceRequest): ConfigurationAggregatorName: ConfigurationAggregatorName - Filters: Optional[ConfigRuleComplianceSummaryFilters] - GroupByKey: Optional[ConfigRuleComplianceSummaryGroupKey] - Limit: Optional[GroupByAPILimit] - NextToken: Optional[NextToken] + Filters: ConfigRuleComplianceSummaryFilters | None + GroupByKey: ConfigRuleComplianceSummaryGroupKey | None + Limit: GroupByAPILimit | None + NextToken: NextToken | None class GetAggregateConfigRuleComplianceSummaryResponse(TypedDict, total=False): - GroupByKey: Optional[StringWithCharLimit256] - AggregateComplianceCounts: Optional[AggregateComplianceCountList] - NextToken: Optional[NextToken] + GroupByKey: StringWithCharLimit256 | None + AggregateComplianceCounts: AggregateComplianceCountList | None + NextToken: NextToken | None class GetAggregateConformancePackComplianceSummaryRequest(ServiceRequest): ConfigurationAggregatorName: ConfigurationAggregatorName - Filters: Optional[AggregateConformancePackComplianceSummaryFilters] - GroupByKey: Optional[AggregateConformancePackComplianceSummaryGroupKey] - Limit: Optional[Limit] - NextToken: Optional[NextToken] + Filters: AggregateConformancePackComplianceSummaryFilters | None + GroupByKey: AggregateConformancePackComplianceSummaryGroupKey | None + Limit: Limit | None + NextToken: NextToken | None class GetAggregateConformancePackComplianceSummaryResponse(TypedDict, total=False): - AggregateConformancePackComplianceSummaries: Optional[ - AggregateConformancePackComplianceSummaryList - ] - GroupByKey: Optional[StringWithCharLimit256] - NextToken: Optional[NextToken] + AggregateConformancePackComplianceSummaries: ( + AggregateConformancePackComplianceSummaryList | None + ) + GroupByKey: StringWithCharLimit256 | None + NextToken: NextToken | None class ResourceCountFilters(TypedDict, total=False): - ResourceType: Optional[ResourceType] - AccountId: Optional[AccountId] - Region: Optional[AwsRegion] + ResourceType: ResourceType | None + AccountId: AccountId | None + Region: AwsRegion | None class GetAggregateDiscoveredResourceCountsRequest(ServiceRequest): ConfigurationAggregatorName: ConfigurationAggregatorName - Filters: Optional[ResourceCountFilters] - GroupByKey: Optional[ResourceCountGroupKey] - Limit: Optional[GroupByAPILimit] - NextToken: Optional[NextToken] + Filters: ResourceCountFilters | None + GroupByKey: ResourceCountGroupKey | None + Limit: GroupByAPILimit | None + NextToken: NextToken | None Long = int @@ -2497,14 +2590,14 @@ class GroupedResourceCount(TypedDict, total=False): ResourceCount: Long -GroupedResourceCountList = List[GroupedResourceCount] +GroupedResourceCountList = list[GroupedResourceCount] class GetAggregateDiscoveredResourceCountsResponse(TypedDict, total=False): TotalDiscoveredResources: Long - GroupByKey: Optional[StringWithCharLimit256] - GroupedResourceCounts: Optional[GroupedResourceCountList] - NextToken: Optional[NextToken] + GroupByKey: StringWithCharLimit256 | None + GroupedResourceCounts: GroupedResourceCountList | None + NextToken: NextToken | None class GetAggregateResourceConfigRequest(ServiceRequest): @@ -2513,159 +2606,157 @@ class GetAggregateResourceConfigRequest(ServiceRequest): class GetAggregateResourceConfigResponse(TypedDict, total=False): - ConfigurationItem: Optional[ConfigurationItem] + ConfigurationItem: ConfigurationItem | None class GetComplianceDetailsByConfigRuleRequest(ServiceRequest): ConfigRuleName: StringWithCharLimit64 - ComplianceTypes: Optional[ComplianceTypes] - Limit: Optional[Limit] - NextToken: Optional[NextToken] + ComplianceTypes: ComplianceTypes | None + Limit: Limit | None + NextToken: NextToken | None class GetComplianceDetailsByConfigRuleResponse(TypedDict, total=False): - EvaluationResults: Optional[EvaluationResults] - NextToken: Optional[NextToken] + EvaluationResults: EvaluationResults | None + NextToken: NextToken | None class GetComplianceDetailsByResourceRequest(ServiceRequest): - ResourceType: Optional[StringWithCharLimit256] - ResourceId: Optional[BaseResourceId] - ComplianceTypes: Optional[ComplianceTypes] - NextToken: Optional[String] - ResourceEvaluationId: Optional[ResourceEvaluationId] + ResourceType: StringWithCharLimit256 | None + ResourceId: BaseResourceId | None + ComplianceTypes: ComplianceTypes | None + NextToken: String | None + ResourceEvaluationId: ResourceEvaluationId | None class GetComplianceDetailsByResourceResponse(TypedDict, total=False): - EvaluationResults: Optional[EvaluationResults] - NextToken: Optional[String] + EvaluationResults: EvaluationResults | None + NextToken: String | None class GetComplianceSummaryByConfigRuleResponse(TypedDict, total=False): - ComplianceSummary: Optional[ComplianceSummary] + ComplianceSummary: ComplianceSummary | None -ResourceTypes = List[StringWithCharLimit256] +ResourceTypes = list[StringWithCharLimit256] class GetComplianceSummaryByResourceTypeRequest(ServiceRequest): - ResourceTypes: Optional[ResourceTypes] + ResourceTypes: ResourceTypes | None class GetComplianceSummaryByResourceTypeResponse(TypedDict, total=False): - ComplianceSummariesByResourceType: Optional[ComplianceSummariesByResourceType] + ComplianceSummariesByResourceType: ComplianceSummariesByResourceType | None class GetConformancePackComplianceDetailsRequest(ServiceRequest): ConformancePackName: ConformancePackName - Filters: Optional[ConformancePackEvaluationFilters] - Limit: Optional[GetConformancePackComplianceDetailsLimit] - NextToken: Optional[NextToken] + Filters: ConformancePackEvaluationFilters | None + Limit: GetConformancePackComplianceDetailsLimit | None + NextToken: NextToken | None class GetConformancePackComplianceDetailsResponse(TypedDict, total=False): ConformancePackName: ConformancePackName - ConformancePackRuleEvaluationResults: Optional[ConformancePackRuleEvaluationResultsList] - NextToken: Optional[NextToken] + ConformancePackRuleEvaluationResults: ConformancePackRuleEvaluationResultsList | None + NextToken: NextToken | None class GetConformancePackComplianceSummaryRequest(ServiceRequest): ConformancePackNames: ConformancePackNamesToSummarizeList - Limit: Optional[PageSizeLimit] - NextToken: Optional[NextToken] + Limit: PageSizeLimit | None + NextToken: NextToken | None class GetConformancePackComplianceSummaryResponse(TypedDict, total=False): - ConformancePackComplianceSummaryList: Optional[ConformancePackComplianceSummaryList] - NextToken: Optional[NextToken] + ConformancePackComplianceSummaryList: ConformancePackComplianceSummaryList | None + NextToken: NextToken | None class GetCustomRulePolicyRequest(ServiceRequest): - ConfigRuleName: Optional[ConfigRuleName] + ConfigRuleName: ConfigRuleName | None class GetCustomRulePolicyResponse(TypedDict, total=False): - PolicyText: Optional[PolicyText] + PolicyText: PolicyText | None class GetDiscoveredResourceCountsRequest(ServiceRequest): - resourceTypes: Optional[ResourceTypes] - limit: Optional[Limit] - nextToken: Optional[NextToken] + resourceTypes: ResourceTypes | None + limit: Limit | None + nextToken: NextToken | None class ResourceCount(TypedDict, total=False): - resourceType: Optional[ResourceType] - count: Optional[Long] + resourceType: ResourceType | None + count: Long | None -ResourceCounts = List[ResourceCount] +ResourceCounts = list[ResourceCount] class GetDiscoveredResourceCountsResponse(TypedDict, total=False): - totalDiscoveredResources: Optional[Long] - resourceCounts: Optional[ResourceCounts] - nextToken: Optional[NextToken] + totalDiscoveredResources: Long | None + resourceCounts: ResourceCounts | None + nextToken: NextToken | None class StatusDetailFilters(TypedDict, total=False): - AccountId: Optional[AccountId] - MemberAccountRuleStatus: Optional[MemberAccountRuleStatus] + AccountId: AccountId | None + MemberAccountRuleStatus: MemberAccountRuleStatus | None class GetOrganizationConfigRuleDetailedStatusRequest(ServiceRequest): OrganizationConfigRuleName: OrganizationConfigRuleName - Filters: Optional[StatusDetailFilters] - Limit: Optional[CosmosPageLimit] - NextToken: Optional[String] + Filters: StatusDetailFilters | None + Limit: CosmosPageLimit | None + NextToken: String | None class MemberAccountStatus(TypedDict, total=False): AccountId: AccountId ConfigRuleName: StringWithCharLimit64 MemberAccountRuleStatus: MemberAccountRuleStatus - ErrorCode: Optional[String] - ErrorMessage: Optional[String] - LastUpdateTime: Optional[Date] + ErrorCode: String | None + ErrorMessage: String | None + LastUpdateTime: Date | None -OrganizationConfigRuleDetailedStatus = List[MemberAccountStatus] +OrganizationConfigRuleDetailedStatus = list[MemberAccountStatus] class GetOrganizationConfigRuleDetailedStatusResponse(TypedDict, total=False): - OrganizationConfigRuleDetailedStatus: Optional[OrganizationConfigRuleDetailedStatus] - NextToken: Optional[String] + OrganizationConfigRuleDetailedStatus: OrganizationConfigRuleDetailedStatus | None + NextToken: String | None class OrganizationResourceDetailedStatusFilters(TypedDict, total=False): - AccountId: Optional[AccountId] - Status: Optional[OrganizationResourceDetailedStatus] + AccountId: AccountId | None + Status: OrganizationResourceDetailedStatus | None class GetOrganizationConformancePackDetailedStatusRequest(ServiceRequest): OrganizationConformancePackName: OrganizationConformancePackName - Filters: Optional[OrganizationResourceDetailedStatusFilters] - Limit: Optional[CosmosPageLimit] - NextToken: Optional[String] + Filters: OrganizationResourceDetailedStatusFilters | None + Limit: CosmosPageLimit | None + NextToken: String | None class OrganizationConformancePackDetailedStatus(TypedDict, total=False): AccountId: AccountId ConformancePackName: StringWithCharLimit256 Status: OrganizationResourceDetailedStatus - ErrorCode: Optional[String] - ErrorMessage: Optional[String] - LastUpdateTime: Optional[Date] + ErrorCode: String | None + ErrorMessage: String | None + LastUpdateTime: Date | None -OrganizationConformancePackDetailedStatuses = List[OrganizationConformancePackDetailedStatus] +OrganizationConformancePackDetailedStatuses = list[OrganizationConformancePackDetailedStatus] class GetOrganizationConformancePackDetailedStatusResponse(TypedDict, total=False): - OrganizationConformancePackDetailedStatuses: Optional[ - OrganizationConformancePackDetailedStatuses - ] - NextToken: Optional[String] + OrganizationConformancePackDetailedStatuses: OrganizationConformancePackDetailedStatuses | None + NextToken: String | None class GetOrganizationCustomRulePolicyRequest(ServiceRequest): @@ -2673,7 +2764,7 @@ class GetOrganizationCustomRulePolicyRequest(ServiceRequest): class GetOrganizationCustomRulePolicyResponse(TypedDict, total=False): - PolicyText: Optional[PolicyText] + PolicyText: PolicyText | None LaterTime = datetime @@ -2682,16 +2773,16 @@ class GetOrganizationCustomRulePolicyResponse(TypedDict, total=False): class GetResourceConfigHistoryRequest(ServiceRequest): resourceType: ResourceType resourceId: ResourceId - laterTime: Optional[LaterTime] - earlierTime: Optional[EarlierTime] - chronologicalOrder: Optional[ChronologicalOrder] - limit: Optional[Limit] - nextToken: Optional[NextToken] + laterTime: LaterTime | None + earlierTime: EarlierTime | None + chronologicalOrder: ChronologicalOrder | None + limit: Limit | None + nextToken: NextToken | None class GetResourceConfigHistoryResponse(TypedDict, total=False): - configurationItems: Optional[ConfigurationItemList] - nextToken: Optional[NextToken] + configurationItems: ConfigurationItemList | None + nextToken: NextToken | None class GetResourceEvaluationSummaryRequest(ServiceRequest): @@ -2702,17 +2793,17 @@ class ResourceDetails(TypedDict, total=False): ResourceId: BaseResourceId ResourceType: StringWithCharLimit256 ResourceConfiguration: ResourceConfiguration - ResourceConfigurationSchemaType: Optional[ResourceConfigurationSchemaType] + ResourceConfigurationSchemaType: ResourceConfigurationSchemaType | None class GetResourceEvaluationSummaryResponse(TypedDict, total=False): - ResourceEvaluationId: Optional[ResourceEvaluationId] - EvaluationMode: Optional[EvaluationMode] - EvaluationStatus: Optional[EvaluationStatus] - EvaluationStartTimestamp: Optional[Date] - Compliance: Optional[ComplianceType] - EvaluationContext: Optional[EvaluationContext] - ResourceDetails: Optional[ResourceDetails] + ResourceEvaluationId: ResourceEvaluationId | None + EvaluationMode: EvaluationMode | None + EvaluationStatus: EvaluationStatus | None + EvaluationStartTimestamp: Date | None + Compliance: ComplianceType | None + EvaluationContext: EvaluationContext | None + ResourceDetails: ResourceDetails | None class GetStoredQueryRequest(ServiceRequest): @@ -2720,222 +2811,223 @@ class GetStoredQueryRequest(ServiceRequest): class StoredQuery(TypedDict, total=False): - QueryId: Optional[QueryId] - QueryArn: Optional[QueryArn] + QueryId: QueryId | None + QueryArn: QueryArn | None QueryName: QueryName - Description: Optional[QueryDescription] - Expression: Optional[QueryExpression] + Description: QueryDescription | None + Expression: QueryExpression | None class GetStoredQueryResponse(TypedDict, total=False): - StoredQuery: Optional[StoredQuery] + StoredQuery: StoredQuery | None class ResourceFilters(TypedDict, total=False): - AccountId: Optional[AccountId] - ResourceId: Optional[ResourceId] - ResourceName: Optional[ResourceName] - Region: Optional[AwsRegion] + AccountId: AccountId | None + ResourceId: ResourceId | None + ResourceName: ResourceName | None + Region: AwsRegion | None class ListAggregateDiscoveredResourcesRequest(ServiceRequest): ConfigurationAggregatorName: ConfigurationAggregatorName ResourceType: ResourceType - Filters: Optional[ResourceFilters] - Limit: Optional[Limit] - NextToken: Optional[NextToken] + Filters: ResourceFilters | None + Limit: Limit | None + NextToken: NextToken | None class ListAggregateDiscoveredResourcesResponse(TypedDict, total=False): - ResourceIdentifiers: Optional[DiscoveredResourceIdentifierList] - NextToken: Optional[NextToken] + ResourceIdentifiers: DiscoveredResourceIdentifierList | None + NextToken: NextToken | None class ListConfigurationRecordersRequest(ServiceRequest): - Filters: Optional[ConfigurationRecorderFilterList] - MaxResults: Optional[MaxResults] - NextToken: Optional[NextToken] + Filters: ConfigurationRecorderFilterList | None + MaxResults: MaxResults | None + NextToken: NextToken | None class ListConfigurationRecordersResponse(TypedDict, total=False): ConfigurationRecorderSummaries: ConfigurationRecorderSummaries - NextToken: Optional[NextToken] + NextToken: NextToken | None class ListConformancePackComplianceScoresRequest(ServiceRequest): - Filters: Optional[ConformancePackComplianceScoresFilters] - SortOrder: Optional[SortOrder] - SortBy: Optional[SortBy] - Limit: Optional[PageSizeLimit] - NextToken: Optional[NextToken] + Filters: ConformancePackComplianceScoresFilters | None + SortOrder: SortOrder | None + SortBy: SortBy | None + Limit: PageSizeLimit | None + NextToken: NextToken | None class ListConformancePackComplianceScoresResponse(TypedDict, total=False): - NextToken: Optional[NextToken] + NextToken: NextToken | None ConformancePackComplianceScores: ConformancePackComplianceScores -ResourceIdList = List[ResourceId] +ResourceIdList = list[ResourceId] class ListDiscoveredResourcesRequest(ServiceRequest): resourceType: ResourceType - resourceIds: Optional[ResourceIdList] - resourceName: Optional[ResourceName] - limit: Optional[Limit] - includeDeletedResources: Optional[Boolean] - nextToken: Optional[NextToken] + resourceIds: ResourceIdList | None + resourceName: ResourceName | None + limit: Limit | None + includeDeletedResources: Boolean | None + nextToken: NextToken | None ResourceDeletionTime = datetime class ResourceIdentifier(TypedDict, total=False): - resourceType: Optional[ResourceType] - resourceId: Optional[ResourceId] - resourceName: Optional[ResourceName] - resourceDeletionTime: Optional[ResourceDeletionTime] + resourceType: ResourceType | None + resourceId: ResourceId | None + resourceName: ResourceName | None + resourceDeletionTime: ResourceDeletionTime | None -ResourceIdentifierList = List[ResourceIdentifier] +ResourceIdentifierList = list[ResourceIdentifier] class ListDiscoveredResourcesResponse(TypedDict, total=False): - resourceIdentifiers: Optional[ResourceIdentifierList] - nextToken: Optional[NextToken] + resourceIdentifiers: ResourceIdentifierList | None + nextToken: NextToken | None class TimeWindow(TypedDict, total=False): - StartTime: Optional[Date] - EndTime: Optional[Date] + StartTime: Date | None + EndTime: Date | None class ResourceEvaluationFilters(TypedDict, total=False): - EvaluationMode: Optional[EvaluationMode] - TimeWindow: Optional[TimeWindow] - EvaluationContextIdentifier: Optional[EvaluationContextIdentifier] + EvaluationMode: EvaluationMode | None + TimeWindow: TimeWindow | None + EvaluationContextIdentifier: EvaluationContextIdentifier | None class ListResourceEvaluationsRequest(ServiceRequest): - Filters: Optional[ResourceEvaluationFilters] - Limit: Optional[ListResourceEvaluationsPageItemLimit] - NextToken: Optional[String] + Filters: ResourceEvaluationFilters | None + Limit: ListResourceEvaluationsPageItemLimit | None + NextToken: String | None class ResourceEvaluation(TypedDict, total=False): - ResourceEvaluationId: Optional[ResourceEvaluationId] - EvaluationMode: Optional[EvaluationMode] - EvaluationStartTimestamp: Optional[Date] + ResourceEvaluationId: ResourceEvaluationId | None + EvaluationMode: EvaluationMode | None + EvaluationStartTimestamp: Date | None -ResourceEvaluations = List[ResourceEvaluation] +ResourceEvaluations = list[ResourceEvaluation] class ListResourceEvaluationsResponse(TypedDict, total=False): - ResourceEvaluations: Optional[ResourceEvaluations] - NextToken: Optional[String] + ResourceEvaluations: ResourceEvaluations | None + NextToken: String | None class ListStoredQueriesRequest(ServiceRequest): - NextToken: Optional[String] - MaxResults: Optional[Limit] + NextToken: String | None + MaxResults: Limit | None class StoredQueryMetadata(TypedDict, total=False): QueryId: QueryId QueryArn: QueryArn QueryName: QueryName - Description: Optional[QueryDescription] + Description: QueryDescription | None -StoredQueryMetadataList = List[StoredQueryMetadata] +StoredQueryMetadataList = list[StoredQueryMetadata] class ListStoredQueriesResponse(TypedDict, total=False): - StoredQueryMetadata: Optional[StoredQueryMetadataList] - NextToken: Optional[String] + StoredQueryMetadata: StoredQueryMetadataList | None + NextToken: String | None class ListTagsForResourceRequest(ServiceRequest): ResourceArn: AmazonResourceName - Limit: Optional[Limit] - NextToken: Optional[NextToken] + Limit: Limit | None + NextToken: NextToken | None class Tag(TypedDict, total=False): - Key: Optional[TagKey] - Value: Optional[TagValue] + Key: TagKey | None + Value: TagValue | None -TagList = List[Tag] +TagList = list[Tag] class ListTagsForResourceResponse(TypedDict, total=False): - Tags: Optional[TagList] - NextToken: Optional[NextToken] + Tags: TagList | None + NextToken: NextToken | None class OrganizationCustomPolicyRuleMetadata(TypedDict, total=False): - Description: Optional[StringWithCharLimit256Min0] - OrganizationConfigRuleTriggerTypes: Optional[OrganizationConfigRuleTriggerTypeNoSNs] - InputParameters: Optional[StringWithCharLimit2048] - MaximumExecutionFrequency: Optional[MaximumExecutionFrequency] - ResourceTypesScope: Optional[ResourceTypesScope] - ResourceIdScope: Optional[StringWithCharLimit768] - TagKeyScope: Optional[StringWithCharLimit128] - TagValueScope: Optional[StringWithCharLimit256] + Description: StringWithCharLimit256Min0 | None + OrganizationConfigRuleTriggerTypes: OrganizationConfigRuleTriggerTypeNoSNs | None + InputParameters: StringWithCharLimit2048 | None + MaximumExecutionFrequency: MaximumExecutionFrequency | None + ResourceTypesScope: ResourceTypesScope | None + ResourceIdScope: StringWithCharLimit768 | None + TagKeyScope: StringWithCharLimit128 | None + TagValueScope: StringWithCharLimit256 | None PolicyRuntime: PolicyRuntime PolicyText: PolicyText - DebugLogDeliveryAccounts: Optional[DebugLogDeliveryAccounts] + DebugLogDeliveryAccounts: DebugLogDeliveryAccounts | None -TagsList = List[Tag] +TagsList = list[Tag] class PutAggregationAuthorizationRequest(ServiceRequest): AuthorizedAccountId: AccountId AuthorizedAwsRegion: AwsRegion - Tags: Optional[TagsList] + Tags: TagsList | None class PutAggregationAuthorizationResponse(TypedDict, total=False): - AggregationAuthorization: Optional[AggregationAuthorization] + AggregationAuthorization: AggregationAuthorization | None class PutConfigRuleRequest(ServiceRequest): ConfigRule: ConfigRule - Tags: Optional[TagsList] + Tags: TagsList | None class PutConfigurationAggregatorRequest(ServiceRequest): ConfigurationAggregatorName: ConfigurationAggregatorName - AccountAggregationSources: Optional[AccountAggregationSourceList] - OrganizationAggregationSource: Optional[OrganizationAggregationSource] - Tags: Optional[TagsList] - AggregatorFilters: Optional[AggregatorFilters] + AccountAggregationSources: AccountAggregationSourceList | None + OrganizationAggregationSource: OrganizationAggregationSource | None + Tags: TagsList | None + AggregatorFilters: AggregatorFilters | None class PutConfigurationAggregatorResponse(TypedDict, total=False): - ConfigurationAggregator: Optional[ConfigurationAggregator] + ConfigurationAggregator: ConfigurationAggregator | None class PutConfigurationRecorderRequest(ServiceRequest): ConfigurationRecorder: ConfigurationRecorder - Tags: Optional[TagsList] + Tags: TagsList | None class PutConformancePackRequest(ServiceRequest): ConformancePackName: ConformancePackName - TemplateS3Uri: Optional[TemplateS3Uri] - TemplateBody: Optional[TemplateBody] - DeliveryS3Bucket: Optional[DeliveryS3Bucket] - DeliveryS3KeyPrefix: Optional[DeliveryS3KeyPrefix] - ConformancePackInputParameters: Optional[ConformancePackInputParameters] - TemplateSSMDocumentDetails: Optional[TemplateSSMDocumentDetails] + TemplateS3Uri: TemplateS3Uri | None + TemplateBody: TemplateBody | None + DeliveryS3Bucket: DeliveryS3Bucket | None + DeliveryS3KeyPrefix: DeliveryS3KeyPrefix | None + ConformancePackInputParameters: ConformancePackInputParameters | None + TemplateSSMDocumentDetails: TemplateSSMDocumentDetails | None + Tags: TagsList | None class PutConformancePackResponse(TypedDict, total=False): - ConformancePackArn: Optional[ConformancePackArn] + ConformancePackArn: ConformancePackArn | None class PutDeliveryChannelRequest(ServiceRequest): @@ -2943,13 +3035,13 @@ class PutDeliveryChannelRequest(ServiceRequest): class PutEvaluationsRequest(ServiceRequest): - Evaluations: Optional[Evaluations] + Evaluations: Evaluations | None ResultToken: String - TestMode: Optional[Boolean] + TestMode: Boolean | None class PutEvaluationsResponse(TypedDict, total=False): - FailedEvaluations: Optional[Evaluations] + FailedEvaluations: Evaluations | None class PutExternalEvaluationRequest(ServiceRequest): @@ -2963,28 +3055,28 @@ class PutExternalEvaluationResponse(TypedDict, total=False): class PutOrganizationConfigRuleRequest(ServiceRequest): OrganizationConfigRuleName: OrganizationConfigRuleName - OrganizationManagedRuleMetadata: Optional[OrganizationManagedRuleMetadata] - OrganizationCustomRuleMetadata: Optional[OrganizationCustomRuleMetadata] - ExcludedAccounts: Optional[ExcludedAccounts] - OrganizationCustomPolicyRuleMetadata: Optional[OrganizationCustomPolicyRuleMetadata] + OrganizationManagedRuleMetadata: OrganizationManagedRuleMetadata | None + OrganizationCustomRuleMetadata: OrganizationCustomRuleMetadata | None + ExcludedAccounts: ExcludedAccounts | None + OrganizationCustomPolicyRuleMetadata: OrganizationCustomPolicyRuleMetadata | None class PutOrganizationConfigRuleResponse(TypedDict, total=False): - OrganizationConfigRuleArn: Optional[StringWithCharLimit256] + OrganizationConfigRuleArn: StringWithCharLimit256 | None class PutOrganizationConformancePackRequest(ServiceRequest): OrganizationConformancePackName: OrganizationConformancePackName - TemplateS3Uri: Optional[TemplateS3Uri] - TemplateBody: Optional[TemplateBody] - DeliveryS3Bucket: Optional[DeliveryS3Bucket] - DeliveryS3KeyPrefix: Optional[DeliveryS3KeyPrefix] - ConformancePackInputParameters: Optional[ConformancePackInputParameters] - ExcludedAccounts: Optional[ExcludedAccounts] + TemplateS3Uri: TemplateS3Uri | None + TemplateBody: TemplateBody | None + DeliveryS3Bucket: DeliveryS3Bucket | None + DeliveryS3KeyPrefix: DeliveryS3KeyPrefix | None + ConformancePackInputParameters: ConformancePackInputParameters | None + ExcludedAccounts: ExcludedAccounts | None class PutOrganizationConformancePackResponse(TypedDict, total=False): - OrganizationConformancePackArn: Optional[StringWithCharLimit256] + OrganizationConformancePackArn: StringWithCharLimit256 | None class PutRemediationConfigurationsRequest(ServiceRequest): @@ -2992,27 +3084,27 @@ class PutRemediationConfigurationsRequest(ServiceRequest): class PutRemediationConfigurationsResponse(TypedDict, total=False): - FailedBatches: Optional[FailedRemediationBatches] + FailedBatches: FailedRemediationBatches | None class PutRemediationExceptionsRequest(ServiceRequest): ConfigRuleName: ConfigRuleName ResourceKeys: RemediationExceptionResourceKeys - Message: Optional[StringWithCharLimit1024] - ExpirationTime: Optional[Date] + Message: StringWithCharLimit1024 | None + ExpirationTime: Date | None class PutRemediationExceptionsResponse(TypedDict, total=False): - FailedBatches: Optional[FailedRemediationExceptionBatches] + FailedBatches: FailedRemediationExceptionBatches | None class PutResourceConfigRequest(ServiceRequest): ResourceType: ResourceTypeString SchemaVersionId: SchemaVersionId ResourceId: ResourceId - ResourceName: Optional[ResourceName] + ResourceName: ResourceName | None Configuration: Configuration - Tags: Optional[Tags] + Tags: Tags | None class PutRetentionConfigurationRequest(ServiceRequest): @@ -3020,64 +3112,64 @@ class PutRetentionConfigurationRequest(ServiceRequest): class PutRetentionConfigurationResponse(TypedDict, total=False): - RetentionConfiguration: Optional[RetentionConfiguration] + RetentionConfiguration: RetentionConfiguration | None class PutServiceLinkedConfigurationRecorderRequest(ServiceRequest): ServicePrincipal: ServicePrincipal - Tags: Optional[TagsList] + Tags: TagsList | None class PutServiceLinkedConfigurationRecorderResponse(TypedDict, total=False): - Arn: Optional[AmazonResourceName] - Name: Optional[RecorderName] + Arn: AmazonResourceName | None + Name: RecorderName | None class PutStoredQueryRequest(ServiceRequest): StoredQuery: StoredQuery - Tags: Optional[TagsList] + Tags: TagsList | None class PutStoredQueryResponse(TypedDict, total=False): - QueryArn: Optional[QueryArn] + QueryArn: QueryArn | None class QueryInfo(TypedDict, total=False): - SelectFields: Optional[FieldInfoList] + SelectFields: FieldInfoList | None -ReevaluateConfigRuleNames = List[ConfigRuleName] -Results = List[String] +ReevaluateConfigRuleNames = list[ConfigRuleName] +Results = list[String] class SelectAggregateResourceConfigRequest(ServiceRequest): Expression: Expression ConfigurationAggregatorName: ConfigurationAggregatorName - Limit: Optional[Limit] - MaxResults: Optional[Limit] - NextToken: Optional[NextToken] + Limit: Limit | None + MaxResults: Limit | None + NextToken: NextToken | None class SelectAggregateResourceConfigResponse(TypedDict, total=False): - Results: Optional[Results] - QueryInfo: Optional[QueryInfo] - NextToken: Optional[NextToken] + Results: Results | None + QueryInfo: QueryInfo | None + NextToken: NextToken | None class SelectResourceConfigRequest(ServiceRequest): Expression: Expression - Limit: Optional[Limit] - NextToken: Optional[NextToken] + Limit: Limit | None + NextToken: NextToken | None class SelectResourceConfigResponse(TypedDict, total=False): - Results: Optional[Results] - QueryInfo: Optional[QueryInfo] - NextToken: Optional[NextToken] + Results: Results | None + QueryInfo: QueryInfo | None + NextToken: NextToken | None class StartConfigRulesEvaluationRequest(ServiceRequest): - ConfigRuleNames: Optional[ReevaluateConfigRuleNames] + ConfigRuleNames: ReevaluateConfigRuleNames | None class StartConfigRulesEvaluationResponse(TypedDict, total=False): @@ -3094,27 +3186,27 @@ class StartRemediationExecutionRequest(ServiceRequest): class StartRemediationExecutionResponse(TypedDict, total=False): - FailureMessage: Optional[String] - FailedItems: Optional[ResourceKeys] + FailureMessage: String | None + FailedItems: ResourceKeys | None class StartResourceEvaluationRequest(ServiceRequest): ResourceDetails: ResourceDetails - EvaluationContext: Optional[EvaluationContext] + EvaluationContext: EvaluationContext | None EvaluationMode: EvaluationMode - EvaluationTimeout: Optional[EvaluationTimeout] - ClientToken: Optional[ClientToken] + EvaluationTimeout: EvaluationTimeout | None + ClientToken: ClientToken | None class StartResourceEvaluationResponse(TypedDict, total=False): - ResourceEvaluationId: Optional[ResourceEvaluationId] + ResourceEvaluationId: ResourceEvaluationId | None class StopConfigurationRecorderRequest(ServiceRequest): ConfigurationRecorderName: RecorderName -TagKeyList = List[TagKey] +TagKeyList = list[TagKey] class TagResourceRequest(ServiceRequest): @@ -3128,8 +3220,8 @@ class UntagResourceRequest(ServiceRequest): class ConfigApi: - service = "config" - version = "2014-11-12" + service: str = "config" + version: str = "2014-11-12" @handler("AssociateResourceTypes") def associate_resource_types( @@ -3911,6 +4003,7 @@ def put_conformance_pack( delivery_s3_key_prefix: DeliveryS3KeyPrefix | None = None, conformance_pack_input_parameters: ConformancePackInputParameters | None = None, template_ssm_document_details: TemplateSSMDocumentDetails | None = None, + tags: TagsList | None = None, **kwargs, ) -> PutConformancePackResponse: raise NotImplementedError diff --git a/localstack-core/localstack/aws/api/dynamodb/__init__.py b/localstack-core/localstack/aws/api/dynamodb/__init__.py index bc0d95548fc9f..8c8e1a6d58903 100644 --- a/localstack-core/localstack/aws/api/dynamodb/__init__.py +++ b/localstack-core/localstack/aws/api/dynamodb/__init__.py @@ -1,6 +1,6 @@ from datetime import datetime from enum import StrEnum -from typing import Dict, List, Optional, TypedDict +from typing import TypedDict from localstack.aws.api import RequestContext, ServiceException, ServiceRequest, handler @@ -215,6 +215,12 @@ class ExportViewType(StrEnum): NEW_AND_OLD_IMAGES = "NEW_AND_OLD_IMAGES" +class GlobalTableSettingsReplicationMode(StrEnum): + ENABLED = "ENABLED" + DISABLED = "DISABLED" + ENABLED_WITH_OVERRIDES = "ENABLED_WITH_OVERRIDES" + + class GlobalTableStatus(StrEnum): CREATING = "CREATING" ACTIVE = "ACTIVE" @@ -387,32 +393,32 @@ class BackupNotFoundException(ServiceException): class AttributeValue(TypedDict, total=False): - S: Optional["StringAttributeValue"] - N: Optional["NumberAttributeValue"] - B: Optional["BinaryAttributeValue"] - SS: Optional["StringSetAttributeValue"] - NS: Optional["NumberSetAttributeValue"] - BS: Optional["BinarySetAttributeValue"] - M: Optional["MapAttributeValue"] - L: Optional["ListAttributeValue"] - NULL: Optional["NullAttributeValue"] - BOOL: Optional["BooleanAttributeValue"] - - -ListAttributeValue = List[AttributeValue] -MapAttributeValue = Dict[AttributeName, AttributeValue] + S: "StringAttributeValue | None" + N: "NumberAttributeValue | None" + B: "BinaryAttributeValue | None" + SS: "StringSetAttributeValue | None" + NS: "NumberSetAttributeValue | None" + BS: "BinarySetAttributeValue | None" + M: "MapAttributeValue | None" + L: "ListAttributeValue | None" + NULL: "NullAttributeValue | None" + BOOL: "BooleanAttributeValue | None" + + +ListAttributeValue = list[AttributeValue] +MapAttributeValue = dict[AttributeName, AttributeValue] BinaryAttributeValue = bytes -BinarySetAttributeValue = List[BinaryAttributeValue] -NumberSetAttributeValue = List[NumberAttributeValue] -StringSetAttributeValue = List[StringAttributeValue] -AttributeMap = Dict[AttributeName, AttributeValue] +BinarySetAttributeValue = list[BinaryAttributeValue] +NumberSetAttributeValue = list[NumberAttributeValue] +StringSetAttributeValue = list[StringAttributeValue] +AttributeMap = dict[AttributeName, AttributeValue] class ConditionalCheckFailedException(ServiceException): code: str = "ConditionalCheckFailedException" sender_fault: bool = False status_code: int = 400 - Item: Optional[AttributeMap] + Item: AttributeMap | None class ContinuousBackupsUnavailableException(ServiceException): @@ -518,18 +524,18 @@ class PolicyNotFoundException(ServiceException): class ThrottlingReason(TypedDict, total=False): - reason: Optional[Reason] - resource: Optional[Resource] + reason: Reason | None + resource: Resource | None -ThrottlingReasonList = List[ThrottlingReason] +ThrottlingReasonList = list[ThrottlingReason] class ProvisionedThroughputExceededException(ServiceException): code: str = "ProvisionedThroughputExceededException" sender_fault: bool = False status_code: int = 400 - ThrottlingReasons: Optional[ThrottlingReasonList] + ThrottlingReasons: ThrottlingReasonList | None class ReplicaAlreadyExistsException(ServiceException): @@ -554,7 +560,7 @@ class RequestLimitExceeded(ServiceException): code: str = "RequestLimitExceeded" sender_fault: bool = False status_code: int = 400 - ThrottlingReasons: Optional[ThrottlingReasonList] + ThrottlingReasons: ThrottlingReasonList | None class ResourceInUseException(ServiceException): @@ -591,23 +597,23 @@ class ThrottlingException(ServiceException): code: str = "ThrottlingException" sender_fault: bool = False status_code: int = 400 - throttlingReasons: Optional[ThrottlingReasonList] + throttlingReasons: ThrottlingReasonList | None class CancellationReason(TypedDict, total=False): - Item: Optional[AttributeMap] - Code: Optional[Code] - Message: Optional[ErrorMessage] + Item: AttributeMap | None + Code: Code | None + Message: ErrorMessage | None -CancellationReasonList = List[CancellationReason] +CancellationReasonList = list[CancellationReason] class TransactionCanceledException(ServiceException): code: str = "TransactionCanceledException" sender_fault: bool = False status_code: int = 400 - CancellationReasons: Optional[CancellationReasonList] + CancellationReasons: CancellationReasonList | None class TransactionConflictException(ServiceException): @@ -626,9 +632,9 @@ class TransactionInProgressException(ServiceException): class ArchivalSummary(TypedDict, total=False): - ArchivalDateTime: Optional[Date] - ArchivalReason: Optional[ArchivalReason] - ArchivalBackupArn: Optional[BackupArn] + ArchivalDateTime: Date | None + ArchivalReason: ArchivalReason | None + ArchivalBackupArn: BackupArn | None class AttributeDefinition(TypedDict, total=False): @@ -636,45 +642,45 @@ class AttributeDefinition(TypedDict, total=False): AttributeType: ScalarAttributeType -AttributeDefinitions = List[AttributeDefinition] -AttributeNameList = List[AttributeName] +AttributeDefinitions = list[AttributeDefinition] +AttributeNameList = list[AttributeName] class AttributeValueUpdate(TypedDict, total=False): - Value: Optional[AttributeValue] - Action: Optional[AttributeAction] + Value: AttributeValue | None + Action: AttributeAction | None -AttributeUpdates = Dict[AttributeName, AttributeValueUpdate] -AttributeValueList = List[AttributeValue] +AttributeUpdates = dict[AttributeName, AttributeValueUpdate] +AttributeValueList = list[AttributeValue] class AutoScalingTargetTrackingScalingPolicyConfigurationDescription(TypedDict, total=False): - DisableScaleIn: Optional[BooleanObject] - ScaleInCooldown: Optional[IntegerObject] - ScaleOutCooldown: Optional[IntegerObject] + DisableScaleIn: BooleanObject | None + ScaleInCooldown: IntegerObject | None + ScaleOutCooldown: IntegerObject | None TargetValue: DoubleObject class AutoScalingPolicyDescription(TypedDict, total=False): - PolicyName: Optional[AutoScalingPolicyName] - TargetTrackingScalingPolicyConfiguration: Optional[ - AutoScalingTargetTrackingScalingPolicyConfigurationDescription - ] + PolicyName: AutoScalingPolicyName | None + TargetTrackingScalingPolicyConfiguration: ( + AutoScalingTargetTrackingScalingPolicyConfigurationDescription | None + ) -AutoScalingPolicyDescriptionList = List[AutoScalingPolicyDescription] +AutoScalingPolicyDescriptionList = list[AutoScalingPolicyDescription] class AutoScalingTargetTrackingScalingPolicyConfigurationUpdate(TypedDict, total=False): - DisableScaleIn: Optional[BooleanObject] - ScaleInCooldown: Optional[IntegerObject] - ScaleOutCooldown: Optional[IntegerObject] + DisableScaleIn: BooleanObject | None + ScaleInCooldown: IntegerObject | None + ScaleOutCooldown: IntegerObject | None TargetValue: DoubleObject class AutoScalingPolicyUpdate(TypedDict, total=False): - PolicyName: Optional[AutoScalingPolicyName] + PolicyName: AutoScalingPolicyName | None TargetTrackingScalingPolicyConfiguration: ( AutoScalingTargetTrackingScalingPolicyConfigurationUpdate ) @@ -684,47 +690,47 @@ class AutoScalingPolicyUpdate(TypedDict, total=False): class AutoScalingSettingsDescription(TypedDict, total=False): - MinimumUnits: Optional[PositiveLongObject] - MaximumUnits: Optional[PositiveLongObject] - AutoScalingDisabled: Optional[BooleanObject] - AutoScalingRoleArn: Optional[String] - ScalingPolicies: Optional[AutoScalingPolicyDescriptionList] + MinimumUnits: PositiveLongObject | None + MaximumUnits: PositiveLongObject | None + AutoScalingDisabled: BooleanObject | None + AutoScalingRoleArn: String | None + ScalingPolicies: AutoScalingPolicyDescriptionList | None class AutoScalingSettingsUpdate(TypedDict, total=False): - MinimumUnits: Optional[PositiveLongObject] - MaximumUnits: Optional[PositiveLongObject] - AutoScalingDisabled: Optional[BooleanObject] - AutoScalingRoleArn: Optional[AutoScalingRoleArn] - ScalingPolicyUpdate: Optional[AutoScalingPolicyUpdate] + MinimumUnits: PositiveLongObject | None + MaximumUnits: PositiveLongObject | None + AutoScalingDisabled: BooleanObject | None + AutoScalingRoleArn: AutoScalingRoleArn | None + ScalingPolicyUpdate: AutoScalingPolicyUpdate | None BackupCreationDateTime = datetime class SSEDescription(TypedDict, total=False): - Status: Optional[SSEStatus] - SSEType: Optional[SSEType] - KMSMasterKeyArn: Optional[KMSMasterKeyArn] - InaccessibleEncryptionDateTime: Optional[Date] + Status: SSEStatus | None + SSEType: SSEType | None + KMSMasterKeyArn: KMSMasterKeyArn | None + InaccessibleEncryptionDateTime: Date | None class TimeToLiveDescription(TypedDict, total=False): - TimeToLiveStatus: Optional[TimeToLiveStatus] - AttributeName: Optional[TimeToLiveAttributeName] + TimeToLiveStatus: TimeToLiveStatus | None + AttributeName: TimeToLiveAttributeName | None class StreamSpecification(TypedDict, total=False): StreamEnabled: StreamEnabled - StreamViewType: Optional[StreamViewType] + StreamViewType: StreamViewType | None LongObject = int class OnDemandThroughput(TypedDict, total=False): - MaxReadRequestUnits: Optional[LongObject] - MaxWriteRequestUnits: Optional[LongObject] + MaxReadRequestUnits: LongObject | None + MaxWriteRequestUnits: LongObject | None class ProvisionedThroughput(TypedDict, total=False): @@ -732,12 +738,12 @@ class ProvisionedThroughput(TypedDict, total=False): WriteCapacityUnits: PositiveLongObject -NonKeyAttributeNameList = List[NonKeyAttributeName] +NonKeyAttributeNameList = list[NonKeyAttributeName] class Projection(TypedDict, total=False): - ProjectionType: Optional[ProjectionType] - NonKeyAttributes: Optional[NonKeyAttributeNameList] + ProjectionType: ProjectionType | None + NonKeyAttributes: NonKeyAttributeNameList | None class KeySchemaElement(TypedDict, total=False): @@ -745,35 +751,35 @@ class KeySchemaElement(TypedDict, total=False): KeyType: KeyType -KeySchema = List[KeySchemaElement] +KeySchema = list[KeySchemaElement] class GlobalSecondaryIndexInfo(TypedDict, total=False): - IndexName: Optional[IndexName] - KeySchema: Optional[KeySchema] - Projection: Optional[Projection] - ProvisionedThroughput: Optional[ProvisionedThroughput] - OnDemandThroughput: Optional[OnDemandThroughput] + IndexName: IndexName | None + KeySchema: KeySchema | None + Projection: Projection | None + ProvisionedThroughput: ProvisionedThroughput | None + OnDemandThroughput: OnDemandThroughput | None -GlobalSecondaryIndexes = List[GlobalSecondaryIndexInfo] +GlobalSecondaryIndexes = list[GlobalSecondaryIndexInfo] class LocalSecondaryIndexInfo(TypedDict, total=False): - IndexName: Optional[IndexName] - KeySchema: Optional[KeySchema] - Projection: Optional[Projection] + IndexName: IndexName | None + KeySchema: KeySchema | None + Projection: Projection | None -LocalSecondaryIndexes = List[LocalSecondaryIndexInfo] +LocalSecondaryIndexes = list[LocalSecondaryIndexInfo] class SourceTableFeatureDetails(TypedDict, total=False): - LocalSecondaryIndexes: Optional[LocalSecondaryIndexes] - GlobalSecondaryIndexes: Optional[GlobalSecondaryIndexes] - StreamDescription: Optional[StreamSpecification] - TimeToLiveDescription: Optional[TimeToLiveDescription] - SSEDescription: Optional[SSEDescription] + LocalSecondaryIndexes: LocalSecondaryIndexes | None + GlobalSecondaryIndexes: GlobalSecondaryIndexes | None + StreamDescription: StreamSpecification | None + TimeToLiveDescription: TimeToLiveDescription | None + SSEDescription: SSEDescription | None ItemCount = int @@ -783,14 +789,14 @@ class SourceTableFeatureDetails(TypedDict, total=False): class SourceTableDetails(TypedDict, total=False): TableName: TableName TableId: TableId - TableArn: Optional[TableArn] - TableSizeBytes: Optional[LongObject] + TableArn: TableArn | None + TableSizeBytes: LongObject | None KeySchema: KeySchema TableCreationDateTime: TableCreationDateTime ProvisionedThroughput: ProvisionedThroughput - OnDemandThroughput: Optional[OnDemandThroughput] - ItemCount: Optional[ItemCount] - BillingMode: Optional[BillingMode] + OnDemandThroughput: OnDemandThroughput | None + ItemCount: ItemCount | None + BillingMode: BillingMode | None BackupSizeBytes = int @@ -799,129 +805,129 @@ class SourceTableDetails(TypedDict, total=False): class BackupDetails(TypedDict, total=False): BackupArn: BackupArn BackupName: BackupName - BackupSizeBytes: Optional[BackupSizeBytes] + BackupSizeBytes: BackupSizeBytes | None BackupStatus: BackupStatus BackupType: BackupType BackupCreationDateTime: BackupCreationDateTime - BackupExpiryDateTime: Optional[Date] + BackupExpiryDateTime: Date | None class BackupDescription(TypedDict, total=False): - BackupDetails: Optional[BackupDetails] - SourceTableDetails: Optional[SourceTableDetails] - SourceTableFeatureDetails: Optional[SourceTableFeatureDetails] + BackupDetails: BackupDetails | None + SourceTableDetails: SourceTableDetails | None + SourceTableFeatureDetails: SourceTableFeatureDetails | None class BackupSummary(TypedDict, total=False): - TableName: Optional[TableName] - TableId: Optional[TableId] - TableArn: Optional[TableArn] - BackupArn: Optional[BackupArn] - BackupName: Optional[BackupName] - BackupCreationDateTime: Optional[BackupCreationDateTime] - BackupExpiryDateTime: Optional[Date] - BackupStatus: Optional[BackupStatus] - BackupType: Optional[BackupType] - BackupSizeBytes: Optional[BackupSizeBytes] + TableName: TableName | None + TableId: TableId | None + TableArn: TableArn | None + BackupArn: BackupArn | None + BackupName: BackupName | None + BackupCreationDateTime: BackupCreationDateTime | None + BackupExpiryDateTime: Date | None + BackupStatus: BackupStatus | None + BackupType: BackupType | None + BackupSizeBytes: BackupSizeBytes | None -BackupSummaries = List[BackupSummary] -PreparedStatementParameters = List[AttributeValue] +BackupSummaries = list[BackupSummary] +PreparedStatementParameters = list[AttributeValue] class BatchStatementRequest(TypedDict, total=False): Statement: PartiQLStatement - Parameters: Optional[PreparedStatementParameters] - ConsistentRead: Optional[ConsistentRead] - ReturnValuesOnConditionCheckFailure: Optional[ReturnValuesOnConditionCheckFailure] + Parameters: PreparedStatementParameters | None + ConsistentRead: ConsistentRead | None + ReturnValuesOnConditionCheckFailure: ReturnValuesOnConditionCheckFailure | None -PartiQLBatchRequest = List[BatchStatementRequest] +PartiQLBatchRequest = list[BatchStatementRequest] class BatchExecuteStatementInput(ServiceRequest): Statements: PartiQLBatchRequest - ReturnConsumedCapacity: Optional[ReturnConsumedCapacity] + ReturnConsumedCapacity: ReturnConsumedCapacity | None class Capacity(TypedDict, total=False): - ReadCapacityUnits: Optional[ConsumedCapacityUnits] - WriteCapacityUnits: Optional[ConsumedCapacityUnits] - CapacityUnits: Optional[ConsumedCapacityUnits] + ReadCapacityUnits: ConsumedCapacityUnits | None + WriteCapacityUnits: ConsumedCapacityUnits | None + CapacityUnits: ConsumedCapacityUnits | None -SecondaryIndexesCapacityMap = Dict[IndexName, Capacity] +SecondaryIndexesCapacityMap = dict[IndexName, Capacity] class ConsumedCapacity(TypedDict, total=False): - TableName: Optional[TableArn] - CapacityUnits: Optional[ConsumedCapacityUnits] - ReadCapacityUnits: Optional[ConsumedCapacityUnits] - WriteCapacityUnits: Optional[ConsumedCapacityUnits] - Table: Optional[Capacity] - LocalSecondaryIndexes: Optional[SecondaryIndexesCapacityMap] - GlobalSecondaryIndexes: Optional[SecondaryIndexesCapacityMap] + TableName: TableArn | None + CapacityUnits: ConsumedCapacityUnits | None + ReadCapacityUnits: ConsumedCapacityUnits | None + WriteCapacityUnits: ConsumedCapacityUnits | None + Table: Capacity | None + LocalSecondaryIndexes: SecondaryIndexesCapacityMap | None + GlobalSecondaryIndexes: SecondaryIndexesCapacityMap | None -ConsumedCapacityMultiple = List[ConsumedCapacity] +ConsumedCapacityMultiple = list[ConsumedCapacity] class BatchStatementError(TypedDict, total=False): - Code: Optional[BatchStatementErrorCodeEnum] - Message: Optional[String] - Item: Optional[AttributeMap] + Code: BatchStatementErrorCodeEnum | None + Message: String | None + Item: AttributeMap | None class BatchStatementResponse(TypedDict, total=False): - Error: Optional[BatchStatementError] - TableName: Optional[TableName] - Item: Optional[AttributeMap] + Error: BatchStatementError | None + TableName: TableName | None + Item: AttributeMap | None -PartiQLBatchResponse = List[BatchStatementResponse] +PartiQLBatchResponse = list[BatchStatementResponse] class BatchExecuteStatementOutput(TypedDict, total=False): - Responses: Optional[PartiQLBatchResponse] - ConsumedCapacity: Optional[ConsumedCapacityMultiple] + Responses: PartiQLBatchResponse | None + ConsumedCapacity: ConsumedCapacityMultiple | None -ExpressionAttributeNameMap = Dict[ExpressionAttributeNameVariable, AttributeName] -Key = Dict[AttributeName, AttributeValue] -KeyList = List[Key] +ExpressionAttributeNameMap = dict[ExpressionAttributeNameVariable, AttributeName] +Key = dict[AttributeName, AttributeValue] +KeyList = list[Key] class KeysAndAttributes(TypedDict, total=False): Keys: KeyList - AttributesToGet: Optional[AttributeNameList] - ConsistentRead: Optional[ConsistentRead] - ProjectionExpression: Optional[ProjectionExpression] - ExpressionAttributeNames: Optional[ExpressionAttributeNameMap] + AttributesToGet: AttributeNameList | None + ConsistentRead: ConsistentRead | None + ProjectionExpression: ProjectionExpression | None + ExpressionAttributeNames: ExpressionAttributeNameMap | None -BatchGetRequestMap = Dict[TableArn, KeysAndAttributes] +BatchGetRequestMap = dict[TableArn, KeysAndAttributes] class BatchGetItemInput(ServiceRequest): RequestItems: BatchGetRequestMap - ReturnConsumedCapacity: Optional[ReturnConsumedCapacity] + ReturnConsumedCapacity: ReturnConsumedCapacity | None -ItemList = List[AttributeMap] -BatchGetResponseMap = Dict[TableArn, ItemList] +ItemList = list[AttributeMap] +BatchGetResponseMap = dict[TableArn, ItemList] class BatchGetItemOutput(TypedDict, total=False): - Responses: Optional[BatchGetResponseMap] - UnprocessedKeys: Optional[BatchGetRequestMap] - ConsumedCapacity: Optional[ConsumedCapacityMultiple] + Responses: BatchGetResponseMap | None + UnprocessedKeys: BatchGetRequestMap | None + ConsumedCapacity: ConsumedCapacityMultiple | None class DeleteRequest(TypedDict, total=False): Key: Key -PutItemInputAttributeMap = Dict[AttributeName, AttributeValue] +PutItemInputAttributeMap = dict[AttributeName, AttributeValue] class PutRequest(TypedDict, total=False): @@ -929,87 +935,87 @@ class PutRequest(TypedDict, total=False): class WriteRequest(TypedDict, total=False): - PutRequest: Optional[PutRequest] - DeleteRequest: Optional[DeleteRequest] + PutRequest: PutRequest | None + DeleteRequest: DeleteRequest | None -WriteRequests = List[WriteRequest] -BatchWriteItemRequestMap = Dict[TableArn, WriteRequests] +WriteRequests = list[WriteRequest] +BatchWriteItemRequestMap = dict[TableArn, WriteRequests] class BatchWriteItemInput(ServiceRequest): RequestItems: BatchWriteItemRequestMap - ReturnConsumedCapacity: Optional[ReturnConsumedCapacity] - ReturnItemCollectionMetrics: Optional[ReturnItemCollectionMetrics] + ReturnConsumedCapacity: ReturnConsumedCapacity | None + ReturnItemCollectionMetrics: ReturnItemCollectionMetrics | None -ItemCollectionSizeEstimateRange = List[ItemCollectionSizeEstimateBound] -ItemCollectionKeyAttributeMap = Dict[AttributeName, AttributeValue] +ItemCollectionSizeEstimateRange = list[ItemCollectionSizeEstimateBound] +ItemCollectionKeyAttributeMap = dict[AttributeName, AttributeValue] class ItemCollectionMetrics(TypedDict, total=False): - ItemCollectionKey: Optional[ItemCollectionKeyAttributeMap] - SizeEstimateRangeGB: Optional[ItemCollectionSizeEstimateRange] + ItemCollectionKey: ItemCollectionKeyAttributeMap | None + SizeEstimateRangeGB: ItemCollectionSizeEstimateRange | None -ItemCollectionMetricsMultiple = List[ItemCollectionMetrics] -ItemCollectionMetricsPerTable = Dict[TableArn, ItemCollectionMetricsMultiple] +ItemCollectionMetricsMultiple = list[ItemCollectionMetrics] +ItemCollectionMetricsPerTable = dict[TableArn, ItemCollectionMetricsMultiple] class BatchWriteItemOutput(TypedDict, total=False): - UnprocessedItems: Optional[BatchWriteItemRequestMap] - ItemCollectionMetrics: Optional[ItemCollectionMetricsPerTable] - ConsumedCapacity: Optional[ConsumedCapacityMultiple] + UnprocessedItems: BatchWriteItemRequestMap | None + ItemCollectionMetrics: ItemCollectionMetricsPerTable | None + ConsumedCapacity: ConsumedCapacityMultiple | None BilledSizeBytes = int class BillingModeSummary(TypedDict, total=False): - BillingMode: Optional[BillingMode] - LastUpdateToPayPerRequestDateTime: Optional[Date] + BillingMode: BillingMode | None + LastUpdateToPayPerRequestDateTime: Date | None class Condition(TypedDict, total=False): - AttributeValueList: Optional[AttributeValueList] + AttributeValueList: AttributeValueList | None ComparisonOperator: ComparisonOperator -ExpressionAttributeValueMap = Dict[ExpressionAttributeValueVariable, AttributeValue] +ExpressionAttributeValueMap = dict[ExpressionAttributeValueVariable, AttributeValue] class ConditionCheck(TypedDict, total=False): Key: Key TableName: TableArn ConditionExpression: ConditionExpression - ExpressionAttributeNames: Optional[ExpressionAttributeNameMap] - ExpressionAttributeValues: Optional[ExpressionAttributeValueMap] - ReturnValuesOnConditionCheckFailure: Optional[ReturnValuesOnConditionCheckFailure] + ExpressionAttributeNames: ExpressionAttributeNameMap | None + ExpressionAttributeValues: ExpressionAttributeValueMap | None + ReturnValuesOnConditionCheckFailure: ReturnValuesOnConditionCheckFailure | None class PointInTimeRecoveryDescription(TypedDict, total=False): - PointInTimeRecoveryStatus: Optional[PointInTimeRecoveryStatus] - RecoveryPeriodInDays: Optional[RecoveryPeriodInDays] - EarliestRestorableDateTime: Optional[Date] - LatestRestorableDateTime: Optional[Date] + PointInTimeRecoveryStatus: PointInTimeRecoveryStatus | None + RecoveryPeriodInDays: RecoveryPeriodInDays | None + EarliestRestorableDateTime: Date | None + LatestRestorableDateTime: Date | None class ContinuousBackupsDescription(TypedDict, total=False): ContinuousBackupsStatus: ContinuousBackupsStatus - PointInTimeRecoveryDescription: Optional[PointInTimeRecoveryDescription] + PointInTimeRecoveryDescription: PointInTimeRecoveryDescription | None -ContributorInsightsRuleList = List[ContributorInsightsRule] +ContributorInsightsRuleList = list[ContributorInsightsRule] class ContributorInsightsSummary(TypedDict, total=False): - TableName: Optional[TableName] - IndexName: Optional[IndexName] - ContributorInsightsStatus: Optional[ContributorInsightsStatus] - ContributorInsightsMode: Optional[ContributorInsightsMode] + TableName: TableName | None + IndexName: IndexName | None + ContributorInsightsStatus: ContributorInsightsStatus | None + ContributorInsightsMode: ContributorInsightsMode | None -ContributorInsightsSummaries = List[ContributorInsightsSummary] +ContributorInsightsSummaries = list[ContributorInsightsSummary] class CreateBackupInput(ServiceRequest): @@ -1018,28 +1024,28 @@ class CreateBackupInput(ServiceRequest): class CreateBackupOutput(TypedDict, total=False): - BackupDetails: Optional[BackupDetails] + BackupDetails: BackupDetails | None class WarmThroughput(TypedDict, total=False): - ReadUnitsPerSecond: Optional[LongObject] - WriteUnitsPerSecond: Optional[LongObject] + ReadUnitsPerSecond: LongObject | None + WriteUnitsPerSecond: LongObject | None class CreateGlobalSecondaryIndexAction(TypedDict, total=False): IndexName: IndexName KeySchema: KeySchema Projection: Projection - ProvisionedThroughput: Optional[ProvisionedThroughput] - OnDemandThroughput: Optional[OnDemandThroughput] - WarmThroughput: Optional[WarmThroughput] + ProvisionedThroughput: ProvisionedThroughput | None + OnDemandThroughput: OnDemandThroughput | None + WarmThroughput: WarmThroughput | None class Replica(TypedDict, total=False): - RegionName: Optional[RegionName] + RegionName: RegionName | None -ReplicaList = List[Replica] +ReplicaList = list[Replica] class CreateGlobalTableInput(ServiceRequest): @@ -1048,67 +1054,68 @@ class CreateGlobalTableInput(ServiceRequest): class TableClassSummary(TypedDict, total=False): - TableClass: Optional[TableClass] - LastUpdateDateTime: Optional[Date] + TableClass: TableClass | None + LastUpdateDateTime: Date | None class GlobalSecondaryIndexWarmThroughputDescription(TypedDict, total=False): - ReadUnitsPerSecond: Optional[PositiveLongObject] - WriteUnitsPerSecond: Optional[PositiveLongObject] - Status: Optional[IndexStatus] + ReadUnitsPerSecond: PositiveLongObject | None + WriteUnitsPerSecond: PositiveLongObject | None + Status: IndexStatus | None class OnDemandThroughputOverride(TypedDict, total=False): - MaxReadRequestUnits: Optional[LongObject] + MaxReadRequestUnits: LongObject | None class ProvisionedThroughputOverride(TypedDict, total=False): - ReadCapacityUnits: Optional[PositiveLongObject] + ReadCapacityUnits: PositiveLongObject | None class ReplicaGlobalSecondaryIndexDescription(TypedDict, total=False): - IndexName: Optional[IndexName] - ProvisionedThroughputOverride: Optional[ProvisionedThroughputOverride] - OnDemandThroughputOverride: Optional[OnDemandThroughputOverride] - WarmThroughput: Optional[GlobalSecondaryIndexWarmThroughputDescription] + IndexName: IndexName | None + ProvisionedThroughputOverride: ProvisionedThroughputOverride | None + OnDemandThroughputOverride: OnDemandThroughputOverride | None + WarmThroughput: GlobalSecondaryIndexWarmThroughputDescription | None -ReplicaGlobalSecondaryIndexDescriptionList = List[ReplicaGlobalSecondaryIndexDescription] +ReplicaGlobalSecondaryIndexDescriptionList = list[ReplicaGlobalSecondaryIndexDescription] class TableWarmThroughputDescription(TypedDict, total=False): - ReadUnitsPerSecond: Optional[PositiveLongObject] - WriteUnitsPerSecond: Optional[PositiveLongObject] - Status: Optional[TableStatus] + ReadUnitsPerSecond: PositiveLongObject | None + WriteUnitsPerSecond: PositiveLongObject | None + Status: TableStatus | None class ReplicaDescription(TypedDict, total=False): - RegionName: Optional[RegionName] - ReplicaStatus: Optional[ReplicaStatus] - ReplicaStatusDescription: Optional[ReplicaStatusDescription] - ReplicaStatusPercentProgress: Optional[ReplicaStatusPercentProgress] - KMSMasterKeyId: Optional[KMSMasterKeyId] - ProvisionedThroughputOverride: Optional[ProvisionedThroughputOverride] - OnDemandThroughputOverride: Optional[OnDemandThroughputOverride] - WarmThroughput: Optional[TableWarmThroughputDescription] - GlobalSecondaryIndexes: Optional[ReplicaGlobalSecondaryIndexDescriptionList] - ReplicaInaccessibleDateTime: Optional[Date] - ReplicaTableClassSummary: Optional[TableClassSummary] + RegionName: RegionName | None + ReplicaStatus: ReplicaStatus | None + ReplicaStatusDescription: ReplicaStatusDescription | None + ReplicaStatusPercentProgress: ReplicaStatusPercentProgress | None + KMSMasterKeyId: KMSMasterKeyId | None + ProvisionedThroughputOverride: ProvisionedThroughputOverride | None + OnDemandThroughputOverride: OnDemandThroughputOverride | None + WarmThroughput: TableWarmThroughputDescription | None + GlobalSecondaryIndexes: ReplicaGlobalSecondaryIndexDescriptionList | None + ReplicaInaccessibleDateTime: Date | None + ReplicaTableClassSummary: TableClassSummary | None + GlobalTableSettingsReplicationMode: GlobalTableSettingsReplicationMode | None -ReplicaDescriptionList = List[ReplicaDescription] +ReplicaDescriptionList = list[ReplicaDescription] class GlobalTableDescription(TypedDict, total=False): - ReplicationGroup: Optional[ReplicaDescriptionList] - GlobalTableArn: Optional[GlobalTableArnString] - CreationDateTime: Optional[Date] - GlobalTableStatus: Optional[GlobalTableStatus] - GlobalTableName: Optional[TableName] + ReplicationGroup: ReplicaDescriptionList | None + GlobalTableArn: GlobalTableArnString | None + CreationDateTime: Date | None + GlobalTableStatus: GlobalTableStatus | None + GlobalTableName: TableName | None class CreateGlobalTableOutput(TypedDict, total=False): - GlobalTableDescription: Optional[GlobalTableDescription] + GlobalTableDescription: GlobalTableDescription | None class CreateGlobalTableWitnessGroupMemberAction(TypedDict, total=False): @@ -1121,20 +1128,20 @@ class CreateReplicaAction(TypedDict, total=False): class ReplicaGlobalSecondaryIndex(TypedDict, total=False): IndexName: IndexName - ProvisionedThroughputOverride: Optional[ProvisionedThroughputOverride] - OnDemandThroughputOverride: Optional[OnDemandThroughputOverride] + ProvisionedThroughputOverride: ProvisionedThroughputOverride | None + OnDemandThroughputOverride: OnDemandThroughputOverride | None -ReplicaGlobalSecondaryIndexList = List[ReplicaGlobalSecondaryIndex] +ReplicaGlobalSecondaryIndexList = list[ReplicaGlobalSecondaryIndex] class CreateReplicationGroupMemberAction(TypedDict, total=False): RegionName: RegionName - KMSMasterKeyId: Optional[KMSMasterKeyId] - ProvisionedThroughputOverride: Optional[ProvisionedThroughputOverride] - OnDemandThroughputOverride: Optional[OnDemandThroughputOverride] - GlobalSecondaryIndexes: Optional[ReplicaGlobalSecondaryIndexList] - TableClassOverride: Optional[TableClass] + KMSMasterKeyId: KMSMasterKeyId | None + ProvisionedThroughputOverride: ProvisionedThroughputOverride | None + OnDemandThroughputOverride: OnDemandThroughputOverride | None + GlobalSecondaryIndexes: ReplicaGlobalSecondaryIndexList | None + TableClassOverride: TableClass | None class Tag(TypedDict, total=False): @@ -1142,25 +1149,25 @@ class Tag(TypedDict, total=False): Value: TagValueString -TagList = List[Tag] +TagList = list[Tag] class SSESpecification(TypedDict, total=False): - Enabled: Optional[SSEEnabled] - SSEType: Optional[SSEType] - KMSMasterKeyId: Optional[KMSMasterKeyId] + Enabled: SSEEnabled | None + SSEType: SSEType | None + KMSMasterKeyId: KMSMasterKeyId | None class GlobalSecondaryIndex(TypedDict, total=False): IndexName: IndexName KeySchema: KeySchema Projection: Projection - ProvisionedThroughput: Optional[ProvisionedThroughput] - OnDemandThroughput: Optional[OnDemandThroughput] - WarmThroughput: Optional[WarmThroughput] + ProvisionedThroughput: ProvisionedThroughput | None + OnDemandThroughput: OnDemandThroughput | None + WarmThroughput: WarmThroughput | None -GlobalSecondaryIndexList = List[GlobalSecondaryIndex] +GlobalSecondaryIndexList = list[GlobalSecondaryIndex] class LocalSecondaryIndex(TypedDict, total=False): @@ -1169,129 +1176,132 @@ class LocalSecondaryIndex(TypedDict, total=False): Projection: Projection -LocalSecondaryIndexList = List[LocalSecondaryIndex] +LocalSecondaryIndexList = list[LocalSecondaryIndex] class CreateTableInput(ServiceRequest): - AttributeDefinitions: AttributeDefinitions + AttributeDefinitions: AttributeDefinitions | None TableName: TableArn - KeySchema: KeySchema - LocalSecondaryIndexes: Optional[LocalSecondaryIndexList] - GlobalSecondaryIndexes: Optional[GlobalSecondaryIndexList] - BillingMode: Optional[BillingMode] - ProvisionedThroughput: Optional[ProvisionedThroughput] - StreamSpecification: Optional[StreamSpecification] - SSESpecification: Optional[SSESpecification] - Tags: Optional[TagList] - TableClass: Optional[TableClass] - DeletionProtectionEnabled: Optional[DeletionProtectionEnabled] - WarmThroughput: Optional[WarmThroughput] - ResourcePolicy: Optional[ResourcePolicy] - OnDemandThroughput: Optional[OnDemandThroughput] + KeySchema: KeySchema | None + LocalSecondaryIndexes: LocalSecondaryIndexList | None + GlobalSecondaryIndexes: GlobalSecondaryIndexList | None + BillingMode: BillingMode | None + ProvisionedThroughput: ProvisionedThroughput | None + StreamSpecification: StreamSpecification | None + SSESpecification: SSESpecification | None + Tags: TagList | None + TableClass: TableClass | None + DeletionProtectionEnabled: DeletionProtectionEnabled | None + WarmThroughput: WarmThroughput | None + ResourcePolicy: ResourcePolicy | None + OnDemandThroughput: OnDemandThroughput | None + GlobalTableSourceArn: TableArn | None + GlobalTableSettingsReplicationMode: GlobalTableSettingsReplicationMode | None class RestoreSummary(TypedDict, total=False): - SourceBackupArn: Optional[BackupArn] - SourceTableArn: Optional[TableArn] + SourceBackupArn: BackupArn | None + SourceTableArn: TableArn | None RestoreDateTime: Date RestoreInProgress: RestoreInProgress class GlobalTableWitnessDescription(TypedDict, total=False): - RegionName: Optional[RegionName] - WitnessStatus: Optional[WitnessStatus] + RegionName: RegionName | None + WitnessStatus: WitnessStatus | None -GlobalTableWitnessDescriptionList = List[GlobalTableWitnessDescription] +GlobalTableWitnessDescriptionList = list[GlobalTableWitnessDescription] NonNegativeLongObject = int class ProvisionedThroughputDescription(TypedDict, total=False): - LastIncreaseDateTime: Optional[Date] - LastDecreaseDateTime: Optional[Date] - NumberOfDecreasesToday: Optional[PositiveLongObject] - ReadCapacityUnits: Optional[NonNegativeLongObject] - WriteCapacityUnits: Optional[NonNegativeLongObject] + LastIncreaseDateTime: Date | None + LastDecreaseDateTime: Date | None + NumberOfDecreasesToday: PositiveLongObject | None + ReadCapacityUnits: NonNegativeLongObject | None + WriteCapacityUnits: NonNegativeLongObject | None class GlobalSecondaryIndexDescription(TypedDict, total=False): - IndexName: Optional[IndexName] - KeySchema: Optional[KeySchema] - Projection: Optional[Projection] - IndexStatus: Optional[IndexStatus] - Backfilling: Optional[Backfilling] - ProvisionedThroughput: Optional[ProvisionedThroughputDescription] - IndexSizeBytes: Optional[LongObject] - ItemCount: Optional[LongObject] - IndexArn: Optional[String] - OnDemandThroughput: Optional[OnDemandThroughput] - WarmThroughput: Optional[GlobalSecondaryIndexWarmThroughputDescription] + IndexName: IndexName | None + KeySchema: KeySchema | None + Projection: Projection | None + IndexStatus: IndexStatus | None + Backfilling: Backfilling | None + ProvisionedThroughput: ProvisionedThroughputDescription | None + IndexSizeBytes: LongObject | None + ItemCount: LongObject | None + IndexArn: String | None + OnDemandThroughput: OnDemandThroughput | None + WarmThroughput: GlobalSecondaryIndexWarmThroughputDescription | None -GlobalSecondaryIndexDescriptionList = List[GlobalSecondaryIndexDescription] +GlobalSecondaryIndexDescriptionList = list[GlobalSecondaryIndexDescription] class LocalSecondaryIndexDescription(TypedDict, total=False): - IndexName: Optional[IndexName] - KeySchema: Optional[KeySchema] - Projection: Optional[Projection] - IndexSizeBytes: Optional[LongObject] - ItemCount: Optional[LongObject] - IndexArn: Optional[String] + IndexName: IndexName | None + KeySchema: KeySchema | None + Projection: Projection | None + IndexSizeBytes: LongObject | None + ItemCount: LongObject | None + IndexArn: String | None -LocalSecondaryIndexDescriptionList = List[LocalSecondaryIndexDescription] +LocalSecondaryIndexDescriptionList = list[LocalSecondaryIndexDescription] class TableDescription(TypedDict, total=False): - AttributeDefinitions: Optional[AttributeDefinitions] - TableName: Optional[TableName] - KeySchema: Optional[KeySchema] - TableStatus: Optional[TableStatus] - CreationDateTime: Optional[Date] - ProvisionedThroughput: Optional[ProvisionedThroughputDescription] - TableSizeBytes: Optional[LongObject] - ItemCount: Optional[LongObject] - TableArn: Optional[String] - TableId: Optional[TableId] - BillingModeSummary: Optional[BillingModeSummary] - LocalSecondaryIndexes: Optional[LocalSecondaryIndexDescriptionList] - GlobalSecondaryIndexes: Optional[GlobalSecondaryIndexDescriptionList] - StreamSpecification: Optional[StreamSpecification] - LatestStreamLabel: Optional[String] - LatestStreamArn: Optional[StreamArn] - GlobalTableVersion: Optional[String] - Replicas: Optional[ReplicaDescriptionList] - GlobalTableWitnesses: Optional[GlobalTableWitnessDescriptionList] - RestoreSummary: Optional[RestoreSummary] - SSEDescription: Optional[SSEDescription] - ArchivalSummary: Optional[ArchivalSummary] - TableClassSummary: Optional[TableClassSummary] - DeletionProtectionEnabled: Optional[DeletionProtectionEnabled] - OnDemandThroughput: Optional[OnDemandThroughput] - WarmThroughput: Optional[TableWarmThroughputDescription] - MultiRegionConsistency: Optional[MultiRegionConsistency] + AttributeDefinitions: AttributeDefinitions | None + TableName: TableName | None + KeySchema: KeySchema | None + TableStatus: TableStatus | None + CreationDateTime: Date | None + ProvisionedThroughput: ProvisionedThroughputDescription | None + TableSizeBytes: LongObject | None + ItemCount: LongObject | None + TableArn: String | None + TableId: TableId | None + BillingModeSummary: BillingModeSummary | None + LocalSecondaryIndexes: LocalSecondaryIndexDescriptionList | None + GlobalSecondaryIndexes: GlobalSecondaryIndexDescriptionList | None + StreamSpecification: StreamSpecification | None + LatestStreamLabel: String | None + LatestStreamArn: StreamArn | None + GlobalTableVersion: String | None + Replicas: ReplicaDescriptionList | None + GlobalTableWitnesses: GlobalTableWitnessDescriptionList | None + GlobalTableSettingsReplicationMode: GlobalTableSettingsReplicationMode | None + RestoreSummary: RestoreSummary | None + SSEDescription: SSEDescription | None + ArchivalSummary: ArchivalSummary | None + TableClassSummary: TableClassSummary | None + DeletionProtectionEnabled: DeletionProtectionEnabled | None + OnDemandThroughput: OnDemandThroughput | None + WarmThroughput: TableWarmThroughputDescription | None + MultiRegionConsistency: MultiRegionConsistency | None class CreateTableOutput(TypedDict, total=False): - TableDescription: Optional[TableDescription] + TableDescription: TableDescription | None -CsvHeaderList = List[CsvHeader] +CsvHeaderList = list[CsvHeader] class CsvOptions(TypedDict, total=False): - Delimiter: Optional[CsvDelimiter] - HeaderList: Optional[CsvHeaderList] + Delimiter: CsvDelimiter | None + HeaderList: CsvHeaderList | None class Delete(TypedDict, total=False): Key: Key TableName: TableArn - ConditionExpression: Optional[ConditionExpression] - ExpressionAttributeNames: Optional[ExpressionAttributeNameMap] - ExpressionAttributeValues: Optional[ExpressionAttributeValueMap] - ReturnValuesOnConditionCheckFailure: Optional[ReturnValuesOnConditionCheckFailure] + ConditionExpression: ConditionExpression | None + ExpressionAttributeNames: ExpressionAttributeNameMap | None + ExpressionAttributeValues: ExpressionAttributeValueMap | None + ReturnValuesOnConditionCheckFailure: ReturnValuesOnConditionCheckFailure | None class DeleteBackupInput(ServiceRequest): @@ -1299,7 +1309,7 @@ class DeleteBackupInput(ServiceRequest): class DeleteBackupOutput(TypedDict, total=False): - BackupDescription: Optional[BackupDescription] + BackupDescription: BackupDescription | None class DeleteGlobalSecondaryIndexAction(TypedDict, total=False): @@ -1311,33 +1321,33 @@ class DeleteGlobalTableWitnessGroupMemberAction(TypedDict, total=False): class ExpectedAttributeValue(TypedDict, total=False): - Value: Optional[AttributeValue] - Exists: Optional[BooleanObject] - ComparisonOperator: Optional[ComparisonOperator] - AttributeValueList: Optional[AttributeValueList] + Value: AttributeValue | None + Exists: BooleanObject | None + ComparisonOperator: ComparisonOperator | None + AttributeValueList: AttributeValueList | None -ExpectedAttributeMap = Dict[AttributeName, ExpectedAttributeValue] +ExpectedAttributeMap = dict[AttributeName, ExpectedAttributeValue] class DeleteItemInput(ServiceRequest): TableName: TableArn Key: Key - Expected: Optional[ExpectedAttributeMap] - ConditionalOperator: Optional[ConditionalOperator] - ReturnValues: Optional[ReturnValue] - ReturnConsumedCapacity: Optional[ReturnConsumedCapacity] - ReturnItemCollectionMetrics: Optional[ReturnItemCollectionMetrics] - ConditionExpression: Optional[ConditionExpression] - ExpressionAttributeNames: Optional[ExpressionAttributeNameMap] - ExpressionAttributeValues: Optional[ExpressionAttributeValueMap] - ReturnValuesOnConditionCheckFailure: Optional[ReturnValuesOnConditionCheckFailure] + Expected: ExpectedAttributeMap | None + ConditionalOperator: ConditionalOperator | None + ReturnValues: ReturnValue | None + ReturnConsumedCapacity: ReturnConsumedCapacity | None + ReturnItemCollectionMetrics: ReturnItemCollectionMetrics | None + ConditionExpression: ConditionExpression | None + ExpressionAttributeNames: ExpressionAttributeNameMap | None + ExpressionAttributeValues: ExpressionAttributeValueMap | None + ReturnValuesOnConditionCheckFailure: ReturnValuesOnConditionCheckFailure | None class DeleteItemOutput(TypedDict, total=False): - Attributes: Optional[AttributeMap] - ConsumedCapacity: Optional[ConsumedCapacity] - ItemCollectionMetrics: Optional[ItemCollectionMetrics] + Attributes: AttributeMap | None + ConsumedCapacity: ConsumedCapacity | None + ItemCollectionMetrics: ItemCollectionMetrics | None class DeleteReplicaAction(TypedDict, total=False): @@ -1350,11 +1360,11 @@ class DeleteReplicationGroupMemberAction(TypedDict, total=False): class DeleteResourcePolicyInput(ServiceRequest): ResourceArn: ResourceArnString - ExpectedRevisionId: Optional[PolicyRevisionId] + ExpectedRevisionId: PolicyRevisionId | None class DeleteResourcePolicyOutput(TypedDict, total=False): - RevisionId: Optional[PolicyRevisionId] + RevisionId: PolicyRevisionId | None class DeleteTableInput(ServiceRequest): @@ -1362,7 +1372,7 @@ class DeleteTableInput(ServiceRequest): class DeleteTableOutput(TypedDict, total=False): - TableDescription: Optional[TableDescription] + TableDescription: TableDescription | None class DescribeBackupInput(ServiceRequest): @@ -1370,7 +1380,7 @@ class DescribeBackupInput(ServiceRequest): class DescribeBackupOutput(TypedDict, total=False): - BackupDescription: Optional[BackupDescription] + BackupDescription: BackupDescription | None class DescribeContinuousBackupsInput(ServiceRequest): @@ -1378,30 +1388,30 @@ class DescribeContinuousBackupsInput(ServiceRequest): class DescribeContinuousBackupsOutput(TypedDict, total=False): - ContinuousBackupsDescription: Optional[ContinuousBackupsDescription] + ContinuousBackupsDescription: ContinuousBackupsDescription | None class DescribeContributorInsightsInput(ServiceRequest): TableName: TableArn - IndexName: Optional[IndexName] + IndexName: IndexName | None class FailureException(TypedDict, total=False): - ExceptionName: Optional[ExceptionName] - ExceptionDescription: Optional[ExceptionDescription] + ExceptionName: ExceptionName | None + ExceptionDescription: ExceptionDescription | None LastUpdateDateTime = datetime class DescribeContributorInsightsOutput(TypedDict, total=False): - TableName: Optional[TableName] - IndexName: Optional[IndexName] - ContributorInsightsRuleList: Optional[ContributorInsightsRuleList] - ContributorInsightsStatus: Optional[ContributorInsightsStatus] - LastUpdateDateTime: Optional[LastUpdateDateTime] - FailureException: Optional[FailureException] - ContributorInsightsMode: Optional[ContributorInsightsMode] + TableName: TableName | None + IndexName: IndexName | None + ContributorInsightsRuleList: ContributorInsightsRuleList | None + ContributorInsightsStatus: ContributorInsightsStatus | None + LastUpdateDateTime: LastUpdateDateTime | None + FailureException: FailureException | None + ContributorInsightsMode: ContributorInsightsMode | None class DescribeEndpointsRequest(ServiceRequest): @@ -1416,7 +1426,7 @@ class Endpoint(TypedDict, total=False): CachePeriodInMinutes: Long -Endpoints = List[Endpoint] +Endpoints = list[Endpoint] class DescribeEndpointsResponse(TypedDict, total=False): @@ -1432,9 +1442,9 @@ class DescribeExportInput(ServiceRequest): class IncrementalExportSpecification(TypedDict, total=False): - ExportFromTime: Optional[ExportFromTime] - ExportToTime: Optional[ExportToTime] - ExportViewType: Optional[ExportViewType] + ExportFromTime: ExportFromTime | None + ExportToTime: ExportToTime | None + ExportViewType: ExportViewType | None ExportTime = datetime @@ -1443,31 +1453,31 @@ class IncrementalExportSpecification(TypedDict, total=False): class ExportDescription(TypedDict, total=False): - ExportArn: Optional[ExportArn] - ExportStatus: Optional[ExportStatus] - StartTime: Optional[ExportStartTime] - EndTime: Optional[ExportEndTime] - ExportManifest: Optional[ExportManifest] - TableArn: Optional[TableArn] - TableId: Optional[TableId] - ExportTime: Optional[ExportTime] - ClientToken: Optional[ClientToken] - S3Bucket: Optional[S3Bucket] - S3BucketOwner: Optional[S3BucketOwner] - S3Prefix: Optional[S3Prefix] - S3SseAlgorithm: Optional[S3SseAlgorithm] - S3SseKmsKeyId: Optional[S3SseKmsKeyId] - FailureCode: Optional[FailureCode] - FailureMessage: Optional[FailureMessage] - ExportFormat: Optional[ExportFormat] - BilledSizeBytes: Optional[BilledSizeBytes] - ItemCount: Optional[ItemCount] - ExportType: Optional[ExportType] - IncrementalExportSpecification: Optional[IncrementalExportSpecification] + ExportArn: ExportArn | None + ExportStatus: ExportStatus | None + StartTime: ExportStartTime | None + EndTime: ExportEndTime | None + ExportManifest: ExportManifest | None + TableArn: TableArn | None + TableId: TableId | None + ExportTime: ExportTime | None + ClientToken: ClientToken | None + S3Bucket: S3Bucket | None + S3BucketOwner: S3BucketOwner | None + S3Prefix: S3Prefix | None + S3SseAlgorithm: S3SseAlgorithm | None + S3SseKmsKeyId: S3SseKmsKeyId | None + FailureCode: FailureCode | None + FailureMessage: FailureMessage | None + ExportFormat: ExportFormat | None + BilledSizeBytes: BilledSizeBytes | None + ItemCount: ItemCount | None + ExportType: ExportType | None + IncrementalExportSpecification: IncrementalExportSpecification | None class DescribeExportOutput(TypedDict, total=False): - ExportDescription: Optional[ExportDescription] + ExportDescription: ExportDescription | None class DescribeGlobalTableInput(ServiceRequest): @@ -1475,7 +1485,7 @@ class DescribeGlobalTableInput(ServiceRequest): class DescribeGlobalTableOutput(TypedDict, total=False): - GlobalTableDescription: Optional[GlobalTableDescription] + GlobalTableDescription: GlobalTableDescription | None class DescribeGlobalTableSettingsInput(ServiceRequest): @@ -1484,38 +1494,36 @@ class DescribeGlobalTableSettingsInput(ServiceRequest): class ReplicaGlobalSecondaryIndexSettingsDescription(TypedDict, total=False): IndexName: IndexName - IndexStatus: Optional[IndexStatus] - ProvisionedReadCapacityUnits: Optional[PositiveLongObject] - ProvisionedReadCapacityAutoScalingSettings: Optional[AutoScalingSettingsDescription] - ProvisionedWriteCapacityUnits: Optional[PositiveLongObject] - ProvisionedWriteCapacityAutoScalingSettings: Optional[AutoScalingSettingsDescription] + IndexStatus: IndexStatus | None + ProvisionedReadCapacityUnits: PositiveLongObject | None + ProvisionedReadCapacityAutoScalingSettings: AutoScalingSettingsDescription | None + ProvisionedWriteCapacityUnits: PositiveLongObject | None + ProvisionedWriteCapacityAutoScalingSettings: AutoScalingSettingsDescription | None -ReplicaGlobalSecondaryIndexSettingsDescriptionList = List[ +ReplicaGlobalSecondaryIndexSettingsDescriptionList = list[ ReplicaGlobalSecondaryIndexSettingsDescription ] class ReplicaSettingsDescription(TypedDict, total=False): RegionName: RegionName - ReplicaStatus: Optional[ReplicaStatus] - ReplicaBillingModeSummary: Optional[BillingModeSummary] - ReplicaProvisionedReadCapacityUnits: Optional[NonNegativeLongObject] - ReplicaProvisionedReadCapacityAutoScalingSettings: Optional[AutoScalingSettingsDescription] - ReplicaProvisionedWriteCapacityUnits: Optional[NonNegativeLongObject] - ReplicaProvisionedWriteCapacityAutoScalingSettings: Optional[AutoScalingSettingsDescription] - ReplicaGlobalSecondaryIndexSettings: Optional[ - ReplicaGlobalSecondaryIndexSettingsDescriptionList - ] - ReplicaTableClassSummary: Optional[TableClassSummary] + ReplicaStatus: ReplicaStatus | None + ReplicaBillingModeSummary: BillingModeSummary | None + ReplicaProvisionedReadCapacityUnits: NonNegativeLongObject | None + ReplicaProvisionedReadCapacityAutoScalingSettings: AutoScalingSettingsDescription | None + ReplicaProvisionedWriteCapacityUnits: NonNegativeLongObject | None + ReplicaProvisionedWriteCapacityAutoScalingSettings: AutoScalingSettingsDescription | None + ReplicaGlobalSecondaryIndexSettings: ReplicaGlobalSecondaryIndexSettingsDescriptionList | None + ReplicaTableClassSummary: TableClassSummary | None -ReplicaSettingsDescriptionList = List[ReplicaSettingsDescription] +ReplicaSettingsDescriptionList = list[ReplicaSettingsDescription] class DescribeGlobalTableSettingsOutput(TypedDict, total=False): - GlobalTableName: Optional[TableName] - ReplicaSettings: Optional[ReplicaSettingsDescriptionList] + GlobalTableName: TableName | None + ReplicaSettings: ReplicaSettingsDescriptionList | None class DescribeImportInput(ServiceRequest): @@ -1532,46 +1540,46 @@ class TableCreationParameters(TypedDict, total=False): TableName: TableName AttributeDefinitions: AttributeDefinitions KeySchema: KeySchema - BillingMode: Optional[BillingMode] - ProvisionedThroughput: Optional[ProvisionedThroughput] - OnDemandThroughput: Optional[OnDemandThroughput] - SSESpecification: Optional[SSESpecification] - GlobalSecondaryIndexes: Optional[GlobalSecondaryIndexList] + BillingMode: BillingMode | None + ProvisionedThroughput: ProvisionedThroughput | None + OnDemandThroughput: OnDemandThroughput | None + SSESpecification: SSESpecification | None + GlobalSecondaryIndexes: GlobalSecondaryIndexList | None class InputFormatOptions(TypedDict, total=False): - Csv: Optional[CsvOptions] + Csv: CsvOptions | None ErrorCount = int class S3BucketSource(TypedDict, total=False): - S3BucketOwner: Optional[S3BucketOwner] + S3BucketOwner: S3BucketOwner | None S3Bucket: S3Bucket - S3KeyPrefix: Optional[S3Prefix] + S3KeyPrefix: S3Prefix | None class ImportTableDescription(TypedDict, total=False): - ImportArn: Optional[ImportArn] - ImportStatus: Optional[ImportStatus] - TableArn: Optional[TableArn] - TableId: Optional[TableId] - ClientToken: Optional[ClientToken] - S3BucketSource: Optional[S3BucketSource] - ErrorCount: Optional[ErrorCount] - CloudWatchLogGroupArn: Optional[CloudWatchLogGroupArn] - InputFormat: Optional[InputFormat] - InputFormatOptions: Optional[InputFormatOptions] - InputCompressionType: Optional[InputCompressionType] - TableCreationParameters: Optional[TableCreationParameters] - StartTime: Optional[ImportStartTime] - EndTime: Optional[ImportEndTime] - ProcessedSizeBytes: Optional[LongObject] - ProcessedItemCount: Optional[ProcessedItemCount] - ImportedItemCount: Optional[ImportedItemCount] - FailureCode: Optional[FailureCode] - FailureMessage: Optional[FailureMessage] + ImportArn: ImportArn | None + ImportStatus: ImportStatus | None + TableArn: TableArn | None + TableId: TableId | None + ClientToken: ClientToken | None + S3BucketSource: S3BucketSource | None + ErrorCount: ErrorCount | None + CloudWatchLogGroupArn: CloudWatchLogGroupArn | None + InputFormat: InputFormat | None + InputFormatOptions: InputFormatOptions | None + InputCompressionType: InputCompressionType | None + TableCreationParameters: TableCreationParameters | None + StartTime: ImportStartTime | None + EndTime: ImportEndTime | None + ProcessedSizeBytes: LongObject | None + ProcessedItemCount: ProcessedItemCount | None + ImportedItemCount: ImportedItemCount | None + FailureCode: FailureCode | None + FailureMessage: FailureMessage | None class DescribeImportOutput(TypedDict, total=False): @@ -1583,18 +1591,18 @@ class DescribeKinesisStreamingDestinationInput(ServiceRequest): class KinesisDataStreamDestination(TypedDict, total=False): - StreamArn: Optional[StreamArn] - DestinationStatus: Optional[DestinationStatus] - DestinationStatusDescription: Optional[String] - ApproximateCreationDateTimePrecision: Optional[ApproximateCreationDateTimePrecision] + StreamArn: StreamArn | None + DestinationStatus: DestinationStatus | None + DestinationStatusDescription: String | None + ApproximateCreationDateTimePrecision: ApproximateCreationDateTimePrecision | None -KinesisDataStreamDestinations = List[KinesisDataStreamDestination] +KinesisDataStreamDestinations = list[KinesisDataStreamDestination] class DescribeKinesisStreamingDestinationOutput(TypedDict, total=False): - TableName: Optional[TableName] - KinesisDataStreamDestinations: Optional[KinesisDataStreamDestinations] + TableName: TableName | None + KinesisDataStreamDestinations: KinesisDataStreamDestinations | None class DescribeLimitsInput(ServiceRequest): @@ -1602,10 +1610,10 @@ class DescribeLimitsInput(ServiceRequest): class DescribeLimitsOutput(TypedDict, total=False): - AccountMaxReadCapacityUnits: Optional[PositiveLongObject] - AccountMaxWriteCapacityUnits: Optional[PositiveLongObject] - TableMaxReadCapacityUnits: Optional[PositiveLongObject] - TableMaxWriteCapacityUnits: Optional[PositiveLongObject] + AccountMaxReadCapacityUnits: PositiveLongObject | None + AccountMaxWriteCapacityUnits: PositiveLongObject | None + TableMaxReadCapacityUnits: PositiveLongObject | None + TableMaxWriteCapacityUnits: PositiveLongObject | None class DescribeTableInput(ServiceRequest): @@ -1613,7 +1621,7 @@ class DescribeTableInput(ServiceRequest): class DescribeTableOutput(TypedDict, total=False): - Table: Optional[TableDescription] + Table: TableDescription | None class DescribeTableReplicaAutoScalingInput(ServiceRequest): @@ -1621,36 +1629,36 @@ class DescribeTableReplicaAutoScalingInput(ServiceRequest): class ReplicaGlobalSecondaryIndexAutoScalingDescription(TypedDict, total=False): - IndexName: Optional[IndexName] - IndexStatus: Optional[IndexStatus] - ProvisionedReadCapacityAutoScalingSettings: Optional[AutoScalingSettingsDescription] - ProvisionedWriteCapacityAutoScalingSettings: Optional[AutoScalingSettingsDescription] + IndexName: IndexName | None + IndexStatus: IndexStatus | None + ProvisionedReadCapacityAutoScalingSettings: AutoScalingSettingsDescription | None + ProvisionedWriteCapacityAutoScalingSettings: AutoScalingSettingsDescription | None -ReplicaGlobalSecondaryIndexAutoScalingDescriptionList = List[ +ReplicaGlobalSecondaryIndexAutoScalingDescriptionList = list[ ReplicaGlobalSecondaryIndexAutoScalingDescription ] class ReplicaAutoScalingDescription(TypedDict, total=False): - RegionName: Optional[RegionName] - GlobalSecondaryIndexes: Optional[ReplicaGlobalSecondaryIndexAutoScalingDescriptionList] - ReplicaProvisionedReadCapacityAutoScalingSettings: Optional[AutoScalingSettingsDescription] - ReplicaProvisionedWriteCapacityAutoScalingSettings: Optional[AutoScalingSettingsDescription] - ReplicaStatus: Optional[ReplicaStatus] + RegionName: RegionName | None + GlobalSecondaryIndexes: ReplicaGlobalSecondaryIndexAutoScalingDescriptionList | None + ReplicaProvisionedReadCapacityAutoScalingSettings: AutoScalingSettingsDescription | None + ReplicaProvisionedWriteCapacityAutoScalingSettings: AutoScalingSettingsDescription | None + ReplicaStatus: ReplicaStatus | None -ReplicaAutoScalingDescriptionList = List[ReplicaAutoScalingDescription] +ReplicaAutoScalingDescriptionList = list[ReplicaAutoScalingDescription] class TableAutoScalingDescription(TypedDict, total=False): - TableName: Optional[TableName] - TableStatus: Optional[TableStatus] - Replicas: Optional[ReplicaAutoScalingDescriptionList] + TableName: TableName | None + TableStatus: TableStatus | None + Replicas: ReplicaAutoScalingDescriptionList | None class DescribeTableReplicaAutoScalingOutput(TypedDict, total=False): - TableAutoScalingDescription: Optional[TableAutoScalingDescription] + TableAutoScalingDescription: TableAutoScalingDescription | None class DescribeTimeToLiveInput(ServiceRequest): @@ -1658,107 +1666,107 @@ class DescribeTimeToLiveInput(ServiceRequest): class DescribeTimeToLiveOutput(TypedDict, total=False): - TimeToLiveDescription: Optional[TimeToLiveDescription] + TimeToLiveDescription: TimeToLiveDescription | None class EnableKinesisStreamingConfiguration(TypedDict, total=False): - ApproximateCreationDateTimePrecision: Optional[ApproximateCreationDateTimePrecision] + ApproximateCreationDateTimePrecision: ApproximateCreationDateTimePrecision | None class ExecuteStatementInput(ServiceRequest): Statement: PartiQLStatement - Parameters: Optional[PreparedStatementParameters] - ConsistentRead: Optional[ConsistentRead] - NextToken: Optional[PartiQLNextToken] - ReturnConsumedCapacity: Optional[ReturnConsumedCapacity] - Limit: Optional[PositiveIntegerObject] - ReturnValuesOnConditionCheckFailure: Optional[ReturnValuesOnConditionCheckFailure] + Parameters: PreparedStatementParameters | None + ConsistentRead: ConsistentRead | None + NextToken: PartiQLNextToken | None + ReturnConsumedCapacity: ReturnConsumedCapacity | None + Limit: PositiveIntegerObject | None + ReturnValuesOnConditionCheckFailure: ReturnValuesOnConditionCheckFailure | None class ExecuteStatementOutput(TypedDict, total=False): - Items: Optional[ItemList] - NextToken: Optional[PartiQLNextToken] - ConsumedCapacity: Optional[ConsumedCapacity] - LastEvaluatedKey: Optional[Key] + Items: ItemList | None + NextToken: PartiQLNextToken | None + ConsumedCapacity: ConsumedCapacity | None + LastEvaluatedKey: Key | None class ParameterizedStatement(TypedDict, total=False): Statement: PartiQLStatement - Parameters: Optional[PreparedStatementParameters] - ReturnValuesOnConditionCheckFailure: Optional[ReturnValuesOnConditionCheckFailure] + Parameters: PreparedStatementParameters | None + ReturnValuesOnConditionCheckFailure: ReturnValuesOnConditionCheckFailure | None -ParameterizedStatements = List[ParameterizedStatement] +ParameterizedStatements = list[ParameterizedStatement] class ExecuteTransactionInput(ServiceRequest): TransactStatements: ParameterizedStatements - ClientRequestToken: Optional[ClientRequestToken] - ReturnConsumedCapacity: Optional[ReturnConsumedCapacity] + ClientRequestToken: ClientRequestToken | None + ReturnConsumedCapacity: ReturnConsumedCapacity | None class ItemResponse(TypedDict, total=False): - Item: Optional[AttributeMap] + Item: AttributeMap | None -ItemResponseList = List[ItemResponse] +ItemResponseList = list[ItemResponse] class ExecuteTransactionOutput(TypedDict, total=False): - Responses: Optional[ItemResponseList] - ConsumedCapacity: Optional[ConsumedCapacityMultiple] + Responses: ItemResponseList | None + ConsumedCapacity: ConsumedCapacityMultiple | None class ExportSummary(TypedDict, total=False): - ExportArn: Optional[ExportArn] - ExportStatus: Optional[ExportStatus] - ExportType: Optional[ExportType] + ExportArn: ExportArn | None + ExportStatus: ExportStatus | None + ExportType: ExportType | None -ExportSummaries = List[ExportSummary] +ExportSummaries = list[ExportSummary] class ExportTableToPointInTimeInput(ServiceRequest): TableArn: TableArn - ExportTime: Optional[ExportTime] - ClientToken: Optional[ClientToken] + ExportTime: ExportTime | None + ClientToken: ClientToken | None S3Bucket: S3Bucket - S3BucketOwner: Optional[S3BucketOwner] - S3Prefix: Optional[S3Prefix] - S3SseAlgorithm: Optional[S3SseAlgorithm] - S3SseKmsKeyId: Optional[S3SseKmsKeyId] - ExportFormat: Optional[ExportFormat] - ExportType: Optional[ExportType] - IncrementalExportSpecification: Optional[IncrementalExportSpecification] + S3BucketOwner: S3BucketOwner | None + S3Prefix: S3Prefix | None + S3SseAlgorithm: S3SseAlgorithm | None + S3SseKmsKeyId: S3SseKmsKeyId | None + ExportFormat: ExportFormat | None + ExportType: ExportType | None + IncrementalExportSpecification: IncrementalExportSpecification | None class ExportTableToPointInTimeOutput(TypedDict, total=False): - ExportDescription: Optional[ExportDescription] + ExportDescription: ExportDescription | None -FilterConditionMap = Dict[AttributeName, Condition] +FilterConditionMap = dict[AttributeName, Condition] class Get(TypedDict, total=False): Key: Key TableName: TableArn - ProjectionExpression: Optional[ProjectionExpression] - ExpressionAttributeNames: Optional[ExpressionAttributeNameMap] + ProjectionExpression: ProjectionExpression | None + ExpressionAttributeNames: ExpressionAttributeNameMap | None class GetItemInput(ServiceRequest): TableName: TableArn Key: Key - AttributesToGet: Optional[AttributeNameList] - ConsistentRead: Optional[ConsistentRead] - ReturnConsumedCapacity: Optional[ReturnConsumedCapacity] - ProjectionExpression: Optional[ProjectionExpression] - ExpressionAttributeNames: Optional[ExpressionAttributeNameMap] + AttributesToGet: AttributeNameList | None + ConsistentRead: ConsistentRead | None + ReturnConsumedCapacity: ReturnConsumedCapacity | None + ProjectionExpression: ProjectionExpression | None + ExpressionAttributeNames: ExpressionAttributeNameMap | None class GetItemOutput(TypedDict, total=False): - Item: Optional[AttributeMap] - ConsumedCapacity: Optional[ConsumedCapacity] + Item: AttributeMap | None + ConsumedCapacity: ConsumedCapacity | None class GetResourcePolicyInput(ServiceRequest): @@ -1766,79 +1774,79 @@ class GetResourcePolicyInput(ServiceRequest): class GetResourcePolicyOutput(TypedDict, total=False): - Policy: Optional[ResourcePolicy] - RevisionId: Optional[PolicyRevisionId] + Policy: ResourcePolicy | None + RevisionId: PolicyRevisionId | None class GlobalSecondaryIndexAutoScalingUpdate(TypedDict, total=False): - IndexName: Optional[IndexName] - ProvisionedWriteCapacityAutoScalingUpdate: Optional[AutoScalingSettingsUpdate] + IndexName: IndexName | None + ProvisionedWriteCapacityAutoScalingUpdate: AutoScalingSettingsUpdate | None -GlobalSecondaryIndexAutoScalingUpdateList = List[GlobalSecondaryIndexAutoScalingUpdate] +GlobalSecondaryIndexAutoScalingUpdateList = list[GlobalSecondaryIndexAutoScalingUpdate] class UpdateGlobalSecondaryIndexAction(TypedDict, total=False): IndexName: IndexName - ProvisionedThroughput: Optional[ProvisionedThroughput] - OnDemandThroughput: Optional[OnDemandThroughput] - WarmThroughput: Optional[WarmThroughput] + ProvisionedThroughput: ProvisionedThroughput | None + OnDemandThroughput: OnDemandThroughput | None + WarmThroughput: WarmThroughput | None class GlobalSecondaryIndexUpdate(TypedDict, total=False): - Update: Optional[UpdateGlobalSecondaryIndexAction] - Create: Optional[CreateGlobalSecondaryIndexAction] - Delete: Optional[DeleteGlobalSecondaryIndexAction] + Update: UpdateGlobalSecondaryIndexAction | None + Create: CreateGlobalSecondaryIndexAction | None + Delete: DeleteGlobalSecondaryIndexAction | None -GlobalSecondaryIndexUpdateList = List[GlobalSecondaryIndexUpdate] +GlobalSecondaryIndexUpdateList = list[GlobalSecondaryIndexUpdate] class GlobalTable(TypedDict, total=False): - GlobalTableName: Optional[TableName] - ReplicationGroup: Optional[ReplicaList] + GlobalTableName: TableName | None + ReplicationGroup: ReplicaList | None class GlobalTableGlobalSecondaryIndexSettingsUpdate(TypedDict, total=False): IndexName: IndexName - ProvisionedWriteCapacityUnits: Optional[PositiveLongObject] - ProvisionedWriteCapacityAutoScalingSettingsUpdate: Optional[AutoScalingSettingsUpdate] + ProvisionedWriteCapacityUnits: PositiveLongObject | None + ProvisionedWriteCapacityAutoScalingSettingsUpdate: AutoScalingSettingsUpdate | None -GlobalTableGlobalSecondaryIndexSettingsUpdateList = List[ +GlobalTableGlobalSecondaryIndexSettingsUpdateList = list[ GlobalTableGlobalSecondaryIndexSettingsUpdate ] -GlobalTableList = List[GlobalTable] +GlobalTableList = list[GlobalTable] class GlobalTableWitnessGroupUpdate(TypedDict, total=False): - Create: Optional[CreateGlobalTableWitnessGroupMemberAction] - Delete: Optional[DeleteGlobalTableWitnessGroupMemberAction] + Create: CreateGlobalTableWitnessGroupMemberAction | None + Delete: DeleteGlobalTableWitnessGroupMemberAction | None -GlobalTableWitnessGroupUpdateList = List[GlobalTableWitnessGroupUpdate] +GlobalTableWitnessGroupUpdateList = list[GlobalTableWitnessGroupUpdate] class ImportSummary(TypedDict, total=False): - ImportArn: Optional[ImportArn] - ImportStatus: Optional[ImportStatus] - TableArn: Optional[TableArn] - S3BucketSource: Optional[S3BucketSource] - CloudWatchLogGroupArn: Optional[CloudWatchLogGroupArn] - InputFormat: Optional[InputFormat] - StartTime: Optional[ImportStartTime] - EndTime: Optional[ImportEndTime] + ImportArn: ImportArn | None + ImportStatus: ImportStatus | None + TableArn: TableArn | None + S3BucketSource: S3BucketSource | None + CloudWatchLogGroupArn: CloudWatchLogGroupArn | None + InputFormat: InputFormat | None + StartTime: ImportStartTime | None + EndTime: ImportEndTime | None -ImportSummaryList = List[ImportSummary] +ImportSummaryList = list[ImportSummary] class ImportTableInput(ServiceRequest): - ClientToken: Optional[ClientToken] + ClientToken: ClientToken | None S3BucketSource: S3BucketSource InputFormat: InputFormat - InputFormatOptions: Optional[InputFormatOptions] - InputCompressionType: Optional[InputCompressionType] + InputFormatOptions: InputFormatOptions | None + InputCompressionType: InputCompressionType | None TableCreationParameters: TableCreationParameters @@ -1846,20 +1854,20 @@ class ImportTableOutput(TypedDict, total=False): ImportTableDescription: ImportTableDescription -KeyConditions = Dict[AttributeName, Condition] +KeyConditions = dict[AttributeName, Condition] class KinesisStreamingDestinationInput(ServiceRequest): TableName: TableArn StreamArn: StreamArn - EnableKinesisStreamingConfiguration: Optional[EnableKinesisStreamingConfiguration] + EnableKinesisStreamingConfiguration: EnableKinesisStreamingConfiguration | None class KinesisStreamingDestinationOutput(TypedDict, total=False): - TableName: Optional[TableName] - StreamArn: Optional[StreamArn] - DestinationStatus: Optional[DestinationStatus] - EnableKinesisStreamingConfiguration: Optional[EnableKinesisStreamingConfiguration] + TableName: TableName | None + StreamArn: StreamArn | None + DestinationStatus: DestinationStatus | None + EnableKinesisStreamingConfiguration: EnableKinesisStreamingConfiguration | None TimeRangeUpperBound = datetime @@ -1867,287 +1875,285 @@ class KinesisStreamingDestinationOutput(TypedDict, total=False): class ListBackupsInput(ServiceRequest): - TableName: Optional[TableArn] - Limit: Optional[BackupsInputLimit] - TimeRangeLowerBound: Optional[TimeRangeLowerBound] - TimeRangeUpperBound: Optional[TimeRangeUpperBound] - ExclusiveStartBackupArn: Optional[BackupArn] - BackupType: Optional[BackupTypeFilter] + TableName: TableArn | None + Limit: BackupsInputLimit | None + TimeRangeLowerBound: TimeRangeLowerBound | None + TimeRangeUpperBound: TimeRangeUpperBound | None + ExclusiveStartBackupArn: BackupArn | None + BackupType: BackupTypeFilter | None class ListBackupsOutput(TypedDict, total=False): - BackupSummaries: Optional[BackupSummaries] - LastEvaluatedBackupArn: Optional[BackupArn] + BackupSummaries: BackupSummaries | None + LastEvaluatedBackupArn: BackupArn | None class ListContributorInsightsInput(ServiceRequest): - TableName: Optional[TableArn] - NextToken: Optional[NextTokenString] - MaxResults: Optional[ListContributorInsightsLimit] + TableName: TableArn | None + NextToken: NextTokenString | None + MaxResults: ListContributorInsightsLimit | None class ListContributorInsightsOutput(TypedDict, total=False): - ContributorInsightsSummaries: Optional[ContributorInsightsSummaries] - NextToken: Optional[NextTokenString] + ContributorInsightsSummaries: ContributorInsightsSummaries | None + NextToken: NextTokenString | None class ListExportsInput(ServiceRequest): - TableArn: Optional[TableArn] - MaxResults: Optional[ListExportsMaxLimit] - NextToken: Optional[ExportNextToken] + TableArn: TableArn | None + MaxResults: ListExportsMaxLimit | None + NextToken: ExportNextToken | None class ListExportsOutput(TypedDict, total=False): - ExportSummaries: Optional[ExportSummaries] - NextToken: Optional[ExportNextToken] + ExportSummaries: ExportSummaries | None + NextToken: ExportNextToken | None class ListGlobalTablesInput(ServiceRequest): - ExclusiveStartGlobalTableName: Optional[TableName] - Limit: Optional[PositiveIntegerObject] - RegionName: Optional[RegionName] + ExclusiveStartGlobalTableName: TableName | None + Limit: PositiveIntegerObject | None + RegionName: RegionName | None class ListGlobalTablesOutput(TypedDict, total=False): - GlobalTables: Optional[GlobalTableList] - LastEvaluatedGlobalTableName: Optional[TableName] + GlobalTables: GlobalTableList | None + LastEvaluatedGlobalTableName: TableName | None class ListImportsInput(ServiceRequest): - TableArn: Optional[TableArn] - PageSize: Optional[ListImportsMaxLimit] - NextToken: Optional[ImportNextToken] + TableArn: TableArn | None + PageSize: ListImportsMaxLimit | None + NextToken: ImportNextToken | None class ListImportsOutput(TypedDict, total=False): - ImportSummaryList: Optional[ImportSummaryList] - NextToken: Optional[ImportNextToken] + ImportSummaryList: ImportSummaryList | None + NextToken: ImportNextToken | None class ListTablesInput(ServiceRequest): - ExclusiveStartTableName: Optional[TableName] - Limit: Optional[ListTablesInputLimit] + ExclusiveStartTableName: TableName | None + Limit: ListTablesInputLimit | None -TableNameList = List[TableName] +TableNameList = list[TableName] class ListTablesOutput(TypedDict, total=False): - TableNames: Optional[TableNameList] - LastEvaluatedTableName: Optional[TableName] + TableNames: TableNameList | None + LastEvaluatedTableName: TableName | None class ListTagsOfResourceInput(ServiceRequest): ResourceArn: ResourceArnString - NextToken: Optional[NextTokenString] + NextToken: NextTokenString | None class ListTagsOfResourceOutput(TypedDict, total=False): - Tags: Optional[TagList] - NextToken: Optional[NextTokenString] + Tags: TagList | None + NextToken: NextTokenString | None class PointInTimeRecoverySpecification(TypedDict, total=False): PointInTimeRecoveryEnabled: BooleanObject - RecoveryPeriodInDays: Optional[RecoveryPeriodInDays] + RecoveryPeriodInDays: RecoveryPeriodInDays | None class Put(TypedDict, total=False): Item: PutItemInputAttributeMap TableName: TableArn - ConditionExpression: Optional[ConditionExpression] - ExpressionAttributeNames: Optional[ExpressionAttributeNameMap] - ExpressionAttributeValues: Optional[ExpressionAttributeValueMap] - ReturnValuesOnConditionCheckFailure: Optional[ReturnValuesOnConditionCheckFailure] + ConditionExpression: ConditionExpression | None + ExpressionAttributeNames: ExpressionAttributeNameMap | None + ExpressionAttributeValues: ExpressionAttributeValueMap | None + ReturnValuesOnConditionCheckFailure: ReturnValuesOnConditionCheckFailure | None class PutItemInput(ServiceRequest): TableName: TableArn Item: PutItemInputAttributeMap - Expected: Optional[ExpectedAttributeMap] - ReturnValues: Optional[ReturnValue] - ReturnConsumedCapacity: Optional[ReturnConsumedCapacity] - ReturnItemCollectionMetrics: Optional[ReturnItemCollectionMetrics] - ConditionalOperator: Optional[ConditionalOperator] - ConditionExpression: Optional[ConditionExpression] - ExpressionAttributeNames: Optional[ExpressionAttributeNameMap] - ExpressionAttributeValues: Optional[ExpressionAttributeValueMap] - ReturnValuesOnConditionCheckFailure: Optional[ReturnValuesOnConditionCheckFailure] + Expected: ExpectedAttributeMap | None + ReturnValues: ReturnValue | None + ReturnConsumedCapacity: ReturnConsumedCapacity | None + ReturnItemCollectionMetrics: ReturnItemCollectionMetrics | None + ConditionalOperator: ConditionalOperator | None + ConditionExpression: ConditionExpression | None + ExpressionAttributeNames: ExpressionAttributeNameMap | None + ExpressionAttributeValues: ExpressionAttributeValueMap | None + ReturnValuesOnConditionCheckFailure: ReturnValuesOnConditionCheckFailure | None class PutItemOutput(TypedDict, total=False): - Attributes: Optional[AttributeMap] - ConsumedCapacity: Optional[ConsumedCapacity] - ItemCollectionMetrics: Optional[ItemCollectionMetrics] + Attributes: AttributeMap | None + ConsumedCapacity: ConsumedCapacity | None + ItemCollectionMetrics: ItemCollectionMetrics | None class PutResourcePolicyInput(ServiceRequest): ResourceArn: ResourceArnString Policy: ResourcePolicy - ExpectedRevisionId: Optional[PolicyRevisionId] - ConfirmRemoveSelfResourceAccess: Optional[ConfirmRemoveSelfResourceAccess] + ExpectedRevisionId: PolicyRevisionId | None + ConfirmRemoveSelfResourceAccess: ConfirmRemoveSelfResourceAccess | None class PutResourcePolicyOutput(TypedDict, total=False): - RevisionId: Optional[PolicyRevisionId] + RevisionId: PolicyRevisionId | None class QueryInput(ServiceRequest): TableName: TableArn - IndexName: Optional[IndexName] - Select: Optional[Select] - AttributesToGet: Optional[AttributeNameList] - Limit: Optional[PositiveIntegerObject] - ConsistentRead: Optional[ConsistentRead] - KeyConditions: Optional[KeyConditions] - QueryFilter: Optional[FilterConditionMap] - ConditionalOperator: Optional[ConditionalOperator] - ScanIndexForward: Optional[BooleanObject] - ExclusiveStartKey: Optional[Key] - ReturnConsumedCapacity: Optional[ReturnConsumedCapacity] - ProjectionExpression: Optional[ProjectionExpression] - FilterExpression: Optional[ConditionExpression] - KeyConditionExpression: Optional[KeyExpression] - ExpressionAttributeNames: Optional[ExpressionAttributeNameMap] - ExpressionAttributeValues: Optional[ExpressionAttributeValueMap] + IndexName: IndexName | None + Select: Select | None + AttributesToGet: AttributeNameList | None + Limit: PositiveIntegerObject | None + ConsistentRead: ConsistentRead | None + KeyConditions: KeyConditions | None + QueryFilter: FilterConditionMap | None + ConditionalOperator: ConditionalOperator | None + ScanIndexForward: BooleanObject | None + ExclusiveStartKey: Key | None + ReturnConsumedCapacity: ReturnConsumedCapacity | None + ProjectionExpression: ProjectionExpression | None + FilterExpression: ConditionExpression | None + KeyConditionExpression: KeyExpression | None + ExpressionAttributeNames: ExpressionAttributeNameMap | None + ExpressionAttributeValues: ExpressionAttributeValueMap | None class QueryOutput(TypedDict, total=False): - Items: Optional[ItemList] - Count: Optional[Integer] - ScannedCount: Optional[Integer] - LastEvaluatedKey: Optional[Key] - ConsumedCapacity: Optional[ConsumedCapacity] + Items: ItemList | None + Count: Integer | None + ScannedCount: Integer | None + LastEvaluatedKey: Key | None + ConsumedCapacity: ConsumedCapacity | None class ReplicaGlobalSecondaryIndexAutoScalingUpdate(TypedDict, total=False): - IndexName: Optional[IndexName] - ProvisionedReadCapacityAutoScalingUpdate: Optional[AutoScalingSettingsUpdate] + IndexName: IndexName | None + ProvisionedReadCapacityAutoScalingUpdate: AutoScalingSettingsUpdate | None -ReplicaGlobalSecondaryIndexAutoScalingUpdateList = List[ +ReplicaGlobalSecondaryIndexAutoScalingUpdateList = list[ ReplicaGlobalSecondaryIndexAutoScalingUpdate ] class ReplicaAutoScalingUpdate(TypedDict, total=False): RegionName: RegionName - ReplicaGlobalSecondaryIndexUpdates: Optional[ReplicaGlobalSecondaryIndexAutoScalingUpdateList] - ReplicaProvisionedReadCapacityAutoScalingUpdate: Optional[AutoScalingSettingsUpdate] + ReplicaGlobalSecondaryIndexUpdates: ReplicaGlobalSecondaryIndexAutoScalingUpdateList | None + ReplicaProvisionedReadCapacityAutoScalingUpdate: AutoScalingSettingsUpdate | None -ReplicaAutoScalingUpdateList = List[ReplicaAutoScalingUpdate] +ReplicaAutoScalingUpdateList = list[ReplicaAutoScalingUpdate] class ReplicaGlobalSecondaryIndexSettingsUpdate(TypedDict, total=False): IndexName: IndexName - ProvisionedReadCapacityUnits: Optional[PositiveLongObject] - ProvisionedReadCapacityAutoScalingSettingsUpdate: Optional[AutoScalingSettingsUpdate] + ProvisionedReadCapacityUnits: PositiveLongObject | None + ProvisionedReadCapacityAutoScalingSettingsUpdate: AutoScalingSettingsUpdate | None -ReplicaGlobalSecondaryIndexSettingsUpdateList = List[ReplicaGlobalSecondaryIndexSettingsUpdate] +ReplicaGlobalSecondaryIndexSettingsUpdateList = list[ReplicaGlobalSecondaryIndexSettingsUpdate] class ReplicaSettingsUpdate(TypedDict, total=False): RegionName: RegionName - ReplicaProvisionedReadCapacityUnits: Optional[PositiveLongObject] - ReplicaProvisionedReadCapacityAutoScalingSettingsUpdate: Optional[AutoScalingSettingsUpdate] - ReplicaGlobalSecondaryIndexSettingsUpdate: Optional[ - ReplicaGlobalSecondaryIndexSettingsUpdateList - ] - ReplicaTableClass: Optional[TableClass] + ReplicaProvisionedReadCapacityUnits: PositiveLongObject | None + ReplicaProvisionedReadCapacityAutoScalingSettingsUpdate: AutoScalingSettingsUpdate | None + ReplicaGlobalSecondaryIndexSettingsUpdate: ReplicaGlobalSecondaryIndexSettingsUpdateList | None + ReplicaTableClass: TableClass | None -ReplicaSettingsUpdateList = List[ReplicaSettingsUpdate] +ReplicaSettingsUpdateList = list[ReplicaSettingsUpdate] class ReplicaUpdate(TypedDict, total=False): - Create: Optional[CreateReplicaAction] - Delete: Optional[DeleteReplicaAction] + Create: CreateReplicaAction | None + Delete: DeleteReplicaAction | None -ReplicaUpdateList = List[ReplicaUpdate] +ReplicaUpdateList = list[ReplicaUpdate] class UpdateReplicationGroupMemberAction(TypedDict, total=False): RegionName: RegionName - KMSMasterKeyId: Optional[KMSMasterKeyId] - ProvisionedThroughputOverride: Optional[ProvisionedThroughputOverride] - OnDemandThroughputOverride: Optional[OnDemandThroughputOverride] - GlobalSecondaryIndexes: Optional[ReplicaGlobalSecondaryIndexList] - TableClassOverride: Optional[TableClass] + KMSMasterKeyId: KMSMasterKeyId | None + ProvisionedThroughputOverride: ProvisionedThroughputOverride | None + OnDemandThroughputOverride: OnDemandThroughputOverride | None + GlobalSecondaryIndexes: ReplicaGlobalSecondaryIndexList | None + TableClassOverride: TableClass | None class ReplicationGroupUpdate(TypedDict, total=False): - Create: Optional[CreateReplicationGroupMemberAction] - Update: Optional[UpdateReplicationGroupMemberAction] - Delete: Optional[DeleteReplicationGroupMemberAction] + Create: CreateReplicationGroupMemberAction | None + Update: UpdateReplicationGroupMemberAction | None + Delete: DeleteReplicationGroupMemberAction | None -ReplicationGroupUpdateList = List[ReplicationGroupUpdate] +ReplicationGroupUpdateList = list[ReplicationGroupUpdate] class RestoreTableFromBackupInput(ServiceRequest): TargetTableName: TableName BackupArn: BackupArn - BillingModeOverride: Optional[BillingMode] - GlobalSecondaryIndexOverride: Optional[GlobalSecondaryIndexList] - LocalSecondaryIndexOverride: Optional[LocalSecondaryIndexList] - ProvisionedThroughputOverride: Optional[ProvisionedThroughput] - OnDemandThroughputOverride: Optional[OnDemandThroughput] - SSESpecificationOverride: Optional[SSESpecification] + BillingModeOverride: BillingMode | None + GlobalSecondaryIndexOverride: GlobalSecondaryIndexList | None + LocalSecondaryIndexOverride: LocalSecondaryIndexList | None + ProvisionedThroughputOverride: ProvisionedThroughput | None + OnDemandThroughputOverride: OnDemandThroughput | None + SSESpecificationOverride: SSESpecification | None class RestoreTableFromBackupOutput(TypedDict, total=False): - TableDescription: Optional[TableDescription] + TableDescription: TableDescription | None class RestoreTableToPointInTimeInput(ServiceRequest): - SourceTableArn: Optional[TableArn] - SourceTableName: Optional[TableName] + SourceTableArn: TableArn | None + SourceTableName: TableName | None TargetTableName: TableName - UseLatestRestorableTime: Optional[BooleanObject] - RestoreDateTime: Optional[Date] - BillingModeOverride: Optional[BillingMode] - GlobalSecondaryIndexOverride: Optional[GlobalSecondaryIndexList] - LocalSecondaryIndexOverride: Optional[LocalSecondaryIndexList] - ProvisionedThroughputOverride: Optional[ProvisionedThroughput] - OnDemandThroughputOverride: Optional[OnDemandThroughput] - SSESpecificationOverride: Optional[SSESpecification] + UseLatestRestorableTime: BooleanObject | None + RestoreDateTime: Date | None + BillingModeOverride: BillingMode | None + GlobalSecondaryIndexOverride: GlobalSecondaryIndexList | None + LocalSecondaryIndexOverride: LocalSecondaryIndexList | None + ProvisionedThroughputOverride: ProvisionedThroughput | None + OnDemandThroughputOverride: OnDemandThroughput | None + SSESpecificationOverride: SSESpecification | None class RestoreTableToPointInTimeOutput(TypedDict, total=False): - TableDescription: Optional[TableDescription] + TableDescription: TableDescription | None class ScanInput(ServiceRequest): TableName: TableArn - IndexName: Optional[IndexName] - AttributesToGet: Optional[AttributeNameList] - Limit: Optional[PositiveIntegerObject] - Select: Optional[Select] - ScanFilter: Optional[FilterConditionMap] - ConditionalOperator: Optional[ConditionalOperator] - ExclusiveStartKey: Optional[Key] - ReturnConsumedCapacity: Optional[ReturnConsumedCapacity] - TotalSegments: Optional[ScanTotalSegments] - Segment: Optional[ScanSegment] - ProjectionExpression: Optional[ProjectionExpression] - FilterExpression: Optional[ConditionExpression] - ExpressionAttributeNames: Optional[ExpressionAttributeNameMap] - ExpressionAttributeValues: Optional[ExpressionAttributeValueMap] - ConsistentRead: Optional[ConsistentRead] + IndexName: IndexName | None + AttributesToGet: AttributeNameList | None + Limit: PositiveIntegerObject | None + Select: Select | None + ScanFilter: FilterConditionMap | None + ConditionalOperator: ConditionalOperator | None + ExclusiveStartKey: Key | None + ReturnConsumedCapacity: ReturnConsumedCapacity | None + TotalSegments: ScanTotalSegments | None + Segment: ScanSegment | None + ProjectionExpression: ProjectionExpression | None + FilterExpression: ConditionExpression | None + ExpressionAttributeNames: ExpressionAttributeNameMap | None + ExpressionAttributeValues: ExpressionAttributeValueMap | None + ConsistentRead: ConsistentRead | None class ScanOutput(TypedDict, total=False): - Items: Optional[ItemList] - Count: Optional[Integer] - ScannedCount: Optional[Integer] - LastEvaluatedKey: Optional[Key] - ConsumedCapacity: Optional[ConsumedCapacity] + Items: ItemList | None + Count: Integer | None + ScannedCount: Integer | None + LastEvaluatedKey: Key | None + ConsumedCapacity: ConsumedCapacity | None -TagKeyList = List[TagKeyString] +TagKeyList = list[TagKeyString] class TagResourceInput(ServiceRequest): @@ -2164,49 +2170,49 @@ class TransactGetItem(TypedDict, total=False): Get: Get -TransactGetItemList = List[TransactGetItem] +TransactGetItemList = list[TransactGetItem] class TransactGetItemsInput(ServiceRequest): TransactItems: TransactGetItemList - ReturnConsumedCapacity: Optional[ReturnConsumedCapacity] + ReturnConsumedCapacity: ReturnConsumedCapacity | None class TransactGetItemsOutput(TypedDict, total=False): - ConsumedCapacity: Optional[ConsumedCapacityMultiple] - Responses: Optional[ItemResponseList] + ConsumedCapacity: ConsumedCapacityMultiple | None + Responses: ItemResponseList | None class Update(TypedDict, total=False): Key: Key UpdateExpression: UpdateExpression TableName: TableArn - ConditionExpression: Optional[ConditionExpression] - ExpressionAttributeNames: Optional[ExpressionAttributeNameMap] - ExpressionAttributeValues: Optional[ExpressionAttributeValueMap] - ReturnValuesOnConditionCheckFailure: Optional[ReturnValuesOnConditionCheckFailure] + ConditionExpression: ConditionExpression | None + ExpressionAttributeNames: ExpressionAttributeNameMap | None + ExpressionAttributeValues: ExpressionAttributeValueMap | None + ReturnValuesOnConditionCheckFailure: ReturnValuesOnConditionCheckFailure | None class TransactWriteItem(TypedDict, total=False): - ConditionCheck: Optional[ConditionCheck] - Put: Optional[Put] - Delete: Optional[Delete] - Update: Optional[Update] + ConditionCheck: ConditionCheck | None + Put: Put | None + Delete: Delete | None + Update: Update | None -TransactWriteItemList = List[TransactWriteItem] +TransactWriteItemList = list[TransactWriteItem] class TransactWriteItemsInput(ServiceRequest): TransactItems: TransactWriteItemList - ReturnConsumedCapacity: Optional[ReturnConsumedCapacity] - ReturnItemCollectionMetrics: Optional[ReturnItemCollectionMetrics] - ClientRequestToken: Optional[ClientRequestToken] + ReturnConsumedCapacity: ReturnConsumedCapacity | None + ReturnItemCollectionMetrics: ReturnItemCollectionMetrics | None + ClientRequestToken: ClientRequestToken | None class TransactWriteItemsOutput(TypedDict, total=False): - ConsumedCapacity: Optional[ConsumedCapacityMultiple] - ItemCollectionMetrics: Optional[ItemCollectionMetricsPerTable] + ConsumedCapacity: ConsumedCapacityMultiple | None + ItemCollectionMetrics: ItemCollectionMetricsPerTable | None class UntagResourceInput(ServiceRequest): @@ -2220,21 +2226,21 @@ class UpdateContinuousBackupsInput(ServiceRequest): class UpdateContinuousBackupsOutput(TypedDict, total=False): - ContinuousBackupsDescription: Optional[ContinuousBackupsDescription] + ContinuousBackupsDescription: ContinuousBackupsDescription | None class UpdateContributorInsightsInput(ServiceRequest): TableName: TableArn - IndexName: Optional[IndexName] + IndexName: IndexName | None ContributorInsightsAction: ContributorInsightsAction - ContributorInsightsMode: Optional[ContributorInsightsMode] + ContributorInsightsMode: ContributorInsightsMode | None class UpdateContributorInsightsOutput(TypedDict, total=False): - TableName: Optional[TableName] - IndexName: Optional[IndexName] - ContributorInsightsStatus: Optional[ContributorInsightsStatus] - ContributorInsightsMode: Optional[ContributorInsightsMode] + TableName: TableName | None + IndexName: IndexName | None + ContributorInsightsStatus: ContributorInsightsStatus | None + ContributorInsightsMode: ContributorInsightsMode | None class UpdateGlobalTableInput(ServiceRequest): @@ -2243,96 +2249,95 @@ class UpdateGlobalTableInput(ServiceRequest): class UpdateGlobalTableOutput(TypedDict, total=False): - GlobalTableDescription: Optional[GlobalTableDescription] + GlobalTableDescription: GlobalTableDescription | None class UpdateGlobalTableSettingsInput(ServiceRequest): GlobalTableName: TableName - GlobalTableBillingMode: Optional[BillingMode] - GlobalTableProvisionedWriteCapacityUnits: Optional[PositiveLongObject] - GlobalTableProvisionedWriteCapacityAutoScalingSettingsUpdate: Optional[ - AutoScalingSettingsUpdate - ] - GlobalTableGlobalSecondaryIndexSettingsUpdate: Optional[ - GlobalTableGlobalSecondaryIndexSettingsUpdateList - ] - ReplicaSettingsUpdate: Optional[ReplicaSettingsUpdateList] + GlobalTableBillingMode: BillingMode | None + GlobalTableProvisionedWriteCapacityUnits: PositiveLongObject | None + GlobalTableProvisionedWriteCapacityAutoScalingSettingsUpdate: AutoScalingSettingsUpdate | None + GlobalTableGlobalSecondaryIndexSettingsUpdate: ( + GlobalTableGlobalSecondaryIndexSettingsUpdateList | None + ) + ReplicaSettingsUpdate: ReplicaSettingsUpdateList | None class UpdateGlobalTableSettingsOutput(TypedDict, total=False): - GlobalTableName: Optional[TableName] - ReplicaSettings: Optional[ReplicaSettingsDescriptionList] + GlobalTableName: TableName | None + ReplicaSettings: ReplicaSettingsDescriptionList | None class UpdateItemInput(ServiceRequest): TableName: TableArn Key: Key - AttributeUpdates: Optional[AttributeUpdates] - Expected: Optional[ExpectedAttributeMap] - ConditionalOperator: Optional[ConditionalOperator] - ReturnValues: Optional[ReturnValue] - ReturnConsumedCapacity: Optional[ReturnConsumedCapacity] - ReturnItemCollectionMetrics: Optional[ReturnItemCollectionMetrics] - UpdateExpression: Optional[UpdateExpression] - ConditionExpression: Optional[ConditionExpression] - ExpressionAttributeNames: Optional[ExpressionAttributeNameMap] - ExpressionAttributeValues: Optional[ExpressionAttributeValueMap] - ReturnValuesOnConditionCheckFailure: Optional[ReturnValuesOnConditionCheckFailure] + AttributeUpdates: AttributeUpdates | None + Expected: ExpectedAttributeMap | None + ConditionalOperator: ConditionalOperator | None + ReturnValues: ReturnValue | None + ReturnConsumedCapacity: ReturnConsumedCapacity | None + ReturnItemCollectionMetrics: ReturnItemCollectionMetrics | None + UpdateExpression: UpdateExpression | None + ConditionExpression: ConditionExpression | None + ExpressionAttributeNames: ExpressionAttributeNameMap | None + ExpressionAttributeValues: ExpressionAttributeValueMap | None + ReturnValuesOnConditionCheckFailure: ReturnValuesOnConditionCheckFailure | None class UpdateItemOutput(TypedDict, total=False): - Attributes: Optional[AttributeMap] - ConsumedCapacity: Optional[ConsumedCapacity] - ItemCollectionMetrics: Optional[ItemCollectionMetrics] + Attributes: AttributeMap | None + ConsumedCapacity: ConsumedCapacity | None + ItemCollectionMetrics: ItemCollectionMetrics | None class UpdateKinesisStreamingConfiguration(TypedDict, total=False): - ApproximateCreationDateTimePrecision: Optional[ApproximateCreationDateTimePrecision] + ApproximateCreationDateTimePrecision: ApproximateCreationDateTimePrecision | None class UpdateKinesisStreamingDestinationInput(ServiceRequest): TableName: TableArn StreamArn: StreamArn - UpdateKinesisStreamingConfiguration: Optional[UpdateKinesisStreamingConfiguration] + UpdateKinesisStreamingConfiguration: UpdateKinesisStreamingConfiguration | None class UpdateKinesisStreamingDestinationOutput(TypedDict, total=False): - TableName: Optional[TableName] - StreamArn: Optional[StreamArn] - DestinationStatus: Optional[DestinationStatus] - UpdateKinesisStreamingConfiguration: Optional[UpdateKinesisStreamingConfiguration] + TableName: TableName | None + StreamArn: StreamArn | None + DestinationStatus: DestinationStatus | None + UpdateKinesisStreamingConfiguration: UpdateKinesisStreamingConfiguration | None class UpdateTableInput(ServiceRequest): - AttributeDefinitions: Optional[AttributeDefinitions] + AttributeDefinitions: AttributeDefinitions | None TableName: TableArn - BillingMode: Optional[BillingMode] - ProvisionedThroughput: Optional[ProvisionedThroughput] - GlobalSecondaryIndexUpdates: Optional[GlobalSecondaryIndexUpdateList] - StreamSpecification: Optional[StreamSpecification] - SSESpecification: Optional[SSESpecification] - ReplicaUpdates: Optional[ReplicationGroupUpdateList] - TableClass: Optional[TableClass] - DeletionProtectionEnabled: Optional[DeletionProtectionEnabled] - MultiRegionConsistency: Optional[MultiRegionConsistency] - GlobalTableWitnessUpdates: Optional[GlobalTableWitnessGroupUpdateList] - OnDemandThroughput: Optional[OnDemandThroughput] - WarmThroughput: Optional[WarmThroughput] + BillingMode: BillingMode | None + ProvisionedThroughput: ProvisionedThroughput | None + GlobalSecondaryIndexUpdates: GlobalSecondaryIndexUpdateList | None + StreamSpecification: StreamSpecification | None + SSESpecification: SSESpecification | None + ReplicaUpdates: ReplicationGroupUpdateList | None + TableClass: TableClass | None + DeletionProtectionEnabled: DeletionProtectionEnabled | None + MultiRegionConsistency: MultiRegionConsistency | None + GlobalTableWitnessUpdates: GlobalTableWitnessGroupUpdateList | None + OnDemandThroughput: OnDemandThroughput | None + WarmThroughput: WarmThroughput | None + GlobalTableSettingsReplicationMode: GlobalTableSettingsReplicationMode | None class UpdateTableOutput(TypedDict, total=False): - TableDescription: Optional[TableDescription] + TableDescription: TableDescription | None class UpdateTableReplicaAutoScalingInput(ServiceRequest): - GlobalSecondaryIndexUpdates: Optional[GlobalSecondaryIndexAutoScalingUpdateList] + GlobalSecondaryIndexUpdates: GlobalSecondaryIndexAutoScalingUpdateList | None TableName: TableArn - ProvisionedWriteCapacityAutoScalingUpdate: Optional[AutoScalingSettingsUpdate] - ReplicaUpdates: Optional[ReplicaAutoScalingUpdateList] + ProvisionedWriteCapacityAutoScalingUpdate: AutoScalingSettingsUpdate | None + ReplicaUpdates: ReplicaAutoScalingUpdateList | None class UpdateTableReplicaAutoScalingOutput(TypedDict, total=False): - TableAutoScalingDescription: Optional[TableAutoScalingDescription] + TableAutoScalingDescription: TableAutoScalingDescription | None class UpdateTimeToLiveInput(ServiceRequest): @@ -2341,12 +2346,12 @@ class UpdateTimeToLiveInput(ServiceRequest): class UpdateTimeToLiveOutput(TypedDict, total=False): - TimeToLiveSpecification: Optional[TimeToLiveSpecification] + TimeToLiveSpecification: TimeToLiveSpecification | None class DynamodbApi: - service = "dynamodb" - version = "2012-08-10" + service: str = "dynamodb" + version: str = "2012-08-10" @handler("BatchExecuteStatement") def batch_execute_statement( @@ -2399,9 +2404,9 @@ def create_global_table( def create_table( self, context: RequestContext, - attribute_definitions: AttributeDefinitions, table_name: TableArn, - key_schema: KeySchema, + attribute_definitions: AttributeDefinitions | None = None, + key_schema: KeySchema | None = None, local_secondary_indexes: LocalSecondaryIndexList | None = None, global_secondary_indexes: GlobalSecondaryIndexList | None = None, billing_mode: BillingMode | None = None, @@ -2414,6 +2419,8 @@ def create_table( warm_throughput: WarmThroughput | None = None, resource_policy: ResourcePolicy | None = None, on_demand_throughput: OnDemandThroughput | None = None, + global_table_source_arn: TableArn | None = None, + global_table_settings_replication_mode: GlobalTableSettingsReplicationMode | None = None, **kwargs, ) -> CreateTableOutput: raise NotImplementedError @@ -2968,6 +2975,7 @@ def update_table( global_table_witness_updates: GlobalTableWitnessGroupUpdateList | None = None, on_demand_throughput: OnDemandThroughput | None = None, warm_throughput: WarmThroughput | None = None, + global_table_settings_replication_mode: GlobalTableSettingsReplicationMode | None = None, **kwargs, ) -> UpdateTableOutput: raise NotImplementedError diff --git a/localstack-core/localstack/aws/api/dynamodbstreams/__init__.py b/localstack-core/localstack/aws/api/dynamodbstreams/__init__.py index 8d550fd1f1f6c..d387a1bf3d58e 100644 --- a/localstack-core/localstack/aws/api/dynamodbstreams/__init__.py +++ b/localstack-core/localstack/aws/api/dynamodbstreams/__init__.py @@ -1,6 +1,6 @@ from datetime import datetime from enum import StrEnum -from typing import Dict, List, Optional, TypedDict +from typing import TypedDict from localstack.aws.api import RequestContext, ServiceException, ServiceRequest, handler @@ -87,52 +87,52 @@ class TrimmedDataAccessException(ServiceException): class AttributeValue(TypedDict, total=False): - S: Optional["StringAttributeValue"] - N: Optional["NumberAttributeValue"] - B: Optional["BinaryAttributeValue"] - SS: Optional["StringSetAttributeValue"] - NS: Optional["NumberSetAttributeValue"] - BS: Optional["BinarySetAttributeValue"] - M: Optional["MapAttributeValue"] - L: Optional["ListAttributeValue"] - NULL: Optional["NullAttributeValue"] - BOOL: Optional["BooleanAttributeValue"] - - -ListAttributeValue = List[AttributeValue] -MapAttributeValue = Dict[AttributeName, AttributeValue] + S: "StringAttributeValue | None" + N: "NumberAttributeValue | None" + B: "BinaryAttributeValue | None" + SS: "StringSetAttributeValue | None" + NS: "NumberSetAttributeValue | None" + BS: "BinarySetAttributeValue | None" + M: "MapAttributeValue | None" + L: "ListAttributeValue | None" + NULL: "NullAttributeValue | None" + BOOL: "BooleanAttributeValue | None" + + +ListAttributeValue = list[AttributeValue] +MapAttributeValue = dict[AttributeName, AttributeValue] BinaryAttributeValue = bytes -BinarySetAttributeValue = List[BinaryAttributeValue] -NumberSetAttributeValue = List[NumberAttributeValue] -StringSetAttributeValue = List[StringAttributeValue] -AttributeMap = Dict[AttributeName, AttributeValue] +BinarySetAttributeValue = list[BinaryAttributeValue] +NumberSetAttributeValue = list[NumberAttributeValue] +StringSetAttributeValue = list[StringAttributeValue] +AttributeMap = dict[AttributeName, AttributeValue] Date = datetime class ShardFilter(TypedDict, total=False): - Type: Optional[ShardFilterType] - ShardId: Optional[ShardId] + Type: ShardFilterType | None + ShardId: ShardId | None class DescribeStreamInput(ServiceRequest): StreamArn: StreamArn - Limit: Optional[PositiveIntegerObject] - ExclusiveStartShardId: Optional[ShardId] - ShardFilter: Optional[ShardFilter] + Limit: PositiveIntegerObject | None + ExclusiveStartShardId: ShardId | None + ShardFilter: ShardFilter | None class SequenceNumberRange(TypedDict, total=False): - StartingSequenceNumber: Optional[SequenceNumber] - EndingSequenceNumber: Optional[SequenceNumber] + StartingSequenceNumber: SequenceNumber | None + EndingSequenceNumber: SequenceNumber | None class Shard(TypedDict, total=False): - ShardId: Optional[ShardId] - SequenceNumberRange: Optional[SequenceNumberRange] - ParentShardId: Optional[ShardId] + ShardId: ShardId | None + SequenceNumberRange: SequenceNumberRange | None + ParentShardId: ShardId | None -ShardDescriptionList = List[Shard] +ShardDescriptionList = list[Shard] class KeySchemaElement(TypedDict, total=False): @@ -140,100 +140,100 @@ class KeySchemaElement(TypedDict, total=False): KeyType: KeyType -KeySchema = List[KeySchemaElement] +KeySchema = list[KeySchemaElement] class StreamDescription(TypedDict, total=False): - StreamArn: Optional[StreamArn] - StreamLabel: Optional[String] - StreamStatus: Optional[StreamStatus] - StreamViewType: Optional[StreamViewType] - CreationRequestDateTime: Optional[Date] - TableName: Optional[TableName] - KeySchema: Optional[KeySchema] - Shards: Optional[ShardDescriptionList] - LastEvaluatedShardId: Optional[ShardId] + StreamArn: StreamArn | None + StreamLabel: String | None + StreamStatus: StreamStatus | None + StreamViewType: StreamViewType | None + CreationRequestDateTime: Date | None + TableName: TableName | None + KeySchema: KeySchema | None + Shards: ShardDescriptionList | None + LastEvaluatedShardId: ShardId | None class DescribeStreamOutput(TypedDict, total=False): - StreamDescription: Optional[StreamDescription] + StreamDescription: StreamDescription | None class GetRecordsInput(ServiceRequest): ShardIterator: ShardIterator - Limit: Optional[PositiveIntegerObject] + Limit: PositiveIntegerObject | None class Identity(TypedDict, total=False): - PrincipalId: Optional[String] - Type: Optional[String] + PrincipalId: String | None + Type: String | None PositiveLongObject = int class StreamRecord(TypedDict, total=False): - ApproximateCreationDateTime: Optional[Date] - Keys: Optional[AttributeMap] - NewImage: Optional[AttributeMap] - OldImage: Optional[AttributeMap] - SequenceNumber: Optional[SequenceNumber] - SizeBytes: Optional[PositiveLongObject] - StreamViewType: Optional[StreamViewType] + ApproximateCreationDateTime: Date | None + Keys: AttributeMap | None + NewImage: AttributeMap | None + OldImage: AttributeMap | None + SequenceNumber: SequenceNumber | None + SizeBytes: PositiveLongObject | None + StreamViewType: StreamViewType | None class Record(TypedDict, total=False): - eventID: Optional[String] - eventName: Optional[OperationType] - eventVersion: Optional[String] - eventSource: Optional[String] - awsRegion: Optional[String] - dynamodb: Optional[StreamRecord] - userIdentity: Optional[Identity] + eventID: String | None + eventName: OperationType | None + eventVersion: String | None + eventSource: String | None + awsRegion: String | None + dynamodb: StreamRecord | None + userIdentity: Identity | None -RecordList = List[Record] +RecordList = list[Record] class GetRecordsOutput(TypedDict, total=False): - Records: Optional[RecordList] - NextShardIterator: Optional[ShardIterator] + Records: RecordList | None + NextShardIterator: ShardIterator | None class GetShardIteratorInput(ServiceRequest): StreamArn: StreamArn ShardId: ShardId ShardIteratorType: ShardIteratorType - SequenceNumber: Optional[SequenceNumber] + SequenceNumber: SequenceNumber | None class GetShardIteratorOutput(TypedDict, total=False): - ShardIterator: Optional[ShardIterator] + ShardIterator: ShardIterator | None class ListStreamsInput(ServiceRequest): - TableName: Optional[TableName] - Limit: Optional[PositiveIntegerObject] - ExclusiveStartStreamArn: Optional[StreamArn] + TableName: TableName | None + Limit: PositiveIntegerObject | None + ExclusiveStartStreamArn: StreamArn | None class Stream(TypedDict, total=False): - StreamArn: Optional[StreamArn] - TableName: Optional[TableName] - StreamLabel: Optional[String] + StreamArn: StreamArn | None + TableName: TableName | None + StreamLabel: String | None -StreamList = List[Stream] +StreamList = list[Stream] class ListStreamsOutput(TypedDict, total=False): - Streams: Optional[StreamList] - LastEvaluatedStreamArn: Optional[StreamArn] + Streams: StreamList | None + LastEvaluatedStreamArn: StreamArn | None class DynamodbstreamsApi: - service = "dynamodbstreams" - version = "2012-08-10" + service: str = "dynamodbstreams" + version: str = "2012-08-10" @handler("DescribeStream") def describe_stream( diff --git a/localstack-core/localstack/aws/api/ec2/__init__.py b/localstack-core/localstack/aws/api/ec2/__init__.py index 6d4e1980f8ddb..ee187ac92316a 100644 --- a/localstack-core/localstack/aws/api/ec2/__init__.py +++ b/localstack-core/localstack/aws/api/ec2/__init__.py @@ -1,11 +1,12 @@ from datetime import datetime from enum import StrEnum -from typing import List, Optional, TypedDict +from typing import TypedDict from localstack.aws.api import RequestContext, ServiceRequest, handler from localstack.aws.api import ServiceException as ServiceException AccountID = str +AdditionalFlexibleNetworkInterfaces = int AddressMaxResults = int AllocationId = str AllowedInstanceType = str @@ -19,6 +20,7 @@ BaselineIops = int BaselineThroughputInMBps = float Boolean = bool +BoxedBoolean = bool BoxedDouble = float BoxedInteger = int BundleId = str @@ -26,6 +28,7 @@ CancelCapacityReservationFleetErrorCode = str CancelCapacityReservationFleetErrorMessage = str CapacityBlockId = str +CapacityManagerDataExportId = str CapacityReservationFleetId = str CapacityReservationId = str CarrierGatewayId = str @@ -64,8 +67,10 @@ DescribeCapacityBlockOfferingsMaxResults = int DescribeCapacityBlockStatusMaxResults = int DescribeCapacityBlocksMaxResults = int +DescribeCapacityManagerDataExportsRequestMaxResults = int DescribeCapacityReservationBillingRequestsRequestMaxResults = int DescribeCapacityReservationFleetsMaxResults = int +DescribeCapacityReservationTopologyMaxResults = int DescribeCapacityReservationsMaxResults = int DescribeClassicLinkInstancesMaxResults = int DescribeClientVpnAuthorizationRulesMaxResults = int @@ -88,6 +93,7 @@ DescribeImageUsageReportsMaxResults = int DescribeInstanceCreditSpecificationsMaxResults = int DescribeInstanceImageMetadataMaxResults = int +DescribeInstanceSqlHaStatesRequestMaxResultsInteger = int DescribeInstanceTopologyMaxResults = int DescribeInternetGatewaysMaxResults = int DescribeIpamByoasnMaxResults = int @@ -104,6 +110,9 @@ DescribeReplaceRootVolumeTasksMaxResults = int DescribeRouteTablesMaxResults = int DescribeScheduledInstanceAvailabilityMaxResults = int +DescribeSecondaryInterfacesMaxResults = int +DescribeSecondaryNetworksMaxResults = int +DescribeSecondarySubnetsMaxResults = int DescribeSecurityGroupRulesMaxResults = int DescribeSecurityGroupVpcAssociationsMaxResults = int DescribeSecurityGroupsMaxResults = int @@ -123,6 +132,7 @@ DescribeVpcBlockPublicAccessExclusionsMaxResults = int DescribeVpcClassicLinkDnsSupportMaxResults = int DescribeVpcClassicLinkDnsSupportNextToken = str +DescribeVpcEncryptionControlsMaxResults = int DescribeVpcPeeringConnectionsMaxResults = int DescribeVpcsMaxResults = int DhcpOptionsId = str @@ -131,6 +141,7 @@ Double = float DoubleWithConstraints = float DrainSeconds = int +EbsCardIndex = int EfaSupportedFlag = bool EgressOnlyInternetGatewayId = str EipAllocationPublicIp = str @@ -162,10 +173,12 @@ GetSecurityGroupsForVpcRequestMaxResults = int GetSubnetCidrReservationsMaxResults = int GetVerifiedAccessEndpointTargetsMaxResults = int +GetVpcResourcesBlockingEncryptionEnforcementMaxResults = int GpuDeviceCount = int GpuDeviceManufacturerName = str GpuDeviceMemorySize = int GpuDeviceName = str +GpuPartitionSize = float HibernationFlag = bool HostReservationId = str Hour = int @@ -206,12 +219,16 @@ IpamId = str IpamMaxResults = int IpamNetmaskLength = int +IpamPolicyId = str IpamPoolAllocationId = str IpamPoolCidrId = str IpamPoolId = str +IpamPrefixListResolverId = str +IpamPrefixListResolverTargetId = str IpamResourceDiscoveryAssociationId = str IpamResourceDiscoveryId = str IpamScopeId = str +Ipv4AddressesPerSecondaryInterface = int Ipv4PoolCoipId = str Ipv4PoolEc2Id = str Ipv6Address = str @@ -238,6 +255,7 @@ LocalGatewayVirtualInterfaceGroupId = str LocalGatewayVirtualInterfaceId = str Location = str +LogicalGpuCount = int MacModificationTaskId = str MarketplaceProductCode = str MarketplaceProductCodeRequest = str @@ -250,11 +268,13 @@ MaximumDaysSinceCreatedValue = int MaximumDaysSinceDeprecatedValue = int MaximumEbsAttachments = int +MaximumEbsCards = int MaximumEfaInterfaces = int MaximumEnaQueueCount = int MaximumEnaQueueCountPerInterface = int MaximumIops = int MaximumNetworkCards = int +MaximumSecondaryNetworkInterfaces = int MaximumThroughputInMBps = float MediaDeviceCount = int MediaDeviceManufacturerName = str @@ -289,9 +309,11 @@ OutpostLagMaxResults = int PasswordData = str PeakBandwidthInGbps = float +Period = int PlacementGroupArn = str PlacementGroupId = str PlacementGroupName = str +PlacementGroupNameWithResolver = str PoolMaxResults = int Port = int PrefixListMaxResults = int @@ -330,6 +352,13 @@ S3StorageUploadPolicy = str S3StorageUploadPolicySignature = str ScheduledInstanceId = str +SecondaryInterfaceId = str +SecondaryNetworkCidrAssociationId = str +SecondaryNetworkId = str +SecondaryNetworkSupportedFlag = bool +SecondarySubnetCidrAssociationId = str +SecondarySubnetId = str +SecretArn = str SecurityGroupId = str SecurityGroupName = str SecurityGroupRuleId = str @@ -365,6 +394,7 @@ TransitGatewayConnectPeerId = str TransitGatewayId = str TransitGatewayMaxResults = int +TransitGatewayMeteringPolicyId = str TransitGatewayMulticastDomainId = str TransitGatewayPolicyTableId = str TransitGatewayRouteTableAnnouncementId = str @@ -388,10 +418,12 @@ VpcId = str VpcPeeringConnectionId = str VpcPeeringConnectionIdWithResolver = str +VpnConcentratorId = str VpnConnectionDeviceSampleConfiguration = str VpnConnectionDeviceTypeId = str VpnConnectionId = str VpnGatewayId = str +Workload = str customerGatewayConfiguration = str maxResults = int preSharedKey = str @@ -421,12 +453,20 @@ class AcceleratorName(StrEnum): a10g = "a10g" h100 = "h100" t4g = "t4g" + l40s = "l40s" + l4 = "l4" + gaudi_hl_205 = "gaudi-hl-205" + inferentia2 = "inferentia2" + trainium = "trainium" + trainium2 = "trainium2" + u30 = "u30" class AcceleratorType(StrEnum): gpu = "gpu" fpga = "fpga" inference = "inference" + media = "media" class AccountAttributeName(StrEnum): @@ -586,6 +626,21 @@ class AutoPlacement(StrEnum): off = "off" +class AutoProvisionZonesState(StrEnum): + enabled = "enabled" + disabled = "disabled" + + +class AutoScalingIpsState(StrEnum): + enabled = "enabled" + disabled = "disabled" + + +class AvailabilityMode(StrEnum): + zonal = "zonal" + regional = "regional" + + class AvailabilityZoneOptInStatus(StrEnum): opt_in_not_required = "opt-in-not-required" opted_in = "opted-in" @@ -665,8 +720,10 @@ class ByoipCidrState(StrEnum): deprovisioned = "deprovisioned" failed_deprovision = "failed-deprovision" failed_provision = "failed-provision" + pending_advertising = "pending-advertising" pending_deprovision = "pending-deprovision" pending_provision = "pending-provision" + pending_withdrawal = "pending-withdrawal" provisioned = "provisioned" provisioned_not_publicly_advertisable = "provisioned-not-publicly-advertisable" @@ -714,6 +771,18 @@ class CapacityBlockResourceState(StrEnum): payment_failed = "payment-failed" +class CapacityManagerDataExportStatus(StrEnum): + pending = "pending" + in_progress = "in-progress" + delivered = "delivered" + failed = "failed" + + +class CapacityManagerStatus(StrEnum): + enabled = "enabled" + disabled = "disabled" + + class CapacityReservationBillingRequestStatus(StrEnum): pending = "pending" accepted = "accepted" @@ -792,6 +861,11 @@ class CapacityReservationType(StrEnum): capacity_block = "capacity-block" +class CapacityTenancy(StrEnum): + default = "default" + dedicated = "dedicated" + + class CarrierGatewayState(StrEnum): pending = "pending" available = "available" @@ -843,6 +917,11 @@ class ClientVpnRouteStatusCode(StrEnum): deleting = "deleting" +class Comparison(StrEnum): + equals = "equals" + in_ = "in" + + class ConnectionNotificationState(StrEnum): Enabled = "Enabled" Disabled = "Disabled" @@ -888,6 +967,12 @@ class DatafeedSubscriptionState(StrEnum): Inactive = "Inactive" +class DefaultHttpTokensEnforcedState(StrEnum): + disabled = "disabled" + enabled = "enabled" + no_preference = "no-preference" + + class DefaultInstanceMetadataEndpointState(StrEnum): disabled = "disabled" enabled = "enabled" @@ -1038,6 +1123,18 @@ class EnaSupport(StrEnum): required = "required" +class EncryptionStateValue(StrEnum): + enabling = "enabling" + enabled = "enabled" + disabling = "disabling" + disabled = "disabled" + + +class EncryptionSupportOptionValue(StrEnum): + enable = "enable" + disable = "disable" + + class EndDateType(StrEnum): unlimited = "unlimited" limited = "limited" @@ -1109,6 +1206,26 @@ class FastSnapshotRestoreStateCode(StrEnum): disabled = "disabled" +class FilterByDimension(StrEnum): + resource_region = "resource-region" + availability_zone_id = "availability-zone-id" + account_id = "account-id" + instance_family = "instance-family" + instance_type = "instance-type" + instance_platform = "instance-platform" + reservation_arn = "reservation-arn" + reservation_id = "reservation-id" + reservation_type = "reservation-type" + reservation_create_timestamp = "reservation-create-timestamp" + reservation_start_timestamp = "reservation-start-timestamp" + reservation_end_timestamp = "reservation-end-timestamp" + reservation_end_date_type = "reservation-end-date-type" + tenancy = "tenancy" + reservation_state = "reservation-state" + reservation_instance_match_criteria = "reservation-instance-match-criteria" + reservation_unused_financial_owner = "reservation-unused-financial-owner" + + class FindingsFound(StrEnum): true = "true" false = "false" @@ -1182,6 +1299,7 @@ class FlowLogsResourceType(StrEnum): NetworkInterface = "NetworkInterface" TransitGateway = "TransitGateway" TransitGatewayAttachment = "TransitGatewayAttachment" + RegionalNatGateway = "RegionalNatGateway" class FpgaImageAttributeName(StrEnum): @@ -1209,6 +1327,33 @@ class GatewayType(StrEnum): ipsec_1 = "ipsec.1" +class GroupBy(StrEnum): + resource_region = "resource-region" + availability_zone_id = "availability-zone-id" + account_id = "account-id" + instance_family = "instance-family" + instance_type = "instance-type" + instance_platform = "instance-platform" + reservation_arn = "reservation-arn" + reservation_id = "reservation-id" + reservation_type = "reservation-type" + reservation_create_timestamp = "reservation-create-timestamp" + reservation_start_timestamp = "reservation-start-timestamp" + reservation_end_timestamp = "reservation-end-timestamp" + reservation_end_date_type = "reservation-end-date-type" + tenancy = "tenancy" + reservation_state = "reservation-state" + reservation_instance_match_criteria = "reservation-instance-match-criteria" + reservation_unused_financial_owner = "reservation-unused-financial-owner" + + +class HaStatus(StrEnum): + processing = "processing" + active = "active" + standby = "standby" + invalid = "invalid" + + class HostMaintenance(StrEnum): on = "on" off = "off" @@ -1230,6 +1375,11 @@ class HostnameType(StrEnum): resource_name = "resource-name" +class HttpTokensEnforcedState(StrEnum): + disabled = "disabled" + enabled = "enabled" + + class HttpTokensState(StrEnum): optional = "optional" required = "required" @@ -1310,9 +1460,16 @@ class ImdsSupportValues(StrEnum): v2_0 = "v2.0" +class IngestionStatus(StrEnum): + initial_ingestion_in_progress = "initial-ingestion-in-progress" + ingestion_complete = "ingestion-complete" + ingestion_failed = "ingestion-failed" + + class InitializationType(StrEnum): default = "default" provisioned_rate = "provisioned-rate" + volume_copy = "volume-copy" class InstanceAttributeName(StrEnum): @@ -1382,6 +1539,7 @@ class InstanceLifecycleType(StrEnum): spot = "spot" scheduled = "scheduled" capacity_block = "capacity-block" + interruptible_capacity_reservation = "interruptible-capacity-reservation" class InstanceMatchCriteria(StrEnum): @@ -2459,6 +2617,188 @@ class InstanceType(StrEnum): r8gn_48xlarge = "r8gn.48xlarge" r8gn_metal_24xl = "r8gn.metal-24xl" r8gn_metal_48xl = "r8gn.metal-48xl" + c8i_large = "c8i.large" + c8i_xlarge = "c8i.xlarge" + c8i_2xlarge = "c8i.2xlarge" + c8i_4xlarge = "c8i.4xlarge" + c8i_8xlarge = "c8i.8xlarge" + c8i_12xlarge = "c8i.12xlarge" + c8i_16xlarge = "c8i.16xlarge" + c8i_24xlarge = "c8i.24xlarge" + c8i_32xlarge = "c8i.32xlarge" + c8i_48xlarge = "c8i.48xlarge" + c8i_96xlarge = "c8i.96xlarge" + c8i_metal_48xl = "c8i.metal-48xl" + c8i_metal_96xl = "c8i.metal-96xl" + c8i_flex_large = "c8i-flex.large" + c8i_flex_xlarge = "c8i-flex.xlarge" + c8i_flex_2xlarge = "c8i-flex.2xlarge" + c8i_flex_4xlarge = "c8i-flex.4xlarge" + c8i_flex_8xlarge = "c8i-flex.8xlarge" + c8i_flex_12xlarge = "c8i-flex.12xlarge" + c8i_flex_16xlarge = "c8i-flex.16xlarge" + r8gb_medium = "r8gb.medium" + r8gb_large = "r8gb.large" + r8gb_xlarge = "r8gb.xlarge" + r8gb_2xlarge = "r8gb.2xlarge" + r8gb_4xlarge = "r8gb.4xlarge" + r8gb_8xlarge = "r8gb.8xlarge" + r8gb_12xlarge = "r8gb.12xlarge" + r8gb_16xlarge = "r8gb.16xlarge" + r8gb_24xlarge = "r8gb.24xlarge" + r8gb_metal_24xl = "r8gb.metal-24xl" + m8a_medium = "m8a.medium" + m8a_large = "m8a.large" + m8a_xlarge = "m8a.xlarge" + m8a_2xlarge = "m8a.2xlarge" + m8a_4xlarge = "m8a.4xlarge" + m8a_8xlarge = "m8a.8xlarge" + m8a_12xlarge = "m8a.12xlarge" + m8a_16xlarge = "m8a.16xlarge" + m8a_24xlarge = "m8a.24xlarge" + m8a_48xlarge = "m8a.48xlarge" + m8a_metal_24xl = "m8a.metal-24xl" + m8a_metal_48xl = "m8a.metal-48xl" + trn2_3xlarge = "trn2.3xlarge" + r8a_medium = "r8a.medium" + r8a_large = "r8a.large" + r8a_xlarge = "r8a.xlarge" + r8a_2xlarge = "r8a.2xlarge" + r8a_4xlarge = "r8a.4xlarge" + r8a_8xlarge = "r8a.8xlarge" + r8a_12xlarge = "r8a.12xlarge" + r8a_16xlarge = "r8a.16xlarge" + r8a_24xlarge = "r8a.24xlarge" + r8a_48xlarge = "r8a.48xlarge" + r8a_metal_24xl = "r8a.metal-24xl" + r8a_metal_48xl = "r8a.metal-48xl" + p6_b300_48xlarge = "p6-b300.48xlarge" + c8a_medium = "c8a.medium" + c8a_large = "c8a.large" + c8a_xlarge = "c8a.xlarge" + c8a_2xlarge = "c8a.2xlarge" + c8a_4xlarge = "c8a.4xlarge" + c8a_8xlarge = "c8a.8xlarge" + c8a_12xlarge = "c8a.12xlarge" + c8a_16xlarge = "c8a.16xlarge" + c8a_24xlarge = "c8a.24xlarge" + c8a_48xlarge = "c8a.48xlarge" + c8a_metal_24xl = "c8a.metal-24xl" + c8a_metal_48xl = "c8a.metal-48xl" + c8gb_12xlarge = "c8gb.12xlarge" + c8gb_16xlarge = "c8gb.16xlarge" + c8gb_24xlarge = "c8gb.24xlarge" + c8gb_2xlarge = "c8gb.2xlarge" + c8gb_4xlarge = "c8gb.4xlarge" + c8gb_8xlarge = "c8gb.8xlarge" + c8gb_large = "c8gb.large" + c8gb_medium = "c8gb.medium" + c8gb_metal_24xl = "c8gb.metal-24xl" + c8gb_xlarge = "c8gb.xlarge" + c8gb_48xlarge = "c8gb.48xlarge" + c8gb_metal_48xl = "c8gb.metal-48xl" + m8gb_12xlarge = "m8gb.12xlarge" + m8gb_16xlarge = "m8gb.16xlarge" + m8gb_24xlarge = "m8gb.24xlarge" + m8gb_2xlarge = "m8gb.2xlarge" + m8gb_4xlarge = "m8gb.4xlarge" + m8gb_8xlarge = "m8gb.8xlarge" + m8gb_large = "m8gb.large" + m8gb_medium = "m8gb.medium" + m8gb_xlarge = "m8gb.xlarge" + m8gb_48xlarge = "m8gb.48xlarge" + m8gb_metal_24xl = "m8gb.metal-24xl" + m8gb_metal_48xl = "m8gb.metal-48xl" + m8gn_12xlarge = "m8gn.12xlarge" + m8gn_16xlarge = "m8gn.16xlarge" + m8gn_24xlarge = "m8gn.24xlarge" + m8gn_2xlarge = "m8gn.2xlarge" + m8gn_48xlarge = "m8gn.48xlarge" + m8gn_4xlarge = "m8gn.4xlarge" + m8gn_8xlarge = "m8gn.8xlarge" + m8gn_large = "m8gn.large" + m8gn_medium = "m8gn.medium" + m8gn_xlarge = "m8gn.xlarge" + m8gn_metal_24xl = "m8gn.metal-24xl" + m8gn_metal_48xl = "m8gn.metal-48xl" + x8aedz_12xlarge = "x8aedz.12xlarge" + x8aedz_24xlarge = "x8aedz.24xlarge" + x8aedz_3xlarge = "x8aedz.3xlarge" + x8aedz_6xlarge = "x8aedz.6xlarge" + x8aedz_large = "x8aedz.large" + x8aedz_metal_12xl = "x8aedz.metal-12xl" + x8aedz_metal_24xl = "x8aedz.metal-24xl" + x8aedz_xlarge = "x8aedz.xlarge" + m8azn_medium = "m8azn.medium" + m8azn_large = "m8azn.large" + m8azn_xlarge = "m8azn.xlarge" + m8azn_3xlarge = "m8azn.3xlarge" + m8azn_6xlarge = "m8azn.6xlarge" + m8azn_12xlarge = "m8azn.12xlarge" + m8azn_24xlarge = "m8azn.24xlarge" + m8azn_metal_12xl = "m8azn.metal-12xl" + m8azn_metal_24xl = "m8azn.metal-24xl" + x8i_large = "x8i.large" + x8i_xlarge = "x8i.xlarge" + x8i_2xlarge = "x8i.2xlarge" + x8i_4xlarge = "x8i.4xlarge" + x8i_8xlarge = "x8i.8xlarge" + x8i_12xlarge = "x8i.12xlarge" + x8i_16xlarge = "x8i.16xlarge" + x8i_24xlarge = "x8i.24xlarge" + x8i_32xlarge = "x8i.32xlarge" + x8i_48xlarge = "x8i.48xlarge" + x8i_64xlarge = "x8i.64xlarge" + x8i_96xlarge = "x8i.96xlarge" + x8i_metal_48xl = "x8i.metal-48xl" + x8i_metal_96xl = "x8i.metal-96xl" + mac_m4max_metal = "mac-m4max.metal" + g7e_2xlarge = "g7e.2xlarge" + g7e_4xlarge = "g7e.4xlarge" + g7e_8xlarge = "g7e.8xlarge" + g7e_12xlarge = "g7e.12xlarge" + g7e_24xlarge = "g7e.24xlarge" + g7e_48xlarge = "g7e.48xlarge" + r8id_large = "r8id.large" + r8id_xlarge = "r8id.xlarge" + r8id_2xlarge = "r8id.2xlarge" + r8id_4xlarge = "r8id.4xlarge" + r8id_8xlarge = "r8id.8xlarge" + r8id_12xlarge = "r8id.12xlarge" + r8id_16xlarge = "r8id.16xlarge" + r8id_24xlarge = "r8id.24xlarge" + r8id_32xlarge = "r8id.32xlarge" + r8id_48xlarge = "r8id.48xlarge" + r8id_96xlarge = "r8id.96xlarge" + r8id_metal_48xl = "r8id.metal-48xl" + r8id_metal_96xl = "r8id.metal-96xl" + c8id_large = "c8id.large" + c8id_xlarge = "c8id.xlarge" + c8id_2xlarge = "c8id.2xlarge" + c8id_4xlarge = "c8id.4xlarge" + c8id_8xlarge = "c8id.8xlarge" + c8id_12xlarge = "c8id.12xlarge" + c8id_16xlarge = "c8id.16xlarge" + c8id_24xlarge = "c8id.24xlarge" + c8id_32xlarge = "c8id.32xlarge" + c8id_48xlarge = "c8id.48xlarge" + c8id_96xlarge = "c8id.96xlarge" + c8id_metal_48xl = "c8id.metal-48xl" + c8id_metal_96xl = "c8id.metal-96xl" + m8id_large = "m8id.large" + m8id_xlarge = "m8id.xlarge" + m8id_2xlarge = "m8id.2xlarge" + m8id_4xlarge = "m8id.4xlarge" + m8id_8xlarge = "m8id.8xlarge" + m8id_12xlarge = "m8id.12xlarge" + m8id_16xlarge = "m8id.16xlarge" + m8id_24xlarge = "m8id.24xlarge" + m8id_32xlarge = "m8id.32xlarge" + m8id_48xlarge = "m8id.48xlarge" + m8id_96xlarge = "m8id.96xlarge" + m8id_metal_48xl = "m8id.metal-48xl" + m8id_metal_96xl = "m8id.metal-96xl" + hpc8a_96xlarge = "hpc8a.96xlarge" class InstanceTypeHypervisor(StrEnum): @@ -2487,6 +2827,19 @@ class InternetGatewayExclusionMode(StrEnum): allow_egress = "allow-egress" +class InterruptibleCapacityReservationAllocationStatus(StrEnum): + pending = "pending" + active = "active" + updating = "updating" + canceling = "canceling" + canceled = "canceled" + failed = "failed" + + +class InterruptionType(StrEnum): + adhoc = "adhoc" + + class IpAddressType(StrEnum): ipv4 = "ipv4" dualstack = "dualstack" @@ -2556,6 +2909,33 @@ class IpamOverlapStatus(StrEnum): ignored = "ignored" +class IpamPolicyManagedBy(StrEnum): + account = "account" + delegated_administrator_for_ipam = "delegated-administrator-for-ipam" + + +class IpamPolicyResourceType(StrEnum): + alb = "alb" + eip = "eip" + rds = "rds" + rnat = "rnat" + + +class IpamPolicyState(StrEnum): + create_in_progress = "create-in-progress" + create_complete = "create-complete" + create_failed = "create-failed" + modify_in_progress = "modify-in-progress" + modify_complete = "modify-complete" + modify_failed = "modify-failed" + delete_in_progress = "delete-in-progress" + delete_complete = "delete-complete" + delete_failed = "delete-failed" + isolate_in_progress = "isolate-in-progress" + isolate_complete = "isolate-complete" + restore_in_progress = "restore-in-progress" + + class IpamPoolAllocationResourceType(StrEnum): ipam_pool = "ipam-pool" vpc = "vpc" @@ -2563,10 +2943,12 @@ class IpamPoolAllocationResourceType(StrEnum): custom = "custom" subnet = "subnet" eip = "eip" + anycast_ip_list = "anycast-ip-list" class IpamPoolAwsService(StrEnum): ec2 = "ec2" + global_services = "global-services" class IpamPoolCidrFailureCode(StrEnum): @@ -2609,6 +2991,57 @@ class IpamPoolState(StrEnum): restore_in_progress = "restore-in-progress" +class IpamPrefixListResolverRuleConditionOperation(StrEnum): + equals = "equals" + not_equals = "not-equals" + subnet_of = "subnet-of" + + +class IpamPrefixListResolverRuleType(StrEnum): + static_cidr = "static-cidr" + ipam_resource_cidr = "ipam-resource-cidr" + ipam_pool_cidr = "ipam-pool-cidr" + + +class IpamPrefixListResolverState(StrEnum): + create_in_progress = "create-in-progress" + create_complete = "create-complete" + create_failed = "create-failed" + modify_in_progress = "modify-in-progress" + modify_complete = "modify-complete" + modify_failed = "modify-failed" + delete_in_progress = "delete-in-progress" + delete_complete = "delete-complete" + delete_failed = "delete-failed" + isolate_in_progress = "isolate-in-progress" + isolate_complete = "isolate-complete" + restore_in_progress = "restore-in-progress" + + +class IpamPrefixListResolverTargetState(StrEnum): + create_in_progress = "create-in-progress" + create_complete = "create-complete" + create_failed = "create-failed" + modify_in_progress = "modify-in-progress" + modify_complete = "modify-complete" + modify_failed = "modify-failed" + sync_in_progress = "sync-in-progress" + sync_complete = "sync-complete" + sync_failed = "sync-failed" + delete_in_progress = "delete-in-progress" + delete_complete = "delete-complete" + delete_failed = "delete-failed" + isolate_in_progress = "isolate-in-progress" + isolate_complete = "isolate-complete" + restore_in_progress = "restore-in-progress" + + +class IpamPrefixListResolverVersionCreationStatus(StrEnum): + pending = "pending" + success = "success" + failure = "failure" + + class IpamPublicAddressAssociationStatus(StrEnum): associated = "associated" disassociated = "disassociated" @@ -2623,6 +3056,7 @@ class IpamPublicAddressAwsService(StrEnum): site_to_site_vpn = "site-to-site-vpn" load_balancer = "load-balancer" global_accelerator = "global-accelerator" + cloudfront = "cloudfront" other = "other" @@ -2633,6 +3067,7 @@ class IpamPublicAddressType(StrEnum): amazon_owned_contig = "amazon-owned-contig" byoip = "byoip" ec2_public_ip = "ec2-public-ip" + anycast_ip_list_ip = "anycast-ip-list-ip" class IpamResourceCidrIpSource(StrEnum): @@ -2675,6 +3110,11 @@ class IpamResourceType(StrEnum): public_ipv4_pool = "public-ipv4-pool" ipv6_pool = "ipv6-pool" eni = "eni" + anycast_ip_list = "anycast-ip-list" + + +class IpamScopeExternalAuthorityType(StrEnum): + infoblox = "infoblox" class IpamScopeState(StrEnum): @@ -2884,6 +3324,7 @@ class ManagedBy(StrEnum): class MarketType(StrEnum): spot = "spot" capacity_block = "capacity-block" + interruptible_capacity_reservation = "interruptible-capacity-reservation" class MembershipType(StrEnum): @@ -2897,6 +3338,58 @@ class MetadataDefaultHttpTokensState(StrEnum): no_preference = "no-preference" +class Metric(StrEnum): + reservation_total_capacity_hrs_vcpu = "reservation-total-capacity-hrs-vcpu" + reservation_total_capacity_hrs_inst = "reservation-total-capacity-hrs-inst" + reservation_max_size_vcpu = "reservation-max-size-vcpu" + reservation_max_size_inst = "reservation-max-size-inst" + reservation_min_size_vcpu = "reservation-min-size-vcpu" + reservation_min_size_inst = "reservation-min-size-inst" + reservation_unused_total_capacity_hrs_vcpu = "reservation-unused-total-capacity-hrs-vcpu" + reservation_unused_total_capacity_hrs_inst = "reservation-unused-total-capacity-hrs-inst" + reservation_unused_total_estimated_cost = "reservation-unused-total-estimated-cost" + reservation_max_unused_size_vcpu = "reservation-max-unused-size-vcpu" + reservation_max_unused_size_inst = "reservation-max-unused-size-inst" + reservation_min_unused_size_vcpu = "reservation-min-unused-size-vcpu" + reservation_min_unused_size_inst = "reservation-min-unused-size-inst" + reservation_max_utilization = "reservation-max-utilization" + reservation_min_utilization = "reservation-min-utilization" + reservation_avg_utilization_vcpu = "reservation-avg-utilization-vcpu" + reservation_avg_utilization_inst = "reservation-avg-utilization-inst" + reservation_total_count = "reservation-total-count" + reservation_total_estimated_cost = "reservation-total-estimated-cost" + reservation_avg_future_size_vcpu = "reservation-avg-future-size-vcpu" + reservation_avg_future_size_inst = "reservation-avg-future-size-inst" + reservation_min_future_size_vcpu = "reservation-min-future-size-vcpu" + reservation_min_future_size_inst = "reservation-min-future-size-inst" + reservation_max_future_size_vcpu = "reservation-max-future-size-vcpu" + reservation_max_future_size_inst = "reservation-max-future-size-inst" + reservation_avg_committed_size_vcpu = "reservation-avg-committed-size-vcpu" + reservation_avg_committed_size_inst = "reservation-avg-committed-size-inst" + reservation_max_committed_size_vcpu = "reservation-max-committed-size-vcpu" + reservation_max_committed_size_inst = "reservation-max-committed-size-inst" + reservation_min_committed_size_vcpu = "reservation-min-committed-size-vcpu" + reservation_min_committed_size_inst = "reservation-min-committed-size-inst" + reserved_total_usage_hrs_vcpu = "reserved-total-usage-hrs-vcpu" + reserved_total_usage_hrs_inst = "reserved-total-usage-hrs-inst" + reserved_total_estimated_cost = "reserved-total-estimated-cost" + unreserved_total_usage_hrs_vcpu = "unreserved-total-usage-hrs-vcpu" + unreserved_total_usage_hrs_inst = "unreserved-total-usage-hrs-inst" + unreserved_total_estimated_cost = "unreserved-total-estimated-cost" + spot_total_usage_hrs_vcpu = "spot-total-usage-hrs-vcpu" + spot_total_usage_hrs_inst = "spot-total-usage-hrs-inst" + spot_total_estimated_cost = "spot-total-estimated-cost" + spot_avg_run_time_before_interruption_inst = "spot-avg-run-time-before-interruption-inst" + spot_max_run_time_before_interruption_inst = "spot-max-run-time-before-interruption-inst" + spot_min_run_time_before_interruption_inst = "spot-min-run-time-before-interruption-inst" + spot_total_interruptions_inst = "spot-total-interruptions-inst" + spot_total_interruptions_vcpu = "spot-total-interruptions-vcpu" + spot_total_count_inst = "spot-total-count-inst" + spot_total_count_vcpu = "spot-total-count-vcpu" + spot_interruption_rate_inst = "spot-interruption-rate-inst" + spot_interruption_rate_vcpu = "spot-interruption-rate-vcpu" + + class MetricType(StrEnum): aggregate_latency = "aggregate-latency" @@ -2932,6 +3425,25 @@ class NatGatewayAddressStatus(StrEnum): failed = "failed" +class NatGatewayApplianceModifyState(StrEnum): + modifying = "modifying" + completed = "completed" + failed = "failed" + + +class NatGatewayApplianceState(StrEnum): + attaching = "attaching" + attached = "attached" + detaching = "detaching" + detached = "detached" + attach_failed = "attach-failed" + detach_failed = "detach-failed" + + +class NatGatewayApplianceType(StrEnum): + network_firewall_proxy = "network-firewall-proxy" + + class NatGatewayState(StrEnum): pending = "pending" failed = "failed" @@ -2940,6 +3452,11 @@ class NatGatewayState(StrEnum): deleted = "deleted" +class NestedVirtualizationSpecification(StrEnum): + enabled = "enabled" + disabled = "disabled" + + class NetworkInterfaceAttribute(StrEnum): description = "description" groupSet = "groupSet" @@ -3025,6 +3542,11 @@ class OperationType(StrEnum): remove = "remove" +class OutputFormat(StrEnum): + csv = "csv" + parquet = "parquet" + + class PartitionLoadFrequency(StrEnum): none = "none" daily = "daily" @@ -3181,13 +3703,30 @@ class ReportStatusType(StrEnum): impaired = "impaired" +class ReservationEndDateType(StrEnum): + limited = "limited" + unlimited = "unlimited" + + class ReservationState(StrEnum): + active = "active" + expired = "expired" + cancelled = "cancelled" + scheduled = "scheduled" + pending = "pending" + failed = "failed" + delayed = "delayed" + unsupported = "unsupported" payment_pending = "payment-pending" payment_failed = "payment-failed" - active = "active" retired = "retired" +class ReservationType(StrEnum): + capacity_block = "capacity-block" + odcr = "odcr" + + class ReservedInstanceState(StrEnum): payment_pending = "payment-pending" active = "active" @@ -3273,6 +3812,7 @@ class ResourceType(StrEnum): transit_gateway_connect_peer = "transit-gateway-connect-peer" transit_gateway_multicast_domain = "transit-gateway-multicast-domain" transit_gateway_policy_table = "transit-gateway-policy-table" + transit_gateway_metering_policy = "transit-gateway-metering-policy" transit_gateway_route_table = "transit-gateway-route-table" transit_gateway_route_table_announcement = "transit-gateway-route-table-announcement" volume = "volume" @@ -3295,6 +3835,7 @@ class ResourceType(StrEnum): verified_access_trust_provider = "verified-access-trust-provider" vpn_connection_device_type = "vpn-connection-device-type" vpc_block_public_access_exclusion = "vpc-block-public-access-exclusion" + vpc_encryption_control = "vpc-encryption-control" route_server = "route-server" route_server_endpoint = "route-server-endpoint" route_server_peer = "route-server-peer" @@ -3305,6 +3846,14 @@ class ResourceType(StrEnum): ipam_external_resource_verification_token = "ipam-external-resource-verification-token" capacity_block = "capacity-block" mac_modification_task = "mac-modification-task" + ipam_prefix_list_resolver = "ipam-prefix-list-resolver" + ipam_policy = "ipam-policy" + ipam_prefix_list_resolver_target = "ipam-prefix-list-resolver-target" + secondary_interface = "secondary-interface" + secondary_network = "secondary-network" + secondary_subnet = "secondary-subnet" + capacity_manager_data_export = "capacity-manager-data-export" + vpn_concentrator = "vpn-concentrator" class RootDeviceType(StrEnum): @@ -3423,6 +3972,59 @@ class SSEType(StrEnum): none = "none" +class Schedule(StrEnum): + hourly = "hourly" + + +class SecondaryInterfaceStatus(StrEnum): + available = "available" + in_use = "in-use" + + +class SecondaryInterfaceType(StrEnum): + secondary = "secondary" + + +class SecondaryNetworkCidrBlockAssociationState(StrEnum): + associating = "associating" + associated = "associated" + association_failed = "association-failed" + disassociating = "disassociating" + disassociated = "disassociated" + disassociation_failed = "disassociation-failed" + + +class SecondaryNetworkState(StrEnum): + create_in_progress = "create-in-progress" + create_complete = "create-complete" + create_failed = "create-failed" + delete_in_progress = "delete-in-progress" + delete_complete = "delete-complete" + delete_failed = "delete-failed" + + +class SecondaryNetworkType(StrEnum): + rdma = "rdma" + + +class SecondarySubnetCidrBlockAssociationState(StrEnum): + associating = "associating" + associated = "associated" + association_failed = "association-failed" + disassociating = "disassociating" + disassociated = "disassociated" + disassociation_failed = "disassociation-failed" + + +class SecondarySubnetState(StrEnum): + create_in_progress = "create-in-progress" + create_complete = "create-complete" + create_failed = "create-failed" + delete_in_progress = "delete-in-progress" + delete_complete = "delete-complete" + delete_failed = "delete-failed" + + class SecurityGroupReferencingSupportValue(StrEnum): enable = "enable" disable = "disable" @@ -3458,6 +4060,7 @@ class ServiceManaged(StrEnum): alb = "alb" nlb = "nlb" rnat = "rnat" + rds = "rds" class ServiceState(StrEnum): @@ -3544,6 +4147,11 @@ class SpreadLevel(StrEnum): rack = "rack" +class SqlServerLicenseUsage(StrEnum): + full = "full" + waived = "waived" + + class State(StrEnum): PendingAcceptance = "PendingAcceptance" Pending = "Pending" @@ -3619,6 +4227,7 @@ class SummaryStatus(StrEnum): class SupportedAdditionalProcessorFeature(StrEnum): amd_sev_snp = "amd-sev-snp" + nested_virtualization = "nested-virtualization" class TargetCapacityUnitType(StrEnum): @@ -3723,6 +4332,7 @@ class TransitGatewayAssociationState(StrEnum): class TransitGatewayAttachmentResourceType(StrEnum): vpc = "vpc" vpn = "vpn" + vpn_concentrator = "vpn-concentrator" direct_connect_gateway = "direct-connect-gateway" connect = "connect" peering = "peering" @@ -3753,6 +4363,25 @@ class TransitGatewayConnectPeerState(StrEnum): deleted = "deleted" +class TransitGatewayMeteringPayerType(StrEnum): + source_attachment_owner = "source-attachment-owner" + destination_attachment_owner = "destination-attachment-owner" + transit_gateway_owner = "transit-gateway-owner" + + +class TransitGatewayMeteringPolicyEntryState(StrEnum): + available = "available" + deleted = "deleted" + + +class TransitGatewayMeteringPolicyState(StrEnum): + available = "available" + deleted = "deleted" + pending = "pending" + modifying = "modifying" + deleting = "deleting" + + class TransitGatewayMulitcastDomainAssociationState(StrEnum): pendingAcceptance = "pendingAcceptance" associating = "associating" @@ -4011,6 +4640,11 @@ class VpcEncryptionControlExclusionState(StrEnum): disabled = "disabled" +class VpcEncryptionControlExclusionStateInput(StrEnum): + enable = "enable" + disable = "disable" + + class VpcEncryptionControlMode(StrEnum): monitor = "monitor" enforce = "enforce" @@ -4057,6 +4691,10 @@ class VpcTenancy(StrEnum): default = "default" +class VpnConcentratorType(StrEnum): + ipsec_1 = "ipsec.1" + + class VpnEcmpSupportValue(StrEnum): enable = "enable" disable = "disable" @@ -4077,6 +4715,11 @@ class VpnStaticRouteSource(StrEnum): Static = "Static" +class VpnTunnelBandwidth(StrEnum): + standard = "standard" + large = "large" + + class VpnTunnelProvisioningStatus(StrEnum): available = "available" pending = "pending" @@ -4099,851 +4742,852 @@ class scope(StrEnum): class AcceleratorCount(TypedDict, total=False): - Min: Optional[Integer] - Max: Optional[Integer] + Min: Integer | None + Max: Integer | None class AcceleratorCountRequest(TypedDict, total=False): - Min: Optional[Integer] - Max: Optional[Integer] + Min: Integer | None + Max: Integer | None -AcceleratorManufacturerSet = List[AcceleratorManufacturer] -AcceleratorNameSet = List[AcceleratorName] +AcceleratorManufacturerSet = list[AcceleratorManufacturer] +AcceleratorNameSet = list[AcceleratorName] class AcceleratorTotalMemoryMiB(TypedDict, total=False): - Min: Optional[Integer] - Max: Optional[Integer] + Min: Integer | None + Max: Integer | None class AcceleratorTotalMemoryMiBRequest(TypedDict, total=False): - Min: Optional[Integer] - Max: Optional[Integer] + Min: Integer | None + Max: Integer | None -AcceleratorTypeSet = List[AcceleratorType] +AcceleratorTypeSet = list[AcceleratorType] class Tag(TypedDict, total=False): - Key: Optional[String] - Value: Optional[String] + Key: String | None + Value: String | None -TagList = List[Tag] +TagList = list[Tag] class TagSpecification(TypedDict, total=False): - ResourceType: Optional[ResourceType] - Tags: Optional[TagList] + ResourceType: ResourceType | None + Tags: TagList | None -TagSpecificationList = List[TagSpecification] +TagSpecificationList = list[TagSpecification] class AcceptAddressTransferRequest(ServiceRequest): Address: String - TagSpecifications: Optional[TagSpecificationList] - DryRun: Optional[Boolean] + TagSpecifications: TagSpecificationList | None + DryRun: Boolean | None MillisecondDateTime = datetime class AddressTransfer(TypedDict, total=False): - PublicIp: Optional[String] - AllocationId: Optional[String] - TransferAccountId: Optional[String] - TransferOfferExpirationTimestamp: Optional[MillisecondDateTime] - TransferOfferAcceptedTimestamp: Optional[MillisecondDateTime] - AddressTransferStatus: Optional[AddressTransferStatus] + PublicIp: String | None + AllocationId: String | None + TransferAccountId: String | None + TransferOfferExpirationTimestamp: MillisecondDateTime | None + TransferOfferAcceptedTimestamp: MillisecondDateTime | None + AddressTransferStatus: AddressTransferStatus | None class AcceptAddressTransferResult(TypedDict, total=False): - AddressTransfer: Optional[AddressTransfer] + AddressTransfer: AddressTransfer | None class AcceptCapacityReservationBillingOwnershipRequest(ServiceRequest): - DryRun: Optional[Boolean] + DryRun: Boolean | None CapacityReservationId: CapacityReservationId class AcceptCapacityReservationBillingOwnershipResult(TypedDict, total=False): - Return: Optional[Boolean] + Return: Boolean | None class TargetConfigurationRequest(TypedDict, total=False): - InstanceCount: Optional[Integer] + InstanceCount: Integer | None OfferingId: ReservedInstancesOfferingId -TargetConfigurationRequestSet = List[TargetConfigurationRequest] -ReservedInstanceIdSet = List[ReservationId] +TargetConfigurationRequestSet = list[TargetConfigurationRequest] +ReservedInstanceIdSet = list[ReservationId] class AcceptReservedInstancesExchangeQuoteRequest(ServiceRequest): - DryRun: Optional[Boolean] + DryRun: Boolean | None ReservedInstanceIds: ReservedInstanceIdSet - TargetConfigurations: Optional[TargetConfigurationRequestSet] + TargetConfigurations: TargetConfigurationRequestSet | None class AcceptReservedInstancesExchangeQuoteResult(TypedDict, total=False): - ExchangeId: Optional[String] + ExchangeId: String | None -ValueStringList = List[String] +ValueStringList = list[String] class AcceptTransitGatewayMulticastDomainAssociationsRequest(ServiceRequest): - TransitGatewayMulticastDomainId: Optional[TransitGatewayMulticastDomainId] - TransitGatewayAttachmentId: Optional[TransitGatewayAttachmentId] - SubnetIds: Optional[ValueStringList] - DryRun: Optional[Boolean] + TransitGatewayMulticastDomainId: TransitGatewayMulticastDomainId | None + TransitGatewayAttachmentId: TransitGatewayAttachmentId | None + SubnetIds: ValueStringList | None + DryRun: Boolean | None class SubnetAssociation(TypedDict, total=False): - SubnetId: Optional[String] - State: Optional[TransitGatewayMulitcastDomainAssociationState] + SubnetId: String | None + State: TransitGatewayMulitcastDomainAssociationState | None -SubnetAssociationList = List[SubnetAssociation] +SubnetAssociationList = list[SubnetAssociation] class TransitGatewayMulticastDomainAssociations(TypedDict, total=False): - TransitGatewayMulticastDomainId: Optional[String] - TransitGatewayAttachmentId: Optional[String] - ResourceId: Optional[String] - ResourceType: Optional[TransitGatewayAttachmentResourceType] - ResourceOwnerId: Optional[String] - Subnets: Optional[SubnetAssociationList] + TransitGatewayMulticastDomainId: String | None + TransitGatewayAttachmentId: String | None + ResourceId: String | None + ResourceType: TransitGatewayAttachmentResourceType | None + ResourceOwnerId: String | None + Subnets: SubnetAssociationList | None class AcceptTransitGatewayMulticastDomainAssociationsResult(TypedDict, total=False): - Associations: Optional[TransitGatewayMulticastDomainAssociations] + Associations: TransitGatewayMulticastDomainAssociations | None class AcceptTransitGatewayPeeringAttachmentRequest(ServiceRequest): TransitGatewayAttachmentId: TransitGatewayAttachmentId - DryRun: Optional[Boolean] + DryRun: Boolean | None DateTime = datetime class PeeringAttachmentStatus(TypedDict, total=False): - Code: Optional[String] - Message: Optional[String] + Code: String | None + Message: String | None class TransitGatewayPeeringAttachmentOptions(TypedDict, total=False): - DynamicRouting: Optional[DynamicRoutingValue] + DynamicRouting: DynamicRoutingValue | None class PeeringTgwInfo(TypedDict, total=False): - TransitGatewayId: Optional[String] - CoreNetworkId: Optional[String] - OwnerId: Optional[String] - Region: Optional[String] + TransitGatewayId: String | None + CoreNetworkId: String | None + OwnerId: String | None + Region: String | None class TransitGatewayPeeringAttachment(TypedDict, total=False): - TransitGatewayAttachmentId: Optional[String] - AccepterTransitGatewayAttachmentId: Optional[String] - RequesterTgwInfo: Optional[PeeringTgwInfo] - AccepterTgwInfo: Optional[PeeringTgwInfo] - Options: Optional[TransitGatewayPeeringAttachmentOptions] - Status: Optional[PeeringAttachmentStatus] - State: Optional[TransitGatewayAttachmentState] - CreationTime: Optional[DateTime] - Tags: Optional[TagList] + TransitGatewayAttachmentId: String | None + AccepterTransitGatewayAttachmentId: String | None + RequesterTgwInfo: PeeringTgwInfo | None + AccepterTgwInfo: PeeringTgwInfo | None + Options: TransitGatewayPeeringAttachmentOptions | None + Status: PeeringAttachmentStatus | None + State: TransitGatewayAttachmentState | None + CreationTime: DateTime | None + Tags: TagList | None class AcceptTransitGatewayPeeringAttachmentResult(TypedDict, total=False): - TransitGatewayPeeringAttachment: Optional[TransitGatewayPeeringAttachment] + TransitGatewayPeeringAttachment: TransitGatewayPeeringAttachment | None class AcceptTransitGatewayVpcAttachmentRequest(ServiceRequest): TransitGatewayAttachmentId: TransitGatewayAttachmentId - DryRun: Optional[Boolean] + DryRun: Boolean | None class TransitGatewayVpcAttachmentOptions(TypedDict, total=False): - DnsSupport: Optional[DnsSupportValue] - SecurityGroupReferencingSupport: Optional[SecurityGroupReferencingSupportValue] - Ipv6Support: Optional[Ipv6SupportValue] - ApplianceModeSupport: Optional[ApplianceModeSupportValue] + DnsSupport: DnsSupportValue | None + SecurityGroupReferencingSupport: SecurityGroupReferencingSupportValue | None + Ipv6Support: Ipv6SupportValue | None + ApplianceModeSupport: ApplianceModeSupportValue | None class TransitGatewayVpcAttachment(TypedDict, total=False): - TransitGatewayAttachmentId: Optional[String] - TransitGatewayId: Optional[String] - VpcId: Optional[String] - VpcOwnerId: Optional[String] - State: Optional[TransitGatewayAttachmentState] - SubnetIds: Optional[ValueStringList] - CreationTime: Optional[DateTime] - Options: Optional[TransitGatewayVpcAttachmentOptions] - Tags: Optional[TagList] + TransitGatewayAttachmentId: String | None + TransitGatewayId: String | None + VpcId: String | None + VpcOwnerId: String | None + State: TransitGatewayAttachmentState | None + SubnetIds: ValueStringList | None + CreationTime: DateTime | None + Options: TransitGatewayVpcAttachmentOptions | None + Tags: TagList | None class AcceptTransitGatewayVpcAttachmentResult(TypedDict, total=False): - TransitGatewayVpcAttachment: Optional[TransitGatewayVpcAttachment] + TransitGatewayVpcAttachment: TransitGatewayVpcAttachment | None -VpcEndpointIdList = List[VpcEndpointId] +VpcEndpointIdList = list[VpcEndpointId] class AcceptVpcEndpointConnectionsRequest(ServiceRequest): - DryRun: Optional[Boolean] + DryRun: Boolean | None ServiceId: VpcEndpointServiceId VpcEndpointIds: VpcEndpointIdList class UnsuccessfulItemError(TypedDict, total=False): - Code: Optional[String] - Message: Optional[String] + Code: String | None + Message: String | None class UnsuccessfulItem(TypedDict, total=False): - Error: Optional[UnsuccessfulItemError] - ResourceId: Optional[String] + Error: UnsuccessfulItemError | None + ResourceId: String | None -UnsuccessfulItemSet = List[UnsuccessfulItem] +UnsuccessfulItemSet = list[UnsuccessfulItem] class AcceptVpcEndpointConnectionsResult(TypedDict, total=False): - Unsuccessful: Optional[UnsuccessfulItemSet] + Unsuccessful: UnsuccessfulItemSet | None class AcceptVpcPeeringConnectionRequest(ServiceRequest): - DryRun: Optional[Boolean] + DryRun: Boolean | None VpcPeeringConnectionId: VpcPeeringConnectionIdWithResolver class VpcPeeringConnectionStateReason(TypedDict, total=False): - Code: Optional[VpcPeeringConnectionStateReasonCode] - Message: Optional[String] + Code: VpcPeeringConnectionStateReasonCode | None + Message: String | None class VpcPeeringConnectionOptionsDescription(TypedDict, total=False): - AllowDnsResolutionFromRemoteVpc: Optional[Boolean] - AllowEgressFromLocalClassicLinkToRemoteVpc: Optional[Boolean] - AllowEgressFromLocalVpcToRemoteClassicLink: Optional[Boolean] + AllowDnsResolutionFromRemoteVpc: Boolean | None + AllowEgressFromLocalClassicLinkToRemoteVpc: Boolean | None + AllowEgressFromLocalVpcToRemoteClassicLink: Boolean | None class CidrBlock(TypedDict, total=False): - CidrBlock: Optional[String] + CidrBlock: String | None -CidrBlockSet = List[CidrBlock] +CidrBlockSet = list[CidrBlock] class Ipv6CidrBlock(TypedDict, total=False): - Ipv6CidrBlock: Optional[String] + Ipv6CidrBlock: String | None -Ipv6CidrBlockSet = List[Ipv6CidrBlock] +Ipv6CidrBlockSet = list[Ipv6CidrBlock] class VpcPeeringConnectionVpcInfo(TypedDict, total=False): - CidrBlock: Optional[String] - Ipv6CidrBlockSet: Optional[Ipv6CidrBlockSet] - CidrBlockSet: Optional[CidrBlockSet] - OwnerId: Optional[String] - PeeringOptions: Optional[VpcPeeringConnectionOptionsDescription] - VpcId: Optional[String] - Region: Optional[String] + CidrBlock: String | None + Ipv6CidrBlockSet: Ipv6CidrBlockSet | None + CidrBlockSet: CidrBlockSet | None + OwnerId: String | None + PeeringOptions: VpcPeeringConnectionOptionsDescription | None + VpcId: String | None + Region: String | None class VpcPeeringConnection(TypedDict, total=False): - AccepterVpcInfo: Optional[VpcPeeringConnectionVpcInfo] - ExpirationTime: Optional[DateTime] - RequesterVpcInfo: Optional[VpcPeeringConnectionVpcInfo] - Status: Optional[VpcPeeringConnectionStateReason] - Tags: Optional[TagList] - VpcPeeringConnectionId: Optional[String] + AccepterVpcInfo: VpcPeeringConnectionVpcInfo | None + ExpirationTime: DateTime | None + RequesterVpcInfo: VpcPeeringConnectionVpcInfo | None + Status: VpcPeeringConnectionStateReason | None + Tags: TagList | None + VpcPeeringConnectionId: String | None class AcceptVpcPeeringConnectionResult(TypedDict, total=False): - VpcPeeringConnection: Optional[VpcPeeringConnection] + VpcPeeringConnection: VpcPeeringConnection | None class PortRange(TypedDict, total=False): - From: Optional[Integer] - To: Optional[Integer] + From: Integer | None + To: Integer | None -PortRangeList = List[PortRange] +PortRangeList = list[PortRange] class FirewallStatefulRule(TypedDict, total=False): - RuleGroupArn: Optional[ResourceArn] - Sources: Optional[ValueStringList] - Destinations: Optional[ValueStringList] - SourcePorts: Optional[PortRangeList] - DestinationPorts: Optional[PortRangeList] - Protocol: Optional[String] - RuleAction: Optional[String] - Direction: Optional[String] + RuleGroupArn: ResourceArn | None + Sources: ValueStringList | None + Destinations: ValueStringList | None + SourcePorts: PortRangeList | None + DestinationPorts: PortRangeList | None + Protocol: String | None + RuleAction: String | None + Direction: String | None -ProtocolIntList = List[ProtocolInt] +ProtocolIntList = list[ProtocolInt] class FirewallStatelessRule(TypedDict, total=False): - RuleGroupArn: Optional[ResourceArn] - Sources: Optional[ValueStringList] - Destinations: Optional[ValueStringList] - SourcePorts: Optional[PortRangeList] - DestinationPorts: Optional[PortRangeList] - Protocols: Optional[ProtocolIntList] - RuleAction: Optional[String] - Priority: Optional[Priority] + RuleGroupArn: ResourceArn | None + Sources: ValueStringList | None + Destinations: ValueStringList | None + SourcePorts: PortRangeList | None + DestinationPorts: PortRangeList | None + Protocols: ProtocolIntList | None + RuleAction: String | None + Priority: Priority | None class AnalysisComponent(TypedDict, total=False): - Id: Optional[String] - Arn: Optional[String] - Name: Optional[String] + Id: String | None + Arn: String | None + Name: String | None class TransitGatewayRouteTableRoute(TypedDict, total=False): - DestinationCidr: Optional[String] - State: Optional[String] - RouteOrigin: Optional[String] - PrefixListId: Optional[String] - AttachmentId: Optional[String] - ResourceId: Optional[String] - ResourceType: Optional[String] + DestinationCidr: String | None + State: String | None + RouteOrigin: String | None + PrefixListId: String | None + AttachmentId: String | None + ResourceId: String | None + ResourceType: String | None -AnalysisComponentList = List[AnalysisComponent] +AnalysisComponentList = list[AnalysisComponent] class AnalysisSecurityGroupRule(TypedDict, total=False): - Cidr: Optional[String] - Direction: Optional[String] - SecurityGroupId: Optional[String] - PortRange: Optional[PortRange] - PrefixListId: Optional[String] - Protocol: Optional[String] + Cidr: String | None + Direction: String | None + SecurityGroupId: String | None + PortRange: PortRange | None + PrefixListId: String | None + Protocol: String | None class AnalysisRouteTableRoute(TypedDict, total=False): - DestinationCidr: Optional[String] - DestinationPrefixListId: Optional[String] - EgressOnlyInternetGatewayId: Optional[String] - GatewayId: Optional[String] - InstanceId: Optional[String] - NatGatewayId: Optional[String] - NetworkInterfaceId: Optional[String] - Origin: Optional[String] - TransitGatewayId: Optional[String] - VpcPeeringConnectionId: Optional[String] - State: Optional[String] - CarrierGatewayId: Optional[String] - CoreNetworkArn: Optional[ResourceArn] - LocalGatewayId: Optional[String] + DestinationCidr: String | None + DestinationPrefixListId: String | None + EgressOnlyInternetGatewayId: String | None + GatewayId: String | None + InstanceId: String | None + NatGatewayId: String | None + NetworkInterfaceId: String | None + Origin: String | None + TransitGatewayId: String | None + VpcPeeringConnectionId: String | None + State: String | None + CarrierGatewayId: String | None + CoreNetworkArn: ResourceArn | None + LocalGatewayId: String | None -StringList = List[String] +StringList = list[String] class AnalysisLoadBalancerTarget(TypedDict, total=False): - Address: Optional[IpAddress] - AvailabilityZone: Optional[String] - AvailabilityZoneId: Optional[String] - Instance: Optional[AnalysisComponent] - Port: Optional[Port] + Address: IpAddress | None + AvailabilityZone: String | None + AvailabilityZoneId: String | None + Instance: AnalysisComponent | None + Port: Port | None class AnalysisLoadBalancerListener(TypedDict, total=False): - LoadBalancerPort: Optional[Port] - InstancePort: Optional[Port] + LoadBalancerPort: Port | None + InstancePort: Port | None -IpAddressList = List[IpAddress] +IpAddressList = list[IpAddress] class AnalysisAclRule(TypedDict, total=False): - Cidr: Optional[String] - Egress: Optional[Boolean] - PortRange: Optional[PortRange] - Protocol: Optional[String] - RuleAction: Optional[String] - RuleNumber: Optional[Integer] + Cidr: String | None + Egress: Boolean | None + PortRange: PortRange | None + Protocol: String | None + RuleAction: String | None + RuleNumber: Integer | None class Explanation(TypedDict, total=False): - Acl: Optional[AnalysisComponent] - AclRule: Optional[AnalysisAclRule] - Address: Optional[IpAddress] - Addresses: Optional[IpAddressList] - AttachedTo: Optional[AnalysisComponent] - AvailabilityZones: Optional[ValueStringList] - AvailabilityZoneIds: Optional[ValueStringList] - Cidrs: Optional[ValueStringList] - Component: Optional[AnalysisComponent] - CustomerGateway: Optional[AnalysisComponent] - Destination: Optional[AnalysisComponent] - DestinationVpc: Optional[AnalysisComponent] - Direction: Optional[String] - ExplanationCode: Optional[String] - IngressRouteTable: Optional[AnalysisComponent] - InternetGateway: Optional[AnalysisComponent] - LoadBalancerArn: Optional[ResourceArn] - ClassicLoadBalancerListener: Optional[AnalysisLoadBalancerListener] - LoadBalancerListenerPort: Optional[Port] - LoadBalancerTarget: Optional[AnalysisLoadBalancerTarget] - LoadBalancerTargetGroup: Optional[AnalysisComponent] - LoadBalancerTargetGroups: Optional[AnalysisComponentList] - LoadBalancerTargetPort: Optional[Port] - ElasticLoadBalancerListener: Optional[AnalysisComponent] - MissingComponent: Optional[String] - NatGateway: Optional[AnalysisComponent] - NetworkInterface: Optional[AnalysisComponent] - PacketField: Optional[String] - VpcPeeringConnection: Optional[AnalysisComponent] - Port: Optional[Port] - PortRanges: Optional[PortRangeList] - PrefixList: Optional[AnalysisComponent] - Protocols: Optional[StringList] - RouteTableRoute: Optional[AnalysisRouteTableRoute] - RouteTable: Optional[AnalysisComponent] - SecurityGroup: Optional[AnalysisComponent] - SecurityGroupRule: Optional[AnalysisSecurityGroupRule] - SecurityGroups: Optional[AnalysisComponentList] - SourceVpc: Optional[AnalysisComponent] - State: Optional[String] - Subnet: Optional[AnalysisComponent] - SubnetRouteTable: Optional[AnalysisComponent] - Vpc: Optional[AnalysisComponent] - VpcEndpoint: Optional[AnalysisComponent] - VpnConnection: Optional[AnalysisComponent] - VpnGateway: Optional[AnalysisComponent] - TransitGateway: Optional[AnalysisComponent] - TransitGatewayRouteTable: Optional[AnalysisComponent] - TransitGatewayRouteTableRoute: Optional[TransitGatewayRouteTableRoute] - TransitGatewayAttachment: Optional[AnalysisComponent] - ComponentAccount: Optional[ComponentAccount] - ComponentRegion: Optional[ComponentRegion] - FirewallStatelessRule: Optional[FirewallStatelessRule] - FirewallStatefulRule: Optional[FirewallStatefulRule] - - -ExplanationList = List[Explanation] + Acl: AnalysisComponent | None + AclRule: AnalysisAclRule | None + Address: IpAddress | None + Addresses: IpAddressList | None + AttachedTo: AnalysisComponent | None + AvailabilityZones: ValueStringList | None + AvailabilityZoneIds: ValueStringList | None + Cidrs: ValueStringList | None + Component: AnalysisComponent | None + CustomerGateway: AnalysisComponent | None + Destination: AnalysisComponent | None + DestinationVpc: AnalysisComponent | None + Direction: String | None + ExplanationCode: String | None + IngressRouteTable: AnalysisComponent | None + InternetGateway: AnalysisComponent | None + LoadBalancerArn: ResourceArn | None + ClassicLoadBalancerListener: AnalysisLoadBalancerListener | None + LoadBalancerListenerPort: Port | None + LoadBalancerTarget: AnalysisLoadBalancerTarget | None + LoadBalancerTargetGroup: AnalysisComponent | None + LoadBalancerTargetGroups: AnalysisComponentList | None + LoadBalancerTargetPort: Port | None + ElasticLoadBalancerListener: AnalysisComponent | None + MissingComponent: String | None + NatGateway: AnalysisComponent | None + NetworkInterface: AnalysisComponent | None + PacketField: String | None + VpcPeeringConnection: AnalysisComponent | None + Port: Port | None + PortRanges: PortRangeList | None + PrefixList: AnalysisComponent | None + Protocols: StringList | None + RouteTableRoute: AnalysisRouteTableRoute | None + RouteTable: AnalysisComponent | None + SecurityGroup: AnalysisComponent | None + SecurityGroupRule: AnalysisSecurityGroupRule | None + SecurityGroups: AnalysisComponentList | None + SourceVpc: AnalysisComponent | None + State: String | None + Subnet: AnalysisComponent | None + SubnetRouteTable: AnalysisComponent | None + Vpc: AnalysisComponent | None + VpcEndpoint: AnalysisComponent | None + VpnConnection: AnalysisComponent | None + VpnGateway: AnalysisComponent | None + TransitGateway: AnalysisComponent | None + TransitGatewayRouteTable: AnalysisComponent | None + TransitGatewayRouteTableRoute: TransitGatewayRouteTableRoute | None + TransitGatewayAttachment: AnalysisComponent | None + ComponentAccount: ComponentAccount | None + ComponentRegion: ComponentRegion | None + FirewallStatelessRule: FirewallStatelessRule | None + FirewallStatefulRule: FirewallStatefulRule | None + + +ExplanationList = list[Explanation] class RuleOption(TypedDict, total=False): - Keyword: Optional[String] - Settings: Optional[StringList] + Keyword: String | None + Settings: StringList | None -RuleOptionList = List[RuleOption] +RuleOptionList = list[RuleOption] class RuleGroupRuleOptionsPair(TypedDict, total=False): - RuleGroupArn: Optional[ResourceArn] - RuleOptions: Optional[RuleOptionList] + RuleGroupArn: ResourceArn | None + RuleOptions: RuleOptionList | None -RuleGroupRuleOptionsPairList = List[RuleGroupRuleOptionsPair] +RuleGroupRuleOptionsPairList = list[RuleGroupRuleOptionsPair] class RuleGroupTypePair(TypedDict, total=False): - RuleGroupArn: Optional[ResourceArn] - RuleGroupType: Optional[String] + RuleGroupArn: ResourceArn | None + RuleGroupType: String | None -RuleGroupTypePairList = List[RuleGroupTypePair] +RuleGroupTypePairList = list[RuleGroupTypePair] class AdditionalDetail(TypedDict, total=False): - AdditionalDetailType: Optional[String] - Component: Optional[AnalysisComponent] - VpcEndpointService: Optional[AnalysisComponent] - RuleOptions: Optional[RuleOptionList] - RuleGroupTypePairs: Optional[RuleGroupTypePairList] - RuleGroupRuleOptionsPairs: Optional[RuleGroupRuleOptionsPairList] - ServiceName: Optional[String] - LoadBalancers: Optional[AnalysisComponentList] + AdditionalDetailType: String | None + Component: AnalysisComponent | None + VpcEndpointService: AnalysisComponent | None + RuleOptions: RuleOptionList | None + RuleGroupTypePairs: RuleGroupTypePairList | None + RuleGroupRuleOptionsPairs: RuleGroupRuleOptionsPairList | None + ServiceName: String | None + LoadBalancers: AnalysisComponentList | None -AdditionalDetailList = List[AdditionalDetail] +AdditionalDetailList = list[AdditionalDetail] class AnalysisPacketHeader(TypedDict, total=False): - DestinationAddresses: Optional[IpAddressList] - DestinationPortRanges: Optional[PortRangeList] - Protocol: Optional[String] - SourceAddresses: Optional[IpAddressList] - SourcePortRanges: Optional[PortRangeList] + DestinationAddresses: IpAddressList | None + DestinationPortRanges: PortRangeList | None + Protocol: String | None + SourceAddresses: IpAddressList | None + SourcePortRanges: PortRangeList | None class PathComponent(TypedDict, total=False): - SequenceNumber: Optional[Integer] - AclRule: Optional[AnalysisAclRule] - AttachedTo: Optional[AnalysisComponent] - Component: Optional[AnalysisComponent] - DestinationVpc: Optional[AnalysisComponent] - OutboundHeader: Optional[AnalysisPacketHeader] - InboundHeader: Optional[AnalysisPacketHeader] - RouteTableRoute: Optional[AnalysisRouteTableRoute] - SecurityGroupRule: Optional[AnalysisSecurityGroupRule] - SourceVpc: Optional[AnalysisComponent] - Subnet: Optional[AnalysisComponent] - Vpc: Optional[AnalysisComponent] - AdditionalDetails: Optional[AdditionalDetailList] - TransitGateway: Optional[AnalysisComponent] - TransitGatewayRouteTableRoute: Optional[TransitGatewayRouteTableRoute] - Explanations: Optional[ExplanationList] - ElasticLoadBalancerListener: Optional[AnalysisComponent] - FirewallStatelessRule: Optional[FirewallStatelessRule] - FirewallStatefulRule: Optional[FirewallStatefulRule] - ServiceName: Optional[String] - - -PathComponentList = List[PathComponent] + SequenceNumber: Integer | None + AclRule: AnalysisAclRule | None + AttachedTo: AnalysisComponent | None + Component: AnalysisComponent | None + DestinationVpc: AnalysisComponent | None + OutboundHeader: AnalysisPacketHeader | None + InboundHeader: AnalysisPacketHeader | None + RouteTableRoute: AnalysisRouteTableRoute | None + SecurityGroupRule: AnalysisSecurityGroupRule | None + SourceVpc: AnalysisComponent | None + Subnet: AnalysisComponent | None + Vpc: AnalysisComponent | None + AdditionalDetails: AdditionalDetailList | None + TransitGateway: AnalysisComponent | None + TransitGatewayRouteTableRoute: TransitGatewayRouteTableRoute | None + Explanations: ExplanationList | None + ElasticLoadBalancerListener: AnalysisComponent | None + FirewallStatelessRule: FirewallStatelessRule | None + FirewallStatefulRule: FirewallStatefulRule | None + ServiceName: String | None + + +PathComponentList = list[PathComponent] class AccessScopeAnalysisFinding(TypedDict, total=False): - NetworkInsightsAccessScopeAnalysisId: Optional[NetworkInsightsAccessScopeAnalysisId] - NetworkInsightsAccessScopeId: Optional[NetworkInsightsAccessScopeId] - FindingId: Optional[String] - FindingComponents: Optional[PathComponentList] + NetworkInsightsAccessScopeAnalysisId: NetworkInsightsAccessScopeAnalysisId | None + NetworkInsightsAccessScopeId: NetworkInsightsAccessScopeId | None + FindingId: String | None + FindingComponents: PathComponentList | None -AccessScopeAnalysisFindingList = List[AccessScopeAnalysisFinding] +AccessScopeAnalysisFindingList = list[AccessScopeAnalysisFinding] class ResourceStatement(TypedDict, total=False): - Resources: Optional[ValueStringList] - ResourceTypes: Optional[ValueStringList] + Resources: ValueStringList | None + ResourceTypes: ValueStringList | None class ThroughResourcesStatement(TypedDict, total=False): - ResourceStatement: Optional[ResourceStatement] + ResourceStatement: ResourceStatement | None -ThroughResourcesStatementList = List[ThroughResourcesStatement] -ProtocolList = List[Protocol] +ThroughResourcesStatementList = list[ThroughResourcesStatement] +ProtocolList = list[Protocol] class PacketHeaderStatement(TypedDict, total=False): - SourceAddresses: Optional[ValueStringList] - DestinationAddresses: Optional[ValueStringList] - SourcePorts: Optional[ValueStringList] - DestinationPorts: Optional[ValueStringList] - SourcePrefixLists: Optional[ValueStringList] - DestinationPrefixLists: Optional[ValueStringList] - Protocols: Optional[ProtocolList] + SourceAddresses: ValueStringList | None + DestinationAddresses: ValueStringList | None + SourcePorts: ValueStringList | None + DestinationPorts: ValueStringList | None + SourcePrefixLists: ValueStringList | None + DestinationPrefixLists: ValueStringList | None + Protocols: ProtocolList | None class PathStatement(TypedDict, total=False): - PacketHeaderStatement: Optional[PacketHeaderStatement] - ResourceStatement: Optional[ResourceStatement] + PacketHeaderStatement: PacketHeaderStatement | None + ResourceStatement: ResourceStatement | None class AccessScopePath(TypedDict, total=False): - Source: Optional[PathStatement] - Destination: Optional[PathStatement] - ThroughResources: Optional[ThroughResourcesStatementList] + Source: PathStatement | None + Destination: PathStatement | None + ThroughResources: ThroughResourcesStatementList | None -AccessScopePathList = List[AccessScopePath] +AccessScopePathList = list[AccessScopePath] class ResourceStatementRequest(TypedDict, total=False): - Resources: Optional[ValueStringList] - ResourceTypes: Optional[ValueStringList] + Resources: ValueStringList | None + ResourceTypes: ValueStringList | None class ThroughResourcesStatementRequest(TypedDict, total=False): - ResourceStatement: Optional[ResourceStatementRequest] + ResourceStatement: ResourceStatementRequest | None -ThroughResourcesStatementRequestList = List[ThroughResourcesStatementRequest] +ThroughResourcesStatementRequestList = list[ThroughResourcesStatementRequest] class PacketHeaderStatementRequest(TypedDict, total=False): - SourceAddresses: Optional[ValueStringList] - DestinationAddresses: Optional[ValueStringList] - SourcePorts: Optional[ValueStringList] - DestinationPorts: Optional[ValueStringList] - SourcePrefixLists: Optional[ValueStringList] - DestinationPrefixLists: Optional[ValueStringList] - Protocols: Optional[ProtocolList] + SourceAddresses: ValueStringList | None + DestinationAddresses: ValueStringList | None + SourcePorts: ValueStringList | None + DestinationPorts: ValueStringList | None + SourcePrefixLists: ValueStringList | None + DestinationPrefixLists: ValueStringList | None + Protocols: ProtocolList | None class PathStatementRequest(TypedDict, total=False): - PacketHeaderStatement: Optional[PacketHeaderStatementRequest] - ResourceStatement: Optional[ResourceStatementRequest] + PacketHeaderStatement: PacketHeaderStatementRequest | None + ResourceStatement: ResourceStatementRequest | None class AccessScopePathRequest(TypedDict, total=False): - Source: Optional[PathStatementRequest] - Destination: Optional[PathStatementRequest] - ThroughResources: Optional[ThroughResourcesStatementRequestList] + Source: PathStatementRequest | None + Destination: PathStatementRequest | None + ThroughResources: ThroughResourcesStatementRequestList | None -AccessScopePathListRequest = List[AccessScopePathRequest] +AccessScopePathListRequest = list[AccessScopePathRequest] class AccountAttributeValue(TypedDict, total=False): - AttributeValue: Optional[String] + AttributeValue: String | None -AccountAttributeValueList = List[AccountAttributeValue] +AccountAttributeValueList = list[AccountAttributeValue] class AccountAttribute(TypedDict, total=False): - AttributeName: Optional[String] - AttributeValues: Optional[AccountAttributeValueList] + AttributeName: String | None + AttributeValues: AccountAttributeValueList | None -AccountAttributeList = List[AccountAttribute] -AccountAttributeNameStringList = List[AccountAttributeName] +AccountAttributeList = list[AccountAttribute] +AccountAttributeNameStringList = list[AccountAttributeName] class ActiveInstance(TypedDict, total=False): - InstanceId: Optional[String] - InstanceType: Optional[String] - SpotInstanceRequestId: Optional[String] - InstanceHealth: Optional[InstanceHealthStatus] + InstanceId: String | None + InstanceType: String | None + SpotInstanceRequestId: String | None + InstanceHealth: InstanceHealthStatus | None -ActiveInstanceSet = List[ActiveInstance] +ActiveInstanceSet = list[ActiveInstance] class ActiveVpnTunnelStatus(TypedDict, total=False): - Phase1EncryptionAlgorithm: Optional[String] - Phase2EncryptionAlgorithm: Optional[String] - Phase1IntegrityAlgorithm: Optional[String] - Phase2IntegrityAlgorithm: Optional[String] - Phase1DHGroup: Optional[Integer] - Phase2DHGroup: Optional[Integer] - IkeVersion: Optional[String] - ProvisioningStatus: Optional[VpnTunnelProvisioningStatus] - ProvisioningStatusReason: Optional[String] + Phase1EncryptionAlgorithm: String | None + Phase2EncryptionAlgorithm: String | None + Phase1IntegrityAlgorithm: String | None + Phase2IntegrityAlgorithm: String | None + Phase1DHGroup: Integer | None + Phase2DHGroup: Integer | None + IkeVersion: String | None + ProvisioningStatus: VpnTunnelProvisioningStatus | None + ProvisioningStatusReason: String | None class AddIpamOperatingRegion(TypedDict, total=False): - RegionName: Optional[String] + RegionName: String | None -AddIpamOperatingRegionSet = List[AddIpamOperatingRegion] +AddIpamOperatingRegionSet = list[AddIpamOperatingRegion] class AddIpamOrganizationalUnitExclusion(TypedDict, total=False): - OrganizationsEntityPath: Optional[String] + OrganizationsEntityPath: String | None -AddIpamOrganizationalUnitExclusionSet = List[AddIpamOrganizationalUnitExclusion] +AddIpamOrganizationalUnitExclusionSet = list[AddIpamOrganizationalUnitExclusion] class AddPrefixListEntry(TypedDict, total=False): Cidr: String - Description: Optional[String] + Description: String | None -AddPrefixListEntries = List[AddPrefixListEntry] +AddPrefixListEntries = list[AddPrefixListEntry] class AddedPrincipal(TypedDict, total=False): - PrincipalType: Optional[PrincipalType] - Principal: Optional[String] - ServicePermissionId: Optional[String] - ServiceId: Optional[String] + PrincipalType: PrincipalType | None + Principal: String | None + ServicePermissionId: String | None + ServiceId: String | None -AddedPrincipalSet = List[AddedPrincipal] +AddedPrincipalSet = list[AddedPrincipal] class Address(TypedDict, total=False): - AllocationId: Optional[String] - AssociationId: Optional[String] - Domain: Optional[DomainType] - NetworkInterfaceId: Optional[String] - NetworkInterfaceOwnerId: Optional[String] - PrivateIpAddress: Optional[String] - Tags: Optional[TagList] - PublicIpv4Pool: Optional[String] - NetworkBorderGroup: Optional[String] - CustomerOwnedIp: Optional[String] - CustomerOwnedIpv4Pool: Optional[String] - CarrierIp: Optional[String] - SubnetId: Optional[String] - ServiceManaged: Optional[ServiceManaged] - InstanceId: Optional[String] - PublicIp: Optional[String] + AllocationId: String | None + AssociationId: String | None + Domain: DomainType | None + NetworkInterfaceId: String | None + NetworkInterfaceOwnerId: String | None + PrivateIpAddress: String | None + Tags: TagList | None + PublicIpv4Pool: String | None + NetworkBorderGroup: String | None + CustomerOwnedIp: String | None + CustomerOwnedIpv4Pool: String | None + CarrierIp: String | None + SubnetId: String | None + ServiceManaged: ServiceManaged | None + InstanceId: String | None + PublicIp: String | None class PtrUpdateStatus(TypedDict, total=False): - Value: Optional[String] - Status: Optional[String] - Reason: Optional[String] + Value: String | None + Status: String | None + Reason: String | None class AddressAttribute(TypedDict, total=False): - PublicIp: Optional[PublicIpAddress] - AllocationId: Optional[AllocationId] - PtrRecord: Optional[String] - PtrRecordUpdate: Optional[PtrUpdateStatus] + PublicIp: PublicIpAddress | None + AllocationId: AllocationId | None + PtrRecord: String | None + PtrRecordUpdate: PtrUpdateStatus | None -AddressList = List[Address] -AddressSet = List[AddressAttribute] -AddressTransferList = List[AddressTransfer] +AddressList = list[Address] +AddressSet = list[AddressAttribute] +AddressTransferList = list[AddressTransfer] class AdvertiseByoipCidrRequest(ServiceRequest): Cidr: String - Asn: Optional[String] - DryRun: Optional[Boolean] - NetworkBorderGroup: Optional[String] + Asn: String | None + DryRun: Boolean | None + NetworkBorderGroup: String | None class AsnAssociation(TypedDict, total=False): - Asn: Optional[String] - Cidr: Optional[String] - StatusMessage: Optional[String] - State: Optional[AsnAssociationState] + Asn: String | None + Cidr: String | None + StatusMessage: String | None + State: AsnAssociationState | None -AsnAssociationSet = List[AsnAssociation] +AsnAssociationSet = list[AsnAssociation] class ByoipCidr(TypedDict, total=False): - Cidr: Optional[String] - Description: Optional[String] - AsnAssociations: Optional[AsnAssociationSet] - StatusMessage: Optional[String] - State: Optional[ByoipCidrState] - NetworkBorderGroup: Optional[String] + Cidr: String | None + Description: String | None + AsnAssociations: AsnAssociationSet | None + StatusMessage: String | None + State: ByoipCidrState | None + NetworkBorderGroup: String | None + AdvertisementType: String | None class AdvertiseByoipCidrResult(TypedDict, total=False): - ByoipCidr: Optional[ByoipCidr] + ByoipCidr: ByoipCidr | None class AllocateAddressRequest(ServiceRequest): - Domain: Optional[DomainType] - Address: Optional[PublicIpAddress] - PublicIpv4Pool: Optional[Ipv4PoolEc2Id] - NetworkBorderGroup: Optional[String] - CustomerOwnedIpv4Pool: Optional[String] - TagSpecifications: Optional[TagSpecificationList] - IpamPoolId: Optional[IpamPoolId] - DryRun: Optional[Boolean] + Domain: DomainType | None + Address: PublicIpAddress | None + PublicIpv4Pool: Ipv4PoolEc2Id | None + NetworkBorderGroup: String | None + CustomerOwnedIpv4Pool: String | None + TagSpecifications: TagSpecificationList | None + IpamPoolId: IpamPoolId | None + DryRun: Boolean | None class AllocateAddressResult(TypedDict, total=False): - AllocationId: Optional[String] - PublicIpv4Pool: Optional[String] - NetworkBorderGroup: Optional[String] - Domain: Optional[DomainType] - CustomerOwnedIp: Optional[String] - CustomerOwnedIpv4Pool: Optional[String] - CarrierIp: Optional[String] - PublicIp: Optional[String] + AllocationId: String | None + PublicIpv4Pool: String | None + NetworkBorderGroup: String | None + Domain: DomainType | None + CustomerOwnedIp: String | None + CustomerOwnedIpv4Pool: String | None + CarrierIp: String | None + PublicIp: String | None -AssetIdList = List[AssetId] +AssetIdList = list[AssetId] class AllocateHostsRequest(ServiceRequest): - InstanceFamily: Optional[String] - TagSpecifications: Optional[TagSpecificationList] - HostRecovery: Optional[HostRecovery] - OutpostArn: Optional[String] - HostMaintenance: Optional[HostMaintenance] - AssetIds: Optional[AssetIdList] - AvailabilityZoneId: Optional[AvailabilityZoneId] - AutoPlacement: Optional[AutoPlacement] - ClientToken: Optional[String] - InstanceType: Optional[String] - Quantity: Optional[Integer] - AvailabilityZone: Optional[String] + InstanceFamily: String | None + TagSpecifications: TagSpecificationList | None + HostRecovery: HostRecovery | None + OutpostArn: String | None + HostMaintenance: HostMaintenance | None + AssetIds: AssetIdList | None + AvailabilityZoneId: AvailabilityZoneId | None + AutoPlacement: AutoPlacement | None + ClientToken: String | None + InstanceType: String | None + Quantity: Integer | None + AvailabilityZone: AvailabilityZoneName | None -ResponseHostIdList = List[String] +ResponseHostIdList = list[String] class AllocateHostsResult(TypedDict, total=False): - HostIds: Optional[ResponseHostIdList] + HostIds: ResponseHostIdList | None -IpamPoolAllocationDisallowedCidrs = List[String] -IpamPoolAllocationAllowedCidrs = List[String] +IpamPoolAllocationDisallowedCidrs = list[String] +IpamPoolAllocationAllowedCidrs = list[String] class AllocateIpamPoolCidrRequest(ServiceRequest): - DryRun: Optional[Boolean] + DryRun: Boolean | None IpamPoolId: IpamPoolId - Cidr: Optional[String] - NetmaskLength: Optional[Integer] - ClientToken: Optional[String] - Description: Optional[String] - PreviewNextCidr: Optional[Boolean] - AllowedCidrs: Optional[IpamPoolAllocationAllowedCidrs] - DisallowedCidrs: Optional[IpamPoolAllocationDisallowedCidrs] + Cidr: String | None + NetmaskLength: Integer | None + ClientToken: String | None + Description: String | None + PreviewNextCidr: Boolean | None + AllowedCidrs: IpamPoolAllocationAllowedCidrs | None + DisallowedCidrs: IpamPoolAllocationDisallowedCidrs | None class IpamPoolAllocation(TypedDict, total=False): - Cidr: Optional[String] - IpamPoolAllocationId: Optional[IpamPoolAllocationId] - Description: Optional[String] - ResourceId: Optional[String] - ResourceType: Optional[IpamPoolAllocationResourceType] - ResourceRegion: Optional[String] - ResourceOwner: Optional[String] + Cidr: String | None + IpamPoolAllocationId: IpamPoolAllocationId | None + Description: String | None + ResourceId: String | None + ResourceType: IpamPoolAllocationResourceType | None + ResourceRegion: String | None + ResourceOwner: String | None class AllocateIpamPoolCidrResult(TypedDict, total=False): - IpamPoolAllocation: Optional[IpamPoolAllocation] + IpamPoolAllocation: IpamPoolAllocation | None -AllocationIdList = List[AllocationId] -AllocationIds = List[AllocationId] -AllowedInstanceTypeSet = List[AllowedInstanceType] +AllocationIdList = list[AllocationId] +AllocationIds = list[AllocationId] +AllowedInstanceTypeSet = list[AllowedInstanceType] class AllowedPrincipal(TypedDict, total=False): - PrincipalType: Optional[PrincipalType] - Principal: Optional[String] - ServicePermissionId: Optional[String] - Tags: Optional[TagList] - ServiceId: Optional[String] + PrincipalType: PrincipalType | None + Principal: String | None + ServicePermissionId: String | None + Tags: TagList | None + ServiceId: String | None -AllowedPrincipalSet = List[AllowedPrincipal] +AllowedPrincipalSet = list[AllowedPrincipal] class AlternatePathHint(TypedDict, total=False): - ComponentId: Optional[String] - ComponentArn: Optional[String] + ComponentId: String | None + ComponentArn: String | None -AlternatePathHintList = List[AlternatePathHint] -ClientVpnSecurityGroupIdSet = List[SecurityGroupId] +AlternatePathHintList = list[AlternatePathHint] +ClientVpnSecurityGroupIdSet = list[SecurityGroupId] class ApplySecurityGroupsToClientVpnTargetNetworkRequest(ServiceRequest): ClientVpnEndpointId: ClientVpnEndpointId VpcId: VpcId SecurityGroupIds: ClientVpnSecurityGroupIdSet - DryRun: Optional[Boolean] + DryRun: Boolean | None class ApplySecurityGroupsToClientVpnTargetNetworkResult(TypedDict, total=False): - SecurityGroupIds: Optional[ClientVpnSecurityGroupIdSet] + SecurityGroupIds: ClientVpnSecurityGroupIdSet | None -ArchitectureTypeList = List[ArchitectureType] -ArchitectureTypeSet = List[ArchitectureType] -ArnList = List[ResourceArn] -AsPath = List[String] +ArchitectureTypeList = list[ArchitectureType] +ArchitectureTypeSet = list[ArchitectureType] +ArnList = list[ResourceArn] +AsPath = list[String] class AsnAuthorizationContext(TypedDict, total=False): @@ -4951,147 +5595,149 @@ class AsnAuthorizationContext(TypedDict, total=False): Signature: String -Ipv6AddressList = List[String] -IpPrefixList = List[String] +Ipv6AddressList = list[String] +IpPrefixList = list[String] class AssignIpv6AddressesRequest(ServiceRequest): - Ipv6PrefixCount: Optional[Integer] - Ipv6Prefixes: Optional[IpPrefixList] + Ipv6PrefixCount: Integer | None + Ipv6Prefixes: IpPrefixList | None NetworkInterfaceId: NetworkInterfaceId - Ipv6Addresses: Optional[Ipv6AddressList] - Ipv6AddressCount: Optional[Integer] + Ipv6Addresses: Ipv6AddressList | None + Ipv6AddressCount: Integer | None class AssignIpv6AddressesResult(TypedDict, total=False): - AssignedIpv6Addresses: Optional[Ipv6AddressList] - AssignedIpv6Prefixes: Optional[IpPrefixList] - NetworkInterfaceId: Optional[String] + AssignedIpv6Addresses: Ipv6AddressList | None + AssignedIpv6Prefixes: IpPrefixList | None + NetworkInterfaceId: String | None -PrivateIpAddressStringList = List[String] +PrivateIpAddressStringList = list[String] class AssignPrivateIpAddressesRequest(ServiceRequest): - Ipv4Prefixes: Optional[IpPrefixList] - Ipv4PrefixCount: Optional[Integer] + Ipv4Prefixes: IpPrefixList | None + Ipv4PrefixCount: Integer | None NetworkInterfaceId: NetworkInterfaceId - PrivateIpAddresses: Optional[PrivateIpAddressStringList] - SecondaryPrivateIpAddressCount: Optional[Integer] - AllowReassignment: Optional[Boolean] + PrivateIpAddresses: PrivateIpAddressStringList | None + SecondaryPrivateIpAddressCount: Integer | None + AllowReassignment: Boolean | None class Ipv4PrefixSpecification(TypedDict, total=False): - Ipv4Prefix: Optional[String] + Ipv4Prefix: String | None -Ipv4PrefixesList = List[Ipv4PrefixSpecification] +Ipv4PrefixesList = list[Ipv4PrefixSpecification] class AssignedPrivateIpAddress(TypedDict, total=False): - PrivateIpAddress: Optional[String] + PrivateIpAddress: String | None -AssignedPrivateIpAddressList = List[AssignedPrivateIpAddress] +AssignedPrivateIpAddressList = list[AssignedPrivateIpAddress] class AssignPrivateIpAddressesResult(TypedDict, total=False): - NetworkInterfaceId: Optional[String] - AssignedPrivateIpAddresses: Optional[AssignedPrivateIpAddressList] - AssignedIpv4Prefixes: Optional[Ipv4PrefixesList] + NetworkInterfaceId: String | None + AssignedPrivateIpAddresses: AssignedPrivateIpAddressList | None + AssignedIpv4Prefixes: Ipv4PrefixesList | None -IpList = List[String] +IpList = list[String] class AssignPrivateNatGatewayAddressRequest(ServiceRequest): NatGatewayId: NatGatewayId - PrivateIpAddresses: Optional[IpList] - PrivateIpAddressCount: Optional[PrivateIpAddressCount] - DryRun: Optional[Boolean] + PrivateIpAddresses: IpList | None + PrivateIpAddressCount: PrivateIpAddressCount | None + DryRun: Boolean | None class NatGatewayAddress(TypedDict, total=False): - AllocationId: Optional[String] - NetworkInterfaceId: Optional[String] - PrivateIp: Optional[String] - PublicIp: Optional[String] - AssociationId: Optional[String] - IsPrimary: Optional[Boolean] - FailureMessage: Optional[String] - Status: Optional[NatGatewayAddressStatus] + AllocationId: String | None + NetworkInterfaceId: String | None + PrivateIp: String | None + PublicIp: String | None + AssociationId: String | None + IsPrimary: Boolean | None + FailureMessage: String | None + Status: NatGatewayAddressStatus | None + AvailabilityZone: AvailabilityZoneName | None + AvailabilityZoneId: AvailabilityZoneId | None -NatGatewayAddressList = List[NatGatewayAddress] +NatGatewayAddressList = list[NatGatewayAddress] class AssignPrivateNatGatewayAddressResult(TypedDict, total=False): - NatGatewayId: Optional[NatGatewayId] - NatGatewayAddresses: Optional[NatGatewayAddressList] + NatGatewayId: NatGatewayId | None + NatGatewayAddresses: NatGatewayAddressList | None class AssociateAddressRequest(ServiceRequest): - AllocationId: Optional[AllocationId] - InstanceId: Optional[InstanceId] - PublicIp: Optional[EipAllocationPublicIp] - DryRun: Optional[Boolean] - NetworkInterfaceId: Optional[NetworkInterfaceId] - PrivateIpAddress: Optional[String] - AllowReassociation: Optional[Boolean] + AllocationId: AllocationId | None + InstanceId: InstanceId | None + PublicIp: EipAllocationPublicIp | None + DryRun: Boolean | None + NetworkInterfaceId: NetworkInterfaceId | None + PrivateIpAddress: String | None + AllowReassociation: Boolean | None class AssociateAddressResult(TypedDict, total=False): - AssociationId: Optional[String] + AssociationId: String | None class AssociateCapacityReservationBillingOwnerRequest(ServiceRequest): - DryRun: Optional[Boolean] + DryRun: Boolean | None CapacityReservationId: CapacityReservationId UnusedReservationBillingOwnerId: AccountID class AssociateCapacityReservationBillingOwnerResult(TypedDict, total=False): - Return: Optional[Boolean] + Return: Boolean | None class AssociateClientVpnTargetNetworkRequest(ServiceRequest): ClientVpnEndpointId: ClientVpnEndpointId SubnetId: SubnetId - ClientToken: Optional[String] - DryRun: Optional[Boolean] + ClientToken: String | None + DryRun: Boolean | None class AssociationStatus(TypedDict, total=False): - Code: Optional[AssociationStatusCode] - Message: Optional[String] + Code: AssociationStatusCode | None + Message: String | None class AssociateClientVpnTargetNetworkResult(TypedDict, total=False): - AssociationId: Optional[String] - Status: Optional[AssociationStatus] + AssociationId: String | None + Status: AssociationStatus | None class AssociateDhcpOptionsRequest(ServiceRequest): DhcpOptionsId: DefaultingDhcpOptionsId VpcId: VpcId - DryRun: Optional[Boolean] + DryRun: Boolean | None class AssociateEnclaveCertificateIamRoleRequest(ServiceRequest): CertificateArn: CertificateId RoleArn: RoleId - DryRun: Optional[Boolean] + DryRun: Boolean | None class AssociateEnclaveCertificateIamRoleResult(TypedDict, total=False): - CertificateS3BucketName: Optional[String] - CertificateS3ObjectKey: Optional[String] - EncryptionKmsKeyId: Optional[String] + CertificateS3BucketName: String | None + CertificateS3ObjectKey: String | None + EncryptionKmsKeyId: String | None class IamInstanceProfileSpecification(TypedDict, total=False): - Arn: Optional[String] - Name: Optional[String] + Arn: String | None + Name: String | None class AssociateIamInstanceProfileRequest(ServiceRequest): @@ -5100,928 +5746,956 @@ class AssociateIamInstanceProfileRequest(ServiceRequest): class IamInstanceProfile(TypedDict, total=False): - Arn: Optional[String] - Id: Optional[String] + Arn: String | None + Id: String | None class IamInstanceProfileAssociation(TypedDict, total=False): - AssociationId: Optional[String] - InstanceId: Optional[String] - IamInstanceProfile: Optional[IamInstanceProfile] - State: Optional[IamInstanceProfileAssociationState] - Timestamp: Optional[DateTime] + AssociationId: String | None + InstanceId: String | None + IamInstanceProfile: IamInstanceProfile | None + State: IamInstanceProfileAssociationState | None + Timestamp: DateTime | None class AssociateIamInstanceProfileResult(TypedDict, total=False): - IamInstanceProfileAssociation: Optional[IamInstanceProfileAssociation] + IamInstanceProfileAssociation: IamInstanceProfileAssociation | None -DedicatedHostIdList = List[DedicatedHostId] -InstanceIdList = List[InstanceId] +DedicatedHostIdList = list[DedicatedHostId] +InstanceIdList = list[InstanceId] class InstanceEventWindowAssociationRequest(TypedDict, total=False): - InstanceIds: Optional[InstanceIdList] - InstanceTags: Optional[TagList] - DedicatedHostIds: Optional[DedicatedHostIdList] + InstanceIds: InstanceIdList | None + InstanceTags: TagList | None + DedicatedHostIds: DedicatedHostIdList | None class AssociateInstanceEventWindowRequest(ServiceRequest): - DryRun: Optional[Boolean] + DryRun: Boolean | None InstanceEventWindowId: InstanceEventWindowId AssociationTarget: InstanceEventWindowAssociationRequest class InstanceEventWindowAssociationTarget(TypedDict, total=False): - InstanceIds: Optional[InstanceIdList] - Tags: Optional[TagList] - DedicatedHostIds: Optional[DedicatedHostIdList] + InstanceIds: InstanceIdList | None + Tags: TagList | None + DedicatedHostIds: DedicatedHostIdList | None class InstanceEventWindowTimeRange(TypedDict, total=False): - StartWeekDay: Optional[WeekDay] - StartHour: Optional[Hour] - EndWeekDay: Optional[WeekDay] - EndHour: Optional[Hour] + StartWeekDay: WeekDay | None + StartHour: Hour | None + EndWeekDay: WeekDay | None + EndHour: Hour | None -InstanceEventWindowTimeRangeList = List[InstanceEventWindowTimeRange] +InstanceEventWindowTimeRangeList = list[InstanceEventWindowTimeRange] class InstanceEventWindow(TypedDict, total=False): - InstanceEventWindowId: Optional[InstanceEventWindowId] - TimeRanges: Optional[InstanceEventWindowTimeRangeList] - Name: Optional[String] - CronExpression: Optional[InstanceEventWindowCronExpression] - AssociationTarget: Optional[InstanceEventWindowAssociationTarget] - State: Optional[InstanceEventWindowState] - Tags: Optional[TagList] + InstanceEventWindowId: InstanceEventWindowId | None + TimeRanges: InstanceEventWindowTimeRangeList | None + Name: String | None + CronExpression: InstanceEventWindowCronExpression | None + AssociationTarget: InstanceEventWindowAssociationTarget | None + State: InstanceEventWindowState | None + Tags: TagList | None class AssociateInstanceEventWindowResult(TypedDict, total=False): - InstanceEventWindow: Optional[InstanceEventWindow] + InstanceEventWindow: InstanceEventWindow | None class AssociateIpamByoasnRequest(ServiceRequest): - DryRun: Optional[Boolean] + DryRun: Boolean | None Asn: String Cidr: String class AssociateIpamByoasnResult(TypedDict, total=False): - AsnAssociation: Optional[AsnAssociation] + AsnAssociation: AsnAssociation | None class AssociateIpamResourceDiscoveryRequest(ServiceRequest): - DryRun: Optional[Boolean] + DryRun: Boolean | None IpamId: IpamId IpamResourceDiscoveryId: IpamResourceDiscoveryId - TagSpecifications: Optional[TagSpecificationList] - ClientToken: Optional[String] + TagSpecifications: TagSpecificationList | None + ClientToken: String | None class IpamResourceDiscoveryAssociation(TypedDict, total=False): - OwnerId: Optional[String] - IpamResourceDiscoveryAssociationId: Optional[IpamResourceDiscoveryAssociationId] - IpamResourceDiscoveryAssociationArn: Optional[String] - IpamResourceDiscoveryId: Optional[IpamResourceDiscoveryId] - IpamId: Optional[IpamId] - IpamArn: Optional[ResourceArn] - IpamRegion: Optional[String] - IsDefault: Optional[Boolean] - ResourceDiscoveryStatus: Optional[IpamAssociatedResourceDiscoveryStatus] - State: Optional[IpamResourceDiscoveryAssociationState] - Tags: Optional[TagList] + OwnerId: String | None + IpamResourceDiscoveryAssociationId: IpamResourceDiscoveryAssociationId | None + IpamResourceDiscoveryAssociationArn: String | None + IpamResourceDiscoveryId: IpamResourceDiscoveryId | None + IpamId: IpamId | None + IpamArn: ResourceArn | None + IpamRegion: String | None + IsDefault: Boolean | None + ResourceDiscoveryStatus: IpamAssociatedResourceDiscoveryStatus | None + State: IpamResourceDiscoveryAssociationState | None + Tags: TagList | None class AssociateIpamResourceDiscoveryResult(TypedDict, total=False): - IpamResourceDiscoveryAssociation: Optional[IpamResourceDiscoveryAssociation] + IpamResourceDiscoveryAssociation: IpamResourceDiscoveryAssociation | None class AssociateNatGatewayAddressRequest(ServiceRequest): NatGatewayId: NatGatewayId AllocationIds: AllocationIdList - PrivateIpAddresses: Optional[IpList] - DryRun: Optional[Boolean] + PrivateIpAddresses: IpList | None + DryRun: Boolean | None + AvailabilityZone: AvailabilityZoneName | None + AvailabilityZoneId: AvailabilityZoneId | None class AssociateNatGatewayAddressResult(TypedDict, total=False): - NatGatewayId: Optional[NatGatewayId] - NatGatewayAddresses: Optional[NatGatewayAddressList] + NatGatewayId: NatGatewayId | None + NatGatewayAddresses: NatGatewayAddressList | None class AssociateRouteServerRequest(ServiceRequest): RouteServerId: RouteServerId VpcId: VpcId - DryRun: Optional[Boolean] + DryRun: Boolean | None class RouteServerAssociation(TypedDict, total=False): - RouteServerId: Optional[RouteServerId] - VpcId: Optional[VpcId] - State: Optional[RouteServerAssociationState] + RouteServerId: RouteServerId | None + VpcId: VpcId | None + State: RouteServerAssociationState | None class AssociateRouteServerResult(TypedDict, total=False): - RouteServerAssociation: Optional[RouteServerAssociation] + RouteServerAssociation: RouteServerAssociation | None class AssociateRouteTableRequest(ServiceRequest): - GatewayId: Optional[RouteGatewayId] - PublicIpv4Pool: Optional[Ipv4PoolEc2Id] - DryRun: Optional[Boolean] - SubnetId: Optional[SubnetId] + GatewayId: RouteGatewayId | None + PublicIpv4Pool: Ipv4PoolEc2Id | None + DryRun: Boolean | None + SubnetId: SubnetId | None RouteTableId: RouteTableId class RouteTableAssociationState(TypedDict, total=False): - State: Optional[RouteTableAssociationStateCode] - StatusMessage: Optional[String] + State: RouteTableAssociationStateCode | None + StatusMessage: String | None class AssociateRouteTableResult(TypedDict, total=False): - AssociationId: Optional[String] - AssociationState: Optional[RouteTableAssociationState] + AssociationId: String | None + AssociationState: RouteTableAssociationState | None class AssociateSecurityGroupVpcRequest(ServiceRequest): GroupId: SecurityGroupId VpcId: VpcId - DryRun: Optional[Boolean] + DryRun: Boolean | None class AssociateSecurityGroupVpcResult(TypedDict, total=False): - State: Optional[SecurityGroupVpcAssociationState] + State: SecurityGroupVpcAssociationState | None class AssociateSubnetCidrBlockRequest(ServiceRequest): - Ipv6IpamPoolId: Optional[IpamPoolId] - Ipv6NetmaskLength: Optional[NetmaskLength] + Ipv6IpamPoolId: IpamPoolId | None + Ipv6NetmaskLength: NetmaskLength | None SubnetId: SubnetId - Ipv6CidrBlock: Optional[String] + Ipv6CidrBlock: String | None class SubnetCidrBlockState(TypedDict, total=False): - State: Optional[SubnetCidrBlockStateCode] - StatusMessage: Optional[String] + State: SubnetCidrBlockStateCode | None + StatusMessage: String | None class SubnetIpv6CidrBlockAssociation(TypedDict, total=False): - AssociationId: Optional[SubnetCidrAssociationId] - Ipv6CidrBlock: Optional[String] - Ipv6CidrBlockState: Optional[SubnetCidrBlockState] - Ipv6AddressAttribute: Optional[Ipv6AddressAttribute] - IpSource: Optional[IpSource] + AssociationId: SubnetCidrAssociationId | None + Ipv6CidrBlock: String | None + Ipv6CidrBlockState: SubnetCidrBlockState | None + Ipv6AddressAttribute: Ipv6AddressAttribute | None + IpSource: IpSource | None class AssociateSubnetCidrBlockResult(TypedDict, total=False): - Ipv6CidrBlockAssociation: Optional[SubnetIpv6CidrBlockAssociation] - SubnetId: Optional[String] + Ipv6CidrBlockAssociation: SubnetIpv6CidrBlockAssociation | None + SubnetId: String | None -TransitGatewaySubnetIdList = List[SubnetId] +TransitGatewaySubnetIdList = list[SubnetId] class AssociateTransitGatewayMulticastDomainRequest(ServiceRequest): TransitGatewayMulticastDomainId: TransitGatewayMulticastDomainId TransitGatewayAttachmentId: TransitGatewayAttachmentId SubnetIds: TransitGatewaySubnetIdList - DryRun: Optional[Boolean] + DryRun: Boolean | None class AssociateTransitGatewayMulticastDomainResult(TypedDict, total=False): - Associations: Optional[TransitGatewayMulticastDomainAssociations] + Associations: TransitGatewayMulticastDomainAssociations | None class AssociateTransitGatewayPolicyTableRequest(ServiceRequest): TransitGatewayPolicyTableId: TransitGatewayPolicyTableId TransitGatewayAttachmentId: TransitGatewayAttachmentId - DryRun: Optional[Boolean] + DryRun: Boolean | None class TransitGatewayPolicyTableAssociation(TypedDict, total=False): - TransitGatewayPolicyTableId: Optional[TransitGatewayPolicyTableId] - TransitGatewayAttachmentId: Optional[TransitGatewayAttachmentId] - ResourceId: Optional[String] - ResourceType: Optional[TransitGatewayAttachmentResourceType] - State: Optional[TransitGatewayAssociationState] + TransitGatewayPolicyTableId: TransitGatewayPolicyTableId | None + TransitGatewayAttachmentId: TransitGatewayAttachmentId | None + ResourceId: String | None + ResourceType: TransitGatewayAttachmentResourceType | None + State: TransitGatewayAssociationState | None class AssociateTransitGatewayPolicyTableResult(TypedDict, total=False): - Association: Optional[TransitGatewayPolicyTableAssociation] + Association: TransitGatewayPolicyTableAssociation | None class AssociateTransitGatewayRouteTableRequest(ServiceRequest): TransitGatewayRouteTableId: TransitGatewayRouteTableId TransitGatewayAttachmentId: TransitGatewayAttachmentId - DryRun: Optional[Boolean] + DryRun: Boolean | None class TransitGatewayAssociation(TypedDict, total=False): - TransitGatewayRouteTableId: Optional[TransitGatewayRouteTableId] - TransitGatewayAttachmentId: Optional[TransitGatewayAttachmentId] - ResourceId: Optional[String] - ResourceType: Optional[TransitGatewayAttachmentResourceType] - State: Optional[TransitGatewayAssociationState] + TransitGatewayRouteTableId: TransitGatewayRouteTableId | None + TransitGatewayAttachmentId: TransitGatewayAttachmentId | None + ResourceId: String | None + ResourceType: TransitGatewayAttachmentResourceType | None + State: TransitGatewayAssociationState | None class AssociateTransitGatewayRouteTableResult(TypedDict, total=False): - Association: Optional[TransitGatewayAssociation] + Association: TransitGatewayAssociation | None class AssociateTrunkInterfaceRequest(ServiceRequest): BranchInterfaceId: NetworkInterfaceId TrunkInterfaceId: NetworkInterfaceId - VlanId: Optional[Integer] - GreKey: Optional[Integer] - ClientToken: Optional[String] - DryRun: Optional[Boolean] + VlanId: Integer | None + GreKey: Integer | None + ClientToken: String | None + DryRun: Boolean | None class TrunkInterfaceAssociation(TypedDict, total=False): - AssociationId: Optional[TrunkInterfaceAssociationId] - BranchInterfaceId: Optional[String] - TrunkInterfaceId: Optional[String] - InterfaceProtocol: Optional[InterfaceProtocolType] - VlanId: Optional[Integer] - GreKey: Optional[Integer] - Tags: Optional[TagList] + AssociationId: TrunkInterfaceAssociationId | None + BranchInterfaceId: String | None + TrunkInterfaceId: String | None + InterfaceProtocol: InterfaceProtocolType | None + VlanId: Integer | None + GreKey: Integer | None + Tags: TagList | None class AssociateTrunkInterfaceResult(TypedDict, total=False): - InterfaceAssociation: Optional[TrunkInterfaceAssociation] - ClientToken: Optional[String] + InterfaceAssociation: TrunkInterfaceAssociation | None + ClientToken: String | None class AssociateVpcCidrBlockRequest(ServiceRequest): - CidrBlock: Optional[String] - Ipv6CidrBlockNetworkBorderGroup: Optional[String] - Ipv6Pool: Optional[Ipv6PoolEc2Id] - Ipv6CidrBlock: Optional[String] - Ipv4IpamPoolId: Optional[IpamPoolId] - Ipv4NetmaskLength: Optional[NetmaskLength] - Ipv6IpamPoolId: Optional[IpamPoolId] - Ipv6NetmaskLength: Optional[NetmaskLength] + CidrBlock: String | None + Ipv6CidrBlockNetworkBorderGroup: String | None + Ipv6Pool: Ipv6PoolEc2Id | None + Ipv6CidrBlock: String | None + Ipv4IpamPoolId: IpamPoolId | None + Ipv4NetmaskLength: NetmaskLength | None + Ipv6IpamPoolId: IpamPoolId | None + Ipv6NetmaskLength: NetmaskLength | None VpcId: VpcId - AmazonProvidedIpv6CidrBlock: Optional[Boolean] + AmazonProvidedIpv6CidrBlock: Boolean | None class VpcCidrBlockState(TypedDict, total=False): - State: Optional[VpcCidrBlockStateCode] - StatusMessage: Optional[String] + State: VpcCidrBlockStateCode | None + StatusMessage: String | None class VpcCidrBlockAssociation(TypedDict, total=False): - AssociationId: Optional[String] - CidrBlock: Optional[String] - CidrBlockState: Optional[VpcCidrBlockState] + AssociationId: String | None + CidrBlock: String | None + CidrBlockState: VpcCidrBlockState | None class VpcIpv6CidrBlockAssociation(TypedDict, total=False): - AssociationId: Optional[String] - Ipv6CidrBlock: Optional[String] - Ipv6CidrBlockState: Optional[VpcCidrBlockState] - NetworkBorderGroup: Optional[String] - Ipv6Pool: Optional[String] - Ipv6AddressAttribute: Optional[Ipv6AddressAttribute] - IpSource: Optional[IpSource] + AssociationId: String | None + Ipv6CidrBlock: String | None + Ipv6CidrBlockState: VpcCidrBlockState | None + NetworkBorderGroup: String | None + Ipv6Pool: String | None + Ipv6AddressAttribute: Ipv6AddressAttribute | None + IpSource: IpSource | None class AssociateVpcCidrBlockResult(TypedDict, total=False): - Ipv6CidrBlockAssociation: Optional[VpcIpv6CidrBlockAssociation] - CidrBlockAssociation: Optional[VpcCidrBlockAssociation] - VpcId: Optional[String] + Ipv6CidrBlockAssociation: VpcIpv6CidrBlockAssociation | None + CidrBlockAssociation: VpcCidrBlockAssociation | None + VpcId: String | None class AssociatedRole(TypedDict, total=False): - AssociatedRoleArn: Optional[ResourceArn] - CertificateS3BucketName: Optional[String] - CertificateS3ObjectKey: Optional[String] - EncryptionKmsKeyId: Optional[String] + AssociatedRoleArn: ResourceArn | None + CertificateS3BucketName: String | None + CertificateS3ObjectKey: String | None + EncryptionKmsKeyId: String | None -AssociatedRolesList = List[AssociatedRole] -AssociatedSubnetList = List[SubnetId] +AssociatedRolesList = list[AssociatedRole] +AssociatedSubnetList = list[SubnetId] class AssociatedTargetNetwork(TypedDict, total=False): - NetworkId: Optional[String] - NetworkType: Optional[AssociatedNetworkType] + NetworkId: String | None + NetworkType: AssociatedNetworkType | None -AssociatedTargetNetworkSet = List[AssociatedTargetNetwork] -AssociationIdList = List[IamInstanceProfileAssociationId] +AssociatedTargetNetworkSet = list[AssociatedTargetNetwork] +AssociationIdList = list[IamInstanceProfileAssociationId] class AthenaIntegration(TypedDict, total=False): IntegrationResultS3DestinationArn: String PartitionLoadFrequency: PartitionLoadFrequency - PartitionStartDate: Optional[MillisecondDateTime] - PartitionEndDate: Optional[MillisecondDateTime] + PartitionStartDate: MillisecondDateTime | None + PartitionEndDate: MillisecondDateTime | None -AthenaIntegrationsSet = List[AthenaIntegration] -GroupIdStringList = List[SecurityGroupId] +AthenaIntegrationsSet = list[AthenaIntegration] +GroupIdStringList = list[SecurityGroupId] class AttachClassicLinkVpcRequest(ServiceRequest): - DryRun: Optional[Boolean] + DryRun: Boolean | None InstanceId: InstanceId VpcId: VpcId Groups: GroupIdStringList class AttachClassicLinkVpcResult(TypedDict, total=False): - Return: Optional[Boolean] + Return: Boolean | None class AttachInternetGatewayRequest(ServiceRequest): - DryRun: Optional[Boolean] + DryRun: Boolean | None InternetGatewayId: InternetGatewayId VpcId: VpcId class EnaSrdUdpSpecification(TypedDict, total=False): - EnaSrdUdpEnabled: Optional[Boolean] + EnaSrdUdpEnabled: Boolean | None class EnaSrdSpecification(TypedDict, total=False): - EnaSrdEnabled: Optional[Boolean] - EnaSrdUdpSpecification: Optional[EnaSrdUdpSpecification] + EnaSrdEnabled: Boolean | None + EnaSrdUdpSpecification: EnaSrdUdpSpecification | None class AttachNetworkInterfaceRequest(ServiceRequest): - NetworkCardIndex: Optional[Integer] - EnaSrdSpecification: Optional[EnaSrdSpecification] - EnaQueueCount: Optional[Integer] - DryRun: Optional[Boolean] + NetworkCardIndex: Integer | None + EnaSrdSpecification: EnaSrdSpecification | None + EnaQueueCount: Integer | None + DryRun: Boolean | None NetworkInterfaceId: NetworkInterfaceId InstanceId: InstanceId DeviceIndex: Integer class AttachNetworkInterfaceResult(TypedDict, total=False): - AttachmentId: Optional[String] - NetworkCardIndex: Optional[Integer] + AttachmentId: String | None + NetworkCardIndex: Integer | None class AttachVerifiedAccessTrustProviderRequest(ServiceRequest): VerifiedAccessInstanceId: VerifiedAccessInstanceId VerifiedAccessTrustProviderId: VerifiedAccessTrustProviderId - ClientToken: Optional[String] - DryRun: Optional[Boolean] + ClientToken: String | None + DryRun: Boolean | None class VerifiedAccessInstanceCustomSubDomain(TypedDict, total=False): - SubDomain: Optional[String] - Nameservers: Optional[ValueStringList] + SubDomain: String | None + Nameservers: ValueStringList | None class VerifiedAccessTrustProviderCondensed(TypedDict, total=False): - VerifiedAccessTrustProviderId: Optional[String] - Description: Optional[String] - TrustProviderType: Optional[TrustProviderType] - UserTrustProviderType: Optional[UserTrustProviderType] - DeviceTrustProviderType: Optional[DeviceTrustProviderType] + VerifiedAccessTrustProviderId: String | None + Description: String | None + TrustProviderType: TrustProviderType | None + UserTrustProviderType: UserTrustProviderType | None + DeviceTrustProviderType: DeviceTrustProviderType | None -VerifiedAccessTrustProviderCondensedList = List[VerifiedAccessTrustProviderCondensed] +VerifiedAccessTrustProviderCondensedList = list[VerifiedAccessTrustProviderCondensed] class VerifiedAccessInstance(TypedDict, total=False): - VerifiedAccessInstanceId: Optional[String] - Description: Optional[String] - VerifiedAccessTrustProviders: Optional[VerifiedAccessTrustProviderCondensedList] - CreationTime: Optional[String] - LastUpdatedTime: Optional[String] - Tags: Optional[TagList] - FipsEnabled: Optional[Boolean] - CidrEndpointsCustomSubDomain: Optional[VerifiedAccessInstanceCustomSubDomain] + VerifiedAccessInstanceId: String | None + Description: String | None + VerifiedAccessTrustProviders: VerifiedAccessTrustProviderCondensedList | None + CreationTime: String | None + LastUpdatedTime: String | None + Tags: TagList | None + FipsEnabled: Boolean | None + CidrEndpointsCustomSubDomain: VerifiedAccessInstanceCustomSubDomain | None class NativeApplicationOidcOptions(TypedDict, total=False): - PublicSigningKeyEndpoint: Optional[String] - Issuer: Optional[String] - AuthorizationEndpoint: Optional[String] - TokenEndpoint: Optional[String] - UserInfoEndpoint: Optional[String] - ClientId: Optional[String] - Scope: Optional[String] + PublicSigningKeyEndpoint: String | None + Issuer: String | None + AuthorizationEndpoint: String | None + TokenEndpoint: String | None + UserInfoEndpoint: String | None + ClientId: String | None + Scope: String | None class VerifiedAccessSseSpecificationResponse(TypedDict, total=False): - CustomerManagedKeyEnabled: Optional[Boolean] - KmsKeyArn: Optional[KmsKeyArn] + CustomerManagedKeyEnabled: Boolean | None + KmsKeyArn: KmsKeyArn | None class DeviceOptions(TypedDict, total=False): - TenantId: Optional[String] - PublicSigningKeyUrl: Optional[String] + TenantId: String | None + PublicSigningKeyUrl: String | None class OidcOptions(TypedDict, total=False): - Issuer: Optional[String] - AuthorizationEndpoint: Optional[String] - TokenEndpoint: Optional[String] - UserInfoEndpoint: Optional[String] - ClientId: Optional[String] - ClientSecret: Optional[ClientSecretType] - Scope: Optional[String] + Issuer: String | None + AuthorizationEndpoint: String | None + TokenEndpoint: String | None + UserInfoEndpoint: String | None + ClientId: String | None + ClientSecret: ClientSecretType | None + Scope: String | None class VerifiedAccessTrustProvider(TypedDict, total=False): - VerifiedAccessTrustProviderId: Optional[String] - Description: Optional[String] - TrustProviderType: Optional[TrustProviderType] - UserTrustProviderType: Optional[UserTrustProviderType] - DeviceTrustProviderType: Optional[DeviceTrustProviderType] - OidcOptions: Optional[OidcOptions] - DeviceOptions: Optional[DeviceOptions] - PolicyReferenceName: Optional[String] - CreationTime: Optional[String] - LastUpdatedTime: Optional[String] - Tags: Optional[TagList] - SseSpecification: Optional[VerifiedAccessSseSpecificationResponse] - NativeApplicationOidcOptions: Optional[NativeApplicationOidcOptions] + VerifiedAccessTrustProviderId: String | None + Description: String | None + TrustProviderType: TrustProviderType | None + UserTrustProviderType: UserTrustProviderType | None + DeviceTrustProviderType: DeviceTrustProviderType | None + OidcOptions: OidcOptions | None + DeviceOptions: DeviceOptions | None + PolicyReferenceName: String | None + CreationTime: String | None + LastUpdatedTime: String | None + Tags: TagList | None + SseSpecification: VerifiedAccessSseSpecificationResponse | None + NativeApplicationOidcOptions: NativeApplicationOidcOptions | None class AttachVerifiedAccessTrustProviderResult(TypedDict, total=False): - VerifiedAccessTrustProvider: Optional[VerifiedAccessTrustProvider] - VerifiedAccessInstance: Optional[VerifiedAccessInstance] + VerifiedAccessTrustProvider: VerifiedAccessTrustProvider | None + VerifiedAccessInstance: VerifiedAccessInstance | None class AttachVolumeRequest(ServiceRequest): Device: String InstanceId: InstanceId VolumeId: VolumeId - DryRun: Optional[Boolean] + EbsCardIndex: BoxedInteger | None + DryRun: Boolean | None class AttachVpnGatewayRequest(ServiceRequest): VpcId: VpcId VpnGatewayId: VpnGatewayId - DryRun: Optional[Boolean] + DryRun: Boolean | None class VpcAttachment(TypedDict, total=False): - VpcId: Optional[String] - State: Optional[AttachmentStatus] + VpcId: String | None + State: AttachmentStatus | None class AttachVpnGatewayResult(TypedDict, total=False): - VpcAttachment: Optional[VpcAttachment] + VpcAttachment: VpcAttachment | None class AttachmentEnaSrdUdpSpecification(TypedDict, total=False): - EnaSrdUdpEnabled: Optional[Boolean] + EnaSrdUdpEnabled: Boolean | None class AttachmentEnaSrdSpecification(TypedDict, total=False): - EnaSrdEnabled: Optional[Boolean] - EnaSrdUdpSpecification: Optional[AttachmentEnaSrdUdpSpecification] + EnaSrdEnabled: Boolean | None + EnaSrdUdpSpecification: AttachmentEnaSrdUdpSpecification | None class AttributeBooleanValue(TypedDict, total=False): - Value: Optional[Boolean] + Value: Boolean | None class RegionalSummary(TypedDict, total=False): - RegionName: Optional[String] - NumberOfMatchedAccounts: Optional[Integer] - NumberOfUnmatchedAccounts: Optional[Integer] + RegionName: String | None + NumberOfMatchedAccounts: Integer | None + NumberOfUnmatchedAccounts: Integer | None -RegionalSummaryList = List[RegionalSummary] +RegionalSummaryList = list[RegionalSummary] class AttributeSummary(TypedDict, total=False): - AttributeName: Optional[String] - MostFrequentValue: Optional[String] - NumberOfMatchedAccounts: Optional[Integer] - NumberOfUnmatchedAccounts: Optional[Integer] - RegionalSummaries: Optional[RegionalSummaryList] + AttributeName: String | None + MostFrequentValue: String | None + NumberOfMatchedAccounts: Integer | None + NumberOfUnmatchedAccounts: Integer | None + RegionalSummaries: RegionalSummaryList | None -AttributeSummaryList = List[AttributeSummary] +AttributeSummaryList = list[AttributeSummary] class AttributeValue(TypedDict, total=False): - Value: Optional[String] + Value: String | None class ClientVpnAuthorizationRuleStatus(TypedDict, total=False): - Code: Optional[ClientVpnAuthorizationRuleStatusCode] - Message: Optional[String] + Code: ClientVpnAuthorizationRuleStatusCode | None + Message: String | None class AuthorizationRule(TypedDict, total=False): - ClientVpnEndpointId: Optional[String] - Description: Optional[String] - GroupId: Optional[String] - AccessAll: Optional[Boolean] - DestinationCidr: Optional[String] - Status: Optional[ClientVpnAuthorizationRuleStatus] + ClientVpnEndpointId: String | None + Description: String | None + GroupId: String | None + AccessAll: Boolean | None + DestinationCidr: String | None + Status: ClientVpnAuthorizationRuleStatus | None -AuthorizationRuleSet = List[AuthorizationRule] +AuthorizationRuleSet = list[AuthorizationRule] class AuthorizeClientVpnIngressRequest(ServiceRequest): ClientVpnEndpointId: ClientVpnEndpointId TargetNetworkCidr: String - AccessGroupId: Optional[String] - AuthorizeAllGroups: Optional[Boolean] - Description: Optional[String] - ClientToken: Optional[String] - DryRun: Optional[Boolean] + AccessGroupId: String | None + AuthorizeAllGroups: Boolean | None + Description: String | None + ClientToken: String | None + DryRun: Boolean | None class AuthorizeClientVpnIngressResult(TypedDict, total=False): - Status: Optional[ClientVpnAuthorizationRuleStatus] + Status: ClientVpnAuthorizationRuleStatus | None class PrefixListId(TypedDict, total=False): - Description: Optional[String] - PrefixListId: Optional[String] + Description: String | None + PrefixListId: String | None -PrefixListIdList = List[PrefixListId] +PrefixListIdList = list[PrefixListId] class Ipv6Range(TypedDict, total=False): - Description: Optional[String] - CidrIpv6: Optional[String] + Description: String | None + CidrIpv6: String | None -Ipv6RangeList = List[Ipv6Range] +Ipv6RangeList = list[Ipv6Range] class IpRange(TypedDict, total=False): - Description: Optional[String] - CidrIp: Optional[String] + Description: String | None + CidrIp: String | None -IpRangeList = List[IpRange] +IpRangeList = list[IpRange] class UserIdGroupPair(TypedDict, total=False): - Description: Optional[String] - UserId: Optional[String] - GroupName: Optional[String] - GroupId: Optional[String] - VpcId: Optional[String] - VpcPeeringConnectionId: Optional[String] - PeeringStatus: Optional[String] + Description: String | None + UserId: String | None + GroupName: String | None + GroupId: String | None + VpcId: String | None + VpcPeeringConnectionId: String | None + PeeringStatus: String | None -UserIdGroupPairList = List[UserIdGroupPair] +UserIdGroupPairList = list[UserIdGroupPair] class IpPermission(TypedDict, total=False): - IpProtocol: Optional[String] - FromPort: Optional[Integer] - ToPort: Optional[Integer] - UserIdGroupPairs: Optional[UserIdGroupPairList] - IpRanges: Optional[IpRangeList] - Ipv6Ranges: Optional[Ipv6RangeList] - PrefixListIds: Optional[PrefixListIdList] + IpProtocol: String | None + FromPort: Integer | None + ToPort: Integer | None + UserIdGroupPairs: UserIdGroupPairList | None + IpRanges: IpRangeList | None + Ipv6Ranges: Ipv6RangeList | None + PrefixListIds: PrefixListIdList | None -IpPermissionList = List[IpPermission] +IpPermissionList = list[IpPermission] class AuthorizeSecurityGroupEgressRequest(ServiceRequest): - TagSpecifications: Optional[TagSpecificationList] - DryRun: Optional[Boolean] + TagSpecifications: TagSpecificationList | None + DryRun: Boolean | None GroupId: SecurityGroupId - SourceSecurityGroupName: Optional[String] - SourceSecurityGroupOwnerId: Optional[String] - IpProtocol: Optional[String] - FromPort: Optional[Integer] - ToPort: Optional[Integer] - CidrIp: Optional[String] - IpPermissions: Optional[IpPermissionList] + SourceSecurityGroupName: String | None + SourceSecurityGroupOwnerId: String | None + IpProtocol: String | None + FromPort: Integer | None + ToPort: Integer | None + CidrIp: String | None + IpPermissions: IpPermissionList | None class ReferencedSecurityGroup(TypedDict, total=False): - GroupId: Optional[String] - PeeringStatus: Optional[String] - UserId: Optional[String] - VpcId: Optional[String] - VpcPeeringConnectionId: Optional[String] + GroupId: String | None + PeeringStatus: String | None + UserId: String | None + VpcId: String | None + VpcPeeringConnectionId: String | None class SecurityGroupRule(TypedDict, total=False): - SecurityGroupRuleId: Optional[SecurityGroupRuleId] - GroupId: Optional[SecurityGroupId] - GroupOwnerId: Optional[String] - IsEgress: Optional[Boolean] - IpProtocol: Optional[String] - FromPort: Optional[Integer] - ToPort: Optional[Integer] - CidrIpv4: Optional[String] - CidrIpv6: Optional[String] - PrefixListId: Optional[PrefixListResourceId] - ReferencedGroupInfo: Optional[ReferencedSecurityGroup] - Description: Optional[String] - Tags: Optional[TagList] - SecurityGroupRuleArn: Optional[String] + SecurityGroupRuleId: SecurityGroupRuleId | None + GroupId: SecurityGroupId | None + GroupOwnerId: String | None + IsEgress: Boolean | None + IpProtocol: String | None + FromPort: Integer | None + ToPort: Integer | None + CidrIpv4: String | None + CidrIpv6: String | None + PrefixListId: PrefixListResourceId | None + ReferencedGroupInfo: ReferencedSecurityGroup | None + Description: String | None + Tags: TagList | None + SecurityGroupRuleArn: String | None -SecurityGroupRuleList = List[SecurityGroupRule] +SecurityGroupRuleList = list[SecurityGroupRule] class AuthorizeSecurityGroupEgressResult(TypedDict, total=False): - Return: Optional[Boolean] - SecurityGroupRules: Optional[SecurityGroupRuleList] + Return: Boolean | None + SecurityGroupRules: SecurityGroupRuleList | None class AuthorizeSecurityGroupIngressRequest(ServiceRequest): - CidrIp: Optional[String] - FromPort: Optional[Integer] - GroupId: Optional[SecurityGroupId] - GroupName: Optional[SecurityGroupName] - IpPermissions: Optional[IpPermissionList] - IpProtocol: Optional[String] - SourceSecurityGroupName: Optional[String] - SourceSecurityGroupOwnerId: Optional[String] - ToPort: Optional[Integer] - TagSpecifications: Optional[TagSpecificationList] - DryRun: Optional[Boolean] + CidrIp: String | None + FromPort: Integer | None + GroupId: SecurityGroupId | None + GroupName: SecurityGroupName | None + IpPermissions: IpPermissionList | None + IpProtocol: String | None + SourceSecurityGroupName: String | None + SourceSecurityGroupOwnerId: String | None + ToPort: Integer | None + TagSpecifications: TagSpecificationList | None + DryRun: Boolean | None class AuthorizeSecurityGroupIngressResult(TypedDict, total=False): - Return: Optional[Boolean] - SecurityGroupRules: Optional[SecurityGroupRuleList] + Return: Boolean | None + SecurityGroupRules: SecurityGroupRuleList | None -class AvailabilityZoneMessage(TypedDict, total=False): - Message: Optional[String] +class AvailabilityZoneSubGeography(TypedDict, total=False): + Name: String | None -AvailabilityZoneMessageList = List[AvailabilityZoneMessage] +AvailabilityZoneSubGeographyList = list[AvailabilityZoneSubGeography] -class AvailabilityZone(TypedDict, total=False): - OptInStatus: Optional[AvailabilityZoneOptInStatus] - Messages: Optional[AvailabilityZoneMessageList] - RegionName: Optional[String] - ZoneName: Optional[String] - ZoneId: Optional[String] - GroupName: Optional[String] - NetworkBorderGroup: Optional[String] - ZoneType: Optional[String] - ParentZoneName: Optional[String] - ParentZoneId: Optional[String] - GroupLongName: Optional[String] - State: Optional[AvailabilityZoneState] +class AvailabilityZoneGeography(TypedDict, total=False): + Name: String | None -AvailabilityZoneList = List[AvailabilityZone] -AvailabilityZoneStringList = List[String] +AvailabilityZoneGeographyList = list[AvailabilityZoneGeography] + + +class AvailabilityZoneMessage(TypedDict, total=False): + Message: String | None + + +AvailabilityZoneMessageList = list[AvailabilityZoneMessage] + + +class AvailabilityZone(TypedDict, total=False): + OptInStatus: AvailabilityZoneOptInStatus | None + Messages: AvailabilityZoneMessageList | None + RegionName: String | None + ZoneName: String | None + ZoneId: String | None + GroupName: String | None + NetworkBorderGroup: String | None + ZoneType: String | None + ParentZoneName: String | None + ParentZoneId: String | None + GroupLongName: String | None + Geography: AvailabilityZoneGeographyList | None + SubGeography: AvailabilityZoneSubGeographyList | None + State: AvailabilityZoneState | None + + +class AvailabilityZoneAddress(TypedDict, total=False): + AvailabilityZone: AvailabilityZoneName | None + AvailabilityZoneId: AvailabilityZoneId | None + AllocationIds: AllocationIdList | None + + +AvailabilityZoneAddresses = list[AvailabilityZoneAddress] +AvailabilityZoneIdStringList = list[String] +AvailabilityZoneList = list[AvailabilityZone] +AvailabilityZoneStringList = list[String] class InstanceCapacity(TypedDict, total=False): - AvailableCapacity: Optional[Integer] - InstanceType: Optional[String] - TotalCapacity: Optional[Integer] + AvailableCapacity: Integer | None + InstanceType: String | None + TotalCapacity: Integer | None -AvailableInstanceCapacityList = List[InstanceCapacity] +AvailableInstanceCapacityList = list[InstanceCapacity] class AvailableCapacity(TypedDict, total=False): - AvailableInstanceCapacity: Optional[AvailableInstanceCapacityList] - AvailableVCpus: Optional[Integer] + AvailableInstanceCapacity: AvailableInstanceCapacityList | None + AvailableVCpus: Integer | None -BandwidthWeightingTypeList = List[BandwidthWeightingType] +BandwidthWeightingTypeList = list[BandwidthWeightingType] class BaselineEbsBandwidthMbps(TypedDict, total=False): - Min: Optional[Integer] - Max: Optional[Integer] + Min: Integer | None + Max: Integer | None class BaselineEbsBandwidthMbpsRequest(TypedDict, total=False): - Min: Optional[Integer] - Max: Optional[Integer] + Min: Integer | None + Max: Integer | None class PerformanceFactorReference(TypedDict, total=False): - InstanceFamily: Optional[String] + InstanceFamily: String | None -PerformanceFactorReferenceSet = List[PerformanceFactorReference] +PerformanceFactorReferenceSet = list[PerformanceFactorReference] class CpuPerformanceFactor(TypedDict, total=False): - References: Optional[PerformanceFactorReferenceSet] + References: PerformanceFactorReferenceSet | None class BaselinePerformanceFactors(TypedDict, total=False): - Cpu: Optional[CpuPerformanceFactor] + Cpu: CpuPerformanceFactor | None class PerformanceFactorReferenceRequest(TypedDict, total=False): - InstanceFamily: Optional[String] + InstanceFamily: String | None -PerformanceFactorReferenceSetRequest = List[PerformanceFactorReferenceRequest] +PerformanceFactorReferenceSetRequest = list[PerformanceFactorReferenceRequest] class CpuPerformanceFactorRequest(TypedDict, total=False): - References: Optional[PerformanceFactorReferenceSetRequest] + References: PerformanceFactorReferenceSetRequest | None class BaselinePerformanceFactorsRequest(TypedDict, total=False): - Cpu: Optional[CpuPerformanceFactorRequest] + Cpu: CpuPerformanceFactorRequest | None -BillingProductList = List[String] +BillingProductList = list[String] Blob = bytes class BlobAttributeValue(TypedDict, total=False): - Value: Optional[Blob] + Value: Blob | None class EbsBlockDevice(TypedDict, total=False): - DeleteOnTermination: Optional[Boolean] - Iops: Optional[Integer] - SnapshotId: Optional[SnapshotId] - VolumeSize: Optional[Integer] - VolumeType: Optional[VolumeType] - KmsKeyId: Optional[String] - Throughput: Optional[Integer] - OutpostArn: Optional[String] - AvailabilityZone: Optional[String] - Encrypted: Optional[Boolean] - VolumeInitializationRate: Optional[Integer] - AvailabilityZoneId: Optional[String] + DeleteOnTermination: Boolean | None + Iops: Integer | None + SnapshotId: SnapshotId | None + VolumeSize: Integer | None + VolumeType: VolumeType | None + KmsKeyId: String | None + Throughput: Integer | None + OutpostArn: String | None + AvailabilityZone: String | None + Encrypted: Boolean | None + VolumeInitializationRate: Integer | None + AvailabilityZoneId: String | None + EbsCardIndex: Integer | None class BlockDeviceMapping(TypedDict, total=False): - Ebs: Optional[EbsBlockDevice] - NoDevice: Optional[String] - DeviceName: Optional[String] - VirtualName: Optional[String] + Ebs: EbsBlockDevice | None + NoDevice: String | None + DeviceName: String | None + VirtualName: String | None -BlockDeviceMappingList = List[BlockDeviceMapping] -BlockDeviceMappingRequestList = List[BlockDeviceMapping] +BlockDeviceMappingList = list[BlockDeviceMapping] +BlockDeviceMappingRequestList = list[BlockDeviceMapping] class EbsBlockDeviceResponse(TypedDict, total=False): - Encrypted: Optional[Boolean] - DeleteOnTermination: Optional[Boolean] - Iops: Optional[Integer] - Throughput: Optional[Integer] - KmsKeyId: Optional[KmsKeyId] - SnapshotId: Optional[SnapshotId] - VolumeSize: Optional[Integer] - VolumeType: Optional[VolumeType] + Encrypted: Boolean | None + DeleteOnTermination: Boolean | None + Iops: Integer | None + Throughput: Integer | None + KmsKeyId: KmsKeyId | None + SnapshotId: SnapshotId | None + VolumeSize: Integer | None + VolumeType: VolumeType | None class BlockDeviceMappingResponse(TypedDict, total=False): - DeviceName: Optional[String] - VirtualName: Optional[String] - Ebs: Optional[EbsBlockDeviceResponse] - NoDevice: Optional[String] + DeviceName: String | None + VirtualName: String | None + Ebs: EbsBlockDeviceResponse | None + NoDevice: String | None -BlockDeviceMappingResponseList = List[BlockDeviceMappingResponse] +BlockDeviceMappingResponseList = list[BlockDeviceMappingResponse] class BlockPublicAccessStates(TypedDict, total=False): - InternetGatewayBlockMode: Optional[BlockPublicAccessMode] + InternetGatewayBlockMode: BlockPublicAccessMode | None -BootModeTypeList = List[BootModeType] +BootModeTypeList = list[BootModeType] BoxedLong = int -BundleIdStringList = List[BundleId] +BundleIdStringList = list[BundleId] class S3Storage(TypedDict, total=False): - AWSAccessKeyId: Optional[String] - Bucket: Optional[String] - Prefix: Optional[String] - UploadPolicy: Optional[Blob] - UploadPolicySignature: Optional[S3StorageUploadPolicySignature] + AWSAccessKeyId: String | None + Bucket: String | None + Prefix: String | None + UploadPolicy: Blob | None + UploadPolicySignature: S3StorageUploadPolicySignature | None class Storage(TypedDict, total=False): - S3: Optional[S3Storage] + S3: S3Storage | None class BundleInstanceRequest(ServiceRequest): InstanceId: InstanceId Storage: Storage - DryRun: Optional[Boolean] + DryRun: Boolean | None class BundleTaskError(TypedDict, total=False): - Code: Optional[String] - Message: Optional[String] + Code: String | None + Message: String | None class BundleTask(TypedDict, total=False): - InstanceId: Optional[String] - BundleId: Optional[String] - State: Optional[BundleTaskState] - StartTime: Optional[DateTime] - UpdateTime: Optional[DateTime] - Storage: Optional[Storage] - Progress: Optional[String] - BundleTaskError: Optional[BundleTaskError] + InstanceId: String | None + BundleId: String | None + State: BundleTaskState | None + StartTime: DateTime | None + UpdateTime: DateTime | None + Storage: Storage | None + Progress: String | None + BundleTaskError: BundleTaskError | None class BundleInstanceResult(TypedDict, total=False): - BundleTask: Optional[BundleTask] + BundleTask: BundleTask | None -BundleTaskList = List[BundleTask] +BundleTaskList = list[BundleTask] class Byoasn(TypedDict, total=False): - Asn: Optional[String] - IpamId: Optional[IpamId] - StatusMessage: Optional[String] - State: Optional[AsnState] + Asn: String | None + IpamId: IpamId | None + StatusMessage: String | None + State: AsnState | None -ByoasnSet = List[Byoasn] -ByoipCidrSet = List[ByoipCidr] +ByoasnSet = list[Byoasn] +ByoipCidrSet = list[ByoipCidr] class CancelBundleTaskRequest(ServiceRequest): BundleId: BundleId - DryRun: Optional[Boolean] + DryRun: Boolean | None class CancelBundleTaskResult(TypedDict, total=False): - BundleTask: Optional[BundleTask] + BundleTask: BundleTask | None class CancelCapacityReservationFleetError(TypedDict, total=False): - Code: Optional[CancelCapacityReservationFleetErrorCode] - Message: Optional[CancelCapacityReservationFleetErrorMessage] + Code: CancelCapacityReservationFleetErrorCode | None + Message: CancelCapacityReservationFleetErrorMessage | None -CapacityReservationFleetIdSet = List[CapacityReservationFleetId] +CapacityReservationFleetIdSet = list[CapacityReservationFleetId] class CancelCapacityReservationFleetsRequest(ServiceRequest): - DryRun: Optional[Boolean] + DryRun: Boolean | None CapacityReservationFleetIds: CapacityReservationFleetIdSet class FailedCapacityReservationFleetCancellationResult(TypedDict, total=False): - CapacityReservationFleetId: Optional[CapacityReservationFleetId] - CancelCapacityReservationFleetError: Optional[CancelCapacityReservationFleetError] + CapacityReservationFleetId: CapacityReservationFleetId | None + CancelCapacityReservationFleetError: CancelCapacityReservationFleetError | None -FailedCapacityReservationFleetCancellationResultSet = List[ +FailedCapacityReservationFleetCancellationResultSet = list[ FailedCapacityReservationFleetCancellationResult ] class CapacityReservationFleetCancellationState(TypedDict, total=False): - CurrentFleetState: Optional[CapacityReservationFleetState] - PreviousFleetState: Optional[CapacityReservationFleetState] - CapacityReservationFleetId: Optional[CapacityReservationFleetId] + CurrentFleetState: CapacityReservationFleetState | None + PreviousFleetState: CapacityReservationFleetState | None + CapacityReservationFleetId: CapacityReservationFleetId | None -CapacityReservationFleetCancellationStateSet = List[CapacityReservationFleetCancellationState] +CapacityReservationFleetCancellationStateSet = list[CapacityReservationFleetCancellationState] class CancelCapacityReservationFleetsResult(TypedDict, total=False): - SuccessfulFleetCancellations: Optional[CapacityReservationFleetCancellationStateSet] - FailedFleetCancellations: Optional[FailedCapacityReservationFleetCancellationResultSet] + SuccessfulFleetCancellations: CapacityReservationFleetCancellationStateSet | None + FailedFleetCancellations: FailedCapacityReservationFleetCancellationResultSet | None class CancelCapacityReservationRequest(ServiceRequest): CapacityReservationId: CapacityReservationId - DryRun: Optional[Boolean] + DryRun: Boolean | None class CancelCapacityReservationResult(TypedDict, total=False): - Return: Optional[Boolean] + Return: Boolean | None class CancelConversionRequest(ServiceRequest): - DryRun: Optional[Boolean] + DryRun: Boolean | None ConversionTaskId: ConversionTaskId - ReasonMessage: Optional[String] + ReasonMessage: String | None class CancelDeclarativePoliciesReportRequest(ServiceRequest): - DryRun: Optional[Boolean] + DryRun: Boolean | None ReportId: DeclarativePoliciesReportId class CancelDeclarativePoliciesReportResult(TypedDict, total=False): - Return: Optional[Boolean] + Return: Boolean | None class CancelExportTaskRequest(ServiceRequest): @@ -6030,23 +6704,23 @@ class CancelExportTaskRequest(ServiceRequest): class CancelImageLaunchPermissionRequest(ServiceRequest): ImageId: ImageId - DryRun: Optional[Boolean] + DryRun: Boolean | None class CancelImageLaunchPermissionResult(TypedDict, total=False): - Return: Optional[Boolean] + Return: Boolean | None class CancelImportTaskRequest(ServiceRequest): - CancelReason: Optional[String] - DryRun: Optional[Boolean] - ImportTaskId: Optional[ImportTaskId] + CancelReason: String | None + DryRun: Boolean | None + ImportTaskId: ImportTaskId | None class CancelImportTaskResult(TypedDict, total=False): - ImportTaskId: Optional[String] - PreviousState: Optional[String] - State: Optional[String] + ImportTaskId: String | None + PreviousState: String | None + State: String | None class CancelReservedInstancesListingRequest(ServiceRequest): @@ -6057,346 +6731,434 @@ class CancelReservedInstancesListingRequest(ServiceRequest): class PriceSchedule(TypedDict, total=False): - Active: Optional[Boolean] - CurrencyCode: Optional[CurrencyCodeValues] - Price: Optional[Double] - Term: Optional[Long] + Active: Boolean | None + CurrencyCode: CurrencyCodeValues | None + Price: Double | None + Term: Long | None -PriceScheduleList = List[PriceSchedule] +PriceScheduleList = list[PriceSchedule] class InstanceCount(TypedDict, total=False): - InstanceCount: Optional[Integer] - State: Optional[ListingState] + InstanceCount: Integer | None + State: ListingState | None -InstanceCountList = List[InstanceCount] +InstanceCountList = list[InstanceCount] class ReservedInstancesListing(TypedDict, total=False): - ClientToken: Optional[String] - CreateDate: Optional[DateTime] - InstanceCounts: Optional[InstanceCountList] - PriceSchedules: Optional[PriceScheduleList] - ReservedInstancesId: Optional[String] - ReservedInstancesListingId: Optional[String] - Status: Optional[ListingStatus] - StatusMessage: Optional[String] - Tags: Optional[TagList] - UpdateDate: Optional[DateTime] + ClientToken: String | None + CreateDate: DateTime | None + InstanceCounts: InstanceCountList | None + PriceSchedules: PriceScheduleList | None + ReservedInstancesId: String | None + ReservedInstancesListingId: String | None + Status: ListingStatus | None + StatusMessage: String | None + Tags: TagList | None + UpdateDate: DateTime | None -ReservedInstancesListingList = List[ReservedInstancesListing] +ReservedInstancesListingList = list[ReservedInstancesListing] class CancelReservedInstancesListingResult(TypedDict, total=False): - ReservedInstancesListings: Optional[ReservedInstancesListingList] + ReservedInstancesListings: ReservedInstancesListingList | None class CancelSpotFleetRequestsError(TypedDict, total=False): - Code: Optional[CancelBatchErrorCode] - Message: Optional[String] + Code: CancelBatchErrorCode | None + Message: String | None class CancelSpotFleetRequestsErrorItem(TypedDict, total=False): - Error: Optional[CancelSpotFleetRequestsError] - SpotFleetRequestId: Optional[String] + Error: CancelSpotFleetRequestsError | None + SpotFleetRequestId: String | None -CancelSpotFleetRequestsErrorSet = List[CancelSpotFleetRequestsErrorItem] -SpotFleetRequestIdList = List[SpotFleetRequestId] +CancelSpotFleetRequestsErrorSet = list[CancelSpotFleetRequestsErrorItem] +SpotFleetRequestIdList = list[SpotFleetRequestId] class CancelSpotFleetRequestsRequest(ServiceRequest): - DryRun: Optional[Boolean] + DryRun: Boolean | None SpotFleetRequestIds: SpotFleetRequestIdList TerminateInstances: Boolean class CancelSpotFleetRequestsSuccessItem(TypedDict, total=False): - CurrentSpotFleetRequestState: Optional[BatchState] - PreviousSpotFleetRequestState: Optional[BatchState] - SpotFleetRequestId: Optional[String] + CurrentSpotFleetRequestState: BatchState | None + PreviousSpotFleetRequestState: BatchState | None + SpotFleetRequestId: String | None -CancelSpotFleetRequestsSuccessSet = List[CancelSpotFleetRequestsSuccessItem] +CancelSpotFleetRequestsSuccessSet = list[CancelSpotFleetRequestsSuccessItem] class CancelSpotFleetRequestsResponse(TypedDict, total=False): - SuccessfulFleetRequests: Optional[CancelSpotFleetRequestsSuccessSet] - UnsuccessfulFleetRequests: Optional[CancelSpotFleetRequestsErrorSet] + SuccessfulFleetRequests: CancelSpotFleetRequestsSuccessSet | None + UnsuccessfulFleetRequests: CancelSpotFleetRequestsErrorSet | None -SpotInstanceRequestIdList = List[SpotInstanceRequestId] +SpotInstanceRequestIdList = list[SpotInstanceRequestId] class CancelSpotInstanceRequestsRequest(ServiceRequest): - DryRun: Optional[Boolean] + DryRun: Boolean | None SpotInstanceRequestIds: SpotInstanceRequestIdList class CancelledSpotInstanceRequest(TypedDict, total=False): - SpotInstanceRequestId: Optional[String] - State: Optional[CancelSpotInstanceRequestState] + SpotInstanceRequestId: String | None + State: CancelSpotInstanceRequestState | None -CancelledSpotInstanceRequestList = List[CancelledSpotInstanceRequest] +CancelledSpotInstanceRequestList = list[CancelledSpotInstanceRequest] class CancelSpotInstanceRequestsResult(TypedDict, total=False): - CancelledSpotInstanceRequests: Optional[CancelledSpotInstanceRequestList] + CancelledSpotInstanceRequests: CancelledSpotInstanceRequestList | None class CapacityAllocation(TypedDict, total=False): - AllocationType: Optional[AllocationType] - Count: Optional[Integer] + AllocationType: AllocationType | None + Count: Integer | None -CapacityAllocations = List[CapacityAllocation] -CapacityReservationIdSet = List[CapacityReservationId] +CapacityAllocations = list[CapacityAllocation] +CapacityReservationIdSet = list[CapacityReservationId] class CapacityBlock(TypedDict, total=False): - CapacityBlockId: Optional[CapacityBlockId] - UltraserverType: Optional[String] - AvailabilityZone: Optional[String] - AvailabilityZoneId: Optional[String] - CapacityReservationIds: Optional[CapacityReservationIdSet] - StartDate: Optional[MillisecondDateTime] - EndDate: Optional[MillisecondDateTime] - CreateDate: Optional[MillisecondDateTime] - State: Optional[CapacityBlockResourceState] - Tags: Optional[TagList] + CapacityBlockId: CapacityBlockId | None + UltraserverType: String | None + AvailabilityZone: String | None + AvailabilityZoneId: String | None + CapacityReservationIds: CapacityReservationIdSet | None + StartDate: MillisecondDateTime | None + EndDate: MillisecondDateTime | None + CreateDate: MillisecondDateTime | None + State: CapacityBlockResourceState | None + Tags: TagList | None class CapacityBlockExtension(TypedDict, total=False): - CapacityReservationId: Optional[CapacityReservationId] - InstanceType: Optional[String] - InstanceCount: Optional[Integer] - AvailabilityZone: Optional[AvailabilityZoneName] - AvailabilityZoneId: Optional[AvailabilityZoneId] - CapacityBlockExtensionOfferingId: Optional[OfferingId] - CapacityBlockExtensionDurationHours: Optional[Integer] - CapacityBlockExtensionStatus: Optional[CapacityBlockExtensionStatus] - CapacityBlockExtensionPurchaseDate: Optional[MillisecondDateTime] - CapacityBlockExtensionStartDate: Optional[MillisecondDateTime] - CapacityBlockExtensionEndDate: Optional[MillisecondDateTime] - UpfrontFee: Optional[String] - CurrencyCode: Optional[String] + CapacityReservationId: CapacityReservationId | None + InstanceType: String | None + InstanceCount: Integer | None + AvailabilityZone: AvailabilityZoneName | None + AvailabilityZoneId: AvailabilityZoneId | None + CapacityBlockExtensionOfferingId: OfferingId | None + CapacityBlockExtensionDurationHours: Integer | None + CapacityBlockExtensionStatus: CapacityBlockExtensionStatus | None + CapacityBlockExtensionPurchaseDate: MillisecondDateTime | None + CapacityBlockExtensionStartDate: MillisecondDateTime | None + CapacityBlockExtensionEndDate: MillisecondDateTime | None + UpfrontFee: String | None + CurrencyCode: String | None + ZoneType: String | None class CapacityBlockExtensionOffering(TypedDict, total=False): - CapacityBlockExtensionOfferingId: Optional[OfferingId] - InstanceType: Optional[String] - InstanceCount: Optional[Integer] - AvailabilityZone: Optional[AvailabilityZoneName] - AvailabilityZoneId: Optional[AvailabilityZoneId] - StartDate: Optional[MillisecondDateTime] - CapacityBlockExtensionStartDate: Optional[MillisecondDateTime] - CapacityBlockExtensionEndDate: Optional[MillisecondDateTime] - CapacityBlockExtensionDurationHours: Optional[Integer] - UpfrontFee: Optional[String] - CurrencyCode: Optional[String] - Tenancy: Optional[CapacityReservationTenancy] - - -CapacityBlockExtensionOfferingSet = List[CapacityBlockExtensionOffering] -CapacityBlockExtensionSet = List[CapacityBlockExtension] -CapacityBlockIds = List[CapacityBlockId] + CapacityBlockExtensionOfferingId: OfferingId | None + InstanceType: String | None + InstanceCount: Integer | None + AvailabilityZone: AvailabilityZoneName | None + AvailabilityZoneId: AvailabilityZoneId | None + StartDate: MillisecondDateTime | None + CapacityBlockExtensionStartDate: MillisecondDateTime | None + CapacityBlockExtensionEndDate: MillisecondDateTime | None + CapacityBlockExtensionDurationHours: Integer | None + UpfrontFee: String | None + CurrencyCode: String | None + Tenancy: CapacityReservationTenancy | None + ZoneType: String | None + + +CapacityBlockExtensionOfferingSet = list[CapacityBlockExtensionOffering] +CapacityBlockExtensionSet = list[CapacityBlockExtension] +CapacityBlockIds = list[CapacityBlockId] class CapacityBlockOffering(TypedDict, total=False): - CapacityBlockOfferingId: Optional[OfferingId] - InstanceType: Optional[String] - AvailabilityZone: Optional[String] - InstanceCount: Optional[Integer] - StartDate: Optional[MillisecondDateTime] - EndDate: Optional[MillisecondDateTime] - CapacityBlockDurationHours: Optional[Integer] - UpfrontFee: Optional[String] - CurrencyCode: Optional[String] - Tenancy: Optional[CapacityReservationTenancy] - UltraserverType: Optional[String] - UltraserverCount: Optional[BoxedInteger] - CapacityBlockDurationMinutes: Optional[Integer] - - -CapacityBlockOfferingSet = List[CapacityBlockOffering] -CapacityBlockSet = List[CapacityBlock] + CapacityBlockOfferingId: OfferingId | None + InstanceType: String | None + AvailabilityZone: String | None + InstanceCount: Integer | None + StartDate: MillisecondDateTime | None + EndDate: MillisecondDateTime | None + CapacityBlockDurationHours: Integer | None + UpfrontFee: String | None + CurrencyCode: String | None + Tenancy: CapacityReservationTenancy | None + UltraserverType: String | None + UltraserverCount: BoxedInteger | None + CapacityBlockDurationMinutes: Integer | None + ZoneType: String | None + + +CapacityBlockOfferingSet = list[CapacityBlockOffering] +CapacityBlockSet = list[CapacityBlock] class CapacityReservationStatus(TypedDict, total=False): - CapacityReservationId: Optional[CapacityReservationId] - TotalCapacity: Optional[Integer] - TotalAvailableCapacity: Optional[Integer] - TotalUnavailableCapacity: Optional[Integer] + CapacityReservationId: CapacityReservationId | None + TotalCapacity: Integer | None + TotalAvailableCapacity: Integer | None + TotalUnavailableCapacity: Integer | None -CapacityReservationStatusSet = List[CapacityReservationStatus] +CapacityReservationStatusSet = list[CapacityReservationStatus] class CapacityBlockStatus(TypedDict, total=False): - CapacityBlockId: Optional[CapacityBlockId] - InterconnectStatus: Optional[CapacityBlockInterconnectStatus] - TotalCapacity: Optional[Integer] - TotalAvailableCapacity: Optional[Integer] - TotalUnavailableCapacity: Optional[Integer] - CapacityReservationStatuses: Optional[CapacityReservationStatusSet] + CapacityBlockId: CapacityBlockId | None + InterconnectStatus: CapacityBlockInterconnectStatus | None + TotalCapacity: Integer | None + TotalAvailableCapacity: Integer | None + TotalUnavailableCapacity: Integer | None + CapacityReservationStatuses: CapacityReservationStatusSet | None -CapacityBlockStatusSet = List[CapacityBlockStatus] +CapacityBlockStatusSet = list[CapacityBlockStatus] +ConditionValueList = list[String] -class CapacityReservationCommitmentInfo(TypedDict, total=False): - CommittedInstanceCount: Optional[Integer] - CommitmentEndDate: Optional[MillisecondDateTime] +class DimensionCondition(TypedDict, total=False): + Dimension: FilterByDimension | None + Comparison: Comparison | None + Values: ConditionValueList | None -class CapacityReservation(TypedDict, total=False): - CapacityReservationId: Optional[String] - OwnerId: Optional[String] - CapacityReservationArn: Optional[String] - AvailabilityZoneId: Optional[String] - InstanceType: Optional[String] - InstancePlatform: Optional[CapacityReservationInstancePlatform] - AvailabilityZone: Optional[String] - Tenancy: Optional[CapacityReservationTenancy] - TotalInstanceCount: Optional[Integer] - AvailableInstanceCount: Optional[Integer] - EbsOptimized: Optional[Boolean] - EphemeralStorage: Optional[Boolean] - State: Optional[CapacityReservationState] - StartDate: Optional[MillisecondDateTime] - EndDate: Optional[DateTime] - EndDateType: Optional[EndDateType] - InstanceMatchCriteria: Optional[InstanceMatchCriteria] - CreateDate: Optional[DateTime] - Tags: Optional[TagList] - OutpostArn: Optional[OutpostArn] - CapacityReservationFleetId: Optional[String] - PlacementGroupArn: Optional[PlacementGroupArn] - CapacityAllocations: Optional[CapacityAllocations] - ReservationType: Optional[CapacityReservationType] - UnusedReservationBillingOwnerId: Optional[AccountID] - CommitmentInfo: Optional[CapacityReservationCommitmentInfo] - DeliveryPreference: Optional[CapacityReservationDeliveryPreference] - CapacityBlockId: Optional[CapacityBlockId] +class CapacityManagerCondition(TypedDict, total=False): + DimensionCondition: DimensionCondition | None -class CapacityReservationInfo(TypedDict, total=False): - InstanceType: Optional[String] - AvailabilityZone: Optional[AvailabilityZoneName] - Tenancy: Optional[CapacityReservationTenancy] - AvailabilityZoneId: Optional[AvailabilityZoneId] +CapacityManagerConditionSet = list[CapacityManagerCondition] +CapacityManagerDataExportIdSet = list[CapacityManagerDataExportId] -class CapacityReservationBillingRequest(TypedDict, total=False): - CapacityReservationId: Optional[String] - RequestedBy: Optional[String] - UnusedReservationBillingOwnerId: Optional[AccountID] - LastUpdateTime: Optional[MillisecondDateTime] - Status: Optional[CapacityReservationBillingRequestStatus] - StatusMessage: Optional[String] - CapacityReservationInfo: Optional[CapacityReservationInfo] +class CapacityManagerDataExportResponse(TypedDict, total=False): + CapacityManagerDataExportId: CapacityManagerDataExportId | None + S3BucketName: String | None + S3BucketPrefix: String | None + Schedule: Schedule | None + OutputFormat: OutputFormat | None + CreateTime: MillisecondDateTime | None + LatestDeliveryStatus: CapacityManagerDataExportStatus | None + LatestDeliveryStatusMessage: String | None + LatestDeliveryS3LocationUri: String | None + LatestDeliveryTime: MillisecondDateTime | None + Tags: TagList | None -CapacityReservationBillingRequestSet = List[CapacityReservationBillingRequest] -CapacityReservationCommitmentDuration = int +CapacityManagerDataExportResponseSet = list[CapacityManagerDataExportResponse] -class FleetCapacityReservation(TypedDict, total=False): - CapacityReservationId: Optional[CapacityReservationId] - AvailabilityZoneId: Optional[String] - InstanceType: Optional[InstanceType] - InstancePlatform: Optional[CapacityReservationInstancePlatform] - AvailabilityZone: Optional[String] - TotalInstanceCount: Optional[Integer] - FulfilledCapacity: Optional[Double] - EbsOptimized: Optional[Boolean] - CreateDate: Optional[MillisecondDateTime] - Weight: Optional[DoubleWithConstraints] - Priority: Optional[IntegerWithConstraints] +class CapacityManagerDimension(TypedDict, total=False): + ResourceRegion: String | None + AvailabilityZoneId: String | None + AccountId: String | None + InstanceFamily: String | None + InstanceType: String | None + InstancePlatform: String | None + ReservationArn: String | None + ReservationId: String | None + ReservationType: ReservationType | None + ReservationCreateTimestamp: MillisecondDateTime | None + ReservationStartTimestamp: MillisecondDateTime | None + ReservationEndTimestamp: MillisecondDateTime | None + ReservationEndDateType: ReservationEndDateType | None + Tenancy: CapacityTenancy | None + ReservationState: ReservationState | None + ReservationInstanceMatchCriteria: String | None + ReservationUnusedFinancialOwner: String | None -FleetCapacityReservationSet = List[FleetCapacityReservation] +class InterruptionInfo(TypedDict, total=False): + SourceCapacityReservationId: String | None + InterruptionType: InterruptionType | None -class CapacityReservationFleet(TypedDict, total=False): - CapacityReservationFleetId: Optional[CapacityReservationFleetId] - CapacityReservationFleetArn: Optional[String] - State: Optional[CapacityReservationFleetState] - TotalTargetCapacity: Optional[Integer] - TotalFulfilledCapacity: Optional[Double] - Tenancy: Optional[FleetCapacityReservationTenancy] - EndDate: Optional[MillisecondDateTime] - CreateTime: Optional[MillisecondDateTime] - InstanceMatchCriteria: Optional[FleetInstanceMatchCriteria] - AllocationStrategy: Optional[String] - InstanceTypeSpecifications: Optional[FleetCapacityReservationSet] - Tags: Optional[TagList] +class InterruptibleCapacityAllocation(TypedDict, total=False): + InstanceCount: Integer | None + TargetInstanceCount: Integer | None + Status: InterruptibleCapacityReservationAllocationStatus | None + InterruptibleCapacityReservationId: String | None + InterruptionType: InterruptionType | None -CapacityReservationFleetSet = List[CapacityReservationFleet] +class CapacityReservationCommitmentInfo(TypedDict, total=False): + CommittedInstanceCount: Integer | None + CommitmentEndDate: MillisecondDateTime | None -class CapacityReservationGroup(TypedDict, total=False): - GroupArn: Optional[String] - OwnerId: Optional[String] +class CapacityReservation(TypedDict, total=False): + CapacityReservationId: String | None + OwnerId: String | None + CapacityReservationArn: String | None + AvailabilityZoneId: String | None + InstanceType: String | None + InstancePlatform: CapacityReservationInstancePlatform | None + AvailabilityZone: String | None + Tenancy: CapacityReservationTenancy | None + TotalInstanceCount: Integer | None + AvailableInstanceCount: Integer | None + EbsOptimized: Boolean | None + EphemeralStorage: Boolean | None + State: CapacityReservationState | None + StartDate: MillisecondDateTime | None + EndDate: DateTime | None + EndDateType: EndDateType | None + InstanceMatchCriteria: InstanceMatchCriteria | None + CreateDate: DateTime | None + Tags: TagList | None + OutpostArn: OutpostArn | None + CapacityReservationFleetId: String | None + PlacementGroupArn: PlacementGroupArn | None + CapacityAllocations: CapacityAllocations | None + ReservationType: CapacityReservationType | None + UnusedReservationBillingOwnerId: AccountID | None + CommitmentInfo: CapacityReservationCommitmentInfo | None + DeliveryPreference: CapacityReservationDeliveryPreference | None + CapacityBlockId: CapacityBlockId | None + Interruptible: BoxedBoolean | None + InterruptibleCapacityAllocation: InterruptibleCapacityAllocation | None + InterruptionInfo: InterruptionInfo | None -CapacityReservationGroupSet = List[CapacityReservationGroup] +class CapacityReservationInfo(TypedDict, total=False): + InstanceType: String | None + AvailabilityZone: AvailabilityZoneName | None + Tenancy: CapacityReservationTenancy | None + AvailabilityZoneId: AvailabilityZoneId | None -class CapacityReservationOptions(TypedDict, total=False): - UsageStrategy: Optional[FleetCapacityReservationUsageStrategy] +class CapacityReservationBillingRequest(TypedDict, total=False): + CapacityReservationId: String | None + RequestedBy: String | None + UnusedReservationBillingOwnerId: AccountID | None + LastUpdateTime: MillisecondDateTime | None + Status: CapacityReservationBillingRequestStatus | None + StatusMessage: String | None + CapacityReservationInfo: CapacityReservationInfo | None + + +CapacityReservationBillingRequestSet = list[CapacityReservationBillingRequest] +CapacityReservationCommitmentDuration = int + + +class FleetCapacityReservation(TypedDict, total=False): + CapacityReservationId: CapacityReservationId | None + AvailabilityZoneId: String | None + InstanceType: InstanceType | None + InstancePlatform: CapacityReservationInstancePlatform | None + AvailabilityZone: String | None + TotalInstanceCount: Integer | None + FulfilledCapacity: Double | None + EbsOptimized: Boolean | None + CreateDate: MillisecondDateTime | None + Weight: DoubleWithConstraints | None + Priority: IntegerWithConstraints | None + + +FleetCapacityReservationSet = list[FleetCapacityReservation] + + +class CapacityReservationFleet(TypedDict, total=False): + CapacityReservationFleetId: CapacityReservationFleetId | None + CapacityReservationFleetArn: String | None + State: CapacityReservationFleetState | None + TotalTargetCapacity: Integer | None + TotalFulfilledCapacity: Double | None + Tenancy: FleetCapacityReservationTenancy | None + EndDate: MillisecondDateTime | None + CreateTime: MillisecondDateTime | None + InstanceMatchCriteria: FleetInstanceMatchCriteria | None + AllocationStrategy: String | None + InstanceTypeSpecifications: FleetCapacityReservationSet | None + Tags: TagList | None + + +CapacityReservationFleetSet = list[CapacityReservationFleet] + + +class CapacityReservationGroup(TypedDict, total=False): + GroupArn: String | None + OwnerId: String | None + + +CapacityReservationGroupSet = list[CapacityReservationGroup] + + +class CapacityReservationOptions(TypedDict, total=False): + UsageStrategy: FleetCapacityReservationUsageStrategy | None class CapacityReservationOptionsRequest(TypedDict, total=False): - UsageStrategy: Optional[FleetCapacityReservationUsageStrategy] + UsageStrategy: FleetCapacityReservationUsageStrategy | None -CapacityReservationSet = List[CapacityReservation] +CapacityReservationSet = list[CapacityReservation] class CapacityReservationTarget(TypedDict, total=False): - CapacityReservationId: Optional[CapacityReservationId] - CapacityReservationResourceGroupArn: Optional[String] + CapacityReservationId: CapacityReservationId | None + CapacityReservationResourceGroupArn: String | None class CapacityReservationSpecification(TypedDict, total=False): - CapacityReservationPreference: Optional[CapacityReservationPreference] - CapacityReservationTarget: Optional[CapacityReservationTarget] + CapacityReservationPreference: CapacityReservationPreference | None + CapacityReservationTarget: CapacityReservationTarget | None class CapacityReservationTargetResponse(TypedDict, total=False): - CapacityReservationId: Optional[String] - CapacityReservationResourceGroupArn: Optional[String] + CapacityReservationId: String | None + CapacityReservationResourceGroupArn: String | None class CapacityReservationSpecificationResponse(TypedDict, total=False): - CapacityReservationPreference: Optional[CapacityReservationPreference] - CapacityReservationTarget: Optional[CapacityReservationTargetResponse] + CapacityReservationPreference: CapacityReservationPreference | None + CapacityReservationTarget: CapacityReservationTargetResponse | None + + +NetworkNodeSet = list[String] + + +class CapacityReservationTopology(TypedDict, total=False): + CapacityReservationId: String | None + CapacityBlockId: String | None + State: String | None + InstanceType: String | None + GroupName: String | None + NetworkNodes: NetworkNodeSet | None + AvailabilityZoneId: String | None + AvailabilityZone: String | None + + +CapacityReservationTopologySet = list[CapacityReservationTopology] class CarrierGateway(TypedDict, total=False): - CarrierGatewayId: Optional[CarrierGatewayId] - VpcId: Optional[VpcId] - State: Optional[CarrierGatewayState] - OwnerId: Optional[String] - Tags: Optional[TagList] + CarrierGatewayId: CarrierGatewayId | None + VpcId: VpcId | None + State: CarrierGatewayState | None + OwnerId: String | None + Tags: TagList | None -CarrierGatewayIdSet = List[CarrierGatewayId] -CarrierGatewaySet = List[CarrierGateway] +CarrierGatewayIdSet = list[CarrierGatewayId] +CarrierGatewaySet = list[CarrierGateway] class CertificateAuthentication(TypedDict, total=False): - ClientRootCertificateChain: Optional[String] + ClientRootCertificateChain: String | None class CertificateAuthenticationRequest(TypedDict, total=False): - ClientRootCertificateChainArn: Optional[String] + ClientRootCertificateChainArn: String | None class CidrAuthorizationContext(TypedDict, total=False): @@ -6405,1601 +7167,1850 @@ class CidrAuthorizationContext(TypedDict, total=False): class ClassicLinkDnsSupport(TypedDict, total=False): - ClassicLinkDnsSupported: Optional[Boolean] - VpcId: Optional[String] + ClassicLinkDnsSupported: Boolean | None + VpcId: String | None -ClassicLinkDnsSupportList = List[ClassicLinkDnsSupport] +ClassicLinkDnsSupportList = list[ClassicLinkDnsSupport] class GroupIdentifier(TypedDict, total=False): - GroupId: Optional[String] - GroupName: Optional[String] + GroupId: String | None + GroupName: String | None -GroupIdentifierList = List[GroupIdentifier] +GroupIdentifierList = list[GroupIdentifier] class ClassicLinkInstance(TypedDict, total=False): - Groups: Optional[GroupIdentifierList] - InstanceId: Optional[String] - Tags: Optional[TagList] - VpcId: Optional[String] + Groups: GroupIdentifierList | None + InstanceId: String | None + Tags: TagList | None + VpcId: String | None -ClassicLinkInstanceList = List[ClassicLinkInstance] +ClassicLinkInstanceList = list[ClassicLinkInstance] class ClassicLoadBalancer(TypedDict, total=False): - Name: Optional[String] + Name: String | None -ClassicLoadBalancers = List[ClassicLoadBalancer] +ClassicLoadBalancers = list[ClassicLoadBalancer] class ClassicLoadBalancersConfig(TypedDict, total=False): - ClassicLoadBalancers: Optional[ClassicLoadBalancers] + ClassicLoadBalancers: ClassicLoadBalancers | None class ClientCertificateRevocationListStatus(TypedDict, total=False): - Code: Optional[ClientCertificateRevocationListStatusCode] - Message: Optional[String] + Code: ClientCertificateRevocationListStatusCode | None + Message: String | None class ClientConnectOptions(TypedDict, total=False): - Enabled: Optional[Boolean] - LambdaFunctionArn: Optional[String] + Enabled: Boolean | None + LambdaFunctionArn: String | None class ClientVpnEndpointAttributeStatus(TypedDict, total=False): - Code: Optional[ClientVpnEndpointAttributeStatusCode] - Message: Optional[String] + Code: ClientVpnEndpointAttributeStatusCode | None + Message: String | None class ClientConnectResponseOptions(TypedDict, total=False): - Enabled: Optional[Boolean] - LambdaFunctionArn: Optional[String] - Status: Optional[ClientVpnEndpointAttributeStatus] + Enabled: Boolean | None + LambdaFunctionArn: String | None + Status: ClientVpnEndpointAttributeStatus | None class ClientData(TypedDict, total=False): - Comment: Optional[String] - UploadEnd: Optional[DateTime] - UploadSize: Optional[Double] - UploadStart: Optional[DateTime] + Comment: String | None + UploadEnd: DateTime | None + UploadSize: Double | None + UploadStart: DateTime | None class ClientLoginBannerOptions(TypedDict, total=False): - Enabled: Optional[Boolean] - BannerText: Optional[String] + Enabled: Boolean | None + BannerText: String | None class ClientLoginBannerResponseOptions(TypedDict, total=False): - Enabled: Optional[Boolean] - BannerText: Optional[String] + Enabled: Boolean | None + BannerText: String | None class ClientRouteEnforcementOptions(TypedDict, total=False): - Enforced: Optional[Boolean] + Enforced: Boolean | None class ClientRouteEnforcementResponseOptions(TypedDict, total=False): - Enforced: Optional[Boolean] + Enforced: Boolean | None class FederatedAuthentication(TypedDict, total=False): - SamlProviderArn: Optional[String] - SelfServiceSamlProviderArn: Optional[String] + SamlProviderArn: String | None + SelfServiceSamlProviderArn: String | None class DirectoryServiceAuthentication(TypedDict, total=False): - DirectoryId: Optional[String] + DirectoryId: String | None class ClientVpnAuthentication(TypedDict, total=False): - Type: Optional[ClientVpnAuthenticationType] - ActiveDirectory: Optional[DirectoryServiceAuthentication] - MutualAuthentication: Optional[CertificateAuthentication] - FederatedAuthentication: Optional[FederatedAuthentication] + Type: ClientVpnAuthenticationType | None + ActiveDirectory: DirectoryServiceAuthentication | None + MutualAuthentication: CertificateAuthentication | None + FederatedAuthentication: FederatedAuthentication | None -ClientVpnAuthenticationList = List[ClientVpnAuthentication] +ClientVpnAuthenticationList = list[ClientVpnAuthentication] class FederatedAuthenticationRequest(TypedDict, total=False): - SAMLProviderArn: Optional[String] - SelfServiceSAMLProviderArn: Optional[String] + SAMLProviderArn: String | None + SelfServiceSAMLProviderArn: String | None class DirectoryServiceAuthenticationRequest(TypedDict, total=False): - DirectoryId: Optional[String] + DirectoryId: String | None class ClientVpnAuthenticationRequest(TypedDict, total=False): - Type: Optional[ClientVpnAuthenticationType] - ActiveDirectory: Optional[DirectoryServiceAuthenticationRequest] - MutualAuthentication: Optional[CertificateAuthenticationRequest] - FederatedAuthentication: Optional[FederatedAuthenticationRequest] + Type: ClientVpnAuthenticationType | None + ActiveDirectory: DirectoryServiceAuthenticationRequest | None + MutualAuthentication: CertificateAuthenticationRequest | None + FederatedAuthentication: FederatedAuthenticationRequest | None -ClientVpnAuthenticationRequestList = List[ClientVpnAuthenticationRequest] +ClientVpnAuthenticationRequestList = list[ClientVpnAuthenticationRequest] class ClientVpnConnectionStatus(TypedDict, total=False): - Code: Optional[ClientVpnConnectionStatusCode] - Message: Optional[String] + Code: ClientVpnConnectionStatusCode | None + Message: String | None class ClientVpnConnection(TypedDict, total=False): - ClientVpnEndpointId: Optional[String] - Timestamp: Optional[String] - ConnectionId: Optional[String] - Username: Optional[String] - ConnectionEstablishedTime: Optional[String] - IngressBytes: Optional[String] - EgressBytes: Optional[String] - IngressPackets: Optional[String] - EgressPackets: Optional[String] - ClientIp: Optional[String] - ClientIpv6Address: Optional[String] - CommonName: Optional[String] - Status: Optional[ClientVpnConnectionStatus] - ConnectionEndTime: Optional[String] - PostureComplianceStatuses: Optional[ValueStringList] - - -ClientVpnConnectionSet = List[ClientVpnConnection] + ClientVpnEndpointId: String | None + Timestamp: String | None + ConnectionId: String | None + Username: String | None + ConnectionEstablishedTime: String | None + IngressBytes: String | None + EgressBytes: String | None + IngressPackets: String | None + EgressPackets: String | None + ClientIp: String | None + ClientIpv6Address: String | None + CommonName: String | None + Status: ClientVpnConnectionStatus | None + ConnectionEndTime: String | None + PostureComplianceStatuses: ValueStringList | None + + +ClientVpnConnectionSet = list[ClientVpnConnection] class ConnectionLogResponseOptions(TypedDict, total=False): - Enabled: Optional[Boolean] - CloudwatchLogGroup: Optional[String] - CloudwatchLogStream: Optional[String] + Enabled: Boolean | None + CloudwatchLogGroup: String | None + CloudwatchLogStream: String | None class ClientVpnEndpointStatus(TypedDict, total=False): - Code: Optional[ClientVpnEndpointStatusCode] - Message: Optional[String] + Code: ClientVpnEndpointStatusCode | None + Message: String | None class ClientVpnEndpoint(TypedDict, total=False): - ClientVpnEndpointId: Optional[String] - Description: Optional[String] - Status: Optional[ClientVpnEndpointStatus] - CreationTime: Optional[String] - DeletionTime: Optional[String] - DnsName: Optional[String] - ClientCidrBlock: Optional[String] - DnsServers: Optional[ValueStringList] - SplitTunnel: Optional[Boolean] - VpnProtocol: Optional[VpnProtocol] - TransportProtocol: Optional[TransportProtocol] - VpnPort: Optional[Integer] - AssociatedTargetNetworks: Optional[AssociatedTargetNetworkSet] - ServerCertificateArn: Optional[String] - AuthenticationOptions: Optional[ClientVpnAuthenticationList] - ConnectionLogOptions: Optional[ConnectionLogResponseOptions] - Tags: Optional[TagList] - SecurityGroupIds: Optional[ClientVpnSecurityGroupIdSet] - VpcId: Optional[VpcId] - SelfServicePortalUrl: Optional[String] - ClientConnectOptions: Optional[ClientConnectResponseOptions] - SessionTimeoutHours: Optional[Integer] - ClientLoginBannerOptions: Optional[ClientLoginBannerResponseOptions] - ClientRouteEnforcementOptions: Optional[ClientRouteEnforcementResponseOptions] - DisconnectOnSessionTimeout: Optional[Boolean] - EndpointIpAddressType: Optional[EndpointIpAddressType] - TrafficIpAddressType: Optional[TrafficIpAddressType] - - -ClientVpnEndpointIdList = List[ClientVpnEndpointId] + ClientVpnEndpointId: String | None + Description: String | None + Status: ClientVpnEndpointStatus | None + CreationTime: String | None + DeletionTime: String | None + DnsName: String | None + ClientCidrBlock: String | None + DnsServers: ValueStringList | None + SplitTunnel: Boolean | None + VpnProtocol: VpnProtocol | None + TransportProtocol: TransportProtocol | None + VpnPort: Integer | None + AssociatedTargetNetworks: AssociatedTargetNetworkSet | None + ServerCertificateArn: String | None + AuthenticationOptions: ClientVpnAuthenticationList | None + ConnectionLogOptions: ConnectionLogResponseOptions | None + Tags: TagList | None + SecurityGroupIds: ClientVpnSecurityGroupIdSet | None + VpcId: VpcId | None + SelfServicePortalUrl: String | None + ClientConnectOptions: ClientConnectResponseOptions | None + SessionTimeoutHours: Integer | None + ClientLoginBannerOptions: ClientLoginBannerResponseOptions | None + ClientRouteEnforcementOptions: ClientRouteEnforcementResponseOptions | None + DisconnectOnSessionTimeout: Boolean | None + EndpointIpAddressType: EndpointIpAddressType | None + TrafficIpAddressType: TrafficIpAddressType | None + + +ClientVpnEndpointIdList = list[ClientVpnEndpointId] class ClientVpnRouteStatus(TypedDict, total=False): - Code: Optional[ClientVpnRouteStatusCode] - Message: Optional[String] + Code: ClientVpnRouteStatusCode | None + Message: String | None class ClientVpnRoute(TypedDict, total=False): - ClientVpnEndpointId: Optional[String] - DestinationCidr: Optional[String] - TargetSubnet: Optional[String] - Type: Optional[String] - Origin: Optional[String] - Status: Optional[ClientVpnRouteStatus] - Description: Optional[String] + ClientVpnEndpointId: String | None + DestinationCidr: String | None + TargetSubnet: String | None + Type: String | None + Origin: String | None + Status: ClientVpnRouteStatus | None + Description: String | None -ClientVpnRouteSet = List[ClientVpnRoute] +ClientVpnRouteSet = list[ClientVpnRoute] class CloudWatchLogOptions(TypedDict, total=False): - LogEnabled: Optional[Boolean] - LogGroupArn: Optional[String] - LogOutputFormat: Optional[String] + LogEnabled: Boolean | None + LogGroupArn: String | None + LogOutputFormat: String | None + BgpLogEnabled: Boolean | None + BgpLogGroupArn: String | None + BgpLogOutputFormat: String | None class CloudWatchLogOptionsSpecification(TypedDict, total=False): - LogEnabled: Optional[Boolean] - LogGroupArn: Optional[CloudWatchLogGroupArn] - LogOutputFormat: Optional[String] + LogEnabled: Boolean | None + LogGroupArn: CloudWatchLogGroupArn | None + LogOutputFormat: String | None + BgpLogEnabled: Boolean | None + BgpLogGroupArn: CloudWatchLogGroupArn | None + BgpLogOutputFormat: String | None class CoipAddressUsage(TypedDict, total=False): - AllocationId: Optional[String] - AwsAccountId: Optional[String] - AwsService: Optional[String] - CoIp: Optional[String] + AllocationId: String | None + AwsAccountId: String | None + AwsService: String | None + CoIp: String | None -CoipAddressUsageSet = List[CoipAddressUsage] +CoipAddressUsageSet = list[CoipAddressUsage] class CoipCidr(TypedDict, total=False): - Cidr: Optional[String] - CoipPoolId: Optional[Ipv4PoolCoipId] - LocalGatewayRouteTableId: Optional[String] + Cidr: String | None + CoipPoolId: Ipv4PoolCoipId | None + LocalGatewayRouteTableId: String | None class CoipPool(TypedDict, total=False): - PoolId: Optional[Ipv4PoolCoipId] - PoolCidrs: Optional[ValueStringList] - LocalGatewayRouteTableId: Optional[LocalGatewayRoutetableId] - Tags: Optional[TagList] - PoolArn: Optional[ResourceArn] + PoolId: Ipv4PoolCoipId | None + PoolCidrs: ValueStringList | None + LocalGatewayRouteTableId: LocalGatewayRoutetableId | None + Tags: TagList | None + PoolArn: ResourceArn | None -CoipPoolIdSet = List[Ipv4PoolCoipId] -CoipPoolSet = List[CoipPool] +CoipPoolIdSet = list[Ipv4PoolCoipId] +CoipPoolSet = list[CoipPool] class ConfirmProductInstanceRequest(ServiceRequest): InstanceId: InstanceId ProductCode: String - DryRun: Optional[Boolean] + DryRun: Boolean | None class ConfirmProductInstanceResult(TypedDict, total=False): - Return: Optional[Boolean] - OwnerId: Optional[String] + Return: Boolean | None + OwnerId: String | None class ConnectionLogOptions(TypedDict, total=False): - Enabled: Optional[Boolean] - CloudwatchLogGroup: Optional[String] - CloudwatchLogStream: Optional[String] + Enabled: Boolean | None + CloudwatchLogGroup: String | None + CloudwatchLogStream: String | None class ConnectionNotification(TypedDict, total=False): - ConnectionNotificationId: Optional[String] - ServiceId: Optional[String] - VpcEndpointId: Optional[String] - ConnectionNotificationType: Optional[ConnectionNotificationType] - ConnectionNotificationArn: Optional[String] - ConnectionEvents: Optional[ValueStringList] - ConnectionNotificationState: Optional[ConnectionNotificationState] - ServiceRegion: Optional[String] + ConnectionNotificationId: String | None + ServiceId: String | None + VpcEndpointId: String | None + ConnectionNotificationType: ConnectionNotificationType | None + ConnectionNotificationArn: String | None + ConnectionEvents: ValueStringList | None + ConnectionNotificationState: ConnectionNotificationState | None + ServiceRegion: String | None -ConnectionNotificationIdsList = List[ConnectionNotificationId] -ConnectionNotificationSet = List[ConnectionNotification] +ConnectionNotificationIdsList = list[ConnectionNotificationId] +ConnectionNotificationSet = list[ConnectionNotification] class ConnectionTrackingConfiguration(TypedDict, total=False): - TcpEstablishedTimeout: Optional[Integer] - UdpStreamTimeout: Optional[Integer] - UdpTimeout: Optional[Integer] + TcpEstablishedTimeout: Integer | None + UdpStreamTimeout: Integer | None + UdpTimeout: Integer | None class ConnectionTrackingSpecification(TypedDict, total=False): - TcpEstablishedTimeout: Optional[Integer] - UdpTimeout: Optional[Integer] - UdpStreamTimeout: Optional[Integer] + TcpEstablishedTimeout: Integer | None + UdpTimeout: Integer | None + UdpStreamTimeout: Integer | None class ConnectionTrackingSpecificationRequest(TypedDict, total=False): - TcpEstablishedTimeout: Optional[Integer] - UdpStreamTimeout: Optional[Integer] - UdpTimeout: Optional[Integer] + TcpEstablishedTimeout: Integer | None + UdpStreamTimeout: Integer | None + UdpTimeout: Integer | None class ConnectionTrackingSpecificationResponse(TypedDict, total=False): - TcpEstablishedTimeout: Optional[Integer] - UdpStreamTimeout: Optional[Integer] - UdpTimeout: Optional[Integer] + TcpEstablishedTimeout: Integer | None + UdpStreamTimeout: Integer | None + UdpTimeout: Integer | None -ConversionIdStringList = List[ConversionTaskId] +ConversionIdStringList = list[ConversionTaskId] class DiskImageVolumeDescription(TypedDict, total=False): - Id: Optional[String] - Size: Optional[Long] + Id: String | None + Size: Long | None class DiskImageDescription(TypedDict, total=False): - Checksum: Optional[String] - Format: Optional[DiskImageFormat] - ImportManifestUrl: Optional[ImportManifestUrl] - Size: Optional[Long] + Checksum: String | None + Format: DiskImageFormat | None + ImportManifestUrl: ImportManifestUrl | None + Size: Long | None class ImportVolumeTaskDetails(TypedDict, total=False): - AvailabilityZone: Optional[String] - AvailabilityZoneId: Optional[String] - BytesConverted: Optional[Long] - Description: Optional[String] - Image: Optional[DiskImageDescription] - Volume: Optional[DiskImageVolumeDescription] + AvailabilityZone: String | None + AvailabilityZoneId: String | None + BytesConverted: Long | None + Description: String | None + Image: DiskImageDescription | None + Volume: DiskImageVolumeDescription | None class ImportInstanceVolumeDetailItem(TypedDict, total=False): - AvailabilityZone: Optional[String] - AvailabilityZoneId: Optional[String] - BytesConverted: Optional[Long] - Description: Optional[String] - Image: Optional[DiskImageDescription] - Status: Optional[String] - StatusMessage: Optional[String] - Volume: Optional[DiskImageVolumeDescription] + AvailabilityZone: String | None + AvailabilityZoneId: String | None + BytesConverted: Long | None + Description: String | None + Image: DiskImageDescription | None + Status: String | None + StatusMessage: String | None + Volume: DiskImageVolumeDescription | None -ImportInstanceVolumeDetailSet = List[ImportInstanceVolumeDetailItem] +ImportInstanceVolumeDetailSet = list[ImportInstanceVolumeDetailItem] class ImportInstanceTaskDetails(TypedDict, total=False): - Description: Optional[String] - InstanceId: Optional[String] - Platform: Optional[PlatformValues] - Volumes: Optional[ImportInstanceVolumeDetailSet] + Description: String | None + InstanceId: String | None + Platform: PlatformValues | None + Volumes: ImportInstanceVolumeDetailSet | None class ConversionTask(TypedDict, total=False): - ConversionTaskId: Optional[String] - ExpirationTime: Optional[String] - ImportInstance: Optional[ImportInstanceTaskDetails] - ImportVolume: Optional[ImportVolumeTaskDetails] - State: Optional[ConversionTaskState] - StatusMessage: Optional[String] - Tags: Optional[TagList] + ConversionTaskId: String | None + ExpirationTime: String | None + ImportInstance: ImportInstanceTaskDetails | None + ImportVolume: ImportVolumeTaskDetails | None + State: ConversionTaskState | None + StatusMessage: String | None + Tags: TagList | None class CopyFpgaImageRequest(ServiceRequest): - DryRun: Optional[Boolean] + DryRun: Boolean | None SourceFpgaImageId: String - Description: Optional[String] - Name: Optional[String] + Description: String | None + Name: String | None SourceRegion: String - ClientToken: Optional[String] + ClientToken: String | None class CopyFpgaImageResult(TypedDict, total=False): - FpgaImageId: Optional[String] + FpgaImageId: String | None class CopyImageRequest(ServiceRequest): - ClientToken: Optional[String] - Description: Optional[String] - Encrypted: Optional[Boolean] - KmsKeyId: Optional[KmsKeyId] + ClientToken: String | None + Description: String | None + Encrypted: Boolean | None + KmsKeyId: KmsKeyId | None Name: String SourceImageId: String SourceRegion: String - DestinationOutpostArn: Optional[String] - CopyImageTags: Optional[Boolean] - TagSpecifications: Optional[TagSpecificationList] - SnapshotCopyCompletionDurationMinutes: Optional[Long] - DestinationAvailabilityZone: Optional[String] - DestinationAvailabilityZoneId: Optional[String] - DryRun: Optional[Boolean] + DestinationOutpostArn: String | None + CopyImageTags: Boolean | None + TagSpecifications: TagSpecificationList | None + SnapshotCopyCompletionDurationMinutes: Long | None + DestinationAvailabilityZone: String | None + DestinationAvailabilityZoneId: String | None + DryRun: Boolean | None class CopyImageResult(TypedDict, total=False): - ImageId: Optional[String] + ImageId: String | None class CopySnapshotRequest(ServiceRequest): - Description: Optional[String] - DestinationOutpostArn: Optional[String] - DestinationRegion: Optional[String] - Encrypted: Optional[Boolean] - KmsKeyId: Optional[KmsKeyId] - PresignedUrl: Optional[CopySnapshotRequestPSU] + Description: String | None + DestinationOutpostArn: String | None + DestinationRegion: String | None + Encrypted: Boolean | None + KmsKeyId: KmsKeyId | None + PresignedUrl: CopySnapshotRequestPSU | None SourceRegion: String SourceSnapshotId: String - TagSpecifications: Optional[TagSpecificationList] - CompletionDurationMinutes: Optional[SnapshotCompletionDurationMinutesRequest] - DestinationAvailabilityZone: Optional[String] - DryRun: Optional[Boolean] + TagSpecifications: TagSpecificationList | None + CompletionDurationMinutes: SnapshotCompletionDurationMinutesRequest | None + DestinationAvailabilityZone: String | None + DryRun: Boolean | None class CopySnapshotResult(TypedDict, total=False): - Tags: Optional[TagList] - SnapshotId: Optional[String] + Tags: TagList | None + SnapshotId: String | None + + +class CopyVolumesRequest(ServiceRequest): + SourceVolumeId: VolumeId + Iops: Integer | None + Size: Integer | None + VolumeType: VolumeType | None + DryRun: Boolean | None + TagSpecifications: TagSpecificationList | None + MultiAttachEnabled: Boolean | None + Throughput: Integer | None + ClientToken: String | None + + +class VolumeAttachment(TypedDict, total=False): + DeleteOnTermination: Boolean | None + AssociatedResource: String | None + InstanceOwningService: String | None + EbsCardIndex: Integer | None + VolumeId: String | None + InstanceId: String | None + Device: String | None + State: VolumeAttachmentState | None + AttachTime: DateTime | None + + +VolumeAttachmentList = list[VolumeAttachment] + + +class OperatorResponse(TypedDict, total=False): + Managed: Boolean | None + Principal: String | None + + +class Volume(TypedDict, total=False): + AvailabilityZoneId: String | None + OutpostArn: String | None + SourceVolumeId: String | None + Iops: Integer | None + Tags: TagList | None + VolumeType: VolumeType | None + FastRestored: Boolean | None + MultiAttachEnabled: Boolean | None + Throughput: Integer | None + SseType: SSEType | None + Operator: OperatorResponse | None + VolumeInitializationRate: Integer | None + VolumeId: String | None + Size: Integer | None + SnapshotId: String | None + AvailabilityZone: String | None + State: VolumeState | None + CreateTime: DateTime | None + Attachments: VolumeAttachmentList | None + Encrypted: Boolean | None + KmsKeyId: String | None + + +VolumeList = list[Volume] + +class CopyVolumesResult(TypedDict, total=False): + Volumes: VolumeList | None -CoreCountList = List[CoreCount] -CpuManufacturerSet = List[CpuManufacturer] + +CoreCountList = list[CoreCount] +CpuManufacturerSet = list[CpuManufacturer] class CpuOptions(TypedDict, total=False): - CoreCount: Optional[Integer] - ThreadsPerCore: Optional[Integer] - AmdSevSnp: Optional[AmdSevSnpSpecification] + CoreCount: Integer | None + ThreadsPerCore: Integer | None + AmdSevSnp: AmdSevSnpSpecification | None + NestedVirtualization: NestedVirtualizationSpecification | None class CpuOptionsRequest(TypedDict, total=False): - CoreCount: Optional[Integer] - ThreadsPerCore: Optional[Integer] - AmdSevSnp: Optional[AmdSevSnpSpecification] + CoreCount: Integer | None + ThreadsPerCore: Integer | None + AmdSevSnp: AmdSevSnpSpecification | None + NestedVirtualization: NestedVirtualizationSpecification | None + + +class CreateCapacityManagerDataExportRequest(ServiceRequest): + S3BucketName: String + S3BucketPrefix: String | None + Schedule: Schedule + OutputFormat: OutputFormat + ClientToken: String | None + DryRun: Boolean | None + TagSpecifications: TagSpecificationList | None + + +class CreateCapacityManagerDataExportResult(TypedDict, total=False): + CapacityManagerDataExportId: CapacityManagerDataExportId | None class CreateCapacityReservationBySplittingRequest(ServiceRequest): - DryRun: Optional[Boolean] - ClientToken: Optional[String] + DryRun: Boolean | None + ClientToken: String | None SourceCapacityReservationId: CapacityReservationId InstanceCount: Integer - TagSpecifications: Optional[TagSpecificationList] + TagSpecifications: TagSpecificationList | None class CreateCapacityReservationBySplittingResult(TypedDict, total=False): - SourceCapacityReservation: Optional[CapacityReservation] - DestinationCapacityReservation: Optional[CapacityReservation] - InstanceCount: Optional[Integer] + SourceCapacityReservation: CapacityReservation | None + DestinationCapacityReservation: CapacityReservation | None + InstanceCount: Integer | None class ReservationFleetInstanceSpecification(TypedDict, total=False): - InstanceType: Optional[InstanceType] - InstancePlatform: Optional[CapacityReservationInstancePlatform] - Weight: Optional[DoubleWithConstraints] - AvailabilityZone: Optional[String] - AvailabilityZoneId: Optional[String] - EbsOptimized: Optional[Boolean] - Priority: Optional[IntegerWithConstraints] + InstanceType: InstanceType | None + InstancePlatform: CapacityReservationInstancePlatform | None + Weight: DoubleWithConstraints | None + AvailabilityZone: String | None + AvailabilityZoneId: String | None + EbsOptimized: Boolean | None + Priority: IntegerWithConstraints | None -ReservationFleetInstanceSpecificationList = List[ReservationFleetInstanceSpecification] +ReservationFleetInstanceSpecificationList = list[ReservationFleetInstanceSpecification] class CreateCapacityReservationFleetRequest(ServiceRequest): - AllocationStrategy: Optional[String] - ClientToken: Optional[String] + AllocationStrategy: String | None + ClientToken: String | None InstanceTypeSpecifications: ReservationFleetInstanceSpecificationList - Tenancy: Optional[FleetCapacityReservationTenancy] + Tenancy: FleetCapacityReservationTenancy | None TotalTargetCapacity: Integer - EndDate: Optional[MillisecondDateTime] - InstanceMatchCriteria: Optional[FleetInstanceMatchCriteria] - TagSpecifications: Optional[TagSpecificationList] - DryRun: Optional[Boolean] + EndDate: MillisecondDateTime | None + InstanceMatchCriteria: FleetInstanceMatchCriteria | None + TagSpecifications: TagSpecificationList | None + DryRun: Boolean | None class CreateCapacityReservationFleetResult(TypedDict, total=False): - CapacityReservationFleetId: Optional[CapacityReservationFleetId] - State: Optional[CapacityReservationFleetState] - TotalTargetCapacity: Optional[Integer] - TotalFulfilledCapacity: Optional[Double] - InstanceMatchCriteria: Optional[FleetInstanceMatchCriteria] - AllocationStrategy: Optional[String] - CreateTime: Optional[MillisecondDateTime] - EndDate: Optional[MillisecondDateTime] - Tenancy: Optional[FleetCapacityReservationTenancy] - FleetCapacityReservations: Optional[FleetCapacityReservationSet] - Tags: Optional[TagList] + CapacityReservationFleetId: CapacityReservationFleetId | None + State: CapacityReservationFleetState | None + TotalTargetCapacity: Integer | None + TotalFulfilledCapacity: Double | None + InstanceMatchCriteria: FleetInstanceMatchCriteria | None + AllocationStrategy: String | None + CreateTime: MillisecondDateTime | None + EndDate: MillisecondDateTime | None + Tenancy: FleetCapacityReservationTenancy | None + FleetCapacityReservations: FleetCapacityReservationSet | None + Tags: TagList | None class CreateCapacityReservationRequest(ServiceRequest): - ClientToken: Optional[String] + ClientToken: String | None InstanceType: String InstancePlatform: CapacityReservationInstancePlatform - AvailabilityZone: Optional[AvailabilityZoneName] - AvailabilityZoneId: Optional[AvailabilityZoneId] - Tenancy: Optional[CapacityReservationTenancy] + AvailabilityZone: AvailabilityZoneName | None + AvailabilityZoneId: AvailabilityZoneId | None + Tenancy: CapacityReservationTenancy | None InstanceCount: Integer - EbsOptimized: Optional[Boolean] - EphemeralStorage: Optional[Boolean] - EndDate: Optional[DateTime] - EndDateType: Optional[EndDateType] - InstanceMatchCriteria: Optional[InstanceMatchCriteria] - TagSpecifications: Optional[TagSpecificationList] - DryRun: Optional[Boolean] - OutpostArn: Optional[OutpostArn] - PlacementGroupArn: Optional[PlacementGroupArn] - StartDate: Optional[MillisecondDateTime] - CommitmentDuration: Optional[CapacityReservationCommitmentDuration] - DeliveryPreference: Optional[CapacityReservationDeliveryPreference] + EbsOptimized: Boolean | None + EphemeralStorage: Boolean | None + EndDate: DateTime | None + EndDateType: EndDateType | None + InstanceMatchCriteria: InstanceMatchCriteria | None + TagSpecifications: TagSpecificationList | None + DryRun: Boolean | None + OutpostArn: OutpostArn | None + PlacementGroupArn: PlacementGroupArn | None + StartDate: MillisecondDateTime | None + CommitmentDuration: CapacityReservationCommitmentDuration | None + DeliveryPreference: CapacityReservationDeliveryPreference | None class CreateCapacityReservationResult(TypedDict, total=False): - CapacityReservation: Optional[CapacityReservation] + CapacityReservation: CapacityReservation | None class CreateCarrierGatewayRequest(ServiceRequest): VpcId: VpcId - TagSpecifications: Optional[TagSpecificationList] - DryRun: Optional[Boolean] - ClientToken: Optional[String] + TagSpecifications: TagSpecificationList | None + DryRun: Boolean | None + ClientToken: String | None class CreateCarrierGatewayResult(TypedDict, total=False): - CarrierGateway: Optional[CarrierGateway] + CarrierGateway: CarrierGateway | None class CreateClientVpnEndpointRequest(ServiceRequest): - ClientCidrBlock: Optional[String] + ClientCidrBlock: String | None ServerCertificateArn: String AuthenticationOptions: ClientVpnAuthenticationRequestList ConnectionLogOptions: ConnectionLogOptions - DnsServers: Optional[ValueStringList] - TransportProtocol: Optional[TransportProtocol] - VpnPort: Optional[Integer] - Description: Optional[String] - SplitTunnel: Optional[Boolean] - DryRun: Optional[Boolean] - ClientToken: Optional[String] - TagSpecifications: Optional[TagSpecificationList] - SecurityGroupIds: Optional[ClientVpnSecurityGroupIdSet] - VpcId: Optional[VpcId] - SelfServicePortal: Optional[SelfServicePortal] - ClientConnectOptions: Optional[ClientConnectOptions] - SessionTimeoutHours: Optional[Integer] - ClientLoginBannerOptions: Optional[ClientLoginBannerOptions] - ClientRouteEnforcementOptions: Optional[ClientRouteEnforcementOptions] - DisconnectOnSessionTimeout: Optional[Boolean] - EndpointIpAddressType: Optional[EndpointIpAddressType] - TrafficIpAddressType: Optional[TrafficIpAddressType] + DnsServers: ValueStringList | None + TransportProtocol: TransportProtocol | None + VpnPort: Integer | None + Description: String | None + SplitTunnel: Boolean | None + DryRun: Boolean | None + ClientToken: String | None + TagSpecifications: TagSpecificationList | None + SecurityGroupIds: ClientVpnSecurityGroupIdSet | None + VpcId: VpcId | None + SelfServicePortal: SelfServicePortal | None + ClientConnectOptions: ClientConnectOptions | None + SessionTimeoutHours: Integer | None + ClientLoginBannerOptions: ClientLoginBannerOptions | None + ClientRouteEnforcementOptions: ClientRouteEnforcementOptions | None + DisconnectOnSessionTimeout: Boolean | None + EndpointIpAddressType: EndpointIpAddressType | None + TrafficIpAddressType: TrafficIpAddressType | None class CreateClientVpnEndpointResult(TypedDict, total=False): - ClientVpnEndpointId: Optional[String] - Status: Optional[ClientVpnEndpointStatus] - DnsName: Optional[String] + ClientVpnEndpointId: String | None + Status: ClientVpnEndpointStatus | None + DnsName: String | None class CreateClientVpnRouteRequest(ServiceRequest): ClientVpnEndpointId: ClientVpnEndpointId DestinationCidrBlock: String TargetVpcSubnetId: SubnetId - Description: Optional[String] - ClientToken: Optional[String] - DryRun: Optional[Boolean] + Description: String | None + ClientToken: String | None + DryRun: Boolean | None class CreateClientVpnRouteResult(TypedDict, total=False): - Status: Optional[ClientVpnRouteStatus] + Status: ClientVpnRouteStatus | None class CreateCoipCidrRequest(ServiceRequest): Cidr: String CoipPoolId: Ipv4PoolCoipId - DryRun: Optional[Boolean] + DryRun: Boolean | None class CreateCoipCidrResult(TypedDict, total=False): - CoipCidr: Optional[CoipCidr] + CoipCidr: CoipCidr | None class CreateCoipPoolRequest(ServiceRequest): LocalGatewayRouteTableId: LocalGatewayRoutetableId - TagSpecifications: Optional[TagSpecificationList] - DryRun: Optional[Boolean] + TagSpecifications: TagSpecificationList | None + DryRun: Boolean | None class CreateCoipPoolResult(TypedDict, total=False): - CoipPool: Optional[CoipPool] + CoipPool: CoipPool | None class CreateCustomerGatewayRequest(ServiceRequest): - BgpAsn: Optional[Integer] - PublicIp: Optional[String] - CertificateArn: Optional[String] + BgpAsn: Integer | None + PublicIp: String | None + CertificateArn: String | None Type: GatewayType - TagSpecifications: Optional[TagSpecificationList] - DeviceName: Optional[String] - IpAddress: Optional[String] - BgpAsnExtended: Optional[Long] - DryRun: Optional[Boolean] + TagSpecifications: TagSpecificationList | None + DeviceName: String | None + IpAddress: String | None + BgpAsnExtended: Long | None + DryRun: Boolean | None class CustomerGateway(TypedDict, total=False): - CertificateArn: Optional[String] - DeviceName: Optional[String] - Tags: Optional[TagList] - BgpAsnExtended: Optional[String] - CustomerGatewayId: Optional[String] - State: Optional[String] - Type: Optional[String] - IpAddress: Optional[String] - BgpAsn: Optional[String] + CertificateArn: String | None + DeviceName: String | None + Tags: TagList | None + BgpAsnExtended: String | None + CustomerGatewayId: String | None + State: String | None + Type: String | None + IpAddress: String | None + BgpAsn: String | None class CreateCustomerGatewayResult(TypedDict, total=False): - CustomerGateway: Optional[CustomerGateway] + CustomerGateway: CustomerGateway | None class CreateDefaultSubnetRequest(ServiceRequest): - AvailabilityZone: Optional[AvailabilityZoneName] - DryRun: Optional[Boolean] - Ipv6Native: Optional[Boolean] - AvailabilityZoneId: Optional[AvailabilityZoneId] + AvailabilityZone: AvailabilityZoneName | None + DryRun: Boolean | None + Ipv6Native: Boolean | None + AvailabilityZoneId: AvailabilityZoneId | None class PrivateDnsNameOptionsOnLaunch(TypedDict, total=False): - HostnameType: Optional[HostnameType] - EnableResourceNameDnsARecord: Optional[Boolean] - EnableResourceNameDnsAAAARecord: Optional[Boolean] + HostnameType: HostnameType | None + EnableResourceNameDnsARecord: Boolean | None + EnableResourceNameDnsAAAARecord: Boolean | None -SubnetIpv6CidrBlockAssociationSet = List[SubnetIpv6CidrBlockAssociation] +SubnetIpv6CidrBlockAssociationSet = list[SubnetIpv6CidrBlockAssociation] class Subnet(TypedDict, total=False): - AvailabilityZoneId: Optional[String] - EnableLniAtDeviceIndex: Optional[Integer] - MapCustomerOwnedIpOnLaunch: Optional[Boolean] - CustomerOwnedIpv4Pool: Optional[CoipPoolId] - OwnerId: Optional[String] - AssignIpv6AddressOnCreation: Optional[Boolean] - Ipv6CidrBlockAssociationSet: Optional[SubnetIpv6CidrBlockAssociationSet] - Tags: Optional[TagList] - SubnetArn: Optional[String] - OutpostArn: Optional[String] - EnableDns64: Optional[Boolean] - Ipv6Native: Optional[Boolean] - PrivateDnsNameOptionsOnLaunch: Optional[PrivateDnsNameOptionsOnLaunch] - BlockPublicAccessStates: Optional[BlockPublicAccessStates] - Type: Optional[String] - SubnetId: Optional[String] - State: Optional[SubnetState] - VpcId: Optional[String] - CidrBlock: Optional[String] - AvailableIpAddressCount: Optional[Integer] - AvailabilityZone: Optional[String] - DefaultForAz: Optional[Boolean] - MapPublicIpOnLaunch: Optional[Boolean] + AvailabilityZoneId: String | None + EnableLniAtDeviceIndex: Integer | None + MapCustomerOwnedIpOnLaunch: Boolean | None + CustomerOwnedIpv4Pool: CoipPoolId | None + OwnerId: String | None + AssignIpv6AddressOnCreation: Boolean | None + Ipv6CidrBlockAssociationSet: SubnetIpv6CidrBlockAssociationSet | None + Tags: TagList | None + SubnetArn: String | None + OutpostArn: String | None + EnableDns64: Boolean | None + Ipv6Native: Boolean | None + PrivateDnsNameOptionsOnLaunch: PrivateDnsNameOptionsOnLaunch | None + BlockPublicAccessStates: BlockPublicAccessStates | None + Type: String | None + SubnetId: String | None + State: SubnetState | None + VpcId: String | None + CidrBlock: String | None + AvailableIpAddressCount: Integer | None + AvailabilityZone: String | None + DefaultForAz: Boolean | None + MapPublicIpOnLaunch: Boolean | None class CreateDefaultSubnetResult(TypedDict, total=False): - Subnet: Optional[Subnet] + Subnet: Subnet | None class CreateDefaultVpcRequest(ServiceRequest): - DryRun: Optional[Boolean] + DryRun: Boolean | None class VpcEncryptionControlExclusion(TypedDict, total=False): - State: Optional[VpcEncryptionControlExclusionState] - StateMessage: Optional[String] + State: VpcEncryptionControlExclusionState | None + StateMessage: String | None class VpcEncryptionControlExclusions(TypedDict, total=False): - InternetGateway: Optional[VpcEncryptionControlExclusion] - EgressOnlyInternetGateway: Optional[VpcEncryptionControlExclusion] - NatGateway: Optional[VpcEncryptionControlExclusion] - VirtualPrivateGateway: Optional[VpcEncryptionControlExclusion] - VpcPeering: Optional[VpcEncryptionControlExclusion] + InternetGateway: VpcEncryptionControlExclusion | None + EgressOnlyInternetGateway: VpcEncryptionControlExclusion | None + NatGateway: VpcEncryptionControlExclusion | None + VirtualPrivateGateway: VpcEncryptionControlExclusion | None + VpcPeering: VpcEncryptionControlExclusion | None + Lambda: VpcEncryptionControlExclusion | None + VpcLattice: VpcEncryptionControlExclusion | None + ElasticFileSystem: VpcEncryptionControlExclusion | None class VpcEncryptionControl(TypedDict, total=False): - VpcId: Optional[VpcId] - VpcEncryptionControlId: Optional[VpcEncryptionControlId] - Mode: Optional[VpcEncryptionControlMode] - State: Optional[VpcEncryptionControlState] - StateMessage: Optional[String] - ResourceExclusions: Optional[VpcEncryptionControlExclusions] - Tags: Optional[TagList] + VpcId: VpcId | None + VpcEncryptionControlId: VpcEncryptionControlId | None + Mode: VpcEncryptionControlMode | None + State: VpcEncryptionControlState | None + StateMessage: String | None + ResourceExclusions: VpcEncryptionControlExclusions | None + Tags: TagList | None -VpcCidrBlockAssociationSet = List[VpcCidrBlockAssociation] -VpcIpv6CidrBlockAssociationSet = List[VpcIpv6CidrBlockAssociation] +VpcCidrBlockAssociationSet = list[VpcCidrBlockAssociation] +VpcIpv6CidrBlockAssociationSet = list[VpcIpv6CidrBlockAssociation] class Vpc(TypedDict, total=False): - OwnerId: Optional[String] - InstanceTenancy: Optional[Tenancy] - Ipv6CidrBlockAssociationSet: Optional[VpcIpv6CidrBlockAssociationSet] - CidrBlockAssociationSet: Optional[VpcCidrBlockAssociationSet] - IsDefault: Optional[Boolean] - EncryptionControl: Optional[VpcEncryptionControl] - Tags: Optional[TagList] - BlockPublicAccessStates: Optional[BlockPublicAccessStates] - VpcId: Optional[String] - State: Optional[VpcState] - CidrBlock: Optional[String] - DhcpOptionsId: Optional[String] + OwnerId: String | None + InstanceTenancy: Tenancy | None + Ipv6CidrBlockAssociationSet: VpcIpv6CidrBlockAssociationSet | None + CidrBlockAssociationSet: VpcCidrBlockAssociationSet | None + IsDefault: Boolean | None + EncryptionControl: VpcEncryptionControl | None + Tags: TagList | None + BlockPublicAccessStates: BlockPublicAccessStates | None + VpcId: String | None + State: VpcState | None + CidrBlock: String | None + DhcpOptionsId: String | None class CreateDefaultVpcResult(TypedDict, total=False): - Vpc: Optional[Vpc] + Vpc: Vpc | None class CreateDelegateMacVolumeOwnershipTaskRequest(ServiceRequest): - ClientToken: Optional[String] - DryRun: Optional[Boolean] + ClientToken: String | None + DryRun: Boolean | None InstanceId: InstanceId MacCredentials: SensitiveMacCredentials - TagSpecifications: Optional[TagSpecificationList] + TagSpecifications: TagSpecificationList | None class MacSystemIntegrityProtectionConfiguration(TypedDict, total=False): - AppleInternal: Optional[MacSystemIntegrityProtectionSettingStatus] - BaseSystem: Optional[MacSystemIntegrityProtectionSettingStatus] - DebuggingRestrictions: Optional[MacSystemIntegrityProtectionSettingStatus] - DTraceRestrictions: Optional[MacSystemIntegrityProtectionSettingStatus] - FilesystemProtections: Optional[MacSystemIntegrityProtectionSettingStatus] - KextSigning: Optional[MacSystemIntegrityProtectionSettingStatus] - NvramProtections: Optional[MacSystemIntegrityProtectionSettingStatus] - Status: Optional[MacSystemIntegrityProtectionSettingStatus] + AppleInternal: MacSystemIntegrityProtectionSettingStatus | None + BaseSystem: MacSystemIntegrityProtectionSettingStatus | None + DebuggingRestrictions: MacSystemIntegrityProtectionSettingStatus | None + DTraceRestrictions: MacSystemIntegrityProtectionSettingStatus | None + FilesystemProtections: MacSystemIntegrityProtectionSettingStatus | None + KextSigning: MacSystemIntegrityProtectionSettingStatus | None + NvramProtections: MacSystemIntegrityProtectionSettingStatus | None + Status: MacSystemIntegrityProtectionSettingStatus | None class MacModificationTask(TypedDict, total=False): - InstanceId: Optional[InstanceId] - MacModificationTaskId: Optional[MacModificationTaskId] - MacSystemIntegrityProtectionConfig: Optional[MacSystemIntegrityProtectionConfiguration] - StartTime: Optional[MillisecondDateTime] - Tags: Optional[TagList] - TaskState: Optional[MacModificationTaskState] - TaskType: Optional[MacModificationTaskType] + InstanceId: InstanceId | None + MacModificationTaskId: MacModificationTaskId | None + MacSystemIntegrityProtectionConfig: MacSystemIntegrityProtectionConfiguration | None + StartTime: MillisecondDateTime | None + Tags: TagList | None + TaskState: MacModificationTaskState | None + TaskType: MacModificationTaskType | None class CreateDelegateMacVolumeOwnershipTaskResult(TypedDict, total=False): - MacModificationTask: Optional[MacModificationTask] + MacModificationTask: MacModificationTask | None class NewDhcpConfiguration(TypedDict, total=False): - Key: Optional[String] - Values: Optional[ValueStringList] + Key: String | None + Values: ValueStringList | None -NewDhcpConfigurationList = List[NewDhcpConfiguration] +NewDhcpConfigurationList = list[NewDhcpConfiguration] class CreateDhcpOptionsRequest(ServiceRequest): DhcpConfigurations: NewDhcpConfigurationList - TagSpecifications: Optional[TagSpecificationList] - DryRun: Optional[Boolean] + TagSpecifications: TagSpecificationList | None + DryRun: Boolean | None -DhcpConfigurationValueList = List[AttributeValue] +DhcpConfigurationValueList = list[AttributeValue] class DhcpConfiguration(TypedDict, total=False): - Key: Optional[String] - Values: Optional[DhcpConfigurationValueList] + Key: String | None + Values: DhcpConfigurationValueList | None -DhcpConfigurationList = List[DhcpConfiguration] +DhcpConfigurationList = list[DhcpConfiguration] class DhcpOptions(TypedDict, total=False): - OwnerId: Optional[String] - Tags: Optional[TagList] - DhcpOptionsId: Optional[String] - DhcpConfigurations: Optional[DhcpConfigurationList] + OwnerId: String | None + Tags: TagList | None + DhcpOptionsId: String | None + DhcpConfigurations: DhcpConfigurationList | None class CreateDhcpOptionsResult(TypedDict, total=False): - DhcpOptions: Optional[DhcpOptions] + DhcpOptions: DhcpOptions | None class CreateEgressOnlyInternetGatewayRequest(ServiceRequest): - ClientToken: Optional[String] - DryRun: Optional[Boolean] + ClientToken: String | None + DryRun: Boolean | None VpcId: VpcId - TagSpecifications: Optional[TagSpecificationList] + TagSpecifications: TagSpecificationList | None class InternetGatewayAttachment(TypedDict, total=False): - State: Optional[AttachmentStatus] - VpcId: Optional[String] + State: AttachmentStatus | None + VpcId: String | None -InternetGatewayAttachmentList = List[InternetGatewayAttachment] +InternetGatewayAttachmentList = list[InternetGatewayAttachment] class EgressOnlyInternetGateway(TypedDict, total=False): - Attachments: Optional[InternetGatewayAttachmentList] - EgressOnlyInternetGatewayId: Optional[EgressOnlyInternetGatewayId] - Tags: Optional[TagList] + Attachments: InternetGatewayAttachmentList | None + EgressOnlyInternetGatewayId: EgressOnlyInternetGatewayId | None + Tags: TagList | None class CreateEgressOnlyInternetGatewayResult(TypedDict, total=False): - ClientToken: Optional[String] - EgressOnlyInternetGateway: Optional[EgressOnlyInternetGateway] + ClientToken: String | None + EgressOnlyInternetGateway: EgressOnlyInternetGateway | None class NetworkBandwidthGbps(TypedDict, total=False): - Min: Optional[Double] - Max: Optional[Double] + Min: Double | None + Max: Double | None class TotalLocalStorageGB(TypedDict, total=False): - Min: Optional[Double] - Max: Optional[Double] + Min: Double | None + Max: Double | None -LocalStorageTypeSet = List[LocalStorageType] +LocalStorageTypeSet = list[LocalStorageType] class NetworkInterfaceCount(TypedDict, total=False): - Min: Optional[Integer] - Max: Optional[Integer] + Min: Integer | None + Max: Integer | None -InstanceGenerationSet = List[InstanceGeneration] -ExcludedInstanceTypeSet = List[ExcludedInstanceType] +InstanceGenerationSet = list[InstanceGeneration] +ExcludedInstanceTypeSet = list[ExcludedInstanceType] class MemoryGiBPerVCpu(TypedDict, total=False): - Min: Optional[Double] - Max: Optional[Double] + Min: Double | None + Max: Double | None class MemoryMiB(TypedDict, total=False): - Min: Optional[Integer] - Max: Optional[Integer] + Min: Integer | None + Max: Integer | None class VCpuCountRange(TypedDict, total=False): - Min: Optional[Integer] - Max: Optional[Integer] + Min: Integer | None + Max: Integer | None class InstanceRequirements(TypedDict, total=False): - VCpuCount: Optional[VCpuCountRange] - MemoryMiB: Optional[MemoryMiB] - CpuManufacturers: Optional[CpuManufacturerSet] - MemoryGiBPerVCpu: Optional[MemoryGiBPerVCpu] - ExcludedInstanceTypes: Optional[ExcludedInstanceTypeSet] - InstanceGenerations: Optional[InstanceGenerationSet] - SpotMaxPricePercentageOverLowestPrice: Optional[Integer] - OnDemandMaxPricePercentageOverLowestPrice: Optional[Integer] - BareMetal: Optional[BareMetal] - BurstablePerformance: Optional[BurstablePerformance] - RequireHibernateSupport: Optional[Boolean] - NetworkInterfaceCount: Optional[NetworkInterfaceCount] - LocalStorage: Optional[LocalStorage] - LocalStorageTypes: Optional[LocalStorageTypeSet] - TotalLocalStorageGB: Optional[TotalLocalStorageGB] - BaselineEbsBandwidthMbps: Optional[BaselineEbsBandwidthMbps] - AcceleratorTypes: Optional[AcceleratorTypeSet] - AcceleratorCount: Optional[AcceleratorCount] - AcceleratorManufacturers: Optional[AcceleratorManufacturerSet] - AcceleratorNames: Optional[AcceleratorNameSet] - AcceleratorTotalMemoryMiB: Optional[AcceleratorTotalMemoryMiB] - NetworkBandwidthGbps: Optional[NetworkBandwidthGbps] - AllowedInstanceTypes: Optional[AllowedInstanceTypeSet] - MaxSpotPriceAsPercentageOfOptimalOnDemandPrice: Optional[Integer] - BaselinePerformanceFactors: Optional[BaselinePerformanceFactors] + VCpuCount: VCpuCountRange | None + MemoryMiB: MemoryMiB | None + CpuManufacturers: CpuManufacturerSet | None + MemoryGiBPerVCpu: MemoryGiBPerVCpu | None + ExcludedInstanceTypes: ExcludedInstanceTypeSet | None + InstanceGenerations: InstanceGenerationSet | None + SpotMaxPricePercentageOverLowestPrice: Integer | None + OnDemandMaxPricePercentageOverLowestPrice: Integer | None + BareMetal: BareMetal | None + BurstablePerformance: BurstablePerformance | None + RequireHibernateSupport: Boolean | None + NetworkInterfaceCount: NetworkInterfaceCount | None + LocalStorage: LocalStorage | None + LocalStorageTypes: LocalStorageTypeSet | None + TotalLocalStorageGB: TotalLocalStorageGB | None + BaselineEbsBandwidthMbps: BaselineEbsBandwidthMbps | None + AcceleratorTypes: AcceleratorTypeSet | None + AcceleratorCount: AcceleratorCount | None + AcceleratorManufacturers: AcceleratorManufacturerSet | None + AcceleratorNames: AcceleratorNameSet | None + AcceleratorTotalMemoryMiB: AcceleratorTotalMemoryMiB | None + NetworkBandwidthGbps: NetworkBandwidthGbps | None + AllowedInstanceTypes: AllowedInstanceTypeSet | None + MaxSpotPriceAsPercentageOfOptimalOnDemandPrice: Integer | None + BaselinePerformanceFactors: BaselinePerformanceFactors | None + RequireEncryptionInTransit: Boolean | None class PlacementResponse(TypedDict, total=False): - GroupName: Optional[PlacementGroupName] + GroupName: PlacementGroupName | None class FleetLaunchTemplateOverrides(TypedDict, total=False): - InstanceType: Optional[InstanceType] - MaxPrice: Optional[String] - SubnetId: Optional[String] - AvailabilityZone: Optional[AvailabilityZoneName] - WeightedCapacity: Optional[Double] - Priority: Optional[Double] - Placement: Optional[PlacementResponse] - InstanceRequirements: Optional[InstanceRequirements] - ImageId: Optional[ImageId] - BlockDeviceMappings: Optional[BlockDeviceMappingResponseList] + InstanceType: InstanceType | None + MaxPrice: String | None + SubnetId: String | None + AvailabilityZone: AvailabilityZoneName | None + WeightedCapacity: Double | None + Priority: Double | None + Placement: PlacementResponse | None + InstanceRequirements: InstanceRequirements | None + ImageId: ImageId | None + BlockDeviceMappings: BlockDeviceMappingResponseList | None + AvailabilityZoneId: AvailabilityZoneId | None class FleetLaunchTemplateSpecification(TypedDict, total=False): - LaunchTemplateId: Optional[String] - LaunchTemplateName: Optional[LaunchTemplateName] - Version: Optional[String] + LaunchTemplateId: String | None + LaunchTemplateName: LaunchTemplateName | None + Version: String | None class LaunchTemplateAndOverridesResponse(TypedDict, total=False): - LaunchTemplateSpecification: Optional[FleetLaunchTemplateSpecification] - Overrides: Optional[FleetLaunchTemplateOverrides] + LaunchTemplateSpecification: FleetLaunchTemplateSpecification | None + Overrides: FleetLaunchTemplateOverrides | None class CreateFleetError(TypedDict, total=False): - LaunchTemplateAndOverrides: Optional[LaunchTemplateAndOverridesResponse] - Lifecycle: Optional[InstanceLifecycle] - ErrorCode: Optional[String] - ErrorMessage: Optional[String] + LaunchTemplateAndOverrides: LaunchTemplateAndOverridesResponse | None + Lifecycle: InstanceLifecycle | None + ErrorCode: String | None + ErrorMessage: String | None -CreateFleetErrorsSet = List[CreateFleetError] -InstanceIdsSet = List[InstanceId] +CreateFleetErrorsSet = list[CreateFleetError] +InstanceIdsSet = list[InstanceId] class CreateFleetInstance(TypedDict, total=False): - LaunchTemplateAndOverrides: Optional[LaunchTemplateAndOverridesResponse] - Lifecycle: Optional[InstanceLifecycle] - InstanceIds: Optional[InstanceIdsSet] - InstanceType: Optional[InstanceType] - Platform: Optional[PlatformValues] + LaunchTemplateAndOverrides: LaunchTemplateAndOverridesResponse | None + Lifecycle: InstanceLifecycle | None + InstanceIds: InstanceIdsSet | None + InstanceType: InstanceType | None + Platform: PlatformValues | None -CreateFleetInstancesSet = List[CreateFleetInstance] +CreateFleetInstancesSet = list[CreateFleetInstance] class TargetCapacitySpecificationRequest(TypedDict, total=False): TotalTargetCapacity: Integer - OnDemandTargetCapacity: Optional[Integer] - SpotTargetCapacity: Optional[Integer] - DefaultTargetCapacityType: Optional[DefaultTargetCapacityType] - TargetCapacityUnitType: Optional[TargetCapacityUnitType] + OnDemandTargetCapacity: Integer | None + SpotTargetCapacity: Integer | None + DefaultTargetCapacityType: DefaultTargetCapacityType | None + TargetCapacityUnitType: TargetCapacityUnitType | None class NetworkBandwidthGbpsRequest(TypedDict, total=False): - Min: Optional[Double] - Max: Optional[Double] + Min: Double | None + Max: Double | None class TotalLocalStorageGBRequest(TypedDict, total=False): - Min: Optional[Double] - Max: Optional[Double] + Min: Double | None + Max: Double | None class NetworkInterfaceCountRequest(TypedDict, total=False): - Min: Optional[Integer] - Max: Optional[Integer] + Min: Integer | None + Max: Integer | None class MemoryGiBPerVCpuRequest(TypedDict, total=False): - Min: Optional[Double] - Max: Optional[Double] + Min: Double | None + Max: Double | None class MemoryMiBRequest(TypedDict, total=False): Min: Integer - Max: Optional[Integer] + Max: Integer | None class VCpuCountRangeRequest(TypedDict, total=False): Min: Integer - Max: Optional[Integer] + Max: Integer | None class InstanceRequirementsRequest(TypedDict, total=False): VCpuCount: VCpuCountRangeRequest MemoryMiB: MemoryMiBRequest - CpuManufacturers: Optional[CpuManufacturerSet] - MemoryGiBPerVCpu: Optional[MemoryGiBPerVCpuRequest] - ExcludedInstanceTypes: Optional[ExcludedInstanceTypeSet] - InstanceGenerations: Optional[InstanceGenerationSet] - SpotMaxPricePercentageOverLowestPrice: Optional[Integer] - OnDemandMaxPricePercentageOverLowestPrice: Optional[Integer] - BareMetal: Optional[BareMetal] - BurstablePerformance: Optional[BurstablePerformance] - RequireHibernateSupport: Optional[Boolean] - NetworkInterfaceCount: Optional[NetworkInterfaceCountRequest] - LocalStorage: Optional[LocalStorage] - LocalStorageTypes: Optional[LocalStorageTypeSet] - TotalLocalStorageGB: Optional[TotalLocalStorageGBRequest] - BaselineEbsBandwidthMbps: Optional[BaselineEbsBandwidthMbpsRequest] - AcceleratorTypes: Optional[AcceleratorTypeSet] - AcceleratorCount: Optional[AcceleratorCountRequest] - AcceleratorManufacturers: Optional[AcceleratorManufacturerSet] - AcceleratorNames: Optional[AcceleratorNameSet] - AcceleratorTotalMemoryMiB: Optional[AcceleratorTotalMemoryMiBRequest] - NetworkBandwidthGbps: Optional[NetworkBandwidthGbpsRequest] - AllowedInstanceTypes: Optional[AllowedInstanceTypeSet] - MaxSpotPriceAsPercentageOfOptimalOnDemandPrice: Optional[Integer] - BaselinePerformanceFactors: Optional[BaselinePerformanceFactorsRequest] + CpuManufacturers: CpuManufacturerSet | None + MemoryGiBPerVCpu: MemoryGiBPerVCpuRequest | None + ExcludedInstanceTypes: ExcludedInstanceTypeSet | None + InstanceGenerations: InstanceGenerationSet | None + SpotMaxPricePercentageOverLowestPrice: Integer | None + OnDemandMaxPricePercentageOverLowestPrice: Integer | None + BareMetal: BareMetal | None + BurstablePerformance: BurstablePerformance | None + RequireHibernateSupport: Boolean | None + NetworkInterfaceCount: NetworkInterfaceCountRequest | None + LocalStorage: LocalStorage | None + LocalStorageTypes: LocalStorageTypeSet | None + TotalLocalStorageGB: TotalLocalStorageGBRequest | None + BaselineEbsBandwidthMbps: BaselineEbsBandwidthMbpsRequest | None + AcceleratorTypes: AcceleratorTypeSet | None + AcceleratorCount: AcceleratorCountRequest | None + AcceleratorManufacturers: AcceleratorManufacturerSet | None + AcceleratorNames: AcceleratorNameSet | None + AcceleratorTotalMemoryMiB: AcceleratorTotalMemoryMiBRequest | None + NetworkBandwidthGbps: NetworkBandwidthGbpsRequest | None + AllowedInstanceTypes: AllowedInstanceTypeSet | None + MaxSpotPriceAsPercentageOfOptimalOnDemandPrice: Integer | None + BaselinePerformanceFactors: BaselinePerformanceFactorsRequest | None + RequireEncryptionInTransit: Boolean | None class FleetEbsBlockDeviceRequest(TypedDict, total=False): - Encrypted: Optional[Boolean] - DeleteOnTermination: Optional[Boolean] - Iops: Optional[Integer] - Throughput: Optional[Integer] - KmsKeyId: Optional[KmsKeyId] - SnapshotId: Optional[SnapshotId] - VolumeSize: Optional[Integer] - VolumeType: Optional[VolumeType] + Encrypted: Boolean | None + DeleteOnTermination: Boolean | None + Iops: Integer | None + Throughput: Integer | None + KmsKeyId: KmsKeyId | None + SnapshotId: SnapshotId | None + VolumeSize: Integer | None + VolumeType: VolumeType | None class FleetBlockDeviceMappingRequest(TypedDict, total=False): - DeviceName: Optional[String] - VirtualName: Optional[String] - Ebs: Optional[FleetEbsBlockDeviceRequest] - NoDevice: Optional[String] + DeviceName: String | None + VirtualName: String | None + Ebs: FleetEbsBlockDeviceRequest | None + NoDevice: String | None -FleetBlockDeviceMappingRequestList = List[FleetBlockDeviceMappingRequest] +FleetBlockDeviceMappingRequestList = list[FleetBlockDeviceMappingRequest] class Placement(TypedDict, total=False): - AvailabilityZoneId: Optional[AvailabilityZoneId] - Affinity: Optional[String] - GroupName: Optional[PlacementGroupName] - PartitionNumber: Optional[Integer] - HostId: Optional[String] - Tenancy: Optional[Tenancy] - SpreadDomain: Optional[String] - HostResourceGroupArn: Optional[String] - GroupId: Optional[PlacementGroupId] - AvailabilityZone: Optional[String] + AvailabilityZoneId: AvailabilityZoneId | None + Affinity: String | None + GroupName: PlacementGroupName | None + PartitionNumber: Integer | None + HostId: String | None + Tenancy: Tenancy | None + SpreadDomain: String | None + HostResourceGroupArn: String | None + GroupId: PlacementGroupId | None + AvailabilityZone: String | None class FleetLaunchTemplateOverridesRequest(TypedDict, total=False): - InstanceType: Optional[InstanceType] - MaxPrice: Optional[String] - SubnetId: Optional[SubnetId] - AvailabilityZone: Optional[AvailabilityZoneName] - WeightedCapacity: Optional[Double] - Priority: Optional[Double] - Placement: Optional[Placement] - BlockDeviceMappings: Optional[FleetBlockDeviceMappingRequestList] - InstanceRequirements: Optional[InstanceRequirementsRequest] - ImageId: Optional[String] + InstanceType: InstanceType | None + MaxPrice: String | None + SubnetId: SubnetId | None + AvailabilityZone: AvailabilityZoneName | None + WeightedCapacity: Double | None + Priority: Double | None + Placement: Placement | None + BlockDeviceMappings: FleetBlockDeviceMappingRequestList | None + InstanceRequirements: InstanceRequirementsRequest | None + ImageId: String | None + AvailabilityZoneId: AvailabilityZoneId | None -FleetLaunchTemplateOverridesListRequest = List[FleetLaunchTemplateOverridesRequest] +FleetLaunchTemplateOverridesListRequest = list[FleetLaunchTemplateOverridesRequest] class FleetLaunchTemplateSpecificationRequest(TypedDict, total=False): - LaunchTemplateId: Optional[LaunchTemplateId] - LaunchTemplateName: Optional[LaunchTemplateName] - Version: Optional[String] + LaunchTemplateId: LaunchTemplateId | None + LaunchTemplateName: LaunchTemplateName | None + Version: String | None class FleetLaunchTemplateConfigRequest(TypedDict, total=False): - LaunchTemplateSpecification: Optional[FleetLaunchTemplateSpecificationRequest] - Overrides: Optional[FleetLaunchTemplateOverridesListRequest] + LaunchTemplateSpecification: FleetLaunchTemplateSpecificationRequest | None + Overrides: FleetLaunchTemplateOverridesListRequest | None -FleetLaunchTemplateConfigListRequest = List[FleetLaunchTemplateConfigRequest] +FleetLaunchTemplateConfigListRequest = list[FleetLaunchTemplateConfigRequest] class OnDemandOptionsRequest(TypedDict, total=False): - AllocationStrategy: Optional[FleetOnDemandAllocationStrategy] - CapacityReservationOptions: Optional[CapacityReservationOptionsRequest] - SingleInstanceType: Optional[Boolean] - SingleAvailabilityZone: Optional[Boolean] - MinTargetCapacity: Optional[Integer] - MaxTotalPrice: Optional[String] + AllocationStrategy: FleetOnDemandAllocationStrategy | None + CapacityReservationOptions: CapacityReservationOptionsRequest | None + SingleInstanceType: Boolean | None + SingleAvailabilityZone: Boolean | None + MinTargetCapacity: Integer | None + MaxTotalPrice: String | None class FleetSpotCapacityRebalanceRequest(TypedDict, total=False): - ReplacementStrategy: Optional[FleetReplacementStrategy] - TerminationDelay: Optional[Integer] + ReplacementStrategy: FleetReplacementStrategy | None + TerminationDelay: Integer | None class FleetSpotMaintenanceStrategiesRequest(TypedDict, total=False): - CapacityRebalance: Optional[FleetSpotCapacityRebalanceRequest] + CapacityRebalance: FleetSpotCapacityRebalanceRequest | None class SpotOptionsRequest(TypedDict, total=False): - AllocationStrategy: Optional[SpotAllocationStrategy] - MaintenanceStrategies: Optional[FleetSpotMaintenanceStrategiesRequest] - InstanceInterruptionBehavior: Optional[SpotInstanceInterruptionBehavior] - InstancePoolsToUseCount: Optional[Integer] - SingleInstanceType: Optional[Boolean] - SingleAvailabilityZone: Optional[Boolean] - MinTargetCapacity: Optional[Integer] - MaxTotalPrice: Optional[String] + AllocationStrategy: SpotAllocationStrategy | None + MaintenanceStrategies: FleetSpotMaintenanceStrategiesRequest | None + InstanceInterruptionBehavior: SpotInstanceInterruptionBehavior | None + InstancePoolsToUseCount: Integer | None + SingleInstanceType: Boolean | None + SingleAvailabilityZone: Boolean | None + MinTargetCapacity: Integer | None + MaxTotalPrice: String | None class CreateFleetRequest(ServiceRequest): - DryRun: Optional[Boolean] - ClientToken: Optional[String] - SpotOptions: Optional[SpotOptionsRequest] - OnDemandOptions: Optional[OnDemandOptionsRequest] - ExcessCapacityTerminationPolicy: Optional[FleetExcessCapacityTerminationPolicy] + DryRun: Boolean | None + ClientToken: String | None + SpotOptions: SpotOptionsRequest | None + OnDemandOptions: OnDemandOptionsRequest | None + ExcessCapacityTerminationPolicy: FleetExcessCapacityTerminationPolicy | None LaunchTemplateConfigs: FleetLaunchTemplateConfigListRequest TargetCapacitySpecification: TargetCapacitySpecificationRequest - TerminateInstancesWithExpiration: Optional[Boolean] - Type: Optional[FleetType] - ValidFrom: Optional[DateTime] - ValidUntil: Optional[DateTime] - ReplaceUnhealthyInstances: Optional[Boolean] - TagSpecifications: Optional[TagSpecificationList] - Context: Optional[String] + TerminateInstancesWithExpiration: Boolean | None + Type: FleetType | None + ValidFrom: DateTime | None + ValidUntil: DateTime | None + ReplaceUnhealthyInstances: Boolean | None + TagSpecifications: TagSpecificationList | None + Context: String | None class CreateFleetResult(TypedDict, total=False): - FleetId: Optional[FleetId] - Errors: Optional[CreateFleetErrorsSet] - Instances: Optional[CreateFleetInstancesSet] + FleetId: FleetId | None + Errors: CreateFleetErrorsSet | None + Instances: CreateFleetInstancesSet | None class DestinationOptionsRequest(TypedDict, total=False): - FileFormat: Optional[DestinationFileFormat] - HiveCompatiblePartitions: Optional[Boolean] - PerHourPartition: Optional[Boolean] + FileFormat: DestinationFileFormat | None + HiveCompatiblePartitions: Boolean | None + PerHourPartition: Boolean | None -FlowLogResourceIds = List[FlowLogResourceId] +FlowLogResourceIds = list[FlowLogResourceId] class CreateFlowLogsRequest(ServiceRequest): - DryRun: Optional[Boolean] - ClientToken: Optional[String] - DeliverLogsPermissionArn: Optional[String] - DeliverCrossAccountRole: Optional[String] - LogGroupName: Optional[String] + DryRun: Boolean | None + ClientToken: String | None + DeliverLogsPermissionArn: String | None + DeliverCrossAccountRole: String | None + LogGroupName: String | None ResourceIds: FlowLogResourceIds ResourceType: FlowLogsResourceType - TrafficType: Optional[TrafficType] - LogDestinationType: Optional[LogDestinationType] - LogDestination: Optional[String] - LogFormat: Optional[String] - TagSpecifications: Optional[TagSpecificationList] - MaxAggregationInterval: Optional[Integer] - DestinationOptions: Optional[DestinationOptionsRequest] + TrafficType: TrafficType | None + LogDestinationType: LogDestinationType | None + LogDestination: String | None + LogFormat: String | None + TagSpecifications: TagSpecificationList | None + MaxAggregationInterval: Integer | None + DestinationOptions: DestinationOptionsRequest | None class CreateFlowLogsResult(TypedDict, total=False): - ClientToken: Optional[String] - FlowLogIds: Optional[ValueStringList] - Unsuccessful: Optional[UnsuccessfulItemSet] + ClientToken: String | None + FlowLogIds: ValueStringList | None + Unsuccessful: UnsuccessfulItemSet | None class StorageLocation(TypedDict, total=False): - Bucket: Optional[String] - Key: Optional[String] + Bucket: String | None + Key: String | None class CreateFpgaImageRequest(ServiceRequest): - DryRun: Optional[Boolean] + DryRun: Boolean | None InputStorageLocation: StorageLocation - LogsStorageLocation: Optional[StorageLocation] - Description: Optional[String] - Name: Optional[String] - ClientToken: Optional[String] - TagSpecifications: Optional[TagSpecificationList] + LogsStorageLocation: StorageLocation | None + Description: String | None + Name: String | None + ClientToken: String | None + TagSpecifications: TagSpecificationList | None class CreateFpgaImageResult(TypedDict, total=False): - FpgaImageId: Optional[String] - FpgaImageGlobalId: Optional[String] + FpgaImageId: String | None + FpgaImageGlobalId: String | None class CreateImageRequest(ServiceRequest): - TagSpecifications: Optional[TagSpecificationList] - SnapshotLocation: Optional[SnapshotLocationEnum] - DryRun: Optional[Boolean] + TagSpecifications: TagSpecificationList | None + SnapshotLocation: SnapshotLocationEnum | None + DryRun: Boolean | None InstanceId: InstanceId Name: String - Description: Optional[String] - NoReboot: Optional[Boolean] - BlockDeviceMappings: Optional[BlockDeviceMappingRequestList] + Description: String | None + NoReboot: Boolean | None + BlockDeviceMappings: BlockDeviceMappingRequestList | None class CreateImageResult(TypedDict, total=False): - ImageId: Optional[String] + ImageId: String | None -ImageUsageReportUserIdStringList = List[String] -ImageUsageResourceTypeOptionValuesList = List[ImageUsageResourceTypeOptionValue] +ImageUsageReportUserIdStringList = list[String] +ImageUsageResourceTypeOptionValuesList = list[ImageUsageResourceTypeOptionValue] class ImageUsageResourceTypeOptionRequest(TypedDict, total=False): - OptionName: Optional[String] - OptionValues: Optional[ImageUsageResourceTypeOptionValuesList] + OptionName: String | None + OptionValues: ImageUsageResourceTypeOptionValuesList | None -ImageUsageResourceTypeOptionRequestList = List[ImageUsageResourceTypeOptionRequest] +ImageUsageResourceTypeOptionRequestList = list[ImageUsageResourceTypeOptionRequest] class ImageUsageResourceTypeRequest(TypedDict, total=False): - ResourceType: Optional[ImageUsageResourceTypeName] - ResourceTypeOptions: Optional[ImageUsageResourceTypeOptionRequestList] + ResourceType: ImageUsageResourceTypeName | None + ResourceTypeOptions: ImageUsageResourceTypeOptionRequestList | None -ImageUsageResourceTypeRequestList = List[ImageUsageResourceTypeRequest] +ImageUsageResourceTypeRequestList = list[ImageUsageResourceTypeRequest] class CreateImageUsageReportRequest(ServiceRequest): ImageId: ImageId - DryRun: Optional[Boolean] + DryRun: Boolean | None ResourceTypes: ImageUsageResourceTypeRequestList - AccountIds: Optional[ImageUsageReportUserIdStringList] - ClientToken: Optional[String] - TagSpecifications: Optional[TagSpecificationList] + AccountIds: ImageUsageReportUserIdStringList | None + ClientToken: String | None + TagSpecifications: TagSpecificationList | None class CreateImageUsageReportResult(TypedDict, total=False): - ReportId: Optional[ImageUsageReportId] + ReportId: ImageUsageReportId | None -SecurityGroupIdStringListRequest = List[SecurityGroupId] +SecurityGroupIdStringListRequest = list[SecurityGroupId] class CreateInstanceConnectEndpointRequest(ServiceRequest): - DryRun: Optional[Boolean] + DryRun: Boolean | None SubnetId: SubnetId - SecurityGroupIds: Optional[SecurityGroupIdStringListRequest] - PreserveClientIp: Optional[Boolean] - ClientToken: Optional[String] - TagSpecifications: Optional[TagSpecificationList] - IpAddressType: Optional[IpAddressType] + SecurityGroupIds: SecurityGroupIdStringListRequest | None + PreserveClientIp: Boolean | None + ClientToken: String | None + TagSpecifications: TagSpecificationList | None + IpAddressType: IpAddressType | None class InstanceConnectEndpointDnsNames(TypedDict, total=False): - DnsName: Optional[String] - FipsDnsName: Optional[String] + DnsName: String | None + FipsDnsName: String | None class InstanceConnectEndpointPublicDnsNames(TypedDict, total=False): - Ipv4: Optional[InstanceConnectEndpointDnsNames] - Dualstack: Optional[InstanceConnectEndpointDnsNames] + Ipv4: InstanceConnectEndpointDnsNames | None + Dualstack: InstanceConnectEndpointDnsNames | None -SecurityGroupIdSet = List[SecurityGroupId] -NetworkInterfaceIdSet = List[String] +SecurityGroupIdSet = list[SecurityGroupId] +NetworkInterfaceIdSet = list[String] class Ec2InstanceConnectEndpoint(TypedDict, total=False): - OwnerId: Optional[String] - InstanceConnectEndpointId: Optional[InstanceConnectEndpointId] - InstanceConnectEndpointArn: Optional[ResourceArn] - State: Optional[Ec2InstanceConnectEndpointState] - StateMessage: Optional[String] - DnsName: Optional[String] - FipsDnsName: Optional[String] - NetworkInterfaceIds: Optional[NetworkInterfaceIdSet] - VpcId: Optional[VpcId] - AvailabilityZone: Optional[String] - CreatedAt: Optional[MillisecondDateTime] - SubnetId: Optional[SubnetId] - PreserveClientIp: Optional[Boolean] - SecurityGroupIds: Optional[SecurityGroupIdSet] - Tags: Optional[TagList] - IpAddressType: Optional[IpAddressType] - PublicDnsNames: Optional[InstanceConnectEndpointPublicDnsNames] + OwnerId: String | None + InstanceConnectEndpointId: InstanceConnectEndpointId | None + InstanceConnectEndpointArn: ResourceArn | None + State: Ec2InstanceConnectEndpointState | None + StateMessage: String | None + DnsName: String | None + FipsDnsName: String | None + NetworkInterfaceIds: NetworkInterfaceIdSet | None + VpcId: VpcId | None + AvailabilityZone: String | None + CreatedAt: MillisecondDateTime | None + SubnetId: SubnetId | None + PreserveClientIp: Boolean | None + SecurityGroupIds: SecurityGroupIdSet | None + Tags: TagList | None + IpAddressType: IpAddressType | None + PublicDnsNames: InstanceConnectEndpointPublicDnsNames | None + AvailabilityZoneId: AvailabilityZoneId | None class CreateInstanceConnectEndpointResult(TypedDict, total=False): - InstanceConnectEndpoint: Optional[Ec2InstanceConnectEndpoint] - ClientToken: Optional[String] + InstanceConnectEndpoint: Ec2InstanceConnectEndpoint | None + ClientToken: String | None class InstanceEventWindowTimeRangeRequest(TypedDict, total=False): - StartWeekDay: Optional[WeekDay] - StartHour: Optional[Hour] - EndWeekDay: Optional[WeekDay] - EndHour: Optional[Hour] + StartWeekDay: WeekDay | None + StartHour: Hour | None + EndWeekDay: WeekDay | None + EndHour: Hour | None -InstanceEventWindowTimeRangeRequestSet = List[InstanceEventWindowTimeRangeRequest] +InstanceEventWindowTimeRangeRequestSet = list[InstanceEventWindowTimeRangeRequest] class CreateInstanceEventWindowRequest(ServiceRequest): - DryRun: Optional[Boolean] - Name: Optional[String] - TimeRanges: Optional[InstanceEventWindowTimeRangeRequestSet] - CronExpression: Optional[InstanceEventWindowCronExpression] - TagSpecifications: Optional[TagSpecificationList] + DryRun: Boolean | None + Name: String | None + TimeRanges: InstanceEventWindowTimeRangeRequestSet | None + CronExpression: InstanceEventWindowCronExpression | None + TagSpecifications: TagSpecificationList | None class CreateInstanceEventWindowResult(TypedDict, total=False): - InstanceEventWindow: Optional[InstanceEventWindow] + InstanceEventWindow: InstanceEventWindow | None class ExportToS3TaskSpecification(TypedDict, total=False): - DiskImageFormat: Optional[DiskImageFormat] - ContainerFormat: Optional[ContainerFormat] - S3Bucket: Optional[String] - S3Prefix: Optional[String] + DiskImageFormat: DiskImageFormat | None + ContainerFormat: ContainerFormat | None + S3Bucket: String | None + S3Prefix: String | None class CreateInstanceExportTaskRequest(ServiceRequest): - TagSpecifications: Optional[TagSpecificationList] - Description: Optional[String] + TagSpecifications: TagSpecificationList | None + Description: String | None InstanceId: InstanceId TargetEnvironment: ExportEnvironment ExportToS3Task: ExportToS3TaskSpecification class InstanceExportDetails(TypedDict, total=False): - InstanceId: Optional[String] - TargetEnvironment: Optional[ExportEnvironment] + InstanceId: String | None + TargetEnvironment: ExportEnvironment | None class ExportToS3Task(TypedDict, total=False): - ContainerFormat: Optional[ContainerFormat] - DiskImageFormat: Optional[DiskImageFormat] - S3Bucket: Optional[String] - S3Key: Optional[String] + ContainerFormat: ContainerFormat | None + DiskImageFormat: DiskImageFormat | None + S3Bucket: String | None + S3Key: String | None class ExportTask(TypedDict, total=False): - Description: Optional[String] - ExportTaskId: Optional[String] - ExportToS3Task: Optional[ExportToS3Task] - InstanceExportDetails: Optional[InstanceExportDetails] - State: Optional[ExportTaskState] - StatusMessage: Optional[String] - Tags: Optional[TagList] + Description: String | None + ExportTaskId: String | None + ExportToS3Task: ExportToS3Task | None + InstanceExportDetails: InstanceExportDetails | None + State: ExportTaskState | None + StatusMessage: String | None + Tags: TagList | None class CreateInstanceExportTaskResult(TypedDict, total=False): - ExportTask: Optional[ExportTask] + ExportTask: ExportTask | None class CreateInternetGatewayRequest(ServiceRequest): - TagSpecifications: Optional[TagSpecificationList] - DryRun: Optional[Boolean] + TagSpecifications: TagSpecificationList | None + DryRun: Boolean | None class InternetGateway(TypedDict, total=False): - Attachments: Optional[InternetGatewayAttachmentList] - InternetGatewayId: Optional[String] - OwnerId: Optional[String] - Tags: Optional[TagList] + Attachments: InternetGatewayAttachmentList | None + InternetGatewayId: String | None + OwnerId: String | None + Tags: TagList | None class CreateInternetGatewayResult(TypedDict, total=False): - InternetGateway: Optional[InternetGateway] + InternetGateway: InternetGateway | None + + +class CreateInterruptibleCapacityReservationAllocationRequest(ServiceRequest): + CapacityReservationId: CapacityReservationId + InstanceCount: Integer + ClientToken: String | None + DryRun: Boolean | None + TagSpecifications: TagSpecificationList | None + + +class CreateInterruptibleCapacityReservationAllocationResult(TypedDict, total=False): + SourceCapacityReservationId: CapacityReservationId | None + TargetInstanceCount: Integer | None + Status: InterruptibleCapacityReservationAllocationStatus | None + InterruptionType: InterruptionType | None class CreateIpamExternalResourceVerificationTokenRequest(ServiceRequest): - DryRun: Optional[Boolean] + DryRun: Boolean | None IpamId: IpamId - TagSpecifications: Optional[TagSpecificationList] - ClientToken: Optional[String] + TagSpecifications: TagSpecificationList | None + ClientToken: String | None class IpamExternalResourceVerificationToken(TypedDict, total=False): - IpamExternalResourceVerificationTokenId: Optional[IpamExternalResourceVerificationTokenId] - IpamExternalResourceVerificationTokenArn: Optional[ResourceArn] - IpamId: Optional[IpamId] - IpamArn: Optional[ResourceArn] - IpamRegion: Optional[String] - TokenValue: Optional[String] - TokenName: Optional[String] - NotAfter: Optional[MillisecondDateTime] - Status: Optional[TokenState] - Tags: Optional[TagList] - State: Optional[IpamExternalResourceVerificationTokenState] + IpamExternalResourceVerificationTokenId: IpamExternalResourceVerificationTokenId | None + IpamExternalResourceVerificationTokenArn: ResourceArn | None + IpamId: IpamId | None + IpamArn: ResourceArn | None + IpamRegion: String | None + TokenValue: String | None + TokenName: String | None + NotAfter: MillisecondDateTime | None + Status: TokenState | None + Tags: TagList | None + State: IpamExternalResourceVerificationTokenState | None class CreateIpamExternalResourceVerificationTokenResult(TypedDict, total=False): - IpamExternalResourceVerificationToken: Optional[IpamExternalResourceVerificationToken] + IpamExternalResourceVerificationToken: IpamExternalResourceVerificationToken | None + + +class CreateIpamPolicyRequest(ServiceRequest): + DryRun: Boolean | None + TagSpecifications: TagSpecificationList | None + ClientToken: String | None + IpamId: IpamId + + +class IpamPolicy(TypedDict, total=False): + OwnerId: String | None + IpamPolicyId: IpamPolicyId | None + IpamPolicyArn: ResourceArn | None + IpamPolicyRegion: String | None + State: IpamPolicyState | None + StateMessage: String | None + Tags: TagList | None + IpamId: IpamId | None + + +class CreateIpamPolicyResult(TypedDict, total=False): + IpamPolicy: IpamPolicy | None class IpamPoolSourceResourceRequest(TypedDict, total=False): - ResourceId: Optional[String] - ResourceType: Optional[IpamPoolSourceResourceType] - ResourceRegion: Optional[String] - ResourceOwner: Optional[String] + ResourceId: String | None + ResourceType: IpamPoolSourceResourceType | None + ResourceRegion: String | None + ResourceOwner: String | None class RequestIpamResourceTag(TypedDict, total=False): - Key: Optional[String] - Value: Optional[String] + Key: String | None + Value: String | None -RequestIpamResourceTagList = List[RequestIpamResourceTag] +RequestIpamResourceTagList = list[RequestIpamResourceTag] class CreateIpamPoolRequest(ServiceRequest): - DryRun: Optional[Boolean] + DryRun: Boolean | None IpamScopeId: IpamScopeId - Locale: Optional[String] - SourceIpamPoolId: Optional[IpamPoolId] - Description: Optional[String] + Locale: String | None + SourceIpamPoolId: IpamPoolId | None + Description: String | None AddressFamily: AddressFamily - AutoImport: Optional[Boolean] - PubliclyAdvertisable: Optional[Boolean] - AllocationMinNetmaskLength: Optional[IpamNetmaskLength] - AllocationMaxNetmaskLength: Optional[IpamNetmaskLength] - AllocationDefaultNetmaskLength: Optional[IpamNetmaskLength] - AllocationResourceTags: Optional[RequestIpamResourceTagList] - TagSpecifications: Optional[TagSpecificationList] - ClientToken: Optional[String] - AwsService: Optional[IpamPoolAwsService] - PublicIpSource: Optional[IpamPoolPublicIpSource] - SourceResource: Optional[IpamPoolSourceResourceRequest] + AutoImport: Boolean | None + PubliclyAdvertisable: Boolean | None + AllocationMinNetmaskLength: IpamNetmaskLength | None + AllocationMaxNetmaskLength: IpamNetmaskLength | None + AllocationDefaultNetmaskLength: IpamNetmaskLength | None + AllocationResourceTags: RequestIpamResourceTagList | None + TagSpecifications: TagSpecificationList | None + ClientToken: String | None + AwsService: IpamPoolAwsService | None + PublicIpSource: IpamPoolPublicIpSource | None + SourceResource: IpamPoolSourceResourceRequest | None class IpamPoolSourceResource(TypedDict, total=False): - ResourceId: Optional[String] - ResourceType: Optional[IpamPoolSourceResourceType] - ResourceRegion: Optional[String] - ResourceOwner: Optional[String] + ResourceId: String | None + ResourceType: IpamPoolSourceResourceType | None + ResourceRegion: String | None + ResourceOwner: String | None class IpamResourceTag(TypedDict, total=False): - Key: Optional[String] - Value: Optional[String] + Key: String | None + Value: String | None -IpamResourceTagList = List[IpamResourceTag] +IpamResourceTagList = list[IpamResourceTag] class IpamPool(TypedDict, total=False): - OwnerId: Optional[String] - IpamPoolId: Optional[IpamPoolId] - SourceIpamPoolId: Optional[IpamPoolId] - IpamPoolArn: Optional[ResourceArn] - IpamScopeArn: Optional[ResourceArn] - IpamScopeType: Optional[IpamScopeType] - IpamArn: Optional[ResourceArn] - IpamRegion: Optional[String] - Locale: Optional[String] - PoolDepth: Optional[Integer] - State: Optional[IpamPoolState] - StateMessage: Optional[String] - Description: Optional[String] - AutoImport: Optional[Boolean] - PubliclyAdvertisable: Optional[Boolean] - AddressFamily: Optional[AddressFamily] - AllocationMinNetmaskLength: Optional[IpamNetmaskLength] - AllocationMaxNetmaskLength: Optional[IpamNetmaskLength] - AllocationDefaultNetmaskLength: Optional[IpamNetmaskLength] - AllocationResourceTags: Optional[IpamResourceTagList] - Tags: Optional[TagList] - AwsService: Optional[IpamPoolAwsService] - PublicIpSource: Optional[IpamPoolPublicIpSource] - SourceResource: Optional[IpamPoolSourceResource] + OwnerId: String | None + IpamPoolId: IpamPoolId | None + SourceIpamPoolId: IpamPoolId | None + IpamPoolArn: ResourceArn | None + IpamScopeArn: ResourceArn | None + IpamScopeType: IpamScopeType | None + IpamArn: ResourceArn | None + IpamRegion: String | None + Locale: String | None + PoolDepth: Integer | None + State: IpamPoolState | None + StateMessage: String | None + Description: String | None + AutoImport: Boolean | None + PubliclyAdvertisable: Boolean | None + AddressFamily: AddressFamily | None + AllocationMinNetmaskLength: IpamNetmaskLength | None + AllocationMaxNetmaskLength: IpamNetmaskLength | None + AllocationDefaultNetmaskLength: IpamNetmaskLength | None + AllocationResourceTags: IpamResourceTagList | None + Tags: TagList | None + AwsService: IpamPoolAwsService | None + PublicIpSource: IpamPoolPublicIpSource | None + SourceResource: IpamPoolSourceResource | None class CreateIpamPoolResult(TypedDict, total=False): - IpamPool: Optional[IpamPool] + IpamPool: IpamPool | None + + +class IpamPrefixListResolverRuleConditionRequest(TypedDict, total=False): + Operation: IpamPrefixListResolverRuleConditionOperation + IpamPoolId: String | None + ResourceId: String | None + ResourceOwner: String | None + ResourceRegion: String | None + ResourceTag: RequestIpamResourceTag | None + Cidr: String | None + + +IpamPrefixListResolverRuleConditionRequestSet = list[IpamPrefixListResolverRuleConditionRequest] + + +class IpamPrefixListResolverRuleRequest(TypedDict, total=False): + RuleType: IpamPrefixListResolverRuleType + StaticCidr: String | None + IpamScopeId: IpamScopeId | None + ResourceType: IpamResourceType | None + Conditions: IpamPrefixListResolverRuleConditionRequestSet | None + + +IpamPrefixListResolverRuleRequestSet = list[IpamPrefixListResolverRuleRequest] + + +class CreateIpamPrefixListResolverRequest(ServiceRequest): + DryRun: Boolean | None + IpamId: IpamId + Description: String | None + AddressFamily: AddressFamily + Rules: IpamPrefixListResolverRuleRequestSet | None + TagSpecifications: TagSpecificationList | None + ClientToken: String | None + + +class IpamPrefixListResolver(TypedDict, total=False): + OwnerId: String | None + IpamPrefixListResolverId: IpamPrefixListResolverId | None + IpamPrefixListResolverArn: ResourceArn | None + IpamArn: ResourceArn | None + IpamRegion: String | None + Description: String | None + AddressFamily: AddressFamily | None + State: IpamPrefixListResolverState | None + Tags: TagList | None + LastVersionCreationStatus: IpamPrefixListResolverVersionCreationStatus | None + LastVersionCreationStatusMessage: String | None + + +class CreateIpamPrefixListResolverResult(TypedDict, total=False): + IpamPrefixListResolver: IpamPrefixListResolver | None + + +class CreateIpamPrefixListResolverTargetRequest(ServiceRequest): + DryRun: Boolean | None + IpamPrefixListResolverId: IpamPrefixListResolverId + PrefixListId: String + PrefixListRegion: String + DesiredVersion: BoxedLong | None + TrackLatestVersion: Boolean + TagSpecifications: TagSpecificationList | None + ClientToken: String | None + + +class IpamPrefixListResolverTarget(TypedDict, total=False): + IpamPrefixListResolverTargetId: IpamPrefixListResolverTargetId | None + IpamPrefixListResolverTargetArn: ResourceArn | None + IpamPrefixListResolverId: IpamPrefixListResolverId | None + OwnerId: String | None + PrefixListId: PrefixListResourceId | None + PrefixListRegion: String | None + DesiredVersion: BoxedLong | None + LastSyncedVersion: BoxedLong | None + TrackLatestVersion: Boolean | None + StateMessage: String | None + State: IpamPrefixListResolverTargetState | None + Tags: TagList | None + + +class CreateIpamPrefixListResolverTargetResult(TypedDict, total=False): + IpamPrefixListResolverTarget: IpamPrefixListResolverTarget | None class CreateIpamRequest(ServiceRequest): - DryRun: Optional[Boolean] - Description: Optional[String] - OperatingRegions: Optional[AddIpamOperatingRegionSet] - TagSpecifications: Optional[TagSpecificationList] - ClientToken: Optional[String] - Tier: Optional[IpamTier] - EnablePrivateGua: Optional[Boolean] - MeteredAccount: Optional[IpamMeteredAccount] + DryRun: Boolean | None + Description: String | None + OperatingRegions: AddIpamOperatingRegionSet | None + TagSpecifications: TagSpecificationList | None + ClientToken: String | None + Tier: IpamTier | None + EnablePrivateGua: Boolean | None + MeteredAccount: IpamMeteredAccount | None class CreateIpamResourceDiscoveryRequest(ServiceRequest): - DryRun: Optional[Boolean] - Description: Optional[String] - OperatingRegions: Optional[AddIpamOperatingRegionSet] - TagSpecifications: Optional[TagSpecificationList] - ClientToken: Optional[String] + DryRun: Boolean | None + Description: String | None + OperatingRegions: AddIpamOperatingRegionSet | None + TagSpecifications: TagSpecificationList | None + ClientToken: String | None class IpamOrganizationalUnitExclusion(TypedDict, total=False): - OrganizationsEntityPath: Optional[String] + OrganizationsEntityPath: String | None -IpamOrganizationalUnitExclusionSet = List[IpamOrganizationalUnitExclusion] +IpamOrganizationalUnitExclusionSet = list[IpamOrganizationalUnitExclusion] class IpamOperatingRegion(TypedDict, total=False): - RegionName: Optional[String] + RegionName: String | None -IpamOperatingRegionSet = List[IpamOperatingRegion] +IpamOperatingRegionSet = list[IpamOperatingRegion] class IpamResourceDiscovery(TypedDict, total=False): - OwnerId: Optional[String] - IpamResourceDiscoveryId: Optional[IpamResourceDiscoveryId] - IpamResourceDiscoveryArn: Optional[String] - IpamResourceDiscoveryRegion: Optional[String] - Description: Optional[String] - OperatingRegions: Optional[IpamOperatingRegionSet] - IsDefault: Optional[Boolean] - State: Optional[IpamResourceDiscoveryState] - Tags: Optional[TagList] - OrganizationalUnitExclusions: Optional[IpamOrganizationalUnitExclusionSet] + OwnerId: String | None + IpamResourceDiscoveryId: IpamResourceDiscoveryId | None + IpamResourceDiscoveryArn: String | None + IpamResourceDiscoveryRegion: String | None + Description: String | None + OperatingRegions: IpamOperatingRegionSet | None + IsDefault: Boolean | None + State: IpamResourceDiscoveryState | None + Tags: TagList | None + OrganizationalUnitExclusions: IpamOrganizationalUnitExclusionSet | None class CreateIpamResourceDiscoveryResult(TypedDict, total=False): - IpamResourceDiscovery: Optional[IpamResourceDiscovery] + IpamResourceDiscovery: IpamResourceDiscovery | None class Ipam(TypedDict, total=False): - OwnerId: Optional[String] - IpamId: Optional[IpamId] - IpamArn: Optional[ResourceArn] - IpamRegion: Optional[String] - PublicDefaultScopeId: Optional[IpamScopeId] - PrivateDefaultScopeId: Optional[IpamScopeId] - ScopeCount: Optional[Integer] - Description: Optional[String] - OperatingRegions: Optional[IpamOperatingRegionSet] - State: Optional[IpamState] - Tags: Optional[TagList] - DefaultResourceDiscoveryId: Optional[IpamResourceDiscoveryId] - DefaultResourceDiscoveryAssociationId: Optional[IpamResourceDiscoveryAssociationId] - ResourceDiscoveryAssociationCount: Optional[Integer] - StateMessage: Optional[String] - Tier: Optional[IpamTier] - EnablePrivateGua: Optional[Boolean] - MeteredAccount: Optional[IpamMeteredAccount] + OwnerId: String | None + IpamId: IpamId | None + IpamArn: ResourceArn | None + IpamRegion: String | None + PublicDefaultScopeId: IpamScopeId | None + PrivateDefaultScopeId: IpamScopeId | None + ScopeCount: Integer | None + Description: String | None + OperatingRegions: IpamOperatingRegionSet | None + State: IpamState | None + Tags: TagList | None + DefaultResourceDiscoveryId: IpamResourceDiscoveryId | None + DefaultResourceDiscoveryAssociationId: IpamResourceDiscoveryAssociationId | None + ResourceDiscoveryAssociationCount: Integer | None + StateMessage: String | None + Tier: IpamTier | None + EnablePrivateGua: Boolean | None + MeteredAccount: IpamMeteredAccount | None class CreateIpamResult(TypedDict, total=False): - Ipam: Optional[Ipam] + Ipam: Ipam | None + + +class ExternalAuthorityConfiguration(TypedDict, total=False): + Type: IpamScopeExternalAuthorityType | None + ExternalResourceIdentifier: String | None class CreateIpamScopeRequest(ServiceRequest): - DryRun: Optional[Boolean] + DryRun: Boolean | None IpamId: IpamId - Description: Optional[String] - TagSpecifications: Optional[TagSpecificationList] - ClientToken: Optional[String] + Description: String | None + TagSpecifications: TagSpecificationList | None + ClientToken: String | None + ExternalAuthorityConfiguration: ExternalAuthorityConfiguration | None + + +class IpamScopeExternalAuthorityConfiguration(TypedDict, total=False): + Type: IpamScopeExternalAuthorityType | None + ExternalResourceIdentifier: String | None class IpamScope(TypedDict, total=False): - OwnerId: Optional[String] - IpamScopeId: Optional[IpamScopeId] - IpamScopeArn: Optional[ResourceArn] - IpamArn: Optional[ResourceArn] - IpamRegion: Optional[String] - IpamScopeType: Optional[IpamScopeType] - IsDefault: Optional[Boolean] - Description: Optional[String] - PoolCount: Optional[Integer] - State: Optional[IpamScopeState] - Tags: Optional[TagList] + OwnerId: String | None + IpamScopeId: IpamScopeId | None + IpamScopeArn: ResourceArn | None + IpamArn: ResourceArn | None + IpamRegion: String | None + IpamScopeType: IpamScopeType | None + IsDefault: Boolean | None + Description: String | None + PoolCount: Integer | None + State: IpamScopeState | None + Tags: TagList | None + ExternalAuthorityConfiguration: IpamScopeExternalAuthorityConfiguration | None class CreateIpamScopeResult(TypedDict, total=False): - IpamScope: Optional[IpamScope] + IpamScope: IpamScope | None class CreateKeyPairRequest(ServiceRequest): KeyName: String - KeyType: Optional[KeyType] - TagSpecifications: Optional[TagSpecificationList] - KeyFormat: Optional[KeyFormat] - DryRun: Optional[Boolean] + KeyType: KeyType | None + TagSpecifications: TagSpecificationList | None + KeyFormat: KeyFormat | None + DryRun: Boolean | None class OperatorRequest(TypedDict, total=False): - Principal: Optional[String] + Principal: String | None + + +class SecondaryInterfacePrivateIpAddressSpecificationRequest(TypedDict, total=False): + PrivateIpAddress: String | None + + +SecondaryInterfacePrivateIpAddressSpecificationListRequest = list[ + SecondaryInterfacePrivateIpAddressSpecificationRequest +] + + +class LaunchTemplateInstanceSecondaryInterfaceSpecificationRequest(TypedDict, total=False): + DeleteOnTermination: Boolean | None + DeviceIndex: Integer | None + PrivateIpAddresses: SecondaryInterfacePrivateIpAddressSpecificationListRequest | None + PrivateIpAddressCount: Integer | None + SecondarySubnetId: SecondarySubnetId | None + InterfaceType: SecondaryInterfaceType | None + NetworkCardIndex: Integer | None + + +LaunchTemplateInstanceSecondaryInterfaceSpecificationRequestList = list[ + LaunchTemplateInstanceSecondaryInterfaceSpecificationRequest +] class LaunchTemplateNetworkPerformanceOptionsRequest(TypedDict, total=False): - BandwidthWeighting: Optional[InstanceBandwidthWeighting] + BandwidthWeighting: InstanceBandwidthWeighting | None class LaunchTemplateInstanceMaintenanceOptionsRequest(TypedDict, total=False): - AutoRecovery: Optional[LaunchTemplateAutoRecoveryState] + AutoRecovery: LaunchTemplateAutoRecoveryState | None class LaunchTemplatePrivateDnsNameOptionsRequest(TypedDict, total=False): - HostnameType: Optional[HostnameType] - EnableResourceNameDnsARecord: Optional[Boolean] - EnableResourceNameDnsAAAARecord: Optional[Boolean] + HostnameType: HostnameType | None + EnableResourceNameDnsARecord: Boolean | None + EnableResourceNameDnsAAAARecord: Boolean | None class LaunchTemplateEnclaveOptionsRequest(TypedDict, total=False): - Enabled: Optional[Boolean] + Enabled: Boolean | None class LaunchTemplateInstanceMetadataOptionsRequest(TypedDict, total=False): - HttpTokens: Optional[LaunchTemplateHttpTokensState] - HttpPutResponseHopLimit: Optional[Integer] - HttpEndpoint: Optional[LaunchTemplateInstanceMetadataEndpointState] - HttpProtocolIpv6: Optional[LaunchTemplateInstanceMetadataProtocolIpv6] - InstanceMetadataTags: Optional[LaunchTemplateInstanceMetadataTagsState] + HttpTokens: LaunchTemplateHttpTokensState | None + HttpPutResponseHopLimit: Integer | None + HttpEndpoint: LaunchTemplateInstanceMetadataEndpointState | None + HttpProtocolIpv6: LaunchTemplateInstanceMetadataProtocolIpv6 | None + InstanceMetadataTags: LaunchTemplateInstanceMetadataTagsState | None class LaunchTemplateHibernationOptionsRequest(TypedDict, total=False): - Configured: Optional[Boolean] + Configured: Boolean | None class LaunchTemplateLicenseConfigurationRequest(TypedDict, total=False): - LicenseConfigurationArn: Optional[String] + LicenseConfigurationArn: String | None -LaunchTemplateLicenseSpecificationListRequest = List[LaunchTemplateLicenseConfigurationRequest] +LaunchTemplateLicenseSpecificationListRequest = list[LaunchTemplateLicenseConfigurationRequest] class LaunchTemplateCapacityReservationSpecificationRequest(TypedDict, total=False): - CapacityReservationPreference: Optional[CapacityReservationPreference] - CapacityReservationTarget: Optional[CapacityReservationTarget] + CapacityReservationPreference: CapacityReservationPreference | None + CapacityReservationTarget: CapacityReservationTarget | None class LaunchTemplateCpuOptionsRequest(TypedDict, total=False): - CoreCount: Optional[Integer] - ThreadsPerCore: Optional[Integer] - AmdSevSnp: Optional[AmdSevSnpSpecification] + CoreCount: Integer | None + ThreadsPerCore: Integer | None + AmdSevSnp: AmdSevSnpSpecification | None + NestedVirtualization: NestedVirtualizationSpecification | None class CreditSpecificationRequest(TypedDict, total=False): @@ -8007,630 +9018,650 @@ class CreditSpecificationRequest(TypedDict, total=False): class LaunchTemplateSpotMarketOptionsRequest(TypedDict, total=False): - MaxPrice: Optional[String] - SpotInstanceType: Optional[SpotInstanceType] - BlockDurationMinutes: Optional[Integer] - ValidUntil: Optional[DateTime] - InstanceInterruptionBehavior: Optional[InstanceInterruptionBehavior] + MaxPrice: String | None + SpotInstanceType: SpotInstanceType | None + BlockDurationMinutes: Integer | None + ValidUntil: DateTime | None + InstanceInterruptionBehavior: InstanceInterruptionBehavior | None class LaunchTemplateInstanceMarketOptionsRequest(TypedDict, total=False): - MarketType: Optional[MarketType] - SpotOptions: Optional[LaunchTemplateSpotMarketOptionsRequest] + MarketType: MarketType | None + SpotOptions: LaunchTemplateSpotMarketOptionsRequest | None -SecurityGroupStringList = List[SecurityGroupName] -SecurityGroupIdStringList = List[SecurityGroupId] +SecurityGroupStringList = list[SecurityGroupName] +SecurityGroupIdStringList = list[SecurityGroupId] class LaunchTemplateElasticInferenceAccelerator(TypedDict, total=False): Type: String - Count: Optional[LaunchTemplateElasticInferenceAcceleratorCount] + Count: LaunchTemplateElasticInferenceAcceleratorCount | None -LaunchTemplateElasticInferenceAcceleratorList = List[LaunchTemplateElasticInferenceAccelerator] +LaunchTemplateElasticInferenceAcceleratorList = list[LaunchTemplateElasticInferenceAccelerator] class ElasticGpuSpecification(TypedDict, total=False): Type: String -ElasticGpuSpecificationList = List[ElasticGpuSpecification] +ElasticGpuSpecificationList = list[ElasticGpuSpecification] class LaunchTemplateTagSpecificationRequest(TypedDict, total=False): - ResourceType: Optional[ResourceType] - Tags: Optional[TagList] + ResourceType: ResourceType | None + Tags: TagList | None -LaunchTemplateTagSpecificationRequestList = List[LaunchTemplateTagSpecificationRequest] +LaunchTemplateTagSpecificationRequestList = list[LaunchTemplateTagSpecificationRequest] class LaunchTemplatePlacementRequest(TypedDict, total=False): - AvailabilityZone: Optional[String] - AvailabilityZoneId: Optional[AvailabilityZoneId] - Affinity: Optional[String] - GroupName: Optional[PlacementGroupName] - HostId: Optional[DedicatedHostId] - Tenancy: Optional[Tenancy] - SpreadDomain: Optional[String] - HostResourceGroupArn: Optional[String] - PartitionNumber: Optional[Integer] - GroupId: Optional[PlacementGroupId] + AvailabilityZone: String | None + AvailabilityZoneId: AvailabilityZoneId | None + Affinity: String | None + GroupName: PlacementGroupName | None + HostId: DedicatedHostId | None + Tenancy: Tenancy | None + SpreadDomain: String | None + HostResourceGroupArn: String | None + PartitionNumber: Integer | None + GroupId: PlacementGroupId | None class LaunchTemplatesMonitoringRequest(TypedDict, total=False): - Enabled: Optional[Boolean] + Enabled: Boolean | None class EnaSrdUdpSpecificationRequest(TypedDict, total=False): - EnaSrdUdpEnabled: Optional[Boolean] + EnaSrdUdpEnabled: Boolean | None class EnaSrdSpecificationRequest(TypedDict, total=False): - EnaSrdEnabled: Optional[Boolean] - EnaSrdUdpSpecification: Optional[EnaSrdUdpSpecificationRequest] + EnaSrdEnabled: Boolean | None + EnaSrdUdpSpecification: EnaSrdUdpSpecificationRequest | None class Ipv6PrefixSpecificationRequest(TypedDict, total=False): - Ipv6Prefix: Optional[String] + Ipv6Prefix: String | None -Ipv6PrefixList = List[Ipv6PrefixSpecificationRequest] +Ipv6PrefixList = list[Ipv6PrefixSpecificationRequest] class Ipv4PrefixSpecificationRequest(TypedDict, total=False): - Ipv4Prefix: Optional[String] + Ipv4Prefix: String | None -Ipv4PrefixList = List[Ipv4PrefixSpecificationRequest] +Ipv4PrefixList = list[Ipv4PrefixSpecificationRequest] class PrivateIpAddressSpecification(TypedDict, total=False): - Primary: Optional[Boolean] - PrivateIpAddress: Optional[String] + Primary: Boolean | None + PrivateIpAddress: String | None -PrivateIpAddressSpecificationList = List[PrivateIpAddressSpecification] +PrivateIpAddressSpecificationList = list[PrivateIpAddressSpecification] class InstanceIpv6AddressRequest(TypedDict, total=False): - Ipv6Address: Optional[String] + Ipv6Address: String | None -InstanceIpv6AddressListRequest = List[InstanceIpv6AddressRequest] +InstanceIpv6AddressListRequest = list[InstanceIpv6AddressRequest] class LaunchTemplateInstanceNetworkInterfaceSpecificationRequest(TypedDict, total=False): - AssociateCarrierIpAddress: Optional[Boolean] - AssociatePublicIpAddress: Optional[Boolean] - DeleteOnTermination: Optional[Boolean] - Description: Optional[String] - DeviceIndex: Optional[Integer] - Groups: Optional[SecurityGroupIdStringList] - InterfaceType: Optional[String] - Ipv6AddressCount: Optional[Integer] - Ipv6Addresses: Optional[InstanceIpv6AddressListRequest] - NetworkInterfaceId: Optional[NetworkInterfaceId] - PrivateIpAddress: Optional[String] - PrivateIpAddresses: Optional[PrivateIpAddressSpecificationList] - SecondaryPrivateIpAddressCount: Optional[Integer] - SubnetId: Optional[SubnetId] - NetworkCardIndex: Optional[Integer] - Ipv4Prefixes: Optional[Ipv4PrefixList] - Ipv4PrefixCount: Optional[Integer] - Ipv6Prefixes: Optional[Ipv6PrefixList] - Ipv6PrefixCount: Optional[Integer] - PrimaryIpv6: Optional[Boolean] - EnaSrdSpecification: Optional[EnaSrdSpecificationRequest] - ConnectionTrackingSpecification: Optional[ConnectionTrackingSpecificationRequest] - EnaQueueCount: Optional[Integer] - - -LaunchTemplateInstanceNetworkInterfaceSpecificationRequestList = List[ + AssociateCarrierIpAddress: Boolean | None + AssociatePublicIpAddress: Boolean | None + DeleteOnTermination: Boolean | None + Description: String | None + DeviceIndex: Integer | None + Groups: SecurityGroupIdStringList | None + InterfaceType: String | None + Ipv6AddressCount: Integer | None + Ipv6Addresses: InstanceIpv6AddressListRequest | None + NetworkInterfaceId: NetworkInterfaceId | None + PrivateIpAddress: String | None + PrivateIpAddresses: PrivateIpAddressSpecificationList | None + SecondaryPrivateIpAddressCount: Integer | None + SubnetId: SubnetId | None + NetworkCardIndex: Integer | None + Ipv4Prefixes: Ipv4PrefixList | None + Ipv4PrefixCount: Integer | None + Ipv6Prefixes: Ipv6PrefixList | None + Ipv6PrefixCount: Integer | None + PrimaryIpv6: Boolean | None + EnaSrdSpecification: EnaSrdSpecificationRequest | None + ConnectionTrackingSpecification: ConnectionTrackingSpecificationRequest | None + EnaQueueCount: Integer | None + + +LaunchTemplateInstanceNetworkInterfaceSpecificationRequestList = list[ LaunchTemplateInstanceNetworkInterfaceSpecificationRequest ] class LaunchTemplateEbsBlockDeviceRequest(TypedDict, total=False): - Encrypted: Optional[Boolean] - DeleteOnTermination: Optional[Boolean] - Iops: Optional[Integer] - KmsKeyId: Optional[KmsKeyId] - SnapshotId: Optional[SnapshotId] - VolumeSize: Optional[Integer] - VolumeType: Optional[VolumeType] - Throughput: Optional[Integer] - VolumeInitializationRate: Optional[Integer] + Encrypted: Boolean | None + DeleteOnTermination: Boolean | None + Iops: Integer | None + KmsKeyId: KmsKeyId | None + SnapshotId: SnapshotId | None + VolumeSize: Integer | None + VolumeType: VolumeType | None + Throughput: Integer | None + VolumeInitializationRate: Integer | None + EbsCardIndex: Integer | None class LaunchTemplateBlockDeviceMappingRequest(TypedDict, total=False): - DeviceName: Optional[String] - VirtualName: Optional[String] - Ebs: Optional[LaunchTemplateEbsBlockDeviceRequest] - NoDevice: Optional[String] + DeviceName: String | None + VirtualName: String | None + Ebs: LaunchTemplateEbsBlockDeviceRequest | None + NoDevice: String | None -LaunchTemplateBlockDeviceMappingRequestList = List[LaunchTemplateBlockDeviceMappingRequest] +LaunchTemplateBlockDeviceMappingRequestList = list[LaunchTemplateBlockDeviceMappingRequest] class LaunchTemplateIamInstanceProfileSpecificationRequest(TypedDict, total=False): - Arn: Optional[String] - Name: Optional[String] + Arn: String | None + Name: String | None class RequestLaunchTemplateData(TypedDict, total=False): - KernelId: Optional[KernelId] - EbsOptimized: Optional[Boolean] - IamInstanceProfile: Optional[LaunchTemplateIamInstanceProfileSpecificationRequest] - BlockDeviceMappings: Optional[LaunchTemplateBlockDeviceMappingRequestList] - NetworkInterfaces: Optional[LaunchTemplateInstanceNetworkInterfaceSpecificationRequestList] - ImageId: Optional[ImageId] - InstanceType: Optional[InstanceType] - KeyName: Optional[KeyPairName] - Monitoring: Optional[LaunchTemplatesMonitoringRequest] - Placement: Optional[LaunchTemplatePlacementRequest] - RamDiskId: Optional[RamdiskId] - DisableApiTermination: Optional[Boolean] - InstanceInitiatedShutdownBehavior: Optional[ShutdownBehavior] - UserData: Optional[SensitiveUserData] - TagSpecifications: Optional[LaunchTemplateTagSpecificationRequestList] - ElasticGpuSpecifications: Optional[ElasticGpuSpecificationList] - ElasticInferenceAccelerators: Optional[LaunchTemplateElasticInferenceAcceleratorList] - SecurityGroupIds: Optional[SecurityGroupIdStringList] - SecurityGroups: Optional[SecurityGroupStringList] - InstanceMarketOptions: Optional[LaunchTemplateInstanceMarketOptionsRequest] - CreditSpecification: Optional[CreditSpecificationRequest] - CpuOptions: Optional[LaunchTemplateCpuOptionsRequest] - CapacityReservationSpecification: Optional[ - LaunchTemplateCapacityReservationSpecificationRequest - ] - LicenseSpecifications: Optional[LaunchTemplateLicenseSpecificationListRequest] - HibernationOptions: Optional[LaunchTemplateHibernationOptionsRequest] - MetadataOptions: Optional[LaunchTemplateInstanceMetadataOptionsRequest] - EnclaveOptions: Optional[LaunchTemplateEnclaveOptionsRequest] - InstanceRequirements: Optional[InstanceRequirementsRequest] - PrivateDnsNameOptions: Optional[LaunchTemplatePrivateDnsNameOptionsRequest] - MaintenanceOptions: Optional[LaunchTemplateInstanceMaintenanceOptionsRequest] - DisableApiStop: Optional[Boolean] - Operator: Optional[OperatorRequest] - NetworkPerformanceOptions: Optional[LaunchTemplateNetworkPerformanceOptionsRequest] + KernelId: KernelId | None + EbsOptimized: Boolean | None + IamInstanceProfile: LaunchTemplateIamInstanceProfileSpecificationRequest | None + BlockDeviceMappings: LaunchTemplateBlockDeviceMappingRequestList | None + NetworkInterfaces: LaunchTemplateInstanceNetworkInterfaceSpecificationRequestList | None + ImageId: ImageId | None + InstanceType: InstanceType | None + KeyName: KeyPairName | None + Monitoring: LaunchTemplatesMonitoringRequest | None + Placement: LaunchTemplatePlacementRequest | None + RamDiskId: RamdiskId | None + DisableApiTermination: Boolean | None + InstanceInitiatedShutdownBehavior: ShutdownBehavior | None + UserData: SensitiveUserData | None + TagSpecifications: LaunchTemplateTagSpecificationRequestList | None + ElasticGpuSpecifications: ElasticGpuSpecificationList | None + ElasticInferenceAccelerators: LaunchTemplateElasticInferenceAcceleratorList | None + SecurityGroupIds: SecurityGroupIdStringList | None + SecurityGroups: SecurityGroupStringList | None + InstanceMarketOptions: LaunchTemplateInstanceMarketOptionsRequest | None + CreditSpecification: CreditSpecificationRequest | None + CpuOptions: LaunchTemplateCpuOptionsRequest | None + CapacityReservationSpecification: LaunchTemplateCapacityReservationSpecificationRequest | None + LicenseSpecifications: LaunchTemplateLicenseSpecificationListRequest | None + HibernationOptions: LaunchTemplateHibernationOptionsRequest | None + MetadataOptions: LaunchTemplateInstanceMetadataOptionsRequest | None + EnclaveOptions: LaunchTemplateEnclaveOptionsRequest | None + InstanceRequirements: InstanceRequirementsRequest | None + PrivateDnsNameOptions: LaunchTemplatePrivateDnsNameOptionsRequest | None + MaintenanceOptions: LaunchTemplateInstanceMaintenanceOptionsRequest | None + DisableApiStop: Boolean | None + Operator: OperatorRequest | None + NetworkPerformanceOptions: LaunchTemplateNetworkPerformanceOptionsRequest | None + SecondaryInterfaces: LaunchTemplateInstanceSecondaryInterfaceSpecificationRequestList | None class CreateLaunchTemplateRequest(ServiceRequest): - DryRun: Optional[Boolean] - ClientToken: Optional[String] + DryRun: Boolean | None + ClientToken: String | None LaunchTemplateName: LaunchTemplateName - VersionDescription: Optional[VersionDescription] + VersionDescription: VersionDescription | None LaunchTemplateData: RequestLaunchTemplateData - Operator: Optional[OperatorRequest] - TagSpecifications: Optional[TagSpecificationList] + Operator: OperatorRequest | None + TagSpecifications: TagSpecificationList | None class ValidationError(TypedDict, total=False): - Code: Optional[String] - Message: Optional[String] + Code: String | None + Message: String | None -ErrorSet = List[ValidationError] +ErrorSet = list[ValidationError] class ValidationWarning(TypedDict, total=False): - Errors: Optional[ErrorSet] - - -class OperatorResponse(TypedDict, total=False): - Managed: Optional[Boolean] - Principal: Optional[String] + Errors: ErrorSet | None class LaunchTemplate(TypedDict, total=False): - LaunchTemplateId: Optional[String] - LaunchTemplateName: Optional[LaunchTemplateName] - CreateTime: Optional[DateTime] - CreatedBy: Optional[String] - DefaultVersionNumber: Optional[Long] - LatestVersionNumber: Optional[Long] - Tags: Optional[TagList] - Operator: Optional[OperatorResponse] + LaunchTemplateId: String | None + LaunchTemplateName: LaunchTemplateName | None + CreateTime: DateTime | None + CreatedBy: String | None + DefaultVersionNumber: Long | None + LatestVersionNumber: Long | None + Tags: TagList | None + Operator: OperatorResponse | None class CreateLaunchTemplateResult(TypedDict, total=False): - LaunchTemplate: Optional[LaunchTemplate] - Warning: Optional[ValidationWarning] + LaunchTemplate: LaunchTemplate | None + Warning: ValidationWarning | None class CreateLaunchTemplateVersionRequest(ServiceRequest): - DryRun: Optional[Boolean] - ClientToken: Optional[String] - LaunchTemplateId: Optional[LaunchTemplateId] - LaunchTemplateName: Optional[LaunchTemplateName] - SourceVersion: Optional[String] - VersionDescription: Optional[VersionDescription] + DryRun: Boolean | None + ClientToken: String | None + LaunchTemplateId: LaunchTemplateId | None + LaunchTemplateName: LaunchTemplateName | None + SourceVersion: String | None + VersionDescription: VersionDescription | None LaunchTemplateData: RequestLaunchTemplateData - ResolveAlias: Optional[Boolean] + ResolveAlias: Boolean | None + + +class SecondaryInterfacePrivateIpAddressSpecification(TypedDict, total=False): + PrivateIpAddress: String | None + + +SecondaryInterfacePrivateIpAddressSpecificationList = list[ + SecondaryInterfacePrivateIpAddressSpecification +] + + +class LaunchTemplateInstanceSecondaryInterfaceSpecification(TypedDict, total=False): + DeleteOnTermination: Boolean | None + DeviceIndex: Integer | None + PrivateIpAddresses: SecondaryInterfacePrivateIpAddressSpecificationList | None + PrivateIpAddressCount: Integer | None + SecondarySubnetId: SecondarySubnetId | None + InterfaceType: SecondaryInterfaceType | None + NetworkCardIndex: Integer | None + + +LaunchTemplateInstanceSecondaryInterfaceSpecificationList = list[ + LaunchTemplateInstanceSecondaryInterfaceSpecification +] class LaunchTemplateNetworkPerformanceOptions(TypedDict, total=False): - BandwidthWeighting: Optional[InstanceBandwidthWeighting] + BandwidthWeighting: InstanceBandwidthWeighting | None class LaunchTemplateInstanceMaintenanceOptions(TypedDict, total=False): - AutoRecovery: Optional[LaunchTemplateAutoRecoveryState] + AutoRecovery: LaunchTemplateAutoRecoveryState | None class LaunchTemplatePrivateDnsNameOptions(TypedDict, total=False): - HostnameType: Optional[HostnameType] - EnableResourceNameDnsARecord: Optional[Boolean] - EnableResourceNameDnsAAAARecord: Optional[Boolean] + HostnameType: HostnameType | None + EnableResourceNameDnsARecord: Boolean | None + EnableResourceNameDnsAAAARecord: Boolean | None class LaunchTemplateEnclaveOptions(TypedDict, total=False): - Enabled: Optional[Boolean] + Enabled: Boolean | None class LaunchTemplateInstanceMetadataOptions(TypedDict, total=False): - State: Optional[LaunchTemplateInstanceMetadataOptionsState] - HttpTokens: Optional[LaunchTemplateHttpTokensState] - HttpPutResponseHopLimit: Optional[Integer] - HttpEndpoint: Optional[LaunchTemplateInstanceMetadataEndpointState] - HttpProtocolIpv6: Optional[LaunchTemplateInstanceMetadataProtocolIpv6] - InstanceMetadataTags: Optional[LaunchTemplateInstanceMetadataTagsState] + State: LaunchTemplateInstanceMetadataOptionsState | None + HttpTokens: LaunchTemplateHttpTokensState | None + HttpPutResponseHopLimit: Integer | None + HttpEndpoint: LaunchTemplateInstanceMetadataEndpointState | None + HttpProtocolIpv6: LaunchTemplateInstanceMetadataProtocolIpv6 | None + InstanceMetadataTags: LaunchTemplateInstanceMetadataTagsState | None class LaunchTemplateHibernationOptions(TypedDict, total=False): - Configured: Optional[Boolean] + Configured: Boolean | None class LaunchTemplateLicenseConfiguration(TypedDict, total=False): - LicenseConfigurationArn: Optional[String] + LicenseConfigurationArn: String | None -LaunchTemplateLicenseList = List[LaunchTemplateLicenseConfiguration] +LaunchTemplateLicenseList = list[LaunchTemplateLicenseConfiguration] class LaunchTemplateCapacityReservationSpecificationResponse(TypedDict, total=False): - CapacityReservationPreference: Optional[CapacityReservationPreference] - CapacityReservationTarget: Optional[CapacityReservationTargetResponse] + CapacityReservationPreference: CapacityReservationPreference | None + CapacityReservationTarget: CapacityReservationTargetResponse | None class LaunchTemplateCpuOptions(TypedDict, total=False): - CoreCount: Optional[Integer] - ThreadsPerCore: Optional[Integer] - AmdSevSnp: Optional[AmdSevSnpSpecification] + CoreCount: Integer | None + ThreadsPerCore: Integer | None + AmdSevSnp: AmdSevSnpSpecification | None + NestedVirtualization: NestedVirtualizationSpecification | None class CreditSpecification(TypedDict, total=False): - CpuCredits: Optional[String] + CpuCredits: String | None class LaunchTemplateSpotMarketOptions(TypedDict, total=False): - MaxPrice: Optional[String] - SpotInstanceType: Optional[SpotInstanceType] - BlockDurationMinutes: Optional[Integer] - ValidUntil: Optional[DateTime] - InstanceInterruptionBehavior: Optional[InstanceInterruptionBehavior] + MaxPrice: String | None + SpotInstanceType: SpotInstanceType | None + BlockDurationMinutes: Integer | None + ValidUntil: DateTime | None + InstanceInterruptionBehavior: InstanceInterruptionBehavior | None class LaunchTemplateInstanceMarketOptions(TypedDict, total=False): - MarketType: Optional[MarketType] - SpotOptions: Optional[LaunchTemplateSpotMarketOptions] + MarketType: MarketType | None + SpotOptions: LaunchTemplateSpotMarketOptions | None class LaunchTemplateElasticInferenceAcceleratorResponse(TypedDict, total=False): - Type: Optional[String] - Count: Optional[Integer] + Type: String | None + Count: Integer | None -LaunchTemplateElasticInferenceAcceleratorResponseList = List[ +LaunchTemplateElasticInferenceAcceleratorResponseList = list[ LaunchTemplateElasticInferenceAcceleratorResponse ] class ElasticGpuSpecificationResponse(TypedDict, total=False): - Type: Optional[String] + Type: String | None -ElasticGpuSpecificationResponseList = List[ElasticGpuSpecificationResponse] +ElasticGpuSpecificationResponseList = list[ElasticGpuSpecificationResponse] class LaunchTemplateTagSpecification(TypedDict, total=False): - ResourceType: Optional[ResourceType] - Tags: Optional[TagList] + ResourceType: ResourceType | None + Tags: TagList | None -LaunchTemplateTagSpecificationList = List[LaunchTemplateTagSpecification] +LaunchTemplateTagSpecificationList = list[LaunchTemplateTagSpecification] class LaunchTemplatePlacement(TypedDict, total=False): - AvailabilityZone: Optional[String] - AvailabilityZoneId: Optional[AvailabilityZoneId] - Affinity: Optional[String] - GroupName: Optional[String] - HostId: Optional[String] - Tenancy: Optional[Tenancy] - SpreadDomain: Optional[String] - HostResourceGroupArn: Optional[String] - PartitionNumber: Optional[Integer] - GroupId: Optional[PlacementGroupId] + AvailabilityZone: String | None + AvailabilityZoneId: AvailabilityZoneId | None + Affinity: String | None + GroupName: String | None + HostId: String | None + Tenancy: Tenancy | None + SpreadDomain: String | None + HostResourceGroupArn: String | None + PartitionNumber: Integer | None + GroupId: PlacementGroupId | None class LaunchTemplatesMonitoring(TypedDict, total=False): - Enabled: Optional[Boolean] + Enabled: Boolean | None class LaunchTemplateEnaSrdUdpSpecification(TypedDict, total=False): - EnaSrdUdpEnabled: Optional[Boolean] + EnaSrdUdpEnabled: Boolean | None class LaunchTemplateEnaSrdSpecification(TypedDict, total=False): - EnaSrdEnabled: Optional[Boolean] - EnaSrdUdpSpecification: Optional[LaunchTemplateEnaSrdUdpSpecification] + EnaSrdEnabled: Boolean | None + EnaSrdUdpSpecification: LaunchTemplateEnaSrdUdpSpecification | None class Ipv6PrefixSpecificationResponse(TypedDict, total=False): - Ipv6Prefix: Optional[String] + Ipv6Prefix: String | None -Ipv6PrefixListResponse = List[Ipv6PrefixSpecificationResponse] +Ipv6PrefixListResponse = list[Ipv6PrefixSpecificationResponse] class Ipv4PrefixSpecificationResponse(TypedDict, total=False): - Ipv4Prefix: Optional[String] + Ipv4Prefix: String | None -Ipv4PrefixListResponse = List[Ipv4PrefixSpecificationResponse] +Ipv4PrefixListResponse = list[Ipv4PrefixSpecificationResponse] class InstanceIpv6Address(TypedDict, total=False): - Ipv6Address: Optional[String] - IsPrimaryIpv6: Optional[Boolean] + Ipv6Address: String | None + IsPrimaryIpv6: Boolean | None -InstanceIpv6AddressList = List[InstanceIpv6Address] +InstanceIpv6AddressList = list[InstanceIpv6Address] class LaunchTemplateInstanceNetworkInterfaceSpecification(TypedDict, total=False): - AssociateCarrierIpAddress: Optional[Boolean] - AssociatePublicIpAddress: Optional[Boolean] - DeleteOnTermination: Optional[Boolean] - Description: Optional[String] - DeviceIndex: Optional[Integer] - Groups: Optional[GroupIdStringList] - InterfaceType: Optional[String] - Ipv6AddressCount: Optional[Integer] - Ipv6Addresses: Optional[InstanceIpv6AddressList] - NetworkInterfaceId: Optional[NetworkInterfaceId] - PrivateIpAddress: Optional[String] - PrivateIpAddresses: Optional[PrivateIpAddressSpecificationList] - SecondaryPrivateIpAddressCount: Optional[Integer] - SubnetId: Optional[SubnetId] - NetworkCardIndex: Optional[Integer] - Ipv4Prefixes: Optional[Ipv4PrefixListResponse] - Ipv4PrefixCount: Optional[Integer] - Ipv6Prefixes: Optional[Ipv6PrefixListResponse] - Ipv6PrefixCount: Optional[Integer] - PrimaryIpv6: Optional[Boolean] - EnaSrdSpecification: Optional[LaunchTemplateEnaSrdSpecification] - ConnectionTrackingSpecification: Optional[ConnectionTrackingSpecification] - EnaQueueCount: Optional[Integer] - - -LaunchTemplateInstanceNetworkInterfaceSpecificationList = List[ + AssociateCarrierIpAddress: Boolean | None + AssociatePublicIpAddress: Boolean | None + DeleteOnTermination: Boolean | None + Description: String | None + DeviceIndex: Integer | None + Groups: GroupIdStringList | None + InterfaceType: String | None + Ipv6AddressCount: Integer | None + Ipv6Addresses: InstanceIpv6AddressList | None + NetworkInterfaceId: NetworkInterfaceId | None + PrivateIpAddress: String | None + PrivateIpAddresses: PrivateIpAddressSpecificationList | None + SecondaryPrivateIpAddressCount: Integer | None + SubnetId: SubnetId | None + NetworkCardIndex: Integer | None + Ipv4Prefixes: Ipv4PrefixListResponse | None + Ipv4PrefixCount: Integer | None + Ipv6Prefixes: Ipv6PrefixListResponse | None + Ipv6PrefixCount: Integer | None + PrimaryIpv6: Boolean | None + EnaSrdSpecification: LaunchTemplateEnaSrdSpecification | None + ConnectionTrackingSpecification: ConnectionTrackingSpecification | None + EnaQueueCount: Integer | None + + +LaunchTemplateInstanceNetworkInterfaceSpecificationList = list[ LaunchTemplateInstanceNetworkInterfaceSpecification ] class LaunchTemplateEbsBlockDevice(TypedDict, total=False): - Encrypted: Optional[Boolean] - DeleteOnTermination: Optional[Boolean] - Iops: Optional[Integer] - KmsKeyId: Optional[KmsKeyId] - SnapshotId: Optional[SnapshotId] - VolumeSize: Optional[Integer] - VolumeType: Optional[VolumeType] - Throughput: Optional[Integer] - VolumeInitializationRate: Optional[Integer] + Encrypted: Boolean | None + DeleteOnTermination: Boolean | None + Iops: Integer | None + KmsKeyId: KmsKeyId | None + SnapshotId: SnapshotId | None + VolumeSize: Integer | None + VolumeType: VolumeType | None + Throughput: Integer | None + VolumeInitializationRate: Integer | None + EbsCardIndex: Integer | None class LaunchTemplateBlockDeviceMapping(TypedDict, total=False): - DeviceName: Optional[String] - VirtualName: Optional[String] - Ebs: Optional[LaunchTemplateEbsBlockDevice] - NoDevice: Optional[String] + DeviceName: String | None + VirtualName: String | None + Ebs: LaunchTemplateEbsBlockDevice | None + NoDevice: String | None -LaunchTemplateBlockDeviceMappingList = List[LaunchTemplateBlockDeviceMapping] +LaunchTemplateBlockDeviceMappingList = list[LaunchTemplateBlockDeviceMapping] class LaunchTemplateIamInstanceProfileSpecification(TypedDict, total=False): - Arn: Optional[String] - Name: Optional[String] + Arn: String | None + Name: String | None class ResponseLaunchTemplateData(TypedDict, total=False): - KernelId: Optional[String] - EbsOptimized: Optional[Boolean] - IamInstanceProfile: Optional[LaunchTemplateIamInstanceProfileSpecification] - BlockDeviceMappings: Optional[LaunchTemplateBlockDeviceMappingList] - NetworkInterfaces: Optional[LaunchTemplateInstanceNetworkInterfaceSpecificationList] - ImageId: Optional[String] - InstanceType: Optional[InstanceType] - KeyName: Optional[String] - Monitoring: Optional[LaunchTemplatesMonitoring] - Placement: Optional[LaunchTemplatePlacement] - RamDiskId: Optional[String] - DisableApiTermination: Optional[Boolean] - InstanceInitiatedShutdownBehavior: Optional[ShutdownBehavior] - UserData: Optional[SensitiveUserData] - TagSpecifications: Optional[LaunchTemplateTagSpecificationList] - ElasticGpuSpecifications: Optional[ElasticGpuSpecificationResponseList] - ElasticInferenceAccelerators: Optional[LaunchTemplateElasticInferenceAcceleratorResponseList] - SecurityGroupIds: Optional[ValueStringList] - SecurityGroups: Optional[ValueStringList] - InstanceMarketOptions: Optional[LaunchTemplateInstanceMarketOptions] - CreditSpecification: Optional[CreditSpecification] - CpuOptions: Optional[LaunchTemplateCpuOptions] - CapacityReservationSpecification: Optional[ - LaunchTemplateCapacityReservationSpecificationResponse - ] - LicenseSpecifications: Optional[LaunchTemplateLicenseList] - HibernationOptions: Optional[LaunchTemplateHibernationOptions] - MetadataOptions: Optional[LaunchTemplateInstanceMetadataOptions] - EnclaveOptions: Optional[LaunchTemplateEnclaveOptions] - InstanceRequirements: Optional[InstanceRequirements] - PrivateDnsNameOptions: Optional[LaunchTemplatePrivateDnsNameOptions] - MaintenanceOptions: Optional[LaunchTemplateInstanceMaintenanceOptions] - DisableApiStop: Optional[Boolean] - Operator: Optional[OperatorResponse] - NetworkPerformanceOptions: Optional[LaunchTemplateNetworkPerformanceOptions] + KernelId: String | None + EbsOptimized: Boolean | None + IamInstanceProfile: LaunchTemplateIamInstanceProfileSpecification | None + BlockDeviceMappings: LaunchTemplateBlockDeviceMappingList | None + NetworkInterfaces: LaunchTemplateInstanceNetworkInterfaceSpecificationList | None + ImageId: String | None + InstanceType: InstanceType | None + KeyName: String | None + Monitoring: LaunchTemplatesMonitoring | None + Placement: LaunchTemplatePlacement | None + RamDiskId: String | None + DisableApiTermination: Boolean | None + InstanceInitiatedShutdownBehavior: ShutdownBehavior | None + UserData: SensitiveUserData | None + TagSpecifications: LaunchTemplateTagSpecificationList | None + ElasticGpuSpecifications: ElasticGpuSpecificationResponseList | None + ElasticInferenceAccelerators: LaunchTemplateElasticInferenceAcceleratorResponseList | None + SecurityGroupIds: ValueStringList | None + SecurityGroups: ValueStringList | None + InstanceMarketOptions: LaunchTemplateInstanceMarketOptions | None + CreditSpecification: CreditSpecification | None + CpuOptions: LaunchTemplateCpuOptions | None + CapacityReservationSpecification: LaunchTemplateCapacityReservationSpecificationResponse | None + LicenseSpecifications: LaunchTemplateLicenseList | None + HibernationOptions: LaunchTemplateHibernationOptions | None + MetadataOptions: LaunchTemplateInstanceMetadataOptions | None + EnclaveOptions: LaunchTemplateEnclaveOptions | None + InstanceRequirements: InstanceRequirements | None + PrivateDnsNameOptions: LaunchTemplatePrivateDnsNameOptions | None + MaintenanceOptions: LaunchTemplateInstanceMaintenanceOptions | None + DisableApiStop: Boolean | None + Operator: OperatorResponse | None + NetworkPerformanceOptions: LaunchTemplateNetworkPerformanceOptions | None + SecondaryInterfaces: LaunchTemplateInstanceSecondaryInterfaceSpecificationList | None class LaunchTemplateVersion(TypedDict, total=False): - LaunchTemplateId: Optional[String] - LaunchTemplateName: Optional[LaunchTemplateName] - VersionNumber: Optional[Long] - VersionDescription: Optional[VersionDescription] - CreateTime: Optional[DateTime] - CreatedBy: Optional[String] - DefaultVersion: Optional[Boolean] - LaunchTemplateData: Optional[ResponseLaunchTemplateData] - Operator: Optional[OperatorResponse] + LaunchTemplateId: String | None + LaunchTemplateName: LaunchTemplateName | None + VersionNumber: Long | None + VersionDescription: VersionDescription | None + CreateTime: DateTime | None + CreatedBy: String | None + DefaultVersion: Boolean | None + LaunchTemplateData: ResponseLaunchTemplateData | None + Operator: OperatorResponse | None class CreateLaunchTemplateVersionResult(TypedDict, total=False): - LaunchTemplateVersion: Optional[LaunchTemplateVersion] - Warning: Optional[ValidationWarning] + LaunchTemplateVersion: LaunchTemplateVersion | None + Warning: ValidationWarning | None class CreateLocalGatewayRouteRequest(ServiceRequest): - DestinationCidrBlock: Optional[String] + DestinationCidrBlock: String | None LocalGatewayRouteTableId: LocalGatewayRoutetableId - LocalGatewayVirtualInterfaceGroupId: Optional[LocalGatewayVirtualInterfaceGroupId] - DryRun: Optional[Boolean] - NetworkInterfaceId: Optional[NetworkInterfaceId] - DestinationPrefixListId: Optional[PrefixListResourceId] + LocalGatewayVirtualInterfaceGroupId: LocalGatewayVirtualInterfaceGroupId | None + DryRun: Boolean | None + NetworkInterfaceId: NetworkInterfaceId | None + DestinationPrefixListId: PrefixListResourceId | None class LocalGatewayRoute(TypedDict, total=False): - DestinationCidrBlock: Optional[String] - LocalGatewayVirtualInterfaceGroupId: Optional[LocalGatewayVirtualInterfaceGroupId] - Type: Optional[LocalGatewayRouteType] - State: Optional[LocalGatewayRouteState] - LocalGatewayRouteTableId: Optional[LocalGatewayRoutetableId] - LocalGatewayRouteTableArn: Optional[ResourceArn] - OwnerId: Optional[String] - SubnetId: Optional[SubnetId] - CoipPoolId: Optional[CoipPoolId] - NetworkInterfaceId: Optional[NetworkInterfaceId] - DestinationPrefixListId: Optional[PrefixListResourceId] + DestinationCidrBlock: String | None + LocalGatewayVirtualInterfaceGroupId: LocalGatewayVirtualInterfaceGroupId | None + Type: LocalGatewayRouteType | None + State: LocalGatewayRouteState | None + LocalGatewayRouteTableId: LocalGatewayRoutetableId | None + LocalGatewayRouteTableArn: ResourceArn | None + OwnerId: String | None + SubnetId: SubnetId | None + CoipPoolId: CoipPoolId | None + NetworkInterfaceId: NetworkInterfaceId | None + DestinationPrefixListId: PrefixListResourceId | None class CreateLocalGatewayRouteResult(TypedDict, total=False): - Route: Optional[LocalGatewayRoute] + Route: LocalGatewayRoute | None class CreateLocalGatewayRouteTableRequest(ServiceRequest): LocalGatewayId: LocalGatewayId - Mode: Optional[LocalGatewayRouteTableMode] - TagSpecifications: Optional[TagSpecificationList] - DryRun: Optional[Boolean] + Mode: LocalGatewayRouteTableMode | None + TagSpecifications: TagSpecificationList | None + DryRun: Boolean | None class StateReason(TypedDict, total=False): - Code: Optional[String] - Message: Optional[String] + Code: String | None + Message: String | None class LocalGatewayRouteTable(TypedDict, total=False): - LocalGatewayRouteTableId: Optional[String] - LocalGatewayRouteTableArn: Optional[ResourceArn] - LocalGatewayId: Optional[LocalGatewayId] - OutpostArn: Optional[String] - OwnerId: Optional[String] - State: Optional[String] - Tags: Optional[TagList] - Mode: Optional[LocalGatewayRouteTableMode] - StateReason: Optional[StateReason] + LocalGatewayRouteTableId: String | None + LocalGatewayRouteTableArn: ResourceArn | None + LocalGatewayId: LocalGatewayId | None + OutpostArn: String | None + OwnerId: String | None + State: String | None + Tags: TagList | None + Mode: LocalGatewayRouteTableMode | None + StateReason: StateReason | None class CreateLocalGatewayRouteTableResult(TypedDict, total=False): - LocalGatewayRouteTable: Optional[LocalGatewayRouteTable] + LocalGatewayRouteTable: LocalGatewayRouteTable | None class CreateLocalGatewayRouteTableVirtualInterfaceGroupAssociationRequest(ServiceRequest): LocalGatewayRouteTableId: LocalGatewayRoutetableId LocalGatewayVirtualInterfaceGroupId: LocalGatewayVirtualInterfaceGroupId - TagSpecifications: Optional[TagSpecificationList] - DryRun: Optional[Boolean] + TagSpecifications: TagSpecificationList | None + DryRun: Boolean | None class LocalGatewayRouteTableVirtualInterfaceGroupAssociation(TypedDict, total=False): - LocalGatewayRouteTableVirtualInterfaceGroupAssociationId: Optional[ - LocalGatewayRouteTableVirtualInterfaceGroupAssociationId - ] - LocalGatewayVirtualInterfaceGroupId: Optional[LocalGatewayVirtualInterfaceGroupId] - LocalGatewayId: Optional[String] - LocalGatewayRouteTableId: Optional[LocalGatewayId] - LocalGatewayRouteTableArn: Optional[ResourceArn] - OwnerId: Optional[String] - State: Optional[String] - Tags: Optional[TagList] + LocalGatewayRouteTableVirtualInterfaceGroupAssociationId: ( + LocalGatewayRouteTableVirtualInterfaceGroupAssociationId | None + ) + LocalGatewayVirtualInterfaceGroupId: LocalGatewayVirtualInterfaceGroupId | None + LocalGatewayId: String | None + LocalGatewayRouteTableId: LocalGatewayId | None + LocalGatewayRouteTableArn: ResourceArn | None + OwnerId: String | None + State: String | None + Tags: TagList | None class CreateLocalGatewayRouteTableVirtualInterfaceGroupAssociationResult(TypedDict, total=False): - LocalGatewayRouteTableVirtualInterfaceGroupAssociation: Optional[ - LocalGatewayRouteTableVirtualInterfaceGroupAssociation - ] + LocalGatewayRouteTableVirtualInterfaceGroupAssociation: ( + LocalGatewayRouteTableVirtualInterfaceGroupAssociation | None + ) class CreateLocalGatewayRouteTableVpcAssociationRequest(ServiceRequest): LocalGatewayRouteTableId: LocalGatewayRoutetableId VpcId: VpcId - TagSpecifications: Optional[TagSpecificationList] - DryRun: Optional[Boolean] + TagSpecifications: TagSpecificationList | None + DryRun: Boolean | None class LocalGatewayRouteTableVpcAssociation(TypedDict, total=False): - LocalGatewayRouteTableVpcAssociationId: Optional[LocalGatewayRouteTableVpcAssociationId] - LocalGatewayRouteTableId: Optional[String] - LocalGatewayRouteTableArn: Optional[ResourceArn] - LocalGatewayId: Optional[String] - VpcId: Optional[String] - OwnerId: Optional[String] - State: Optional[String] - Tags: Optional[TagList] + LocalGatewayRouteTableVpcAssociationId: LocalGatewayRouteTableVpcAssociationId | None + LocalGatewayRouteTableId: String | None + LocalGatewayRouteTableArn: ResourceArn | None + LocalGatewayId: String | None + VpcId: String | None + OwnerId: String | None + State: String | None + Tags: TagList | None class CreateLocalGatewayRouteTableVpcAssociationResult(TypedDict, total=False): - LocalGatewayRouteTableVpcAssociation: Optional[LocalGatewayRouteTableVpcAssociation] + LocalGatewayRouteTableVpcAssociation: LocalGatewayRouteTableVpcAssociation | None class CreateLocalGatewayVirtualInterfaceGroupRequest(ServiceRequest): LocalGatewayId: LocalGatewayId - LocalBgpAsn: Optional[Integer] - LocalBgpAsnExtended: Optional[Long] - TagSpecifications: Optional[TagSpecificationList] - DryRun: Optional[Boolean] + LocalBgpAsn: Integer | None + LocalBgpAsnExtended: Long | None + TagSpecifications: TagSpecificationList | None + DryRun: Boolean | None -LocalGatewayVirtualInterfaceIdSet = List[LocalGatewayVirtualInterfaceId] +LocalGatewayVirtualInterfaceIdSet = list[LocalGatewayVirtualInterfaceId] class LocalGatewayVirtualInterfaceGroup(TypedDict, total=False): - LocalGatewayVirtualInterfaceGroupId: Optional[LocalGatewayVirtualInterfaceGroupId] - LocalGatewayVirtualInterfaceIds: Optional[LocalGatewayVirtualInterfaceIdSet] - LocalGatewayId: Optional[String] - OwnerId: Optional[String] - LocalBgpAsn: Optional[Integer] - LocalBgpAsnExtended: Optional[Long] - LocalGatewayVirtualInterfaceGroupArn: Optional[ResourceArn] - Tags: Optional[TagList] - ConfigurationState: Optional[LocalGatewayVirtualInterfaceGroupConfigurationState] + LocalGatewayVirtualInterfaceGroupId: LocalGatewayVirtualInterfaceGroupId | None + LocalGatewayVirtualInterfaceIds: LocalGatewayVirtualInterfaceIdSet | None + LocalGatewayId: String | None + OwnerId: String | None + LocalBgpAsn: Integer | None + LocalBgpAsnExtended: Long | None + LocalGatewayVirtualInterfaceGroupArn: ResourceArn | None + Tags: TagList | None + ConfigurationState: LocalGatewayVirtualInterfaceGroupConfigurationState | None class CreateLocalGatewayVirtualInterfaceGroupResult(TypedDict, total=False): - LocalGatewayVirtualInterfaceGroup: Optional[LocalGatewayVirtualInterfaceGroup] + LocalGatewayVirtualInterfaceGroup: LocalGatewayVirtualInterfaceGroup | None class CreateLocalGatewayVirtualInterfaceRequest(ServiceRequest): @@ -8639,487 +9670,515 @@ class CreateLocalGatewayVirtualInterfaceRequest(ServiceRequest): Vlan: Integer LocalAddress: String PeerAddress: String - PeerBgpAsn: Optional[Integer] - TagSpecifications: Optional[TagSpecificationList] - DryRun: Optional[Boolean] - PeerBgpAsnExtended: Optional[Long] + PeerBgpAsn: Integer | None + TagSpecifications: TagSpecificationList | None + DryRun: Boolean | None + PeerBgpAsnExtended: Long | None class LocalGatewayVirtualInterface(TypedDict, total=False): - LocalGatewayVirtualInterfaceId: Optional[LocalGatewayVirtualInterfaceId] - LocalGatewayId: Optional[String] - LocalGatewayVirtualInterfaceGroupId: Optional[LocalGatewayVirtualInterfaceGroupId] - LocalGatewayVirtualInterfaceArn: Optional[ResourceArn] - OutpostLagId: Optional[String] - Vlan: Optional[Integer] - LocalAddress: Optional[String] - PeerAddress: Optional[String] - LocalBgpAsn: Optional[Integer] - PeerBgpAsn: Optional[Integer] - PeerBgpAsnExtended: Optional[Long] - OwnerId: Optional[String] - Tags: Optional[TagList] - ConfigurationState: Optional[LocalGatewayVirtualInterfaceConfigurationState] + LocalGatewayVirtualInterfaceId: LocalGatewayVirtualInterfaceId | None + LocalGatewayId: String | None + LocalGatewayVirtualInterfaceGroupId: LocalGatewayVirtualInterfaceGroupId | None + LocalGatewayVirtualInterfaceArn: ResourceArn | None + OutpostLagId: String | None + Vlan: Integer | None + LocalAddress: String | None + PeerAddress: String | None + LocalBgpAsn: Integer | None + PeerBgpAsn: Integer | None + PeerBgpAsnExtended: Long | None + OwnerId: String | None + Tags: TagList | None + ConfigurationState: LocalGatewayVirtualInterfaceConfigurationState | None class CreateLocalGatewayVirtualInterfaceResult(TypedDict, total=False): - LocalGatewayVirtualInterface: Optional[LocalGatewayVirtualInterface] + LocalGatewayVirtualInterface: LocalGatewayVirtualInterface | None class MacSystemIntegrityProtectionConfigurationRequest(TypedDict, total=False): - AppleInternal: Optional[MacSystemIntegrityProtectionSettingStatus] - BaseSystem: Optional[MacSystemIntegrityProtectionSettingStatus] - DebuggingRestrictions: Optional[MacSystemIntegrityProtectionSettingStatus] - DTraceRestrictions: Optional[MacSystemIntegrityProtectionSettingStatus] - FilesystemProtections: Optional[MacSystemIntegrityProtectionSettingStatus] - KextSigning: Optional[MacSystemIntegrityProtectionSettingStatus] - NvramProtections: Optional[MacSystemIntegrityProtectionSettingStatus] + AppleInternal: MacSystemIntegrityProtectionSettingStatus | None + BaseSystem: MacSystemIntegrityProtectionSettingStatus | None + DebuggingRestrictions: MacSystemIntegrityProtectionSettingStatus | None + DTraceRestrictions: MacSystemIntegrityProtectionSettingStatus | None + FilesystemProtections: MacSystemIntegrityProtectionSettingStatus | None + KextSigning: MacSystemIntegrityProtectionSettingStatus | None + NvramProtections: MacSystemIntegrityProtectionSettingStatus | None class CreateMacSystemIntegrityProtectionModificationTaskRequest(ServiceRequest): - ClientToken: Optional[String] - DryRun: Optional[Boolean] + ClientToken: String | None + DryRun: Boolean | None InstanceId: InstanceId - MacCredentials: Optional[SensitiveMacCredentials] - MacSystemIntegrityProtectionConfiguration: Optional[ - MacSystemIntegrityProtectionConfigurationRequest - ] + MacCredentials: SensitiveMacCredentials | None + MacSystemIntegrityProtectionConfiguration: ( + MacSystemIntegrityProtectionConfigurationRequest | None + ) MacSystemIntegrityProtectionStatus: MacSystemIntegrityProtectionSettingStatus - TagSpecifications: Optional[TagSpecificationList] + TagSpecifications: TagSpecificationList | None class CreateMacSystemIntegrityProtectionModificationTaskResult(TypedDict, total=False): - MacModificationTask: Optional[MacModificationTask] + MacModificationTask: MacModificationTask | None class CreateManagedPrefixListRequest(ServiceRequest): - DryRun: Optional[Boolean] + DryRun: Boolean | None PrefixListName: String - Entries: Optional[AddPrefixListEntries] + Entries: AddPrefixListEntries | None MaxEntries: Integer - TagSpecifications: Optional[TagSpecificationList] + TagSpecifications: TagSpecificationList | None AddressFamily: String - ClientToken: Optional[String] + ClientToken: String | None class ManagedPrefixList(TypedDict, total=False): - PrefixListId: Optional[PrefixListResourceId] - AddressFamily: Optional[String] - State: Optional[PrefixListState] - StateMessage: Optional[String] - PrefixListArn: Optional[ResourceArn] - PrefixListName: Optional[String] - MaxEntries: Optional[Integer] - Version: Optional[Long] - Tags: Optional[TagList] - OwnerId: Optional[String] + PrefixListId: PrefixListResourceId | None + AddressFamily: String | None + State: PrefixListState | None + StateMessage: String | None + PrefixListArn: ResourceArn | None + PrefixListName: String | None + MaxEntries: Integer | None + Version: Long | None + Tags: TagList | None + OwnerId: String | None + IpamPrefixListResolverTargetId: String | None + IpamPrefixListResolverSyncEnabled: Boolean | None class CreateManagedPrefixListResult(TypedDict, total=False): - PrefixList: Optional[ManagedPrefixList] + PrefixList: ManagedPrefixList | None class CreateNatGatewayRequest(ServiceRequest): - AllocationId: Optional[AllocationId] - ClientToken: Optional[String] - DryRun: Optional[Boolean] - SubnetId: SubnetId - TagSpecifications: Optional[TagSpecificationList] - ConnectivityType: Optional[ConnectivityType] - PrivateIpAddress: Optional[String] - SecondaryAllocationIds: Optional[AllocationIdList] - SecondaryPrivateIpAddresses: Optional[IpList] - SecondaryPrivateIpAddressCount: Optional[PrivateIpAddressCount] + AvailabilityMode: AvailabilityMode | None + AllocationId: AllocationId | None + ClientToken: String | None + DryRun: Boolean | None + SubnetId: SubnetId | None + VpcId: VpcId | None + AvailabilityZoneAddresses: AvailabilityZoneAddresses | None + TagSpecifications: TagSpecificationList | None + ConnectivityType: ConnectivityType | None + PrivateIpAddress: String | None + SecondaryAllocationIds: AllocationIdList | None + SecondaryPrivateIpAddresses: IpList | None + SecondaryPrivateIpAddressCount: PrivateIpAddressCount | None + + +class NatGatewayAttachedAppliance(TypedDict, total=False): + Type: NatGatewayApplianceType | None + ApplianceArn: String | None + VpcEndpointId: String | None + AttachmentState: NatGatewayApplianceState | None + ModificationState: NatGatewayApplianceModifyState | None + FailureCode: String | None + FailureMessage: String | None + + +NatGatewayAttachedApplianceList = list[NatGatewayAttachedAppliance] class ProvisionedBandwidth(TypedDict, total=False): - ProvisionTime: Optional[DateTime] - Provisioned: Optional[String] - RequestTime: Optional[DateTime] - Requested: Optional[String] - Status: Optional[String] + ProvisionTime: DateTime | None + Provisioned: String | None + RequestTime: DateTime | None + Requested: String | None + Status: String | None class NatGateway(TypedDict, total=False): - CreateTime: Optional[DateTime] - DeleteTime: Optional[DateTime] - FailureCode: Optional[String] - FailureMessage: Optional[String] - NatGatewayAddresses: Optional[NatGatewayAddressList] - NatGatewayId: Optional[String] - ProvisionedBandwidth: Optional[ProvisionedBandwidth] - State: Optional[NatGatewayState] - SubnetId: Optional[String] - VpcId: Optional[String] - Tags: Optional[TagList] - ConnectivityType: Optional[ConnectivityType] + CreateTime: DateTime | None + DeleteTime: DateTime | None + FailureCode: String | None + FailureMessage: String | None + NatGatewayAddresses: NatGatewayAddressList | None + NatGatewayId: String | None + ProvisionedBandwidth: ProvisionedBandwidth | None + State: NatGatewayState | None + SubnetId: String | None + VpcId: String | None + Tags: TagList | None + ConnectivityType: ConnectivityType | None + AvailabilityMode: AvailabilityMode | None + AutoScalingIps: AutoScalingIpsState | None + AutoProvisionZones: AutoProvisionZonesState | None + AttachedAppliances: NatGatewayAttachedApplianceList | None + RouteTableId: String | None class CreateNatGatewayResult(TypedDict, total=False): - ClientToken: Optional[String] - NatGateway: Optional[NatGateway] + ClientToken: String | None + NatGateway: NatGateway | None class IcmpTypeCode(TypedDict, total=False): - Code: Optional[Integer] - Type: Optional[Integer] + Code: Integer | None + Type: Integer | None class CreateNetworkAclEntryRequest(ServiceRequest): - DryRun: Optional[Boolean] + DryRun: Boolean | None NetworkAclId: NetworkAclId RuleNumber: Integer Protocol: String RuleAction: RuleAction Egress: Boolean - CidrBlock: Optional[String] - Ipv6CidrBlock: Optional[String] - IcmpTypeCode: Optional[IcmpTypeCode] - PortRange: Optional[PortRange] + CidrBlock: String | None + Ipv6CidrBlock: String | None + IcmpTypeCode: IcmpTypeCode | None + PortRange: PortRange | None class CreateNetworkAclRequest(ServiceRequest): - TagSpecifications: Optional[TagSpecificationList] - ClientToken: Optional[String] - DryRun: Optional[Boolean] + TagSpecifications: TagSpecificationList | None + ClientToken: String | None + DryRun: Boolean | None VpcId: VpcId class NetworkAclEntry(TypedDict, total=False): - CidrBlock: Optional[String] - Egress: Optional[Boolean] - IcmpTypeCode: Optional[IcmpTypeCode] - Ipv6CidrBlock: Optional[String] - PortRange: Optional[PortRange] - Protocol: Optional[String] - RuleAction: Optional[RuleAction] - RuleNumber: Optional[Integer] + CidrBlock: String | None + Egress: Boolean | None + IcmpTypeCode: IcmpTypeCode | None + Ipv6CidrBlock: String | None + PortRange: PortRange | None + Protocol: String | None + RuleAction: RuleAction | None + RuleNumber: Integer | None -NetworkAclEntryList = List[NetworkAclEntry] +NetworkAclEntryList = list[NetworkAclEntry] class NetworkAclAssociation(TypedDict, total=False): - NetworkAclAssociationId: Optional[String] - NetworkAclId: Optional[String] - SubnetId: Optional[String] + NetworkAclAssociationId: String | None + NetworkAclId: String | None + SubnetId: String | None -NetworkAclAssociationList = List[NetworkAclAssociation] +NetworkAclAssociationList = list[NetworkAclAssociation] class NetworkAcl(TypedDict, total=False): - Associations: Optional[NetworkAclAssociationList] - Entries: Optional[NetworkAclEntryList] - IsDefault: Optional[Boolean] - NetworkAclId: Optional[String] - Tags: Optional[TagList] - VpcId: Optional[String] - OwnerId: Optional[String] + Associations: NetworkAclAssociationList | None + Entries: NetworkAclEntryList | None + IsDefault: Boolean | None + NetworkAclId: String | None + Tags: TagList | None + VpcId: String | None + OwnerId: String | None class CreateNetworkAclResult(TypedDict, total=False): - NetworkAcl: Optional[NetworkAcl] - ClientToken: Optional[String] + NetworkAcl: NetworkAcl | None + ClientToken: String | None class CreateNetworkInsightsAccessScopeRequest(ServiceRequest): - MatchPaths: Optional[AccessScopePathListRequest] - ExcludePaths: Optional[AccessScopePathListRequest] + MatchPaths: AccessScopePathListRequest | None + ExcludePaths: AccessScopePathListRequest | None ClientToken: String - TagSpecifications: Optional[TagSpecificationList] - DryRun: Optional[Boolean] + TagSpecifications: TagSpecificationList | None + DryRun: Boolean | None class NetworkInsightsAccessScopeContent(TypedDict, total=False): - NetworkInsightsAccessScopeId: Optional[NetworkInsightsAccessScopeId] - MatchPaths: Optional[AccessScopePathList] - ExcludePaths: Optional[AccessScopePathList] + NetworkInsightsAccessScopeId: NetworkInsightsAccessScopeId | None + MatchPaths: AccessScopePathList | None + ExcludePaths: AccessScopePathList | None class NetworkInsightsAccessScope(TypedDict, total=False): - NetworkInsightsAccessScopeId: Optional[NetworkInsightsAccessScopeId] - NetworkInsightsAccessScopeArn: Optional[ResourceArn] - CreatedDate: Optional[MillisecondDateTime] - UpdatedDate: Optional[MillisecondDateTime] - Tags: Optional[TagList] + NetworkInsightsAccessScopeId: NetworkInsightsAccessScopeId | None + NetworkInsightsAccessScopeArn: ResourceArn | None + CreatedDate: MillisecondDateTime | None + UpdatedDate: MillisecondDateTime | None + Tags: TagList | None class CreateNetworkInsightsAccessScopeResult(TypedDict, total=False): - NetworkInsightsAccessScope: Optional[NetworkInsightsAccessScope] - NetworkInsightsAccessScopeContent: Optional[NetworkInsightsAccessScopeContent] + NetworkInsightsAccessScope: NetworkInsightsAccessScope | None + NetworkInsightsAccessScopeContent: NetworkInsightsAccessScopeContent | None class RequestFilterPortRange(TypedDict, total=False): - FromPort: Optional[Port] - ToPort: Optional[Port] + FromPort: Port | None + ToPort: Port | None class PathRequestFilter(TypedDict, total=False): - SourceAddress: Optional[IpAddress] - SourcePortRange: Optional[RequestFilterPortRange] - DestinationAddress: Optional[IpAddress] - DestinationPortRange: Optional[RequestFilterPortRange] + SourceAddress: IpAddress | None + SourcePortRange: RequestFilterPortRange | None + DestinationAddress: IpAddress | None + DestinationPortRange: RequestFilterPortRange | None class CreateNetworkInsightsPathRequest(ServiceRequest): - SourceIp: Optional[IpAddress] - DestinationIp: Optional[IpAddress] + SourceIp: IpAddress | None + DestinationIp: IpAddress | None Source: NetworkInsightsResourceId - Destination: Optional[NetworkInsightsResourceId] + Destination: NetworkInsightsResourceId | None Protocol: Protocol - DestinationPort: Optional[Port] - TagSpecifications: Optional[TagSpecificationList] - DryRun: Optional[Boolean] + DestinationPort: Port | None + TagSpecifications: TagSpecificationList | None + DryRun: Boolean | None ClientToken: String - FilterAtSource: Optional[PathRequestFilter] - FilterAtDestination: Optional[PathRequestFilter] + FilterAtSource: PathRequestFilter | None + FilterAtDestination: PathRequestFilter | None class FilterPortRange(TypedDict, total=False): - FromPort: Optional[Port] - ToPort: Optional[Port] + FromPort: Port | None + ToPort: Port | None class PathFilter(TypedDict, total=False): - SourceAddress: Optional[IpAddress] - SourcePortRange: Optional[FilterPortRange] - DestinationAddress: Optional[IpAddress] - DestinationPortRange: Optional[FilterPortRange] + SourceAddress: IpAddress | None + SourcePortRange: FilterPortRange | None + DestinationAddress: IpAddress | None + DestinationPortRange: FilterPortRange | None class NetworkInsightsPath(TypedDict, total=False): - NetworkInsightsPathId: Optional[NetworkInsightsPathId] - NetworkInsightsPathArn: Optional[ResourceArn] - CreatedDate: Optional[MillisecondDateTime] - Source: Optional[String] - Destination: Optional[String] - SourceArn: Optional[ResourceArn] - DestinationArn: Optional[ResourceArn] - SourceIp: Optional[IpAddress] - DestinationIp: Optional[IpAddress] - Protocol: Optional[Protocol] - DestinationPort: Optional[Integer] - Tags: Optional[TagList] - FilterAtSource: Optional[PathFilter] - FilterAtDestination: Optional[PathFilter] + NetworkInsightsPathId: NetworkInsightsPathId | None + NetworkInsightsPathArn: ResourceArn | None + CreatedDate: MillisecondDateTime | None + Source: String | None + Destination: String | None + SourceArn: ResourceArn | None + DestinationArn: ResourceArn | None + SourceIp: IpAddress | None + DestinationIp: IpAddress | None + Protocol: Protocol | None + DestinationPort: Integer | None + Tags: TagList | None + FilterAtSource: PathFilter | None + FilterAtDestination: PathFilter | None class CreateNetworkInsightsPathResult(TypedDict, total=False): - NetworkInsightsPath: Optional[NetworkInsightsPath] + NetworkInsightsPath: NetworkInsightsPath | None class CreateNetworkInterfacePermissionRequest(ServiceRequest): NetworkInterfaceId: NetworkInterfaceId - AwsAccountId: Optional[String] - AwsService: Optional[String] + AwsAccountId: String | None + AwsService: String | None Permission: InterfacePermissionType - DryRun: Optional[Boolean] + DryRun: Boolean | None class NetworkInterfacePermissionState(TypedDict, total=False): - State: Optional[NetworkInterfacePermissionStateCode] - StatusMessage: Optional[String] + State: NetworkInterfacePermissionStateCode | None + StatusMessage: String | None class NetworkInterfacePermission(TypedDict, total=False): - NetworkInterfacePermissionId: Optional[String] - NetworkInterfaceId: Optional[String] - AwsAccountId: Optional[String] - AwsService: Optional[String] - Permission: Optional[InterfacePermissionType] - PermissionState: Optional[NetworkInterfacePermissionState] + NetworkInterfacePermissionId: String | None + NetworkInterfaceId: String | None + AwsAccountId: String | None + AwsService: String | None + Permission: InterfacePermissionType | None + PermissionState: NetworkInterfacePermissionState | None class CreateNetworkInterfacePermissionResult(TypedDict, total=False): - InterfacePermission: Optional[NetworkInterfacePermission] + InterfacePermission: NetworkInterfacePermission | None class CreateNetworkInterfaceRequest(ServiceRequest): - Ipv4Prefixes: Optional[Ipv4PrefixList] - Ipv4PrefixCount: Optional[Integer] - Ipv6Prefixes: Optional[Ipv6PrefixList] - Ipv6PrefixCount: Optional[Integer] - InterfaceType: Optional[NetworkInterfaceCreationType] - TagSpecifications: Optional[TagSpecificationList] - ClientToken: Optional[String] - EnablePrimaryIpv6: Optional[Boolean] - ConnectionTrackingSpecification: Optional[ConnectionTrackingSpecificationRequest] - Operator: Optional[OperatorRequest] + Ipv4Prefixes: Ipv4PrefixList | None + Ipv4PrefixCount: Integer | None + Ipv6Prefixes: Ipv6PrefixList | None + Ipv6PrefixCount: Integer | None + InterfaceType: NetworkInterfaceCreationType | None + TagSpecifications: TagSpecificationList | None + ClientToken: String | None + EnablePrimaryIpv6: Boolean | None + ConnectionTrackingSpecification: ConnectionTrackingSpecificationRequest | None + Operator: OperatorRequest | None SubnetId: SubnetId - Description: Optional[String] - PrivateIpAddress: Optional[String] - Groups: Optional[SecurityGroupIdStringList] - PrivateIpAddresses: Optional[PrivateIpAddressSpecificationList] - SecondaryPrivateIpAddressCount: Optional[Integer] - Ipv6Addresses: Optional[InstanceIpv6AddressList] - Ipv6AddressCount: Optional[Integer] - DryRun: Optional[Boolean] + Description: String | None + PrivateIpAddress: String | None + Groups: SecurityGroupIdStringList | None + PrivateIpAddresses: PrivateIpAddressSpecificationList | None + SecondaryPrivateIpAddressCount: Integer | None + Ipv6Addresses: InstanceIpv6AddressList | None + Ipv6AddressCount: Integer | None + DryRun: Boolean | None class Ipv6PrefixSpecification(TypedDict, total=False): - Ipv6Prefix: Optional[String] + Ipv6Prefix: String | None -Ipv6PrefixesList = List[Ipv6PrefixSpecification] +Ipv6PrefixesList = list[Ipv6PrefixSpecification] class NetworkInterfaceAssociation(TypedDict, total=False): - AllocationId: Optional[String] - AssociationId: Optional[String] - IpOwnerId: Optional[String] - PublicDnsName: Optional[String] - PublicIp: Optional[String] - CustomerOwnedIp: Optional[String] - CarrierIp: Optional[String] + AllocationId: String | None + AssociationId: String | None + IpOwnerId: String | None + PublicDnsName: String | None + PublicIp: String | None + CustomerOwnedIp: String | None + CarrierIp: String | None class NetworkInterfacePrivateIpAddress(TypedDict, total=False): - Association: Optional[NetworkInterfaceAssociation] - Primary: Optional[Boolean] - PrivateDnsName: Optional[String] - PrivateIpAddress: Optional[String] + Association: NetworkInterfaceAssociation | None + Primary: Boolean | None + PrivateDnsName: String | None + PrivateIpAddress: String | None -NetworkInterfacePrivateIpAddressList = List[NetworkInterfacePrivateIpAddress] +NetworkInterfacePrivateIpAddressList = list[NetworkInterfacePrivateIpAddress] class PublicIpDnsNameOptions(TypedDict, total=False): - DnsHostnameType: Optional[String] - PublicIpv4DnsName: Optional[String] - PublicIpv6DnsName: Optional[String] - PublicDualStackDnsName: Optional[String] + DnsHostnameType: String | None + PublicIpv4DnsName: String | None + PublicIpv6DnsName: String | None + PublicDualStackDnsName: String | None class NetworkInterfaceIpv6Address(TypedDict, total=False): - Ipv6Address: Optional[String] - PublicIpv6DnsName: Optional[String] - IsPrimaryIpv6: Optional[Boolean] + Ipv6Address: String | None + PublicIpv6DnsName: String | None + IsPrimaryIpv6: Boolean | None -NetworkInterfaceIpv6AddressesList = List[NetworkInterfaceIpv6Address] +NetworkInterfaceIpv6AddressesList = list[NetworkInterfaceIpv6Address] class NetworkInterfaceAttachment(TypedDict, total=False): - AttachTime: Optional[DateTime] - AttachmentId: Optional[String] - DeleteOnTermination: Optional[Boolean] - DeviceIndex: Optional[Integer] - NetworkCardIndex: Optional[Integer] - InstanceId: Optional[String] - InstanceOwnerId: Optional[String] - Status: Optional[AttachmentStatus] - EnaSrdSpecification: Optional[AttachmentEnaSrdSpecification] - EnaQueueCount: Optional[Integer] + AttachTime: DateTime | None + AttachmentId: String | None + DeleteOnTermination: Boolean | None + DeviceIndex: Integer | None + NetworkCardIndex: Integer | None + InstanceId: String | None + InstanceOwnerId: String | None + Status: AttachmentStatus | None + EnaSrdSpecification: AttachmentEnaSrdSpecification | None + EnaQueueCount: Integer | None class NetworkInterface(TypedDict, total=False): - Association: Optional[NetworkInterfaceAssociation] - Attachment: Optional[NetworkInterfaceAttachment] - AvailabilityZone: Optional[String] - ConnectionTrackingConfiguration: Optional[ConnectionTrackingConfiguration] - Description: Optional[String] - Groups: Optional[GroupIdentifierList] - InterfaceType: Optional[NetworkInterfaceType] - Ipv6Addresses: Optional[NetworkInterfaceIpv6AddressesList] - MacAddress: Optional[String] - NetworkInterfaceId: Optional[String] - OutpostArn: Optional[String] - OwnerId: Optional[String] - PrivateDnsName: Optional[String] - PublicDnsName: Optional[String] - PublicIpDnsNameOptions: Optional[PublicIpDnsNameOptions] - PrivateIpAddress: Optional[String] - PrivateIpAddresses: Optional[NetworkInterfacePrivateIpAddressList] - Ipv4Prefixes: Optional[Ipv4PrefixesList] - Ipv6Prefixes: Optional[Ipv6PrefixesList] - RequesterId: Optional[String] - RequesterManaged: Optional[Boolean] - SourceDestCheck: Optional[Boolean] - Status: Optional[NetworkInterfaceStatus] - SubnetId: Optional[String] - TagSet: Optional[TagList] - VpcId: Optional[String] - DenyAllIgwTraffic: Optional[Boolean] - Ipv6Native: Optional[Boolean] - Ipv6Address: Optional[String] - Operator: Optional[OperatorResponse] - AssociatedSubnets: Optional[AssociatedSubnetList] + Association: NetworkInterfaceAssociation | None + Attachment: NetworkInterfaceAttachment | None + AvailabilityZone: String | None + ConnectionTrackingConfiguration: ConnectionTrackingConfiguration | None + Description: String | None + Groups: GroupIdentifierList | None + InterfaceType: NetworkInterfaceType | None + Ipv6Addresses: NetworkInterfaceIpv6AddressesList | None + MacAddress: String | None + NetworkInterfaceId: String | None + OutpostArn: String | None + OwnerId: String | None + PrivateDnsName: String | None + PublicDnsName: String | None + PublicIpDnsNameOptions: PublicIpDnsNameOptions | None + PrivateIpAddress: String | None + PrivateIpAddresses: NetworkInterfacePrivateIpAddressList | None + Ipv4Prefixes: Ipv4PrefixesList | None + Ipv6Prefixes: Ipv6PrefixesList | None + RequesterId: String | None + RequesterManaged: Boolean | None + SourceDestCheck: Boolean | None + Status: NetworkInterfaceStatus | None + SubnetId: String | None + TagSet: TagList | None + VpcId: String | None + DenyAllIgwTraffic: Boolean | None + Ipv6Native: Boolean | None + Ipv6Address: String | None + Operator: OperatorResponse | None + AssociatedSubnets: AssociatedSubnetList | None + AvailabilityZoneId: String | None class CreateNetworkInterfaceResult(TypedDict, total=False): - NetworkInterface: Optional[NetworkInterface] - ClientToken: Optional[String] + NetworkInterface: NetworkInterface | None + ClientToken: String | None class CreatePlacementGroupRequest(ServiceRequest): - PartitionCount: Optional[Integer] - TagSpecifications: Optional[TagSpecificationList] - SpreadLevel: Optional[SpreadLevel] - DryRun: Optional[Boolean] - GroupName: Optional[String] - Strategy: Optional[PlacementStrategy] + PartitionCount: Integer | None + TagSpecifications: TagSpecificationList | None + SpreadLevel: SpreadLevel | None + LinkedGroupId: PlacementGroupId | None + Operator: OperatorRequest | None + DryRun: Boolean | None + GroupName: String | None + Strategy: PlacementStrategy | None class PlacementGroup(TypedDict, total=False): - GroupName: Optional[String] - State: Optional[PlacementGroupState] - Strategy: Optional[PlacementStrategy] - PartitionCount: Optional[Integer] - GroupId: Optional[String] - Tags: Optional[TagList] - GroupArn: Optional[String] - SpreadLevel: Optional[SpreadLevel] + GroupName: String | None + State: PlacementGroupState | None + Strategy: PlacementStrategy | None + PartitionCount: Integer | None + GroupId: String | None + Tags: TagList | None + GroupArn: String | None + SpreadLevel: SpreadLevel | None + LinkedGroupId: PlacementGroupId | None + Operator: OperatorResponse | None class CreatePlacementGroupResult(TypedDict, total=False): - PlacementGroup: Optional[PlacementGroup] + PlacementGroup: PlacementGroup | None class CreatePublicIpv4PoolRequest(ServiceRequest): - DryRun: Optional[Boolean] - TagSpecifications: Optional[TagSpecificationList] - NetworkBorderGroup: Optional[String] + DryRun: Boolean | None + TagSpecifications: TagSpecificationList | None + NetworkBorderGroup: String | None class CreatePublicIpv4PoolResult(TypedDict, total=False): - PoolId: Optional[Ipv4PoolEc2Id] + PoolId: Ipv4PoolEc2Id | None class CreateReplaceRootVolumeTaskRequest(ServiceRequest): InstanceId: InstanceId - SnapshotId: Optional[SnapshotId] - ClientToken: Optional[String] - DryRun: Optional[Boolean] - TagSpecifications: Optional[TagSpecificationList] - ImageId: Optional[ImageId] - DeleteReplacedRootVolume: Optional[Boolean] - VolumeInitializationRate: Optional[Long] + SnapshotId: SnapshotId | None + ClientToken: String | None + DryRun: Boolean | None + TagSpecifications: TagSpecificationList | None + ImageId: ImageId | None + DeleteReplacedRootVolume: Boolean | None + VolumeInitializationRate: Long | None class ReplaceRootVolumeTask(TypedDict, total=False): - ReplaceRootVolumeTaskId: Optional[ReplaceRootVolumeTaskId] - InstanceId: Optional[String] - TaskState: Optional[ReplaceRootVolumeTaskState] - StartTime: Optional[String] - CompleteTime: Optional[String] - Tags: Optional[TagList] - ImageId: Optional[ImageId] - SnapshotId: Optional[SnapshotId] - DeleteReplacedRootVolume: Optional[Boolean] + ReplaceRootVolumeTaskId: ReplaceRootVolumeTaskId | None + InstanceId: String | None + TaskState: ReplaceRootVolumeTaskState | None + StartTime: String | None + CompleteTime: String | None + Tags: TagList | None + ImageId: ImageId | None + SnapshotId: SnapshotId | None + DeleteReplacedRootVolume: Boolean | None class CreateReplaceRootVolumeTaskResult(TypedDict, total=False): - ReplaceRootVolumeTask: Optional[ReplaceRootVolumeTask] + ReplaceRootVolumeTask: ReplaceRootVolumeTask | None class PriceScheduleSpecification(TypedDict, total=False): - Term: Optional[Long] - Price: Optional[Double] - CurrencyCode: Optional[CurrencyCodeValues] + Term: Long | None + Price: Double | None + CurrencyCode: CurrencyCodeValues | None -PriceScheduleSpecificationList = List[PriceScheduleSpecification] +PriceScheduleSpecificationList = list[PriceScheduleSpecification] class CreateReservedInstancesListingRequest(ServiceRequest): @@ -9130,416 +10189,489 @@ class CreateReservedInstancesListingRequest(ServiceRequest): class CreateReservedInstancesListingResult(TypedDict, total=False): - ReservedInstancesListings: Optional[ReservedInstancesListingList] + ReservedInstancesListings: ReservedInstancesListingList | None class CreateRestoreImageTaskRequest(ServiceRequest): Bucket: String ObjectKey: String - Name: Optional[String] - TagSpecifications: Optional[TagSpecificationList] - DryRun: Optional[Boolean] + Name: String | None + TagSpecifications: TagSpecificationList | None + DryRun: Boolean | None class CreateRestoreImageTaskResult(TypedDict, total=False): - ImageId: Optional[String] + ImageId: String | None class CreateRouteRequest(ServiceRequest): - DestinationPrefixListId: Optional[PrefixListResourceId] - VpcEndpointId: Optional[VpcEndpointId] - TransitGatewayId: Optional[TransitGatewayId] - LocalGatewayId: Optional[LocalGatewayId] - CarrierGatewayId: Optional[CarrierGatewayId] - CoreNetworkArn: Optional[CoreNetworkArn] - OdbNetworkArn: Optional[OdbNetworkArn] - DryRun: Optional[Boolean] + DestinationPrefixListId: PrefixListResourceId | None + VpcEndpointId: VpcEndpointId | None + TransitGatewayId: TransitGatewayId | None + LocalGatewayId: LocalGatewayId | None + CarrierGatewayId: CarrierGatewayId | None + CoreNetworkArn: CoreNetworkArn | None + OdbNetworkArn: OdbNetworkArn | None + DryRun: Boolean | None RouteTableId: RouteTableId - DestinationCidrBlock: Optional[String] - GatewayId: Optional[RouteGatewayId] - DestinationIpv6CidrBlock: Optional[String] - EgressOnlyInternetGatewayId: Optional[EgressOnlyInternetGatewayId] - InstanceId: Optional[InstanceId] - NetworkInterfaceId: Optional[NetworkInterfaceId] - VpcPeeringConnectionId: Optional[VpcPeeringConnectionId] - NatGatewayId: Optional[NatGatewayId] + DestinationCidrBlock: String | None + GatewayId: RouteGatewayId | None + DestinationIpv6CidrBlock: String | None + EgressOnlyInternetGatewayId: EgressOnlyInternetGatewayId | None + InstanceId: InstanceId | None + NetworkInterfaceId: NetworkInterfaceId | None + VpcPeeringConnectionId: VpcPeeringConnectionId | None + NatGatewayId: NatGatewayId | None class CreateRouteResult(TypedDict, total=False): - Return: Optional[Boolean] + Return: Boolean | None class CreateRouteServerEndpointRequest(ServiceRequest): RouteServerId: RouteServerId SubnetId: SubnetId - ClientToken: Optional[String] - DryRun: Optional[Boolean] - TagSpecifications: Optional[TagSpecificationList] + ClientToken: String | None + DryRun: Boolean | None + TagSpecifications: TagSpecificationList | None class RouteServerEndpoint(TypedDict, total=False): - RouteServerId: Optional[RouteServerId] - RouteServerEndpointId: Optional[RouteServerEndpointId] - VpcId: Optional[VpcId] - SubnetId: Optional[SubnetId] - EniId: Optional[NetworkInterfaceId] - EniAddress: Optional[String] - State: Optional[RouteServerEndpointState] - FailureReason: Optional[String] - Tags: Optional[TagList] + RouteServerId: RouteServerId | None + RouteServerEndpointId: RouteServerEndpointId | None + VpcId: VpcId | None + SubnetId: SubnetId | None + EniId: NetworkInterfaceId | None + EniAddress: String | None + State: RouteServerEndpointState | None + FailureReason: String | None + Tags: TagList | None class CreateRouteServerEndpointResult(TypedDict, total=False): - RouteServerEndpoint: Optional[RouteServerEndpoint] + RouteServerEndpoint: RouteServerEndpoint | None class RouteServerBgpOptionsRequest(TypedDict, total=False): PeerAsn: Long - PeerLivenessDetection: Optional[RouteServerPeerLivenessMode] + PeerLivenessDetection: RouteServerPeerLivenessMode | None class CreateRouteServerPeerRequest(ServiceRequest): RouteServerEndpointId: RouteServerEndpointId PeerAddress: String BgpOptions: RouteServerBgpOptionsRequest - DryRun: Optional[Boolean] - TagSpecifications: Optional[TagSpecificationList] + DryRun: Boolean | None + TagSpecifications: TagSpecificationList | None class RouteServerBfdStatus(TypedDict, total=False): - Status: Optional[RouteServerBfdState] + Status: RouteServerBfdState | None class RouteServerBgpStatus(TypedDict, total=False): - Status: Optional[RouteServerBgpState] + Status: RouteServerBgpState | None class RouteServerBgpOptions(TypedDict, total=False): - PeerAsn: Optional[Long] - PeerLivenessDetection: Optional[RouteServerPeerLivenessMode] + PeerAsn: Long | None + PeerLivenessDetection: RouteServerPeerLivenessMode | None class RouteServerPeer(TypedDict, total=False): - RouteServerPeerId: Optional[RouteServerPeerId] - RouteServerEndpointId: Optional[RouteServerEndpointId] - RouteServerId: Optional[RouteServerId] - VpcId: Optional[VpcId] - SubnetId: Optional[SubnetId] - State: Optional[RouteServerPeerState] - FailureReason: Optional[String] - EndpointEniId: Optional[NetworkInterfaceId] - EndpointEniAddress: Optional[String] - PeerAddress: Optional[String] - BgpOptions: Optional[RouteServerBgpOptions] - BgpStatus: Optional[RouteServerBgpStatus] - BfdStatus: Optional[RouteServerBfdStatus] - Tags: Optional[TagList] + RouteServerPeerId: RouteServerPeerId | None + RouteServerEndpointId: RouteServerEndpointId | None + RouteServerId: RouteServerId | None + VpcId: VpcId | None + SubnetId: SubnetId | None + State: RouteServerPeerState | None + FailureReason: String | None + EndpointEniId: NetworkInterfaceId | None + EndpointEniAddress: String | None + PeerAddress: String | None + BgpOptions: RouteServerBgpOptions | None + BgpStatus: RouteServerBgpStatus | None + BfdStatus: RouteServerBfdStatus | None + Tags: TagList | None class CreateRouteServerPeerResult(TypedDict, total=False): - RouteServerPeer: Optional[RouteServerPeer] + RouteServerPeer: RouteServerPeer | None class CreateRouteServerRequest(ServiceRequest): AmazonSideAsn: Long - ClientToken: Optional[String] - DryRun: Optional[Boolean] - PersistRoutes: Optional[RouteServerPersistRoutesAction] - PersistRoutesDuration: Optional[BoxedLong] - SnsNotificationsEnabled: Optional[Boolean] - TagSpecifications: Optional[TagSpecificationList] + ClientToken: String | None + DryRun: Boolean | None + PersistRoutes: RouteServerPersistRoutesAction | None + PersistRoutesDuration: BoxedLong | None + SnsNotificationsEnabled: Boolean | None + TagSpecifications: TagSpecificationList | None class RouteServer(TypedDict, total=False): - RouteServerId: Optional[RouteServerId] - AmazonSideAsn: Optional[Long] - State: Optional[RouteServerState] - Tags: Optional[TagList] - PersistRoutesState: Optional[RouteServerPersistRoutesState] - PersistRoutesDuration: Optional[BoxedLong] - SnsNotificationsEnabled: Optional[Boolean] - SnsTopicArn: Optional[String] + RouteServerId: RouteServerId | None + AmazonSideAsn: Long | None + State: RouteServerState | None + Tags: TagList | None + PersistRoutesState: RouteServerPersistRoutesState | None + PersistRoutesDuration: BoxedLong | None + SnsNotificationsEnabled: Boolean | None + SnsTopicArn: String | None class CreateRouteServerResult(TypedDict, total=False): - RouteServer: Optional[RouteServer] + RouteServer: RouteServer | None class CreateRouteTableRequest(ServiceRequest): - TagSpecifications: Optional[TagSpecificationList] - ClientToken: Optional[String] - DryRun: Optional[Boolean] + TagSpecifications: TagSpecificationList | None + ClientToken: String | None + DryRun: Boolean | None VpcId: VpcId class Route(TypedDict, total=False): - DestinationCidrBlock: Optional[String] - DestinationIpv6CidrBlock: Optional[String] - DestinationPrefixListId: Optional[String] - EgressOnlyInternetGatewayId: Optional[String] - GatewayId: Optional[String] - InstanceId: Optional[String] - InstanceOwnerId: Optional[String] - NatGatewayId: Optional[String] - TransitGatewayId: Optional[String] - LocalGatewayId: Optional[String] - CarrierGatewayId: Optional[CarrierGatewayId] - NetworkInterfaceId: Optional[String] - Origin: Optional[RouteOrigin] - State: Optional[RouteState] - VpcPeeringConnectionId: Optional[String] - CoreNetworkArn: Optional[CoreNetworkArn] - OdbNetworkArn: Optional[OdbNetworkArn] - IpAddress: Optional[String] - - -RouteList = List[Route] + DestinationCidrBlock: String | None + DestinationIpv6CidrBlock: String | None + DestinationPrefixListId: String | None + EgressOnlyInternetGatewayId: String | None + GatewayId: String | None + InstanceId: String | None + InstanceOwnerId: String | None + NatGatewayId: String | None + TransitGatewayId: String | None + LocalGatewayId: String | None + CarrierGatewayId: CarrierGatewayId | None + NetworkInterfaceId: String | None + Origin: RouteOrigin | None + State: RouteState | None + VpcPeeringConnectionId: String | None + CoreNetworkArn: CoreNetworkArn | None + OdbNetworkArn: OdbNetworkArn | None + IpAddress: String | None + + +RouteList = list[Route] class PropagatingVgw(TypedDict, total=False): - GatewayId: Optional[String] + GatewayId: String | None -PropagatingVgwList = List[PropagatingVgw] +PropagatingVgwList = list[PropagatingVgw] class RouteTableAssociation(TypedDict, total=False): - Main: Optional[Boolean] - RouteTableAssociationId: Optional[String] - RouteTableId: Optional[String] - SubnetId: Optional[String] - GatewayId: Optional[String] - PublicIpv4Pool: Optional[String] - AssociationState: Optional[RouteTableAssociationState] + Main: Boolean | None + RouteTableAssociationId: String | None + RouteTableId: String | None + SubnetId: String | None + GatewayId: String | None + PublicIpv4Pool: String | None + AssociationState: RouteTableAssociationState | None -RouteTableAssociationList = List[RouteTableAssociation] +RouteTableAssociationList = list[RouteTableAssociation] class RouteTable(TypedDict, total=False): - Associations: Optional[RouteTableAssociationList] - PropagatingVgws: Optional[PropagatingVgwList] - RouteTableId: Optional[String] - Routes: Optional[RouteList] - Tags: Optional[TagList] - VpcId: Optional[String] - OwnerId: Optional[String] + Associations: RouteTableAssociationList | None + PropagatingVgws: PropagatingVgwList | None + RouteTableId: String | None + Routes: RouteList | None + Tags: TagList | None + VpcId: String | None + OwnerId: String | None class CreateRouteTableResult(TypedDict, total=False): - RouteTable: Optional[RouteTable] - ClientToken: Optional[String] + RouteTable: RouteTable | None + ClientToken: String | None + + +class CreateSecondaryNetworkRequest(ServiceRequest): + ClientToken: String | None + DryRun: Boolean | None + Ipv4CidrBlock: String + NetworkType: SecondaryNetworkType + TagSpecifications: TagSpecificationList | None + + +class SecondaryNetworkIpv4CidrBlockAssociation(TypedDict, total=False): + AssociationId: SecondaryNetworkCidrAssociationId | None + CidrBlock: String | None + State: SecondaryNetworkCidrBlockAssociationState | None + StateReason: String | None + + +SecondaryNetworkIpv4CidrBlockAssociationList = list[SecondaryNetworkIpv4CidrBlockAssociation] + + +class SecondaryNetwork(TypedDict, total=False): + SecondaryNetworkId: SecondaryNetworkId | None + SecondaryNetworkArn: String | None + OwnerId: String | None + Type: SecondaryNetworkType | None + State: SecondaryNetworkState | None + StateReason: String | None + Ipv4CidrBlockAssociations: SecondaryNetworkIpv4CidrBlockAssociationList | None + Tags: TagList | None + + +class CreateSecondaryNetworkResult(TypedDict, total=False): + SecondaryNetwork: SecondaryNetwork | None + ClientToken: String | None + + +class CreateSecondarySubnetRequest(ServiceRequest): + ClientToken: String | None + AvailabilityZone: AvailabilityZoneName | None + AvailabilityZoneId: AvailabilityZoneId | None + DryRun: Boolean | None + Ipv4CidrBlock: String + SecondaryNetworkId: SecondaryNetworkId + TagSpecifications: TagSpecificationList | None + + +class SecondarySubnetIpv4CidrBlockAssociation(TypedDict, total=False): + AssociationId: SecondarySubnetCidrAssociationId | None + CidrBlock: String | None + State: SecondarySubnetCidrBlockAssociationState | None + StateReason: String | None + + +SecondarySubnetIpv4CidrBlockAssociationList = list[SecondarySubnetIpv4CidrBlockAssociation] + + +class SecondarySubnet(TypedDict, total=False): + SecondarySubnetId: SecondarySubnetId | None + SecondarySubnetArn: String | None + SecondaryNetworkId: SecondaryNetworkId | None + SecondaryNetworkType: SecondaryNetworkType | None + OwnerId: String | None + AvailabilityZoneId: AvailabilityZoneId | None + AvailabilityZone: AvailabilityZoneName | None + Ipv4CidrBlockAssociations: SecondarySubnetIpv4CidrBlockAssociationList | None + State: SecondarySubnetState | None + StateReason: String | None + Tags: TagList | None + + +class CreateSecondarySubnetResult(TypedDict, total=False): + SecondarySubnet: SecondarySubnet | None + ClientToken: String | None class CreateSecurityGroupRequest(ServiceRequest): Description: String GroupName: String - VpcId: Optional[VpcId] - TagSpecifications: Optional[TagSpecificationList] - DryRun: Optional[Boolean] + VpcId: VpcId | None + TagSpecifications: TagSpecificationList | None + DryRun: Boolean | None class CreateSecurityGroupResult(TypedDict, total=False): - GroupId: Optional[String] - Tags: Optional[TagList] - SecurityGroupArn: Optional[String] + GroupId: String | None + Tags: TagList | None + SecurityGroupArn: String | None class CreateSnapshotRequest(ServiceRequest): - Description: Optional[String] - OutpostArn: Optional[String] + Description: String | None + OutpostArn: String | None VolumeId: VolumeId - TagSpecifications: Optional[TagSpecificationList] - Location: Optional[SnapshotLocationEnum] - DryRun: Optional[Boolean] + TagSpecifications: TagSpecificationList | None + Location: SnapshotLocationEnum | None + DryRun: Boolean | None -VolumeIdStringList = List[VolumeId] +VolumeIdStringList = list[VolumeId] class InstanceSpecification(TypedDict, total=False): InstanceId: InstanceIdWithVolumeResolver - ExcludeBootVolume: Optional[Boolean] - ExcludeDataVolumeIds: Optional[VolumeIdStringList] + ExcludeBootVolume: Boolean | None + ExcludeDataVolumeIds: VolumeIdStringList | None class CreateSnapshotsRequest(ServiceRequest): - Description: Optional[String] + Description: String | None InstanceSpecification: InstanceSpecification - OutpostArn: Optional[String] - TagSpecifications: Optional[TagSpecificationList] - DryRun: Optional[Boolean] - CopyTagsFromSource: Optional[CopyTagsFromSource] - Location: Optional[SnapshotLocationEnum] + OutpostArn: String | None + TagSpecifications: TagSpecificationList | None + DryRun: Boolean | None + CopyTagsFromSource: CopyTagsFromSource | None + Location: SnapshotLocationEnum | None class SnapshotInfo(TypedDict, total=False): - Description: Optional[String] - Tags: Optional[TagList] - Encrypted: Optional[Boolean] - VolumeId: Optional[String] - State: Optional[SnapshotState] - VolumeSize: Optional[Integer] - StartTime: Optional[MillisecondDateTime] - Progress: Optional[String] - OwnerId: Optional[String] - SnapshotId: Optional[String] - OutpostArn: Optional[String] - SseType: Optional[SSEType] - AvailabilityZone: Optional[String] + Description: String | None + Tags: TagList | None + Encrypted: Boolean | None + VolumeId: String | None + State: SnapshotState | None + VolumeSize: Integer | None + StartTime: MillisecondDateTime | None + Progress: String | None + OwnerId: String | None + SnapshotId: String | None + OutpostArn: String | None + SseType: SSEType | None + AvailabilityZone: String | None -SnapshotSet = List[SnapshotInfo] +SnapshotSet = list[SnapshotInfo] class CreateSnapshotsResult(TypedDict, total=False): - Snapshots: Optional[SnapshotSet] + Snapshots: SnapshotSet | None class CreateSpotDatafeedSubscriptionRequest(ServiceRequest): - DryRun: Optional[Boolean] + DryRun: Boolean | None Bucket: String - Prefix: Optional[String] + Prefix: String | None class SpotInstanceStateFault(TypedDict, total=False): - Code: Optional[String] - Message: Optional[String] + Code: String | None + Message: String | None class SpotDatafeedSubscription(TypedDict, total=False): - Bucket: Optional[String] - Fault: Optional[SpotInstanceStateFault] - OwnerId: Optional[String] - Prefix: Optional[String] - State: Optional[DatafeedSubscriptionState] + Bucket: String | None + Fault: SpotInstanceStateFault | None + OwnerId: String | None + Prefix: String | None + State: DatafeedSubscriptionState | None class CreateSpotDatafeedSubscriptionResult(TypedDict, total=False): - SpotDatafeedSubscription: Optional[SpotDatafeedSubscription] + SpotDatafeedSubscription: SpotDatafeedSubscription | None class S3ObjectTag(TypedDict, total=False): - Key: Optional[String] - Value: Optional[String] + Key: String | None + Value: String | None -S3ObjectTagList = List[S3ObjectTag] +S3ObjectTagList = list[S3ObjectTag] class CreateStoreImageTaskRequest(ServiceRequest): ImageId: ImageId Bucket: String - S3ObjectTags: Optional[S3ObjectTagList] - DryRun: Optional[Boolean] + S3ObjectTags: S3ObjectTagList | None + DryRun: Boolean | None class CreateStoreImageTaskResult(TypedDict, total=False): - ObjectKey: Optional[String] + ObjectKey: String | None class CreateSubnetCidrReservationRequest(ServiceRequest): SubnetId: SubnetId Cidr: String ReservationType: SubnetCidrReservationType - Description: Optional[String] - DryRun: Optional[Boolean] - TagSpecifications: Optional[TagSpecificationList] + Description: String | None + DryRun: Boolean | None + TagSpecifications: TagSpecificationList | None class SubnetCidrReservation(TypedDict, total=False): - SubnetCidrReservationId: Optional[SubnetCidrReservationId] - SubnetId: Optional[SubnetId] - Cidr: Optional[String] - ReservationType: Optional[SubnetCidrReservationType] - OwnerId: Optional[String] - Description: Optional[String] - Tags: Optional[TagList] + SubnetCidrReservationId: SubnetCidrReservationId | None + SubnetId: SubnetId | None + Cidr: String | None + ReservationType: SubnetCidrReservationType | None + OwnerId: String | None + Description: String | None + Tags: TagList | None class CreateSubnetCidrReservationResult(TypedDict, total=False): - SubnetCidrReservation: Optional[SubnetCidrReservation] + SubnetCidrReservation: SubnetCidrReservation | None class CreateSubnetRequest(ServiceRequest): - TagSpecifications: Optional[TagSpecificationList] - AvailabilityZone: Optional[String] - AvailabilityZoneId: Optional[String] - CidrBlock: Optional[String] - Ipv6CidrBlock: Optional[String] - OutpostArn: Optional[String] + TagSpecifications: TagSpecificationList | None + AvailabilityZone: String | None + AvailabilityZoneId: String | None + CidrBlock: String | None + Ipv6CidrBlock: String | None + OutpostArn: String | None VpcId: VpcId - Ipv6Native: Optional[Boolean] - Ipv4IpamPoolId: Optional[IpamPoolId] - Ipv4NetmaskLength: Optional[NetmaskLength] - Ipv6IpamPoolId: Optional[IpamPoolId] - Ipv6NetmaskLength: Optional[NetmaskLength] - DryRun: Optional[Boolean] + Ipv6Native: Boolean | None + Ipv4IpamPoolId: IpamPoolId | None + Ipv4NetmaskLength: NetmaskLength | None + Ipv6IpamPoolId: IpamPoolId | None + Ipv6NetmaskLength: NetmaskLength | None + DryRun: Boolean | None class CreateSubnetResult(TypedDict, total=False): - Subnet: Optional[Subnet] + Subnet: Subnet | None -ResourceIdList = List[TaggableResourceId] +ResourceIdList = list[TaggableResourceId] class CreateTagsRequest(ServiceRequest): - DryRun: Optional[Boolean] + DryRun: Boolean | None Resources: ResourceIdList Tags: TagList class CreateTrafficMirrorFilterRequest(ServiceRequest): - Description: Optional[String] - TagSpecifications: Optional[TagSpecificationList] - DryRun: Optional[Boolean] - ClientToken: Optional[String] + Description: String | None + TagSpecifications: TagSpecificationList | None + DryRun: Boolean | None + ClientToken: String | None -TrafficMirrorNetworkServiceList = List[TrafficMirrorNetworkService] +TrafficMirrorNetworkServiceList = list[TrafficMirrorNetworkService] class TrafficMirrorPortRange(TypedDict, total=False): - FromPort: Optional[Integer] - ToPort: Optional[Integer] + FromPort: Integer | None + ToPort: Integer | None class TrafficMirrorFilterRule(TypedDict, total=False): - TrafficMirrorFilterRuleId: Optional[String] - TrafficMirrorFilterId: Optional[String] - TrafficDirection: Optional[TrafficDirection] - RuleNumber: Optional[Integer] - RuleAction: Optional[TrafficMirrorRuleAction] - Protocol: Optional[Integer] - DestinationPortRange: Optional[TrafficMirrorPortRange] - SourcePortRange: Optional[TrafficMirrorPortRange] - DestinationCidrBlock: Optional[String] - SourceCidrBlock: Optional[String] - Description: Optional[String] - Tags: Optional[TagList] + TrafficMirrorFilterRuleId: String | None + TrafficMirrorFilterId: String | None + TrafficDirection: TrafficDirection | None + RuleNumber: Integer | None + RuleAction: TrafficMirrorRuleAction | None + Protocol: Integer | None + DestinationPortRange: TrafficMirrorPortRange | None + SourcePortRange: TrafficMirrorPortRange | None + DestinationCidrBlock: String | None + SourceCidrBlock: String | None + Description: String | None + Tags: TagList | None -TrafficMirrorFilterRuleList = List[TrafficMirrorFilterRule] +TrafficMirrorFilterRuleList = list[TrafficMirrorFilterRule] class TrafficMirrorFilter(TypedDict, total=False): - TrafficMirrorFilterId: Optional[String] - IngressFilterRules: Optional[TrafficMirrorFilterRuleList] - EgressFilterRules: Optional[TrafficMirrorFilterRuleList] - NetworkServices: Optional[TrafficMirrorNetworkServiceList] - Description: Optional[String] - Tags: Optional[TagList] + TrafficMirrorFilterId: String | None + IngressFilterRules: TrafficMirrorFilterRuleList | None + EgressFilterRules: TrafficMirrorFilterRuleList | None + NetworkServices: TrafficMirrorNetworkServiceList | None + Description: String | None + Tags: TagList | None class CreateTrafficMirrorFilterResult(TypedDict, total=False): - TrafficMirrorFilter: Optional[TrafficMirrorFilter] - ClientToken: Optional[String] + TrafficMirrorFilter: TrafficMirrorFilter | None + ClientToken: String | None class TrafficMirrorPortRangeRequest(TypedDict, total=False): - FromPort: Optional[Integer] - ToPort: Optional[Integer] + FromPort: Integer | None + ToPort: Integer | None class CreateTrafficMirrorFilterRuleRequest(ServiceRequest): @@ -9547,126 +10679,126 @@ class CreateTrafficMirrorFilterRuleRequest(ServiceRequest): TrafficDirection: TrafficDirection RuleNumber: Integer RuleAction: TrafficMirrorRuleAction - DestinationPortRange: Optional[TrafficMirrorPortRangeRequest] - SourcePortRange: Optional[TrafficMirrorPortRangeRequest] - Protocol: Optional[Integer] + DestinationPortRange: TrafficMirrorPortRangeRequest | None + SourcePortRange: TrafficMirrorPortRangeRequest | None + Protocol: Integer | None DestinationCidrBlock: String SourceCidrBlock: String - Description: Optional[String] - DryRun: Optional[Boolean] - ClientToken: Optional[String] - TagSpecifications: Optional[TagSpecificationList] + Description: String | None + DryRun: Boolean | None + ClientToken: String | None + TagSpecifications: TagSpecificationList | None class CreateTrafficMirrorFilterRuleResult(TypedDict, total=False): - TrafficMirrorFilterRule: Optional[TrafficMirrorFilterRule] - ClientToken: Optional[String] + TrafficMirrorFilterRule: TrafficMirrorFilterRule | None + ClientToken: String | None class CreateTrafficMirrorSessionRequest(ServiceRequest): NetworkInterfaceId: NetworkInterfaceId TrafficMirrorTargetId: TrafficMirrorTargetId TrafficMirrorFilterId: TrafficMirrorFilterId - PacketLength: Optional[Integer] + PacketLength: Integer | None SessionNumber: Integer - VirtualNetworkId: Optional[Integer] - Description: Optional[String] - TagSpecifications: Optional[TagSpecificationList] - DryRun: Optional[Boolean] - ClientToken: Optional[String] + VirtualNetworkId: Integer | None + Description: String | None + TagSpecifications: TagSpecificationList | None + DryRun: Boolean | None + ClientToken: String | None class TrafficMirrorSession(TypedDict, total=False): - TrafficMirrorSessionId: Optional[String] - TrafficMirrorTargetId: Optional[String] - TrafficMirrorFilterId: Optional[String] - NetworkInterfaceId: Optional[String] - OwnerId: Optional[String] - PacketLength: Optional[Integer] - SessionNumber: Optional[Integer] - VirtualNetworkId: Optional[Integer] - Description: Optional[String] - Tags: Optional[TagList] + TrafficMirrorSessionId: String | None + TrafficMirrorTargetId: String | None + TrafficMirrorFilterId: String | None + NetworkInterfaceId: String | None + OwnerId: String | None + PacketLength: Integer | None + SessionNumber: Integer | None + VirtualNetworkId: Integer | None + Description: String | None + Tags: TagList | None class CreateTrafficMirrorSessionResult(TypedDict, total=False): - TrafficMirrorSession: Optional[TrafficMirrorSession] - ClientToken: Optional[String] + TrafficMirrorSession: TrafficMirrorSession | None + ClientToken: String | None class CreateTrafficMirrorTargetRequest(ServiceRequest): - NetworkInterfaceId: Optional[NetworkInterfaceId] - NetworkLoadBalancerArn: Optional[String] - Description: Optional[String] - TagSpecifications: Optional[TagSpecificationList] - DryRun: Optional[Boolean] - ClientToken: Optional[String] - GatewayLoadBalancerEndpointId: Optional[VpcEndpointId] + NetworkInterfaceId: NetworkInterfaceId | None + NetworkLoadBalancerArn: String | None + Description: String | None + TagSpecifications: TagSpecificationList | None + DryRun: Boolean | None + ClientToken: String | None + GatewayLoadBalancerEndpointId: VpcEndpointId | None class TrafficMirrorTarget(TypedDict, total=False): - TrafficMirrorTargetId: Optional[String] - NetworkInterfaceId: Optional[String] - NetworkLoadBalancerArn: Optional[String] - Type: Optional[TrafficMirrorTargetType] - Description: Optional[String] - OwnerId: Optional[String] - Tags: Optional[TagList] - GatewayLoadBalancerEndpointId: Optional[String] + TrafficMirrorTargetId: String | None + NetworkInterfaceId: String | None + NetworkLoadBalancerArn: String | None + Type: TrafficMirrorTargetType | None + Description: String | None + OwnerId: String | None + Tags: TagList | None + GatewayLoadBalancerEndpointId: String | None class CreateTrafficMirrorTargetResult(TypedDict, total=False): - TrafficMirrorTarget: Optional[TrafficMirrorTarget] - ClientToken: Optional[String] + TrafficMirrorTarget: TrafficMirrorTarget | None + ClientToken: String | None -InsideCidrBlocksStringList = List[String] +InsideCidrBlocksStringList = list[String] class TransitGatewayConnectRequestBgpOptions(TypedDict, total=False): - PeerAsn: Optional[Long] + PeerAsn: Long | None class CreateTransitGatewayConnectPeerRequest(ServiceRequest): TransitGatewayAttachmentId: TransitGatewayAttachmentId - TransitGatewayAddress: Optional[String] + TransitGatewayAddress: String | None PeerAddress: String - BgpOptions: Optional[TransitGatewayConnectRequestBgpOptions] + BgpOptions: TransitGatewayConnectRequestBgpOptions | None InsideCidrBlocks: InsideCidrBlocksStringList - TagSpecifications: Optional[TagSpecificationList] - DryRun: Optional[Boolean] + TagSpecifications: TagSpecificationList | None + DryRun: Boolean | None class TransitGatewayAttachmentBgpConfiguration(TypedDict, total=False): - TransitGatewayAsn: Optional[Long] - PeerAsn: Optional[Long] - TransitGatewayAddress: Optional[String] - PeerAddress: Optional[String] - BgpStatus: Optional[BgpStatus] + TransitGatewayAsn: Long | None + PeerAsn: Long | None + TransitGatewayAddress: String | None + PeerAddress: String | None + BgpStatus: BgpStatus | None -TransitGatewayAttachmentBgpConfigurationList = List[TransitGatewayAttachmentBgpConfiguration] +TransitGatewayAttachmentBgpConfigurationList = list[TransitGatewayAttachmentBgpConfiguration] class TransitGatewayConnectPeerConfiguration(TypedDict, total=False): - TransitGatewayAddress: Optional[String] - PeerAddress: Optional[String] - InsideCidrBlocks: Optional[InsideCidrBlocksStringList] - Protocol: Optional[ProtocolValue] - BgpConfigurations: Optional[TransitGatewayAttachmentBgpConfigurationList] + TransitGatewayAddress: String | None + PeerAddress: String | None + InsideCidrBlocks: InsideCidrBlocksStringList | None + Protocol: ProtocolValue | None + BgpConfigurations: TransitGatewayAttachmentBgpConfigurationList | None class TransitGatewayConnectPeer(TypedDict, total=False): - TransitGatewayAttachmentId: Optional[TransitGatewayAttachmentId] - TransitGatewayConnectPeerId: Optional[TransitGatewayConnectPeerId] - State: Optional[TransitGatewayConnectPeerState] - CreationTime: Optional[DateTime] - ConnectPeerConfiguration: Optional[TransitGatewayConnectPeerConfiguration] - Tags: Optional[TagList] + TransitGatewayAttachmentId: TransitGatewayAttachmentId | None + TransitGatewayConnectPeerId: TransitGatewayConnectPeerId | None + State: TransitGatewayConnectPeerState | None + CreationTime: DateTime | None + ConnectPeerConfiguration: TransitGatewayConnectPeerConfiguration | None + Tags: TagList | None class CreateTransitGatewayConnectPeerResult(TypedDict, total=False): - TransitGatewayConnectPeer: Optional[TransitGatewayConnectPeer] + TransitGatewayConnectPeer: TransitGatewayConnectPeer | None class CreateTransitGatewayConnectRequestOptions(TypedDict, total=False): @@ -9676,64 +10808,128 @@ class CreateTransitGatewayConnectRequestOptions(TypedDict, total=False): class CreateTransitGatewayConnectRequest(ServiceRequest): TransportTransitGatewayAttachmentId: TransitGatewayAttachmentId Options: CreateTransitGatewayConnectRequestOptions - TagSpecifications: Optional[TagSpecificationList] - DryRun: Optional[Boolean] + TagSpecifications: TagSpecificationList | None + DryRun: Boolean | None class TransitGatewayConnectOptions(TypedDict, total=False): - Protocol: Optional[ProtocolValue] + Protocol: ProtocolValue | None class TransitGatewayConnect(TypedDict, total=False): - TransitGatewayAttachmentId: Optional[TransitGatewayAttachmentId] - TransportTransitGatewayAttachmentId: Optional[TransitGatewayAttachmentId] - TransitGatewayId: Optional[TransitGatewayId] - State: Optional[TransitGatewayAttachmentState] - CreationTime: Optional[DateTime] - Options: Optional[TransitGatewayConnectOptions] - Tags: Optional[TagList] + TransitGatewayAttachmentId: TransitGatewayAttachmentId | None + TransportTransitGatewayAttachmentId: TransitGatewayAttachmentId | None + TransitGatewayId: TransitGatewayId | None + State: TransitGatewayAttachmentState | None + CreationTime: DateTime | None + Options: TransitGatewayConnectOptions | None + Tags: TagList | None class CreateTransitGatewayConnectResult(TypedDict, total=False): - TransitGatewayConnect: Optional[TransitGatewayConnect] + TransitGatewayConnect: TransitGatewayConnect | None + + +class CreateTransitGatewayMeteringPolicyEntryRequest(ServiceRequest): + TransitGatewayMeteringPolicyId: TransitGatewayMeteringPolicyId + PolicyRuleNumber: Integer + SourceTransitGatewayAttachmentId: TransitGatewayAttachmentId | None + SourceTransitGatewayAttachmentType: TransitGatewayAttachmentResourceType | None + SourceCidrBlock: String | None + SourcePortRange: String | None + DestinationTransitGatewayAttachmentId: TransitGatewayAttachmentId | None + DestinationTransitGatewayAttachmentType: TransitGatewayAttachmentResourceType | None + DestinationCidrBlock: String | None + DestinationPortRange: String | None + Protocol: String | None + MeteredAccount: TransitGatewayMeteringPayerType + DryRun: Boolean | None + + +class TransitGatewayMeteringPolicyRule(TypedDict, total=False): + SourceTransitGatewayAttachmentId: TransitGatewayAttachmentId | None + SourceTransitGatewayAttachmentType: TransitGatewayAttachmentResourceType | None + SourceCidrBlock: String | None + SourcePortRange: String | None + DestinationTransitGatewayAttachmentId: TransitGatewayAttachmentId | None + DestinationTransitGatewayAttachmentType: TransitGatewayAttachmentResourceType | None + DestinationCidrBlock: String | None + DestinationPortRange: String | None + Protocol: String | None + + +class TransitGatewayMeteringPolicyEntry(TypedDict, total=False): + PolicyRuleNumber: String | None + MeteredAccount: TransitGatewayMeteringPayerType | None + State: TransitGatewayMeteringPolicyEntryState | None + UpdatedAt: MillisecondDateTime | None + UpdateEffectiveAt: MillisecondDateTime | None + MeteringPolicyRule: TransitGatewayMeteringPolicyRule | None + + +class CreateTransitGatewayMeteringPolicyEntryResult(TypedDict, total=False): + TransitGatewayMeteringPolicyEntry: TransitGatewayMeteringPolicyEntry | None + + +TransitGatewayAttachmentIdStringList = list[TransitGatewayAttachmentId] + + +class CreateTransitGatewayMeteringPolicyRequest(ServiceRequest): + TransitGatewayId: TransitGatewayId + MiddleboxAttachmentIds: TransitGatewayAttachmentIdStringList | None + TagSpecifications: TagSpecificationList | None + DryRun: Boolean | None + + +class TransitGatewayMeteringPolicy(TypedDict, total=False): + TransitGatewayMeteringPolicyId: TransitGatewayMeteringPolicyId | None + TransitGatewayId: TransitGatewayId | None + MiddleboxAttachmentIds: ValueStringList | None + State: TransitGatewayMeteringPolicyState | None + UpdateEffectiveAt: MillisecondDateTime | None + Tags: TagList | None + + +class CreateTransitGatewayMeteringPolicyResult(TypedDict, total=False): + TransitGatewayMeteringPolicy: TransitGatewayMeteringPolicy | None class CreateTransitGatewayMulticastDomainRequestOptions(TypedDict, total=False): - Igmpv2Support: Optional[Igmpv2SupportValue] - StaticSourcesSupport: Optional[StaticSourcesSupportValue] - AutoAcceptSharedAssociations: Optional[AutoAcceptSharedAssociationsValue] + Igmpv2Support: Igmpv2SupportValue | None + StaticSourcesSupport: StaticSourcesSupportValue | None + AutoAcceptSharedAssociations: AutoAcceptSharedAssociationsValue | None class CreateTransitGatewayMulticastDomainRequest(ServiceRequest): TransitGatewayId: TransitGatewayId - Options: Optional[CreateTransitGatewayMulticastDomainRequestOptions] - TagSpecifications: Optional[TagSpecificationList] - DryRun: Optional[Boolean] + Options: CreateTransitGatewayMulticastDomainRequestOptions | None + TagSpecifications: TagSpecificationList | None + DryRun: Boolean | None class TransitGatewayMulticastDomainOptions(TypedDict, total=False): - Igmpv2Support: Optional[Igmpv2SupportValue] - StaticSourcesSupport: Optional[StaticSourcesSupportValue] - AutoAcceptSharedAssociations: Optional[AutoAcceptSharedAssociationsValue] + Igmpv2Support: Igmpv2SupportValue | None + StaticSourcesSupport: StaticSourcesSupportValue | None + AutoAcceptSharedAssociations: AutoAcceptSharedAssociationsValue | None class TransitGatewayMulticastDomain(TypedDict, total=False): - TransitGatewayMulticastDomainId: Optional[String] - TransitGatewayId: Optional[String] - TransitGatewayMulticastDomainArn: Optional[String] - OwnerId: Optional[String] - Options: Optional[TransitGatewayMulticastDomainOptions] - State: Optional[TransitGatewayMulticastDomainState] - CreationTime: Optional[DateTime] - Tags: Optional[TagList] + TransitGatewayMulticastDomainId: String | None + TransitGatewayId: String | None + TransitGatewayMulticastDomainArn: String | None + OwnerId: String | None + Options: TransitGatewayMulticastDomainOptions | None + State: TransitGatewayMulticastDomainState | None + CreationTime: DateTime | None + Tags: TagList | None class CreateTransitGatewayMulticastDomainResult(TypedDict, total=False): - TransitGatewayMulticastDomain: Optional[TransitGatewayMulticastDomain] + TransitGatewayMulticastDomain: TransitGatewayMulticastDomain | None class CreateTransitGatewayPeeringAttachmentRequestOptions(TypedDict, total=False): - DynamicRouting: Optional[DynamicRoutingValue] + DynamicRouting: DynamicRoutingValue | None class CreateTransitGatewayPeeringAttachmentRequest(ServiceRequest): @@ -9741,945 +10937,1003 @@ class CreateTransitGatewayPeeringAttachmentRequest(ServiceRequest): PeerTransitGatewayId: TransitAssociationGatewayId PeerAccountId: String PeerRegion: String - Options: Optional[CreateTransitGatewayPeeringAttachmentRequestOptions] - TagSpecifications: Optional[TagSpecificationList] - DryRun: Optional[Boolean] + Options: CreateTransitGatewayPeeringAttachmentRequestOptions | None + TagSpecifications: TagSpecificationList | None + DryRun: Boolean | None class CreateTransitGatewayPeeringAttachmentResult(TypedDict, total=False): - TransitGatewayPeeringAttachment: Optional[TransitGatewayPeeringAttachment] + TransitGatewayPeeringAttachment: TransitGatewayPeeringAttachment | None class CreateTransitGatewayPolicyTableRequest(ServiceRequest): TransitGatewayId: TransitGatewayId - TagSpecifications: Optional[TagSpecificationList] - DryRun: Optional[Boolean] + TagSpecifications: TagSpecificationList | None + DryRun: Boolean | None class TransitGatewayPolicyTable(TypedDict, total=False): - TransitGatewayPolicyTableId: Optional[TransitGatewayPolicyTableId] - TransitGatewayId: Optional[TransitGatewayId] - State: Optional[TransitGatewayPolicyTableState] - CreationTime: Optional[DateTime] - Tags: Optional[TagList] + TransitGatewayPolicyTableId: TransitGatewayPolicyTableId | None + TransitGatewayId: TransitGatewayId | None + State: TransitGatewayPolicyTableState | None + CreationTime: DateTime | None + Tags: TagList | None class CreateTransitGatewayPolicyTableResult(TypedDict, total=False): - TransitGatewayPolicyTable: Optional[TransitGatewayPolicyTable] + TransitGatewayPolicyTable: TransitGatewayPolicyTable | None class CreateTransitGatewayPrefixListReferenceRequest(ServiceRequest): TransitGatewayRouteTableId: TransitGatewayRouteTableId PrefixListId: PrefixListResourceId - TransitGatewayAttachmentId: Optional[TransitGatewayAttachmentId] - Blackhole: Optional[Boolean] - DryRun: Optional[Boolean] + TransitGatewayAttachmentId: TransitGatewayAttachmentId | None + Blackhole: Boolean | None + DryRun: Boolean | None class TransitGatewayPrefixListAttachment(TypedDict, total=False): - TransitGatewayAttachmentId: Optional[TransitGatewayAttachmentId] - ResourceType: Optional[TransitGatewayAttachmentResourceType] - ResourceId: Optional[String] + TransitGatewayAttachmentId: TransitGatewayAttachmentId | None + ResourceType: TransitGatewayAttachmentResourceType | None + ResourceId: String | None class TransitGatewayPrefixListReference(TypedDict, total=False): - TransitGatewayRouteTableId: Optional[TransitGatewayRouteTableId] - PrefixListId: Optional[PrefixListResourceId] - PrefixListOwnerId: Optional[String] - State: Optional[TransitGatewayPrefixListReferenceState] - Blackhole: Optional[Boolean] - TransitGatewayAttachment: Optional[TransitGatewayPrefixListAttachment] + TransitGatewayRouteTableId: TransitGatewayRouteTableId | None + PrefixListId: PrefixListResourceId | None + PrefixListOwnerId: String | None + State: TransitGatewayPrefixListReferenceState | None + Blackhole: Boolean | None + TransitGatewayAttachment: TransitGatewayPrefixListAttachment | None class CreateTransitGatewayPrefixListReferenceResult(TypedDict, total=False): - TransitGatewayPrefixListReference: Optional[TransitGatewayPrefixListReference] + TransitGatewayPrefixListReference: TransitGatewayPrefixListReference | None -TransitGatewayCidrBlockStringList = List[String] +TransitGatewayCidrBlockStringList = list[String] class TransitGatewayRequestOptions(TypedDict, total=False): - AmazonSideAsn: Optional[Long] - AutoAcceptSharedAttachments: Optional[AutoAcceptSharedAttachmentsValue] - DefaultRouteTableAssociation: Optional[DefaultRouteTableAssociationValue] - DefaultRouteTablePropagation: Optional[DefaultRouteTablePropagationValue] - VpnEcmpSupport: Optional[VpnEcmpSupportValue] - DnsSupport: Optional[DnsSupportValue] - SecurityGroupReferencingSupport: Optional[SecurityGroupReferencingSupportValue] - MulticastSupport: Optional[MulticastSupportValue] - TransitGatewayCidrBlocks: Optional[TransitGatewayCidrBlockStringList] + AmazonSideAsn: Long | None + AutoAcceptSharedAttachments: AutoAcceptSharedAttachmentsValue | None + DefaultRouteTableAssociation: DefaultRouteTableAssociationValue | None + DefaultRouteTablePropagation: DefaultRouteTablePropagationValue | None + VpnEcmpSupport: VpnEcmpSupportValue | None + DnsSupport: DnsSupportValue | None + SecurityGroupReferencingSupport: SecurityGroupReferencingSupportValue | None + MulticastSupport: MulticastSupportValue | None + TransitGatewayCidrBlocks: TransitGatewayCidrBlockStringList | None class CreateTransitGatewayRequest(ServiceRequest): - Description: Optional[String] - Options: Optional[TransitGatewayRequestOptions] - TagSpecifications: Optional[TagSpecificationList] - DryRun: Optional[Boolean] + Description: String | None + Options: TransitGatewayRequestOptions | None + TagSpecifications: TagSpecificationList | None + DryRun: Boolean | None + + +class EncryptionSupport(TypedDict, total=False): + EncryptionState: EncryptionStateValue | None + StateMessage: String | None class TransitGatewayOptions(TypedDict, total=False): - AmazonSideAsn: Optional[Long] - TransitGatewayCidrBlocks: Optional[ValueStringList] - AutoAcceptSharedAttachments: Optional[AutoAcceptSharedAttachmentsValue] - DefaultRouteTableAssociation: Optional[DefaultRouteTableAssociationValue] - AssociationDefaultRouteTableId: Optional[String] - DefaultRouteTablePropagation: Optional[DefaultRouteTablePropagationValue] - PropagationDefaultRouteTableId: Optional[String] - VpnEcmpSupport: Optional[VpnEcmpSupportValue] - DnsSupport: Optional[DnsSupportValue] - SecurityGroupReferencingSupport: Optional[SecurityGroupReferencingSupportValue] - MulticastSupport: Optional[MulticastSupportValue] + AmazonSideAsn: Long | None + TransitGatewayCidrBlocks: ValueStringList | None + AutoAcceptSharedAttachments: AutoAcceptSharedAttachmentsValue | None + DefaultRouteTableAssociation: DefaultRouteTableAssociationValue | None + AssociationDefaultRouteTableId: String | None + DefaultRouteTablePropagation: DefaultRouteTablePropagationValue | None + PropagationDefaultRouteTableId: String | None + VpnEcmpSupport: VpnEcmpSupportValue | None + DnsSupport: DnsSupportValue | None + SecurityGroupReferencingSupport: SecurityGroupReferencingSupportValue | None + MulticastSupport: MulticastSupportValue | None + EncryptionSupport: EncryptionSupport | None class TransitGateway(TypedDict, total=False): - TransitGatewayId: Optional[String] - TransitGatewayArn: Optional[String] - State: Optional[TransitGatewayState] - OwnerId: Optional[String] - Description: Optional[String] - CreationTime: Optional[DateTime] - Options: Optional[TransitGatewayOptions] - Tags: Optional[TagList] + TransitGatewayId: String | None + TransitGatewayArn: String | None + State: TransitGatewayState | None + OwnerId: String | None + Description: String | None + CreationTime: DateTime | None + Options: TransitGatewayOptions | None + Tags: TagList | None class CreateTransitGatewayResult(TypedDict, total=False): - TransitGateway: Optional[TransitGateway] + TransitGateway: TransitGateway | None class CreateTransitGatewayRouteRequest(ServiceRequest): DestinationCidrBlock: String TransitGatewayRouteTableId: TransitGatewayRouteTableId - TransitGatewayAttachmentId: Optional[TransitGatewayAttachmentId] - Blackhole: Optional[Boolean] - DryRun: Optional[Boolean] + TransitGatewayAttachmentId: TransitGatewayAttachmentId | None + Blackhole: Boolean | None + DryRun: Boolean | None class TransitGatewayRouteAttachment(TypedDict, total=False): - ResourceId: Optional[String] - TransitGatewayAttachmentId: Optional[String] - ResourceType: Optional[TransitGatewayAttachmentResourceType] + ResourceId: String | None + TransitGatewayAttachmentId: String | None + ResourceType: TransitGatewayAttachmentResourceType | None -TransitGatewayRouteAttachmentList = List[TransitGatewayRouteAttachment] +TransitGatewayRouteAttachmentList = list[TransitGatewayRouteAttachment] class TransitGatewayRoute(TypedDict, total=False): - DestinationCidrBlock: Optional[String] - PrefixListId: Optional[PrefixListResourceId] - TransitGatewayRouteTableAnnouncementId: Optional[TransitGatewayRouteTableAnnouncementId] - TransitGatewayAttachments: Optional[TransitGatewayRouteAttachmentList] - Type: Optional[TransitGatewayRouteType] - State: Optional[TransitGatewayRouteState] + DestinationCidrBlock: String | None + PrefixListId: PrefixListResourceId | None + TransitGatewayRouteTableAnnouncementId: TransitGatewayRouteTableAnnouncementId | None + TransitGatewayAttachments: TransitGatewayRouteAttachmentList | None + Type: TransitGatewayRouteType | None + State: TransitGatewayRouteState | None class CreateTransitGatewayRouteResult(TypedDict, total=False): - Route: Optional[TransitGatewayRoute] + Route: TransitGatewayRoute | None class CreateTransitGatewayRouteTableAnnouncementRequest(ServiceRequest): TransitGatewayRouteTableId: TransitGatewayRouteTableId PeeringAttachmentId: TransitGatewayAttachmentId - TagSpecifications: Optional[TagSpecificationList] - DryRun: Optional[Boolean] + TagSpecifications: TagSpecificationList | None + DryRun: Boolean | None class TransitGatewayRouteTableAnnouncement(TypedDict, total=False): - TransitGatewayRouteTableAnnouncementId: Optional[TransitGatewayRouteTableAnnouncementId] - TransitGatewayId: Optional[TransitGatewayId] - CoreNetworkId: Optional[String] - PeerTransitGatewayId: Optional[TransitGatewayId] - PeerCoreNetworkId: Optional[String] - PeeringAttachmentId: Optional[TransitGatewayAttachmentId] - AnnouncementDirection: Optional[TransitGatewayRouteTableAnnouncementDirection] - TransitGatewayRouteTableId: Optional[TransitGatewayRouteTableId] - State: Optional[TransitGatewayRouteTableAnnouncementState] - CreationTime: Optional[DateTime] - Tags: Optional[TagList] + TransitGatewayRouteTableAnnouncementId: TransitGatewayRouteTableAnnouncementId | None + TransitGatewayId: TransitGatewayId | None + CoreNetworkId: String | None + PeerTransitGatewayId: TransitGatewayId | None + PeerCoreNetworkId: String | None + PeeringAttachmentId: TransitGatewayAttachmentId | None + AnnouncementDirection: TransitGatewayRouteTableAnnouncementDirection | None + TransitGatewayRouteTableId: TransitGatewayRouteTableId | None + State: TransitGatewayRouteTableAnnouncementState | None + CreationTime: DateTime | None + Tags: TagList | None class CreateTransitGatewayRouteTableAnnouncementResult(TypedDict, total=False): - TransitGatewayRouteTableAnnouncement: Optional[TransitGatewayRouteTableAnnouncement] + TransitGatewayRouteTableAnnouncement: TransitGatewayRouteTableAnnouncement | None class CreateTransitGatewayRouteTableRequest(ServiceRequest): TransitGatewayId: TransitGatewayId - TagSpecifications: Optional[TagSpecificationList] - DryRun: Optional[Boolean] + TagSpecifications: TagSpecificationList | None + DryRun: Boolean | None class TransitGatewayRouteTable(TypedDict, total=False): - TransitGatewayRouteTableId: Optional[String] - TransitGatewayId: Optional[String] - State: Optional[TransitGatewayRouteTableState] - DefaultAssociationRouteTable: Optional[Boolean] - DefaultPropagationRouteTable: Optional[Boolean] - CreationTime: Optional[DateTime] - Tags: Optional[TagList] + TransitGatewayRouteTableId: String | None + TransitGatewayId: String | None + State: TransitGatewayRouteTableState | None + DefaultAssociationRouteTable: Boolean | None + DefaultPropagationRouteTable: Boolean | None + CreationTime: DateTime | None + Tags: TagList | None class CreateTransitGatewayRouteTableResult(TypedDict, total=False): - TransitGatewayRouteTable: Optional[TransitGatewayRouteTable] + TransitGatewayRouteTable: TransitGatewayRouteTable | None class CreateTransitGatewayVpcAttachmentRequestOptions(TypedDict, total=False): - DnsSupport: Optional[DnsSupportValue] - SecurityGroupReferencingSupport: Optional[SecurityGroupReferencingSupportValue] - Ipv6Support: Optional[Ipv6SupportValue] - ApplianceModeSupport: Optional[ApplianceModeSupportValue] + DnsSupport: DnsSupportValue | None + SecurityGroupReferencingSupport: SecurityGroupReferencingSupportValue | None + Ipv6Support: Ipv6SupportValue | None + ApplianceModeSupport: ApplianceModeSupportValue | None class CreateTransitGatewayVpcAttachmentRequest(ServiceRequest): TransitGatewayId: TransitGatewayId VpcId: VpcId SubnetIds: TransitGatewaySubnetIdList - Options: Optional[CreateTransitGatewayVpcAttachmentRequestOptions] - TagSpecifications: Optional[TagSpecificationList] - DryRun: Optional[Boolean] + Options: CreateTransitGatewayVpcAttachmentRequestOptions | None + TagSpecifications: TagSpecificationList | None + DryRun: Boolean | None class CreateTransitGatewayVpcAttachmentResult(TypedDict, total=False): - TransitGatewayVpcAttachment: Optional[TransitGatewayVpcAttachment] + TransitGatewayVpcAttachment: TransitGatewayVpcAttachment | None class CreateVerifiedAccessEndpointPortRange(TypedDict, total=False): - FromPort: Optional[VerifiedAccessEndpointPortNumber] - ToPort: Optional[VerifiedAccessEndpointPortNumber] + FromPort: VerifiedAccessEndpointPortNumber | None + ToPort: VerifiedAccessEndpointPortNumber | None -CreateVerifiedAccessEndpointPortRangeList = List[CreateVerifiedAccessEndpointPortRange] -CreateVerifiedAccessEndpointSubnetIdList = List[SubnetId] +CreateVerifiedAccessEndpointPortRangeList = list[CreateVerifiedAccessEndpointPortRange] +CreateVerifiedAccessEndpointSubnetIdList = list[SubnetId] class CreateVerifiedAccessEndpointCidrOptions(TypedDict, total=False): - Protocol: Optional[VerifiedAccessEndpointProtocol] - SubnetIds: Optional[CreateVerifiedAccessEndpointSubnetIdList] - Cidr: Optional[String] - PortRanges: Optional[CreateVerifiedAccessEndpointPortRangeList] + Protocol: VerifiedAccessEndpointProtocol | None + SubnetIds: CreateVerifiedAccessEndpointSubnetIdList | None + Cidr: String | None + PortRanges: CreateVerifiedAccessEndpointPortRangeList | None class CreateVerifiedAccessEndpointEniOptions(TypedDict, total=False): - NetworkInterfaceId: Optional[NetworkInterfaceId] - Protocol: Optional[VerifiedAccessEndpointProtocol] - Port: Optional[VerifiedAccessEndpointPortNumber] - PortRanges: Optional[CreateVerifiedAccessEndpointPortRangeList] + NetworkInterfaceId: NetworkInterfaceId | None + Protocol: VerifiedAccessEndpointProtocol | None + Port: VerifiedAccessEndpointPortNumber | None + PortRanges: CreateVerifiedAccessEndpointPortRangeList | None class CreateVerifiedAccessEndpointLoadBalancerOptions(TypedDict, total=False): - Protocol: Optional[VerifiedAccessEndpointProtocol] - Port: Optional[VerifiedAccessEndpointPortNumber] - LoadBalancerArn: Optional[LoadBalancerArn] - SubnetIds: Optional[CreateVerifiedAccessEndpointSubnetIdList] - PortRanges: Optional[CreateVerifiedAccessEndpointPortRangeList] + Protocol: VerifiedAccessEndpointProtocol | None + Port: VerifiedAccessEndpointPortNumber | None + LoadBalancerArn: LoadBalancerArn | None + SubnetIds: CreateVerifiedAccessEndpointSubnetIdList | None + PortRanges: CreateVerifiedAccessEndpointPortRangeList | None class CreateVerifiedAccessEndpointRdsOptions(TypedDict, total=False): - Protocol: Optional[VerifiedAccessEndpointProtocol] - Port: Optional[VerifiedAccessEndpointPortNumber] - RdsDbInstanceArn: Optional[RdsDbInstanceArn] - RdsDbClusterArn: Optional[RdsDbClusterArn] - RdsDbProxyArn: Optional[RdsDbProxyArn] - RdsEndpoint: Optional[String] - SubnetIds: Optional[CreateVerifiedAccessEndpointSubnetIdList] + Protocol: VerifiedAccessEndpointProtocol | None + Port: VerifiedAccessEndpointPortNumber | None + RdsDbInstanceArn: RdsDbInstanceArn | None + RdsDbClusterArn: RdsDbClusterArn | None + RdsDbProxyArn: RdsDbProxyArn | None + RdsEndpoint: String | None + SubnetIds: CreateVerifiedAccessEndpointSubnetIdList | None class VerifiedAccessSseSpecificationRequest(TypedDict, total=False): - CustomerManagedKeyEnabled: Optional[Boolean] - KmsKeyArn: Optional[KmsKeyArn] + CustomerManagedKeyEnabled: Boolean | None + KmsKeyArn: KmsKeyArn | None -SecurityGroupIdList = List[SecurityGroupId] +SecurityGroupIdList = list[SecurityGroupId] class CreateVerifiedAccessEndpointRequest(ServiceRequest): VerifiedAccessGroupId: VerifiedAccessGroupId EndpointType: VerifiedAccessEndpointType AttachmentType: VerifiedAccessEndpointAttachmentType - DomainCertificateArn: Optional[CertificateArn] - ApplicationDomain: Optional[String] - EndpointDomainPrefix: Optional[String] - SecurityGroupIds: Optional[SecurityGroupIdList] - LoadBalancerOptions: Optional[CreateVerifiedAccessEndpointLoadBalancerOptions] - NetworkInterfaceOptions: Optional[CreateVerifiedAccessEndpointEniOptions] - Description: Optional[String] - PolicyDocument: Optional[String] - TagSpecifications: Optional[TagSpecificationList] - ClientToken: Optional[String] - DryRun: Optional[Boolean] - SseSpecification: Optional[VerifiedAccessSseSpecificationRequest] - RdsOptions: Optional[CreateVerifiedAccessEndpointRdsOptions] - CidrOptions: Optional[CreateVerifiedAccessEndpointCidrOptions] + DomainCertificateArn: CertificateArn | None + ApplicationDomain: String | None + EndpointDomainPrefix: String | None + SecurityGroupIds: SecurityGroupIdList | None + LoadBalancerOptions: CreateVerifiedAccessEndpointLoadBalancerOptions | None + NetworkInterfaceOptions: CreateVerifiedAccessEndpointEniOptions | None + Description: String | None + PolicyDocument: String | None + TagSpecifications: TagSpecificationList | None + ClientToken: String | None + DryRun: Boolean | None + SseSpecification: VerifiedAccessSseSpecificationRequest | None + RdsOptions: CreateVerifiedAccessEndpointRdsOptions | None + CidrOptions: CreateVerifiedAccessEndpointCidrOptions | None -VerifiedAccessEndpointSubnetIdList = List[SubnetId] +VerifiedAccessEndpointSubnetIdList = list[SubnetId] class VerifiedAccessEndpointPortRange(TypedDict, total=False): - FromPort: Optional[VerifiedAccessEndpointPortNumber] - ToPort: Optional[VerifiedAccessEndpointPortNumber] + FromPort: VerifiedAccessEndpointPortNumber | None + ToPort: VerifiedAccessEndpointPortNumber | None -VerifiedAccessEndpointPortRangeList = List[VerifiedAccessEndpointPortRange] +VerifiedAccessEndpointPortRangeList = list[VerifiedAccessEndpointPortRange] class VerifiedAccessEndpointCidrOptions(TypedDict, total=False): - Cidr: Optional[String] - PortRanges: Optional[VerifiedAccessEndpointPortRangeList] - Protocol: Optional[VerifiedAccessEndpointProtocol] - SubnetIds: Optional[VerifiedAccessEndpointSubnetIdList] + Cidr: String | None + PortRanges: VerifiedAccessEndpointPortRangeList | None + Protocol: VerifiedAccessEndpointProtocol | None + SubnetIds: VerifiedAccessEndpointSubnetIdList | None class VerifiedAccessEndpointRdsOptions(TypedDict, total=False): - Protocol: Optional[VerifiedAccessEndpointProtocol] - Port: Optional[VerifiedAccessEndpointPortNumber] - RdsDbInstanceArn: Optional[String] - RdsDbClusterArn: Optional[String] - RdsDbProxyArn: Optional[String] - RdsEndpoint: Optional[String] - SubnetIds: Optional[VerifiedAccessEndpointSubnetIdList] + Protocol: VerifiedAccessEndpointProtocol | None + Port: VerifiedAccessEndpointPortNumber | None + RdsDbInstanceArn: String | None + RdsDbClusterArn: String | None + RdsDbProxyArn: String | None + RdsEndpoint: String | None + SubnetIds: VerifiedAccessEndpointSubnetIdList | None class VerifiedAccessEndpointStatus(TypedDict, total=False): - Code: Optional[VerifiedAccessEndpointStatusCode] - Message: Optional[String] + Code: VerifiedAccessEndpointStatusCode | None + Message: String | None class VerifiedAccessEndpointEniOptions(TypedDict, total=False): - NetworkInterfaceId: Optional[NetworkInterfaceId] - Protocol: Optional[VerifiedAccessEndpointProtocol] - Port: Optional[VerifiedAccessEndpointPortNumber] - PortRanges: Optional[VerifiedAccessEndpointPortRangeList] + NetworkInterfaceId: NetworkInterfaceId | None + Protocol: VerifiedAccessEndpointProtocol | None + Port: VerifiedAccessEndpointPortNumber | None + PortRanges: VerifiedAccessEndpointPortRangeList | None class VerifiedAccessEndpointLoadBalancerOptions(TypedDict, total=False): - Protocol: Optional[VerifiedAccessEndpointProtocol] - Port: Optional[VerifiedAccessEndpointPortNumber] - LoadBalancerArn: Optional[String] - SubnetIds: Optional[VerifiedAccessEndpointSubnetIdList] - PortRanges: Optional[VerifiedAccessEndpointPortRangeList] + Protocol: VerifiedAccessEndpointProtocol | None + Port: VerifiedAccessEndpointPortNumber | None + LoadBalancerArn: String | None + SubnetIds: VerifiedAccessEndpointSubnetIdList | None + PortRanges: VerifiedAccessEndpointPortRangeList | None class VerifiedAccessEndpoint(TypedDict, total=False): - VerifiedAccessInstanceId: Optional[String] - VerifiedAccessGroupId: Optional[String] - VerifiedAccessEndpointId: Optional[String] - ApplicationDomain: Optional[String] - EndpointType: Optional[VerifiedAccessEndpointType] - AttachmentType: Optional[VerifiedAccessEndpointAttachmentType] - DomainCertificateArn: Optional[String] - EndpointDomain: Optional[String] - DeviceValidationDomain: Optional[String] - SecurityGroupIds: Optional[SecurityGroupIdList] - LoadBalancerOptions: Optional[VerifiedAccessEndpointLoadBalancerOptions] - NetworkInterfaceOptions: Optional[VerifiedAccessEndpointEniOptions] - Status: Optional[VerifiedAccessEndpointStatus] - Description: Optional[String] - CreationTime: Optional[String] - LastUpdatedTime: Optional[String] - DeletionTime: Optional[String] - Tags: Optional[TagList] - SseSpecification: Optional[VerifiedAccessSseSpecificationResponse] - RdsOptions: Optional[VerifiedAccessEndpointRdsOptions] - CidrOptions: Optional[VerifiedAccessEndpointCidrOptions] + VerifiedAccessInstanceId: String | None + VerifiedAccessGroupId: String | None + VerifiedAccessEndpointId: String | None + ApplicationDomain: String | None + EndpointType: VerifiedAccessEndpointType | None + AttachmentType: VerifiedAccessEndpointAttachmentType | None + DomainCertificateArn: String | None + EndpointDomain: String | None + DeviceValidationDomain: String | None + SecurityGroupIds: SecurityGroupIdList | None + LoadBalancerOptions: VerifiedAccessEndpointLoadBalancerOptions | None + NetworkInterfaceOptions: VerifiedAccessEndpointEniOptions | None + Status: VerifiedAccessEndpointStatus | None + Description: String | None + CreationTime: String | None + LastUpdatedTime: String | None + DeletionTime: String | None + Tags: TagList | None + SseSpecification: VerifiedAccessSseSpecificationResponse | None + RdsOptions: VerifiedAccessEndpointRdsOptions | None + CidrOptions: VerifiedAccessEndpointCidrOptions | None class CreateVerifiedAccessEndpointResult(TypedDict, total=False): - VerifiedAccessEndpoint: Optional[VerifiedAccessEndpoint] + VerifiedAccessEndpoint: VerifiedAccessEndpoint | None class CreateVerifiedAccessGroupRequest(ServiceRequest): VerifiedAccessInstanceId: VerifiedAccessInstanceId - Description: Optional[String] - PolicyDocument: Optional[String] - TagSpecifications: Optional[TagSpecificationList] - ClientToken: Optional[String] - DryRun: Optional[Boolean] - SseSpecification: Optional[VerifiedAccessSseSpecificationRequest] + Description: String | None + PolicyDocument: String | None + TagSpecifications: TagSpecificationList | None + ClientToken: String | None + DryRun: Boolean | None + SseSpecification: VerifiedAccessSseSpecificationRequest | None class VerifiedAccessGroup(TypedDict, total=False): - VerifiedAccessGroupId: Optional[String] - VerifiedAccessInstanceId: Optional[String] - Description: Optional[String] - Owner: Optional[String] - VerifiedAccessGroupArn: Optional[String] - CreationTime: Optional[String] - LastUpdatedTime: Optional[String] - DeletionTime: Optional[String] - Tags: Optional[TagList] - SseSpecification: Optional[VerifiedAccessSseSpecificationResponse] + VerifiedAccessGroupId: String | None + VerifiedAccessInstanceId: String | None + Description: String | None + Owner: String | None + VerifiedAccessGroupArn: String | None + CreationTime: String | None + LastUpdatedTime: String | None + DeletionTime: String | None + Tags: TagList | None + SseSpecification: VerifiedAccessSseSpecificationResponse | None class CreateVerifiedAccessGroupResult(TypedDict, total=False): - VerifiedAccessGroup: Optional[VerifiedAccessGroup] + VerifiedAccessGroup: VerifiedAccessGroup | None class CreateVerifiedAccessInstanceRequest(ServiceRequest): - Description: Optional[String] - TagSpecifications: Optional[TagSpecificationList] - ClientToken: Optional[String] - DryRun: Optional[Boolean] - FIPSEnabled: Optional[Boolean] - CidrEndpointsCustomSubDomain: Optional[String] + Description: String | None + TagSpecifications: TagSpecificationList | None + ClientToken: String | None + DryRun: Boolean | None + FIPSEnabled: Boolean | None + CidrEndpointsCustomSubDomain: String | None class CreateVerifiedAccessInstanceResult(TypedDict, total=False): - VerifiedAccessInstance: Optional[VerifiedAccessInstance] + VerifiedAccessInstance: VerifiedAccessInstance | None class CreateVerifiedAccessNativeApplicationOidcOptions(TypedDict, total=False): - PublicSigningKeyEndpoint: Optional[String] - Issuer: Optional[String] - AuthorizationEndpoint: Optional[String] - TokenEndpoint: Optional[String] - UserInfoEndpoint: Optional[String] - ClientId: Optional[String] - ClientSecret: Optional[ClientSecretType] - Scope: Optional[String] + PublicSigningKeyEndpoint: String | None + Issuer: String | None + AuthorizationEndpoint: String | None + TokenEndpoint: String | None + UserInfoEndpoint: String | None + ClientId: String | None + ClientSecret: ClientSecretType | None + Scope: String | None class CreateVerifiedAccessTrustProviderDeviceOptions(TypedDict, total=False): - TenantId: Optional[String] - PublicSigningKeyUrl: Optional[String] + TenantId: String | None + PublicSigningKeyUrl: String | None class CreateVerifiedAccessTrustProviderOidcOptions(TypedDict, total=False): - Issuer: Optional[String] - AuthorizationEndpoint: Optional[String] - TokenEndpoint: Optional[String] - UserInfoEndpoint: Optional[String] - ClientId: Optional[String] - ClientSecret: Optional[ClientSecretType] - Scope: Optional[String] + Issuer: String | None + AuthorizationEndpoint: String | None + TokenEndpoint: String | None + UserInfoEndpoint: String | None + ClientId: String | None + ClientSecret: ClientSecretType | None + Scope: String | None class CreateVerifiedAccessTrustProviderRequest(ServiceRequest): TrustProviderType: TrustProviderType - UserTrustProviderType: Optional[UserTrustProviderType] - DeviceTrustProviderType: Optional[DeviceTrustProviderType] - OidcOptions: Optional[CreateVerifiedAccessTrustProviderOidcOptions] - DeviceOptions: Optional[CreateVerifiedAccessTrustProviderDeviceOptions] + UserTrustProviderType: UserTrustProviderType | None + DeviceTrustProviderType: DeviceTrustProviderType | None + OidcOptions: CreateVerifiedAccessTrustProviderOidcOptions | None + DeviceOptions: CreateVerifiedAccessTrustProviderDeviceOptions | None PolicyReferenceName: String - Description: Optional[String] - TagSpecifications: Optional[TagSpecificationList] - ClientToken: Optional[String] - DryRun: Optional[Boolean] - SseSpecification: Optional[VerifiedAccessSseSpecificationRequest] - NativeApplicationOidcOptions: Optional[CreateVerifiedAccessNativeApplicationOidcOptions] + Description: String | None + TagSpecifications: TagSpecificationList | None + ClientToken: String | None + DryRun: Boolean | None + SseSpecification: VerifiedAccessSseSpecificationRequest | None + NativeApplicationOidcOptions: CreateVerifiedAccessNativeApplicationOidcOptions | None class CreateVerifiedAccessTrustProviderResult(TypedDict, total=False): - VerifiedAccessTrustProvider: Optional[VerifiedAccessTrustProvider] + VerifiedAccessTrustProvider: VerifiedAccessTrustProvider | None class CreateVolumePermission(TypedDict, total=False): - UserId: Optional[String] - Group: Optional[PermissionGroup] + UserId: String | None + Group: PermissionGroup | None -CreateVolumePermissionList = List[CreateVolumePermission] +CreateVolumePermissionList = list[CreateVolumePermission] class CreateVolumePermissionModifications(TypedDict, total=False): - Add: Optional[CreateVolumePermissionList] - Remove: Optional[CreateVolumePermissionList] + Add: CreateVolumePermissionList | None + Remove: CreateVolumePermissionList | None class CreateVolumeRequest(ServiceRequest): - AvailabilityZone: Optional[AvailabilityZoneName] - AvailabilityZoneId: Optional[AvailabilityZoneId] - Encrypted: Optional[Boolean] - Iops: Optional[Integer] - KmsKeyId: Optional[KmsKeyId] - OutpostArn: Optional[String] - Size: Optional[Integer] - SnapshotId: Optional[SnapshotId] - VolumeType: Optional[VolumeType] - TagSpecifications: Optional[TagSpecificationList] - MultiAttachEnabled: Optional[Boolean] - Throughput: Optional[Integer] - ClientToken: Optional[String] - VolumeInitializationRate: Optional[Integer] - Operator: Optional[OperatorRequest] - DryRun: Optional[Boolean] + AvailabilityZone: AvailabilityZoneName | None + AvailabilityZoneId: AvailabilityZoneId | None + Encrypted: Boolean | None + Iops: Integer | None + KmsKeyId: KmsKeyId | None + OutpostArn: String | None + Size: Integer | None + SnapshotId: SnapshotId | None + VolumeType: VolumeType | None + TagSpecifications: TagSpecificationList | None + MultiAttachEnabled: Boolean | None + Throughput: Integer | None + ClientToken: String | None + VolumeInitializationRate: Integer | None + Operator: OperatorRequest | None + DryRun: Boolean | None class CreateVpcBlockPublicAccessExclusionRequest(ServiceRequest): - DryRun: Optional[Boolean] - SubnetId: Optional[SubnetId] - VpcId: Optional[VpcId] + DryRun: Boolean | None + SubnetId: SubnetId | None + VpcId: VpcId | None InternetGatewayExclusionMode: InternetGatewayExclusionMode - TagSpecifications: Optional[TagSpecificationList] + TagSpecifications: TagSpecificationList | None class VpcBlockPublicAccessExclusion(TypedDict, total=False): - ExclusionId: Optional[VpcBlockPublicAccessExclusionId] - InternetGatewayExclusionMode: Optional[InternetGatewayExclusionMode] - ResourceArn: Optional[ResourceArn] - State: Optional[VpcBlockPublicAccessExclusionState] - Reason: Optional[String] - CreationTimestamp: Optional[MillisecondDateTime] - LastUpdateTimestamp: Optional[MillisecondDateTime] - DeletionTimestamp: Optional[MillisecondDateTime] - Tags: Optional[TagList] + ExclusionId: VpcBlockPublicAccessExclusionId | None + InternetGatewayExclusionMode: InternetGatewayExclusionMode | None + ResourceArn: ResourceArn | None + State: VpcBlockPublicAccessExclusionState | None + Reason: String | None + CreationTimestamp: MillisecondDateTime | None + LastUpdateTimestamp: MillisecondDateTime | None + DeletionTimestamp: MillisecondDateTime | None + Tags: TagList | None class CreateVpcBlockPublicAccessExclusionResult(TypedDict, total=False): - VpcBlockPublicAccessExclusion: Optional[VpcBlockPublicAccessExclusion] + VpcBlockPublicAccessExclusion: VpcBlockPublicAccessExclusion | None + + +class CreateVpcEncryptionControlRequest(ServiceRequest): + DryRun: Boolean | None + VpcId: VpcId + TagSpecifications: TagSpecificationList | None + + +class CreateVpcEncryptionControlResult(TypedDict, total=False): + VpcEncryptionControl: VpcEncryptionControl | None class CreateVpcEndpointConnectionNotificationRequest(ServiceRequest): - DryRun: Optional[Boolean] - ServiceId: Optional[VpcEndpointServiceId] - VpcEndpointId: Optional[VpcEndpointId] + DryRun: Boolean | None + ServiceId: VpcEndpointServiceId | None + VpcEndpointId: VpcEndpointId | None ConnectionNotificationArn: String ConnectionEvents: ValueStringList - ClientToken: Optional[String] + ClientToken: String | None class CreateVpcEndpointConnectionNotificationResult(TypedDict, total=False): - ConnectionNotification: Optional[ConnectionNotification] - ClientToken: Optional[String] + ConnectionNotification: ConnectionNotification | None + ClientToken: String | None class SubnetConfiguration(TypedDict, total=False): - SubnetId: Optional[SubnetId] - Ipv4: Optional[String] - Ipv6: Optional[String] + SubnetId: SubnetId | None + Ipv4: String | None + Ipv6: String | None -SubnetConfigurationsList = List[SubnetConfiguration] +SubnetConfigurationsList = list[SubnetConfiguration] +PrivateDnsSpecifiedDomainSet = list[String] class DnsOptionsSpecification(TypedDict, total=False): - DnsRecordIpType: Optional[DnsRecordIpType] - PrivateDnsOnlyForInboundResolverEndpoint: Optional[Boolean] + DnsRecordIpType: DnsRecordIpType | None + PrivateDnsOnlyForInboundResolverEndpoint: Boolean | None + PrivateDnsPreference: String | None + PrivateDnsSpecifiedDomains: PrivateDnsSpecifiedDomainSet | None -VpcEndpointSecurityGroupIdList = List[SecurityGroupId] -VpcEndpointSubnetIdList = List[SubnetId] -VpcEndpointRouteTableIdList = List[RouteTableId] +VpcEndpointSecurityGroupIdList = list[SecurityGroupId] +VpcEndpointSubnetIdList = list[SubnetId] +VpcEndpointRouteTableIdList = list[RouteTableId] class CreateVpcEndpointRequest(ServiceRequest): - DryRun: Optional[Boolean] - VpcEndpointType: Optional[VpcEndpointType] + DryRun: Boolean | None + VpcEndpointType: VpcEndpointType | None VpcId: VpcId - ServiceName: Optional[String] - PolicyDocument: Optional[String] - RouteTableIds: Optional[VpcEndpointRouteTableIdList] - SubnetIds: Optional[VpcEndpointSubnetIdList] - SecurityGroupIds: Optional[VpcEndpointSecurityGroupIdList] - IpAddressType: Optional[IpAddressType] - DnsOptions: Optional[DnsOptionsSpecification] - ClientToken: Optional[String] - PrivateDnsEnabled: Optional[Boolean] - TagSpecifications: Optional[TagSpecificationList] - SubnetConfigurations: Optional[SubnetConfigurationsList] - ServiceNetworkArn: Optional[ServiceNetworkArn] - ResourceConfigurationArn: Optional[ResourceConfigurationArn] - ServiceRegion: Optional[String] + ServiceName: String | None + PolicyDocument: String | None + RouteTableIds: VpcEndpointRouteTableIdList | None + SubnetIds: VpcEndpointSubnetIdList | None + SecurityGroupIds: VpcEndpointSecurityGroupIdList | None + IpAddressType: IpAddressType | None + DnsOptions: DnsOptionsSpecification | None + ClientToken: String | None + PrivateDnsEnabled: Boolean | None + TagSpecifications: TagSpecificationList | None + SubnetConfigurations: SubnetConfigurationsList | None + ServiceNetworkArn: ServiceNetworkArn | None + ResourceConfigurationArn: ResourceConfigurationArn | None + ServiceRegion: String | None class SubnetIpPrefixes(TypedDict, total=False): - SubnetId: Optional[String] - IpPrefixes: Optional[ValueStringList] + SubnetId: String | None + IpPrefixes: ValueStringList | None -SubnetIpPrefixesList = List[SubnetIpPrefixes] +SubnetIpPrefixesList = list[SubnetIpPrefixes] class LastError(TypedDict, total=False): - Message: Optional[String] - Code: Optional[String] + Message: String | None + Code: String | None class DnsEntry(TypedDict, total=False): - DnsName: Optional[String] - HostedZoneId: Optional[String] + DnsName: String | None + HostedZoneId: String | None -DnsEntrySet = List[DnsEntry] +DnsEntrySet = list[DnsEntry] class DnsOptions(TypedDict, total=False): - DnsRecordIpType: Optional[DnsRecordIpType] - PrivateDnsOnlyForInboundResolverEndpoint: Optional[Boolean] + DnsRecordIpType: DnsRecordIpType | None + PrivateDnsOnlyForInboundResolverEndpoint: Boolean | None + PrivateDnsPreference: String | None + PrivateDnsSpecifiedDomains: PrivateDnsSpecifiedDomainSet | None class SecurityGroupIdentifier(TypedDict, total=False): - GroupId: Optional[String] - GroupName: Optional[String] + GroupId: String | None + GroupName: String | None -GroupIdentifierSet = List[SecurityGroupIdentifier] +GroupIdentifierSet = list[SecurityGroupIdentifier] class VpcEndpoint(TypedDict, total=False): - VpcEndpointId: Optional[String] - VpcEndpointType: Optional[VpcEndpointType] - VpcId: Optional[String] - ServiceName: Optional[String] - State: Optional[State] - PolicyDocument: Optional[String] - RouteTableIds: Optional[ValueStringList] - SubnetIds: Optional[ValueStringList] - Groups: Optional[GroupIdentifierSet] - IpAddressType: Optional[IpAddressType] - DnsOptions: Optional[DnsOptions] - PrivateDnsEnabled: Optional[Boolean] - RequesterManaged: Optional[Boolean] - NetworkInterfaceIds: Optional[ValueStringList] - DnsEntries: Optional[DnsEntrySet] - CreationTimestamp: Optional[MillisecondDateTime] - Tags: Optional[TagList] - OwnerId: Optional[String] - LastError: Optional[LastError] - Ipv4Prefixes: Optional[SubnetIpPrefixesList] - Ipv6Prefixes: Optional[SubnetIpPrefixesList] - FailureReason: Optional[String] - ServiceNetworkArn: Optional[ServiceNetworkArn] - ResourceConfigurationArn: Optional[ResourceConfigurationArn] - ServiceRegion: Optional[String] + VpcEndpointId: String | None + VpcEndpointType: VpcEndpointType | None + VpcId: String | None + ServiceName: String | None + State: State | None + PolicyDocument: String | None + RouteTableIds: ValueStringList | None + SubnetIds: ValueStringList | None + Groups: GroupIdentifierSet | None + IpAddressType: IpAddressType | None + DnsOptions: DnsOptions | None + PrivateDnsEnabled: Boolean | None + RequesterManaged: Boolean | None + NetworkInterfaceIds: ValueStringList | None + DnsEntries: DnsEntrySet | None + CreationTimestamp: MillisecondDateTime | None + Tags: TagList | None + OwnerId: String | None + LastError: LastError | None + Ipv4Prefixes: SubnetIpPrefixesList | None + Ipv6Prefixes: SubnetIpPrefixesList | None + FailureReason: String | None + ServiceNetworkArn: ServiceNetworkArn | None + ResourceConfigurationArn: ResourceConfigurationArn | None + ServiceRegion: String | None class CreateVpcEndpointResult(TypedDict, total=False): - VpcEndpoint: Optional[VpcEndpoint] - ClientToken: Optional[String] + VpcEndpoint: VpcEndpoint | None + ClientToken: String | None class CreateVpcEndpointServiceConfigurationRequest(ServiceRequest): - DryRun: Optional[Boolean] - AcceptanceRequired: Optional[Boolean] - PrivateDnsName: Optional[String] - NetworkLoadBalancerArns: Optional[ValueStringList] - GatewayLoadBalancerArns: Optional[ValueStringList] - SupportedIpAddressTypes: Optional[ValueStringList] - SupportedRegions: Optional[ValueStringList] - ClientToken: Optional[String] - TagSpecifications: Optional[TagSpecificationList] + DryRun: Boolean | None + AcceptanceRequired: Boolean | None + PrivateDnsName: String | None + NetworkLoadBalancerArns: ValueStringList | None + GatewayLoadBalancerArns: ValueStringList | None + SupportedIpAddressTypes: ValueStringList | None + SupportedRegions: ValueStringList | None + ClientToken: String | None + TagSpecifications: TagSpecificationList | None class SupportedRegionDetail(TypedDict, total=False): - Region: Optional[String] - ServiceState: Optional[String] + Region: String | None + ServiceState: String | None -SupportedRegionSet = List[SupportedRegionDetail] +SupportedRegionSet = list[SupportedRegionDetail] class PrivateDnsNameConfiguration(TypedDict, total=False): - State: Optional[DnsNameState] - Type: Optional[String] - Value: Optional[String] - Name: Optional[String] + State: DnsNameState | None + Type: String | None + Value: String | None + Name: String | None -SupportedIpAddressTypes = List[ServiceConnectivityType] +SupportedIpAddressTypes = list[ServiceConnectivityType] class ServiceTypeDetail(TypedDict, total=False): - ServiceType: Optional[ServiceType] + ServiceType: ServiceType | None -ServiceTypeDetailSet = List[ServiceTypeDetail] +ServiceTypeDetailSet = list[ServiceTypeDetail] class ServiceConfiguration(TypedDict, total=False): - ServiceType: Optional[ServiceTypeDetailSet] - ServiceId: Optional[String] - ServiceName: Optional[String] - ServiceState: Optional[ServiceState] - AvailabilityZoneIds: Optional[ValueStringList] - AvailabilityZones: Optional[ValueStringList] - AcceptanceRequired: Optional[Boolean] - ManagesVpcEndpoints: Optional[Boolean] - NetworkLoadBalancerArns: Optional[ValueStringList] - GatewayLoadBalancerArns: Optional[ValueStringList] - SupportedIpAddressTypes: Optional[SupportedIpAddressTypes] - BaseEndpointDnsNames: Optional[ValueStringList] - PrivateDnsName: Optional[String] - PrivateDnsNameConfiguration: Optional[PrivateDnsNameConfiguration] - PayerResponsibility: Optional[PayerResponsibility] - Tags: Optional[TagList] - SupportedRegions: Optional[SupportedRegionSet] - RemoteAccessEnabled: Optional[Boolean] + ServiceType: ServiceTypeDetailSet | None + ServiceId: String | None + ServiceName: String | None + ServiceState: ServiceState | None + AvailabilityZoneIds: ValueStringList | None + AvailabilityZones: ValueStringList | None + AcceptanceRequired: Boolean | None + ManagesVpcEndpoints: Boolean | None + NetworkLoadBalancerArns: ValueStringList | None + GatewayLoadBalancerArns: ValueStringList | None + SupportedIpAddressTypes: SupportedIpAddressTypes | None + BaseEndpointDnsNames: ValueStringList | None + PrivateDnsName: String | None + PrivateDnsNameConfiguration: PrivateDnsNameConfiguration | None + PayerResponsibility: PayerResponsibility | None + Tags: TagList | None + SupportedRegions: SupportedRegionSet | None + RemoteAccessEnabled: Boolean | None class CreateVpcEndpointServiceConfigurationResult(TypedDict, total=False): - ServiceConfiguration: Optional[ServiceConfiguration] - ClientToken: Optional[String] + ServiceConfiguration: ServiceConfiguration | None + ClientToken: String | None class CreateVpcPeeringConnectionRequest(ServiceRequest): - PeerRegion: Optional[String] - TagSpecifications: Optional[TagSpecificationList] - DryRun: Optional[Boolean] + PeerRegion: String | None + TagSpecifications: TagSpecificationList | None + DryRun: Boolean | None VpcId: VpcId - PeerVpcId: Optional[String] - PeerOwnerId: Optional[String] + PeerVpcId: String | None + PeerOwnerId: String | None class CreateVpcPeeringConnectionResult(TypedDict, total=False): - VpcPeeringConnection: Optional[VpcPeeringConnection] + VpcPeeringConnection: VpcPeeringConnection | None + + +class VpcEncryptionControlConfiguration(TypedDict, total=False): + Mode: VpcEncryptionControlMode + InternetGatewayExclusion: VpcEncryptionControlExclusionStateInput | None + EgressOnlyInternetGatewayExclusion: VpcEncryptionControlExclusionStateInput | None + NatGatewayExclusion: VpcEncryptionControlExclusionStateInput | None + VirtualPrivateGatewayExclusion: VpcEncryptionControlExclusionStateInput | None + VpcPeeringExclusion: VpcEncryptionControlExclusionStateInput | None + LambdaExclusion: VpcEncryptionControlExclusionStateInput | None + VpcLatticeExclusion: VpcEncryptionControlExclusionStateInput | None + ElasticFileSystemExclusion: VpcEncryptionControlExclusionStateInput | None class CreateVpcRequest(ServiceRequest): - CidrBlock: Optional[String] - Ipv6Pool: Optional[Ipv6PoolEc2Id] - Ipv6CidrBlock: Optional[String] - Ipv4IpamPoolId: Optional[IpamPoolId] - Ipv4NetmaskLength: Optional[NetmaskLength] - Ipv6IpamPoolId: Optional[IpamPoolId] - Ipv6NetmaskLength: Optional[NetmaskLength] - Ipv6CidrBlockNetworkBorderGroup: Optional[String] - TagSpecifications: Optional[TagSpecificationList] - DryRun: Optional[Boolean] - InstanceTenancy: Optional[Tenancy] - AmazonProvidedIpv6CidrBlock: Optional[Boolean] + CidrBlock: String | None + Ipv6Pool: Ipv6PoolEc2Id | None + Ipv6CidrBlock: String | None + Ipv4IpamPoolId: IpamPoolId | None + Ipv4NetmaskLength: NetmaskLength | None + Ipv6IpamPoolId: IpamPoolId | None + Ipv6NetmaskLength: NetmaskLength | None + Ipv6CidrBlockNetworkBorderGroup: String | None + VpcEncryptionControl: VpcEncryptionControlConfiguration | None + TagSpecifications: TagSpecificationList | None + DryRun: Boolean | None + InstanceTenancy: Tenancy | None + AmazonProvidedIpv6CidrBlock: Boolean | None class CreateVpcResult(TypedDict, total=False): - Vpc: Optional[Vpc] + Vpc: Vpc | None + + +class CreateVpnConcentratorRequest(ServiceRequest): + Type: VpnConcentratorType + TransitGatewayId: TransitGatewayId | None + TagSpecifications: TagSpecificationList | None + DryRun: Boolean | None + + +class VpnConcentrator(TypedDict, total=False): + VpnConcentratorId: String | None + State: String | None + TransitGatewayId: String | None + TransitGatewayAttachmentId: String | None + Type: String | None + Tags: TagList | None + + +class CreateVpnConcentratorResult(TypedDict, total=False): + VpnConcentrator: VpnConcentrator | None class VpnTunnelLogOptionsSpecification(TypedDict, total=False): - CloudWatchLogOptions: Optional[CloudWatchLogOptionsSpecification] + CloudWatchLogOptions: CloudWatchLogOptionsSpecification | None class IKEVersionsRequestListValue(TypedDict, total=False): - Value: Optional[String] + Value: String | None -IKEVersionsRequestList = List[IKEVersionsRequestListValue] +IKEVersionsRequestList = list[IKEVersionsRequestListValue] class Phase2DHGroupNumbersRequestListValue(TypedDict, total=False): - Value: Optional[Integer] + Value: Integer | None -Phase2DHGroupNumbersRequestList = List[Phase2DHGroupNumbersRequestListValue] +Phase2DHGroupNumbersRequestList = list[Phase2DHGroupNumbersRequestListValue] class Phase1DHGroupNumbersRequestListValue(TypedDict, total=False): - Value: Optional[Integer] + Value: Integer | None -Phase1DHGroupNumbersRequestList = List[Phase1DHGroupNumbersRequestListValue] +Phase1DHGroupNumbersRequestList = list[Phase1DHGroupNumbersRequestListValue] class Phase2IntegrityAlgorithmsRequestListValue(TypedDict, total=False): - Value: Optional[String] + Value: String | None -Phase2IntegrityAlgorithmsRequestList = List[Phase2IntegrityAlgorithmsRequestListValue] +Phase2IntegrityAlgorithmsRequestList = list[Phase2IntegrityAlgorithmsRequestListValue] class Phase1IntegrityAlgorithmsRequestListValue(TypedDict, total=False): - Value: Optional[String] + Value: String | None -Phase1IntegrityAlgorithmsRequestList = List[Phase1IntegrityAlgorithmsRequestListValue] +Phase1IntegrityAlgorithmsRequestList = list[Phase1IntegrityAlgorithmsRequestListValue] class Phase2EncryptionAlgorithmsRequestListValue(TypedDict, total=False): - Value: Optional[String] + Value: String | None -Phase2EncryptionAlgorithmsRequestList = List[Phase2EncryptionAlgorithmsRequestListValue] +Phase2EncryptionAlgorithmsRequestList = list[Phase2EncryptionAlgorithmsRequestListValue] class Phase1EncryptionAlgorithmsRequestListValue(TypedDict, total=False): - Value: Optional[String] + Value: String | None -Phase1EncryptionAlgorithmsRequestList = List[Phase1EncryptionAlgorithmsRequestListValue] +Phase1EncryptionAlgorithmsRequestList = list[Phase1EncryptionAlgorithmsRequestListValue] class VpnTunnelOptionsSpecification(TypedDict, total=False): - TunnelInsideCidr: Optional[String] - TunnelInsideIpv6Cidr: Optional[String] - PreSharedKey: Optional[preSharedKey] - Phase1LifetimeSeconds: Optional[Integer] - Phase2LifetimeSeconds: Optional[Integer] - RekeyMarginTimeSeconds: Optional[Integer] - RekeyFuzzPercentage: Optional[Integer] - ReplayWindowSize: Optional[Integer] - DPDTimeoutSeconds: Optional[Integer] - DPDTimeoutAction: Optional[String] - Phase1EncryptionAlgorithms: Optional[Phase1EncryptionAlgorithmsRequestList] - Phase2EncryptionAlgorithms: Optional[Phase2EncryptionAlgorithmsRequestList] - Phase1IntegrityAlgorithms: Optional[Phase1IntegrityAlgorithmsRequestList] - Phase2IntegrityAlgorithms: Optional[Phase2IntegrityAlgorithmsRequestList] - Phase1DHGroupNumbers: Optional[Phase1DHGroupNumbersRequestList] - Phase2DHGroupNumbers: Optional[Phase2DHGroupNumbersRequestList] - IKEVersions: Optional[IKEVersionsRequestList] - StartupAction: Optional[String] - LogOptions: Optional[VpnTunnelLogOptionsSpecification] - EnableTunnelLifecycleControl: Optional[Boolean] - - -VpnTunnelOptionsSpecificationsList = List[VpnTunnelOptionsSpecification] + TunnelInsideCidr: String | None + TunnelInsideIpv6Cidr: String | None + PreSharedKey: preSharedKey | None + Phase1LifetimeSeconds: Integer | None + Phase2LifetimeSeconds: Integer | None + RekeyMarginTimeSeconds: Integer | None + RekeyFuzzPercentage: Integer | None + ReplayWindowSize: Integer | None + DPDTimeoutSeconds: Integer | None + DPDTimeoutAction: String | None + Phase1EncryptionAlgorithms: Phase1EncryptionAlgorithmsRequestList | None + Phase2EncryptionAlgorithms: Phase2EncryptionAlgorithmsRequestList | None + Phase1IntegrityAlgorithms: Phase1IntegrityAlgorithmsRequestList | None + Phase2IntegrityAlgorithms: Phase2IntegrityAlgorithmsRequestList | None + Phase1DHGroupNumbers: Phase1DHGroupNumbersRequestList | None + Phase2DHGroupNumbers: Phase2DHGroupNumbersRequestList | None + IKEVersions: IKEVersionsRequestList | None + StartupAction: String | None + LogOptions: VpnTunnelLogOptionsSpecification | None + EnableTunnelLifecycleControl: Boolean | None + + +VpnTunnelOptionsSpecificationsList = list[VpnTunnelOptionsSpecification] class VpnConnectionOptionsSpecification(TypedDict, total=False): - EnableAcceleration: Optional[Boolean] - TunnelInsideIpVersion: Optional[TunnelInsideIpVersion] - TunnelOptions: Optional[VpnTunnelOptionsSpecificationsList] - LocalIpv4NetworkCidr: Optional[String] - RemoteIpv4NetworkCidr: Optional[String] - LocalIpv6NetworkCidr: Optional[String] - RemoteIpv6NetworkCidr: Optional[String] - OutsideIpAddressType: Optional[String] - TransportTransitGatewayAttachmentId: Optional[TransitGatewayAttachmentId] - StaticRoutesOnly: Optional[Boolean] + EnableAcceleration: Boolean | None + TunnelInsideIpVersion: TunnelInsideIpVersion | None + TunnelOptions: VpnTunnelOptionsSpecificationsList | None + LocalIpv4NetworkCidr: String | None + RemoteIpv4NetworkCidr: String | None + LocalIpv6NetworkCidr: String | None + RemoteIpv6NetworkCidr: String | None + OutsideIpAddressType: String | None + TransportTransitGatewayAttachmentId: TransitGatewayAttachmentId | None + TunnelBandwidth: VpnTunnelBandwidth | None + StaticRoutesOnly: Boolean | None class CreateVpnConnectionRequest(ServiceRequest): CustomerGatewayId: CustomerGatewayId Type: String - VpnGatewayId: Optional[VpnGatewayId] - TransitGatewayId: Optional[TransitGatewayId] - TagSpecifications: Optional[TagSpecificationList] - PreSharedKeyStorage: Optional[String] - DryRun: Optional[Boolean] - Options: Optional[VpnConnectionOptionsSpecification] + VpnGatewayId: VpnGatewayId | None + TransitGatewayId: TransitGatewayId | None + VpnConcentratorId: VpnConcentratorId | None + TagSpecifications: TagSpecificationList | None + PreSharedKeyStorage: String | None + DryRun: Boolean | None + Options: VpnConnectionOptionsSpecification | None class VgwTelemetry(TypedDict, total=False): - AcceptedRouteCount: Optional[Integer] - LastStatusChange: Optional[DateTime] - OutsideIpAddress: Optional[String] - Status: Optional[TelemetryStatus] - StatusMessage: Optional[String] - CertificateArn: Optional[String] + AcceptedRouteCount: Integer | None + LastStatusChange: DateTime | None + OutsideIpAddress: String | None + Status: TelemetryStatus | None + StatusMessage: String | None + CertificateArn: String | None -VgwTelemetryList = List[VgwTelemetry] +VgwTelemetryList = list[VgwTelemetry] class VpnStaticRoute(TypedDict, total=False): - DestinationCidrBlock: Optional[String] - Source: Optional[VpnStaticRouteSource] - State: Optional[VpnState] + DestinationCidrBlock: String | None + Source: VpnStaticRouteSource | None + State: VpnState | None -VpnStaticRouteList = List[VpnStaticRoute] +VpnStaticRouteList = list[VpnStaticRoute] class VpnTunnelLogOptions(TypedDict, total=False): - CloudWatchLogOptions: Optional[CloudWatchLogOptions] + CloudWatchLogOptions: CloudWatchLogOptions | None class IKEVersionsListValue(TypedDict, total=False): - Value: Optional[String] + Value: String | None -IKEVersionsList = List[IKEVersionsListValue] +IKEVersionsList = list[IKEVersionsListValue] class Phase2DHGroupNumbersListValue(TypedDict, total=False): - Value: Optional[Integer] + Value: Integer | None -Phase2DHGroupNumbersList = List[Phase2DHGroupNumbersListValue] +Phase2DHGroupNumbersList = list[Phase2DHGroupNumbersListValue] class Phase1DHGroupNumbersListValue(TypedDict, total=False): - Value: Optional[Integer] + Value: Integer | None -Phase1DHGroupNumbersList = List[Phase1DHGroupNumbersListValue] +Phase1DHGroupNumbersList = list[Phase1DHGroupNumbersListValue] class Phase2IntegrityAlgorithmsListValue(TypedDict, total=False): - Value: Optional[String] + Value: String | None -Phase2IntegrityAlgorithmsList = List[Phase2IntegrityAlgorithmsListValue] +Phase2IntegrityAlgorithmsList = list[Phase2IntegrityAlgorithmsListValue] class Phase1IntegrityAlgorithmsListValue(TypedDict, total=False): - Value: Optional[String] + Value: String | None -Phase1IntegrityAlgorithmsList = List[Phase1IntegrityAlgorithmsListValue] +Phase1IntegrityAlgorithmsList = list[Phase1IntegrityAlgorithmsListValue] class Phase2EncryptionAlgorithmsListValue(TypedDict, total=False): - Value: Optional[String] + Value: String | None -Phase2EncryptionAlgorithmsList = List[Phase2EncryptionAlgorithmsListValue] +Phase2EncryptionAlgorithmsList = list[Phase2EncryptionAlgorithmsListValue] class Phase1EncryptionAlgorithmsListValue(TypedDict, total=False): - Value: Optional[String] + Value: String | None -Phase1EncryptionAlgorithmsList = List[Phase1EncryptionAlgorithmsListValue] +Phase1EncryptionAlgorithmsList = list[Phase1EncryptionAlgorithmsListValue] class TunnelOption(TypedDict, total=False): - OutsideIpAddress: Optional[String] - TunnelInsideCidr: Optional[String] - TunnelInsideIpv6Cidr: Optional[String] - PreSharedKey: Optional[preSharedKey] - Phase1LifetimeSeconds: Optional[Integer] - Phase2LifetimeSeconds: Optional[Integer] - RekeyMarginTimeSeconds: Optional[Integer] - RekeyFuzzPercentage: Optional[Integer] - ReplayWindowSize: Optional[Integer] - DpdTimeoutSeconds: Optional[Integer] - DpdTimeoutAction: Optional[String] - Phase1EncryptionAlgorithms: Optional[Phase1EncryptionAlgorithmsList] - Phase2EncryptionAlgorithms: Optional[Phase2EncryptionAlgorithmsList] - Phase1IntegrityAlgorithms: Optional[Phase1IntegrityAlgorithmsList] - Phase2IntegrityAlgorithms: Optional[Phase2IntegrityAlgorithmsList] - Phase1DHGroupNumbers: Optional[Phase1DHGroupNumbersList] - Phase2DHGroupNumbers: Optional[Phase2DHGroupNumbersList] - IkeVersions: Optional[IKEVersionsList] - StartupAction: Optional[String] - LogOptions: Optional[VpnTunnelLogOptions] - EnableTunnelLifecycleControl: Optional[Boolean] - - -TunnelOptionsList = List[TunnelOption] + OutsideIpAddress: String | None + TunnelInsideCidr: String | None + TunnelInsideIpv6Cidr: String | None + PreSharedKey: preSharedKey | None + Phase1LifetimeSeconds: Integer | None + Phase2LifetimeSeconds: Integer | None + RekeyMarginTimeSeconds: Integer | None + RekeyFuzzPercentage: Integer | None + ReplayWindowSize: Integer | None + DpdTimeoutSeconds: Integer | None + DpdTimeoutAction: String | None + Phase1EncryptionAlgorithms: Phase1EncryptionAlgorithmsList | None + Phase2EncryptionAlgorithms: Phase2EncryptionAlgorithmsList | None + Phase1IntegrityAlgorithms: Phase1IntegrityAlgorithmsList | None + Phase2IntegrityAlgorithms: Phase2IntegrityAlgorithmsList | None + Phase1DHGroupNumbers: Phase1DHGroupNumbersList | None + Phase2DHGroupNumbers: Phase2DHGroupNumbersList | None + IkeVersions: IKEVersionsList | None + StartupAction: String | None + LogOptions: VpnTunnelLogOptions | None + EnableTunnelLifecycleControl: Boolean | None + + +TunnelOptionsList = list[TunnelOption] class VpnConnectionOptions(TypedDict, total=False): - EnableAcceleration: Optional[Boolean] - StaticRoutesOnly: Optional[Boolean] - LocalIpv4NetworkCidr: Optional[String] - RemoteIpv4NetworkCidr: Optional[String] - LocalIpv6NetworkCidr: Optional[String] - RemoteIpv6NetworkCidr: Optional[String] - OutsideIpAddressType: Optional[String] - TransportTransitGatewayAttachmentId: Optional[String] - TunnelInsideIpVersion: Optional[TunnelInsideIpVersion] - TunnelOptions: Optional[TunnelOptionsList] + EnableAcceleration: Boolean | None + StaticRoutesOnly: Boolean | None + LocalIpv4NetworkCidr: String | None + RemoteIpv4NetworkCidr: String | None + LocalIpv6NetworkCidr: String | None + RemoteIpv6NetworkCidr: String | None + OutsideIpAddressType: String | None + TransportTransitGatewayAttachmentId: String | None + TunnelInsideIpVersion: TunnelInsideIpVersion | None + TunnelOptions: TunnelOptionsList | None + TunnelBandwidth: VpnTunnelBandwidth | None class VpnConnection(TypedDict, total=False): - Category: Optional[String] - TransitGatewayId: Optional[String] - CoreNetworkArn: Optional[String] - CoreNetworkAttachmentArn: Optional[String] - GatewayAssociationState: Optional[GatewayAssociationState] - Options: Optional[VpnConnectionOptions] - Routes: Optional[VpnStaticRouteList] - Tags: Optional[TagList] - VgwTelemetry: Optional[VgwTelemetryList] - PreSharedKeyArn: Optional[String] - VpnConnectionId: Optional[String] - State: Optional[VpnState] - CustomerGatewayConfiguration: Optional[customerGatewayConfiguration] - Type: Optional[GatewayType] - CustomerGatewayId: Optional[String] - VpnGatewayId: Optional[String] + Category: String | None + TransitGatewayId: String | None + VpnConcentratorId: String | None + CoreNetworkArn: String | None + CoreNetworkAttachmentArn: String | None + GatewayAssociationState: GatewayAssociationState | None + Options: VpnConnectionOptions | None + Routes: VpnStaticRouteList | None + Tags: TagList | None + VgwTelemetry: VgwTelemetryList | None + PreSharedKeyArn: String | None + VpnConnectionId: String | None + State: VpnState | None + CustomerGatewayConfiguration: customerGatewayConfiguration | None + Type: GatewayType | None + CustomerGatewayId: String | None + VpnGatewayId: String | None class CreateVpnConnectionResult(TypedDict, total=False): - VpnConnection: Optional[VpnConnection] + VpnConnection: VpnConnection | None class CreateVpnConnectionRouteRequest(ServiceRequest): @@ -10688,879 +11942,970 @@ class CreateVpnConnectionRouteRequest(ServiceRequest): class CreateVpnGatewayRequest(ServiceRequest): - AvailabilityZone: Optional[String] + AvailabilityZone: String | None Type: GatewayType - TagSpecifications: Optional[TagSpecificationList] - AmazonSideAsn: Optional[Long] - DryRun: Optional[Boolean] + TagSpecifications: TagSpecificationList | None + AmazonSideAsn: Long | None + DryRun: Boolean | None -VpcAttachmentList = List[VpcAttachment] +VpcAttachmentList = list[VpcAttachment] class VpnGateway(TypedDict, total=False): - AmazonSideAsn: Optional[Long] - Tags: Optional[TagList] - VpnGatewayId: Optional[String] - State: Optional[VpnState] - Type: Optional[GatewayType] - AvailabilityZone: Optional[String] - VpcAttachments: Optional[VpcAttachmentList] + AmazonSideAsn: Long | None + Tags: TagList | None + VpnGatewayId: String | None + State: VpnState | None + Type: GatewayType | None + AvailabilityZone: String | None + VpcAttachments: VpcAttachmentList | None class CreateVpnGatewayResult(TypedDict, total=False): - VpnGateway: Optional[VpnGateway] + VpnGateway: VpnGateway | None class CreationDateCondition(TypedDict, total=False): - MaximumDaysSinceCreated: Optional[MaximumDaysSinceCreatedValue] + MaximumDaysSinceCreated: MaximumDaysSinceCreatedValue | None class CreationDateConditionRequest(TypedDict, total=False): - MaximumDaysSinceCreated: Optional[MaximumDaysSinceCreatedValue] + MaximumDaysSinceCreated: MaximumDaysSinceCreatedValue | None -CustomerGatewayIdStringList = List[CustomerGatewayId] -CustomerGatewayList = List[CustomerGateway] +CustomerGatewayIdStringList = list[CustomerGatewayId] +CustomerGatewayList = list[CustomerGateway] class DataQuery(TypedDict, total=False): - Id: Optional[String] - Source: Optional[String] - Destination: Optional[String] - Metric: Optional[MetricType] - Statistic: Optional[StatisticType] - Period: Optional[PeriodType] + Id: String | None + Source: String | None + Destination: String | None + Metric: MetricType | None + Statistic: StatisticType | None + Period: PeriodType | None -DataQueries = List[DataQuery] +DataQueries = list[DataQuery] class MetricPoint(TypedDict, total=False): - StartDate: Optional[MillisecondDateTime] - EndDate: Optional[MillisecondDateTime] - Value: Optional[Float] - Status: Optional[String] + StartDate: MillisecondDateTime | None + EndDate: MillisecondDateTime | None + Value: Float | None + Status: String | None -MetricPoints = List[MetricPoint] +MetricPoints = list[MetricPoint] class DataResponse(TypedDict, total=False): - Id: Optional[String] - Source: Optional[String] - Destination: Optional[String] - Metric: Optional[MetricType] - Statistic: Optional[StatisticType] - Period: Optional[PeriodType] - MetricPoints: Optional[MetricPoints] + Id: String | None + Source: String | None + Destination: String | None + Metric: MetricType | None + Statistic: StatisticType | None + Period: PeriodType | None + MetricPoints: MetricPoints | None -DataResponses = List[DataResponse] +DataResponses = list[DataResponse] class DeclarativePoliciesReport(TypedDict, total=False): - ReportId: Optional[String] - S3Bucket: Optional[String] - S3Prefix: Optional[String] - TargetId: Optional[String] - StartTime: Optional[MillisecondDateTime] - EndTime: Optional[MillisecondDateTime] - Status: Optional[ReportState] - Tags: Optional[TagList] + ReportId: String | None + S3Bucket: String | None + S3Prefix: String | None + TargetId: String | None + StartTime: MillisecondDateTime | None + EndTime: MillisecondDateTime | None + Status: ReportState | None + Tags: TagList | None + +DeclarativePoliciesReportList = list[DeclarativePoliciesReport] -DeclarativePoliciesReportList = List[DeclarativePoliciesReport] + +class DeleteCapacityManagerDataExportRequest(ServiceRequest): + CapacityManagerDataExportId: CapacityManagerDataExportId + DryRun: Boolean | None + + +class DeleteCapacityManagerDataExportResult(TypedDict, total=False): + CapacityManagerDataExportId: CapacityManagerDataExportId | None class DeleteCarrierGatewayRequest(ServiceRequest): CarrierGatewayId: CarrierGatewayId - DryRun: Optional[Boolean] + DryRun: Boolean | None class DeleteCarrierGatewayResult(TypedDict, total=False): - CarrierGateway: Optional[CarrierGateway] + CarrierGateway: CarrierGateway | None class DeleteClientVpnEndpointRequest(ServiceRequest): ClientVpnEndpointId: ClientVpnEndpointId - DryRun: Optional[Boolean] + DryRun: Boolean | None class DeleteClientVpnEndpointResult(TypedDict, total=False): - Status: Optional[ClientVpnEndpointStatus] + Status: ClientVpnEndpointStatus | None class DeleteClientVpnRouteRequest(ServiceRequest): ClientVpnEndpointId: ClientVpnEndpointId - TargetVpcSubnetId: Optional[SubnetId] + TargetVpcSubnetId: SubnetId | None DestinationCidrBlock: String - DryRun: Optional[Boolean] + DryRun: Boolean | None class DeleteClientVpnRouteResult(TypedDict, total=False): - Status: Optional[ClientVpnRouteStatus] + Status: ClientVpnRouteStatus | None class DeleteCoipCidrRequest(ServiceRequest): Cidr: String CoipPoolId: Ipv4PoolCoipId - DryRun: Optional[Boolean] + DryRun: Boolean | None class DeleteCoipCidrResult(TypedDict, total=False): - CoipCidr: Optional[CoipCidr] + CoipCidr: CoipCidr | None class DeleteCoipPoolRequest(ServiceRequest): CoipPoolId: Ipv4PoolCoipId - DryRun: Optional[Boolean] + DryRun: Boolean | None class DeleteCoipPoolResult(TypedDict, total=False): - CoipPool: Optional[CoipPool] + CoipPool: CoipPool | None class DeleteCustomerGatewayRequest(ServiceRequest): CustomerGatewayId: CustomerGatewayId - DryRun: Optional[Boolean] + DryRun: Boolean | None class DeleteDhcpOptionsRequest(ServiceRequest): DhcpOptionsId: DhcpOptionsId - DryRun: Optional[Boolean] + DryRun: Boolean | None class DeleteEgressOnlyInternetGatewayRequest(ServiceRequest): - DryRun: Optional[Boolean] + DryRun: Boolean | None EgressOnlyInternetGatewayId: EgressOnlyInternetGatewayId class DeleteEgressOnlyInternetGatewayResult(TypedDict, total=False): - ReturnCode: Optional[Boolean] + ReturnCode: Boolean | None class DeleteFleetError(TypedDict, total=False): - Code: Optional[DeleteFleetErrorCode] - Message: Optional[String] + Code: DeleteFleetErrorCode | None + Message: String | None class DeleteFleetErrorItem(TypedDict, total=False): - Error: Optional[DeleteFleetError] - FleetId: Optional[FleetId] + Error: DeleteFleetError | None + FleetId: FleetId | None -DeleteFleetErrorSet = List[DeleteFleetErrorItem] +DeleteFleetErrorSet = list[DeleteFleetErrorItem] class DeleteFleetSuccessItem(TypedDict, total=False): - CurrentFleetState: Optional[FleetStateCode] - PreviousFleetState: Optional[FleetStateCode] - FleetId: Optional[FleetId] + CurrentFleetState: FleetStateCode | None + PreviousFleetState: FleetStateCode | None + FleetId: FleetId | None -DeleteFleetSuccessSet = List[DeleteFleetSuccessItem] -FleetIdSet = List[FleetId] +DeleteFleetSuccessSet = list[DeleteFleetSuccessItem] +FleetIdSet = list[FleetId] class DeleteFleetsRequest(ServiceRequest): - DryRun: Optional[Boolean] + DryRun: Boolean | None FleetIds: FleetIdSet TerminateInstances: Boolean class DeleteFleetsResult(TypedDict, total=False): - SuccessfulFleetDeletions: Optional[DeleteFleetSuccessSet] - UnsuccessfulFleetDeletions: Optional[DeleteFleetErrorSet] + SuccessfulFleetDeletions: DeleteFleetSuccessSet | None + UnsuccessfulFleetDeletions: DeleteFleetErrorSet | None -FlowLogIdList = List[VpcFlowLogId] +FlowLogIdList = list[VpcFlowLogId] class DeleteFlowLogsRequest(ServiceRequest): - DryRun: Optional[Boolean] + DryRun: Boolean | None FlowLogIds: FlowLogIdList class DeleteFlowLogsResult(TypedDict, total=False): - Unsuccessful: Optional[UnsuccessfulItemSet] + Unsuccessful: UnsuccessfulItemSet | None class DeleteFpgaImageRequest(ServiceRequest): - DryRun: Optional[Boolean] + DryRun: Boolean | None FpgaImageId: FpgaImageId class DeleteFpgaImageResult(TypedDict, total=False): - Return: Optional[Boolean] + Return: Boolean | None class DeleteImageUsageReportRequest(ServiceRequest): ReportId: ImageUsageReportId - DryRun: Optional[Boolean] + DryRun: Boolean | None class DeleteImageUsageReportResult(TypedDict, total=False): - Return: Optional[Boolean] + Return: Boolean | None class DeleteInstanceConnectEndpointRequest(ServiceRequest): - DryRun: Optional[Boolean] + DryRun: Boolean | None InstanceConnectEndpointId: InstanceConnectEndpointId class DeleteInstanceConnectEndpointResult(TypedDict, total=False): - InstanceConnectEndpoint: Optional[Ec2InstanceConnectEndpoint] + InstanceConnectEndpoint: Ec2InstanceConnectEndpoint | None class DeleteInstanceEventWindowRequest(ServiceRequest): - DryRun: Optional[Boolean] - ForceDelete: Optional[Boolean] + DryRun: Boolean | None + ForceDelete: Boolean | None InstanceEventWindowId: InstanceEventWindowId class InstanceEventWindowStateChange(TypedDict, total=False): - InstanceEventWindowId: Optional[InstanceEventWindowId] - State: Optional[InstanceEventWindowState] + InstanceEventWindowId: InstanceEventWindowId | None + State: InstanceEventWindowState | None class DeleteInstanceEventWindowResult(TypedDict, total=False): - InstanceEventWindowState: Optional[InstanceEventWindowStateChange] + InstanceEventWindowState: InstanceEventWindowStateChange | None class DeleteInternetGatewayRequest(ServiceRequest): - DryRun: Optional[Boolean] + DryRun: Boolean | None InternetGatewayId: InternetGatewayId class DeleteIpamExternalResourceVerificationTokenRequest(ServiceRequest): - DryRun: Optional[Boolean] + DryRun: Boolean | None IpamExternalResourceVerificationTokenId: IpamExternalResourceVerificationTokenId class DeleteIpamExternalResourceVerificationTokenResult(TypedDict, total=False): - IpamExternalResourceVerificationToken: Optional[IpamExternalResourceVerificationToken] + IpamExternalResourceVerificationToken: IpamExternalResourceVerificationToken | None + + +class DeleteIpamPolicyRequest(ServiceRequest): + DryRun: Boolean | None + IpamPolicyId: IpamPolicyId + + +class DeleteIpamPolicyResult(TypedDict, total=False): + IpamPolicy: IpamPolicy | None class DeleteIpamPoolRequest(ServiceRequest): - DryRun: Optional[Boolean] + DryRun: Boolean | None IpamPoolId: IpamPoolId - Cascade: Optional[Boolean] + Cascade: Boolean | None class DeleteIpamPoolResult(TypedDict, total=False): - IpamPool: Optional[IpamPool] + IpamPool: IpamPool | None + + +class DeleteIpamPrefixListResolverRequest(ServiceRequest): + DryRun: Boolean | None + IpamPrefixListResolverId: IpamPrefixListResolverId + + +class DeleteIpamPrefixListResolverResult(TypedDict, total=False): + IpamPrefixListResolver: IpamPrefixListResolver | None + + +class DeleteIpamPrefixListResolverTargetRequest(ServiceRequest): + DryRun: Boolean | None + IpamPrefixListResolverTargetId: IpamPrefixListResolverTargetId + + +class DeleteIpamPrefixListResolverTargetResult(TypedDict, total=False): + IpamPrefixListResolverTarget: IpamPrefixListResolverTarget | None class DeleteIpamRequest(ServiceRequest): - DryRun: Optional[Boolean] + DryRun: Boolean | None IpamId: IpamId - Cascade: Optional[Boolean] + Cascade: Boolean | None class DeleteIpamResourceDiscoveryRequest(ServiceRequest): - DryRun: Optional[Boolean] + DryRun: Boolean | None IpamResourceDiscoveryId: IpamResourceDiscoveryId class DeleteIpamResourceDiscoveryResult(TypedDict, total=False): - IpamResourceDiscovery: Optional[IpamResourceDiscovery] + IpamResourceDiscovery: IpamResourceDiscovery | None class DeleteIpamResult(TypedDict, total=False): - Ipam: Optional[Ipam] + Ipam: Ipam | None class DeleteIpamScopeRequest(ServiceRequest): - DryRun: Optional[Boolean] + DryRun: Boolean | None IpamScopeId: IpamScopeId class DeleteIpamScopeResult(TypedDict, total=False): - IpamScope: Optional[IpamScope] + IpamScope: IpamScope | None class DeleteKeyPairRequest(ServiceRequest): - KeyName: Optional[KeyPairNameWithResolver] - KeyPairId: Optional[KeyPairId] - DryRun: Optional[Boolean] + KeyName: KeyPairNameWithResolver | None + KeyPairId: KeyPairId | None + DryRun: Boolean | None class DeleteKeyPairResult(TypedDict, total=False): - Return: Optional[Boolean] - KeyPairId: Optional[String] + Return: Boolean | None + KeyPairId: String | None class DeleteLaunchTemplateRequest(ServiceRequest): - DryRun: Optional[Boolean] - LaunchTemplateId: Optional[LaunchTemplateId] - LaunchTemplateName: Optional[LaunchTemplateName] + DryRun: Boolean | None + LaunchTemplateId: LaunchTemplateId | None + LaunchTemplateName: LaunchTemplateName | None class DeleteLaunchTemplateResult(TypedDict, total=False): - LaunchTemplate: Optional[LaunchTemplate] + LaunchTemplate: LaunchTemplate | None -VersionStringList = List[String] +VersionStringList = list[String] class DeleteLaunchTemplateVersionsRequest(ServiceRequest): - DryRun: Optional[Boolean] - LaunchTemplateId: Optional[LaunchTemplateId] - LaunchTemplateName: Optional[LaunchTemplateName] + DryRun: Boolean | None + LaunchTemplateId: LaunchTemplateId | None + LaunchTemplateName: LaunchTemplateName | None Versions: VersionStringList class ResponseError(TypedDict, total=False): - Code: Optional[LaunchTemplateErrorCode] - Message: Optional[String] + Code: LaunchTemplateErrorCode | None + Message: String | None class DeleteLaunchTemplateVersionsResponseErrorItem(TypedDict, total=False): - LaunchTemplateId: Optional[String] - LaunchTemplateName: Optional[String] - VersionNumber: Optional[Long] - ResponseError: Optional[ResponseError] + LaunchTemplateId: String | None + LaunchTemplateName: String | None + VersionNumber: Long | None + ResponseError: ResponseError | None -DeleteLaunchTemplateVersionsResponseErrorSet = List[DeleteLaunchTemplateVersionsResponseErrorItem] +DeleteLaunchTemplateVersionsResponseErrorSet = list[DeleteLaunchTemplateVersionsResponseErrorItem] class DeleteLaunchTemplateVersionsResponseSuccessItem(TypedDict, total=False): - LaunchTemplateId: Optional[String] - LaunchTemplateName: Optional[String] - VersionNumber: Optional[Long] + LaunchTemplateId: String | None + LaunchTemplateName: String | None + VersionNumber: Long | None -DeleteLaunchTemplateVersionsResponseSuccessSet = List[ +DeleteLaunchTemplateVersionsResponseSuccessSet = list[ DeleteLaunchTemplateVersionsResponseSuccessItem ] class DeleteLaunchTemplateVersionsResult(TypedDict, total=False): - SuccessfullyDeletedLaunchTemplateVersions: Optional[ - DeleteLaunchTemplateVersionsResponseSuccessSet - ] - UnsuccessfullyDeletedLaunchTemplateVersions: Optional[ - DeleteLaunchTemplateVersionsResponseErrorSet - ] + SuccessfullyDeletedLaunchTemplateVersions: DeleteLaunchTemplateVersionsResponseSuccessSet | None + UnsuccessfullyDeletedLaunchTemplateVersions: DeleteLaunchTemplateVersionsResponseErrorSet | None class DeleteLocalGatewayRouteRequest(ServiceRequest): - DestinationCidrBlock: Optional[String] + DestinationCidrBlock: String | None LocalGatewayRouteTableId: LocalGatewayRoutetableId - DryRun: Optional[Boolean] - DestinationPrefixListId: Optional[PrefixListResourceId] + DryRun: Boolean | None + DestinationPrefixListId: PrefixListResourceId | None class DeleteLocalGatewayRouteResult(TypedDict, total=False): - Route: Optional[LocalGatewayRoute] + Route: LocalGatewayRoute | None class DeleteLocalGatewayRouteTableRequest(ServiceRequest): LocalGatewayRouteTableId: LocalGatewayRoutetableId - DryRun: Optional[Boolean] + DryRun: Boolean | None class DeleteLocalGatewayRouteTableResult(TypedDict, total=False): - LocalGatewayRouteTable: Optional[LocalGatewayRouteTable] + LocalGatewayRouteTable: LocalGatewayRouteTable | None class DeleteLocalGatewayRouteTableVirtualInterfaceGroupAssociationRequest(ServiceRequest): LocalGatewayRouteTableVirtualInterfaceGroupAssociationId: ( LocalGatewayRouteTableVirtualInterfaceGroupAssociationId ) - DryRun: Optional[Boolean] + DryRun: Boolean | None class DeleteLocalGatewayRouteTableVirtualInterfaceGroupAssociationResult(TypedDict, total=False): - LocalGatewayRouteTableVirtualInterfaceGroupAssociation: Optional[ - LocalGatewayRouteTableVirtualInterfaceGroupAssociation - ] + LocalGatewayRouteTableVirtualInterfaceGroupAssociation: ( + LocalGatewayRouteTableVirtualInterfaceGroupAssociation | None + ) class DeleteLocalGatewayRouteTableVpcAssociationRequest(ServiceRequest): LocalGatewayRouteTableVpcAssociationId: LocalGatewayRouteTableVpcAssociationId - DryRun: Optional[Boolean] + DryRun: Boolean | None class DeleteLocalGatewayRouteTableVpcAssociationResult(TypedDict, total=False): - LocalGatewayRouteTableVpcAssociation: Optional[LocalGatewayRouteTableVpcAssociation] + LocalGatewayRouteTableVpcAssociation: LocalGatewayRouteTableVpcAssociation | None class DeleteLocalGatewayVirtualInterfaceGroupRequest(ServiceRequest): LocalGatewayVirtualInterfaceGroupId: LocalGatewayVirtualInterfaceGroupId - DryRun: Optional[Boolean] + DryRun: Boolean | None class DeleteLocalGatewayVirtualInterfaceGroupResult(TypedDict, total=False): - LocalGatewayVirtualInterfaceGroup: Optional[LocalGatewayVirtualInterfaceGroup] + LocalGatewayVirtualInterfaceGroup: LocalGatewayVirtualInterfaceGroup | None class DeleteLocalGatewayVirtualInterfaceRequest(ServiceRequest): LocalGatewayVirtualInterfaceId: LocalGatewayVirtualInterfaceId - DryRun: Optional[Boolean] + DryRun: Boolean | None class DeleteLocalGatewayVirtualInterfaceResult(TypedDict, total=False): - LocalGatewayVirtualInterface: Optional[LocalGatewayVirtualInterface] + LocalGatewayVirtualInterface: LocalGatewayVirtualInterface | None class DeleteManagedPrefixListRequest(ServiceRequest): - DryRun: Optional[Boolean] + DryRun: Boolean | None PrefixListId: PrefixListResourceId class DeleteManagedPrefixListResult(TypedDict, total=False): - PrefixList: Optional[ManagedPrefixList] + PrefixList: ManagedPrefixList | None class DeleteNatGatewayRequest(ServiceRequest): - DryRun: Optional[Boolean] + DryRun: Boolean | None NatGatewayId: NatGatewayId class DeleteNatGatewayResult(TypedDict, total=False): - NatGatewayId: Optional[String] + NatGatewayId: String | None class DeleteNetworkAclEntryRequest(ServiceRequest): - DryRun: Optional[Boolean] + DryRun: Boolean | None NetworkAclId: NetworkAclId RuleNumber: Integer Egress: Boolean class DeleteNetworkAclRequest(ServiceRequest): - DryRun: Optional[Boolean] + DryRun: Boolean | None NetworkAclId: NetworkAclId class DeleteNetworkInsightsAccessScopeAnalysisRequest(ServiceRequest): NetworkInsightsAccessScopeAnalysisId: NetworkInsightsAccessScopeAnalysisId - DryRun: Optional[Boolean] + DryRun: Boolean | None class DeleteNetworkInsightsAccessScopeAnalysisResult(TypedDict, total=False): - NetworkInsightsAccessScopeAnalysisId: Optional[NetworkInsightsAccessScopeAnalysisId] + NetworkInsightsAccessScopeAnalysisId: NetworkInsightsAccessScopeAnalysisId | None class DeleteNetworkInsightsAccessScopeRequest(ServiceRequest): - DryRun: Optional[Boolean] + DryRun: Boolean | None NetworkInsightsAccessScopeId: NetworkInsightsAccessScopeId class DeleteNetworkInsightsAccessScopeResult(TypedDict, total=False): - NetworkInsightsAccessScopeId: Optional[NetworkInsightsAccessScopeId] + NetworkInsightsAccessScopeId: NetworkInsightsAccessScopeId | None class DeleteNetworkInsightsAnalysisRequest(ServiceRequest): - DryRun: Optional[Boolean] + DryRun: Boolean | None NetworkInsightsAnalysisId: NetworkInsightsAnalysisId class DeleteNetworkInsightsAnalysisResult(TypedDict, total=False): - NetworkInsightsAnalysisId: Optional[NetworkInsightsAnalysisId] + NetworkInsightsAnalysisId: NetworkInsightsAnalysisId | None class DeleteNetworkInsightsPathRequest(ServiceRequest): - DryRun: Optional[Boolean] + DryRun: Boolean | None NetworkInsightsPathId: NetworkInsightsPathId class DeleteNetworkInsightsPathResult(TypedDict, total=False): - NetworkInsightsPathId: Optional[NetworkInsightsPathId] + NetworkInsightsPathId: NetworkInsightsPathId | None class DeleteNetworkInterfacePermissionRequest(ServiceRequest): NetworkInterfacePermissionId: NetworkInterfacePermissionId - Force: Optional[Boolean] - DryRun: Optional[Boolean] + Force: Boolean | None + DryRun: Boolean | None class DeleteNetworkInterfacePermissionResult(TypedDict, total=False): - Return: Optional[Boolean] + Return: Boolean | None class DeleteNetworkInterfaceRequest(ServiceRequest): - DryRun: Optional[Boolean] + DryRun: Boolean | None NetworkInterfaceId: NetworkInterfaceId class DeletePlacementGroupRequest(ServiceRequest): - DryRun: Optional[Boolean] - GroupName: PlacementGroupName + DryRun: Boolean | None + GroupName: PlacementGroupNameWithResolver class DeletePublicIpv4PoolRequest(ServiceRequest): - DryRun: Optional[Boolean] + DryRun: Boolean | None PoolId: Ipv4PoolEc2Id - NetworkBorderGroup: Optional[String] + NetworkBorderGroup: String | None class DeletePublicIpv4PoolResult(TypedDict, total=False): - ReturnValue: Optional[Boolean] + ReturnValue: Boolean | None class DeleteQueuedReservedInstancesError(TypedDict, total=False): - Code: Optional[DeleteQueuedReservedInstancesErrorCode] - Message: Optional[String] + Code: DeleteQueuedReservedInstancesErrorCode | None + Message: String | None -DeleteQueuedReservedInstancesIdList = List[ReservationId] +DeleteQueuedReservedInstancesIdList = list[ReservationId] class DeleteQueuedReservedInstancesRequest(ServiceRequest): - DryRun: Optional[Boolean] + DryRun: Boolean | None ReservedInstancesIds: DeleteQueuedReservedInstancesIdList class FailedQueuedPurchaseDeletion(TypedDict, total=False): - Error: Optional[DeleteQueuedReservedInstancesError] - ReservedInstancesId: Optional[String] + Error: DeleteQueuedReservedInstancesError | None + ReservedInstancesId: String | None -FailedQueuedPurchaseDeletionSet = List[FailedQueuedPurchaseDeletion] +FailedQueuedPurchaseDeletionSet = list[FailedQueuedPurchaseDeletion] class SuccessfulQueuedPurchaseDeletion(TypedDict, total=False): - ReservedInstancesId: Optional[String] + ReservedInstancesId: String | None -SuccessfulQueuedPurchaseDeletionSet = List[SuccessfulQueuedPurchaseDeletion] +SuccessfulQueuedPurchaseDeletionSet = list[SuccessfulQueuedPurchaseDeletion] class DeleteQueuedReservedInstancesResult(TypedDict, total=False): - SuccessfulQueuedPurchaseDeletions: Optional[SuccessfulQueuedPurchaseDeletionSet] - FailedQueuedPurchaseDeletions: Optional[FailedQueuedPurchaseDeletionSet] + SuccessfulQueuedPurchaseDeletions: SuccessfulQueuedPurchaseDeletionSet | None + FailedQueuedPurchaseDeletions: FailedQueuedPurchaseDeletionSet | None class DeleteRouteRequest(ServiceRequest): - DestinationPrefixListId: Optional[PrefixListResourceId] - DryRun: Optional[Boolean] + DestinationPrefixListId: PrefixListResourceId | None + DryRun: Boolean | None RouteTableId: RouteTableId - DestinationCidrBlock: Optional[String] - DestinationIpv6CidrBlock: Optional[String] + DestinationCidrBlock: String | None + DestinationIpv6CidrBlock: String | None class DeleteRouteServerEndpointRequest(ServiceRequest): RouteServerEndpointId: RouteServerEndpointId - DryRun: Optional[Boolean] + DryRun: Boolean | None class DeleteRouteServerEndpointResult(TypedDict, total=False): - RouteServerEndpoint: Optional[RouteServerEndpoint] + RouteServerEndpoint: RouteServerEndpoint | None class DeleteRouteServerPeerRequest(ServiceRequest): RouteServerPeerId: RouteServerPeerId - DryRun: Optional[Boolean] + DryRun: Boolean | None class DeleteRouteServerPeerResult(TypedDict, total=False): - RouteServerPeer: Optional[RouteServerPeer] + RouteServerPeer: RouteServerPeer | None class DeleteRouteServerRequest(ServiceRequest): RouteServerId: RouteServerId - DryRun: Optional[Boolean] + DryRun: Boolean | None class DeleteRouteServerResult(TypedDict, total=False): - RouteServer: Optional[RouteServer] + RouteServer: RouteServer | None class DeleteRouteTableRequest(ServiceRequest): - DryRun: Optional[Boolean] + DryRun: Boolean | None RouteTableId: RouteTableId +class DeleteSecondaryNetworkRequest(ServiceRequest): + ClientToken: String | None + DryRun: Boolean | None + SecondaryNetworkId: SecondaryNetworkId + + +class DeleteSecondaryNetworkResult(TypedDict, total=False): + SecondaryNetwork: SecondaryNetwork | None + ClientToken: String | None + + +class DeleteSecondarySubnetRequest(ServiceRequest): + ClientToken: String | None + DryRun: Boolean | None + SecondarySubnetId: SecondarySubnetId + + +class DeleteSecondarySubnetResult(TypedDict, total=False): + SecondarySubnet: SecondarySubnet | None + ClientToken: String | None + + class DeleteSecurityGroupRequest(ServiceRequest): - GroupId: Optional[SecurityGroupId] - GroupName: Optional[SecurityGroupName] - DryRun: Optional[Boolean] + GroupId: SecurityGroupId | None + GroupName: SecurityGroupName | None + DryRun: Boolean | None class DeleteSecurityGroupResult(TypedDict, total=False): - Return: Optional[Boolean] - GroupId: Optional[SecurityGroupId] + Return: Boolean | None + GroupId: SecurityGroupId | None class DeleteSnapshotRequest(ServiceRequest): SnapshotId: SnapshotId - DryRun: Optional[Boolean] + DryRun: Boolean | None class DeleteSnapshotReturnCode(TypedDict, total=False): - SnapshotId: Optional[SnapshotId] - ReturnCode: Optional[SnapshotReturnCodes] + SnapshotId: SnapshotId | None + ReturnCode: SnapshotReturnCodes | None -DeleteSnapshotResultSet = List[DeleteSnapshotReturnCode] +DeleteSnapshotResultSet = list[DeleteSnapshotReturnCode] class DeleteSpotDatafeedSubscriptionRequest(ServiceRequest): - DryRun: Optional[Boolean] + DryRun: Boolean | None class DeleteSubnetCidrReservationRequest(ServiceRequest): SubnetCidrReservationId: SubnetCidrReservationId - DryRun: Optional[Boolean] + DryRun: Boolean | None class DeleteSubnetCidrReservationResult(TypedDict, total=False): - DeletedSubnetCidrReservation: Optional[SubnetCidrReservation] + DeletedSubnetCidrReservation: SubnetCidrReservation | None class DeleteSubnetRequest(ServiceRequest): SubnetId: SubnetId - DryRun: Optional[Boolean] + DryRun: Boolean | None class DeleteTagsRequest(ServiceRequest): - DryRun: Optional[Boolean] + DryRun: Boolean | None Resources: ResourceIdList - Tags: Optional[TagList] + Tags: TagList | None class DeleteTrafficMirrorFilterRequest(ServiceRequest): TrafficMirrorFilterId: TrafficMirrorFilterId - DryRun: Optional[Boolean] + DryRun: Boolean | None class DeleteTrafficMirrorFilterResult(TypedDict, total=False): - TrafficMirrorFilterId: Optional[String] + TrafficMirrorFilterId: String | None class DeleteTrafficMirrorFilterRuleRequest(ServiceRequest): TrafficMirrorFilterRuleId: TrafficMirrorFilterRuleIdWithResolver - DryRun: Optional[Boolean] + DryRun: Boolean | None class DeleteTrafficMirrorFilterRuleResult(TypedDict, total=False): - TrafficMirrorFilterRuleId: Optional[String] + TrafficMirrorFilterRuleId: String | None class DeleteTrafficMirrorSessionRequest(ServiceRequest): TrafficMirrorSessionId: TrafficMirrorSessionId - DryRun: Optional[Boolean] + DryRun: Boolean | None class DeleteTrafficMirrorSessionResult(TypedDict, total=False): - TrafficMirrorSessionId: Optional[String] + TrafficMirrorSessionId: String | None class DeleteTrafficMirrorTargetRequest(ServiceRequest): TrafficMirrorTargetId: TrafficMirrorTargetId - DryRun: Optional[Boolean] + DryRun: Boolean | None class DeleteTrafficMirrorTargetResult(TypedDict, total=False): - TrafficMirrorTargetId: Optional[String] + TrafficMirrorTargetId: String | None class DeleteTransitGatewayConnectPeerRequest(ServiceRequest): TransitGatewayConnectPeerId: TransitGatewayConnectPeerId - DryRun: Optional[Boolean] + DryRun: Boolean | None class DeleteTransitGatewayConnectPeerResult(TypedDict, total=False): - TransitGatewayConnectPeer: Optional[TransitGatewayConnectPeer] + TransitGatewayConnectPeer: TransitGatewayConnectPeer | None class DeleteTransitGatewayConnectRequest(ServiceRequest): TransitGatewayAttachmentId: TransitGatewayAttachmentId - DryRun: Optional[Boolean] + DryRun: Boolean | None class DeleteTransitGatewayConnectResult(TypedDict, total=False): - TransitGatewayConnect: Optional[TransitGatewayConnect] + TransitGatewayConnect: TransitGatewayConnect | None + + +class DeleteTransitGatewayMeteringPolicyEntryRequest(ServiceRequest): + TransitGatewayMeteringPolicyId: TransitGatewayMeteringPolicyId + PolicyRuleNumber: Integer + DryRun: Boolean | None + + +class DeleteTransitGatewayMeteringPolicyEntryResult(TypedDict, total=False): + TransitGatewayMeteringPolicyEntry: TransitGatewayMeteringPolicyEntry | None + + +class DeleteTransitGatewayMeteringPolicyRequest(ServiceRequest): + TransitGatewayMeteringPolicyId: TransitGatewayMeteringPolicyId + DryRun: Boolean | None + + +class DeleteTransitGatewayMeteringPolicyResult(TypedDict, total=False): + TransitGatewayMeteringPolicy: TransitGatewayMeteringPolicy | None class DeleteTransitGatewayMulticastDomainRequest(ServiceRequest): TransitGatewayMulticastDomainId: TransitGatewayMulticastDomainId - DryRun: Optional[Boolean] + DryRun: Boolean | None class DeleteTransitGatewayMulticastDomainResult(TypedDict, total=False): - TransitGatewayMulticastDomain: Optional[TransitGatewayMulticastDomain] + TransitGatewayMulticastDomain: TransitGatewayMulticastDomain | None class DeleteTransitGatewayPeeringAttachmentRequest(ServiceRequest): TransitGatewayAttachmentId: TransitGatewayAttachmentId - DryRun: Optional[Boolean] + DryRun: Boolean | None class DeleteTransitGatewayPeeringAttachmentResult(TypedDict, total=False): - TransitGatewayPeeringAttachment: Optional[TransitGatewayPeeringAttachment] + TransitGatewayPeeringAttachment: TransitGatewayPeeringAttachment | None class DeleteTransitGatewayPolicyTableRequest(ServiceRequest): TransitGatewayPolicyTableId: TransitGatewayPolicyTableId - DryRun: Optional[Boolean] + DryRun: Boolean | None class DeleteTransitGatewayPolicyTableResult(TypedDict, total=False): - TransitGatewayPolicyTable: Optional[TransitGatewayPolicyTable] + TransitGatewayPolicyTable: TransitGatewayPolicyTable | None class DeleteTransitGatewayPrefixListReferenceRequest(ServiceRequest): TransitGatewayRouteTableId: TransitGatewayRouteTableId PrefixListId: PrefixListResourceId - DryRun: Optional[Boolean] + DryRun: Boolean | None class DeleteTransitGatewayPrefixListReferenceResult(TypedDict, total=False): - TransitGatewayPrefixListReference: Optional[TransitGatewayPrefixListReference] + TransitGatewayPrefixListReference: TransitGatewayPrefixListReference | None class DeleteTransitGatewayRequest(ServiceRequest): TransitGatewayId: TransitGatewayId - DryRun: Optional[Boolean] + DryRun: Boolean | None class DeleteTransitGatewayResult(TypedDict, total=False): - TransitGateway: Optional[TransitGateway] + TransitGateway: TransitGateway | None class DeleteTransitGatewayRouteRequest(ServiceRequest): TransitGatewayRouteTableId: TransitGatewayRouteTableId DestinationCidrBlock: String - DryRun: Optional[Boolean] + DryRun: Boolean | None class DeleteTransitGatewayRouteResult(TypedDict, total=False): - Route: Optional[TransitGatewayRoute] + Route: TransitGatewayRoute | None class DeleteTransitGatewayRouteTableAnnouncementRequest(ServiceRequest): TransitGatewayRouteTableAnnouncementId: TransitGatewayRouteTableAnnouncementId - DryRun: Optional[Boolean] + DryRun: Boolean | None class DeleteTransitGatewayRouteTableAnnouncementResult(TypedDict, total=False): - TransitGatewayRouteTableAnnouncement: Optional[TransitGatewayRouteTableAnnouncement] + TransitGatewayRouteTableAnnouncement: TransitGatewayRouteTableAnnouncement | None class DeleteTransitGatewayRouteTableRequest(ServiceRequest): TransitGatewayRouteTableId: TransitGatewayRouteTableId - DryRun: Optional[Boolean] + DryRun: Boolean | None class DeleteTransitGatewayRouteTableResult(TypedDict, total=False): - TransitGatewayRouteTable: Optional[TransitGatewayRouteTable] + TransitGatewayRouteTable: TransitGatewayRouteTable | None class DeleteTransitGatewayVpcAttachmentRequest(ServiceRequest): TransitGatewayAttachmentId: TransitGatewayAttachmentId - DryRun: Optional[Boolean] + DryRun: Boolean | None class DeleteTransitGatewayVpcAttachmentResult(TypedDict, total=False): - TransitGatewayVpcAttachment: Optional[TransitGatewayVpcAttachment] + TransitGatewayVpcAttachment: TransitGatewayVpcAttachment | None class DeleteVerifiedAccessEndpointRequest(ServiceRequest): VerifiedAccessEndpointId: VerifiedAccessEndpointId - ClientToken: Optional[String] - DryRun: Optional[Boolean] + ClientToken: String | None + DryRun: Boolean | None class DeleteVerifiedAccessEndpointResult(TypedDict, total=False): - VerifiedAccessEndpoint: Optional[VerifiedAccessEndpoint] + VerifiedAccessEndpoint: VerifiedAccessEndpoint | None class DeleteVerifiedAccessGroupRequest(ServiceRequest): VerifiedAccessGroupId: VerifiedAccessGroupId - ClientToken: Optional[String] - DryRun: Optional[Boolean] + ClientToken: String | None + DryRun: Boolean | None class DeleteVerifiedAccessGroupResult(TypedDict, total=False): - VerifiedAccessGroup: Optional[VerifiedAccessGroup] + VerifiedAccessGroup: VerifiedAccessGroup | None class DeleteVerifiedAccessInstanceRequest(ServiceRequest): VerifiedAccessInstanceId: VerifiedAccessInstanceId - DryRun: Optional[Boolean] - ClientToken: Optional[String] + DryRun: Boolean | None + ClientToken: String | None class DeleteVerifiedAccessInstanceResult(TypedDict, total=False): - VerifiedAccessInstance: Optional[VerifiedAccessInstance] + VerifiedAccessInstance: VerifiedAccessInstance | None class DeleteVerifiedAccessTrustProviderRequest(ServiceRequest): VerifiedAccessTrustProviderId: VerifiedAccessTrustProviderId - DryRun: Optional[Boolean] - ClientToken: Optional[String] + DryRun: Boolean | None + ClientToken: String | None class DeleteVerifiedAccessTrustProviderResult(TypedDict, total=False): - VerifiedAccessTrustProvider: Optional[VerifiedAccessTrustProvider] + VerifiedAccessTrustProvider: VerifiedAccessTrustProvider | None class DeleteVolumeRequest(ServiceRequest): VolumeId: VolumeId - DryRun: Optional[Boolean] + DryRun: Boolean | None class DeleteVpcBlockPublicAccessExclusionRequest(ServiceRequest): - DryRun: Optional[Boolean] + DryRun: Boolean | None ExclusionId: VpcBlockPublicAccessExclusionId class DeleteVpcBlockPublicAccessExclusionResult(TypedDict, total=False): - VpcBlockPublicAccessExclusion: Optional[VpcBlockPublicAccessExclusion] + VpcBlockPublicAccessExclusion: VpcBlockPublicAccessExclusion | None + + +class DeleteVpcEncryptionControlRequest(ServiceRequest): + DryRun: Boolean | None + VpcEncryptionControlId: VpcEncryptionControlId + + +class DeleteVpcEncryptionControlResult(TypedDict, total=False): + VpcEncryptionControl: VpcEncryptionControl | None class DeleteVpcEndpointConnectionNotificationsRequest(ServiceRequest): - DryRun: Optional[Boolean] + DryRun: Boolean | None ConnectionNotificationIds: ConnectionNotificationIdsList class DeleteVpcEndpointConnectionNotificationsResult(TypedDict, total=False): - Unsuccessful: Optional[UnsuccessfulItemSet] + Unsuccessful: UnsuccessfulItemSet | None -VpcEndpointServiceIdList = List[VpcEndpointServiceId] +VpcEndpointServiceIdList = list[VpcEndpointServiceId] class DeleteVpcEndpointServiceConfigurationsRequest(ServiceRequest): - DryRun: Optional[Boolean] + DryRun: Boolean | None ServiceIds: VpcEndpointServiceIdList class DeleteVpcEndpointServiceConfigurationsResult(TypedDict, total=False): - Unsuccessful: Optional[UnsuccessfulItemSet] + Unsuccessful: UnsuccessfulItemSet | None class DeleteVpcEndpointsRequest(ServiceRequest): - DryRun: Optional[Boolean] + DryRun: Boolean | None VpcEndpointIds: VpcEndpointIdList class DeleteVpcEndpointsResult(TypedDict, total=False): - Unsuccessful: Optional[UnsuccessfulItemSet] + Unsuccessful: UnsuccessfulItemSet | None class DeleteVpcPeeringConnectionRequest(ServiceRequest): - DryRun: Optional[Boolean] + DryRun: Boolean | None VpcPeeringConnectionId: VpcPeeringConnectionId class DeleteVpcPeeringConnectionResult(TypedDict, total=False): - Return: Optional[Boolean] + Return: Boolean | None class DeleteVpcRequest(ServiceRequest): VpcId: VpcId - DryRun: Optional[Boolean] + DryRun: Boolean | None + + +class DeleteVpnConcentratorRequest(ServiceRequest): + VpnConcentratorId: VpnConcentratorId + DryRun: Boolean | None + + +class DeleteVpnConcentratorResult(TypedDict, total=False): + Return: Boolean | None class DeleteVpnConnectionRequest(ServiceRequest): VpnConnectionId: VpnConnectionId - DryRun: Optional[Boolean] + DryRun: Boolean | None class DeleteVpnConnectionRouteRequest(ServiceRequest): @@ -11570,3340 +12915,3525 @@ class DeleteVpnConnectionRouteRequest(ServiceRequest): class DeleteVpnGatewayRequest(ServiceRequest): VpnGatewayId: VpnGatewayId - DryRun: Optional[Boolean] + DryRun: Boolean | None class DeprecationTimeCondition(TypedDict, total=False): - MaximumDaysSinceDeprecated: Optional[MaximumDaysSinceDeprecatedValue] + MaximumDaysSinceDeprecated: MaximumDaysSinceDeprecatedValue | None class DeprecationTimeConditionRequest(TypedDict, total=False): - MaximumDaysSinceDeprecated: Optional[MaximumDaysSinceDeprecatedValue] + MaximumDaysSinceDeprecated: MaximumDaysSinceDeprecatedValue | None class DeprovisionByoipCidrRequest(ServiceRequest): Cidr: String - DryRun: Optional[Boolean] + DryRun: Boolean | None class DeprovisionByoipCidrResult(TypedDict, total=False): - ByoipCidr: Optional[ByoipCidr] + ByoipCidr: ByoipCidr | None class DeprovisionIpamByoasnRequest(ServiceRequest): - DryRun: Optional[Boolean] + DryRun: Boolean | None IpamId: IpamId Asn: String class DeprovisionIpamByoasnResult(TypedDict, total=False): - Byoasn: Optional[Byoasn] + Byoasn: Byoasn | None class DeprovisionIpamPoolCidrRequest(ServiceRequest): - DryRun: Optional[Boolean] + DryRun: Boolean | None IpamPoolId: IpamPoolId - Cidr: Optional[String] + Cidr: String | None class IpamPoolCidrFailureReason(TypedDict, total=False): - Code: Optional[IpamPoolCidrFailureCode] - Message: Optional[String] + Code: IpamPoolCidrFailureCode | None + Message: String | None class IpamPoolCidr(TypedDict, total=False): - Cidr: Optional[String] - State: Optional[IpamPoolCidrState] - FailureReason: Optional[IpamPoolCidrFailureReason] - IpamPoolCidrId: Optional[IpamPoolCidrId] - NetmaskLength: Optional[Integer] + Cidr: String | None + State: IpamPoolCidrState | None + FailureReason: IpamPoolCidrFailureReason | None + IpamPoolCidrId: IpamPoolCidrId | None + NetmaskLength: Integer | None class DeprovisionIpamPoolCidrResult(TypedDict, total=False): - IpamPoolCidr: Optional[IpamPoolCidr] + IpamPoolCidr: IpamPoolCidr | None class DeprovisionPublicIpv4PoolCidrRequest(ServiceRequest): - DryRun: Optional[Boolean] + DryRun: Boolean | None PoolId: Ipv4PoolEc2Id Cidr: String -DeprovisionedAddressSet = List[String] +DeprovisionedAddressSet = list[String] class DeprovisionPublicIpv4PoolCidrResult(TypedDict, total=False): - PoolId: Optional[Ipv4PoolEc2Id] - DeprovisionedAddresses: Optional[DeprovisionedAddressSet] + PoolId: Ipv4PoolEc2Id | None + DeprovisionedAddresses: DeprovisionedAddressSet | None class DeregisterImageRequest(ServiceRequest): ImageId: ImageId - DeleteAssociatedSnapshots: Optional[Boolean] - DryRun: Optional[Boolean] + DeleteAssociatedSnapshots: Boolean | None + DryRun: Boolean | None class DeregisterImageResult(TypedDict, total=False): - Return: Optional[Boolean] - DeleteSnapshotResults: Optional[DeleteSnapshotResultSet] + Return: Boolean | None + DeleteSnapshotResults: DeleteSnapshotResultSet | None -InstanceTagKeySet = List[String] +InstanceTagKeySet = list[String] class DeregisterInstanceTagAttributeRequest(TypedDict, total=False): - IncludeAllTagsOfInstance: Optional[Boolean] - InstanceTagKeys: Optional[InstanceTagKeySet] + IncludeAllTagsOfInstance: Boolean | None + InstanceTagKeys: InstanceTagKeySet | None class DeregisterInstanceEventNotificationAttributesRequest(ServiceRequest): - DryRun: Optional[Boolean] + DryRun: Boolean | None InstanceTagAttribute: DeregisterInstanceTagAttributeRequest class InstanceTagNotificationAttribute(TypedDict, total=False): - InstanceTagKeys: Optional[InstanceTagKeySet] - IncludeAllTagsOfInstance: Optional[Boolean] + InstanceTagKeys: InstanceTagKeySet | None + IncludeAllTagsOfInstance: Boolean | None class DeregisterInstanceEventNotificationAttributesResult(TypedDict, total=False): - InstanceTagAttribute: Optional[InstanceTagNotificationAttribute] + InstanceTagAttribute: InstanceTagNotificationAttribute | None -TransitGatewayNetworkInterfaceIdList = List[NetworkInterfaceId] +TransitGatewayNetworkInterfaceIdList = list[NetworkInterfaceId] class DeregisterTransitGatewayMulticastGroupMembersRequest(ServiceRequest): - TransitGatewayMulticastDomainId: Optional[TransitGatewayMulticastDomainId] - GroupIpAddress: Optional[String] - NetworkInterfaceIds: Optional[TransitGatewayNetworkInterfaceIdList] - DryRun: Optional[Boolean] + TransitGatewayMulticastDomainId: TransitGatewayMulticastDomainId | None + GroupIpAddress: String | None + NetworkInterfaceIds: TransitGatewayNetworkInterfaceIdList | None + DryRun: Boolean | None class TransitGatewayMulticastDeregisteredGroupMembers(TypedDict, total=False): - TransitGatewayMulticastDomainId: Optional[String] - DeregisteredNetworkInterfaceIds: Optional[ValueStringList] - GroupIpAddress: Optional[String] + TransitGatewayMulticastDomainId: String | None + DeregisteredNetworkInterfaceIds: ValueStringList | None + GroupIpAddress: String | None class DeregisterTransitGatewayMulticastGroupMembersResult(TypedDict, total=False): - DeregisteredMulticastGroupMembers: Optional[TransitGatewayMulticastDeregisteredGroupMembers] + DeregisteredMulticastGroupMembers: TransitGatewayMulticastDeregisteredGroupMembers | None class DeregisterTransitGatewayMulticastGroupSourcesRequest(ServiceRequest): - TransitGatewayMulticastDomainId: Optional[TransitGatewayMulticastDomainId] - GroupIpAddress: Optional[String] - NetworkInterfaceIds: Optional[TransitGatewayNetworkInterfaceIdList] - DryRun: Optional[Boolean] + TransitGatewayMulticastDomainId: TransitGatewayMulticastDomainId | None + GroupIpAddress: String | None + NetworkInterfaceIds: TransitGatewayNetworkInterfaceIdList | None + DryRun: Boolean | None class TransitGatewayMulticastDeregisteredGroupSources(TypedDict, total=False): - TransitGatewayMulticastDomainId: Optional[String] - DeregisteredNetworkInterfaceIds: Optional[ValueStringList] - GroupIpAddress: Optional[String] + TransitGatewayMulticastDomainId: String | None + DeregisteredNetworkInterfaceIds: ValueStringList | None + GroupIpAddress: String | None class DeregisterTransitGatewayMulticastGroupSourcesResult(TypedDict, total=False): - DeregisteredMulticastGroupSources: Optional[TransitGatewayMulticastDeregisteredGroupSources] + DeregisteredMulticastGroupSources: TransitGatewayMulticastDeregisteredGroupSources | None class DescribeAccountAttributesRequest(ServiceRequest): - DryRun: Optional[Boolean] - AttributeNames: Optional[AccountAttributeNameStringList] + DryRun: Boolean | None + AttributeNames: AccountAttributeNameStringList | None class DescribeAccountAttributesResult(TypedDict, total=False): - AccountAttributes: Optional[AccountAttributeList] + AccountAttributes: AccountAttributeList | None class DescribeAddressTransfersRequest(ServiceRequest): - AllocationIds: Optional[AllocationIdList] - NextToken: Optional[String] - MaxResults: Optional[DescribeAddressTransfersMaxResults] - DryRun: Optional[Boolean] + AllocationIds: AllocationIdList | None + NextToken: String | None + MaxResults: DescribeAddressTransfersMaxResults | None + DryRun: Boolean | None class DescribeAddressTransfersResult(TypedDict, total=False): - AddressTransfers: Optional[AddressTransferList] - NextToken: Optional[String] + AddressTransfers: AddressTransferList | None + NextToken: String | None class DescribeAddressesAttributeRequest(ServiceRequest): - AllocationIds: Optional[AllocationIds] - Attribute: Optional[AddressAttributeName] - NextToken: Optional[NextToken] - MaxResults: Optional[AddressMaxResults] - DryRun: Optional[Boolean] + AllocationIds: AllocationIds | None + Attribute: AddressAttributeName | None + NextToken: NextToken | None + MaxResults: AddressMaxResults | None + DryRun: Boolean | None class DescribeAddressesAttributeResult(TypedDict, total=False): - Addresses: Optional[AddressSet] - NextToken: Optional[NextToken] + Addresses: AddressSet | None + NextToken: NextToken | None class Filter(TypedDict, total=False): - Name: Optional[String] - Values: Optional[ValueStringList] + Name: String | None + Values: ValueStringList | None -FilterList = List[Filter] -PublicIpStringList = List[String] +FilterList = list[Filter] +PublicIpStringList = list[String] class DescribeAddressesRequest(ServiceRequest): - PublicIps: Optional[PublicIpStringList] - DryRun: Optional[Boolean] - Filters: Optional[FilterList] - AllocationIds: Optional[AllocationIdList] + PublicIps: PublicIpStringList | None + DryRun: Boolean | None + Filters: FilterList | None + AllocationIds: AllocationIdList | None class DescribeAddressesResult(TypedDict, total=False): - Addresses: Optional[AddressList] + Addresses: AddressList | None class DescribeAggregateIdFormatRequest(ServiceRequest): - DryRun: Optional[Boolean] + DryRun: Boolean | None class IdFormat(TypedDict, total=False): - Deadline: Optional[DateTime] - Resource: Optional[String] - UseLongIds: Optional[Boolean] + Deadline: DateTime | None + Resource: String | None + UseLongIds: Boolean | None -IdFormatList = List[IdFormat] +IdFormatList = list[IdFormat] class DescribeAggregateIdFormatResult(TypedDict, total=False): - UseLongIdsAggregated: Optional[Boolean] - Statuses: Optional[IdFormatList] + UseLongIdsAggregated: Boolean | None + Statuses: IdFormatList | None -ZoneIdStringList = List[String] -ZoneNameStringList = List[String] +ZoneIdStringList = list[String] +ZoneNameStringList = list[String] class DescribeAvailabilityZonesRequest(ServiceRequest): - ZoneNames: Optional[ZoneNameStringList] - ZoneIds: Optional[ZoneIdStringList] - AllAvailabilityZones: Optional[Boolean] - DryRun: Optional[Boolean] - Filters: Optional[FilterList] + ZoneNames: ZoneNameStringList | None + ZoneIds: ZoneIdStringList | None + AllAvailabilityZones: Boolean | None + DryRun: Boolean | None + Filters: FilterList | None class DescribeAvailabilityZonesResult(TypedDict, total=False): - AvailabilityZones: Optional[AvailabilityZoneList] + AvailabilityZones: AvailabilityZoneList | None class DescribeAwsNetworkPerformanceMetricSubscriptionsRequest(ServiceRequest): - MaxResults: Optional[MaxResultsParam] - NextToken: Optional[String] - Filters: Optional[FilterList] - DryRun: Optional[Boolean] + MaxResults: MaxResultsParam | None + NextToken: String | None + Filters: FilterList | None + DryRun: Boolean | None class Subscription(TypedDict, total=False): - Source: Optional[String] - Destination: Optional[String] - Metric: Optional[MetricType] - Statistic: Optional[StatisticType] - Period: Optional[PeriodType] + Source: String | None + Destination: String | None + Metric: MetricType | None + Statistic: StatisticType | None + Period: PeriodType | None -SubscriptionList = List[Subscription] +SubscriptionList = list[Subscription] class DescribeAwsNetworkPerformanceMetricSubscriptionsResult(TypedDict, total=False): - NextToken: Optional[String] - Subscriptions: Optional[SubscriptionList] + NextToken: String | None + Subscriptions: SubscriptionList | None class DescribeBundleTasksRequest(ServiceRequest): - BundleIds: Optional[BundleIdStringList] - DryRun: Optional[Boolean] - Filters: Optional[FilterList] + BundleIds: BundleIdStringList | None + DryRun: Boolean | None + Filters: FilterList | None class DescribeBundleTasksResult(TypedDict, total=False): - BundleTasks: Optional[BundleTaskList] + BundleTasks: BundleTaskList | None class DescribeByoipCidrsRequest(ServiceRequest): - DryRun: Optional[Boolean] + DryRun: Boolean | None MaxResults: DescribeByoipCidrsMaxResults - NextToken: Optional[NextToken] + NextToken: NextToken | None class DescribeByoipCidrsResult(TypedDict, total=False): - ByoipCidrs: Optional[ByoipCidrSet] - NextToken: Optional[String] + ByoipCidrs: ByoipCidrSet | None + NextToken: String | None class DescribeCapacityBlockExtensionHistoryRequest(ServiceRequest): - CapacityReservationIds: Optional[CapacityReservationIdSet] - NextToken: Optional[String] - MaxResults: Optional[DescribeFutureCapacityMaxResults] - Filters: Optional[FilterList] - DryRun: Optional[Boolean] + CapacityReservationIds: CapacityReservationIdSet | None + NextToken: String | None + MaxResults: DescribeFutureCapacityMaxResults | None + Filters: FilterList | None + DryRun: Boolean | None class DescribeCapacityBlockExtensionHistoryResult(TypedDict, total=False): - CapacityBlockExtensions: Optional[CapacityBlockExtensionSet] - NextToken: Optional[String] + CapacityBlockExtensions: CapacityBlockExtensionSet | None + NextToken: String | None class DescribeCapacityBlockExtensionOfferingsRequest(ServiceRequest): - DryRun: Optional[Boolean] + DryRun: Boolean | None CapacityBlockExtensionDurationHours: Integer CapacityReservationId: CapacityReservationId - NextToken: Optional[String] - MaxResults: Optional[DescribeCapacityBlockExtensionOfferingsMaxResults] + NextToken: String | None + MaxResults: DescribeCapacityBlockExtensionOfferingsMaxResults | None class DescribeCapacityBlockExtensionOfferingsResult(TypedDict, total=False): - CapacityBlockExtensionOfferings: Optional[CapacityBlockExtensionOfferingSet] - NextToken: Optional[String] + CapacityBlockExtensionOfferings: CapacityBlockExtensionOfferingSet | None + NextToken: String | None class DescribeCapacityBlockOfferingsRequest(ServiceRequest): - DryRun: Optional[Boolean] - InstanceType: Optional[String] - InstanceCount: Optional[Integer] - StartDateRange: Optional[MillisecondDateTime] - EndDateRange: Optional[MillisecondDateTime] + DryRun: Boolean | None + InstanceType: String | None + InstanceCount: Integer | None + StartDateRange: MillisecondDateTime | None + EndDateRange: MillisecondDateTime | None CapacityDurationHours: Integer - NextToken: Optional[String] - MaxResults: Optional[DescribeCapacityBlockOfferingsMaxResults] - UltraserverType: Optional[String] - UltraserverCount: Optional[Integer] + NextToken: String | None + MaxResults: DescribeCapacityBlockOfferingsMaxResults | None + UltraserverType: String | None + UltraserverCount: Integer | None + AllAvailabilityZones: Boolean | None class DescribeCapacityBlockOfferingsResult(TypedDict, total=False): - CapacityBlockOfferings: Optional[CapacityBlockOfferingSet] - NextToken: Optional[String] + CapacityBlockOfferings: CapacityBlockOfferingSet | None + NextToken: String | None class DescribeCapacityBlockStatusRequest(ServiceRequest): - CapacityBlockIds: Optional[CapacityBlockIds] - NextToken: Optional[String] - MaxResults: Optional[DescribeCapacityBlockStatusMaxResults] - Filters: Optional[FilterList] - DryRun: Optional[Boolean] + CapacityBlockIds: CapacityBlockIds | None + NextToken: String | None + MaxResults: DescribeCapacityBlockStatusMaxResults | None + Filters: FilterList | None + DryRun: Boolean | None class DescribeCapacityBlockStatusResult(TypedDict, total=False): - CapacityBlockStatuses: Optional[CapacityBlockStatusSet] - NextToken: Optional[String] + CapacityBlockStatuses: CapacityBlockStatusSet | None + NextToken: String | None class DescribeCapacityBlocksRequest(ServiceRequest): - CapacityBlockIds: Optional[CapacityBlockIds] - NextToken: Optional[String] - MaxResults: Optional[DescribeCapacityBlocksMaxResults] - Filters: Optional[FilterList] - DryRun: Optional[Boolean] + CapacityBlockIds: CapacityBlockIds | None + NextToken: String | None + MaxResults: DescribeCapacityBlocksMaxResults | None + Filters: FilterList | None + DryRun: Boolean | None class DescribeCapacityBlocksResult(TypedDict, total=False): - CapacityBlocks: Optional[CapacityBlockSet] - NextToken: Optional[String] + CapacityBlocks: CapacityBlockSet | None + NextToken: String | None + + +class DescribeCapacityManagerDataExportsRequest(ServiceRequest): + CapacityManagerDataExportIds: CapacityManagerDataExportIdSet | None + MaxResults: DescribeCapacityManagerDataExportsRequestMaxResults | None + NextToken: String | None + DryRun: Boolean | None + Filters: FilterList | None + + +class DescribeCapacityManagerDataExportsResult(TypedDict, total=False): + CapacityManagerDataExports: CapacityManagerDataExportResponseSet | None + NextToken: String | None class DescribeCapacityReservationBillingRequestsRequest(ServiceRequest): - CapacityReservationIds: Optional[CapacityReservationIdSet] + CapacityReservationIds: CapacityReservationIdSet | None Role: CallerRole - NextToken: Optional[String] - MaxResults: Optional[DescribeCapacityReservationBillingRequestsRequestMaxResults] - Filters: Optional[FilterList] - DryRun: Optional[Boolean] + NextToken: String | None + MaxResults: DescribeCapacityReservationBillingRequestsRequestMaxResults | None + Filters: FilterList | None + DryRun: Boolean | None class DescribeCapacityReservationBillingRequestsResult(TypedDict, total=False): - NextToken: Optional[String] - CapacityReservationBillingRequests: Optional[CapacityReservationBillingRequestSet] + NextToken: String | None + CapacityReservationBillingRequests: CapacityReservationBillingRequestSet | None class DescribeCapacityReservationFleetsRequest(ServiceRequest): - CapacityReservationFleetIds: Optional[CapacityReservationFleetIdSet] - NextToken: Optional[String] - MaxResults: Optional[DescribeCapacityReservationFleetsMaxResults] - Filters: Optional[FilterList] - DryRun: Optional[Boolean] + CapacityReservationFleetIds: CapacityReservationFleetIdSet | None + NextToken: String | None + MaxResults: DescribeCapacityReservationFleetsMaxResults | None + Filters: FilterList | None + DryRun: Boolean | None class DescribeCapacityReservationFleetsResult(TypedDict, total=False): - CapacityReservationFleets: Optional[CapacityReservationFleetSet] - NextToken: Optional[String] + CapacityReservationFleets: CapacityReservationFleetSet | None + NextToken: String | None + + +class DescribeCapacityReservationTopologyRequest(ServiceRequest): + DryRun: Boolean | None + NextToken: String | None + MaxResults: DescribeCapacityReservationTopologyMaxResults | None + CapacityReservationIds: CapacityReservationIdSet | None + Filters: FilterList | None + + +class DescribeCapacityReservationTopologyResult(TypedDict, total=False): + NextToken: String | None + CapacityReservations: CapacityReservationTopologySet | None class DescribeCapacityReservationsRequest(ServiceRequest): - CapacityReservationIds: Optional[CapacityReservationIdSet] - NextToken: Optional[String] - MaxResults: Optional[DescribeCapacityReservationsMaxResults] - Filters: Optional[FilterList] - DryRun: Optional[Boolean] + CapacityReservationIds: CapacityReservationIdSet | None + NextToken: String | None + MaxResults: DescribeCapacityReservationsMaxResults | None + Filters: FilterList | None + DryRun: Boolean | None class DescribeCapacityReservationsResult(TypedDict, total=False): - NextToken: Optional[String] - CapacityReservations: Optional[CapacityReservationSet] + NextToken: String | None + CapacityReservations: CapacityReservationSet | None class DescribeCarrierGatewaysRequest(ServiceRequest): - CarrierGatewayIds: Optional[CarrierGatewayIdSet] - Filters: Optional[FilterList] - MaxResults: Optional[CarrierGatewayMaxResults] - NextToken: Optional[String] - DryRun: Optional[Boolean] + CarrierGatewayIds: CarrierGatewayIdSet | None + Filters: FilterList | None + MaxResults: CarrierGatewayMaxResults | None + NextToken: String | None + DryRun: Boolean | None class DescribeCarrierGatewaysResult(TypedDict, total=False): - CarrierGateways: Optional[CarrierGatewaySet] - NextToken: Optional[String] + CarrierGateways: CarrierGatewaySet | None + NextToken: String | None -InstanceIdStringList = List[InstanceId] +InstanceIdStringList = list[InstanceId] class DescribeClassicLinkInstancesRequest(ServiceRequest): - DryRun: Optional[Boolean] - InstanceIds: Optional[InstanceIdStringList] - Filters: Optional[FilterList] - NextToken: Optional[String] - MaxResults: Optional[DescribeClassicLinkInstancesMaxResults] + DryRun: Boolean | None + InstanceIds: InstanceIdStringList | None + Filters: FilterList | None + NextToken: String | None + MaxResults: DescribeClassicLinkInstancesMaxResults | None class DescribeClassicLinkInstancesResult(TypedDict, total=False): - Instances: Optional[ClassicLinkInstanceList] - NextToken: Optional[String] + Instances: ClassicLinkInstanceList | None + NextToken: String | None class DescribeClientVpnAuthorizationRulesRequest(ServiceRequest): ClientVpnEndpointId: ClientVpnEndpointId - DryRun: Optional[Boolean] - NextToken: Optional[NextToken] - Filters: Optional[FilterList] - MaxResults: Optional[DescribeClientVpnAuthorizationRulesMaxResults] + DryRun: Boolean | None + NextToken: NextToken | None + Filters: FilterList | None + MaxResults: DescribeClientVpnAuthorizationRulesMaxResults | None class DescribeClientVpnAuthorizationRulesResult(TypedDict, total=False): - AuthorizationRules: Optional[AuthorizationRuleSet] - NextToken: Optional[NextToken] + AuthorizationRules: AuthorizationRuleSet | None + NextToken: NextToken | None class DescribeClientVpnConnectionsRequest(ServiceRequest): ClientVpnEndpointId: ClientVpnEndpointId - Filters: Optional[FilterList] - NextToken: Optional[NextToken] - MaxResults: Optional[DescribeClientVpnConnectionsMaxResults] - DryRun: Optional[Boolean] + Filters: FilterList | None + NextToken: NextToken | None + MaxResults: DescribeClientVpnConnectionsMaxResults | None + DryRun: Boolean | None class DescribeClientVpnConnectionsResult(TypedDict, total=False): - Connections: Optional[ClientVpnConnectionSet] - NextToken: Optional[NextToken] + Connections: ClientVpnConnectionSet | None + NextToken: NextToken | None class DescribeClientVpnEndpointsRequest(ServiceRequest): - ClientVpnEndpointIds: Optional[ClientVpnEndpointIdList] - MaxResults: Optional[DescribeClientVpnEndpointMaxResults] - NextToken: Optional[NextToken] - Filters: Optional[FilterList] - DryRun: Optional[Boolean] + ClientVpnEndpointIds: ClientVpnEndpointIdList | None + MaxResults: DescribeClientVpnEndpointMaxResults | None + NextToken: NextToken | None + Filters: FilterList | None + DryRun: Boolean | None -EndpointSet = List[ClientVpnEndpoint] +EndpointSet = list[ClientVpnEndpoint] class DescribeClientVpnEndpointsResult(TypedDict, total=False): - ClientVpnEndpoints: Optional[EndpointSet] - NextToken: Optional[NextToken] + ClientVpnEndpoints: EndpointSet | None + NextToken: NextToken | None class DescribeClientVpnRoutesRequest(ServiceRequest): ClientVpnEndpointId: ClientVpnEndpointId - Filters: Optional[FilterList] - MaxResults: Optional[DescribeClientVpnRoutesMaxResults] - NextToken: Optional[NextToken] - DryRun: Optional[Boolean] + Filters: FilterList | None + MaxResults: DescribeClientVpnRoutesMaxResults | None + NextToken: NextToken | None + DryRun: Boolean | None class DescribeClientVpnRoutesResult(TypedDict, total=False): - Routes: Optional[ClientVpnRouteSet] - NextToken: Optional[NextToken] + Routes: ClientVpnRouteSet | None + NextToken: NextToken | None class DescribeClientVpnTargetNetworksRequest(ServiceRequest): ClientVpnEndpointId: ClientVpnEndpointId - AssociationIds: Optional[ValueStringList] - MaxResults: Optional[DescribeClientVpnTargetNetworksMaxResults] - NextToken: Optional[NextToken] - Filters: Optional[FilterList] - DryRun: Optional[Boolean] + AssociationIds: ValueStringList | None + MaxResults: DescribeClientVpnTargetNetworksMaxResults | None + NextToken: NextToken | None + Filters: FilterList | None + DryRun: Boolean | None class TargetNetwork(TypedDict, total=False): - AssociationId: Optional[String] - VpcId: Optional[String] - TargetNetworkId: Optional[String] - ClientVpnEndpointId: Optional[String] - Status: Optional[AssociationStatus] - SecurityGroups: Optional[ValueStringList] + AssociationId: String | None + VpcId: String | None + TargetNetworkId: String | None + ClientVpnEndpointId: String | None + Status: AssociationStatus | None + SecurityGroups: ValueStringList | None -TargetNetworkSet = List[TargetNetwork] +TargetNetworkSet = list[TargetNetwork] class DescribeClientVpnTargetNetworksResult(TypedDict, total=False): - ClientVpnTargetNetworks: Optional[TargetNetworkSet] - NextToken: Optional[NextToken] + ClientVpnTargetNetworks: TargetNetworkSet | None + NextToken: NextToken | None class DescribeCoipPoolsRequest(ServiceRequest): - PoolIds: Optional[CoipPoolIdSet] - Filters: Optional[FilterList] - MaxResults: Optional[CoipPoolMaxResults] - NextToken: Optional[String] - DryRun: Optional[Boolean] + PoolIds: CoipPoolIdSet | None + Filters: FilterList | None + MaxResults: CoipPoolMaxResults | None + NextToken: String | None + DryRun: Boolean | None class DescribeCoipPoolsResult(TypedDict, total=False): - CoipPools: Optional[CoipPoolSet] - NextToken: Optional[String] + CoipPools: CoipPoolSet | None + NextToken: String | None -DescribeConversionTaskList = List[ConversionTask] +DescribeConversionTaskList = list[ConversionTask] class DescribeConversionTasksRequest(ServiceRequest): - DryRun: Optional[Boolean] - ConversionTaskIds: Optional[ConversionIdStringList] + DryRun: Boolean | None + ConversionTaskIds: ConversionIdStringList | None class DescribeConversionTasksResult(TypedDict, total=False): - ConversionTasks: Optional[DescribeConversionTaskList] + ConversionTasks: DescribeConversionTaskList | None class DescribeCustomerGatewaysRequest(ServiceRequest): - CustomerGatewayIds: Optional[CustomerGatewayIdStringList] - Filters: Optional[FilterList] - DryRun: Optional[Boolean] + CustomerGatewayIds: CustomerGatewayIdStringList | None + Filters: FilterList | None + DryRun: Boolean | None class DescribeCustomerGatewaysResult(TypedDict, total=False): - CustomerGateways: Optional[CustomerGatewayList] + CustomerGateways: CustomerGatewayList | None class DescribeDeclarativePoliciesReportsRequest(ServiceRequest): - DryRun: Optional[Boolean] - NextToken: Optional[String] - MaxResults: Optional[DeclarativePoliciesMaxResults] - ReportIds: Optional[ValueStringList] + DryRun: Boolean | None + NextToken: String | None + MaxResults: DeclarativePoliciesMaxResults | None + ReportIds: ValueStringList | None class DescribeDeclarativePoliciesReportsResult(TypedDict, total=False): - NextToken: Optional[String] - Reports: Optional[DeclarativePoliciesReportList] + NextToken: String | None + Reports: DeclarativePoliciesReportList | None -DhcpOptionsIdStringList = List[DhcpOptionsId] +DhcpOptionsIdStringList = list[DhcpOptionsId] class DescribeDhcpOptionsRequest(ServiceRequest): - DhcpOptionsIds: Optional[DhcpOptionsIdStringList] - NextToken: Optional[String] - MaxResults: Optional[DescribeDhcpOptionsMaxResults] - DryRun: Optional[Boolean] - Filters: Optional[FilterList] + DhcpOptionsIds: DhcpOptionsIdStringList | None + NextToken: String | None + MaxResults: DescribeDhcpOptionsMaxResults | None + DryRun: Boolean | None + Filters: FilterList | None -DhcpOptionsList = List[DhcpOptions] +DhcpOptionsList = list[DhcpOptions] class DescribeDhcpOptionsResult(TypedDict, total=False): - NextToken: Optional[String] - DhcpOptions: Optional[DhcpOptionsList] + NextToken: String | None + DhcpOptions: DhcpOptionsList | None -EgressOnlyInternetGatewayIdList = List[EgressOnlyInternetGatewayId] +EgressOnlyInternetGatewayIdList = list[EgressOnlyInternetGatewayId] class DescribeEgressOnlyInternetGatewaysRequest(ServiceRequest): - DryRun: Optional[Boolean] - EgressOnlyInternetGatewayIds: Optional[EgressOnlyInternetGatewayIdList] - MaxResults: Optional[DescribeEgressOnlyInternetGatewaysMaxResults] - NextToken: Optional[String] - Filters: Optional[FilterList] + DryRun: Boolean | None + EgressOnlyInternetGatewayIds: EgressOnlyInternetGatewayIdList | None + MaxResults: DescribeEgressOnlyInternetGatewaysMaxResults | None + NextToken: String | None + Filters: FilterList | None -EgressOnlyInternetGatewayList = List[EgressOnlyInternetGateway] +EgressOnlyInternetGatewayList = list[EgressOnlyInternetGateway] class DescribeEgressOnlyInternetGatewaysResult(TypedDict, total=False): - EgressOnlyInternetGateways: Optional[EgressOnlyInternetGatewayList] - NextToken: Optional[String] + EgressOnlyInternetGateways: EgressOnlyInternetGatewayList | None + NextToken: String | None -ElasticGpuIdSet = List[ElasticGpuId] +ElasticGpuIdSet = list[ElasticGpuId] class DescribeElasticGpusRequest(ServiceRequest): - ElasticGpuIds: Optional[ElasticGpuIdSet] - DryRun: Optional[Boolean] - Filters: Optional[FilterList] - MaxResults: Optional[DescribeElasticGpusMaxResults] - NextToken: Optional[String] + ElasticGpuIds: ElasticGpuIdSet | None + DryRun: Boolean | None + Filters: FilterList | None + MaxResults: DescribeElasticGpusMaxResults | None + NextToken: String | None class ElasticGpuHealth(TypedDict, total=False): - Status: Optional[ElasticGpuStatus] + Status: ElasticGpuStatus | None class ElasticGpus(TypedDict, total=False): - ElasticGpuId: Optional[String] - AvailabilityZone: Optional[String] - ElasticGpuType: Optional[String] - ElasticGpuHealth: Optional[ElasticGpuHealth] - ElasticGpuState: Optional[ElasticGpuState] - InstanceId: Optional[String] - Tags: Optional[TagList] + ElasticGpuId: String | None + AvailabilityZone: String | None + ElasticGpuType: String | None + ElasticGpuHealth: ElasticGpuHealth | None + ElasticGpuState: ElasticGpuState | None + InstanceId: String | None + Tags: TagList | None -ElasticGpuSet = List[ElasticGpus] +ElasticGpuSet = list[ElasticGpus] class DescribeElasticGpusResult(TypedDict, total=False): - ElasticGpuSet: Optional[ElasticGpuSet] - MaxResults: Optional[Integer] - NextToken: Optional[String] + ElasticGpuSet: ElasticGpuSet | None + MaxResults: Integer | None + NextToken: String | None -ExportImageTaskIdList = List[ExportImageTaskId] +ExportImageTaskIdList = list[ExportImageTaskId] class DescribeExportImageTasksRequest(ServiceRequest): - DryRun: Optional[Boolean] - Filters: Optional[FilterList] - ExportImageTaskIds: Optional[ExportImageTaskIdList] - MaxResults: Optional[DescribeExportImageTasksMaxResults] - NextToken: Optional[NextToken] + DryRun: Boolean | None + Filters: FilterList | None + ExportImageTaskIds: ExportImageTaskIdList | None + MaxResults: DescribeExportImageTasksMaxResults | None + NextToken: NextToken | None class ExportTaskS3Location(TypedDict, total=False): - S3Bucket: Optional[String] - S3Prefix: Optional[String] + S3Bucket: String | None + S3Prefix: String | None class ExportImageTask(TypedDict, total=False): - Description: Optional[String] - ExportImageTaskId: Optional[String] - ImageId: Optional[String] - Progress: Optional[String] - S3ExportLocation: Optional[ExportTaskS3Location] - Status: Optional[String] - StatusMessage: Optional[String] - Tags: Optional[TagList] + Description: String | None + ExportImageTaskId: String | None + ImageId: String | None + Progress: String | None + S3ExportLocation: ExportTaskS3Location | None + Status: String | None + StatusMessage: String | None + Tags: TagList | None -ExportImageTaskList = List[ExportImageTask] +ExportImageTaskList = list[ExportImageTask] class DescribeExportImageTasksResult(TypedDict, total=False): - ExportImageTasks: Optional[ExportImageTaskList] - NextToken: Optional[NextToken] + ExportImageTasks: ExportImageTaskList | None + NextToken: NextToken | None -ExportTaskIdStringList = List[ExportTaskId] +ExportTaskIdStringList = list[ExportTaskId] class DescribeExportTasksRequest(ServiceRequest): - Filters: Optional[FilterList] - ExportTaskIds: Optional[ExportTaskIdStringList] + Filters: FilterList | None + ExportTaskIds: ExportTaskIdStringList | None -ExportTaskList = List[ExportTask] +ExportTaskList = list[ExportTask] class DescribeExportTasksResult(TypedDict, total=False): - ExportTasks: Optional[ExportTaskList] + ExportTasks: ExportTaskList | None -FastLaunchImageIdList = List[ImageId] +FastLaunchImageIdList = list[ImageId] class DescribeFastLaunchImagesRequest(ServiceRequest): - ImageIds: Optional[FastLaunchImageIdList] - Filters: Optional[FilterList] - MaxResults: Optional[DescribeFastLaunchImagesRequestMaxResults] - NextToken: Optional[NextToken] - DryRun: Optional[Boolean] + ImageIds: FastLaunchImageIdList | None + Filters: FilterList | None + MaxResults: DescribeFastLaunchImagesRequestMaxResults | None + NextToken: NextToken | None + DryRun: Boolean | None class FastLaunchLaunchTemplateSpecificationResponse(TypedDict, total=False): - LaunchTemplateId: Optional[LaunchTemplateId] - LaunchTemplateName: Optional[String] - Version: Optional[String] + LaunchTemplateId: LaunchTemplateId | None + LaunchTemplateName: String | None + Version: String | None class FastLaunchSnapshotConfigurationResponse(TypedDict, total=False): - TargetResourceCount: Optional[Integer] + TargetResourceCount: Integer | None class DescribeFastLaunchImagesSuccessItem(TypedDict, total=False): - ImageId: Optional[ImageId] - ResourceType: Optional[FastLaunchResourceType] - SnapshotConfiguration: Optional[FastLaunchSnapshotConfigurationResponse] - LaunchTemplate: Optional[FastLaunchLaunchTemplateSpecificationResponse] - MaxParallelLaunches: Optional[Integer] - OwnerId: Optional[String] - State: Optional[FastLaunchStateCode] - StateTransitionReason: Optional[String] - StateTransitionTime: Optional[MillisecondDateTime] + ImageId: ImageId | None + ResourceType: FastLaunchResourceType | None + SnapshotConfiguration: FastLaunchSnapshotConfigurationResponse | None + LaunchTemplate: FastLaunchLaunchTemplateSpecificationResponse | None + MaxParallelLaunches: Integer | None + OwnerId: String | None + State: FastLaunchStateCode | None + StateTransitionReason: String | None + StateTransitionTime: MillisecondDateTime | None -DescribeFastLaunchImagesSuccessSet = List[DescribeFastLaunchImagesSuccessItem] +DescribeFastLaunchImagesSuccessSet = list[DescribeFastLaunchImagesSuccessItem] class DescribeFastLaunchImagesResult(TypedDict, total=False): - FastLaunchImages: Optional[DescribeFastLaunchImagesSuccessSet] - NextToken: Optional[NextToken] + FastLaunchImages: DescribeFastLaunchImagesSuccessSet | None + NextToken: NextToken | None class DescribeFastSnapshotRestoreSuccessItem(TypedDict, total=False): - SnapshotId: Optional[String] - AvailabilityZone: Optional[String] - State: Optional[FastSnapshotRestoreStateCode] - StateTransitionReason: Optional[String] - OwnerId: Optional[String] - OwnerAlias: Optional[String] - EnablingTime: Optional[MillisecondDateTime] - OptimizingTime: Optional[MillisecondDateTime] - EnabledTime: Optional[MillisecondDateTime] - DisablingTime: Optional[MillisecondDateTime] - DisabledTime: Optional[MillisecondDateTime] + SnapshotId: String | None + AvailabilityZone: String | None + AvailabilityZoneId: String | None + State: FastSnapshotRestoreStateCode | None + StateTransitionReason: String | None + OwnerId: String | None + OwnerAlias: String | None + EnablingTime: MillisecondDateTime | None + OptimizingTime: MillisecondDateTime | None + EnabledTime: MillisecondDateTime | None + DisablingTime: MillisecondDateTime | None + DisabledTime: MillisecondDateTime | None -DescribeFastSnapshotRestoreSuccessSet = List[DescribeFastSnapshotRestoreSuccessItem] +DescribeFastSnapshotRestoreSuccessSet = list[DescribeFastSnapshotRestoreSuccessItem] class DescribeFastSnapshotRestoresRequest(ServiceRequest): - Filters: Optional[FilterList] - MaxResults: Optional[DescribeFastSnapshotRestoresMaxResults] - NextToken: Optional[NextToken] - DryRun: Optional[Boolean] + Filters: FilterList | None + MaxResults: DescribeFastSnapshotRestoresMaxResults | None + NextToken: NextToken | None + DryRun: Boolean | None class DescribeFastSnapshotRestoresResult(TypedDict, total=False): - FastSnapshotRestores: Optional[DescribeFastSnapshotRestoreSuccessSet] - NextToken: Optional[NextToken] + FastSnapshotRestores: DescribeFastSnapshotRestoreSuccessSet | None + NextToken: NextToken | None class DescribeFleetError(TypedDict, total=False): - LaunchTemplateAndOverrides: Optional[LaunchTemplateAndOverridesResponse] - Lifecycle: Optional[InstanceLifecycle] - ErrorCode: Optional[String] - ErrorMessage: Optional[String] + LaunchTemplateAndOverrides: LaunchTemplateAndOverridesResponse | None + Lifecycle: InstanceLifecycle | None + ErrorCode: String | None + ErrorMessage: String | None class DescribeFleetHistoryRequest(ServiceRequest): - DryRun: Optional[Boolean] - EventType: Optional[FleetEventType] - MaxResults: Optional[Integer] - NextToken: Optional[String] + DryRun: Boolean | None + EventType: FleetEventType | None + MaxResults: Integer | None + NextToken: String | None FleetId: FleetId StartTime: DateTime class EventInformation(TypedDict, total=False): - EventDescription: Optional[String] - EventSubType: Optional[String] - InstanceId: Optional[String] + EventDescription: String | None + EventSubType: String | None + InstanceId: String | None class HistoryRecordEntry(TypedDict, total=False): - EventInformation: Optional[EventInformation] - EventType: Optional[FleetEventType] - Timestamp: Optional[DateTime] + EventInformation: EventInformation | None + EventType: FleetEventType | None + Timestamp: DateTime | None -HistoryRecordSet = List[HistoryRecordEntry] +HistoryRecordSet = list[HistoryRecordEntry] class DescribeFleetHistoryResult(TypedDict, total=False): - HistoryRecords: Optional[HistoryRecordSet] - LastEvaluatedTime: Optional[DateTime] - NextToken: Optional[String] - FleetId: Optional[FleetId] - StartTime: Optional[DateTime] + HistoryRecords: HistoryRecordSet | None + LastEvaluatedTime: DateTime | None + NextToken: String | None + FleetId: FleetId | None + StartTime: DateTime | None class DescribeFleetInstancesRequest(ServiceRequest): - DryRun: Optional[Boolean] - MaxResults: Optional[Integer] - NextToken: Optional[String] + DryRun: Boolean | None + MaxResults: Integer | None + NextToken: String | None FleetId: FleetId - Filters: Optional[FilterList] + Filters: FilterList | None class DescribeFleetInstancesResult(TypedDict, total=False): - ActiveInstances: Optional[ActiveInstanceSet] - NextToken: Optional[String] - FleetId: Optional[FleetId] + ActiveInstances: ActiveInstanceSet | None + NextToken: String | None + FleetId: FleetId | None -DescribeFleetsErrorSet = List[DescribeFleetError] +DescribeFleetsErrorSet = list[DescribeFleetError] class DescribeFleetsInstances(TypedDict, total=False): - LaunchTemplateAndOverrides: Optional[LaunchTemplateAndOverridesResponse] - Lifecycle: Optional[InstanceLifecycle] - InstanceIds: Optional[InstanceIdsSet] - InstanceType: Optional[InstanceType] - Platform: Optional[PlatformValues] + LaunchTemplateAndOverrides: LaunchTemplateAndOverridesResponse | None + Lifecycle: InstanceLifecycle | None + InstanceIds: InstanceIdsSet | None + InstanceType: InstanceType | None + Platform: PlatformValues | None -DescribeFleetsInstancesSet = List[DescribeFleetsInstances] +DescribeFleetsInstancesSet = list[DescribeFleetsInstances] class DescribeFleetsRequest(ServiceRequest): - DryRun: Optional[Boolean] - MaxResults: Optional[Integer] - NextToken: Optional[String] - FleetIds: Optional[FleetIdSet] - Filters: Optional[FilterList] + DryRun: Boolean | None + MaxResults: Integer | None + NextToken: String | None + FleetIds: FleetIdSet | None + Filters: FilterList | None class OnDemandOptions(TypedDict, total=False): - AllocationStrategy: Optional[FleetOnDemandAllocationStrategy] - CapacityReservationOptions: Optional[CapacityReservationOptions] - SingleInstanceType: Optional[Boolean] - SingleAvailabilityZone: Optional[Boolean] - MinTargetCapacity: Optional[Integer] - MaxTotalPrice: Optional[String] + AllocationStrategy: FleetOnDemandAllocationStrategy | None + CapacityReservationOptions: CapacityReservationOptions | None + SingleInstanceType: Boolean | None + SingleAvailabilityZone: Boolean | None + MinTargetCapacity: Integer | None + MaxTotalPrice: String | None class FleetSpotCapacityRebalance(TypedDict, total=False): - ReplacementStrategy: Optional[FleetReplacementStrategy] - TerminationDelay: Optional[Integer] + ReplacementStrategy: FleetReplacementStrategy | None + TerminationDelay: Integer | None class FleetSpotMaintenanceStrategies(TypedDict, total=False): - CapacityRebalance: Optional[FleetSpotCapacityRebalance] + CapacityRebalance: FleetSpotCapacityRebalance | None class SpotOptions(TypedDict, total=False): - AllocationStrategy: Optional[SpotAllocationStrategy] - MaintenanceStrategies: Optional[FleetSpotMaintenanceStrategies] - InstanceInterruptionBehavior: Optional[SpotInstanceInterruptionBehavior] - InstancePoolsToUseCount: Optional[Integer] - SingleInstanceType: Optional[Boolean] - SingleAvailabilityZone: Optional[Boolean] - MinTargetCapacity: Optional[Integer] - MaxTotalPrice: Optional[String] + AllocationStrategy: SpotAllocationStrategy | None + MaintenanceStrategies: FleetSpotMaintenanceStrategies | None + InstanceInterruptionBehavior: SpotInstanceInterruptionBehavior | None + InstancePoolsToUseCount: Integer | None + SingleInstanceType: Boolean | None + SingleAvailabilityZone: Boolean | None + MinTargetCapacity: Integer | None + MaxTotalPrice: String | None class TargetCapacitySpecification(TypedDict, total=False): - TotalTargetCapacity: Optional[Integer] - OnDemandTargetCapacity: Optional[Integer] - SpotTargetCapacity: Optional[Integer] - DefaultTargetCapacityType: Optional[DefaultTargetCapacityType] - TargetCapacityUnitType: Optional[TargetCapacityUnitType] + TotalTargetCapacity: Integer | None + OnDemandTargetCapacity: Integer | None + SpotTargetCapacity: Integer | None + DefaultTargetCapacityType: DefaultTargetCapacityType | None + TargetCapacityUnitType: TargetCapacityUnitType | None -FleetLaunchTemplateOverridesList = List[FleetLaunchTemplateOverrides] +FleetLaunchTemplateOverridesList = list[FleetLaunchTemplateOverrides] class FleetLaunchTemplateConfig(TypedDict, total=False): - LaunchTemplateSpecification: Optional[FleetLaunchTemplateSpecification] - Overrides: Optional[FleetLaunchTemplateOverridesList] + LaunchTemplateSpecification: FleetLaunchTemplateSpecification | None + Overrides: FleetLaunchTemplateOverridesList | None -FleetLaunchTemplateConfigList = List[FleetLaunchTemplateConfig] +FleetLaunchTemplateConfigList = list[FleetLaunchTemplateConfig] class FleetData(TypedDict, total=False): - ActivityStatus: Optional[FleetActivityStatus] - CreateTime: Optional[DateTime] - FleetId: Optional[FleetId] - FleetState: Optional[FleetStateCode] - ClientToken: Optional[String] - ExcessCapacityTerminationPolicy: Optional[FleetExcessCapacityTerminationPolicy] - FulfilledCapacity: Optional[Double] - FulfilledOnDemandCapacity: Optional[Double] - LaunchTemplateConfigs: Optional[FleetLaunchTemplateConfigList] - TargetCapacitySpecification: Optional[TargetCapacitySpecification] - TerminateInstancesWithExpiration: Optional[Boolean] - Type: Optional[FleetType] - ValidFrom: Optional[DateTime] - ValidUntil: Optional[DateTime] - ReplaceUnhealthyInstances: Optional[Boolean] - SpotOptions: Optional[SpotOptions] - OnDemandOptions: Optional[OnDemandOptions] - Tags: Optional[TagList] - Errors: Optional[DescribeFleetsErrorSet] - Instances: Optional[DescribeFleetsInstancesSet] - Context: Optional[String] - - -FleetSet = List[FleetData] + ActivityStatus: FleetActivityStatus | None + CreateTime: DateTime | None + FleetId: FleetId | None + FleetState: FleetStateCode | None + ClientToken: String | None + ExcessCapacityTerminationPolicy: FleetExcessCapacityTerminationPolicy | None + FulfilledCapacity: Double | None + FulfilledOnDemandCapacity: Double | None + LaunchTemplateConfigs: FleetLaunchTemplateConfigList | None + TargetCapacitySpecification: TargetCapacitySpecification | None + TerminateInstancesWithExpiration: Boolean | None + Type: FleetType | None + ValidFrom: DateTime | None + ValidUntil: DateTime | None + ReplaceUnhealthyInstances: Boolean | None + SpotOptions: SpotOptions | None + OnDemandOptions: OnDemandOptions | None + Tags: TagList | None + Errors: DescribeFleetsErrorSet | None + Instances: DescribeFleetsInstancesSet | None + Context: String | None + + +FleetSet = list[FleetData] class DescribeFleetsResult(TypedDict, total=False): - NextToken: Optional[String] - Fleets: Optional[FleetSet] + NextToken: String | None + Fleets: FleetSet | None class DescribeFlowLogsRequest(ServiceRequest): - DryRun: Optional[Boolean] - Filter: Optional[FilterList] - FlowLogIds: Optional[FlowLogIdList] - MaxResults: Optional[Integer] - NextToken: Optional[String] + DryRun: Boolean | None + Filter: FilterList | None + FlowLogIds: FlowLogIdList | None + MaxResults: Integer | None + NextToken: String | None class DestinationOptionsResponse(TypedDict, total=False): - FileFormat: Optional[DestinationFileFormat] - HiveCompatiblePartitions: Optional[Boolean] - PerHourPartition: Optional[Boolean] + FileFormat: DestinationFileFormat | None + HiveCompatiblePartitions: Boolean | None + PerHourPartition: Boolean | None class FlowLog(TypedDict, total=False): - CreationTime: Optional[MillisecondDateTime] - DeliverLogsErrorMessage: Optional[String] - DeliverLogsPermissionArn: Optional[String] - DeliverCrossAccountRole: Optional[String] - DeliverLogsStatus: Optional[String] - FlowLogId: Optional[String] - FlowLogStatus: Optional[String] - LogGroupName: Optional[String] - ResourceId: Optional[String] - TrafficType: Optional[TrafficType] - LogDestinationType: Optional[LogDestinationType] - LogDestination: Optional[String] - LogFormat: Optional[String] - Tags: Optional[TagList] - MaxAggregationInterval: Optional[Integer] - DestinationOptions: Optional[DestinationOptionsResponse] - - -FlowLogSet = List[FlowLog] + CreationTime: MillisecondDateTime | None + DeliverLogsErrorMessage: String | None + DeliverLogsPermissionArn: String | None + DeliverCrossAccountRole: String | None + DeliverLogsStatus: String | None + FlowLogId: String | None + FlowLogStatus: String | None + LogGroupName: String | None + ResourceId: String | None + TrafficType: TrafficType | None + LogDestinationType: LogDestinationType | None + LogDestination: String | None + LogFormat: String | None + Tags: TagList | None + MaxAggregationInterval: Integer | None + DestinationOptions: DestinationOptionsResponse | None + + +FlowLogSet = list[FlowLog] class DescribeFlowLogsResult(TypedDict, total=False): - FlowLogs: Optional[FlowLogSet] - NextToken: Optional[String] + FlowLogs: FlowLogSet | None + NextToken: String | None class DescribeFpgaImageAttributeRequest(ServiceRequest): - DryRun: Optional[Boolean] + DryRun: Boolean | None FpgaImageId: FpgaImageId Attribute: FpgaImageAttributeName class ProductCode(TypedDict, total=False): - ProductCodeId: Optional[String] - ProductCodeType: Optional[ProductCodeValues] + ProductCodeId: String | None + ProductCodeType: ProductCodeValues | None -ProductCodeList = List[ProductCode] +ProductCodeList = list[ProductCode] class LoadPermission(TypedDict, total=False): - UserId: Optional[String] - Group: Optional[PermissionGroup] + UserId: String | None + Group: PermissionGroup | None -LoadPermissionList = List[LoadPermission] +LoadPermissionList = list[LoadPermission] class FpgaImageAttribute(TypedDict, total=False): - FpgaImageId: Optional[String] - Name: Optional[String] - Description: Optional[String] - LoadPermissions: Optional[LoadPermissionList] - ProductCodes: Optional[ProductCodeList] + FpgaImageId: String | None + Name: String | None + Description: String | None + LoadPermissions: LoadPermissionList | None + ProductCodes: ProductCodeList | None class DescribeFpgaImageAttributeResult(TypedDict, total=False): - FpgaImageAttribute: Optional[FpgaImageAttribute] + FpgaImageAttribute: FpgaImageAttribute | None -OwnerStringList = List[String] -FpgaImageIdList = List[FpgaImageId] +OwnerStringList = list[String] +FpgaImageIdList = list[FpgaImageId] class DescribeFpgaImagesRequest(ServiceRequest): - DryRun: Optional[Boolean] - FpgaImageIds: Optional[FpgaImageIdList] - Owners: Optional[OwnerStringList] - Filters: Optional[FilterList] - NextToken: Optional[NextToken] - MaxResults: Optional[DescribeFpgaImagesMaxResults] + DryRun: Boolean | None + FpgaImageIds: FpgaImageIdList | None + Owners: OwnerStringList | None + Filters: FilterList | None + NextToken: NextToken | None + MaxResults: DescribeFpgaImagesMaxResults | None -InstanceTypesList = List[String] +InstanceTypesList = list[String] class FpgaImageState(TypedDict, total=False): - Code: Optional[FpgaImageStateCode] - Message: Optional[String] + Code: FpgaImageStateCode | None + Message: String | None class PciId(TypedDict, total=False): - DeviceId: Optional[String] - VendorId: Optional[String] - SubsystemId: Optional[String] - SubsystemVendorId: Optional[String] + DeviceId: String | None + VendorId: String | None + SubsystemId: String | None + SubsystemVendorId: String | None class FpgaImage(TypedDict, total=False): - FpgaImageId: Optional[String] - FpgaImageGlobalId: Optional[String] - Name: Optional[String] - Description: Optional[String] - ShellVersion: Optional[String] - PciId: Optional[PciId] - State: Optional[FpgaImageState] - CreateTime: Optional[DateTime] - UpdateTime: Optional[DateTime] - OwnerId: Optional[String] - OwnerAlias: Optional[String] - ProductCodes: Optional[ProductCodeList] - Tags: Optional[TagList] - Public: Optional[Boolean] - DataRetentionSupport: Optional[Boolean] - InstanceTypes: Optional[InstanceTypesList] - - -FpgaImageList = List[FpgaImage] + FpgaImageId: String | None + FpgaImageGlobalId: String | None + Name: String | None + Description: String | None + ShellVersion: String | None + PciId: PciId | None + State: FpgaImageState | None + CreateTime: DateTime | None + UpdateTime: DateTime | None + OwnerId: String | None + OwnerAlias: String | None + ProductCodes: ProductCodeList | None + Tags: TagList | None + Public: Boolean | None + DataRetentionSupport: Boolean | None + InstanceTypes: InstanceTypesList | None + + +FpgaImageList = list[FpgaImage] class DescribeFpgaImagesResult(TypedDict, total=False): - FpgaImages: Optional[FpgaImageList] - NextToken: Optional[NextToken] + FpgaImages: FpgaImageList | None + NextToken: NextToken | None class DescribeHostReservationOfferingsRequest(ServiceRequest): - Filter: Optional[FilterList] - MaxDuration: Optional[Integer] - MaxResults: Optional[DescribeHostReservationsMaxResults] - MinDuration: Optional[Integer] - NextToken: Optional[String] - OfferingId: Optional[OfferingId] + Filter: FilterList | None + MaxDuration: Integer | None + MaxResults: DescribeHostReservationsMaxResults | None + MinDuration: Integer | None + NextToken: String | None + OfferingId: OfferingId | None class HostOffering(TypedDict, total=False): - CurrencyCode: Optional[CurrencyCodeValues] - Duration: Optional[Integer] - HourlyPrice: Optional[String] - InstanceFamily: Optional[String] - OfferingId: Optional[OfferingId] - PaymentOption: Optional[PaymentOption] - UpfrontPrice: Optional[String] + CurrencyCode: CurrencyCodeValues | None + Duration: Integer | None + HourlyPrice: String | None + InstanceFamily: String | None + OfferingId: OfferingId | None + PaymentOption: PaymentOption | None + UpfrontPrice: String | None -HostOfferingSet = List[HostOffering] +HostOfferingSet = list[HostOffering] class DescribeHostReservationOfferingsResult(TypedDict, total=False): - NextToken: Optional[String] - OfferingSet: Optional[HostOfferingSet] + NextToken: String | None + OfferingSet: HostOfferingSet | None -HostReservationIdSet = List[HostReservationId] +HostReservationIdSet = list[HostReservationId] class DescribeHostReservationsRequest(ServiceRequest): - Filter: Optional[FilterList] - HostReservationIdSet: Optional[HostReservationIdSet] - MaxResults: Optional[Integer] - NextToken: Optional[String] + Filter: FilterList | None + HostReservationIdSet: HostReservationIdSet | None + MaxResults: Integer | None + NextToken: String | None -ResponseHostIdSet = List[String] +ResponseHostIdSet = list[String] class HostReservation(TypedDict, total=False): - Count: Optional[Integer] - CurrencyCode: Optional[CurrencyCodeValues] - Duration: Optional[Integer] - End: Optional[DateTime] - HostIdSet: Optional[ResponseHostIdSet] - HostReservationId: Optional[HostReservationId] - HourlyPrice: Optional[String] - InstanceFamily: Optional[String] - OfferingId: Optional[OfferingId] - PaymentOption: Optional[PaymentOption] - Start: Optional[DateTime] - State: Optional[ReservationState] - UpfrontPrice: Optional[String] - Tags: Optional[TagList] + Count: Integer | None + CurrencyCode: CurrencyCodeValues | None + Duration: Integer | None + End: DateTime | None + HostIdSet: ResponseHostIdSet | None + HostReservationId: HostReservationId | None + HourlyPrice: String | None + InstanceFamily: String | None + OfferingId: OfferingId | None + PaymentOption: PaymentOption | None + Start: DateTime | None + State: ReservationState | None + UpfrontPrice: String | None + Tags: TagList | None -HostReservationSet = List[HostReservation] +HostReservationSet = list[HostReservation] class DescribeHostReservationsResult(TypedDict, total=False): - HostReservationSet: Optional[HostReservationSet] - NextToken: Optional[String] + HostReservationSet: HostReservationSet | None + NextToken: String | None -RequestHostIdList = List[DedicatedHostId] +RequestHostIdList = list[DedicatedHostId] class DescribeHostsRequest(ServiceRequest): - HostIds: Optional[RequestHostIdList] - NextToken: Optional[String] - MaxResults: Optional[Integer] - Filter: Optional[FilterList] + HostIds: RequestHostIdList | None + NextToken: String | None + MaxResults: Integer | None + Filter: FilterList | None class HostInstance(TypedDict, total=False): - InstanceId: Optional[String] - InstanceType: Optional[String] - OwnerId: Optional[String] + InstanceId: String | None + InstanceType: String | None + OwnerId: String | None -HostInstanceList = List[HostInstance] +HostInstanceList = list[HostInstance] class HostProperties(TypedDict, total=False): - Cores: Optional[Integer] - InstanceType: Optional[String] - InstanceFamily: Optional[String] - Sockets: Optional[Integer] - TotalVCpus: Optional[Integer] + Cores: Integer | None + InstanceType: String | None + InstanceFamily: String | None + Sockets: Integer | None + TotalVCpus: Integer | None class Host(TypedDict, total=False): - AutoPlacement: Optional[AutoPlacement] - AvailabilityZone: Optional[String] - AvailableCapacity: Optional[AvailableCapacity] - ClientToken: Optional[String] - HostId: Optional[String] - HostProperties: Optional[HostProperties] - HostReservationId: Optional[String] - Instances: Optional[HostInstanceList] - State: Optional[AllocationState] - AllocationTime: Optional[DateTime] - ReleaseTime: Optional[DateTime] - Tags: Optional[TagList] - HostRecovery: Optional[HostRecovery] - AllowsMultipleInstanceTypes: Optional[AllowsMultipleInstanceTypes] - OwnerId: Optional[String] - AvailabilityZoneId: Optional[String] - MemberOfServiceLinkedResourceGroup: Optional[Boolean] - OutpostArn: Optional[String] - HostMaintenance: Optional[HostMaintenance] - AssetId: Optional[AssetId] - - -HostList = List[Host] + AutoPlacement: AutoPlacement | None + AvailabilityZone: String | None + AvailableCapacity: AvailableCapacity | None + ClientToken: String | None + HostId: String | None + HostProperties: HostProperties | None + HostReservationId: String | None + Instances: HostInstanceList | None + State: AllocationState | None + AllocationTime: DateTime | None + ReleaseTime: DateTime | None + Tags: TagList | None + HostRecovery: HostRecovery | None + AllowsMultipleInstanceTypes: AllowsMultipleInstanceTypes | None + OwnerId: String | None + AvailabilityZoneId: String | None + MemberOfServiceLinkedResourceGroup: Boolean | None + OutpostArn: String | None + HostMaintenance: HostMaintenance | None + AssetId: AssetId | None + + +HostList = list[Host] class DescribeHostsResult(TypedDict, total=False): - Hosts: Optional[HostList] - NextToken: Optional[String] + Hosts: HostList | None + NextToken: String | None class DescribeIamInstanceProfileAssociationsRequest(ServiceRequest): - AssociationIds: Optional[AssociationIdList] - Filters: Optional[FilterList] - MaxResults: Optional[DescribeIamInstanceProfileAssociationsMaxResults] - NextToken: Optional[NextToken] + AssociationIds: AssociationIdList | None + Filters: FilterList | None + MaxResults: DescribeIamInstanceProfileAssociationsMaxResults | None + NextToken: NextToken | None -IamInstanceProfileAssociationSet = List[IamInstanceProfileAssociation] +IamInstanceProfileAssociationSet = list[IamInstanceProfileAssociation] class DescribeIamInstanceProfileAssociationsResult(TypedDict, total=False): - IamInstanceProfileAssociations: Optional[IamInstanceProfileAssociationSet] - NextToken: Optional[NextToken] + IamInstanceProfileAssociations: IamInstanceProfileAssociationSet | None + NextToken: NextToken | None class DescribeIdFormatRequest(ServiceRequest): - Resource: Optional[String] + Resource: String | None class DescribeIdFormatResult(TypedDict, total=False): - Statuses: Optional[IdFormatList] + Statuses: IdFormatList | None class DescribeIdentityIdFormatRequest(ServiceRequest): - Resource: Optional[String] + Resource: String | None PrincipalArn: String class DescribeIdentityIdFormatResult(TypedDict, total=False): - Statuses: Optional[IdFormatList] + Statuses: IdFormatList | None class DescribeImageAttributeRequest(ServiceRequest): Attribute: ImageAttributeName ImageId: ImageId - DryRun: Optional[Boolean] + DryRun: Boolean | None -DescribeImageReferencesImageIdStringList = List[ImageId] -ResourceTypeOptionValuesList = List[ResourceTypeOptionValue] +DescribeImageReferencesImageIdStringList = list[ImageId] +ResourceTypeOptionValuesList = list[ResourceTypeOptionValue] class ResourceTypeOption(TypedDict, total=False): - OptionName: Optional[ImageReferenceOptionName] - OptionValues: Optional[ResourceTypeOptionValuesList] + OptionName: ImageReferenceOptionName | None + OptionValues: ResourceTypeOptionValuesList | None -ResourceTypeOptionList = List[ResourceTypeOption] +ResourceTypeOptionList = list[ResourceTypeOption] class ResourceTypeRequest(TypedDict, total=False): - ResourceType: Optional[ImageReferenceResourceType] - ResourceTypeOptions: Optional[ResourceTypeOptionList] + ResourceType: ImageReferenceResourceType | None + ResourceTypeOptions: ResourceTypeOptionList | None -ResourceTypeRequestList = List[ResourceTypeRequest] +ResourceTypeRequestList = list[ResourceTypeRequest] class DescribeImageReferencesRequest(ServiceRequest): ImageIds: DescribeImageReferencesImageIdStringList - IncludeAllResourceTypes: Optional[Boolean] - ResourceTypes: Optional[ResourceTypeRequestList] - NextToken: Optional[String] - DryRun: Optional[Boolean] - MaxResults: Optional[DescribeImageReferencesMaxResults] + IncludeAllResourceTypes: Boolean | None + ResourceTypes: ResourceTypeRequestList | None + NextToken: String | None + DryRun: Boolean | None + MaxResults: DescribeImageReferencesMaxResults | None class ImageReference(TypedDict, total=False): - ImageId: Optional[ImageId] - ResourceType: Optional[ImageReferenceResourceType] - Arn: Optional[String] + ImageId: ImageId | None + ResourceType: ImageReferenceResourceType | None + Arn: String | None -ImageReferenceList = List[ImageReference] +ImageReferenceList = list[ImageReference] class DescribeImageReferencesResult(TypedDict, total=False): - NextToken: Optional[String] - ImageReferences: Optional[ImageReferenceList] + NextToken: String | None + ImageReferences: ImageReferenceList | None -ImageUsageReportIdStringList = List[ImageUsageReportId] -DescribeImageUsageReportsImageIdStringList = List[ImageId] +ImageUsageReportIdStringList = list[ImageUsageReportId] +DescribeImageUsageReportsImageIdStringList = list[ImageId] class DescribeImageUsageReportEntriesRequest(ServiceRequest): - ImageIds: Optional[DescribeImageUsageReportsImageIdStringList] - ReportIds: Optional[ImageUsageReportIdStringList] - NextToken: Optional[String] - Filters: Optional[FilterList] - DryRun: Optional[Boolean] - MaxResults: Optional[DescribeImageUsageReportEntriesMaxResults] + ImageIds: DescribeImageUsageReportsImageIdStringList | None + ReportIds: ImageUsageReportIdStringList | None + NextToken: String | None + Filters: FilterList | None + DryRun: Boolean | None + MaxResults: DescribeImageUsageReportEntriesMaxResults | None class ImageUsageReportEntry(TypedDict, total=False): - ResourceType: Optional[ImageUsageResourceTypeName] - ReportId: Optional[ImageUsageReportId] - UsageCount: Optional[Long] - AccountId: Optional[String] - ImageId: Optional[ImageId] - ReportCreationTime: Optional[MillisecondDateTime] + ResourceType: ImageUsageResourceTypeName | None + ReportId: ImageUsageReportId | None + UsageCount: Long | None + AccountId: String | None + ImageId: ImageId | None + ReportCreationTime: MillisecondDateTime | None -ImageUsageReportEntryList = List[ImageUsageReportEntry] +ImageUsageReportEntryList = list[ImageUsageReportEntry] class DescribeImageUsageReportEntriesResult(TypedDict, total=False): - NextToken: Optional[String] - ImageUsageReportEntries: Optional[ImageUsageReportEntryList] + NextToken: String | None + ImageUsageReportEntries: ImageUsageReportEntryList | None class DescribeImageUsageReportsRequest(ServiceRequest): - ImageIds: Optional[DescribeImageUsageReportsImageIdStringList] - ReportIds: Optional[ImageUsageReportIdStringList] - NextToken: Optional[String] - Filters: Optional[FilterList] - DryRun: Optional[Boolean] - MaxResults: Optional[DescribeImageUsageReportsMaxResults] + ImageIds: DescribeImageUsageReportsImageIdStringList | None + ReportIds: ImageUsageReportIdStringList | None + NextToken: String | None + Filters: FilterList | None + DryRun: Boolean | None + MaxResults: DescribeImageUsageReportsMaxResults | None -UserIdList = List[String] +UserIdList = list[String] class ImageUsageResourceTypeOption(TypedDict, total=False): - OptionName: Optional[String] - OptionValues: Optional[ImageUsageResourceTypeOptionValuesList] + OptionName: String | None + OptionValues: ImageUsageResourceTypeOptionValuesList | None -ImageUsageResourceTypeOptionList = List[ImageUsageResourceTypeOption] +ImageUsageResourceTypeOptionList = list[ImageUsageResourceTypeOption] class ImageUsageResourceType(TypedDict, total=False): - ResourceType: Optional[ImageUsageResourceTypeName] - ResourceTypeOptions: Optional[ImageUsageResourceTypeOptionList] + ResourceType: ImageUsageResourceTypeName | None + ResourceTypeOptions: ImageUsageResourceTypeOptionList | None -ImageUsageResourceTypeList = List[ImageUsageResourceType] +ImageUsageResourceTypeList = list[ImageUsageResourceType] class ImageUsageReport(TypedDict, total=False): - ImageId: Optional[ImageId] - ReportId: Optional[ImageUsageReportId] - ResourceTypes: Optional[ImageUsageResourceTypeList] - AccountIds: Optional[UserIdList] - State: Optional[ImageUsageReportState] - StateReason: Optional[ImageUsageReportStateReason] - CreationTime: Optional[MillisecondDateTime] - ExpirationTime: Optional[MillisecondDateTime] - Tags: Optional[TagList] + ImageId: ImageId | None + ReportId: ImageUsageReportId | None + ResourceTypes: ImageUsageResourceTypeList | None + AccountIds: UserIdList | None + State: ImageUsageReportState | None + StateReason: ImageUsageReportStateReason | None + CreationTime: MillisecondDateTime | None + ExpirationTime: MillisecondDateTime | None + Tags: TagList | None -ImageUsageReportList = List[ImageUsageReport] +ImageUsageReportList = list[ImageUsageReport] class DescribeImageUsageReportsResult(TypedDict, total=False): - NextToken: Optional[String] - ImageUsageReports: Optional[ImageUsageReportList] + NextToken: String | None + ImageUsageReports: ImageUsageReportList | None -ImageIdStringList = List[ImageId] -ExecutableByStringList = List[String] +ImageIdStringList = list[ImageId] +ExecutableByStringList = list[String] class DescribeImagesRequest(ServiceRequest): - ExecutableUsers: Optional[ExecutableByStringList] - ImageIds: Optional[ImageIdStringList] - Owners: Optional[OwnerStringList] - IncludeDeprecated: Optional[Boolean] - IncludeDisabled: Optional[Boolean] - MaxResults: Optional[Integer] - NextToken: Optional[String] - DryRun: Optional[Boolean] - Filters: Optional[FilterList] + ExecutableUsers: ExecutableByStringList | None + ImageIds: ImageIdStringList | None + Owners: OwnerStringList | None + IncludeDeprecated: Boolean | None + IncludeDisabled: Boolean | None + MaxResults: Integer | None + NextToken: String | None + DryRun: Boolean | None + Filters: FilterList | None class Image(TypedDict, total=False): - PlatformDetails: Optional[String] - UsageOperation: Optional[String] - BlockDeviceMappings: Optional[BlockDeviceMappingList] - Description: Optional[String] - EnaSupport: Optional[Boolean] - Hypervisor: Optional[HypervisorType] - ImageOwnerAlias: Optional[String] - Name: Optional[String] - RootDeviceName: Optional[String] - RootDeviceType: Optional[DeviceType] - SriovNetSupport: Optional[String] - StateReason: Optional[StateReason] - Tags: Optional[TagList] - VirtualizationType: Optional[VirtualizationType] - BootMode: Optional[BootModeValues] - TpmSupport: Optional[TpmSupportValues] - DeprecationTime: Optional[String] - ImdsSupport: Optional[ImdsSupportValues] - SourceInstanceId: Optional[String] - DeregistrationProtection: Optional[String] - LastLaunchedTime: Optional[String] - ImageAllowed: Optional[Boolean] - SourceImageId: Optional[String] - SourceImageRegion: Optional[String] - FreeTierEligible: Optional[Boolean] - ImageId: Optional[String] - ImageLocation: Optional[String] - State: Optional[ImageState] - OwnerId: Optional[String] - CreationDate: Optional[String] - Public: Optional[Boolean] - ProductCodes: Optional[ProductCodeList] - Architecture: Optional[ArchitectureValues] - ImageType: Optional[ImageTypeValues] - KernelId: Optional[String] - RamdiskId: Optional[String] - Platform: Optional[PlatformValues] - - -ImageList = List[Image] + PlatformDetails: String | None + UsageOperation: String | None + BlockDeviceMappings: BlockDeviceMappingList | None + Description: String | None + EnaSupport: Boolean | None + Hypervisor: HypervisorType | None + ImageOwnerAlias: String | None + Name: String | None + RootDeviceName: String | None + RootDeviceType: DeviceType | None + SriovNetSupport: String | None + StateReason: StateReason | None + Tags: TagList | None + VirtualizationType: VirtualizationType | None + BootMode: BootModeValues | None + TpmSupport: TpmSupportValues | None + DeprecationTime: String | None + ImdsSupport: ImdsSupportValues | None + SourceInstanceId: String | None + DeregistrationProtection: String | None + LastLaunchedTime: String | None + ImageAllowed: Boolean | None + SourceImageId: String | None + SourceImageRegion: String | None + FreeTierEligible: Boolean | None + ImageId: String | None + ImageLocation: String | None + State: ImageState | None + OwnerId: String | None + CreationDate: String | None + Public: Boolean | None + ProductCodes: ProductCodeList | None + Architecture: ArchitectureValues | None + ImageType: ImageTypeValues | None + KernelId: String | None + RamdiskId: String | None + Platform: PlatformValues | None + + +ImageList = list[Image] class DescribeImagesResult(TypedDict, total=False): - NextToken: Optional[String] - Images: Optional[ImageList] + NextToken: String | None + Images: ImageList | None -ImportTaskIdList = List[ImportImageTaskId] +ImportTaskIdList = list[ImportImageTaskId] class DescribeImportImageTasksRequest(ServiceRequest): - DryRun: Optional[Boolean] - Filters: Optional[FilterList] - ImportTaskIds: Optional[ImportTaskIdList] - MaxResults: Optional[Integer] - NextToken: Optional[String] + DryRun: Boolean | None + Filters: FilterList | None + ImportTaskIds: ImportTaskIdList | None + MaxResults: Integer | None + NextToken: String | None class ImportImageLicenseConfigurationResponse(TypedDict, total=False): - LicenseConfigurationArn: Optional[String] + LicenseConfigurationArn: String | None -ImportImageLicenseSpecificationListResponse = List[ImportImageLicenseConfigurationResponse] +ImportImageLicenseSpecificationListResponse = list[ImportImageLicenseConfigurationResponse] class UserBucketDetails(TypedDict, total=False): - S3Bucket: Optional[String] - S3Key: Optional[String] + S3Bucket: String | None + S3Key: String | None class SnapshotDetail(TypedDict, total=False): - Description: Optional[String] - DeviceName: Optional[String] - DiskImageSize: Optional[Double] - Format: Optional[String] - Progress: Optional[String] - SnapshotId: Optional[String] - Status: Optional[String] - StatusMessage: Optional[String] - Url: Optional[SensitiveUrl] - UserBucket: Optional[UserBucketDetails] + Description: String | None + DeviceName: String | None + DiskImageSize: Double | None + Format: String | None + Progress: String | None + SnapshotId: String | None + Status: String | None + StatusMessage: String | None + Url: SensitiveUrl | None + UserBucket: UserBucketDetails | None -SnapshotDetailList = List[SnapshotDetail] +SnapshotDetailList = list[SnapshotDetail] class ImportImageTask(TypedDict, total=False): - Architecture: Optional[String] - Description: Optional[String] - Encrypted: Optional[Boolean] - Hypervisor: Optional[String] - ImageId: Optional[String] - ImportTaskId: Optional[String] - KmsKeyId: Optional[String] - LicenseType: Optional[String] - Platform: Optional[String] - Progress: Optional[String] - SnapshotDetails: Optional[SnapshotDetailList] - Status: Optional[String] - StatusMessage: Optional[String] - Tags: Optional[TagList] - LicenseSpecifications: Optional[ImportImageLicenseSpecificationListResponse] - UsageOperation: Optional[String] - BootMode: Optional[BootModeValues] - - -ImportImageTaskList = List[ImportImageTask] + Architecture: String | None + Description: String | None + Encrypted: Boolean | None + Hypervisor: String | None + ImageId: String | None + ImportTaskId: String | None + KmsKeyId: String | None + LicenseType: String | None + Platform: String | None + Progress: String | None + SnapshotDetails: SnapshotDetailList | None + Status: String | None + StatusMessage: String | None + Tags: TagList | None + LicenseSpecifications: ImportImageLicenseSpecificationListResponse | None + UsageOperation: String | None + BootMode: BootModeValues | None + + +ImportImageTaskList = list[ImportImageTask] class DescribeImportImageTasksResult(TypedDict, total=False): - ImportImageTasks: Optional[ImportImageTaskList] - NextToken: Optional[String] + ImportImageTasks: ImportImageTaskList | None + NextToken: String | None -ImportSnapshotTaskIdList = List[ImportSnapshotTaskId] +ImportSnapshotTaskIdList = list[ImportSnapshotTaskId] class DescribeImportSnapshotTasksRequest(ServiceRequest): - DryRun: Optional[Boolean] - Filters: Optional[FilterList] - ImportTaskIds: Optional[ImportSnapshotTaskIdList] - MaxResults: Optional[Integer] - NextToken: Optional[String] + DryRun: Boolean | None + Filters: FilterList | None + ImportTaskIds: ImportSnapshotTaskIdList | None + MaxResults: Integer | None + NextToken: String | None class SnapshotTaskDetail(TypedDict, total=False): - Description: Optional[String] - DiskImageSize: Optional[Double] - Encrypted: Optional[Boolean] - Format: Optional[String] - KmsKeyId: Optional[String] - Progress: Optional[String] - SnapshotId: Optional[String] - Status: Optional[String] - StatusMessage: Optional[String] - Url: Optional[SensitiveUrl] - UserBucket: Optional[UserBucketDetails] + Description: String | None + DiskImageSize: Double | None + Encrypted: Boolean | None + Format: String | None + KmsKeyId: String | None + Progress: String | None + SnapshotId: String | None + Status: String | None + StatusMessage: String | None + Url: SensitiveUrl | None + UserBucket: UserBucketDetails | None class ImportSnapshotTask(TypedDict, total=False): - Description: Optional[String] - ImportTaskId: Optional[String] - SnapshotTaskDetail: Optional[SnapshotTaskDetail] - Tags: Optional[TagList] + Description: String | None + ImportTaskId: String | None + SnapshotTaskDetail: SnapshotTaskDetail | None + Tags: TagList | None -ImportSnapshotTaskList = List[ImportSnapshotTask] +ImportSnapshotTaskList = list[ImportSnapshotTask] class DescribeImportSnapshotTasksResult(TypedDict, total=False): - ImportSnapshotTasks: Optional[ImportSnapshotTaskList] - NextToken: Optional[String] + ImportSnapshotTasks: ImportSnapshotTaskList | None + NextToken: String | None class DescribeInstanceAttributeRequest(ServiceRequest): - DryRun: Optional[Boolean] + DryRun: Boolean | None InstanceId: InstanceId Attribute: InstanceAttributeName class DescribeInstanceConnectEndpointsRequest(ServiceRequest): - DryRun: Optional[Boolean] - MaxResults: Optional[InstanceConnectEndpointMaxResults] - NextToken: Optional[NextToken] - Filters: Optional[FilterList] - InstanceConnectEndpointIds: Optional[ValueStringList] + DryRun: Boolean | None + MaxResults: InstanceConnectEndpointMaxResults | None + NextToken: NextToken | None + Filters: FilterList | None + InstanceConnectEndpointIds: ValueStringList | None -InstanceConnectEndpointSet = List[Ec2InstanceConnectEndpoint] +InstanceConnectEndpointSet = list[Ec2InstanceConnectEndpoint] class DescribeInstanceConnectEndpointsResult(TypedDict, total=False): - InstanceConnectEndpoints: Optional[InstanceConnectEndpointSet] - NextToken: Optional[NextToken] + InstanceConnectEndpoints: InstanceConnectEndpointSet | None + NextToken: NextToken | None class DescribeInstanceCreditSpecificationsRequest(ServiceRequest): - DryRun: Optional[Boolean] - Filters: Optional[FilterList] - InstanceIds: Optional[InstanceIdStringList] - MaxResults: Optional[DescribeInstanceCreditSpecificationsMaxResults] - NextToken: Optional[String] + DryRun: Boolean | None + Filters: FilterList | None + InstanceIds: InstanceIdStringList | None + MaxResults: DescribeInstanceCreditSpecificationsMaxResults | None + NextToken: String | None class InstanceCreditSpecification(TypedDict, total=False): - InstanceId: Optional[String] - CpuCredits: Optional[String] + InstanceId: String | None + CpuCredits: String | None -InstanceCreditSpecificationList = List[InstanceCreditSpecification] +InstanceCreditSpecificationList = list[InstanceCreditSpecification] class DescribeInstanceCreditSpecificationsResult(TypedDict, total=False): - InstanceCreditSpecifications: Optional[InstanceCreditSpecificationList] - NextToken: Optional[String] + InstanceCreditSpecifications: InstanceCreditSpecificationList | None + NextToken: String | None class DescribeInstanceEventNotificationAttributesRequest(ServiceRequest): - DryRun: Optional[Boolean] + DryRun: Boolean | None class DescribeInstanceEventNotificationAttributesResult(TypedDict, total=False): - InstanceTagAttribute: Optional[InstanceTagNotificationAttribute] + InstanceTagAttribute: InstanceTagNotificationAttribute | None -InstanceEventWindowIdSet = List[InstanceEventWindowId] +InstanceEventWindowIdSet = list[InstanceEventWindowId] class DescribeInstanceEventWindowsRequest(ServiceRequest): - DryRun: Optional[Boolean] - InstanceEventWindowIds: Optional[InstanceEventWindowIdSet] - Filters: Optional[FilterList] - MaxResults: Optional[ResultRange] - NextToken: Optional[String] + DryRun: Boolean | None + InstanceEventWindowIds: InstanceEventWindowIdSet | None + Filters: FilterList | None + MaxResults: ResultRange | None + NextToken: String | None -InstanceEventWindowSet = List[InstanceEventWindow] +InstanceEventWindowSet = list[InstanceEventWindow] class DescribeInstanceEventWindowsResult(TypedDict, total=False): - InstanceEventWindows: Optional[InstanceEventWindowSet] - NextToken: Optional[String] + InstanceEventWindows: InstanceEventWindowSet | None + NextToken: String | None class DescribeInstanceImageMetadataRequest(ServiceRequest): - Filters: Optional[FilterList] - InstanceIds: Optional[InstanceIdStringList] - MaxResults: Optional[DescribeInstanceImageMetadataMaxResults] - NextToken: Optional[String] - DryRun: Optional[Boolean] + Filters: FilterList | None + InstanceIds: InstanceIdStringList | None + MaxResults: DescribeInstanceImageMetadataMaxResults | None + NextToken: String | None + DryRun: Boolean | None class ImageMetadata(TypedDict, total=False): - ImageId: Optional[ImageId] - Name: Optional[String] - OwnerId: Optional[String] - State: Optional[ImageState] - ImageOwnerAlias: Optional[String] - CreationDate: Optional[String] - DeprecationTime: Optional[String] - ImageAllowed: Optional[Boolean] - IsPublic: Optional[Boolean] + ImageId: ImageId | None + Name: String | None + OwnerId: String | None + State: ImageState | None + ImageOwnerAlias: String | None + CreationDate: String | None + DeprecationTime: String | None + ImageAllowed: Boolean | None + IsPublic: Boolean | None class InstanceState(TypedDict, total=False): - Code: Optional[Integer] - Name: Optional[InstanceStateName] + Code: Integer | None + Name: InstanceStateName | None class InstanceImageMetadata(TypedDict, total=False): - InstanceId: Optional[InstanceId] - InstanceType: Optional[InstanceType] - LaunchTime: Optional[MillisecondDateTime] - AvailabilityZone: Optional[String] - ZoneId: Optional[String] - State: Optional[InstanceState] - OwnerId: Optional[String] - Tags: Optional[TagList] - ImageMetadata: Optional[ImageMetadata] - Operator: Optional[OperatorResponse] + InstanceId: InstanceId | None + InstanceType: InstanceType | None + LaunchTime: MillisecondDateTime | None + AvailabilityZone: String | None + ZoneId: String | None + State: InstanceState | None + OwnerId: String | None + Tags: TagList | None + ImageMetadata: ImageMetadata | None + Operator: OperatorResponse | None -InstanceImageMetadataList = List[InstanceImageMetadata] +InstanceImageMetadataList = list[InstanceImageMetadata] class DescribeInstanceImageMetadataResult(TypedDict, total=False): - InstanceImageMetadata: Optional[InstanceImageMetadataList] - NextToken: Optional[String] + InstanceImageMetadata: InstanceImageMetadataList | None + NextToken: String | None + + +class DescribeInstanceSqlHaHistoryStatesRequest(ServiceRequest): + InstanceIds: InstanceIdStringList | None + StartTime: MillisecondDateTime | None + EndTime: MillisecondDateTime | None + NextToken: NextToken | None + MaxResults: DescribeInstanceSqlHaStatesRequestMaxResultsInteger | None + Filters: FilterList | None + DryRun: Boolean | None + + +class RegisteredInstance(TypedDict, total=False): + InstanceId: InstanceId | None + SqlServerLicenseUsage: SqlServerLicenseUsage | None + HaStatus: HaStatus | None + ProcessingStatus: String | None + LastUpdatedTime: MillisecondDateTime | None + SqlServerCredentials: String | None + Tags: TagList | None + + +RegisteredInstanceList = list[RegisteredInstance] + + +class DescribeInstanceSqlHaHistoryStatesResult(TypedDict, total=False): + Instances: RegisteredInstanceList | None + NextToken: NextToken | None + + +class DescribeInstanceSqlHaStatesRequest(ServiceRequest): + InstanceIds: InstanceIdStringList | None + NextToken: NextToken | None + MaxResults: DescribeInstanceSqlHaStatesRequestMaxResultsInteger | None + Filters: FilterList | None + DryRun: Boolean | None + + +class DescribeInstanceSqlHaStatesResult(TypedDict, total=False): + Instances: RegisteredInstanceList | None + NextToken: NextToken | None class DescribeInstanceStatusRequest(ServiceRequest): - InstanceIds: Optional[InstanceIdStringList] - MaxResults: Optional[Integer] - NextToken: Optional[String] - DryRun: Optional[Boolean] - Filters: Optional[FilterList] - IncludeAllInstances: Optional[Boolean] + InstanceIds: InstanceIdStringList | None + MaxResults: Integer | None + NextToken: String | None + DryRun: Boolean | None + Filters: FilterList | None + IncludeAllInstances: Boolean | None class EbsStatusDetails(TypedDict, total=False): - ImpairedSince: Optional[MillisecondDateTime] - Name: Optional[StatusName] - Status: Optional[StatusType] + ImpairedSince: MillisecondDateTime | None + Name: StatusName | None + Status: StatusType | None -EbsStatusDetailsList = List[EbsStatusDetails] +EbsStatusDetailsList = list[EbsStatusDetails] class EbsStatusSummary(TypedDict, total=False): - Details: Optional[EbsStatusDetailsList] - Status: Optional[SummaryStatus] + Details: EbsStatusDetailsList | None + Status: SummaryStatus | None class InstanceStatusDetails(TypedDict, total=False): - ImpairedSince: Optional[DateTime] - Name: Optional[StatusName] - Status: Optional[StatusType] + ImpairedSince: DateTime | None + Name: StatusName | None + Status: StatusType | None -InstanceStatusDetailsList = List[InstanceStatusDetails] +InstanceStatusDetailsList = list[InstanceStatusDetails] class InstanceStatusSummary(TypedDict, total=False): - Details: Optional[InstanceStatusDetailsList] - Status: Optional[SummaryStatus] + Details: InstanceStatusDetailsList | None + Status: SummaryStatus | None class InstanceStatusEvent(TypedDict, total=False): - InstanceEventId: Optional[InstanceEventId] - Code: Optional[EventCode] - Description: Optional[String] - NotAfter: Optional[DateTime] - NotBefore: Optional[DateTime] - NotBeforeDeadline: Optional[DateTime] + InstanceEventId: InstanceEventId | None + Code: EventCode | None + Description: String | None + NotAfter: DateTime | None + NotBefore: DateTime | None + NotBeforeDeadline: DateTime | None -InstanceStatusEventList = List[InstanceStatusEvent] +InstanceStatusEventList = list[InstanceStatusEvent] class InstanceStatus(TypedDict, total=False): - AvailabilityZone: Optional[String] - AvailabilityZoneId: Optional[AvailabilityZoneId] - OutpostArn: Optional[String] - Operator: Optional[OperatorResponse] - Events: Optional[InstanceStatusEventList] - InstanceId: Optional[String] - InstanceState: Optional[InstanceState] - InstanceStatus: Optional[InstanceStatusSummary] - SystemStatus: Optional[InstanceStatusSummary] - AttachedEbsStatus: Optional[EbsStatusSummary] + AvailabilityZone: String | None + AvailabilityZoneId: AvailabilityZoneId | None + OutpostArn: String | None + Operator: OperatorResponse | None + Events: InstanceStatusEventList | None + InstanceId: String | None + InstanceState: InstanceState | None + InstanceStatus: InstanceStatusSummary | None + SystemStatus: InstanceStatusSummary | None + AttachedEbsStatus: EbsStatusSummary | None -InstanceStatusList = List[InstanceStatus] +InstanceStatusList = list[InstanceStatus] class DescribeInstanceStatusResult(TypedDict, total=False): - InstanceStatuses: Optional[InstanceStatusList] - NextToken: Optional[String] + InstanceStatuses: InstanceStatusList | None + NextToken: String | None -DescribeInstanceTopologyGroupNameSet = List[PlacementGroupName] -DescribeInstanceTopologyInstanceIdSet = List[InstanceId] +DescribeInstanceTopologyGroupNameSet = list[PlacementGroupName] +DescribeInstanceTopologyInstanceIdSet = list[InstanceId] class DescribeInstanceTopologyRequest(ServiceRequest): - DryRun: Optional[Boolean] - NextToken: Optional[String] - MaxResults: Optional[DescribeInstanceTopologyMaxResults] - InstanceIds: Optional[DescribeInstanceTopologyInstanceIdSet] - GroupNames: Optional[DescribeInstanceTopologyGroupNameSet] - Filters: Optional[FilterList] + DryRun: Boolean | None + NextToken: String | None + MaxResults: DescribeInstanceTopologyMaxResults | None + InstanceIds: DescribeInstanceTopologyInstanceIdSet | None + GroupNames: DescribeInstanceTopologyGroupNameSet | None + Filters: FilterList | None -NetworkNodesList = List[String] +NetworkNodesList = list[String] class InstanceTopology(TypedDict, total=False): - InstanceId: Optional[String] - InstanceType: Optional[String] - GroupName: Optional[String] - NetworkNodes: Optional[NetworkNodesList] - AvailabilityZone: Optional[String] - ZoneId: Optional[String] - CapacityBlockId: Optional[String] + InstanceId: String | None + InstanceType: String | None + GroupName: String | None + NetworkNodes: NetworkNodesList | None + AvailabilityZone: String | None + ZoneId: String | None + CapacityBlockId: String | None -InstanceSet = List[InstanceTopology] +InstanceSet = list[InstanceTopology] class DescribeInstanceTopologyResult(TypedDict, total=False): - Instances: Optional[InstanceSet] - NextToken: Optional[String] + Instances: InstanceSet | None + NextToken: String | None class DescribeInstanceTypeOfferingsRequest(ServiceRequest): - DryRun: Optional[Boolean] - LocationType: Optional[LocationType] - Filters: Optional[FilterList] - MaxResults: Optional[DITOMaxResults] - NextToken: Optional[NextToken] + DryRun: Boolean | None + LocationType: LocationType | None + Filters: FilterList | None + MaxResults: DITOMaxResults | None + NextToken: NextToken | None class InstanceTypeOffering(TypedDict, total=False): - InstanceType: Optional[InstanceType] - LocationType: Optional[LocationType] - Location: Optional[Location] + InstanceType: InstanceType | None + LocationType: LocationType | None + Location: Location | None -InstanceTypeOfferingsList = List[InstanceTypeOffering] +InstanceTypeOfferingsList = list[InstanceTypeOffering] class DescribeInstanceTypeOfferingsResult(TypedDict, total=False): - InstanceTypeOfferings: Optional[InstanceTypeOfferingsList] - NextToken: Optional[NextToken] + InstanceTypeOfferings: InstanceTypeOfferingsList | None + NextToken: NextToken | None -RequestInstanceTypeList = List[InstanceType] +RequestInstanceTypeList = list[InstanceType] class DescribeInstanceTypesRequest(ServiceRequest): - DryRun: Optional[Boolean] - InstanceTypes: Optional[RequestInstanceTypeList] - Filters: Optional[FilterList] - MaxResults: Optional[DITMaxResults] - NextToken: Optional[NextToken] + DryRun: Boolean | None + InstanceTypes: RequestInstanceTypeList | None + Filters: FilterList | None + MaxResults: DITMaxResults | None + NextToken: NextToken | None class NeuronDeviceMemoryInfo(TypedDict, total=False): - SizeInMiB: Optional[NeuronDeviceMemorySize] + SizeInMiB: NeuronDeviceMemorySize | None class NeuronDeviceCoreInfo(TypedDict, total=False): - Count: Optional[NeuronDeviceCoreCount] - Version: Optional[NeuronDeviceCoreVersion] + Count: NeuronDeviceCoreCount | None + Version: NeuronDeviceCoreVersion | None class NeuronDeviceInfo(TypedDict, total=False): - Count: Optional[NeuronDeviceCount] - Name: Optional[NeuronDeviceName] - CoreInfo: Optional[NeuronDeviceCoreInfo] - MemoryInfo: Optional[NeuronDeviceMemoryInfo] + Count: NeuronDeviceCount | None + Name: NeuronDeviceName | None + CoreInfo: NeuronDeviceCoreInfo | None + MemoryInfo: NeuronDeviceMemoryInfo | None -NeuronDeviceInfoList = List[NeuronDeviceInfo] +NeuronDeviceInfoList = list[NeuronDeviceInfo] class NeuronInfo(TypedDict, total=False): - NeuronDevices: Optional[NeuronDeviceInfoList] - TotalNeuronDeviceMemoryInMiB: Optional[TotalNeuronMemory] + NeuronDevices: NeuronDeviceInfoList | None + TotalNeuronDeviceMemoryInMiB: TotalNeuronMemory | None class MediaDeviceMemoryInfo(TypedDict, total=False): - SizeInMiB: Optional[MediaDeviceMemorySize] + SizeInMiB: MediaDeviceMemorySize | None class MediaDeviceInfo(TypedDict, total=False): - Count: Optional[MediaDeviceCount] - Name: Optional[MediaDeviceName] - Manufacturer: Optional[MediaDeviceManufacturerName] - MemoryInfo: Optional[MediaDeviceMemoryInfo] + Count: MediaDeviceCount | None + Name: MediaDeviceName | None + Manufacturer: MediaDeviceManufacturerName | None + MemoryInfo: MediaDeviceMemoryInfo | None -MediaDeviceInfoList = List[MediaDeviceInfo] +MediaDeviceInfoList = list[MediaDeviceInfo] class MediaAcceleratorInfo(TypedDict, total=False): - Accelerators: Optional[MediaDeviceInfoList] - TotalMediaMemoryInMiB: Optional[TotalMediaMemory] + Accelerators: MediaDeviceInfoList | None + TotalMediaMemoryInMiB: TotalMediaMemory | None -NitroTpmSupportedVersionsList = List[NitroTpmSupportedVersionType] +NitroTpmSupportedVersionsList = list[NitroTpmSupportedVersionType] class NitroTpmInfo(TypedDict, total=False): - SupportedVersions: Optional[NitroTpmSupportedVersionsList] + SupportedVersions: NitroTpmSupportedVersionsList | None class InferenceDeviceMemoryInfo(TypedDict, total=False): - SizeInMiB: Optional[InferenceDeviceMemorySize] + SizeInMiB: InferenceDeviceMemorySize | None class InferenceDeviceInfo(TypedDict, total=False): - Count: Optional[InferenceDeviceCount] - Name: Optional[InferenceDeviceName] - Manufacturer: Optional[InferenceDeviceManufacturerName] - MemoryInfo: Optional[InferenceDeviceMemoryInfo] + Count: InferenceDeviceCount | None + Name: InferenceDeviceName | None + Manufacturer: InferenceDeviceManufacturerName | None + MemoryInfo: InferenceDeviceMemoryInfo | None -InferenceDeviceInfoList = List[InferenceDeviceInfo] +InferenceDeviceInfoList = list[InferenceDeviceInfo] class InferenceAcceleratorInfo(TypedDict, total=False): - Accelerators: Optional[InferenceDeviceInfoList] - TotalInferenceMemoryInMiB: Optional[totalInferenceMemory] + Accelerators: InferenceDeviceInfoList | None + TotalInferenceMemoryInMiB: totalInferenceMemory | None -PlacementGroupStrategyList = List[PlacementGroupStrategy] +PlacementGroupStrategyList = list[PlacementGroupStrategy] class PlacementGroupInfo(TypedDict, total=False): - SupportedStrategies: Optional[PlacementGroupStrategyList] + SupportedStrategies: PlacementGroupStrategyList | None class FpgaDeviceMemoryInfo(TypedDict, total=False): - SizeInMiB: Optional[FpgaDeviceMemorySize] + SizeInMiB: FpgaDeviceMemorySize | None class FpgaDeviceInfo(TypedDict, total=False): - Name: Optional[FpgaDeviceName] - Manufacturer: Optional[FpgaDeviceManufacturerName] - Count: Optional[FpgaDeviceCount] - MemoryInfo: Optional[FpgaDeviceMemoryInfo] + Name: FpgaDeviceName | None + Manufacturer: FpgaDeviceManufacturerName | None + Count: FpgaDeviceCount | None + MemoryInfo: FpgaDeviceMemoryInfo | None -FpgaDeviceInfoList = List[FpgaDeviceInfo] +FpgaDeviceInfoList = list[FpgaDeviceInfo] class FpgaInfo(TypedDict, total=False): - Fpgas: Optional[FpgaDeviceInfoList] - TotalFpgaMemoryInMiB: Optional[totalFpgaMemory] + Fpgas: FpgaDeviceInfoList | None + TotalFpgaMemoryInMiB: totalFpgaMemory | None class GpuDeviceMemoryInfo(TypedDict, total=False): - SizeInMiB: Optional[GpuDeviceMemorySize] + SizeInMiB: GpuDeviceMemorySize | None + + +WorkloadsList = list[Workload] class GpuDeviceInfo(TypedDict, total=False): - Name: Optional[GpuDeviceName] - Manufacturer: Optional[GpuDeviceManufacturerName] - Count: Optional[GpuDeviceCount] - MemoryInfo: Optional[GpuDeviceMemoryInfo] + Name: GpuDeviceName | None + Manufacturer: GpuDeviceManufacturerName | None + Count: GpuDeviceCount | None + LogicalGpuCount: LogicalGpuCount | None + GpuPartitionSize: GpuPartitionSize | None + Workloads: WorkloadsList | None + MemoryInfo: GpuDeviceMemoryInfo | None -GpuDeviceInfoList = List[GpuDeviceInfo] +GpuDeviceInfoList = list[GpuDeviceInfo] class GpuInfo(TypedDict, total=False): - Gpus: Optional[GpuDeviceInfoList] - TotalGpuMemoryInMiB: Optional[totalGpuMemory] + Gpus: GpuDeviceInfoList | None + TotalGpuMemoryInMiB: totalGpuMemory | None class EfaInfo(TypedDict, total=False): - MaximumEfaInterfaces: Optional[MaximumEfaInterfaces] + MaximumEfaInterfaces: MaximumEfaInterfaces | None class NetworkCardInfo(TypedDict, total=False): - NetworkCardIndex: Optional[NetworkCardIndex] - NetworkPerformance: Optional[NetworkPerformance] - MaximumNetworkInterfaces: Optional[MaxNetworkInterfaces] - BaselineBandwidthInGbps: Optional[BaselineBandwidthInGbps] - PeakBandwidthInGbps: Optional[PeakBandwidthInGbps] - DefaultEnaQueueCountPerInterface: Optional[DefaultEnaQueueCountPerInterface] - MaximumEnaQueueCount: Optional[MaximumEnaQueueCount] - MaximumEnaQueueCountPerInterface: Optional[MaximumEnaQueueCountPerInterface] + NetworkCardIndex: NetworkCardIndex | None + NetworkPerformance: NetworkPerformance | None + MaximumNetworkInterfaces: MaxNetworkInterfaces | None + AdditionalFlexibleNetworkInterfaces: AdditionalFlexibleNetworkInterfaces | None + BaselineBandwidthInGbps: BaselineBandwidthInGbps | None + PeakBandwidthInGbps: PeakBandwidthInGbps | None + DefaultEnaQueueCountPerInterface: DefaultEnaQueueCountPerInterface | None + MaximumEnaQueueCount: MaximumEnaQueueCount | None + MaximumEnaQueueCountPerInterface: MaximumEnaQueueCountPerInterface | None -NetworkCardInfoList = List[NetworkCardInfo] +NetworkCardInfoList = list[NetworkCardInfo] class NetworkInfo(TypedDict, total=False): - NetworkPerformance: Optional[NetworkPerformance] - MaximumNetworkInterfaces: Optional[MaxNetworkInterfaces] - MaximumNetworkCards: Optional[MaximumNetworkCards] - DefaultNetworkCardIndex: Optional[DefaultNetworkCardIndex] - NetworkCards: Optional[NetworkCardInfoList] - Ipv4AddressesPerInterface: Optional[MaxIpv4AddrPerInterface] - Ipv6AddressesPerInterface: Optional[MaxIpv6AddrPerInterface] - Ipv6Supported: Optional[Ipv6Flag] - EnaSupport: Optional[EnaSupport] - EfaSupported: Optional[EfaSupportedFlag] - EfaInfo: Optional[EfaInfo] - EncryptionInTransitSupported: Optional[EncryptionInTransitSupported] - EnaSrdSupported: Optional[EnaSrdSupported] - BandwidthWeightings: Optional[BandwidthWeightingTypeList] - FlexibleEnaQueuesSupport: Optional[FlexibleEnaQueuesSupport] + NetworkPerformance: NetworkPerformance | None + MaximumNetworkInterfaces: MaxNetworkInterfaces | None + MaximumNetworkCards: MaximumNetworkCards | None + DefaultNetworkCardIndex: DefaultNetworkCardIndex | None + NetworkCards: NetworkCardInfoList | None + Ipv4AddressesPerInterface: MaxIpv4AddrPerInterface | None + Ipv6AddressesPerInterface: MaxIpv6AddrPerInterface | None + Ipv6Supported: Ipv6Flag | None + EnaSupport: EnaSupport | None + EfaSupported: EfaSupportedFlag | None + EfaInfo: EfaInfo | None + EncryptionInTransitSupported: EncryptionInTransitSupported | None + EnaSrdSupported: EnaSrdSupported | None + BandwidthWeightings: BandwidthWeightingTypeList | None + FlexibleEnaQueuesSupport: FlexibleEnaQueuesSupport | None + SecondaryNetworkSupported: SecondaryNetworkSupportedFlag | None + MaximumSecondaryNetworkInterfaces: MaximumSecondaryNetworkInterfaces | None + Ipv4AddressesPerSecondaryInterface: Ipv4AddressesPerSecondaryInterface | None + + +class EbsCardInfo(TypedDict, total=False): + EbsCardIndex: EbsCardIndex | None + BaselineBandwidthInMbps: BaselineBandwidthInMbps | None + BaselineThroughputInMBps: BaselineThroughputInMBps | None + BaselineIops: BaselineIops | None + MaximumBandwidthInMbps: MaximumBandwidthInMbps | None + MaximumThroughputInMBps: MaximumThroughputInMBps | None + MaximumIops: MaximumIops | None + + +EbsCardInfoList = list[EbsCardInfo] class EbsOptimizedInfo(TypedDict, total=False): - BaselineBandwidthInMbps: Optional[BaselineBandwidthInMbps] - BaselineThroughputInMBps: Optional[BaselineThroughputInMBps] - BaselineIops: Optional[BaselineIops] - MaximumBandwidthInMbps: Optional[MaximumBandwidthInMbps] - MaximumThroughputInMBps: Optional[MaximumThroughputInMBps] - MaximumIops: Optional[MaximumIops] + BaselineBandwidthInMbps: BaselineBandwidthInMbps | None + BaselineThroughputInMBps: BaselineThroughputInMBps | None + BaselineIops: BaselineIops | None + MaximumBandwidthInMbps: MaximumBandwidthInMbps | None + MaximumThroughputInMBps: MaximumThroughputInMBps | None + MaximumIops: MaximumIops | None class EbsInfo(TypedDict, total=False): - EbsOptimizedSupport: Optional[EbsOptimizedSupport] - EncryptionSupport: Optional[EbsEncryptionSupport] - EbsOptimizedInfo: Optional[EbsOptimizedInfo] - NvmeSupport: Optional[EbsNvmeSupport] - MaximumEbsAttachments: Optional[MaximumEbsAttachments] - AttachmentLimitType: Optional[AttachmentLimitType] + EbsOptimizedSupport: EbsOptimizedSupport | None + EncryptionSupport: EbsEncryptionSupport | None + EbsOptimizedInfo: EbsOptimizedInfo | None + NvmeSupport: EbsNvmeSupport | None + MaximumEbsAttachments: MaximumEbsAttachments | None + AttachmentLimitType: AttachmentLimitType | None + MaximumEbsCards: MaximumEbsCards | None + EbsCards: EbsCardInfoList | None DiskSize = int class DiskInfo(TypedDict, total=False): - SizeInGB: Optional[DiskSize] - Count: Optional[DiskCount] - Type: Optional[DiskType] + SizeInGB: DiskSize | None + Count: DiskCount | None + Type: DiskType | None -DiskInfoList = List[DiskInfo] +DiskInfoList = list[DiskInfo] class InstanceStorageInfo(TypedDict, total=False): - TotalSizeInGB: Optional[DiskSize] - Disks: Optional[DiskInfoList] - NvmeSupport: Optional[EphemeralNvmeSupport] - EncryptionSupport: Optional[InstanceStorageEncryptionSupport] + TotalSizeInGB: DiskSize | None + Disks: DiskInfoList | None + NvmeSupport: EphemeralNvmeSupport | None + EncryptionSupport: InstanceStorageEncryptionSupport | None MemorySize = int class MemoryInfo(TypedDict, total=False): - SizeInMiB: Optional[MemorySize] + SizeInMiB: MemorySize | None -ThreadsPerCoreList = List[ThreadsPerCore] +ThreadsPerCoreList = list[ThreadsPerCore] class VCpuInfo(TypedDict, total=False): - DefaultVCpus: Optional[VCpuCount] - DefaultCores: Optional[CoreCount] - DefaultThreadsPerCore: Optional[ThreadsPerCore] - ValidCores: Optional[CoreCountList] - ValidThreadsPerCore: Optional[ThreadsPerCoreList] + DefaultVCpus: VCpuCount | None + DefaultCores: CoreCount | None + DefaultThreadsPerCore: ThreadsPerCore | None + ValidCores: CoreCountList | None + ValidThreadsPerCore: ThreadsPerCoreList | None -SupportedAdditionalProcessorFeatureList = List[SupportedAdditionalProcessorFeature] +SupportedAdditionalProcessorFeatureList = list[SupportedAdditionalProcessorFeature] class ProcessorInfo(TypedDict, total=False): - SupportedArchitectures: Optional[ArchitectureTypeList] - SustainedClockSpeedInGhz: Optional[ProcessorSustainedClockSpeed] - SupportedFeatures: Optional[SupportedAdditionalProcessorFeatureList] - Manufacturer: Optional[CpuManufacturerName] + SupportedArchitectures: ArchitectureTypeList | None + SustainedClockSpeedInGhz: ProcessorSustainedClockSpeed | None + SupportedFeatures: SupportedAdditionalProcessorFeatureList | None + Manufacturer: CpuManufacturerName | None -VirtualizationTypeList = List[VirtualizationType] -RootDeviceTypeList = List[RootDeviceType] -UsageClassTypeList = List[UsageClassType] +VirtualizationTypeList = list[VirtualizationType] +RootDeviceTypeList = list[RootDeviceType] +UsageClassTypeList = list[UsageClassType] class InstanceTypeInfo(TypedDict, total=False): - InstanceType: Optional[InstanceType] - CurrentGeneration: Optional[CurrentGenerationFlag] - FreeTierEligible: Optional[FreeTierEligibleFlag] - SupportedUsageClasses: Optional[UsageClassTypeList] - SupportedRootDeviceTypes: Optional[RootDeviceTypeList] - SupportedVirtualizationTypes: Optional[VirtualizationTypeList] - BareMetal: Optional[BareMetalFlag] - Hypervisor: Optional[InstanceTypeHypervisor] - ProcessorInfo: Optional[ProcessorInfo] - VCpuInfo: Optional[VCpuInfo] - MemoryInfo: Optional[MemoryInfo] - InstanceStorageSupported: Optional[InstanceStorageFlag] - InstanceStorageInfo: Optional[InstanceStorageInfo] - EbsInfo: Optional[EbsInfo] - NetworkInfo: Optional[NetworkInfo] - GpuInfo: Optional[GpuInfo] - FpgaInfo: Optional[FpgaInfo] - PlacementGroupInfo: Optional[PlacementGroupInfo] - InferenceAcceleratorInfo: Optional[InferenceAcceleratorInfo] - HibernationSupported: Optional[HibernationFlag] - BurstablePerformanceSupported: Optional[BurstablePerformanceFlag] - DedicatedHostsSupported: Optional[DedicatedHostFlag] - AutoRecoverySupported: Optional[AutoRecoveryFlag] - SupportedBootModes: Optional[BootModeTypeList] - NitroEnclavesSupport: Optional[NitroEnclavesSupport] - NitroTpmSupport: Optional[NitroTpmSupport] - NitroTpmInfo: Optional[NitroTpmInfo] - MediaAcceleratorInfo: Optional[MediaAcceleratorInfo] - NeuronInfo: Optional[NeuronInfo] - PhcSupport: Optional[PhcSupport] - RebootMigrationSupport: Optional[RebootMigrationSupport] - - -InstanceTypeInfoList = List[InstanceTypeInfo] + InstanceType: InstanceType | None + CurrentGeneration: CurrentGenerationFlag | None + FreeTierEligible: FreeTierEligibleFlag | None + SupportedUsageClasses: UsageClassTypeList | None + SupportedRootDeviceTypes: RootDeviceTypeList | None + SupportedVirtualizationTypes: VirtualizationTypeList | None + BareMetal: BareMetalFlag | None + Hypervisor: InstanceTypeHypervisor | None + ProcessorInfo: ProcessorInfo | None + VCpuInfo: VCpuInfo | None + MemoryInfo: MemoryInfo | None + InstanceStorageSupported: InstanceStorageFlag | None + InstanceStorageInfo: InstanceStorageInfo | None + EbsInfo: EbsInfo | None + NetworkInfo: NetworkInfo | None + GpuInfo: GpuInfo | None + FpgaInfo: FpgaInfo | None + PlacementGroupInfo: PlacementGroupInfo | None + InferenceAcceleratorInfo: InferenceAcceleratorInfo | None + HibernationSupported: HibernationFlag | None + BurstablePerformanceSupported: BurstablePerformanceFlag | None + DedicatedHostsSupported: DedicatedHostFlag | None + AutoRecoverySupported: AutoRecoveryFlag | None + SupportedBootModes: BootModeTypeList | None + NitroEnclavesSupport: NitroEnclavesSupport | None + NitroTpmSupport: NitroTpmSupport | None + NitroTpmInfo: NitroTpmInfo | None + MediaAcceleratorInfo: MediaAcceleratorInfo | None + NeuronInfo: NeuronInfo | None + PhcSupport: PhcSupport | None + RebootMigrationSupport: RebootMigrationSupport | None + + +InstanceTypeInfoList = list[InstanceTypeInfo] class DescribeInstanceTypesResult(TypedDict, total=False): - InstanceTypes: Optional[InstanceTypeInfoList] - NextToken: Optional[NextToken] + InstanceTypes: InstanceTypeInfoList | None + NextToken: NextToken | None class DescribeInstancesRequest(ServiceRequest): - InstanceIds: Optional[InstanceIdStringList] - DryRun: Optional[Boolean] - Filters: Optional[FilterList] - NextToken: Optional[String] - MaxResults: Optional[Integer] + InstanceIds: InstanceIdStringList | None + DryRun: Boolean | None + Filters: FilterList | None + NextToken: String | None + MaxResults: Integer | None class Monitoring(TypedDict, total=False): - State: Optional[MonitoringState] + State: MonitoringState | None + + +class InstanceSecondaryInterfacePrivateIpAddress(TypedDict, total=False): + PrivateIpAddress: String | None + + +InstanceSecondaryInterfacePrivateIpAddressList = list[InstanceSecondaryInterfacePrivateIpAddress] + + +class InstanceSecondaryInterfaceAttachment(TypedDict, total=False): + AttachTime: MillisecondDateTime | None + AttachmentId: String | None + DeleteOnTermination: Boolean | None + DeviceIndex: Integer | None + Status: AttachmentStatus | None + NetworkCardIndex: Integer | None + + +class InstanceSecondaryInterface(TypedDict, total=False): + Attachment: InstanceSecondaryInterfaceAttachment | None + MacAddress: String | None + SecondaryInterfaceId: SecondaryInterfaceId | None + OwnerId: String | None + PrivateIpAddresses: InstanceSecondaryInterfacePrivateIpAddressList | None + SourceDestCheck: Boolean | None + Status: SecondaryInterfaceStatus | None + SecondarySubnetId: SecondarySubnetId | None + SecondaryNetworkId: SecondaryNetworkId | None + InterfaceType: SecondaryInterfaceType | None + + +InstanceSecondaryInterfaceList = list[InstanceSecondaryInterface] class InstanceNetworkPerformanceOptions(TypedDict, total=False): - BandwidthWeighting: Optional[InstanceBandwidthWeighting] + BandwidthWeighting: InstanceBandwidthWeighting | None class InstanceMaintenanceOptions(TypedDict, total=False): - AutoRecovery: Optional[InstanceAutoRecoveryState] - RebootMigration: Optional[InstanceRebootMigrationState] + AutoRecovery: InstanceAutoRecoveryState | None + RebootMigration: InstanceRebootMigrationState | None class PrivateDnsNameOptionsResponse(TypedDict, total=False): - HostnameType: Optional[HostnameType] - EnableResourceNameDnsARecord: Optional[Boolean] - EnableResourceNameDnsAAAARecord: Optional[Boolean] + HostnameType: HostnameType | None + EnableResourceNameDnsARecord: Boolean | None + EnableResourceNameDnsAAAARecord: Boolean | None class EnclaveOptions(TypedDict, total=False): - Enabled: Optional[Boolean] + Enabled: Boolean | None class InstanceMetadataOptionsResponse(TypedDict, total=False): - State: Optional[InstanceMetadataOptionsState] - HttpTokens: Optional[HttpTokensState] - HttpPutResponseHopLimit: Optional[Integer] - HttpEndpoint: Optional[InstanceMetadataEndpointState] - HttpProtocolIpv6: Optional[InstanceMetadataProtocolState] - InstanceMetadataTags: Optional[InstanceMetadataTagsState] + State: InstanceMetadataOptionsState | None + HttpTokens: HttpTokensState | None + HttpPutResponseHopLimit: Integer | None + HttpEndpoint: InstanceMetadataEndpointState | None + HttpProtocolIpv6: InstanceMetadataProtocolState | None + InstanceMetadataTags: InstanceMetadataTagsState | None class LicenseConfiguration(TypedDict, total=False): - LicenseConfigurationArn: Optional[String] + LicenseConfigurationArn: String | None -LicenseList = List[LicenseConfiguration] +LicenseList = list[LicenseConfiguration] class HibernationOptions(TypedDict, total=False): - Configured: Optional[Boolean] + Configured: Boolean | None class InstanceIpv6Prefix(TypedDict, total=False): - Ipv6Prefix: Optional[String] + Ipv6Prefix: String | None -InstanceIpv6PrefixList = List[InstanceIpv6Prefix] +InstanceIpv6PrefixList = list[InstanceIpv6Prefix] class InstanceIpv4Prefix(TypedDict, total=False): - Ipv4Prefix: Optional[String] + Ipv4Prefix: String | None -InstanceIpv4PrefixList = List[InstanceIpv4Prefix] +InstanceIpv4PrefixList = list[InstanceIpv4Prefix] class InstanceNetworkInterfaceAssociation(TypedDict, total=False): - CarrierIp: Optional[String] - CustomerOwnedIp: Optional[String] - IpOwnerId: Optional[String] - PublicDnsName: Optional[String] - PublicIp: Optional[String] + CarrierIp: String | None + CustomerOwnedIp: String | None + IpOwnerId: String | None + PublicDnsName: String | None + PublicIp: String | None class InstancePrivateIpAddress(TypedDict, total=False): - Association: Optional[InstanceNetworkInterfaceAssociation] - Primary: Optional[Boolean] - PrivateDnsName: Optional[String] - PrivateIpAddress: Optional[String] + Association: InstanceNetworkInterfaceAssociation | None + Primary: Boolean | None + PrivateDnsName: String | None + PrivateIpAddress: String | None -InstancePrivateIpAddressList = List[InstancePrivateIpAddress] +InstancePrivateIpAddressList = list[InstancePrivateIpAddress] class InstanceAttachmentEnaSrdUdpSpecification(TypedDict, total=False): - EnaSrdUdpEnabled: Optional[Boolean] + EnaSrdUdpEnabled: Boolean | None class InstanceAttachmentEnaSrdSpecification(TypedDict, total=False): - EnaSrdEnabled: Optional[Boolean] - EnaSrdUdpSpecification: Optional[InstanceAttachmentEnaSrdUdpSpecification] + EnaSrdEnabled: Boolean | None + EnaSrdUdpSpecification: InstanceAttachmentEnaSrdUdpSpecification | None class InstanceNetworkInterfaceAttachment(TypedDict, total=False): - AttachTime: Optional[DateTime] - AttachmentId: Optional[String] - DeleteOnTermination: Optional[Boolean] - DeviceIndex: Optional[Integer] - Status: Optional[AttachmentStatus] - NetworkCardIndex: Optional[Integer] - EnaSrdSpecification: Optional[InstanceAttachmentEnaSrdSpecification] - EnaQueueCount: Optional[Integer] + AttachTime: DateTime | None + AttachmentId: String | None + DeleteOnTermination: Boolean | None + DeviceIndex: Integer | None + Status: AttachmentStatus | None + NetworkCardIndex: Integer | None + EnaSrdSpecification: InstanceAttachmentEnaSrdSpecification | None + EnaQueueCount: Integer | None class InstanceNetworkInterface(TypedDict, total=False): - Association: Optional[InstanceNetworkInterfaceAssociation] - Attachment: Optional[InstanceNetworkInterfaceAttachment] - Description: Optional[String] - Groups: Optional[GroupIdentifierList] - Ipv6Addresses: Optional[InstanceIpv6AddressList] - MacAddress: Optional[String] - NetworkInterfaceId: Optional[String] - OwnerId: Optional[String] - PrivateDnsName: Optional[String] - PrivateIpAddress: Optional[String] - PrivateIpAddresses: Optional[InstancePrivateIpAddressList] - SourceDestCheck: Optional[Boolean] - Status: Optional[NetworkInterfaceStatus] - SubnetId: Optional[String] - VpcId: Optional[String] - InterfaceType: Optional[String] - Ipv4Prefixes: Optional[InstanceIpv4PrefixList] - Ipv6Prefixes: Optional[InstanceIpv6PrefixList] - ConnectionTrackingConfiguration: Optional[ConnectionTrackingSpecificationResponse] - Operator: Optional[OperatorResponse] - - -InstanceNetworkInterfaceList = List[InstanceNetworkInterface] + Association: InstanceNetworkInterfaceAssociation | None + Attachment: InstanceNetworkInterfaceAttachment | None + Description: String | None + Groups: GroupIdentifierList | None + Ipv6Addresses: InstanceIpv6AddressList | None + MacAddress: String | None + NetworkInterfaceId: String | None + OwnerId: String | None + PrivateDnsName: String | None + PrivateIpAddress: String | None + PrivateIpAddresses: InstancePrivateIpAddressList | None + SourceDestCheck: Boolean | None + Status: NetworkInterfaceStatus | None + SubnetId: String | None + VpcId: String | None + InterfaceType: String | None + Ipv4Prefixes: InstanceIpv4PrefixList | None + Ipv6Prefixes: InstanceIpv6PrefixList | None + ConnectionTrackingConfiguration: ConnectionTrackingSpecificationResponse | None + Operator: OperatorResponse | None + + +InstanceNetworkInterfaceList = list[InstanceNetworkInterface] class ElasticInferenceAcceleratorAssociation(TypedDict, total=False): - ElasticInferenceAcceleratorArn: Optional[String] - ElasticInferenceAcceleratorAssociationId: Optional[String] - ElasticInferenceAcceleratorAssociationState: Optional[String] - ElasticInferenceAcceleratorAssociationTime: Optional[DateTime] + ElasticInferenceAcceleratorArn: String | None + ElasticInferenceAcceleratorAssociationId: String | None + ElasticInferenceAcceleratorAssociationState: String | None + ElasticInferenceAcceleratorAssociationTime: DateTime | None -ElasticInferenceAcceleratorAssociationList = List[ElasticInferenceAcceleratorAssociation] +ElasticInferenceAcceleratorAssociationList = list[ElasticInferenceAcceleratorAssociation] class ElasticGpuAssociation(TypedDict, total=False): - ElasticGpuId: Optional[ElasticGpuId] - ElasticGpuAssociationId: Optional[String] - ElasticGpuAssociationState: Optional[String] - ElasticGpuAssociationTime: Optional[String] + ElasticGpuId: ElasticGpuId | None + ElasticGpuAssociationId: String | None + ElasticGpuAssociationState: String | None + ElasticGpuAssociationTime: String | None -ElasticGpuAssociationList = List[ElasticGpuAssociation] +ElasticGpuAssociationList = list[ElasticGpuAssociation] class EbsInstanceBlockDevice(TypedDict, total=False): - AttachTime: Optional[DateTime] - DeleteOnTermination: Optional[Boolean] - Status: Optional[AttachmentStatus] - VolumeId: Optional[String] - AssociatedResource: Optional[String] - VolumeOwnerId: Optional[String] - Operator: Optional[OperatorResponse] + AttachTime: DateTime | None + DeleteOnTermination: Boolean | None + Status: AttachmentStatus | None + VolumeId: String | None + AssociatedResource: String | None + VolumeOwnerId: String | None + Operator: OperatorResponse | None + EbsCardIndex: Integer | None class InstanceBlockDeviceMapping(TypedDict, total=False): - DeviceName: Optional[String] - Ebs: Optional[EbsInstanceBlockDevice] + DeviceName: String | None + Ebs: EbsInstanceBlockDevice | None -InstanceBlockDeviceMappingList = List[InstanceBlockDeviceMapping] +InstanceBlockDeviceMappingList = list[InstanceBlockDeviceMapping] class Instance(TypedDict, total=False): - Architecture: Optional[ArchitectureValues] - BlockDeviceMappings: Optional[InstanceBlockDeviceMappingList] - ClientToken: Optional[String] - EbsOptimized: Optional[Boolean] - EnaSupport: Optional[Boolean] - Hypervisor: Optional[HypervisorType] - IamInstanceProfile: Optional[IamInstanceProfile] - InstanceLifecycle: Optional[InstanceLifecycleType] - ElasticGpuAssociations: Optional[ElasticGpuAssociationList] - ElasticInferenceAcceleratorAssociations: Optional[ElasticInferenceAcceleratorAssociationList] - NetworkInterfaces: Optional[InstanceNetworkInterfaceList] - OutpostArn: Optional[String] - RootDeviceName: Optional[String] - RootDeviceType: Optional[DeviceType] - SecurityGroups: Optional[GroupIdentifierList] - SourceDestCheck: Optional[Boolean] - SpotInstanceRequestId: Optional[String] - SriovNetSupport: Optional[String] - StateReason: Optional[StateReason] - Tags: Optional[TagList] - VirtualizationType: Optional[VirtualizationType] - CpuOptions: Optional[CpuOptions] - CapacityBlockId: Optional[String] - CapacityReservationId: Optional[String] - CapacityReservationSpecification: Optional[CapacityReservationSpecificationResponse] - HibernationOptions: Optional[HibernationOptions] - Licenses: Optional[LicenseList] - MetadataOptions: Optional[InstanceMetadataOptionsResponse] - EnclaveOptions: Optional[EnclaveOptions] - BootMode: Optional[BootModeValues] - PlatformDetails: Optional[String] - UsageOperation: Optional[String] - UsageOperationUpdateTime: Optional[MillisecondDateTime] - PrivateDnsNameOptions: Optional[PrivateDnsNameOptionsResponse] - Ipv6Address: Optional[String] - TpmSupport: Optional[String] - MaintenanceOptions: Optional[InstanceMaintenanceOptions] - CurrentInstanceBootMode: Optional[InstanceBootModeValues] - NetworkPerformanceOptions: Optional[InstanceNetworkPerformanceOptions] - Operator: Optional[OperatorResponse] - InstanceId: Optional[String] - ImageId: Optional[String] - State: Optional[InstanceState] - PrivateDnsName: Optional[String] - PublicDnsName: Optional[String] - StateTransitionReason: Optional[String] - KeyName: Optional[String] - AmiLaunchIndex: Optional[Integer] - ProductCodes: Optional[ProductCodeList] - InstanceType: Optional[InstanceType] - LaunchTime: Optional[DateTime] - Placement: Optional[Placement] - KernelId: Optional[String] - RamdiskId: Optional[String] - Platform: Optional[PlatformValues] - Monitoring: Optional[Monitoring] - SubnetId: Optional[String] - VpcId: Optional[String] - PrivateIpAddress: Optional[String] - PublicIpAddress: Optional[String] - - -InstanceList = List[Instance] + Architecture: ArchitectureValues | None + BlockDeviceMappings: InstanceBlockDeviceMappingList | None + ClientToken: String | None + EbsOptimized: Boolean | None + EnaSupport: Boolean | None + Hypervisor: HypervisorType | None + IamInstanceProfile: IamInstanceProfile | None + InstanceLifecycle: InstanceLifecycleType | None + ElasticGpuAssociations: ElasticGpuAssociationList | None + ElasticInferenceAcceleratorAssociations: ElasticInferenceAcceleratorAssociationList | None + NetworkInterfaces: InstanceNetworkInterfaceList | None + OutpostArn: String | None + RootDeviceName: String | None + RootDeviceType: DeviceType | None + SecurityGroups: GroupIdentifierList | None + SourceDestCheck: Boolean | None + SpotInstanceRequestId: String | None + SriovNetSupport: String | None + StateReason: StateReason | None + Tags: TagList | None + VirtualizationType: VirtualizationType | None + CpuOptions: CpuOptions | None + CapacityBlockId: String | None + CapacityReservationId: String | None + CapacityReservationSpecification: CapacityReservationSpecificationResponse | None + HibernationOptions: HibernationOptions | None + Licenses: LicenseList | None + MetadataOptions: InstanceMetadataOptionsResponse | None + EnclaveOptions: EnclaveOptions | None + BootMode: BootModeValues | None + PlatformDetails: String | None + UsageOperation: String | None + UsageOperationUpdateTime: MillisecondDateTime | None + PrivateDnsNameOptions: PrivateDnsNameOptionsResponse | None + Ipv6Address: String | None + TpmSupport: String | None + MaintenanceOptions: InstanceMaintenanceOptions | None + CurrentInstanceBootMode: InstanceBootModeValues | None + NetworkPerformanceOptions: InstanceNetworkPerformanceOptions | None + Operator: OperatorResponse | None + SecondaryInterfaces: InstanceSecondaryInterfaceList | None + InstanceId: String | None + ImageId: String | None + State: InstanceState | None + PrivateDnsName: String | None + PublicDnsName: String | None + StateTransitionReason: String | None + KeyName: String | None + AmiLaunchIndex: Integer | None + ProductCodes: ProductCodeList | None + InstanceType: InstanceType | None + LaunchTime: DateTime | None + Placement: Placement | None + KernelId: String | None + RamdiskId: String | None + Platform: PlatformValues | None + Monitoring: Monitoring | None + SubnetId: String | None + VpcId: String | None + PrivateIpAddress: String | None + PublicIpAddress: String | None + + +InstanceList = list[Instance] class Reservation(TypedDict, total=False): - ReservationId: Optional[String] - OwnerId: Optional[String] - RequesterId: Optional[String] - Groups: Optional[GroupIdentifierList] - Instances: Optional[InstanceList] + ReservationId: String | None + OwnerId: String | None + RequesterId: String | None + Groups: GroupIdentifierList | None + Instances: InstanceList | None -ReservationList = List[Reservation] +ReservationList = list[Reservation] class DescribeInstancesResult(TypedDict, total=False): - NextToken: Optional[String] - Reservations: Optional[ReservationList] + NextToken: String | None + Reservations: ReservationList | None -InternetGatewayIdList = List[InternetGatewayId] +InternetGatewayIdList = list[InternetGatewayId] class DescribeInternetGatewaysRequest(ServiceRequest): - NextToken: Optional[String] - MaxResults: Optional[DescribeInternetGatewaysMaxResults] - DryRun: Optional[Boolean] - InternetGatewayIds: Optional[InternetGatewayIdList] - Filters: Optional[FilterList] + NextToken: String | None + MaxResults: DescribeInternetGatewaysMaxResults | None + DryRun: Boolean | None + InternetGatewayIds: InternetGatewayIdList | None + Filters: FilterList | None -InternetGatewayList = List[InternetGateway] +InternetGatewayList = list[InternetGateway] class DescribeInternetGatewaysResult(TypedDict, total=False): - InternetGateways: Optional[InternetGatewayList] - NextToken: Optional[String] + InternetGateways: InternetGatewayList | None + NextToken: String | None class DescribeIpamByoasnRequest(ServiceRequest): - DryRun: Optional[Boolean] - MaxResults: Optional[DescribeIpamByoasnMaxResults] - NextToken: Optional[NextToken] + DryRun: Boolean | None + MaxResults: DescribeIpamByoasnMaxResults | None + NextToken: NextToken | None class DescribeIpamByoasnResult(TypedDict, total=False): - Byoasns: Optional[ByoasnSet] - NextToken: Optional[String] + Byoasns: ByoasnSet | None + NextToken: String | None class DescribeIpamExternalResourceVerificationTokensRequest(ServiceRequest): - DryRun: Optional[Boolean] - Filters: Optional[FilterList] - NextToken: Optional[NextToken] - MaxResults: Optional[IpamMaxResults] - IpamExternalResourceVerificationTokenIds: Optional[ValueStringList] + DryRun: Boolean | None + Filters: FilterList | None + NextToken: NextToken | None + MaxResults: IpamMaxResults | None + IpamExternalResourceVerificationTokenIds: ValueStringList | None -IpamExternalResourceVerificationTokenSet = List[IpamExternalResourceVerificationToken] +IpamExternalResourceVerificationTokenSet = list[IpamExternalResourceVerificationToken] class DescribeIpamExternalResourceVerificationTokensResult(TypedDict, total=False): - NextToken: Optional[NextToken] - IpamExternalResourceVerificationTokens: Optional[IpamExternalResourceVerificationTokenSet] + NextToken: NextToken | None + IpamExternalResourceVerificationTokens: IpamExternalResourceVerificationTokenSet | None + + +class DescribeIpamPoliciesRequest(ServiceRequest): + DryRun: Boolean | None + Filters: FilterList | None + MaxResults: IpamMaxResults | None + NextToken: NextToken | None + IpamPolicyIds: ValueStringList | None + + +IpamPolicySet = list[IpamPolicy] + + +class DescribeIpamPoliciesResult(TypedDict, total=False): + NextToken: NextToken | None + IpamPolicies: IpamPolicySet | None class DescribeIpamPoolsRequest(ServiceRequest): - DryRun: Optional[Boolean] - Filters: Optional[FilterList] - MaxResults: Optional[IpamMaxResults] - NextToken: Optional[NextToken] - IpamPoolIds: Optional[ValueStringList] + DryRun: Boolean | None + Filters: FilterList | None + MaxResults: IpamMaxResults | None + NextToken: NextToken | None + IpamPoolIds: ValueStringList | None -IpamPoolSet = List[IpamPool] +IpamPoolSet = list[IpamPool] class DescribeIpamPoolsResult(TypedDict, total=False): - NextToken: Optional[NextToken] - IpamPools: Optional[IpamPoolSet] + NextToken: NextToken | None + IpamPools: IpamPoolSet | None + + +class DescribeIpamPrefixListResolverTargetsRequest(ServiceRequest): + DryRun: Boolean | None + Filters: FilterList | None + MaxResults: IpamMaxResults | None + NextToken: NextToken | None + IpamPrefixListResolverTargetIds: ValueStringList | None + IpamPrefixListResolverId: IpamPrefixListResolverId | None + + +IpamPrefixListResolverTargetSet = list[IpamPrefixListResolverTarget] + + +class DescribeIpamPrefixListResolverTargetsResult(TypedDict, total=False): + NextToken: NextToken | None + IpamPrefixListResolverTargets: IpamPrefixListResolverTargetSet | None + + +class DescribeIpamPrefixListResolversRequest(ServiceRequest): + DryRun: Boolean | None + Filters: FilterList | None + MaxResults: IpamMaxResults | None + NextToken: NextToken | None + IpamPrefixListResolverIds: ValueStringList | None + + +IpamPrefixListResolverSet = list[IpamPrefixListResolver] + + +class DescribeIpamPrefixListResolversResult(TypedDict, total=False): + NextToken: NextToken | None + IpamPrefixListResolvers: IpamPrefixListResolverSet | None class DescribeIpamResourceDiscoveriesRequest(ServiceRequest): - DryRun: Optional[Boolean] - IpamResourceDiscoveryIds: Optional[ValueStringList] - NextToken: Optional[NextToken] - MaxResults: Optional[IpamMaxResults] - Filters: Optional[FilterList] + DryRun: Boolean | None + IpamResourceDiscoveryIds: ValueStringList | None + NextToken: NextToken | None + MaxResults: IpamMaxResults | None + Filters: FilterList | None -IpamResourceDiscoverySet = List[IpamResourceDiscovery] +IpamResourceDiscoverySet = list[IpamResourceDiscovery] class DescribeIpamResourceDiscoveriesResult(TypedDict, total=False): - IpamResourceDiscoveries: Optional[IpamResourceDiscoverySet] - NextToken: Optional[NextToken] + IpamResourceDiscoveries: IpamResourceDiscoverySet | None + NextToken: NextToken | None class DescribeIpamResourceDiscoveryAssociationsRequest(ServiceRequest): - DryRun: Optional[Boolean] - IpamResourceDiscoveryAssociationIds: Optional[ValueStringList] - NextToken: Optional[NextToken] - MaxResults: Optional[IpamMaxResults] - Filters: Optional[FilterList] + DryRun: Boolean | None + IpamResourceDiscoveryAssociationIds: ValueStringList | None + NextToken: NextToken | None + MaxResults: IpamMaxResults | None + Filters: FilterList | None -IpamResourceDiscoveryAssociationSet = List[IpamResourceDiscoveryAssociation] +IpamResourceDiscoveryAssociationSet = list[IpamResourceDiscoveryAssociation] class DescribeIpamResourceDiscoveryAssociationsResult(TypedDict, total=False): - IpamResourceDiscoveryAssociations: Optional[IpamResourceDiscoveryAssociationSet] - NextToken: Optional[NextToken] + IpamResourceDiscoveryAssociations: IpamResourceDiscoveryAssociationSet | None + NextToken: NextToken | None class DescribeIpamScopesRequest(ServiceRequest): - DryRun: Optional[Boolean] - Filters: Optional[FilterList] - MaxResults: Optional[IpamMaxResults] - NextToken: Optional[NextToken] - IpamScopeIds: Optional[ValueStringList] + DryRun: Boolean | None + Filters: FilterList | None + MaxResults: IpamMaxResults | None + NextToken: NextToken | None + IpamScopeIds: ValueStringList | None -IpamScopeSet = List[IpamScope] +IpamScopeSet = list[IpamScope] class DescribeIpamScopesResult(TypedDict, total=False): - NextToken: Optional[NextToken] - IpamScopes: Optional[IpamScopeSet] + NextToken: NextToken | None + IpamScopes: IpamScopeSet | None class DescribeIpamsRequest(ServiceRequest): - DryRun: Optional[Boolean] - Filters: Optional[FilterList] - MaxResults: Optional[IpamMaxResults] - NextToken: Optional[NextToken] - IpamIds: Optional[ValueStringList] + DryRun: Boolean | None + Filters: FilterList | None + MaxResults: IpamMaxResults | None + NextToken: NextToken | None + IpamIds: ValueStringList | None -IpamSet = List[Ipam] +IpamSet = list[Ipam] class DescribeIpamsResult(TypedDict, total=False): - NextToken: Optional[NextToken] - Ipams: Optional[IpamSet] + NextToken: NextToken | None + Ipams: IpamSet | None -Ipv6PoolIdList = List[Ipv6PoolEc2Id] +Ipv6PoolIdList = list[Ipv6PoolEc2Id] class DescribeIpv6PoolsRequest(ServiceRequest): - PoolIds: Optional[Ipv6PoolIdList] - NextToken: Optional[NextToken] - MaxResults: Optional[Ipv6PoolMaxResults] - DryRun: Optional[Boolean] - Filters: Optional[FilterList] + PoolIds: Ipv6PoolIdList | None + NextToken: NextToken | None + MaxResults: Ipv6PoolMaxResults | None + DryRun: Boolean | None + Filters: FilterList | None class PoolCidrBlock(TypedDict, total=False): - Cidr: Optional[String] + Cidr: String | None -PoolCidrBlocksSet = List[PoolCidrBlock] +PoolCidrBlocksSet = list[PoolCidrBlock] class Ipv6Pool(TypedDict, total=False): - PoolId: Optional[String] - Description: Optional[String] - PoolCidrBlocks: Optional[PoolCidrBlocksSet] - Tags: Optional[TagList] + PoolId: String | None + Description: String | None + PoolCidrBlocks: PoolCidrBlocksSet | None + Tags: TagList | None -Ipv6PoolSet = List[Ipv6Pool] +Ipv6PoolSet = list[Ipv6Pool] class DescribeIpv6PoolsResult(TypedDict, total=False): - Ipv6Pools: Optional[Ipv6PoolSet] - NextToken: Optional[NextToken] + Ipv6Pools: Ipv6PoolSet | None + NextToken: NextToken | None -KeyPairIdStringList = List[KeyPairId] -KeyNameStringList = List[KeyPairName] +KeyPairIdStringList = list[KeyPairId] +KeyNameStringList = list[KeyPairName] class DescribeKeyPairsRequest(ServiceRequest): - KeyNames: Optional[KeyNameStringList] - KeyPairIds: Optional[KeyPairIdStringList] - IncludePublicKey: Optional[Boolean] - DryRun: Optional[Boolean] - Filters: Optional[FilterList] + KeyNames: KeyNameStringList | None + KeyPairIds: KeyPairIdStringList | None + IncludePublicKey: Boolean | None + DryRun: Boolean | None + Filters: FilterList | None class KeyPairInfo(TypedDict, total=False): - KeyPairId: Optional[String] - KeyType: Optional[KeyType] - Tags: Optional[TagList] - PublicKey: Optional[String] - CreateTime: Optional[MillisecondDateTime] - KeyName: Optional[String] - KeyFingerprint: Optional[String] + KeyPairId: String | None + KeyType: KeyType | None + Tags: TagList | None + PublicKey: String | None + CreateTime: MillisecondDateTime | None + KeyName: String | None + KeyFingerprint: String | None -KeyPairList = List[KeyPairInfo] +KeyPairList = list[KeyPairInfo] class DescribeKeyPairsResult(TypedDict, total=False): - KeyPairs: Optional[KeyPairList] + KeyPairs: KeyPairList | None class DescribeLaunchTemplateVersionsRequest(ServiceRequest): - DryRun: Optional[Boolean] - LaunchTemplateId: Optional[LaunchTemplateId] - LaunchTemplateName: Optional[LaunchTemplateName] - Versions: Optional[VersionStringList] - MinVersion: Optional[String] - MaxVersion: Optional[String] - NextToken: Optional[String] - MaxResults: Optional[Integer] - Filters: Optional[FilterList] - ResolveAlias: Optional[Boolean] + DryRun: Boolean | None + LaunchTemplateId: LaunchTemplateId | None + LaunchTemplateName: LaunchTemplateName | None + Versions: VersionStringList | None + MinVersion: String | None + MaxVersion: String | None + NextToken: String | None + MaxResults: Integer | None + Filters: FilterList | None + ResolveAlias: Boolean | None -LaunchTemplateVersionSet = List[LaunchTemplateVersion] +LaunchTemplateVersionSet = list[LaunchTemplateVersion] class DescribeLaunchTemplateVersionsResult(TypedDict, total=False): - LaunchTemplateVersions: Optional[LaunchTemplateVersionSet] - NextToken: Optional[String] + LaunchTemplateVersions: LaunchTemplateVersionSet | None + NextToken: String | None -LaunchTemplateNameStringList = List[LaunchTemplateName] -LaunchTemplateIdStringList = List[LaunchTemplateId] +LaunchTemplateNameStringList = list[LaunchTemplateName] +LaunchTemplateIdStringList = list[LaunchTemplateId] class DescribeLaunchTemplatesRequest(ServiceRequest): - DryRun: Optional[Boolean] - LaunchTemplateIds: Optional[LaunchTemplateIdStringList] - LaunchTemplateNames: Optional[LaunchTemplateNameStringList] - Filters: Optional[FilterList] - NextToken: Optional[String] - MaxResults: Optional[DescribeLaunchTemplatesMaxResults] + DryRun: Boolean | None + LaunchTemplateIds: LaunchTemplateIdStringList | None + LaunchTemplateNames: LaunchTemplateNameStringList | None + Filters: FilterList | None + NextToken: String | None + MaxResults: DescribeLaunchTemplatesMaxResults | None -LaunchTemplateSet = List[LaunchTemplate] +LaunchTemplateSet = list[LaunchTemplate] class DescribeLaunchTemplatesResult(TypedDict, total=False): - LaunchTemplates: Optional[LaunchTemplateSet] - NextToken: Optional[String] + LaunchTemplates: LaunchTemplateSet | None + NextToken: String | None -LocalGatewayRouteTableVirtualInterfaceGroupAssociationIdSet = List[ +LocalGatewayRouteTableVirtualInterfaceGroupAssociationIdSet = list[ LocalGatewayRouteTableVirtualInterfaceGroupAssociationId ] class DescribeLocalGatewayRouteTableVirtualInterfaceGroupAssociationsRequest(ServiceRequest): - LocalGatewayRouteTableVirtualInterfaceGroupAssociationIds: Optional[ - LocalGatewayRouteTableVirtualInterfaceGroupAssociationIdSet - ] - Filters: Optional[FilterList] - MaxResults: Optional[LocalGatewayMaxResults] - NextToken: Optional[String] - DryRun: Optional[Boolean] + LocalGatewayRouteTableVirtualInterfaceGroupAssociationIds: ( + LocalGatewayRouteTableVirtualInterfaceGroupAssociationIdSet | None + ) + Filters: FilterList | None + MaxResults: LocalGatewayMaxResults | None + NextToken: String | None + DryRun: Boolean | None -LocalGatewayRouteTableVirtualInterfaceGroupAssociationSet = List[ +LocalGatewayRouteTableVirtualInterfaceGroupAssociationSet = list[ LocalGatewayRouteTableVirtualInterfaceGroupAssociation ] class DescribeLocalGatewayRouteTableVirtualInterfaceGroupAssociationsResult(TypedDict, total=False): - LocalGatewayRouteTableVirtualInterfaceGroupAssociations: Optional[ - LocalGatewayRouteTableVirtualInterfaceGroupAssociationSet - ] - NextToken: Optional[String] + LocalGatewayRouteTableVirtualInterfaceGroupAssociations: ( + LocalGatewayRouteTableVirtualInterfaceGroupAssociationSet | None + ) + NextToken: String | None -LocalGatewayRouteTableVpcAssociationIdSet = List[LocalGatewayRouteTableVpcAssociationId] +LocalGatewayRouteTableVpcAssociationIdSet = list[LocalGatewayRouteTableVpcAssociationId] class DescribeLocalGatewayRouteTableVpcAssociationsRequest(ServiceRequest): - LocalGatewayRouteTableVpcAssociationIds: Optional[LocalGatewayRouteTableVpcAssociationIdSet] - Filters: Optional[FilterList] - MaxResults: Optional[LocalGatewayMaxResults] - NextToken: Optional[String] - DryRun: Optional[Boolean] + LocalGatewayRouteTableVpcAssociationIds: LocalGatewayRouteTableVpcAssociationIdSet | None + Filters: FilterList | None + MaxResults: LocalGatewayMaxResults | None + NextToken: String | None + DryRun: Boolean | None -LocalGatewayRouteTableVpcAssociationSet = List[LocalGatewayRouteTableVpcAssociation] +LocalGatewayRouteTableVpcAssociationSet = list[LocalGatewayRouteTableVpcAssociation] class DescribeLocalGatewayRouteTableVpcAssociationsResult(TypedDict, total=False): - LocalGatewayRouteTableVpcAssociations: Optional[LocalGatewayRouteTableVpcAssociationSet] - NextToken: Optional[String] + LocalGatewayRouteTableVpcAssociations: LocalGatewayRouteTableVpcAssociationSet | None + NextToken: String | None -LocalGatewayRouteTableIdSet = List[LocalGatewayRoutetableId] +LocalGatewayRouteTableIdSet = list[LocalGatewayRoutetableId] class DescribeLocalGatewayRouteTablesRequest(ServiceRequest): - LocalGatewayRouteTableIds: Optional[LocalGatewayRouteTableIdSet] - Filters: Optional[FilterList] - MaxResults: Optional[LocalGatewayMaxResults] - NextToken: Optional[String] - DryRun: Optional[Boolean] + LocalGatewayRouteTableIds: LocalGatewayRouteTableIdSet | None + Filters: FilterList | None + MaxResults: LocalGatewayMaxResults | None + NextToken: String | None + DryRun: Boolean | None -LocalGatewayRouteTableSet = List[LocalGatewayRouteTable] +LocalGatewayRouteTableSet = list[LocalGatewayRouteTable] class DescribeLocalGatewayRouteTablesResult(TypedDict, total=False): - LocalGatewayRouteTables: Optional[LocalGatewayRouteTableSet] - NextToken: Optional[String] + LocalGatewayRouteTables: LocalGatewayRouteTableSet | None + NextToken: String | None -LocalGatewayVirtualInterfaceGroupIdSet = List[LocalGatewayVirtualInterfaceGroupId] +LocalGatewayVirtualInterfaceGroupIdSet = list[LocalGatewayVirtualInterfaceGroupId] class DescribeLocalGatewayVirtualInterfaceGroupsRequest(ServiceRequest): - LocalGatewayVirtualInterfaceGroupIds: Optional[LocalGatewayVirtualInterfaceGroupIdSet] - Filters: Optional[FilterList] - MaxResults: Optional[LocalGatewayMaxResults] - NextToken: Optional[String] - DryRun: Optional[Boolean] + LocalGatewayVirtualInterfaceGroupIds: LocalGatewayVirtualInterfaceGroupIdSet | None + Filters: FilterList | None + MaxResults: LocalGatewayMaxResults | None + NextToken: String | None + DryRun: Boolean | None -LocalGatewayVirtualInterfaceGroupSet = List[LocalGatewayVirtualInterfaceGroup] +LocalGatewayVirtualInterfaceGroupSet = list[LocalGatewayVirtualInterfaceGroup] class DescribeLocalGatewayVirtualInterfaceGroupsResult(TypedDict, total=False): - LocalGatewayVirtualInterfaceGroups: Optional[LocalGatewayVirtualInterfaceGroupSet] - NextToken: Optional[String] + LocalGatewayVirtualInterfaceGroups: LocalGatewayVirtualInterfaceGroupSet | None + NextToken: String | None class DescribeLocalGatewayVirtualInterfacesRequest(ServiceRequest): - LocalGatewayVirtualInterfaceIds: Optional[LocalGatewayVirtualInterfaceIdSet] - Filters: Optional[FilterList] - MaxResults: Optional[LocalGatewayMaxResults] - NextToken: Optional[String] - DryRun: Optional[Boolean] + LocalGatewayVirtualInterfaceIds: LocalGatewayVirtualInterfaceIdSet | None + Filters: FilterList | None + MaxResults: LocalGatewayMaxResults | None + NextToken: String | None + DryRun: Boolean | None -LocalGatewayVirtualInterfaceSet = List[LocalGatewayVirtualInterface] +LocalGatewayVirtualInterfaceSet = list[LocalGatewayVirtualInterface] class DescribeLocalGatewayVirtualInterfacesResult(TypedDict, total=False): - LocalGatewayVirtualInterfaces: Optional[LocalGatewayVirtualInterfaceSet] - NextToken: Optional[String] + LocalGatewayVirtualInterfaces: LocalGatewayVirtualInterfaceSet | None + NextToken: String | None -LocalGatewayIdSet = List[LocalGatewayId] +LocalGatewayIdSet = list[LocalGatewayId] class DescribeLocalGatewaysRequest(ServiceRequest): - LocalGatewayIds: Optional[LocalGatewayIdSet] - Filters: Optional[FilterList] - MaxResults: Optional[LocalGatewayMaxResults] - NextToken: Optional[String] - DryRun: Optional[Boolean] + LocalGatewayIds: LocalGatewayIdSet | None + Filters: FilterList | None + MaxResults: LocalGatewayMaxResults | None + NextToken: String | None + DryRun: Boolean | None class LocalGateway(TypedDict, total=False): - LocalGatewayId: Optional[LocalGatewayId] - OutpostArn: Optional[String] - OwnerId: Optional[String] - State: Optional[String] - Tags: Optional[TagList] + LocalGatewayId: LocalGatewayId | None + OutpostArn: String | None + OwnerId: String | None + State: String | None + Tags: TagList | None -LocalGatewaySet = List[LocalGateway] +LocalGatewaySet = list[LocalGateway] class DescribeLocalGatewaysResult(TypedDict, total=False): - LocalGateways: Optional[LocalGatewaySet] - NextToken: Optional[String] + LocalGateways: LocalGatewaySet | None + NextToken: String | None -SnapshotIdStringList = List[SnapshotId] +SnapshotIdStringList = list[SnapshotId] class DescribeLockedSnapshotsRequest(ServiceRequest): - Filters: Optional[FilterList] - MaxResults: Optional[DescribeLockedSnapshotsMaxResults] - NextToken: Optional[String] - SnapshotIds: Optional[SnapshotIdStringList] - DryRun: Optional[Boolean] + Filters: FilterList | None + MaxResults: DescribeLockedSnapshotsMaxResults | None + NextToken: String | None + SnapshotIds: SnapshotIdStringList | None + DryRun: Boolean | None class LockedSnapshotsInfo(TypedDict, total=False): - OwnerId: Optional[String] - SnapshotId: Optional[String] - LockState: Optional[LockState] - LockDuration: Optional[RetentionPeriodResponseDays] - CoolOffPeriod: Optional[CoolOffPeriodResponseHours] - CoolOffPeriodExpiresOn: Optional[MillisecondDateTime] - LockCreatedOn: Optional[MillisecondDateTime] - LockDurationStartTime: Optional[MillisecondDateTime] - LockExpiresOn: Optional[MillisecondDateTime] + OwnerId: String | None + SnapshotId: String | None + LockState: LockState | None + LockDuration: RetentionPeriodResponseDays | None + CoolOffPeriod: CoolOffPeriodResponseHours | None + CoolOffPeriodExpiresOn: MillisecondDateTime | None + LockCreatedOn: MillisecondDateTime | None + LockDurationStartTime: MillisecondDateTime | None + LockExpiresOn: MillisecondDateTime | None -LockedSnapshotsInfoList = List[LockedSnapshotsInfo] +LockedSnapshotsInfoList = list[LockedSnapshotsInfo] class DescribeLockedSnapshotsResult(TypedDict, total=False): - Snapshots: Optional[LockedSnapshotsInfoList] - NextToken: Optional[String] + Snapshots: LockedSnapshotsInfoList | None + NextToken: String | None class DescribeMacHostsRequest(ServiceRequest): - Filters: Optional[FilterList] - HostIds: Optional[RequestHostIdList] - MaxResults: Optional[DescribeMacHostsRequestMaxResults] - NextToken: Optional[String] + Filters: FilterList | None + HostIds: RequestHostIdList | None + MaxResults: DescribeMacHostsRequestMaxResults | None + NextToken: String | None -MacOSVersionStringList = List[String] +MacOSVersionStringList = list[String] class MacHost(TypedDict, total=False): - HostId: Optional[DedicatedHostId] - MacOSLatestSupportedVersions: Optional[MacOSVersionStringList] + HostId: DedicatedHostId | None + MacOSLatestSupportedVersions: MacOSVersionStringList | None -MacHostList = List[MacHost] +MacHostList = list[MacHost] class DescribeMacHostsResult(TypedDict, total=False): - MacHosts: Optional[MacHostList] - NextToken: Optional[String] + MacHosts: MacHostList | None + NextToken: String | None -MacModificationTaskIdList = List[MacModificationTaskId] +MacModificationTaskIdList = list[MacModificationTaskId] class DescribeMacModificationTasksRequest(ServiceRequest): - DryRun: Optional[Boolean] - Filters: Optional[FilterList] - MacModificationTaskIds: Optional[MacModificationTaskIdList] - MaxResults: Optional[DescribeMacModificationTasksMaxResults] - NextToken: Optional[String] + DryRun: Boolean | None + Filters: FilterList | None + MacModificationTaskIds: MacModificationTaskIdList | None + MaxResults: DescribeMacModificationTasksMaxResults | None + NextToken: String | None -MacModificationTaskList = List[MacModificationTask] +MacModificationTaskList = list[MacModificationTask] class DescribeMacModificationTasksResult(TypedDict, total=False): - MacModificationTasks: Optional[MacModificationTaskList] - NextToken: Optional[String] + MacModificationTasks: MacModificationTaskList | None + NextToken: String | None class DescribeManagedPrefixListsRequest(ServiceRequest): - DryRun: Optional[Boolean] - Filters: Optional[FilterList] - MaxResults: Optional[PrefixListMaxResults] - NextToken: Optional[NextToken] - PrefixListIds: Optional[ValueStringList] + DryRun: Boolean | None + Filters: FilterList | None + MaxResults: PrefixListMaxResults | None + NextToken: NextToken | None + PrefixListIds: ValueStringList | None -ManagedPrefixListSet = List[ManagedPrefixList] +ManagedPrefixListSet = list[ManagedPrefixList] class DescribeManagedPrefixListsResult(TypedDict, total=False): - NextToken: Optional[NextToken] - PrefixLists: Optional[ManagedPrefixListSet] + NextToken: NextToken | None + PrefixLists: ManagedPrefixListSet | None class DescribeMovingAddressesRequest(ServiceRequest): - DryRun: Optional[Boolean] - PublicIps: Optional[ValueStringList] - NextToken: Optional[String] - Filters: Optional[FilterList] - MaxResults: Optional[DescribeMovingAddressesMaxResults] + DryRun: Boolean | None + PublicIps: ValueStringList | None + NextToken: String | None + Filters: FilterList | None + MaxResults: DescribeMovingAddressesMaxResults | None class MovingAddressStatus(TypedDict, total=False): - MoveStatus: Optional[MoveStatus] - PublicIp: Optional[String] + MoveStatus: MoveStatus | None + PublicIp: String | None -MovingAddressStatusSet = List[MovingAddressStatus] +MovingAddressStatusSet = list[MovingAddressStatus] class DescribeMovingAddressesResult(TypedDict, total=False): - MovingAddressStatuses: Optional[MovingAddressStatusSet] - NextToken: Optional[String] + MovingAddressStatuses: MovingAddressStatusSet | None + NextToken: String | None -NatGatewayIdStringList = List[NatGatewayId] +NatGatewayIdStringList = list[NatGatewayId] class DescribeNatGatewaysRequest(ServiceRequest): - DryRun: Optional[Boolean] - Filter: Optional[FilterList] - MaxResults: Optional[DescribeNatGatewaysMaxResults] - NatGatewayIds: Optional[NatGatewayIdStringList] - NextToken: Optional[String] + DryRun: Boolean | None + Filter: FilterList | None + MaxResults: DescribeNatGatewaysMaxResults | None + NatGatewayIds: NatGatewayIdStringList | None + NextToken: String | None -NatGatewayList = List[NatGateway] +NatGatewayList = list[NatGateway] class DescribeNatGatewaysResult(TypedDict, total=False): - NatGateways: Optional[NatGatewayList] - NextToken: Optional[String] + NatGateways: NatGatewayList | None + NextToken: String | None -NetworkAclIdStringList = List[NetworkAclId] +NetworkAclIdStringList = list[NetworkAclId] class DescribeNetworkAclsRequest(ServiceRequest): - NextToken: Optional[String] - MaxResults: Optional[DescribeNetworkAclsMaxResults] - DryRun: Optional[Boolean] - NetworkAclIds: Optional[NetworkAclIdStringList] - Filters: Optional[FilterList] + NextToken: String | None + MaxResults: DescribeNetworkAclsMaxResults | None + DryRun: Boolean | None + NetworkAclIds: NetworkAclIdStringList | None + Filters: FilterList | None -NetworkAclList = List[NetworkAcl] +NetworkAclList = list[NetworkAcl] class DescribeNetworkAclsResult(TypedDict, total=False): - NetworkAcls: Optional[NetworkAclList] - NextToken: Optional[String] + NetworkAcls: NetworkAclList | None + NextToken: String | None -NetworkInsightsAccessScopeAnalysisIdList = List[NetworkInsightsAccessScopeAnalysisId] +NetworkInsightsAccessScopeAnalysisIdList = list[NetworkInsightsAccessScopeAnalysisId] class DescribeNetworkInsightsAccessScopeAnalysesRequest(ServiceRequest): - NetworkInsightsAccessScopeAnalysisIds: Optional[NetworkInsightsAccessScopeAnalysisIdList] - NetworkInsightsAccessScopeId: Optional[NetworkInsightsAccessScopeId] - AnalysisStartTimeBegin: Optional[MillisecondDateTime] - AnalysisStartTimeEnd: Optional[MillisecondDateTime] - Filters: Optional[FilterList] - MaxResults: Optional[NetworkInsightsMaxResults] - DryRun: Optional[Boolean] - NextToken: Optional[NextToken] + NetworkInsightsAccessScopeAnalysisIds: NetworkInsightsAccessScopeAnalysisIdList | None + NetworkInsightsAccessScopeId: NetworkInsightsAccessScopeId | None + AnalysisStartTimeBegin: MillisecondDateTime | None + AnalysisStartTimeEnd: MillisecondDateTime | None + Filters: FilterList | None + MaxResults: NetworkInsightsMaxResults | None + DryRun: Boolean | None + NextToken: NextToken | None class NetworkInsightsAccessScopeAnalysis(TypedDict, total=False): - NetworkInsightsAccessScopeAnalysisId: Optional[NetworkInsightsAccessScopeAnalysisId] - NetworkInsightsAccessScopeAnalysisArn: Optional[ResourceArn] - NetworkInsightsAccessScopeId: Optional[NetworkInsightsAccessScopeId] - Status: Optional[AnalysisStatus] - StatusMessage: Optional[String] - WarningMessage: Optional[String] - StartDate: Optional[MillisecondDateTime] - EndDate: Optional[MillisecondDateTime] - FindingsFound: Optional[FindingsFound] - AnalyzedEniCount: Optional[Integer] - Tags: Optional[TagList] + NetworkInsightsAccessScopeAnalysisId: NetworkInsightsAccessScopeAnalysisId | None + NetworkInsightsAccessScopeAnalysisArn: ResourceArn | None + NetworkInsightsAccessScopeId: NetworkInsightsAccessScopeId | None + Status: AnalysisStatus | None + StatusMessage: String | None + WarningMessage: String | None + StartDate: MillisecondDateTime | None + EndDate: MillisecondDateTime | None + FindingsFound: FindingsFound | None + AnalyzedEniCount: Integer | None + Tags: TagList | None -NetworkInsightsAccessScopeAnalysisList = List[NetworkInsightsAccessScopeAnalysis] +NetworkInsightsAccessScopeAnalysisList = list[NetworkInsightsAccessScopeAnalysis] class DescribeNetworkInsightsAccessScopeAnalysesResult(TypedDict, total=False): - NetworkInsightsAccessScopeAnalyses: Optional[NetworkInsightsAccessScopeAnalysisList] - NextToken: Optional[String] + NetworkInsightsAccessScopeAnalyses: NetworkInsightsAccessScopeAnalysisList | None + NextToken: String | None -NetworkInsightsAccessScopeIdList = List[NetworkInsightsAccessScopeId] +NetworkInsightsAccessScopeIdList = list[NetworkInsightsAccessScopeId] class DescribeNetworkInsightsAccessScopesRequest(ServiceRequest): - NetworkInsightsAccessScopeIds: Optional[NetworkInsightsAccessScopeIdList] - Filters: Optional[FilterList] - MaxResults: Optional[NetworkInsightsMaxResults] - DryRun: Optional[Boolean] - NextToken: Optional[NextToken] + NetworkInsightsAccessScopeIds: NetworkInsightsAccessScopeIdList | None + Filters: FilterList | None + MaxResults: NetworkInsightsMaxResults | None + DryRun: Boolean | None + NextToken: NextToken | None -NetworkInsightsAccessScopeList = List[NetworkInsightsAccessScope] +NetworkInsightsAccessScopeList = list[NetworkInsightsAccessScope] class DescribeNetworkInsightsAccessScopesResult(TypedDict, total=False): - NetworkInsightsAccessScopes: Optional[NetworkInsightsAccessScopeList] - NextToken: Optional[String] + NetworkInsightsAccessScopes: NetworkInsightsAccessScopeList | None + NextToken: String | None -NetworkInsightsAnalysisIdList = List[NetworkInsightsAnalysisId] +NetworkInsightsAnalysisIdList = list[NetworkInsightsAnalysisId] class DescribeNetworkInsightsAnalysesRequest(ServiceRequest): - NetworkInsightsAnalysisIds: Optional[NetworkInsightsAnalysisIdList] - NetworkInsightsPathId: Optional[NetworkInsightsPathId] - AnalysisStartTime: Optional[MillisecondDateTime] - AnalysisEndTime: Optional[MillisecondDateTime] - Filters: Optional[FilterList] - MaxResults: Optional[NetworkInsightsMaxResults] - DryRun: Optional[Boolean] - NextToken: Optional[NextToken] + NetworkInsightsAnalysisIds: NetworkInsightsAnalysisIdList | None + NetworkInsightsPathId: NetworkInsightsPathId | None + AnalysisStartTime: MillisecondDateTime | None + AnalysisEndTime: MillisecondDateTime | None + Filters: FilterList | None + MaxResults: NetworkInsightsMaxResults | None + DryRun: Boolean | None + NextToken: NextToken | None class NetworkInsightsAnalysis(TypedDict, total=False): - NetworkInsightsAnalysisId: Optional[NetworkInsightsAnalysisId] - NetworkInsightsAnalysisArn: Optional[ResourceArn] - NetworkInsightsPathId: Optional[NetworkInsightsPathId] - AdditionalAccounts: Optional[ValueStringList] - FilterInArns: Optional[ArnList] - FilterOutArns: Optional[ArnList] - StartDate: Optional[MillisecondDateTime] - Status: Optional[AnalysisStatus] - StatusMessage: Optional[String] - WarningMessage: Optional[String] - NetworkPathFound: Optional[Boolean] - ForwardPathComponents: Optional[PathComponentList] - ReturnPathComponents: Optional[PathComponentList] - Explanations: Optional[ExplanationList] - AlternatePathHints: Optional[AlternatePathHintList] - SuggestedAccounts: Optional[ValueStringList] - Tags: Optional[TagList] - - -NetworkInsightsAnalysisList = List[NetworkInsightsAnalysis] + NetworkInsightsAnalysisId: NetworkInsightsAnalysisId | None + NetworkInsightsAnalysisArn: ResourceArn | None + NetworkInsightsPathId: NetworkInsightsPathId | None + AdditionalAccounts: ValueStringList | None + FilterInArns: ArnList | None + FilterOutArns: ArnList | None + StartDate: MillisecondDateTime | None + Status: AnalysisStatus | None + StatusMessage: String | None + WarningMessage: String | None + NetworkPathFound: Boolean | None + ForwardPathComponents: PathComponentList | None + ReturnPathComponents: PathComponentList | None + Explanations: ExplanationList | None + AlternatePathHints: AlternatePathHintList | None + SuggestedAccounts: ValueStringList | None + Tags: TagList | None + + +NetworkInsightsAnalysisList = list[NetworkInsightsAnalysis] class DescribeNetworkInsightsAnalysesResult(TypedDict, total=False): - NetworkInsightsAnalyses: Optional[NetworkInsightsAnalysisList] - NextToken: Optional[String] + NetworkInsightsAnalyses: NetworkInsightsAnalysisList | None + NextToken: String | None -NetworkInsightsPathIdList = List[NetworkInsightsPathId] +NetworkInsightsPathIdList = list[NetworkInsightsPathId] class DescribeNetworkInsightsPathsRequest(ServiceRequest): - NetworkInsightsPathIds: Optional[NetworkInsightsPathIdList] - Filters: Optional[FilterList] - MaxResults: Optional[NetworkInsightsMaxResults] - DryRun: Optional[Boolean] - NextToken: Optional[NextToken] + NetworkInsightsPathIds: NetworkInsightsPathIdList | None + Filters: FilterList | None + MaxResults: NetworkInsightsMaxResults | None + DryRun: Boolean | None + NextToken: NextToken | None -NetworkInsightsPathList = List[NetworkInsightsPath] +NetworkInsightsPathList = list[NetworkInsightsPath] class DescribeNetworkInsightsPathsResult(TypedDict, total=False): - NetworkInsightsPaths: Optional[NetworkInsightsPathList] - NextToken: Optional[String] + NetworkInsightsPaths: NetworkInsightsPathList | None + NextToken: String | None class DescribeNetworkInterfaceAttributeRequest(ServiceRequest): - DryRun: Optional[Boolean] + DryRun: Boolean | None NetworkInterfaceId: NetworkInterfaceId - Attribute: Optional[NetworkInterfaceAttribute] + Attribute: NetworkInterfaceAttribute | None class DescribeNetworkInterfaceAttributeResult(TypedDict, total=False): - Attachment: Optional[NetworkInterfaceAttachment] - Description: Optional[AttributeValue] - Groups: Optional[GroupIdentifierList] - NetworkInterfaceId: Optional[String] - SourceDestCheck: Optional[AttributeBooleanValue] - AssociatePublicIpAddress: Optional[Boolean] + Attachment: NetworkInterfaceAttachment | None + Description: AttributeValue | None + Groups: GroupIdentifierList | None + NetworkInterfaceId: String | None + SourceDestCheck: AttributeBooleanValue | None + AssociatePublicIpAddress: Boolean | None -NetworkInterfacePermissionIdList = List[NetworkInterfacePermissionId] +NetworkInterfacePermissionIdList = list[NetworkInterfacePermissionId] class DescribeNetworkInterfacePermissionsRequest(ServiceRequest): - NetworkInterfacePermissionIds: Optional[NetworkInterfacePermissionIdList] - Filters: Optional[FilterList] - NextToken: Optional[String] - MaxResults: Optional[DescribeNetworkInterfacePermissionsMaxResults] + NetworkInterfacePermissionIds: NetworkInterfacePermissionIdList | None + Filters: FilterList | None + NextToken: String | None + MaxResults: DescribeNetworkInterfacePermissionsMaxResults | None -NetworkInterfacePermissionList = List[NetworkInterfacePermission] +NetworkInterfacePermissionList = list[NetworkInterfacePermission] class DescribeNetworkInterfacePermissionsResult(TypedDict, total=False): - NetworkInterfacePermissions: Optional[NetworkInterfacePermissionList] - NextToken: Optional[String] + NetworkInterfacePermissions: NetworkInterfacePermissionList | None + NextToken: String | None -NetworkInterfaceIdList = List[NetworkInterfaceId] +NetworkInterfaceIdList = list[NetworkInterfaceId] class DescribeNetworkInterfacesRequest(ServiceRequest): - NextToken: Optional[String] - MaxResults: Optional[DescribeNetworkInterfacesMaxResults] - DryRun: Optional[Boolean] - NetworkInterfaceIds: Optional[NetworkInterfaceIdList] - Filters: Optional[FilterList] + NextToken: String | None + MaxResults: DescribeNetworkInterfacesMaxResults | None + DryRun: Boolean | None + NetworkInterfaceIds: NetworkInterfaceIdList | None + Filters: FilterList | None -NetworkInterfaceList = List[NetworkInterface] +NetworkInterfaceList = list[NetworkInterface] class DescribeNetworkInterfacesResult(TypedDict, total=False): - NetworkInterfaces: Optional[NetworkInterfaceList] - NextToken: Optional[String] + NetworkInterfaces: NetworkInterfaceList | None + NextToken: String | None -OutpostLagIdSet = List[OutpostLagId] +OutpostLagIdSet = list[OutpostLagId] class DescribeOutpostLagsRequest(ServiceRequest): - OutpostLagIds: Optional[OutpostLagIdSet] - Filters: Optional[FilterList] - MaxResults: Optional[OutpostLagMaxResults] - NextToken: Optional[String] - DryRun: Optional[Boolean] + OutpostLagIds: OutpostLagIdSet | None + Filters: FilterList | None + MaxResults: OutpostLagMaxResults | None + NextToken: String | None + DryRun: Boolean | None -ServiceLinkVirtualInterfaceIdSet = List[ServiceLinkVirtualInterfaceId] +ServiceLinkVirtualInterfaceIdSet = list[ServiceLinkVirtualInterfaceId] class OutpostLag(TypedDict, total=False): - OutpostArn: Optional[String] - OwnerId: Optional[String] - State: Optional[String] - OutpostLagId: Optional[OutpostLagId] - LocalGatewayVirtualInterfaceIds: Optional[LocalGatewayVirtualInterfaceIdSet] - ServiceLinkVirtualInterfaceIds: Optional[ServiceLinkVirtualInterfaceIdSet] - Tags: Optional[TagList] + OutpostArn: String | None + OwnerId: String | None + State: String | None + OutpostLagId: OutpostLagId | None + LocalGatewayVirtualInterfaceIds: LocalGatewayVirtualInterfaceIdSet | None + ServiceLinkVirtualInterfaceIds: ServiceLinkVirtualInterfaceIdSet | None + Tags: TagList | None -OutpostLagSet = List[OutpostLag] +OutpostLagSet = list[OutpostLag] class DescribeOutpostLagsResult(TypedDict, total=False): - OutpostLags: Optional[OutpostLagSet] - NextToken: Optional[String] + OutpostLags: OutpostLagSet | None + NextToken: String | None -PlacementGroupStringList = List[PlacementGroupName] -PlacementGroupIdStringList = List[PlacementGroupId] +PlacementGroupStringList = list[PlacementGroupName] +PlacementGroupIdStringList = list[PlacementGroupId] class DescribePlacementGroupsRequest(ServiceRequest): - GroupIds: Optional[PlacementGroupIdStringList] - DryRun: Optional[Boolean] - GroupNames: Optional[PlacementGroupStringList] - Filters: Optional[FilterList] + GroupIds: PlacementGroupIdStringList | None + DryRun: Boolean | None + GroupNames: PlacementGroupStringList | None + Filters: FilterList | None -PlacementGroupList = List[PlacementGroup] +PlacementGroupList = list[PlacementGroup] class DescribePlacementGroupsResult(TypedDict, total=False): - PlacementGroups: Optional[PlacementGroupList] + PlacementGroups: PlacementGroupList | None -PrefixListResourceIdStringList = List[PrefixListResourceId] +PrefixListResourceIdStringList = list[PrefixListResourceId] class DescribePrefixListsRequest(ServiceRequest): - DryRun: Optional[Boolean] - Filters: Optional[FilterList] - MaxResults: Optional[Integer] - NextToken: Optional[String] - PrefixListIds: Optional[PrefixListResourceIdStringList] + DryRun: Boolean | None + Filters: FilterList | None + MaxResults: Integer | None + NextToken: String | None + PrefixListIds: PrefixListResourceIdStringList | None class PrefixList(TypedDict, total=False): - Cidrs: Optional[ValueStringList] - PrefixListId: Optional[String] - PrefixListName: Optional[String] + Cidrs: ValueStringList | None + PrefixListId: String | None + PrefixListName: String | None -PrefixListSet = List[PrefixList] +PrefixListSet = list[PrefixList] class DescribePrefixListsResult(TypedDict, total=False): - NextToken: Optional[String] - PrefixLists: Optional[PrefixListSet] + NextToken: String | None + PrefixLists: PrefixListSet | None -ResourceList = List[String] +ResourceList = list[String] class DescribePrincipalIdFormatRequest(ServiceRequest): - DryRun: Optional[Boolean] - Resources: Optional[ResourceList] - MaxResults: Optional[DescribePrincipalIdFormatMaxResults] - NextToken: Optional[String] + DryRun: Boolean | None + Resources: ResourceList | None + MaxResults: DescribePrincipalIdFormatMaxResults | None + NextToken: String | None class PrincipalIdFormat(TypedDict, total=False): - Arn: Optional[String] - Statuses: Optional[IdFormatList] + Arn: String | None + Statuses: IdFormatList | None -PrincipalIdFormatList = List[PrincipalIdFormat] +PrincipalIdFormatList = list[PrincipalIdFormat] class DescribePrincipalIdFormatResult(TypedDict, total=False): - Principals: Optional[PrincipalIdFormatList] - NextToken: Optional[String] + Principals: PrincipalIdFormatList | None + NextToken: String | None -PublicIpv4PoolIdStringList = List[Ipv4PoolEc2Id] +PublicIpv4PoolIdStringList = list[Ipv4PoolEc2Id] class DescribePublicIpv4PoolsRequest(ServiceRequest): - PoolIds: Optional[PublicIpv4PoolIdStringList] - NextToken: Optional[NextToken] - MaxResults: Optional[PoolMaxResults] - Filters: Optional[FilterList] + PoolIds: PublicIpv4PoolIdStringList | None + NextToken: NextToken | None + MaxResults: PoolMaxResults | None + Filters: FilterList | None class PublicIpv4PoolRange(TypedDict, total=False): - FirstAddress: Optional[String] - LastAddress: Optional[String] - AddressCount: Optional[Integer] - AvailableAddressCount: Optional[Integer] + FirstAddress: String | None + LastAddress: String | None + AddressCount: Integer | None + AvailableAddressCount: Integer | None -PublicIpv4PoolRangeSet = List[PublicIpv4PoolRange] +PublicIpv4PoolRangeSet = list[PublicIpv4PoolRange] class PublicIpv4Pool(TypedDict, total=False): - PoolId: Optional[String] - Description: Optional[String] - PoolAddressRanges: Optional[PublicIpv4PoolRangeSet] - TotalAddressCount: Optional[Integer] - TotalAvailableAddressCount: Optional[Integer] - NetworkBorderGroup: Optional[String] - Tags: Optional[TagList] + PoolId: String | None + Description: String | None + PoolAddressRanges: PublicIpv4PoolRangeSet | None + TotalAddressCount: Integer | None + TotalAvailableAddressCount: Integer | None + NetworkBorderGroup: String | None + Tags: TagList | None -PublicIpv4PoolSet = List[PublicIpv4Pool] +PublicIpv4PoolSet = list[PublicIpv4Pool] class DescribePublicIpv4PoolsResult(TypedDict, total=False): - PublicIpv4Pools: Optional[PublicIpv4PoolSet] - NextToken: Optional[String] + PublicIpv4Pools: PublicIpv4PoolSet | None + NextToken: String | None -RegionNameStringList = List[String] +RegionNameStringList = list[String] class DescribeRegionsRequest(ServiceRequest): - RegionNames: Optional[RegionNameStringList] - AllRegions: Optional[Boolean] - DryRun: Optional[Boolean] - Filters: Optional[FilterList] + RegionNames: RegionNameStringList | None + AllRegions: Boolean | None + DryRun: Boolean | None + Filters: FilterList | None + + +class RegionGeography(TypedDict, total=False): + Name: String | None + + +RegionGeographyList = list[RegionGeography] class Region(TypedDict, total=False): - OptInStatus: Optional[String] - RegionName: Optional[String] - Endpoint: Optional[String] + OptInStatus: String | None + Geography: RegionGeographyList | None + RegionName: String | None + Endpoint: String | None -RegionList = List[Region] +RegionList = list[Region] class DescribeRegionsResult(TypedDict, total=False): - Regions: Optional[RegionList] + Regions: RegionList | None -ReplaceRootVolumeTaskIds = List[ReplaceRootVolumeTaskId] +ReplaceRootVolumeTaskIds = list[ReplaceRootVolumeTaskId] class DescribeReplaceRootVolumeTasksRequest(ServiceRequest): - ReplaceRootVolumeTaskIds: Optional[ReplaceRootVolumeTaskIds] - Filters: Optional[FilterList] - MaxResults: Optional[DescribeReplaceRootVolumeTasksMaxResults] - NextToken: Optional[NextToken] - DryRun: Optional[Boolean] + ReplaceRootVolumeTaskIds: ReplaceRootVolumeTaskIds | None + Filters: FilterList | None + MaxResults: DescribeReplaceRootVolumeTasksMaxResults | None + NextToken: NextToken | None + DryRun: Boolean | None -ReplaceRootVolumeTasks = List[ReplaceRootVolumeTask] +ReplaceRootVolumeTasks = list[ReplaceRootVolumeTask] class DescribeReplaceRootVolumeTasksResult(TypedDict, total=False): - ReplaceRootVolumeTasks: Optional[ReplaceRootVolumeTasks] - NextToken: Optional[String] + ReplaceRootVolumeTasks: ReplaceRootVolumeTasks | None + NextToken: String | None class DescribeReservedInstancesListingsRequest(ServiceRequest): - ReservedInstancesId: Optional[ReservationId] - ReservedInstancesListingId: Optional[ReservedInstancesListingId] - Filters: Optional[FilterList] + ReservedInstancesId: ReservationId | None + ReservedInstancesListingId: ReservedInstancesListingId | None + Filters: FilterList | None class DescribeReservedInstancesListingsResult(TypedDict, total=False): - ReservedInstancesListings: Optional[ReservedInstancesListingList] + ReservedInstancesListings: ReservedInstancesListingList | None -ReservedInstancesModificationIdStringList = List[ReservedInstancesModificationId] +ReservedInstancesModificationIdStringList = list[ReservedInstancesModificationId] class DescribeReservedInstancesModificationsRequest(ServiceRequest): - ReservedInstancesModificationIds: Optional[ReservedInstancesModificationIdStringList] - NextToken: Optional[String] - Filters: Optional[FilterList] + ReservedInstancesModificationIds: ReservedInstancesModificationIdStringList | None + NextToken: String | None + Filters: FilterList | None class ReservedInstancesId(TypedDict, total=False): - ReservedInstancesId: Optional[String] + ReservedInstancesId: String | None -ReservedIntancesIds = List[ReservedInstancesId] +ReservedIntancesIds = list[ReservedInstancesId] class ReservedInstancesConfiguration(TypedDict, total=False): - AvailabilityZone: Optional[String] - InstanceCount: Optional[Integer] - InstanceType: Optional[InstanceType] - Platform: Optional[String] - Scope: Optional[scope] - AvailabilityZoneId: Optional[String] + AvailabilityZone: String | None + InstanceCount: Integer | None + InstanceType: InstanceType | None + Platform: String | None + Scope: scope | None + AvailabilityZoneId: String | None class ReservedInstancesModificationResult(TypedDict, total=False): - ReservedInstancesId: Optional[String] - TargetConfiguration: Optional[ReservedInstancesConfiguration] + ReservedInstancesId: String | None + TargetConfiguration: ReservedInstancesConfiguration | None -ReservedInstancesModificationResultList = List[ReservedInstancesModificationResult] +ReservedInstancesModificationResultList = list[ReservedInstancesModificationResult] class ReservedInstancesModification(TypedDict, total=False): - ClientToken: Optional[String] - CreateDate: Optional[DateTime] - EffectiveDate: Optional[DateTime] - ModificationResults: Optional[ReservedInstancesModificationResultList] - ReservedInstancesIds: Optional[ReservedIntancesIds] - ReservedInstancesModificationId: Optional[String] - Status: Optional[String] - StatusMessage: Optional[String] - UpdateDate: Optional[DateTime] + ClientToken: String | None + CreateDate: DateTime | None + EffectiveDate: DateTime | None + ModificationResults: ReservedInstancesModificationResultList | None + ReservedInstancesIds: ReservedIntancesIds | None + ReservedInstancesModificationId: String | None + Status: String | None + StatusMessage: String | None + UpdateDate: DateTime | None -ReservedInstancesModificationList = List[ReservedInstancesModification] +ReservedInstancesModificationList = list[ReservedInstancesModification] class DescribeReservedInstancesModificationsResult(TypedDict, total=False): - NextToken: Optional[String] - ReservedInstancesModifications: Optional[ReservedInstancesModificationList] + NextToken: String | None + ReservedInstancesModifications: ReservedInstancesModificationList | None -ReservedInstancesOfferingIdStringList = List[ReservedInstancesOfferingId] +ReservedInstancesOfferingIdStringList = list[ReservedInstancesOfferingId] class DescribeReservedInstancesOfferingsRequest(ServiceRequest): - AvailabilityZone: Optional[String] - IncludeMarketplace: Optional[Boolean] - InstanceType: Optional[InstanceType] - MaxDuration: Optional[Long] - MaxInstanceCount: Optional[Integer] - MinDuration: Optional[Long] - OfferingClass: Optional[OfferingClassType] - ProductDescription: Optional[RIProductDescription] - ReservedInstancesOfferingIds: Optional[ReservedInstancesOfferingIdStringList] - AvailabilityZoneId: Optional[AvailabilityZoneId] - DryRun: Optional[Boolean] - Filters: Optional[FilterList] - InstanceTenancy: Optional[Tenancy] - OfferingType: Optional[OfferingTypeValues] - NextToken: Optional[String] - MaxResults: Optional[Integer] + AvailabilityZone: String | None + IncludeMarketplace: Boolean | None + InstanceType: InstanceType | None + MaxDuration: Long | None + MaxInstanceCount: Integer | None + MinDuration: Long | None + OfferingClass: OfferingClassType | None + ProductDescription: RIProductDescription | None + ReservedInstancesOfferingIds: ReservedInstancesOfferingIdStringList | None + AvailabilityZoneId: AvailabilityZoneId | None + DryRun: Boolean | None + Filters: FilterList | None + InstanceTenancy: Tenancy | None + OfferingType: OfferingTypeValues | None + NextToken: String | None + MaxResults: Integer | None class RecurringCharge(TypedDict, total=False): - Amount: Optional[Double] - Frequency: Optional[RecurringChargeFrequency] + Amount: Double | None + Frequency: RecurringChargeFrequency | None -RecurringChargesList = List[RecurringCharge] +RecurringChargesList = list[RecurringCharge] class PricingDetail(TypedDict, total=False): - Count: Optional[Integer] - Price: Optional[Double] + Count: Integer | None + Price: Double | None -PricingDetailsList = List[PricingDetail] +PricingDetailsList = list[PricingDetail] class ReservedInstancesOffering(TypedDict, total=False): - CurrencyCode: Optional[CurrencyCodeValues] - InstanceTenancy: Optional[Tenancy] - Marketplace: Optional[Boolean] - OfferingClass: Optional[OfferingClassType] - OfferingType: Optional[OfferingTypeValues] - PricingDetails: Optional[PricingDetailsList] - RecurringCharges: Optional[RecurringChargesList] - Scope: Optional[scope] - AvailabilityZoneId: Optional[AvailabilityZoneId] - ReservedInstancesOfferingId: Optional[String] - InstanceType: Optional[InstanceType] - AvailabilityZone: Optional[String] - Duration: Optional[Long] - UsagePrice: Optional[Float] - FixedPrice: Optional[Float] - ProductDescription: Optional[RIProductDescription] - - -ReservedInstancesOfferingList = List[ReservedInstancesOffering] + CurrencyCode: CurrencyCodeValues | None + InstanceTenancy: Tenancy | None + Marketplace: Boolean | None + OfferingClass: OfferingClassType | None + OfferingType: OfferingTypeValues | None + PricingDetails: PricingDetailsList | None + RecurringCharges: RecurringChargesList | None + Scope: scope | None + AvailabilityZoneId: AvailabilityZoneId | None + ReservedInstancesOfferingId: String | None + InstanceType: InstanceType | None + AvailabilityZone: String | None + Duration: Long | None + UsagePrice: Float | None + FixedPrice: Float | None + ProductDescription: RIProductDescription | None + + +ReservedInstancesOfferingList = list[ReservedInstancesOffering] class DescribeReservedInstancesOfferingsResult(TypedDict, total=False): - NextToken: Optional[String] - ReservedInstancesOfferings: Optional[ReservedInstancesOfferingList] + NextToken: String | None + ReservedInstancesOfferings: ReservedInstancesOfferingList | None -ReservedInstancesIdStringList = List[ReservationId] +ReservedInstancesIdStringList = list[ReservationId] class DescribeReservedInstancesRequest(ServiceRequest): - OfferingClass: Optional[OfferingClassType] - ReservedInstancesIds: Optional[ReservedInstancesIdStringList] - DryRun: Optional[Boolean] - Filters: Optional[FilterList] - OfferingType: Optional[OfferingTypeValues] + OfferingClass: OfferingClassType | None + ReservedInstancesIds: ReservedInstancesIdStringList | None + DryRun: Boolean | None + Filters: FilterList | None + OfferingType: OfferingTypeValues | None class ReservedInstances(TypedDict, total=False): - CurrencyCode: Optional[CurrencyCodeValues] - InstanceTenancy: Optional[Tenancy] - OfferingClass: Optional[OfferingClassType] - OfferingType: Optional[OfferingTypeValues] - RecurringCharges: Optional[RecurringChargesList] - Scope: Optional[scope] - Tags: Optional[TagList] - AvailabilityZoneId: Optional[String] - ReservedInstancesId: Optional[String] - InstanceType: Optional[InstanceType] - AvailabilityZone: Optional[String] - Start: Optional[DateTime] - End: Optional[DateTime] - Duration: Optional[Long] - UsagePrice: Optional[Float] - FixedPrice: Optional[Float] - InstanceCount: Optional[Integer] - ProductDescription: Optional[RIProductDescription] - State: Optional[ReservedInstanceState] - - -ReservedInstancesList = List[ReservedInstances] + CurrencyCode: CurrencyCodeValues | None + InstanceTenancy: Tenancy | None + OfferingClass: OfferingClassType | None + OfferingType: OfferingTypeValues | None + RecurringCharges: RecurringChargesList | None + Scope: scope | None + Tags: TagList | None + AvailabilityZoneId: String | None + ReservedInstancesId: String | None + InstanceType: InstanceType | None + AvailabilityZone: String | None + Start: DateTime | None + End: DateTime | None + Duration: Long | None + UsagePrice: Float | None + FixedPrice: Float | None + InstanceCount: Integer | None + ProductDescription: RIProductDescription | None + State: ReservedInstanceState | None + + +ReservedInstancesList = list[ReservedInstances] class DescribeReservedInstancesResult(TypedDict, total=False): - ReservedInstances: Optional[ReservedInstancesList] + ReservedInstances: ReservedInstancesList | None -RouteServerEndpointIdsList = List[RouteServerEndpointId] +RouteServerEndpointIdsList = list[RouteServerEndpointId] class DescribeRouteServerEndpointsRequest(ServiceRequest): - RouteServerEndpointIds: Optional[RouteServerEndpointIdsList] - NextToken: Optional[String] - MaxResults: Optional[RouteServerMaxResults] - Filters: Optional[FilterList] - DryRun: Optional[Boolean] + RouteServerEndpointIds: RouteServerEndpointIdsList | None + NextToken: String | None + MaxResults: RouteServerMaxResults | None + Filters: FilterList | None + DryRun: Boolean | None -RouteServerEndpointsList = List[RouteServerEndpoint] +RouteServerEndpointsList = list[RouteServerEndpoint] class DescribeRouteServerEndpointsResult(TypedDict, total=False): - RouteServerEndpoints: Optional[RouteServerEndpointsList] - NextToken: Optional[String] + RouteServerEndpoints: RouteServerEndpointsList | None + NextToken: String | None -RouteServerPeerIdsList = List[RouteServerPeerId] +RouteServerPeerIdsList = list[RouteServerPeerId] class DescribeRouteServerPeersRequest(ServiceRequest): - RouteServerPeerIds: Optional[RouteServerPeerIdsList] - NextToken: Optional[String] - MaxResults: Optional[RouteServerMaxResults] - Filters: Optional[FilterList] - DryRun: Optional[Boolean] + RouteServerPeerIds: RouteServerPeerIdsList | None + NextToken: String | None + MaxResults: RouteServerMaxResults | None + Filters: FilterList | None + DryRun: Boolean | None -RouteServerPeersList = List[RouteServerPeer] +RouteServerPeersList = list[RouteServerPeer] class DescribeRouteServerPeersResult(TypedDict, total=False): - RouteServerPeers: Optional[RouteServerPeersList] - NextToken: Optional[String] + RouteServerPeers: RouteServerPeersList | None + NextToken: String | None -RouteServerIdsList = List[RouteServerId] +RouteServerIdsList = list[RouteServerId] class DescribeRouteServersRequest(ServiceRequest): - RouteServerIds: Optional[RouteServerIdsList] - NextToken: Optional[String] - MaxResults: Optional[RouteServerMaxResults] - Filters: Optional[FilterList] - DryRun: Optional[Boolean] + RouteServerIds: RouteServerIdsList | None + NextToken: String | None + MaxResults: RouteServerMaxResults | None + Filters: FilterList | None + DryRun: Boolean | None -RouteServersList = List[RouteServer] +RouteServersList = list[RouteServer] class DescribeRouteServersResult(TypedDict, total=False): - RouteServers: Optional[RouteServersList] - NextToken: Optional[String] + RouteServers: RouteServersList | None + NextToken: String | None -RouteTableIdStringList = List[RouteTableId] +RouteTableIdStringList = list[RouteTableId] class DescribeRouteTablesRequest(ServiceRequest): - NextToken: Optional[String] - MaxResults: Optional[DescribeRouteTablesMaxResults] - DryRun: Optional[Boolean] - RouteTableIds: Optional[RouteTableIdStringList] - Filters: Optional[FilterList] + NextToken: String | None + MaxResults: DescribeRouteTablesMaxResults | None + DryRun: Boolean | None + RouteTableIds: RouteTableIdStringList | None + Filters: FilterList | None -RouteTableList = List[RouteTable] +RouteTableList = list[RouteTable] class DescribeRouteTablesResult(TypedDict, total=False): - RouteTables: Optional[RouteTableList] - NextToken: Optional[String] + RouteTables: RouteTableList | None + NextToken: String | None -OccurrenceDayRequestSet = List[Integer] +OccurrenceDayRequestSet = list[Integer] class ScheduledInstanceRecurrenceRequest(TypedDict, total=False): - Frequency: Optional[String] - Interval: Optional[Integer] - OccurrenceDays: Optional[OccurrenceDayRequestSet] - OccurrenceRelativeToEnd: Optional[Boolean] - OccurrenceUnit: Optional[String] + Frequency: String | None + Interval: Integer | None + OccurrenceDays: OccurrenceDayRequestSet | None + OccurrenceRelativeToEnd: Boolean | None + OccurrenceUnit: String | None class SlotDateTimeRangeRequest(TypedDict, total=False): @@ -14912,538 +16442,633 @@ class SlotDateTimeRangeRequest(TypedDict, total=False): class DescribeScheduledInstanceAvailabilityRequest(ServiceRequest): - DryRun: Optional[Boolean] - Filters: Optional[FilterList] + DryRun: Boolean | None + Filters: FilterList | None FirstSlotStartTimeRange: SlotDateTimeRangeRequest - MaxResults: Optional[DescribeScheduledInstanceAvailabilityMaxResults] - MaxSlotDurationInHours: Optional[Integer] - MinSlotDurationInHours: Optional[Integer] - NextToken: Optional[String] + MaxResults: DescribeScheduledInstanceAvailabilityMaxResults | None + MaxSlotDurationInHours: Integer | None + MinSlotDurationInHours: Integer | None + NextToken: String | None Recurrence: ScheduledInstanceRecurrenceRequest -OccurrenceDaySet = List[Integer] +OccurrenceDaySet = list[Integer] class ScheduledInstanceRecurrence(TypedDict, total=False): - Frequency: Optional[String] - Interval: Optional[Integer] - OccurrenceDaySet: Optional[OccurrenceDaySet] - OccurrenceRelativeToEnd: Optional[Boolean] - OccurrenceUnit: Optional[String] + Frequency: String | None + Interval: Integer | None + OccurrenceDaySet: OccurrenceDaySet | None + OccurrenceRelativeToEnd: Boolean | None + OccurrenceUnit: String | None class ScheduledInstanceAvailability(TypedDict, total=False): - AvailabilityZone: Optional[String] - AvailableInstanceCount: Optional[Integer] - FirstSlotStartTime: Optional[DateTime] - HourlyPrice: Optional[String] - InstanceType: Optional[String] - MaxTermDurationInDays: Optional[Integer] - MinTermDurationInDays: Optional[Integer] - NetworkPlatform: Optional[String] - Platform: Optional[String] - PurchaseToken: Optional[String] - Recurrence: Optional[ScheduledInstanceRecurrence] - SlotDurationInHours: Optional[Integer] - TotalScheduledInstanceHours: Optional[Integer] + AvailabilityZone: String | None + AvailableInstanceCount: Integer | None + FirstSlotStartTime: DateTime | None + HourlyPrice: String | None + InstanceType: String | None + MaxTermDurationInDays: Integer | None + MinTermDurationInDays: Integer | None + NetworkPlatform: String | None + Platform: String | None + PurchaseToken: String | None + Recurrence: ScheduledInstanceRecurrence | None + SlotDurationInHours: Integer | None + TotalScheduledInstanceHours: Integer | None -ScheduledInstanceAvailabilitySet = List[ScheduledInstanceAvailability] +ScheduledInstanceAvailabilitySet = list[ScheduledInstanceAvailability] class DescribeScheduledInstanceAvailabilityResult(TypedDict, total=False): - NextToken: Optional[String] - ScheduledInstanceAvailabilitySet: Optional[ScheduledInstanceAvailabilitySet] + NextToken: String | None + ScheduledInstanceAvailabilitySet: ScheduledInstanceAvailabilitySet | None class SlotStartTimeRangeRequest(TypedDict, total=False): - EarliestTime: Optional[DateTime] - LatestTime: Optional[DateTime] + EarliestTime: DateTime | None + LatestTime: DateTime | None -ScheduledInstanceIdRequestSet = List[ScheduledInstanceId] +ScheduledInstanceIdRequestSet = list[ScheduledInstanceId] class DescribeScheduledInstancesRequest(ServiceRequest): - DryRun: Optional[Boolean] - Filters: Optional[FilterList] - MaxResults: Optional[Integer] - NextToken: Optional[String] - ScheduledInstanceIds: Optional[ScheduledInstanceIdRequestSet] - SlotStartTimeRange: Optional[SlotStartTimeRangeRequest] + DryRun: Boolean | None + Filters: FilterList | None + MaxResults: Integer | None + NextToken: String | None + ScheduledInstanceIds: ScheduledInstanceIdRequestSet | None + SlotStartTimeRange: SlotStartTimeRangeRequest | None class ScheduledInstance(TypedDict, total=False): - AvailabilityZone: Optional[String] - CreateDate: Optional[DateTime] - HourlyPrice: Optional[String] - InstanceCount: Optional[Integer] - InstanceType: Optional[String] - NetworkPlatform: Optional[String] - NextSlotStartTime: Optional[DateTime] - Platform: Optional[String] - PreviousSlotEndTime: Optional[DateTime] - Recurrence: Optional[ScheduledInstanceRecurrence] - ScheduledInstanceId: Optional[String] - SlotDurationInHours: Optional[Integer] - TermEndDate: Optional[DateTime] - TermStartDate: Optional[DateTime] - TotalScheduledInstanceHours: Optional[Integer] - - -ScheduledInstanceSet = List[ScheduledInstance] + AvailabilityZone: String | None + CreateDate: DateTime | None + HourlyPrice: String | None + InstanceCount: Integer | None + InstanceType: String | None + NetworkPlatform: String | None + NextSlotStartTime: DateTime | None + Platform: String | None + PreviousSlotEndTime: DateTime | None + Recurrence: ScheduledInstanceRecurrence | None + ScheduledInstanceId: String | None + SlotDurationInHours: Integer | None + TermEndDate: DateTime | None + TermStartDate: DateTime | None + TotalScheduledInstanceHours: Integer | None + + +ScheduledInstanceSet = list[ScheduledInstance] class DescribeScheduledInstancesResult(TypedDict, total=False): - NextToken: Optional[String] - ScheduledInstanceSet: Optional[ScheduledInstanceSet] + NextToken: String | None + ScheduledInstanceSet: ScheduledInstanceSet | None -GroupIds = List[SecurityGroupId] +SecondaryInterfaceIdList = list[SecondaryInterfaceId] + + +class DescribeSecondaryInterfacesRequest(ServiceRequest): + DryRun: Boolean | None + Filters: FilterList | None + MaxResults: DescribeSecondaryInterfacesMaxResults | None + NextToken: String | None + SecondaryInterfaceIds: SecondaryInterfaceIdList | None + + +class SecondaryInterfaceIpv4Address(TypedDict, total=False): + PrivateIpAddress: String | None + + +SecondaryInterfaceIpv4AddressList = list[SecondaryInterfaceIpv4Address] + + +class SecondaryInterfaceAttachment(TypedDict, total=False): + AttachmentId: String | None + AttachTime: MillisecondDateTime | None + DeleteOnTermination: Boolean | None + DeviceIndex: Integer | None + InstanceId: String | None + InstanceOwnerId: String | None + NetworkCardIndex: Integer | None + Status: AttachmentStatus | None + + +class SecondaryInterface(TypedDict, total=False): + AvailabilityZone: AvailabilityZoneName | None + AvailabilityZoneId: AvailabilityZoneId | None + Attachment: SecondaryInterfaceAttachment | None + MacAddress: String | None + OwnerId: String | None + PrivateIpv4Addresses: SecondaryInterfaceIpv4AddressList | None + SecondaryInterfaceId: SecondaryInterfaceId | None + SecondaryInterfaceArn: String | None + SecondaryInterfaceType: SecondaryInterfaceType | None + SecondarySubnetId: SecondarySubnetId | None + SecondaryNetworkId: SecondaryNetworkId | None + SecondaryNetworkType: SecondaryNetworkType | None + SourceDestCheck: Boolean | None + Status: SecondaryInterfaceStatus | None + Tags: TagList | None + + +SecondaryInterfaceList = list[SecondaryInterface] + + +class DescribeSecondaryInterfacesResult(TypedDict, total=False): + SecondaryInterfaces: SecondaryInterfaceList | None + NextToken: String | None + + +SecondaryNetworkIdList = list[SecondaryNetworkId] + + +class DescribeSecondaryNetworksRequest(ServiceRequest): + DryRun: Boolean | None + Filters: FilterList | None + MaxResults: DescribeSecondaryNetworksMaxResults | None + NextToken: String | None + SecondaryNetworkIds: SecondaryNetworkIdList | None + + +SecondaryNetworkList = list[SecondaryNetwork] + + +class DescribeSecondaryNetworksResult(TypedDict, total=False): + SecondaryNetworks: SecondaryNetworkList | None + NextToken: String | None + + +SecondarySubnetIdList = list[SecondarySubnetId] + + +class DescribeSecondarySubnetsRequest(ServiceRequest): + DryRun: Boolean | None + Filters: FilterList | None + MaxResults: DescribeSecondarySubnetsMaxResults | None + NextToken: String | None + SecondarySubnetIds: SecondarySubnetIdList | None + + +SecondarySubnetList = list[SecondarySubnet] + + +class DescribeSecondarySubnetsResult(TypedDict, total=False): + SecondarySubnets: SecondarySubnetList | None + NextToken: String | None + + +GroupIds = list[SecurityGroupId] class DescribeSecurityGroupReferencesRequest(ServiceRequest): - DryRun: Optional[Boolean] + DryRun: Boolean | None GroupId: GroupIds class SecurityGroupReference(TypedDict, total=False): - GroupId: Optional[String] - ReferencingVpcId: Optional[String] - VpcPeeringConnectionId: Optional[String] - TransitGatewayId: Optional[String] + GroupId: String | None + ReferencingVpcId: String | None + VpcPeeringConnectionId: String | None + TransitGatewayId: String | None -SecurityGroupReferences = List[SecurityGroupReference] +SecurityGroupReferences = list[SecurityGroupReference] class DescribeSecurityGroupReferencesResult(TypedDict, total=False): - SecurityGroupReferenceSet: Optional[SecurityGroupReferences] + SecurityGroupReferenceSet: SecurityGroupReferences | None -SecurityGroupRuleIdList = List[String] +SecurityGroupRuleIdList = list[String] class DescribeSecurityGroupRulesRequest(ServiceRequest): - Filters: Optional[FilterList] - SecurityGroupRuleIds: Optional[SecurityGroupRuleIdList] - DryRun: Optional[Boolean] - NextToken: Optional[String] - MaxResults: Optional[DescribeSecurityGroupRulesMaxResults] + Filters: FilterList | None + SecurityGroupRuleIds: SecurityGroupRuleIdList | None + DryRun: Boolean | None + NextToken: String | None + MaxResults: DescribeSecurityGroupRulesMaxResults | None class DescribeSecurityGroupRulesResult(TypedDict, total=False): - SecurityGroupRules: Optional[SecurityGroupRuleList] - NextToken: Optional[String] + SecurityGroupRules: SecurityGroupRuleList | None + NextToken: String | None class DescribeSecurityGroupVpcAssociationsRequest(ServiceRequest): - Filters: Optional[FilterList] - NextToken: Optional[String] - MaxResults: Optional[DescribeSecurityGroupVpcAssociationsMaxResults] - DryRun: Optional[Boolean] + Filters: FilterList | None + NextToken: String | None + MaxResults: DescribeSecurityGroupVpcAssociationsMaxResults | None + DryRun: Boolean | None class SecurityGroupVpcAssociation(TypedDict, total=False): - GroupId: Optional[SecurityGroupId] - VpcId: Optional[VpcId] - VpcOwnerId: Optional[String] - State: Optional[SecurityGroupVpcAssociationState] - StateReason: Optional[String] - GroupOwnerId: Optional[String] + GroupId: SecurityGroupId | None + VpcId: VpcId | None + VpcOwnerId: String | None + State: SecurityGroupVpcAssociationState | None + StateReason: String | None + GroupOwnerId: String | None -SecurityGroupVpcAssociationList = List[SecurityGroupVpcAssociation] +SecurityGroupVpcAssociationList = list[SecurityGroupVpcAssociation] class DescribeSecurityGroupVpcAssociationsResult(TypedDict, total=False): - SecurityGroupVpcAssociations: Optional[SecurityGroupVpcAssociationList] - NextToken: Optional[String] + SecurityGroupVpcAssociations: SecurityGroupVpcAssociationList | None + NextToken: String | None -GroupNameStringList = List[SecurityGroupName] +GroupNameStringList = list[SecurityGroupName] class DescribeSecurityGroupsRequest(ServiceRequest): - GroupIds: Optional[GroupIdStringList] - GroupNames: Optional[GroupNameStringList] - NextToken: Optional[String] - MaxResults: Optional[DescribeSecurityGroupsMaxResults] - DryRun: Optional[Boolean] - Filters: Optional[FilterList] + GroupIds: GroupIdStringList | None + GroupNames: GroupNameStringList | None + NextToken: String | None + MaxResults: DescribeSecurityGroupsMaxResults | None + DryRun: Boolean | None + Filters: FilterList | None class SecurityGroup(TypedDict, total=False): - GroupId: Optional[String] - IpPermissionsEgress: Optional[IpPermissionList] - Tags: Optional[TagList] - VpcId: Optional[String] - SecurityGroupArn: Optional[String] - OwnerId: Optional[String] - GroupName: Optional[String] - Description: Optional[String] - IpPermissions: Optional[IpPermissionList] + GroupId: String | None + IpPermissionsEgress: IpPermissionList | None + Tags: TagList | None + VpcId: String | None + SecurityGroupArn: String | None + OwnerId: String | None + GroupName: String | None + Description: String | None + IpPermissions: IpPermissionList | None -SecurityGroupList = List[SecurityGroup] +SecurityGroupList = list[SecurityGroup] class DescribeSecurityGroupsResult(TypedDict, total=False): - NextToken: Optional[String] - SecurityGroups: Optional[SecurityGroupList] + NextToken: String | None + SecurityGroups: SecurityGroupList | None class DescribeServiceLinkVirtualInterfacesRequest(ServiceRequest): - ServiceLinkVirtualInterfaceIds: Optional[ServiceLinkVirtualInterfaceIdSet] - Filters: Optional[FilterList] - MaxResults: Optional[ServiceLinkMaxResults] - NextToken: Optional[String] - DryRun: Optional[Boolean] + ServiceLinkVirtualInterfaceIds: ServiceLinkVirtualInterfaceIdSet | None + Filters: FilterList | None + MaxResults: ServiceLinkMaxResults | None + NextToken: String | None + DryRun: Boolean | None class ServiceLinkVirtualInterface(TypedDict, total=False): - ServiceLinkVirtualInterfaceId: Optional[ServiceLinkVirtualInterfaceId] - ServiceLinkVirtualInterfaceArn: Optional[ResourceArn] - OutpostId: Optional[String] - OutpostArn: Optional[String] - OwnerId: Optional[String] - LocalAddress: Optional[String] - PeerAddress: Optional[String] - PeerBgpAsn: Optional[Long] - Vlan: Optional[Integer] - OutpostLagId: Optional[OutpostLagId] - Tags: Optional[TagList] - ConfigurationState: Optional[ServiceLinkVirtualInterfaceConfigurationState] + ServiceLinkVirtualInterfaceId: ServiceLinkVirtualInterfaceId | None + ServiceLinkVirtualInterfaceArn: ResourceArn | None + OutpostId: String | None + OutpostArn: String | None + OwnerId: String | None + LocalAddress: String | None + PeerAddress: String | None + PeerBgpAsn: Long | None + Vlan: Integer | None + OutpostLagId: OutpostLagId | None + Tags: TagList | None + ConfigurationState: ServiceLinkVirtualInterfaceConfigurationState | None -ServiceLinkVirtualInterfaceSet = List[ServiceLinkVirtualInterface] +ServiceLinkVirtualInterfaceSet = list[ServiceLinkVirtualInterface] class DescribeServiceLinkVirtualInterfacesResult(TypedDict, total=False): - ServiceLinkVirtualInterfaces: Optional[ServiceLinkVirtualInterfaceSet] - NextToken: Optional[String] + ServiceLinkVirtualInterfaces: ServiceLinkVirtualInterfaceSet | None + NextToken: String | None class DescribeSnapshotAttributeRequest(ServiceRequest): Attribute: SnapshotAttributeName SnapshotId: SnapshotId - DryRun: Optional[Boolean] + DryRun: Boolean | None class DescribeSnapshotAttributeResult(TypedDict, total=False): - ProductCodes: Optional[ProductCodeList] - SnapshotId: Optional[String] - CreateVolumePermissions: Optional[CreateVolumePermissionList] + ProductCodes: ProductCodeList | None + SnapshotId: String | None + CreateVolumePermissions: CreateVolumePermissionList | None class DescribeSnapshotTierStatusRequest(ServiceRequest): - Filters: Optional[FilterList] - DryRun: Optional[Boolean] - NextToken: Optional[String] - MaxResults: Optional[DescribeSnapshotTierStatusMaxResults] + Filters: FilterList | None + DryRun: Boolean | None + NextToken: String | None + MaxResults: DescribeSnapshotTierStatusMaxResults | None class SnapshotTierStatus(TypedDict, total=False): - SnapshotId: Optional[SnapshotId] - VolumeId: Optional[VolumeId] - Status: Optional[SnapshotState] - OwnerId: Optional[String] - Tags: Optional[TagList] - StorageTier: Optional[StorageTier] - LastTieringStartTime: Optional[MillisecondDateTime] - LastTieringProgress: Optional[Integer] - LastTieringOperationStatus: Optional[TieringOperationStatus] - LastTieringOperationStatusDetail: Optional[String] - ArchivalCompleteTime: Optional[MillisecondDateTime] - RestoreExpiryTime: Optional[MillisecondDateTime] + SnapshotId: SnapshotId | None + VolumeId: VolumeId | None + Status: SnapshotState | None + OwnerId: String | None + Tags: TagList | None + StorageTier: StorageTier | None + LastTieringStartTime: MillisecondDateTime | None + LastTieringProgress: Integer | None + LastTieringOperationStatus: TieringOperationStatus | None + LastTieringOperationStatusDetail: String | None + ArchivalCompleteTime: MillisecondDateTime | None + RestoreExpiryTime: MillisecondDateTime | None -snapshotTierStatusSet = List[SnapshotTierStatus] +snapshotTierStatusSet = list[SnapshotTierStatus] class DescribeSnapshotTierStatusResult(TypedDict, total=False): - SnapshotTierStatuses: Optional[snapshotTierStatusSet] - NextToken: Optional[String] + SnapshotTierStatuses: snapshotTierStatusSet | None + NextToken: String | None -RestorableByStringList = List[String] +RestorableByStringList = list[String] class DescribeSnapshotsRequest(ServiceRequest): - MaxResults: Optional[Integer] - NextToken: Optional[String] - OwnerIds: Optional[OwnerStringList] - RestorableByUserIds: Optional[RestorableByStringList] - SnapshotIds: Optional[SnapshotIdStringList] - DryRun: Optional[Boolean] - Filters: Optional[FilterList] + MaxResults: Integer | None + NextToken: String | None + OwnerIds: OwnerStringList | None + RestorableByUserIds: RestorableByStringList | None + SnapshotIds: SnapshotIdStringList | None + DryRun: Boolean | None + Filters: FilterList | None class Snapshot(TypedDict, total=False): - OwnerAlias: Optional[String] - OutpostArn: Optional[String] - Tags: Optional[TagList] - StorageTier: Optional[StorageTier] - RestoreExpiryTime: Optional[MillisecondDateTime] - SseType: Optional[SSEType] - AvailabilityZone: Optional[String] - TransferType: Optional[TransferType] - CompletionDurationMinutes: Optional[SnapshotCompletionDurationMinutesResponse] - CompletionTime: Optional[MillisecondDateTime] - FullSnapshotSizeInBytes: Optional[Long] - SnapshotId: Optional[String] - VolumeId: Optional[String] - State: Optional[SnapshotState] - StateMessage: Optional[String] - StartTime: Optional[DateTime] - Progress: Optional[String] - OwnerId: Optional[String] - Description: Optional[String] - VolumeSize: Optional[Integer] - Encrypted: Optional[Boolean] - KmsKeyId: Optional[String] - DataEncryptionKeyId: Optional[String] - - -SnapshotList = List[Snapshot] + OwnerAlias: String | None + OutpostArn: String | None + Tags: TagList | None + StorageTier: StorageTier | None + RestoreExpiryTime: MillisecondDateTime | None + SseType: SSEType | None + AvailabilityZone: String | None + TransferType: TransferType | None + CompletionDurationMinutes: SnapshotCompletionDurationMinutesResponse | None + CompletionTime: MillisecondDateTime | None + FullSnapshotSizeInBytes: Long | None + SnapshotId: String | None + VolumeId: String | None + State: SnapshotState | None + StateMessage: String | None + StartTime: DateTime | None + Progress: String | None + OwnerId: String | None + Description: String | None + VolumeSize: Integer | None + Encrypted: Boolean | None + KmsKeyId: String | None + DataEncryptionKeyId: String | None + + +SnapshotList = list[Snapshot] class DescribeSnapshotsResult(TypedDict, total=False): - NextToken: Optional[String] - Snapshots: Optional[SnapshotList] + NextToken: String | None + Snapshots: SnapshotList | None class DescribeSpotDatafeedSubscriptionRequest(ServiceRequest): - DryRun: Optional[Boolean] + DryRun: Boolean | None class DescribeSpotDatafeedSubscriptionResult(TypedDict, total=False): - SpotDatafeedSubscription: Optional[SpotDatafeedSubscription] + SpotDatafeedSubscription: SpotDatafeedSubscription | None class DescribeSpotFleetInstancesRequest(ServiceRequest): - DryRun: Optional[Boolean] + DryRun: Boolean | None SpotFleetRequestId: SpotFleetRequestId - NextToken: Optional[String] - MaxResults: Optional[DescribeSpotFleetInstancesMaxResults] + NextToken: String | None + MaxResults: DescribeSpotFleetInstancesMaxResults | None class DescribeSpotFleetInstancesResponse(TypedDict, total=False): - ActiveInstances: Optional[ActiveInstanceSet] - NextToken: Optional[String] - SpotFleetRequestId: Optional[String] + ActiveInstances: ActiveInstanceSet | None + NextToken: String | None + SpotFleetRequestId: String | None class DescribeSpotFleetRequestHistoryRequest(ServiceRequest): - DryRun: Optional[Boolean] + DryRun: Boolean | None SpotFleetRequestId: SpotFleetRequestId - EventType: Optional[EventType] + EventType: EventType | None StartTime: DateTime - NextToken: Optional[String] - MaxResults: Optional[DescribeSpotFleetRequestHistoryMaxResults] + NextToken: String | None + MaxResults: DescribeSpotFleetRequestHistoryMaxResults | None class HistoryRecord(TypedDict, total=False): - EventInformation: Optional[EventInformation] - EventType: Optional[EventType] - Timestamp: Optional[DateTime] + EventInformation: EventInformation | None + EventType: EventType | None + Timestamp: DateTime | None -HistoryRecords = List[HistoryRecord] +HistoryRecords = list[HistoryRecord] class DescribeSpotFleetRequestHistoryResponse(TypedDict, total=False): - HistoryRecords: Optional[HistoryRecords] - LastEvaluatedTime: Optional[DateTime] - NextToken: Optional[String] - SpotFleetRequestId: Optional[String] - StartTime: Optional[DateTime] + HistoryRecords: HistoryRecords | None + LastEvaluatedTime: DateTime | None + NextToken: String | None + SpotFleetRequestId: String | None + StartTime: DateTime | None class DescribeSpotFleetRequestsRequest(ServiceRequest): - DryRun: Optional[Boolean] - SpotFleetRequestIds: Optional[SpotFleetRequestIdList] - NextToken: Optional[String] - MaxResults: Optional[Integer] + DryRun: Boolean | None + SpotFleetRequestIds: SpotFleetRequestIdList | None + NextToken: String | None + MaxResults: Integer | None class TargetGroup(TypedDict, total=False): - Arn: Optional[String] + Arn: String | None -TargetGroups = List[TargetGroup] +TargetGroups = list[TargetGroup] class TargetGroupsConfig(TypedDict, total=False): - TargetGroups: Optional[TargetGroups] + TargetGroups: TargetGroups | None class LoadBalancersConfig(TypedDict, total=False): - ClassicLoadBalancersConfig: Optional[ClassicLoadBalancersConfig] - TargetGroupsConfig: Optional[TargetGroupsConfig] + ClassicLoadBalancersConfig: ClassicLoadBalancersConfig | None + TargetGroupsConfig: TargetGroupsConfig | None class LaunchTemplateOverrides(TypedDict, total=False): - InstanceType: Optional[InstanceType] - SpotPrice: Optional[String] - SubnetId: Optional[SubnetId] - AvailabilityZone: Optional[String] - WeightedCapacity: Optional[Double] - Priority: Optional[Double] - InstanceRequirements: Optional[InstanceRequirements] + InstanceType: InstanceType | None + SpotPrice: String | None + SubnetId: SubnetId | None + AvailabilityZone: String | None + WeightedCapacity: Double | None + Priority: Double | None + InstanceRequirements: InstanceRequirements | None + AvailabilityZoneId: AvailabilityZoneId | None -LaunchTemplateOverridesList = List[LaunchTemplateOverrides] +LaunchTemplateOverridesList = list[LaunchTemplateOverrides] class LaunchTemplateConfig(TypedDict, total=False): - LaunchTemplateSpecification: Optional[FleetLaunchTemplateSpecification] - Overrides: Optional[LaunchTemplateOverridesList] + LaunchTemplateSpecification: FleetLaunchTemplateSpecification | None + Overrides: LaunchTemplateOverridesList | None -LaunchTemplateConfigList = List[LaunchTemplateConfig] +LaunchTemplateConfigList = list[LaunchTemplateConfig] class SpotFleetTagSpecification(TypedDict, total=False): - ResourceType: Optional[ResourceType] - Tags: Optional[TagList] + ResourceType: ResourceType | None + Tags: TagList | None -SpotFleetTagSpecificationList = List[SpotFleetTagSpecification] +SpotFleetTagSpecificationList = list[SpotFleetTagSpecification] class SpotPlacement(TypedDict, total=False): - AvailabilityZone: Optional[String] - GroupName: Optional[PlacementGroupName] - Tenancy: Optional[Tenancy] + AvailabilityZone: String | None + GroupName: PlacementGroupName | None + Tenancy: Tenancy | None + AvailabilityZoneId: String | None class InstanceNetworkInterfaceSpecification(TypedDict, total=False): - AssociatePublicIpAddress: Optional[Boolean] - DeleteOnTermination: Optional[Boolean] - Description: Optional[String] - DeviceIndex: Optional[Integer] - Groups: Optional[SecurityGroupIdStringList] - Ipv6AddressCount: Optional[Integer] - Ipv6Addresses: Optional[InstanceIpv6AddressList] - NetworkInterfaceId: Optional[NetworkInterfaceId] - PrivateIpAddress: Optional[String] - PrivateIpAddresses: Optional[PrivateIpAddressSpecificationList] - SecondaryPrivateIpAddressCount: Optional[Integer] - SubnetId: Optional[String] - AssociateCarrierIpAddress: Optional[Boolean] - InterfaceType: Optional[String] - NetworkCardIndex: Optional[Integer] - Ipv4Prefixes: Optional[Ipv4PrefixList] - Ipv4PrefixCount: Optional[Integer] - Ipv6Prefixes: Optional[Ipv6PrefixList] - Ipv6PrefixCount: Optional[Integer] - PrimaryIpv6: Optional[Boolean] - EnaSrdSpecification: Optional[EnaSrdSpecificationRequest] - ConnectionTrackingSpecification: Optional[ConnectionTrackingSpecificationRequest] - EnaQueueCount: Optional[Integer] - - -InstanceNetworkInterfaceSpecificationList = List[InstanceNetworkInterfaceSpecification] + AssociatePublicIpAddress: Boolean | None + DeleteOnTermination: Boolean | None + Description: String | None + DeviceIndex: Integer | None + Groups: SecurityGroupIdStringList | None + Ipv6AddressCount: Integer | None + Ipv6Addresses: InstanceIpv6AddressList | None + NetworkInterfaceId: NetworkInterfaceId | None + PrivateIpAddress: String | None + PrivateIpAddresses: PrivateIpAddressSpecificationList | None + SecondaryPrivateIpAddressCount: Integer | None + SubnetId: String | None + AssociateCarrierIpAddress: Boolean | None + InterfaceType: String | None + NetworkCardIndex: Integer | None + Ipv4Prefixes: Ipv4PrefixList | None + Ipv4PrefixCount: Integer | None + Ipv6Prefixes: Ipv6PrefixList | None + Ipv6PrefixCount: Integer | None + PrimaryIpv6: Boolean | None + EnaSrdSpecification: EnaSrdSpecificationRequest | None + ConnectionTrackingSpecification: ConnectionTrackingSpecificationRequest | None + EnaQueueCount: Integer | None + + +InstanceNetworkInterfaceSpecificationList = list[InstanceNetworkInterfaceSpecification] class SpotFleetMonitoring(TypedDict, total=False): - Enabled: Optional[Boolean] + Enabled: Boolean | None class SpotFleetLaunchSpecification(TypedDict, total=False): - AddressingType: Optional[String] - BlockDeviceMappings: Optional[BlockDeviceMappingList] - EbsOptimized: Optional[Boolean] - IamInstanceProfile: Optional[IamInstanceProfileSpecification] - ImageId: Optional[ImageId] - InstanceType: Optional[InstanceType] - KernelId: Optional[String] - KeyName: Optional[KeyPairName] - Monitoring: Optional[SpotFleetMonitoring] - NetworkInterfaces: Optional[InstanceNetworkInterfaceSpecificationList] - Placement: Optional[SpotPlacement] - RamdiskId: Optional[String] - SpotPrice: Optional[String] - SubnetId: Optional[SubnetId] - UserData: Optional[SensitiveUserData] - WeightedCapacity: Optional[Double] - TagSpecifications: Optional[SpotFleetTagSpecificationList] - InstanceRequirements: Optional[InstanceRequirements] - SecurityGroups: Optional[GroupIdentifierList] - - -LaunchSpecsList = List[SpotFleetLaunchSpecification] + AddressingType: String | None + BlockDeviceMappings: BlockDeviceMappingList | None + EbsOptimized: Boolean | None + IamInstanceProfile: IamInstanceProfileSpecification | None + ImageId: ImageId | None + InstanceType: InstanceType | None + KernelId: String | None + KeyName: KeyPairName | None + Monitoring: SpotFleetMonitoring | None + NetworkInterfaces: InstanceNetworkInterfaceSpecificationList | None + Placement: SpotPlacement | None + RamdiskId: String | None + SpotPrice: String | None + SubnetId: SubnetId | None + UserData: SensitiveUserData | None + WeightedCapacity: Double | None + TagSpecifications: SpotFleetTagSpecificationList | None + InstanceRequirements: InstanceRequirements | None + SecurityGroups: GroupIdentifierList | None + + +LaunchSpecsList = list[SpotFleetLaunchSpecification] class SpotCapacityRebalance(TypedDict, total=False): - ReplacementStrategy: Optional[ReplacementStrategy] - TerminationDelay: Optional[Integer] + ReplacementStrategy: ReplacementStrategy | None + TerminationDelay: Integer | None class SpotMaintenanceStrategies(TypedDict, total=False): - CapacityRebalance: Optional[SpotCapacityRebalance] + CapacityRebalance: SpotCapacityRebalance | None class SpotFleetRequestConfigData(TypedDict, total=False): - AllocationStrategy: Optional[AllocationStrategy] - OnDemandAllocationStrategy: Optional[OnDemandAllocationStrategy] - SpotMaintenanceStrategies: Optional[SpotMaintenanceStrategies] - ClientToken: Optional[String] - ExcessCapacityTerminationPolicy: Optional[ExcessCapacityTerminationPolicy] - FulfilledCapacity: Optional[Double] - OnDemandFulfilledCapacity: Optional[Double] + AllocationStrategy: AllocationStrategy | None + OnDemandAllocationStrategy: OnDemandAllocationStrategy | None + SpotMaintenanceStrategies: SpotMaintenanceStrategies | None + ClientToken: String | None + ExcessCapacityTerminationPolicy: ExcessCapacityTerminationPolicy | None + FulfilledCapacity: Double | None + OnDemandFulfilledCapacity: Double | None IamFleetRole: String - LaunchSpecifications: Optional[LaunchSpecsList] - LaunchTemplateConfigs: Optional[LaunchTemplateConfigList] - SpotPrice: Optional[String] + LaunchSpecifications: LaunchSpecsList | None + LaunchTemplateConfigs: LaunchTemplateConfigList | None + SpotPrice: String | None TargetCapacity: Integer - OnDemandTargetCapacity: Optional[Integer] - OnDemandMaxTotalPrice: Optional[String] - SpotMaxTotalPrice: Optional[String] - TerminateInstancesWithExpiration: Optional[Boolean] - Type: Optional[FleetType] - ValidFrom: Optional[DateTime] - ValidUntil: Optional[DateTime] - ReplaceUnhealthyInstances: Optional[Boolean] - InstanceInterruptionBehavior: Optional[InstanceInterruptionBehavior] - LoadBalancersConfig: Optional[LoadBalancersConfig] - InstancePoolsToUseCount: Optional[Integer] - Context: Optional[String] - TargetCapacityUnitType: Optional[TargetCapacityUnitType] - TagSpecifications: Optional[TagSpecificationList] + OnDemandTargetCapacity: Integer | None + OnDemandMaxTotalPrice: String | None + SpotMaxTotalPrice: String | None + TerminateInstancesWithExpiration: Boolean | None + Type: FleetType | None + ValidFrom: DateTime | None + ValidUntil: DateTime | None + ReplaceUnhealthyInstances: Boolean | None + InstanceInterruptionBehavior: InstanceInterruptionBehavior | None + LoadBalancersConfig: LoadBalancersConfig | None + InstancePoolsToUseCount: Integer | None + Context: String | None + TargetCapacityUnitType: TargetCapacityUnitType | None + TagSpecifications: TagSpecificationList | None class SpotFleetRequestConfig(TypedDict, total=False): - ActivityStatus: Optional[ActivityStatus] - CreateTime: Optional[MillisecondDateTime] - SpotFleetRequestConfig: Optional[SpotFleetRequestConfigData] - SpotFleetRequestId: Optional[String] - SpotFleetRequestState: Optional[BatchState] - Tags: Optional[TagList] + ActivityStatus: ActivityStatus | None + CreateTime: MillisecondDateTime | None + SpotFleetRequestConfig: SpotFleetRequestConfigData | None + SpotFleetRequestId: String | None + SpotFleetRequestState: BatchState | None + Tags: TagList | None -SpotFleetRequestConfigSet = List[SpotFleetRequestConfig] +SpotFleetRequestConfigSet = list[SpotFleetRequestConfig] class DescribeSpotFleetRequestsResponse(TypedDict, total=False): - NextToken: Optional[String] - SpotFleetRequestConfigs: Optional[SpotFleetRequestConfigSet] + NextToken: String | None + SpotFleetRequestConfigs: SpotFleetRequestConfigSet | None class DescribeSpotInstanceRequestsRequest(ServiceRequest): - NextToken: Optional[String] - MaxResults: Optional[Integer] - DryRun: Optional[Boolean] - SpotInstanceRequestIds: Optional[SpotInstanceRequestIdList] - Filters: Optional[FilterList] + NextToken: String | None + MaxResults: Integer | None + DryRun: Boolean | None + SpotInstanceRequestIds: SpotInstanceRequestIdList | None + Filters: FilterList | None class SpotInstanceStatus(TypedDict, total=False): - Code: Optional[String] - Message: Optional[String] - UpdateTime: Optional[DateTime] + Code: String | None + Message: String | None + UpdateTime: DateTime | None class RunInstancesMonitoringEnabled(TypedDict, total=False): @@ -15451,1433 +17076,1479 @@ class RunInstancesMonitoringEnabled(TypedDict, total=False): class LaunchSpecification(TypedDict, total=False): - UserData: Optional[SensitiveUserData] - AddressingType: Optional[String] - BlockDeviceMappings: Optional[BlockDeviceMappingList] - EbsOptimized: Optional[Boolean] - IamInstanceProfile: Optional[IamInstanceProfileSpecification] - ImageId: Optional[String] - InstanceType: Optional[InstanceType] - KernelId: Optional[String] - KeyName: Optional[String] - NetworkInterfaces: Optional[InstanceNetworkInterfaceSpecificationList] - Placement: Optional[SpotPlacement] - RamdiskId: Optional[String] - SubnetId: Optional[String] - SecurityGroups: Optional[GroupIdentifierList] - Monitoring: Optional[RunInstancesMonitoringEnabled] + UserData: SensitiveUserData | None + AddressingType: String | None + BlockDeviceMappings: BlockDeviceMappingList | None + EbsOptimized: Boolean | None + IamInstanceProfile: IamInstanceProfileSpecification | None + ImageId: String | None + InstanceType: InstanceType | None + KernelId: String | None + KeyName: String | None + NetworkInterfaces: InstanceNetworkInterfaceSpecificationList | None + Placement: SpotPlacement | None + RamdiskId: String | None + SubnetId: String | None + SecurityGroups: GroupIdentifierList | None + Monitoring: RunInstancesMonitoringEnabled | None class SpotInstanceRequest(TypedDict, total=False): - ActualBlockHourlyPrice: Optional[String] - AvailabilityZoneGroup: Optional[String] - BlockDurationMinutes: Optional[Integer] - CreateTime: Optional[DateTime] - Fault: Optional[SpotInstanceStateFault] - InstanceId: Optional[InstanceId] - LaunchGroup: Optional[String] - LaunchSpecification: Optional[LaunchSpecification] - LaunchedAvailabilityZone: Optional[String] - LaunchedAvailabilityZoneId: Optional[String] - ProductDescription: Optional[RIProductDescription] - SpotInstanceRequestId: Optional[String] - SpotPrice: Optional[String] - State: Optional[SpotInstanceState] - Status: Optional[SpotInstanceStatus] - Tags: Optional[TagList] - Type: Optional[SpotInstanceType] - ValidFrom: Optional[DateTime] - ValidUntil: Optional[DateTime] - InstanceInterruptionBehavior: Optional[InstanceInterruptionBehavior] - - -SpotInstanceRequestList = List[SpotInstanceRequest] + ActualBlockHourlyPrice: String | None + AvailabilityZoneGroup: String | None + BlockDurationMinutes: Integer | None + CreateTime: DateTime | None + Fault: SpotInstanceStateFault | None + InstanceId: InstanceId | None + LaunchGroup: String | None + LaunchSpecification: LaunchSpecification | None + LaunchedAvailabilityZone: String | None + LaunchedAvailabilityZoneId: String | None + ProductDescription: RIProductDescription | None + SpotInstanceRequestId: String | None + SpotPrice: String | None + State: SpotInstanceState | None + Status: SpotInstanceStatus | None + Tags: TagList | None + Type: SpotInstanceType | None + ValidFrom: DateTime | None + ValidUntil: DateTime | None + InstanceInterruptionBehavior: InstanceInterruptionBehavior | None + + +SpotInstanceRequestList = list[SpotInstanceRequest] class DescribeSpotInstanceRequestsResult(TypedDict, total=False): - SpotInstanceRequests: Optional[SpotInstanceRequestList] - NextToken: Optional[String] + SpotInstanceRequests: SpotInstanceRequestList | None + NextToken: String | None -ProductDescriptionList = List[String] -InstanceTypeList = List[InstanceType] +ProductDescriptionList = list[String] +InstanceTypeList = list[InstanceType] class DescribeSpotPriceHistoryRequest(ServiceRequest): - AvailabilityZoneId: Optional[AvailabilityZoneId] - DryRun: Optional[Boolean] - StartTime: Optional[DateTime] - EndTime: Optional[DateTime] - InstanceTypes: Optional[InstanceTypeList] - ProductDescriptions: Optional[ProductDescriptionList] - Filters: Optional[FilterList] - AvailabilityZone: Optional[String] - MaxResults: Optional[Integer] - NextToken: Optional[String] + AvailabilityZoneId: AvailabilityZoneId | None + DryRun: Boolean | None + StartTime: DateTime | None + EndTime: DateTime | None + InstanceTypes: InstanceTypeList | None + ProductDescriptions: ProductDescriptionList | None + Filters: FilterList | None + AvailabilityZone: String | None + MaxResults: Integer | None + NextToken: String | None class SpotPrice(TypedDict, total=False): - AvailabilityZone: Optional[String] - AvailabilityZoneId: Optional[String] - InstanceType: Optional[InstanceType] - ProductDescription: Optional[RIProductDescription] - SpotPrice: Optional[String] - Timestamp: Optional[DateTime] + AvailabilityZone: String | None + AvailabilityZoneId: String | None + InstanceType: InstanceType | None + ProductDescription: RIProductDescription | None + SpotPrice: String | None + Timestamp: DateTime | None -SpotPriceHistoryList = List[SpotPrice] +SpotPriceHistoryList = list[SpotPrice] class DescribeSpotPriceHistoryResult(TypedDict, total=False): - NextToken: Optional[String] - SpotPriceHistory: Optional[SpotPriceHistoryList] + NextToken: String | None + SpotPriceHistory: SpotPriceHistoryList | None class DescribeStaleSecurityGroupsRequest(ServiceRequest): - DryRun: Optional[Boolean] - MaxResults: Optional[DescribeStaleSecurityGroupsMaxResults] - NextToken: Optional[DescribeStaleSecurityGroupsNextToken] + DryRun: Boolean | None + MaxResults: DescribeStaleSecurityGroupsMaxResults | None + NextToken: DescribeStaleSecurityGroupsNextToken | None VpcId: VpcId -UserIdGroupPairSet = List[UserIdGroupPair] -PrefixListIdSet = List[String] -IpRanges = List[String] +UserIdGroupPairSet = list[UserIdGroupPair] +PrefixListIdSet = list[String] +IpRanges = list[String] class StaleIpPermission(TypedDict, total=False): - FromPort: Optional[Integer] - IpProtocol: Optional[String] - IpRanges: Optional[IpRanges] - PrefixListIds: Optional[PrefixListIdSet] - ToPort: Optional[Integer] - UserIdGroupPairs: Optional[UserIdGroupPairSet] + FromPort: Integer | None + IpProtocol: String | None + IpRanges: IpRanges | None + PrefixListIds: PrefixListIdSet | None + ToPort: Integer | None + UserIdGroupPairs: UserIdGroupPairSet | None -StaleIpPermissionSet = List[StaleIpPermission] +StaleIpPermissionSet = list[StaleIpPermission] class StaleSecurityGroup(TypedDict, total=False): - Description: Optional[String] - GroupId: Optional[String] - GroupName: Optional[String] - StaleIpPermissions: Optional[StaleIpPermissionSet] - StaleIpPermissionsEgress: Optional[StaleIpPermissionSet] - VpcId: Optional[String] + Description: String | None + GroupId: String | None + GroupName: String | None + StaleIpPermissions: StaleIpPermissionSet | None + StaleIpPermissionsEgress: StaleIpPermissionSet | None + VpcId: String | None -StaleSecurityGroupSet = List[StaleSecurityGroup] +StaleSecurityGroupSet = list[StaleSecurityGroup] class DescribeStaleSecurityGroupsResult(TypedDict, total=False): - NextToken: Optional[String] - StaleSecurityGroupSet: Optional[StaleSecurityGroupSet] + NextToken: String | None + StaleSecurityGroupSet: StaleSecurityGroupSet | None -ImageIdList = List[ImageId] +ImageIdList = list[ImageId] class DescribeStoreImageTasksRequest(ServiceRequest): - ImageIds: Optional[ImageIdList] - DryRun: Optional[Boolean] - Filters: Optional[FilterList] - NextToken: Optional[String] - MaxResults: Optional[DescribeStoreImageTasksRequestMaxResults] + ImageIds: ImageIdList | None + DryRun: Boolean | None + Filters: FilterList | None + NextToken: String | None + MaxResults: DescribeStoreImageTasksRequestMaxResults | None class StoreImageTaskResult(TypedDict, total=False): - AmiId: Optional[String] - TaskStartTime: Optional[MillisecondDateTime] - Bucket: Optional[String] - S3objectKey: Optional[String] - ProgressPercentage: Optional[Integer] - StoreTaskState: Optional[String] - StoreTaskFailureReason: Optional[String] + AmiId: String | None + TaskStartTime: MillisecondDateTime | None + Bucket: String | None + S3objectKey: String | None + ProgressPercentage: Integer | None + StoreTaskState: String | None + StoreTaskFailureReason: String | None -StoreImageTaskResultSet = List[StoreImageTaskResult] +StoreImageTaskResultSet = list[StoreImageTaskResult] class DescribeStoreImageTasksResult(TypedDict, total=False): - StoreImageTaskResults: Optional[StoreImageTaskResultSet] - NextToken: Optional[String] + StoreImageTaskResults: StoreImageTaskResultSet | None + NextToken: String | None -SubnetIdStringList = List[SubnetId] +SubnetIdStringList = list[SubnetId] class DescribeSubnetsRequest(ServiceRequest): - Filters: Optional[FilterList] - SubnetIds: Optional[SubnetIdStringList] - NextToken: Optional[String] - MaxResults: Optional[DescribeSubnetsMaxResults] - DryRun: Optional[Boolean] + Filters: FilterList | None + SubnetIds: SubnetIdStringList | None + NextToken: String | None + MaxResults: DescribeSubnetsMaxResults | None + DryRun: Boolean | None -SubnetList = List[Subnet] +SubnetList = list[Subnet] class DescribeSubnetsResult(TypedDict, total=False): - NextToken: Optional[String] - Subnets: Optional[SubnetList] + NextToken: String | None + Subnets: SubnetList | None class DescribeTagsRequest(ServiceRequest): - DryRun: Optional[Boolean] - Filters: Optional[FilterList] - MaxResults: Optional[Integer] - NextToken: Optional[String] + DryRun: Boolean | None + Filters: FilterList | None + MaxResults: Integer | None + NextToken: String | None class TagDescription(TypedDict, total=False): - Key: Optional[String] - ResourceId: Optional[String] - ResourceType: Optional[ResourceType] - Value: Optional[String] + Key: String | None + ResourceId: String | None + ResourceType: ResourceType | None + Value: String | None -TagDescriptionList = List[TagDescription] +TagDescriptionList = list[TagDescription] class DescribeTagsResult(TypedDict, total=False): - NextToken: Optional[String] - Tags: Optional[TagDescriptionList] + NextToken: String | None + Tags: TagDescriptionList | None -TrafficMirrorFilterRuleIdList = List[TrafficMirrorFilterRuleIdWithResolver] +TrafficMirrorFilterRuleIdList = list[TrafficMirrorFilterRuleIdWithResolver] class DescribeTrafficMirrorFilterRulesRequest(ServiceRequest): - TrafficMirrorFilterRuleIds: Optional[TrafficMirrorFilterRuleIdList] - TrafficMirrorFilterId: Optional[TrafficMirrorFilterId] - DryRun: Optional[Boolean] - Filters: Optional[FilterList] - MaxResults: Optional[TrafficMirroringMaxResults] - NextToken: Optional[NextToken] + TrafficMirrorFilterRuleIds: TrafficMirrorFilterRuleIdList | None + TrafficMirrorFilterId: TrafficMirrorFilterId | None + DryRun: Boolean | None + Filters: FilterList | None + MaxResults: TrafficMirroringMaxResults | None + NextToken: NextToken | None -TrafficMirrorFilterRuleSet = List[TrafficMirrorFilterRule] +TrafficMirrorFilterRuleSet = list[TrafficMirrorFilterRule] class DescribeTrafficMirrorFilterRulesResult(TypedDict, total=False): - TrafficMirrorFilterRules: Optional[TrafficMirrorFilterRuleSet] - NextToken: Optional[String] + TrafficMirrorFilterRules: TrafficMirrorFilterRuleSet | None + NextToken: String | None -TrafficMirrorFilterIdList = List[TrafficMirrorFilterId] +TrafficMirrorFilterIdList = list[TrafficMirrorFilterId] class DescribeTrafficMirrorFiltersRequest(ServiceRequest): - TrafficMirrorFilterIds: Optional[TrafficMirrorFilterIdList] - DryRun: Optional[Boolean] - Filters: Optional[FilterList] - MaxResults: Optional[TrafficMirroringMaxResults] - NextToken: Optional[NextToken] + TrafficMirrorFilterIds: TrafficMirrorFilterIdList | None + DryRun: Boolean | None + Filters: FilterList | None + MaxResults: TrafficMirroringMaxResults | None + NextToken: NextToken | None -TrafficMirrorFilterSet = List[TrafficMirrorFilter] +TrafficMirrorFilterSet = list[TrafficMirrorFilter] class DescribeTrafficMirrorFiltersResult(TypedDict, total=False): - TrafficMirrorFilters: Optional[TrafficMirrorFilterSet] - NextToken: Optional[String] + TrafficMirrorFilters: TrafficMirrorFilterSet | None + NextToken: String | None -TrafficMirrorSessionIdList = List[TrafficMirrorSessionId] +TrafficMirrorSessionIdList = list[TrafficMirrorSessionId] class DescribeTrafficMirrorSessionsRequest(ServiceRequest): - TrafficMirrorSessionIds: Optional[TrafficMirrorSessionIdList] - DryRun: Optional[Boolean] - Filters: Optional[FilterList] - MaxResults: Optional[TrafficMirroringMaxResults] - NextToken: Optional[NextToken] + TrafficMirrorSessionIds: TrafficMirrorSessionIdList | None + DryRun: Boolean | None + Filters: FilterList | None + MaxResults: TrafficMirroringMaxResults | None + NextToken: NextToken | None -TrafficMirrorSessionSet = List[TrafficMirrorSession] +TrafficMirrorSessionSet = list[TrafficMirrorSession] class DescribeTrafficMirrorSessionsResult(TypedDict, total=False): - TrafficMirrorSessions: Optional[TrafficMirrorSessionSet] - NextToken: Optional[String] + TrafficMirrorSessions: TrafficMirrorSessionSet | None + NextToken: String | None -TrafficMirrorTargetIdList = List[TrafficMirrorTargetId] +TrafficMirrorTargetIdList = list[TrafficMirrorTargetId] class DescribeTrafficMirrorTargetsRequest(ServiceRequest): - TrafficMirrorTargetIds: Optional[TrafficMirrorTargetIdList] - DryRun: Optional[Boolean] - Filters: Optional[FilterList] - MaxResults: Optional[TrafficMirroringMaxResults] - NextToken: Optional[NextToken] + TrafficMirrorTargetIds: TrafficMirrorTargetIdList | None + DryRun: Boolean | None + Filters: FilterList | None + MaxResults: TrafficMirroringMaxResults | None + NextToken: NextToken | None -TrafficMirrorTargetSet = List[TrafficMirrorTarget] +TrafficMirrorTargetSet = list[TrafficMirrorTarget] class DescribeTrafficMirrorTargetsResult(TypedDict, total=False): - TrafficMirrorTargets: Optional[TrafficMirrorTargetSet] - NextToken: Optional[String] - - -TransitGatewayAttachmentIdStringList = List[TransitGatewayAttachmentId] + TrafficMirrorTargets: TrafficMirrorTargetSet | None + NextToken: String | None class DescribeTransitGatewayAttachmentsRequest(ServiceRequest): - TransitGatewayAttachmentIds: Optional[TransitGatewayAttachmentIdStringList] - Filters: Optional[FilterList] - MaxResults: Optional[TransitGatewayMaxResults] - NextToken: Optional[String] - DryRun: Optional[Boolean] + TransitGatewayAttachmentIds: TransitGatewayAttachmentIdStringList | None + Filters: FilterList | None + MaxResults: TransitGatewayMaxResults | None + NextToken: String | None + DryRun: Boolean | None class TransitGatewayAttachmentAssociation(TypedDict, total=False): - TransitGatewayRouteTableId: Optional[String] - State: Optional[TransitGatewayAssociationState] + TransitGatewayRouteTableId: String | None + State: TransitGatewayAssociationState | None class TransitGatewayAttachment(TypedDict, total=False): - TransitGatewayAttachmentId: Optional[String] - TransitGatewayId: Optional[String] - TransitGatewayOwnerId: Optional[String] - ResourceOwnerId: Optional[String] - ResourceType: Optional[TransitGatewayAttachmentResourceType] - ResourceId: Optional[String] - State: Optional[TransitGatewayAttachmentState] - Association: Optional[TransitGatewayAttachmentAssociation] - CreationTime: Optional[DateTime] - Tags: Optional[TagList] + TransitGatewayAttachmentId: String | None + TransitGatewayId: String | None + TransitGatewayOwnerId: String | None + ResourceOwnerId: String | None + ResourceType: TransitGatewayAttachmentResourceType | None + ResourceId: String | None + State: TransitGatewayAttachmentState | None + Association: TransitGatewayAttachmentAssociation | None + CreationTime: DateTime | None + Tags: TagList | None -TransitGatewayAttachmentList = List[TransitGatewayAttachment] +TransitGatewayAttachmentList = list[TransitGatewayAttachment] class DescribeTransitGatewayAttachmentsResult(TypedDict, total=False): - TransitGatewayAttachments: Optional[TransitGatewayAttachmentList] - NextToken: Optional[String] + TransitGatewayAttachments: TransitGatewayAttachmentList | None + NextToken: String | None -TransitGatewayConnectPeerIdStringList = List[TransitGatewayConnectPeerId] +TransitGatewayConnectPeerIdStringList = list[TransitGatewayConnectPeerId] class DescribeTransitGatewayConnectPeersRequest(ServiceRequest): - TransitGatewayConnectPeerIds: Optional[TransitGatewayConnectPeerIdStringList] - Filters: Optional[FilterList] - MaxResults: Optional[TransitGatewayMaxResults] - NextToken: Optional[String] - DryRun: Optional[Boolean] + TransitGatewayConnectPeerIds: TransitGatewayConnectPeerIdStringList | None + Filters: FilterList | None + MaxResults: TransitGatewayMaxResults | None + NextToken: String | None + DryRun: Boolean | None -TransitGatewayConnectPeerList = List[TransitGatewayConnectPeer] +TransitGatewayConnectPeerList = list[TransitGatewayConnectPeer] class DescribeTransitGatewayConnectPeersResult(TypedDict, total=False): - TransitGatewayConnectPeers: Optional[TransitGatewayConnectPeerList] - NextToken: Optional[String] + TransitGatewayConnectPeers: TransitGatewayConnectPeerList | None + NextToken: String | None class DescribeTransitGatewayConnectsRequest(ServiceRequest): - TransitGatewayAttachmentIds: Optional[TransitGatewayAttachmentIdStringList] - Filters: Optional[FilterList] - MaxResults: Optional[TransitGatewayMaxResults] - NextToken: Optional[String] - DryRun: Optional[Boolean] + TransitGatewayAttachmentIds: TransitGatewayAttachmentIdStringList | None + Filters: FilterList | None + MaxResults: TransitGatewayMaxResults | None + NextToken: String | None + DryRun: Boolean | None -TransitGatewayConnectList = List[TransitGatewayConnect] +TransitGatewayConnectList = list[TransitGatewayConnect] class DescribeTransitGatewayConnectsResult(TypedDict, total=False): - TransitGatewayConnects: Optional[TransitGatewayConnectList] - NextToken: Optional[String] + TransitGatewayConnects: TransitGatewayConnectList | None + NextToken: String | None + + +TransitGatewayMeteringPolicyIdStringList = list[TransitGatewayMeteringPolicyId] + + +class DescribeTransitGatewayMeteringPoliciesRequest(ServiceRequest): + TransitGatewayMeteringPolicyIds: TransitGatewayMeteringPolicyIdStringList | None + Filters: FilterList | None + MaxResults: TransitGatewayMaxResults | None + NextToken: String | None + DryRun: Boolean | None + + +TransitGatewayMeteringPolicyList = list[TransitGatewayMeteringPolicy] -TransitGatewayMulticastDomainIdStringList = List[TransitGatewayMulticastDomainId] +class DescribeTransitGatewayMeteringPoliciesResult(TypedDict, total=False): + TransitGatewayMeteringPolicies: TransitGatewayMeteringPolicyList | None + NextToken: String | None + + +TransitGatewayMulticastDomainIdStringList = list[TransitGatewayMulticastDomainId] class DescribeTransitGatewayMulticastDomainsRequest(ServiceRequest): - TransitGatewayMulticastDomainIds: Optional[TransitGatewayMulticastDomainIdStringList] - Filters: Optional[FilterList] - MaxResults: Optional[TransitGatewayMaxResults] - NextToken: Optional[String] - DryRun: Optional[Boolean] + TransitGatewayMulticastDomainIds: TransitGatewayMulticastDomainIdStringList | None + Filters: FilterList | None + MaxResults: TransitGatewayMaxResults | None + NextToken: String | None + DryRun: Boolean | None -TransitGatewayMulticastDomainList = List[TransitGatewayMulticastDomain] +TransitGatewayMulticastDomainList = list[TransitGatewayMulticastDomain] class DescribeTransitGatewayMulticastDomainsResult(TypedDict, total=False): - TransitGatewayMulticastDomains: Optional[TransitGatewayMulticastDomainList] - NextToken: Optional[String] + TransitGatewayMulticastDomains: TransitGatewayMulticastDomainList | None + NextToken: String | None class DescribeTransitGatewayPeeringAttachmentsRequest(ServiceRequest): - TransitGatewayAttachmentIds: Optional[TransitGatewayAttachmentIdStringList] - Filters: Optional[FilterList] - MaxResults: Optional[TransitGatewayMaxResults] - NextToken: Optional[String] - DryRun: Optional[Boolean] + TransitGatewayAttachmentIds: TransitGatewayAttachmentIdStringList | None + Filters: FilterList | None + MaxResults: TransitGatewayMaxResults | None + NextToken: String | None + DryRun: Boolean | None -TransitGatewayPeeringAttachmentList = List[TransitGatewayPeeringAttachment] +TransitGatewayPeeringAttachmentList = list[TransitGatewayPeeringAttachment] class DescribeTransitGatewayPeeringAttachmentsResult(TypedDict, total=False): - TransitGatewayPeeringAttachments: Optional[TransitGatewayPeeringAttachmentList] - NextToken: Optional[String] + TransitGatewayPeeringAttachments: TransitGatewayPeeringAttachmentList | None + NextToken: String | None -TransitGatewayPolicyTableIdStringList = List[TransitGatewayPolicyTableId] +TransitGatewayPolicyTableIdStringList = list[TransitGatewayPolicyTableId] class DescribeTransitGatewayPolicyTablesRequest(ServiceRequest): - TransitGatewayPolicyTableIds: Optional[TransitGatewayPolicyTableIdStringList] - Filters: Optional[FilterList] - MaxResults: Optional[TransitGatewayMaxResults] - NextToken: Optional[String] - DryRun: Optional[Boolean] + TransitGatewayPolicyTableIds: TransitGatewayPolicyTableIdStringList | None + Filters: FilterList | None + MaxResults: TransitGatewayMaxResults | None + NextToken: String | None + DryRun: Boolean | None -TransitGatewayPolicyTableList = List[TransitGatewayPolicyTable] +TransitGatewayPolicyTableList = list[TransitGatewayPolicyTable] class DescribeTransitGatewayPolicyTablesResult(TypedDict, total=False): - TransitGatewayPolicyTables: Optional[TransitGatewayPolicyTableList] - NextToken: Optional[String] + TransitGatewayPolicyTables: TransitGatewayPolicyTableList | None + NextToken: String | None -TransitGatewayRouteTableAnnouncementIdStringList = List[TransitGatewayRouteTableAnnouncementId] +TransitGatewayRouteTableAnnouncementIdStringList = list[TransitGatewayRouteTableAnnouncementId] class DescribeTransitGatewayRouteTableAnnouncementsRequest(ServiceRequest): - TransitGatewayRouteTableAnnouncementIds: Optional[ - TransitGatewayRouteTableAnnouncementIdStringList - ] - Filters: Optional[FilterList] - MaxResults: Optional[TransitGatewayMaxResults] - NextToken: Optional[String] - DryRun: Optional[Boolean] + TransitGatewayRouteTableAnnouncementIds: TransitGatewayRouteTableAnnouncementIdStringList | None + Filters: FilterList | None + MaxResults: TransitGatewayMaxResults | None + NextToken: String | None + DryRun: Boolean | None -TransitGatewayRouteTableAnnouncementList = List[TransitGatewayRouteTableAnnouncement] +TransitGatewayRouteTableAnnouncementList = list[TransitGatewayRouteTableAnnouncement] class DescribeTransitGatewayRouteTableAnnouncementsResult(TypedDict, total=False): - TransitGatewayRouteTableAnnouncements: Optional[TransitGatewayRouteTableAnnouncementList] - NextToken: Optional[String] + TransitGatewayRouteTableAnnouncements: TransitGatewayRouteTableAnnouncementList | None + NextToken: String | None -TransitGatewayRouteTableIdStringList = List[TransitGatewayRouteTableId] +TransitGatewayRouteTableIdStringList = list[TransitGatewayRouteTableId] class DescribeTransitGatewayRouteTablesRequest(ServiceRequest): - TransitGatewayRouteTableIds: Optional[TransitGatewayRouteTableIdStringList] - Filters: Optional[FilterList] - MaxResults: Optional[TransitGatewayMaxResults] - NextToken: Optional[String] - DryRun: Optional[Boolean] + TransitGatewayRouteTableIds: TransitGatewayRouteTableIdStringList | None + Filters: FilterList | None + MaxResults: TransitGatewayMaxResults | None + NextToken: String | None + DryRun: Boolean | None -TransitGatewayRouteTableList = List[TransitGatewayRouteTable] +TransitGatewayRouteTableList = list[TransitGatewayRouteTable] class DescribeTransitGatewayRouteTablesResult(TypedDict, total=False): - TransitGatewayRouteTables: Optional[TransitGatewayRouteTableList] - NextToken: Optional[String] + TransitGatewayRouteTables: TransitGatewayRouteTableList | None + NextToken: String | None class DescribeTransitGatewayVpcAttachmentsRequest(ServiceRequest): - TransitGatewayAttachmentIds: Optional[TransitGatewayAttachmentIdStringList] - Filters: Optional[FilterList] - MaxResults: Optional[TransitGatewayMaxResults] - NextToken: Optional[String] - DryRun: Optional[Boolean] + TransitGatewayAttachmentIds: TransitGatewayAttachmentIdStringList | None + Filters: FilterList | None + MaxResults: TransitGatewayMaxResults | None + NextToken: String | None + DryRun: Boolean | None -TransitGatewayVpcAttachmentList = List[TransitGatewayVpcAttachment] +TransitGatewayVpcAttachmentList = list[TransitGatewayVpcAttachment] class DescribeTransitGatewayVpcAttachmentsResult(TypedDict, total=False): - TransitGatewayVpcAttachments: Optional[TransitGatewayVpcAttachmentList] - NextToken: Optional[String] + TransitGatewayVpcAttachments: TransitGatewayVpcAttachmentList | None + NextToken: String | None -TransitGatewayIdStringList = List[TransitGatewayId] +TransitGatewayIdStringList = list[TransitGatewayId] class DescribeTransitGatewaysRequest(ServiceRequest): - TransitGatewayIds: Optional[TransitGatewayIdStringList] - Filters: Optional[FilterList] - MaxResults: Optional[TransitGatewayMaxResults] - NextToken: Optional[String] - DryRun: Optional[Boolean] + TransitGatewayIds: TransitGatewayIdStringList | None + Filters: FilterList | None + MaxResults: TransitGatewayMaxResults | None + NextToken: String | None + DryRun: Boolean | None -TransitGatewayList = List[TransitGateway] +TransitGatewayList = list[TransitGateway] class DescribeTransitGatewaysResult(TypedDict, total=False): - TransitGateways: Optional[TransitGatewayList] - NextToken: Optional[String] + TransitGateways: TransitGatewayList | None + NextToken: String | None -TrunkInterfaceAssociationIdList = List[TrunkInterfaceAssociationId] +TrunkInterfaceAssociationIdList = list[TrunkInterfaceAssociationId] class DescribeTrunkInterfaceAssociationsRequest(ServiceRequest): - AssociationIds: Optional[TrunkInterfaceAssociationIdList] - DryRun: Optional[Boolean] - Filters: Optional[FilterList] - NextToken: Optional[String] - MaxResults: Optional[DescribeTrunkInterfaceAssociationsMaxResults] + AssociationIds: TrunkInterfaceAssociationIdList | None + DryRun: Boolean | None + Filters: FilterList | None + NextToken: String | None + MaxResults: DescribeTrunkInterfaceAssociationsMaxResults | None -TrunkInterfaceAssociationList = List[TrunkInterfaceAssociation] +TrunkInterfaceAssociationList = list[TrunkInterfaceAssociation] class DescribeTrunkInterfaceAssociationsResult(TypedDict, total=False): - InterfaceAssociations: Optional[TrunkInterfaceAssociationList] - NextToken: Optional[String] + InterfaceAssociations: TrunkInterfaceAssociationList | None + NextToken: String | None -VerifiedAccessEndpointIdList = List[VerifiedAccessEndpointId] +VerifiedAccessEndpointIdList = list[VerifiedAccessEndpointId] class DescribeVerifiedAccessEndpointsRequest(ServiceRequest): - VerifiedAccessEndpointIds: Optional[VerifiedAccessEndpointIdList] - VerifiedAccessInstanceId: Optional[VerifiedAccessInstanceId] - VerifiedAccessGroupId: Optional[VerifiedAccessGroupId] - MaxResults: Optional[DescribeVerifiedAccessEndpointsMaxResults] - NextToken: Optional[NextToken] - Filters: Optional[FilterList] - DryRun: Optional[Boolean] + VerifiedAccessEndpointIds: VerifiedAccessEndpointIdList | None + VerifiedAccessInstanceId: VerifiedAccessInstanceId | None + VerifiedAccessGroupId: VerifiedAccessGroupId | None + MaxResults: DescribeVerifiedAccessEndpointsMaxResults | None + NextToken: NextToken | None + Filters: FilterList | None + DryRun: Boolean | None -VerifiedAccessEndpointList = List[VerifiedAccessEndpoint] +VerifiedAccessEndpointList = list[VerifiedAccessEndpoint] class DescribeVerifiedAccessEndpointsResult(TypedDict, total=False): - VerifiedAccessEndpoints: Optional[VerifiedAccessEndpointList] - NextToken: Optional[NextToken] + VerifiedAccessEndpoints: VerifiedAccessEndpointList | None + NextToken: NextToken | None -VerifiedAccessGroupIdList = List[VerifiedAccessGroupId] +VerifiedAccessGroupIdList = list[VerifiedAccessGroupId] class DescribeVerifiedAccessGroupsRequest(ServiceRequest): - VerifiedAccessGroupIds: Optional[VerifiedAccessGroupIdList] - VerifiedAccessInstanceId: Optional[VerifiedAccessInstanceId] - MaxResults: Optional[DescribeVerifiedAccessGroupMaxResults] - NextToken: Optional[NextToken] - Filters: Optional[FilterList] - DryRun: Optional[Boolean] + VerifiedAccessGroupIds: VerifiedAccessGroupIdList | None + VerifiedAccessInstanceId: VerifiedAccessInstanceId | None + MaxResults: DescribeVerifiedAccessGroupMaxResults | None + NextToken: NextToken | None + Filters: FilterList | None + DryRun: Boolean | None -VerifiedAccessGroupList = List[VerifiedAccessGroup] +VerifiedAccessGroupList = list[VerifiedAccessGroup] class DescribeVerifiedAccessGroupsResult(TypedDict, total=False): - VerifiedAccessGroups: Optional[VerifiedAccessGroupList] - NextToken: Optional[NextToken] + VerifiedAccessGroups: VerifiedAccessGroupList | None + NextToken: NextToken | None -VerifiedAccessInstanceIdList = List[VerifiedAccessInstanceId] +VerifiedAccessInstanceIdList = list[VerifiedAccessInstanceId] class DescribeVerifiedAccessInstanceLoggingConfigurationsRequest(ServiceRequest): - VerifiedAccessInstanceIds: Optional[VerifiedAccessInstanceIdList] - MaxResults: Optional[DescribeVerifiedAccessInstanceLoggingConfigurationsMaxResults] - NextToken: Optional[NextToken] - Filters: Optional[FilterList] - DryRun: Optional[Boolean] + VerifiedAccessInstanceIds: VerifiedAccessInstanceIdList | None + MaxResults: DescribeVerifiedAccessInstanceLoggingConfigurationsMaxResults | None + NextToken: NextToken | None + Filters: FilterList | None + DryRun: Boolean | None class VerifiedAccessLogDeliveryStatus(TypedDict, total=False): - Code: Optional[VerifiedAccessLogDeliveryStatusCode] - Message: Optional[String] + Code: VerifiedAccessLogDeliveryStatusCode | None + Message: String | None class VerifiedAccessLogKinesisDataFirehoseDestination(TypedDict, total=False): - Enabled: Optional[Boolean] - DeliveryStatus: Optional[VerifiedAccessLogDeliveryStatus] - DeliveryStream: Optional[String] + Enabled: Boolean | None + DeliveryStatus: VerifiedAccessLogDeliveryStatus | None + DeliveryStream: String | None class VerifiedAccessLogCloudWatchLogsDestination(TypedDict, total=False): - Enabled: Optional[Boolean] - DeliveryStatus: Optional[VerifiedAccessLogDeliveryStatus] - LogGroup: Optional[String] + Enabled: Boolean | None + DeliveryStatus: VerifiedAccessLogDeliveryStatus | None + LogGroup: String | None class VerifiedAccessLogS3Destination(TypedDict, total=False): - Enabled: Optional[Boolean] - DeliveryStatus: Optional[VerifiedAccessLogDeliveryStatus] - BucketName: Optional[String] - Prefix: Optional[String] - BucketOwner: Optional[String] + Enabled: Boolean | None + DeliveryStatus: VerifiedAccessLogDeliveryStatus | None + BucketName: String | None + Prefix: String | None + BucketOwner: String | None class VerifiedAccessLogs(TypedDict, total=False): - S3: Optional[VerifiedAccessLogS3Destination] - CloudWatchLogs: Optional[VerifiedAccessLogCloudWatchLogsDestination] - KinesisDataFirehose: Optional[VerifiedAccessLogKinesisDataFirehoseDestination] - LogVersion: Optional[String] - IncludeTrustContext: Optional[Boolean] + S3: VerifiedAccessLogS3Destination | None + CloudWatchLogs: VerifiedAccessLogCloudWatchLogsDestination | None + KinesisDataFirehose: VerifiedAccessLogKinesisDataFirehoseDestination | None + LogVersion: String | None + IncludeTrustContext: Boolean | None class VerifiedAccessInstanceLoggingConfiguration(TypedDict, total=False): - VerifiedAccessInstanceId: Optional[String] - AccessLogs: Optional[VerifiedAccessLogs] + VerifiedAccessInstanceId: String | None + AccessLogs: VerifiedAccessLogs | None -VerifiedAccessInstanceLoggingConfigurationList = List[VerifiedAccessInstanceLoggingConfiguration] +VerifiedAccessInstanceLoggingConfigurationList = list[VerifiedAccessInstanceLoggingConfiguration] class DescribeVerifiedAccessInstanceLoggingConfigurationsResult(TypedDict, total=False): - LoggingConfigurations: Optional[VerifiedAccessInstanceLoggingConfigurationList] - NextToken: Optional[NextToken] + LoggingConfigurations: VerifiedAccessInstanceLoggingConfigurationList | None + NextToken: NextToken | None class DescribeVerifiedAccessInstancesRequest(ServiceRequest): - VerifiedAccessInstanceIds: Optional[VerifiedAccessInstanceIdList] - MaxResults: Optional[DescribeVerifiedAccessInstancesMaxResults] - NextToken: Optional[NextToken] - Filters: Optional[FilterList] - DryRun: Optional[Boolean] + VerifiedAccessInstanceIds: VerifiedAccessInstanceIdList | None + MaxResults: DescribeVerifiedAccessInstancesMaxResults | None + NextToken: NextToken | None + Filters: FilterList | None + DryRun: Boolean | None -VerifiedAccessInstanceList = List[VerifiedAccessInstance] +VerifiedAccessInstanceList = list[VerifiedAccessInstance] class DescribeVerifiedAccessInstancesResult(TypedDict, total=False): - VerifiedAccessInstances: Optional[VerifiedAccessInstanceList] - NextToken: Optional[NextToken] + VerifiedAccessInstances: VerifiedAccessInstanceList | None + NextToken: NextToken | None -VerifiedAccessTrustProviderIdList = List[VerifiedAccessTrustProviderId] +VerifiedAccessTrustProviderIdList = list[VerifiedAccessTrustProviderId] class DescribeVerifiedAccessTrustProvidersRequest(ServiceRequest): - VerifiedAccessTrustProviderIds: Optional[VerifiedAccessTrustProviderIdList] - MaxResults: Optional[DescribeVerifiedAccessTrustProvidersMaxResults] - NextToken: Optional[NextToken] - Filters: Optional[FilterList] - DryRun: Optional[Boolean] + VerifiedAccessTrustProviderIds: VerifiedAccessTrustProviderIdList | None + MaxResults: DescribeVerifiedAccessTrustProvidersMaxResults | None + NextToken: NextToken | None + Filters: FilterList | None + DryRun: Boolean | None -VerifiedAccessTrustProviderList = List[VerifiedAccessTrustProvider] +VerifiedAccessTrustProviderList = list[VerifiedAccessTrustProvider] class DescribeVerifiedAccessTrustProvidersResult(TypedDict, total=False): - VerifiedAccessTrustProviders: Optional[VerifiedAccessTrustProviderList] - NextToken: Optional[NextToken] + VerifiedAccessTrustProviders: VerifiedAccessTrustProviderList | None + NextToken: NextToken | None class DescribeVolumeAttributeRequest(ServiceRequest): Attribute: VolumeAttributeName VolumeId: VolumeId - DryRun: Optional[Boolean] + DryRun: Boolean | None class DescribeVolumeAttributeResult(TypedDict, total=False): - AutoEnableIO: Optional[AttributeBooleanValue] - ProductCodes: Optional[ProductCodeList] - VolumeId: Optional[String] + AutoEnableIO: AttributeBooleanValue | None + ProductCodes: ProductCodeList | None + VolumeId: String | None class DescribeVolumeStatusRequest(ServiceRequest): - MaxResults: Optional[Integer] - NextToken: Optional[String] - VolumeIds: Optional[VolumeIdStringList] - DryRun: Optional[Boolean] - Filters: Optional[FilterList] + MaxResults: Integer | None + NextToken: String | None + VolumeIds: VolumeIdStringList | None + DryRun: Boolean | None + Filters: FilterList | None class InitializationStatusDetails(TypedDict, total=False): - InitializationType: Optional[InitializationType] - Progress: Optional[Long] - EstimatedTimeToCompleteInSeconds: Optional[Long] + InitializationType: InitializationType | None + Progress: Long | None + EstimatedTimeToCompleteInSeconds: Long | None class VolumeStatusAttachmentStatus(TypedDict, total=False): - IoPerformance: Optional[String] - InstanceId: Optional[String] + IoPerformance: String | None + InstanceId: String | None -VolumeStatusAttachmentStatusList = List[VolumeStatusAttachmentStatus] +VolumeStatusAttachmentStatusList = list[VolumeStatusAttachmentStatus] class VolumeStatusDetails(TypedDict, total=False): - Name: Optional[VolumeStatusName] - Status: Optional[String] + Name: VolumeStatusName | None + Status: String | None -VolumeStatusDetailsList = List[VolumeStatusDetails] +VolumeStatusDetailsList = list[VolumeStatusDetails] class VolumeStatusInfo(TypedDict, total=False): - Details: Optional[VolumeStatusDetailsList] - Status: Optional[VolumeStatusInfoStatus] + Details: VolumeStatusDetailsList | None + Status: VolumeStatusInfoStatus | None class VolumeStatusEvent(TypedDict, total=False): - Description: Optional[String] - EventId: Optional[String] - EventType: Optional[String] - NotAfter: Optional[MillisecondDateTime] - NotBefore: Optional[MillisecondDateTime] - InstanceId: Optional[String] + Description: String | None + EventId: String | None + EventType: String | None + NotAfter: MillisecondDateTime | None + NotBefore: MillisecondDateTime | None + InstanceId: String | None -VolumeStatusEventsList = List[VolumeStatusEvent] +VolumeStatusEventsList = list[VolumeStatusEvent] class VolumeStatusAction(TypedDict, total=False): - Code: Optional[String] - Description: Optional[String] - EventId: Optional[String] - EventType: Optional[String] + Code: String | None + Description: String | None + EventId: String | None + EventType: String | None -VolumeStatusActionsList = List[VolumeStatusAction] +VolumeStatusActionsList = list[VolumeStatusAction] class VolumeStatusItem(TypedDict, total=False): - Actions: Optional[VolumeStatusActionsList] - AvailabilityZone: Optional[String] - OutpostArn: Optional[String] - Events: Optional[VolumeStatusEventsList] - VolumeId: Optional[String] - VolumeStatus: Optional[VolumeStatusInfo] - AttachmentStatuses: Optional[VolumeStatusAttachmentStatusList] - InitializationStatusDetails: Optional[InitializationStatusDetails] - AvailabilityZoneId: Optional[String] + Actions: VolumeStatusActionsList | None + AvailabilityZone: String | None + OutpostArn: String | None + Events: VolumeStatusEventsList | None + VolumeId: String | None + VolumeStatus: VolumeStatusInfo | None + AttachmentStatuses: VolumeStatusAttachmentStatusList | None + InitializationStatusDetails: InitializationStatusDetails | None + AvailabilityZoneId: String | None -VolumeStatusList = List[VolumeStatusItem] +VolumeStatusList = list[VolumeStatusItem] class DescribeVolumeStatusResult(TypedDict, total=False): - NextToken: Optional[String] - VolumeStatuses: Optional[VolumeStatusList] + NextToken: String | None + VolumeStatuses: VolumeStatusList | None class DescribeVolumesModificationsRequest(ServiceRequest): - DryRun: Optional[Boolean] - VolumeIds: Optional[VolumeIdStringList] - Filters: Optional[FilterList] - NextToken: Optional[String] - MaxResults: Optional[Integer] + DryRun: Boolean | None + VolumeIds: VolumeIdStringList | None + Filters: FilterList | None + NextToken: String | None + MaxResults: Integer | None class VolumeModification(TypedDict, total=False): - VolumeId: Optional[String] - ModificationState: Optional[VolumeModificationState] - StatusMessage: Optional[String] - TargetSize: Optional[Integer] - TargetIops: Optional[Integer] - TargetVolumeType: Optional[VolumeType] - TargetThroughput: Optional[Integer] - TargetMultiAttachEnabled: Optional[Boolean] - OriginalSize: Optional[Integer] - OriginalIops: Optional[Integer] - OriginalVolumeType: Optional[VolumeType] - OriginalThroughput: Optional[Integer] - OriginalMultiAttachEnabled: Optional[Boolean] - Progress: Optional[Long] - StartTime: Optional[DateTime] - EndTime: Optional[DateTime] - - -VolumeModificationList = List[VolumeModification] + VolumeId: String | None + ModificationState: VolumeModificationState | None + StatusMessage: String | None + TargetSize: Integer | None + TargetIops: Integer | None + TargetVolumeType: VolumeType | None + TargetThroughput: Integer | None + TargetMultiAttachEnabled: Boolean | None + OriginalSize: Integer | None + OriginalIops: Integer | None + OriginalVolumeType: VolumeType | None + OriginalThroughput: Integer | None + OriginalMultiAttachEnabled: Boolean | None + Progress: Long | None + StartTime: DateTime | None + EndTime: DateTime | None + + +VolumeModificationList = list[VolumeModification] class DescribeVolumesModificationsResult(TypedDict, total=False): - NextToken: Optional[String] - VolumesModifications: Optional[VolumeModificationList] + NextToken: String | None + VolumesModifications: VolumeModificationList | None class DescribeVolumesRequest(ServiceRequest): - VolumeIds: Optional[VolumeIdStringList] - DryRun: Optional[Boolean] - Filters: Optional[FilterList] - NextToken: Optional[String] - MaxResults: Optional[Integer] - - -class VolumeAttachment(TypedDict, total=False): - DeleteOnTermination: Optional[Boolean] - AssociatedResource: Optional[String] - InstanceOwningService: Optional[String] - VolumeId: Optional[String] - InstanceId: Optional[String] - Device: Optional[String] - State: Optional[VolumeAttachmentState] - AttachTime: Optional[DateTime] - - -VolumeAttachmentList = List[VolumeAttachment] - - -class Volume(TypedDict, total=False): - AvailabilityZoneId: Optional[String] - OutpostArn: Optional[String] - Iops: Optional[Integer] - Tags: Optional[TagList] - VolumeType: Optional[VolumeType] - FastRestored: Optional[Boolean] - MultiAttachEnabled: Optional[Boolean] - Throughput: Optional[Integer] - SseType: Optional[SSEType] - Operator: Optional[OperatorResponse] - VolumeInitializationRate: Optional[Integer] - VolumeId: Optional[String] - Size: Optional[Integer] - SnapshotId: Optional[String] - AvailabilityZone: Optional[String] - State: Optional[VolumeState] - CreateTime: Optional[DateTime] - Attachments: Optional[VolumeAttachmentList] - Encrypted: Optional[Boolean] - KmsKeyId: Optional[String] - - -VolumeList = List[Volume] + VolumeIds: VolumeIdStringList | None + DryRun: Boolean | None + Filters: FilterList | None + NextToken: String | None + MaxResults: Integer | None class DescribeVolumesResult(TypedDict, total=False): - NextToken: Optional[String] - Volumes: Optional[VolumeList] + NextToken: String | None + Volumes: VolumeList | None class DescribeVpcAttributeRequest(ServiceRequest): Attribute: VpcAttributeName VpcId: VpcId - DryRun: Optional[Boolean] + DryRun: Boolean | None class DescribeVpcAttributeResult(TypedDict, total=False): - EnableDnsHostnames: Optional[AttributeBooleanValue] - EnableDnsSupport: Optional[AttributeBooleanValue] - EnableNetworkAddressUsageMetrics: Optional[AttributeBooleanValue] - VpcId: Optional[String] + EnableDnsHostnames: AttributeBooleanValue | None + EnableDnsSupport: AttributeBooleanValue | None + EnableNetworkAddressUsageMetrics: AttributeBooleanValue | None + VpcId: String | None -VpcBlockPublicAccessExclusionIdList = List[VpcBlockPublicAccessExclusionId] +VpcBlockPublicAccessExclusionIdList = list[VpcBlockPublicAccessExclusionId] class DescribeVpcBlockPublicAccessExclusionsRequest(ServiceRequest): - DryRun: Optional[Boolean] - Filters: Optional[FilterList] - ExclusionIds: Optional[VpcBlockPublicAccessExclusionIdList] - NextToken: Optional[String] - MaxResults: Optional[DescribeVpcBlockPublicAccessExclusionsMaxResults] + DryRun: Boolean | None + Filters: FilterList | None + ExclusionIds: VpcBlockPublicAccessExclusionIdList | None + NextToken: String | None + MaxResults: DescribeVpcBlockPublicAccessExclusionsMaxResults | None -VpcBlockPublicAccessExclusionList = List[VpcBlockPublicAccessExclusion] +VpcBlockPublicAccessExclusionList = list[VpcBlockPublicAccessExclusion] class DescribeVpcBlockPublicAccessExclusionsResult(TypedDict, total=False): - VpcBlockPublicAccessExclusions: Optional[VpcBlockPublicAccessExclusionList] - NextToken: Optional[String] + VpcBlockPublicAccessExclusions: VpcBlockPublicAccessExclusionList | None + NextToken: String | None class DescribeVpcBlockPublicAccessOptionsRequest(ServiceRequest): - DryRun: Optional[Boolean] + DryRun: Boolean | None class VpcBlockPublicAccessOptions(TypedDict, total=False): - AwsAccountId: Optional[String] - AwsRegion: Optional[String] - State: Optional[VpcBlockPublicAccessState] - InternetGatewayBlockMode: Optional[InternetGatewayBlockMode] - Reason: Optional[String] - LastUpdateTimestamp: Optional[MillisecondDateTime] - ManagedBy: Optional[ManagedBy] - ExclusionsAllowed: Optional[VpcBlockPublicAccessExclusionsAllowed] + AwsAccountId: String | None + AwsRegion: String | None + State: VpcBlockPublicAccessState | None + InternetGatewayBlockMode: InternetGatewayBlockMode | None + Reason: String | None + LastUpdateTimestamp: MillisecondDateTime | None + ManagedBy: ManagedBy | None + ExclusionsAllowed: VpcBlockPublicAccessExclusionsAllowed | None class DescribeVpcBlockPublicAccessOptionsResult(TypedDict, total=False): - VpcBlockPublicAccessOptions: Optional[VpcBlockPublicAccessOptions] + VpcBlockPublicAccessOptions: VpcBlockPublicAccessOptions | None -VpcClassicLinkIdList = List[VpcId] +VpcClassicLinkIdList = list[VpcId] class DescribeVpcClassicLinkDnsSupportRequest(ServiceRequest): - VpcIds: Optional[VpcClassicLinkIdList] - MaxResults: Optional[DescribeVpcClassicLinkDnsSupportMaxResults] - NextToken: Optional[DescribeVpcClassicLinkDnsSupportNextToken] + VpcIds: VpcClassicLinkIdList | None + MaxResults: DescribeVpcClassicLinkDnsSupportMaxResults | None + NextToken: DescribeVpcClassicLinkDnsSupportNextToken | None class DescribeVpcClassicLinkDnsSupportResult(TypedDict, total=False): - NextToken: Optional[DescribeVpcClassicLinkDnsSupportNextToken] - Vpcs: Optional[ClassicLinkDnsSupportList] + NextToken: DescribeVpcClassicLinkDnsSupportNextToken | None + Vpcs: ClassicLinkDnsSupportList | None class DescribeVpcClassicLinkRequest(ServiceRequest): - DryRun: Optional[Boolean] - VpcIds: Optional[VpcClassicLinkIdList] - Filters: Optional[FilterList] + DryRun: Boolean | None + VpcIds: VpcClassicLinkIdList | None + Filters: FilterList | None class VpcClassicLink(TypedDict, total=False): - ClassicLinkEnabled: Optional[Boolean] - Tags: Optional[TagList] - VpcId: Optional[String] + ClassicLinkEnabled: Boolean | None + Tags: TagList | None + VpcId: String | None -VpcClassicLinkList = List[VpcClassicLink] +VpcClassicLinkList = list[VpcClassicLink] class DescribeVpcClassicLinkResult(TypedDict, total=False): - Vpcs: Optional[VpcClassicLinkList] + Vpcs: VpcClassicLinkList | None + + +VpcIdStringList = list[VpcId] +VpcEncryptionControlIdList = list[VpcEncryptionControlId] + + +class DescribeVpcEncryptionControlsRequest(ServiceRequest): + DryRun: Boolean | None + Filters: FilterList | None + VpcEncryptionControlIds: VpcEncryptionControlIdList | None + VpcIds: VpcIdStringList | None + NextToken: String | None + MaxResults: DescribeVpcEncryptionControlsMaxResults | None + + +VpcEncryptionControlList = list[VpcEncryptionControl] + + +class DescribeVpcEncryptionControlsResult(TypedDict, total=False): + VpcEncryptionControls: VpcEncryptionControlList | None + NextToken: String | None class DescribeVpcEndpointAssociationsRequest(ServiceRequest): - DryRun: Optional[Boolean] - VpcEndpointIds: Optional[VpcEndpointIdList] - Filters: Optional[FilterList] - MaxResults: Optional[maxResults] - NextToken: Optional[String] + DryRun: Boolean | None + VpcEndpointIds: VpcEndpointIdList | None + Filters: FilterList | None + MaxResults: maxResults | None + NextToken: String | None class VpcEndpointAssociation(TypedDict, total=False): - Id: Optional[String] - VpcEndpointId: Optional[VpcEndpointId] - ServiceNetworkArn: Optional[ServiceNetworkArn] - ServiceNetworkName: Optional[String] - AssociatedResourceAccessibility: Optional[String] - FailureReason: Optional[String] - FailureCode: Optional[String] - DnsEntry: Optional[DnsEntry] - PrivateDnsEntry: Optional[DnsEntry] - AssociatedResourceArn: Optional[String] - ResourceConfigurationGroupArn: Optional[String] - Tags: Optional[TagList] + Id: String | None + VpcEndpointId: VpcEndpointId | None + ServiceNetworkArn: ServiceNetworkArn | None + ServiceNetworkName: String | None + AssociatedResourceAccessibility: String | None + FailureReason: String | None + FailureCode: String | None + DnsEntry: DnsEntry | None + PrivateDnsEntry: DnsEntry | None + AssociatedResourceArn: String | None + ResourceConfigurationGroupArn: String | None + Tags: TagList | None -VpcEndpointAssociationSet = List[VpcEndpointAssociation] +VpcEndpointAssociationSet = list[VpcEndpointAssociation] class DescribeVpcEndpointAssociationsResult(TypedDict, total=False): - VpcEndpointAssociations: Optional[VpcEndpointAssociationSet] - NextToken: Optional[String] + VpcEndpointAssociations: VpcEndpointAssociationSet | None + NextToken: String | None class DescribeVpcEndpointConnectionNotificationsRequest(ServiceRequest): - DryRun: Optional[Boolean] - ConnectionNotificationId: Optional[ConnectionNotificationId] - Filters: Optional[FilterList] - MaxResults: Optional[Integer] - NextToken: Optional[String] + DryRun: Boolean | None + ConnectionNotificationId: ConnectionNotificationId | None + Filters: FilterList | None + MaxResults: Integer | None + NextToken: String | None class DescribeVpcEndpointConnectionNotificationsResult(TypedDict, total=False): - ConnectionNotificationSet: Optional[ConnectionNotificationSet] - NextToken: Optional[String] + ConnectionNotificationSet: ConnectionNotificationSet | None + NextToken: String | None class DescribeVpcEndpointConnectionsRequest(ServiceRequest): - DryRun: Optional[Boolean] - Filters: Optional[FilterList] - MaxResults: Optional[Integer] - NextToken: Optional[String] + DryRun: Boolean | None + Filters: FilterList | None + MaxResults: Integer | None + NextToken: String | None class VpcEndpointConnection(TypedDict, total=False): - ServiceId: Optional[String] - VpcEndpointId: Optional[String] - VpcEndpointOwner: Optional[String] - VpcEndpointState: Optional[State] - CreationTimestamp: Optional[MillisecondDateTime] - DnsEntries: Optional[DnsEntrySet] - NetworkLoadBalancerArns: Optional[ValueStringList] - GatewayLoadBalancerArns: Optional[ValueStringList] - IpAddressType: Optional[IpAddressType] - VpcEndpointConnectionId: Optional[String] - Tags: Optional[TagList] - VpcEndpointRegion: Optional[String] + ServiceId: String | None + VpcEndpointId: String | None + VpcEndpointOwner: String | None + VpcEndpointState: State | None + CreationTimestamp: MillisecondDateTime | None + DnsEntries: DnsEntrySet | None + NetworkLoadBalancerArns: ValueStringList | None + GatewayLoadBalancerArns: ValueStringList | None + IpAddressType: IpAddressType | None + VpcEndpointConnectionId: String | None + Tags: TagList | None + VpcEndpointRegion: String | None -VpcEndpointConnectionSet = List[VpcEndpointConnection] +VpcEndpointConnectionSet = list[VpcEndpointConnection] class DescribeVpcEndpointConnectionsResult(TypedDict, total=False): - VpcEndpointConnections: Optional[VpcEndpointConnectionSet] - NextToken: Optional[String] + VpcEndpointConnections: VpcEndpointConnectionSet | None + NextToken: String | None class DescribeVpcEndpointServiceConfigurationsRequest(ServiceRequest): - DryRun: Optional[Boolean] - ServiceIds: Optional[VpcEndpointServiceIdList] - Filters: Optional[FilterList] - MaxResults: Optional[Integer] - NextToken: Optional[String] + DryRun: Boolean | None + ServiceIds: VpcEndpointServiceIdList | None + Filters: FilterList | None + MaxResults: Integer | None + NextToken: String | None -ServiceConfigurationSet = List[ServiceConfiguration] +ServiceConfigurationSet = list[ServiceConfiguration] class DescribeVpcEndpointServiceConfigurationsResult(TypedDict, total=False): - ServiceConfigurations: Optional[ServiceConfigurationSet] - NextToken: Optional[String] + ServiceConfigurations: ServiceConfigurationSet | None + NextToken: String | None class DescribeVpcEndpointServicePermissionsRequest(ServiceRequest): - DryRun: Optional[Boolean] + DryRun: Boolean | None ServiceId: VpcEndpointServiceId - Filters: Optional[FilterList] - MaxResults: Optional[Integer] - NextToken: Optional[String] + Filters: FilterList | None + MaxResults: Integer | None + NextToken: String | None class DescribeVpcEndpointServicePermissionsResult(TypedDict, total=False): - AllowedPrincipals: Optional[AllowedPrincipalSet] - NextToken: Optional[String] + AllowedPrincipals: AllowedPrincipalSet | None + NextToken: String | None class DescribeVpcEndpointServicesRequest(ServiceRequest): - DryRun: Optional[Boolean] - ServiceNames: Optional[ValueStringList] - Filters: Optional[FilterList] - MaxResults: Optional[Integer] - NextToken: Optional[String] - ServiceRegions: Optional[ValueStringList] + DryRun: Boolean | None + ServiceNames: ValueStringList | None + Filters: FilterList | None + MaxResults: Integer | None + NextToken: String | None + ServiceRegions: ValueStringList | None class PrivateDnsDetails(TypedDict, total=False): - PrivateDnsName: Optional[String] + PrivateDnsName: String | None -PrivateDnsDetailsSet = List[PrivateDnsDetails] +PrivateDnsDetailsSet = list[PrivateDnsDetails] class ServiceDetail(TypedDict, total=False): - ServiceName: Optional[String] - ServiceId: Optional[String] - ServiceType: Optional[ServiceTypeDetailSet] - ServiceRegion: Optional[String] - AvailabilityZoneIds: Optional[ValueStringList] - AvailabilityZones: Optional[ValueStringList] - Owner: Optional[String] - BaseEndpointDnsNames: Optional[ValueStringList] - PrivateDnsName: Optional[String] - PrivateDnsNames: Optional[PrivateDnsDetailsSet] - VpcEndpointPolicySupported: Optional[Boolean] - AcceptanceRequired: Optional[Boolean] - ManagesVpcEndpoints: Optional[Boolean] - PayerResponsibility: Optional[PayerResponsibility] - Tags: Optional[TagList] - PrivateDnsNameVerificationState: Optional[DnsNameState] - SupportedIpAddressTypes: Optional[SupportedIpAddressTypes] - - -ServiceDetailSet = List[ServiceDetail] + ServiceName: String | None + ServiceId: String | None + ServiceType: ServiceTypeDetailSet | None + ServiceRegion: String | None + AvailabilityZoneIds: ValueStringList | None + AvailabilityZones: ValueStringList | None + Owner: String | None + BaseEndpointDnsNames: ValueStringList | None + PrivateDnsName: String | None + PrivateDnsNames: PrivateDnsDetailsSet | None + VpcEndpointPolicySupported: Boolean | None + AcceptanceRequired: Boolean | None + ManagesVpcEndpoints: Boolean | None + PayerResponsibility: PayerResponsibility | None + Tags: TagList | None + PrivateDnsNameVerificationState: DnsNameState | None + SupportedIpAddressTypes: SupportedIpAddressTypes | None + + +ServiceDetailSet = list[ServiceDetail] class DescribeVpcEndpointServicesResult(TypedDict, total=False): - ServiceNames: Optional[ValueStringList] - ServiceDetails: Optional[ServiceDetailSet] - NextToken: Optional[String] + ServiceNames: ValueStringList | None + ServiceDetails: ServiceDetailSet | None + NextToken: String | None class DescribeVpcEndpointsRequest(ServiceRequest): - DryRun: Optional[Boolean] - VpcEndpointIds: Optional[VpcEndpointIdList] - Filters: Optional[FilterList] - MaxResults: Optional[Integer] - NextToken: Optional[String] + DryRun: Boolean | None + VpcEndpointIds: VpcEndpointIdList | None + Filters: FilterList | None + MaxResults: Integer | None + NextToken: String | None -VpcEndpointSet = List[VpcEndpoint] +VpcEndpointSet = list[VpcEndpoint] class DescribeVpcEndpointsResult(TypedDict, total=False): - VpcEndpoints: Optional[VpcEndpointSet] - NextToken: Optional[String] + VpcEndpoints: VpcEndpointSet | None + NextToken: String | None -VpcPeeringConnectionIdList = List[VpcPeeringConnectionId] +VpcPeeringConnectionIdList = list[VpcPeeringConnectionId] class DescribeVpcPeeringConnectionsRequest(ServiceRequest): - NextToken: Optional[String] - MaxResults: Optional[DescribeVpcPeeringConnectionsMaxResults] - DryRun: Optional[Boolean] - VpcPeeringConnectionIds: Optional[VpcPeeringConnectionIdList] - Filters: Optional[FilterList] + NextToken: String | None + MaxResults: DescribeVpcPeeringConnectionsMaxResults | None + DryRun: Boolean | None + VpcPeeringConnectionIds: VpcPeeringConnectionIdList | None + Filters: FilterList | None -VpcPeeringConnectionList = List[VpcPeeringConnection] +VpcPeeringConnectionList = list[VpcPeeringConnection] class DescribeVpcPeeringConnectionsResult(TypedDict, total=False): - VpcPeeringConnections: Optional[VpcPeeringConnectionList] - NextToken: Optional[String] - - -VpcIdStringList = List[VpcId] + VpcPeeringConnections: VpcPeeringConnectionList | None + NextToken: String | None class DescribeVpcsRequest(ServiceRequest): - Filters: Optional[FilterList] - VpcIds: Optional[VpcIdStringList] - NextToken: Optional[String] - MaxResults: Optional[DescribeVpcsMaxResults] - DryRun: Optional[Boolean] + Filters: FilterList | None + VpcIds: VpcIdStringList | None + NextToken: String | None + MaxResults: DescribeVpcsMaxResults | None + DryRun: Boolean | None -VpcList = List[Vpc] +VpcList = list[Vpc] class DescribeVpcsResult(TypedDict, total=False): - NextToken: Optional[String] - Vpcs: Optional[VpcList] + NextToken: String | None + Vpcs: VpcList | None + + +VpnConcentratorIdStringList = list[VpnConcentratorId] + +class DescribeVpnConcentratorsRequest(ServiceRequest): + VpnConcentratorIds: VpnConcentratorIdStringList | None + Filters: FilterList | None + MaxResults: GVCDMaxResults | None + NextToken: NextToken | None + DryRun: Boolean | None -VpnConnectionIdStringList = List[VpnConnectionId] + +VpnConcentratorList = list[VpnConcentrator] + + +class DescribeVpnConcentratorsResult(TypedDict, total=False): + VpnConcentrators: VpnConcentratorList | None + NextToken: NextToken | None + + +VpnConnectionIdStringList = list[VpnConnectionId] class DescribeVpnConnectionsRequest(ServiceRequest): - Filters: Optional[FilterList] - VpnConnectionIds: Optional[VpnConnectionIdStringList] - DryRun: Optional[Boolean] + Filters: FilterList | None + VpnConnectionIds: VpnConnectionIdStringList | None + DryRun: Boolean | None -VpnConnectionList = List[VpnConnection] +VpnConnectionList = list[VpnConnection] class DescribeVpnConnectionsResult(TypedDict, total=False): - VpnConnections: Optional[VpnConnectionList] + VpnConnections: VpnConnectionList | None -VpnGatewayIdStringList = List[VpnGatewayId] +VpnGatewayIdStringList = list[VpnGatewayId] class DescribeVpnGatewaysRequest(ServiceRequest): - Filters: Optional[FilterList] - VpnGatewayIds: Optional[VpnGatewayIdStringList] - DryRun: Optional[Boolean] + Filters: FilterList | None + VpnGatewayIds: VpnGatewayIdStringList | None + DryRun: Boolean | None -VpnGatewayList = List[VpnGateway] +VpnGatewayList = list[VpnGateway] class DescribeVpnGatewaysResult(TypedDict, total=False): - VpnGateways: Optional[VpnGatewayList] + VpnGateways: VpnGatewayList | None class DetachClassicLinkVpcRequest(ServiceRequest): - DryRun: Optional[Boolean] + DryRun: Boolean | None InstanceId: InstanceId VpcId: VpcId class DetachClassicLinkVpcResult(TypedDict, total=False): - Return: Optional[Boolean] + Return: Boolean | None class DetachInternetGatewayRequest(ServiceRequest): - DryRun: Optional[Boolean] + DryRun: Boolean | None InternetGatewayId: InternetGatewayId VpcId: VpcId class DetachNetworkInterfaceRequest(ServiceRequest): - DryRun: Optional[Boolean] + DryRun: Boolean | None AttachmentId: NetworkInterfaceAttachmentId - Force: Optional[Boolean] + Force: Boolean | None class DetachVerifiedAccessTrustProviderRequest(ServiceRequest): VerifiedAccessInstanceId: VerifiedAccessInstanceId VerifiedAccessTrustProviderId: VerifiedAccessTrustProviderId - ClientToken: Optional[String] - DryRun: Optional[Boolean] + ClientToken: String | None + DryRun: Boolean | None class DetachVerifiedAccessTrustProviderResult(TypedDict, total=False): - VerifiedAccessTrustProvider: Optional[VerifiedAccessTrustProvider] - VerifiedAccessInstance: Optional[VerifiedAccessInstance] + VerifiedAccessTrustProvider: VerifiedAccessTrustProvider | None + VerifiedAccessInstance: VerifiedAccessInstance | None class DetachVolumeRequest(ServiceRequest): - Device: Optional[String] - Force: Optional[Boolean] - InstanceId: Optional[InstanceIdForResolver] + Device: String | None + Force: Boolean | None + InstanceId: InstanceIdForResolver | None VolumeId: VolumeIdWithResolver - DryRun: Optional[Boolean] + DryRun: Boolean | None class DetachVpnGatewayRequest(ServiceRequest): VpcId: VpcId VpnGatewayId: VpnGatewayId - DryRun: Optional[Boolean] + DryRun: Boolean | None -DeviceTrustProviderTypeList = List[DeviceTrustProviderType] +DeviceTrustProviderTypeList = list[DeviceTrustProviderType] class DisableAddressTransferRequest(ServiceRequest): AllocationId: AllocationId - DryRun: Optional[Boolean] + DryRun: Boolean | None class DisableAddressTransferResult(TypedDict, total=False): - AddressTransfer: Optional[AddressTransfer] + AddressTransfer: AddressTransfer | None class DisableAllowedImagesSettingsRequest(ServiceRequest): - DryRun: Optional[Boolean] + DryRun: Boolean | None class DisableAllowedImagesSettingsResult(TypedDict, total=False): - AllowedImagesSettingsState: Optional[AllowedImagesSettingsDisabledState] + AllowedImagesSettingsState: AllowedImagesSettingsDisabledState | None class DisableAwsNetworkPerformanceMetricSubscriptionRequest(ServiceRequest): - Source: Optional[String] - Destination: Optional[String] - Metric: Optional[MetricType] - Statistic: Optional[StatisticType] - DryRun: Optional[Boolean] + Source: String | None + Destination: String | None + Metric: MetricType | None + Statistic: StatisticType | None + DryRun: Boolean | None class DisableAwsNetworkPerformanceMetricSubscriptionResult(TypedDict, total=False): - Output: Optional[Boolean] + Output: Boolean | None + + +class DisableCapacityManagerRequest(ServiceRequest): + DryRun: Boolean | None + ClientToken: String | None + + +class DisableCapacityManagerResult(TypedDict, total=False): + CapacityManagerStatus: CapacityManagerStatus | None + OrganizationsAccess: Boolean | None class DisableEbsEncryptionByDefaultRequest(ServiceRequest): - DryRun: Optional[Boolean] + DryRun: Boolean | None class DisableEbsEncryptionByDefaultResult(TypedDict, total=False): - EbsEncryptionByDefault: Optional[Boolean] + EbsEncryptionByDefault: Boolean | None class DisableFastLaunchRequest(ServiceRequest): ImageId: ImageId - Force: Optional[Boolean] - DryRun: Optional[Boolean] + Force: Boolean | None + DryRun: Boolean | None class DisableFastLaunchResult(TypedDict, total=False): - ImageId: Optional[ImageId] - ResourceType: Optional[FastLaunchResourceType] - SnapshotConfiguration: Optional[FastLaunchSnapshotConfigurationResponse] - LaunchTemplate: Optional[FastLaunchLaunchTemplateSpecificationResponse] - MaxParallelLaunches: Optional[Integer] - OwnerId: Optional[String] - State: Optional[FastLaunchStateCode] - StateTransitionReason: Optional[String] - StateTransitionTime: Optional[MillisecondDateTime] + ImageId: ImageId | None + ResourceType: FastLaunchResourceType | None + SnapshotConfiguration: FastLaunchSnapshotConfigurationResponse | None + LaunchTemplate: FastLaunchLaunchTemplateSpecificationResponse | None + MaxParallelLaunches: Integer | None + OwnerId: String | None + State: FastLaunchStateCode | None + StateTransitionReason: String | None + StateTransitionTime: MillisecondDateTime | None class DisableFastSnapshotRestoreStateError(TypedDict, total=False): - Code: Optional[String] - Message: Optional[String] + Code: String | None + Message: String | None class DisableFastSnapshotRestoreStateErrorItem(TypedDict, total=False): - AvailabilityZone: Optional[String] - Error: Optional[DisableFastSnapshotRestoreStateError] + AvailabilityZone: String | None + AvailabilityZoneId: String | None + Error: DisableFastSnapshotRestoreStateError | None -DisableFastSnapshotRestoreStateErrorSet = List[DisableFastSnapshotRestoreStateErrorItem] +DisableFastSnapshotRestoreStateErrorSet = list[DisableFastSnapshotRestoreStateErrorItem] class DisableFastSnapshotRestoreErrorItem(TypedDict, total=False): - SnapshotId: Optional[String] - FastSnapshotRestoreStateErrors: Optional[DisableFastSnapshotRestoreStateErrorSet] + SnapshotId: String | None + FastSnapshotRestoreStateErrors: DisableFastSnapshotRestoreStateErrorSet | None -DisableFastSnapshotRestoreErrorSet = List[DisableFastSnapshotRestoreErrorItem] +DisableFastSnapshotRestoreErrorSet = list[DisableFastSnapshotRestoreErrorItem] class DisableFastSnapshotRestoreSuccessItem(TypedDict, total=False): - SnapshotId: Optional[String] - AvailabilityZone: Optional[String] - State: Optional[FastSnapshotRestoreStateCode] - StateTransitionReason: Optional[String] - OwnerId: Optional[String] - OwnerAlias: Optional[String] - EnablingTime: Optional[MillisecondDateTime] - OptimizingTime: Optional[MillisecondDateTime] - EnabledTime: Optional[MillisecondDateTime] - DisablingTime: Optional[MillisecondDateTime] - DisabledTime: Optional[MillisecondDateTime] + SnapshotId: String | None + AvailabilityZone: String | None + AvailabilityZoneId: String | None + State: FastSnapshotRestoreStateCode | None + StateTransitionReason: String | None + OwnerId: String | None + OwnerAlias: String | None + EnablingTime: MillisecondDateTime | None + OptimizingTime: MillisecondDateTime | None + EnabledTime: MillisecondDateTime | None + DisablingTime: MillisecondDateTime | None + DisabledTime: MillisecondDateTime | None -DisableFastSnapshotRestoreSuccessSet = List[DisableFastSnapshotRestoreSuccessItem] +DisableFastSnapshotRestoreSuccessSet = list[DisableFastSnapshotRestoreSuccessItem] class DisableFastSnapshotRestoresRequest(ServiceRequest): - AvailabilityZones: AvailabilityZoneStringList + AvailabilityZones: AvailabilityZoneStringList | None + AvailabilityZoneIds: AvailabilityZoneIdStringList | None SourceSnapshotIds: SnapshotIdStringList - DryRun: Optional[Boolean] + DryRun: Boolean | None class DisableFastSnapshotRestoresResult(TypedDict, total=False): - Successful: Optional[DisableFastSnapshotRestoreSuccessSet] - Unsuccessful: Optional[DisableFastSnapshotRestoreErrorSet] + Successful: DisableFastSnapshotRestoreSuccessSet | None + Unsuccessful: DisableFastSnapshotRestoreErrorSet | None class DisableImageBlockPublicAccessRequest(ServiceRequest): - DryRun: Optional[Boolean] + DryRun: Boolean | None class DisableImageBlockPublicAccessResult(TypedDict, total=False): - ImageBlockPublicAccessState: Optional[ImageBlockPublicAccessDisabledState] + ImageBlockPublicAccessState: ImageBlockPublicAccessDisabledState | None class DisableImageDeprecationRequest(ServiceRequest): ImageId: ImageId - DryRun: Optional[Boolean] + DryRun: Boolean | None class DisableImageDeprecationResult(TypedDict, total=False): - Return: Optional[Boolean] + Return: Boolean | None class DisableImageDeregistrationProtectionRequest(ServiceRequest): ImageId: ImageId - DryRun: Optional[Boolean] + DryRun: Boolean | None class DisableImageDeregistrationProtectionResult(TypedDict, total=False): - Return: Optional[String] + Return: String | None class DisableImageRequest(ServiceRequest): ImageId: ImageId - DryRun: Optional[Boolean] + DryRun: Boolean | None class DisableImageResult(TypedDict, total=False): - Return: Optional[Boolean] + Return: Boolean | None + + +InstanceIdUpdateStringList = list[InstanceId] + + +class DisableInstanceSqlHaStandbyDetectionsRequest(ServiceRequest): + InstanceIds: InstanceIdUpdateStringList + DryRun: Boolean | None + + +class DisableInstanceSqlHaStandbyDetectionsResult(TypedDict, total=False): + Instances: RegisteredInstanceList | None class DisableIpamOrganizationAdminAccountRequest(ServiceRequest): - DryRun: Optional[Boolean] + DryRun: Boolean | None DelegatedAdminAccountId: String class DisableIpamOrganizationAdminAccountResult(TypedDict, total=False): - Success: Optional[Boolean] + Success: Boolean | None + + +class DisableIpamPolicyRequest(ServiceRequest): + DryRun: Boolean | None + IpamPolicyId: IpamPolicyId + OrganizationTargetId: String | None + + +class DisableIpamPolicyResult(TypedDict, total=False): + Return: Boolean | None class DisableRouteServerPropagationRequest(ServiceRequest): RouteServerId: RouteServerId RouteTableId: RouteTableId - DryRun: Optional[Boolean] + DryRun: Boolean | None class RouteServerPropagation(TypedDict, total=False): - RouteServerId: Optional[RouteServerId] - RouteTableId: Optional[RouteTableId] - State: Optional[RouteServerPropagationState] + RouteServerId: RouteServerId | None + RouteTableId: RouteTableId | None + State: RouteServerPropagationState | None class DisableRouteServerPropagationResult(TypedDict, total=False): - RouteServerPropagation: Optional[RouteServerPropagation] + RouteServerPropagation: RouteServerPropagation | None class DisableSerialConsoleAccessRequest(ServiceRequest): - DryRun: Optional[Boolean] + DryRun: Boolean | None class DisableSerialConsoleAccessResult(TypedDict, total=False): - SerialConsoleAccessEnabled: Optional[Boolean] + SerialConsoleAccessEnabled: Boolean | None class DisableSnapshotBlockPublicAccessRequest(ServiceRequest): - DryRun: Optional[Boolean] + DryRun: Boolean | None class DisableSnapshotBlockPublicAccessResult(TypedDict, total=False): - State: Optional[SnapshotBlockPublicAccessState] + State: SnapshotBlockPublicAccessState | None class DisableTransitGatewayRouteTablePropagationRequest(ServiceRequest): TransitGatewayRouteTableId: TransitGatewayRouteTableId - TransitGatewayAttachmentId: Optional[TransitGatewayAttachmentId] - DryRun: Optional[Boolean] - TransitGatewayRouteTableAnnouncementId: Optional[TransitGatewayRouteTableAnnouncementId] + TransitGatewayAttachmentId: TransitGatewayAttachmentId | None + DryRun: Boolean | None + TransitGatewayRouteTableAnnouncementId: TransitGatewayRouteTableAnnouncementId | None class TransitGatewayPropagation(TypedDict, total=False): - TransitGatewayAttachmentId: Optional[TransitGatewayAttachmentId] - ResourceId: Optional[String] - ResourceType: Optional[TransitGatewayAttachmentResourceType] - TransitGatewayRouteTableId: Optional[String] - State: Optional[TransitGatewayPropagationState] - TransitGatewayRouteTableAnnouncementId: Optional[TransitGatewayRouteTableAnnouncementId] + TransitGatewayAttachmentId: TransitGatewayAttachmentId | None + ResourceId: String | None + ResourceType: TransitGatewayAttachmentResourceType | None + TransitGatewayRouteTableId: String | None + State: TransitGatewayPropagationState | None + TransitGatewayRouteTableAnnouncementId: TransitGatewayRouteTableAnnouncementId | None class DisableTransitGatewayRouteTablePropagationResult(TypedDict, total=False): - Propagation: Optional[TransitGatewayPropagation] + Propagation: TransitGatewayPropagation | None class DisableVgwRoutePropagationRequest(ServiceRequest): GatewayId: VpnGatewayId RouteTableId: RouteTableId - DryRun: Optional[Boolean] + DryRun: Boolean | None class DisableVpcClassicLinkDnsSupportRequest(ServiceRequest): - VpcId: Optional[VpcId] + VpcId: VpcId | None class DisableVpcClassicLinkDnsSupportResult(TypedDict, total=False): - Return: Optional[Boolean] + Return: Boolean | None class DisableVpcClassicLinkRequest(ServiceRequest): - DryRun: Optional[Boolean] + DryRun: Boolean | None VpcId: VpcId class DisableVpcClassicLinkResult(TypedDict, total=False): - Return: Optional[Boolean] + Return: Boolean | None class DisassociateAddressRequest(ServiceRequest): - AssociationId: Optional[ElasticIpAssociationId] - PublicIp: Optional[EipAllocationPublicIp] - DryRun: Optional[Boolean] + AssociationId: ElasticIpAssociationId | None + PublicIp: EipAllocationPublicIp | None + DryRun: Boolean | None class DisassociateCapacityReservationBillingOwnerRequest(ServiceRequest): - DryRun: Optional[Boolean] + DryRun: Boolean | None CapacityReservationId: CapacityReservationId UnusedReservationBillingOwnerId: AccountID class DisassociateCapacityReservationBillingOwnerResult(TypedDict, total=False): - Return: Optional[Boolean] + Return: Boolean | None class DisassociateClientVpnTargetNetworkRequest(ServiceRequest): ClientVpnEndpointId: ClientVpnEndpointId AssociationId: String - DryRun: Optional[Boolean] + DryRun: Boolean | None class DisassociateClientVpnTargetNetworkResult(TypedDict, total=False): - AssociationId: Optional[String] - Status: Optional[AssociationStatus] + AssociationId: String | None + Status: AssociationStatus | None class DisassociateEnclaveCertificateIamRoleRequest(ServiceRequest): CertificateArn: CertificateId RoleArn: RoleId - DryRun: Optional[Boolean] + DryRun: Boolean | None class DisassociateEnclaveCertificateIamRoleResult(TypedDict, total=False): - Return: Optional[Boolean] + Return: Boolean | None class DisassociateIamInstanceProfileRequest(ServiceRequest): @@ -16885,82 +18556,82 @@ class DisassociateIamInstanceProfileRequest(ServiceRequest): class DisassociateIamInstanceProfileResult(TypedDict, total=False): - IamInstanceProfileAssociation: Optional[IamInstanceProfileAssociation] + IamInstanceProfileAssociation: IamInstanceProfileAssociation | None class InstanceEventWindowDisassociationRequest(TypedDict, total=False): - InstanceIds: Optional[InstanceIdList] - InstanceTags: Optional[TagList] - DedicatedHostIds: Optional[DedicatedHostIdList] + InstanceIds: InstanceIdList | None + InstanceTags: TagList | None + DedicatedHostIds: DedicatedHostIdList | None class DisassociateInstanceEventWindowRequest(ServiceRequest): - DryRun: Optional[Boolean] + DryRun: Boolean | None InstanceEventWindowId: InstanceEventWindowId AssociationTarget: InstanceEventWindowDisassociationRequest class DisassociateInstanceEventWindowResult(TypedDict, total=False): - InstanceEventWindow: Optional[InstanceEventWindow] + InstanceEventWindow: InstanceEventWindow | None class DisassociateIpamByoasnRequest(ServiceRequest): - DryRun: Optional[Boolean] + DryRun: Boolean | None Asn: String Cidr: String class DisassociateIpamByoasnResult(TypedDict, total=False): - AsnAssociation: Optional[AsnAssociation] + AsnAssociation: AsnAssociation | None class DisassociateIpamResourceDiscoveryRequest(ServiceRequest): - DryRun: Optional[Boolean] + DryRun: Boolean | None IpamResourceDiscoveryAssociationId: IpamResourceDiscoveryAssociationId class DisassociateIpamResourceDiscoveryResult(TypedDict, total=False): - IpamResourceDiscoveryAssociation: Optional[IpamResourceDiscoveryAssociation] + IpamResourceDiscoveryAssociation: IpamResourceDiscoveryAssociation | None -EipAssociationIdList = List[ElasticIpAssociationId] +EipAssociationIdList = list[ElasticIpAssociationId] class DisassociateNatGatewayAddressRequest(ServiceRequest): NatGatewayId: NatGatewayId AssociationIds: EipAssociationIdList - MaxDrainDurationSeconds: Optional[DrainSeconds] - DryRun: Optional[Boolean] + MaxDrainDurationSeconds: DrainSeconds | None + DryRun: Boolean | None class DisassociateNatGatewayAddressResult(TypedDict, total=False): - NatGatewayId: Optional[NatGatewayId] - NatGatewayAddresses: Optional[NatGatewayAddressList] + NatGatewayId: NatGatewayId | None + NatGatewayAddresses: NatGatewayAddressList | None class DisassociateRouteServerRequest(ServiceRequest): RouteServerId: RouteServerId VpcId: VpcId - DryRun: Optional[Boolean] + DryRun: Boolean | None class DisassociateRouteServerResult(TypedDict, total=False): - RouteServerAssociation: Optional[RouteServerAssociation] + RouteServerAssociation: RouteServerAssociation | None class DisassociateRouteTableRequest(ServiceRequest): - DryRun: Optional[Boolean] + DryRun: Boolean | None AssociationId: RouteTableAssociationId class DisassociateSecurityGroupVpcRequest(ServiceRequest): GroupId: DisassociateSecurityGroupVpcSecurityGroupId VpcId: String - DryRun: Optional[Boolean] + DryRun: Boolean | None class DisassociateSecurityGroupVpcResult(TypedDict, total=False): - State: Optional[SecurityGroupVpcAssociationState] + State: SecurityGroupVpcAssociationState | None class DisassociateSubnetCidrBlockRequest(ServiceRequest): @@ -16968,50 +18639,50 @@ class DisassociateSubnetCidrBlockRequest(ServiceRequest): class DisassociateSubnetCidrBlockResult(TypedDict, total=False): - Ipv6CidrBlockAssociation: Optional[SubnetIpv6CidrBlockAssociation] - SubnetId: Optional[String] + Ipv6CidrBlockAssociation: SubnetIpv6CidrBlockAssociation | None + SubnetId: String | None class DisassociateTransitGatewayMulticastDomainRequest(ServiceRequest): TransitGatewayMulticastDomainId: TransitGatewayMulticastDomainId TransitGatewayAttachmentId: TransitGatewayAttachmentId SubnetIds: TransitGatewaySubnetIdList - DryRun: Optional[Boolean] + DryRun: Boolean | None class DisassociateTransitGatewayMulticastDomainResult(TypedDict, total=False): - Associations: Optional[TransitGatewayMulticastDomainAssociations] + Associations: TransitGatewayMulticastDomainAssociations | None class DisassociateTransitGatewayPolicyTableRequest(ServiceRequest): TransitGatewayPolicyTableId: TransitGatewayPolicyTableId TransitGatewayAttachmentId: TransitGatewayAttachmentId - DryRun: Optional[Boolean] + DryRun: Boolean | None class DisassociateTransitGatewayPolicyTableResult(TypedDict, total=False): - Association: Optional[TransitGatewayPolicyTableAssociation] + Association: TransitGatewayPolicyTableAssociation | None class DisassociateTransitGatewayRouteTableRequest(ServiceRequest): TransitGatewayRouteTableId: TransitGatewayRouteTableId TransitGatewayAttachmentId: TransitGatewayAttachmentId - DryRun: Optional[Boolean] + DryRun: Boolean | None class DisassociateTransitGatewayRouteTableResult(TypedDict, total=False): - Association: Optional[TransitGatewayAssociation] + Association: TransitGatewayAssociation | None class DisassociateTrunkInterfaceRequest(ServiceRequest): AssociationId: TrunkInterfaceAssociationId - ClientToken: Optional[String] - DryRun: Optional[Boolean] + ClientToken: String | None + DryRun: Boolean | None class DisassociateTrunkInterfaceResult(TypedDict, total=False): - Return: Optional[Boolean] - ClientToken: Optional[String] + Return: Boolean | None + ClientToken: String | None class DisassociateVpcCidrBlockRequest(ServiceRequest): @@ -17019,9 +18690,9 @@ class DisassociateVpcCidrBlockRequest(ServiceRequest): class DisassociateVpcCidrBlockResult(TypedDict, total=False): - Ipv6CidrBlockAssociation: Optional[VpcIpv6CidrBlockAssociation] - CidrBlockAssociation: Optional[VpcCidrBlockAssociation] - VpcId: Optional[String] + Ipv6CidrBlockAssociation: VpcIpv6CidrBlockAssociation | None + CidrBlockAssociation: VpcCidrBlockAssociation | None + VpcId: String | None class VolumeDetail(TypedDict, total=False): @@ -17035,602 +18706,720 @@ class DiskImageDetail(TypedDict, total=False): class DiskImage(TypedDict, total=False): - Description: Optional[String] - Image: Optional[DiskImageDetail] - Volume: Optional[VolumeDetail] + Description: String | None + Image: DiskImageDetail | None + Volume: VolumeDetail | None -DiskImageList = List[DiskImage] +DiskImageList = list[DiskImage] class DnsServersOptionsModifyStructure(TypedDict, total=False): - CustomDnsServers: Optional[ValueStringList] - Enabled: Optional[Boolean] + CustomDnsServers: ValueStringList | None + Enabled: Boolean | None class EbsInstanceBlockDeviceSpecification(TypedDict, total=False): - VolumeId: Optional[VolumeId] - DeleteOnTermination: Optional[Boolean] + VolumeId: VolumeId | None + DeleteOnTermination: Boolean | None -ElasticGpuSpecifications = List[ElasticGpuSpecification] +ElasticGpuSpecifications = list[ElasticGpuSpecification] class ElasticInferenceAccelerator(TypedDict, total=False): Type: String - Count: Optional[ElasticInferenceAcceleratorCount] + Count: ElasticInferenceAcceleratorCount | None -ElasticInferenceAccelerators = List[ElasticInferenceAccelerator] +ElasticInferenceAccelerators = list[ElasticInferenceAccelerator] class EnableAddressTransferRequest(ServiceRequest): AllocationId: AllocationId TransferAccountId: String - DryRun: Optional[Boolean] + DryRun: Boolean | None class EnableAddressTransferResult(TypedDict, total=False): - AddressTransfer: Optional[AddressTransfer] + AddressTransfer: AddressTransfer | None class EnableAllowedImagesSettingsRequest(ServiceRequest): AllowedImagesSettingsState: AllowedImagesSettingsEnabledState - DryRun: Optional[Boolean] + DryRun: Boolean | None class EnableAllowedImagesSettingsResult(TypedDict, total=False): - AllowedImagesSettingsState: Optional[AllowedImagesSettingsEnabledState] + AllowedImagesSettingsState: AllowedImagesSettingsEnabledState | None class EnableAwsNetworkPerformanceMetricSubscriptionRequest(ServiceRequest): - Source: Optional[String] - Destination: Optional[String] - Metric: Optional[MetricType] - Statistic: Optional[StatisticType] - DryRun: Optional[Boolean] + Source: String | None + Destination: String | None + Metric: MetricType | None + Statistic: StatisticType | None + DryRun: Boolean | None class EnableAwsNetworkPerformanceMetricSubscriptionResult(TypedDict, total=False): - Output: Optional[Boolean] + Output: Boolean | None + + +class EnableCapacityManagerRequest(ServiceRequest): + OrganizationsAccess: Boolean | None + DryRun: Boolean | None + ClientToken: String | None + + +class EnableCapacityManagerResult(TypedDict, total=False): + CapacityManagerStatus: CapacityManagerStatus | None + OrganizationsAccess: Boolean | None class EnableEbsEncryptionByDefaultRequest(ServiceRequest): - DryRun: Optional[Boolean] + DryRun: Boolean | None class EnableEbsEncryptionByDefaultResult(TypedDict, total=False): - EbsEncryptionByDefault: Optional[Boolean] + EbsEncryptionByDefault: Boolean | None class FastLaunchLaunchTemplateSpecificationRequest(TypedDict, total=False): - LaunchTemplateId: Optional[LaunchTemplateId] - LaunchTemplateName: Optional[String] + LaunchTemplateId: LaunchTemplateId | None + LaunchTemplateName: String | None Version: String class FastLaunchSnapshotConfigurationRequest(TypedDict, total=False): - TargetResourceCount: Optional[Integer] + TargetResourceCount: Integer | None class EnableFastLaunchRequest(ServiceRequest): ImageId: ImageId - ResourceType: Optional[String] - SnapshotConfiguration: Optional[FastLaunchSnapshotConfigurationRequest] - LaunchTemplate: Optional[FastLaunchLaunchTemplateSpecificationRequest] - MaxParallelLaunches: Optional[Integer] - DryRun: Optional[Boolean] + ResourceType: String | None + SnapshotConfiguration: FastLaunchSnapshotConfigurationRequest | None + LaunchTemplate: FastLaunchLaunchTemplateSpecificationRequest | None + MaxParallelLaunches: Integer | None + DryRun: Boolean | None class EnableFastLaunchResult(TypedDict, total=False): - ImageId: Optional[ImageId] - ResourceType: Optional[FastLaunchResourceType] - SnapshotConfiguration: Optional[FastLaunchSnapshotConfigurationResponse] - LaunchTemplate: Optional[FastLaunchLaunchTemplateSpecificationResponse] - MaxParallelLaunches: Optional[Integer] - OwnerId: Optional[String] - State: Optional[FastLaunchStateCode] - StateTransitionReason: Optional[String] - StateTransitionTime: Optional[MillisecondDateTime] + ImageId: ImageId | None + ResourceType: FastLaunchResourceType | None + SnapshotConfiguration: FastLaunchSnapshotConfigurationResponse | None + LaunchTemplate: FastLaunchLaunchTemplateSpecificationResponse | None + MaxParallelLaunches: Integer | None + OwnerId: String | None + State: FastLaunchStateCode | None + StateTransitionReason: String | None + StateTransitionTime: MillisecondDateTime | None class EnableFastSnapshotRestoreStateError(TypedDict, total=False): - Code: Optional[String] - Message: Optional[String] + Code: String | None + Message: String | None class EnableFastSnapshotRestoreStateErrorItem(TypedDict, total=False): - AvailabilityZone: Optional[String] - Error: Optional[EnableFastSnapshotRestoreStateError] + AvailabilityZone: String | None + AvailabilityZoneId: String | None + Error: EnableFastSnapshotRestoreStateError | None -EnableFastSnapshotRestoreStateErrorSet = List[EnableFastSnapshotRestoreStateErrorItem] +EnableFastSnapshotRestoreStateErrorSet = list[EnableFastSnapshotRestoreStateErrorItem] class EnableFastSnapshotRestoreErrorItem(TypedDict, total=False): - SnapshotId: Optional[String] - FastSnapshotRestoreStateErrors: Optional[EnableFastSnapshotRestoreStateErrorSet] + SnapshotId: String | None + FastSnapshotRestoreStateErrors: EnableFastSnapshotRestoreStateErrorSet | None -EnableFastSnapshotRestoreErrorSet = List[EnableFastSnapshotRestoreErrorItem] +EnableFastSnapshotRestoreErrorSet = list[EnableFastSnapshotRestoreErrorItem] class EnableFastSnapshotRestoreSuccessItem(TypedDict, total=False): - SnapshotId: Optional[String] - AvailabilityZone: Optional[String] - State: Optional[FastSnapshotRestoreStateCode] - StateTransitionReason: Optional[String] - OwnerId: Optional[String] - OwnerAlias: Optional[String] - EnablingTime: Optional[MillisecondDateTime] - OptimizingTime: Optional[MillisecondDateTime] - EnabledTime: Optional[MillisecondDateTime] - DisablingTime: Optional[MillisecondDateTime] - DisabledTime: Optional[MillisecondDateTime] + SnapshotId: String | None + AvailabilityZone: String | None + AvailabilityZoneId: String | None + State: FastSnapshotRestoreStateCode | None + StateTransitionReason: String | None + OwnerId: String | None + OwnerAlias: String | None + EnablingTime: MillisecondDateTime | None + OptimizingTime: MillisecondDateTime | None + EnabledTime: MillisecondDateTime | None + DisablingTime: MillisecondDateTime | None + DisabledTime: MillisecondDateTime | None -EnableFastSnapshotRestoreSuccessSet = List[EnableFastSnapshotRestoreSuccessItem] +EnableFastSnapshotRestoreSuccessSet = list[EnableFastSnapshotRestoreSuccessItem] class EnableFastSnapshotRestoresRequest(ServiceRequest): - AvailabilityZones: AvailabilityZoneStringList + AvailabilityZones: AvailabilityZoneStringList | None + AvailabilityZoneIds: AvailabilityZoneIdStringList | None SourceSnapshotIds: SnapshotIdStringList - DryRun: Optional[Boolean] + DryRun: Boolean | None class EnableFastSnapshotRestoresResult(TypedDict, total=False): - Successful: Optional[EnableFastSnapshotRestoreSuccessSet] - Unsuccessful: Optional[EnableFastSnapshotRestoreErrorSet] + Successful: EnableFastSnapshotRestoreSuccessSet | None + Unsuccessful: EnableFastSnapshotRestoreErrorSet | None class EnableImageBlockPublicAccessRequest(ServiceRequest): ImageBlockPublicAccessState: ImageBlockPublicAccessEnabledState - DryRun: Optional[Boolean] + DryRun: Boolean | None class EnableImageBlockPublicAccessResult(TypedDict, total=False): - ImageBlockPublicAccessState: Optional[ImageBlockPublicAccessEnabledState] + ImageBlockPublicAccessState: ImageBlockPublicAccessEnabledState | None class EnableImageDeprecationRequest(ServiceRequest): ImageId: ImageId DeprecateAt: MillisecondDateTime - DryRun: Optional[Boolean] + DryRun: Boolean | None class EnableImageDeprecationResult(TypedDict, total=False): - Return: Optional[Boolean] + Return: Boolean | None class EnableImageDeregistrationProtectionRequest(ServiceRequest): ImageId: ImageId - WithCooldown: Optional[Boolean] - DryRun: Optional[Boolean] + WithCooldown: Boolean | None + DryRun: Boolean | None class EnableImageDeregistrationProtectionResult(TypedDict, total=False): - Return: Optional[String] + Return: String | None class EnableImageRequest(ServiceRequest): ImageId: ImageId - DryRun: Optional[Boolean] + DryRun: Boolean | None class EnableImageResult(TypedDict, total=False): - Return: Optional[Boolean] + Return: Boolean | None + + +class EnableInstanceSqlHaStandbyDetectionsRequest(ServiceRequest): + InstanceIds: InstanceIdUpdateStringList + SqlServerCredentials: SecretArn | None + DryRun: Boolean | None + + +class EnableInstanceSqlHaStandbyDetectionsResult(TypedDict, total=False): + Instances: RegisteredInstanceList | None class EnableIpamOrganizationAdminAccountRequest(ServiceRequest): - DryRun: Optional[Boolean] + DryRun: Boolean | None DelegatedAdminAccountId: String class EnableIpamOrganizationAdminAccountResult(TypedDict, total=False): - Success: Optional[Boolean] + Success: Boolean | None + + +class EnableIpamPolicyRequest(ServiceRequest): + DryRun: Boolean | None + IpamPolicyId: IpamPolicyId + OrganizationTargetId: String | None + + +class EnableIpamPolicyResult(TypedDict, total=False): + IpamPolicyId: IpamPolicyId | None class EnableReachabilityAnalyzerOrganizationSharingRequest(ServiceRequest): - DryRun: Optional[Boolean] + DryRun: Boolean | None class EnableReachabilityAnalyzerOrganizationSharingResult(TypedDict, total=False): - ReturnValue: Optional[Boolean] + ReturnValue: Boolean | None class EnableRouteServerPropagationRequest(ServiceRequest): RouteServerId: RouteServerId RouteTableId: RouteTableId - DryRun: Optional[Boolean] + DryRun: Boolean | None class EnableRouteServerPropagationResult(TypedDict, total=False): - RouteServerPropagation: Optional[RouteServerPropagation] + RouteServerPropagation: RouteServerPropagation | None class EnableSerialConsoleAccessRequest(ServiceRequest): - DryRun: Optional[Boolean] + DryRun: Boolean | None class EnableSerialConsoleAccessResult(TypedDict, total=False): - SerialConsoleAccessEnabled: Optional[Boolean] + SerialConsoleAccessEnabled: Boolean | None class EnableSnapshotBlockPublicAccessRequest(ServiceRequest): State: SnapshotBlockPublicAccessState - DryRun: Optional[Boolean] + DryRun: Boolean | None class EnableSnapshotBlockPublicAccessResult(TypedDict, total=False): - State: Optional[SnapshotBlockPublicAccessState] + State: SnapshotBlockPublicAccessState | None class EnableTransitGatewayRouteTablePropagationRequest(ServiceRequest): TransitGatewayRouteTableId: TransitGatewayRouteTableId - TransitGatewayAttachmentId: Optional[TransitGatewayAttachmentId] - DryRun: Optional[Boolean] - TransitGatewayRouteTableAnnouncementId: Optional[TransitGatewayRouteTableAnnouncementId] + TransitGatewayAttachmentId: TransitGatewayAttachmentId | None + DryRun: Boolean | None + TransitGatewayRouteTableAnnouncementId: TransitGatewayRouteTableAnnouncementId | None class EnableTransitGatewayRouteTablePropagationResult(TypedDict, total=False): - Propagation: Optional[TransitGatewayPropagation] + Propagation: TransitGatewayPropagation | None class EnableVgwRoutePropagationRequest(ServiceRequest): GatewayId: VpnGatewayId RouteTableId: RouteTableId - DryRun: Optional[Boolean] + DryRun: Boolean | None class EnableVolumeIORequest(ServiceRequest): - DryRun: Optional[Boolean] + DryRun: Boolean | None VolumeId: VolumeId class EnableVpcClassicLinkDnsSupportRequest(ServiceRequest): - VpcId: Optional[VpcId] + VpcId: VpcId | None class EnableVpcClassicLinkDnsSupportResult(TypedDict, total=False): - Return: Optional[Boolean] + Return: Boolean | None class EnableVpcClassicLinkRequest(ServiceRequest): - DryRun: Optional[Boolean] + DryRun: Boolean | None VpcId: VpcId class EnableVpcClassicLinkResult(TypedDict, total=False): - Return: Optional[Boolean] + Return: Boolean | None class EnclaveOptionsRequest(TypedDict, total=False): - Enabled: Optional[Boolean] + Enabled: Boolean | None class ExportClientVpnClientCertificateRevocationListRequest(ServiceRequest): ClientVpnEndpointId: ClientVpnEndpointId - DryRun: Optional[Boolean] + DryRun: Boolean | None class ExportClientVpnClientCertificateRevocationListResult(TypedDict, total=False): - CertificateRevocationList: Optional[String] - Status: Optional[ClientCertificateRevocationListStatus] + CertificateRevocationList: String | None + Status: ClientCertificateRevocationListStatus | None class ExportClientVpnClientConfigurationRequest(ServiceRequest): ClientVpnEndpointId: ClientVpnEndpointId - DryRun: Optional[Boolean] + DryRun: Boolean | None class ExportClientVpnClientConfigurationResult(TypedDict, total=False): - ClientConfiguration: Optional[String] + ClientConfiguration: String | None class ExportTaskS3LocationRequest(TypedDict, total=False): S3Bucket: String - S3Prefix: Optional[String] + S3Prefix: String | None class ExportImageRequest(ServiceRequest): - ClientToken: Optional[String] - Description: Optional[String] + ClientToken: String | None + Description: String | None DiskImageFormat: DiskImageFormat - DryRun: Optional[Boolean] + DryRun: Boolean | None ImageId: ImageId S3ExportLocation: ExportTaskS3LocationRequest - RoleName: Optional[String] - TagSpecifications: Optional[TagSpecificationList] + RoleName: String | None + TagSpecifications: TagSpecificationList | None class ExportImageResult(TypedDict, total=False): - Description: Optional[String] - DiskImageFormat: Optional[DiskImageFormat] - ExportImageTaskId: Optional[String] - ImageId: Optional[String] - RoleName: Optional[String] - Progress: Optional[String] - S3ExportLocation: Optional[ExportTaskS3Location] - Status: Optional[String] - StatusMessage: Optional[String] - Tags: Optional[TagList] + Description: String | None + DiskImageFormat: DiskImageFormat | None + ExportImageTaskId: String | None + ImageId: String | None + RoleName: String | None + Progress: String | None + S3ExportLocation: ExportTaskS3Location | None + Status: String | None + StatusMessage: String | None + Tags: TagList | None class ExportTransitGatewayRoutesRequest(ServiceRequest): TransitGatewayRouteTableId: TransitGatewayRouteTableId - Filters: Optional[FilterList] + Filters: FilterList | None S3Bucket: String - DryRun: Optional[Boolean] + DryRun: Boolean | None class ExportTransitGatewayRoutesResult(TypedDict, total=False): - S3Location: Optional[String] + S3Location: String | None class ExportVerifiedAccessInstanceClientConfigurationRequest(ServiceRequest): VerifiedAccessInstanceId: VerifiedAccessInstanceId - DryRun: Optional[Boolean] + DryRun: Boolean | None class VerifiedAccessInstanceOpenVpnClientConfigurationRoute(TypedDict, total=False): - Cidr: Optional[String] + Cidr: String | None -VerifiedAccessInstanceOpenVpnClientConfigurationRouteList = List[ +VerifiedAccessInstanceOpenVpnClientConfigurationRouteList = list[ VerifiedAccessInstanceOpenVpnClientConfigurationRoute ] class VerifiedAccessInstanceOpenVpnClientConfiguration(TypedDict, total=False): - Config: Optional[String] - Routes: Optional[VerifiedAccessInstanceOpenVpnClientConfigurationRouteList] + Config: String | None + Routes: VerifiedAccessInstanceOpenVpnClientConfigurationRouteList | None -VerifiedAccessInstanceOpenVpnClientConfigurationList = List[ +VerifiedAccessInstanceOpenVpnClientConfigurationList = list[ VerifiedAccessInstanceOpenVpnClientConfiguration ] class VerifiedAccessInstanceUserTrustProviderClientConfiguration(TypedDict, total=False): - Type: Optional[UserTrustProviderType] - Scopes: Optional[String] - Issuer: Optional[String] - AuthorizationEndpoint: Optional[String] - PublicSigningKeyEndpoint: Optional[String] - TokenEndpoint: Optional[String] - UserInfoEndpoint: Optional[String] - ClientId: Optional[String] - ClientSecret: Optional[ClientSecretType] - PkceEnabled: Optional[Boolean] + Type: UserTrustProviderType | None + Scopes: String | None + Issuer: String | None + AuthorizationEndpoint: String | None + PublicSigningKeyEndpoint: String | None + TokenEndpoint: String | None + UserInfoEndpoint: String | None + ClientId: String | None + ClientSecret: ClientSecretType | None + PkceEnabled: Boolean | None class ExportVerifiedAccessInstanceClientConfigurationResult(TypedDict, total=False): - Version: Optional[String] - VerifiedAccessInstanceId: Optional[String] - Region: Optional[String] - DeviceTrustProviders: Optional[DeviceTrustProviderTypeList] - UserTrustProvider: Optional[VerifiedAccessInstanceUserTrustProviderClientConfiguration] - OpenVpnConfigurations: Optional[VerifiedAccessInstanceOpenVpnClientConfigurationList] + Version: String | None + VerifiedAccessInstanceId: String | None + Region: String | None + DeviceTrustProviders: DeviceTrustProviderTypeList | None + UserTrustProvider: VerifiedAccessInstanceUserTrustProviderClientConfiguration | None + OpenVpnConfigurations: VerifiedAccessInstanceOpenVpnClientConfigurationList | None class GetActiveVpnTunnelStatusRequest(ServiceRequest): VpnConnectionId: VpnConnectionId VpnTunnelOutsideIpAddress: String - DryRun: Optional[Boolean] + DryRun: Boolean | None class GetActiveVpnTunnelStatusResult(TypedDict, total=False): - ActiveVpnTunnelStatus: Optional[ActiveVpnTunnelStatus] + ActiveVpnTunnelStatus: ActiveVpnTunnelStatus | None class GetAllowedImagesSettingsRequest(ServiceRequest): - DryRun: Optional[Boolean] + DryRun: Boolean | None -ImageNameList = List[ImageName] -MarketplaceProductCodeList = List[MarketplaceProductCode] -ImageProviderList = List[ImageProvider] +ImageNameList = list[ImageName] +MarketplaceProductCodeList = list[MarketplaceProductCode] +ImageProviderList = list[ImageProvider] class ImageCriterion(TypedDict, total=False): - ImageProviders: Optional[ImageProviderList] - MarketplaceProductCodes: Optional[MarketplaceProductCodeList] - ImageNames: Optional[ImageNameList] - DeprecationTimeCondition: Optional[DeprecationTimeCondition] - CreationDateCondition: Optional[CreationDateCondition] + ImageProviders: ImageProviderList | None + MarketplaceProductCodes: MarketplaceProductCodeList | None + ImageNames: ImageNameList | None + DeprecationTimeCondition: DeprecationTimeCondition | None + CreationDateCondition: CreationDateCondition | None -ImageCriterionList = List[ImageCriterion] +ImageCriterionList = list[ImageCriterion] class GetAllowedImagesSettingsResult(TypedDict, total=False): - State: Optional[String] - ImageCriteria: Optional[ImageCriterionList] - ManagedBy: Optional[ManagedBy] + State: String | None + ImageCriteria: ImageCriterionList | None + ManagedBy: ManagedBy | None class GetAssociatedEnclaveCertificateIamRolesRequest(ServiceRequest): CertificateArn: CertificateId - DryRun: Optional[Boolean] + DryRun: Boolean | None class GetAssociatedEnclaveCertificateIamRolesResult(TypedDict, total=False): - AssociatedRoles: Optional[AssociatedRolesList] + AssociatedRoles: AssociatedRolesList | None class GetAssociatedIpv6PoolCidrsRequest(ServiceRequest): PoolId: Ipv6PoolEc2Id - NextToken: Optional[NextToken] - MaxResults: Optional[Ipv6PoolMaxResults] - DryRun: Optional[Boolean] + NextToken: NextToken | None + MaxResults: Ipv6PoolMaxResults | None + DryRun: Boolean | None class Ipv6CidrAssociation(TypedDict, total=False): - Ipv6Cidr: Optional[String] - AssociatedResource: Optional[String] + Ipv6Cidr: String | None + AssociatedResource: String | None -Ipv6CidrAssociationSet = List[Ipv6CidrAssociation] +Ipv6CidrAssociationSet = list[Ipv6CidrAssociation] class GetAssociatedIpv6PoolCidrsResult(TypedDict, total=False): - Ipv6CidrAssociations: Optional[Ipv6CidrAssociationSet] - NextToken: Optional[String] + Ipv6CidrAssociations: Ipv6CidrAssociationSet | None + NextToken: String | None class GetAwsNetworkPerformanceDataRequest(ServiceRequest): - DataQueries: Optional[DataQueries] - StartTime: Optional[MillisecondDateTime] - EndTime: Optional[MillisecondDateTime] - MaxResults: Optional[Integer] - NextToken: Optional[String] - DryRun: Optional[Boolean] + DataQueries: DataQueries | None + StartTime: MillisecondDateTime | None + EndTime: MillisecondDateTime | None + MaxResults: Integer | None + NextToken: String | None + DryRun: Boolean | None class GetAwsNetworkPerformanceDataResult(TypedDict, total=False): - DataResponses: Optional[DataResponses] - NextToken: Optional[String] + DataResponses: DataResponses | None + NextToken: String | None + + +class GetCapacityManagerAttributesRequest(ServiceRequest): + DryRun: Boolean | None + + +class GetCapacityManagerAttributesResult(TypedDict, total=False): + CapacityManagerStatus: CapacityManagerStatus | None + OrganizationsAccess: Boolean | None + DataExportCount: Integer | None + IngestionStatus: IngestionStatus | None + IngestionStatusMessage: String | None + EarliestDatapointTimestamp: MillisecondDateTime | None + LatestDatapointTimestamp: MillisecondDateTime | None + + +GroupBySet = list[GroupBy] +MetricSet = list[Metric] + + +class GetCapacityManagerMetricDataRequest(ServiceRequest): + MetricNames: MetricSet + StartTime: MillisecondDateTime + EndTime: MillisecondDateTime + Period: Period + GroupBy: GroupBySet | None + FilterBy: CapacityManagerConditionSet | None + MaxResults: MaxResults | None + NextToken: NextToken | None + DryRun: Boolean | None + + +class MetricValue(TypedDict, total=False): + Metric: Metric | None + Value: Double | None + + +MetricValueSet = list[MetricValue] + + +class MetricDataResult(TypedDict, total=False): + Dimension: CapacityManagerDimension | None + Timestamp: MillisecondDateTime | None + MetricValues: MetricValueSet | None + + +MetricDataResultSet = list[MetricDataResult] + + +class GetCapacityManagerMetricDataResult(TypedDict, total=False): + MetricDataResults: MetricDataResultSet | None + NextToken: NextToken | None + + +class GetCapacityManagerMetricDimensionsRequest(ServiceRequest): + GroupBy: GroupBySet + FilterBy: CapacityManagerConditionSet | None + StartTime: MillisecondDateTime + EndTime: MillisecondDateTime + MetricNames: MetricSet + MaxResults: MaxResults | None + NextToken: NextToken | None + DryRun: Boolean | None + + +MetricDimensionResultSet = list[CapacityManagerDimension] + + +class GetCapacityManagerMetricDimensionsResult(TypedDict, total=False): + MetricDimensionResults: MetricDimensionResultSet | None + NextToken: NextToken | None class GetCapacityReservationUsageRequest(ServiceRequest): CapacityReservationId: CapacityReservationId - NextToken: Optional[String] - MaxResults: Optional[GetCapacityReservationUsageRequestMaxResults] - DryRun: Optional[Boolean] + NextToken: String | None + MaxResults: GetCapacityReservationUsageRequestMaxResults | None + DryRun: Boolean | None class InstanceUsage(TypedDict, total=False): - AccountId: Optional[String] - UsedInstanceCount: Optional[Integer] + AccountId: String | None + UsedInstanceCount: Integer | None -InstanceUsageSet = List[InstanceUsage] +InstanceUsageSet = list[InstanceUsage] class GetCapacityReservationUsageResult(TypedDict, total=False): - NextToken: Optional[String] - CapacityReservationId: Optional[String] - InstanceType: Optional[String] - TotalInstanceCount: Optional[Integer] - AvailableInstanceCount: Optional[Integer] - State: Optional[CapacityReservationState] - InstanceUsages: Optional[InstanceUsageSet] + NextToken: String | None + CapacityReservationId: String | None + InstanceType: String | None + TotalInstanceCount: Integer | None + AvailableInstanceCount: Integer | None + State: CapacityReservationState | None + InstanceUsages: InstanceUsageSet | None + Interruptible: BoxedBoolean | None + InterruptibleCapacityAllocation: InterruptibleCapacityAllocation | None + InterruptionInfo: InterruptionInfo | None class GetCoipPoolUsageRequest(ServiceRequest): PoolId: Ipv4PoolCoipId - Filters: Optional[FilterList] - MaxResults: Optional[CoipPoolMaxResults] - NextToken: Optional[String] - DryRun: Optional[Boolean] + Filters: FilterList | None + MaxResults: CoipPoolMaxResults | None + NextToken: String | None + DryRun: Boolean | None class GetCoipPoolUsageResult(TypedDict, total=False): - CoipPoolId: Optional[String] - CoipAddressUsages: Optional[CoipAddressUsageSet] - LocalGatewayRouteTableId: Optional[String] - NextToken: Optional[String] + CoipPoolId: String | None + CoipAddressUsages: CoipAddressUsageSet | None + LocalGatewayRouteTableId: String | None + NextToken: String | None class GetConsoleOutputRequest(ServiceRequest): InstanceId: InstanceId - Latest: Optional[Boolean] - DryRun: Optional[Boolean] + Latest: Boolean | None + DryRun: Boolean | None class GetConsoleOutputResult(TypedDict, total=False): - InstanceId: Optional[String] - Timestamp: Optional[DateTime] - Output: Optional[String] + InstanceId: String | None + Timestamp: DateTime | None + Output: String | None class GetConsoleScreenshotRequest(ServiceRequest): - DryRun: Optional[Boolean] + DryRun: Boolean | None InstanceId: InstanceId - WakeUp: Optional[Boolean] + WakeUp: Boolean | None class GetConsoleScreenshotResult(TypedDict, total=False): - ImageData: Optional[String] - InstanceId: Optional[String] + ImageData: String | None + InstanceId: String | None class GetDeclarativePoliciesReportSummaryRequest(ServiceRequest): - DryRun: Optional[Boolean] + DryRun: Boolean | None ReportId: DeclarativePoliciesReportId class GetDeclarativePoliciesReportSummaryResult(TypedDict, total=False): - ReportId: Optional[String] - S3Bucket: Optional[String] - S3Prefix: Optional[String] - TargetId: Optional[String] - StartTime: Optional[MillisecondDateTime] - EndTime: Optional[MillisecondDateTime] - NumberOfAccounts: Optional[Integer] - NumberOfFailedAccounts: Optional[Integer] - AttributeSummaries: Optional[AttributeSummaryList] + ReportId: String | None + S3Bucket: String | None + S3Prefix: String | None + TargetId: String | None + StartTime: MillisecondDateTime | None + EndTime: MillisecondDateTime | None + NumberOfAccounts: Integer | None + NumberOfFailedAccounts: Integer | None + AttributeSummaries: AttributeSummaryList | None class GetDefaultCreditSpecificationRequest(ServiceRequest): - DryRun: Optional[Boolean] + DryRun: Boolean | None InstanceFamily: UnlimitedSupportedInstanceFamily class InstanceFamilyCreditSpecification(TypedDict, total=False): - InstanceFamily: Optional[UnlimitedSupportedInstanceFamily] - CpuCredits: Optional[String] + InstanceFamily: UnlimitedSupportedInstanceFamily | None + CpuCredits: String | None class GetDefaultCreditSpecificationResult(TypedDict, total=False): - InstanceFamilyCreditSpecification: Optional[InstanceFamilyCreditSpecification] + InstanceFamilyCreditSpecification: InstanceFamilyCreditSpecification | None class GetEbsDefaultKmsKeyIdRequest(ServiceRequest): - DryRun: Optional[Boolean] + DryRun: Boolean | None class GetEbsDefaultKmsKeyIdResult(TypedDict, total=False): - KmsKeyId: Optional[String] + KmsKeyId: String | None class GetEbsEncryptionByDefaultRequest(ServiceRequest): - DryRun: Optional[Boolean] + DryRun: Boolean | None class GetEbsEncryptionByDefaultResult(TypedDict, total=False): - EbsEncryptionByDefault: Optional[Boolean] - SseType: Optional[SSEType] + EbsEncryptionByDefault: Boolean | None + SseType: SSEType | None + + +class GetEnabledIpamPolicyRequest(ServiceRequest): + DryRun: Boolean | None + + +class GetEnabledIpamPolicyResult(TypedDict, total=False): + IpamPolicyEnabled: Boolean | None + IpamPolicyId: IpamPolicyId | None + ManagedBy: IpamPolicyManagedBy | None class IntegrateServices(TypedDict, total=False): - AthenaIntegrations: Optional[AthenaIntegrationsSet] + AthenaIntegrations: AthenaIntegrationsSet | None class GetFlowLogsIntegrationTemplateRequest(ServiceRequest): - DryRun: Optional[Boolean] + DryRun: Boolean | None FlowLogId: VpcFlowLogId ConfigDeliveryS3DestinationArn: String IntegrateServices: IntegrateServices class GetFlowLogsIntegrationTemplateResult(TypedDict, total=False): - Result: Optional[String] + Result: String | None class GetGroupsForCapacityReservationRequest(ServiceRequest): CapacityReservationId: CapacityReservationId - NextToken: Optional[String] - MaxResults: Optional[GetGroupsForCapacityReservationRequestMaxResults] - DryRun: Optional[Boolean] + NextToken: String | None + MaxResults: GetGroupsForCapacityReservationRequestMaxResults | None + DryRun: Boolean | None class GetGroupsForCapacityReservationResult(TypedDict, total=False): - NextToken: Optional[String] - CapacityReservationGroups: Optional[CapacityReservationGroupSet] + NextToken: String | None + CapacityReservationGroups: CapacityReservationGroupSet | None -RequestHostIdSet = List[DedicatedHostId] +RequestHostIdSet = list[DedicatedHostId] class GetHostReservationPurchasePreviewRequest(ServiceRequest): @@ -17639,1412 +19428,1668 @@ class GetHostReservationPurchasePreviewRequest(ServiceRequest): class Purchase(TypedDict, total=False): - CurrencyCode: Optional[CurrencyCodeValues] - Duration: Optional[Integer] - HostIdSet: Optional[ResponseHostIdSet] - HostReservationId: Optional[HostReservationId] - HourlyPrice: Optional[String] - InstanceFamily: Optional[String] - PaymentOption: Optional[PaymentOption] - UpfrontPrice: Optional[String] + CurrencyCode: CurrencyCodeValues | None + Duration: Integer | None + HostIdSet: ResponseHostIdSet | None + HostReservationId: HostReservationId | None + HourlyPrice: String | None + InstanceFamily: String | None + PaymentOption: PaymentOption | None + UpfrontPrice: String | None -PurchaseSet = List[Purchase] +PurchaseSet = list[Purchase] class GetHostReservationPurchasePreviewResult(TypedDict, total=False): - CurrencyCode: Optional[CurrencyCodeValues] - Purchase: Optional[PurchaseSet] - TotalHourlyPrice: Optional[String] - TotalUpfrontPrice: Optional[String] + CurrencyCode: CurrencyCodeValues | None + Purchase: PurchaseSet | None + TotalHourlyPrice: String | None + TotalUpfrontPrice: String | None + + +class GetImageAncestryRequest(ServiceRequest): + ImageId: ImageId + DryRun: Boolean | None + + +class ImageAncestryEntry(TypedDict, total=False): + CreationDate: MillisecondDateTime | None + ImageId: ImageId | None + ImageOwnerAlias: String | None + SourceImageId: ImageId | None + SourceImageRegion: String | None + + +ImageAncestryEntryList = list[ImageAncestryEntry] + + +class GetImageAncestryResult(TypedDict, total=False): + ImageAncestryEntries: ImageAncestryEntryList | None class GetImageBlockPublicAccessStateRequest(ServiceRequest): - DryRun: Optional[Boolean] + DryRun: Boolean | None class GetImageBlockPublicAccessStateResult(TypedDict, total=False): - ImageBlockPublicAccessState: Optional[String] - ManagedBy: Optional[ManagedBy] + ImageBlockPublicAccessState: String | None + ManagedBy: ManagedBy | None class GetInstanceMetadataDefaultsRequest(ServiceRequest): - DryRun: Optional[Boolean] + DryRun: Boolean | None class InstanceMetadataDefaultsResponse(TypedDict, total=False): - HttpTokens: Optional[HttpTokensState] - HttpPutResponseHopLimit: Optional[BoxedInteger] - HttpEndpoint: Optional[InstanceMetadataEndpointState] - InstanceMetadataTags: Optional[InstanceMetadataTagsState] - ManagedBy: Optional[ManagedBy] - ManagedExceptionMessage: Optional[String] + HttpTokens: HttpTokensState | None + HttpPutResponseHopLimit: BoxedInteger | None + HttpEndpoint: InstanceMetadataEndpointState | None + InstanceMetadataTags: InstanceMetadataTagsState | None + ManagedBy: ManagedBy | None + ManagedExceptionMessage: String | None + HttpTokensEnforced: HttpTokensEnforcedState | None class GetInstanceMetadataDefaultsResult(TypedDict, total=False): - AccountLevel: Optional[InstanceMetadataDefaultsResponse] + AccountLevel: InstanceMetadataDefaultsResponse | None class GetInstanceTpmEkPubRequest(ServiceRequest): InstanceId: InstanceId KeyType: EkPubKeyType KeyFormat: EkPubKeyFormat - DryRun: Optional[Boolean] + DryRun: Boolean | None class GetInstanceTpmEkPubResult(TypedDict, total=False): - InstanceId: Optional[InstanceId] - KeyType: Optional[EkPubKeyType] - KeyFormat: Optional[EkPubKeyFormat] - KeyValue: Optional[EkPubKeyValue] + InstanceId: InstanceId | None + KeyType: EkPubKeyType | None + KeyFormat: EkPubKeyFormat | None + KeyValue: EkPubKeyValue | None -VirtualizationTypeSet = List[VirtualizationType] +VirtualizationTypeSet = list[VirtualizationType] class GetInstanceTypesFromInstanceRequirementsRequest(ServiceRequest): - DryRun: Optional[Boolean] + DryRun: Boolean | None ArchitectureTypes: ArchitectureTypeSet VirtualizationTypes: VirtualizationTypeSet InstanceRequirements: InstanceRequirementsRequest - MaxResults: Optional[Integer] - NextToken: Optional[String] - Context: Optional[String] + MaxResults: Integer | None + NextToken: String | None + Context: String | None class InstanceTypeInfoFromInstanceRequirements(TypedDict, total=False): - InstanceType: Optional[String] + InstanceType: String | None -InstanceTypeInfoFromInstanceRequirementsSet = List[InstanceTypeInfoFromInstanceRequirements] +InstanceTypeInfoFromInstanceRequirementsSet = list[InstanceTypeInfoFromInstanceRequirements] class GetInstanceTypesFromInstanceRequirementsResult(TypedDict, total=False): - InstanceTypes: Optional[InstanceTypeInfoFromInstanceRequirementsSet] - NextToken: Optional[String] + InstanceTypes: InstanceTypeInfoFromInstanceRequirementsSet | None + NextToken: String | None class GetInstanceUefiDataRequest(ServiceRequest): InstanceId: InstanceId - DryRun: Optional[Boolean] + DryRun: Boolean | None class GetInstanceUefiDataResult(TypedDict, total=False): - InstanceId: Optional[InstanceId] - UefiData: Optional[String] + InstanceId: InstanceId | None + UefiData: String | None class GetIpamAddressHistoryRequest(ServiceRequest): - DryRun: Optional[Boolean] + DryRun: Boolean | None Cidr: String IpamScopeId: IpamScopeId - VpcId: Optional[String] - StartTime: Optional[MillisecondDateTime] - EndTime: Optional[MillisecondDateTime] - MaxResults: Optional[IpamAddressHistoryMaxResults] - NextToken: Optional[NextToken] + VpcId: String | None + StartTime: MillisecondDateTime | None + EndTime: MillisecondDateTime | None + MaxResults: IpamAddressHistoryMaxResults | None + NextToken: NextToken | None class IpamAddressHistoryRecord(TypedDict, total=False): - ResourceOwnerId: Optional[String] - ResourceRegion: Optional[String] - ResourceType: Optional[IpamAddressHistoryResourceType] - ResourceId: Optional[String] - ResourceCidr: Optional[String] - ResourceName: Optional[String] - ResourceComplianceStatus: Optional[IpamComplianceStatus] - ResourceOverlapStatus: Optional[IpamOverlapStatus] - VpcId: Optional[String] - SampledStartTime: Optional[MillisecondDateTime] - SampledEndTime: Optional[MillisecondDateTime] + ResourceOwnerId: String | None + ResourceRegion: String | None + ResourceType: IpamAddressHistoryResourceType | None + ResourceId: String | None + ResourceCidr: String | None + ResourceName: String | None + ResourceComplianceStatus: IpamComplianceStatus | None + ResourceOverlapStatus: IpamOverlapStatus | None + VpcId: String | None + SampledStartTime: MillisecondDateTime | None + SampledEndTime: MillisecondDateTime | None -IpamAddressHistoryRecordSet = List[IpamAddressHistoryRecord] +IpamAddressHistoryRecordSet = list[IpamAddressHistoryRecord] class GetIpamAddressHistoryResult(TypedDict, total=False): - HistoryRecords: Optional[IpamAddressHistoryRecordSet] - NextToken: Optional[NextToken] + HistoryRecords: IpamAddressHistoryRecordSet | None + NextToken: NextToken | None class GetIpamDiscoveredAccountsRequest(ServiceRequest): - DryRun: Optional[Boolean] + DryRun: Boolean | None IpamResourceDiscoveryId: IpamResourceDiscoveryId DiscoveryRegion: String - Filters: Optional[FilterList] - NextToken: Optional[NextToken] - MaxResults: Optional[IpamMaxResults] + Filters: FilterList | None + NextToken: NextToken | None + MaxResults: IpamMaxResults | None class IpamDiscoveryFailureReason(TypedDict, total=False): - Code: Optional[IpamDiscoveryFailureCode] - Message: Optional[String] + Code: IpamDiscoveryFailureCode | None + Message: String | None class IpamDiscoveredAccount(TypedDict, total=False): - AccountId: Optional[String] - DiscoveryRegion: Optional[String] - FailureReason: Optional[IpamDiscoveryFailureReason] - LastAttemptedDiscoveryTime: Optional[MillisecondDateTime] - LastSuccessfulDiscoveryTime: Optional[MillisecondDateTime] - OrganizationalUnitId: Optional[String] + AccountId: String | None + DiscoveryRegion: String | None + FailureReason: IpamDiscoveryFailureReason | None + LastAttemptedDiscoveryTime: MillisecondDateTime | None + LastSuccessfulDiscoveryTime: MillisecondDateTime | None + OrganizationalUnitId: String | None -IpamDiscoveredAccountSet = List[IpamDiscoveredAccount] +IpamDiscoveredAccountSet = list[IpamDiscoveredAccount] class GetIpamDiscoveredAccountsResult(TypedDict, total=False): - IpamDiscoveredAccounts: Optional[IpamDiscoveredAccountSet] - NextToken: Optional[NextToken] + IpamDiscoveredAccounts: IpamDiscoveredAccountSet | None + NextToken: NextToken | None class GetIpamDiscoveredPublicAddressesRequest(ServiceRequest): - DryRun: Optional[Boolean] + DryRun: Boolean | None IpamResourceDiscoveryId: IpamResourceDiscoveryId AddressRegion: String - Filters: Optional[FilterList] - NextToken: Optional[NextToken] - MaxResults: Optional[IpamMaxResults] + Filters: FilterList | None + NextToken: NextToken | None + MaxResults: IpamMaxResults | None class IpamPublicAddressSecurityGroup(TypedDict, total=False): - GroupName: Optional[String] - GroupId: Optional[String] + GroupName: String | None + GroupId: String | None -IpamPublicAddressSecurityGroupList = List[IpamPublicAddressSecurityGroup] +IpamPublicAddressSecurityGroupList = list[IpamPublicAddressSecurityGroup] class IpamPublicAddressTag(TypedDict, total=False): - Key: Optional[String] - Value: Optional[String] + Key: String | None + Value: String | None -IpamPublicAddressTagList = List[IpamPublicAddressTag] +IpamPublicAddressTagList = list[IpamPublicAddressTag] class IpamPublicAddressTags(TypedDict, total=False): - EipTags: Optional[IpamPublicAddressTagList] + EipTags: IpamPublicAddressTagList | None class IpamDiscoveredPublicAddress(TypedDict, total=False): - IpamResourceDiscoveryId: Optional[IpamResourceDiscoveryId] - AddressRegion: Optional[String] - Address: Optional[String] - AddressOwnerId: Optional[String] - AddressAllocationId: Optional[String] - AssociationStatus: Optional[IpamPublicAddressAssociationStatus] - AddressType: Optional[IpamPublicAddressType] - Service: Optional[IpamPublicAddressAwsService] - ServiceResource: Optional[String] - VpcId: Optional[String] - SubnetId: Optional[String] - PublicIpv4PoolId: Optional[String] - NetworkInterfaceId: Optional[String] - NetworkInterfaceDescription: Optional[String] - InstanceId: Optional[String] - Tags: Optional[IpamPublicAddressTags] - NetworkBorderGroup: Optional[String] - SecurityGroups: Optional[IpamPublicAddressSecurityGroupList] - SampleTime: Optional[MillisecondDateTime] - - -IpamDiscoveredPublicAddressSet = List[IpamDiscoveredPublicAddress] + IpamResourceDiscoveryId: IpamResourceDiscoveryId | None + AddressRegion: String | None + Address: String | None + AddressOwnerId: String | None + AddressAllocationId: String | None + AssociationStatus: IpamPublicAddressAssociationStatus | None + AddressType: IpamPublicAddressType | None + Service: IpamPublicAddressAwsService | None + ServiceResource: String | None + VpcId: String | None + SubnetId: String | None + PublicIpv4PoolId: String | None + NetworkInterfaceId: String | None + NetworkInterfaceDescription: String | None + InstanceId: String | None + Tags: IpamPublicAddressTags | None + NetworkBorderGroup: String | None + SecurityGroups: IpamPublicAddressSecurityGroupList | None + SampleTime: MillisecondDateTime | None + + +IpamDiscoveredPublicAddressSet = list[IpamDiscoveredPublicAddress] class GetIpamDiscoveredPublicAddressesResult(TypedDict, total=False): - IpamDiscoveredPublicAddresses: Optional[IpamDiscoveredPublicAddressSet] - OldestSampleTime: Optional[MillisecondDateTime] - NextToken: Optional[NextToken] + IpamDiscoveredPublicAddresses: IpamDiscoveredPublicAddressSet | None + OldestSampleTime: MillisecondDateTime | None + NextToken: NextToken | None class GetIpamDiscoveredResourceCidrsRequest(ServiceRequest): - DryRun: Optional[Boolean] + DryRun: Boolean | None IpamResourceDiscoveryId: IpamResourceDiscoveryId ResourceRegion: String - Filters: Optional[FilterList] - NextToken: Optional[NextToken] - MaxResults: Optional[IpamMaxResults] + Filters: FilterList | None + NextToken: NextToken | None + MaxResults: IpamMaxResults | None class IpamDiscoveredResourceCidr(TypedDict, total=False): - IpamResourceDiscoveryId: Optional[IpamResourceDiscoveryId] - ResourceRegion: Optional[String] - ResourceId: Optional[String] - ResourceOwnerId: Optional[String] - ResourceCidr: Optional[String] - IpSource: Optional[IpamResourceCidrIpSource] - ResourceType: Optional[IpamResourceType] - ResourceTags: Optional[IpamResourceTagList] - IpUsage: Optional[BoxedDouble] - VpcId: Optional[String] - SubnetId: Optional[String] - NetworkInterfaceAttachmentStatus: Optional[IpamNetworkInterfaceAttachmentStatus] - SampleTime: Optional[MillisecondDateTime] - AvailabilityZoneId: Optional[String] + IpamResourceDiscoveryId: IpamResourceDiscoveryId | None + ResourceRegion: String | None + ResourceId: String | None + ResourceOwnerId: String | None + ResourceCidr: String | None + IpSource: IpamResourceCidrIpSource | None + ResourceType: IpamResourceType | None + ResourceTags: IpamResourceTagList | None + IpUsage: BoxedDouble | None + VpcId: String | None + SubnetId: String | None + NetworkInterfaceAttachmentStatus: IpamNetworkInterfaceAttachmentStatus | None + SampleTime: MillisecondDateTime | None + AvailabilityZoneId: String | None -IpamDiscoveredResourceCidrSet = List[IpamDiscoveredResourceCidr] +IpamDiscoveredResourceCidrSet = list[IpamDiscoveredResourceCidr] class GetIpamDiscoveredResourceCidrsResult(TypedDict, total=False): - IpamDiscoveredResourceCidrs: Optional[IpamDiscoveredResourceCidrSet] - NextToken: Optional[NextToken] + IpamDiscoveredResourceCidrs: IpamDiscoveredResourceCidrSet | None + NextToken: NextToken | None + + +class GetIpamPolicyAllocationRulesRequest(ServiceRequest): + DryRun: Boolean | None + IpamPolicyId: IpamPolicyId + Filters: FilterList | None + Locale: String | None + ResourceType: IpamPolicyResourceType | None + MaxResults: IpamMaxResults | None + NextToken: NextToken | None + + +class IpamPolicyAllocationRule(TypedDict, total=False): + SourceIpamPoolId: IpamPoolId | None + + +IpamPolicyAllocationRuleList = list[IpamPolicyAllocationRule] + + +class IpamPolicyDocument(TypedDict, total=False): + IpamPolicyId: IpamPolicyId | None + Locale: String | None + ResourceType: IpamPolicyResourceType | None + AllocationRules: IpamPolicyAllocationRuleList | None + + +IpamPolicyDocumentSet = list[IpamPolicyDocument] + + +class GetIpamPolicyAllocationRulesResult(TypedDict, total=False): + IpamPolicyDocuments: IpamPolicyDocumentSet | None + NextToken: NextToken | None + + +class GetIpamPolicyOrganizationTargetsRequest(ServiceRequest): + DryRun: Boolean | None + MaxResults: IpamMaxResults | None + NextToken: NextToken | None + IpamPolicyId: IpamPolicyId + Filters: FilterList | None + + +class IpamPolicyOrganizationTarget(TypedDict, total=False): + OrganizationTargetId: String | None + + +IpamPolicyOrganizationTargetSet = list[IpamPolicyOrganizationTarget] + + +class GetIpamPolicyOrganizationTargetsResult(TypedDict, total=False): + OrganizationTargets: IpamPolicyOrganizationTargetSet | None + NextToken: NextToken | None class GetIpamPoolAllocationsRequest(ServiceRequest): - DryRun: Optional[Boolean] + DryRun: Boolean | None IpamPoolId: IpamPoolId - IpamPoolAllocationId: Optional[IpamPoolAllocationId] - Filters: Optional[FilterList] - MaxResults: Optional[GetIpamPoolAllocationsMaxResults] - NextToken: Optional[NextToken] + IpamPoolAllocationId: IpamPoolAllocationId | None + Filters: FilterList | None + MaxResults: GetIpamPoolAllocationsMaxResults | None + NextToken: NextToken | None -IpamPoolAllocationSet = List[IpamPoolAllocation] +IpamPoolAllocationSet = list[IpamPoolAllocation] class GetIpamPoolAllocationsResult(TypedDict, total=False): - IpamPoolAllocations: Optional[IpamPoolAllocationSet] - NextToken: Optional[NextToken] + IpamPoolAllocations: IpamPoolAllocationSet | None + NextToken: NextToken | None class GetIpamPoolCidrsRequest(ServiceRequest): - DryRun: Optional[Boolean] + DryRun: Boolean | None IpamPoolId: IpamPoolId - Filters: Optional[FilterList] - MaxResults: Optional[IpamMaxResults] - NextToken: Optional[NextToken] + Filters: FilterList | None + MaxResults: IpamMaxResults | None + NextToken: NextToken | None -IpamPoolCidrSet = List[IpamPoolCidr] +IpamPoolCidrSet = list[IpamPoolCidr] class GetIpamPoolCidrsResult(TypedDict, total=False): - IpamPoolCidrs: Optional[IpamPoolCidrSet] - NextToken: Optional[NextToken] + IpamPoolCidrs: IpamPoolCidrSet | None + NextToken: NextToken | None + + +class GetIpamPrefixListResolverRulesRequest(ServiceRequest): + DryRun: Boolean | None + IpamPrefixListResolverId: IpamPrefixListResolverId + Filters: FilterList | None + MaxResults: IpamMaxResults | None + NextToken: NextToken | None + + +class IpamPrefixListResolverRuleCondition(TypedDict, total=False): + Operation: IpamPrefixListResolverRuleConditionOperation | None + IpamPoolId: String | None + ResourceId: String | None + ResourceOwner: String | None + ResourceRegion: String | None + ResourceTag: IpamResourceTag | None + Cidr: String | None + + +IpamPrefixListResolverRuleConditionSet = list[IpamPrefixListResolverRuleCondition] + + +class IpamPrefixListResolverRule(TypedDict, total=False): + RuleType: IpamPrefixListResolverRuleType | None + StaticCidr: String | None + IpamScopeId: IpamScopeId | None + ResourceType: IpamResourceType | None + Conditions: IpamPrefixListResolverRuleConditionSet | None + + +IpamPrefixListResolverRuleSet = list[IpamPrefixListResolverRule] + + +class GetIpamPrefixListResolverRulesResult(TypedDict, total=False): + Rules: IpamPrefixListResolverRuleSet | None + NextToken: NextToken | None + + +class GetIpamPrefixListResolverVersionEntriesRequest(ServiceRequest): + DryRun: Boolean | None + IpamPrefixListResolverId: IpamPrefixListResolverId + IpamPrefixListResolverVersion: Long + MaxResults: IpamMaxResults | None + NextToken: NextToken | None + + +class IpamPrefixListResolverVersionEntry(TypedDict, total=False): + Cidr: String | None + + +IpamPrefixListResolverVersionEntrySet = list[IpamPrefixListResolverVersionEntry] + + +class GetIpamPrefixListResolverVersionEntriesResult(TypedDict, total=False): + Entries: IpamPrefixListResolverVersionEntrySet | None + NextToken: NextToken | None + + +IpamPrefixListResolverVersionNumberSet = list[Long] + + +class GetIpamPrefixListResolverVersionsRequest(ServiceRequest): + DryRun: Boolean | None + IpamPrefixListResolverId: IpamPrefixListResolverId + IpamPrefixListResolverVersions: IpamPrefixListResolverVersionNumberSet | None + MaxResults: IpamMaxResults | None + Filters: FilterList | None + NextToken: NextToken | None + + +class IpamPrefixListResolverVersion(TypedDict, total=False): + Version: Long | None + + +IpamPrefixListResolverVersionSet = list[IpamPrefixListResolverVersion] + + +class GetIpamPrefixListResolverVersionsResult(TypedDict, total=False): + IpamPrefixListResolverVersions: IpamPrefixListResolverVersionSet | None + NextToken: NextToken | None class GetIpamResourceCidrsRequest(ServiceRequest): - DryRun: Optional[Boolean] - Filters: Optional[FilterList] - MaxResults: Optional[IpamMaxResults] - NextToken: Optional[NextToken] + DryRun: Boolean | None + Filters: FilterList | None + MaxResults: IpamMaxResults | None + NextToken: NextToken | None IpamScopeId: IpamScopeId - IpamPoolId: Optional[IpamPoolId] - ResourceId: Optional[String] - ResourceType: Optional[IpamResourceType] - ResourceTag: Optional[RequestIpamResourceTag] - ResourceOwner: Optional[String] + IpamPoolId: IpamPoolId | None + ResourceId: String | None + ResourceType: IpamResourceType | None + ResourceTag: RequestIpamResourceTag | None + ResourceOwner: String | None class IpamResourceCidr(TypedDict, total=False): - IpamId: Optional[IpamId] - IpamScopeId: Optional[IpamScopeId] - IpamPoolId: Optional[IpamPoolId] - ResourceRegion: Optional[String] - ResourceOwnerId: Optional[String] - ResourceId: Optional[String] - ResourceName: Optional[String] - ResourceCidr: Optional[String] - ResourceType: Optional[IpamResourceType] - ResourceTags: Optional[IpamResourceTagList] - IpUsage: Optional[BoxedDouble] - ComplianceStatus: Optional[IpamComplianceStatus] - ManagementState: Optional[IpamManagementState] - OverlapStatus: Optional[IpamOverlapStatus] - VpcId: Optional[String] - AvailabilityZoneId: Optional[String] - - -IpamResourceCidrSet = List[IpamResourceCidr] + IpamId: IpamId | None + IpamScopeId: IpamScopeId | None + IpamPoolId: IpamPoolId | None + ResourceRegion: String | None + ResourceOwnerId: String | None + ResourceId: String | None + ResourceName: String | None + ResourceCidr: String | None + ResourceType: IpamResourceType | None + ResourceTags: IpamResourceTagList | None + IpUsage: BoxedDouble | None + ComplianceStatus: IpamComplianceStatus | None + ManagementState: IpamManagementState | None + OverlapStatus: IpamOverlapStatus | None + VpcId: String | None + AvailabilityZoneId: String | None + + +IpamResourceCidrSet = list[IpamResourceCidr] class GetIpamResourceCidrsResult(TypedDict, total=False): - NextToken: Optional[NextToken] - IpamResourceCidrs: Optional[IpamResourceCidrSet] + NextToken: NextToken | None + IpamResourceCidrs: IpamResourceCidrSet | None class GetLaunchTemplateDataRequest(ServiceRequest): - DryRun: Optional[Boolean] + DryRun: Boolean | None InstanceId: InstanceId class GetLaunchTemplateDataResult(TypedDict, total=False): - LaunchTemplateData: Optional[ResponseLaunchTemplateData] + LaunchTemplateData: ResponseLaunchTemplateData | None class GetManagedPrefixListAssociationsRequest(ServiceRequest): - DryRun: Optional[Boolean] + DryRun: Boolean | None PrefixListId: PrefixListResourceId - MaxResults: Optional[GetManagedPrefixListAssociationsMaxResults] - NextToken: Optional[NextToken] + MaxResults: GetManagedPrefixListAssociationsMaxResults | None + NextToken: NextToken | None class PrefixListAssociation(TypedDict, total=False): - ResourceId: Optional[String] - ResourceOwner: Optional[String] + ResourceId: String | None + ResourceOwner: String | None -PrefixListAssociationSet = List[PrefixListAssociation] +PrefixListAssociationSet = list[PrefixListAssociation] class GetManagedPrefixListAssociationsResult(TypedDict, total=False): - PrefixListAssociations: Optional[PrefixListAssociationSet] - NextToken: Optional[String] + PrefixListAssociations: PrefixListAssociationSet | None + NextToken: String | None class GetManagedPrefixListEntriesRequest(ServiceRequest): - DryRun: Optional[Boolean] + DryRun: Boolean | None PrefixListId: PrefixListResourceId - TargetVersion: Optional[Long] - MaxResults: Optional[PrefixListMaxResults] - NextToken: Optional[NextToken] + TargetVersion: Long | None + MaxResults: PrefixListMaxResults | None + NextToken: NextToken | None class PrefixListEntry(TypedDict, total=False): - Cidr: Optional[String] - Description: Optional[String] + Cidr: String | None + Description: String | None -PrefixListEntrySet = List[PrefixListEntry] +PrefixListEntrySet = list[PrefixListEntry] class GetManagedPrefixListEntriesResult(TypedDict, total=False): - Entries: Optional[PrefixListEntrySet] - NextToken: Optional[NextToken] + Entries: PrefixListEntrySet | None + NextToken: NextToken | None class GetNetworkInsightsAccessScopeAnalysisFindingsRequest(ServiceRequest): NetworkInsightsAccessScopeAnalysisId: NetworkInsightsAccessScopeAnalysisId - MaxResults: Optional[GetNetworkInsightsAccessScopeAnalysisFindingsMaxResults] - NextToken: Optional[NextToken] - DryRun: Optional[Boolean] + MaxResults: GetNetworkInsightsAccessScopeAnalysisFindingsMaxResults | None + NextToken: NextToken | None + DryRun: Boolean | None class GetNetworkInsightsAccessScopeAnalysisFindingsResult(TypedDict, total=False): - NetworkInsightsAccessScopeAnalysisId: Optional[NetworkInsightsAccessScopeAnalysisId] - AnalysisStatus: Optional[AnalysisStatus] - AnalysisFindings: Optional[AccessScopeAnalysisFindingList] - NextToken: Optional[String] + NetworkInsightsAccessScopeAnalysisId: NetworkInsightsAccessScopeAnalysisId | None + AnalysisStatus: AnalysisStatus | None + AnalysisFindings: AccessScopeAnalysisFindingList | None + NextToken: String | None class GetNetworkInsightsAccessScopeContentRequest(ServiceRequest): NetworkInsightsAccessScopeId: NetworkInsightsAccessScopeId - DryRun: Optional[Boolean] + DryRun: Boolean | None class GetNetworkInsightsAccessScopeContentResult(TypedDict, total=False): - NetworkInsightsAccessScopeContent: Optional[NetworkInsightsAccessScopeContent] + NetworkInsightsAccessScopeContent: NetworkInsightsAccessScopeContent | None class GetPasswordDataRequest(ServiceRequest): InstanceId: InstanceId - DryRun: Optional[Boolean] + DryRun: Boolean | None class GetPasswordDataResult(TypedDict, total=False): - InstanceId: Optional[String] - Timestamp: Optional[DateTime] - PasswordData: Optional[PasswordData] + InstanceId: String | None + Timestamp: DateTime | None + PasswordData: PasswordData | None class GetReservedInstancesExchangeQuoteRequest(ServiceRequest): - DryRun: Optional[Boolean] + DryRun: Boolean | None ReservedInstanceIds: ReservedInstanceIdSet - TargetConfigurations: Optional[TargetConfigurationRequestSet] + TargetConfigurations: TargetConfigurationRequestSet | None class TargetConfiguration(TypedDict, total=False): - InstanceCount: Optional[Integer] - OfferingId: Optional[String] + InstanceCount: Integer | None + OfferingId: String | None class ReservationValue(TypedDict, total=False): - HourlyPrice: Optional[String] - RemainingTotalValue: Optional[String] - RemainingUpfrontValue: Optional[String] + HourlyPrice: String | None + RemainingTotalValue: String | None + RemainingUpfrontValue: String | None class TargetReservationValue(TypedDict, total=False): - ReservationValue: Optional[ReservationValue] - TargetConfiguration: Optional[TargetConfiguration] + ReservationValue: ReservationValue | None + TargetConfiguration: TargetConfiguration | None -TargetReservationValueSet = List[TargetReservationValue] +TargetReservationValueSet = list[TargetReservationValue] class ReservedInstanceReservationValue(TypedDict, total=False): - ReservationValue: Optional[ReservationValue] - ReservedInstanceId: Optional[String] + ReservationValue: ReservationValue | None + ReservedInstanceId: String | None -ReservedInstanceReservationValueSet = List[ReservedInstanceReservationValue] +ReservedInstanceReservationValueSet = list[ReservedInstanceReservationValue] class GetReservedInstancesExchangeQuoteResult(TypedDict, total=False): - CurrencyCode: Optional[String] - IsValidExchange: Optional[Boolean] - OutputReservedInstancesWillExpireAt: Optional[DateTime] - PaymentDue: Optional[String] - ReservedInstanceValueRollup: Optional[ReservationValue] - ReservedInstanceValueSet: Optional[ReservedInstanceReservationValueSet] - TargetConfigurationValueRollup: Optional[ReservationValue] - TargetConfigurationValueSet: Optional[TargetReservationValueSet] - ValidationFailureReason: Optional[String] + CurrencyCode: String | None + IsValidExchange: Boolean | None + OutputReservedInstancesWillExpireAt: DateTime | None + PaymentDue: String | None + ReservedInstanceValueRollup: ReservationValue | None + ReservedInstanceValueSet: ReservedInstanceReservationValueSet | None + TargetConfigurationValueRollup: ReservationValue | None + TargetConfigurationValueSet: TargetReservationValueSet | None + ValidationFailureReason: String | None class GetRouteServerAssociationsRequest(ServiceRequest): RouteServerId: RouteServerId - DryRun: Optional[Boolean] + DryRun: Boolean | None -RouteServerAssociationsList = List[RouteServerAssociation] +RouteServerAssociationsList = list[RouteServerAssociation] class GetRouteServerAssociationsResult(TypedDict, total=False): - RouteServerAssociations: Optional[RouteServerAssociationsList] + RouteServerAssociations: RouteServerAssociationsList | None class GetRouteServerPropagationsRequest(ServiceRequest): RouteServerId: RouteServerId - RouteTableId: Optional[RouteTableId] - DryRun: Optional[Boolean] + RouteTableId: RouteTableId | None + DryRun: Boolean | None -RouteServerPropagationsList = List[RouteServerPropagation] +RouteServerPropagationsList = list[RouteServerPropagation] class GetRouteServerPropagationsResult(TypedDict, total=False): - RouteServerPropagations: Optional[RouteServerPropagationsList] + RouteServerPropagations: RouteServerPropagationsList | None class GetRouteServerRoutingDatabaseRequest(ServiceRequest): RouteServerId: RouteServerId - NextToken: Optional[String] - MaxResults: Optional[RouteServerMaxResults] - DryRun: Optional[Boolean] - Filters: Optional[FilterList] + NextToken: String | None + MaxResults: RouteServerMaxResults | None + DryRun: Boolean | None + Filters: FilterList | None class RouteServerRouteInstallationDetail(TypedDict, total=False): - RouteTableId: Optional[RouteTableId] - RouteInstallationStatus: Optional[RouteServerRouteInstallationStatus] - RouteInstallationStatusReason: Optional[String] + RouteTableId: RouteTableId | None + RouteInstallationStatus: RouteServerRouteInstallationStatus | None + RouteInstallationStatusReason: String | None -RouteServerRouteInstallationDetails = List[RouteServerRouteInstallationDetail] +RouteServerRouteInstallationDetails = list[RouteServerRouteInstallationDetail] class RouteServerRoute(TypedDict, total=False): - RouteServerEndpointId: Optional[RouteServerEndpointId] - RouteServerPeerId: Optional[RouteServerPeerId] - RouteInstallationDetails: Optional[RouteServerRouteInstallationDetails] - RouteStatus: Optional[RouteServerRouteStatus] - Prefix: Optional[String] - AsPaths: Optional[AsPath] - Med: Optional[Integer] - NextHopIp: Optional[String] + RouteServerEndpointId: RouteServerEndpointId | None + RouteServerPeerId: RouteServerPeerId | None + RouteInstallationDetails: RouteServerRouteInstallationDetails | None + RouteStatus: RouteServerRouteStatus | None + Prefix: String | None + AsPaths: AsPath | None + Med: Integer | None + NextHopIp: String | None -RouteServerRouteList = List[RouteServerRoute] +RouteServerRouteList = list[RouteServerRoute] class GetRouteServerRoutingDatabaseResult(TypedDict, total=False): - AreRoutesPersisted: Optional[Boolean] - Routes: Optional[RouteServerRouteList] - NextToken: Optional[String] + AreRoutesPersisted: Boolean | None + Routes: RouteServerRouteList | None + NextToken: String | None class GetSecurityGroupsForVpcRequest(ServiceRequest): VpcId: VpcId - NextToken: Optional[String] - MaxResults: Optional[GetSecurityGroupsForVpcRequestMaxResults] - Filters: Optional[FilterList] - DryRun: Optional[Boolean] + NextToken: String | None + MaxResults: GetSecurityGroupsForVpcRequestMaxResults | None + Filters: FilterList | None + DryRun: Boolean | None class SecurityGroupForVpc(TypedDict, total=False): - Description: Optional[String] - GroupName: Optional[String] - OwnerId: Optional[String] - GroupId: Optional[String] - Tags: Optional[TagList] - PrimaryVpcId: Optional[String] + Description: String | None + GroupName: String | None + OwnerId: String | None + GroupId: String | None + Tags: TagList | None + PrimaryVpcId: String | None -SecurityGroupForVpcList = List[SecurityGroupForVpc] +SecurityGroupForVpcList = list[SecurityGroupForVpc] class GetSecurityGroupsForVpcResult(TypedDict, total=False): - NextToken: Optional[String] - SecurityGroupForVpcs: Optional[SecurityGroupForVpcList] + NextToken: String | None + SecurityGroupForVpcs: SecurityGroupForVpcList | None class GetSerialConsoleAccessStatusRequest(ServiceRequest): - DryRun: Optional[Boolean] + DryRun: Boolean | None class GetSerialConsoleAccessStatusResult(TypedDict, total=False): - SerialConsoleAccessEnabled: Optional[Boolean] - ManagedBy: Optional[ManagedBy] + SerialConsoleAccessEnabled: Boolean | None + ManagedBy: ManagedBy | None class GetSnapshotBlockPublicAccessStateRequest(ServiceRequest): - DryRun: Optional[Boolean] + DryRun: Boolean | None class GetSnapshotBlockPublicAccessStateResult(TypedDict, total=False): - State: Optional[SnapshotBlockPublicAccessState] - ManagedBy: Optional[ManagedBy] + State: SnapshotBlockPublicAccessState | None + ManagedBy: ManagedBy | None class InstanceRequirementsWithMetadataRequest(TypedDict, total=False): - ArchitectureTypes: Optional[ArchitectureTypeSet] - VirtualizationTypes: Optional[VirtualizationTypeSet] - InstanceRequirements: Optional[InstanceRequirementsRequest] + ArchitectureTypes: ArchitectureTypeSet | None + VirtualizationTypes: VirtualizationTypeSet | None + InstanceRequirements: InstanceRequirementsRequest | None -RegionNames = List[String] -InstanceTypes = List[String] +RegionNames = list[String] +InstanceTypes = list[String] class GetSpotPlacementScoresRequest(ServiceRequest): - InstanceTypes: Optional[InstanceTypes] + InstanceTypes: InstanceTypes | None TargetCapacity: SpotPlacementScoresTargetCapacity - TargetCapacityUnitType: Optional[TargetCapacityUnitType] - SingleAvailabilityZone: Optional[Boolean] - RegionNames: Optional[RegionNames] - InstanceRequirementsWithMetadata: Optional[InstanceRequirementsWithMetadataRequest] - DryRun: Optional[Boolean] - MaxResults: Optional[SpotPlacementScoresMaxResults] - NextToken: Optional[String] + TargetCapacityUnitType: TargetCapacityUnitType | None + SingleAvailabilityZone: Boolean | None + RegionNames: RegionNames | None + InstanceRequirementsWithMetadata: InstanceRequirementsWithMetadataRequest | None + DryRun: Boolean | None + MaxResults: SpotPlacementScoresMaxResults | None + NextToken: String | None class SpotPlacementScore(TypedDict, total=False): - Region: Optional[String] - AvailabilityZoneId: Optional[String] - Score: Optional[Integer] + Region: String | None + AvailabilityZoneId: String | None + Score: Integer | None -SpotPlacementScores = List[SpotPlacementScore] +SpotPlacementScores = list[SpotPlacementScore] class GetSpotPlacementScoresResult(TypedDict, total=False): - SpotPlacementScores: Optional[SpotPlacementScores] - NextToken: Optional[String] + SpotPlacementScores: SpotPlacementScores | None + NextToken: String | None class GetSubnetCidrReservationsRequest(ServiceRequest): - Filters: Optional[FilterList] + Filters: FilterList | None SubnetId: SubnetId - DryRun: Optional[Boolean] - NextToken: Optional[String] - MaxResults: Optional[GetSubnetCidrReservationsMaxResults] + DryRun: Boolean | None + NextToken: String | None + MaxResults: GetSubnetCidrReservationsMaxResults | None -SubnetCidrReservationList = List[SubnetCidrReservation] +SubnetCidrReservationList = list[SubnetCidrReservation] class GetSubnetCidrReservationsResult(TypedDict, total=False): - SubnetIpv4CidrReservations: Optional[SubnetCidrReservationList] - SubnetIpv6CidrReservations: Optional[SubnetCidrReservationList] - NextToken: Optional[String] + SubnetIpv4CidrReservations: SubnetCidrReservationList | None + SubnetIpv6CidrReservations: SubnetCidrReservationList | None + NextToken: String | None class GetTransitGatewayAttachmentPropagationsRequest(ServiceRequest): TransitGatewayAttachmentId: TransitGatewayAttachmentId - Filters: Optional[FilterList] - MaxResults: Optional[TransitGatewayMaxResults] - NextToken: Optional[String] - DryRun: Optional[Boolean] + Filters: FilterList | None + MaxResults: TransitGatewayMaxResults | None + NextToken: String | None + DryRun: Boolean | None class TransitGatewayAttachmentPropagation(TypedDict, total=False): - TransitGatewayRouteTableId: Optional[String] - State: Optional[TransitGatewayPropagationState] + TransitGatewayRouteTableId: String | None + State: TransitGatewayPropagationState | None -TransitGatewayAttachmentPropagationList = List[TransitGatewayAttachmentPropagation] +TransitGatewayAttachmentPropagationList = list[TransitGatewayAttachmentPropagation] class GetTransitGatewayAttachmentPropagationsResult(TypedDict, total=False): - TransitGatewayAttachmentPropagations: Optional[TransitGatewayAttachmentPropagationList] - NextToken: Optional[String] + TransitGatewayAttachmentPropagations: TransitGatewayAttachmentPropagationList | None + NextToken: String | None + + +class GetTransitGatewayMeteringPolicyEntriesRequest(ServiceRequest): + TransitGatewayMeteringPolicyId: TransitGatewayMeteringPolicyId + Filters: FilterList | None + MaxResults: TransitGatewayMaxResults | None + NextToken: String | None + DryRun: Boolean | None + + +TransitGatewayMeteringPolicyEntryList = list[TransitGatewayMeteringPolicyEntry] + + +class GetTransitGatewayMeteringPolicyEntriesResult(TypedDict, total=False): + TransitGatewayMeteringPolicyEntries: TransitGatewayMeteringPolicyEntryList | None + NextToken: String | None class GetTransitGatewayMulticastDomainAssociationsRequest(ServiceRequest): TransitGatewayMulticastDomainId: TransitGatewayMulticastDomainId - Filters: Optional[FilterList] - MaxResults: Optional[TransitGatewayMaxResults] - NextToken: Optional[String] - DryRun: Optional[Boolean] + Filters: FilterList | None + MaxResults: TransitGatewayMaxResults | None + NextToken: String | None + DryRun: Boolean | None class TransitGatewayMulticastDomainAssociation(TypedDict, total=False): - TransitGatewayAttachmentId: Optional[String] - ResourceId: Optional[String] - ResourceType: Optional[TransitGatewayAttachmentResourceType] - ResourceOwnerId: Optional[String] - Subnet: Optional[SubnetAssociation] + TransitGatewayAttachmentId: String | None + ResourceId: String | None + ResourceType: TransitGatewayAttachmentResourceType | None + ResourceOwnerId: String | None + Subnet: SubnetAssociation | None -TransitGatewayMulticastDomainAssociationList = List[TransitGatewayMulticastDomainAssociation] +TransitGatewayMulticastDomainAssociationList = list[TransitGatewayMulticastDomainAssociation] class GetTransitGatewayMulticastDomainAssociationsResult(TypedDict, total=False): - MulticastDomainAssociations: Optional[TransitGatewayMulticastDomainAssociationList] - NextToken: Optional[String] + MulticastDomainAssociations: TransitGatewayMulticastDomainAssociationList | None + NextToken: String | None class GetTransitGatewayPolicyTableAssociationsRequest(ServiceRequest): TransitGatewayPolicyTableId: TransitGatewayPolicyTableId - Filters: Optional[FilterList] - MaxResults: Optional[TransitGatewayMaxResults] - NextToken: Optional[String] - DryRun: Optional[Boolean] + Filters: FilterList | None + MaxResults: TransitGatewayMaxResults | None + NextToken: String | None + DryRun: Boolean | None -TransitGatewayPolicyTableAssociationList = List[TransitGatewayPolicyTableAssociation] +TransitGatewayPolicyTableAssociationList = list[TransitGatewayPolicyTableAssociation] class GetTransitGatewayPolicyTableAssociationsResult(TypedDict, total=False): - Associations: Optional[TransitGatewayPolicyTableAssociationList] - NextToken: Optional[String] + Associations: TransitGatewayPolicyTableAssociationList | None + NextToken: String | None class GetTransitGatewayPolicyTableEntriesRequest(ServiceRequest): TransitGatewayPolicyTableId: TransitGatewayPolicyTableId - Filters: Optional[FilterList] - MaxResults: Optional[TransitGatewayMaxResults] - NextToken: Optional[String] - DryRun: Optional[Boolean] + Filters: FilterList | None + MaxResults: TransitGatewayMaxResults | None + NextToken: String | None + DryRun: Boolean | None class TransitGatewayPolicyRuleMetaData(TypedDict, total=False): - MetaDataKey: Optional[String] - MetaDataValue: Optional[String] + MetaDataKey: String | None + MetaDataValue: String | None class TransitGatewayPolicyRule(TypedDict, total=False): - SourceCidrBlock: Optional[String] - SourcePortRange: Optional[String] - DestinationCidrBlock: Optional[String] - DestinationPortRange: Optional[String] - Protocol: Optional[String] - MetaData: Optional[TransitGatewayPolicyRuleMetaData] + SourceCidrBlock: String | None + SourcePortRange: String | None + DestinationCidrBlock: String | None + DestinationPortRange: String | None + Protocol: String | None + MetaData: TransitGatewayPolicyRuleMetaData | None class TransitGatewayPolicyTableEntry(TypedDict, total=False): - PolicyRuleNumber: Optional[String] - PolicyRule: Optional[TransitGatewayPolicyRule] - TargetRouteTableId: Optional[TransitGatewayRouteTableId] + PolicyRuleNumber: String | None + PolicyRule: TransitGatewayPolicyRule | None + TargetRouteTableId: TransitGatewayRouteTableId | None -TransitGatewayPolicyTableEntryList = List[TransitGatewayPolicyTableEntry] +TransitGatewayPolicyTableEntryList = list[TransitGatewayPolicyTableEntry] class GetTransitGatewayPolicyTableEntriesResult(TypedDict, total=False): - TransitGatewayPolicyTableEntries: Optional[TransitGatewayPolicyTableEntryList] + TransitGatewayPolicyTableEntries: TransitGatewayPolicyTableEntryList | None class GetTransitGatewayPrefixListReferencesRequest(ServiceRequest): TransitGatewayRouteTableId: TransitGatewayRouteTableId - Filters: Optional[FilterList] - MaxResults: Optional[TransitGatewayMaxResults] - NextToken: Optional[String] - DryRun: Optional[Boolean] + Filters: FilterList | None + MaxResults: TransitGatewayMaxResults | None + NextToken: String | None + DryRun: Boolean | None -TransitGatewayPrefixListReferenceSet = List[TransitGatewayPrefixListReference] +TransitGatewayPrefixListReferenceSet = list[TransitGatewayPrefixListReference] class GetTransitGatewayPrefixListReferencesResult(TypedDict, total=False): - TransitGatewayPrefixListReferences: Optional[TransitGatewayPrefixListReferenceSet] - NextToken: Optional[String] + TransitGatewayPrefixListReferences: TransitGatewayPrefixListReferenceSet | None + NextToken: String | None class GetTransitGatewayRouteTableAssociationsRequest(ServiceRequest): TransitGatewayRouteTableId: TransitGatewayRouteTableId - Filters: Optional[FilterList] - MaxResults: Optional[TransitGatewayMaxResults] - NextToken: Optional[String] - DryRun: Optional[Boolean] + Filters: FilterList | None + MaxResults: TransitGatewayMaxResults | None + NextToken: String | None + DryRun: Boolean | None class TransitGatewayRouteTableAssociation(TypedDict, total=False): - TransitGatewayAttachmentId: Optional[String] - ResourceId: Optional[String] - ResourceType: Optional[TransitGatewayAttachmentResourceType] - State: Optional[TransitGatewayAssociationState] + TransitGatewayAttachmentId: String | None + ResourceId: String | None + ResourceType: TransitGatewayAttachmentResourceType | None + State: TransitGatewayAssociationState | None -TransitGatewayRouteTableAssociationList = List[TransitGatewayRouteTableAssociation] +TransitGatewayRouteTableAssociationList = list[TransitGatewayRouteTableAssociation] class GetTransitGatewayRouteTableAssociationsResult(TypedDict, total=False): - Associations: Optional[TransitGatewayRouteTableAssociationList] - NextToken: Optional[String] + Associations: TransitGatewayRouteTableAssociationList | None + NextToken: String | None class GetTransitGatewayRouteTablePropagationsRequest(ServiceRequest): TransitGatewayRouteTableId: TransitGatewayRouteTableId - Filters: Optional[FilterList] - MaxResults: Optional[TransitGatewayMaxResults] - NextToken: Optional[String] - DryRun: Optional[Boolean] + Filters: FilterList | None + MaxResults: TransitGatewayMaxResults | None + NextToken: String | None + DryRun: Boolean | None class TransitGatewayRouteTablePropagation(TypedDict, total=False): - TransitGatewayAttachmentId: Optional[String] - ResourceId: Optional[String] - ResourceType: Optional[TransitGatewayAttachmentResourceType] - State: Optional[TransitGatewayPropagationState] - TransitGatewayRouteTableAnnouncementId: Optional[TransitGatewayRouteTableAnnouncementId] + TransitGatewayAttachmentId: String | None + ResourceId: String | None + ResourceType: TransitGatewayAttachmentResourceType | None + State: TransitGatewayPropagationState | None + TransitGatewayRouteTableAnnouncementId: TransitGatewayRouteTableAnnouncementId | None -TransitGatewayRouteTablePropagationList = List[TransitGatewayRouteTablePropagation] +TransitGatewayRouteTablePropagationList = list[TransitGatewayRouteTablePropagation] class GetTransitGatewayRouteTablePropagationsResult(TypedDict, total=False): - TransitGatewayRouteTablePropagations: Optional[TransitGatewayRouteTablePropagationList] - NextToken: Optional[String] + TransitGatewayRouteTablePropagations: TransitGatewayRouteTablePropagationList | None + NextToken: String | None class GetVerifiedAccessEndpointPolicyRequest(ServiceRequest): VerifiedAccessEndpointId: VerifiedAccessEndpointId - DryRun: Optional[Boolean] + DryRun: Boolean | None class GetVerifiedAccessEndpointPolicyResult(TypedDict, total=False): - PolicyEnabled: Optional[Boolean] - PolicyDocument: Optional[String] + PolicyEnabled: Boolean | None + PolicyDocument: String | None class GetVerifiedAccessEndpointTargetsRequest(ServiceRequest): VerifiedAccessEndpointId: VerifiedAccessEndpointId - MaxResults: Optional[GetVerifiedAccessEndpointTargetsMaxResults] - NextToken: Optional[NextToken] - DryRun: Optional[Boolean] + MaxResults: GetVerifiedAccessEndpointTargetsMaxResults | None + NextToken: NextToken | None + DryRun: Boolean | None class VerifiedAccessEndpointTarget(TypedDict, total=False): - VerifiedAccessEndpointId: Optional[VerifiedAccessEndpointId] - VerifiedAccessEndpointTargetIpAddress: Optional[String] - VerifiedAccessEndpointTargetDns: Optional[String] + VerifiedAccessEndpointId: VerifiedAccessEndpointId | None + VerifiedAccessEndpointTargetIpAddress: String | None + VerifiedAccessEndpointTargetDns: String | None -VerifiedAccessEndpointTargetList = List[VerifiedAccessEndpointTarget] +VerifiedAccessEndpointTargetList = list[VerifiedAccessEndpointTarget] class GetVerifiedAccessEndpointTargetsResult(TypedDict, total=False): - VerifiedAccessEndpointTargets: Optional[VerifiedAccessEndpointTargetList] - NextToken: Optional[NextToken] + VerifiedAccessEndpointTargets: VerifiedAccessEndpointTargetList | None + NextToken: NextToken | None class GetVerifiedAccessGroupPolicyRequest(ServiceRequest): VerifiedAccessGroupId: VerifiedAccessGroupId - DryRun: Optional[Boolean] + DryRun: Boolean | None class GetVerifiedAccessGroupPolicyResult(TypedDict, total=False): - PolicyEnabled: Optional[Boolean] - PolicyDocument: Optional[String] + PolicyEnabled: Boolean | None + PolicyDocument: String | None + + +class GetVpcResourcesBlockingEncryptionEnforcementRequest(ServiceRequest): + VpcId: VpcId + MaxResults: GetVpcResourcesBlockingEncryptionEnforcementMaxResults | None + NextToken: String | None + DryRun: Boolean | None + + +class VpcEncryptionNonCompliantResource(TypedDict, total=False): + Id: String | None + Type: String | None + Description: String | None + IsExcludable: Boolean | None + + +VpcEncryptionNonCompliantResourceList = list[VpcEncryptionNonCompliantResource] + + +class GetVpcResourcesBlockingEncryptionEnforcementResult(TypedDict, total=False): + NonCompliantResources: VpcEncryptionNonCompliantResourceList | None + NextToken: String | None class GetVpnConnectionDeviceSampleConfigurationRequest(ServiceRequest): VpnConnectionId: VpnConnectionId VpnConnectionDeviceTypeId: VpnConnectionDeviceTypeId - InternetKeyExchangeVersion: Optional[String] - SampleType: Optional[String] - DryRun: Optional[Boolean] + InternetKeyExchangeVersion: String | None + SampleType: String | None + DryRun: Boolean | None class GetVpnConnectionDeviceSampleConfigurationResult(TypedDict, total=False): - VpnConnectionDeviceSampleConfiguration: Optional[VpnConnectionDeviceSampleConfiguration] + VpnConnectionDeviceSampleConfiguration: VpnConnectionDeviceSampleConfiguration | None class GetVpnConnectionDeviceTypesRequest(ServiceRequest): - MaxResults: Optional[GVCDMaxResults] - NextToken: Optional[NextToken] - DryRun: Optional[Boolean] + MaxResults: GVCDMaxResults | None + NextToken: NextToken | None + DryRun: Boolean | None class VpnConnectionDeviceType(TypedDict, total=False): - VpnConnectionDeviceTypeId: Optional[String] - Vendor: Optional[String] - Platform: Optional[String] - Software: Optional[String] + VpnConnectionDeviceTypeId: String | None + Vendor: String | None + Platform: String | None + Software: String | None -VpnConnectionDeviceTypeList = List[VpnConnectionDeviceType] +VpnConnectionDeviceTypeList = list[VpnConnectionDeviceType] class GetVpnConnectionDeviceTypesResult(TypedDict, total=False): - VpnConnectionDeviceTypes: Optional[VpnConnectionDeviceTypeList] - NextToken: Optional[NextToken] + VpnConnectionDeviceTypes: VpnConnectionDeviceTypeList | None + NextToken: NextToken | None class GetVpnTunnelReplacementStatusRequest(ServiceRequest): VpnConnectionId: VpnConnectionId VpnTunnelOutsideIpAddress: String - DryRun: Optional[Boolean] + DryRun: Boolean | None class MaintenanceDetails(TypedDict, total=False): - PendingMaintenance: Optional[String] - MaintenanceAutoAppliedAfter: Optional[MillisecondDateTime] - LastMaintenanceApplied: Optional[MillisecondDateTime] + PendingMaintenance: String | None + MaintenanceAutoAppliedAfter: MillisecondDateTime | None + LastMaintenanceApplied: MillisecondDateTime | None class GetVpnTunnelReplacementStatusResult(TypedDict, total=False): - VpnConnectionId: Optional[VpnConnectionId] - TransitGatewayId: Optional[TransitGatewayId] - CustomerGatewayId: Optional[CustomerGatewayId] - VpnGatewayId: Optional[VpnGatewayId] - VpnTunnelOutsideIpAddress: Optional[String] - MaintenanceDetails: Optional[MaintenanceDetails] + VpnConnectionId: VpnConnectionId | None + TransitGatewayId: TransitGatewayId | None + CustomerGatewayId: CustomerGatewayId | None + VpnGatewayId: VpnGatewayId | None + VpnTunnelOutsideIpAddress: String | None + MaintenanceDetails: MaintenanceDetails | None class HibernationOptionsRequest(TypedDict, total=False): - Configured: Optional[Boolean] + Configured: Boolean | None class LaunchPermission(TypedDict, total=False): - OrganizationArn: Optional[String] - OrganizationalUnitArn: Optional[String] - UserId: Optional[String] - Group: Optional[PermissionGroup] + OrganizationArn: String | None + OrganizationalUnitArn: String | None + UserId: String | None + Group: PermissionGroup | None -LaunchPermissionList = List[LaunchPermission] +LaunchPermissionList = list[LaunchPermission] class ImageAttribute(TypedDict, total=False): - Description: Optional[AttributeValue] - KernelId: Optional[AttributeValue] - RamdiskId: Optional[AttributeValue] - SriovNetSupport: Optional[AttributeValue] - BootMode: Optional[AttributeValue] - TpmSupport: Optional[AttributeValue] - UefiData: Optional[AttributeValue] - LastLaunchedTime: Optional[AttributeValue] - ImdsSupport: Optional[AttributeValue] - DeregistrationProtection: Optional[AttributeValue] - ImageId: Optional[String] - LaunchPermissions: Optional[LaunchPermissionList] - ProductCodes: Optional[ProductCodeList] - BlockDeviceMappings: Optional[BlockDeviceMappingList] - - -ImageNameRequestList = List[ImageNameRequest] -MarketplaceProductCodeRequestList = List[MarketplaceProductCodeRequest] -ImageProviderRequestList = List[ImageProviderRequest] + Description: AttributeValue | None + KernelId: AttributeValue | None + RamdiskId: AttributeValue | None + SriovNetSupport: AttributeValue | None + BootMode: AttributeValue | None + TpmSupport: AttributeValue | None + UefiData: AttributeValue | None + LastLaunchedTime: AttributeValue | None + ImdsSupport: AttributeValue | None + DeregistrationProtection: AttributeValue | None + ImageId: String | None + LaunchPermissions: LaunchPermissionList | None + ProductCodes: ProductCodeList | None + BlockDeviceMappings: BlockDeviceMappingList | None + + +ImageNameRequestList = list[ImageNameRequest] +MarketplaceProductCodeRequestList = list[MarketplaceProductCodeRequest] +ImageProviderRequestList = list[ImageProviderRequest] class ImageCriterionRequest(TypedDict, total=False): - ImageProviders: Optional[ImageProviderRequestList] - MarketplaceProductCodes: Optional[MarketplaceProductCodeRequestList] - ImageNames: Optional[ImageNameRequestList] - DeprecationTimeCondition: Optional[DeprecationTimeConditionRequest] - CreationDateCondition: Optional[CreationDateConditionRequest] + ImageProviders: ImageProviderRequestList | None + MarketplaceProductCodes: MarketplaceProductCodeRequestList | None + ImageNames: ImageNameRequestList | None + DeprecationTimeCondition: DeprecationTimeConditionRequest | None + CreationDateCondition: CreationDateConditionRequest | None -ImageCriterionRequestList = List[ImageCriterionRequest] +ImageCriterionRequestList = list[ImageCriterionRequest] class UserBucket(TypedDict, total=False): - S3Bucket: Optional[String] - S3Key: Optional[String] + S3Bucket: String | None + S3Key: String | None class ImageDiskContainer(TypedDict, total=False): - Description: Optional[String] - DeviceName: Optional[String] - Format: Optional[String] - SnapshotId: Optional[SnapshotId] - Url: Optional[SensitiveUrl] - UserBucket: Optional[UserBucket] + Description: String | None + DeviceName: String | None + Format: String | None + SnapshotId: SnapshotId | None + Url: SensitiveUrl | None + UserBucket: UserBucket | None -ImageDiskContainerList = List[ImageDiskContainer] +ImageDiskContainerList = list[ImageDiskContainer] class ImageRecycleBinInfo(TypedDict, total=False): - ImageId: Optional[String] - Name: Optional[String] - Description: Optional[String] - RecycleBinEnterTime: Optional[MillisecondDateTime] - RecycleBinExitTime: Optional[MillisecondDateTime] + ImageId: String | None + Name: String | None + Description: String | None + RecycleBinEnterTime: MillisecondDateTime | None + RecycleBinExitTime: MillisecondDateTime | None -ImageRecycleBinInfoList = List[ImageRecycleBinInfo] +ImageRecycleBinInfoList = list[ImageRecycleBinInfo] class ImportClientVpnClientCertificateRevocationListRequest(ServiceRequest): ClientVpnEndpointId: ClientVpnEndpointId CertificateRevocationList: String - DryRun: Optional[Boolean] + DryRun: Boolean | None class ImportClientVpnClientCertificateRevocationListResult(TypedDict, total=False): - Return: Optional[Boolean] + Return: Boolean | None class ImportImageLicenseConfigurationRequest(TypedDict, total=False): - LicenseConfigurationArn: Optional[String] + LicenseConfigurationArn: String | None -ImportImageLicenseSpecificationListRequest = List[ImportImageLicenseConfigurationRequest] +ImportImageLicenseSpecificationListRequest = list[ImportImageLicenseConfigurationRequest] class ImportImageRequest(ServiceRequest): - Architecture: Optional[String] - ClientData: Optional[ClientData] - ClientToken: Optional[String] - Description: Optional[String] - DiskContainers: Optional[ImageDiskContainerList] - DryRun: Optional[Boolean] - Encrypted: Optional[Boolean] - Hypervisor: Optional[String] - KmsKeyId: Optional[KmsKeyId] - LicenseType: Optional[String] - Platform: Optional[String] - RoleName: Optional[String] - LicenseSpecifications: Optional[ImportImageLicenseSpecificationListRequest] - TagSpecifications: Optional[TagSpecificationList] - UsageOperation: Optional[String] - BootMode: Optional[BootModeValues] + Architecture: String | None + ClientData: ClientData | None + ClientToken: String | None + Description: String | None + DiskContainers: ImageDiskContainerList | None + DryRun: Boolean | None + Encrypted: Boolean | None + Hypervisor: String | None + KmsKeyId: KmsKeyId | None + LicenseType: String | None + Platform: String | None + RoleName: String | None + LicenseSpecifications: ImportImageLicenseSpecificationListRequest | None + TagSpecifications: TagSpecificationList | None + UsageOperation: String | None + BootMode: BootModeValues | None class ImportImageResult(TypedDict, total=False): - Architecture: Optional[String] - Description: Optional[String] - Encrypted: Optional[Boolean] - Hypervisor: Optional[String] - ImageId: Optional[String] - ImportTaskId: Optional[ImportImageTaskId] - KmsKeyId: Optional[KmsKeyId] - LicenseType: Optional[String] - Platform: Optional[String] - Progress: Optional[String] - SnapshotDetails: Optional[SnapshotDetailList] - Status: Optional[String] - StatusMessage: Optional[String] - LicenseSpecifications: Optional[ImportImageLicenseSpecificationListResponse] - Tags: Optional[TagList] - UsageOperation: Optional[String] + Architecture: String | None + Description: String | None + Encrypted: Boolean | None + Hypervisor: String | None + ImageId: String | None + ImportTaskId: ImportImageTaskId | None + KmsKeyId: KmsKeyId | None + LicenseType: String | None + Platform: String | None + Progress: String | None + SnapshotDetails: SnapshotDetailList | None + Status: String | None + StatusMessage: String | None + LicenseSpecifications: ImportImageLicenseSpecificationListResponse | None + Tags: TagList | None + UsageOperation: String | None class UserData(TypedDict, total=False): - Data: Optional[String] + Data: String | None class ImportInstanceLaunchSpecification(TypedDict, total=False): - Architecture: Optional[ArchitectureValues] - GroupNames: Optional[SecurityGroupStringList] - GroupIds: Optional[SecurityGroupIdStringList] - AdditionalInfo: Optional[String] - UserData: Optional[UserData] - InstanceType: Optional[InstanceType] - Placement: Optional[Placement] - Monitoring: Optional[Boolean] - SubnetId: Optional[SubnetId] - InstanceInitiatedShutdownBehavior: Optional[ShutdownBehavior] - PrivateIpAddress: Optional[String] + Architecture: ArchitectureValues | None + GroupNames: SecurityGroupStringList | None + GroupIds: SecurityGroupIdStringList | None + AdditionalInfo: String | None + UserData: UserData | None + InstanceType: InstanceType | None + Placement: Placement | None + Monitoring: Boolean | None + SubnetId: SubnetId | None + InstanceInitiatedShutdownBehavior: ShutdownBehavior | None + PrivateIpAddress: String | None class ImportInstanceRequest(ServiceRequest): - DryRun: Optional[Boolean] - Description: Optional[String] - LaunchSpecification: Optional[ImportInstanceLaunchSpecification] - DiskImages: Optional[DiskImageList] + DryRun: Boolean | None + Description: String | None + LaunchSpecification: ImportInstanceLaunchSpecification | None + DiskImages: DiskImageList | None Platform: PlatformValues class ImportInstanceResult(TypedDict, total=False): - ConversionTask: Optional[ConversionTask] + ConversionTask: ConversionTask | None class ImportKeyPairRequest(ServiceRequest): - TagSpecifications: Optional[TagSpecificationList] - DryRun: Optional[Boolean] + TagSpecifications: TagSpecificationList | None + DryRun: Boolean | None KeyName: String PublicKeyMaterial: Blob class ImportKeyPairResult(TypedDict, total=False): - KeyFingerprint: Optional[String] - KeyName: Optional[String] - KeyPairId: Optional[String] - Tags: Optional[TagList] + KeyFingerprint: String | None + KeyName: String | None + KeyPairId: String | None + Tags: TagList | None class SnapshotDiskContainer(TypedDict, total=False): - Description: Optional[String] - Format: Optional[String] - Url: Optional[SensitiveUrl] - UserBucket: Optional[UserBucket] + Description: String | None + Format: String | None + Url: SensitiveUrl | None + UserBucket: UserBucket | None class ImportSnapshotRequest(ServiceRequest): - ClientData: Optional[ClientData] - ClientToken: Optional[String] - Description: Optional[String] - DiskContainer: Optional[SnapshotDiskContainer] - DryRun: Optional[Boolean] - Encrypted: Optional[Boolean] - KmsKeyId: Optional[KmsKeyId] - RoleName: Optional[String] - TagSpecifications: Optional[TagSpecificationList] + ClientData: ClientData | None + ClientToken: String | None + Description: String | None + DiskContainer: SnapshotDiskContainer | None + DryRun: Boolean | None + Encrypted: Boolean | None + KmsKeyId: KmsKeyId | None + RoleName: String | None + TagSpecifications: TagSpecificationList | None class ImportSnapshotResult(TypedDict, total=False): - Description: Optional[String] - ImportTaskId: Optional[String] - SnapshotTaskDetail: Optional[SnapshotTaskDetail] - Tags: Optional[TagList] + Description: String | None + ImportTaskId: String | None + SnapshotTaskDetail: SnapshotTaskDetail | None + Tags: TagList | None class ImportVolumeRequest(ServiceRequest): - AvailabilityZoneId: Optional[AvailabilityZoneId] - DryRun: Optional[Boolean] - AvailabilityZone: Optional[String] + AvailabilityZoneId: AvailabilityZoneId | None + DryRun: Boolean | None + AvailabilityZone: String | None Image: DiskImageDetail - Description: Optional[String] + Description: String | None Volume: VolumeDetail class ImportVolumeResult(TypedDict, total=False): - ConversionTask: Optional[ConversionTask] + ConversionTask: ConversionTask | None class InstanceAttribute(TypedDict, total=False): - BlockDeviceMappings: Optional[InstanceBlockDeviceMappingList] - DisableApiTermination: Optional[AttributeBooleanValue] - EnaSupport: Optional[AttributeBooleanValue] - EnclaveOptions: Optional[EnclaveOptions] - EbsOptimized: Optional[AttributeBooleanValue] - InstanceId: Optional[String] - InstanceInitiatedShutdownBehavior: Optional[AttributeValue] - InstanceType: Optional[AttributeValue] - KernelId: Optional[AttributeValue] - ProductCodes: Optional[ProductCodeList] - RamdiskId: Optional[AttributeValue] - RootDeviceName: Optional[AttributeValue] - SourceDestCheck: Optional[AttributeBooleanValue] - SriovNetSupport: Optional[AttributeValue] - UserData: Optional[AttributeValue] - DisableApiStop: Optional[AttributeBooleanValue] - Groups: Optional[GroupIdentifierList] + BlockDeviceMappings: InstanceBlockDeviceMappingList | None + DisableApiTermination: AttributeBooleanValue | None + EnaSupport: AttributeBooleanValue | None + EnclaveOptions: EnclaveOptions | None + EbsOptimized: AttributeBooleanValue | None + InstanceId: String | None + InstanceInitiatedShutdownBehavior: AttributeValue | None + InstanceType: AttributeValue | None + KernelId: AttributeValue | None + ProductCodes: ProductCodeList | None + RamdiskId: AttributeValue | None + RootDeviceName: AttributeValue | None + SourceDestCheck: AttributeBooleanValue | None + SriovNetSupport: AttributeValue | None + UserData: AttributeValue | None + DisableApiStop: AttributeBooleanValue | None + Groups: GroupIdentifierList | None class InstanceBlockDeviceMappingSpecification(TypedDict, total=False): - DeviceName: Optional[String] - Ebs: Optional[EbsInstanceBlockDeviceSpecification] - VirtualName: Optional[String] - NoDevice: Optional[String] + DeviceName: String | None + Ebs: EbsInstanceBlockDeviceSpecification | None + VirtualName: String | None + NoDevice: String | None -InstanceBlockDeviceMappingSpecificationList = List[InstanceBlockDeviceMappingSpecification] +InstanceBlockDeviceMappingSpecificationList = list[InstanceBlockDeviceMappingSpecification] class InstanceCreditSpecificationRequest(TypedDict, total=False): InstanceId: InstanceId - CpuCredits: Optional[String] + CpuCredits: String | None -InstanceCreditSpecificationListRequest = List[InstanceCreditSpecificationRequest] -InstanceIdSet = List[InstanceId] +InstanceCreditSpecificationListRequest = list[InstanceCreditSpecificationRequest] +InstanceIdSet = list[InstanceId] class InstanceMaintenanceOptionsRequest(TypedDict, total=False): - AutoRecovery: Optional[InstanceAutoRecoveryState] + AutoRecovery: InstanceAutoRecoveryState | None class SpotMarketOptions(TypedDict, total=False): - MaxPrice: Optional[String] - SpotInstanceType: Optional[SpotInstanceType] - BlockDurationMinutes: Optional[Integer] - ValidUntil: Optional[DateTime] - InstanceInterruptionBehavior: Optional[InstanceInterruptionBehavior] + MaxPrice: String | None + SpotInstanceType: SpotInstanceType | None + BlockDurationMinutes: Integer | None + ValidUntil: DateTime | None + InstanceInterruptionBehavior: InstanceInterruptionBehavior | None class InstanceMarketOptionsRequest(TypedDict, total=False): - MarketType: Optional[MarketType] - SpotOptions: Optional[SpotMarketOptions] + MarketType: MarketType | None + SpotOptions: SpotMarketOptions | None class InstanceMetadataOptionsRequest(TypedDict, total=False): - HttpTokens: Optional[HttpTokensState] - HttpPutResponseHopLimit: Optional[Integer] - HttpEndpoint: Optional[InstanceMetadataEndpointState] - HttpProtocolIpv6: Optional[InstanceMetadataProtocolState] - InstanceMetadataTags: Optional[InstanceMetadataTagsState] + HttpTokens: HttpTokensState | None + HttpPutResponseHopLimit: Integer | None + HttpEndpoint: InstanceMetadataEndpointState | None + HttpProtocolIpv6: InstanceMetadataProtocolState | None + InstanceMetadataTags: InstanceMetadataTagsState | None class InstanceMonitoring(TypedDict, total=False): - InstanceId: Optional[String] - Monitoring: Optional[Monitoring] + InstanceId: String | None + Monitoring: Monitoring | None -InstanceMonitoringList = List[InstanceMonitoring] +InstanceMonitoringList = list[InstanceMonitoring] class InstanceNetworkPerformanceOptionsRequest(TypedDict, total=False): - BandwidthWeighting: Optional[InstanceBandwidthWeighting] + BandwidthWeighting: InstanceBandwidthWeighting | None + + +class InstanceSecondaryInterfacePrivateIpAddressRequest(TypedDict, total=False): + PrivateIpAddress: String + + +InstanceSecondaryInterfacePrivateIpAddressListRequest = list[ + InstanceSecondaryInterfacePrivateIpAddressRequest +] + + +class InstanceSecondaryInterfaceSpecificationRequest(TypedDict, total=False): + DeleteOnTermination: Boolean | None + DeviceIndex: Integer | None + PrivateIpAddresses: InstanceSecondaryInterfacePrivateIpAddressListRequest | None + PrivateIpAddressCount: Integer | None + SecondarySubnetId: SecondarySubnetId | None + InterfaceType: SecondaryInterfaceType | None + NetworkCardIndex: Integer | None + + +InstanceSecondaryInterfaceSpecificationListRequest = list[ + InstanceSecondaryInterfaceSpecificationRequest +] class InstanceStateChange(TypedDict, total=False): - InstanceId: Optional[String] - CurrentState: Optional[InstanceState] - PreviousState: Optional[InstanceState] + InstanceId: String | None + CurrentState: InstanceState | None + PreviousState: InstanceState | None -InstanceStateChangeList = List[InstanceStateChange] +InstanceStateChangeList = list[InstanceStateChange] class IpamCidrAuthorizationContext(TypedDict, total=False): - Message: Optional[String] - Signature: Optional[String] + Message: String | None + Signature: String | None + + +class IpamPolicyAllocationRuleRequest(TypedDict, total=False): + SourceIpamPoolId: IpamPoolId | None + + +IpamPolicyAllocationRuleListRequest = list[IpamPolicyAllocationRuleRequest] class KeyPair(TypedDict, total=False): - KeyPairId: Optional[String] - Tags: Optional[TagList] - KeyName: Optional[String] - KeyFingerprint: Optional[String] - KeyMaterial: Optional[SensitiveUserData] + KeyPairId: String | None + Tags: TagList | None + KeyName: String | None + KeyFingerprint: String | None + KeyMaterial: SensitiveUserData | None class LaunchPermissionModifications(TypedDict, total=False): - Add: Optional[LaunchPermissionList] - Remove: Optional[LaunchPermissionList] + Add: LaunchPermissionList | None + Remove: LaunchPermissionList | None class LaunchTemplateSpecification(TypedDict, total=False): - LaunchTemplateId: Optional[LaunchTemplateId] - LaunchTemplateName: Optional[String] - Version: Optional[String] + LaunchTemplateId: LaunchTemplateId | None + LaunchTemplateName: String | None + Version: String | None class LicenseConfigurationRequest(TypedDict, total=False): - LicenseConfigurationArn: Optional[String] + LicenseConfigurationArn: String | None -LicenseSpecificationListRequest = List[LicenseConfigurationRequest] +LicenseSpecificationListRequest = list[LicenseConfigurationRequest] class ListImagesInRecycleBinRequest(ServiceRequest): - ImageIds: Optional[ImageIdStringList] - NextToken: Optional[String] - MaxResults: Optional[ListImagesInRecycleBinMaxResults] - DryRun: Optional[Boolean] + ImageIds: ImageIdStringList | None + NextToken: String | None + MaxResults: ListImagesInRecycleBinMaxResults | None + DryRun: Boolean | None class ListImagesInRecycleBinResult(TypedDict, total=False): - Images: Optional[ImageRecycleBinInfoList] - NextToken: Optional[String] + Images: ImageRecycleBinInfoList | None + NextToken: String | None class ListSnapshotsInRecycleBinRequest(ServiceRequest): - MaxResults: Optional[ListSnapshotsInRecycleBinMaxResults] - NextToken: Optional[String] - SnapshotIds: Optional[SnapshotIdStringList] - DryRun: Optional[Boolean] + MaxResults: ListSnapshotsInRecycleBinMaxResults | None + NextToken: String | None + SnapshotIds: SnapshotIdStringList | None + DryRun: Boolean | None class SnapshotRecycleBinInfo(TypedDict, total=False): - SnapshotId: Optional[String] - RecycleBinEnterTime: Optional[MillisecondDateTime] - RecycleBinExitTime: Optional[MillisecondDateTime] - Description: Optional[String] - VolumeId: Optional[String] + SnapshotId: String | None + RecycleBinEnterTime: MillisecondDateTime | None + RecycleBinExitTime: MillisecondDateTime | None + Description: String | None + VolumeId: String | None -SnapshotRecycleBinInfoList = List[SnapshotRecycleBinInfo] +SnapshotRecycleBinInfoList = list[SnapshotRecycleBinInfo] class ListSnapshotsInRecycleBinResult(TypedDict, total=False): - Snapshots: Optional[SnapshotRecycleBinInfoList] - NextToken: Optional[String] + Snapshots: SnapshotRecycleBinInfoList | None + NextToken: String | None + + +class ListVolumesInRecycleBinRequest(ServiceRequest): + VolumeIds: VolumeIdStringList | None + DryRun: Boolean | None + MaxResults: Integer | None + NextToken: String | None + + +class VolumeRecycleBinInfo(TypedDict, total=False): + VolumeId: VolumeId | None + VolumeType: VolumeType | None + State: VolumeState | None + Size: Integer | None + Iops: Integer | None + Throughput: Integer | None + OutpostArn: String | None + AvailabilityZone: String | None + AvailabilityZoneId: String | None + SourceVolumeId: String | None + SnapshotId: String | None + Operator: OperatorResponse | None + CreateTime: DateTime | None + RecycleBinEnterTime: MillisecondDateTime | None + RecycleBinExitTime: MillisecondDateTime | None + + +VolumeRecycleBinInfoList = list[VolumeRecycleBinInfo] + + +class ListVolumesInRecycleBinResult(TypedDict, total=False): + Volumes: VolumeRecycleBinInfoList | None + NextToken: String | None class LoadPermissionRequest(TypedDict, total=False): - Group: Optional[PermissionGroup] - UserId: Optional[String] + Group: PermissionGroup | None + UserId: String | None -LoadPermissionListRequest = List[LoadPermissionRequest] +LoadPermissionListRequest = list[LoadPermissionRequest] class LoadPermissionModifications(TypedDict, total=False): - Add: Optional[LoadPermissionListRequest] - Remove: Optional[LoadPermissionListRequest] + Add: LoadPermissionListRequest | None + Remove: LoadPermissionListRequest | None -LocalGatewayRouteList = List[LocalGatewayRoute] +LocalGatewayRouteList = list[LocalGatewayRoute] class LockSnapshotRequest(ServiceRequest): SnapshotId: SnapshotId - DryRun: Optional[Boolean] + DryRun: Boolean | None LockMode: LockMode - CoolOffPeriod: Optional[CoolOffPeriodRequestHours] - LockDuration: Optional[RetentionPeriodRequestDays] - ExpirationDate: Optional[MillisecondDateTime] + CoolOffPeriod: CoolOffPeriodRequestHours | None + LockDuration: RetentionPeriodRequestDays | None + ExpirationDate: MillisecondDateTime | None class LockSnapshotResult(TypedDict, total=False): - SnapshotId: Optional[String] - LockState: Optional[LockState] - LockDuration: Optional[RetentionPeriodResponseDays] - CoolOffPeriod: Optional[CoolOffPeriodResponseHours] - CoolOffPeriodExpiresOn: Optional[MillisecondDateTime] - LockCreatedOn: Optional[MillisecondDateTime] - LockExpiresOn: Optional[MillisecondDateTime] - LockDurationStartTime: Optional[MillisecondDateTime] + SnapshotId: String | None + LockState: LockState | None + LockDuration: RetentionPeriodResponseDays | None + CoolOffPeriod: CoolOffPeriodResponseHours | None + CoolOffPeriodExpiresOn: MillisecondDateTime | None + LockCreatedOn: MillisecondDateTime | None + LockExpiresOn: MillisecondDateTime | None + LockDurationStartTime: MillisecondDateTime | None class ModifyAddressAttributeRequest(ServiceRequest): AllocationId: AllocationId - DomainName: Optional[String] - DryRun: Optional[Boolean] + DomainName: String | None + DryRun: Boolean | None class ModifyAddressAttributeResult(TypedDict, total=False): - Address: Optional[AddressAttribute] + Address: AddressAttribute | None class ModifyAvailabilityZoneGroupRequest(ServiceRequest): GroupName: String OptInStatus: ModifyAvailabilityZoneOptInStatus - DryRun: Optional[Boolean] + DryRun: Boolean | None class ModifyAvailabilityZoneGroupResult(TypedDict, total=False): - Return: Optional[Boolean] + Return: Boolean | None class ModifyCapacityReservationFleetRequest(ServiceRequest): CapacityReservationFleetId: CapacityReservationFleetId - TotalTargetCapacity: Optional[Integer] - EndDate: Optional[MillisecondDateTime] - DryRun: Optional[Boolean] - RemoveEndDate: Optional[Boolean] + TotalTargetCapacity: Integer | None + EndDate: MillisecondDateTime | None + DryRun: Boolean | None + RemoveEndDate: Boolean | None class ModifyCapacityReservationFleetResult(TypedDict, total=False): - Return: Optional[Boolean] + Return: Boolean | None class ModifyCapacityReservationRequest(ServiceRequest): CapacityReservationId: CapacityReservationId - InstanceCount: Optional[Integer] - EndDate: Optional[DateTime] - EndDateType: Optional[EndDateType] - Accept: Optional[Boolean] - DryRun: Optional[Boolean] - AdditionalInfo: Optional[String] - InstanceMatchCriteria: Optional[InstanceMatchCriteria] + InstanceCount: Integer | None + EndDate: DateTime | None + EndDateType: EndDateType | None + Accept: Boolean | None + DryRun: Boolean | None + AdditionalInfo: String | None + InstanceMatchCriteria: InstanceMatchCriteria | None class ModifyCapacityReservationResult(TypedDict, total=False): - Return: Optional[Boolean] + Return: Boolean | None class ModifyClientVpnEndpointRequest(ServiceRequest): ClientVpnEndpointId: ClientVpnEndpointId - ServerCertificateArn: Optional[String] - ConnectionLogOptions: Optional[ConnectionLogOptions] - DnsServers: Optional[DnsServersOptionsModifyStructure] - VpnPort: Optional[Integer] - Description: Optional[String] - SplitTunnel: Optional[Boolean] - DryRun: Optional[Boolean] - SecurityGroupIds: Optional[ClientVpnSecurityGroupIdSet] - VpcId: Optional[VpcId] - SelfServicePortal: Optional[SelfServicePortal] - ClientConnectOptions: Optional[ClientConnectOptions] - SessionTimeoutHours: Optional[Integer] - ClientLoginBannerOptions: Optional[ClientLoginBannerOptions] - ClientRouteEnforcementOptions: Optional[ClientRouteEnforcementOptions] - DisconnectOnSessionTimeout: Optional[Boolean] + ServerCertificateArn: String | None + ConnectionLogOptions: ConnectionLogOptions | None + DnsServers: DnsServersOptionsModifyStructure | None + VpnPort: Integer | None + Description: String | None + SplitTunnel: Boolean | None + DryRun: Boolean | None + SecurityGroupIds: ClientVpnSecurityGroupIdSet | None + VpcId: VpcId | None + SelfServicePortal: SelfServicePortal | None + ClientConnectOptions: ClientConnectOptions | None + SessionTimeoutHours: Integer | None + ClientLoginBannerOptions: ClientLoginBannerOptions | None + ClientRouteEnforcementOptions: ClientRouteEnforcementOptions | None + DisconnectOnSessionTimeout: Boolean | None class ModifyClientVpnEndpointResult(TypedDict, total=False): - Return: Optional[Boolean] + Return: Boolean | None class ModifyDefaultCreditSpecificationRequest(ServiceRequest): - DryRun: Optional[Boolean] + DryRun: Boolean | None InstanceFamily: UnlimitedSupportedInstanceFamily CpuCredits: String class ModifyDefaultCreditSpecificationResult(TypedDict, total=False): - InstanceFamilyCreditSpecification: Optional[InstanceFamilyCreditSpecification] + InstanceFamilyCreditSpecification: InstanceFamilyCreditSpecification | None class ModifyEbsDefaultKmsKeyIdRequest(ServiceRequest): KmsKeyId: KmsKeyId - DryRun: Optional[Boolean] + DryRun: Boolean | None class ModifyEbsDefaultKmsKeyIdResult(TypedDict, total=False): - KmsKeyId: Optional[String] + KmsKeyId: String | None class ModifyFleetRequest(ServiceRequest): - DryRun: Optional[Boolean] - ExcessCapacityTerminationPolicy: Optional[FleetExcessCapacityTerminationPolicy] - LaunchTemplateConfigs: Optional[FleetLaunchTemplateConfigListRequest] + DryRun: Boolean | None + ExcessCapacityTerminationPolicy: FleetExcessCapacityTerminationPolicy | None + LaunchTemplateConfigs: FleetLaunchTemplateConfigListRequest | None FleetId: FleetId - TargetCapacitySpecification: Optional[TargetCapacitySpecificationRequest] - Context: Optional[String] + TargetCapacitySpecification: TargetCapacitySpecificationRequest | None + Context: String | None class ModifyFleetResult(TypedDict, total=False): - Return: Optional[Boolean] + Return: Boolean | None -ProductCodeStringList = List[String] -UserGroupStringList = List[String] -UserIdStringList = List[String] +ProductCodeStringList = list[String] +UserGroupStringList = list[String] +UserIdStringList = list[String] class ModifyFpgaImageAttributeRequest(ServiceRequest): - DryRun: Optional[Boolean] + DryRun: Boolean | None FpgaImageId: FpgaImageId - Attribute: Optional[FpgaImageAttributeName] - OperationType: Optional[OperationType] - UserIds: Optional[UserIdStringList] - UserGroups: Optional[UserGroupStringList] - ProductCodes: Optional[ProductCodeStringList] - LoadPermission: Optional[LoadPermissionModifications] - Description: Optional[String] - Name: Optional[String] + Attribute: FpgaImageAttributeName | None + OperationType: OperationType | None + UserIds: UserIdStringList | None + UserGroups: UserGroupStringList | None + ProductCodes: ProductCodeStringList | None + LoadPermission: LoadPermissionModifications | None + Description: String | None + Name: String | None class ModifyFpgaImageAttributeResult(TypedDict, total=False): - FpgaImageAttribute: Optional[FpgaImageAttribute] + FpgaImageAttribute: FpgaImageAttribute | None class ModifyHostsRequest(ServiceRequest): - HostRecovery: Optional[HostRecovery] - InstanceType: Optional[String] - InstanceFamily: Optional[String] - HostMaintenance: Optional[HostMaintenance] + HostRecovery: HostRecovery | None + InstanceType: String | None + InstanceFamily: String | None + HostMaintenance: HostMaintenance | None HostIds: RequestHostIdList - AutoPlacement: Optional[AutoPlacement] + AutoPlacement: AutoPlacement | None -UnsuccessfulItemList = List[UnsuccessfulItem] +UnsuccessfulItemList = list[UnsuccessfulItem] class ModifyHostsResult(TypedDict, total=False): - Successful: Optional[ResponseHostIdList] - Unsuccessful: Optional[UnsuccessfulItemList] + Successful: ResponseHostIdList | None + Unsuccessful: UnsuccessfulItemList | None class ModifyIdFormatRequest(ServiceRequest): @@ -19058,1141 +21103,1212 @@ class ModifyIdentityIdFormatRequest(ServiceRequest): PrincipalArn: String -OrganizationalUnitArnStringList = List[String] -OrganizationArnStringList = List[String] +OrganizationalUnitArnStringList = list[String] +OrganizationArnStringList = list[String] class ModifyImageAttributeRequest(ServiceRequest): - Attribute: Optional[String] - Description: Optional[AttributeValue] + Attribute: String | None + Description: AttributeValue | None ImageId: ImageId - LaunchPermission: Optional[LaunchPermissionModifications] - OperationType: Optional[OperationType] - ProductCodes: Optional[ProductCodeStringList] - UserGroups: Optional[UserGroupStringList] - UserIds: Optional[UserIdStringList] - Value: Optional[String] - OrganizationArns: Optional[OrganizationArnStringList] - OrganizationalUnitArns: Optional[OrganizationalUnitArnStringList] - ImdsSupport: Optional[AttributeValue] - DryRun: Optional[Boolean] + LaunchPermission: LaunchPermissionModifications | None + OperationType: OperationType | None + ProductCodes: ProductCodeStringList | None + UserGroups: UserGroupStringList | None + UserIds: UserIdStringList | None + Value: String | None + OrganizationArns: OrganizationArnStringList | None + OrganizationalUnitArns: OrganizationalUnitArnStringList | None + ImdsSupport: AttributeValue | None + DryRun: Boolean | None class ModifyInstanceAttributeRequest(ServiceRequest): - SourceDestCheck: Optional[AttributeBooleanValue] - DisableApiStop: Optional[AttributeBooleanValue] - DryRun: Optional[Boolean] + SourceDestCheck: AttributeBooleanValue | None + DisableApiStop: AttributeBooleanValue | None + DryRun: Boolean | None InstanceId: InstanceId - Attribute: Optional[InstanceAttributeName] - Value: Optional[String] - BlockDeviceMappings: Optional[InstanceBlockDeviceMappingSpecificationList] - DisableApiTermination: Optional[AttributeBooleanValue] - InstanceType: Optional[AttributeValue] - Kernel: Optional[AttributeValue] - Ramdisk: Optional[AttributeValue] - UserData: Optional[BlobAttributeValue] - InstanceInitiatedShutdownBehavior: Optional[AttributeValue] - Groups: Optional[GroupIdStringList] - EbsOptimized: Optional[AttributeBooleanValue] - SriovNetSupport: Optional[AttributeValue] - EnaSupport: Optional[AttributeBooleanValue] + Attribute: InstanceAttributeName | None + Value: String | None + BlockDeviceMappings: InstanceBlockDeviceMappingSpecificationList | None + DisableApiTermination: AttributeBooleanValue | None + InstanceType: AttributeValue | None + Kernel: AttributeValue | None + Ramdisk: AttributeValue | None + UserData: BlobAttributeValue | None + InstanceInitiatedShutdownBehavior: AttributeValue | None + Groups: GroupIdStringList | None + EbsOptimized: AttributeBooleanValue | None + SriovNetSupport: AttributeValue | None + EnaSupport: AttributeBooleanValue | None class ModifyInstanceCapacityReservationAttributesRequest(ServiceRequest): InstanceId: InstanceId CapacityReservationSpecification: CapacityReservationSpecification - DryRun: Optional[Boolean] + DryRun: Boolean | None class ModifyInstanceCapacityReservationAttributesResult(TypedDict, total=False): - Return: Optional[Boolean] + Return: Boolean | None class ModifyInstanceConnectEndpointRequest(ServiceRequest): - DryRun: Optional[Boolean] + DryRun: Boolean | None InstanceConnectEndpointId: InstanceConnectEndpointId - IpAddressType: Optional[IpAddressType] - SecurityGroupIds: Optional[SecurityGroupIdStringListRequest] - PreserveClientIp: Optional[Boolean] + IpAddressType: IpAddressType | None + SecurityGroupIds: SecurityGroupIdStringListRequest | None + PreserveClientIp: Boolean | None class ModifyInstanceConnectEndpointResult(TypedDict, total=False): - Return: Optional[Boolean] + Return: Boolean | None class ModifyInstanceCpuOptionsRequest(ServiceRequest): InstanceId: InstanceId - CoreCount: Integer - ThreadsPerCore: Integer - DryRun: Optional[Boolean] + CoreCount: Integer | None + ThreadsPerCore: Integer | None + NestedVirtualization: NestedVirtualizationSpecification | None + DryRun: Boolean | None class ModifyInstanceCpuOptionsResult(TypedDict, total=False): - InstanceId: Optional[InstanceId] - CoreCount: Optional[Integer] - ThreadsPerCore: Optional[Integer] + InstanceId: InstanceId | None + CoreCount: Integer | None + ThreadsPerCore: Integer | None + NestedVirtualization: NestedVirtualizationSpecification | None class ModifyInstanceCreditSpecificationRequest(ServiceRequest): - DryRun: Optional[Boolean] - ClientToken: Optional[String] + DryRun: Boolean | None + ClientToken: String | None InstanceCreditSpecifications: InstanceCreditSpecificationListRequest class UnsuccessfulInstanceCreditSpecificationItemError(TypedDict, total=False): - Code: Optional[UnsuccessfulInstanceCreditSpecificationErrorCode] - Message: Optional[String] + Code: UnsuccessfulInstanceCreditSpecificationErrorCode | None + Message: String | None class UnsuccessfulInstanceCreditSpecificationItem(TypedDict, total=False): - InstanceId: Optional[String] - Error: Optional[UnsuccessfulInstanceCreditSpecificationItemError] + InstanceId: String | None + Error: UnsuccessfulInstanceCreditSpecificationItemError | None -UnsuccessfulInstanceCreditSpecificationSet = List[UnsuccessfulInstanceCreditSpecificationItem] +UnsuccessfulInstanceCreditSpecificationSet = list[UnsuccessfulInstanceCreditSpecificationItem] class SuccessfulInstanceCreditSpecificationItem(TypedDict, total=False): - InstanceId: Optional[String] + InstanceId: String | None -SuccessfulInstanceCreditSpecificationSet = List[SuccessfulInstanceCreditSpecificationItem] +SuccessfulInstanceCreditSpecificationSet = list[SuccessfulInstanceCreditSpecificationItem] class ModifyInstanceCreditSpecificationResult(TypedDict, total=False): - SuccessfulInstanceCreditSpecifications: Optional[SuccessfulInstanceCreditSpecificationSet] - UnsuccessfulInstanceCreditSpecifications: Optional[UnsuccessfulInstanceCreditSpecificationSet] + SuccessfulInstanceCreditSpecifications: SuccessfulInstanceCreditSpecificationSet | None + UnsuccessfulInstanceCreditSpecifications: UnsuccessfulInstanceCreditSpecificationSet | None class ModifyInstanceEventStartTimeRequest(ServiceRequest): - DryRun: Optional[Boolean] + DryRun: Boolean | None InstanceId: InstanceId InstanceEventId: String NotBefore: DateTime class ModifyInstanceEventStartTimeResult(TypedDict, total=False): - Event: Optional[InstanceStatusEvent] + Event: InstanceStatusEvent | None class ModifyInstanceEventWindowRequest(ServiceRequest): - DryRun: Optional[Boolean] - Name: Optional[String] + DryRun: Boolean | None + Name: String | None InstanceEventWindowId: InstanceEventWindowId - TimeRanges: Optional[InstanceEventWindowTimeRangeRequestSet] - CronExpression: Optional[InstanceEventWindowCronExpression] + TimeRanges: InstanceEventWindowTimeRangeRequestSet | None + CronExpression: InstanceEventWindowCronExpression | None class ModifyInstanceEventWindowResult(TypedDict, total=False): - InstanceEventWindow: Optional[InstanceEventWindow] + InstanceEventWindow: InstanceEventWindow | None class ModifyInstanceMaintenanceOptionsRequest(ServiceRequest): InstanceId: InstanceId - AutoRecovery: Optional[InstanceAutoRecoveryState] - RebootMigration: Optional[InstanceRebootMigrationState] - DryRun: Optional[Boolean] + AutoRecovery: InstanceAutoRecoveryState | None + RebootMigration: InstanceRebootMigrationState | None + DryRun: Boolean | None class ModifyInstanceMaintenanceOptionsResult(TypedDict, total=False): - InstanceId: Optional[String] - AutoRecovery: Optional[InstanceAutoRecoveryState] - RebootMigration: Optional[InstanceRebootMigrationState] + InstanceId: String | None + AutoRecovery: InstanceAutoRecoveryState | None + RebootMigration: InstanceRebootMigrationState | None class ModifyInstanceMetadataDefaultsRequest(ServiceRequest): - HttpTokens: Optional[MetadataDefaultHttpTokensState] - HttpPutResponseHopLimit: Optional[BoxedInteger] - HttpEndpoint: Optional[DefaultInstanceMetadataEndpointState] - InstanceMetadataTags: Optional[DefaultInstanceMetadataTagsState] - DryRun: Optional[Boolean] + HttpTokens: MetadataDefaultHttpTokensState | None + HttpPutResponseHopLimit: BoxedInteger | None + HttpEndpoint: DefaultInstanceMetadataEndpointState | None + InstanceMetadataTags: DefaultInstanceMetadataTagsState | None + DryRun: Boolean | None + HttpTokensEnforced: DefaultHttpTokensEnforcedState | None class ModifyInstanceMetadataDefaultsResult(TypedDict, total=False): - Return: Optional[Boolean] + Return: Boolean | None class ModifyInstanceMetadataOptionsRequest(ServiceRequest): InstanceId: InstanceId - HttpTokens: Optional[HttpTokensState] - HttpPutResponseHopLimit: Optional[Integer] - HttpEndpoint: Optional[InstanceMetadataEndpointState] - DryRun: Optional[Boolean] - HttpProtocolIpv6: Optional[InstanceMetadataProtocolState] - InstanceMetadataTags: Optional[InstanceMetadataTagsState] + HttpTokens: HttpTokensState | None + HttpPutResponseHopLimit: Integer | None + HttpEndpoint: InstanceMetadataEndpointState | None + DryRun: Boolean | None + HttpProtocolIpv6: InstanceMetadataProtocolState | None + InstanceMetadataTags: InstanceMetadataTagsState | None class ModifyInstanceMetadataOptionsResult(TypedDict, total=False): - InstanceId: Optional[String] - InstanceMetadataOptions: Optional[InstanceMetadataOptionsResponse] + InstanceId: String | None + InstanceMetadataOptions: InstanceMetadataOptionsResponse | None class ModifyInstanceNetworkPerformanceRequest(ServiceRequest): InstanceId: InstanceId BandwidthWeighting: InstanceBandwidthWeighting - DryRun: Optional[Boolean] + DryRun: Boolean | None class ModifyInstanceNetworkPerformanceResult(TypedDict, total=False): - InstanceId: Optional[InstanceId] - BandwidthWeighting: Optional[InstanceBandwidthWeighting] + InstanceId: InstanceId | None + BandwidthWeighting: InstanceBandwidthWeighting | None class ModifyInstancePlacementRequest(ServiceRequest): - GroupName: Optional[PlacementGroupName] - PartitionNumber: Optional[Integer] - HostResourceGroupArn: Optional[String] - GroupId: Optional[PlacementGroupId] + GroupName: PlacementGroupName | None + PartitionNumber: Integer | None + HostResourceGroupArn: String | None + GroupId: PlacementGroupId | None InstanceId: InstanceId - Tenancy: Optional[HostTenancy] - Affinity: Optional[Affinity] - HostId: Optional[DedicatedHostId] + Tenancy: HostTenancy | None + Affinity: Affinity | None + HostId: DedicatedHostId | None class ModifyInstancePlacementResult(TypedDict, total=False): - Return: Optional[Boolean] + Return: Boolean | None + + +class ModifyIpamPolicyAllocationRulesRequest(ServiceRequest): + DryRun: Boolean | None + IpamPolicyId: IpamPolicyId + Locale: String + ResourceType: IpamPolicyResourceType + AllocationRules: IpamPolicyAllocationRuleListRequest | None + + +class ModifyIpamPolicyAllocationRulesResult(TypedDict, total=False): + IpamPolicyDocument: IpamPolicyDocument | None class ModifyIpamPoolRequest(ServiceRequest): - DryRun: Optional[Boolean] + DryRun: Boolean | None IpamPoolId: IpamPoolId - Description: Optional[String] - AutoImport: Optional[Boolean] - AllocationMinNetmaskLength: Optional[IpamNetmaskLength] - AllocationMaxNetmaskLength: Optional[IpamNetmaskLength] - AllocationDefaultNetmaskLength: Optional[IpamNetmaskLength] - ClearAllocationDefaultNetmaskLength: Optional[Boolean] - AddAllocationResourceTags: Optional[RequestIpamResourceTagList] - RemoveAllocationResourceTags: Optional[RequestIpamResourceTagList] + Description: String | None + AutoImport: Boolean | None + AllocationMinNetmaskLength: IpamNetmaskLength | None + AllocationMaxNetmaskLength: IpamNetmaskLength | None + AllocationDefaultNetmaskLength: IpamNetmaskLength | None + ClearAllocationDefaultNetmaskLength: Boolean | None + AddAllocationResourceTags: RequestIpamResourceTagList | None + RemoveAllocationResourceTags: RequestIpamResourceTagList | None class ModifyIpamPoolResult(TypedDict, total=False): - IpamPool: Optional[IpamPool] + IpamPool: IpamPool | None + + +class ModifyIpamPrefixListResolverRequest(ServiceRequest): + DryRun: Boolean | None + IpamPrefixListResolverId: IpamPrefixListResolverId + Description: String | None + Rules: IpamPrefixListResolverRuleRequestSet | None + + +class ModifyIpamPrefixListResolverResult(TypedDict, total=False): + IpamPrefixListResolver: IpamPrefixListResolver | None + + +class ModifyIpamPrefixListResolverTargetRequest(ServiceRequest): + DryRun: Boolean | None + IpamPrefixListResolverTargetId: IpamPrefixListResolverTargetId + DesiredVersion: BoxedLong | None + TrackLatestVersion: BoxedBoolean | None + ClientToken: String | None + + +class ModifyIpamPrefixListResolverTargetResult(TypedDict, total=False): + IpamPrefixListResolverTarget: IpamPrefixListResolverTarget | None class RemoveIpamOperatingRegion(TypedDict, total=False): - RegionName: Optional[String] + RegionName: String | None -RemoveIpamOperatingRegionSet = List[RemoveIpamOperatingRegion] +RemoveIpamOperatingRegionSet = list[RemoveIpamOperatingRegion] class ModifyIpamRequest(ServiceRequest): - DryRun: Optional[Boolean] + DryRun: Boolean | None IpamId: IpamId - Description: Optional[String] - AddOperatingRegions: Optional[AddIpamOperatingRegionSet] - RemoveOperatingRegions: Optional[RemoveIpamOperatingRegionSet] - Tier: Optional[IpamTier] - EnablePrivateGua: Optional[Boolean] - MeteredAccount: Optional[IpamMeteredAccount] + Description: String | None + AddOperatingRegions: AddIpamOperatingRegionSet | None + RemoveOperatingRegions: RemoveIpamOperatingRegionSet | None + Tier: IpamTier | None + EnablePrivateGua: Boolean | None + MeteredAccount: IpamMeteredAccount | None class ModifyIpamResourceCidrRequest(ServiceRequest): - DryRun: Optional[Boolean] + DryRun: Boolean | None ResourceId: String ResourceCidr: String ResourceRegion: String CurrentIpamScopeId: IpamScopeId - DestinationIpamScopeId: Optional[IpamScopeId] + DestinationIpamScopeId: IpamScopeId | None Monitored: Boolean class ModifyIpamResourceCidrResult(TypedDict, total=False): - IpamResourceCidr: Optional[IpamResourceCidr] + IpamResourceCidr: IpamResourceCidr | None class RemoveIpamOrganizationalUnitExclusion(TypedDict, total=False): - OrganizationsEntityPath: Optional[String] + OrganizationsEntityPath: String | None -RemoveIpamOrganizationalUnitExclusionSet = List[RemoveIpamOrganizationalUnitExclusion] +RemoveIpamOrganizationalUnitExclusionSet = list[RemoveIpamOrganizationalUnitExclusion] class ModifyIpamResourceDiscoveryRequest(ServiceRequest): - DryRun: Optional[Boolean] + DryRun: Boolean | None IpamResourceDiscoveryId: IpamResourceDiscoveryId - Description: Optional[String] - AddOperatingRegions: Optional[AddIpamOperatingRegionSet] - RemoveOperatingRegions: Optional[RemoveIpamOperatingRegionSet] - AddOrganizationalUnitExclusions: Optional[AddIpamOrganizationalUnitExclusionSet] - RemoveOrganizationalUnitExclusions: Optional[RemoveIpamOrganizationalUnitExclusionSet] + Description: String | None + AddOperatingRegions: AddIpamOperatingRegionSet | None + RemoveOperatingRegions: RemoveIpamOperatingRegionSet | None + AddOrganizationalUnitExclusions: AddIpamOrganizationalUnitExclusionSet | None + RemoveOrganizationalUnitExclusions: RemoveIpamOrganizationalUnitExclusionSet | None class ModifyIpamResourceDiscoveryResult(TypedDict, total=False): - IpamResourceDiscovery: Optional[IpamResourceDiscovery] + IpamResourceDiscovery: IpamResourceDiscovery | None class ModifyIpamResult(TypedDict, total=False): - Ipam: Optional[Ipam] + Ipam: Ipam | None class ModifyIpamScopeRequest(ServiceRequest): - DryRun: Optional[Boolean] + DryRun: Boolean | None IpamScopeId: IpamScopeId - Description: Optional[String] + Description: String | None + ExternalAuthorityConfiguration: ExternalAuthorityConfiguration | None + RemoveExternalAuthorityConfiguration: Boolean | None class ModifyIpamScopeResult(TypedDict, total=False): - IpamScope: Optional[IpamScope] + IpamScope: IpamScope | None class ModifyLaunchTemplateRequest(ServiceRequest): - DryRun: Optional[Boolean] - ClientToken: Optional[String] - LaunchTemplateId: Optional[LaunchTemplateId] - LaunchTemplateName: Optional[LaunchTemplateName] - DefaultVersion: Optional[String] + DryRun: Boolean | None + ClientToken: String | None + LaunchTemplateId: LaunchTemplateId | None + LaunchTemplateName: LaunchTemplateName | None + DefaultVersion: String | None class ModifyLaunchTemplateResult(TypedDict, total=False): - LaunchTemplate: Optional[LaunchTemplate] + LaunchTemplate: LaunchTemplate | None class ModifyLocalGatewayRouteRequest(ServiceRequest): - DestinationCidrBlock: Optional[String] + DestinationCidrBlock: String | None LocalGatewayRouteTableId: LocalGatewayRoutetableId - LocalGatewayVirtualInterfaceGroupId: Optional[LocalGatewayVirtualInterfaceGroupId] - NetworkInterfaceId: Optional[NetworkInterfaceId] - DryRun: Optional[Boolean] - DestinationPrefixListId: Optional[PrefixListResourceId] + LocalGatewayVirtualInterfaceGroupId: LocalGatewayVirtualInterfaceGroupId | None + NetworkInterfaceId: NetworkInterfaceId | None + DryRun: Boolean | None + DestinationPrefixListId: PrefixListResourceId | None class ModifyLocalGatewayRouteResult(TypedDict, total=False): - Route: Optional[LocalGatewayRoute] + Route: LocalGatewayRoute | None class RemovePrefixListEntry(TypedDict, total=False): Cidr: String -RemovePrefixListEntries = List[RemovePrefixListEntry] +RemovePrefixListEntries = list[RemovePrefixListEntry] class ModifyManagedPrefixListRequest(ServiceRequest): - DryRun: Optional[Boolean] + DryRun: Boolean | None PrefixListId: PrefixListResourceId - CurrentVersion: Optional[Long] - PrefixListName: Optional[String] - AddEntries: Optional[AddPrefixListEntries] - RemoveEntries: Optional[RemovePrefixListEntries] - MaxEntries: Optional[Integer] + CurrentVersion: Long | None + PrefixListName: String | None + AddEntries: AddPrefixListEntries | None + RemoveEntries: RemovePrefixListEntries | None + MaxEntries: Integer | None + IpamPrefixListResolverSyncEnabled: BoxedBoolean | None class ModifyManagedPrefixListResult(TypedDict, total=False): - PrefixList: Optional[ManagedPrefixList] + PrefixList: ManagedPrefixList | None class NetworkInterfaceAttachmentChanges(TypedDict, total=False): - DefaultEnaQueueCount: Optional[Boolean] - EnaQueueCount: Optional[Integer] - AttachmentId: Optional[NetworkInterfaceAttachmentId] - DeleteOnTermination: Optional[Boolean] + DefaultEnaQueueCount: Boolean | None + EnaQueueCount: Integer | None + AttachmentId: NetworkInterfaceAttachmentId | None + DeleteOnTermination: Boolean | None -SubnetIdList = List[SubnetId] +SubnetIdList = list[SubnetId] class ModifyNetworkInterfaceAttributeRequest(ServiceRequest): - EnaSrdSpecification: Optional[EnaSrdSpecification] - EnablePrimaryIpv6: Optional[Boolean] - ConnectionTrackingSpecification: Optional[ConnectionTrackingSpecificationRequest] - AssociatePublicIpAddress: Optional[Boolean] - AssociatedSubnetIds: Optional[SubnetIdList] - DryRun: Optional[Boolean] + EnaSrdSpecification: EnaSrdSpecification | None + EnablePrimaryIpv6: Boolean | None + ConnectionTrackingSpecification: ConnectionTrackingSpecificationRequest | None + AssociatePublicIpAddress: Boolean | None + AssociatedSubnetIds: SubnetIdList | None + DryRun: Boolean | None NetworkInterfaceId: NetworkInterfaceId - Description: Optional[AttributeValue] - SourceDestCheck: Optional[AttributeBooleanValue] - Groups: Optional[SecurityGroupIdStringList] - Attachment: Optional[NetworkInterfaceAttachmentChanges] + Description: AttributeValue | None + SourceDestCheck: AttributeBooleanValue | None + Groups: SecurityGroupIdStringList | None + Attachment: NetworkInterfaceAttachmentChanges | None class ModifyPrivateDnsNameOptionsRequest(ServiceRequest): - DryRun: Optional[Boolean] + DryRun: Boolean | None InstanceId: InstanceId - PrivateDnsHostnameType: Optional[HostnameType] - EnableResourceNameDnsARecord: Optional[Boolean] - EnableResourceNameDnsAAAARecord: Optional[Boolean] + PrivateDnsHostnameType: HostnameType | None + EnableResourceNameDnsARecord: Boolean | None + EnableResourceNameDnsAAAARecord: Boolean | None class ModifyPrivateDnsNameOptionsResult(TypedDict, total=False): - Return: Optional[Boolean] + Return: Boolean | None class ModifyPublicIpDnsNameOptionsRequest(ServiceRequest): NetworkInterfaceId: NetworkInterfaceId HostnameType: PublicIpDnsOption - DryRun: Optional[Boolean] + DryRun: Boolean | None class ModifyPublicIpDnsNameOptionsResult(TypedDict, total=False): - Successful: Optional[Boolean] + Successful: Boolean | None -ReservedInstancesConfigurationList = List[ReservedInstancesConfiguration] +ReservedInstancesConfigurationList = list[ReservedInstancesConfiguration] class ModifyReservedInstancesRequest(ServiceRequest): ReservedInstancesIds: ReservedInstancesIdStringList - ClientToken: Optional[String] + ClientToken: String | None TargetConfigurations: ReservedInstancesConfigurationList class ModifyReservedInstancesResult(TypedDict, total=False): - ReservedInstancesModificationId: Optional[String] + ReservedInstancesModificationId: String | None class ModifyRouteServerRequest(ServiceRequest): RouteServerId: RouteServerId - PersistRoutes: Optional[RouteServerPersistRoutesAction] - PersistRoutesDuration: Optional[BoxedLong] - SnsNotificationsEnabled: Optional[Boolean] - DryRun: Optional[Boolean] + PersistRoutes: RouteServerPersistRoutesAction | None + PersistRoutesDuration: BoxedLong | None + SnsNotificationsEnabled: Boolean | None + DryRun: Boolean | None class ModifyRouteServerResult(TypedDict, total=False): - RouteServer: Optional[RouteServer] + RouteServer: RouteServer | None class SecurityGroupRuleRequest(TypedDict, total=False): - IpProtocol: Optional[String] - FromPort: Optional[Integer] - ToPort: Optional[Integer] - CidrIpv4: Optional[String] - CidrIpv6: Optional[String] - PrefixListId: Optional[PrefixListResourceId] - ReferencedGroupId: Optional[SecurityGroupId] - Description: Optional[String] + IpProtocol: String | None + FromPort: Integer | None + ToPort: Integer | None + CidrIpv4: String | None + CidrIpv6: String | None + PrefixListId: PrefixListResourceId | None + ReferencedGroupId: SecurityGroupId | None + Description: String | None class SecurityGroupRuleUpdate(TypedDict, total=False): SecurityGroupRuleId: SecurityGroupRuleId - SecurityGroupRule: Optional[SecurityGroupRuleRequest] + SecurityGroupRule: SecurityGroupRuleRequest | None -SecurityGroupRuleUpdateList = List[SecurityGroupRuleUpdate] +SecurityGroupRuleUpdateList = list[SecurityGroupRuleUpdate] class ModifySecurityGroupRulesRequest(ServiceRequest): GroupId: SecurityGroupId SecurityGroupRules: SecurityGroupRuleUpdateList - DryRun: Optional[Boolean] + DryRun: Boolean | None class ModifySecurityGroupRulesResult(TypedDict, total=False): - Return: Optional[Boolean] + Return: Boolean | None class ModifySnapshotAttributeRequest(ServiceRequest): - Attribute: Optional[SnapshotAttributeName] - CreateVolumePermission: Optional[CreateVolumePermissionModifications] - GroupNames: Optional[GroupNameStringList] - OperationType: Optional[OperationType] + Attribute: SnapshotAttributeName | None + CreateVolumePermission: CreateVolumePermissionModifications | None + GroupNames: GroupNameStringList | None + OperationType: OperationType | None SnapshotId: SnapshotId - UserIds: Optional[UserIdStringList] - DryRun: Optional[Boolean] + UserIds: UserIdStringList | None + DryRun: Boolean | None class ModifySnapshotTierRequest(ServiceRequest): SnapshotId: SnapshotId - StorageTier: Optional[TargetStorageTier] - DryRun: Optional[Boolean] + StorageTier: TargetStorageTier | None + DryRun: Boolean | None class ModifySnapshotTierResult(TypedDict, total=False): - SnapshotId: Optional[String] - TieringStartTime: Optional[MillisecondDateTime] + SnapshotId: String | None + TieringStartTime: MillisecondDateTime | None class ModifySpotFleetRequestRequest(ServiceRequest): - LaunchTemplateConfigs: Optional[LaunchTemplateConfigList] - OnDemandTargetCapacity: Optional[Integer] - Context: Optional[String] + LaunchTemplateConfigs: LaunchTemplateConfigList | None + OnDemandTargetCapacity: Integer | None + Context: String | None SpotFleetRequestId: SpotFleetRequestId - TargetCapacity: Optional[Integer] - ExcessCapacityTerminationPolicy: Optional[ExcessCapacityTerminationPolicy] + TargetCapacity: Integer | None + ExcessCapacityTerminationPolicy: ExcessCapacityTerminationPolicy | None class ModifySpotFleetRequestResponse(TypedDict, total=False): - Return: Optional[Boolean] + Return: Boolean | None class ModifySubnetAttributeRequest(ServiceRequest): - AssignIpv6AddressOnCreation: Optional[AttributeBooleanValue] - MapPublicIpOnLaunch: Optional[AttributeBooleanValue] + AssignIpv6AddressOnCreation: AttributeBooleanValue | None + MapPublicIpOnLaunch: AttributeBooleanValue | None SubnetId: SubnetId - MapCustomerOwnedIpOnLaunch: Optional[AttributeBooleanValue] - CustomerOwnedIpv4Pool: Optional[CoipPoolId] - EnableDns64: Optional[AttributeBooleanValue] - PrivateDnsHostnameTypeOnLaunch: Optional[HostnameType] - EnableResourceNameDnsARecordOnLaunch: Optional[AttributeBooleanValue] - EnableResourceNameDnsAAAARecordOnLaunch: Optional[AttributeBooleanValue] - EnableLniAtDeviceIndex: Optional[Integer] - DisableLniAtDeviceIndex: Optional[AttributeBooleanValue] + MapCustomerOwnedIpOnLaunch: AttributeBooleanValue | None + CustomerOwnedIpv4Pool: CoipPoolId | None + EnableDns64: AttributeBooleanValue | None + PrivateDnsHostnameTypeOnLaunch: HostnameType | None + EnableResourceNameDnsARecordOnLaunch: AttributeBooleanValue | None + EnableResourceNameDnsAAAARecordOnLaunch: AttributeBooleanValue | None + EnableLniAtDeviceIndex: Integer | None + DisableLniAtDeviceIndex: AttributeBooleanValue | None class ModifyTrafficMirrorFilterNetworkServicesRequest(ServiceRequest): TrafficMirrorFilterId: TrafficMirrorFilterId - AddNetworkServices: Optional[TrafficMirrorNetworkServiceList] - RemoveNetworkServices: Optional[TrafficMirrorNetworkServiceList] - DryRun: Optional[Boolean] + AddNetworkServices: TrafficMirrorNetworkServiceList | None + RemoveNetworkServices: TrafficMirrorNetworkServiceList | None + DryRun: Boolean | None class ModifyTrafficMirrorFilterNetworkServicesResult(TypedDict, total=False): - TrafficMirrorFilter: Optional[TrafficMirrorFilter] + TrafficMirrorFilter: TrafficMirrorFilter | None -TrafficMirrorFilterRuleFieldList = List[TrafficMirrorFilterRuleField] +TrafficMirrorFilterRuleFieldList = list[TrafficMirrorFilterRuleField] class ModifyTrafficMirrorFilterRuleRequest(ServiceRequest): TrafficMirrorFilterRuleId: TrafficMirrorFilterRuleIdWithResolver - TrafficDirection: Optional[TrafficDirection] - RuleNumber: Optional[Integer] - RuleAction: Optional[TrafficMirrorRuleAction] - DestinationPortRange: Optional[TrafficMirrorPortRangeRequest] - SourcePortRange: Optional[TrafficMirrorPortRangeRequest] - Protocol: Optional[Integer] - DestinationCidrBlock: Optional[String] - SourceCidrBlock: Optional[String] - Description: Optional[String] - RemoveFields: Optional[TrafficMirrorFilterRuleFieldList] - DryRun: Optional[Boolean] + TrafficDirection: TrafficDirection | None + RuleNumber: Integer | None + RuleAction: TrafficMirrorRuleAction | None + DestinationPortRange: TrafficMirrorPortRangeRequest | None + SourcePortRange: TrafficMirrorPortRangeRequest | None + Protocol: Integer | None + DestinationCidrBlock: String | None + SourceCidrBlock: String | None + Description: String | None + RemoveFields: TrafficMirrorFilterRuleFieldList | None + DryRun: Boolean | None class ModifyTrafficMirrorFilterRuleResult(TypedDict, total=False): - TrafficMirrorFilterRule: Optional[TrafficMirrorFilterRule] + TrafficMirrorFilterRule: TrafficMirrorFilterRule | None -TrafficMirrorSessionFieldList = List[TrafficMirrorSessionField] +TrafficMirrorSessionFieldList = list[TrafficMirrorSessionField] class ModifyTrafficMirrorSessionRequest(ServiceRequest): TrafficMirrorSessionId: TrafficMirrorSessionId - TrafficMirrorTargetId: Optional[TrafficMirrorTargetId] - TrafficMirrorFilterId: Optional[TrafficMirrorFilterId] - PacketLength: Optional[Integer] - SessionNumber: Optional[Integer] - VirtualNetworkId: Optional[Integer] - Description: Optional[String] - RemoveFields: Optional[TrafficMirrorSessionFieldList] - DryRun: Optional[Boolean] + TrafficMirrorTargetId: TrafficMirrorTargetId | None + TrafficMirrorFilterId: TrafficMirrorFilterId | None + PacketLength: Integer | None + SessionNumber: Integer | None + VirtualNetworkId: Integer | None + Description: String | None + RemoveFields: TrafficMirrorSessionFieldList | None + DryRun: Boolean | None class ModifyTrafficMirrorSessionResult(TypedDict, total=False): - TrafficMirrorSession: Optional[TrafficMirrorSession] + TrafficMirrorSession: TrafficMirrorSession | None + + +class ModifyTransitGatewayMeteringPolicyRequest(ServiceRequest): + TransitGatewayMeteringPolicyId: TransitGatewayMeteringPolicyId + AddMiddleboxAttachmentIds: TransitGatewayAttachmentIdStringList | None + RemoveMiddleboxAttachmentIds: TransitGatewayAttachmentIdStringList | None + DryRun: Boolean | None + + +class ModifyTransitGatewayMeteringPolicyResult(TypedDict, total=False): + TransitGatewayMeteringPolicy: TransitGatewayMeteringPolicy | None class ModifyTransitGatewayOptions(TypedDict, total=False): - AddTransitGatewayCidrBlocks: Optional[TransitGatewayCidrBlockStringList] - RemoveTransitGatewayCidrBlocks: Optional[TransitGatewayCidrBlockStringList] - VpnEcmpSupport: Optional[VpnEcmpSupportValue] - DnsSupport: Optional[DnsSupportValue] - SecurityGroupReferencingSupport: Optional[SecurityGroupReferencingSupportValue] - AutoAcceptSharedAttachments: Optional[AutoAcceptSharedAttachmentsValue] - DefaultRouteTableAssociation: Optional[DefaultRouteTableAssociationValue] - AssociationDefaultRouteTableId: Optional[TransitGatewayRouteTableId] - DefaultRouteTablePropagation: Optional[DefaultRouteTablePropagationValue] - PropagationDefaultRouteTableId: Optional[TransitGatewayRouteTableId] - AmazonSideAsn: Optional[Long] + AddTransitGatewayCidrBlocks: TransitGatewayCidrBlockStringList | None + RemoveTransitGatewayCidrBlocks: TransitGatewayCidrBlockStringList | None + VpnEcmpSupport: VpnEcmpSupportValue | None + DnsSupport: DnsSupportValue | None + SecurityGroupReferencingSupport: SecurityGroupReferencingSupportValue | None + AutoAcceptSharedAttachments: AutoAcceptSharedAttachmentsValue | None + DefaultRouteTableAssociation: DefaultRouteTableAssociationValue | None + AssociationDefaultRouteTableId: TransitGatewayRouteTableId | None + DefaultRouteTablePropagation: DefaultRouteTablePropagationValue | None + PropagationDefaultRouteTableId: TransitGatewayRouteTableId | None + AmazonSideAsn: Long | None + EncryptionSupport: EncryptionSupportOptionValue | None class ModifyTransitGatewayPrefixListReferenceRequest(ServiceRequest): TransitGatewayRouteTableId: TransitGatewayRouteTableId PrefixListId: PrefixListResourceId - TransitGatewayAttachmentId: Optional[TransitGatewayAttachmentId] - Blackhole: Optional[Boolean] - DryRun: Optional[Boolean] + TransitGatewayAttachmentId: TransitGatewayAttachmentId | None + Blackhole: Boolean | None + DryRun: Boolean | None class ModifyTransitGatewayPrefixListReferenceResult(TypedDict, total=False): - TransitGatewayPrefixListReference: Optional[TransitGatewayPrefixListReference] + TransitGatewayPrefixListReference: TransitGatewayPrefixListReference | None class ModifyTransitGatewayRequest(ServiceRequest): TransitGatewayId: TransitGatewayId - Description: Optional[String] - Options: Optional[ModifyTransitGatewayOptions] - DryRun: Optional[Boolean] + Description: String | None + Options: ModifyTransitGatewayOptions | None + DryRun: Boolean | None class ModifyTransitGatewayResult(TypedDict, total=False): - TransitGateway: Optional[TransitGateway] + TransitGateway: TransitGateway | None class ModifyTransitGatewayVpcAttachmentRequestOptions(TypedDict, total=False): - DnsSupport: Optional[DnsSupportValue] - SecurityGroupReferencingSupport: Optional[SecurityGroupReferencingSupportValue] - Ipv6Support: Optional[Ipv6SupportValue] - ApplianceModeSupport: Optional[ApplianceModeSupportValue] + DnsSupport: DnsSupportValue | None + SecurityGroupReferencingSupport: SecurityGroupReferencingSupportValue | None + Ipv6Support: Ipv6SupportValue | None + ApplianceModeSupport: ApplianceModeSupportValue | None class ModifyTransitGatewayVpcAttachmentRequest(ServiceRequest): TransitGatewayAttachmentId: TransitGatewayAttachmentId - AddSubnetIds: Optional[TransitGatewaySubnetIdList] - RemoveSubnetIds: Optional[TransitGatewaySubnetIdList] - Options: Optional[ModifyTransitGatewayVpcAttachmentRequestOptions] - DryRun: Optional[Boolean] + AddSubnetIds: TransitGatewaySubnetIdList | None + RemoveSubnetIds: TransitGatewaySubnetIdList | None + Options: ModifyTransitGatewayVpcAttachmentRequestOptions | None + DryRun: Boolean | None class ModifyTransitGatewayVpcAttachmentResult(TypedDict, total=False): - TransitGatewayVpcAttachment: Optional[TransitGatewayVpcAttachment] + TransitGatewayVpcAttachment: TransitGatewayVpcAttachment | None class ModifyVerifiedAccessEndpointPortRange(TypedDict, total=False): - FromPort: Optional[VerifiedAccessEndpointPortNumber] - ToPort: Optional[VerifiedAccessEndpointPortNumber] + FromPort: VerifiedAccessEndpointPortNumber | None + ToPort: VerifiedAccessEndpointPortNumber | None -ModifyVerifiedAccessEndpointPortRangeList = List[ModifyVerifiedAccessEndpointPortRange] +ModifyVerifiedAccessEndpointPortRangeList = list[ModifyVerifiedAccessEndpointPortRange] class ModifyVerifiedAccessEndpointCidrOptions(TypedDict, total=False): - PortRanges: Optional[ModifyVerifiedAccessEndpointPortRangeList] + PortRanges: ModifyVerifiedAccessEndpointPortRangeList | None class ModifyVerifiedAccessEndpointEniOptions(TypedDict, total=False): - Protocol: Optional[VerifiedAccessEndpointProtocol] - Port: Optional[VerifiedAccessEndpointPortNumber] - PortRanges: Optional[ModifyVerifiedAccessEndpointPortRangeList] + Protocol: VerifiedAccessEndpointProtocol | None + Port: VerifiedAccessEndpointPortNumber | None + PortRanges: ModifyVerifiedAccessEndpointPortRangeList | None -ModifyVerifiedAccessEndpointSubnetIdList = List[SubnetId] +ModifyVerifiedAccessEndpointSubnetIdList = list[SubnetId] class ModifyVerifiedAccessEndpointLoadBalancerOptions(TypedDict, total=False): - SubnetIds: Optional[ModifyVerifiedAccessEndpointSubnetIdList] - Protocol: Optional[VerifiedAccessEndpointProtocol] - Port: Optional[VerifiedAccessEndpointPortNumber] - PortRanges: Optional[ModifyVerifiedAccessEndpointPortRangeList] + SubnetIds: ModifyVerifiedAccessEndpointSubnetIdList | None + Protocol: VerifiedAccessEndpointProtocol | None + Port: VerifiedAccessEndpointPortNumber | None + PortRanges: ModifyVerifiedAccessEndpointPortRangeList | None class ModifyVerifiedAccessEndpointPolicyRequest(ServiceRequest): VerifiedAccessEndpointId: VerifiedAccessEndpointId - PolicyEnabled: Optional[Boolean] - PolicyDocument: Optional[String] - ClientToken: Optional[String] - DryRun: Optional[Boolean] - SseSpecification: Optional[VerifiedAccessSseSpecificationRequest] + PolicyEnabled: Boolean | None + PolicyDocument: String | None + ClientToken: String | None + DryRun: Boolean | None + SseSpecification: VerifiedAccessSseSpecificationRequest | None class ModifyVerifiedAccessEndpointPolicyResult(TypedDict, total=False): - PolicyEnabled: Optional[Boolean] - PolicyDocument: Optional[String] - SseSpecification: Optional[VerifiedAccessSseSpecificationResponse] + PolicyEnabled: Boolean | None + PolicyDocument: String | None + SseSpecification: VerifiedAccessSseSpecificationResponse | None class ModifyVerifiedAccessEndpointRdsOptions(TypedDict, total=False): - SubnetIds: Optional[ModifyVerifiedAccessEndpointSubnetIdList] - Port: Optional[VerifiedAccessEndpointPortNumber] - RdsEndpoint: Optional[String] + SubnetIds: ModifyVerifiedAccessEndpointSubnetIdList | None + Port: VerifiedAccessEndpointPortNumber | None + RdsEndpoint: String | None class ModifyVerifiedAccessEndpointRequest(ServiceRequest): VerifiedAccessEndpointId: VerifiedAccessEndpointId - VerifiedAccessGroupId: Optional[VerifiedAccessGroupId] - LoadBalancerOptions: Optional[ModifyVerifiedAccessEndpointLoadBalancerOptions] - NetworkInterfaceOptions: Optional[ModifyVerifiedAccessEndpointEniOptions] - Description: Optional[String] - ClientToken: Optional[String] - DryRun: Optional[Boolean] - RdsOptions: Optional[ModifyVerifiedAccessEndpointRdsOptions] - CidrOptions: Optional[ModifyVerifiedAccessEndpointCidrOptions] + VerifiedAccessGroupId: VerifiedAccessGroupId | None + LoadBalancerOptions: ModifyVerifiedAccessEndpointLoadBalancerOptions | None + NetworkInterfaceOptions: ModifyVerifiedAccessEndpointEniOptions | None + Description: String | None + ClientToken: String | None + DryRun: Boolean | None + RdsOptions: ModifyVerifiedAccessEndpointRdsOptions | None + CidrOptions: ModifyVerifiedAccessEndpointCidrOptions | None class ModifyVerifiedAccessEndpointResult(TypedDict, total=False): - VerifiedAccessEndpoint: Optional[VerifiedAccessEndpoint] + VerifiedAccessEndpoint: VerifiedAccessEndpoint | None class ModifyVerifiedAccessGroupPolicyRequest(ServiceRequest): VerifiedAccessGroupId: VerifiedAccessGroupId - PolicyEnabled: Optional[Boolean] - PolicyDocument: Optional[String] - ClientToken: Optional[String] - DryRun: Optional[Boolean] - SseSpecification: Optional[VerifiedAccessSseSpecificationRequest] + PolicyEnabled: Boolean | None + PolicyDocument: String | None + ClientToken: String | None + DryRun: Boolean | None + SseSpecification: VerifiedAccessSseSpecificationRequest | None class ModifyVerifiedAccessGroupPolicyResult(TypedDict, total=False): - PolicyEnabled: Optional[Boolean] - PolicyDocument: Optional[String] - SseSpecification: Optional[VerifiedAccessSseSpecificationResponse] + PolicyEnabled: Boolean | None + PolicyDocument: String | None + SseSpecification: VerifiedAccessSseSpecificationResponse | None class ModifyVerifiedAccessGroupRequest(ServiceRequest): VerifiedAccessGroupId: VerifiedAccessGroupId - VerifiedAccessInstanceId: Optional[VerifiedAccessInstanceId] - Description: Optional[String] - ClientToken: Optional[String] - DryRun: Optional[Boolean] + VerifiedAccessInstanceId: VerifiedAccessInstanceId | None + Description: String | None + ClientToken: String | None + DryRun: Boolean | None class ModifyVerifiedAccessGroupResult(TypedDict, total=False): - VerifiedAccessGroup: Optional[VerifiedAccessGroup] + VerifiedAccessGroup: VerifiedAccessGroup | None class VerifiedAccessLogKinesisDataFirehoseDestinationOptions(TypedDict, total=False): Enabled: Boolean - DeliveryStream: Optional[String] + DeliveryStream: String | None class VerifiedAccessLogCloudWatchLogsDestinationOptions(TypedDict, total=False): Enabled: Boolean - LogGroup: Optional[String] + LogGroup: String | None class VerifiedAccessLogS3DestinationOptions(TypedDict, total=False): Enabled: Boolean - BucketName: Optional[String] - Prefix: Optional[String] - BucketOwner: Optional[String] + BucketName: String | None + Prefix: String | None + BucketOwner: String | None class VerifiedAccessLogOptions(TypedDict, total=False): - S3: Optional[VerifiedAccessLogS3DestinationOptions] - CloudWatchLogs: Optional[VerifiedAccessLogCloudWatchLogsDestinationOptions] - KinesisDataFirehose: Optional[VerifiedAccessLogKinesisDataFirehoseDestinationOptions] - LogVersion: Optional[String] - IncludeTrustContext: Optional[Boolean] + S3: VerifiedAccessLogS3DestinationOptions | None + CloudWatchLogs: VerifiedAccessLogCloudWatchLogsDestinationOptions | None + KinesisDataFirehose: VerifiedAccessLogKinesisDataFirehoseDestinationOptions | None + LogVersion: String | None + IncludeTrustContext: Boolean | None class ModifyVerifiedAccessInstanceLoggingConfigurationRequest(ServiceRequest): VerifiedAccessInstanceId: VerifiedAccessInstanceId AccessLogs: VerifiedAccessLogOptions - DryRun: Optional[Boolean] - ClientToken: Optional[String] + DryRun: Boolean | None + ClientToken: String | None class ModifyVerifiedAccessInstanceLoggingConfigurationResult(TypedDict, total=False): - LoggingConfiguration: Optional[VerifiedAccessInstanceLoggingConfiguration] + LoggingConfiguration: VerifiedAccessInstanceLoggingConfiguration | None class ModifyVerifiedAccessInstanceRequest(ServiceRequest): VerifiedAccessInstanceId: VerifiedAccessInstanceId - Description: Optional[String] - DryRun: Optional[Boolean] - ClientToken: Optional[String] - CidrEndpointsCustomSubDomain: Optional[String] + Description: String | None + DryRun: Boolean | None + ClientToken: String | None + CidrEndpointsCustomSubDomain: String | None class ModifyVerifiedAccessInstanceResult(TypedDict, total=False): - VerifiedAccessInstance: Optional[VerifiedAccessInstance] + VerifiedAccessInstance: VerifiedAccessInstance | None class ModifyVerifiedAccessNativeApplicationOidcOptions(TypedDict, total=False): - PublicSigningKeyEndpoint: Optional[String] - Issuer: Optional[String] - AuthorizationEndpoint: Optional[String] - TokenEndpoint: Optional[String] - UserInfoEndpoint: Optional[String] - ClientId: Optional[String] - ClientSecret: Optional[ClientSecretType] - Scope: Optional[String] + PublicSigningKeyEndpoint: String | None + Issuer: String | None + AuthorizationEndpoint: String | None + TokenEndpoint: String | None + UserInfoEndpoint: String | None + ClientId: String | None + ClientSecret: ClientSecretType | None + Scope: String | None class ModifyVerifiedAccessTrustProviderDeviceOptions(TypedDict, total=False): - PublicSigningKeyUrl: Optional[String] + PublicSigningKeyUrl: String | None class ModifyVerifiedAccessTrustProviderOidcOptions(TypedDict, total=False): - Issuer: Optional[String] - AuthorizationEndpoint: Optional[String] - TokenEndpoint: Optional[String] - UserInfoEndpoint: Optional[String] - ClientId: Optional[String] - ClientSecret: Optional[ClientSecretType] - Scope: Optional[String] + Issuer: String | None + AuthorizationEndpoint: String | None + TokenEndpoint: String | None + UserInfoEndpoint: String | None + ClientId: String | None + ClientSecret: ClientSecretType | None + Scope: String | None class ModifyVerifiedAccessTrustProviderRequest(ServiceRequest): VerifiedAccessTrustProviderId: VerifiedAccessTrustProviderId - OidcOptions: Optional[ModifyVerifiedAccessTrustProviderOidcOptions] - DeviceOptions: Optional[ModifyVerifiedAccessTrustProviderDeviceOptions] - Description: Optional[String] - DryRun: Optional[Boolean] - ClientToken: Optional[String] - SseSpecification: Optional[VerifiedAccessSseSpecificationRequest] - NativeApplicationOidcOptions: Optional[ModifyVerifiedAccessNativeApplicationOidcOptions] + OidcOptions: ModifyVerifiedAccessTrustProviderOidcOptions | None + DeviceOptions: ModifyVerifiedAccessTrustProviderDeviceOptions | None + Description: String | None + DryRun: Boolean | None + ClientToken: String | None + SseSpecification: VerifiedAccessSseSpecificationRequest | None + NativeApplicationOidcOptions: ModifyVerifiedAccessNativeApplicationOidcOptions | None class ModifyVerifiedAccessTrustProviderResult(TypedDict, total=False): - VerifiedAccessTrustProvider: Optional[VerifiedAccessTrustProvider] + VerifiedAccessTrustProvider: VerifiedAccessTrustProvider | None class ModifyVolumeAttributeRequest(ServiceRequest): - AutoEnableIO: Optional[AttributeBooleanValue] + AutoEnableIO: AttributeBooleanValue | None VolumeId: VolumeId - DryRun: Optional[Boolean] + DryRun: Boolean | None class ModifyVolumeRequest(ServiceRequest): - DryRun: Optional[Boolean] + DryRun: Boolean | None VolumeId: VolumeId - Size: Optional[Integer] - VolumeType: Optional[VolumeType] - Iops: Optional[Integer] - Throughput: Optional[Integer] - MultiAttachEnabled: Optional[Boolean] + Size: Integer | None + VolumeType: VolumeType | None + Iops: Integer | None + Throughput: Integer | None + MultiAttachEnabled: Boolean | None class ModifyVolumeResult(TypedDict, total=False): - VolumeModification: Optional[VolumeModification] + VolumeModification: VolumeModification | None class ModifyVpcAttributeRequest(ServiceRequest): - EnableDnsHostnames: Optional[AttributeBooleanValue] - EnableDnsSupport: Optional[AttributeBooleanValue] + EnableDnsHostnames: AttributeBooleanValue | None + EnableDnsSupport: AttributeBooleanValue | None VpcId: VpcId - EnableNetworkAddressUsageMetrics: Optional[AttributeBooleanValue] + EnableNetworkAddressUsageMetrics: AttributeBooleanValue | None class ModifyVpcBlockPublicAccessExclusionRequest(ServiceRequest): - DryRun: Optional[Boolean] + DryRun: Boolean | None ExclusionId: VpcBlockPublicAccessExclusionId InternetGatewayExclusionMode: InternetGatewayExclusionMode class ModifyVpcBlockPublicAccessExclusionResult(TypedDict, total=False): - VpcBlockPublicAccessExclusion: Optional[VpcBlockPublicAccessExclusion] + VpcBlockPublicAccessExclusion: VpcBlockPublicAccessExclusion | None class ModifyVpcBlockPublicAccessOptionsRequest(ServiceRequest): - DryRun: Optional[Boolean] + DryRun: Boolean | None InternetGatewayBlockMode: InternetGatewayBlockMode class ModifyVpcBlockPublicAccessOptionsResult(TypedDict, total=False): - VpcBlockPublicAccessOptions: Optional[VpcBlockPublicAccessOptions] + VpcBlockPublicAccessOptions: VpcBlockPublicAccessOptions | None + + +class ModifyVpcEncryptionControlRequest(ServiceRequest): + DryRun: Boolean | None + VpcEncryptionControlId: VpcEncryptionControlId + Mode: VpcEncryptionControlMode | None + InternetGatewayExclusion: VpcEncryptionControlExclusionStateInput | None + EgressOnlyInternetGatewayExclusion: VpcEncryptionControlExclusionStateInput | None + NatGatewayExclusion: VpcEncryptionControlExclusionStateInput | None + VirtualPrivateGatewayExclusion: VpcEncryptionControlExclusionStateInput | None + VpcPeeringExclusion: VpcEncryptionControlExclusionStateInput | None + LambdaExclusion: VpcEncryptionControlExclusionStateInput | None + VpcLatticeExclusion: VpcEncryptionControlExclusionStateInput | None + ElasticFileSystemExclusion: VpcEncryptionControlExclusionStateInput | None + + +class ModifyVpcEncryptionControlResult(TypedDict, total=False): + VpcEncryptionControl: VpcEncryptionControl | None class ModifyVpcEndpointConnectionNotificationRequest(ServiceRequest): - DryRun: Optional[Boolean] + DryRun: Boolean | None ConnectionNotificationId: ConnectionNotificationId - ConnectionNotificationArn: Optional[String] - ConnectionEvents: Optional[ValueStringList] + ConnectionNotificationArn: String | None + ConnectionEvents: ValueStringList | None class ModifyVpcEndpointConnectionNotificationResult(TypedDict, total=False): - ReturnValue: Optional[Boolean] + ReturnValue: Boolean | None class ModifyVpcEndpointRequest(ServiceRequest): - DryRun: Optional[Boolean] + DryRun: Boolean | None VpcEndpointId: VpcEndpointId - ResetPolicy: Optional[Boolean] - PolicyDocument: Optional[String] - AddRouteTableIds: Optional[VpcEndpointRouteTableIdList] - RemoveRouteTableIds: Optional[VpcEndpointRouteTableIdList] - AddSubnetIds: Optional[VpcEndpointSubnetIdList] - RemoveSubnetIds: Optional[VpcEndpointSubnetIdList] - AddSecurityGroupIds: Optional[VpcEndpointSecurityGroupIdList] - RemoveSecurityGroupIds: Optional[VpcEndpointSecurityGroupIdList] - IpAddressType: Optional[IpAddressType] - DnsOptions: Optional[DnsOptionsSpecification] - PrivateDnsEnabled: Optional[Boolean] - SubnetConfigurations: Optional[SubnetConfigurationsList] + ResetPolicy: Boolean | None + PolicyDocument: String | None + AddRouteTableIds: VpcEndpointRouteTableIdList | None + RemoveRouteTableIds: VpcEndpointRouteTableIdList | None + AddSubnetIds: VpcEndpointSubnetIdList | None + RemoveSubnetIds: VpcEndpointSubnetIdList | None + AddSecurityGroupIds: VpcEndpointSecurityGroupIdList | None + RemoveSecurityGroupIds: VpcEndpointSecurityGroupIdList | None + IpAddressType: IpAddressType | None + DnsOptions: DnsOptionsSpecification | None + PrivateDnsEnabled: Boolean | None + SubnetConfigurations: SubnetConfigurationsList | None class ModifyVpcEndpointResult(TypedDict, total=False): - Return: Optional[Boolean] + Return: Boolean | None class ModifyVpcEndpointServiceConfigurationRequest(ServiceRequest): - DryRun: Optional[Boolean] + DryRun: Boolean | None ServiceId: VpcEndpointServiceId - PrivateDnsName: Optional[String] - RemovePrivateDnsName: Optional[Boolean] - AcceptanceRequired: Optional[Boolean] - AddNetworkLoadBalancerArns: Optional[ValueStringList] - RemoveNetworkLoadBalancerArns: Optional[ValueStringList] - AddGatewayLoadBalancerArns: Optional[ValueStringList] - RemoveGatewayLoadBalancerArns: Optional[ValueStringList] - AddSupportedIpAddressTypes: Optional[ValueStringList] - RemoveSupportedIpAddressTypes: Optional[ValueStringList] - AddSupportedRegions: Optional[ValueStringList] - RemoveSupportedRegions: Optional[ValueStringList] + PrivateDnsName: String | None + RemovePrivateDnsName: Boolean | None + AcceptanceRequired: Boolean | None + AddNetworkLoadBalancerArns: ValueStringList | None + RemoveNetworkLoadBalancerArns: ValueStringList | None + AddGatewayLoadBalancerArns: ValueStringList | None + RemoveGatewayLoadBalancerArns: ValueStringList | None + AddSupportedIpAddressTypes: ValueStringList | None + RemoveSupportedIpAddressTypes: ValueStringList | None + AddSupportedRegions: ValueStringList | None + RemoveSupportedRegions: ValueStringList | None class ModifyVpcEndpointServiceConfigurationResult(TypedDict, total=False): - Return: Optional[Boolean] + Return: Boolean | None class ModifyVpcEndpointServicePayerResponsibilityRequest(ServiceRequest): - DryRun: Optional[Boolean] + DryRun: Boolean | None ServiceId: VpcEndpointServiceId PayerResponsibility: PayerResponsibility class ModifyVpcEndpointServicePayerResponsibilityResult(TypedDict, total=False): - ReturnValue: Optional[Boolean] + ReturnValue: Boolean | None class ModifyVpcEndpointServicePermissionsRequest(ServiceRequest): - DryRun: Optional[Boolean] + DryRun: Boolean | None ServiceId: VpcEndpointServiceId - AddAllowedPrincipals: Optional[ValueStringList] - RemoveAllowedPrincipals: Optional[ValueStringList] + AddAllowedPrincipals: ValueStringList | None + RemoveAllowedPrincipals: ValueStringList | None class ModifyVpcEndpointServicePermissionsResult(TypedDict, total=False): - AddedPrincipals: Optional[AddedPrincipalSet] - ReturnValue: Optional[Boolean] + AddedPrincipals: AddedPrincipalSet | None + ReturnValue: Boolean | None class PeeringConnectionOptionsRequest(TypedDict, total=False): - AllowDnsResolutionFromRemoteVpc: Optional[Boolean] - AllowEgressFromLocalClassicLinkToRemoteVpc: Optional[Boolean] - AllowEgressFromLocalVpcToRemoteClassicLink: Optional[Boolean] + AllowDnsResolutionFromRemoteVpc: Boolean | None + AllowEgressFromLocalClassicLinkToRemoteVpc: Boolean | None + AllowEgressFromLocalVpcToRemoteClassicLink: Boolean | None class ModifyVpcPeeringConnectionOptionsRequest(ServiceRequest): - AccepterPeeringConnectionOptions: Optional[PeeringConnectionOptionsRequest] - DryRun: Optional[Boolean] - RequesterPeeringConnectionOptions: Optional[PeeringConnectionOptionsRequest] + AccepterPeeringConnectionOptions: PeeringConnectionOptionsRequest | None + DryRun: Boolean | None + RequesterPeeringConnectionOptions: PeeringConnectionOptionsRequest | None VpcPeeringConnectionId: VpcPeeringConnectionId class PeeringConnectionOptions(TypedDict, total=False): - AllowDnsResolutionFromRemoteVpc: Optional[Boolean] - AllowEgressFromLocalClassicLinkToRemoteVpc: Optional[Boolean] - AllowEgressFromLocalVpcToRemoteClassicLink: Optional[Boolean] + AllowDnsResolutionFromRemoteVpc: Boolean | None + AllowEgressFromLocalClassicLinkToRemoteVpc: Boolean | None + AllowEgressFromLocalVpcToRemoteClassicLink: Boolean | None class ModifyVpcPeeringConnectionOptionsResult(TypedDict, total=False): - AccepterPeeringConnectionOptions: Optional[PeeringConnectionOptions] - RequesterPeeringConnectionOptions: Optional[PeeringConnectionOptions] + AccepterPeeringConnectionOptions: PeeringConnectionOptions | None + RequesterPeeringConnectionOptions: PeeringConnectionOptions | None class ModifyVpcTenancyRequest(ServiceRequest): VpcId: VpcId InstanceTenancy: VpcTenancy - DryRun: Optional[Boolean] + DryRun: Boolean | None class ModifyVpcTenancyResult(TypedDict, total=False): - ReturnValue: Optional[Boolean] + ReturnValue: Boolean | None class ModifyVpnConnectionOptionsRequest(ServiceRequest): VpnConnectionId: VpnConnectionId - LocalIpv4NetworkCidr: Optional[String] - RemoteIpv4NetworkCidr: Optional[String] - LocalIpv6NetworkCidr: Optional[String] - RemoteIpv6NetworkCidr: Optional[String] - DryRun: Optional[Boolean] + LocalIpv4NetworkCidr: String | None + RemoteIpv4NetworkCidr: String | None + LocalIpv6NetworkCidr: String | None + RemoteIpv6NetworkCidr: String | None + DryRun: Boolean | None class ModifyVpnConnectionOptionsResult(TypedDict, total=False): - VpnConnection: Optional[VpnConnection] + VpnConnection: VpnConnection | None class ModifyVpnConnectionRequest(ServiceRequest): VpnConnectionId: VpnConnectionId - TransitGatewayId: Optional[TransitGatewayId] - CustomerGatewayId: Optional[CustomerGatewayId] - VpnGatewayId: Optional[VpnGatewayId] - DryRun: Optional[Boolean] + TransitGatewayId: TransitGatewayId | None + CustomerGatewayId: CustomerGatewayId | None + VpnGatewayId: VpnGatewayId | None + DryRun: Boolean | None class ModifyVpnConnectionResult(TypedDict, total=False): - VpnConnection: Optional[VpnConnection] + VpnConnection: VpnConnection | None class ModifyVpnTunnelCertificateRequest(ServiceRequest): VpnConnectionId: VpnConnectionId VpnTunnelOutsideIpAddress: String - DryRun: Optional[Boolean] + DryRun: Boolean | None class ModifyVpnTunnelCertificateResult(TypedDict, total=False): - VpnConnection: Optional[VpnConnection] + VpnConnection: VpnConnection | None class ModifyVpnTunnelOptionsSpecification(TypedDict, total=False): - TunnelInsideCidr: Optional[String] - TunnelInsideIpv6Cidr: Optional[String] - PreSharedKey: Optional[preSharedKey] - Phase1LifetimeSeconds: Optional[Integer] - Phase2LifetimeSeconds: Optional[Integer] - RekeyMarginTimeSeconds: Optional[Integer] - RekeyFuzzPercentage: Optional[Integer] - ReplayWindowSize: Optional[Integer] - DPDTimeoutSeconds: Optional[Integer] - DPDTimeoutAction: Optional[String] - Phase1EncryptionAlgorithms: Optional[Phase1EncryptionAlgorithmsRequestList] - Phase2EncryptionAlgorithms: Optional[Phase2EncryptionAlgorithmsRequestList] - Phase1IntegrityAlgorithms: Optional[Phase1IntegrityAlgorithmsRequestList] - Phase2IntegrityAlgorithms: Optional[Phase2IntegrityAlgorithmsRequestList] - Phase1DHGroupNumbers: Optional[Phase1DHGroupNumbersRequestList] - Phase2DHGroupNumbers: Optional[Phase2DHGroupNumbersRequestList] - IKEVersions: Optional[IKEVersionsRequestList] - StartupAction: Optional[String] - LogOptions: Optional[VpnTunnelLogOptionsSpecification] - EnableTunnelLifecycleControl: Optional[Boolean] + TunnelInsideCidr: String | None + TunnelInsideIpv6Cidr: String | None + PreSharedKey: preSharedKey | None + Phase1LifetimeSeconds: Integer | None + Phase2LifetimeSeconds: Integer | None + RekeyMarginTimeSeconds: Integer | None + RekeyFuzzPercentage: Integer | None + ReplayWindowSize: Integer | None + DPDTimeoutSeconds: Integer | None + DPDTimeoutAction: String | None + Phase1EncryptionAlgorithms: Phase1EncryptionAlgorithmsRequestList | None + Phase2EncryptionAlgorithms: Phase2EncryptionAlgorithmsRequestList | None + Phase1IntegrityAlgorithms: Phase1IntegrityAlgorithmsRequestList | None + Phase2IntegrityAlgorithms: Phase2IntegrityAlgorithmsRequestList | None + Phase1DHGroupNumbers: Phase1DHGroupNumbersRequestList | None + Phase2DHGroupNumbers: Phase2DHGroupNumbersRequestList | None + IKEVersions: IKEVersionsRequestList | None + StartupAction: String | None + LogOptions: VpnTunnelLogOptionsSpecification | None + EnableTunnelLifecycleControl: Boolean | None class ModifyVpnTunnelOptionsRequest(ServiceRequest): VpnConnectionId: VpnConnectionId VpnTunnelOutsideIpAddress: String TunnelOptions: ModifyVpnTunnelOptionsSpecification - DryRun: Optional[Boolean] - SkipTunnelReplacement: Optional[Boolean] - PreSharedKeyStorage: Optional[String] + DryRun: Boolean | None + SkipTunnelReplacement: Boolean | None + PreSharedKeyStorage: String | None class ModifyVpnTunnelOptionsResult(TypedDict, total=False): - VpnConnection: Optional[VpnConnection] + VpnConnection: VpnConnection | None class MonitorInstancesRequest(ServiceRequest): InstanceIds: InstanceIdStringList - DryRun: Optional[Boolean] + DryRun: Boolean | None class MonitorInstancesResult(TypedDict, total=False): - InstanceMonitorings: Optional[InstanceMonitoringList] + InstanceMonitorings: InstanceMonitoringList | None class MoveAddressToVpcRequest(ServiceRequest): - DryRun: Optional[Boolean] + DryRun: Boolean | None PublicIp: String class MoveAddressToVpcResult(TypedDict, total=False): - AllocationId: Optional[String] - Status: Optional[Status] + AllocationId: String | None + Status: Status | None class MoveByoipCidrToIpamRequest(ServiceRequest): - DryRun: Optional[Boolean] + DryRun: Boolean | None Cidr: String IpamPoolId: IpamPoolId IpamPoolOwner: String class MoveByoipCidrToIpamResult(TypedDict, total=False): - ByoipCidr: Optional[ByoipCidr] + ByoipCidr: ByoipCidr | None class MoveCapacityReservationInstancesRequest(ServiceRequest): - DryRun: Optional[Boolean] - ClientToken: Optional[String] + DryRun: Boolean | None + ClientToken: String | None SourceCapacityReservationId: CapacityReservationId DestinationCapacityReservationId: CapacityReservationId InstanceCount: Integer class MoveCapacityReservationInstancesResult(TypedDict, total=False): - SourceCapacityReservation: Optional[CapacityReservation] - DestinationCapacityReservation: Optional[CapacityReservation] - InstanceCount: Optional[Integer] + SourceCapacityReservation: CapacityReservation | None + DestinationCapacityReservation: CapacityReservation | None + InstanceCount: Integer | None class PrivateDnsNameOptionsRequest(TypedDict, total=False): - HostnameType: Optional[HostnameType] - EnableResourceNameDnsARecord: Optional[Boolean] - EnableResourceNameDnsAAAARecord: Optional[Boolean] + HostnameType: HostnameType | None + EnableResourceNameDnsARecord: Boolean | None + EnableResourceNameDnsAAAARecord: Boolean | None class ScheduledInstancesPrivateIpAddressConfig(TypedDict, total=False): - Primary: Optional[Boolean] - PrivateIpAddress: Optional[String] + Primary: Boolean | None + PrivateIpAddress: String | None -PrivateIpAddressConfigSet = List[ScheduledInstancesPrivateIpAddressConfig] +PrivateIpAddressConfigSet = list[ScheduledInstancesPrivateIpAddressConfig] class ProvisionByoipCidrRequest(ServiceRequest): Cidr: String - CidrAuthorizationContext: Optional[CidrAuthorizationContext] - PubliclyAdvertisable: Optional[Boolean] - Description: Optional[String] - DryRun: Optional[Boolean] - PoolTagSpecifications: Optional[TagSpecificationList] - MultiRegion: Optional[Boolean] - NetworkBorderGroup: Optional[String] + CidrAuthorizationContext: CidrAuthorizationContext | None + PubliclyAdvertisable: Boolean | None + Description: String | None + DryRun: Boolean | None + PoolTagSpecifications: TagSpecificationList | None + MultiRegion: Boolean | None + NetworkBorderGroup: String | None class ProvisionByoipCidrResult(TypedDict, total=False): - ByoipCidr: Optional[ByoipCidr] + ByoipCidr: ByoipCidr | None class ProvisionIpamByoasnRequest(ServiceRequest): - DryRun: Optional[Boolean] + DryRun: Boolean | None IpamId: IpamId Asn: String AsnAuthorizationContext: AsnAuthorizationContext class ProvisionIpamByoasnResult(TypedDict, total=False): - Byoasn: Optional[Byoasn] + Byoasn: Byoasn | None class ProvisionIpamPoolCidrRequest(ServiceRequest): - DryRun: Optional[Boolean] + DryRun: Boolean | None IpamPoolId: IpamPoolId - Cidr: Optional[String] - CidrAuthorizationContext: Optional[IpamCidrAuthorizationContext] - NetmaskLength: Optional[Integer] - ClientToken: Optional[String] - VerificationMethod: Optional[VerificationMethod] - IpamExternalResourceVerificationTokenId: Optional[IpamExternalResourceVerificationTokenId] + Cidr: String | None + CidrAuthorizationContext: IpamCidrAuthorizationContext | None + NetmaskLength: Integer | None + ClientToken: String | None + VerificationMethod: VerificationMethod | None + IpamExternalResourceVerificationTokenId: IpamExternalResourceVerificationTokenId | None class ProvisionIpamPoolCidrResult(TypedDict, total=False): - IpamPoolCidr: Optional[IpamPoolCidr] + IpamPoolCidr: IpamPoolCidr | None class ProvisionPublicIpv4PoolCidrRequest(ServiceRequest): - DryRun: Optional[Boolean] + DryRun: Boolean | None IpamPoolId: IpamPoolId PoolId: Ipv4PoolEc2Id NetmaskLength: Integer - NetworkBorderGroup: Optional[String] + NetworkBorderGroup: String | None class ProvisionPublicIpv4PoolCidrResult(TypedDict, total=False): - PoolId: Optional[Ipv4PoolEc2Id] - PoolAddressRange: Optional[PublicIpv4PoolRange] + PoolId: Ipv4PoolEc2Id | None + PoolAddressRange: PublicIpv4PoolRange | None class PurchaseCapacityBlockExtensionRequest(ServiceRequest): CapacityBlockExtensionOfferingId: OfferingId CapacityReservationId: CapacityReservationId - DryRun: Optional[Boolean] + DryRun: Boolean | None class PurchaseCapacityBlockExtensionResult(TypedDict, total=False): - CapacityBlockExtensions: Optional[CapacityBlockExtensionSet] + CapacityBlockExtensions: CapacityBlockExtensionSet | None class PurchaseCapacityBlockRequest(ServiceRequest): - DryRun: Optional[Boolean] - TagSpecifications: Optional[TagSpecificationList] + DryRun: Boolean | None + TagSpecifications: TagSpecificationList | None CapacityBlockOfferingId: OfferingId InstancePlatform: CapacityReservationInstancePlatform class PurchaseCapacityBlockResult(TypedDict, total=False): - CapacityReservation: Optional[CapacityReservation] - CapacityBlocks: Optional[CapacityBlockSet] + CapacityReservation: CapacityReservation | None + CapacityBlocks: CapacityBlockSet | None class PurchaseHostReservationRequest(ServiceRequest): - ClientToken: Optional[String] - CurrencyCode: Optional[CurrencyCodeValues] + ClientToken: String | None + CurrencyCode: CurrencyCodeValues | None HostIdSet: RequestHostIdSet - LimitPrice: Optional[String] + LimitPrice: String | None OfferingId: OfferingId - TagSpecifications: Optional[TagSpecificationList] + TagSpecifications: TagSpecificationList | None class PurchaseHostReservationResult(TypedDict, total=False): - ClientToken: Optional[String] - CurrencyCode: Optional[CurrencyCodeValues] - Purchase: Optional[PurchaseSet] - TotalHourlyPrice: Optional[String] - TotalUpfrontPrice: Optional[String] + ClientToken: String | None + CurrencyCode: CurrencyCodeValues | None + Purchase: PurchaseSet | None + TotalHourlyPrice: String | None + TotalUpfrontPrice: String | None class PurchaseRequest(TypedDict, total=False): @@ -20200,182 +22316,182 @@ class PurchaseRequest(TypedDict, total=False): PurchaseToken: String -PurchaseRequestSet = List[PurchaseRequest] +PurchaseRequestSet = list[PurchaseRequest] class ReservedInstanceLimitPrice(TypedDict, total=False): - Amount: Optional[Double] - CurrencyCode: Optional[CurrencyCodeValues] + Amount: Double | None + CurrencyCode: CurrencyCodeValues | None class PurchaseReservedInstancesOfferingRequest(ServiceRequest): InstanceCount: Integer ReservedInstancesOfferingId: ReservedInstancesOfferingId - PurchaseTime: Optional[DateTime] - DryRun: Optional[Boolean] - LimitPrice: Optional[ReservedInstanceLimitPrice] + PurchaseTime: DateTime | None + DryRun: Boolean | None + LimitPrice: ReservedInstanceLimitPrice | None class PurchaseReservedInstancesOfferingResult(TypedDict, total=False): - ReservedInstancesId: Optional[String] + ReservedInstancesId: String | None class PurchaseScheduledInstancesRequest(ServiceRequest): - ClientToken: Optional[String] - DryRun: Optional[Boolean] + ClientToken: String | None + DryRun: Boolean | None PurchaseRequests: PurchaseRequestSet -PurchasedScheduledInstanceSet = List[ScheduledInstance] +PurchasedScheduledInstanceSet = list[ScheduledInstance] class PurchaseScheduledInstancesResult(TypedDict, total=False): - ScheduledInstanceSet: Optional[PurchasedScheduledInstanceSet] + ScheduledInstanceSet: PurchasedScheduledInstanceSet | None -ReasonCodesList = List[ReportInstanceReasonCodes] +ReasonCodesList = list[ReportInstanceReasonCodes] class RebootInstancesRequest(ServiceRequest): InstanceIds: InstanceIdStringList - DryRun: Optional[Boolean] + DryRun: Boolean | None class RegisterImageRequest(ServiceRequest): - ImageLocation: Optional[String] - BillingProducts: Optional[BillingProductList] - BootMode: Optional[BootModeValues] - TpmSupport: Optional[TpmSupportValues] - UefiData: Optional[StringType] - ImdsSupport: Optional[ImdsSupportValues] - TagSpecifications: Optional[TagSpecificationList] - DryRun: Optional[Boolean] + ImageLocation: String | None + BillingProducts: BillingProductList | None + BootMode: BootModeValues | None + TpmSupport: TpmSupportValues | None + UefiData: StringType | None + ImdsSupport: ImdsSupportValues | None + TagSpecifications: TagSpecificationList | None + DryRun: Boolean | None Name: String - Description: Optional[String] - Architecture: Optional[ArchitectureValues] - KernelId: Optional[KernelId] - RamdiskId: Optional[RamdiskId] - RootDeviceName: Optional[String] - BlockDeviceMappings: Optional[BlockDeviceMappingRequestList] - VirtualizationType: Optional[String] - SriovNetSupport: Optional[String] - EnaSupport: Optional[Boolean] + Description: String | None + Architecture: ArchitectureValues | None + KernelId: KernelId | None + RamdiskId: RamdiskId | None + RootDeviceName: String | None + BlockDeviceMappings: BlockDeviceMappingRequestList | None + VirtualizationType: String | None + SriovNetSupport: String | None + EnaSupport: Boolean | None class RegisterImageResult(TypedDict, total=False): - ImageId: Optional[String] + ImageId: String | None class RegisterInstanceTagAttributeRequest(TypedDict, total=False): - IncludeAllTagsOfInstance: Optional[Boolean] - InstanceTagKeys: Optional[InstanceTagKeySet] + IncludeAllTagsOfInstance: Boolean | None + InstanceTagKeys: InstanceTagKeySet | None class RegisterInstanceEventNotificationAttributesRequest(ServiceRequest): - DryRun: Optional[Boolean] + DryRun: Boolean | None InstanceTagAttribute: RegisterInstanceTagAttributeRequest class RegisterInstanceEventNotificationAttributesResult(TypedDict, total=False): - InstanceTagAttribute: Optional[InstanceTagNotificationAttribute] + InstanceTagAttribute: InstanceTagNotificationAttribute | None class RegisterTransitGatewayMulticastGroupMembersRequest(ServiceRequest): TransitGatewayMulticastDomainId: TransitGatewayMulticastDomainId - GroupIpAddress: Optional[String] + GroupIpAddress: String | None NetworkInterfaceIds: TransitGatewayNetworkInterfaceIdList - DryRun: Optional[Boolean] + DryRun: Boolean | None class TransitGatewayMulticastRegisteredGroupMembers(TypedDict, total=False): - TransitGatewayMulticastDomainId: Optional[String] - RegisteredNetworkInterfaceIds: Optional[ValueStringList] - GroupIpAddress: Optional[String] + TransitGatewayMulticastDomainId: String | None + RegisteredNetworkInterfaceIds: ValueStringList | None + GroupIpAddress: String | None class RegisterTransitGatewayMulticastGroupMembersResult(TypedDict, total=False): - RegisteredMulticastGroupMembers: Optional[TransitGatewayMulticastRegisteredGroupMembers] + RegisteredMulticastGroupMembers: TransitGatewayMulticastRegisteredGroupMembers | None class RegisterTransitGatewayMulticastGroupSourcesRequest(ServiceRequest): TransitGatewayMulticastDomainId: TransitGatewayMulticastDomainId - GroupIpAddress: Optional[String] + GroupIpAddress: String | None NetworkInterfaceIds: TransitGatewayNetworkInterfaceIdList - DryRun: Optional[Boolean] + DryRun: Boolean | None class TransitGatewayMulticastRegisteredGroupSources(TypedDict, total=False): - TransitGatewayMulticastDomainId: Optional[String] - RegisteredNetworkInterfaceIds: Optional[ValueStringList] - GroupIpAddress: Optional[String] + TransitGatewayMulticastDomainId: String | None + RegisteredNetworkInterfaceIds: ValueStringList | None + GroupIpAddress: String | None class RegisterTransitGatewayMulticastGroupSourcesResult(TypedDict, total=False): - RegisteredMulticastGroupSources: Optional[TransitGatewayMulticastRegisteredGroupSources] + RegisteredMulticastGroupSources: TransitGatewayMulticastRegisteredGroupSources | None class RejectCapacityReservationBillingOwnershipRequest(ServiceRequest): - DryRun: Optional[Boolean] + DryRun: Boolean | None CapacityReservationId: CapacityReservationId class RejectCapacityReservationBillingOwnershipResult(TypedDict, total=False): - Return: Optional[Boolean] + Return: Boolean | None class RejectTransitGatewayMulticastDomainAssociationsRequest(ServiceRequest): - TransitGatewayMulticastDomainId: Optional[TransitGatewayMulticastDomainId] - TransitGatewayAttachmentId: Optional[TransitGatewayAttachmentId] - SubnetIds: Optional[ValueStringList] - DryRun: Optional[Boolean] + TransitGatewayMulticastDomainId: TransitGatewayMulticastDomainId | None + TransitGatewayAttachmentId: TransitGatewayAttachmentId | None + SubnetIds: ValueStringList | None + DryRun: Boolean | None class RejectTransitGatewayMulticastDomainAssociationsResult(TypedDict, total=False): - Associations: Optional[TransitGatewayMulticastDomainAssociations] + Associations: TransitGatewayMulticastDomainAssociations | None class RejectTransitGatewayPeeringAttachmentRequest(ServiceRequest): TransitGatewayAttachmentId: TransitGatewayAttachmentId - DryRun: Optional[Boolean] + DryRun: Boolean | None class RejectTransitGatewayPeeringAttachmentResult(TypedDict, total=False): - TransitGatewayPeeringAttachment: Optional[TransitGatewayPeeringAttachment] + TransitGatewayPeeringAttachment: TransitGatewayPeeringAttachment | None class RejectTransitGatewayVpcAttachmentRequest(ServiceRequest): TransitGatewayAttachmentId: TransitGatewayAttachmentId - DryRun: Optional[Boolean] + DryRun: Boolean | None class RejectTransitGatewayVpcAttachmentResult(TypedDict, total=False): - TransitGatewayVpcAttachment: Optional[TransitGatewayVpcAttachment] + TransitGatewayVpcAttachment: TransitGatewayVpcAttachment | None class RejectVpcEndpointConnectionsRequest(ServiceRequest): - DryRun: Optional[Boolean] + DryRun: Boolean | None ServiceId: VpcEndpointServiceId VpcEndpointIds: VpcEndpointIdList class RejectVpcEndpointConnectionsResult(TypedDict, total=False): - Unsuccessful: Optional[UnsuccessfulItemSet] + Unsuccessful: UnsuccessfulItemSet | None class RejectVpcPeeringConnectionRequest(ServiceRequest): - DryRun: Optional[Boolean] + DryRun: Boolean | None VpcPeeringConnectionId: VpcPeeringConnectionId class RejectVpcPeeringConnectionResult(TypedDict, total=False): - Return: Optional[Boolean] + Return: Boolean | None class ReleaseAddressRequest(ServiceRequest): - AllocationId: Optional[AllocationId] - PublicIp: Optional[String] - NetworkBorderGroup: Optional[String] - DryRun: Optional[Boolean] + AllocationId: AllocationId | None + PublicIp: String | None + NetworkBorderGroup: String | None + DryRun: Boolean | None class ReleaseHostsRequest(ServiceRequest): @@ -20383,19 +22499,19 @@ class ReleaseHostsRequest(ServiceRequest): class ReleaseHostsResult(TypedDict, total=False): - Successful: Optional[ResponseHostIdList] - Unsuccessful: Optional[UnsuccessfulItemList] + Successful: ResponseHostIdList | None + Unsuccessful: UnsuccessfulItemList | None class ReleaseIpamPoolAllocationRequest(ServiceRequest): - DryRun: Optional[Boolean] + DryRun: Boolean | None IpamPoolId: IpamPoolId Cidr: String IpamPoolAllocationId: IpamPoolAllocationId class ReleaseIpamPoolAllocationResult(TypedDict, total=False): - Success: Optional[Boolean] + Success: Boolean | None class ReplaceIamInstanceProfileAssociationRequest(ServiceRequest): @@ -20404,733 +22520,771 @@ class ReplaceIamInstanceProfileAssociationRequest(ServiceRequest): class ReplaceIamInstanceProfileAssociationResult(TypedDict, total=False): - IamInstanceProfileAssociation: Optional[IamInstanceProfileAssociation] + IamInstanceProfileAssociation: IamInstanceProfileAssociation | None class ReplaceImageCriteriaInAllowedImagesSettingsRequest(ServiceRequest): - ImageCriteria: Optional[ImageCriterionRequestList] - DryRun: Optional[Boolean] + ImageCriteria: ImageCriterionRequestList | None + DryRun: Boolean | None class ReplaceImageCriteriaInAllowedImagesSettingsResult(TypedDict, total=False): - ReturnValue: Optional[Boolean] + ReturnValue: Boolean | None class ReplaceNetworkAclAssociationRequest(ServiceRequest): - DryRun: Optional[Boolean] + DryRun: Boolean | None AssociationId: NetworkAclAssociationId NetworkAclId: NetworkAclId class ReplaceNetworkAclAssociationResult(TypedDict, total=False): - NewAssociationId: Optional[String] + NewAssociationId: String | None class ReplaceNetworkAclEntryRequest(ServiceRequest): - DryRun: Optional[Boolean] + DryRun: Boolean | None NetworkAclId: NetworkAclId RuleNumber: Integer Protocol: String RuleAction: RuleAction Egress: Boolean - CidrBlock: Optional[String] - Ipv6CidrBlock: Optional[String] - IcmpTypeCode: Optional[IcmpTypeCode] - PortRange: Optional[PortRange] + CidrBlock: String | None + Ipv6CidrBlock: String | None + IcmpTypeCode: IcmpTypeCode | None + PortRange: PortRange | None class ReplaceRouteRequest(ServiceRequest): - DestinationPrefixListId: Optional[PrefixListResourceId] - VpcEndpointId: Optional[VpcEndpointId] - LocalTarget: Optional[Boolean] - TransitGatewayId: Optional[TransitGatewayId] - LocalGatewayId: Optional[LocalGatewayId] - CarrierGatewayId: Optional[CarrierGatewayId] - CoreNetworkArn: Optional[CoreNetworkArn] - OdbNetworkArn: Optional[OdbNetworkArn] - DryRun: Optional[Boolean] + DestinationPrefixListId: PrefixListResourceId | None + VpcEndpointId: VpcEndpointId | None + LocalTarget: Boolean | None + TransitGatewayId: TransitGatewayId | None + LocalGatewayId: LocalGatewayId | None + CarrierGatewayId: CarrierGatewayId | None + CoreNetworkArn: CoreNetworkArn | None + OdbNetworkArn: OdbNetworkArn | None + DryRun: Boolean | None RouteTableId: RouteTableId - DestinationCidrBlock: Optional[String] - GatewayId: Optional[RouteGatewayId] - DestinationIpv6CidrBlock: Optional[String] - EgressOnlyInternetGatewayId: Optional[EgressOnlyInternetGatewayId] - InstanceId: Optional[InstanceId] - NetworkInterfaceId: Optional[NetworkInterfaceId] - VpcPeeringConnectionId: Optional[VpcPeeringConnectionId] - NatGatewayId: Optional[NatGatewayId] + DestinationCidrBlock: String | None + GatewayId: RouteGatewayId | None + DestinationIpv6CidrBlock: String | None + EgressOnlyInternetGatewayId: EgressOnlyInternetGatewayId | None + InstanceId: InstanceId | None + NetworkInterfaceId: NetworkInterfaceId | None + VpcPeeringConnectionId: VpcPeeringConnectionId | None + NatGatewayId: NatGatewayId | None class ReplaceRouteTableAssociationRequest(ServiceRequest): - DryRun: Optional[Boolean] + DryRun: Boolean | None AssociationId: RouteTableAssociationId RouteTableId: RouteTableId class ReplaceRouteTableAssociationResult(TypedDict, total=False): - NewAssociationId: Optional[String] - AssociationState: Optional[RouteTableAssociationState] + NewAssociationId: String | None + AssociationState: RouteTableAssociationState | None class ReplaceTransitGatewayRouteRequest(ServiceRequest): DestinationCidrBlock: String TransitGatewayRouteTableId: TransitGatewayRouteTableId - TransitGatewayAttachmentId: Optional[TransitGatewayAttachmentId] - Blackhole: Optional[Boolean] - DryRun: Optional[Boolean] + TransitGatewayAttachmentId: TransitGatewayAttachmentId | None + Blackhole: Boolean | None + DryRun: Boolean | None class ReplaceTransitGatewayRouteResult(TypedDict, total=False): - Route: Optional[TransitGatewayRoute] + Route: TransitGatewayRoute | None class ReplaceVpnTunnelRequest(ServiceRequest): VpnConnectionId: VpnConnectionId VpnTunnelOutsideIpAddress: String - ApplyPendingMaintenance: Optional[Boolean] - DryRun: Optional[Boolean] + ApplyPendingMaintenance: Boolean | None + DryRun: Boolean | None class ReplaceVpnTunnelResult(TypedDict, total=False): - Return: Optional[Boolean] + Return: Boolean | None class ReportInstanceStatusRequest(ServiceRequest): - DryRun: Optional[Boolean] + DryRun: Boolean | None Instances: InstanceIdStringList Status: ReportStatusType - StartTime: Optional[DateTime] - EndTime: Optional[DateTime] + StartTime: DateTime | None + EndTime: DateTime | None ReasonCodes: ReasonCodesList - Description: Optional[ReportInstanceStatusRequestDescription] + Description: ReportInstanceStatusRequestDescription | None class RequestSpotFleetRequest(ServiceRequest): - DryRun: Optional[Boolean] + DryRun: Boolean | None SpotFleetRequestConfig: SpotFleetRequestConfigData class RequestSpotFleetResponse(TypedDict, total=False): - SpotFleetRequestId: Optional[String] + SpotFleetRequestId: String | None -RequestSpotLaunchSpecificationSecurityGroupList = List[String] -RequestSpotLaunchSpecificationSecurityGroupIdList = List[SecurityGroupId] +RequestSpotLaunchSpecificationSecurityGroupList = list[String] +RequestSpotLaunchSpecificationSecurityGroupIdList = list[SecurityGroupId] class RequestSpotLaunchSpecification(TypedDict, total=False): - SecurityGroupIds: Optional[RequestSpotLaunchSpecificationSecurityGroupIdList] - SecurityGroups: Optional[RequestSpotLaunchSpecificationSecurityGroupList] - AddressingType: Optional[String] - BlockDeviceMappings: Optional[BlockDeviceMappingList] - EbsOptimized: Optional[Boolean] - IamInstanceProfile: Optional[IamInstanceProfileSpecification] - ImageId: Optional[ImageId] - InstanceType: Optional[InstanceType] - KernelId: Optional[KernelId] - KeyName: Optional[KeyPairNameWithResolver] - Monitoring: Optional[RunInstancesMonitoringEnabled] - NetworkInterfaces: Optional[InstanceNetworkInterfaceSpecificationList] - Placement: Optional[SpotPlacement] - RamdiskId: Optional[RamdiskId] - SubnetId: Optional[SubnetId] - UserData: Optional[SensitiveUserData] + SecurityGroupIds: RequestSpotLaunchSpecificationSecurityGroupIdList | None + SecurityGroups: RequestSpotLaunchSpecificationSecurityGroupList | None + AddressingType: String | None + BlockDeviceMappings: BlockDeviceMappingList | None + EbsOptimized: Boolean | None + IamInstanceProfile: IamInstanceProfileSpecification | None + ImageId: ImageId | None + InstanceType: InstanceType | None + KernelId: KernelId | None + KeyName: KeyPairNameWithResolver | None + Monitoring: RunInstancesMonitoringEnabled | None + NetworkInterfaces: InstanceNetworkInterfaceSpecificationList | None + Placement: SpotPlacement | None + RamdiskId: RamdiskId | None + SubnetId: SubnetId | None + UserData: SensitiveUserData | None class RequestSpotInstancesRequest(ServiceRequest): - LaunchSpecification: Optional[RequestSpotLaunchSpecification] - TagSpecifications: Optional[TagSpecificationList] - InstanceInterruptionBehavior: Optional[InstanceInterruptionBehavior] - DryRun: Optional[Boolean] - SpotPrice: Optional[String] - ClientToken: Optional[String] - InstanceCount: Optional[Integer] - Type: Optional[SpotInstanceType] - ValidFrom: Optional[DateTime] - ValidUntil: Optional[DateTime] - LaunchGroup: Optional[String] - AvailabilityZoneGroup: Optional[String] - BlockDurationMinutes: Optional[Integer] + LaunchSpecification: RequestSpotLaunchSpecification | None + TagSpecifications: TagSpecificationList | None + InstanceInterruptionBehavior: InstanceInterruptionBehavior | None + DryRun: Boolean | None + SpotPrice: String | None + ClientToken: String | None + InstanceCount: Integer | None + Type: SpotInstanceType | None + ValidFrom: DateTime | None + ValidUntil: DateTime | None + LaunchGroup: String | None + AvailabilityZoneGroup: String | None + BlockDurationMinutes: Integer | None class RequestSpotInstancesResult(TypedDict, total=False): - SpotInstanceRequests: Optional[SpotInstanceRequestList] + SpotInstanceRequests: SpotInstanceRequestList | None class ResetAddressAttributeRequest(ServiceRequest): AllocationId: AllocationId Attribute: AddressAttributeName - DryRun: Optional[Boolean] + DryRun: Boolean | None class ResetAddressAttributeResult(TypedDict, total=False): - Address: Optional[AddressAttribute] + Address: AddressAttribute | None class ResetEbsDefaultKmsKeyIdRequest(ServiceRequest): - DryRun: Optional[Boolean] + DryRun: Boolean | None class ResetEbsDefaultKmsKeyIdResult(TypedDict, total=False): - KmsKeyId: Optional[String] + KmsKeyId: String | None class ResetFpgaImageAttributeRequest(ServiceRequest): - DryRun: Optional[Boolean] + DryRun: Boolean | None FpgaImageId: FpgaImageId - Attribute: Optional[ResetFpgaImageAttributeName] + Attribute: ResetFpgaImageAttributeName | None class ResetFpgaImageAttributeResult(TypedDict, total=False): - Return: Optional[Boolean] + Return: Boolean | None class ResetImageAttributeRequest(ServiceRequest): Attribute: ResetImageAttributeName ImageId: ImageId - DryRun: Optional[Boolean] + DryRun: Boolean | None class ResetInstanceAttributeRequest(ServiceRequest): - DryRun: Optional[Boolean] + DryRun: Boolean | None InstanceId: InstanceId Attribute: InstanceAttributeName class ResetNetworkInterfaceAttributeRequest(ServiceRequest): - DryRun: Optional[Boolean] + DryRun: Boolean | None NetworkInterfaceId: NetworkInterfaceId - SourceDestCheck: Optional[String] + SourceDestCheck: String | None class ResetSnapshotAttributeRequest(ServiceRequest): Attribute: SnapshotAttributeName SnapshotId: SnapshotId - DryRun: Optional[Boolean] + DryRun: Boolean | None class RestoreAddressToClassicRequest(ServiceRequest): - DryRun: Optional[Boolean] + DryRun: Boolean | None PublicIp: String class RestoreAddressToClassicResult(TypedDict, total=False): - PublicIp: Optional[String] - Status: Optional[Status] + PublicIp: String | None + Status: Status | None class RestoreImageFromRecycleBinRequest(ServiceRequest): ImageId: ImageId - DryRun: Optional[Boolean] + DryRun: Boolean | None class RestoreImageFromRecycleBinResult(TypedDict, total=False): - Return: Optional[Boolean] + Return: Boolean | None class RestoreManagedPrefixListVersionRequest(ServiceRequest): - DryRun: Optional[Boolean] + DryRun: Boolean | None PrefixListId: PrefixListResourceId PreviousVersion: Long CurrentVersion: Long class RestoreManagedPrefixListVersionResult(TypedDict, total=False): - PrefixList: Optional[ManagedPrefixList] + PrefixList: ManagedPrefixList | None class RestoreSnapshotFromRecycleBinRequest(ServiceRequest): SnapshotId: SnapshotId - DryRun: Optional[Boolean] + DryRun: Boolean | None class RestoreSnapshotFromRecycleBinResult(TypedDict, total=False): - SnapshotId: Optional[String] - OutpostArn: Optional[String] - Description: Optional[String] - Encrypted: Optional[Boolean] - OwnerId: Optional[String] - Progress: Optional[String] - StartTime: Optional[MillisecondDateTime] - State: Optional[SnapshotState] - VolumeId: Optional[String] - VolumeSize: Optional[Integer] - SseType: Optional[SSEType] + SnapshotId: String | None + OutpostArn: String | None + Description: String | None + Encrypted: Boolean | None + OwnerId: String | None + Progress: String | None + StartTime: MillisecondDateTime | None + State: SnapshotState | None + VolumeId: String | None + VolumeSize: Integer | None + SseType: SSEType | None class RestoreSnapshotTierRequest(ServiceRequest): SnapshotId: SnapshotId - TemporaryRestoreDays: Optional[RestoreSnapshotTierRequestTemporaryRestoreDays] - PermanentRestore: Optional[Boolean] - DryRun: Optional[Boolean] + TemporaryRestoreDays: RestoreSnapshotTierRequestTemporaryRestoreDays | None + PermanentRestore: Boolean | None + DryRun: Boolean | None class RestoreSnapshotTierResult(TypedDict, total=False): - SnapshotId: Optional[String] - RestoreStartTime: Optional[MillisecondDateTime] - RestoreDuration: Optional[Integer] - IsPermanentRestore: Optional[Boolean] + SnapshotId: String | None + RestoreStartTime: MillisecondDateTime | None + RestoreDuration: Integer | None + IsPermanentRestore: Boolean | None + + +class RestoreVolumeFromRecycleBinRequest(ServiceRequest): + VolumeId: VolumeId + DryRun: Boolean | None + + +class RestoreVolumeFromRecycleBinResult(TypedDict, total=False): + Return: Boolean | None class RevokeClientVpnIngressRequest(ServiceRequest): ClientVpnEndpointId: ClientVpnEndpointId TargetNetworkCidr: String - AccessGroupId: Optional[String] - RevokeAllGroups: Optional[Boolean] - DryRun: Optional[Boolean] + AccessGroupId: String | None + RevokeAllGroups: Boolean | None + DryRun: Boolean | None class RevokeClientVpnIngressResult(TypedDict, total=False): - Status: Optional[ClientVpnAuthorizationRuleStatus] + Status: ClientVpnAuthorizationRuleStatus | None class RevokeSecurityGroupEgressRequest(ServiceRequest): - SecurityGroupRuleIds: Optional[SecurityGroupRuleIdList] - DryRun: Optional[Boolean] + SecurityGroupRuleIds: SecurityGroupRuleIdList | None + DryRun: Boolean | None GroupId: SecurityGroupId - SourceSecurityGroupName: Optional[String] - SourceSecurityGroupOwnerId: Optional[String] - IpProtocol: Optional[String] - FromPort: Optional[Integer] - ToPort: Optional[Integer] - CidrIp: Optional[String] - IpPermissions: Optional[IpPermissionList] + SourceSecurityGroupName: String | None + SourceSecurityGroupOwnerId: String | None + IpProtocol: String | None + FromPort: Integer | None + ToPort: Integer | None + CidrIp: String | None + IpPermissions: IpPermissionList | None class RevokedSecurityGroupRule(TypedDict, total=False): - SecurityGroupRuleId: Optional[SecurityGroupRuleId] - GroupId: Optional[SecurityGroupId] - IsEgress: Optional[Boolean] - IpProtocol: Optional[String] - FromPort: Optional[Integer] - ToPort: Optional[Integer] - CidrIpv4: Optional[String] - CidrIpv6: Optional[String] - PrefixListId: Optional[PrefixListResourceId] - ReferencedGroupId: Optional[SecurityGroupId] - Description: Optional[String] + SecurityGroupRuleId: SecurityGroupRuleId | None + GroupId: SecurityGroupId | None + IsEgress: Boolean | None + IpProtocol: String | None + FromPort: Integer | None + ToPort: Integer | None + CidrIpv4: String | None + CidrIpv6: String | None + PrefixListId: PrefixListResourceId | None + ReferencedGroupId: SecurityGroupId | None + Description: String | None -RevokedSecurityGroupRuleList = List[RevokedSecurityGroupRule] +RevokedSecurityGroupRuleList = list[RevokedSecurityGroupRule] class RevokeSecurityGroupEgressResult(TypedDict, total=False): - Return: Optional[Boolean] - UnknownIpPermissions: Optional[IpPermissionList] - RevokedSecurityGroupRules: Optional[RevokedSecurityGroupRuleList] + Return: Boolean | None + UnknownIpPermissions: IpPermissionList | None + RevokedSecurityGroupRules: RevokedSecurityGroupRuleList | None class RevokeSecurityGroupIngressRequest(ServiceRequest): - CidrIp: Optional[String] - FromPort: Optional[Integer] - GroupId: Optional[SecurityGroupId] - GroupName: Optional[SecurityGroupName] - IpPermissions: Optional[IpPermissionList] - IpProtocol: Optional[String] - SourceSecurityGroupName: Optional[String] - SourceSecurityGroupOwnerId: Optional[String] - ToPort: Optional[Integer] - SecurityGroupRuleIds: Optional[SecurityGroupRuleIdList] - DryRun: Optional[Boolean] + CidrIp: String | None + FromPort: Integer | None + GroupId: SecurityGroupId | None + GroupName: SecurityGroupName | None + IpPermissions: IpPermissionList | None + IpProtocol: String | None + SourceSecurityGroupName: String | None + SourceSecurityGroupOwnerId: String | None + ToPort: Integer | None + SecurityGroupRuleIds: SecurityGroupRuleIdList | None + DryRun: Boolean | None class RevokeSecurityGroupIngressResult(TypedDict, total=False): - Return: Optional[Boolean] - UnknownIpPermissions: Optional[IpPermissionList] - RevokedSecurityGroupRules: Optional[RevokedSecurityGroupRuleList] + Return: Boolean | None + UnknownIpPermissions: IpPermissionList | None + RevokedSecurityGroupRules: RevokedSecurityGroupRuleList | None class RunInstancesRequest(ServiceRequest): - BlockDeviceMappings: Optional[BlockDeviceMappingRequestList] - ImageId: Optional[ImageId] - InstanceType: Optional[InstanceType] - Ipv6AddressCount: Optional[Integer] - Ipv6Addresses: Optional[InstanceIpv6AddressList] - KernelId: Optional[KernelId] - KeyName: Optional[KeyPairName] + BlockDeviceMappings: BlockDeviceMappingRequestList | None + ImageId: ImageId | None + InstanceType: InstanceType | None + Ipv6AddressCount: Integer | None + Ipv6Addresses: InstanceIpv6AddressList | None + KernelId: KernelId | None + KeyName: KeyPairName | None MaxCount: Integer MinCount: Integer - Monitoring: Optional[RunInstancesMonitoringEnabled] - Placement: Optional[Placement] - RamdiskId: Optional[RamdiskId] - SecurityGroupIds: Optional[SecurityGroupIdStringList] - SecurityGroups: Optional[SecurityGroupStringList] - SubnetId: Optional[SubnetId] - UserData: Optional[RunInstancesUserData] - ElasticGpuSpecification: Optional[ElasticGpuSpecifications] - ElasticInferenceAccelerators: Optional[ElasticInferenceAccelerators] - TagSpecifications: Optional[TagSpecificationList] - LaunchTemplate: Optional[LaunchTemplateSpecification] - InstanceMarketOptions: Optional[InstanceMarketOptionsRequest] - CreditSpecification: Optional[CreditSpecificationRequest] - CpuOptions: Optional[CpuOptionsRequest] - CapacityReservationSpecification: Optional[CapacityReservationSpecification] - HibernationOptions: Optional[HibernationOptionsRequest] - LicenseSpecifications: Optional[LicenseSpecificationListRequest] - MetadataOptions: Optional[InstanceMetadataOptionsRequest] - EnclaveOptions: Optional[EnclaveOptionsRequest] - PrivateDnsNameOptions: Optional[PrivateDnsNameOptionsRequest] - MaintenanceOptions: Optional[InstanceMaintenanceOptionsRequest] - DisableApiStop: Optional[Boolean] - EnablePrimaryIpv6: Optional[Boolean] - NetworkPerformanceOptions: Optional[InstanceNetworkPerformanceOptionsRequest] - Operator: Optional[OperatorRequest] - DryRun: Optional[Boolean] - DisableApiTermination: Optional[Boolean] - InstanceInitiatedShutdownBehavior: Optional[ShutdownBehavior] - PrivateIpAddress: Optional[String] - ClientToken: Optional[String] - AdditionalInfo: Optional[String] - NetworkInterfaces: Optional[InstanceNetworkInterfaceSpecificationList] - IamInstanceProfile: Optional[IamInstanceProfileSpecification] - EbsOptimized: Optional[Boolean] - - -ScheduledInstancesSecurityGroupIdSet = List[SecurityGroupId] + Monitoring: RunInstancesMonitoringEnabled | None + Placement: Placement | None + RamdiskId: RamdiskId | None + SecurityGroupIds: SecurityGroupIdStringList | None + SecurityGroups: SecurityGroupStringList | None + SubnetId: SubnetId | None + UserData: RunInstancesUserData | None + ElasticGpuSpecification: ElasticGpuSpecifications | None + ElasticInferenceAccelerators: ElasticInferenceAccelerators | None + TagSpecifications: TagSpecificationList | None + LaunchTemplate: LaunchTemplateSpecification | None + InstanceMarketOptions: InstanceMarketOptionsRequest | None + CreditSpecification: CreditSpecificationRequest | None + CpuOptions: CpuOptionsRequest | None + CapacityReservationSpecification: CapacityReservationSpecification | None + HibernationOptions: HibernationOptionsRequest | None + LicenseSpecifications: LicenseSpecificationListRequest | None + MetadataOptions: InstanceMetadataOptionsRequest | None + EnclaveOptions: EnclaveOptionsRequest | None + PrivateDnsNameOptions: PrivateDnsNameOptionsRequest | None + MaintenanceOptions: InstanceMaintenanceOptionsRequest | None + DisableApiStop: Boolean | None + EnablePrimaryIpv6: Boolean | None + NetworkPerformanceOptions: InstanceNetworkPerformanceOptionsRequest | None + Operator: OperatorRequest | None + SecondaryInterfaces: InstanceSecondaryInterfaceSpecificationListRequest | None + DryRun: Boolean | None + DisableApiTermination: Boolean | None + InstanceInitiatedShutdownBehavior: ShutdownBehavior | None + PrivateIpAddress: String | None + ClientToken: String | None + AdditionalInfo: String | None + NetworkInterfaces: InstanceNetworkInterfaceSpecificationList | None + IamInstanceProfile: IamInstanceProfileSpecification | None + EbsOptimized: Boolean | None + + +ScheduledInstancesSecurityGroupIdSet = list[SecurityGroupId] class ScheduledInstancesPlacement(TypedDict, total=False): - AvailabilityZone: Optional[String] - GroupName: Optional[PlacementGroupName] + AvailabilityZone: String | None + GroupName: PlacementGroupName | None class ScheduledInstancesIpv6Address(TypedDict, total=False): - Ipv6Address: Optional[Ipv6Address] + Ipv6Address: Ipv6Address | None -ScheduledInstancesIpv6AddressList = List[ScheduledInstancesIpv6Address] +ScheduledInstancesIpv6AddressList = list[ScheduledInstancesIpv6Address] class ScheduledInstancesNetworkInterface(TypedDict, total=False): - AssociatePublicIpAddress: Optional[Boolean] - DeleteOnTermination: Optional[Boolean] - Description: Optional[String] - DeviceIndex: Optional[Integer] - Groups: Optional[ScheduledInstancesSecurityGroupIdSet] - Ipv6AddressCount: Optional[Integer] - Ipv6Addresses: Optional[ScheduledInstancesIpv6AddressList] - NetworkInterfaceId: Optional[NetworkInterfaceId] - PrivateIpAddress: Optional[String] - PrivateIpAddressConfigs: Optional[PrivateIpAddressConfigSet] - SecondaryPrivateIpAddressCount: Optional[Integer] - SubnetId: Optional[SubnetId] + AssociatePublicIpAddress: Boolean | None + DeleteOnTermination: Boolean | None + Description: String | None + DeviceIndex: Integer | None + Groups: ScheduledInstancesSecurityGroupIdSet | None + Ipv6AddressCount: Integer | None + Ipv6Addresses: ScheduledInstancesIpv6AddressList | None + NetworkInterfaceId: NetworkInterfaceId | None + PrivateIpAddress: String | None + PrivateIpAddressConfigs: PrivateIpAddressConfigSet | None + SecondaryPrivateIpAddressCount: Integer | None + SubnetId: SubnetId | None -ScheduledInstancesNetworkInterfaceSet = List[ScheduledInstancesNetworkInterface] +ScheduledInstancesNetworkInterfaceSet = list[ScheduledInstancesNetworkInterface] class ScheduledInstancesMonitoring(TypedDict, total=False): - Enabled: Optional[Boolean] + Enabled: Boolean | None class ScheduledInstancesIamInstanceProfile(TypedDict, total=False): - Arn: Optional[String] - Name: Optional[String] + Arn: String | None + Name: String | None class ScheduledInstancesEbs(TypedDict, total=False): - DeleteOnTermination: Optional[Boolean] - Encrypted: Optional[Boolean] - Iops: Optional[Integer] - SnapshotId: Optional[SnapshotId] - VolumeSize: Optional[Integer] - VolumeType: Optional[String] + DeleteOnTermination: Boolean | None + Encrypted: Boolean | None + Iops: Integer | None + SnapshotId: SnapshotId | None + VolumeSize: Integer | None + VolumeType: String | None class ScheduledInstancesBlockDeviceMapping(TypedDict, total=False): - DeviceName: Optional[String] - Ebs: Optional[ScheduledInstancesEbs] - NoDevice: Optional[String] - VirtualName: Optional[String] + DeviceName: String | None + Ebs: ScheduledInstancesEbs | None + NoDevice: String | None + VirtualName: String | None -ScheduledInstancesBlockDeviceMappingSet = List[ScheduledInstancesBlockDeviceMapping] +ScheduledInstancesBlockDeviceMappingSet = list[ScheduledInstancesBlockDeviceMapping] class ScheduledInstancesLaunchSpecification(TypedDict, total=False): - BlockDeviceMappings: Optional[ScheduledInstancesBlockDeviceMappingSet] - EbsOptimized: Optional[Boolean] - IamInstanceProfile: Optional[ScheduledInstancesIamInstanceProfile] + BlockDeviceMappings: ScheduledInstancesBlockDeviceMappingSet | None + EbsOptimized: Boolean | None + IamInstanceProfile: ScheduledInstancesIamInstanceProfile | None ImageId: ImageId - InstanceType: Optional[String] - KernelId: Optional[KernelId] - KeyName: Optional[KeyPairName] - Monitoring: Optional[ScheduledInstancesMonitoring] - NetworkInterfaces: Optional[ScheduledInstancesNetworkInterfaceSet] - Placement: Optional[ScheduledInstancesPlacement] - RamdiskId: Optional[RamdiskId] - SecurityGroupIds: Optional[ScheduledInstancesSecurityGroupIdSet] - SubnetId: Optional[SubnetId] - UserData: Optional[String] + InstanceType: String | None + KernelId: KernelId | None + KeyName: KeyPairName | None + Monitoring: ScheduledInstancesMonitoring | None + NetworkInterfaces: ScheduledInstancesNetworkInterfaceSet | None + Placement: ScheduledInstancesPlacement | None + RamdiskId: RamdiskId | None + SecurityGroupIds: ScheduledInstancesSecurityGroupIdSet | None + SubnetId: SubnetId | None + UserData: String | None class RunScheduledInstancesRequest(ServiceRequest): - ClientToken: Optional[String] - DryRun: Optional[Boolean] - InstanceCount: Optional[Integer] + ClientToken: String | None + DryRun: Boolean | None + InstanceCount: Integer | None LaunchSpecification: ScheduledInstancesLaunchSpecification ScheduledInstanceId: ScheduledInstanceId class RunScheduledInstancesResult(TypedDict, total=False): - InstanceIdSet: Optional[InstanceIdSet] + InstanceIdSet: InstanceIdSet | None class SearchLocalGatewayRoutesRequest(ServiceRequest): LocalGatewayRouteTableId: LocalGatewayRoutetableId - Filters: Optional[FilterList] - MaxResults: Optional[MaxResults] - NextToken: Optional[String] - DryRun: Optional[Boolean] + Filters: FilterList | None + MaxResults: MaxResults | None + NextToken: String | None + DryRun: Boolean | None class SearchLocalGatewayRoutesResult(TypedDict, total=False): - Routes: Optional[LocalGatewayRouteList] - NextToken: Optional[String] + Routes: LocalGatewayRouteList | None + NextToken: String | None class SearchTransitGatewayMulticastGroupsRequest(ServiceRequest): TransitGatewayMulticastDomainId: TransitGatewayMulticastDomainId - Filters: Optional[FilterList] - MaxResults: Optional[TransitGatewayMaxResults] - NextToken: Optional[String] - DryRun: Optional[Boolean] + Filters: FilterList | None + MaxResults: TransitGatewayMaxResults | None + NextToken: String | None + DryRun: Boolean | None class TransitGatewayMulticastGroup(TypedDict, total=False): - GroupIpAddress: Optional[String] - TransitGatewayAttachmentId: Optional[String] - SubnetId: Optional[String] - ResourceId: Optional[String] - ResourceType: Optional[TransitGatewayAttachmentResourceType] - ResourceOwnerId: Optional[String] - NetworkInterfaceId: Optional[String] - GroupMember: Optional[Boolean] - GroupSource: Optional[Boolean] - MemberType: Optional[MembershipType] - SourceType: Optional[MembershipType] + GroupIpAddress: String | None + TransitGatewayAttachmentId: String | None + SubnetId: String | None + ResourceId: String | None + ResourceType: TransitGatewayAttachmentResourceType | None + ResourceOwnerId: String | None + NetworkInterfaceId: String | None + GroupMember: Boolean | None + GroupSource: Boolean | None + MemberType: MembershipType | None + SourceType: MembershipType | None -TransitGatewayMulticastGroupList = List[TransitGatewayMulticastGroup] +TransitGatewayMulticastGroupList = list[TransitGatewayMulticastGroup] class SearchTransitGatewayMulticastGroupsResult(TypedDict, total=False): - MulticastGroups: Optional[TransitGatewayMulticastGroupList] - NextToken: Optional[String] + MulticastGroups: TransitGatewayMulticastGroupList | None + NextToken: String | None class SearchTransitGatewayRoutesRequest(ServiceRequest): TransitGatewayRouteTableId: TransitGatewayRouteTableId Filters: FilterList - MaxResults: Optional[TransitGatewayMaxResults] - DryRun: Optional[Boolean] + MaxResults: TransitGatewayMaxResults | None + DryRun: Boolean | None + NextToken: String | None -TransitGatewayRouteList = List[TransitGatewayRoute] +TransitGatewayRouteList = list[TransitGatewayRoute] class SearchTransitGatewayRoutesResult(TypedDict, total=False): - Routes: Optional[TransitGatewayRouteList] - AdditionalRoutesAvailable: Optional[Boolean] + Routes: TransitGatewayRouteList | None + AdditionalRoutesAvailable: Boolean | None + NextToken: String | None class SecurityGroupRuleDescription(TypedDict, total=False): - SecurityGroupRuleId: Optional[String] - Description: Optional[String] + SecurityGroupRuleId: String | None + Description: String | None -SecurityGroupRuleDescriptionList = List[SecurityGroupRuleDescription] +SecurityGroupRuleDescriptionList = list[SecurityGroupRuleDescription] class SendDiagnosticInterruptRequest(ServiceRequest): InstanceId: InstanceId - DryRun: Optional[Boolean] + DryRun: Boolean | None class StartDeclarativePoliciesReportRequest(ServiceRequest): - DryRun: Optional[Boolean] + DryRun: Boolean | None S3Bucket: String - S3Prefix: Optional[String] + S3Prefix: String | None TargetId: String - TagSpecifications: Optional[TagSpecificationList] + TagSpecifications: TagSpecificationList | None class StartDeclarativePoliciesReportResult(TypedDict, total=False): - ReportId: Optional[String] + ReportId: String | None class StartInstancesRequest(ServiceRequest): InstanceIds: InstanceIdStringList - AdditionalInfo: Optional[String] - DryRun: Optional[Boolean] + AdditionalInfo: String | None + DryRun: Boolean | None class StartInstancesResult(TypedDict, total=False): - StartingInstances: Optional[InstanceStateChangeList] + StartingInstances: InstanceStateChangeList | None class StartNetworkInsightsAccessScopeAnalysisRequest(ServiceRequest): NetworkInsightsAccessScopeId: NetworkInsightsAccessScopeId - DryRun: Optional[Boolean] - TagSpecifications: Optional[TagSpecificationList] + DryRun: Boolean | None + TagSpecifications: TagSpecificationList | None ClientToken: String class StartNetworkInsightsAccessScopeAnalysisResult(TypedDict, total=False): - NetworkInsightsAccessScopeAnalysis: Optional[NetworkInsightsAccessScopeAnalysis] + NetworkInsightsAccessScopeAnalysis: NetworkInsightsAccessScopeAnalysis | None class StartNetworkInsightsAnalysisRequest(ServiceRequest): NetworkInsightsPathId: NetworkInsightsPathId - AdditionalAccounts: Optional[ValueStringList] - FilterInArns: Optional[ArnList] - FilterOutArns: Optional[ArnList] - DryRun: Optional[Boolean] - TagSpecifications: Optional[TagSpecificationList] + AdditionalAccounts: ValueStringList | None + FilterInArns: ArnList | None + FilterOutArns: ArnList | None + DryRun: Boolean | None + TagSpecifications: TagSpecificationList | None ClientToken: String class StartNetworkInsightsAnalysisResult(TypedDict, total=False): - NetworkInsightsAnalysis: Optional[NetworkInsightsAnalysis] + NetworkInsightsAnalysis: NetworkInsightsAnalysis | None class StartVpcEndpointServicePrivateDnsVerificationRequest(ServiceRequest): - DryRun: Optional[Boolean] + DryRun: Boolean | None ServiceId: VpcEndpointServiceId class StartVpcEndpointServicePrivateDnsVerificationResult(TypedDict, total=False): - ReturnValue: Optional[Boolean] + ReturnValue: Boolean | None class StopInstancesRequest(ServiceRequest): InstanceIds: InstanceIdStringList - Hibernate: Optional[Boolean] - SkipOsShutdown: Optional[Boolean] - DryRun: Optional[Boolean] - Force: Optional[Boolean] + Hibernate: Boolean | None + SkipOsShutdown: Boolean | None + DryRun: Boolean | None + Force: Boolean | None class StopInstancesResult(TypedDict, total=False): - StoppingInstances: Optional[InstanceStateChangeList] + StoppingInstances: InstanceStateChangeList | None class TerminateClientVpnConnectionsRequest(ServiceRequest): ClientVpnEndpointId: ClientVpnEndpointId - ConnectionId: Optional[String] - Username: Optional[String] - DryRun: Optional[Boolean] + ConnectionId: String | None + Username: String | None + DryRun: Boolean | None class TerminateConnectionStatus(TypedDict, total=False): - ConnectionId: Optional[String] - PreviousStatus: Optional[ClientVpnConnectionStatus] - CurrentStatus: Optional[ClientVpnConnectionStatus] + ConnectionId: String | None + PreviousStatus: ClientVpnConnectionStatus | None + CurrentStatus: ClientVpnConnectionStatus | None -TerminateConnectionStatusSet = List[TerminateConnectionStatus] +TerminateConnectionStatusSet = list[TerminateConnectionStatus] class TerminateClientVpnConnectionsResult(TypedDict, total=False): - ClientVpnEndpointId: Optional[String] - Username: Optional[String] - ConnectionStatuses: Optional[TerminateConnectionStatusSet] + ClientVpnEndpointId: String | None + Username: String | None + ConnectionStatuses: TerminateConnectionStatusSet | None class TerminateInstancesRequest(ServiceRequest): InstanceIds: InstanceIdStringList - Force: Optional[Boolean] - SkipOsShutdown: Optional[Boolean] - DryRun: Optional[Boolean] + Force: Boolean | None + SkipOsShutdown: Boolean | None + DryRun: Boolean | None class TerminateInstancesResult(TypedDict, total=False): - TerminatingInstances: Optional[InstanceStateChangeList] + TerminatingInstances: InstanceStateChangeList | None class UnassignIpv6AddressesRequest(ServiceRequest): - Ipv6Prefixes: Optional[IpPrefixList] + Ipv6Prefixes: IpPrefixList | None NetworkInterfaceId: NetworkInterfaceId - Ipv6Addresses: Optional[Ipv6AddressList] + Ipv6Addresses: Ipv6AddressList | None class UnassignIpv6AddressesResult(TypedDict, total=False): - NetworkInterfaceId: Optional[String] - UnassignedIpv6Addresses: Optional[Ipv6AddressList] - UnassignedIpv6Prefixes: Optional[IpPrefixList] + NetworkInterfaceId: String | None + UnassignedIpv6Addresses: Ipv6AddressList | None + UnassignedIpv6Prefixes: IpPrefixList | None class UnassignPrivateIpAddressesRequest(ServiceRequest): - Ipv4Prefixes: Optional[IpPrefixList] + Ipv4Prefixes: IpPrefixList | None NetworkInterfaceId: NetworkInterfaceId - PrivateIpAddresses: Optional[PrivateIpAddressStringList] + PrivateIpAddresses: PrivateIpAddressStringList | None class UnassignPrivateNatGatewayAddressRequest(ServiceRequest): NatGatewayId: NatGatewayId PrivateIpAddresses: IpList - MaxDrainDurationSeconds: Optional[DrainSeconds] - DryRun: Optional[Boolean] + MaxDrainDurationSeconds: DrainSeconds | None + DryRun: Boolean | None class UnassignPrivateNatGatewayAddressResult(TypedDict, total=False): - NatGatewayId: Optional[NatGatewayId] - NatGatewayAddresses: Optional[NatGatewayAddressList] + NatGatewayId: NatGatewayId | None + NatGatewayAddresses: NatGatewayAddressList | None class UnlockSnapshotRequest(ServiceRequest): SnapshotId: SnapshotId - DryRun: Optional[Boolean] + DryRun: Boolean | None class UnlockSnapshotResult(TypedDict, total=False): - SnapshotId: Optional[String] + SnapshotId: String | None class UnmonitorInstancesRequest(ServiceRequest): InstanceIds: InstanceIdStringList - DryRun: Optional[Boolean] + DryRun: Boolean | None class UnmonitorInstancesResult(TypedDict, total=False): - InstanceMonitorings: Optional[InstanceMonitoringList] + InstanceMonitorings: InstanceMonitoringList | None + + +class UpdateCapacityManagerOrganizationsAccessRequest(ServiceRequest): + OrganizationsAccess: BoxedBoolean + DryRun: Boolean | None + ClientToken: String | None + + +class UpdateCapacityManagerOrganizationsAccessResult(TypedDict, total=False): + CapacityManagerStatus: CapacityManagerStatus | None + OrganizationsAccess: Boolean | None + + +class UpdateInterruptibleCapacityReservationAllocationRequest(ServiceRequest): + CapacityReservationId: CapacityReservationId + TargetInstanceCount: Integer + DryRun: Boolean | None + + +class UpdateInterruptibleCapacityReservationAllocationResult(TypedDict, total=False): + InterruptibleCapacityReservationId: CapacityReservationId | None + SourceCapacityReservationId: CapacityReservationId | None + InstanceCount: Integer | None + TargetInstanceCount: Integer | None + Status: InterruptibleCapacityReservationAllocationStatus | None + InterruptionType: InterruptionType | None class UpdateSecurityGroupRuleDescriptionsEgressRequest(ServiceRequest): - DryRun: Optional[Boolean] - GroupId: Optional[SecurityGroupId] - GroupName: Optional[SecurityGroupName] - IpPermissions: Optional[IpPermissionList] - SecurityGroupRuleDescriptions: Optional[SecurityGroupRuleDescriptionList] + DryRun: Boolean | None + GroupId: SecurityGroupId | None + GroupName: SecurityGroupName | None + IpPermissions: IpPermissionList | None + SecurityGroupRuleDescriptions: SecurityGroupRuleDescriptionList | None class UpdateSecurityGroupRuleDescriptionsEgressResult(TypedDict, total=False): - Return: Optional[Boolean] + Return: Boolean | None class UpdateSecurityGroupRuleDescriptionsIngressRequest(ServiceRequest): - DryRun: Optional[Boolean] - GroupId: Optional[SecurityGroupId] - GroupName: Optional[SecurityGroupName] - IpPermissions: Optional[IpPermissionList] - SecurityGroupRuleDescriptions: Optional[SecurityGroupRuleDescriptionList] + DryRun: Boolean | None + GroupId: SecurityGroupId | None + GroupName: SecurityGroupName | None + IpPermissions: IpPermissionList | None + SecurityGroupRuleDescriptions: SecurityGroupRuleDescriptionList | None class UpdateSecurityGroupRuleDescriptionsIngressResult(TypedDict, total=False): - Return: Optional[Boolean] + Return: Boolean | None class WithdrawByoipCidrRequest(ServiceRequest): Cidr: String - DryRun: Optional[Boolean] + DryRun: Boolean | None class WithdrawByoipCidrResult(TypedDict, total=False): - ByoipCidr: Optional[ByoipCidr] + ByoipCidr: ByoipCidr | None class Ec2Api: - service = "ec2" - version = "2016-11-15" + service: str = "ec2" + version: str = "2016-11-15" @handler("AcceptAddressTransfer") def accept_address_transfer( @@ -21260,7 +23414,7 @@ def allocate_hosts( client_token: String | None = None, instance_type: String | None = None, quantity: Integer | None = None, - availability_zone: String | None = None, + availability_zone: AvailabilityZoneName | None = None, **kwargs, ) -> AllocateHostsResult: raise NotImplementedError @@ -21446,6 +23600,8 @@ def associate_nat_gateway_address( allocation_ids: AllocationIdList, private_ip_addresses: IpList | None = None, dry_run: Boolean | None = None, + availability_zone: AvailabilityZoneName | None = None, + availability_zone_id: AvailabilityZoneId | None = None, **kwargs, ) -> AssociateNatGatewayAddressResult: raise NotImplementedError @@ -21620,6 +23776,7 @@ def attach_volume( device: String, instance_id: InstanceId, volume_id: VolumeId, + ebs_card_index: BoxedInteger | None = None, dry_run: Boolean | None = None, **kwargs, ) -> VolumeAttachment: @@ -21866,6 +24023,38 @@ def copy_snapshot( ) -> CopySnapshotResult: raise NotImplementedError + @handler("CopyVolumes") + def copy_volumes( + self, + context: RequestContext, + source_volume_id: VolumeId, + iops: Integer | None = None, + size: Integer | None = None, + volume_type: VolumeType | None = None, + dry_run: Boolean | None = None, + tag_specifications: TagSpecificationList | None = None, + multi_attach_enabled: Boolean | None = None, + throughput: Integer | None = None, + client_token: String | None = None, + **kwargs, + ) -> CopyVolumesResult: + raise NotImplementedError + + @handler("CreateCapacityManagerDataExport") + def create_capacity_manager_data_export( + self, + context: RequestContext, + s3_bucket_name: String, + schedule: Schedule, + output_format: OutputFormat, + s3_bucket_prefix: String | None = None, + client_token: String | None = None, + dry_run: Boolean | None = None, + tag_specifications: TagSpecificationList | None = None, + **kwargs, + ) -> CreateCapacityManagerDataExportResult: + raise NotImplementedError + @handler("CreateCapacityReservation") def create_capacity_reservation( self, @@ -22185,6 +24374,19 @@ def create_internet_gateway( ) -> CreateInternetGatewayResult: raise NotImplementedError + @handler("CreateInterruptibleCapacityReservationAllocation") + def create_interruptible_capacity_reservation_allocation( + self, + context: RequestContext, + capacity_reservation_id: CapacityReservationId, + instance_count: Integer, + client_token: String | None = None, + dry_run: Boolean | None = None, + tag_specifications: TagSpecificationList | None = None, + **kwargs, + ) -> CreateInterruptibleCapacityReservationAllocationResult: + raise NotImplementedError + @handler("CreateIpam") def create_ipam( self, @@ -22213,6 +24415,18 @@ def create_ipam_external_resource_verification_token( ) -> CreateIpamExternalResourceVerificationTokenResult: raise NotImplementedError + @handler("CreateIpamPolicy") + def create_ipam_policy( + self, + context: RequestContext, + ipam_id: IpamId, + dry_run: Boolean | None = None, + tag_specifications: TagSpecificationList | None = None, + client_token: String | None = None, + **kwargs, + ) -> CreateIpamPolicyResult: + raise NotImplementedError + @handler("CreateIpamPool") def create_ipam_pool( self, @@ -22238,6 +24452,37 @@ def create_ipam_pool( ) -> CreateIpamPoolResult: raise NotImplementedError + @handler("CreateIpamPrefixListResolver") + def create_ipam_prefix_list_resolver( + self, + context: RequestContext, + ipam_id: IpamId, + address_family: AddressFamily, + dry_run: Boolean | None = None, + description: String | None = None, + rules: IpamPrefixListResolverRuleRequestSet | None = None, + tag_specifications: TagSpecificationList | None = None, + client_token: String | None = None, + **kwargs, + ) -> CreateIpamPrefixListResolverResult: + raise NotImplementedError + + @handler("CreateIpamPrefixListResolverTarget") + def create_ipam_prefix_list_resolver_target( + self, + context: RequestContext, + ipam_prefix_list_resolver_id: IpamPrefixListResolverId, + prefix_list_id: String, + prefix_list_region: String, + track_latest_version: Boolean, + dry_run: Boolean | None = None, + desired_version: BoxedLong | None = None, + tag_specifications: TagSpecificationList | None = None, + client_token: String | None = None, + **kwargs, + ) -> CreateIpamPrefixListResolverTargetResult: + raise NotImplementedError + @handler("CreateIpamResourceDiscovery") def create_ipam_resource_discovery( self, @@ -22260,6 +24505,7 @@ def create_ipam_scope( description: String | None = None, tag_specifications: TagSpecificationList | None = None, client_token: String | None = None, + external_authority_configuration: ExternalAuthorityConfiguration | None = None, **kwargs, ) -> CreateIpamScopeResult: raise NotImplementedError @@ -22423,10 +24669,13 @@ def create_managed_prefix_list( def create_nat_gateway( self, context: RequestContext, - subnet_id: SubnetId, + availability_mode: AvailabilityMode | None = None, allocation_id: AllocationId | None = None, client_token: String | None = None, dry_run: Boolean | None = None, + subnet_id: SubnetId | None = None, + vpc_id: VpcId | None = None, + availability_zone_addresses: AvailabilityZoneAddresses | None = None, tag_specifications: TagSpecificationList | None = None, connectivity_type: ConnectivityType | None = None, private_ip_address: String | None = None, @@ -22546,6 +24795,8 @@ def create_placement_group( partition_count: Integer | None = None, tag_specifications: TagSpecificationList | None = None, spread_level: SpreadLevel | None = None, + linked_group_id: PlacementGroupId | None = None, + operator: OperatorRequest | None = None, dry_run: Boolean | None = None, group_name: String | None = None, strategy: PlacementStrategy | None = None, @@ -22683,6 +24934,34 @@ def create_route_table( ) -> CreateRouteTableResult: raise NotImplementedError + @handler("CreateSecondaryNetwork") + def create_secondary_network( + self, + context: RequestContext, + ipv4_cidr_block: String, + network_type: SecondaryNetworkType, + client_token: String | None = None, + dry_run: Boolean | None = None, + tag_specifications: TagSpecificationList | None = None, + **kwargs, + ) -> CreateSecondaryNetworkResult: + raise NotImplementedError + + @handler("CreateSecondarySubnet") + def create_secondary_subnet( + self, + context: RequestContext, + ipv4_cidr_block: String, + secondary_network_id: SecondaryNetworkId, + client_token: String | None = None, + availability_zone: AvailabilityZoneName | None = None, + availability_zone_id: AvailabilityZoneId | None = None, + dry_run: Boolean | None = None, + tag_specifications: TagSpecificationList | None = None, + **kwargs, + ) -> CreateSecondarySubnetResult: + raise NotImplementedError + @handler("CreateSecurityGroup") def create_security_group( self, @@ -22899,6 +25178,40 @@ def create_transit_gateway_connect_peer( ) -> CreateTransitGatewayConnectPeerResult: raise NotImplementedError + @handler("CreateTransitGatewayMeteringPolicy") + def create_transit_gateway_metering_policy( + self, + context: RequestContext, + transit_gateway_id: TransitGatewayId, + middlebox_attachment_ids: TransitGatewayAttachmentIdStringList | None = None, + tag_specifications: TagSpecificationList | None = None, + dry_run: Boolean | None = None, + **kwargs, + ) -> CreateTransitGatewayMeteringPolicyResult: + raise NotImplementedError + + @handler("CreateTransitGatewayMeteringPolicyEntry") + def create_transit_gateway_metering_policy_entry( + self, + context: RequestContext, + transit_gateway_metering_policy_id: TransitGatewayMeteringPolicyId, + policy_rule_number: Integer, + metered_account: TransitGatewayMeteringPayerType, + source_transit_gateway_attachment_id: TransitGatewayAttachmentId | None = None, + source_transit_gateway_attachment_type: TransitGatewayAttachmentResourceType | None = None, + source_cidr_block: String | None = None, + source_port_range: String | None = None, + destination_transit_gateway_attachment_id: TransitGatewayAttachmentId | None = None, + destination_transit_gateway_attachment_type: TransitGatewayAttachmentResourceType + | None = None, + destination_cidr_block: String | None = None, + destination_port_range: String | None = None, + protocol: String | None = None, + dry_run: Boolean | None = None, + **kwargs, + ) -> CreateTransitGatewayMeteringPolicyEntryResult: + raise NotImplementedError + @handler("CreateTransitGatewayMulticastDomain") def create_transit_gateway_multicast_domain( self, @@ -23111,6 +25424,7 @@ def create_vpc( ipv6_ipam_pool_id: IpamPoolId | None = None, ipv6_netmask_length: NetmaskLength | None = None, ipv6_cidr_block_network_border_group: String | None = None, + vpc_encryption_control: VpcEncryptionControlConfiguration | None = None, tag_specifications: TagSpecificationList | None = None, dry_run: Boolean | None = None, instance_tenancy: Tenancy | None = None, @@ -23132,6 +25446,17 @@ def create_vpc_block_public_access_exclusion( ) -> CreateVpcBlockPublicAccessExclusionResult: raise NotImplementedError + @handler("CreateVpcEncryptionControl") + def create_vpc_encryption_control( + self, + context: RequestContext, + vpc_id: VpcId, + dry_run: Boolean | None = None, + tag_specifications: TagSpecificationList | None = None, + **kwargs, + ) -> CreateVpcEncryptionControlResult: + raise NotImplementedError + @handler("CreateVpcEndpoint") def create_vpc_endpoint( self, @@ -23202,6 +25527,12 @@ def create_vpc_peering_connection( ) -> CreateVpcPeeringConnectionResult: raise NotImplementedError + @handler("CreateVpnConcentrator", expand=False) + def create_vpn_concentrator( + self, context: RequestContext, request: CreateVpnConcentratorRequest, **kwargs + ) -> CreateVpnConcentratorResult: + raise NotImplementedError + @handler("CreateVpnConnection", expand=False) def create_vpn_connection( self, context: RequestContext, request: CreateVpnConnectionRequest, **kwargs @@ -23224,6 +25555,16 @@ def create_vpn_gateway( ) -> CreateVpnGatewayResult: raise NotImplementedError + @handler("DeleteCapacityManagerDataExport") + def delete_capacity_manager_data_export( + self, + context: RequestContext, + capacity_manager_data_export_id: CapacityManagerDataExportId, + dry_run: Boolean | None = None, + **kwargs, + ) -> DeleteCapacityManagerDataExportResult: + raise NotImplementedError + @handler("DeleteCarrierGateway") def delete_carrier_gateway( self, @@ -23400,6 +25741,16 @@ def delete_ipam_external_resource_verification_token( ) -> DeleteIpamExternalResourceVerificationTokenResult: raise NotImplementedError + @handler("DeleteIpamPolicy") + def delete_ipam_policy( + self, + context: RequestContext, + ipam_policy_id: IpamPolicyId, + dry_run: Boolean | None = None, + **kwargs, + ) -> DeleteIpamPolicyResult: + raise NotImplementedError + @handler("DeleteIpamPool") def delete_ipam_pool( self, @@ -23411,6 +25762,26 @@ def delete_ipam_pool( ) -> DeleteIpamPoolResult: raise NotImplementedError + @handler("DeleteIpamPrefixListResolver") + def delete_ipam_prefix_list_resolver( + self, + context: RequestContext, + ipam_prefix_list_resolver_id: IpamPrefixListResolverId, + dry_run: Boolean | None = None, + **kwargs, + ) -> DeleteIpamPrefixListResolverResult: + raise NotImplementedError + + @handler("DeleteIpamPrefixListResolverTarget") + def delete_ipam_prefix_list_resolver_target( + self, + context: RequestContext, + ipam_prefix_list_resolver_target_id: IpamPrefixListResolverTargetId, + dry_run: Boolean | None = None, + **kwargs, + ) -> DeleteIpamPrefixListResolverTargetResult: + raise NotImplementedError + @handler("DeleteIpamResourceDiscovery") def delete_ipam_resource_discovery( self, @@ -23634,7 +26005,7 @@ def delete_network_interface_permission( def delete_placement_group( self, context: RequestContext, - group_name: PlacementGroupName, + group_name: PlacementGroupNameWithResolver, dry_run: Boolean | None = None, **kwargs, ) -> None: @@ -23714,6 +26085,28 @@ def delete_route_table( ) -> None: raise NotImplementedError + @handler("DeleteSecondaryNetwork") + def delete_secondary_network( + self, + context: RequestContext, + secondary_network_id: SecondaryNetworkId, + client_token: String | None = None, + dry_run: Boolean | None = None, + **kwargs, + ) -> DeleteSecondaryNetworkResult: + raise NotImplementedError + + @handler("DeleteSecondarySubnet") + def delete_secondary_subnet( + self, + context: RequestContext, + secondary_subnet_id: SecondarySubnetId, + client_token: String | None = None, + dry_run: Boolean | None = None, + **kwargs, + ) -> DeleteSecondarySubnetResult: + raise NotImplementedError + @handler("DeleteSecurityGroup") def delete_security_group( self, @@ -23838,6 +26231,27 @@ def delete_transit_gateway_connect_peer( ) -> DeleteTransitGatewayConnectPeerResult: raise NotImplementedError + @handler("DeleteTransitGatewayMeteringPolicy") + def delete_transit_gateway_metering_policy( + self, + context: RequestContext, + transit_gateway_metering_policy_id: TransitGatewayMeteringPolicyId, + dry_run: Boolean | None = None, + **kwargs, + ) -> DeleteTransitGatewayMeteringPolicyResult: + raise NotImplementedError + + @handler("DeleteTransitGatewayMeteringPolicyEntry") + def delete_transit_gateway_metering_policy_entry( + self, + context: RequestContext, + transit_gateway_metering_policy_id: TransitGatewayMeteringPolicyId, + policy_rule_number: Integer, + dry_run: Boolean | None = None, + **kwargs, + ) -> DeleteTransitGatewayMeteringPolicyEntryResult: + raise NotImplementedError + @handler("DeleteTransitGatewayMulticastDomain") def delete_transit_gateway_multicast_domain( self, @@ -23986,6 +26400,16 @@ def delete_vpc_block_public_access_exclusion( ) -> DeleteVpcBlockPublicAccessExclusionResult: raise NotImplementedError + @handler("DeleteVpcEncryptionControl") + def delete_vpc_encryption_control( + self, + context: RequestContext, + vpc_encryption_control_id: VpcEncryptionControlId, + dry_run: Boolean | None = None, + **kwargs, + ) -> DeleteVpcEncryptionControlResult: + raise NotImplementedError + @handler("DeleteVpcEndpointConnectionNotifications") def delete_vpc_endpoint_connection_notifications( self, @@ -24026,6 +26450,16 @@ def delete_vpc_peering_connection( ) -> DeleteVpcPeeringConnectionResult: raise NotImplementedError + @handler("DeleteVpnConcentrator") + def delete_vpn_concentrator( + self, + context: RequestContext, + vpn_concentrator_id: VpnConcentratorId, + dry_run: Boolean | None = None, + **kwargs, + ) -> DeleteVpnConcentratorResult: + raise NotImplementedError + @handler("DeleteVpnConnection") def delete_vpn_connection( self, @@ -24280,6 +26714,7 @@ def describe_capacity_block_offerings( max_results: DescribeCapacityBlockOfferingsMaxResults | None = None, ultraserver_type: String | None = None, ultraserver_count: Integer | None = None, + all_availability_zones: Boolean | None = None, **kwargs, ) -> DescribeCapacityBlockOfferingsResult: raise NotImplementedError @@ -24310,6 +26745,19 @@ def describe_capacity_blocks( ) -> DescribeCapacityBlocksResult: raise NotImplementedError + @handler("DescribeCapacityManagerDataExports") + def describe_capacity_manager_data_exports( + self, + context: RequestContext, + capacity_manager_data_export_ids: CapacityManagerDataExportIdSet | None = None, + max_results: DescribeCapacityManagerDataExportsRequestMaxResults | None = None, + next_token: String | None = None, + dry_run: Boolean | None = None, + filters: FilterList | None = None, + **kwargs, + ) -> DescribeCapacityManagerDataExportsResult: + raise NotImplementedError + @handler("DescribeCapacityReservationBillingRequests") def describe_capacity_reservation_billing_requests( self, @@ -24337,6 +26785,19 @@ def describe_capacity_reservation_fleets( ) -> DescribeCapacityReservationFleetsResult: raise NotImplementedError + @handler("DescribeCapacityReservationTopology") + def describe_capacity_reservation_topology( + self, + context: RequestContext, + dry_run: Boolean | None = None, + next_token: String | None = None, + max_results: DescribeCapacityReservationTopologyMaxResults | None = None, + capacity_reservation_ids: CapacityReservationIdSet | None = None, + filters: FilterList | None = None, + **kwargs, + ) -> DescribeCapacityReservationTopologyResult: + raise NotImplementedError + @handler("DescribeCapacityReservations") def describe_capacity_reservations( self, @@ -24884,6 +27345,34 @@ def describe_instance_image_metadata( ) -> DescribeInstanceImageMetadataResult: raise NotImplementedError + @handler("DescribeInstanceSqlHaHistoryStates") + def describe_instance_sql_ha_history_states( + self, + context: RequestContext, + instance_ids: InstanceIdStringList | None = None, + start_time: MillisecondDateTime | None = None, + end_time: MillisecondDateTime | None = None, + next_token: NextToken | None = None, + max_results: DescribeInstanceSqlHaStatesRequestMaxResultsInteger | None = None, + filters: FilterList | None = None, + dry_run: Boolean | None = None, + **kwargs, + ) -> DescribeInstanceSqlHaHistoryStatesResult: + raise NotImplementedError + + @handler("DescribeInstanceSqlHaStates") + def describe_instance_sql_ha_states( + self, + context: RequestContext, + instance_ids: InstanceIdStringList | None = None, + next_token: NextToken | None = None, + max_results: DescribeInstanceSqlHaStatesRequestMaxResultsInteger | None = None, + filters: FilterList | None = None, + dry_run: Boolean | None = None, + **kwargs, + ) -> DescribeInstanceSqlHaStatesResult: + raise NotImplementedError + @handler("DescribeInstanceStatus") def describe_instance_status( self, @@ -24964,41 +27453,81 @@ def describe_internet_gateways( ) -> DescribeInternetGatewaysResult: raise NotImplementedError - @handler("DescribeIpamByoasn") - def describe_ipam_byoasn( + @handler("DescribeIpamByoasn") + def describe_ipam_byoasn( + self, + context: RequestContext, + dry_run: Boolean | None = None, + max_results: DescribeIpamByoasnMaxResults | None = None, + next_token: NextToken | None = None, + **kwargs, + ) -> DescribeIpamByoasnResult: + raise NotImplementedError + + @handler("DescribeIpamExternalResourceVerificationTokens") + def describe_ipam_external_resource_verification_tokens( + self, + context: RequestContext, + dry_run: Boolean | None = None, + filters: FilterList | None = None, + next_token: NextToken | None = None, + max_results: IpamMaxResults | None = None, + ipam_external_resource_verification_token_ids: ValueStringList | None = None, + **kwargs, + ) -> DescribeIpamExternalResourceVerificationTokensResult: + raise NotImplementedError + + @handler("DescribeIpamPolicies") + def describe_ipam_policies( + self, + context: RequestContext, + dry_run: Boolean | None = None, + filters: FilterList | None = None, + max_results: IpamMaxResults | None = None, + next_token: NextToken | None = None, + ipam_policy_ids: ValueStringList | None = None, + **kwargs, + ) -> DescribeIpamPoliciesResult: + raise NotImplementedError + + @handler("DescribeIpamPools") + def describe_ipam_pools( self, context: RequestContext, dry_run: Boolean | None = None, - max_results: DescribeIpamByoasnMaxResults | None = None, + filters: FilterList | None = None, + max_results: IpamMaxResults | None = None, next_token: NextToken | None = None, + ipam_pool_ids: ValueStringList | None = None, **kwargs, - ) -> DescribeIpamByoasnResult: + ) -> DescribeIpamPoolsResult: raise NotImplementedError - @handler("DescribeIpamExternalResourceVerificationTokens") - def describe_ipam_external_resource_verification_tokens( + @handler("DescribeIpamPrefixListResolverTargets") + def describe_ipam_prefix_list_resolver_targets( self, context: RequestContext, dry_run: Boolean | None = None, filters: FilterList | None = None, - next_token: NextToken | None = None, max_results: IpamMaxResults | None = None, - ipam_external_resource_verification_token_ids: ValueStringList | None = None, + next_token: NextToken | None = None, + ipam_prefix_list_resolver_target_ids: ValueStringList | None = None, + ipam_prefix_list_resolver_id: IpamPrefixListResolverId | None = None, **kwargs, - ) -> DescribeIpamExternalResourceVerificationTokensResult: + ) -> DescribeIpamPrefixListResolverTargetsResult: raise NotImplementedError - @handler("DescribeIpamPools") - def describe_ipam_pools( + @handler("DescribeIpamPrefixListResolvers") + def describe_ipam_prefix_list_resolvers( self, context: RequestContext, dry_run: Boolean | None = None, filters: FilterList | None = None, max_results: IpamMaxResults | None = None, next_token: NextToken | None = None, - ipam_pool_ids: ValueStringList | None = None, + ipam_prefix_list_resolver_ids: ValueStringList | None = None, **kwargs, - ) -> DescribeIpamPoolsResult: + ) -> DescribeIpamPrefixListResolversResult: raise NotImplementedError @handler("DescribeIpamResourceDiscoveries") @@ -25606,6 +28135,45 @@ def describe_scheduled_instances( ) -> DescribeScheduledInstancesResult: raise NotImplementedError + @handler("DescribeSecondaryInterfaces") + def describe_secondary_interfaces( + self, + context: RequestContext, + dry_run: Boolean | None = None, + filters: FilterList | None = None, + max_results: DescribeSecondaryInterfacesMaxResults | None = None, + next_token: String | None = None, + secondary_interface_ids: SecondaryInterfaceIdList | None = None, + **kwargs, + ) -> DescribeSecondaryInterfacesResult: + raise NotImplementedError + + @handler("DescribeSecondaryNetworks") + def describe_secondary_networks( + self, + context: RequestContext, + dry_run: Boolean | None = None, + filters: FilterList | None = None, + max_results: DescribeSecondaryNetworksMaxResults | None = None, + next_token: String | None = None, + secondary_network_ids: SecondaryNetworkIdList | None = None, + **kwargs, + ) -> DescribeSecondaryNetworksResult: + raise NotImplementedError + + @handler("DescribeSecondarySubnets") + def describe_secondary_subnets( + self, + context: RequestContext, + dry_run: Boolean | None = None, + filters: FilterList | None = None, + max_results: DescribeSecondarySubnetsMaxResults | None = None, + next_token: String | None = None, + secondary_subnet_ids: SecondarySubnetIdList | None = None, + **kwargs, + ) -> DescribeSecondarySubnetsResult: + raise NotImplementedError + @handler("DescribeSecurityGroupReferences") def describe_security_group_references( self, context: RequestContext, group_id: GroupIds, dry_run: Boolean | None = None, **kwargs @@ -25919,6 +28487,19 @@ def describe_transit_gateway_connects( ) -> DescribeTransitGatewayConnectsResult: raise NotImplementedError + @handler("DescribeTransitGatewayMeteringPolicies") + def describe_transit_gateway_metering_policies( + self, + context: RequestContext, + transit_gateway_metering_policy_ids: TransitGatewayMeteringPolicyIdStringList | None = None, + filters: FilterList | None = None, + max_results: TransitGatewayMaxResults | None = None, + next_token: String | None = None, + dry_run: Boolean | None = None, + **kwargs, + ) -> DescribeTransitGatewayMeteringPoliciesResult: + raise NotImplementedError + @handler("DescribeTransitGatewayMulticastDomains") def describe_transit_gateway_multicast_domains( self, @@ -26195,6 +28776,20 @@ def describe_vpc_classic_link_dns_support( ) -> DescribeVpcClassicLinkDnsSupportResult: raise NotImplementedError + @handler("DescribeVpcEncryptionControls") + def describe_vpc_encryption_controls( + self, + context: RequestContext, + dry_run: Boolean | None = None, + filters: FilterList | None = None, + vpc_encryption_control_ids: VpcEncryptionControlIdList | None = None, + vpc_ids: VpcIdStringList | None = None, + next_token: String | None = None, + max_results: DescribeVpcEncryptionControlsMaxResults | None = None, + **kwargs, + ) -> DescribeVpcEncryptionControlsResult: + raise NotImplementedError + @handler("DescribeVpcEndpointAssociations") def describe_vpc_endpoint_associations( self, @@ -26312,6 +28907,19 @@ def describe_vpcs( ) -> DescribeVpcsResult: raise NotImplementedError + @handler("DescribeVpnConcentrators") + def describe_vpn_concentrators( + self, + context: RequestContext, + vpn_concentrator_ids: VpnConcentratorIdStringList | None = None, + filters: FilterList | None = None, + max_results: GVCDMaxResults | None = None, + next_token: NextToken | None = None, + dry_run: Boolean | None = None, + **kwargs, + ) -> DescribeVpnConcentratorsResult: + raise NotImplementedError + @handler("DescribeVpnConnections") def describe_vpn_connections( self, @@ -26432,6 +29040,16 @@ def disable_aws_network_performance_metric_subscription( ) -> DisableAwsNetworkPerformanceMetricSubscriptionResult: raise NotImplementedError + @handler("DisableCapacityManager") + def disable_capacity_manager( + self, + context: RequestContext, + dry_run: Boolean | None = None, + client_token: String | None = None, + **kwargs, + ) -> DisableCapacityManagerResult: + raise NotImplementedError + @handler("DisableEbsEncryptionByDefault") def disable_ebs_encryption_by_default( self, context: RequestContext, dry_run: Boolean | None = None, **kwargs @@ -26453,8 +29071,9 @@ def disable_fast_launch( def disable_fast_snapshot_restores( self, context: RequestContext, - availability_zones: AvailabilityZoneStringList, source_snapshot_ids: SnapshotIdStringList, + availability_zones: AvailabilityZoneStringList | None = None, + availability_zone_ids: AvailabilityZoneIdStringList | None = None, dry_run: Boolean | None = None, **kwargs, ) -> DisableFastSnapshotRestoresResult: @@ -26484,6 +29103,16 @@ def disable_image_deregistration_protection( ) -> DisableImageDeregistrationProtectionResult: raise NotImplementedError + @handler("DisableInstanceSqlHaStandbyDetections") + def disable_instance_sql_ha_standby_detections( + self, + context: RequestContext, + instance_ids: InstanceIdUpdateStringList, + dry_run: Boolean | None = None, + **kwargs, + ) -> DisableInstanceSqlHaStandbyDetectionsResult: + raise NotImplementedError + @handler("DisableIpamOrganizationAdminAccount") def disable_ipam_organization_admin_account( self, @@ -26494,6 +29123,17 @@ def disable_ipam_organization_admin_account( ) -> DisableIpamOrganizationAdminAccountResult: raise NotImplementedError + @handler("DisableIpamPolicy") + def disable_ipam_policy( + self, + context: RequestContext, + ipam_policy_id: IpamPolicyId, + dry_run: Boolean | None = None, + organization_target_id: String | None = None, + **kwargs, + ) -> DisableIpamPolicyResult: + raise NotImplementedError + @handler("DisableRouteServerPropagation") def disable_route_server_propagation( self, @@ -26770,6 +29410,17 @@ def enable_aws_network_performance_metric_subscription( ) -> EnableAwsNetworkPerformanceMetricSubscriptionResult: raise NotImplementedError + @handler("EnableCapacityManager") + def enable_capacity_manager( + self, + context: RequestContext, + organizations_access: Boolean | None = None, + dry_run: Boolean | None = None, + client_token: String | None = None, + **kwargs, + ) -> EnableCapacityManagerResult: + raise NotImplementedError + @handler("EnableEbsEncryptionByDefault") def enable_ebs_encryption_by_default( self, context: RequestContext, dry_run: Boolean | None = None, **kwargs @@ -26794,8 +29445,9 @@ def enable_fast_launch( def enable_fast_snapshot_restores( self, context: RequestContext, - availability_zones: AvailabilityZoneStringList, source_snapshot_ids: SnapshotIdStringList, + availability_zones: AvailabilityZoneStringList | None = None, + availability_zone_ids: AvailabilityZoneIdStringList | None = None, dry_run: Boolean | None = None, **kwargs, ) -> EnableFastSnapshotRestoresResult: @@ -26839,6 +29491,17 @@ def enable_image_deregistration_protection( ) -> EnableImageDeregistrationProtectionResult: raise NotImplementedError + @handler("EnableInstanceSqlHaStandbyDetections") + def enable_instance_sql_ha_standby_detections( + self, + context: RequestContext, + instance_ids: InstanceIdUpdateStringList, + sql_server_credentials: SecretArn | None = None, + dry_run: Boolean | None = None, + **kwargs, + ) -> EnableInstanceSqlHaStandbyDetectionsResult: + raise NotImplementedError + @handler("EnableIpamOrganizationAdminAccount") def enable_ipam_organization_admin_account( self, @@ -26849,6 +29512,17 @@ def enable_ipam_organization_admin_account( ) -> EnableIpamOrganizationAdminAccountResult: raise NotImplementedError + @handler("EnableIpamPolicy") + def enable_ipam_policy( + self, + context: RequestContext, + ipam_policy_id: IpamPolicyId, + dry_run: Boolean | None = None, + organization_target_id: String | None = None, + **kwargs, + ) -> EnableIpamPolicyResult: + raise NotImplementedError + @handler("EnableReachabilityAnalyzerOrganizationSharing") def enable_reachability_analyzer_organization_sharing( self, context: RequestContext, dry_run: Boolean | None = None, **kwargs @@ -27035,6 +29709,45 @@ def get_aws_network_performance_data( ) -> GetAwsNetworkPerformanceDataResult: raise NotImplementedError + @handler("GetCapacityManagerAttributes") + def get_capacity_manager_attributes( + self, context: RequestContext, dry_run: Boolean | None = None, **kwargs + ) -> GetCapacityManagerAttributesResult: + raise NotImplementedError + + @handler("GetCapacityManagerMetricData") + def get_capacity_manager_metric_data( + self, + context: RequestContext, + metric_names: MetricSet, + start_time: MillisecondDateTime, + end_time: MillisecondDateTime, + period: Period, + group_by: GroupBySet | None = None, + filter_by: CapacityManagerConditionSet | None = None, + max_results: MaxResults | None = None, + next_token: NextToken | None = None, + dry_run: Boolean | None = None, + **kwargs, + ) -> GetCapacityManagerMetricDataResult: + raise NotImplementedError + + @handler("GetCapacityManagerMetricDimensions") + def get_capacity_manager_metric_dimensions( + self, + context: RequestContext, + group_by: GroupBySet, + start_time: MillisecondDateTime, + end_time: MillisecondDateTime, + metric_names: MetricSet, + filter_by: CapacityManagerConditionSet | None = None, + max_results: MaxResults | None = None, + next_token: NextToken | None = None, + dry_run: Boolean | None = None, + **kwargs, + ) -> GetCapacityManagerMetricDimensionsResult: + raise NotImplementedError + @handler("GetCapacityReservationUsage") def get_capacity_reservation_usage( self, @@ -27114,6 +29827,12 @@ def get_ebs_encryption_by_default( ) -> GetEbsEncryptionByDefaultResult: raise NotImplementedError + @handler("GetEnabledIpamPolicy") + def get_enabled_ipam_policy( + self, context: RequestContext, dry_run: Boolean | None = None, **kwargs + ) -> GetEnabledIpamPolicyResult: + raise NotImplementedError + @handler("GetFlowLogsIntegrationTemplate") def get_flow_logs_integration_template( self, @@ -27148,6 +29867,12 @@ def get_host_reservation_purchase_preview( ) -> GetHostReservationPurchasePreviewResult: raise NotImplementedError + @handler("GetImageAncestry") + def get_image_ancestry( + self, context: RequestContext, image_id: ImageId, dry_run: Boolean | None = None, **kwargs + ) -> GetImageAncestryResult: + raise NotImplementedError + @handler("GetImageBlockPublicAccessState") def get_image_block_public_access_state( self, context: RequestContext, dry_run: Boolean | None = None, **kwargs @@ -27249,6 +29974,34 @@ def get_ipam_discovered_resource_cidrs( ) -> GetIpamDiscoveredResourceCidrsResult: raise NotImplementedError + @handler("GetIpamPolicyAllocationRules") + def get_ipam_policy_allocation_rules( + self, + context: RequestContext, + ipam_policy_id: IpamPolicyId, + dry_run: Boolean | None = None, + filters: FilterList | None = None, + locale: String | None = None, + resource_type: IpamPolicyResourceType | None = None, + max_results: IpamMaxResults | None = None, + next_token: NextToken | None = None, + **kwargs, + ) -> GetIpamPolicyAllocationRulesResult: + raise NotImplementedError + + @handler("GetIpamPolicyOrganizationTargets") + def get_ipam_policy_organization_targets( + self, + context: RequestContext, + ipam_policy_id: IpamPolicyId, + dry_run: Boolean | None = None, + max_results: IpamMaxResults | None = None, + next_token: NextToken | None = None, + filters: FilterList | None = None, + **kwargs, + ) -> GetIpamPolicyOrganizationTargetsResult: + raise NotImplementedError + @handler("GetIpamPoolAllocations") def get_ipam_pool_allocations( self, @@ -27276,6 +30029,46 @@ def get_ipam_pool_cidrs( ) -> GetIpamPoolCidrsResult: raise NotImplementedError + @handler("GetIpamPrefixListResolverRules") + def get_ipam_prefix_list_resolver_rules( + self, + context: RequestContext, + ipam_prefix_list_resolver_id: IpamPrefixListResolverId, + dry_run: Boolean | None = None, + filters: FilterList | None = None, + max_results: IpamMaxResults | None = None, + next_token: NextToken | None = None, + **kwargs, + ) -> GetIpamPrefixListResolverRulesResult: + raise NotImplementedError + + @handler("GetIpamPrefixListResolverVersionEntries") + def get_ipam_prefix_list_resolver_version_entries( + self, + context: RequestContext, + ipam_prefix_list_resolver_id: IpamPrefixListResolverId, + ipam_prefix_list_resolver_version: Long, + dry_run: Boolean | None = None, + max_results: IpamMaxResults | None = None, + next_token: NextToken | None = None, + **kwargs, + ) -> GetIpamPrefixListResolverVersionEntriesResult: + raise NotImplementedError + + @handler("GetIpamPrefixListResolverVersions") + def get_ipam_prefix_list_resolver_versions( + self, + context: RequestContext, + ipam_prefix_list_resolver_id: IpamPrefixListResolverId, + dry_run: Boolean | None = None, + ipam_prefix_list_resolver_versions: IpamPrefixListResolverVersionNumberSet | None = None, + max_results: IpamMaxResults | None = None, + filters: FilterList | None = None, + next_token: NextToken | None = None, + **kwargs, + ) -> GetIpamPrefixListResolverVersionsResult: + raise NotImplementedError + @handler("GetIpamResourceCidrs") def get_ipam_resource_cidrs( self, @@ -27474,6 +30267,19 @@ def get_transit_gateway_attachment_propagations( ) -> GetTransitGatewayAttachmentPropagationsResult: raise NotImplementedError + @handler("GetTransitGatewayMeteringPolicyEntries") + def get_transit_gateway_metering_policy_entries( + self, + context: RequestContext, + transit_gateway_metering_policy_id: TransitGatewayMeteringPolicyId, + filters: FilterList | None = None, + max_results: TransitGatewayMaxResults | None = None, + next_token: String | None = None, + dry_run: Boolean | None = None, + **kwargs, + ) -> GetTransitGatewayMeteringPolicyEntriesResult: + raise NotImplementedError + @handler("GetTransitGatewayMulticastDomainAssociations") def get_transit_gateway_multicast_domain_associations( self, @@ -27584,6 +30390,18 @@ def get_verified_access_group_policy( ) -> GetVerifiedAccessGroupPolicyResult: raise NotImplementedError + @handler("GetVpcResourcesBlockingEncryptionEnforcement") + def get_vpc_resources_blocking_encryption_enforcement( + self, + context: RequestContext, + vpc_id: VpcId, + max_results: GetVpcResourcesBlockingEncryptionEnforcementMaxResults | None = None, + next_token: String | None = None, + dry_run: Boolean | None = None, + **kwargs, + ) -> GetVpcResourcesBlockingEncryptionEnforcementResult: + raise NotImplementedError + @handler("GetVpnConnectionDeviceSampleConfiguration") def get_vpn_connection_device_sample_configuration( self, @@ -27734,6 +30552,18 @@ def list_snapshots_in_recycle_bin( ) -> ListSnapshotsInRecycleBinResult: raise NotImplementedError + @handler("ListVolumesInRecycleBin") + def list_volumes_in_recycle_bin( + self, + context: RequestContext, + volume_ids: VolumeIdStringList | None = None, + dry_run: Boolean | None = None, + max_results: Integer | None = None, + next_token: String | None = None, + **kwargs, + ) -> ListVolumesInRecycleBinResult: + raise NotImplementedError + @handler("LockSnapshot") def lock_snapshot( self, @@ -27974,8 +30804,9 @@ def modify_instance_cpu_options( self, context: RequestContext, instance_id: InstanceId, - core_count: Integer, - threads_per_core: Integer, + core_count: Integer | None = None, + threads_per_core: Integer | None = None, + nested_virtualization: NestedVirtualizationSpecification | None = None, dry_run: Boolean | None = None, **kwargs, ) -> ModifyInstanceCpuOptionsResult: @@ -28038,6 +30869,7 @@ def modify_instance_metadata_defaults( http_endpoint: DefaultInstanceMetadataEndpointState | None = None, instance_metadata_tags: DefaultInstanceMetadataTagsState | None = None, dry_run: Boolean | None = None, + http_tokens_enforced: DefaultHttpTokensEnforcedState | None = None, **kwargs, ) -> ModifyInstanceMetadataDefaultsResult: raise NotImplementedError @@ -28100,6 +30932,19 @@ def modify_ipam( ) -> ModifyIpamResult: raise NotImplementedError + @handler("ModifyIpamPolicyAllocationRules") + def modify_ipam_policy_allocation_rules( + self, + context: RequestContext, + ipam_policy_id: IpamPolicyId, + locale: String, + resource_type: IpamPolicyResourceType, + dry_run: Boolean | None = None, + allocation_rules: IpamPolicyAllocationRuleListRequest | None = None, + **kwargs, + ) -> ModifyIpamPolicyAllocationRulesResult: + raise NotImplementedError + @handler("ModifyIpamPool") def modify_ipam_pool( self, @@ -28118,6 +30963,31 @@ def modify_ipam_pool( ) -> ModifyIpamPoolResult: raise NotImplementedError + @handler("ModifyIpamPrefixListResolver") + def modify_ipam_prefix_list_resolver( + self, + context: RequestContext, + ipam_prefix_list_resolver_id: IpamPrefixListResolverId, + dry_run: Boolean | None = None, + description: String | None = None, + rules: IpamPrefixListResolverRuleRequestSet | None = None, + **kwargs, + ) -> ModifyIpamPrefixListResolverResult: + raise NotImplementedError + + @handler("ModifyIpamPrefixListResolverTarget") + def modify_ipam_prefix_list_resolver_target( + self, + context: RequestContext, + ipam_prefix_list_resolver_target_id: IpamPrefixListResolverTargetId, + dry_run: Boolean | None = None, + desired_version: BoxedLong | None = None, + track_latest_version: BoxedBoolean | None = None, + client_token: String | None = None, + **kwargs, + ) -> ModifyIpamPrefixListResolverTargetResult: + raise NotImplementedError + @handler("ModifyIpamResourceCidr") def modify_ipam_resource_cidr( self, @@ -28156,6 +31026,8 @@ def modify_ipam_scope( ipam_scope_id: IpamScopeId, dry_run: Boolean | None = None, description: String | None = None, + external_authority_configuration: ExternalAuthorityConfiguration | None = None, + remove_external_authority_configuration: Boolean | None = None, **kwargs, ) -> ModifyIpamScopeResult: raise NotImplementedError @@ -28198,6 +31070,7 @@ def modify_managed_prefix_list( add_entries: AddPrefixListEntries | None = None, remove_entries: RemovePrefixListEntries | None = None, max_entries: Integer | None = None, + ipam_prefix_list_resolver_sync_enabled: BoxedBoolean | None = None, **kwargs, ) -> ModifyManagedPrefixListResult: raise NotImplementedError @@ -28392,6 +31265,18 @@ def modify_transit_gateway( ) -> ModifyTransitGatewayResult: raise NotImplementedError + @handler("ModifyTransitGatewayMeteringPolicy") + def modify_transit_gateway_metering_policy( + self, + context: RequestContext, + transit_gateway_metering_policy_id: TransitGatewayMeteringPolicyId, + add_middlebox_attachment_ids: TransitGatewayAttachmentIdStringList | None = None, + remove_middlebox_attachment_ids: TransitGatewayAttachmentIdStringList | None = None, + dry_run: Boolean | None = None, + **kwargs, + ) -> ModifyTransitGatewayMeteringPolicyResult: + raise NotImplementedError + @handler("ModifyTransitGatewayPrefixListReference") def modify_transit_gateway_prefix_list_reference( self, @@ -28577,6 +31462,26 @@ def modify_vpc_block_public_access_options( ) -> ModifyVpcBlockPublicAccessOptionsResult: raise NotImplementedError + @handler("ModifyVpcEncryptionControl") + def modify_vpc_encryption_control( + self, + context: RequestContext, + vpc_encryption_control_id: VpcEncryptionControlId, + dry_run: Boolean | None = None, + mode: VpcEncryptionControlMode | None = None, + internet_gateway_exclusion: VpcEncryptionControlExclusionStateInput | None = None, + egress_only_internet_gateway_exclusion: VpcEncryptionControlExclusionStateInput + | None = None, + nat_gateway_exclusion: VpcEncryptionControlExclusionStateInput | None = None, + virtual_private_gateway_exclusion: VpcEncryptionControlExclusionStateInput | None = None, + vpc_peering_exclusion: VpcEncryptionControlExclusionStateInput | None = None, + lambda_exclusion: VpcEncryptionControlExclusionStateInput | None = None, + vpc_lattice_exclusion: VpcEncryptionControlExclusionStateInput | None = None, + elastic_file_system_exclusion: VpcEncryptionControlExclusionStateInput | None = None, + **kwargs, + ) -> ModifyVpcEncryptionControlResult: + raise NotImplementedError + @handler("ModifyVpcEndpoint") def modify_vpc_endpoint( self, @@ -29313,6 +32218,12 @@ def restore_snapshot_tier( ) -> RestoreSnapshotTierResult: raise NotImplementedError + @handler("RestoreVolumeFromRecycleBin") + def restore_volume_from_recycle_bin( + self, context: RequestContext, volume_id: VolumeId, dry_run: Boolean | None = None, **kwargs + ) -> RestoreVolumeFromRecycleBinResult: + raise NotImplementedError + @handler("RevokeClientVpnIngress") def revoke_client_vpn_ingress( self, @@ -29401,6 +32312,7 @@ def run_instances( enable_primary_ipv6: Boolean | None = None, network_performance_options: InstanceNetworkPerformanceOptionsRequest | None = None, operator: OperatorRequest | None = None, + secondary_interfaces: InstanceSecondaryInterfaceSpecificationListRequest | None = None, dry_run: Boolean | None = None, disable_api_termination: Boolean | None = None, instance_initiated_shutdown_behavior: ShutdownBehavior | None = None, @@ -29461,6 +32373,7 @@ def search_transit_gateway_routes( filters: FilterList, max_results: TransitGatewayMaxResults | None = None, dry_run: Boolean | None = None, + next_token: String | None = None, **kwargs, ) -> SearchTransitGatewayRoutesResult: raise NotImplementedError @@ -29627,6 +32540,28 @@ def unmonitor_instances( ) -> UnmonitorInstancesResult: raise NotImplementedError + @handler("UpdateCapacityManagerOrganizationsAccess") + def update_capacity_manager_organizations_access( + self, + context: RequestContext, + organizations_access: BoxedBoolean, + dry_run: Boolean | None = None, + client_token: String | None = None, + **kwargs, + ) -> UpdateCapacityManagerOrganizationsAccessResult: + raise NotImplementedError + + @handler("UpdateInterruptibleCapacityReservationAllocation") + def update_interruptible_capacity_reservation_allocation( + self, + context: RequestContext, + capacity_reservation_id: CapacityReservationId, + target_instance_count: Integer, + dry_run: Boolean | None = None, + **kwargs, + ) -> UpdateInterruptibleCapacityReservationAllocationResult: + raise NotImplementedError + @handler("UpdateSecurityGroupRuleDescriptionsEgress") def update_security_group_rule_descriptions_egress( self, diff --git a/localstack-core/localstack/aws/api/es/__init__.py b/localstack-core/localstack/aws/api/es/__init__.py index 4c5774cbd36fa..80f61f5f2081a 100644 --- a/localstack-core/localstack/aws/api/es/__init__.py +++ b/localstack-core/localstack/aws/api/es/__init__.py @@ -1,6 +1,6 @@ from datetime import datetime from enum import StrEnum -from typing import Dict, List, Optional, TypedDict +from typing import TypedDict from localstack.aws.api import RequestContext, ServiceException, ServiceRequest, handler @@ -418,25 +418,25 @@ class AcceptInboundCrossClusterSearchConnectionRequest(ServiceRequest): class InboundCrossClusterSearchConnectionStatus(TypedDict, total=False): - StatusCode: Optional[InboundCrossClusterSearchConnectionStatusCode] - Message: Optional[CrossClusterSearchConnectionStatusMessage] + StatusCode: InboundCrossClusterSearchConnectionStatusCode | None + Message: CrossClusterSearchConnectionStatusMessage | None class DomainInformation(TypedDict, total=False): - OwnerId: Optional[OwnerId] + OwnerId: OwnerId | None DomainName: DomainName - Region: Optional[Region] + Region: Region | None class InboundCrossClusterSearchConnection(TypedDict, total=False): - SourceDomainInfo: Optional[DomainInformation] - DestinationDomainInfo: Optional[DomainInformation] - CrossClusterSearchConnectionId: Optional[CrossClusterSearchConnectionId] - ConnectionStatus: Optional[InboundCrossClusterSearchConnectionStatus] + SourceDomainInfo: DomainInformation | None + DestinationDomainInfo: DomainInformation | None + CrossClusterSearchConnectionId: CrossClusterSearchConnectionId | None + ConnectionStatus: InboundCrossClusterSearchConnectionStatus | None class AcceptInboundCrossClusterSearchConnectionResponse(TypedDict, total=False): - CrossClusterSearchConnection: Optional[InboundCrossClusterSearchConnection] + CrossClusterSearchConnection: InboundCrossClusterSearchConnection | None UpdateTimestamp = datetime @@ -445,9 +445,9 @@ class AcceptInboundCrossClusterSearchConnectionResponse(TypedDict, total=False): class OptionStatus(TypedDict, total=False): CreationDate: UpdateTimestamp UpdateDate: UpdateTimestamp - UpdateVersion: Optional[UIntValue] + UpdateVersion: UIntValue | None State: OptionState - PendingDeletion: Optional[Boolean] + PendingDeletion: Boolean | None class AccessPoliciesStatus(TypedDict, total=False): @@ -460,7 +460,7 @@ class Tag(TypedDict, total=False): Value: TagValue -TagList = List[Tag] +TagList = list[Tag] class AddTagsRequest(ServiceRequest): @@ -468,16 +468,16 @@ class AddTagsRequest(ServiceRequest): TagList: TagList -LimitValueList = List[LimitValue] +LimitValueList = list[LimitValue] class AdditionalLimit(TypedDict, total=False): - LimitName: Optional[LimitName] - LimitValues: Optional[LimitValueList] + LimitName: LimitName | None + LimitValues: LimitValueList | None -AdditionalLimitList = List[AdditionalLimit] -AdvancedOptions = Dict[String, String] +AdditionalLimitList = list[AdditionalLimit] +AdvancedOptions = dict[String, String] class AdvancedOptionsStatus(TypedDict, total=False): @@ -494,43 +494,43 @@ class SAMLIdp(TypedDict, total=False): class SAMLOptionsOutput(TypedDict, total=False): - Enabled: Optional[Boolean] - Idp: Optional[SAMLIdp] - SubjectKey: Optional[String] - RolesKey: Optional[String] - SessionTimeoutMinutes: Optional[IntegerClass] + Enabled: Boolean | None + Idp: SAMLIdp | None + SubjectKey: String | None + RolesKey: String | None + SessionTimeoutMinutes: IntegerClass | None class AdvancedSecurityOptions(TypedDict, total=False): - Enabled: Optional[Boolean] - InternalUserDatabaseEnabled: Optional[Boolean] - SAMLOptions: Optional[SAMLOptionsOutput] - AnonymousAuthDisableDate: Optional[DisableTimestamp] - AnonymousAuthEnabled: Optional[Boolean] + Enabled: Boolean | None + InternalUserDatabaseEnabled: Boolean | None + SAMLOptions: SAMLOptionsOutput | None + AnonymousAuthDisableDate: DisableTimestamp | None + AnonymousAuthEnabled: Boolean | None class SAMLOptionsInput(TypedDict, total=False): - Enabled: Optional[Boolean] - Idp: Optional[SAMLIdp] - MasterUserName: Optional[Username] - MasterBackendRole: Optional[BackendRole] - SubjectKey: Optional[String] - RolesKey: Optional[String] - SessionTimeoutMinutes: Optional[IntegerClass] + Enabled: Boolean | None + Idp: SAMLIdp | None + MasterUserName: Username | None + MasterBackendRole: BackendRole | None + SubjectKey: String | None + RolesKey: String | None + SessionTimeoutMinutes: IntegerClass | None class MasterUserOptions(TypedDict, total=False): - MasterUserARN: Optional[ARN] - MasterUserName: Optional[Username] - MasterUserPassword: Optional[Password] + MasterUserARN: ARN | None + MasterUserName: Username | None + MasterUserPassword: Password | None class AdvancedSecurityOptionsInput(TypedDict, total=False): - Enabled: Optional[Boolean] - InternalUserDatabaseEnabled: Optional[Boolean] - MasterUserOptions: Optional[MasterUserOptions] - SAMLOptions: Optional[SAMLOptionsInput] - AnonymousAuthEnabled: Optional[Boolean] + Enabled: Boolean | None + InternalUserDatabaseEnabled: Boolean | None + MasterUserOptions: MasterUserOptions | None + SAMLOptions: SAMLOptionsInput | None + AnonymousAuthEnabled: Boolean | None class AdvancedSecurityOptionsStatus(TypedDict, total=False): @@ -544,27 +544,27 @@ class AssociatePackageRequest(ServiceRequest): class ErrorDetails(TypedDict, total=False): - ErrorType: Optional[ErrorType] - ErrorMessage: Optional[ErrorMessage] + ErrorType: ErrorType | None + ErrorMessage: ErrorMessage | None LastUpdated = datetime class DomainPackageDetails(TypedDict, total=False): - PackageID: Optional[PackageID] - PackageName: Optional[PackageName] - PackageType: Optional[PackageType] - LastUpdated: Optional[LastUpdated] - DomainName: Optional[DomainName] - DomainPackageStatus: Optional[DomainPackageStatus] - PackageVersion: Optional[PackageVersion] - ReferencePath: Optional[ReferencePath] - ErrorDetails: Optional[ErrorDetails] + PackageID: PackageID | None + PackageName: PackageName | None + PackageType: PackageType | None + LastUpdated: LastUpdated | None + DomainName: DomainName | None + DomainPackageStatus: DomainPackageStatus | None + PackageVersion: PackageVersion | None + ReferencePath: ReferencePath | None + ErrorDetails: ErrorDetails | None class AssociatePackageResponse(TypedDict, total=False): - DomainPackageDetails: Optional[DomainPackageDetails] + DomainPackageDetails: DomainPackageDetails | None class AuthorizeVpcEndpointAccessRequest(ServiceRequest): @@ -573,104 +573,104 @@ class AuthorizeVpcEndpointAccessRequest(ServiceRequest): class AuthorizedPrincipal(TypedDict, total=False): - PrincipalType: Optional[PrincipalType] - Principal: Optional[String] + PrincipalType: PrincipalType | None + Principal: String | None class AuthorizeVpcEndpointAccessResponse(TypedDict, total=False): AuthorizedPrincipal: AuthorizedPrincipal -AuthorizedPrincipalList = List[AuthorizedPrincipal] +AuthorizedPrincipalList = list[AuthorizedPrincipal] AutoTuneDate = datetime class ScheduledAutoTuneDetails(TypedDict, total=False): - Date: Optional[AutoTuneDate] - ActionType: Optional[ScheduledAutoTuneActionType] - Action: Optional[ScheduledAutoTuneDescription] - Severity: Optional[ScheduledAutoTuneSeverityType] + Date: AutoTuneDate | None + ActionType: ScheduledAutoTuneActionType | None + Action: ScheduledAutoTuneDescription | None + Severity: ScheduledAutoTuneSeverityType | None class AutoTuneDetails(TypedDict, total=False): - ScheduledAutoTuneDetails: Optional[ScheduledAutoTuneDetails] + ScheduledAutoTuneDetails: ScheduledAutoTuneDetails | None class AutoTune(TypedDict, total=False): - AutoTuneType: Optional[AutoTuneType] - AutoTuneDetails: Optional[AutoTuneDetails] + AutoTuneType: AutoTuneType | None + AutoTuneDetails: AutoTuneDetails | None -AutoTuneList = List[AutoTune] +AutoTuneList = list[AutoTune] DurationValue = int class Duration(TypedDict, total=False): - Value: Optional[DurationValue] - Unit: Optional[TimeUnit] + Value: DurationValue | None + Unit: TimeUnit | None StartAt = datetime class AutoTuneMaintenanceSchedule(TypedDict, total=False): - StartAt: Optional[StartAt] - Duration: Optional[Duration] - CronExpressionForRecurrence: Optional[String] + StartAt: StartAt | None + Duration: Duration | None + CronExpressionForRecurrence: String | None -AutoTuneMaintenanceScheduleList = List[AutoTuneMaintenanceSchedule] +AutoTuneMaintenanceScheduleList = list[AutoTuneMaintenanceSchedule] class AutoTuneOptions(TypedDict, total=False): - DesiredState: Optional[AutoTuneDesiredState] - RollbackOnDisable: Optional[RollbackOnDisable] - MaintenanceSchedules: Optional[AutoTuneMaintenanceScheduleList] + DesiredState: AutoTuneDesiredState | None + RollbackOnDisable: RollbackOnDisable | None + MaintenanceSchedules: AutoTuneMaintenanceScheduleList | None class AutoTuneOptionsInput(TypedDict, total=False): - DesiredState: Optional[AutoTuneDesiredState] - MaintenanceSchedules: Optional[AutoTuneMaintenanceScheduleList] + DesiredState: AutoTuneDesiredState | None + MaintenanceSchedules: AutoTuneMaintenanceScheduleList | None class AutoTuneOptionsOutput(TypedDict, total=False): - State: Optional[AutoTuneState] - ErrorMessage: Optional[String] + State: AutoTuneState | None + ErrorMessage: String | None class AutoTuneStatus(TypedDict, total=False): CreationDate: UpdateTimestamp UpdateDate: UpdateTimestamp - UpdateVersion: Optional[UIntValue] + UpdateVersion: UIntValue | None State: AutoTuneState - ErrorMessage: Optional[String] - PendingDeletion: Optional[Boolean] + ErrorMessage: String | None + PendingDeletion: Boolean | None class AutoTuneOptionsStatus(TypedDict, total=False): - Options: Optional[AutoTuneOptions] - Status: Optional[AutoTuneStatus] + Options: AutoTuneOptions | None + Status: AutoTuneStatus | None class CancelDomainConfigChangeRequest(ServiceRequest): DomainName: DomainName - DryRun: Optional[DryRun] + DryRun: DryRun | None class CancelledChangeProperty(TypedDict, total=False): - PropertyName: Optional[String] - CancelledValue: Optional[String] - ActiveValue: Optional[String] + PropertyName: String | None + CancelledValue: String | None + ActiveValue: String | None -CancelledChangePropertyList = List[CancelledChangeProperty] -GUIDList = List[GUID] +CancelledChangePropertyList = list[CancelledChangeProperty] +GUIDList = list[GUID] class CancelDomainConfigChangeResponse(TypedDict, total=False): - DryRun: Optional[DryRun] - CancelledChangeIds: Optional[GUIDList] - CancelledChangeProperties: Optional[CancelledChangePropertyList] + DryRun: DryRun | None + CancelledChangeIds: GUIDList | None + CancelledChangeProperties: CancelledChangePropertyList | None class CancelElasticsearchServiceSoftwareUpdateRequest(ServiceRequest): @@ -681,58 +681,58 @@ class CancelElasticsearchServiceSoftwareUpdateRequest(ServiceRequest): class ServiceSoftwareOptions(TypedDict, total=False): - CurrentVersion: Optional[String] - NewVersion: Optional[String] - UpdateAvailable: Optional[Boolean] - Cancellable: Optional[Boolean] - UpdateStatus: Optional[DeploymentStatus] - Description: Optional[String] - AutomatedUpdateDate: Optional[DeploymentCloseDateTimeStamp] - OptionalDeployment: Optional[Boolean] + CurrentVersion: String | None + NewVersion: String | None + UpdateAvailable: Boolean | None + Cancellable: Boolean | None + UpdateStatus: DeploymentStatus | None + Description: String | None + AutomatedUpdateDate: DeploymentCloseDateTimeStamp | None + OptionalDeployment: Boolean | None class CancelElasticsearchServiceSoftwareUpdateResponse(TypedDict, total=False): - ServiceSoftwareOptions: Optional[ServiceSoftwareOptions] + ServiceSoftwareOptions: ServiceSoftwareOptions | None class ChangeProgressDetails(TypedDict, total=False): - ChangeId: Optional[GUID] - Message: Optional[Message] - ConfigChangeStatus: Optional[ConfigChangeStatus] - StartTime: Optional[UpdateTimestamp] - LastUpdatedTime: Optional[UpdateTimestamp] - InitiatedBy: Optional[InitiatedBy] + ChangeId: GUID | None + Message: Message | None + ConfigChangeStatus: ConfigChangeStatus | None + StartTime: UpdateTimestamp | None + LastUpdatedTime: UpdateTimestamp | None + InitiatedBy: InitiatedBy | None class ChangeProgressStage(TypedDict, total=False): - Name: Optional[ChangeProgressStageName] - Status: Optional[ChangeProgressStageStatus] - Description: Optional[Description] - LastUpdated: Optional[LastUpdated] + Name: ChangeProgressStageName | None + Status: ChangeProgressStageStatus | None + Description: Description | None + LastUpdated: LastUpdated | None -ChangeProgressStageList = List[ChangeProgressStage] -StringList = List[String] +ChangeProgressStageList = list[ChangeProgressStage] +StringList = list[String] class ChangeProgressStatusDetails(TypedDict, total=False): - ChangeId: Optional[GUID] - StartTime: Optional[UpdateTimestamp] - Status: Optional[OverallChangeStatus] - PendingProperties: Optional[StringList] - CompletedProperties: Optional[StringList] - TotalNumberOfStages: Optional[TotalNumberOfStages] - ChangeProgressStages: Optional[ChangeProgressStageList] - ConfigChangeStatus: Optional[ConfigChangeStatus] - LastUpdatedTime: Optional[UpdateTimestamp] - InitiatedBy: Optional[InitiatedBy] + ChangeId: GUID | None + StartTime: UpdateTimestamp | None + Status: OverallChangeStatus | None + PendingProperties: StringList | None + CompletedProperties: StringList | None + TotalNumberOfStages: TotalNumberOfStages | None + ChangeProgressStages: ChangeProgressStageList | None + ConfigChangeStatus: ConfigChangeStatus | None + LastUpdatedTime: UpdateTimestamp | None + InitiatedBy: InitiatedBy | None class CognitoOptions(TypedDict, total=False): - Enabled: Optional[Boolean] - UserPoolId: Optional[UserPoolId] - IdentityPoolId: Optional[IdentityPoolId] - RoleArn: Optional[RoleArn] + Enabled: Boolean | None + UserPoolId: UserPoolId | None + IdentityPoolId: IdentityPoolId | None + RoleArn: RoleArn | None class CognitoOptionsStatus(TypedDict, total=False): @@ -744,148 +744,148 @@ class ColdStorageOptions(TypedDict, total=False): Enabled: Boolean -ElasticsearchVersionList = List[ElasticsearchVersionString] +ElasticsearchVersionList = list[ElasticsearchVersionString] class CompatibleVersionsMap(TypedDict, total=False): - SourceVersion: Optional[ElasticsearchVersionString] - TargetVersions: Optional[ElasticsearchVersionList] + SourceVersion: ElasticsearchVersionString | None + TargetVersions: ElasticsearchVersionList | None -CompatibleElasticsearchVersionsList = List[CompatibleVersionsMap] +CompatibleElasticsearchVersionsList = list[CompatibleVersionsMap] class DomainEndpointOptions(TypedDict, total=False): - EnforceHTTPS: Optional[Boolean] - TLSSecurityPolicy: Optional[TLSSecurityPolicy] - CustomEndpointEnabled: Optional[Boolean] - CustomEndpoint: Optional[DomainNameFqdn] - CustomEndpointCertificateArn: Optional[ARN] + EnforceHTTPS: Boolean | None + TLSSecurityPolicy: TLSSecurityPolicy | None + CustomEndpointEnabled: Boolean | None + CustomEndpoint: DomainNameFqdn | None + CustomEndpointCertificateArn: ARN | None class LogPublishingOption(TypedDict, total=False): - CloudWatchLogsLogGroupArn: Optional[CloudWatchLogsLogGroupArn] - Enabled: Optional[Boolean] + CloudWatchLogsLogGroupArn: CloudWatchLogsLogGroupArn | None + Enabled: Boolean | None -LogPublishingOptions = Dict[LogType, LogPublishingOption] +LogPublishingOptions = dict[LogType, LogPublishingOption] class NodeToNodeEncryptionOptions(TypedDict, total=False): - Enabled: Optional[Boolean] + Enabled: Boolean | None class EncryptionAtRestOptions(TypedDict, total=False): - Enabled: Optional[Boolean] - KmsKeyId: Optional[KmsKeyId] + Enabled: Boolean | None + KmsKeyId: KmsKeyId | None class VPCOptions(TypedDict, total=False): - SubnetIds: Optional[StringList] - SecurityGroupIds: Optional[StringList] + SubnetIds: StringList | None + SecurityGroupIds: StringList | None class SnapshotOptions(TypedDict, total=False): - AutomatedSnapshotStartHour: Optional[IntegerClass] + AutomatedSnapshotStartHour: IntegerClass | None class EBSOptions(TypedDict, total=False): - EBSEnabled: Optional[Boolean] - VolumeType: Optional[VolumeType] - VolumeSize: Optional[IntegerClass] - Iops: Optional[IntegerClass] - Throughput: Optional[IntegerClass] + EBSEnabled: Boolean | None + VolumeType: VolumeType | None + VolumeSize: IntegerClass | None + Iops: IntegerClass | None + Throughput: IntegerClass | None class ZoneAwarenessConfig(TypedDict, total=False): - AvailabilityZoneCount: Optional[IntegerClass] + AvailabilityZoneCount: IntegerClass | None class ElasticsearchClusterConfig(TypedDict, total=False): - InstanceType: Optional[ESPartitionInstanceType] - InstanceCount: Optional[IntegerClass] - DedicatedMasterEnabled: Optional[Boolean] - ZoneAwarenessEnabled: Optional[Boolean] - ZoneAwarenessConfig: Optional[ZoneAwarenessConfig] - DedicatedMasterType: Optional[ESPartitionInstanceType] - DedicatedMasterCount: Optional[IntegerClass] - WarmEnabled: Optional[Boolean] - WarmType: Optional[ESWarmPartitionInstanceType] - WarmCount: Optional[IntegerClass] - ColdStorageOptions: Optional[ColdStorageOptions] + InstanceType: ESPartitionInstanceType | None + InstanceCount: IntegerClass | None + DedicatedMasterEnabled: Boolean | None + ZoneAwarenessEnabled: Boolean | None + ZoneAwarenessConfig: ZoneAwarenessConfig | None + DedicatedMasterType: ESPartitionInstanceType | None + DedicatedMasterCount: IntegerClass | None + WarmEnabled: Boolean | None + WarmType: ESWarmPartitionInstanceType | None + WarmCount: IntegerClass | None + ColdStorageOptions: ColdStorageOptions | None class CreateElasticsearchDomainRequest(ServiceRequest): DomainName: DomainName - ElasticsearchVersion: Optional[ElasticsearchVersionString] - ElasticsearchClusterConfig: Optional[ElasticsearchClusterConfig] - EBSOptions: Optional[EBSOptions] - AccessPolicies: Optional[PolicyDocument] - SnapshotOptions: Optional[SnapshotOptions] - VPCOptions: Optional[VPCOptions] - CognitoOptions: Optional[CognitoOptions] - EncryptionAtRestOptions: Optional[EncryptionAtRestOptions] - NodeToNodeEncryptionOptions: Optional[NodeToNodeEncryptionOptions] - AdvancedOptions: Optional[AdvancedOptions] - LogPublishingOptions: Optional[LogPublishingOptions] - DomainEndpointOptions: Optional[DomainEndpointOptions] - AdvancedSecurityOptions: Optional[AdvancedSecurityOptionsInput] - AutoTuneOptions: Optional[AutoTuneOptionsInput] - TagList: Optional[TagList] + ElasticsearchVersion: ElasticsearchVersionString | None + ElasticsearchClusterConfig: ElasticsearchClusterConfig | None + EBSOptions: EBSOptions | None + AccessPolicies: PolicyDocument | None + SnapshotOptions: SnapshotOptions | None + VPCOptions: VPCOptions | None + CognitoOptions: CognitoOptions | None + EncryptionAtRestOptions: EncryptionAtRestOptions | None + NodeToNodeEncryptionOptions: NodeToNodeEncryptionOptions | None + AdvancedOptions: AdvancedOptions | None + LogPublishingOptions: LogPublishingOptions | None + DomainEndpointOptions: DomainEndpointOptions | None + AdvancedSecurityOptions: AdvancedSecurityOptionsInput | None + AutoTuneOptions: AutoTuneOptionsInput | None + TagList: TagList | None class ModifyingProperties(TypedDict, total=False): - Name: Optional[String] - ActiveValue: Optional[String] - PendingValue: Optional[String] - ValueType: Optional[PropertyValueType] + Name: String | None + ActiveValue: String | None + PendingValue: String | None + ValueType: PropertyValueType | None -ModifyingPropertiesList = List[ModifyingProperties] +ModifyingPropertiesList = list[ModifyingProperties] class VPCDerivedInfo(TypedDict, total=False): - VPCId: Optional[String] - SubnetIds: Optional[StringList] - AvailabilityZones: Optional[StringList] - SecurityGroupIds: Optional[StringList] + VPCId: String | None + SubnetIds: StringList | None + AvailabilityZones: StringList | None + SecurityGroupIds: StringList | None -EndpointsMap = Dict[String, ServiceUrl] +EndpointsMap = dict[String, ServiceUrl] class ElasticsearchDomainStatus(TypedDict, total=False): DomainId: DomainId DomainName: DomainName ARN: ARN - Created: Optional[Boolean] - Deleted: Optional[Boolean] - Endpoint: Optional[ServiceUrl] - Endpoints: Optional[EndpointsMap] - Processing: Optional[Boolean] - UpgradeProcessing: Optional[Boolean] - ElasticsearchVersion: Optional[ElasticsearchVersionString] + Created: Boolean | None + Deleted: Boolean | None + Endpoint: ServiceUrl | None + Endpoints: EndpointsMap | None + Processing: Boolean | None + UpgradeProcessing: Boolean | None + ElasticsearchVersion: ElasticsearchVersionString | None ElasticsearchClusterConfig: ElasticsearchClusterConfig - EBSOptions: Optional[EBSOptions] - AccessPolicies: Optional[PolicyDocument] - SnapshotOptions: Optional[SnapshotOptions] - VPCOptions: Optional[VPCDerivedInfo] - CognitoOptions: Optional[CognitoOptions] - EncryptionAtRestOptions: Optional[EncryptionAtRestOptions] - NodeToNodeEncryptionOptions: Optional[NodeToNodeEncryptionOptions] - AdvancedOptions: Optional[AdvancedOptions] - LogPublishingOptions: Optional[LogPublishingOptions] - ServiceSoftwareOptions: Optional[ServiceSoftwareOptions] - DomainEndpointOptions: Optional[DomainEndpointOptions] - AdvancedSecurityOptions: Optional[AdvancedSecurityOptions] - AutoTuneOptions: Optional[AutoTuneOptionsOutput] - ChangeProgressDetails: Optional[ChangeProgressDetails] - DomainProcessingStatus: Optional[DomainProcessingStatusType] - ModifyingProperties: Optional[ModifyingPropertiesList] + EBSOptions: EBSOptions | None + AccessPolicies: PolicyDocument | None + SnapshotOptions: SnapshotOptions | None + VPCOptions: VPCDerivedInfo | None + CognitoOptions: CognitoOptions | None + EncryptionAtRestOptions: EncryptionAtRestOptions | None + NodeToNodeEncryptionOptions: NodeToNodeEncryptionOptions | None + AdvancedOptions: AdvancedOptions | None + LogPublishingOptions: LogPublishingOptions | None + ServiceSoftwareOptions: ServiceSoftwareOptions | None + DomainEndpointOptions: DomainEndpointOptions | None + AdvancedSecurityOptions: AdvancedSecurityOptions | None + AutoTuneOptions: AutoTuneOptionsOutput | None + ChangeProgressDetails: ChangeProgressDetails | None + DomainProcessingStatus: DomainProcessingStatusType | None + ModifyingProperties: ModifyingPropertiesList | None class CreateElasticsearchDomainResponse(TypedDict, total=False): - DomainStatus: Optional[ElasticsearchDomainStatus] + DomainStatus: ElasticsearchDomainStatus | None class CreateOutboundCrossClusterSearchConnectionRequest(ServiceRequest): @@ -895,27 +895,27 @@ class CreateOutboundCrossClusterSearchConnectionRequest(ServiceRequest): class OutboundCrossClusterSearchConnectionStatus(TypedDict, total=False): - StatusCode: Optional[OutboundCrossClusterSearchConnectionStatusCode] - Message: Optional[CrossClusterSearchConnectionStatusMessage] + StatusCode: OutboundCrossClusterSearchConnectionStatusCode | None + Message: CrossClusterSearchConnectionStatusMessage | None class CreateOutboundCrossClusterSearchConnectionResponse(TypedDict, total=False): - SourceDomainInfo: Optional[DomainInformation] - DestinationDomainInfo: Optional[DomainInformation] - ConnectionAlias: Optional[ConnectionAlias] - ConnectionStatus: Optional[OutboundCrossClusterSearchConnectionStatus] - CrossClusterSearchConnectionId: Optional[CrossClusterSearchConnectionId] + SourceDomainInfo: DomainInformation | None + DestinationDomainInfo: DomainInformation | None + ConnectionAlias: ConnectionAlias | None + ConnectionStatus: OutboundCrossClusterSearchConnectionStatus | None + CrossClusterSearchConnectionId: CrossClusterSearchConnectionId | None class PackageSource(TypedDict, total=False): - S3BucketName: Optional[S3BucketName] - S3Key: Optional[S3Key] + S3BucketName: S3BucketName | None + S3Key: S3Key | None class CreatePackageRequest(ServiceRequest): PackageName: PackageName PackageType: PackageType - PackageDescription: Optional[PackageDescription] + PackageDescription: PackageDescription | None PackageSource: PackageSource @@ -923,34 +923,34 @@ class CreatePackageRequest(ServiceRequest): class PackageDetails(TypedDict, total=False): - PackageID: Optional[PackageID] - PackageName: Optional[PackageName] - PackageType: Optional[PackageType] - PackageDescription: Optional[PackageDescription] - PackageStatus: Optional[PackageStatus] - CreatedAt: Optional[CreatedAt] - LastUpdatedAt: Optional[LastUpdated] - AvailablePackageVersion: Optional[PackageVersion] - ErrorDetails: Optional[ErrorDetails] + PackageID: PackageID | None + PackageName: PackageName | None + PackageType: PackageType | None + PackageDescription: PackageDescription | None + PackageStatus: PackageStatus | None + CreatedAt: CreatedAt | None + LastUpdatedAt: LastUpdated | None + AvailablePackageVersion: PackageVersion | None + ErrorDetails: ErrorDetails | None class CreatePackageResponse(TypedDict, total=False): - PackageDetails: Optional[PackageDetails] + PackageDetails: PackageDetails | None class CreateVpcEndpointRequest(ServiceRequest): DomainArn: DomainArn VpcOptions: VPCOptions - ClientToken: Optional[ClientToken] + ClientToken: ClientToken | None class VpcEndpoint(TypedDict, total=False): - VpcEndpointId: Optional[VpcEndpointId] - VpcEndpointOwner: Optional[AWSAccount] - DomainArn: Optional[DomainArn] - VpcOptions: Optional[VPCDerivedInfo] - Status: Optional[VpcEndpointStatus] - Endpoint: Optional[Endpoint] + VpcEndpointId: VpcEndpointId | None + VpcEndpointOwner: AWSAccount | None + DomainArn: DomainArn | None + VpcOptions: VPCDerivedInfo | None + Status: VpcEndpointStatus | None + Endpoint: Endpoint | None class CreateVpcEndpointResponse(TypedDict, total=False): @@ -962,7 +962,7 @@ class DeleteElasticsearchDomainRequest(ServiceRequest): class DeleteElasticsearchDomainResponse(TypedDict, total=False): - DomainStatus: Optional[ElasticsearchDomainStatus] + DomainStatus: ElasticsearchDomainStatus | None class DeleteInboundCrossClusterSearchConnectionRequest(ServiceRequest): @@ -970,7 +970,7 @@ class DeleteInboundCrossClusterSearchConnectionRequest(ServiceRequest): class DeleteInboundCrossClusterSearchConnectionResponse(TypedDict, total=False): - CrossClusterSearchConnection: Optional[InboundCrossClusterSearchConnection] + CrossClusterSearchConnection: InboundCrossClusterSearchConnection | None class DeleteOutboundCrossClusterSearchConnectionRequest(ServiceRequest): @@ -978,15 +978,15 @@ class DeleteOutboundCrossClusterSearchConnectionRequest(ServiceRequest): class OutboundCrossClusterSearchConnection(TypedDict, total=False): - SourceDomainInfo: Optional[DomainInformation] - DestinationDomainInfo: Optional[DomainInformation] - CrossClusterSearchConnectionId: Optional[CrossClusterSearchConnectionId] - ConnectionAlias: Optional[ConnectionAlias] - ConnectionStatus: Optional[OutboundCrossClusterSearchConnectionStatus] + SourceDomainInfo: DomainInformation | None + DestinationDomainInfo: DomainInformation | None + CrossClusterSearchConnectionId: CrossClusterSearchConnectionId | None + ConnectionAlias: ConnectionAlias | None + ConnectionStatus: OutboundCrossClusterSearchConnectionStatus | None class DeleteOutboundCrossClusterSearchConnectionResponse(TypedDict, total=False): - CrossClusterSearchConnection: Optional[OutboundCrossClusterSearchConnection] + CrossClusterSearchConnection: OutboundCrossClusterSearchConnection | None class DeletePackageRequest(ServiceRequest): @@ -994,7 +994,7 @@ class DeletePackageRequest(ServiceRequest): class DeletePackageResponse(TypedDict, total=False): - PackageDetails: Optional[PackageDetails] + PackageDetails: PackageDetails | None class DeleteVpcEndpointRequest(ServiceRequest): @@ -1002,10 +1002,10 @@ class DeleteVpcEndpointRequest(ServiceRequest): class VpcEndpointSummary(TypedDict, total=False): - VpcEndpointId: Optional[VpcEndpointId] - VpcEndpointOwner: Optional[String] - DomainArn: Optional[DomainArn] - Status: Optional[VpcEndpointStatus] + VpcEndpointId: VpcEndpointId | None + VpcEndpointOwner: String | None + DomainArn: DomainArn | None + Status: VpcEndpointStatus | None class DeleteVpcEndpointResponse(TypedDict, total=False): @@ -1014,22 +1014,22 @@ class DeleteVpcEndpointResponse(TypedDict, total=False): class DescribeDomainAutoTunesRequest(ServiceRequest): DomainName: DomainName - MaxResults: Optional[MaxResults] - NextToken: Optional[NextToken] + MaxResults: MaxResults | None + NextToken: NextToken | None class DescribeDomainAutoTunesResponse(TypedDict, total=False): - AutoTunes: Optional[AutoTuneList] - NextToken: Optional[NextToken] + AutoTunes: AutoTuneList | None + NextToken: NextToken | None class DescribeDomainChangeProgressRequest(ServiceRequest): DomainName: DomainName - ChangeId: Optional[GUID] + ChangeId: GUID | None class DescribeDomainChangeProgressResponse(TypedDict, total=False): - ChangeProgressStatus: Optional[ChangeProgressStatusDetails] + ChangeProgressStatus: ChangeProgressStatusDetails | None class DescribeElasticsearchDomainConfigRequest(ServiceRequest): @@ -1042,8 +1042,8 @@ class DomainEndpointOptionsStatus(TypedDict, total=False): class LogPublishingOptionsStatus(TypedDict, total=False): - Options: Optional[LogPublishingOptions] - Status: Optional[OptionStatus] + Options: LogPublishingOptions | None + Status: OptionStatus | None class NodeToNodeEncryptionOptionsStatus(TypedDict, total=False): @@ -1082,22 +1082,22 @@ class ElasticsearchVersionStatus(TypedDict, total=False): class ElasticsearchDomainConfig(TypedDict, total=False): - ElasticsearchVersion: Optional[ElasticsearchVersionStatus] - ElasticsearchClusterConfig: Optional[ElasticsearchClusterConfigStatus] - EBSOptions: Optional[EBSOptionsStatus] - AccessPolicies: Optional[AccessPoliciesStatus] - SnapshotOptions: Optional[SnapshotOptionsStatus] - VPCOptions: Optional[VPCDerivedInfoStatus] - CognitoOptions: Optional[CognitoOptionsStatus] - EncryptionAtRestOptions: Optional[EncryptionAtRestOptionsStatus] - NodeToNodeEncryptionOptions: Optional[NodeToNodeEncryptionOptionsStatus] - AdvancedOptions: Optional[AdvancedOptionsStatus] - LogPublishingOptions: Optional[LogPublishingOptionsStatus] - DomainEndpointOptions: Optional[DomainEndpointOptionsStatus] - AdvancedSecurityOptions: Optional[AdvancedSecurityOptionsStatus] - AutoTuneOptions: Optional[AutoTuneOptionsStatus] - ChangeProgressDetails: Optional[ChangeProgressDetails] - ModifyingProperties: Optional[ModifyingPropertiesList] + ElasticsearchVersion: ElasticsearchVersionStatus | None + ElasticsearchClusterConfig: ElasticsearchClusterConfigStatus | None + EBSOptions: EBSOptionsStatus | None + AccessPolicies: AccessPoliciesStatus | None + SnapshotOptions: SnapshotOptionsStatus | None + VPCOptions: VPCDerivedInfoStatus | None + CognitoOptions: CognitoOptionsStatus | None + EncryptionAtRestOptions: EncryptionAtRestOptionsStatus | None + NodeToNodeEncryptionOptions: NodeToNodeEncryptionOptionsStatus | None + AdvancedOptions: AdvancedOptionsStatus | None + LogPublishingOptions: LogPublishingOptionsStatus | None + DomainEndpointOptions: DomainEndpointOptionsStatus | None + AdvancedSecurityOptions: AdvancedSecurityOptionsStatus | None + AutoTuneOptions: AutoTuneOptionsStatus | None + ChangeProgressDetails: ChangeProgressDetails | None + ModifyingProperties: ModifyingPropertiesList | None class DescribeElasticsearchDomainConfigResponse(TypedDict, total=False): @@ -1112,14 +1112,14 @@ class DescribeElasticsearchDomainResponse(TypedDict, total=False): DomainStatus: ElasticsearchDomainStatus -DomainNameList = List[DomainName] +DomainNameList = list[DomainName] class DescribeElasticsearchDomainsRequest(ServiceRequest): DomainNames: DomainNameList -ElasticsearchDomainStatusList = List[ElasticsearchDomainStatus] +ElasticsearchDomainStatusList = list[ElasticsearchDomainStatus] class DescribeElasticsearchDomainsResponse(TypedDict, total=False): @@ -1127,178 +1127,178 @@ class DescribeElasticsearchDomainsResponse(TypedDict, total=False): class DescribeElasticsearchInstanceTypeLimitsRequest(ServiceRequest): - DomainName: Optional[DomainName] + DomainName: DomainName | None InstanceType: ESPartitionInstanceType ElasticsearchVersion: ElasticsearchVersionString class InstanceCountLimits(TypedDict, total=False): - MinimumInstanceCount: Optional[MinimumInstanceCount] - MaximumInstanceCount: Optional[MaximumInstanceCount] + MinimumInstanceCount: MinimumInstanceCount | None + MaximumInstanceCount: MaximumInstanceCount | None class InstanceLimits(TypedDict, total=False): - InstanceCountLimits: Optional[InstanceCountLimits] + InstanceCountLimits: InstanceCountLimits | None class StorageTypeLimit(TypedDict, total=False): - LimitName: Optional[LimitName] - LimitValues: Optional[LimitValueList] + LimitName: LimitName | None + LimitValues: LimitValueList | None -StorageTypeLimitList = List[StorageTypeLimit] +StorageTypeLimitList = list[StorageTypeLimit] class StorageType(TypedDict, total=False): - StorageTypeName: Optional[StorageTypeName] - StorageSubTypeName: Optional[StorageSubTypeName] - StorageTypeLimits: Optional[StorageTypeLimitList] + StorageTypeName: StorageTypeName | None + StorageSubTypeName: StorageSubTypeName | None + StorageTypeLimits: StorageTypeLimitList | None -StorageTypeList = List[StorageType] +StorageTypeList = list[StorageType] class Limits(TypedDict, total=False): - StorageTypes: Optional[StorageTypeList] - InstanceLimits: Optional[InstanceLimits] - AdditionalLimits: Optional[AdditionalLimitList] + StorageTypes: StorageTypeList | None + InstanceLimits: InstanceLimits | None + AdditionalLimits: AdditionalLimitList | None -LimitsByRole = Dict[InstanceRole, Limits] +LimitsByRole = dict[InstanceRole, Limits] class DescribeElasticsearchInstanceTypeLimitsResponse(TypedDict, total=False): - LimitsByRole: Optional[LimitsByRole] + LimitsByRole: LimitsByRole | None -ValueStringList = List[NonEmptyString] +ValueStringList = list[NonEmptyString] class Filter(TypedDict, total=False): - Name: Optional[NonEmptyString] - Values: Optional[ValueStringList] + Name: NonEmptyString | None + Values: ValueStringList | None -FilterList = List[Filter] +FilterList = list[Filter] class DescribeInboundCrossClusterSearchConnectionsRequest(ServiceRequest): - Filters: Optional[FilterList] - MaxResults: Optional[MaxResults] - NextToken: Optional[NextToken] + Filters: FilterList | None + MaxResults: MaxResults | None + NextToken: NextToken | None -InboundCrossClusterSearchConnections = List[InboundCrossClusterSearchConnection] +InboundCrossClusterSearchConnections = list[InboundCrossClusterSearchConnection] class DescribeInboundCrossClusterSearchConnectionsResponse(TypedDict, total=False): - CrossClusterSearchConnections: Optional[InboundCrossClusterSearchConnections] - NextToken: Optional[NextToken] + CrossClusterSearchConnections: InboundCrossClusterSearchConnections | None + NextToken: NextToken | None class DescribeOutboundCrossClusterSearchConnectionsRequest(ServiceRequest): - Filters: Optional[FilterList] - MaxResults: Optional[MaxResults] - NextToken: Optional[NextToken] + Filters: FilterList | None + MaxResults: MaxResults | None + NextToken: NextToken | None -OutboundCrossClusterSearchConnections = List[OutboundCrossClusterSearchConnection] +OutboundCrossClusterSearchConnections = list[OutboundCrossClusterSearchConnection] class DescribeOutboundCrossClusterSearchConnectionsResponse(TypedDict, total=False): - CrossClusterSearchConnections: Optional[OutboundCrossClusterSearchConnections] - NextToken: Optional[NextToken] + CrossClusterSearchConnections: OutboundCrossClusterSearchConnections | None + NextToken: NextToken | None -DescribePackagesFilterValues = List[DescribePackagesFilterValue] +DescribePackagesFilterValues = list[DescribePackagesFilterValue] class DescribePackagesFilter(TypedDict, total=False): - Name: Optional[DescribePackagesFilterName] - Value: Optional[DescribePackagesFilterValues] + Name: DescribePackagesFilterName | None + Value: DescribePackagesFilterValues | None -DescribePackagesFilterList = List[DescribePackagesFilter] +DescribePackagesFilterList = list[DescribePackagesFilter] class DescribePackagesRequest(ServiceRequest): - Filters: Optional[DescribePackagesFilterList] - MaxResults: Optional[MaxResults] - NextToken: Optional[NextToken] + Filters: DescribePackagesFilterList | None + MaxResults: MaxResults | None + NextToken: NextToken | None -PackageDetailsList = List[PackageDetails] +PackageDetailsList = list[PackageDetails] class DescribePackagesResponse(TypedDict, total=False): - PackageDetailsList: Optional[PackageDetailsList] - NextToken: Optional[String] + PackageDetailsList: PackageDetailsList | None + NextToken: String | None class DescribeReservedElasticsearchInstanceOfferingsRequest(ServiceRequest): - ReservedElasticsearchInstanceOfferingId: Optional[GUID] - MaxResults: Optional[MaxResults] - NextToken: Optional[NextToken] + ReservedElasticsearchInstanceOfferingId: GUID | None + MaxResults: MaxResults | None + NextToken: NextToken | None class RecurringCharge(TypedDict, total=False): - RecurringChargeAmount: Optional[Double] - RecurringChargeFrequency: Optional[String] + RecurringChargeAmount: Double | None + RecurringChargeFrequency: String | None -RecurringChargeList = List[RecurringCharge] +RecurringChargeList = list[RecurringCharge] class ReservedElasticsearchInstanceOffering(TypedDict, total=False): - ReservedElasticsearchInstanceOfferingId: Optional[GUID] - ElasticsearchInstanceType: Optional[ESPartitionInstanceType] - Duration: Optional[Integer] - FixedPrice: Optional[Double] - UsagePrice: Optional[Double] - CurrencyCode: Optional[String] - PaymentOption: Optional[ReservedElasticsearchInstancePaymentOption] - RecurringCharges: Optional[RecurringChargeList] + ReservedElasticsearchInstanceOfferingId: GUID | None + ElasticsearchInstanceType: ESPartitionInstanceType | None + Duration: Integer | None + FixedPrice: Double | None + UsagePrice: Double | None + CurrencyCode: String | None + PaymentOption: ReservedElasticsearchInstancePaymentOption | None + RecurringCharges: RecurringChargeList | None -ReservedElasticsearchInstanceOfferingList = List[ReservedElasticsearchInstanceOffering] +ReservedElasticsearchInstanceOfferingList = list[ReservedElasticsearchInstanceOffering] class DescribeReservedElasticsearchInstanceOfferingsResponse(TypedDict, total=False): - NextToken: Optional[NextToken] - ReservedElasticsearchInstanceOfferings: Optional[ReservedElasticsearchInstanceOfferingList] + NextToken: NextToken | None + ReservedElasticsearchInstanceOfferings: ReservedElasticsearchInstanceOfferingList | None class DescribeReservedElasticsearchInstancesRequest(ServiceRequest): - ReservedElasticsearchInstanceId: Optional[GUID] - MaxResults: Optional[MaxResults] - NextToken: Optional[NextToken] + ReservedElasticsearchInstanceId: GUID | None + MaxResults: MaxResults | None + NextToken: NextToken | None class ReservedElasticsearchInstance(TypedDict, total=False): - ReservationName: Optional[ReservationToken] - ReservedElasticsearchInstanceId: Optional[GUID] - ReservedElasticsearchInstanceOfferingId: Optional[String] - ElasticsearchInstanceType: Optional[ESPartitionInstanceType] - StartTime: Optional[UpdateTimestamp] - Duration: Optional[Integer] - FixedPrice: Optional[Double] - UsagePrice: Optional[Double] - CurrencyCode: Optional[String] - ElasticsearchInstanceCount: Optional[Integer] - State: Optional[String] - PaymentOption: Optional[ReservedElasticsearchInstancePaymentOption] - RecurringCharges: Optional[RecurringChargeList] + ReservationName: ReservationToken | None + ReservedElasticsearchInstanceId: GUID | None + ReservedElasticsearchInstanceOfferingId: String | None + ElasticsearchInstanceType: ESPartitionInstanceType | None + StartTime: UpdateTimestamp | None + Duration: Integer | None + FixedPrice: Double | None + UsagePrice: Double | None + CurrencyCode: String | None + ElasticsearchInstanceCount: Integer | None + State: String | None + PaymentOption: ReservedElasticsearchInstancePaymentOption | None + RecurringCharges: RecurringChargeList | None -ReservedElasticsearchInstanceList = List[ReservedElasticsearchInstance] +ReservedElasticsearchInstanceList = list[ReservedElasticsearchInstance] class DescribeReservedElasticsearchInstancesResponse(TypedDict, total=False): - NextToken: Optional[String] - ReservedElasticsearchInstances: Optional[ReservedElasticsearchInstanceList] + NextToken: String | None + ReservedElasticsearchInstances: ReservedElasticsearchInstanceList | None -VpcEndpointIdList = List[VpcEndpointId] +VpcEndpointIdList = list[VpcEndpointId] class DescribeVpcEndpointsRequest(ServiceRequest): @@ -1306,13 +1306,13 @@ class DescribeVpcEndpointsRequest(ServiceRequest): class VpcEndpointError(TypedDict, total=False): - VpcEndpointId: Optional[VpcEndpointId] - ErrorCode: Optional[VpcEndpointErrorCode] - ErrorMessage: Optional[String] + VpcEndpointId: VpcEndpointId | None + ErrorCode: VpcEndpointErrorCode | None + ErrorMessage: String | None -VpcEndpointErrorList = List[VpcEndpointError] -VpcEndpoints = List[VpcEndpoint] +VpcEndpointErrorList = list[VpcEndpointError] +VpcEndpoints = list[VpcEndpoint] class DescribeVpcEndpointsResponse(TypedDict, total=False): @@ -1326,88 +1326,88 @@ class DissociatePackageRequest(ServiceRequest): class DissociatePackageResponse(TypedDict, total=False): - DomainPackageDetails: Optional[DomainPackageDetails] + DomainPackageDetails: DomainPackageDetails | None class DomainInfo(TypedDict, total=False): - DomainName: Optional[DomainName] - EngineType: Optional[EngineType] + DomainName: DomainName | None + EngineType: EngineType | None -DomainInfoList = List[DomainInfo] -DomainPackageDetailsList = List[DomainPackageDetails] +DomainInfoList = list[DomainInfo] +DomainPackageDetailsList = list[DomainPackageDetails] class DryRunResults(TypedDict, total=False): - DeploymentType: Optional[DeploymentType] - Message: Optional[Message] + DeploymentType: DeploymentType | None + Message: Message | None -ElasticsearchInstanceTypeList = List[ESPartitionInstanceType] +ElasticsearchInstanceTypeList = list[ESPartitionInstanceType] class GetCompatibleElasticsearchVersionsRequest(ServiceRequest): - DomainName: Optional[DomainName] + DomainName: DomainName | None class GetCompatibleElasticsearchVersionsResponse(TypedDict, total=False): - CompatibleElasticsearchVersions: Optional[CompatibleElasticsearchVersionsList] + CompatibleElasticsearchVersions: CompatibleElasticsearchVersionsList | None class GetPackageVersionHistoryRequest(ServiceRequest): PackageID: PackageID - MaxResults: Optional[MaxResults] - NextToken: Optional[NextToken] + MaxResults: MaxResults | None + NextToken: NextToken | None class PackageVersionHistory(TypedDict, total=False): - PackageVersion: Optional[PackageVersion] - CommitMessage: Optional[CommitMessage] - CreatedAt: Optional[CreatedAt] + PackageVersion: PackageVersion | None + CommitMessage: CommitMessage | None + CreatedAt: CreatedAt | None -PackageVersionHistoryList = List[PackageVersionHistory] +PackageVersionHistoryList = list[PackageVersionHistory] class GetPackageVersionHistoryResponse(TypedDict, total=False): - PackageID: Optional[PackageID] - PackageVersionHistoryList: Optional[PackageVersionHistoryList] - NextToken: Optional[String] + PackageID: PackageID | None + PackageVersionHistoryList: PackageVersionHistoryList | None + NextToken: String | None class GetUpgradeHistoryRequest(ServiceRequest): DomainName: DomainName - MaxResults: Optional[MaxResults] - NextToken: Optional[NextToken] + MaxResults: MaxResults | None + NextToken: NextToken | None -Issues = List[Issue] +Issues = list[Issue] class UpgradeStepItem(TypedDict, total=False): - UpgradeStep: Optional[UpgradeStep] - UpgradeStepStatus: Optional[UpgradeStatus] - Issues: Optional[Issues] - ProgressPercent: Optional[Double] + UpgradeStep: UpgradeStep | None + UpgradeStepStatus: UpgradeStatus | None + Issues: Issues | None + ProgressPercent: Double | None -UpgradeStepsList = List[UpgradeStepItem] +UpgradeStepsList = list[UpgradeStepItem] StartTimestamp = datetime class UpgradeHistory(TypedDict, total=False): - UpgradeName: Optional[UpgradeName] - StartTimestamp: Optional[StartTimestamp] - UpgradeStatus: Optional[UpgradeStatus] - StepsList: Optional[UpgradeStepsList] + UpgradeName: UpgradeName | None + StartTimestamp: StartTimestamp | None + UpgradeStatus: UpgradeStatus | None + StepsList: UpgradeStepsList | None -UpgradeHistoryList = List[UpgradeHistory] +UpgradeHistoryList = list[UpgradeHistory] class GetUpgradeHistoryResponse(TypedDict, total=False): - UpgradeHistories: Optional[UpgradeHistoryList] - NextToken: Optional[String] + UpgradeHistories: UpgradeHistoryList | None + NextToken: String | None class GetUpgradeStatusRequest(ServiceRequest): @@ -1415,61 +1415,61 @@ class GetUpgradeStatusRequest(ServiceRequest): class GetUpgradeStatusResponse(TypedDict, total=False): - UpgradeStep: Optional[UpgradeStep] - StepStatus: Optional[UpgradeStatus] - UpgradeName: Optional[UpgradeName] + UpgradeStep: UpgradeStep | None + StepStatus: UpgradeStatus | None + UpgradeName: UpgradeName | None class ListDomainNamesRequest(ServiceRequest): - EngineType: Optional[EngineType] + EngineType: EngineType | None class ListDomainNamesResponse(TypedDict, total=False): - DomainNames: Optional[DomainInfoList] + DomainNames: DomainInfoList | None class ListDomainsForPackageRequest(ServiceRequest): PackageID: PackageID - MaxResults: Optional[MaxResults] - NextToken: Optional[NextToken] + MaxResults: MaxResults | None + NextToken: NextToken | None class ListDomainsForPackageResponse(TypedDict, total=False): - DomainPackageDetailsList: Optional[DomainPackageDetailsList] - NextToken: Optional[String] + DomainPackageDetailsList: DomainPackageDetailsList | None + NextToken: String | None class ListElasticsearchInstanceTypesRequest(ServiceRequest): ElasticsearchVersion: ElasticsearchVersionString - DomainName: Optional[DomainName] - MaxResults: Optional[MaxResults] - NextToken: Optional[NextToken] + DomainName: DomainName | None + MaxResults: MaxResults | None + NextToken: NextToken | None class ListElasticsearchInstanceTypesResponse(TypedDict, total=False): - ElasticsearchInstanceTypes: Optional[ElasticsearchInstanceTypeList] - NextToken: Optional[NextToken] + ElasticsearchInstanceTypes: ElasticsearchInstanceTypeList | None + NextToken: NextToken | None class ListElasticsearchVersionsRequest(ServiceRequest): - MaxResults: Optional[MaxResults] - NextToken: Optional[NextToken] + MaxResults: MaxResults | None + NextToken: NextToken | None class ListElasticsearchVersionsResponse(TypedDict, total=False): - ElasticsearchVersions: Optional[ElasticsearchVersionList] - NextToken: Optional[NextToken] + ElasticsearchVersions: ElasticsearchVersionList | None + NextToken: NextToken | None class ListPackagesForDomainRequest(ServiceRequest): DomainName: DomainName - MaxResults: Optional[MaxResults] - NextToken: Optional[NextToken] + MaxResults: MaxResults | None + NextToken: NextToken | None class ListPackagesForDomainResponse(TypedDict, total=False): - DomainPackageDetailsList: Optional[DomainPackageDetailsList] - NextToken: Optional[String] + DomainPackageDetailsList: DomainPackageDetailsList | None + NextToken: String | None class ListTagsRequest(ServiceRequest): @@ -1477,12 +1477,12 @@ class ListTagsRequest(ServiceRequest): class ListTagsResponse(TypedDict, total=False): - TagList: Optional[TagList] + TagList: TagList | None class ListVpcEndpointAccessRequest(ServiceRequest): DomainName: DomainName - NextToken: Optional[NextToken] + NextToken: NextToken | None class ListVpcEndpointAccessResponse(TypedDict, total=False): @@ -1492,10 +1492,10 @@ class ListVpcEndpointAccessResponse(TypedDict, total=False): class ListVpcEndpointsForDomainRequest(ServiceRequest): DomainName: DomainName - NextToken: Optional[NextToken] + NextToken: NextToken | None -VpcEndpointSummaryList = List[VpcEndpointSummary] +VpcEndpointSummaryList = list[VpcEndpointSummary] class ListVpcEndpointsForDomainResponse(TypedDict, total=False): @@ -1504,7 +1504,7 @@ class ListVpcEndpointsForDomainResponse(TypedDict, total=False): class ListVpcEndpointsRequest(ServiceRequest): - NextToken: Optional[NextToken] + NextToken: NextToken | None class ListVpcEndpointsResponse(TypedDict, total=False): @@ -1515,12 +1515,12 @@ class ListVpcEndpointsResponse(TypedDict, total=False): class PurchaseReservedElasticsearchInstanceOfferingRequest(ServiceRequest): ReservedElasticsearchInstanceOfferingId: GUID ReservationName: ReservationToken - InstanceCount: Optional[InstanceCount] + InstanceCount: InstanceCount | None class PurchaseReservedElasticsearchInstanceOfferingResponse(TypedDict, total=False): - ReservedElasticsearchInstanceId: Optional[GUID] - ReservationName: Optional[ReservationToken] + ReservedElasticsearchInstanceId: GUID | None + ReservationName: ReservationToken | None class RejectInboundCrossClusterSearchConnectionRequest(ServiceRequest): @@ -1528,7 +1528,7 @@ class RejectInboundCrossClusterSearchConnectionRequest(ServiceRequest): class RejectInboundCrossClusterSearchConnectionResponse(TypedDict, total=False): - CrossClusterSearchConnection: Optional[InboundCrossClusterSearchConnection] + CrossClusterSearchConnection: InboundCrossClusterSearchConnection | None class RemoveTagsRequest(ServiceRequest): @@ -1550,41 +1550,41 @@ class StartElasticsearchServiceSoftwareUpdateRequest(ServiceRequest): class StartElasticsearchServiceSoftwareUpdateResponse(TypedDict, total=False): - ServiceSoftwareOptions: Optional[ServiceSoftwareOptions] + ServiceSoftwareOptions: ServiceSoftwareOptions | None class UpdateElasticsearchDomainConfigRequest(ServiceRequest): DomainName: DomainName - ElasticsearchClusterConfig: Optional[ElasticsearchClusterConfig] - EBSOptions: Optional[EBSOptions] - SnapshotOptions: Optional[SnapshotOptions] - VPCOptions: Optional[VPCOptions] - CognitoOptions: Optional[CognitoOptions] - AdvancedOptions: Optional[AdvancedOptions] - AccessPolicies: Optional[PolicyDocument] - LogPublishingOptions: Optional[LogPublishingOptions] - DomainEndpointOptions: Optional[DomainEndpointOptions] - AdvancedSecurityOptions: Optional[AdvancedSecurityOptionsInput] - NodeToNodeEncryptionOptions: Optional[NodeToNodeEncryptionOptions] - EncryptionAtRestOptions: Optional[EncryptionAtRestOptions] - AutoTuneOptions: Optional[AutoTuneOptions] - DryRun: Optional[DryRun] + ElasticsearchClusterConfig: ElasticsearchClusterConfig | None + EBSOptions: EBSOptions | None + SnapshotOptions: SnapshotOptions | None + VPCOptions: VPCOptions | None + CognitoOptions: CognitoOptions | None + AdvancedOptions: AdvancedOptions | None + AccessPolicies: PolicyDocument | None + LogPublishingOptions: LogPublishingOptions | None + DomainEndpointOptions: DomainEndpointOptions | None + AdvancedSecurityOptions: AdvancedSecurityOptionsInput | None + NodeToNodeEncryptionOptions: NodeToNodeEncryptionOptions | None + EncryptionAtRestOptions: EncryptionAtRestOptions | None + AutoTuneOptions: AutoTuneOptions | None + DryRun: DryRun | None class UpdateElasticsearchDomainConfigResponse(TypedDict, total=False): DomainConfig: ElasticsearchDomainConfig - DryRunResults: Optional[DryRunResults] + DryRunResults: DryRunResults | None class UpdatePackageRequest(ServiceRequest): PackageID: PackageID PackageSource: PackageSource - PackageDescription: Optional[PackageDescription] - CommitMessage: Optional[CommitMessage] + PackageDescription: PackageDescription | None + CommitMessage: CommitMessage | None class UpdatePackageResponse(TypedDict, total=False): - PackageDetails: Optional[PackageDetails] + PackageDetails: PackageDetails | None class UpdateVpcEndpointRequest(ServiceRequest): @@ -1599,19 +1599,19 @@ class UpdateVpcEndpointResponse(TypedDict, total=False): class UpgradeElasticsearchDomainRequest(ServiceRequest): DomainName: DomainName TargetVersion: ElasticsearchVersionString - PerformCheckOnly: Optional[Boolean] + PerformCheckOnly: Boolean | None class UpgradeElasticsearchDomainResponse(TypedDict, total=False): - DomainName: Optional[DomainName] - TargetVersion: Optional[ElasticsearchVersionString] - PerformCheckOnly: Optional[Boolean] - ChangeProgressDetails: Optional[ChangeProgressDetails] + DomainName: DomainName | None + TargetVersion: ElasticsearchVersionString | None + PerformCheckOnly: Boolean | None + ChangeProgressDetails: ChangeProgressDetails | None class EsApi: - service = "es" - version = "2015-01-01" + service: str = "es" + version: str = "2015-01-01" @handler("AcceptInboundCrossClusterSearchConnection") def accept_inbound_cross_cluster_search_connection( diff --git a/localstack-core/localstack/aws/api/events/__init__.py b/localstack-core/localstack/aws/api/events/__init__.py index f62bb74e14457..486f41bab31d2 100644 --- a/localstack-core/localstack/aws/api/events/__init__.py +++ b/localstack-core/localstack/aws/api/events/__init__.py @@ -1,6 +1,6 @@ from datetime import datetime from enum import StrEnum -from typing import Dict, List, Optional, TypedDict +from typing import TypedDict from localstack.aws.api import RequestContext, ServiceException, ServiceRequest, handler @@ -319,61 +319,61 @@ class ActivateEventSourceRequest(ServiceRequest): class ApiDestination(TypedDict, total=False): - ApiDestinationArn: Optional[ApiDestinationArn] - Name: Optional[ApiDestinationName] - ApiDestinationState: Optional[ApiDestinationState] - ConnectionArn: Optional[ConnectionArn] - InvocationEndpoint: Optional[HttpsEndpoint] - HttpMethod: Optional[ApiDestinationHttpMethod] - InvocationRateLimitPerSecond: Optional[ApiDestinationInvocationRateLimitPerSecond] - CreationTime: Optional[Timestamp] - LastModifiedTime: Optional[Timestamp] + ApiDestinationArn: ApiDestinationArn | None + Name: ApiDestinationName | None + ApiDestinationState: ApiDestinationState | None + ConnectionArn: ConnectionArn | None + InvocationEndpoint: HttpsEndpoint | None + HttpMethod: ApiDestinationHttpMethod | None + InvocationRateLimitPerSecond: ApiDestinationInvocationRateLimitPerSecond | None + CreationTime: Timestamp | None + LastModifiedTime: Timestamp | None -ApiDestinationResponseList = List[ApiDestination] +ApiDestinationResponseList = list[ApiDestination] class AppSyncParameters(TypedDict, total=False): - GraphQLOperation: Optional[GraphQLOperation] + GraphQLOperation: GraphQLOperation | None Long = int class Archive(TypedDict, total=False): - ArchiveName: Optional[ArchiveName] - EventSourceArn: Optional[EventBusArn] - State: Optional[ArchiveState] - StateReason: Optional[ArchiveStateReason] - RetentionDays: Optional[RetentionDays] - SizeBytes: Optional[Long] - EventCount: Optional[Long] - CreationTime: Optional[Timestamp] + ArchiveName: ArchiveName | None + EventSourceArn: EventBusArn | None + State: ArchiveState | None + StateReason: ArchiveStateReason | None + RetentionDays: RetentionDays | None + SizeBytes: Long | None + EventCount: Long | None + CreationTime: Timestamp | None -ArchiveResponseList = List[Archive] -StringList = List[String] +ArchiveResponseList = list[Archive] +StringList = list[String] class AwsVpcConfiguration(TypedDict, total=False): Subnets: StringList - SecurityGroups: Optional[StringList] - AssignPublicIp: Optional[AssignPublicIp] + SecurityGroups: StringList | None + AssignPublicIp: AssignPublicIp | None class BatchArrayProperties(TypedDict, total=False): - Size: Optional[Integer] + Size: Integer | None class BatchRetryStrategy(TypedDict, total=False): - Attempts: Optional[Integer] + Attempts: Integer | None class BatchParameters(TypedDict, total=False): JobDefinition: String JobName: String - ArrayProperties: Optional[BatchArrayProperties] - RetryStrategy: Optional[BatchRetryStrategy] + ArrayProperties: BatchArrayProperties | None + RetryStrategy: BatchRetryStrategy | None class CancelReplayRequest(ServiceRequest): @@ -381,18 +381,18 @@ class CancelReplayRequest(ServiceRequest): class CancelReplayResponse(TypedDict, total=False): - ReplayArn: Optional[ReplayArn] - State: Optional[ReplayState] - StateReason: Optional[ReplayStateReason] + ReplayArn: ReplayArn | None + State: ReplayState | None + StateReason: ReplayStateReason | None class CapacityProviderStrategyItem(TypedDict, total=False): capacityProvider: CapacityProvider - weight: Optional[CapacityProviderStrategyItemWeight] - base: Optional[CapacityProviderStrategyItemBase] + weight: CapacityProviderStrategyItemWeight | None + base: CapacityProviderStrategyItemBase | None -CapacityProviderStrategy = List[CapacityProviderStrategyItem] +CapacityProviderStrategy = list[CapacityProviderStrategyItem] class Condition(TypedDict, total=False): @@ -402,18 +402,18 @@ class Condition(TypedDict, total=False): class Connection(TypedDict, total=False): - ConnectionArn: Optional[ConnectionArn] - Name: Optional[ConnectionName] - ConnectionState: Optional[ConnectionState] - StateReason: Optional[ConnectionStateReason] - AuthorizationType: Optional[ConnectionAuthorizationType] - CreationTime: Optional[Timestamp] - LastModifiedTime: Optional[Timestamp] - LastAuthorizedTime: Optional[Timestamp] + ConnectionArn: ConnectionArn | None + Name: ConnectionName | None + ConnectionState: ConnectionState | None + StateReason: ConnectionStateReason | None + AuthorizationType: ConnectionAuthorizationType | None + CreationTime: Timestamp | None + LastModifiedTime: Timestamp | None + LastAuthorizedTime: Timestamp | None class ConnectionApiKeyAuthResponseParameters(TypedDict, total=False): - ApiKeyName: Optional[AuthHeaderParameters] + ApiKeyName: AuthHeaderParameters | None class DescribeConnectionResourceParameters(TypedDict, total=False): @@ -426,62 +426,62 @@ class DescribeConnectionConnectivityParameters(TypedDict, total=False): class ConnectionBodyParameter(TypedDict, total=False): - Key: Optional[String] - Value: Optional[SensitiveString] - IsValueSecret: Optional[Boolean] + Key: String | None + Value: SensitiveString | None + IsValueSecret: Boolean | None -ConnectionBodyParametersList = List[ConnectionBodyParameter] +ConnectionBodyParametersList = list[ConnectionBodyParameter] class ConnectionQueryStringParameter(TypedDict, total=False): - Key: Optional[QueryStringKey] - Value: Optional[QueryStringValueSensitive] - IsValueSecret: Optional[Boolean] + Key: QueryStringKey | None + Value: QueryStringValueSensitive | None + IsValueSecret: Boolean | None -ConnectionQueryStringParametersList = List[ConnectionQueryStringParameter] +ConnectionQueryStringParametersList = list[ConnectionQueryStringParameter] class ConnectionHeaderParameter(TypedDict, total=False): - Key: Optional[HeaderKey] - Value: Optional[HeaderValueSensitive] - IsValueSecret: Optional[Boolean] + Key: HeaderKey | None + Value: HeaderValueSensitive | None + IsValueSecret: Boolean | None -ConnectionHeaderParametersList = List[ConnectionHeaderParameter] +ConnectionHeaderParametersList = list[ConnectionHeaderParameter] class ConnectionHttpParameters(TypedDict, total=False): - HeaderParameters: Optional[ConnectionHeaderParametersList] - QueryStringParameters: Optional[ConnectionQueryStringParametersList] - BodyParameters: Optional[ConnectionBodyParametersList] + HeaderParameters: ConnectionHeaderParametersList | None + QueryStringParameters: ConnectionQueryStringParametersList | None + BodyParameters: ConnectionBodyParametersList | None class ConnectionOAuthClientResponseParameters(TypedDict, total=False): - ClientID: Optional[AuthHeaderParameters] + ClientID: AuthHeaderParameters | None class ConnectionOAuthResponseParameters(TypedDict, total=False): - ClientParameters: Optional[ConnectionOAuthClientResponseParameters] - AuthorizationEndpoint: Optional[HttpsEndpoint] - HttpMethod: Optional[ConnectionOAuthHttpMethod] - OAuthHttpParameters: Optional[ConnectionHttpParameters] + ClientParameters: ConnectionOAuthClientResponseParameters | None + AuthorizationEndpoint: HttpsEndpoint | None + HttpMethod: ConnectionOAuthHttpMethod | None + OAuthHttpParameters: ConnectionHttpParameters | None class ConnectionBasicAuthResponseParameters(TypedDict, total=False): - Username: Optional[AuthHeaderParameters] + Username: AuthHeaderParameters | None class ConnectionAuthResponseParameters(TypedDict, total=False): - BasicAuthParameters: Optional[ConnectionBasicAuthResponseParameters] - OAuthParameters: Optional[ConnectionOAuthResponseParameters] - ApiKeyAuthParameters: Optional[ConnectionApiKeyAuthResponseParameters] - InvocationHttpParameters: Optional[ConnectionHttpParameters] - ConnectivityParameters: Optional[DescribeConnectionConnectivityParameters] + BasicAuthParameters: ConnectionBasicAuthResponseParameters | None + OAuthParameters: ConnectionOAuthResponseParameters | None + ApiKeyAuthParameters: ConnectionApiKeyAuthResponseParameters | None + InvocationHttpParameters: ConnectionHttpParameters | None + ConnectivityParameters: DescribeConnectionConnectivityParameters | None -ConnectionResponseList = List[Connection] +ConnectionResponseList = list[Connection] class ConnectivityResourceConfigurationArn(TypedDict, total=False): @@ -494,34 +494,34 @@ class ConnectivityResourceParameters(TypedDict, total=False): class CreateApiDestinationRequest(ServiceRequest): Name: ApiDestinationName - Description: Optional[ApiDestinationDescription] + Description: ApiDestinationDescription | None ConnectionArn: ConnectionArn InvocationEndpoint: HttpsEndpoint HttpMethod: ApiDestinationHttpMethod - InvocationRateLimitPerSecond: Optional[ApiDestinationInvocationRateLimitPerSecond] + InvocationRateLimitPerSecond: ApiDestinationInvocationRateLimitPerSecond | None class CreateApiDestinationResponse(TypedDict, total=False): - ApiDestinationArn: Optional[ApiDestinationArn] - ApiDestinationState: Optional[ApiDestinationState] - CreationTime: Optional[Timestamp] - LastModifiedTime: Optional[Timestamp] + ApiDestinationArn: ApiDestinationArn | None + ApiDestinationState: ApiDestinationState | None + CreationTime: Timestamp | None + LastModifiedTime: Timestamp | None class CreateArchiveRequest(ServiceRequest): ArchiveName: ArchiveName EventSourceArn: EventBusArn - Description: Optional[ArchiveDescription] - EventPattern: Optional[EventPattern] - RetentionDays: Optional[RetentionDays] - KmsKeyIdentifier: Optional[KmsKeyIdentifier] + Description: ArchiveDescription | None + EventPattern: EventPattern | None + RetentionDays: RetentionDays | None + KmsKeyIdentifier: KmsKeyIdentifier | None class CreateArchiveResponse(TypedDict, total=False): - ArchiveArn: Optional[ArchiveArn] - State: Optional[ArchiveState] - StateReason: Optional[ArchiveStateReason] - CreationTime: Optional[Timestamp] + ArchiveArn: ArchiveArn | None + State: ArchiveState | None + StateReason: ArchiveStateReason | None + CreationTime: Timestamp | None class CreateConnectionApiKeyAuthRequestParameters(TypedDict, total=False): @@ -538,7 +538,7 @@ class CreateConnectionOAuthRequestParameters(TypedDict, total=False): ClientParameters: CreateConnectionOAuthClientRequestParameters AuthorizationEndpoint: HttpsEndpoint HttpMethod: ConnectionOAuthHttpMethod - OAuthHttpParameters: Optional[ConnectionHttpParameters] + OAuthHttpParameters: ConnectionHttpParameters | None class CreateConnectionBasicAuthRequestParameters(TypedDict, total=False): @@ -547,38 +547,38 @@ class CreateConnectionBasicAuthRequestParameters(TypedDict, total=False): class CreateConnectionAuthRequestParameters(TypedDict, total=False): - BasicAuthParameters: Optional[CreateConnectionBasicAuthRequestParameters] - OAuthParameters: Optional[CreateConnectionOAuthRequestParameters] - ApiKeyAuthParameters: Optional[CreateConnectionApiKeyAuthRequestParameters] - InvocationHttpParameters: Optional[ConnectionHttpParameters] - ConnectivityParameters: Optional[ConnectivityResourceParameters] + BasicAuthParameters: CreateConnectionBasicAuthRequestParameters | None + OAuthParameters: CreateConnectionOAuthRequestParameters | None + ApiKeyAuthParameters: CreateConnectionApiKeyAuthRequestParameters | None + InvocationHttpParameters: ConnectionHttpParameters | None + ConnectivityParameters: ConnectivityResourceParameters | None class CreateConnectionRequest(ServiceRequest): Name: ConnectionName - Description: Optional[ConnectionDescription] + Description: ConnectionDescription | None AuthorizationType: ConnectionAuthorizationType AuthParameters: CreateConnectionAuthRequestParameters - InvocationConnectivityParameters: Optional[ConnectivityResourceParameters] - KmsKeyIdentifier: Optional[KmsKeyIdentifier] + InvocationConnectivityParameters: ConnectivityResourceParameters | None + KmsKeyIdentifier: KmsKeyIdentifier | None class CreateConnectionResponse(TypedDict, total=False): - ConnectionArn: Optional[ConnectionArn] - ConnectionState: Optional[ConnectionState] - CreationTime: Optional[Timestamp] - LastModifiedTime: Optional[Timestamp] + ConnectionArn: ConnectionArn | None + ConnectionState: ConnectionState | None + CreationTime: Timestamp | None + LastModifiedTime: Timestamp | None class EndpointEventBus(TypedDict, total=False): EventBusArn: NonPartnerEventBusArn -EndpointEventBusList = List[EndpointEventBus] +EndpointEventBusList = list[EndpointEventBus] class ReplicationConfig(TypedDict, total=False): - State: Optional[ReplicationState] + State: ReplicationState | None class Secondary(TypedDict, total=False): @@ -600,21 +600,21 @@ class RoutingConfig(TypedDict, total=False): class CreateEndpointRequest(ServiceRequest): Name: EndpointName - Description: Optional[EndpointDescription] + Description: EndpointDescription | None RoutingConfig: RoutingConfig - ReplicationConfig: Optional[ReplicationConfig] + ReplicationConfig: ReplicationConfig | None EventBuses: EndpointEventBusList - RoleArn: Optional[IamRoleArn] + RoleArn: IamRoleArn | None class CreateEndpointResponse(TypedDict, total=False): - Name: Optional[EndpointName] - Arn: Optional[EndpointArn] - RoutingConfig: Optional[RoutingConfig] - ReplicationConfig: Optional[ReplicationConfig] - EventBuses: Optional[EndpointEventBusList] - RoleArn: Optional[IamRoleArn] - State: Optional[EndpointState] + Name: EndpointName | None + Arn: EndpointArn | None + RoutingConfig: RoutingConfig | None + ReplicationConfig: ReplicationConfig | None + EventBuses: EndpointEventBusList | None + RoleArn: IamRoleArn | None + State: EndpointState | None class Tag(TypedDict, total=False): @@ -622,34 +622,34 @@ class Tag(TypedDict, total=False): Value: TagValue -TagList = List[Tag] +TagList = list[Tag] class LogConfig(TypedDict, total=False): - IncludeDetail: Optional[IncludeDetail] - Level: Optional[Level] + IncludeDetail: IncludeDetail | None + Level: Level | None class DeadLetterConfig(TypedDict, total=False): - Arn: Optional[ResourceArn] + Arn: ResourceArn | None class CreateEventBusRequest(ServiceRequest): Name: EventBusName - EventSourceName: Optional[EventSourceName] - Description: Optional[EventBusDescription] - KmsKeyIdentifier: Optional[KmsKeyIdentifier] - DeadLetterConfig: Optional[DeadLetterConfig] - LogConfig: Optional[LogConfig] - Tags: Optional[TagList] + EventSourceName: EventSourceName | None + Description: EventBusDescription | None + KmsKeyIdentifier: KmsKeyIdentifier | None + DeadLetterConfig: DeadLetterConfig | None + LogConfig: LogConfig | None + Tags: TagList | None class CreateEventBusResponse(TypedDict, total=False): - EventBusArn: Optional[String] - Description: Optional[EventBusDescription] - KmsKeyIdentifier: Optional[KmsKeyIdentifier] - DeadLetterConfig: Optional[DeadLetterConfig] - LogConfig: Optional[LogConfig] + EventBusArn: String | None + Description: EventBusDescription | None + KmsKeyIdentifier: KmsKeyIdentifier | None + DeadLetterConfig: DeadLetterConfig | None + LogConfig: LogConfig | None class CreatePartnerEventSourceRequest(ServiceRequest): @@ -658,7 +658,7 @@ class CreatePartnerEventSourceRequest(ServiceRequest): class CreatePartnerEventSourceResponse(TypedDict, total=False): - EventSourceArn: Optional[String] + EventSourceArn: String | None class DeactivateEventSourceRequest(ServiceRequest): @@ -670,11 +670,11 @@ class DeauthorizeConnectionRequest(ServiceRequest): class DeauthorizeConnectionResponse(TypedDict, total=False): - ConnectionArn: Optional[ConnectionArn] - ConnectionState: Optional[ConnectionState] - CreationTime: Optional[Timestamp] - LastModifiedTime: Optional[Timestamp] - LastAuthorizedTime: Optional[Timestamp] + ConnectionArn: ConnectionArn | None + ConnectionState: ConnectionState | None + CreationTime: Timestamp | None + LastModifiedTime: Timestamp | None + LastAuthorizedTime: Timestamp | None class DeleteApiDestinationRequest(ServiceRequest): @@ -698,11 +698,11 @@ class DeleteConnectionRequest(ServiceRequest): class DeleteConnectionResponse(TypedDict, total=False): - ConnectionArn: Optional[ConnectionArn] - ConnectionState: Optional[ConnectionState] - CreationTime: Optional[Timestamp] - LastModifiedTime: Optional[Timestamp] - LastAuthorizedTime: Optional[Timestamp] + ConnectionArn: ConnectionArn | None + ConnectionState: ConnectionState | None + CreationTime: Timestamp | None + LastModifiedTime: Timestamp | None + LastAuthorizedTime: Timestamp | None class DeleteEndpointRequest(ServiceRequest): @@ -724,8 +724,8 @@ class DeletePartnerEventSourceRequest(ServiceRequest): class DeleteRuleRequest(ServiceRequest): Name: RuleName - EventBusName: Optional[EventBusNameOrArn] - Force: Optional[Boolean] + EventBusName: EventBusNameOrArn | None + Force: Boolean | None class DescribeApiDestinationRequest(ServiceRequest): @@ -733,16 +733,16 @@ class DescribeApiDestinationRequest(ServiceRequest): class DescribeApiDestinationResponse(TypedDict, total=False): - ApiDestinationArn: Optional[ApiDestinationArn] - Name: Optional[ApiDestinationName] - Description: Optional[ApiDestinationDescription] - ApiDestinationState: Optional[ApiDestinationState] - ConnectionArn: Optional[ConnectionArn] - InvocationEndpoint: Optional[HttpsEndpoint] - HttpMethod: Optional[ApiDestinationHttpMethod] - InvocationRateLimitPerSecond: Optional[ApiDestinationInvocationRateLimitPerSecond] - CreationTime: Optional[Timestamp] - LastModifiedTime: Optional[Timestamp] + ApiDestinationArn: ApiDestinationArn | None + Name: ApiDestinationName | None + Description: ApiDestinationDescription | None + ApiDestinationState: ApiDestinationState | None + ConnectionArn: ConnectionArn | None + InvocationEndpoint: HttpsEndpoint | None + HttpMethod: ApiDestinationHttpMethod | None + InvocationRateLimitPerSecond: ApiDestinationInvocationRateLimitPerSecond | None + CreationTime: Timestamp | None + LastModifiedTime: Timestamp | None class DescribeArchiveRequest(ServiceRequest): @@ -750,18 +750,18 @@ class DescribeArchiveRequest(ServiceRequest): class DescribeArchiveResponse(TypedDict, total=False): - ArchiveArn: Optional[ArchiveArn] - ArchiveName: Optional[ArchiveName] - EventSourceArn: Optional[EventBusArn] - Description: Optional[ArchiveDescription] - EventPattern: Optional[EventPattern] - State: Optional[ArchiveState] - StateReason: Optional[ArchiveStateReason] - KmsKeyIdentifier: Optional[KmsKeyIdentifier] - RetentionDays: Optional[RetentionDays] - SizeBytes: Optional[Long] - EventCount: Optional[Long] - CreationTime: Optional[Timestamp] + ArchiveArn: ArchiveArn | None + ArchiveName: ArchiveName | None + EventSourceArn: EventBusArn | None + Description: ArchiveDescription | None + EventPattern: EventPattern | None + State: ArchiveState | None + StateReason: ArchiveStateReason | None + KmsKeyIdentifier: KmsKeyIdentifier | None + RetentionDays: RetentionDays | None + SizeBytes: Long | None + EventCount: Long | None + CreationTime: Timestamp | None class DescribeConnectionRequest(ServiceRequest): @@ -769,56 +769,56 @@ class DescribeConnectionRequest(ServiceRequest): class DescribeConnectionResponse(TypedDict, total=False): - ConnectionArn: Optional[ConnectionArn] - Name: Optional[ConnectionName] - Description: Optional[ConnectionDescription] - InvocationConnectivityParameters: Optional[DescribeConnectionConnectivityParameters] - ConnectionState: Optional[ConnectionState] - StateReason: Optional[ConnectionStateReason] - AuthorizationType: Optional[ConnectionAuthorizationType] - SecretArn: Optional[SecretsManagerSecretArn] - KmsKeyIdentifier: Optional[KmsKeyIdentifier] - AuthParameters: Optional[ConnectionAuthResponseParameters] - CreationTime: Optional[Timestamp] - LastModifiedTime: Optional[Timestamp] - LastAuthorizedTime: Optional[Timestamp] + ConnectionArn: ConnectionArn | None + Name: ConnectionName | None + Description: ConnectionDescription | None + InvocationConnectivityParameters: DescribeConnectionConnectivityParameters | None + ConnectionState: ConnectionState | None + StateReason: ConnectionStateReason | None + AuthorizationType: ConnectionAuthorizationType | None + SecretArn: SecretsManagerSecretArn | None + KmsKeyIdentifier: KmsKeyIdentifier | None + AuthParameters: ConnectionAuthResponseParameters | None + CreationTime: Timestamp | None + LastModifiedTime: Timestamp | None + LastAuthorizedTime: Timestamp | None class DescribeEndpointRequest(ServiceRequest): Name: EndpointName - HomeRegion: Optional[HomeRegion] + HomeRegion: HomeRegion | None class DescribeEndpointResponse(TypedDict, total=False): - Name: Optional[EndpointName] - Description: Optional[EndpointDescription] - Arn: Optional[EndpointArn] - RoutingConfig: Optional[RoutingConfig] - ReplicationConfig: Optional[ReplicationConfig] - EventBuses: Optional[EndpointEventBusList] - RoleArn: Optional[IamRoleArn] - EndpointId: Optional[EndpointId] - EndpointUrl: Optional[EndpointUrl] - State: Optional[EndpointState] - StateReason: Optional[EndpointStateReason] - CreationTime: Optional[Timestamp] - LastModifiedTime: Optional[Timestamp] + Name: EndpointName | None + Description: EndpointDescription | None + Arn: EndpointArn | None + RoutingConfig: RoutingConfig | None + ReplicationConfig: ReplicationConfig | None + EventBuses: EndpointEventBusList | None + RoleArn: IamRoleArn | None + EndpointId: EndpointId | None + EndpointUrl: EndpointUrl | None + State: EndpointState | None + StateReason: EndpointStateReason | None + CreationTime: Timestamp | None + LastModifiedTime: Timestamp | None class DescribeEventBusRequest(ServiceRequest): - Name: Optional[EventBusNameOrArn] + Name: EventBusNameOrArn | None class DescribeEventBusResponse(TypedDict, total=False): - Name: Optional[String] - Arn: Optional[String] - Description: Optional[EventBusDescription] - KmsKeyIdentifier: Optional[KmsKeyIdentifier] - DeadLetterConfig: Optional[DeadLetterConfig] - Policy: Optional[String] - LogConfig: Optional[LogConfig] - CreationTime: Optional[Timestamp] - LastModifiedTime: Optional[Timestamp] + Name: String | None + Arn: String | None + Description: EventBusDescription | None + KmsKeyIdentifier: KmsKeyIdentifier | None + DeadLetterConfig: DeadLetterConfig | None + Policy: String | None + LogConfig: LogConfig | None + CreationTime: Timestamp | None + LastModifiedTime: Timestamp | None class DescribeEventSourceRequest(ServiceRequest): @@ -826,12 +826,12 @@ class DescribeEventSourceRequest(ServiceRequest): class DescribeEventSourceResponse(TypedDict, total=False): - Arn: Optional[String] - CreatedBy: Optional[String] - CreationTime: Optional[Timestamp] - ExpirationTime: Optional[Timestamp] - Name: Optional[String] - State: Optional[EventSourceState] + Arn: String | None + CreatedBy: String | None + CreationTime: Timestamp | None + ExpirationTime: Timestamp | None + Name: String | None + State: EventSourceState | None class DescribePartnerEventSourceRequest(ServiceRequest): @@ -839,161 +839,161 @@ class DescribePartnerEventSourceRequest(ServiceRequest): class DescribePartnerEventSourceResponse(TypedDict, total=False): - Arn: Optional[String] - Name: Optional[String] + Arn: String | None + Name: String | None class DescribeReplayRequest(ServiceRequest): ReplayName: ReplayName -ReplayDestinationFilters = List[Arn] +ReplayDestinationFilters = list[Arn] class ReplayDestination(TypedDict, total=False): Arn: Arn - FilterArns: Optional[ReplayDestinationFilters] + FilterArns: ReplayDestinationFilters | None class DescribeReplayResponse(TypedDict, total=False): - ReplayName: Optional[ReplayName] - ReplayArn: Optional[ReplayArn] - Description: Optional[ReplayDescription] - State: Optional[ReplayState] - StateReason: Optional[ReplayStateReason] - EventSourceArn: Optional[ArchiveArn] - Destination: Optional[ReplayDestination] - EventStartTime: Optional[Timestamp] - EventEndTime: Optional[Timestamp] - EventLastReplayedTime: Optional[Timestamp] - ReplayStartTime: Optional[Timestamp] - ReplayEndTime: Optional[Timestamp] + ReplayName: ReplayName | None + ReplayArn: ReplayArn | None + Description: ReplayDescription | None + State: ReplayState | None + StateReason: ReplayStateReason | None + EventSourceArn: ArchiveArn | None + Destination: ReplayDestination | None + EventStartTime: Timestamp | None + EventEndTime: Timestamp | None + EventLastReplayedTime: Timestamp | None + ReplayStartTime: Timestamp | None + ReplayEndTime: Timestamp | None class DescribeRuleRequest(ServiceRequest): Name: RuleName - EventBusName: Optional[EventBusNameOrArn] + EventBusName: EventBusNameOrArn | None class DescribeRuleResponse(TypedDict, total=False): - Name: Optional[RuleName] - Arn: Optional[RuleArn] - EventPattern: Optional[EventPattern] - ScheduleExpression: Optional[ScheduleExpression] - State: Optional[RuleState] - Description: Optional[RuleDescription] - RoleArn: Optional[RoleArn] - ManagedBy: Optional[ManagedBy] - EventBusName: Optional[EventBusName] - CreatedBy: Optional[CreatedBy] + Name: RuleName | None + Arn: RuleArn | None + EventPattern: EventPattern | None + ScheduleExpression: ScheduleExpression | None + State: RuleState | None + Description: RuleDescription | None + RoleArn: RoleArn | None + ManagedBy: ManagedBy | None + EventBusName: EventBusName | None + CreatedBy: CreatedBy | None class DisableRuleRequest(ServiceRequest): Name: RuleName - EventBusName: Optional[EventBusNameOrArn] + EventBusName: EventBusNameOrArn | None class PlacementStrategy(TypedDict, total=False): - type: Optional[PlacementStrategyType] - field: Optional[PlacementStrategyField] + type: PlacementStrategyType | None + field: PlacementStrategyField | None -PlacementStrategies = List[PlacementStrategy] +PlacementStrategies = list[PlacementStrategy] class PlacementConstraint(TypedDict, total=False): - type: Optional[PlacementConstraintType] - expression: Optional[PlacementConstraintExpression] + type: PlacementConstraintType | None + expression: PlacementConstraintExpression | None -PlacementConstraints = List[PlacementConstraint] +PlacementConstraints = list[PlacementConstraint] class NetworkConfiguration(TypedDict, total=False): - awsvpcConfiguration: Optional[AwsVpcConfiguration] + awsvpcConfiguration: AwsVpcConfiguration | None class EcsParameters(TypedDict, total=False): TaskDefinitionArn: Arn - TaskCount: Optional[LimitMin1] - LaunchType: Optional[LaunchType] - NetworkConfiguration: Optional[NetworkConfiguration] - PlatformVersion: Optional[String] - Group: Optional[String] - CapacityProviderStrategy: Optional[CapacityProviderStrategy] - EnableECSManagedTags: Optional[Boolean] - EnableExecuteCommand: Optional[Boolean] - PlacementConstraints: Optional[PlacementConstraints] - PlacementStrategy: Optional[PlacementStrategies] - PropagateTags: Optional[PropagateTags] - ReferenceId: Optional[ReferenceId] - Tags: Optional[TagList] + TaskCount: LimitMin1 | None + LaunchType: LaunchType | None + NetworkConfiguration: NetworkConfiguration | None + PlatformVersion: String | None + Group: String | None + CapacityProviderStrategy: CapacityProviderStrategy | None + EnableECSManagedTags: Boolean | None + EnableExecuteCommand: Boolean | None + PlacementConstraints: PlacementConstraints | None + PlacementStrategy: PlacementStrategies | None + PropagateTags: PropagateTags | None + ReferenceId: ReferenceId | None + Tags: TagList | None class EnableRuleRequest(ServiceRequest): Name: RuleName - EventBusName: Optional[EventBusNameOrArn] + EventBusName: EventBusNameOrArn | None class Endpoint(TypedDict, total=False): - Name: Optional[EndpointName] - Description: Optional[EndpointDescription] - Arn: Optional[EndpointArn] - RoutingConfig: Optional[RoutingConfig] - ReplicationConfig: Optional[ReplicationConfig] - EventBuses: Optional[EndpointEventBusList] - RoleArn: Optional[IamRoleArn] - EndpointId: Optional[EndpointId] - EndpointUrl: Optional[EndpointUrl] - State: Optional[EndpointState] - StateReason: Optional[EndpointStateReason] - CreationTime: Optional[Timestamp] - LastModifiedTime: Optional[Timestamp] + Name: EndpointName | None + Description: EndpointDescription | None + Arn: EndpointArn | None + RoutingConfig: RoutingConfig | None + ReplicationConfig: ReplicationConfig | None + EventBuses: EndpointEventBusList | None + RoleArn: IamRoleArn | None + EndpointId: EndpointId | None + EndpointUrl: EndpointUrl | None + State: EndpointState | None + StateReason: EndpointStateReason | None + CreationTime: Timestamp | None + LastModifiedTime: Timestamp | None -EndpointList = List[Endpoint] +EndpointList = list[Endpoint] class EventBus(TypedDict, total=False): - Name: Optional[String] - Arn: Optional[String] - Description: Optional[EventBusDescription] - Policy: Optional[String] - CreationTime: Optional[Timestamp] - LastModifiedTime: Optional[Timestamp] + Name: String | None + Arn: String | None + Description: EventBusDescription | None + Policy: String | None + CreationTime: Timestamp | None + LastModifiedTime: Timestamp | None -EventBusList = List[EventBus] -EventResourceList = List[EventResource] +EventBusList = list[EventBus] +EventResourceList = list[EventResource] class EventSource(TypedDict, total=False): - Arn: Optional[String] - CreatedBy: Optional[String] - CreationTime: Optional[Timestamp] - ExpirationTime: Optional[Timestamp] - Name: Optional[String] - State: Optional[EventSourceState] + Arn: String | None + CreatedBy: String | None + CreationTime: Timestamp | None + ExpirationTime: Timestamp | None + Name: String | None + State: EventSourceState | None -EventSourceList = List[EventSource] +EventSourceList = list[EventSource] EventTime = datetime -HeaderParametersMap = Dict[HeaderKey, HeaderValue] -QueryStringParametersMap = Dict[QueryStringKey, QueryStringValue] -PathParameterList = List[PathParameter] +HeaderParametersMap = dict[HeaderKey, HeaderValue] +QueryStringParametersMap = dict[QueryStringKey, QueryStringValue] +PathParameterList = list[PathParameter] class HttpParameters(TypedDict, total=False): - PathParameterValues: Optional[PathParameterList] - HeaderParameters: Optional[HeaderParametersMap] - QueryStringParameters: Optional[QueryStringParametersMap] + PathParameterValues: PathParameterList | None + HeaderParameters: HeaderParametersMap | None + QueryStringParameters: QueryStringParametersMap | None -TransformerPaths = Dict[InputTransformerPathKey, TargetInputPath] +TransformerPaths = dict[InputTransformerPathKey, TargetInputPath] class InputTransformer(TypedDict, total=False): - InputPathsMap: Optional[TransformerPaths] + InputPathsMap: TransformerPaths | None InputTemplate: TransformerInput @@ -1002,184 +1002,184 @@ class KinesisParameters(TypedDict, total=False): class ListApiDestinationsRequest(ServiceRequest): - NamePrefix: Optional[ApiDestinationName] - ConnectionArn: Optional[ConnectionArn] - NextToken: Optional[NextToken] - Limit: Optional[LimitMax100] + NamePrefix: ApiDestinationName | None + ConnectionArn: ConnectionArn | None + NextToken: NextToken | None + Limit: LimitMax100 | None class ListApiDestinationsResponse(TypedDict, total=False): - ApiDestinations: Optional[ApiDestinationResponseList] - NextToken: Optional[NextToken] + ApiDestinations: ApiDestinationResponseList | None + NextToken: NextToken | None class ListArchivesRequest(ServiceRequest): - NamePrefix: Optional[ArchiveName] - EventSourceArn: Optional[EventBusArn] - State: Optional[ArchiveState] - NextToken: Optional[NextToken] - Limit: Optional[LimitMax100] + NamePrefix: ArchiveName | None + EventSourceArn: EventBusArn | None + State: ArchiveState | None + NextToken: NextToken | None + Limit: LimitMax100 | None class ListArchivesResponse(TypedDict, total=False): - Archives: Optional[ArchiveResponseList] - NextToken: Optional[NextToken] + Archives: ArchiveResponseList | None + NextToken: NextToken | None class ListConnectionsRequest(ServiceRequest): - NamePrefix: Optional[ConnectionName] - ConnectionState: Optional[ConnectionState] - NextToken: Optional[NextToken] - Limit: Optional[LimitMax100] + NamePrefix: ConnectionName | None + ConnectionState: ConnectionState | None + NextToken: NextToken | None + Limit: LimitMax100 | None class ListConnectionsResponse(TypedDict, total=False): - Connections: Optional[ConnectionResponseList] - NextToken: Optional[NextToken] + Connections: ConnectionResponseList | None + NextToken: NextToken | None class ListEndpointsRequest(ServiceRequest): - NamePrefix: Optional[EndpointName] - HomeRegion: Optional[HomeRegion] - NextToken: Optional[NextToken] - MaxResults: Optional[LimitMax100] + NamePrefix: EndpointName | None + HomeRegion: HomeRegion | None + NextToken: NextToken | None + MaxResults: LimitMax100 | None class ListEndpointsResponse(TypedDict, total=False): - Endpoints: Optional[EndpointList] - NextToken: Optional[NextToken] + Endpoints: EndpointList | None + NextToken: NextToken | None class ListEventBusesRequest(ServiceRequest): - NamePrefix: Optional[EventBusName] - NextToken: Optional[NextToken] - Limit: Optional[LimitMax100] + NamePrefix: EventBusName | None + NextToken: NextToken | None + Limit: LimitMax100 | None class ListEventBusesResponse(TypedDict, total=False): - EventBuses: Optional[EventBusList] - NextToken: Optional[NextToken] + EventBuses: EventBusList | None + NextToken: NextToken | None class ListEventSourcesRequest(ServiceRequest): - NamePrefix: Optional[EventSourceNamePrefix] - NextToken: Optional[NextToken] - Limit: Optional[LimitMax100] + NamePrefix: EventSourceNamePrefix | None + NextToken: NextToken | None + Limit: LimitMax100 | None class ListEventSourcesResponse(TypedDict, total=False): - EventSources: Optional[EventSourceList] - NextToken: Optional[NextToken] + EventSources: EventSourceList | None + NextToken: NextToken | None class ListPartnerEventSourceAccountsRequest(ServiceRequest): EventSourceName: EventSourceName - NextToken: Optional[NextToken] - Limit: Optional[LimitMax100] + NextToken: NextToken | None + Limit: LimitMax100 | None class PartnerEventSourceAccount(TypedDict, total=False): - Account: Optional[AccountId] - CreationTime: Optional[Timestamp] - ExpirationTime: Optional[Timestamp] - State: Optional[EventSourceState] + Account: AccountId | None + CreationTime: Timestamp | None + ExpirationTime: Timestamp | None + State: EventSourceState | None -PartnerEventSourceAccountList = List[PartnerEventSourceAccount] +PartnerEventSourceAccountList = list[PartnerEventSourceAccount] class ListPartnerEventSourceAccountsResponse(TypedDict, total=False): - PartnerEventSourceAccounts: Optional[PartnerEventSourceAccountList] - NextToken: Optional[NextToken] + PartnerEventSourceAccounts: PartnerEventSourceAccountList | None + NextToken: NextToken | None class ListPartnerEventSourcesRequest(ServiceRequest): NamePrefix: PartnerEventSourceNamePrefix - NextToken: Optional[NextToken] - Limit: Optional[LimitMax100] + NextToken: NextToken | None + Limit: LimitMax100 | None class PartnerEventSource(TypedDict, total=False): - Arn: Optional[String] - Name: Optional[String] + Arn: String | None + Name: String | None -PartnerEventSourceList = List[PartnerEventSource] +PartnerEventSourceList = list[PartnerEventSource] class ListPartnerEventSourcesResponse(TypedDict, total=False): - PartnerEventSources: Optional[PartnerEventSourceList] - NextToken: Optional[NextToken] + PartnerEventSources: PartnerEventSourceList | None + NextToken: NextToken | None class ListReplaysRequest(ServiceRequest): - NamePrefix: Optional[ReplayName] - State: Optional[ReplayState] - EventSourceArn: Optional[ArchiveArn] - NextToken: Optional[NextToken] - Limit: Optional[LimitMax100] + NamePrefix: ReplayName | None + State: ReplayState | None + EventSourceArn: ArchiveArn | None + NextToken: NextToken | None + Limit: LimitMax100 | None class Replay(TypedDict, total=False): - ReplayName: Optional[ReplayName] - EventSourceArn: Optional[ArchiveArn] - State: Optional[ReplayState] - StateReason: Optional[ReplayStateReason] - EventStartTime: Optional[Timestamp] - EventEndTime: Optional[Timestamp] - EventLastReplayedTime: Optional[Timestamp] - ReplayStartTime: Optional[Timestamp] - ReplayEndTime: Optional[Timestamp] + ReplayName: ReplayName | None + EventSourceArn: ArchiveArn | None + State: ReplayState | None + StateReason: ReplayStateReason | None + EventStartTime: Timestamp | None + EventEndTime: Timestamp | None + EventLastReplayedTime: Timestamp | None + ReplayStartTime: Timestamp | None + ReplayEndTime: Timestamp | None -ReplayList = List[Replay] +ReplayList = list[Replay] class ListReplaysResponse(TypedDict, total=False): - Replays: Optional[ReplayList] - NextToken: Optional[NextToken] + Replays: ReplayList | None + NextToken: NextToken | None class ListRuleNamesByTargetRequest(ServiceRequest): TargetArn: TargetArn - EventBusName: Optional[EventBusNameOrArn] - NextToken: Optional[NextToken] - Limit: Optional[LimitMax100] + EventBusName: EventBusNameOrArn | None + NextToken: NextToken | None + Limit: LimitMax100 | None -RuleNameList = List[RuleName] +RuleNameList = list[RuleName] class ListRuleNamesByTargetResponse(TypedDict, total=False): - RuleNames: Optional[RuleNameList] - NextToken: Optional[NextToken] + RuleNames: RuleNameList | None + NextToken: NextToken | None class ListRulesRequest(ServiceRequest): - NamePrefix: Optional[RuleName] - EventBusName: Optional[EventBusNameOrArn] - NextToken: Optional[NextToken] - Limit: Optional[LimitMax100] + NamePrefix: RuleName | None + EventBusName: EventBusNameOrArn | None + NextToken: NextToken | None + Limit: LimitMax100 | None class Rule(TypedDict, total=False): - Name: Optional[RuleName] - Arn: Optional[RuleArn] - EventPattern: Optional[EventPattern] - State: Optional[RuleState] - Description: Optional[RuleDescription] - ScheduleExpression: Optional[ScheduleExpression] - RoleArn: Optional[RoleArn] - ManagedBy: Optional[ManagedBy] - EventBusName: Optional[EventBusName] + Name: RuleName | None + Arn: RuleArn | None + EventPattern: EventPattern | None + State: RuleState | None + Description: RuleDescription | None + ScheduleExpression: ScheduleExpression | None + RoleArn: RoleArn | None + ManagedBy: ManagedBy | None + EventBusName: EventBusName | None -RuleResponseList = List[Rule] +RuleResponseList = list[Rule] class ListRulesResponse(TypedDict, total=False): - Rules: Optional[RuleResponseList] - NextToken: Optional[NextToken] + Rules: RuleResponseList | None + NextToken: NextToken | None class ListTagsForResourceRequest(ServiceRequest): @@ -1187,19 +1187,19 @@ class ListTagsForResourceRequest(ServiceRequest): class ListTagsForResourceResponse(TypedDict, total=False): - Tags: Optional[TagList] + Tags: TagList | None class ListTargetsByRuleRequest(ServiceRequest): Rule: RuleName - EventBusName: Optional[EventBusNameOrArn] - NextToken: Optional[NextToken] - Limit: Optional[LimitMax100] + EventBusName: EventBusNameOrArn | None + NextToken: NextToken | None + Limit: LimitMax100 | None class RetryPolicy(TypedDict, total=False): - MaximumRetryAttempts: Optional[MaximumRetryAttempts] - MaximumEventAgeInSeconds: Optional[MaximumEventAgeInSeconds] + MaximumRetryAttempts: MaximumRetryAttempts | None + MaximumEventAgeInSeconds: MaximumEventAgeInSeconds | None class SageMakerPipelineParameter(TypedDict, total=False): @@ -1207,31 +1207,31 @@ class SageMakerPipelineParameter(TypedDict, total=False): Value: SageMakerPipelineParameterValue -SageMakerPipelineParameterList = List[SageMakerPipelineParameter] +SageMakerPipelineParameterList = list[SageMakerPipelineParameter] class SageMakerPipelineParameters(TypedDict, total=False): - PipelineParameterList: Optional[SageMakerPipelineParameterList] + PipelineParameterList: SageMakerPipelineParameterList | None -Sqls = List[Sql] +Sqls = list[Sql] class RedshiftDataParameters(TypedDict, total=False): - SecretManagerArn: Optional[RedshiftSecretManagerArn] + SecretManagerArn: RedshiftSecretManagerArn | None Database: Database - DbUser: Optional[DbUser] - Sql: Optional[Sql] - StatementName: Optional[StatementName] - WithEvent: Optional[Boolean] - Sqls: Optional[Sqls] + DbUser: DbUser | None + Sql: Sql | None + StatementName: StatementName | None + WithEvent: Boolean | None + Sqls: Sqls | None class SqsParameters(TypedDict, total=False): - MessageGroupId: Optional[MessageGroupId] + MessageGroupId: MessageGroupId | None -RunCommandTargetValues = List[RunCommandTargetValue] +RunCommandTargetValues = list[RunCommandTargetValue] class RunCommandTarget(TypedDict, total=False): @@ -1239,7 +1239,7 @@ class RunCommandTarget(TypedDict, total=False): Values: RunCommandTargetValues -RunCommandTargets = List[RunCommandTarget] +RunCommandTargets = list[RunCommandTarget] class RunCommandParameters(TypedDict, total=False): @@ -1249,72 +1249,72 @@ class RunCommandParameters(TypedDict, total=False): class Target(TypedDict, total=False): Id: TargetId Arn: TargetArn - RoleArn: Optional[RoleArn] - Input: Optional[TargetInput] - InputPath: Optional[TargetInputPath] - InputTransformer: Optional[InputTransformer] - KinesisParameters: Optional[KinesisParameters] - RunCommandParameters: Optional[RunCommandParameters] - EcsParameters: Optional[EcsParameters] - BatchParameters: Optional[BatchParameters] - SqsParameters: Optional[SqsParameters] - HttpParameters: Optional[HttpParameters] - RedshiftDataParameters: Optional[RedshiftDataParameters] - SageMakerPipelineParameters: Optional[SageMakerPipelineParameters] - DeadLetterConfig: Optional[DeadLetterConfig] - RetryPolicy: Optional[RetryPolicy] - AppSyncParameters: Optional[AppSyncParameters] - - -TargetList = List[Target] + RoleArn: RoleArn | None + Input: TargetInput | None + InputPath: TargetInputPath | None + InputTransformer: InputTransformer | None + KinesisParameters: KinesisParameters | None + RunCommandParameters: RunCommandParameters | None + EcsParameters: EcsParameters | None + BatchParameters: BatchParameters | None + SqsParameters: SqsParameters | None + HttpParameters: HttpParameters | None + RedshiftDataParameters: RedshiftDataParameters | None + SageMakerPipelineParameters: SageMakerPipelineParameters | None + DeadLetterConfig: DeadLetterConfig | None + RetryPolicy: RetryPolicy | None + AppSyncParameters: AppSyncParameters | None + + +TargetList = list[Target] class ListTargetsByRuleResponse(TypedDict, total=False): - Targets: Optional[TargetList] - NextToken: Optional[NextToken] + Targets: TargetList | None + NextToken: NextToken | None class PutEventsRequestEntry(TypedDict, total=False): - Time: Optional[EventTime] - Source: Optional[String] - Resources: Optional[EventResourceList] - DetailType: Optional[String] - Detail: Optional[String] - EventBusName: Optional[NonPartnerEventBusNameOrArn] - TraceHeader: Optional[TraceHeader] + Time: EventTime | None + Source: String | None + Resources: EventResourceList | None + DetailType: String | None + Detail: String | None + EventBusName: NonPartnerEventBusNameOrArn | None + TraceHeader: TraceHeader | None -PutEventsRequestEntryList = List[PutEventsRequestEntry] +PutEventsRequestEntryList = list[PutEventsRequestEntry] class PutEventsRequest(ServiceRequest): Entries: PutEventsRequestEntryList - EndpointId: Optional[EndpointId] + EndpointId: EndpointId | None class PutEventsResultEntry(TypedDict, total=False): - EventId: Optional[EventId] - ErrorCode: Optional[ErrorCode] - ErrorMessage: Optional[ErrorMessage] + EventId: EventId | None + ErrorCode: ErrorCode | None + ErrorMessage: ErrorMessage | None -PutEventsResultEntryList = List[PutEventsResultEntry] +PutEventsResultEntryList = list[PutEventsResultEntry] class PutEventsResponse(TypedDict, total=False): - FailedEntryCount: Optional[Integer] - Entries: Optional[PutEventsResultEntryList] + FailedEntryCount: Integer | None + Entries: PutEventsResultEntryList | None class PutPartnerEventsRequestEntry(TypedDict, total=False): - Time: Optional[EventTime] - Source: Optional[EventSourceName] - Resources: Optional[EventResourceList] - DetailType: Optional[String] - Detail: Optional[String] + Time: EventTime | None + Source: EventSourceName | None + Resources: EventResourceList | None + DetailType: String | None + Detail: String | None -PutPartnerEventsRequestEntryList = List[PutPartnerEventsRequestEntry] +PutPartnerEventsRequestEntryList = list[PutPartnerEventsRequestEntry] class PutPartnerEventsRequest(ServiceRequest): @@ -1322,96 +1322,96 @@ class PutPartnerEventsRequest(ServiceRequest): class PutPartnerEventsResultEntry(TypedDict, total=False): - EventId: Optional[EventId] - ErrorCode: Optional[ErrorCode] - ErrorMessage: Optional[ErrorMessage] + EventId: EventId | None + ErrorCode: ErrorCode | None + ErrorMessage: ErrorMessage | None -PutPartnerEventsResultEntryList = List[PutPartnerEventsResultEntry] +PutPartnerEventsResultEntryList = list[PutPartnerEventsResultEntry] class PutPartnerEventsResponse(TypedDict, total=False): - FailedEntryCount: Optional[Integer] - Entries: Optional[PutPartnerEventsResultEntryList] + FailedEntryCount: Integer | None + Entries: PutPartnerEventsResultEntryList | None class PutPermissionRequest(ServiceRequest): - EventBusName: Optional[NonPartnerEventBusName] - Action: Optional[Action] - Principal: Optional[Principal] - StatementId: Optional[StatementId] - Condition: Optional[Condition] - Policy: Optional[String] + EventBusName: NonPartnerEventBusName | None + Action: Action | None + Principal: Principal | None + StatementId: StatementId | None + Condition: Condition | None + Policy: String | None class PutRuleRequest(ServiceRequest): Name: RuleName - ScheduleExpression: Optional[ScheduleExpression] - EventPattern: Optional[EventPattern] - State: Optional[RuleState] - Description: Optional[RuleDescription] - RoleArn: Optional[RoleArn] - Tags: Optional[TagList] - EventBusName: Optional[EventBusNameOrArn] + ScheduleExpression: ScheduleExpression | None + EventPattern: EventPattern | None + State: RuleState | None + Description: RuleDescription | None + RoleArn: RoleArn | None + Tags: TagList | None + EventBusName: EventBusNameOrArn | None class PutRuleResponse(TypedDict, total=False): - RuleArn: Optional[RuleArn] + RuleArn: RuleArn | None class PutTargetsRequest(ServiceRequest): Rule: RuleName - EventBusName: Optional[EventBusNameOrArn] + EventBusName: EventBusNameOrArn | None Targets: TargetList class PutTargetsResultEntry(TypedDict, total=False): - TargetId: Optional[TargetId] - ErrorCode: Optional[ErrorCode] - ErrorMessage: Optional[ErrorMessage] + TargetId: TargetId | None + ErrorCode: ErrorCode | None + ErrorMessage: ErrorMessage | None -PutTargetsResultEntryList = List[PutTargetsResultEntry] +PutTargetsResultEntryList = list[PutTargetsResultEntry] class PutTargetsResponse(TypedDict, total=False): - FailedEntryCount: Optional[Integer] - FailedEntries: Optional[PutTargetsResultEntryList] + FailedEntryCount: Integer | None + FailedEntries: PutTargetsResultEntryList | None class RemovePermissionRequest(ServiceRequest): - StatementId: Optional[StatementId] - RemoveAllPermissions: Optional[Boolean] - EventBusName: Optional[NonPartnerEventBusName] + StatementId: StatementId | None + RemoveAllPermissions: Boolean | None + EventBusName: NonPartnerEventBusName | None -TargetIdList = List[TargetId] +TargetIdList = list[TargetId] class RemoveTargetsRequest(ServiceRequest): Rule: RuleName - EventBusName: Optional[EventBusNameOrArn] + EventBusName: EventBusNameOrArn | None Ids: TargetIdList - Force: Optional[Boolean] + Force: Boolean | None class RemoveTargetsResultEntry(TypedDict, total=False): - TargetId: Optional[TargetId] - ErrorCode: Optional[ErrorCode] - ErrorMessage: Optional[ErrorMessage] + TargetId: TargetId | None + ErrorCode: ErrorCode | None + ErrorMessage: ErrorMessage | None -RemoveTargetsResultEntryList = List[RemoveTargetsResultEntry] +RemoveTargetsResultEntryList = list[RemoveTargetsResultEntry] class RemoveTargetsResponse(TypedDict, total=False): - FailedEntryCount: Optional[Integer] - FailedEntries: Optional[RemoveTargetsResultEntryList] + FailedEntryCount: Integer | None + FailedEntries: RemoveTargetsResultEntryList | None class StartReplayRequest(ServiceRequest): ReplayName: ReplayName - Description: Optional[ReplayDescription] + Description: ReplayDescription | None EventSourceArn: ArchiveArn EventStartTime: Timestamp EventEndTime: Timestamp @@ -1419,13 +1419,13 @@ class StartReplayRequest(ServiceRequest): class StartReplayResponse(TypedDict, total=False): - ReplayArn: Optional[ReplayArn] - State: Optional[ReplayState] - StateReason: Optional[ReplayStateReason] - ReplayStartTime: Optional[Timestamp] + ReplayArn: ReplayArn | None + State: ReplayState | None + StateReason: ReplayStateReason | None + ReplayStartTime: Timestamp | None -TagKeyList = List[TagKey] +TagKeyList = list[TagKey] class TagResourceRequest(ServiceRequest): @@ -1443,7 +1443,7 @@ class TestEventPatternRequest(ServiceRequest): class TestEventPatternResponse(TypedDict, total=False): - Result: Optional[Boolean] + Result: Boolean | None class UntagResourceRequest(ServiceRequest): @@ -1457,123 +1457,123 @@ class UntagResourceResponse(TypedDict, total=False): class UpdateApiDestinationRequest(ServiceRequest): Name: ApiDestinationName - Description: Optional[ApiDestinationDescription] - ConnectionArn: Optional[ConnectionArn] - InvocationEndpoint: Optional[HttpsEndpoint] - HttpMethod: Optional[ApiDestinationHttpMethod] - InvocationRateLimitPerSecond: Optional[ApiDestinationInvocationRateLimitPerSecond] + Description: ApiDestinationDescription | None + ConnectionArn: ConnectionArn | None + InvocationEndpoint: HttpsEndpoint | None + HttpMethod: ApiDestinationHttpMethod | None + InvocationRateLimitPerSecond: ApiDestinationInvocationRateLimitPerSecond | None class UpdateApiDestinationResponse(TypedDict, total=False): - ApiDestinationArn: Optional[ApiDestinationArn] - ApiDestinationState: Optional[ApiDestinationState] - CreationTime: Optional[Timestamp] - LastModifiedTime: Optional[Timestamp] + ApiDestinationArn: ApiDestinationArn | None + ApiDestinationState: ApiDestinationState | None + CreationTime: Timestamp | None + LastModifiedTime: Timestamp | None class UpdateArchiveRequest(ServiceRequest): ArchiveName: ArchiveName - Description: Optional[ArchiveDescription] - EventPattern: Optional[EventPattern] - RetentionDays: Optional[RetentionDays] - KmsKeyIdentifier: Optional[KmsKeyIdentifier] + Description: ArchiveDescription | None + EventPattern: EventPattern | None + RetentionDays: RetentionDays | None + KmsKeyIdentifier: KmsKeyIdentifier | None class UpdateArchiveResponse(TypedDict, total=False): - ArchiveArn: Optional[ArchiveArn] - State: Optional[ArchiveState] - StateReason: Optional[ArchiveStateReason] - CreationTime: Optional[Timestamp] + ArchiveArn: ArchiveArn | None + State: ArchiveState | None + StateReason: ArchiveStateReason | None + CreationTime: Timestamp | None class UpdateConnectionApiKeyAuthRequestParameters(TypedDict, total=False): - ApiKeyName: Optional[AuthHeaderParameters] - ApiKeyValue: Optional[AuthHeaderParametersSensitive] + ApiKeyName: AuthHeaderParameters | None + ApiKeyValue: AuthHeaderParametersSensitive | None class UpdateConnectionOAuthClientRequestParameters(TypedDict, total=False): - ClientID: Optional[AuthHeaderParameters] - ClientSecret: Optional[AuthHeaderParametersSensitive] + ClientID: AuthHeaderParameters | None + ClientSecret: AuthHeaderParametersSensitive | None class UpdateConnectionOAuthRequestParameters(TypedDict, total=False): - ClientParameters: Optional[UpdateConnectionOAuthClientRequestParameters] - AuthorizationEndpoint: Optional[HttpsEndpoint] - HttpMethod: Optional[ConnectionOAuthHttpMethod] - OAuthHttpParameters: Optional[ConnectionHttpParameters] + ClientParameters: UpdateConnectionOAuthClientRequestParameters | None + AuthorizationEndpoint: HttpsEndpoint | None + HttpMethod: ConnectionOAuthHttpMethod | None + OAuthHttpParameters: ConnectionHttpParameters | None class UpdateConnectionBasicAuthRequestParameters(TypedDict, total=False): - Username: Optional[AuthHeaderParameters] - Password: Optional[AuthHeaderParametersSensitive] + Username: AuthHeaderParameters | None + Password: AuthHeaderParametersSensitive | None class UpdateConnectionAuthRequestParameters(TypedDict, total=False): - BasicAuthParameters: Optional[UpdateConnectionBasicAuthRequestParameters] - OAuthParameters: Optional[UpdateConnectionOAuthRequestParameters] - ApiKeyAuthParameters: Optional[UpdateConnectionApiKeyAuthRequestParameters] - InvocationHttpParameters: Optional[ConnectionHttpParameters] - ConnectivityParameters: Optional[ConnectivityResourceParameters] + BasicAuthParameters: UpdateConnectionBasicAuthRequestParameters | None + OAuthParameters: UpdateConnectionOAuthRequestParameters | None + ApiKeyAuthParameters: UpdateConnectionApiKeyAuthRequestParameters | None + InvocationHttpParameters: ConnectionHttpParameters | None + ConnectivityParameters: ConnectivityResourceParameters | None class UpdateConnectionRequest(ServiceRequest): Name: ConnectionName - Description: Optional[ConnectionDescription] - AuthorizationType: Optional[ConnectionAuthorizationType] - AuthParameters: Optional[UpdateConnectionAuthRequestParameters] - InvocationConnectivityParameters: Optional[ConnectivityResourceParameters] - KmsKeyIdentifier: Optional[KmsKeyIdentifier] + Description: ConnectionDescription | None + AuthorizationType: ConnectionAuthorizationType | None + AuthParameters: UpdateConnectionAuthRequestParameters | None + InvocationConnectivityParameters: ConnectivityResourceParameters | None + KmsKeyIdentifier: KmsKeyIdentifier | None class UpdateConnectionResponse(TypedDict, total=False): - ConnectionArn: Optional[ConnectionArn] - ConnectionState: Optional[ConnectionState] - CreationTime: Optional[Timestamp] - LastModifiedTime: Optional[Timestamp] - LastAuthorizedTime: Optional[Timestamp] + ConnectionArn: ConnectionArn | None + ConnectionState: ConnectionState | None + CreationTime: Timestamp | None + LastModifiedTime: Timestamp | None + LastAuthorizedTime: Timestamp | None class UpdateEndpointRequest(ServiceRequest): Name: EndpointName - Description: Optional[EndpointDescription] - RoutingConfig: Optional[RoutingConfig] - ReplicationConfig: Optional[ReplicationConfig] - EventBuses: Optional[EndpointEventBusList] - RoleArn: Optional[IamRoleArn] + Description: EndpointDescription | None + RoutingConfig: RoutingConfig | None + ReplicationConfig: ReplicationConfig | None + EventBuses: EndpointEventBusList | None + RoleArn: IamRoleArn | None class UpdateEndpointResponse(TypedDict, total=False): - Name: Optional[EndpointName] - Arn: Optional[EndpointArn] - RoutingConfig: Optional[RoutingConfig] - ReplicationConfig: Optional[ReplicationConfig] - EventBuses: Optional[EndpointEventBusList] - RoleArn: Optional[IamRoleArn] - EndpointId: Optional[EndpointId] - EndpointUrl: Optional[EndpointUrl] - State: Optional[EndpointState] + Name: EndpointName | None + Arn: EndpointArn | None + RoutingConfig: RoutingConfig | None + ReplicationConfig: ReplicationConfig | None + EventBuses: EndpointEventBusList | None + RoleArn: IamRoleArn | None + EndpointId: EndpointId | None + EndpointUrl: EndpointUrl | None + State: EndpointState | None class UpdateEventBusRequest(ServiceRequest): - Name: Optional[EventBusName] - KmsKeyIdentifier: Optional[KmsKeyIdentifier] - Description: Optional[EventBusDescription] - DeadLetterConfig: Optional[DeadLetterConfig] - LogConfig: Optional[LogConfig] + Name: EventBusName | None + KmsKeyIdentifier: KmsKeyIdentifier | None + Description: EventBusDescription | None + DeadLetterConfig: DeadLetterConfig | None + LogConfig: LogConfig | None class UpdateEventBusResponse(TypedDict, total=False): - Arn: Optional[String] - Name: Optional[EventBusName] - KmsKeyIdentifier: Optional[KmsKeyIdentifier] - Description: Optional[EventBusDescription] - DeadLetterConfig: Optional[DeadLetterConfig] - LogConfig: Optional[LogConfig] + Arn: String | None + Name: EventBusName | None + KmsKeyIdentifier: KmsKeyIdentifier | None + Description: EventBusDescription | None + DeadLetterConfig: DeadLetterConfig | None + LogConfig: LogConfig | None class EventsApi: - service = "events" - version = "2015-10-07" + service: str = "events" + version: str = "2015-10-07" @handler("ActivateEventSource") def activate_event_source( diff --git a/localstack-core/localstack/aws/api/firehose/__init__.py b/localstack-core/localstack/aws/api/firehose/__init__.py index f1b3c79ac204d..902bfb916e45d 100644 --- a/localstack-core/localstack/aws/api/firehose/__init__.py +++ b/localstack-core/localstack/aws/api/firehose/__init__.py @@ -1,6 +1,6 @@ from datetime import datetime from enum import StrEnum -from typing import Dict, List, Optional, TypedDict +from typing import TypedDict from localstack.aws.api import RequestContext, ServiceException, ServiceRequest, handler @@ -371,12 +371,12 @@ class ServiceUnavailableException(ServiceException): class AmazonOpenSearchServerlessBufferingHints(TypedDict, total=False): - IntervalInSeconds: Optional[AmazonOpenSearchServerlessBufferingIntervalInSeconds] - SizeInMBs: Optional[AmazonOpenSearchServerlessBufferingSizeInMBs] + IntervalInSeconds: AmazonOpenSearchServerlessBufferingIntervalInSeconds | None + SizeInMBs: AmazonOpenSearchServerlessBufferingSizeInMBs | None -SecurityGroupIdList = List[NonEmptyStringWithoutWhitespace] -SubnetIdList = List[NonEmptyStringWithoutWhitespace] +SecurityGroupIdList = list[NonEmptyStringWithoutWhitespace] +SubnetIdList = list[NonEmptyStringWithoutWhitespace] class VpcConfiguration(TypedDict, total=False): @@ -386,9 +386,9 @@ class VpcConfiguration(TypedDict, total=False): class CloudWatchLoggingOptions(TypedDict, total=False): - Enabled: Optional[BooleanObject] - LogGroupName: Optional[LogGroupName] - LogStreamName: Optional[LogStreamName] + Enabled: BooleanObject | None + LogGroupName: LogGroupName | None + LogStreamName: LogStreamName | None class ProcessorParameter(TypedDict, total=False): @@ -396,20 +396,20 @@ class ProcessorParameter(TypedDict, total=False): ParameterValue: ProcessorParameterValue -ProcessorParameterList = List[ProcessorParameter] +ProcessorParameterList = list[ProcessorParameter] class Processor(TypedDict, total=False): Type: ProcessorType - Parameters: Optional[ProcessorParameterList] + Parameters: ProcessorParameterList | None -ProcessorList = List[Processor] +ProcessorList = list[Processor] class ProcessingConfiguration(TypedDict, total=False): - Enabled: Optional[BooleanObject] - Processors: Optional[ProcessorList] + Enabled: BooleanObject | None + Processors: ProcessorList | None class KMSEncryptionConfig(TypedDict, total=False): @@ -417,41 +417,41 @@ class KMSEncryptionConfig(TypedDict, total=False): class EncryptionConfiguration(TypedDict, total=False): - NoEncryptionConfig: Optional[NoEncryptionConfig] - KMSEncryptionConfig: Optional[KMSEncryptionConfig] + NoEncryptionConfig: NoEncryptionConfig | None + KMSEncryptionConfig: KMSEncryptionConfig | None class BufferingHints(TypedDict, total=False): - SizeInMBs: Optional[SizeInMBs] - IntervalInSeconds: Optional[IntervalInSeconds] + SizeInMBs: SizeInMBs | None + IntervalInSeconds: IntervalInSeconds | None class S3DestinationConfiguration(TypedDict, total=False): RoleARN: RoleARN BucketARN: BucketARN - Prefix: Optional[Prefix] - ErrorOutputPrefix: Optional[ErrorOutputPrefix] - BufferingHints: Optional[BufferingHints] - CompressionFormat: Optional[CompressionFormat] - EncryptionConfiguration: Optional[EncryptionConfiguration] - CloudWatchLoggingOptions: Optional[CloudWatchLoggingOptions] + Prefix: Prefix | None + ErrorOutputPrefix: ErrorOutputPrefix | None + BufferingHints: BufferingHints | None + CompressionFormat: CompressionFormat | None + EncryptionConfiguration: EncryptionConfiguration | None + CloudWatchLoggingOptions: CloudWatchLoggingOptions | None class AmazonOpenSearchServerlessRetryOptions(TypedDict, total=False): - DurationInSeconds: Optional[AmazonOpenSearchServerlessRetryDurationInSeconds] + DurationInSeconds: AmazonOpenSearchServerlessRetryDurationInSeconds | None class AmazonOpenSearchServerlessDestinationConfiguration(TypedDict, total=False): RoleARN: RoleARN - CollectionEndpoint: Optional[AmazonOpenSearchServerlessCollectionEndpoint] + CollectionEndpoint: AmazonOpenSearchServerlessCollectionEndpoint | None IndexName: AmazonOpenSearchServerlessIndexName - BufferingHints: Optional[AmazonOpenSearchServerlessBufferingHints] - RetryOptions: Optional[AmazonOpenSearchServerlessRetryOptions] - S3BackupMode: Optional[AmazonOpenSearchServerlessS3BackupMode] + BufferingHints: AmazonOpenSearchServerlessBufferingHints | None + RetryOptions: AmazonOpenSearchServerlessRetryOptions | None + S3BackupMode: AmazonOpenSearchServerlessS3BackupMode | None S3Configuration: S3DestinationConfiguration - ProcessingConfiguration: Optional[ProcessingConfiguration] - CloudWatchLoggingOptions: Optional[CloudWatchLoggingOptions] - VpcConfiguration: Optional[VpcConfiguration] + ProcessingConfiguration: ProcessingConfiguration | None + CloudWatchLoggingOptions: CloudWatchLoggingOptions | None + VpcConfiguration: VpcConfiguration | None class VpcConfigurationDescription(TypedDict, total=False): @@ -464,52 +464,52 @@ class VpcConfigurationDescription(TypedDict, total=False): class S3DestinationDescription(TypedDict, total=False): RoleARN: RoleARN BucketARN: BucketARN - Prefix: Optional[Prefix] - ErrorOutputPrefix: Optional[ErrorOutputPrefix] + Prefix: Prefix | None + ErrorOutputPrefix: ErrorOutputPrefix | None BufferingHints: BufferingHints CompressionFormat: CompressionFormat EncryptionConfiguration: EncryptionConfiguration - CloudWatchLoggingOptions: Optional[CloudWatchLoggingOptions] + CloudWatchLoggingOptions: CloudWatchLoggingOptions | None class AmazonOpenSearchServerlessDestinationDescription(TypedDict, total=False): - RoleARN: Optional[RoleARN] - CollectionEndpoint: Optional[AmazonOpenSearchServerlessCollectionEndpoint] - IndexName: Optional[AmazonOpenSearchServerlessIndexName] - BufferingHints: Optional[AmazonOpenSearchServerlessBufferingHints] - RetryOptions: Optional[AmazonOpenSearchServerlessRetryOptions] - S3BackupMode: Optional[AmazonOpenSearchServerlessS3BackupMode] - S3DestinationDescription: Optional[S3DestinationDescription] - ProcessingConfiguration: Optional[ProcessingConfiguration] - CloudWatchLoggingOptions: Optional[CloudWatchLoggingOptions] - VpcConfigurationDescription: Optional[VpcConfigurationDescription] + RoleARN: RoleARN | None + CollectionEndpoint: AmazonOpenSearchServerlessCollectionEndpoint | None + IndexName: AmazonOpenSearchServerlessIndexName | None + BufferingHints: AmazonOpenSearchServerlessBufferingHints | None + RetryOptions: AmazonOpenSearchServerlessRetryOptions | None + S3BackupMode: AmazonOpenSearchServerlessS3BackupMode | None + S3DestinationDescription: S3DestinationDescription | None + ProcessingConfiguration: ProcessingConfiguration | None + CloudWatchLoggingOptions: CloudWatchLoggingOptions | None + VpcConfigurationDescription: VpcConfigurationDescription | None class S3DestinationUpdate(TypedDict, total=False): - RoleARN: Optional[RoleARN] - BucketARN: Optional[BucketARN] - Prefix: Optional[Prefix] - ErrorOutputPrefix: Optional[ErrorOutputPrefix] - BufferingHints: Optional[BufferingHints] - CompressionFormat: Optional[CompressionFormat] - EncryptionConfiguration: Optional[EncryptionConfiguration] - CloudWatchLoggingOptions: Optional[CloudWatchLoggingOptions] + RoleARN: RoleARN | None + BucketARN: BucketARN | None + Prefix: Prefix | None + ErrorOutputPrefix: ErrorOutputPrefix | None + BufferingHints: BufferingHints | None + CompressionFormat: CompressionFormat | None + EncryptionConfiguration: EncryptionConfiguration | None + CloudWatchLoggingOptions: CloudWatchLoggingOptions | None class AmazonOpenSearchServerlessDestinationUpdate(TypedDict, total=False): - RoleARN: Optional[RoleARN] - CollectionEndpoint: Optional[AmazonOpenSearchServerlessCollectionEndpoint] - IndexName: Optional[AmazonOpenSearchServerlessIndexName] - BufferingHints: Optional[AmazonOpenSearchServerlessBufferingHints] - RetryOptions: Optional[AmazonOpenSearchServerlessRetryOptions] - S3Update: Optional[S3DestinationUpdate] - ProcessingConfiguration: Optional[ProcessingConfiguration] - CloudWatchLoggingOptions: Optional[CloudWatchLoggingOptions] + RoleARN: RoleARN | None + CollectionEndpoint: AmazonOpenSearchServerlessCollectionEndpoint | None + IndexName: AmazonOpenSearchServerlessIndexName | None + BufferingHints: AmazonOpenSearchServerlessBufferingHints | None + RetryOptions: AmazonOpenSearchServerlessRetryOptions | None + S3Update: S3DestinationUpdate | None + ProcessingConfiguration: ProcessingConfiguration | None + CloudWatchLoggingOptions: CloudWatchLoggingOptions | None class AmazonopensearchserviceBufferingHints(TypedDict, total=False): - IntervalInSeconds: Optional[AmazonopensearchserviceBufferingIntervalInSeconds] - SizeInMBs: Optional[AmazonopensearchserviceBufferingSizeInMBs] + IntervalInSeconds: AmazonopensearchserviceBufferingIntervalInSeconds | None + SizeInMBs: AmazonopensearchserviceBufferingSizeInMBs | None class DocumentIdOptions(TypedDict, total=False): @@ -517,56 +517,56 @@ class DocumentIdOptions(TypedDict, total=False): class AmazonopensearchserviceRetryOptions(TypedDict, total=False): - DurationInSeconds: Optional[AmazonopensearchserviceRetryDurationInSeconds] + DurationInSeconds: AmazonopensearchserviceRetryDurationInSeconds | None class AmazonopensearchserviceDestinationConfiguration(TypedDict, total=False): RoleARN: RoleARN - DomainARN: Optional[AmazonopensearchserviceDomainARN] - ClusterEndpoint: Optional[AmazonopensearchserviceClusterEndpoint] + DomainARN: AmazonopensearchserviceDomainARN | None + ClusterEndpoint: AmazonopensearchserviceClusterEndpoint | None IndexName: AmazonopensearchserviceIndexName - TypeName: Optional[AmazonopensearchserviceTypeName] - IndexRotationPeriod: Optional[AmazonopensearchserviceIndexRotationPeriod] - BufferingHints: Optional[AmazonopensearchserviceBufferingHints] - RetryOptions: Optional[AmazonopensearchserviceRetryOptions] - S3BackupMode: Optional[AmazonopensearchserviceS3BackupMode] + TypeName: AmazonopensearchserviceTypeName | None + IndexRotationPeriod: AmazonopensearchserviceIndexRotationPeriod | None + BufferingHints: AmazonopensearchserviceBufferingHints | None + RetryOptions: AmazonopensearchserviceRetryOptions | None + S3BackupMode: AmazonopensearchserviceS3BackupMode | None S3Configuration: S3DestinationConfiguration - ProcessingConfiguration: Optional[ProcessingConfiguration] - CloudWatchLoggingOptions: Optional[CloudWatchLoggingOptions] - VpcConfiguration: Optional[VpcConfiguration] - DocumentIdOptions: Optional[DocumentIdOptions] + ProcessingConfiguration: ProcessingConfiguration | None + CloudWatchLoggingOptions: CloudWatchLoggingOptions | None + VpcConfiguration: VpcConfiguration | None + DocumentIdOptions: DocumentIdOptions | None class AmazonopensearchserviceDestinationDescription(TypedDict, total=False): - RoleARN: Optional[RoleARN] - DomainARN: Optional[AmazonopensearchserviceDomainARN] - ClusterEndpoint: Optional[AmazonopensearchserviceClusterEndpoint] - IndexName: Optional[AmazonopensearchserviceIndexName] - TypeName: Optional[AmazonopensearchserviceTypeName] - IndexRotationPeriod: Optional[AmazonopensearchserviceIndexRotationPeriod] - BufferingHints: Optional[AmazonopensearchserviceBufferingHints] - RetryOptions: Optional[AmazonopensearchserviceRetryOptions] - S3BackupMode: Optional[AmazonopensearchserviceS3BackupMode] - S3DestinationDescription: Optional[S3DestinationDescription] - ProcessingConfiguration: Optional[ProcessingConfiguration] - CloudWatchLoggingOptions: Optional[CloudWatchLoggingOptions] - VpcConfigurationDescription: Optional[VpcConfigurationDescription] - DocumentIdOptions: Optional[DocumentIdOptions] + RoleARN: RoleARN | None + DomainARN: AmazonopensearchserviceDomainARN | None + ClusterEndpoint: AmazonopensearchserviceClusterEndpoint | None + IndexName: AmazonopensearchserviceIndexName | None + TypeName: AmazonopensearchserviceTypeName | None + IndexRotationPeriod: AmazonopensearchserviceIndexRotationPeriod | None + BufferingHints: AmazonopensearchserviceBufferingHints | None + RetryOptions: AmazonopensearchserviceRetryOptions | None + S3BackupMode: AmazonopensearchserviceS3BackupMode | None + S3DestinationDescription: S3DestinationDescription | None + ProcessingConfiguration: ProcessingConfiguration | None + CloudWatchLoggingOptions: CloudWatchLoggingOptions | None + VpcConfigurationDescription: VpcConfigurationDescription | None + DocumentIdOptions: DocumentIdOptions | None class AmazonopensearchserviceDestinationUpdate(TypedDict, total=False): - RoleARN: Optional[RoleARN] - DomainARN: Optional[AmazonopensearchserviceDomainARN] - ClusterEndpoint: Optional[AmazonopensearchserviceClusterEndpoint] - IndexName: Optional[AmazonopensearchserviceIndexName] - TypeName: Optional[AmazonopensearchserviceTypeName] - IndexRotationPeriod: Optional[AmazonopensearchserviceIndexRotationPeriod] - BufferingHints: Optional[AmazonopensearchserviceBufferingHints] - RetryOptions: Optional[AmazonopensearchserviceRetryOptions] - S3Update: Optional[S3DestinationUpdate] - ProcessingConfiguration: Optional[ProcessingConfiguration] - CloudWatchLoggingOptions: Optional[CloudWatchLoggingOptions] - DocumentIdOptions: Optional[DocumentIdOptions] + RoleARN: RoleARN | None + DomainARN: AmazonopensearchserviceDomainARN | None + ClusterEndpoint: AmazonopensearchserviceClusterEndpoint | None + IndexName: AmazonopensearchserviceIndexName | None + TypeName: AmazonopensearchserviceTypeName | None + IndexRotationPeriod: AmazonopensearchserviceIndexRotationPeriod | None + BufferingHints: AmazonopensearchserviceBufferingHints | None + RetryOptions: AmazonopensearchserviceRetryOptions | None + S3Update: S3DestinationUpdate | None + ProcessingConfiguration: ProcessingConfiguration | None + CloudWatchLoggingOptions: CloudWatchLoggingOptions | None + DocumentIdOptions: DocumentIdOptions | None class AuthenticationConfiguration(TypedDict, total=False): @@ -575,17 +575,17 @@ class AuthenticationConfiguration(TypedDict, total=False): class CatalogConfiguration(TypedDict, total=False): - CatalogARN: Optional[GlueDataCatalogARN] - WarehouseLocation: Optional[WarehouseLocation] + CatalogARN: GlueDataCatalogARN | None + WarehouseLocation: WarehouseLocation | None -ColumnToJsonKeyMappings = Dict[NonEmptyStringWithoutWhitespace, NonEmptyString] +ColumnToJsonKeyMappings = dict[NonEmptyStringWithoutWhitespace, NonEmptyString] class CopyCommand(TypedDict, total=False): DataTableName: DataTableName - DataTableColumns: Optional[DataTableColumns] - CopyOptions: Optional[CopyOptions] + DataTableColumns: DataTableColumns | None + CopyOptions: CopyOptions | None class DatabaseSourceVPCConfiguration(TypedDict, total=False): @@ -593,8 +593,8 @@ class DatabaseSourceVPCConfiguration(TypedDict, total=False): class SecretsManagerConfiguration(TypedDict, total=False): - SecretARN: Optional[SecretARN] - RoleARN: Optional[RoleARN] + SecretARN: SecretARN | None + RoleARN: RoleARN | None Enabled: BooleanObject @@ -602,47 +602,47 @@ class DatabaseSourceAuthenticationConfiguration(TypedDict, total=False): SecretsManagerConfiguration: SecretsManagerConfiguration -DatabaseSurrogateKeyList = List[NonEmptyStringWithoutWhitespace] -DatabaseColumnIncludeOrExcludeList = List[DatabaseColumnName] +DatabaseSurrogateKeyList = list[NonEmptyStringWithoutWhitespace] +DatabaseColumnIncludeOrExcludeList = list[DatabaseColumnName] class DatabaseColumnList(TypedDict, total=False): - Include: Optional[DatabaseColumnIncludeOrExcludeList] - Exclude: Optional[DatabaseColumnIncludeOrExcludeList] + Include: DatabaseColumnIncludeOrExcludeList | None + Exclude: DatabaseColumnIncludeOrExcludeList | None -DatabaseTableIncludeOrExcludeList = List[DatabaseTableName] +DatabaseTableIncludeOrExcludeList = list[DatabaseTableName] class DatabaseTableList(TypedDict, total=False): - Include: Optional[DatabaseTableIncludeOrExcludeList] - Exclude: Optional[DatabaseTableIncludeOrExcludeList] + Include: DatabaseTableIncludeOrExcludeList | None + Exclude: DatabaseTableIncludeOrExcludeList | None -DatabaseIncludeOrExcludeList = List[DatabaseName] +DatabaseIncludeOrExcludeList = list[DatabaseName] class DatabaseList(TypedDict, total=False): - Include: Optional[DatabaseIncludeOrExcludeList] - Exclude: Optional[DatabaseIncludeOrExcludeList] + Include: DatabaseIncludeOrExcludeList | None + Exclude: DatabaseIncludeOrExcludeList | None class DatabaseSourceConfiguration(TypedDict, total=False): Type: DatabaseType Endpoint: DatabaseEndpoint Port: DatabasePort - SSLMode: Optional[SSLMode] + SSLMode: SSLMode | None Databases: DatabaseList Tables: DatabaseTableList - Columns: Optional[DatabaseColumnList] - SurrogateKeys: Optional[DatabaseSurrogateKeyList] + Columns: DatabaseColumnList | None + SurrogateKeys: DatabaseSurrogateKeyList | None SnapshotWatermarkTable: DatabaseTableName DatabaseSourceAuthenticationConfiguration: DatabaseSourceAuthenticationConfiguration DatabaseSourceVPCConfiguration: DatabaseSourceVPCConfiguration class RetryOptions(TypedDict, total=False): - DurationInSeconds: Optional[RetryDurationInSeconds] + DurationInSeconds: RetryDurationInSeconds | None class TableCreationConfiguration(TypedDict, total=False): @@ -657,49 +657,49 @@ class PartitionField(TypedDict, total=False): SourceName: NonEmptyStringWithoutWhitespace -PartitionFields = List[PartitionField] +PartitionFields = list[PartitionField] class PartitionSpec(TypedDict, total=False): - Identity: Optional[PartitionFields] + Identity: PartitionFields | None -ListOfNonEmptyStringsWithoutWhitespace = List[NonEmptyStringWithoutWhitespace] +ListOfNonEmptyStringsWithoutWhitespace = list[NonEmptyStringWithoutWhitespace] class DestinationTableConfiguration(TypedDict, total=False): DestinationTableName: StringWithLettersDigitsUnderscoresDots DestinationDatabaseName: StringWithLettersDigitsUnderscoresDots - UniqueKeys: Optional[ListOfNonEmptyStringsWithoutWhitespace] - PartitionSpec: Optional[PartitionSpec] - S3ErrorOutputPrefix: Optional[ErrorOutputPrefix] + UniqueKeys: ListOfNonEmptyStringsWithoutWhitespace | None + PartitionSpec: PartitionSpec | None + S3ErrorOutputPrefix: ErrorOutputPrefix | None -DestinationTableConfigurationList = List[DestinationTableConfiguration] +DestinationTableConfigurationList = list[DestinationTableConfiguration] class IcebergDestinationConfiguration(TypedDict, total=False): - DestinationTableConfigurationList: Optional[DestinationTableConfigurationList] - SchemaEvolutionConfiguration: Optional[SchemaEvolutionConfiguration] - TableCreationConfiguration: Optional[TableCreationConfiguration] - BufferingHints: Optional[BufferingHints] - CloudWatchLoggingOptions: Optional[CloudWatchLoggingOptions] - ProcessingConfiguration: Optional[ProcessingConfiguration] - S3BackupMode: Optional[IcebergS3BackupMode] - RetryOptions: Optional[RetryOptions] + DestinationTableConfigurationList: DestinationTableConfigurationList | None + SchemaEvolutionConfiguration: SchemaEvolutionConfiguration | None + TableCreationConfiguration: TableCreationConfiguration | None + BufferingHints: BufferingHints | None + CloudWatchLoggingOptions: CloudWatchLoggingOptions | None + ProcessingConfiguration: ProcessingConfiguration | None + S3BackupMode: IcebergS3BackupMode | None + RetryOptions: RetryOptions | None RoleARN: RoleARN - AppendOnly: Optional[BooleanObject] + AppendOnly: BooleanObject | None CatalogConfiguration: CatalogConfiguration S3Configuration: S3DestinationConfiguration class SnowflakeBufferingHints(TypedDict, total=False): - SizeInMBs: Optional[SnowflakeBufferingSizeInMBs] - IntervalInSeconds: Optional[SnowflakeBufferingIntervalInSeconds] + SizeInMBs: SnowflakeBufferingSizeInMBs | None + IntervalInSeconds: SnowflakeBufferingIntervalInSeconds | None class SnowflakeRetryOptions(TypedDict, total=False): - DurationInSeconds: Optional[SnowflakeRetryDurationInSeconds] + DurationInSeconds: SnowflakeRetryDurationInSeconds | None class SnowflakeVpcConfiguration(TypedDict, total=False): @@ -707,31 +707,31 @@ class SnowflakeVpcConfiguration(TypedDict, total=False): class SnowflakeRoleConfiguration(TypedDict, total=False): - Enabled: Optional[BooleanObject] - SnowflakeRole: Optional[SnowflakeRole] + Enabled: BooleanObject | None + SnowflakeRole: SnowflakeRole | None class SnowflakeDestinationConfiguration(TypedDict, total=False): AccountUrl: SnowflakeAccountUrl - PrivateKey: Optional[SnowflakePrivateKey] - KeyPassphrase: Optional[SnowflakeKeyPassphrase] - User: Optional[SnowflakeUser] + PrivateKey: SnowflakePrivateKey | None + KeyPassphrase: SnowflakeKeyPassphrase | None + User: SnowflakeUser | None Database: SnowflakeDatabase Schema: SnowflakeSchema Table: SnowflakeTable - SnowflakeRoleConfiguration: Optional[SnowflakeRoleConfiguration] - DataLoadingOption: Optional[SnowflakeDataLoadingOption] - MetaDataColumnName: Optional[SnowflakeMetaDataColumnName] - ContentColumnName: Optional[SnowflakeContentColumnName] - SnowflakeVpcConfiguration: Optional[SnowflakeVpcConfiguration] - CloudWatchLoggingOptions: Optional[CloudWatchLoggingOptions] - ProcessingConfiguration: Optional[ProcessingConfiguration] + SnowflakeRoleConfiguration: SnowflakeRoleConfiguration | None + DataLoadingOption: SnowflakeDataLoadingOption | None + MetaDataColumnName: SnowflakeMetaDataColumnName | None + ContentColumnName: SnowflakeContentColumnName | None + SnowflakeVpcConfiguration: SnowflakeVpcConfiguration | None + CloudWatchLoggingOptions: CloudWatchLoggingOptions | None + ProcessingConfiguration: ProcessingConfiguration | None RoleARN: RoleARN - RetryOptions: Optional[SnowflakeRetryOptions] - S3BackupMode: Optional[SnowflakeS3BackupMode] + RetryOptions: SnowflakeRetryOptions | None + S3BackupMode: SnowflakeS3BackupMode | None S3Configuration: S3DestinationConfiguration - SecretsManagerConfiguration: Optional[SecretsManagerConfiguration] - BufferingHints: Optional[SnowflakeBufferingHints] + SecretsManagerConfiguration: SecretsManagerConfiguration | None + BufferingHints: SnowflakeBufferingHints | None ReadFromTimestamp = datetime @@ -741,19 +741,19 @@ class MSKSourceConfiguration(TypedDict, total=False): MSKClusterARN: MSKClusterARN TopicName: TopicName AuthenticationConfiguration: AuthenticationConfiguration - ReadFromTimestamp: Optional[ReadFromTimestamp] + ReadFromTimestamp: ReadFromTimestamp | None class Tag(TypedDict, total=False): Key: TagKey - Value: Optional[TagValue] + Value: TagValue | None -TagDeliveryStreamInputTagList = List[Tag] +TagDeliveryStreamInputTagList = list[Tag] class HttpEndpointRetryOptions(TypedDict, total=False): - DurationInSeconds: Optional[HttpEndpointRetryDurationInSeconds] + DurationInSeconds: HttpEndpointRetryDurationInSeconds | None class HttpEndpointCommonAttribute(TypedDict, total=False): @@ -761,200 +761,200 @@ class HttpEndpointCommonAttribute(TypedDict, total=False): AttributeValue: HttpEndpointAttributeValue -HttpEndpointCommonAttributesList = List[HttpEndpointCommonAttribute] +HttpEndpointCommonAttributesList = list[HttpEndpointCommonAttribute] class HttpEndpointRequestConfiguration(TypedDict, total=False): - ContentEncoding: Optional[ContentEncoding] - CommonAttributes: Optional[HttpEndpointCommonAttributesList] + ContentEncoding: ContentEncoding | None + CommonAttributes: HttpEndpointCommonAttributesList | None class HttpEndpointBufferingHints(TypedDict, total=False): - SizeInMBs: Optional[HttpEndpointBufferingSizeInMBs] - IntervalInSeconds: Optional[HttpEndpointBufferingIntervalInSeconds] + SizeInMBs: HttpEndpointBufferingSizeInMBs | None + IntervalInSeconds: HttpEndpointBufferingIntervalInSeconds | None class HttpEndpointConfiguration(TypedDict, total=False): Url: HttpEndpointUrl - Name: Optional[HttpEndpointName] - AccessKey: Optional[HttpEndpointAccessKey] + Name: HttpEndpointName | None + AccessKey: HttpEndpointAccessKey | None class HttpEndpointDestinationConfiguration(TypedDict, total=False): EndpointConfiguration: HttpEndpointConfiguration - BufferingHints: Optional[HttpEndpointBufferingHints] - CloudWatchLoggingOptions: Optional[CloudWatchLoggingOptions] - RequestConfiguration: Optional[HttpEndpointRequestConfiguration] - ProcessingConfiguration: Optional[ProcessingConfiguration] - RoleARN: Optional[RoleARN] - RetryOptions: Optional[HttpEndpointRetryOptions] - S3BackupMode: Optional[HttpEndpointS3BackupMode] + BufferingHints: HttpEndpointBufferingHints | None + CloudWatchLoggingOptions: CloudWatchLoggingOptions | None + RequestConfiguration: HttpEndpointRequestConfiguration | None + ProcessingConfiguration: ProcessingConfiguration | None + RoleARN: RoleARN | None + RetryOptions: HttpEndpointRetryOptions | None + S3BackupMode: HttpEndpointS3BackupMode | None S3Configuration: S3DestinationConfiguration - SecretsManagerConfiguration: Optional[SecretsManagerConfiguration] + SecretsManagerConfiguration: SecretsManagerConfiguration | None class SplunkBufferingHints(TypedDict, total=False): - IntervalInSeconds: Optional[SplunkBufferingIntervalInSeconds] - SizeInMBs: Optional[SplunkBufferingSizeInMBs] + IntervalInSeconds: SplunkBufferingIntervalInSeconds | None + SizeInMBs: SplunkBufferingSizeInMBs | None class SplunkRetryOptions(TypedDict, total=False): - DurationInSeconds: Optional[SplunkRetryDurationInSeconds] + DurationInSeconds: SplunkRetryDurationInSeconds | None class SplunkDestinationConfiguration(TypedDict, total=False): HECEndpoint: HECEndpoint HECEndpointType: HECEndpointType - HECToken: Optional[HECToken] - HECAcknowledgmentTimeoutInSeconds: Optional[HECAcknowledgmentTimeoutInSeconds] - RetryOptions: Optional[SplunkRetryOptions] - S3BackupMode: Optional[SplunkS3BackupMode] + HECToken: HECToken | None + HECAcknowledgmentTimeoutInSeconds: HECAcknowledgmentTimeoutInSeconds | None + RetryOptions: SplunkRetryOptions | None + S3BackupMode: SplunkS3BackupMode | None S3Configuration: S3DestinationConfiguration - ProcessingConfiguration: Optional[ProcessingConfiguration] - CloudWatchLoggingOptions: Optional[CloudWatchLoggingOptions] - BufferingHints: Optional[SplunkBufferingHints] - SecretsManagerConfiguration: Optional[SecretsManagerConfiguration] + ProcessingConfiguration: ProcessingConfiguration | None + CloudWatchLoggingOptions: CloudWatchLoggingOptions | None + BufferingHints: SplunkBufferingHints | None + SecretsManagerConfiguration: SecretsManagerConfiguration | None class ElasticsearchRetryOptions(TypedDict, total=False): - DurationInSeconds: Optional[ElasticsearchRetryDurationInSeconds] + DurationInSeconds: ElasticsearchRetryDurationInSeconds | None class ElasticsearchBufferingHints(TypedDict, total=False): - IntervalInSeconds: Optional[ElasticsearchBufferingIntervalInSeconds] - SizeInMBs: Optional[ElasticsearchBufferingSizeInMBs] + IntervalInSeconds: ElasticsearchBufferingIntervalInSeconds | None + SizeInMBs: ElasticsearchBufferingSizeInMBs | None class ElasticsearchDestinationConfiguration(TypedDict, total=False): RoleARN: RoleARN - DomainARN: Optional[ElasticsearchDomainARN] - ClusterEndpoint: Optional[ElasticsearchClusterEndpoint] + DomainARN: ElasticsearchDomainARN | None + ClusterEndpoint: ElasticsearchClusterEndpoint | None IndexName: ElasticsearchIndexName - TypeName: Optional[ElasticsearchTypeName] - IndexRotationPeriod: Optional[ElasticsearchIndexRotationPeriod] - BufferingHints: Optional[ElasticsearchBufferingHints] - RetryOptions: Optional[ElasticsearchRetryOptions] - S3BackupMode: Optional[ElasticsearchS3BackupMode] + TypeName: ElasticsearchTypeName | None + IndexRotationPeriod: ElasticsearchIndexRotationPeriod | None + BufferingHints: ElasticsearchBufferingHints | None + RetryOptions: ElasticsearchRetryOptions | None + S3BackupMode: ElasticsearchS3BackupMode | None S3Configuration: S3DestinationConfiguration - ProcessingConfiguration: Optional[ProcessingConfiguration] - CloudWatchLoggingOptions: Optional[CloudWatchLoggingOptions] - VpcConfiguration: Optional[VpcConfiguration] - DocumentIdOptions: Optional[DocumentIdOptions] + ProcessingConfiguration: ProcessingConfiguration | None + CloudWatchLoggingOptions: CloudWatchLoggingOptions | None + VpcConfiguration: VpcConfiguration | None + DocumentIdOptions: DocumentIdOptions | None class RedshiftRetryOptions(TypedDict, total=False): - DurationInSeconds: Optional[RedshiftRetryDurationInSeconds] + DurationInSeconds: RedshiftRetryDurationInSeconds | None class RedshiftDestinationConfiguration(TypedDict, total=False): RoleARN: RoleARN ClusterJDBCURL: ClusterJDBCURL CopyCommand: CopyCommand - Username: Optional[Username] - Password: Optional[Password] - RetryOptions: Optional[RedshiftRetryOptions] + Username: Username | None + Password: Password | None + RetryOptions: RedshiftRetryOptions | None S3Configuration: S3DestinationConfiguration - ProcessingConfiguration: Optional[ProcessingConfiguration] - S3BackupMode: Optional[RedshiftS3BackupMode] - S3BackupConfiguration: Optional[S3DestinationConfiguration] - CloudWatchLoggingOptions: Optional[CloudWatchLoggingOptions] - SecretsManagerConfiguration: Optional[SecretsManagerConfiguration] + ProcessingConfiguration: ProcessingConfiguration | None + S3BackupMode: RedshiftS3BackupMode | None + S3BackupConfiguration: S3DestinationConfiguration | None + CloudWatchLoggingOptions: CloudWatchLoggingOptions | None + SecretsManagerConfiguration: SecretsManagerConfiguration | None class DynamicPartitioningConfiguration(TypedDict, total=False): - RetryOptions: Optional[RetryOptions] - Enabled: Optional[BooleanObject] + RetryOptions: RetryOptions | None + Enabled: BooleanObject | None class OrcSerDe(TypedDict, total=False): - StripeSizeBytes: Optional[OrcStripeSizeBytes] - BlockSizeBytes: Optional[BlockSizeBytes] - RowIndexStride: Optional[OrcRowIndexStride] - EnablePadding: Optional[BooleanObject] - PaddingTolerance: Optional[Proportion] - Compression: Optional[OrcCompression] - BloomFilterColumns: Optional[ListOfNonEmptyStringsWithoutWhitespace] - BloomFilterFalsePositiveProbability: Optional[Proportion] - DictionaryKeyThreshold: Optional[Proportion] - FormatVersion: Optional[OrcFormatVersion] + StripeSizeBytes: OrcStripeSizeBytes | None + BlockSizeBytes: BlockSizeBytes | None + RowIndexStride: OrcRowIndexStride | None + EnablePadding: BooleanObject | None + PaddingTolerance: Proportion | None + Compression: OrcCompression | None + BloomFilterColumns: ListOfNonEmptyStringsWithoutWhitespace | None + BloomFilterFalsePositiveProbability: Proportion | None + DictionaryKeyThreshold: Proportion | None + FormatVersion: OrcFormatVersion | None class ParquetSerDe(TypedDict, total=False): - BlockSizeBytes: Optional[BlockSizeBytes] - PageSizeBytes: Optional[ParquetPageSizeBytes] - Compression: Optional[ParquetCompression] - EnableDictionaryCompression: Optional[BooleanObject] - MaxPaddingBytes: Optional[NonNegativeIntegerObject] - WriterVersion: Optional[ParquetWriterVersion] + BlockSizeBytes: BlockSizeBytes | None + PageSizeBytes: ParquetPageSizeBytes | None + Compression: ParquetCompression | None + EnableDictionaryCompression: BooleanObject | None + MaxPaddingBytes: NonNegativeIntegerObject | None + WriterVersion: ParquetWriterVersion | None class Serializer(TypedDict, total=False): - ParquetSerDe: Optional[ParquetSerDe] - OrcSerDe: Optional[OrcSerDe] + ParquetSerDe: ParquetSerDe | None + OrcSerDe: OrcSerDe | None class OutputFormatConfiguration(TypedDict, total=False): - Serializer: Optional[Serializer] + Serializer: Serializer | None -ListOfNonEmptyStrings = List[NonEmptyString] +ListOfNonEmptyStrings = list[NonEmptyString] class HiveJsonSerDe(TypedDict, total=False): - TimestampFormats: Optional[ListOfNonEmptyStrings] + TimestampFormats: ListOfNonEmptyStrings | None class OpenXJsonSerDe(TypedDict, total=False): - ConvertDotsInJsonKeysToUnderscores: Optional[BooleanObject] - CaseInsensitive: Optional[BooleanObject] - ColumnToJsonKeyMappings: Optional[ColumnToJsonKeyMappings] + ConvertDotsInJsonKeysToUnderscores: BooleanObject | None + CaseInsensitive: BooleanObject | None + ColumnToJsonKeyMappings: ColumnToJsonKeyMappings | None class Deserializer(TypedDict, total=False): - OpenXJsonSerDe: Optional[OpenXJsonSerDe] - HiveJsonSerDe: Optional[HiveJsonSerDe] + OpenXJsonSerDe: OpenXJsonSerDe | None + HiveJsonSerDe: HiveJsonSerDe | None class InputFormatConfiguration(TypedDict, total=False): - Deserializer: Optional[Deserializer] + Deserializer: Deserializer | None class SchemaConfiguration(TypedDict, total=False): - RoleARN: Optional[NonEmptyStringWithoutWhitespace] - CatalogId: Optional[NonEmptyStringWithoutWhitespace] - DatabaseName: Optional[NonEmptyStringWithoutWhitespace] - TableName: Optional[NonEmptyStringWithoutWhitespace] - Region: Optional[NonEmptyStringWithoutWhitespace] - VersionId: Optional[NonEmptyStringWithoutWhitespace] + RoleARN: NonEmptyStringWithoutWhitespace | None + CatalogId: NonEmptyStringWithoutWhitespace | None + DatabaseName: NonEmptyStringWithoutWhitespace | None + TableName: NonEmptyStringWithoutWhitespace | None + Region: NonEmptyStringWithoutWhitespace | None + VersionId: NonEmptyStringWithoutWhitespace | None class DataFormatConversionConfiguration(TypedDict, total=False): - SchemaConfiguration: Optional[SchemaConfiguration] - InputFormatConfiguration: Optional[InputFormatConfiguration] - OutputFormatConfiguration: Optional[OutputFormatConfiguration] - Enabled: Optional[BooleanObject] + SchemaConfiguration: SchemaConfiguration | None + InputFormatConfiguration: InputFormatConfiguration | None + OutputFormatConfiguration: OutputFormatConfiguration | None + Enabled: BooleanObject | None class ExtendedS3DestinationConfiguration(TypedDict, total=False): RoleARN: RoleARN BucketARN: BucketARN - Prefix: Optional[Prefix] - ErrorOutputPrefix: Optional[ErrorOutputPrefix] - BufferingHints: Optional[BufferingHints] - CompressionFormat: Optional[CompressionFormat] - EncryptionConfiguration: Optional[EncryptionConfiguration] - CloudWatchLoggingOptions: Optional[CloudWatchLoggingOptions] - ProcessingConfiguration: Optional[ProcessingConfiguration] - S3BackupMode: Optional[S3BackupMode] - S3BackupConfiguration: Optional[S3DestinationConfiguration] - DataFormatConversionConfiguration: Optional[DataFormatConversionConfiguration] - DynamicPartitioningConfiguration: Optional[DynamicPartitioningConfiguration] - FileExtension: Optional[FileExtension] - CustomTimeZone: Optional[CustomTimeZone] + Prefix: Prefix | None + ErrorOutputPrefix: ErrorOutputPrefix | None + BufferingHints: BufferingHints | None + CompressionFormat: CompressionFormat | None + EncryptionConfiguration: EncryptionConfiguration | None + CloudWatchLoggingOptions: CloudWatchLoggingOptions | None + ProcessingConfiguration: ProcessingConfiguration | None + S3BackupMode: S3BackupMode | None + S3BackupConfiguration: S3DestinationConfiguration | None + DataFormatConversionConfiguration: DataFormatConversionConfiguration | None + DynamicPartitioningConfiguration: DynamicPartitioningConfiguration | None + FileExtension: FileExtension | None + CustomTimeZone: CustomTimeZone | None class DeliveryStreamEncryptionConfigurationInput(TypedDict, total=False): - KeyARN: Optional[AWSKMSKeyARN] + KeyARN: AWSKMSKeyARN | None KeyType: KeyType @@ -969,31 +969,31 @@ class DirectPutSourceConfiguration(TypedDict, total=False): class CreateDeliveryStreamInput(ServiceRequest): DeliveryStreamName: DeliveryStreamName - DeliveryStreamType: Optional[DeliveryStreamType] - DirectPutSourceConfiguration: Optional[DirectPutSourceConfiguration] - KinesisStreamSourceConfiguration: Optional[KinesisStreamSourceConfiguration] - DeliveryStreamEncryptionConfigurationInput: Optional[DeliveryStreamEncryptionConfigurationInput] - S3DestinationConfiguration: Optional[S3DestinationConfiguration] - ExtendedS3DestinationConfiguration: Optional[ExtendedS3DestinationConfiguration] - RedshiftDestinationConfiguration: Optional[RedshiftDestinationConfiguration] - ElasticsearchDestinationConfiguration: Optional[ElasticsearchDestinationConfiguration] - AmazonopensearchserviceDestinationConfiguration: Optional[ - AmazonopensearchserviceDestinationConfiguration - ] - SplunkDestinationConfiguration: Optional[SplunkDestinationConfiguration] - HttpEndpointDestinationConfiguration: Optional[HttpEndpointDestinationConfiguration] - Tags: Optional[TagDeliveryStreamInputTagList] - AmazonOpenSearchServerlessDestinationConfiguration: Optional[ - AmazonOpenSearchServerlessDestinationConfiguration - ] - MSKSourceConfiguration: Optional[MSKSourceConfiguration] - SnowflakeDestinationConfiguration: Optional[SnowflakeDestinationConfiguration] - IcebergDestinationConfiguration: Optional[IcebergDestinationConfiguration] - DatabaseSourceConfiguration: Optional[DatabaseSourceConfiguration] + DeliveryStreamType: DeliveryStreamType | None + DirectPutSourceConfiguration: DirectPutSourceConfiguration | None + KinesisStreamSourceConfiguration: KinesisStreamSourceConfiguration | None + DeliveryStreamEncryptionConfigurationInput: DeliveryStreamEncryptionConfigurationInput | None + S3DestinationConfiguration: S3DestinationConfiguration | None + ExtendedS3DestinationConfiguration: ExtendedS3DestinationConfiguration | None + RedshiftDestinationConfiguration: RedshiftDestinationConfiguration | None + ElasticsearchDestinationConfiguration: ElasticsearchDestinationConfiguration | None + AmazonopensearchserviceDestinationConfiguration: ( + AmazonopensearchserviceDestinationConfiguration | None + ) + SplunkDestinationConfiguration: SplunkDestinationConfiguration | None + HttpEndpointDestinationConfiguration: HttpEndpointDestinationConfiguration | None + Tags: TagDeliveryStreamInputTagList | None + AmazonOpenSearchServerlessDestinationConfiguration: ( + AmazonOpenSearchServerlessDestinationConfiguration | None + ) + MSKSourceConfiguration: MSKSourceConfiguration | None + SnowflakeDestinationConfiguration: SnowflakeDestinationConfiguration | None + IcebergDestinationConfiguration: IcebergDestinationConfiguration | None + DatabaseSourceConfiguration: DatabaseSourceConfiguration | None class CreateDeliveryStreamOutput(TypedDict, total=False): - DeliveryStreamARN: Optional[DeliveryStreamARN] + DeliveryStreamARN: DeliveryStreamARN | None Data = bytes @@ -1013,30 +1013,30 @@ class DatabaseSnapshotInfo(TypedDict, total=False): RequestTimestamp: Timestamp RequestedBy: SnapshotRequestedBy Status: SnapshotStatus - FailureDescription: Optional[FailureDescription] + FailureDescription: FailureDescription | None -DatabaseSnapshotInfoList = List[DatabaseSnapshotInfo] +DatabaseSnapshotInfoList = list[DatabaseSnapshotInfo] class DatabaseSourceDescription(TypedDict, total=False): - Type: Optional[DatabaseType] - Endpoint: Optional[DatabaseEndpoint] - Port: Optional[DatabasePort] - SSLMode: Optional[SSLMode] - Databases: Optional[DatabaseList] - Tables: Optional[DatabaseTableList] - Columns: Optional[DatabaseColumnList] - SurrogateKeys: Optional[DatabaseColumnIncludeOrExcludeList] - SnapshotWatermarkTable: Optional[DatabaseTableName] - SnapshotInfo: Optional[DatabaseSnapshotInfoList] - DatabaseSourceAuthenticationConfiguration: Optional[DatabaseSourceAuthenticationConfiguration] - DatabaseSourceVPCConfiguration: Optional[DatabaseSourceVPCConfiguration] + Type: DatabaseType | None + Endpoint: DatabaseEndpoint | None + Port: DatabasePort | None + SSLMode: SSLMode | None + Databases: DatabaseList | None + Tables: DatabaseTableList | None + Columns: DatabaseColumnList | None + SurrogateKeys: DatabaseColumnIncludeOrExcludeList | None + SnapshotWatermarkTable: DatabaseTableName | None + SnapshotInfo: DatabaseSnapshotInfoList | None + DatabaseSourceAuthenticationConfiguration: DatabaseSourceAuthenticationConfiguration | None + DatabaseSourceVPCConfiguration: DatabaseSourceVPCConfiguration | None class DeleteDeliveryStreamInput(ServiceRequest): DeliveryStreamName: DeliveryStreamName - AllowForceDelete: Optional[BooleanObject] + AllowForceDelete: BooleanObject | None class DeleteDeliveryStreamOutput(TypedDict, total=False): @@ -1047,197 +1047,197 @@ class DeleteDeliveryStreamOutput(TypedDict, total=False): class IcebergDestinationDescription(TypedDict, total=False): - DestinationTableConfigurationList: Optional[DestinationTableConfigurationList] - SchemaEvolutionConfiguration: Optional[SchemaEvolutionConfiguration] - TableCreationConfiguration: Optional[TableCreationConfiguration] - BufferingHints: Optional[BufferingHints] - CloudWatchLoggingOptions: Optional[CloudWatchLoggingOptions] - ProcessingConfiguration: Optional[ProcessingConfiguration] - S3BackupMode: Optional[IcebergS3BackupMode] - RetryOptions: Optional[RetryOptions] - RoleARN: Optional[RoleARN] - AppendOnly: Optional[BooleanObject] - CatalogConfiguration: Optional[CatalogConfiguration] - S3DestinationDescription: Optional[S3DestinationDescription] + DestinationTableConfigurationList: DestinationTableConfigurationList | None + SchemaEvolutionConfiguration: SchemaEvolutionConfiguration | None + TableCreationConfiguration: TableCreationConfiguration | None + BufferingHints: BufferingHints | None + CloudWatchLoggingOptions: CloudWatchLoggingOptions | None + ProcessingConfiguration: ProcessingConfiguration | None + S3BackupMode: IcebergS3BackupMode | None + RetryOptions: RetryOptions | None + RoleARN: RoleARN | None + AppendOnly: BooleanObject | None + CatalogConfiguration: CatalogConfiguration | None + S3DestinationDescription: S3DestinationDescription | None class SnowflakeDestinationDescription(TypedDict, total=False): - AccountUrl: Optional[SnowflakeAccountUrl] - User: Optional[SnowflakeUser] - Database: Optional[SnowflakeDatabase] - Schema: Optional[SnowflakeSchema] - Table: Optional[SnowflakeTable] - SnowflakeRoleConfiguration: Optional[SnowflakeRoleConfiguration] - DataLoadingOption: Optional[SnowflakeDataLoadingOption] - MetaDataColumnName: Optional[SnowflakeMetaDataColumnName] - ContentColumnName: Optional[SnowflakeContentColumnName] - SnowflakeVpcConfiguration: Optional[SnowflakeVpcConfiguration] - CloudWatchLoggingOptions: Optional[CloudWatchLoggingOptions] - ProcessingConfiguration: Optional[ProcessingConfiguration] - RoleARN: Optional[RoleARN] - RetryOptions: Optional[SnowflakeRetryOptions] - S3BackupMode: Optional[SnowflakeS3BackupMode] - S3DestinationDescription: Optional[S3DestinationDescription] - SecretsManagerConfiguration: Optional[SecretsManagerConfiguration] - BufferingHints: Optional[SnowflakeBufferingHints] + AccountUrl: SnowflakeAccountUrl | None + User: SnowflakeUser | None + Database: SnowflakeDatabase | None + Schema: SnowflakeSchema | None + Table: SnowflakeTable | None + SnowflakeRoleConfiguration: SnowflakeRoleConfiguration | None + DataLoadingOption: SnowflakeDataLoadingOption | None + MetaDataColumnName: SnowflakeMetaDataColumnName | None + ContentColumnName: SnowflakeContentColumnName | None + SnowflakeVpcConfiguration: SnowflakeVpcConfiguration | None + CloudWatchLoggingOptions: CloudWatchLoggingOptions | None + ProcessingConfiguration: ProcessingConfiguration | None + RoleARN: RoleARN | None + RetryOptions: SnowflakeRetryOptions | None + S3BackupMode: SnowflakeS3BackupMode | None + S3DestinationDescription: S3DestinationDescription | None + SecretsManagerConfiguration: SecretsManagerConfiguration | None + BufferingHints: SnowflakeBufferingHints | None class HttpEndpointDescription(TypedDict, total=False): - Url: Optional[HttpEndpointUrl] - Name: Optional[HttpEndpointName] + Url: HttpEndpointUrl | None + Name: HttpEndpointName | None class HttpEndpointDestinationDescription(TypedDict, total=False): - EndpointConfiguration: Optional[HttpEndpointDescription] - BufferingHints: Optional[HttpEndpointBufferingHints] - CloudWatchLoggingOptions: Optional[CloudWatchLoggingOptions] - RequestConfiguration: Optional[HttpEndpointRequestConfiguration] - ProcessingConfiguration: Optional[ProcessingConfiguration] - RoleARN: Optional[RoleARN] - RetryOptions: Optional[HttpEndpointRetryOptions] - S3BackupMode: Optional[HttpEndpointS3BackupMode] - S3DestinationDescription: Optional[S3DestinationDescription] - SecretsManagerConfiguration: Optional[SecretsManagerConfiguration] + EndpointConfiguration: HttpEndpointDescription | None + BufferingHints: HttpEndpointBufferingHints | None + CloudWatchLoggingOptions: CloudWatchLoggingOptions | None + RequestConfiguration: HttpEndpointRequestConfiguration | None + ProcessingConfiguration: ProcessingConfiguration | None + RoleARN: RoleARN | None + RetryOptions: HttpEndpointRetryOptions | None + S3BackupMode: HttpEndpointS3BackupMode | None + S3DestinationDescription: S3DestinationDescription | None + SecretsManagerConfiguration: SecretsManagerConfiguration | None class SplunkDestinationDescription(TypedDict, total=False): - HECEndpoint: Optional[HECEndpoint] - HECEndpointType: Optional[HECEndpointType] - HECToken: Optional[HECToken] - HECAcknowledgmentTimeoutInSeconds: Optional[HECAcknowledgmentTimeoutInSeconds] - RetryOptions: Optional[SplunkRetryOptions] - S3BackupMode: Optional[SplunkS3BackupMode] - S3DestinationDescription: Optional[S3DestinationDescription] - ProcessingConfiguration: Optional[ProcessingConfiguration] - CloudWatchLoggingOptions: Optional[CloudWatchLoggingOptions] - BufferingHints: Optional[SplunkBufferingHints] - SecretsManagerConfiguration: Optional[SecretsManagerConfiguration] + HECEndpoint: HECEndpoint | None + HECEndpointType: HECEndpointType | None + HECToken: HECToken | None + HECAcknowledgmentTimeoutInSeconds: HECAcknowledgmentTimeoutInSeconds | None + RetryOptions: SplunkRetryOptions | None + S3BackupMode: SplunkS3BackupMode | None + S3DestinationDescription: S3DestinationDescription | None + ProcessingConfiguration: ProcessingConfiguration | None + CloudWatchLoggingOptions: CloudWatchLoggingOptions | None + BufferingHints: SplunkBufferingHints | None + SecretsManagerConfiguration: SecretsManagerConfiguration | None class ElasticsearchDestinationDescription(TypedDict, total=False): - RoleARN: Optional[RoleARN] - DomainARN: Optional[ElasticsearchDomainARN] - ClusterEndpoint: Optional[ElasticsearchClusterEndpoint] - IndexName: Optional[ElasticsearchIndexName] - TypeName: Optional[ElasticsearchTypeName] - IndexRotationPeriod: Optional[ElasticsearchIndexRotationPeriod] - BufferingHints: Optional[ElasticsearchBufferingHints] - RetryOptions: Optional[ElasticsearchRetryOptions] - S3BackupMode: Optional[ElasticsearchS3BackupMode] - S3DestinationDescription: Optional[S3DestinationDescription] - ProcessingConfiguration: Optional[ProcessingConfiguration] - CloudWatchLoggingOptions: Optional[CloudWatchLoggingOptions] - VpcConfigurationDescription: Optional[VpcConfigurationDescription] - DocumentIdOptions: Optional[DocumentIdOptions] + RoleARN: RoleARN | None + DomainARN: ElasticsearchDomainARN | None + ClusterEndpoint: ElasticsearchClusterEndpoint | None + IndexName: ElasticsearchIndexName | None + TypeName: ElasticsearchTypeName | None + IndexRotationPeriod: ElasticsearchIndexRotationPeriod | None + BufferingHints: ElasticsearchBufferingHints | None + RetryOptions: ElasticsearchRetryOptions | None + S3BackupMode: ElasticsearchS3BackupMode | None + S3DestinationDescription: S3DestinationDescription | None + ProcessingConfiguration: ProcessingConfiguration | None + CloudWatchLoggingOptions: CloudWatchLoggingOptions | None + VpcConfigurationDescription: VpcConfigurationDescription | None + DocumentIdOptions: DocumentIdOptions | None class RedshiftDestinationDescription(TypedDict, total=False): RoleARN: RoleARN ClusterJDBCURL: ClusterJDBCURL CopyCommand: CopyCommand - Username: Optional[Username] - RetryOptions: Optional[RedshiftRetryOptions] + Username: Username | None + RetryOptions: RedshiftRetryOptions | None S3DestinationDescription: S3DestinationDescription - ProcessingConfiguration: Optional[ProcessingConfiguration] - S3BackupMode: Optional[RedshiftS3BackupMode] - S3BackupDescription: Optional[S3DestinationDescription] - CloudWatchLoggingOptions: Optional[CloudWatchLoggingOptions] - SecretsManagerConfiguration: Optional[SecretsManagerConfiguration] + ProcessingConfiguration: ProcessingConfiguration | None + S3BackupMode: RedshiftS3BackupMode | None + S3BackupDescription: S3DestinationDescription | None + CloudWatchLoggingOptions: CloudWatchLoggingOptions | None + SecretsManagerConfiguration: SecretsManagerConfiguration | None class ExtendedS3DestinationDescription(TypedDict, total=False): RoleARN: RoleARN BucketARN: BucketARN - Prefix: Optional[Prefix] - ErrorOutputPrefix: Optional[ErrorOutputPrefix] + Prefix: Prefix | None + ErrorOutputPrefix: ErrorOutputPrefix | None BufferingHints: BufferingHints CompressionFormat: CompressionFormat EncryptionConfiguration: EncryptionConfiguration - CloudWatchLoggingOptions: Optional[CloudWatchLoggingOptions] - ProcessingConfiguration: Optional[ProcessingConfiguration] - S3BackupMode: Optional[S3BackupMode] - S3BackupDescription: Optional[S3DestinationDescription] - DataFormatConversionConfiguration: Optional[DataFormatConversionConfiguration] - DynamicPartitioningConfiguration: Optional[DynamicPartitioningConfiguration] - FileExtension: Optional[FileExtension] - CustomTimeZone: Optional[CustomTimeZone] + CloudWatchLoggingOptions: CloudWatchLoggingOptions | None + ProcessingConfiguration: ProcessingConfiguration | None + S3BackupMode: S3BackupMode | None + S3BackupDescription: S3DestinationDescription | None + DataFormatConversionConfiguration: DataFormatConversionConfiguration | None + DynamicPartitioningConfiguration: DynamicPartitioningConfiguration | None + FileExtension: FileExtension | None + CustomTimeZone: CustomTimeZone | None class DestinationDescription(TypedDict, total=False): DestinationId: DestinationId - S3DestinationDescription: Optional[S3DestinationDescription] - ExtendedS3DestinationDescription: Optional[ExtendedS3DestinationDescription] - RedshiftDestinationDescription: Optional[RedshiftDestinationDescription] - ElasticsearchDestinationDescription: Optional[ElasticsearchDestinationDescription] - AmazonopensearchserviceDestinationDescription: Optional[ - AmazonopensearchserviceDestinationDescription - ] - SplunkDestinationDescription: Optional[SplunkDestinationDescription] - HttpEndpointDestinationDescription: Optional[HttpEndpointDestinationDescription] - SnowflakeDestinationDescription: Optional[SnowflakeDestinationDescription] - AmazonOpenSearchServerlessDestinationDescription: Optional[ - AmazonOpenSearchServerlessDestinationDescription - ] - IcebergDestinationDescription: Optional[IcebergDestinationDescription] + S3DestinationDescription: S3DestinationDescription | None + ExtendedS3DestinationDescription: ExtendedS3DestinationDescription | None + RedshiftDestinationDescription: RedshiftDestinationDescription | None + ElasticsearchDestinationDescription: ElasticsearchDestinationDescription | None + AmazonopensearchserviceDestinationDescription: ( + AmazonopensearchserviceDestinationDescription | None + ) + SplunkDestinationDescription: SplunkDestinationDescription | None + HttpEndpointDestinationDescription: HttpEndpointDestinationDescription | None + SnowflakeDestinationDescription: SnowflakeDestinationDescription | None + AmazonOpenSearchServerlessDestinationDescription: ( + AmazonOpenSearchServerlessDestinationDescription | None + ) + IcebergDestinationDescription: IcebergDestinationDescription | None -DestinationDescriptionList = List[DestinationDescription] +DestinationDescriptionList = list[DestinationDescription] class MSKSourceDescription(TypedDict, total=False): - MSKClusterARN: Optional[MSKClusterARN] - TopicName: Optional[TopicName] - AuthenticationConfiguration: Optional[AuthenticationConfiguration] - DeliveryStartTimestamp: Optional[DeliveryStartTimestamp] - ReadFromTimestamp: Optional[ReadFromTimestamp] + MSKClusterARN: MSKClusterARN | None + TopicName: TopicName | None + AuthenticationConfiguration: AuthenticationConfiguration | None + DeliveryStartTimestamp: DeliveryStartTimestamp | None + ReadFromTimestamp: ReadFromTimestamp | None class KinesisStreamSourceDescription(TypedDict, total=False): - KinesisStreamARN: Optional[KinesisStreamARN] - RoleARN: Optional[RoleARN] - DeliveryStartTimestamp: Optional[DeliveryStartTimestamp] + KinesisStreamARN: KinesisStreamARN | None + RoleARN: RoleARN | None + DeliveryStartTimestamp: DeliveryStartTimestamp | None class DirectPutSourceDescription(TypedDict, total=False): - ThroughputHintInMBs: Optional[ThroughputHintInMBs] + ThroughputHintInMBs: ThroughputHintInMBs | None class SourceDescription(TypedDict, total=False): - DirectPutSourceDescription: Optional[DirectPutSourceDescription] - KinesisStreamSourceDescription: Optional[KinesisStreamSourceDescription] - MSKSourceDescription: Optional[MSKSourceDescription] - DatabaseSourceDescription: Optional[DatabaseSourceDescription] + DirectPutSourceDescription: DirectPutSourceDescription | None + KinesisStreamSourceDescription: KinesisStreamSourceDescription | None + MSKSourceDescription: MSKSourceDescription | None + DatabaseSourceDescription: DatabaseSourceDescription | None class DeliveryStreamEncryptionConfiguration(TypedDict, total=False): - KeyARN: Optional[AWSKMSKeyARN] - KeyType: Optional[KeyType] - Status: Optional[DeliveryStreamEncryptionStatus] - FailureDescription: Optional[FailureDescription] + KeyARN: AWSKMSKeyARN | None + KeyType: KeyType | None + Status: DeliveryStreamEncryptionStatus | None + FailureDescription: FailureDescription | None class DeliveryStreamDescription(TypedDict, total=False): DeliveryStreamName: DeliveryStreamName DeliveryStreamARN: DeliveryStreamARN DeliveryStreamStatus: DeliveryStreamStatus - FailureDescription: Optional[FailureDescription] - DeliveryStreamEncryptionConfiguration: Optional[DeliveryStreamEncryptionConfiguration] + FailureDescription: FailureDescription | None + DeliveryStreamEncryptionConfiguration: DeliveryStreamEncryptionConfiguration | None DeliveryStreamType: DeliveryStreamType VersionId: DeliveryStreamVersionId - CreateTimestamp: Optional[Timestamp] - LastUpdateTimestamp: Optional[Timestamp] - Source: Optional[SourceDescription] + CreateTimestamp: Timestamp | None + LastUpdateTimestamp: Timestamp | None + Source: SourceDescription | None Destinations: DestinationDescriptionList HasMoreDestinations: BooleanObject -DeliveryStreamNameList = List[DeliveryStreamName] +DeliveryStreamNameList = list[DeliveryStreamName] class DescribeDeliveryStreamInput(ServiceRequest): DeliveryStreamName: DeliveryStreamName - Limit: Optional[DescribeDeliveryStreamInputLimit] - ExclusiveStartDestinationId: Optional[DestinationId] + Limit: DescribeDeliveryStreamInputLimit | None + ExclusiveStartDestinationId: DestinationId | None class DescribeDeliveryStreamOutput(TypedDict, total=False): @@ -1245,70 +1245,70 @@ class DescribeDeliveryStreamOutput(TypedDict, total=False): class ElasticsearchDestinationUpdate(TypedDict, total=False): - RoleARN: Optional[RoleARN] - DomainARN: Optional[ElasticsearchDomainARN] - ClusterEndpoint: Optional[ElasticsearchClusterEndpoint] - IndexName: Optional[ElasticsearchIndexName] - TypeName: Optional[ElasticsearchTypeName] - IndexRotationPeriod: Optional[ElasticsearchIndexRotationPeriod] - BufferingHints: Optional[ElasticsearchBufferingHints] - RetryOptions: Optional[ElasticsearchRetryOptions] - S3Update: Optional[S3DestinationUpdate] - ProcessingConfiguration: Optional[ProcessingConfiguration] - CloudWatchLoggingOptions: Optional[CloudWatchLoggingOptions] - DocumentIdOptions: Optional[DocumentIdOptions] + RoleARN: RoleARN | None + DomainARN: ElasticsearchDomainARN | None + ClusterEndpoint: ElasticsearchClusterEndpoint | None + IndexName: ElasticsearchIndexName | None + TypeName: ElasticsearchTypeName | None + IndexRotationPeriod: ElasticsearchIndexRotationPeriod | None + BufferingHints: ElasticsearchBufferingHints | None + RetryOptions: ElasticsearchRetryOptions | None + S3Update: S3DestinationUpdate | None + ProcessingConfiguration: ProcessingConfiguration | None + CloudWatchLoggingOptions: CloudWatchLoggingOptions | None + DocumentIdOptions: DocumentIdOptions | None class ExtendedS3DestinationUpdate(TypedDict, total=False): - RoleARN: Optional[RoleARN] - BucketARN: Optional[BucketARN] - Prefix: Optional[Prefix] - ErrorOutputPrefix: Optional[ErrorOutputPrefix] - BufferingHints: Optional[BufferingHints] - CompressionFormat: Optional[CompressionFormat] - EncryptionConfiguration: Optional[EncryptionConfiguration] - CloudWatchLoggingOptions: Optional[CloudWatchLoggingOptions] - ProcessingConfiguration: Optional[ProcessingConfiguration] - S3BackupMode: Optional[S3BackupMode] - S3BackupUpdate: Optional[S3DestinationUpdate] - DataFormatConversionConfiguration: Optional[DataFormatConversionConfiguration] - DynamicPartitioningConfiguration: Optional[DynamicPartitioningConfiguration] - FileExtension: Optional[FileExtension] - CustomTimeZone: Optional[CustomTimeZone] + RoleARN: RoleARN | None + BucketARN: BucketARN | None + Prefix: Prefix | None + ErrorOutputPrefix: ErrorOutputPrefix | None + BufferingHints: BufferingHints | None + CompressionFormat: CompressionFormat | None + EncryptionConfiguration: EncryptionConfiguration | None + CloudWatchLoggingOptions: CloudWatchLoggingOptions | None + ProcessingConfiguration: ProcessingConfiguration | None + S3BackupMode: S3BackupMode | None + S3BackupUpdate: S3DestinationUpdate | None + DataFormatConversionConfiguration: DataFormatConversionConfiguration | None + DynamicPartitioningConfiguration: DynamicPartitioningConfiguration | None + FileExtension: FileExtension | None + CustomTimeZone: CustomTimeZone | None class HttpEndpointDestinationUpdate(TypedDict, total=False): - EndpointConfiguration: Optional[HttpEndpointConfiguration] - BufferingHints: Optional[HttpEndpointBufferingHints] - CloudWatchLoggingOptions: Optional[CloudWatchLoggingOptions] - RequestConfiguration: Optional[HttpEndpointRequestConfiguration] - ProcessingConfiguration: Optional[ProcessingConfiguration] - RoleARN: Optional[RoleARN] - RetryOptions: Optional[HttpEndpointRetryOptions] - S3BackupMode: Optional[HttpEndpointS3BackupMode] - S3Update: Optional[S3DestinationUpdate] - SecretsManagerConfiguration: Optional[SecretsManagerConfiguration] + EndpointConfiguration: HttpEndpointConfiguration | None + BufferingHints: HttpEndpointBufferingHints | None + CloudWatchLoggingOptions: CloudWatchLoggingOptions | None + RequestConfiguration: HttpEndpointRequestConfiguration | None + ProcessingConfiguration: ProcessingConfiguration | None + RoleARN: RoleARN | None + RetryOptions: HttpEndpointRetryOptions | None + S3BackupMode: HttpEndpointS3BackupMode | None + S3Update: S3DestinationUpdate | None + SecretsManagerConfiguration: SecretsManagerConfiguration | None class IcebergDestinationUpdate(TypedDict, total=False): - DestinationTableConfigurationList: Optional[DestinationTableConfigurationList] - SchemaEvolutionConfiguration: Optional[SchemaEvolutionConfiguration] - TableCreationConfiguration: Optional[TableCreationConfiguration] - BufferingHints: Optional[BufferingHints] - CloudWatchLoggingOptions: Optional[CloudWatchLoggingOptions] - ProcessingConfiguration: Optional[ProcessingConfiguration] - S3BackupMode: Optional[IcebergS3BackupMode] - RetryOptions: Optional[RetryOptions] - RoleARN: Optional[RoleARN] - AppendOnly: Optional[BooleanObject] - CatalogConfiguration: Optional[CatalogConfiguration] - S3Configuration: Optional[S3DestinationConfiguration] + DestinationTableConfigurationList: DestinationTableConfigurationList | None + SchemaEvolutionConfiguration: SchemaEvolutionConfiguration | None + TableCreationConfiguration: TableCreationConfiguration | None + BufferingHints: BufferingHints | None + CloudWatchLoggingOptions: CloudWatchLoggingOptions | None + ProcessingConfiguration: ProcessingConfiguration | None + S3BackupMode: IcebergS3BackupMode | None + RetryOptions: RetryOptions | None + RoleARN: RoleARN | None + AppendOnly: BooleanObject | None + CatalogConfiguration: CatalogConfiguration | None + S3Configuration: S3DestinationConfiguration | None class ListDeliveryStreamsInput(ServiceRequest): - Limit: Optional[ListDeliveryStreamsInputLimit] - DeliveryStreamType: Optional[DeliveryStreamType] - ExclusiveStartDeliveryStreamName: Optional[DeliveryStreamName] + Limit: ListDeliveryStreamsInputLimit | None + DeliveryStreamType: DeliveryStreamType | None + ExclusiveStartDeliveryStreamName: DeliveryStreamName | None class ListDeliveryStreamsOutput(TypedDict, total=False): @@ -1318,11 +1318,11 @@ class ListDeliveryStreamsOutput(TypedDict, total=False): class ListTagsForDeliveryStreamInput(ServiceRequest): DeliveryStreamName: DeliveryStreamName - ExclusiveStartTagKey: Optional[TagKey] - Limit: Optional[ListTagsForDeliveryStreamInputLimit] + ExclusiveStartTagKey: TagKey | None + Limit: ListTagsForDeliveryStreamInputLimit | None -ListTagsForDeliveryStreamOutputTagList = List[Tag] +ListTagsForDeliveryStreamOutputTagList = list[Tag] class ListTagsForDeliveryStreamOutput(TypedDict, total=False): @@ -1334,7 +1334,7 @@ class Record(TypedDict, total=False): Data: Data -PutRecordBatchRequestEntryList = List[Record] +PutRecordBatchRequestEntryList = list[Record] class PutRecordBatchInput(ServiceRequest): @@ -1343,17 +1343,17 @@ class PutRecordBatchInput(ServiceRequest): class PutRecordBatchResponseEntry(TypedDict, total=False): - RecordId: Optional[PutResponseRecordId] - ErrorCode: Optional[ErrorCode] - ErrorMessage: Optional[ErrorMessage] + RecordId: PutResponseRecordId | None + ErrorCode: ErrorCode | None + ErrorMessage: ErrorMessage | None -PutRecordBatchResponseEntryList = List[PutRecordBatchResponseEntry] +PutRecordBatchResponseEntryList = list[PutRecordBatchResponseEntry] class PutRecordBatchOutput(TypedDict, total=False): FailedPutCount: NonNegativeIntegerObject - Encrypted: Optional[BooleanObject] + Encrypted: BooleanObject | None RequestResponses: PutRecordBatchResponseEntryList @@ -1364,63 +1364,63 @@ class PutRecordInput(ServiceRequest): class PutRecordOutput(TypedDict, total=False): RecordId: PutResponseRecordId - Encrypted: Optional[BooleanObject] + Encrypted: BooleanObject | None class RedshiftDestinationUpdate(TypedDict, total=False): - RoleARN: Optional[RoleARN] - ClusterJDBCURL: Optional[ClusterJDBCURL] - CopyCommand: Optional[CopyCommand] - Username: Optional[Username] - Password: Optional[Password] - RetryOptions: Optional[RedshiftRetryOptions] - S3Update: Optional[S3DestinationUpdate] - ProcessingConfiguration: Optional[ProcessingConfiguration] - S3BackupMode: Optional[RedshiftS3BackupMode] - S3BackupUpdate: Optional[S3DestinationUpdate] - CloudWatchLoggingOptions: Optional[CloudWatchLoggingOptions] - SecretsManagerConfiguration: Optional[SecretsManagerConfiguration] + RoleARN: RoleARN | None + ClusterJDBCURL: ClusterJDBCURL | None + CopyCommand: CopyCommand | None + Username: Username | None + Password: Password | None + RetryOptions: RedshiftRetryOptions | None + S3Update: S3DestinationUpdate | None + ProcessingConfiguration: ProcessingConfiguration | None + S3BackupMode: RedshiftS3BackupMode | None + S3BackupUpdate: S3DestinationUpdate | None + CloudWatchLoggingOptions: CloudWatchLoggingOptions | None + SecretsManagerConfiguration: SecretsManagerConfiguration | None class SnowflakeDestinationUpdate(TypedDict, total=False): - AccountUrl: Optional[SnowflakeAccountUrl] - PrivateKey: Optional[SnowflakePrivateKey] - KeyPassphrase: Optional[SnowflakeKeyPassphrase] - User: Optional[SnowflakeUser] - Database: Optional[SnowflakeDatabase] - Schema: Optional[SnowflakeSchema] - Table: Optional[SnowflakeTable] - SnowflakeRoleConfiguration: Optional[SnowflakeRoleConfiguration] - DataLoadingOption: Optional[SnowflakeDataLoadingOption] - MetaDataColumnName: Optional[SnowflakeMetaDataColumnName] - ContentColumnName: Optional[SnowflakeContentColumnName] - CloudWatchLoggingOptions: Optional[CloudWatchLoggingOptions] - ProcessingConfiguration: Optional[ProcessingConfiguration] - RoleARN: Optional[RoleARN] - RetryOptions: Optional[SnowflakeRetryOptions] - S3BackupMode: Optional[SnowflakeS3BackupMode] - S3Update: Optional[S3DestinationUpdate] - SecretsManagerConfiguration: Optional[SecretsManagerConfiguration] - BufferingHints: Optional[SnowflakeBufferingHints] + AccountUrl: SnowflakeAccountUrl | None + PrivateKey: SnowflakePrivateKey | None + KeyPassphrase: SnowflakeKeyPassphrase | None + User: SnowflakeUser | None + Database: SnowflakeDatabase | None + Schema: SnowflakeSchema | None + Table: SnowflakeTable | None + SnowflakeRoleConfiguration: SnowflakeRoleConfiguration | None + DataLoadingOption: SnowflakeDataLoadingOption | None + MetaDataColumnName: SnowflakeMetaDataColumnName | None + ContentColumnName: SnowflakeContentColumnName | None + CloudWatchLoggingOptions: CloudWatchLoggingOptions | None + ProcessingConfiguration: ProcessingConfiguration | None + RoleARN: RoleARN | None + RetryOptions: SnowflakeRetryOptions | None + S3BackupMode: SnowflakeS3BackupMode | None + S3Update: S3DestinationUpdate | None + SecretsManagerConfiguration: SecretsManagerConfiguration | None + BufferingHints: SnowflakeBufferingHints | None class SplunkDestinationUpdate(TypedDict, total=False): - HECEndpoint: Optional[HECEndpoint] - HECEndpointType: Optional[HECEndpointType] - HECToken: Optional[HECToken] - HECAcknowledgmentTimeoutInSeconds: Optional[HECAcknowledgmentTimeoutInSeconds] - RetryOptions: Optional[SplunkRetryOptions] - S3BackupMode: Optional[SplunkS3BackupMode] - S3Update: Optional[S3DestinationUpdate] - ProcessingConfiguration: Optional[ProcessingConfiguration] - CloudWatchLoggingOptions: Optional[CloudWatchLoggingOptions] - BufferingHints: Optional[SplunkBufferingHints] - SecretsManagerConfiguration: Optional[SecretsManagerConfiguration] + HECEndpoint: HECEndpoint | None + HECEndpointType: HECEndpointType | None + HECToken: HECToken | None + HECAcknowledgmentTimeoutInSeconds: HECAcknowledgmentTimeoutInSeconds | None + RetryOptions: SplunkRetryOptions | None + S3BackupMode: SplunkS3BackupMode | None + S3Update: S3DestinationUpdate | None + ProcessingConfiguration: ProcessingConfiguration | None + CloudWatchLoggingOptions: CloudWatchLoggingOptions | None + BufferingHints: SplunkBufferingHints | None + SecretsManagerConfiguration: SecretsManagerConfiguration | None class StartDeliveryStreamEncryptionInput(ServiceRequest): DeliveryStreamName: DeliveryStreamName - DeliveryStreamEncryptionConfigurationInput: Optional[DeliveryStreamEncryptionConfigurationInput] + DeliveryStreamEncryptionConfigurationInput: DeliveryStreamEncryptionConfigurationInput | None class StartDeliveryStreamEncryptionOutput(TypedDict, total=False): @@ -1444,7 +1444,7 @@ class TagDeliveryStreamOutput(TypedDict, total=False): pass -TagKeyList = List[TagKey] +TagKeyList = list[TagKey] class UntagDeliveryStreamInput(ServiceRequest): @@ -1460,18 +1460,16 @@ class UpdateDestinationInput(ServiceRequest): DeliveryStreamName: DeliveryStreamName CurrentDeliveryStreamVersionId: DeliveryStreamVersionId DestinationId: DestinationId - S3DestinationUpdate: Optional[S3DestinationUpdate] - ExtendedS3DestinationUpdate: Optional[ExtendedS3DestinationUpdate] - RedshiftDestinationUpdate: Optional[RedshiftDestinationUpdate] - ElasticsearchDestinationUpdate: Optional[ElasticsearchDestinationUpdate] - AmazonopensearchserviceDestinationUpdate: Optional[AmazonopensearchserviceDestinationUpdate] - SplunkDestinationUpdate: Optional[SplunkDestinationUpdate] - HttpEndpointDestinationUpdate: Optional[HttpEndpointDestinationUpdate] - AmazonOpenSearchServerlessDestinationUpdate: Optional[ - AmazonOpenSearchServerlessDestinationUpdate - ] - SnowflakeDestinationUpdate: Optional[SnowflakeDestinationUpdate] - IcebergDestinationUpdate: Optional[IcebergDestinationUpdate] + S3DestinationUpdate: S3DestinationUpdate | None + ExtendedS3DestinationUpdate: ExtendedS3DestinationUpdate | None + RedshiftDestinationUpdate: RedshiftDestinationUpdate | None + ElasticsearchDestinationUpdate: ElasticsearchDestinationUpdate | None + AmazonopensearchserviceDestinationUpdate: AmazonopensearchserviceDestinationUpdate | None + SplunkDestinationUpdate: SplunkDestinationUpdate | None + HttpEndpointDestinationUpdate: HttpEndpointDestinationUpdate | None + AmazonOpenSearchServerlessDestinationUpdate: AmazonOpenSearchServerlessDestinationUpdate | None + SnowflakeDestinationUpdate: SnowflakeDestinationUpdate | None + IcebergDestinationUpdate: IcebergDestinationUpdate | None class UpdateDestinationOutput(TypedDict, total=False): @@ -1479,8 +1477,8 @@ class UpdateDestinationOutput(TypedDict, total=False): class FirehoseApi: - service = "firehose" - version = "2015-08-04" + service: str = "firehose" + version: str = "2015-08-04" @handler("CreateDeliveryStream") def create_delivery_stream( diff --git a/localstack-core/localstack/aws/api/iam/__init__.py b/localstack-core/localstack/aws/api/iam/__init__.py index 6967249f66bf8..cb76197128008 100644 --- a/localstack-core/localstack/aws/api/iam/__init__.py +++ b/localstack-core/localstack/aws/api/iam/__init__.py @@ -1,6 +1,6 @@ from datetime import datetime from enum import StrEnum -from typing import Dict, List, Optional, TypedDict +from typing import TypedDict from localstack.aws.api import RequestContext, ServiceException, ServiceRequest, handler @@ -13,6 +13,8 @@ ContextKeyValueType = str DeletionTaskIdType = str EvalDecisionSourceType = str +FeatureDisabledMessage = str +FeatureEnabledMessage = str LineNumber = int OpenIDConnectProviderUrlType = str OrganizationIdType = str @@ -27,6 +29,7 @@ accessKeyIdType = str accessKeySecretType = str accountAliasType = str +accountIdType = str allUsers = bool arnType = str attachmentCountType = int @@ -37,11 +40,14 @@ certificateChainType = str certificateIdType = str clientIDType = str +consoleDeepLinkType = str credentialAgeDays = int credentialReportExpiredExceptionMessage = str credentialReportNotPresentExceptionMessage = str credentialReportNotReadyExceptionMessage = str customSuffixType = str +delegationRequestDescriptionType = str +delegationRequestIdType = str deleteConflictMessage = str duplicateCertificateMessage = str duplicateSSHPublicKeyMessage = str @@ -61,6 +67,7 @@ jobIDType = str keyPairMismatchMessage = str limitExceededMessage = str +localeType = str malformedCertificateMessage = str malformedPolicyDocumentMessage = str markerType = str @@ -68,19 +75,25 @@ maxPasswordAgeType = int minimumPasswordLengthType = int noSuchEntityMessage = str +notesType = str +notificationChannelType = str openIdIdpCommunicationErrorExceptionMessage = str organizationsEntityPathType = str organizationsPolicyIdType = str +ownerIdType = str passwordPolicyViolationMessage = str passwordReusePreventionType = int passwordType = str pathPrefixType = str pathType = str +permissionType = str policyDescriptionType = str policyDocumentType = str policyEvaluationErrorMessage = str policyNameType = str policyNotAttachableMessage = str +policyParameterNameType = str +policyParameterValueType = str policyPathType = str policyVersionIdType = str privateKeyIdType = str @@ -88,7 +101,11 @@ publicKeyFingerprintType = str publicKeyIdType = str publicKeyMaterialType = str +redirectUrlType = str reportGenerationLimitExceededMessage = str +requestMessageType = str +requestorNameType = str +requestorWorkflowIdType = str responseMarkerType = str roleDescriptionType = str roleMaxSessionDurationType = int @@ -105,7 +122,9 @@ servicePassword = str serviceSpecificCredentialId = str serviceUserName = str +sessionDurationType = int stringType = str +summaryContentType = str summaryValueType = int tagKeyType = str tagValueType = str @@ -166,6 +185,11 @@ class PolicyEvaluationDecisionType(StrEnum): implicitDeny = "implicitDeny" +class PolicyParameterTypeEnum(StrEnum): + string = "string" + stringList = "stringList" + + class PolicySourceType(StrEnum): user = "user" group = "group" @@ -218,6 +242,18 @@ class jobStatusType(StrEnum): FAILED = "FAILED" +class permissionCheckResultType(StrEnum): + ALLOWED = "ALLOWED" + DENIED = "DENIED" + UNSURE = "UNSURE" + + +class permissionCheckStatusType(StrEnum): + COMPLETE = "COMPLETE" + IN_PROGRESS = "IN_PROGRESS" + FAILED = "FAILED" + + class policyOwnerEntityType(StrEnum): USER = "USER" ROLE = "ROLE" @@ -242,6 +278,16 @@ class sortKeyType(StrEnum): LAST_AUTHENTICATED_TIME_DESCENDING = "LAST_AUTHENTICATED_TIME_DESCENDING" +class stateType(StrEnum): + UNASSIGNED = "UNASSIGNED" + ASSIGNED = "ASSIGNED" + PENDING_APPROVAL = "PENDING_APPROVAL" + FINALIZED = "FINALIZED" + ACCEPTED = "ACCEPTED" + REJECTED = "REJECTED" + EXPIRED = "EXPIRED" + + class statusType(StrEnum): Active = "Active" Inactive = "Inactive" @@ -276,6 +322,20 @@ class summaryKeyType(StrEnum): PolicyVersionsInUseQuota = "PolicyVersionsInUseQuota" VersionsPerPolicyQuota = "VersionsPerPolicyQuota" GlobalEndpointTokenVersion = "GlobalEndpointTokenVersion" + AssumeRolePolicySizeQuota = "AssumeRolePolicySizeQuota" + InstanceProfiles = "InstanceProfiles" + InstanceProfilesQuota = "InstanceProfilesQuota" + Providers = "Providers" + RolePolicySizeQuota = "RolePolicySizeQuota" + Roles = "Roles" + RolesQuota = "RolesQuota" + + +class summaryStateType(StrEnum): + AVAILABLE = "AVAILABLE" + NOT_AVAILABLE = "NOT_AVAILABLE" + NOT_SUPPORTED = "NOT_SUPPORTED" + FAILED = "FAILED" class AccountNotManagementOrDelegatedAdministratorException(ServiceException): @@ -344,6 +404,18 @@ class EntityTemporarilyUnmodifiableException(ServiceException): status_code: int = 409 +class FeatureDisabledException(ServiceException): + code: str = "FeatureDisabled" + sender_fault: bool = True + status_code: int = 404 + + +class FeatureEnabledException(ServiceException): + code: str = "FeatureEnabled" + sender_fault: bool = True + status_code: int = 409 + + class InvalidAuthenticationCodeException(ServiceException): code: str = "InvalidAuthenticationCode" sender_fault: bool = True @@ -476,19 +548,23 @@ class UnrecognizedPublicKeyEncodingException(ServiceException): status_code: int = 400 +class AcceptDelegationRequestRequest(ServiceRequest): + DelegationRequestId: delegationRequestIdType + + dateType = datetime class AccessDetail(TypedDict, total=False): ServiceName: serviceNameType ServiceNamespace: serviceNamespaceType - Region: Optional[stringType] - EntityPath: Optional[organizationsEntityPathType] - LastAuthenticatedTime: Optional[dateType] - TotalAuthenticatedEntities: Optional[integerType] + Region: stringType | None + EntityPath: organizationsEntityPathType | None + LastAuthenticatedTime: dateType | None + TotalAuthenticatedEntities: integerType | None -AccessDetails = List[AccessDetail] +AccessDetails = list[AccessDetail] class AccessKey(TypedDict, total=False): @@ -496,23 +572,23 @@ class AccessKey(TypedDict, total=False): AccessKeyId: accessKeyIdType Status: statusType SecretAccessKey: accessKeySecretType - CreateDate: Optional[dateType] + CreateDate: dateType | None class AccessKeyLastUsed(TypedDict, total=False): - LastUsedDate: Optional[dateType] + LastUsedDate: dateType | None ServiceName: stringType Region: stringType class AccessKeyMetadata(TypedDict, total=False): - UserName: Optional[userNameType] - AccessKeyId: Optional[accessKeyIdType] - Status: Optional[statusType] - CreateDate: Optional[dateType] + UserName: userNameType | None + AccessKeyId: accessKeyIdType | None + Status: statusType | None + CreateDate: dateType | None -ActionNameListType = List[ActionNameType] +ActionNameListType = list[ActionNameType] class AddClientIDToOpenIDConnectProviderRequest(ServiceRequest): @@ -530,7 +606,11 @@ class AddUserToGroupRequest(ServiceRequest): UserName: existingUserNameType -ArnListType = List[arnType] +ArnListType = list[arnType] + + +class AssociateDelegationRequestRequest(ServiceRequest): + DelegationRequestId: delegationRequestIdType class AttachGroupPolicyRequest(ServiceRequest): @@ -549,17 +629,17 @@ class AttachUserPolicyRequest(ServiceRequest): class AttachedPermissionsBoundary(TypedDict, total=False): - PermissionsBoundaryType: Optional[PermissionsBoundaryAttachmentType] - PermissionsBoundaryArn: Optional[arnType] + PermissionsBoundaryType: PermissionsBoundaryAttachmentType | None + PermissionsBoundaryArn: arnType | None class AttachedPolicy(TypedDict, total=False): - PolicyName: Optional[policyNameType] - PolicyArn: Optional[arnType] + PolicyName: policyNameType | None + PolicyArn: arnType | None BootstrapDatum = bytes -CertificationMapType = Dict[CertificationKeyType, CertificationValueType] +CertificationMapType = dict[CertificationKeyType, CertificationValueType] class ChangePasswordRequest(ServiceRequest): @@ -567,21 +647,21 @@ class ChangePasswordRequest(ServiceRequest): NewPassword: passwordType -ContextKeyValueListType = List[ContextKeyValueType] +ContextKeyValueListType = list[ContextKeyValueType] class ContextEntry(TypedDict, total=False): - ContextKeyName: Optional[ContextKeyNameType] - ContextKeyValues: Optional[ContextKeyValueListType] - ContextKeyType: Optional[ContextKeyTypeEnum] + ContextKeyName: ContextKeyNameType | None + ContextKeyValues: ContextKeyValueListType | None + ContextKeyType: ContextKeyTypeEnum | None -ContextEntryListType = List[ContextEntry] -ContextKeyNamesResultListType = List[ContextKeyNameType] +ContextEntryListType = list[ContextEntry] +ContextKeyNamesResultListType = list[ContextKeyNameType] class CreateAccessKeyRequest(ServiceRequest): - UserName: Optional[existingUserNameType] + UserName: existingUserNameType | None class CreateAccessKeyResponse(TypedDict, total=False): @@ -592,8 +672,42 @@ class CreateAccountAliasRequest(ServiceRequest): AccountAlias: accountAliasType +policyParameterValuesListType = list[policyParameterValueType] + + +class PolicyParameter(TypedDict, total=False): + Name: policyParameterNameType | None + Values: policyParameterValuesListType | None + Type: PolicyParameterTypeEnum | None + + +policyParameterListType = list[PolicyParameter] + + +class DelegationPermission(TypedDict, total=False): + PolicyTemplateArn: arnType | None + Parameters: policyParameterListType | None + + +class CreateDelegationRequestRequest(ServiceRequest): + OwnerAccountId: accountIdType | None + Description: delegationRequestDescriptionType + Permissions: DelegationPermission + RequestMessage: requestMessageType | None + RequestorWorkflowId: requestorWorkflowIdType + RedirectUrl: redirectUrlType | None + NotificationChannel: notificationChannelType + SessionDuration: sessionDurationType + OnlySendByOwner: booleanType | None + + +class CreateDelegationRequestResponse(TypedDict, total=False): + ConsoleDeepLink: consoleDeepLinkType | None + DelegationRequestId: delegationRequestIdType | None + + class CreateGroupRequest(ServiceRequest): - Path: Optional[pathType] + Path: pathType | None GroupName: groupNameType @@ -614,18 +728,18 @@ class Tag(TypedDict, total=False): Value: tagValueType -tagListType = List[Tag] +tagListType = list[Tag] class CreateInstanceProfileRequest(ServiceRequest): InstanceProfileName: instanceProfileNameType - Path: Optional[pathType] - Tags: Optional[tagListType] + Path: pathType | None + Tags: tagListType | None class RoleLastUsed(TypedDict, total=False): - LastUsedDate: Optional[dateType] - Region: Optional[stringType] + LastUsedDate: dateType | None + Region: stringType | None class Role(TypedDict, total=False): @@ -634,15 +748,15 @@ class Role(TypedDict, total=False): RoleId: idType Arn: arnType CreateDate: dateType - AssumeRolePolicyDocument: Optional[policyDocumentType] - Description: Optional[roleDescriptionType] - MaxSessionDuration: Optional[roleMaxSessionDurationType] - PermissionsBoundary: Optional[AttachedPermissionsBoundary] - Tags: Optional[tagListType] - RoleLastUsed: Optional[RoleLastUsed] + AssumeRolePolicyDocument: policyDocumentType | None + Description: roleDescriptionType | None + MaxSessionDuration: roleMaxSessionDurationType | None + PermissionsBoundary: AttachedPermissionsBoundary | None + Tags: tagListType | None + RoleLastUsed: RoleLastUsed | None -roleListType = List[Role] +roleListType = list[Role] class InstanceProfile(TypedDict, total=False): @@ -652,7 +766,7 @@ class InstanceProfile(TypedDict, total=False): Arn: arnType CreateDate: dateType Roles: roleListType - Tags: Optional[tagListType] + Tags: tagListType | None class CreateInstanceProfileResponse(TypedDict, total=False): @@ -660,89 +774,89 @@ class CreateInstanceProfileResponse(TypedDict, total=False): class CreateLoginProfileRequest(ServiceRequest): - UserName: Optional[userNameType] - Password: Optional[passwordType] - PasswordResetRequired: Optional[booleanType] + UserName: userNameType | None + Password: passwordType | None + PasswordResetRequired: booleanType | None class LoginProfile(TypedDict, total=False): UserName: userNameType CreateDate: dateType - PasswordResetRequired: Optional[booleanType] + PasswordResetRequired: booleanType | None class CreateLoginProfileResponse(TypedDict, total=False): LoginProfile: LoginProfile -thumbprintListType = List[thumbprintType] -clientIDListType = List[clientIDType] +thumbprintListType = list[thumbprintType] +clientIDListType = list[clientIDType] class CreateOpenIDConnectProviderRequest(ServiceRequest): Url: OpenIDConnectProviderUrlType - ClientIDList: Optional[clientIDListType] - ThumbprintList: Optional[thumbprintListType] - Tags: Optional[tagListType] + ClientIDList: clientIDListType | None + ThumbprintList: thumbprintListType | None + Tags: tagListType | None class CreateOpenIDConnectProviderResponse(TypedDict, total=False): - OpenIDConnectProviderArn: Optional[arnType] - Tags: Optional[tagListType] + OpenIDConnectProviderArn: arnType | None + Tags: tagListType | None class CreatePolicyRequest(ServiceRequest): PolicyName: policyNameType - Path: Optional[policyPathType] + Path: policyPathType | None PolicyDocument: policyDocumentType - Description: Optional[policyDescriptionType] - Tags: Optional[tagListType] + Description: policyDescriptionType | None + Tags: tagListType | None class Policy(TypedDict, total=False): - PolicyName: Optional[policyNameType] - PolicyId: Optional[idType] - Arn: Optional[arnType] - Path: Optional[policyPathType] - DefaultVersionId: Optional[policyVersionIdType] - AttachmentCount: Optional[attachmentCountType] - PermissionsBoundaryUsageCount: Optional[attachmentCountType] - IsAttachable: Optional[booleanType] - Description: Optional[policyDescriptionType] - CreateDate: Optional[dateType] - UpdateDate: Optional[dateType] - Tags: Optional[tagListType] + PolicyName: policyNameType | None + PolicyId: idType | None + Arn: arnType | None + Path: policyPathType | None + DefaultVersionId: policyVersionIdType | None + AttachmentCount: attachmentCountType | None + PermissionsBoundaryUsageCount: attachmentCountType | None + IsAttachable: booleanType | None + Description: policyDescriptionType | None + CreateDate: dateType | None + UpdateDate: dateType | None + Tags: tagListType | None class CreatePolicyResponse(TypedDict, total=False): - Policy: Optional[Policy] + Policy: Policy | None class CreatePolicyVersionRequest(ServiceRequest): PolicyArn: arnType PolicyDocument: policyDocumentType - SetAsDefault: Optional[booleanType] + SetAsDefault: booleanType | None class PolicyVersion(TypedDict, total=False): - Document: Optional[policyDocumentType] - VersionId: Optional[policyVersionIdType] - IsDefaultVersion: Optional[booleanType] - CreateDate: Optional[dateType] + Document: policyDocumentType | None + VersionId: policyVersionIdType | None + IsDefaultVersion: booleanType | None + CreateDate: dateType | None class CreatePolicyVersionResponse(TypedDict, total=False): - PolicyVersion: Optional[PolicyVersion] + PolicyVersion: PolicyVersion | None class CreateRoleRequest(ServiceRequest): - Path: Optional[pathType] + Path: pathType | None RoleName: roleNameType AssumeRolePolicyDocument: policyDocumentType - Description: Optional[roleDescriptionType] - MaxSessionDuration: Optional[roleMaxSessionDurationType] - PermissionsBoundary: Optional[arnType] - Tags: Optional[tagListType] + Description: roleDescriptionType | None + MaxSessionDuration: roleMaxSessionDurationType | None + PermissionsBoundary: arnType | None + Tags: tagListType | None class CreateRoleResponse(TypedDict, total=False): @@ -752,54 +866,54 @@ class CreateRoleResponse(TypedDict, total=False): class CreateSAMLProviderRequest(ServiceRequest): SAMLMetadataDocument: SAMLMetadataDocumentType Name: SAMLProviderNameType - Tags: Optional[tagListType] - AssertionEncryptionMode: Optional[assertionEncryptionModeType] - AddPrivateKey: Optional[privateKeyType] + Tags: tagListType | None + AssertionEncryptionMode: assertionEncryptionModeType | None + AddPrivateKey: privateKeyType | None class CreateSAMLProviderResponse(TypedDict, total=False): - SAMLProviderArn: Optional[arnType] - Tags: Optional[tagListType] + SAMLProviderArn: arnType | None + Tags: tagListType | None class CreateServiceLinkedRoleRequest(ServiceRequest): AWSServiceName: groupNameType - Description: Optional[roleDescriptionType] - CustomSuffix: Optional[customSuffixType] + Description: roleDescriptionType | None + CustomSuffix: customSuffixType | None class CreateServiceLinkedRoleResponse(TypedDict, total=False): - Role: Optional[Role] + Role: Role | None class CreateServiceSpecificCredentialRequest(ServiceRequest): UserName: userNameType ServiceName: serviceName - CredentialAgeDays: Optional[credentialAgeDays] + CredentialAgeDays: credentialAgeDays | None class ServiceSpecificCredential(TypedDict, total=False): CreateDate: dateType - ExpirationDate: Optional[dateType] + ExpirationDate: dateType | None ServiceName: serviceName - ServiceUserName: Optional[serviceUserName] - ServicePassword: Optional[servicePassword] - ServiceCredentialAlias: Optional[serviceCredentialAlias] - ServiceCredentialSecret: Optional[serviceCredentialSecret] + ServiceUserName: serviceUserName | None + ServicePassword: servicePassword | None + ServiceCredentialAlias: serviceCredentialAlias | None + ServiceCredentialSecret: serviceCredentialSecret | None ServiceSpecificCredentialId: serviceSpecificCredentialId UserName: userNameType Status: statusType class CreateServiceSpecificCredentialResponse(TypedDict, total=False): - ServiceSpecificCredential: Optional[ServiceSpecificCredential] + ServiceSpecificCredential: ServiceSpecificCredential | None class CreateUserRequest(ServiceRequest): - Path: Optional[pathType] + Path: pathType | None UserName: userNameType - PermissionsBoundary: Optional[arnType] - Tags: Optional[tagListType] + PermissionsBoundary: arnType | None + Tags: tagListType | None class User(TypedDict, total=False): @@ -808,28 +922,28 @@ class User(TypedDict, total=False): UserId: idType Arn: arnType CreateDate: dateType - PasswordLastUsed: Optional[dateType] - PermissionsBoundary: Optional[AttachedPermissionsBoundary] - Tags: Optional[tagListType] + PasswordLastUsed: dateType | None + PermissionsBoundary: AttachedPermissionsBoundary | None + Tags: tagListType | None class CreateUserResponse(TypedDict, total=False): - User: Optional[User] + User: User | None class CreateVirtualMFADeviceRequest(ServiceRequest): - Path: Optional[pathType] + Path: pathType | None VirtualMFADeviceName: virtualMFADeviceName - Tags: Optional[tagListType] + Tags: tagListType | None class VirtualMFADevice(TypedDict, total=False): SerialNumber: serialNumberType - Base32StringSeed: Optional[BootstrapDatum] - QRCodePNG: Optional[BootstrapDatum] - User: Optional[User] - EnableDate: Optional[dateType] - Tags: Optional[tagListType] + Base32StringSeed: BootstrapDatum | None + QRCodePNG: BootstrapDatum | None + User: User | None + EnableDate: dateType | None + Tags: tagListType | None class CreateVirtualMFADeviceResponse(TypedDict, total=False): @@ -837,12 +951,38 @@ class CreateVirtualMFADeviceResponse(TypedDict, total=False): class DeactivateMFADeviceRequest(ServiceRequest): - UserName: Optional[existingUserNameType] + UserName: existingUserNameType | None SerialNumber: serialNumberType +rolePermissionRestrictionArnListType = list[arnType] + + +class DelegationRequest(TypedDict, total=False): + DelegationRequestId: delegationRequestIdType | None + OwnerAccountId: accountIdType | None + Description: delegationRequestDescriptionType | None + RequestMessage: requestMessageType | None + Permissions: DelegationPermission | None + PermissionPolicy: permissionType | None + RolePermissionRestrictionArns: rolePermissionRestrictionArnListType | None + OwnerId: ownerIdType | None + ApproverId: arnType | None + State: stateType | None + ExpirationTime: dateType | None + RequestorId: accountIdType | None + RequestorName: requestorNameType | None + CreateDate: dateType | None + SessionDuration: sessionDurationType | None + RedirectUrl: redirectUrlType | None + Notes: notesType | None + RejectionReason: notesType | None + OnlySendByOwner: booleanType | None + UpdatedTime: dateType | None + + class DeleteAccessKeyRequest(ServiceRequest): - UserName: Optional[existingUserNameType] + UserName: existingUserNameType | None AccessKeyId: accessKeyIdType @@ -864,7 +1004,7 @@ class DeleteInstanceProfileRequest(ServiceRequest): class DeleteLoginProfileRequest(ServiceRequest): - UserName: Optional[userNameType] + UserName: userNameType | None class DeleteOpenIDConnectProviderRequest(ServiceRequest): @@ -915,12 +1055,12 @@ class DeleteServiceLinkedRoleResponse(TypedDict, total=False): class DeleteServiceSpecificCredentialRequest(ServiceRequest): - UserName: Optional[userNameType] + UserName: userNameType | None ServiceSpecificCredentialId: serviceSpecificCredentialId class DeleteSigningCertificateRequest(ServiceRequest): - UserName: Optional[existingUserNameType] + UserName: existingUserNameType | None CertificateId: certificateIdType @@ -942,16 +1082,16 @@ class DeleteVirtualMFADeviceRequest(ServiceRequest): class RoleUsageType(TypedDict, total=False): - Region: Optional[RegionNameType] - Resources: Optional[ArnListType] + Region: RegionNameType | None + Resources: ArnListType | None -RoleUsageListType = List[RoleUsageType] +RoleUsageListType = list[RoleUsageType] class DeletionTaskFailureReasonType(TypedDict, total=False): - Reason: Optional[ReasonType] - RoleUsageList: Optional[RoleUsageListType] + Reason: ReasonType | None + RoleUsageList: RoleUsageListType | None class DetachGroupPolicyRequest(ServiceRequest): @@ -973,12 +1113,12 @@ class DisableOrganizationsRootCredentialsManagementRequest(ServiceRequest): pass -FeaturesListType = List[FeatureType] +FeaturesListType = list[FeatureType] class DisableOrganizationsRootCredentialsManagementResponse(TypedDict, total=False): - OrganizationId: Optional[OrganizationIdType] - EnabledFeatures: Optional[FeaturesListType] + OrganizationId: OrganizationIdType | None + EnabledFeatures: FeaturesListType | None class DisableOrganizationsRootSessionsRequest(ServiceRequest): @@ -986,8 +1126,8 @@ class DisableOrganizationsRootSessionsRequest(ServiceRequest): class DisableOrganizationsRootSessionsResponse(TypedDict, total=False): - OrganizationId: Optional[OrganizationIdType] - EnabledFeatures: Optional[FeaturesListType] + OrganizationId: OrganizationIdType | None + EnabledFeatures: FeaturesListType | None class EnableMFADeviceRequest(ServiceRequest): @@ -1002,8 +1142,8 @@ class EnableOrganizationsRootCredentialsManagementRequest(ServiceRequest): class EnableOrganizationsRootCredentialsManagementResponse(TypedDict, total=False): - OrganizationId: Optional[OrganizationIdType] - EnabledFeatures: Optional[FeaturesListType] + OrganizationId: OrganizationIdType | None + EnabledFeatures: FeaturesListType | None class EnableOrganizationsRootSessionsRequest(ServiceRequest): @@ -1011,8 +1151,12 @@ class EnableOrganizationsRootSessionsRequest(ServiceRequest): class EnableOrganizationsRootSessionsResponse(TypedDict, total=False): - OrganizationId: Optional[OrganizationIdType] - EnabledFeatures: Optional[FeaturesListType] + OrganizationId: OrganizationIdType | None + EnabledFeatures: FeaturesListType | None + + +class EnableOutboundWebIdentityFederationResponse(TypedDict, total=False): + IssuerIdentifier: stringType | None class EntityInfo(TypedDict, total=False): @@ -1020,12 +1164,12 @@ class EntityInfo(TypedDict, total=False): Name: userNameType Type: policyOwnerEntityType Id: idType - Path: Optional[pathType] + Path: pathType | None class EntityDetails(TypedDict, total=False): EntityInfo: EntityInfo - LastAuthenticated: Optional[dateType] + LastAuthenticated: dateType | None class ErrorDetails(TypedDict, total=False): @@ -1033,80 +1177,80 @@ class ErrorDetails(TypedDict, total=False): Code: stringType -EvalDecisionDetailsType = Dict[EvalDecisionSourceType, PolicyEvaluationDecisionType] +EvalDecisionDetailsType = dict[EvalDecisionSourceType, PolicyEvaluationDecisionType] class PermissionsBoundaryDecisionDetail(TypedDict, total=False): - AllowedByPermissionsBoundary: Optional[booleanType] + AllowedByPermissionsBoundary: booleanType | None class Position(TypedDict, total=False): - Line: Optional[LineNumber] - Column: Optional[ColumnNumber] + Line: LineNumber | None + Column: ColumnNumber | None class Statement(TypedDict, total=False): - SourcePolicyId: Optional[PolicyIdentifierType] - SourcePolicyType: Optional[PolicySourceType] - StartPosition: Optional[Position] - EndPosition: Optional[Position] + SourcePolicyId: PolicyIdentifierType | None + SourcePolicyType: PolicySourceType | None + StartPosition: Position | None + EndPosition: Position | None -StatementListType = List[Statement] +StatementListType = list[Statement] class ResourceSpecificResult(TypedDict, total=False): EvalResourceName: ResourceNameType EvalResourceDecision: PolicyEvaluationDecisionType - MatchedStatements: Optional[StatementListType] - MissingContextValues: Optional[ContextKeyNamesResultListType] - EvalDecisionDetails: Optional[EvalDecisionDetailsType] - PermissionsBoundaryDecisionDetail: Optional[PermissionsBoundaryDecisionDetail] + MatchedStatements: StatementListType | None + MissingContextValues: ContextKeyNamesResultListType | None + EvalDecisionDetails: EvalDecisionDetailsType | None + PermissionsBoundaryDecisionDetail: PermissionsBoundaryDecisionDetail | None -ResourceSpecificResultListType = List[ResourceSpecificResult] +ResourceSpecificResultListType = list[ResourceSpecificResult] class OrganizationsDecisionDetail(TypedDict, total=False): - AllowedByOrganizations: Optional[booleanType] + AllowedByOrganizations: booleanType | None class EvaluationResult(TypedDict, total=False): EvalActionName: ActionNameType - EvalResourceName: Optional[ResourceNameType] + EvalResourceName: ResourceNameType | None EvalDecision: PolicyEvaluationDecisionType - MatchedStatements: Optional[StatementListType] - MissingContextValues: Optional[ContextKeyNamesResultListType] - OrganizationsDecisionDetail: Optional[OrganizationsDecisionDetail] - PermissionsBoundaryDecisionDetail: Optional[PermissionsBoundaryDecisionDetail] - EvalDecisionDetails: Optional[EvalDecisionDetailsType] - ResourceSpecificResults: Optional[ResourceSpecificResultListType] + MatchedStatements: StatementListType | None + MissingContextValues: ContextKeyNamesResultListType | None + OrganizationsDecisionDetail: OrganizationsDecisionDetail | None + PermissionsBoundaryDecisionDetail: PermissionsBoundaryDecisionDetail | None + EvalDecisionDetails: EvalDecisionDetailsType | None + ResourceSpecificResults: ResourceSpecificResultListType | None -EvaluationResultsListType = List[EvaluationResult] +EvaluationResultsListType = list[EvaluationResult] class GenerateCredentialReportResponse(TypedDict, total=False): - State: Optional[ReportStateType] - Description: Optional[ReportStateDescriptionType] + State: ReportStateType | None + Description: ReportStateDescriptionType | None class GenerateOrganizationsAccessReportRequest(ServiceRequest): EntityPath: organizationsEntityPathType - OrganizationsPolicyId: Optional[organizationsPolicyIdType] + OrganizationsPolicyId: organizationsPolicyIdType | None class GenerateOrganizationsAccessReportResponse(TypedDict, total=False): - JobId: Optional[jobIDType] + JobId: jobIDType | None class GenerateServiceLastAccessedDetailsRequest(ServiceRequest): Arn: arnType - Granularity: Optional[AccessAdvisorUsageGranularityType] + Granularity: AccessAdvisorUsageGranularityType | None class GenerateServiceLastAccessedDetailsResponse(TypedDict, total=False): - JobId: Optional[jobIDType] + JobId: jobIDType | None class GetAccessKeyLastUsedRequest(ServiceRequest): @@ -1114,132 +1258,132 @@ class GetAccessKeyLastUsedRequest(ServiceRequest): class GetAccessKeyLastUsedResponse(TypedDict, total=False): - UserName: Optional[existingUserNameType] - AccessKeyLastUsed: Optional[AccessKeyLastUsed] + UserName: existingUserNameType | None + AccessKeyLastUsed: AccessKeyLastUsed | None -entityListType = List[EntityType] +entityListType = list[EntityType] class GetAccountAuthorizationDetailsRequest(ServiceRequest): - Filter: Optional[entityListType] - MaxItems: Optional[maxItemsType] - Marker: Optional[markerType] + Filter: entityListType | None + MaxItems: maxItemsType | None + Marker: markerType | None -policyDocumentVersionListType = List[PolicyVersion] +policyDocumentVersionListType = list[PolicyVersion] class ManagedPolicyDetail(TypedDict, total=False): - PolicyName: Optional[policyNameType] - PolicyId: Optional[idType] - Arn: Optional[arnType] - Path: Optional[policyPathType] - DefaultVersionId: Optional[policyVersionIdType] - AttachmentCount: Optional[attachmentCountType] - PermissionsBoundaryUsageCount: Optional[attachmentCountType] - IsAttachable: Optional[booleanType] - Description: Optional[policyDescriptionType] - CreateDate: Optional[dateType] - UpdateDate: Optional[dateType] - PolicyVersionList: Optional[policyDocumentVersionListType] + PolicyName: policyNameType | None + PolicyId: idType | None + Arn: arnType | None + Path: policyPathType | None + DefaultVersionId: policyVersionIdType | None + AttachmentCount: attachmentCountType | None + PermissionsBoundaryUsageCount: attachmentCountType | None + IsAttachable: booleanType | None + Description: policyDescriptionType | None + CreateDate: dateType | None + UpdateDate: dateType | None + PolicyVersionList: policyDocumentVersionListType | None -ManagedPolicyDetailListType = List[ManagedPolicyDetail] -attachedPoliciesListType = List[AttachedPolicy] +ManagedPolicyDetailListType = list[ManagedPolicyDetail] +attachedPoliciesListType = list[AttachedPolicy] class PolicyDetail(TypedDict, total=False): - PolicyName: Optional[policyNameType] - PolicyDocument: Optional[policyDocumentType] + PolicyName: policyNameType | None + PolicyDocument: policyDocumentType | None -policyDetailListType = List[PolicyDetail] -instanceProfileListType = List[InstanceProfile] +policyDetailListType = list[PolicyDetail] +instanceProfileListType = list[InstanceProfile] class RoleDetail(TypedDict, total=False): - Path: Optional[pathType] - RoleName: Optional[roleNameType] - RoleId: Optional[idType] - Arn: Optional[arnType] - CreateDate: Optional[dateType] - AssumeRolePolicyDocument: Optional[policyDocumentType] - InstanceProfileList: Optional[instanceProfileListType] - RolePolicyList: Optional[policyDetailListType] - AttachedManagedPolicies: Optional[attachedPoliciesListType] - PermissionsBoundary: Optional[AttachedPermissionsBoundary] - Tags: Optional[tagListType] - RoleLastUsed: Optional[RoleLastUsed] + Path: pathType | None + RoleName: roleNameType | None + RoleId: idType | None + Arn: arnType | None + CreateDate: dateType | None + AssumeRolePolicyDocument: policyDocumentType | None + InstanceProfileList: instanceProfileListType | None + RolePolicyList: policyDetailListType | None + AttachedManagedPolicies: attachedPoliciesListType | None + PermissionsBoundary: AttachedPermissionsBoundary | None + Tags: tagListType | None + RoleLastUsed: RoleLastUsed | None -roleDetailListType = List[RoleDetail] +roleDetailListType = list[RoleDetail] class GroupDetail(TypedDict, total=False): - Path: Optional[pathType] - GroupName: Optional[groupNameType] - GroupId: Optional[idType] - Arn: Optional[arnType] - CreateDate: Optional[dateType] - GroupPolicyList: Optional[policyDetailListType] - AttachedManagedPolicies: Optional[attachedPoliciesListType] + Path: pathType | None + GroupName: groupNameType | None + GroupId: idType | None + Arn: arnType | None + CreateDate: dateType | None + GroupPolicyList: policyDetailListType | None + AttachedManagedPolicies: attachedPoliciesListType | None -groupDetailListType = List[GroupDetail] -groupNameListType = List[groupNameType] +groupDetailListType = list[GroupDetail] +groupNameListType = list[groupNameType] class UserDetail(TypedDict, total=False): - Path: Optional[pathType] - UserName: Optional[userNameType] - UserId: Optional[idType] - Arn: Optional[arnType] - CreateDate: Optional[dateType] - UserPolicyList: Optional[policyDetailListType] - GroupList: Optional[groupNameListType] - AttachedManagedPolicies: Optional[attachedPoliciesListType] - PermissionsBoundary: Optional[AttachedPermissionsBoundary] - Tags: Optional[tagListType] + Path: pathType | None + UserName: userNameType | None + UserId: idType | None + Arn: arnType | None + CreateDate: dateType | None + UserPolicyList: policyDetailListType | None + GroupList: groupNameListType | None + AttachedManagedPolicies: attachedPoliciesListType | None + PermissionsBoundary: AttachedPermissionsBoundary | None + Tags: tagListType | None -userDetailListType = List[UserDetail] +userDetailListType = list[UserDetail] class GetAccountAuthorizationDetailsResponse(TypedDict, total=False): - UserDetailList: Optional[userDetailListType] - GroupDetailList: Optional[groupDetailListType] - RoleDetailList: Optional[roleDetailListType] - Policies: Optional[ManagedPolicyDetailListType] - IsTruncated: Optional[booleanType] - Marker: Optional[responseMarkerType] + UserDetailList: userDetailListType | None + GroupDetailList: groupDetailListType | None + RoleDetailList: roleDetailListType | None + Policies: ManagedPolicyDetailListType | None + IsTruncated: booleanType | None + Marker: responseMarkerType | None class PasswordPolicy(TypedDict, total=False): - MinimumPasswordLength: Optional[minimumPasswordLengthType] - RequireSymbols: Optional[booleanType] - RequireNumbers: Optional[booleanType] - RequireUppercaseCharacters: Optional[booleanType] - RequireLowercaseCharacters: Optional[booleanType] - AllowUsersToChangePassword: Optional[booleanType] - ExpirePasswords: Optional[booleanType] - MaxPasswordAge: Optional[maxPasswordAgeType] - PasswordReusePrevention: Optional[passwordReusePreventionType] - HardExpiry: Optional[booleanObjectType] + MinimumPasswordLength: minimumPasswordLengthType | None + RequireSymbols: booleanType | None + RequireNumbers: booleanType | None + RequireUppercaseCharacters: booleanType | None + RequireLowercaseCharacters: booleanType | None + AllowUsersToChangePassword: booleanType | None + ExpirePasswords: booleanType | None + MaxPasswordAge: maxPasswordAgeType | None + PasswordReusePrevention: passwordReusePreventionType | None + HardExpiry: booleanObjectType | None class GetAccountPasswordPolicyResponse(TypedDict, total=False): PasswordPolicy: PasswordPolicy -summaryMapType = Dict[summaryKeyType, summaryValueType] +summaryMapType = dict[summaryKeyType, summaryValueType] class GetAccountSummaryResponse(TypedDict, total=False): - SummaryMap: Optional[summaryMapType] + SummaryMap: summaryMapType | None -SimulationPolicyListType = List[policyDocumentType] +SimulationPolicyListType = list[policyDocumentType] class GetContextKeysForCustomPolicyRequest(ServiceRequest): @@ -1247,21 +1391,32 @@ class GetContextKeysForCustomPolicyRequest(ServiceRequest): class GetContextKeysForPolicyResponse(TypedDict, total=False): - ContextKeyNames: Optional[ContextKeyNamesResultListType] + ContextKeyNames: ContextKeyNamesResultListType | None class GetContextKeysForPrincipalPolicyRequest(ServiceRequest): PolicySourceArn: arnType - PolicyInputList: Optional[SimulationPolicyListType] + PolicyInputList: SimulationPolicyListType | None ReportContentType = bytes class GetCredentialReportResponse(TypedDict, total=False): - Content: Optional[ReportContentType] - ReportFormat: Optional[ReportFormatType] - GeneratedTime: Optional[dateType] + Content: ReportContentType | None + ReportFormat: ReportFormatType | None + GeneratedTime: dateType | None + + +class GetDelegationRequestRequest(ServiceRequest): + DelegationRequestId: delegationRequestIdType + DelegationPermissionCheck: booleanType | None + + +class GetDelegationRequestResponse(TypedDict, total=False): + DelegationRequest: DelegationRequest | None + PermissionCheckStatus: permissionCheckStatusType | None + PermissionCheckResult: permissionCheckResultType | None class GetGroupPolicyRequest(ServiceRequest): @@ -1277,18 +1432,29 @@ class GetGroupPolicyResponse(TypedDict, total=False): class GetGroupRequest(ServiceRequest): GroupName: groupNameType - Marker: Optional[markerType] - MaxItems: Optional[maxItemsType] + Marker: markerType | None + MaxItems: maxItemsType | None -userListType = List[User] +userListType = list[User] class GetGroupResponse(TypedDict, total=False): Group: Group Users: userListType - IsTruncated: Optional[booleanType] - Marker: Optional[responseMarkerType] + IsTruncated: booleanType | None + Marker: responseMarkerType | None + + +class GetHumanReadableSummaryRequest(ServiceRequest): + EntityArn: arnType + Locale: localeType | None + + +class GetHumanReadableSummaryResponse(TypedDict, total=False): + SummaryContent: summaryContentType | None + Locale: localeType | None + SummaryState: summaryStateType | None class GetInstanceProfileRequest(ServiceRequest): @@ -1300,7 +1466,7 @@ class GetInstanceProfileResponse(TypedDict, total=False): class GetLoginProfileRequest(ServiceRequest): - UserName: Optional[userNameType] + UserName: userNameType | None class GetLoginProfileResponse(TypedDict, total=False): @@ -1309,14 +1475,14 @@ class GetLoginProfileResponse(TypedDict, total=False): class GetMFADeviceRequest(ServiceRequest): SerialNumber: serialNumberType - UserName: Optional[userNameType] + UserName: userNameType | None class GetMFADeviceResponse(TypedDict, total=False): - UserName: Optional[userNameType] + UserName: userNameType | None SerialNumber: serialNumberType - EnableDate: Optional[dateType] - Certifications: Optional[CertificationMapType] + EnableDate: dateType | None + Certifications: CertificationMapType | None class GetOpenIDConnectProviderRequest(ServiceRequest): @@ -1324,30 +1490,35 @@ class GetOpenIDConnectProviderRequest(ServiceRequest): class GetOpenIDConnectProviderResponse(TypedDict, total=False): - Url: Optional[OpenIDConnectProviderUrlType] - ClientIDList: Optional[clientIDListType] - ThumbprintList: Optional[thumbprintListType] - CreateDate: Optional[dateType] - Tags: Optional[tagListType] + Url: OpenIDConnectProviderUrlType | None + ClientIDList: clientIDListType | None + ThumbprintList: thumbprintListType | None + CreateDate: dateType | None + Tags: tagListType | None class GetOrganizationsAccessReportRequest(ServiceRequest): JobId: jobIDType - MaxItems: Optional[maxItemsType] - Marker: Optional[markerType] - SortKey: Optional[sortKeyType] + MaxItems: maxItemsType | None + Marker: markerType | None + SortKey: sortKeyType | None class GetOrganizationsAccessReportResponse(TypedDict, total=False): JobStatus: jobStatusType JobCreationDate: dateType - JobCompletionDate: Optional[dateType] - NumberOfServicesAccessible: Optional[integerType] - NumberOfServicesNotAccessed: Optional[integerType] - AccessDetails: Optional[AccessDetails] - IsTruncated: Optional[booleanType] - Marker: Optional[markerType] - ErrorDetails: Optional[ErrorDetails] + JobCompletionDate: dateType | None + NumberOfServicesAccessible: integerType | None + NumberOfServicesNotAccessed: integerType | None + AccessDetails: AccessDetails | None + IsTruncated: booleanType | None + Marker: markerType | None + ErrorDetails: ErrorDetails | None + + +class GetOutboundWebIdentityFederationInfoResponse(TypedDict, total=False): + IssuerIdentifier: stringType | None + JwtVendingEnabled: booleanType | None class GetPolicyRequest(ServiceRequest): @@ -1355,7 +1526,7 @@ class GetPolicyRequest(ServiceRequest): class GetPolicyResponse(TypedDict, total=False): - Policy: Optional[Policy] + Policy: Policy | None class GetPolicyVersionRequest(ServiceRequest): @@ -1364,7 +1535,7 @@ class GetPolicyVersionRequest(ServiceRequest): class GetPolicyVersionResponse(TypedDict, total=False): - PolicyVersion: Optional[PolicyVersion] + PolicyVersion: PolicyVersion | None class GetRolePolicyRequest(ServiceRequest): @@ -1391,21 +1562,21 @@ class GetSAMLProviderRequest(ServiceRequest): class SAMLPrivateKey(TypedDict, total=False): - KeyId: Optional[privateKeyIdType] - Timestamp: Optional[dateType] + KeyId: privateKeyIdType | None + Timestamp: dateType | None -privateKeyList = List[SAMLPrivateKey] +privateKeyList = list[SAMLPrivateKey] class GetSAMLProviderResponse(TypedDict, total=False): - SAMLProviderUUID: Optional[privateKeyIdType] - SAMLMetadataDocument: Optional[SAMLMetadataDocumentType] - CreateDate: Optional[dateType] - ValidUntil: Optional[dateType] - Tags: Optional[tagListType] - AssertionEncryptionMode: Optional[assertionEncryptionModeType] - PrivateKeyList: Optional[privateKeyList] + SAMLProviderUUID: privateKeyIdType | None + SAMLMetadataDocument: SAMLMetadataDocumentType | None + CreateDate: dateType | None + ValidUntil: dateType | None + Tags: tagListType | None + AssertionEncryptionMode: assertionEncryptionModeType | None + PrivateKeyList: privateKeyList | None class GetSSHPublicKeyRequest(ServiceRequest): @@ -1420,11 +1591,11 @@ class SSHPublicKey(TypedDict, total=False): Fingerprint: publicKeyFingerprintType SSHPublicKeyBody: publicKeyMaterialType Status: statusType - UploadDate: Optional[dateType] + UploadDate: dateType | None class GetSSHPublicKeyResponse(TypedDict, total=False): - SSHPublicKey: Optional[SSHPublicKey] + SSHPublicKey: SSHPublicKey | None class GetServerCertificateRequest(ServiceRequest): @@ -1436,15 +1607,15 @@ class ServerCertificateMetadata(TypedDict, total=False): ServerCertificateName: serverCertificateNameType ServerCertificateId: idType Arn: arnType - UploadDate: Optional[dateType] - Expiration: Optional[dateType] + UploadDate: dateType | None + Expiration: dateType | None class ServerCertificate(TypedDict, total=False): ServerCertificateMetadata: ServerCertificateMetadata CertificateBody: certificateBodyType - CertificateChain: Optional[certificateChainType] - Tags: Optional[tagListType] + CertificateChain: certificateChainType | None + Tags: tagListType | None class GetServerCertificateResponse(TypedDict, total=False): @@ -1453,52 +1624,52 @@ class GetServerCertificateResponse(TypedDict, total=False): class GetServiceLastAccessedDetailsRequest(ServiceRequest): JobId: jobIDType - MaxItems: Optional[maxItemsType] - Marker: Optional[markerType] + MaxItems: maxItemsType | None + Marker: markerType | None class TrackedActionLastAccessed(TypedDict, total=False): - ActionName: Optional[stringType] - LastAccessedEntity: Optional[arnType] - LastAccessedTime: Optional[dateType] - LastAccessedRegion: Optional[stringType] + ActionName: stringType | None + LastAccessedEntity: arnType | None + LastAccessedTime: dateType | None + LastAccessedRegion: stringType | None -TrackedActionsLastAccessed = List[TrackedActionLastAccessed] +TrackedActionsLastAccessed = list[TrackedActionLastAccessed] class ServiceLastAccessed(TypedDict, total=False): ServiceName: serviceNameType - LastAuthenticated: Optional[dateType] + LastAuthenticated: dateType | None ServiceNamespace: serviceNamespaceType - LastAuthenticatedEntity: Optional[arnType] - LastAuthenticatedRegion: Optional[stringType] - TotalAuthenticatedEntities: Optional[integerType] - TrackedActionsLastAccessed: Optional[TrackedActionsLastAccessed] + LastAuthenticatedEntity: arnType | None + LastAuthenticatedRegion: stringType | None + TotalAuthenticatedEntities: integerType | None + TrackedActionsLastAccessed: TrackedActionsLastAccessed | None -ServicesLastAccessed = List[ServiceLastAccessed] +ServicesLastAccessed = list[ServiceLastAccessed] class GetServiceLastAccessedDetailsResponse(TypedDict, total=False): JobStatus: jobStatusType - JobType: Optional[AccessAdvisorUsageGranularityType] + JobType: AccessAdvisorUsageGranularityType | None JobCreationDate: dateType ServicesLastAccessed: ServicesLastAccessed JobCompletionDate: dateType - IsTruncated: Optional[booleanType] - Marker: Optional[responseMarkerType] - Error: Optional[ErrorDetails] + IsTruncated: booleanType | None + Marker: responseMarkerType | None + Error: ErrorDetails | None class GetServiceLastAccessedDetailsWithEntitiesRequest(ServiceRequest): JobId: jobIDType ServiceNamespace: serviceNamespaceType - MaxItems: Optional[maxItemsType] - Marker: Optional[markerType] + MaxItems: maxItemsType | None + Marker: markerType | None -entityDetailsListType = List[EntityDetails] +entityDetailsListType = list[EntityDetails] class GetServiceLastAccessedDetailsWithEntitiesResponse(TypedDict, total=False): @@ -1506,9 +1677,9 @@ class GetServiceLastAccessedDetailsWithEntitiesResponse(TypedDict, total=False): JobCreationDate: dateType JobCompletionDate: dateType EntityDetailsList: entityDetailsListType - IsTruncated: Optional[booleanType] - Marker: Optional[responseMarkerType] - Error: Optional[ErrorDetails] + IsTruncated: booleanType | None + Marker: responseMarkerType | None + Error: ErrorDetails | None class GetServiceLinkedRoleDeletionStatusRequest(ServiceRequest): @@ -1517,7 +1688,7 @@ class GetServiceLinkedRoleDeletionStatusRequest(ServiceRequest): class GetServiceLinkedRoleDeletionStatusResponse(TypedDict, total=False): Status: DeletionTaskStatusType - Reason: Optional[DeletionTaskFailureReasonType] + Reason: DeletionTaskFailureReasonType | None class GetUserPolicyRequest(ServiceRequest): @@ -1532,7 +1703,7 @@ class GetUserPolicyResponse(TypedDict, total=False): class GetUserRequest(ServiceRequest): - UserName: Optional[existingUserNameType] + UserName: existingUserNameType | None class GetUserResponse(TypedDict, total=False): @@ -1540,208 +1711,223 @@ class GetUserResponse(TypedDict, total=False): class ListAccessKeysRequest(ServiceRequest): - UserName: Optional[existingUserNameType] - Marker: Optional[markerType] - MaxItems: Optional[maxItemsType] + UserName: existingUserNameType | None + Marker: markerType | None + MaxItems: maxItemsType | None -accessKeyMetadataListType = List[AccessKeyMetadata] +accessKeyMetadataListType = list[AccessKeyMetadata] class ListAccessKeysResponse(TypedDict, total=False): AccessKeyMetadata: accessKeyMetadataListType - IsTruncated: Optional[booleanType] - Marker: Optional[responseMarkerType] + IsTruncated: booleanType | None + Marker: responseMarkerType | None class ListAccountAliasesRequest(ServiceRequest): - Marker: Optional[markerType] - MaxItems: Optional[maxItemsType] + Marker: markerType | None + MaxItems: maxItemsType | None -accountAliasListType = List[accountAliasType] +accountAliasListType = list[accountAliasType] class ListAccountAliasesResponse(TypedDict, total=False): AccountAliases: accountAliasListType - IsTruncated: Optional[booleanType] - Marker: Optional[responseMarkerType] + IsTruncated: booleanType | None + Marker: responseMarkerType | None class ListAttachedGroupPoliciesRequest(ServiceRequest): GroupName: groupNameType - PathPrefix: Optional[policyPathType] - Marker: Optional[markerType] - MaxItems: Optional[maxItemsType] + PathPrefix: policyPathType | None + Marker: markerType | None + MaxItems: maxItemsType | None class ListAttachedGroupPoliciesResponse(TypedDict, total=False): - AttachedPolicies: Optional[attachedPoliciesListType] - IsTruncated: Optional[booleanType] - Marker: Optional[responseMarkerType] + AttachedPolicies: attachedPoliciesListType | None + IsTruncated: booleanType | None + Marker: responseMarkerType | None class ListAttachedRolePoliciesRequest(ServiceRequest): RoleName: roleNameType - PathPrefix: Optional[policyPathType] - Marker: Optional[markerType] - MaxItems: Optional[maxItemsType] + PathPrefix: policyPathType | None + Marker: markerType | None + MaxItems: maxItemsType | None class ListAttachedRolePoliciesResponse(TypedDict, total=False): - AttachedPolicies: Optional[attachedPoliciesListType] - IsTruncated: Optional[booleanType] - Marker: Optional[responseMarkerType] + AttachedPolicies: attachedPoliciesListType | None + IsTruncated: booleanType | None + Marker: responseMarkerType | None class ListAttachedUserPoliciesRequest(ServiceRequest): UserName: userNameType - PathPrefix: Optional[policyPathType] - Marker: Optional[markerType] - MaxItems: Optional[maxItemsType] + PathPrefix: policyPathType | None + Marker: markerType | None + MaxItems: maxItemsType | None class ListAttachedUserPoliciesResponse(TypedDict, total=False): - AttachedPolicies: Optional[attachedPoliciesListType] - IsTruncated: Optional[booleanType] - Marker: Optional[responseMarkerType] + AttachedPolicies: attachedPoliciesListType | None + IsTruncated: booleanType | None + Marker: responseMarkerType | None + + +class ListDelegationRequestsRequest(ServiceRequest): + OwnerId: ownerIdType | None + Marker: markerType | None + MaxItems: maxItemsType | None + + +delegationRequestsListType = list[DelegationRequest] + + +class ListDelegationRequestsResponse(TypedDict, total=False): + DelegationRequests: delegationRequestsListType | None + Marker: markerType | None + isTruncated: booleanType | None class ListEntitiesForPolicyRequest(ServiceRequest): PolicyArn: arnType - EntityFilter: Optional[EntityType] - PathPrefix: Optional[pathType] - PolicyUsageFilter: Optional[PolicyUsageType] - Marker: Optional[markerType] - MaxItems: Optional[maxItemsType] + EntityFilter: EntityType | None + PathPrefix: pathType | None + PolicyUsageFilter: PolicyUsageType | None + Marker: markerType | None + MaxItems: maxItemsType | None class PolicyRole(TypedDict, total=False): - RoleName: Optional[roleNameType] - RoleId: Optional[idType] + RoleName: roleNameType | None + RoleId: idType | None -PolicyRoleListType = List[PolicyRole] +PolicyRoleListType = list[PolicyRole] class PolicyUser(TypedDict, total=False): - UserName: Optional[userNameType] - UserId: Optional[idType] + UserName: userNameType | None + UserId: idType | None -PolicyUserListType = List[PolicyUser] +PolicyUserListType = list[PolicyUser] class PolicyGroup(TypedDict, total=False): - GroupName: Optional[groupNameType] - GroupId: Optional[idType] + GroupName: groupNameType | None + GroupId: idType | None -PolicyGroupListType = List[PolicyGroup] +PolicyGroupListType = list[PolicyGroup] class ListEntitiesForPolicyResponse(TypedDict, total=False): - PolicyGroups: Optional[PolicyGroupListType] - PolicyUsers: Optional[PolicyUserListType] - PolicyRoles: Optional[PolicyRoleListType] - IsTruncated: Optional[booleanType] - Marker: Optional[responseMarkerType] + PolicyGroups: PolicyGroupListType | None + PolicyUsers: PolicyUserListType | None + PolicyRoles: PolicyRoleListType | None + IsTruncated: booleanType | None + Marker: responseMarkerType | None class ListGroupPoliciesRequest(ServiceRequest): GroupName: groupNameType - Marker: Optional[markerType] - MaxItems: Optional[maxItemsType] + Marker: markerType | None + MaxItems: maxItemsType | None -policyNameListType = List[policyNameType] +policyNameListType = list[policyNameType] class ListGroupPoliciesResponse(TypedDict, total=False): PolicyNames: policyNameListType - IsTruncated: Optional[booleanType] - Marker: Optional[responseMarkerType] + IsTruncated: booleanType | None + Marker: responseMarkerType | None class ListGroupsForUserRequest(ServiceRequest): UserName: existingUserNameType - Marker: Optional[markerType] - MaxItems: Optional[maxItemsType] + Marker: markerType | None + MaxItems: maxItemsType | None -groupListType = List[Group] +groupListType = list[Group] class ListGroupsForUserResponse(TypedDict, total=False): Groups: groupListType - IsTruncated: Optional[booleanType] - Marker: Optional[responseMarkerType] + IsTruncated: booleanType | None + Marker: responseMarkerType | None class ListGroupsRequest(ServiceRequest): - PathPrefix: Optional[pathPrefixType] - Marker: Optional[markerType] - MaxItems: Optional[maxItemsType] + PathPrefix: pathPrefixType | None + Marker: markerType | None + MaxItems: maxItemsType | None class ListGroupsResponse(TypedDict, total=False): Groups: groupListType - IsTruncated: Optional[booleanType] - Marker: Optional[responseMarkerType] + IsTruncated: booleanType | None + Marker: responseMarkerType | None class ListInstanceProfileTagsRequest(ServiceRequest): InstanceProfileName: instanceProfileNameType - Marker: Optional[markerType] - MaxItems: Optional[maxItemsType] + Marker: markerType | None + MaxItems: maxItemsType | None class ListInstanceProfileTagsResponse(TypedDict, total=False): Tags: tagListType - IsTruncated: Optional[booleanType] - Marker: Optional[responseMarkerType] + IsTruncated: booleanType | None + Marker: responseMarkerType | None class ListInstanceProfilesForRoleRequest(ServiceRequest): RoleName: roleNameType - Marker: Optional[markerType] - MaxItems: Optional[maxItemsType] + Marker: markerType | None + MaxItems: maxItemsType | None class ListInstanceProfilesForRoleResponse(TypedDict, total=False): InstanceProfiles: instanceProfileListType - IsTruncated: Optional[booleanType] - Marker: Optional[responseMarkerType] + IsTruncated: booleanType | None + Marker: responseMarkerType | None class ListInstanceProfilesRequest(ServiceRequest): - PathPrefix: Optional[pathPrefixType] - Marker: Optional[markerType] - MaxItems: Optional[maxItemsType] + PathPrefix: pathPrefixType | None + Marker: markerType | None + MaxItems: maxItemsType | None class ListInstanceProfilesResponse(TypedDict, total=False): InstanceProfiles: instanceProfileListType - IsTruncated: Optional[booleanType] - Marker: Optional[responseMarkerType] + IsTruncated: booleanType | None + Marker: responseMarkerType | None class ListMFADeviceTagsRequest(ServiceRequest): SerialNumber: serialNumberType - Marker: Optional[markerType] - MaxItems: Optional[maxItemsType] + Marker: markerType | None + MaxItems: maxItemsType | None class ListMFADeviceTagsResponse(TypedDict, total=False): Tags: tagListType - IsTruncated: Optional[booleanType] - Marker: Optional[responseMarkerType] + IsTruncated: booleanType | None + Marker: responseMarkerType | None class ListMFADevicesRequest(ServiceRequest): - UserName: Optional[existingUserNameType] - Marker: Optional[markerType] - MaxItems: Optional[maxItemsType] + UserName: existingUserNameType | None + Marker: markerType | None + MaxItems: maxItemsType | None class MFADevice(TypedDict, total=False): @@ -1750,25 +1936,25 @@ class MFADevice(TypedDict, total=False): EnableDate: dateType -mfaDeviceListType = List[MFADevice] +mfaDeviceListType = list[MFADevice] class ListMFADevicesResponse(TypedDict, total=False): MFADevices: mfaDeviceListType - IsTruncated: Optional[booleanType] - Marker: Optional[responseMarkerType] + IsTruncated: booleanType | None + Marker: responseMarkerType | None class ListOpenIDConnectProviderTagsRequest(ServiceRequest): OpenIDConnectProviderArn: arnType - Marker: Optional[markerType] - MaxItems: Optional[maxItemsType] + Marker: markerType | None + MaxItems: maxItemsType | None class ListOpenIDConnectProviderTagsResponse(TypedDict, total=False): Tags: tagListType - IsTruncated: Optional[booleanType] - Marker: Optional[responseMarkerType] + IsTruncated: booleanType | None + Marker: responseMarkerType | None class ListOpenIDConnectProvidersRequest(ServiceRequest): @@ -1776,14 +1962,14 @@ class ListOpenIDConnectProvidersRequest(ServiceRequest): class OpenIDConnectProviderListEntry(TypedDict, total=False): - Arn: Optional[arnType] + Arn: arnType | None -OpenIDConnectProviderListType = List[OpenIDConnectProviderListEntry] +OpenIDConnectProviderListType = list[OpenIDConnectProviderListEntry] class ListOpenIDConnectProvidersResponse(TypedDict, total=False): - OpenIDConnectProviderList: Optional[OpenIDConnectProviderListType] + OpenIDConnectProviderList: OpenIDConnectProviderListType | None class ListOrganizationsFeaturesRequest(ServiceRequest): @@ -1791,132 +1977,132 @@ class ListOrganizationsFeaturesRequest(ServiceRequest): class ListOrganizationsFeaturesResponse(TypedDict, total=False): - OrganizationId: Optional[OrganizationIdType] - EnabledFeatures: Optional[FeaturesListType] + OrganizationId: OrganizationIdType | None + EnabledFeatures: FeaturesListType | None class PolicyGrantingServiceAccess(TypedDict, total=False): PolicyName: policyNameType PolicyType: policyType - PolicyArn: Optional[arnType] - EntityType: Optional[policyOwnerEntityType] - EntityName: Optional[entityNameType] + PolicyArn: arnType | None + EntityType: policyOwnerEntityType | None + EntityName: entityNameType | None -policyGrantingServiceAccessListType = List[PolicyGrantingServiceAccess] +policyGrantingServiceAccessListType = list[PolicyGrantingServiceAccess] class ListPoliciesGrantingServiceAccessEntry(TypedDict, total=False): - ServiceNamespace: Optional[serviceNamespaceType] - Policies: Optional[policyGrantingServiceAccessListType] + ServiceNamespace: serviceNamespaceType | None + Policies: policyGrantingServiceAccessListType | None -serviceNamespaceListType = List[serviceNamespaceType] +serviceNamespaceListType = list[serviceNamespaceType] class ListPoliciesGrantingServiceAccessRequest(ServiceRequest): - Marker: Optional[markerType] + Marker: markerType | None Arn: arnType ServiceNamespaces: serviceNamespaceListType -listPolicyGrantingServiceAccessResponseListType = List[ListPoliciesGrantingServiceAccessEntry] +listPolicyGrantingServiceAccessResponseListType = list[ListPoliciesGrantingServiceAccessEntry] class ListPoliciesGrantingServiceAccessResponse(TypedDict, total=False): PoliciesGrantingServiceAccess: listPolicyGrantingServiceAccessResponseListType - IsTruncated: Optional[booleanType] - Marker: Optional[responseMarkerType] + IsTruncated: booleanType | None + Marker: responseMarkerType | None class ListPoliciesRequest(ServiceRequest): - Scope: Optional[policyScopeType] - OnlyAttached: Optional[booleanType] - PathPrefix: Optional[policyPathType] - PolicyUsageFilter: Optional[PolicyUsageType] - Marker: Optional[markerType] - MaxItems: Optional[maxItemsType] + Scope: policyScopeType | None + OnlyAttached: booleanType | None + PathPrefix: policyPathType | None + PolicyUsageFilter: PolicyUsageType | None + Marker: markerType | None + MaxItems: maxItemsType | None -policyListType = List[Policy] +policyListType = list[Policy] class ListPoliciesResponse(TypedDict, total=False): - Policies: Optional[policyListType] - IsTruncated: Optional[booleanType] - Marker: Optional[responseMarkerType] + Policies: policyListType | None + IsTruncated: booleanType | None + Marker: responseMarkerType | None class ListPolicyTagsRequest(ServiceRequest): PolicyArn: arnType - Marker: Optional[markerType] - MaxItems: Optional[maxItemsType] + Marker: markerType | None + MaxItems: maxItemsType | None class ListPolicyTagsResponse(TypedDict, total=False): Tags: tagListType - IsTruncated: Optional[booleanType] - Marker: Optional[responseMarkerType] + IsTruncated: booleanType | None + Marker: responseMarkerType | None class ListPolicyVersionsRequest(ServiceRequest): PolicyArn: arnType - Marker: Optional[markerType] - MaxItems: Optional[maxItemsType] + Marker: markerType | None + MaxItems: maxItemsType | None class ListPolicyVersionsResponse(TypedDict, total=False): - Versions: Optional[policyDocumentVersionListType] - IsTruncated: Optional[booleanType] - Marker: Optional[responseMarkerType] + Versions: policyDocumentVersionListType | None + IsTruncated: booleanType | None + Marker: responseMarkerType | None class ListRolePoliciesRequest(ServiceRequest): RoleName: roleNameType - Marker: Optional[markerType] - MaxItems: Optional[maxItemsType] + Marker: markerType | None + MaxItems: maxItemsType | None class ListRolePoliciesResponse(TypedDict, total=False): PolicyNames: policyNameListType - IsTruncated: Optional[booleanType] - Marker: Optional[responseMarkerType] + IsTruncated: booleanType | None + Marker: responseMarkerType | None class ListRoleTagsRequest(ServiceRequest): RoleName: roleNameType - Marker: Optional[markerType] - MaxItems: Optional[maxItemsType] + Marker: markerType | None + MaxItems: maxItemsType | None class ListRoleTagsResponse(TypedDict, total=False): Tags: tagListType - IsTruncated: Optional[booleanType] - Marker: Optional[responseMarkerType] + IsTruncated: booleanType | None + Marker: responseMarkerType | None class ListRolesRequest(ServiceRequest): - PathPrefix: Optional[pathPrefixType] - Marker: Optional[markerType] - MaxItems: Optional[maxItemsType] + PathPrefix: pathPrefixType | None + Marker: markerType | None + MaxItems: maxItemsType | None class ListRolesResponse(TypedDict, total=False): Roles: roleListType - IsTruncated: Optional[booleanType] - Marker: Optional[responseMarkerType] + IsTruncated: booleanType | None + Marker: responseMarkerType | None class ListSAMLProviderTagsRequest(ServiceRequest): SAMLProviderArn: arnType - Marker: Optional[markerType] - MaxItems: Optional[maxItemsType] + Marker: markerType | None + MaxItems: maxItemsType | None class ListSAMLProviderTagsResponse(TypedDict, total=False): Tags: tagListType - IsTruncated: Optional[booleanType] - Marker: Optional[responseMarkerType] + IsTruncated: booleanType | None + Marker: responseMarkerType | None class ListSAMLProvidersRequest(ServiceRequest): @@ -1924,22 +2110,22 @@ class ListSAMLProvidersRequest(ServiceRequest): class SAMLProviderListEntry(TypedDict, total=False): - Arn: Optional[arnType] - ValidUntil: Optional[dateType] - CreateDate: Optional[dateType] + Arn: arnType | None + ValidUntil: dateType | None + CreateDate: dateType | None -SAMLProviderListType = List[SAMLProviderListEntry] +SAMLProviderListType = list[SAMLProviderListEntry] class ListSAMLProvidersResponse(TypedDict, total=False): - SAMLProviderList: Optional[SAMLProviderListType] + SAMLProviderList: SAMLProviderListType | None class ListSSHPublicKeysRequest(ServiceRequest): - UserName: Optional[userNameType] - Marker: Optional[markerType] - MaxItems: Optional[maxItemsType] + UserName: userNameType | None + Marker: markerType | None + MaxItems: maxItemsType | None class SSHPublicKeyMetadata(TypedDict, total=False): @@ -1949,74 +2135,74 @@ class SSHPublicKeyMetadata(TypedDict, total=False): UploadDate: dateType -SSHPublicKeyListType = List[SSHPublicKeyMetadata] +SSHPublicKeyListType = list[SSHPublicKeyMetadata] class ListSSHPublicKeysResponse(TypedDict, total=False): - SSHPublicKeys: Optional[SSHPublicKeyListType] - IsTruncated: Optional[booleanType] - Marker: Optional[responseMarkerType] + SSHPublicKeys: SSHPublicKeyListType | None + IsTruncated: booleanType | None + Marker: responseMarkerType | None class ListServerCertificateTagsRequest(ServiceRequest): ServerCertificateName: serverCertificateNameType - Marker: Optional[markerType] - MaxItems: Optional[maxItemsType] + Marker: markerType | None + MaxItems: maxItemsType | None class ListServerCertificateTagsResponse(TypedDict, total=False): Tags: tagListType - IsTruncated: Optional[booleanType] - Marker: Optional[responseMarkerType] + IsTruncated: booleanType | None + Marker: responseMarkerType | None class ListServerCertificatesRequest(ServiceRequest): - PathPrefix: Optional[pathPrefixType] - Marker: Optional[markerType] - MaxItems: Optional[maxItemsType] + PathPrefix: pathPrefixType | None + Marker: markerType | None + MaxItems: maxItemsType | None -serverCertificateMetadataListType = List[ServerCertificateMetadata] +serverCertificateMetadataListType = list[ServerCertificateMetadata] class ListServerCertificatesResponse(TypedDict, total=False): ServerCertificateMetadataList: serverCertificateMetadataListType - IsTruncated: Optional[booleanType] - Marker: Optional[responseMarkerType] + IsTruncated: booleanType | None + Marker: responseMarkerType | None class ListServiceSpecificCredentialsRequest(ServiceRequest): - UserName: Optional[userNameType] - ServiceName: Optional[serviceName] - AllUsers: Optional[allUsers] - Marker: Optional[markerType] - MaxItems: Optional[maxItemsType] + UserName: userNameType | None + ServiceName: serviceName | None + AllUsers: allUsers | None + Marker: markerType | None + MaxItems: maxItemsType | None class ServiceSpecificCredentialMetadata(TypedDict, total=False): UserName: userNameType Status: statusType - ServiceUserName: Optional[serviceUserName] - ServiceCredentialAlias: Optional[serviceCredentialAlias] + ServiceUserName: serviceUserName | None + ServiceCredentialAlias: serviceCredentialAlias | None CreateDate: dateType - ExpirationDate: Optional[dateType] + ExpirationDate: dateType | None ServiceSpecificCredentialId: serviceSpecificCredentialId ServiceName: serviceName -ServiceSpecificCredentialsListType = List[ServiceSpecificCredentialMetadata] +ServiceSpecificCredentialsListType = list[ServiceSpecificCredentialMetadata] class ListServiceSpecificCredentialsResponse(TypedDict, total=False): - ServiceSpecificCredentials: Optional[ServiceSpecificCredentialsListType] - Marker: Optional[responseMarkerType] - IsTruncated: Optional[booleanType] + ServiceSpecificCredentials: ServiceSpecificCredentialsListType | None + Marker: responseMarkerType | None + IsTruncated: booleanType | None class ListSigningCertificatesRequest(ServiceRequest): - UserName: Optional[existingUserNameType] - Marker: Optional[markerType] - MaxItems: Optional[maxItemsType] + UserName: existingUserNameType | None + Marker: markerType | None + MaxItems: maxItemsType | None class SigningCertificate(TypedDict, total=False): @@ -2024,67 +2210,67 @@ class SigningCertificate(TypedDict, total=False): CertificateId: certificateIdType CertificateBody: certificateBodyType Status: statusType - UploadDate: Optional[dateType] + UploadDate: dateType | None -certificateListType = List[SigningCertificate] +certificateListType = list[SigningCertificate] class ListSigningCertificatesResponse(TypedDict, total=False): Certificates: certificateListType - IsTruncated: Optional[booleanType] - Marker: Optional[responseMarkerType] + IsTruncated: booleanType | None + Marker: responseMarkerType | None class ListUserPoliciesRequest(ServiceRequest): UserName: existingUserNameType - Marker: Optional[markerType] - MaxItems: Optional[maxItemsType] + Marker: markerType | None + MaxItems: maxItemsType | None class ListUserPoliciesResponse(TypedDict, total=False): PolicyNames: policyNameListType - IsTruncated: Optional[booleanType] - Marker: Optional[responseMarkerType] + IsTruncated: booleanType | None + Marker: responseMarkerType | None class ListUserTagsRequest(ServiceRequest): UserName: existingUserNameType - Marker: Optional[markerType] - MaxItems: Optional[maxItemsType] + Marker: markerType | None + MaxItems: maxItemsType | None class ListUserTagsResponse(TypedDict, total=False): Tags: tagListType - IsTruncated: Optional[booleanType] - Marker: Optional[responseMarkerType] + IsTruncated: booleanType | None + Marker: responseMarkerType | None class ListUsersRequest(ServiceRequest): - PathPrefix: Optional[pathPrefixType] - Marker: Optional[markerType] - MaxItems: Optional[maxItemsType] + PathPrefix: pathPrefixType | None + Marker: markerType | None + MaxItems: maxItemsType | None class ListUsersResponse(TypedDict, total=False): Users: userListType - IsTruncated: Optional[booleanType] - Marker: Optional[responseMarkerType] + IsTruncated: booleanType | None + Marker: responseMarkerType | None class ListVirtualMFADevicesRequest(ServiceRequest): - AssignmentStatus: Optional[assignmentStatusType] - Marker: Optional[markerType] - MaxItems: Optional[maxItemsType] + AssignmentStatus: assignmentStatusType | None + Marker: markerType | None + MaxItems: maxItemsType | None -virtualMFADeviceListType = List[VirtualMFADevice] +virtualMFADeviceListType = list[VirtualMFADevice] class ListVirtualMFADevicesResponse(TypedDict, total=False): VirtualMFADevices: virtualMFADeviceListType - IsTruncated: Optional[booleanType] - Marker: Optional[responseMarkerType] + IsTruncated: booleanType | None + Marker: responseMarkerType | None class PutGroupPolicyRequest(ServiceRequest): @@ -2115,6 +2301,11 @@ class PutUserPolicyRequest(ServiceRequest): PolicyDocument: policyDocumentType +class RejectDelegationRequestRequest(ServiceRequest): + DelegationRequestId: delegationRequestIdType + Notes: notesType | None + + class RemoveClientIDFromOpenIDConnectProviderRequest(ServiceRequest): OpenIDConnectProviderArn: arnType ClientID: clientIDType @@ -2131,15 +2322,15 @@ class RemoveUserFromGroupRequest(ServiceRequest): class ResetServiceSpecificCredentialRequest(ServiceRequest): - UserName: Optional[userNameType] + UserName: userNameType | None ServiceSpecificCredentialId: serviceSpecificCredentialId class ResetServiceSpecificCredentialResponse(TypedDict, total=False): - ServiceSpecificCredential: Optional[ServiceSpecificCredential] + ServiceSpecificCredential: ServiceSpecificCredential | None -ResourceNameListType = List[ResourceNameType] +ResourceNameListType = list[ResourceNameType] class ResyncMFADeviceRequest(ServiceRequest): @@ -2149,6 +2340,10 @@ class ResyncMFADeviceRequest(ServiceRequest): AuthenticationCode2: authenticationCodeType +class SendDelegationTokenRequest(ServiceRequest): + DelegationRequestId: delegationRequestIdType + + class SetDefaultPolicyVersionRequest(ServiceRequest): PolicyArn: arnType VersionId: policyVersionIdType @@ -2160,37 +2355,37 @@ class SetSecurityTokenServicePreferencesRequest(ServiceRequest): class SimulateCustomPolicyRequest(ServiceRequest): PolicyInputList: SimulationPolicyListType - PermissionsBoundaryPolicyInputList: Optional[SimulationPolicyListType] + PermissionsBoundaryPolicyInputList: SimulationPolicyListType | None ActionNames: ActionNameListType - ResourceArns: Optional[ResourceNameListType] - ResourcePolicy: Optional[policyDocumentType] - ResourceOwner: Optional[ResourceNameType] - CallerArn: Optional[ResourceNameType] - ContextEntries: Optional[ContextEntryListType] - ResourceHandlingOption: Optional[ResourceHandlingOptionType] - MaxItems: Optional[maxItemsType] - Marker: Optional[markerType] + ResourceArns: ResourceNameListType | None + ResourcePolicy: policyDocumentType | None + ResourceOwner: ResourceNameType | None + CallerArn: ResourceNameType | None + ContextEntries: ContextEntryListType | None + ResourceHandlingOption: ResourceHandlingOptionType | None + MaxItems: maxItemsType | None + Marker: markerType | None class SimulatePolicyResponse(TypedDict, total=False): - EvaluationResults: Optional[EvaluationResultsListType] - IsTruncated: Optional[booleanType] - Marker: Optional[responseMarkerType] + EvaluationResults: EvaluationResultsListType | None + IsTruncated: booleanType | None + Marker: responseMarkerType | None class SimulatePrincipalPolicyRequest(ServiceRequest): PolicySourceArn: arnType - PolicyInputList: Optional[SimulationPolicyListType] - PermissionsBoundaryPolicyInputList: Optional[SimulationPolicyListType] + PolicyInputList: SimulationPolicyListType | None + PermissionsBoundaryPolicyInputList: SimulationPolicyListType | None ActionNames: ActionNameListType - ResourceArns: Optional[ResourceNameListType] - ResourcePolicy: Optional[policyDocumentType] - ResourceOwner: Optional[ResourceNameType] - CallerArn: Optional[ResourceNameType] - ContextEntries: Optional[ContextEntryListType] - ResourceHandlingOption: Optional[ResourceHandlingOptionType] - MaxItems: Optional[maxItemsType] - Marker: Optional[markerType] + ResourceArns: ResourceNameListType | None + ResourcePolicy: policyDocumentType | None + ResourceOwner: ResourceNameType | None + CallerArn: ResourceNameType | None + ContextEntries: ContextEntryListType | None + ResourceHandlingOption: ResourceHandlingOptionType | None + MaxItems: maxItemsType | None + Marker: markerType | None class TagInstanceProfileRequest(ServiceRequest): @@ -2233,7 +2428,7 @@ class TagUserRequest(ServiceRequest): Tags: tagListType -tagKeyListType = List[tagKeyType] +tagKeyListType = list[tagKeyType] class UntagInstanceProfileRequest(ServiceRequest): @@ -2277,21 +2472,21 @@ class UntagUserRequest(ServiceRequest): class UpdateAccessKeyRequest(ServiceRequest): - UserName: Optional[existingUserNameType] + UserName: existingUserNameType | None AccessKeyId: accessKeyIdType Status: statusType class UpdateAccountPasswordPolicyRequest(ServiceRequest): - MinimumPasswordLength: Optional[minimumPasswordLengthType] - RequireSymbols: Optional[booleanType] - RequireNumbers: Optional[booleanType] - RequireUppercaseCharacters: Optional[booleanType] - RequireLowercaseCharacters: Optional[booleanType] - AllowUsersToChangePassword: Optional[booleanType] - MaxPasswordAge: Optional[maxPasswordAgeType] - PasswordReusePrevention: Optional[passwordReusePreventionType] - HardExpiry: Optional[booleanObjectType] + MinimumPasswordLength: minimumPasswordLengthType | None + RequireSymbols: booleanType | None + RequireNumbers: booleanType | None + RequireUppercaseCharacters: booleanType | None + RequireLowercaseCharacters: booleanType | None + AllowUsersToChangePassword: booleanType | None + MaxPasswordAge: maxPasswordAgeType | None + PasswordReusePrevention: passwordReusePreventionType | None + HardExpiry: booleanObjectType | None class UpdateAssumeRolePolicyRequest(ServiceRequest): @@ -2299,16 +2494,21 @@ class UpdateAssumeRolePolicyRequest(ServiceRequest): PolicyDocument: policyDocumentType +class UpdateDelegationRequestRequest(ServiceRequest): + DelegationRequestId: delegationRequestIdType + Notes: notesType | None + + class UpdateGroupRequest(ServiceRequest): GroupName: groupNameType - NewPath: Optional[pathType] - NewGroupName: Optional[groupNameType] + NewPath: pathType | None + NewGroupName: groupNameType | None class UpdateLoginProfileRequest(ServiceRequest): UserName: userNameType - Password: Optional[passwordType] - PasswordResetRequired: Optional[booleanObjectType] + Password: passwordType | None + PasswordResetRequired: booleanObjectType | None class UpdateOpenIDConnectProviderThumbprintRequest(ServiceRequest): @@ -2322,13 +2522,13 @@ class UpdateRoleDescriptionRequest(ServiceRequest): class UpdateRoleDescriptionResponse(TypedDict, total=False): - Role: Optional[Role] + Role: Role | None class UpdateRoleRequest(ServiceRequest): RoleName: roleNameType - Description: Optional[roleDescriptionType] - MaxSessionDuration: Optional[roleMaxSessionDurationType] + Description: roleDescriptionType | None + MaxSessionDuration: roleMaxSessionDurationType | None class UpdateRoleResponse(TypedDict, total=False): @@ -2336,15 +2536,15 @@ class UpdateRoleResponse(TypedDict, total=False): class UpdateSAMLProviderRequest(ServiceRequest): - SAMLMetadataDocument: Optional[SAMLMetadataDocumentType] + SAMLMetadataDocument: SAMLMetadataDocumentType | None SAMLProviderArn: arnType - AssertionEncryptionMode: Optional[assertionEncryptionModeType] - AddPrivateKey: Optional[privateKeyType] - RemovePrivateKey: Optional[privateKeyIdType] + AssertionEncryptionMode: assertionEncryptionModeType | None + AddPrivateKey: privateKeyType | None + RemovePrivateKey: privateKeyIdType | None class UpdateSAMLProviderResponse(TypedDict, total=False): - SAMLProviderArn: Optional[arnType] + SAMLProviderArn: arnType | None class UpdateSSHPublicKeyRequest(ServiceRequest): @@ -2355,26 +2555,26 @@ class UpdateSSHPublicKeyRequest(ServiceRequest): class UpdateServerCertificateRequest(ServiceRequest): ServerCertificateName: serverCertificateNameType - NewPath: Optional[pathType] - NewServerCertificateName: Optional[serverCertificateNameType] + NewPath: pathType | None + NewServerCertificateName: serverCertificateNameType | None class UpdateServiceSpecificCredentialRequest(ServiceRequest): - UserName: Optional[userNameType] + UserName: userNameType | None ServiceSpecificCredentialId: serviceSpecificCredentialId Status: statusType class UpdateSigningCertificateRequest(ServiceRequest): - UserName: Optional[existingUserNameType] + UserName: existingUserNameType | None CertificateId: certificateIdType Status: statusType class UpdateUserRequest(ServiceRequest): UserName: existingUserNameType - NewPath: Optional[pathType] - NewUserName: Optional[userNameType] + NewPath: pathType | None + NewUserName: userNameType | None class UploadSSHPublicKeyRequest(ServiceRequest): @@ -2383,25 +2583,25 @@ class UploadSSHPublicKeyRequest(ServiceRequest): class UploadSSHPublicKeyResponse(TypedDict, total=False): - SSHPublicKey: Optional[SSHPublicKey] + SSHPublicKey: SSHPublicKey | None class UploadServerCertificateRequest(ServiceRequest): - Path: Optional[pathType] + Path: pathType | None ServerCertificateName: serverCertificateNameType CertificateBody: certificateBodyType PrivateKey: privateKeyType - CertificateChain: Optional[certificateChainType] - Tags: Optional[tagListType] + CertificateChain: certificateChainType | None + Tags: tagListType | None class UploadServerCertificateResponse(TypedDict, total=False): - ServerCertificateMetadata: Optional[ServerCertificateMetadata] - Tags: Optional[tagListType] + ServerCertificateMetadata: ServerCertificateMetadata | None + Tags: tagListType | None class UploadSigningCertificateRequest(ServiceRequest): - UserName: Optional[existingUserNameType] + UserName: existingUserNameType | None CertificateBody: certificateBodyType @@ -2410,8 +2610,14 @@ class UploadSigningCertificateResponse(TypedDict, total=False): class IamApi: - service = "iam" - version = "2010-05-08" + service: str = "iam" + version: str = "2010-05-08" + + @handler("AcceptDelegationRequest") + def accept_delegation_request( + self, context: RequestContext, delegation_request_id: delegationRequestIdType, **kwargs + ) -> None: + raise NotImplementedError @handler("AddClientIDToOpenIDConnectProvider") def add_client_id_to_open_id_connect_provider( @@ -2443,6 +2649,12 @@ def add_user_to_group( ) -> None: raise NotImplementedError + @handler("AssociateDelegationRequest") + def associate_delegation_request( + self, context: RequestContext, delegation_request_id: delegationRequestIdType, **kwargs + ) -> None: + raise NotImplementedError + @handler("AttachGroupPolicy") def attach_group_policy( self, context: RequestContext, group_name: groupNameType, policy_arn: arnType, **kwargs @@ -2483,6 +2695,23 @@ def create_account_alias( ) -> None: raise NotImplementedError + @handler("CreateDelegationRequest") + def create_delegation_request( + self, + context: RequestContext, + description: delegationRequestDescriptionType, + permissions: DelegationPermission, + requestor_workflow_id: requestorWorkflowIdType, + notification_channel: notificationChannelType, + session_duration: sessionDurationType, + owner_account_id: accountIdType | None = None, + request_message: requestMessageType | None = None, + redirect_url: redirectUrlType | None = None, + only_send_by_owner: booleanType | None = None, + **kwargs, + ) -> CreateDelegationRequestResponse: + raise NotImplementedError + @handler("CreateGroup") def create_group( self, @@ -2826,6 +3055,10 @@ def disable_organizations_root_sessions( ) -> DisableOrganizationsRootSessionsResponse: raise NotImplementedError + @handler("DisableOutboundWebIdentityFederation") + def disable_outbound_web_identity_federation(self, context: RequestContext, **kwargs) -> None: + raise NotImplementedError + @handler("EnableMFADevice") def enable_mfa_device( self, @@ -2850,6 +3083,12 @@ def enable_organizations_root_sessions( ) -> EnableOrganizationsRootSessionsResponse: raise NotImplementedError + @handler("EnableOutboundWebIdentityFederation") + def enable_outbound_web_identity_federation( + self, context: RequestContext, **kwargs + ) -> EnableOutboundWebIdentityFederationResponse: + raise NotImplementedError + @handler("GenerateCredentialReport") def generate_credential_report( self, context: RequestContext, **kwargs @@ -2925,6 +3164,16 @@ def get_credential_report( ) -> GetCredentialReportResponse: raise NotImplementedError + @handler("GetDelegationRequest") + def get_delegation_request( + self, + context: RequestContext, + delegation_request_id: delegationRequestIdType, + delegation_permission_check: booleanType | None = None, + **kwargs, + ) -> GetDelegationRequestResponse: + raise NotImplementedError + @handler("GetGroup") def get_group( self, @@ -2946,6 +3195,16 @@ def get_group_policy( ) -> GetGroupPolicyResponse: raise NotImplementedError + @handler("GetHumanReadableSummary") + def get_human_readable_summary( + self, + context: RequestContext, + entity_arn: arnType, + locale: localeType | None = None, + **kwargs, + ) -> GetHumanReadableSummaryResponse: + raise NotImplementedError + @handler("GetInstanceProfile") def get_instance_profile( self, context: RequestContext, instance_profile_name: instanceProfileNameType, **kwargs @@ -2986,6 +3245,12 @@ def get_organizations_access_report( ) -> GetOrganizationsAccessReportResponse: raise NotImplementedError + @handler("GetOutboundWebIdentityFederationInfo") + def get_outbound_web_identity_federation_info( + self, context: RequestContext, **kwargs + ) -> GetOutboundWebIdentityFederationInfoResponse: + raise NotImplementedError + @handler("GetPolicy") def get_policy( self, context: RequestContext, policy_arn: arnType, **kwargs @@ -3143,6 +3408,17 @@ def list_attached_user_policies( ) -> ListAttachedUserPoliciesResponse: raise NotImplementedError + @handler("ListDelegationRequests") + def list_delegation_requests( + self, + context: RequestContext, + owner_id: ownerIdType | None = None, + marker: markerType | None = None, + max_items: maxItemsType | None = None, + **kwargs, + ) -> ListDelegationRequestsResponse: + raise NotImplementedError + @handler("ListEntitiesForPolicy") def list_entities_for_policy( self, @@ -3517,6 +3793,16 @@ def put_user_policy( ) -> None: raise NotImplementedError + @handler("RejectDelegationRequest") + def reject_delegation_request( + self, + context: RequestContext, + delegation_request_id: delegationRequestIdType, + notes: notesType | None = None, + **kwargs, + ) -> None: + raise NotImplementedError + @handler("RemoveClientIDFromOpenIDConnectProvider") def remove_client_id_from_open_id_connect_provider( self, @@ -3569,6 +3855,12 @@ def resync_mfa_device( ) -> None: raise NotImplementedError + @handler("SendDelegationToken") + def send_delegation_token( + self, context: RequestContext, delegation_request_id: delegationRequestIdType, **kwargs + ) -> None: + raise NotImplementedError + @handler("SetDefaultPolicyVersion") def set_default_policy_version( self, @@ -3797,6 +4089,16 @@ def update_assume_role_policy( ) -> None: raise NotImplementedError + @handler("UpdateDelegationRequest") + def update_delegation_request( + self, + context: RequestContext, + delegation_request_id: delegationRequestIdType, + notes: notesType | None = None, + **kwargs, + ) -> None: + raise NotImplementedError + @handler("UpdateGroup") def update_group( self, diff --git a/localstack-core/localstack/aws/api/kinesis/__init__.py b/localstack-core/localstack/aws/api/kinesis/__init__.py index 61f6f105fac9c..578d33a79a342 100644 --- a/localstack-core/localstack/aws/api/kinesis/__init__.py +++ b/localstack-core/localstack/aws/api/kinesis/__init__.py @@ -1,6 +1,7 @@ +from collections.abc import Iterator from datetime import datetime from enum import StrEnum -from typing import Dict, Iterator, List, Optional, TypedDict +from typing import TypedDict from localstack.aws.api import RequestContext, ServiceException, ServiceRequest, handler @@ -18,6 +19,8 @@ ListStreamConsumersInputLimit = int ListStreamsInputLimit = int ListTagsForStreamInputLimit = int +MaxRecordSizeInKiB = int +NaturalIntegerObject = int NextToken = str OnDemandStreamCountLimitObject = int OnDemandStreamCountObject = int @@ -31,6 +34,7 @@ ShardId = str ShardIterator = str StreamARN = str +StreamId = str StreamName = str TagKey = str TagValue = str @@ -58,6 +62,17 @@ class MetricsName(StrEnum): ALL = "ALL" +class MinimumThroughputBillingCommitmentInputStatus(StrEnum): + ENABLED = "ENABLED" + DISABLED = "DISABLED" + + +class MinimumThroughputBillingCommitmentOutputStatus(StrEnum): + ENABLED = "ENABLED" + DISABLED = "DISABLED" + ENABLED_UNTIL_EARLIEST_ALLOWED_END = "ENABLED_UNTIL_EARLIEST_ALLOWED_END" + + class ScalingType(StrEnum): UNIFORM_SCALING = "UNIFORM_SCALING" @@ -187,13 +202,14 @@ class ValidationException(ServiceException): status_code: int = 400 -TagMap = Dict[TagKey, TagValue] +TagMap = dict[TagKey, TagValue] class AddTagsToStreamInput(ServiceRequest): - StreamName: Optional[StreamName] + StreamName: StreamName | None Tags: TagMap - StreamARN: Optional[StreamARN] + StreamARN: StreamARN | None + StreamId: StreamId | None class HashKeyRange(TypedDict, total=False): @@ -201,7 +217,7 @@ class HashKeyRange(TypedDict, total=False): EndingHashKey: HashKey -ShardIdList = List[ShardId] +ShardIdList = list[ShardId] class ChildShard(TypedDict, total=False): @@ -210,7 +226,7 @@ class ChildShard(TypedDict, total=False): HashKeyRange: HashKeyRange -ChildShardList = List[ChildShard] +ChildShardList = list[ChildShard] Timestamp = datetime @@ -229,7 +245,7 @@ class ConsumerDescription(TypedDict, total=False): StreamARN: StreamARN -ConsumerList = List[Consumer] +ConsumerList = list[Consumer] class StreamModeDetails(TypedDict, total=False): @@ -238,34 +254,55 @@ class StreamModeDetails(TypedDict, total=False): class CreateStreamInput(ServiceRequest): StreamName: StreamName - ShardCount: Optional[PositiveIntegerObject] - StreamModeDetails: Optional[StreamModeDetails] - Tags: Optional[TagMap] + ShardCount: PositiveIntegerObject | None + StreamModeDetails: StreamModeDetails | None + Tags: TagMap | None + WarmThroughputMiBps: NaturalIntegerObject | None + MaxRecordSizeInKiB: MaxRecordSizeInKiB | None Data = bytes class DecreaseStreamRetentionPeriodInput(ServiceRequest): - StreamName: Optional[StreamName] + StreamName: StreamName | None RetentionPeriodHours: RetentionPeriodHours - StreamARN: Optional[StreamARN] + StreamARN: StreamARN | None + StreamId: StreamId | None class DeleteResourcePolicyInput(ServiceRequest): ResourceARN: ResourceARN + StreamId: StreamId | None class DeleteStreamInput(ServiceRequest): - StreamName: Optional[StreamName] - EnforceConsumerDeletion: Optional[BooleanObject] - StreamARN: Optional[StreamARN] + StreamName: StreamName | None + EnforceConsumerDeletion: BooleanObject | None + StreamARN: StreamARN | None + StreamId: StreamId | None class DeregisterStreamConsumerInput(ServiceRequest): - StreamARN: Optional[StreamARN] - ConsumerName: Optional[ConsumerName] - ConsumerARN: Optional[ConsumerARN] + StreamARN: StreamARN | None + ConsumerName: ConsumerName | None + ConsumerARN: ConsumerARN | None + StreamId: StreamId | None + + +class DescribeAccountSettingsInput(ServiceRequest): + pass + + +class MinimumThroughputBillingCommitmentOutput(TypedDict, total=False): + Status: MinimumThroughputBillingCommitmentOutputStatus + StartedAt: Timestamp | None + EndedAt: Timestamp | None + EarliestAllowedEndAt: Timestamp | None + + +class DescribeAccountSettingsOutput(TypedDict, total=False): + MinimumThroughputBillingCommitment: MinimumThroughputBillingCommitmentOutput | None class DescribeLimitsInput(ServiceRequest): @@ -280,9 +317,10 @@ class DescribeLimitsOutput(TypedDict, total=False): class DescribeStreamConsumerInput(ServiceRequest): - StreamARN: Optional[StreamARN] - ConsumerName: Optional[ConsumerName] - ConsumerARN: Optional[ConsumerARN] + StreamARN: StreamARN | None + ConsumerName: ConsumerName | None + ConsumerARN: ConsumerARN | None + StreamId: StreamId | None class DescribeStreamConsumerOutput(TypedDict, total=False): @@ -290,50 +328,51 @@ class DescribeStreamConsumerOutput(TypedDict, total=False): class DescribeStreamInput(ServiceRequest): - StreamName: Optional[StreamName] - Limit: Optional[DescribeStreamInputLimit] - ExclusiveStartShardId: Optional[ShardId] - StreamARN: Optional[StreamARN] + StreamName: StreamName | None + Limit: DescribeStreamInputLimit | None + ExclusiveStartShardId: ShardId | None + StreamARN: StreamARN | None + StreamId: StreamId | None -MetricsNameList = List[MetricsName] +MetricsNameList = list[MetricsName] class EnhancedMetrics(TypedDict, total=False): - ShardLevelMetrics: Optional[MetricsNameList] + ShardLevelMetrics: MetricsNameList | None -EnhancedMonitoringList = List[EnhancedMetrics] +EnhancedMonitoringList = list[EnhancedMetrics] class SequenceNumberRange(TypedDict, total=False): StartingSequenceNumber: SequenceNumber - EndingSequenceNumber: Optional[SequenceNumber] + EndingSequenceNumber: SequenceNumber | None class Shard(TypedDict, total=False): ShardId: ShardId - ParentShardId: Optional[ShardId] - AdjacentParentShardId: Optional[ShardId] + ParentShardId: ShardId | None + AdjacentParentShardId: ShardId | None HashKeyRange: HashKeyRange SequenceNumberRange: SequenceNumberRange -ShardList = List[Shard] +ShardList = list[Shard] class StreamDescription(TypedDict, total=False): StreamName: StreamName StreamARN: StreamARN StreamStatus: StreamStatus - StreamModeDetails: Optional[StreamModeDetails] + StreamModeDetails: StreamModeDetails | None Shards: ShardList HasMoreShards: BooleanObject RetentionPeriodHours: RetentionPeriodHours StreamCreationTimestamp: Timestamp EnhancedMonitoring: EnhancedMonitoringList - EncryptionType: Optional[EncryptionType] - KeyId: Optional[KeyId] + EncryptionType: EncryptionType | None + KeyId: KeyId | None class DescribeStreamOutput(TypedDict, total=False): @@ -341,22 +380,31 @@ class DescribeStreamOutput(TypedDict, total=False): class DescribeStreamSummaryInput(ServiceRequest): - StreamName: Optional[StreamName] - StreamARN: Optional[StreamARN] + StreamName: StreamName | None + StreamARN: StreamARN | None + StreamId: StreamId | None + + +class WarmThroughputObject(TypedDict, total=False): + TargetMiBps: NaturalIntegerObject | None + CurrentMiBps: NaturalIntegerObject | None class StreamDescriptionSummary(TypedDict, total=False): StreamName: StreamName StreamARN: StreamARN + StreamId: StreamId | None StreamStatus: StreamStatus - StreamModeDetails: Optional[StreamModeDetails] + StreamModeDetails: StreamModeDetails | None RetentionPeriodHours: RetentionPeriodHours StreamCreationTimestamp: Timestamp EnhancedMonitoring: EnhancedMonitoringList - EncryptionType: Optional[EncryptionType] - KeyId: Optional[KeyId] + EncryptionType: EncryptionType | None + KeyId: KeyId | None OpenShardCount: ShardCountObject - ConsumerCount: Optional[ConsumerCountObject] + ConsumerCount: ConsumerCountObject | None + WarmThroughput: WarmThroughputObject | None + MaxRecordSizeInKiB: MaxRecordSizeInKiB | None class DescribeStreamSummaryOutput(TypedDict, total=False): @@ -364,28 +412,31 @@ class DescribeStreamSummaryOutput(TypedDict, total=False): class DisableEnhancedMonitoringInput(ServiceRequest): - StreamName: Optional[StreamName] + StreamName: StreamName | None ShardLevelMetrics: MetricsNameList - StreamARN: Optional[StreamARN] + StreamARN: StreamARN | None + StreamId: StreamId | None class EnableEnhancedMonitoringInput(ServiceRequest): - StreamName: Optional[StreamName] + StreamName: StreamName | None ShardLevelMetrics: MetricsNameList - StreamARN: Optional[StreamARN] + StreamARN: StreamARN | None + StreamId: StreamId | None class EnhancedMonitoringOutput(TypedDict, total=False): - StreamName: Optional[StreamName] - CurrentShardLevelMetrics: Optional[MetricsNameList] - DesiredShardLevelMetrics: Optional[MetricsNameList] - StreamARN: Optional[StreamARN] + StreamName: StreamName | None + CurrentShardLevelMetrics: MetricsNameList | None + DesiredShardLevelMetrics: MetricsNameList | None + StreamARN: StreamARN | None class GetRecordsInput(ServiceRequest): ShardIterator: ShardIterator - Limit: Optional[GetRecordsInputLimit] - StreamARN: Optional[StreamARN] + Limit: GetRecordsInputLimit | None + StreamARN: StreamARN | None + StreamId: StreamId | None MillisBehindLatest = int @@ -393,24 +444,25 @@ class GetRecordsInput(ServiceRequest): class Record(TypedDict, total=False): SequenceNumber: SequenceNumber - ApproximateArrivalTimestamp: Optional[Timestamp] + ApproximateArrivalTimestamp: Timestamp | None Data: Data PartitionKey: PartitionKey - EncryptionType: Optional[EncryptionType] + EncryptionType: EncryptionType | None -RecordList = List[Record] +RecordList = list[Record] class GetRecordsOutput(TypedDict, total=False): Records: RecordList - NextShardIterator: Optional[ShardIterator] - MillisBehindLatest: Optional[MillisBehindLatest] - ChildShards: Optional[ChildShardList] + NextShardIterator: ShardIterator | None + MillisBehindLatest: MillisBehindLatest | None + ChildShards: ChildShardList | None class GetResourcePolicyInput(ServiceRequest): ResourceARN: ResourceARN + StreamId: StreamId | None class GetResourcePolicyOutput(TypedDict, total=False): @@ -418,103 +470,109 @@ class GetResourcePolicyOutput(TypedDict, total=False): class GetShardIteratorInput(ServiceRequest): - StreamName: Optional[StreamName] + StreamName: StreamName | None ShardId: ShardId ShardIteratorType: ShardIteratorType - StartingSequenceNumber: Optional[SequenceNumber] - Timestamp: Optional[Timestamp] - StreamARN: Optional[StreamARN] + StartingSequenceNumber: SequenceNumber | None + Timestamp: Timestamp | None + StreamARN: StreamARN | None + StreamId: StreamId | None class GetShardIteratorOutput(TypedDict, total=False): - ShardIterator: Optional[ShardIterator] + ShardIterator: ShardIterator | None class IncreaseStreamRetentionPeriodInput(ServiceRequest): - StreamName: Optional[StreamName] + StreamName: StreamName | None RetentionPeriodHours: RetentionPeriodHours - StreamARN: Optional[StreamARN] + StreamARN: StreamARN | None + StreamId: StreamId | None class ShardFilter(TypedDict, total=False): Type: ShardFilterType - ShardId: Optional[ShardId] - Timestamp: Optional[Timestamp] + ShardId: ShardId | None + Timestamp: Timestamp | None class ListShardsInput(ServiceRequest): - StreamName: Optional[StreamName] - NextToken: Optional[NextToken] - ExclusiveStartShardId: Optional[ShardId] - MaxResults: Optional[ListShardsInputLimit] - StreamCreationTimestamp: Optional[Timestamp] - ShardFilter: Optional[ShardFilter] - StreamARN: Optional[StreamARN] + StreamName: StreamName | None + NextToken: NextToken | None + ExclusiveStartShardId: ShardId | None + MaxResults: ListShardsInputLimit | None + StreamCreationTimestamp: Timestamp | None + ShardFilter: ShardFilter | None + StreamARN: StreamARN | None + StreamId: StreamId | None class ListShardsOutput(TypedDict, total=False): - Shards: Optional[ShardList] - NextToken: Optional[NextToken] + Shards: ShardList | None + NextToken: NextToken | None class ListStreamConsumersInput(ServiceRequest): StreamARN: StreamARN - NextToken: Optional[NextToken] - MaxResults: Optional[ListStreamConsumersInputLimit] - StreamCreationTimestamp: Optional[Timestamp] + NextToken: NextToken | None + MaxResults: ListStreamConsumersInputLimit | None + StreamCreationTimestamp: Timestamp | None + StreamId: StreamId | None class ListStreamConsumersOutput(TypedDict, total=False): - Consumers: Optional[ConsumerList] - NextToken: Optional[NextToken] + Consumers: ConsumerList | None + NextToken: NextToken | None class ListStreamsInput(ServiceRequest): - Limit: Optional[ListStreamsInputLimit] - ExclusiveStartStreamName: Optional[StreamName] - NextToken: Optional[NextToken] + Limit: ListStreamsInputLimit | None + ExclusiveStartStreamName: StreamName | None + NextToken: NextToken | None class StreamSummary(TypedDict, total=False): StreamName: StreamName StreamARN: StreamARN StreamStatus: StreamStatus - StreamModeDetails: Optional[StreamModeDetails] - StreamCreationTimestamp: Optional[Timestamp] + StreamModeDetails: StreamModeDetails | None + StreamCreationTimestamp: Timestamp | None -StreamSummaryList = List[StreamSummary] -StreamNameList = List[StreamName] +StreamSummaryList = list[StreamSummary] +StreamNameList = list[StreamName] class ListStreamsOutput(TypedDict, total=False): StreamNames: StreamNameList HasMoreStreams: BooleanObject - NextToken: Optional[NextToken] - StreamSummaries: Optional[StreamSummaryList] + NextToken: NextToken | None + StreamSummaries: StreamSummaryList | None class ListTagsForResourceInput(ServiceRequest): ResourceARN: ResourceARN + StreamId: StreamId | None class Tag(TypedDict, total=False): Key: TagKey - Value: Optional[TagValue] + Value: TagValue | None -TagList = List[Tag] +TagList = list[Tag] class ListTagsForResourceOutput(TypedDict, total=False): - Tags: Optional[TagList] + Tags: TagList | None class ListTagsForStreamInput(ServiceRequest): - StreamName: Optional[StreamName] - ExclusiveStartTagKey: Optional[TagKey] - Limit: Optional[ListTagsForStreamInputLimit] - StreamARN: Optional[StreamARN] + StreamName: StreamName | None + ExclusiveStartTagKey: TagKey | None + Limit: ListTagsForStreamInputLimit | None + StreamARN: StreamARN | None + StreamId: StreamId | None class ListTagsForStreamOutput(TypedDict, total=False): @@ -523,131 +581,145 @@ class ListTagsForStreamOutput(TypedDict, total=False): class MergeShardsInput(ServiceRequest): - StreamName: Optional[StreamName] + StreamName: StreamName | None ShardToMerge: ShardId AdjacentShardToMerge: ShardId - StreamARN: Optional[StreamARN] + StreamARN: StreamARN | None + StreamId: StreamId | None + + +class MinimumThroughputBillingCommitmentInput(TypedDict, total=False): + Status: MinimumThroughputBillingCommitmentInputStatus class PutRecordInput(ServiceRequest): - StreamName: Optional[StreamName] + StreamName: StreamName | None Data: Data PartitionKey: PartitionKey - ExplicitHashKey: Optional[HashKey] - SequenceNumberForOrdering: Optional[SequenceNumber] - StreamARN: Optional[StreamARN] + ExplicitHashKey: HashKey | None + SequenceNumberForOrdering: SequenceNumber | None + StreamARN: StreamARN | None + StreamId: StreamId | None class PutRecordOutput(TypedDict, total=False): ShardId: ShardId SequenceNumber: SequenceNumber - EncryptionType: Optional[EncryptionType] + EncryptionType: EncryptionType | None class PutRecordsRequestEntry(TypedDict, total=False): Data: Data - ExplicitHashKey: Optional[HashKey] + ExplicitHashKey: HashKey | None PartitionKey: PartitionKey -PutRecordsRequestEntryList = List[PutRecordsRequestEntry] +PutRecordsRequestEntryList = list[PutRecordsRequestEntry] class PutRecordsInput(ServiceRequest): Records: PutRecordsRequestEntryList - StreamName: Optional[StreamName] - StreamARN: Optional[StreamARN] + StreamName: StreamName | None + StreamARN: StreamARN | None + StreamId: StreamId | None class PutRecordsResultEntry(TypedDict, total=False): - SequenceNumber: Optional[SequenceNumber] - ShardId: Optional[ShardId] - ErrorCode: Optional[ErrorCode] - ErrorMessage: Optional[ErrorMessage] + SequenceNumber: SequenceNumber | None + ShardId: ShardId | None + ErrorCode: ErrorCode | None + ErrorMessage: ErrorMessage | None -PutRecordsResultEntryList = List[PutRecordsResultEntry] +PutRecordsResultEntryList = list[PutRecordsResultEntry] class PutRecordsOutput(TypedDict, total=False): - FailedRecordCount: Optional[PositiveIntegerObject] + FailedRecordCount: PositiveIntegerObject | None Records: PutRecordsResultEntryList - EncryptionType: Optional[EncryptionType] + EncryptionType: EncryptionType | None class PutResourcePolicyInput(ServiceRequest): ResourceARN: ResourceARN + StreamId: StreamId | None Policy: Policy class RegisterStreamConsumerInput(ServiceRequest): StreamARN: StreamARN ConsumerName: ConsumerName - Tags: Optional[TagMap] + StreamId: StreamId | None + Tags: TagMap | None class RegisterStreamConsumerOutput(TypedDict, total=False): Consumer: Consumer -TagKeyList = List[TagKey] +TagKeyList = list[TagKey] class RemoveTagsFromStreamInput(ServiceRequest): - StreamName: Optional[StreamName] + StreamName: StreamName | None TagKeys: TagKeyList - StreamARN: Optional[StreamARN] + StreamARN: StreamARN | None + StreamId: StreamId | None class SplitShardInput(ServiceRequest): - StreamName: Optional[StreamName] + StreamName: StreamName | None ShardToSplit: ShardId NewStartingHashKey: HashKey - StreamARN: Optional[StreamARN] + StreamARN: StreamARN | None + StreamId: StreamId | None class StartStreamEncryptionInput(ServiceRequest): - StreamName: Optional[StreamName] + StreamName: StreamName | None EncryptionType: EncryptionType KeyId: KeyId - StreamARN: Optional[StreamARN] + StreamARN: StreamARN | None + StreamId: StreamId | None class StartingPosition(TypedDict, total=False): Type: ShardIteratorType - SequenceNumber: Optional[SequenceNumber] - Timestamp: Optional[Timestamp] + SequenceNumber: SequenceNumber | None + Timestamp: Timestamp | None class StopStreamEncryptionInput(ServiceRequest): - StreamName: Optional[StreamName] + StreamName: StreamName | None EncryptionType: EncryptionType KeyId: KeyId - StreamARN: Optional[StreamARN] + StreamARN: StreamARN | None + StreamId: StreamId | None class SubscribeToShardEvent(TypedDict, total=False): Records: RecordList ContinuationSequenceNumber: SequenceNumber MillisBehindLatest: MillisBehindLatest - ChildShards: Optional[ChildShardList] + ChildShards: ChildShardList | None class SubscribeToShardEventStream(TypedDict, total=False): SubscribeToShardEvent: SubscribeToShardEvent - ResourceNotFoundException: Optional[ResourceNotFoundException] - ResourceInUseException: Optional[ResourceInUseException] - KMSDisabledException: Optional[KMSDisabledException] - KMSInvalidStateException: Optional[KMSInvalidStateException] - KMSAccessDeniedException: Optional[KMSAccessDeniedException] - KMSNotFoundException: Optional[KMSNotFoundException] - KMSOptInRequired: Optional[KMSOptInRequired] - KMSThrottlingException: Optional[KMSThrottlingException] - InternalFailureException: Optional[InternalFailureException] + ResourceNotFoundException: ResourceNotFoundException | None + ResourceInUseException: ResourceInUseException | None + KMSDisabledException: KMSDisabledException | None + KMSInvalidStateException: KMSInvalidStateException | None + KMSAccessDeniedException: KMSAccessDeniedException | None + KMSNotFoundException: KMSNotFoundException | None + KMSOptInRequired: KMSOptInRequired | None + KMSThrottlingException: KMSThrottlingException | None + InternalFailureException: InternalFailureException | None class SubscribeToShardInput(ServiceRequest): ConsumerARN: ConsumerARN + StreamId: StreamId | None ShardId: ShardId StartingPosition: StartingPosition @@ -659,35 +731,67 @@ class SubscribeToShardOutput(TypedDict, total=False): class TagResourceInput(ServiceRequest): Tags: TagMap ResourceARN: ResourceARN + StreamId: StreamId | None class UntagResourceInput(ServiceRequest): TagKeys: TagKeyList ResourceARN: ResourceARN + StreamId: StreamId | None + + +class UpdateAccountSettingsInput(ServiceRequest): + MinimumThroughputBillingCommitment: MinimumThroughputBillingCommitmentInput + + +class UpdateAccountSettingsOutput(TypedDict, total=False): + MinimumThroughputBillingCommitment: MinimumThroughputBillingCommitmentOutput | None + + +class UpdateMaxRecordSizeInput(ServiceRequest): + StreamARN: StreamARN | None + StreamId: StreamId | None + MaxRecordSizeInKiB: MaxRecordSizeInKiB class UpdateShardCountInput(ServiceRequest): - StreamName: Optional[StreamName] + StreamName: StreamName | None TargetShardCount: PositiveIntegerObject ScalingType: ScalingType - StreamARN: Optional[StreamARN] + StreamARN: StreamARN | None + StreamId: StreamId | None class UpdateShardCountOutput(TypedDict, total=False): - StreamName: Optional[StreamName] - CurrentShardCount: Optional[PositiveIntegerObject] - TargetShardCount: Optional[PositiveIntegerObject] - StreamARN: Optional[StreamARN] + StreamName: StreamName | None + CurrentShardCount: PositiveIntegerObject | None + TargetShardCount: PositiveIntegerObject | None + StreamARN: StreamARN | None class UpdateStreamModeInput(ServiceRequest): StreamARN: StreamARN + StreamId: StreamId | None StreamModeDetails: StreamModeDetails + WarmThroughputMiBps: NaturalIntegerObject | None + + +class UpdateStreamWarmThroughputInput(ServiceRequest): + StreamARN: StreamARN | None + StreamName: StreamName | None + StreamId: StreamId | None + WarmThroughputMiBps: NaturalIntegerObject + + +class UpdateStreamWarmThroughputOutput(TypedDict, total=False): + StreamARN: StreamARN | None + StreamName: StreamName | None + WarmThroughput: WarmThroughputObject | None class KinesisApi: - service = "kinesis" - version = "2013-12-02" + service: str = "kinesis" + version: str = "2013-12-02" @handler("AddTagsToStream") def add_tags_to_stream( @@ -696,6 +800,7 @@ def add_tags_to_stream( tags: TagMap, stream_name: StreamName | None = None, stream_arn: StreamARN | None = None, + stream_id: StreamId | None = None, **kwargs, ) -> None: raise NotImplementedError @@ -708,6 +813,8 @@ def create_stream( shard_count: PositiveIntegerObject | None = None, stream_mode_details: StreamModeDetails | None = None, tags: TagMap | None = None, + warm_throughput_mi_bps: NaturalIntegerObject | None = None, + max_record_size_in_ki_b: MaxRecordSizeInKiB | None = None, **kwargs, ) -> None: raise NotImplementedError @@ -719,13 +826,18 @@ def decrease_stream_retention_period( retention_period_hours: RetentionPeriodHours, stream_name: StreamName | None = None, stream_arn: StreamARN | None = None, + stream_id: StreamId | None = None, **kwargs, ) -> None: raise NotImplementedError @handler("DeleteResourcePolicy") def delete_resource_policy( - self, context: RequestContext, resource_arn: ResourceARN, **kwargs + self, + context: RequestContext, + resource_arn: ResourceARN, + stream_id: StreamId | None = None, + **kwargs, ) -> None: raise NotImplementedError @@ -736,6 +848,7 @@ def delete_stream( stream_name: StreamName | None = None, enforce_consumer_deletion: BooleanObject | None = None, stream_arn: StreamARN | None = None, + stream_id: StreamId | None = None, **kwargs, ) -> None: raise NotImplementedError @@ -747,10 +860,17 @@ def deregister_stream_consumer( stream_arn: StreamARN | None = None, consumer_name: ConsumerName | None = None, consumer_arn: ConsumerARN | None = None, + stream_id: StreamId | None = None, **kwargs, ) -> None: raise NotImplementedError + @handler("DescribeAccountSettings") + def describe_account_settings( + self, context: RequestContext, **kwargs + ) -> DescribeAccountSettingsOutput: + raise NotImplementedError + @handler("DescribeLimits") def describe_limits(self, context: RequestContext, **kwargs) -> DescribeLimitsOutput: raise NotImplementedError @@ -763,6 +883,7 @@ def describe_stream( limit: DescribeStreamInputLimit | None = None, exclusive_start_shard_id: ShardId | None = None, stream_arn: StreamARN | None = None, + stream_id: StreamId | None = None, **kwargs, ) -> DescribeStreamOutput: raise NotImplementedError @@ -774,6 +895,7 @@ def describe_stream_consumer( stream_arn: StreamARN | None = None, consumer_name: ConsumerName | None = None, consumer_arn: ConsumerARN | None = None, + stream_id: StreamId | None = None, **kwargs, ) -> DescribeStreamConsumerOutput: raise NotImplementedError @@ -784,6 +906,7 @@ def describe_stream_summary( context: RequestContext, stream_name: StreamName | None = None, stream_arn: StreamARN | None = None, + stream_id: StreamId | None = None, **kwargs, ) -> DescribeStreamSummaryOutput: raise NotImplementedError @@ -795,6 +918,7 @@ def disable_enhanced_monitoring( shard_level_metrics: MetricsNameList, stream_name: StreamName | None = None, stream_arn: StreamARN | None = None, + stream_id: StreamId | None = None, **kwargs, ) -> EnhancedMonitoringOutput: raise NotImplementedError @@ -806,6 +930,7 @@ def enable_enhanced_monitoring( shard_level_metrics: MetricsNameList, stream_name: StreamName | None = None, stream_arn: StreamARN | None = None, + stream_id: StreamId | None = None, **kwargs, ) -> EnhancedMonitoringOutput: raise NotImplementedError @@ -817,13 +942,18 @@ def get_records( shard_iterator: ShardIterator, limit: GetRecordsInputLimit | None = None, stream_arn: StreamARN | None = None, + stream_id: StreamId | None = None, **kwargs, ) -> GetRecordsOutput: raise NotImplementedError @handler("GetResourcePolicy") def get_resource_policy( - self, context: RequestContext, resource_arn: ResourceARN, **kwargs + self, + context: RequestContext, + resource_arn: ResourceARN, + stream_id: StreamId | None = None, + **kwargs, ) -> GetResourcePolicyOutput: raise NotImplementedError @@ -837,6 +967,7 @@ def get_shard_iterator( starting_sequence_number: SequenceNumber | None = None, timestamp: Timestamp | None = None, stream_arn: StreamARN | None = None, + stream_id: StreamId | None = None, **kwargs, ) -> GetShardIteratorOutput: raise NotImplementedError @@ -848,6 +979,7 @@ def increase_stream_retention_period( retention_period_hours: RetentionPeriodHours, stream_name: StreamName | None = None, stream_arn: StreamARN | None = None, + stream_id: StreamId | None = None, **kwargs, ) -> None: raise NotImplementedError @@ -863,6 +995,7 @@ def list_shards( stream_creation_timestamp: Timestamp | None = None, shard_filter: ShardFilter | None = None, stream_arn: StreamARN | None = None, + stream_id: StreamId | None = None, **kwargs, ) -> ListShardsOutput: raise NotImplementedError @@ -875,6 +1008,7 @@ def list_stream_consumers( next_token: NextToken | None = None, max_results: ListStreamConsumersInputLimit | None = None, stream_creation_timestamp: Timestamp | None = None, + stream_id: StreamId | None = None, **kwargs, ) -> ListStreamConsumersOutput: raise NotImplementedError @@ -892,7 +1026,11 @@ def list_streams( @handler("ListTagsForResource") def list_tags_for_resource( - self, context: RequestContext, resource_arn: ResourceARN, **kwargs + self, + context: RequestContext, + resource_arn: ResourceARN, + stream_id: StreamId | None = None, + **kwargs, ) -> ListTagsForResourceOutput: raise NotImplementedError @@ -904,6 +1042,7 @@ def list_tags_for_stream( exclusive_start_tag_key: TagKey | None = None, limit: ListTagsForStreamInputLimit | None = None, stream_arn: StreamARN | None = None, + stream_id: StreamId | None = None, **kwargs, ) -> ListTagsForStreamOutput: raise NotImplementedError @@ -916,6 +1055,7 @@ def merge_shards( adjacent_shard_to_merge: ShardId, stream_name: StreamName | None = None, stream_arn: StreamARN | None = None, + stream_id: StreamId | None = None, **kwargs, ) -> None: raise NotImplementedError @@ -930,6 +1070,7 @@ def put_record( explicit_hash_key: HashKey | None = None, sequence_number_for_ordering: SequenceNumber | None = None, stream_arn: StreamARN | None = None, + stream_id: StreamId | None = None, **kwargs, ) -> PutRecordOutput: raise NotImplementedError @@ -941,13 +1082,19 @@ def put_records( records: PutRecordsRequestEntryList, stream_name: StreamName | None = None, stream_arn: StreamARN | None = None, + stream_id: StreamId | None = None, **kwargs, ) -> PutRecordsOutput: raise NotImplementedError @handler("PutResourcePolicy") def put_resource_policy( - self, context: RequestContext, resource_arn: ResourceARN, policy: Policy, **kwargs + self, + context: RequestContext, + resource_arn: ResourceARN, + policy: Policy, + stream_id: StreamId | None = None, + **kwargs, ) -> None: raise NotImplementedError @@ -957,6 +1104,7 @@ def register_stream_consumer( context: RequestContext, stream_arn: StreamARN, consumer_name: ConsumerName, + stream_id: StreamId | None = None, tags: TagMap | None = None, **kwargs, ) -> RegisterStreamConsumerOutput: @@ -969,6 +1117,7 @@ def remove_tags_from_stream( tag_keys: TagKeyList, stream_name: StreamName | None = None, stream_arn: StreamARN | None = None, + stream_id: StreamId | None = None, **kwargs, ) -> None: raise NotImplementedError @@ -981,6 +1130,7 @@ def split_shard( new_starting_hash_key: HashKey, stream_name: StreamName | None = None, stream_arn: StreamARN | None = None, + stream_id: StreamId | None = None, **kwargs, ) -> None: raise NotImplementedError @@ -993,6 +1143,7 @@ def start_stream_encryption( key_id: KeyId, stream_name: StreamName | None = None, stream_arn: StreamARN | None = None, + stream_id: StreamId | None = None, **kwargs, ) -> None: raise NotImplementedError @@ -1005,6 +1156,7 @@ def stop_stream_encryption( key_id: KeyId, stream_name: StreamName | None = None, stream_arn: StreamARN | None = None, + stream_id: StreamId | None = None, **kwargs, ) -> None: raise NotImplementedError @@ -1016,19 +1168,50 @@ def subscribe_to_shard( consumer_arn: ConsumerARN, shard_id: ShardId, starting_position: StartingPosition, + stream_id: StreamId | None = None, **kwargs, ) -> SubscribeToShardOutput: raise NotImplementedError @handler("TagResource") def tag_resource( - self, context: RequestContext, tags: TagMap, resource_arn: ResourceARN, **kwargs + self, + context: RequestContext, + tags: TagMap, + resource_arn: ResourceARN, + stream_id: StreamId | None = None, + **kwargs, ) -> None: raise NotImplementedError @handler("UntagResource") def untag_resource( - self, context: RequestContext, tag_keys: TagKeyList, resource_arn: ResourceARN, **kwargs + self, + context: RequestContext, + tag_keys: TagKeyList, + resource_arn: ResourceARN, + stream_id: StreamId | None = None, + **kwargs, + ) -> None: + raise NotImplementedError + + @handler("UpdateAccountSettings") + def update_account_settings( + self, + context: RequestContext, + minimum_throughput_billing_commitment: MinimumThroughputBillingCommitmentInput, + **kwargs, + ) -> UpdateAccountSettingsOutput: + raise NotImplementedError + + @handler("UpdateMaxRecordSize") + def update_max_record_size( + self, + context: RequestContext, + max_record_size_in_ki_b: MaxRecordSizeInKiB, + stream_arn: StreamARN | None = None, + stream_id: StreamId | None = None, + **kwargs, ) -> None: raise NotImplementedError @@ -1040,6 +1223,7 @@ def update_shard_count( scaling_type: ScalingType, stream_name: StreamName | None = None, stream_arn: StreamARN | None = None, + stream_id: StreamId | None = None, **kwargs, ) -> UpdateShardCountOutput: raise NotImplementedError @@ -1050,6 +1234,20 @@ def update_stream_mode( context: RequestContext, stream_arn: StreamARN, stream_mode_details: StreamModeDetails, + stream_id: StreamId | None = None, + warm_throughput_mi_bps: NaturalIntegerObject | None = None, **kwargs, ) -> None: raise NotImplementedError + + @handler("UpdateStreamWarmThroughput") + def update_stream_warm_throughput( + self, + context: RequestContext, + warm_throughput_mi_bps: NaturalIntegerObject, + stream_arn: StreamARN | None = None, + stream_name: StreamName | None = None, + stream_id: StreamId | None = None, + **kwargs, + ) -> UpdateStreamWarmThroughputOutput: + raise NotImplementedError diff --git a/localstack-core/localstack/aws/api/kms/__init__.py b/localstack-core/localstack/aws/api/kms/__init__.py index b5e0fec886732..d320caa179a35 100644 --- a/localstack-core/localstack/aws/api/kms/__init__.py +++ b/localstack-core/localstack/aws/api/kms/__init__.py @@ -1,10 +1,11 @@ from datetime import datetime from enum import StrEnum -from typing import Dict, List, Optional, TypedDict +from typing import TypedDict from localstack.aws.api import RequestContext, ServiceException, ServiceRequest, handler AWSAccountIdType = str +AccountIdType = str AliasNameType = str ArnType = str BackingKeyIdResponseType = str @@ -114,6 +115,7 @@ class DataKeyPairSpec(StrEnum): ECC_NIST_P521 = "ECC_NIST_P521" ECC_SECG_P256K1 = "ECC_SECG_P256K1" SM2 = "SM2" + ECC_NIST_EDWARDS25519 = "ECC_NIST_EDWARDS25519" class DataKeySpec(StrEnum): @@ -121,6 +123,10 @@ class DataKeySpec(StrEnum): AES_128 = "AES_128" +class DryRunModifierType(StrEnum): + IGNORE_CIPHERTEXT = "IGNORE_CIPHERTEXT" + + class EncryptionAlgorithmSpec(StrEnum): SYMMETRIC_DEFAULT = "SYMMETRIC_DEFAULT" RSAES_OAEP_SHA_1 = "RSAES_OAEP_SHA_1" @@ -185,6 +191,7 @@ class KeyMaterialState(StrEnum): NON_CURRENT = "NON_CURRENT" CURRENT = "CURRENT" PENDING_ROTATION = "PENDING_ROTATION" + PENDING_MULTI_REGION_IMPORT_AND_ROTATION = "PENDING_MULTI_REGION_IMPORT_AND_ROTATION" class KeySpec(StrEnum): @@ -204,6 +211,7 @@ class KeySpec(StrEnum): ML_DSA_44 = "ML_DSA_44" ML_DSA_65 = "ML_DSA_65" ML_DSA_87 = "ML_DSA_87" + ECC_NIST_EDWARDS25519 = "ECC_NIST_EDWARDS25519" class KeyState(StrEnum): @@ -266,6 +274,8 @@ class SigningAlgorithmSpec(StrEnum): ECDSA_SHA_512 = "ECDSA_SHA_512" SM2DSA = "SM2DSA" ML_DSA_SHAKE_256 = "ML_DSA_SHAKE_256" + ED25519_SHA_512 = "ED25519_SHA_512" + ED25519_PH_SHA_512 = "ED25519_PH_SHA_512" class WrappingKeySpec(StrEnum): @@ -572,14 +582,14 @@ class XksProxyVpcEndpointServiceNotFoundException(ServiceException): class AliasListEntry(TypedDict, total=False): - AliasName: Optional[AliasNameType] - AliasArn: Optional[ArnType] - TargetKeyId: Optional[KeyIdType] - CreationDate: Optional[DateType] - LastUpdatedDate: Optional[DateType] + AliasName: AliasNameType | None + AliasArn: ArnType | None + TargetKeyId: KeyIdType | None + CreationDate: DateType | None + LastUpdatedDate: DateType | None -AliasList = List[AliasListEntry] +AliasList = list[AliasListEntry] AttestationDocumentType = bytes @@ -588,7 +598,7 @@ class CancelKeyDeletionRequest(ServiceRequest): class CancelKeyDeletionResponse(TypedDict, total=False): - KeyId: Optional[KeyIdType] + KeyId: KeyIdType | None CiphertextType = bytes @@ -614,47 +624,48 @@ class XksProxyAuthenticationCredentialType(TypedDict, total=False): class CreateCustomKeyStoreRequest(ServiceRequest): CustomKeyStoreName: CustomKeyStoreNameType - CloudHsmClusterId: Optional[CloudHsmClusterIdType] - TrustAnchorCertificate: Optional[TrustAnchorCertificateType] - KeyStorePassword: Optional[KeyStorePasswordType] - CustomKeyStoreType: Optional[CustomKeyStoreType] - XksProxyUriEndpoint: Optional[XksProxyUriEndpointType] - XksProxyUriPath: Optional[XksProxyUriPathType] - XksProxyVpcEndpointServiceName: Optional[XksProxyVpcEndpointServiceNameType] - XksProxyAuthenticationCredential: Optional[XksProxyAuthenticationCredentialType] - XksProxyConnectivity: Optional[XksProxyConnectivityType] + CloudHsmClusterId: CloudHsmClusterIdType | None + TrustAnchorCertificate: TrustAnchorCertificateType | None + KeyStorePassword: KeyStorePasswordType | None + CustomKeyStoreType: CustomKeyStoreType | None + XksProxyUriEndpoint: XksProxyUriEndpointType | None + XksProxyUriPath: XksProxyUriPathType | None + XksProxyVpcEndpointServiceName: XksProxyVpcEndpointServiceNameType | None + XksProxyVpcEndpointServiceOwner: AccountIdType | None + XksProxyAuthenticationCredential: XksProxyAuthenticationCredentialType | None + XksProxyConnectivity: XksProxyConnectivityType | None class CreateCustomKeyStoreResponse(TypedDict, total=False): - CustomKeyStoreId: Optional[CustomKeyStoreIdType] + CustomKeyStoreId: CustomKeyStoreIdType | None -GrantTokenList = List[GrantTokenType] -EncryptionContextType = Dict[EncryptionContextKey, EncryptionContextValue] +GrantTokenList = list[GrantTokenType] +EncryptionContextType = dict[EncryptionContextKey, EncryptionContextValue] class GrantConstraints(TypedDict, total=False): - EncryptionContextSubset: Optional[EncryptionContextType] - EncryptionContextEquals: Optional[EncryptionContextType] + EncryptionContextSubset: EncryptionContextType | None + EncryptionContextEquals: EncryptionContextType | None -GrantOperationList = List[GrantOperation] +GrantOperationList = list[GrantOperation] class CreateGrantRequest(ServiceRequest): KeyId: KeyIdType GranteePrincipal: PrincipalIdType - RetiringPrincipal: Optional[PrincipalIdType] + RetiringPrincipal: PrincipalIdType | None Operations: GrantOperationList - Constraints: Optional[GrantConstraints] - GrantTokens: Optional[GrantTokenList] - Name: Optional[GrantNameType] - DryRun: Optional[NullableBooleanType] + Constraints: GrantConstraints | None + GrantTokens: GrantTokenList | None + Name: GrantNameType | None + DryRun: NullableBooleanType | None class CreateGrantResponse(TypedDict, total=False): - GrantToken: Optional[GrantTokenType] - GrantId: Optional[GrantIdType] + GrantToken: GrantTokenType | None + GrantId: GrantIdType | None class Tag(TypedDict, total=False): @@ -662,129 +673,132 @@ class Tag(TypedDict, total=False): TagValue: TagValueType -TagList = List[Tag] +TagList = list[Tag] class CreateKeyRequest(ServiceRequest): - Policy: Optional[PolicyType] - Description: Optional[DescriptionType] - KeyUsage: Optional[KeyUsageType] - CustomerMasterKeySpec: Optional[CustomerMasterKeySpec] - KeySpec: Optional[KeySpec] - Origin: Optional[OriginType] - CustomKeyStoreId: Optional[CustomKeyStoreIdType] - BypassPolicyLockoutSafetyCheck: Optional[BooleanType] - Tags: Optional[TagList] - MultiRegion: Optional[NullableBooleanType] - XksKeyId: Optional[XksKeyIdType] + Policy: PolicyType | None + Description: DescriptionType | None + KeyUsage: KeyUsageType | None + CustomerMasterKeySpec: CustomerMasterKeySpec | None + KeySpec: KeySpec | None + Origin: OriginType | None + CustomKeyStoreId: CustomKeyStoreIdType | None + BypassPolicyLockoutSafetyCheck: BooleanType | None + Tags: TagList | None + MultiRegion: NullableBooleanType | None + XksKeyId: XksKeyIdType | None class XksKeyConfigurationType(TypedDict, total=False): - Id: Optional[XksKeyIdType] + Id: XksKeyIdType | None -MacAlgorithmSpecList = List[MacAlgorithmSpec] +MacAlgorithmSpecList = list[MacAlgorithmSpec] class MultiRegionKey(TypedDict, total=False): - Arn: Optional[ArnType] - Region: Optional[RegionType] + Arn: ArnType | None + Region: RegionType | None -MultiRegionKeyList = List[MultiRegionKey] +MultiRegionKeyList = list[MultiRegionKey] class MultiRegionConfiguration(TypedDict, total=False): - MultiRegionKeyType: Optional[MultiRegionKeyType] - PrimaryKey: Optional[MultiRegionKey] - ReplicaKeys: Optional[MultiRegionKeyList] + MultiRegionKeyType: MultiRegionKeyType | None + PrimaryKey: MultiRegionKey | None + ReplicaKeys: MultiRegionKeyList | None -KeyAgreementAlgorithmSpecList = List[KeyAgreementAlgorithmSpec] -SigningAlgorithmSpecList = List[SigningAlgorithmSpec] -EncryptionAlgorithmSpecList = List[EncryptionAlgorithmSpec] +KeyAgreementAlgorithmSpecList = list[KeyAgreementAlgorithmSpec] +SigningAlgorithmSpecList = list[SigningAlgorithmSpec] +EncryptionAlgorithmSpecList = list[EncryptionAlgorithmSpec] class KeyMetadata(TypedDict, total=False): - AWSAccountId: Optional[AWSAccountIdType] + AWSAccountId: AWSAccountIdType | None KeyId: KeyIdType - Arn: Optional[ArnType] - CreationDate: Optional[DateType] - Enabled: Optional[BooleanType] - Description: Optional[DescriptionType] - KeyUsage: Optional[KeyUsageType] - KeyState: Optional[KeyState] - DeletionDate: Optional[DateType] - ValidTo: Optional[DateType] - Origin: Optional[OriginType] - CustomKeyStoreId: Optional[CustomKeyStoreIdType] - CloudHsmClusterId: Optional[CloudHsmClusterIdType] - ExpirationModel: Optional[ExpirationModelType] - KeyManager: Optional[KeyManagerType] - CustomerMasterKeySpec: Optional[CustomerMasterKeySpec] - KeySpec: Optional[KeySpec] - EncryptionAlgorithms: Optional[EncryptionAlgorithmSpecList] - SigningAlgorithms: Optional[SigningAlgorithmSpecList] - KeyAgreementAlgorithms: Optional[KeyAgreementAlgorithmSpecList] - MultiRegion: Optional[NullableBooleanType] - MultiRegionConfiguration: Optional[MultiRegionConfiguration] - PendingDeletionWindowInDays: Optional[PendingWindowInDaysType] - MacAlgorithms: Optional[MacAlgorithmSpecList] - XksKeyConfiguration: Optional[XksKeyConfigurationType] - CurrentKeyMaterialId: Optional[BackingKeyIdType] + Arn: ArnType | None + CreationDate: DateType | None + Enabled: BooleanType | None + Description: DescriptionType | None + KeyUsage: KeyUsageType | None + KeyState: KeyState | None + DeletionDate: DateType | None + ValidTo: DateType | None + Origin: OriginType | None + CustomKeyStoreId: CustomKeyStoreIdType | None + CloudHsmClusterId: CloudHsmClusterIdType | None + ExpirationModel: ExpirationModelType | None + KeyManager: KeyManagerType | None + CustomerMasterKeySpec: CustomerMasterKeySpec | None + KeySpec: KeySpec | None + EncryptionAlgorithms: EncryptionAlgorithmSpecList | None + SigningAlgorithms: SigningAlgorithmSpecList | None + KeyAgreementAlgorithms: KeyAgreementAlgorithmSpecList | None + MultiRegion: NullableBooleanType | None + MultiRegionConfiguration: MultiRegionConfiguration | None + PendingDeletionWindowInDays: PendingWindowInDaysType | None + MacAlgorithms: MacAlgorithmSpecList | None + XksKeyConfiguration: XksKeyConfigurationType | None + CurrentKeyMaterialId: BackingKeyIdType | None class CreateKeyResponse(TypedDict, total=False): - KeyMetadata: Optional[KeyMetadata] + KeyMetadata: KeyMetadata | None class XksProxyConfigurationType(TypedDict, total=False): - Connectivity: Optional[XksProxyConnectivityType] - AccessKeyId: Optional[XksProxyAuthenticationAccessKeyIdType] - UriEndpoint: Optional[XksProxyUriEndpointType] - UriPath: Optional[XksProxyUriPathType] - VpcEndpointServiceName: Optional[XksProxyVpcEndpointServiceNameType] + Connectivity: XksProxyConnectivityType | None + AccessKeyId: XksProxyAuthenticationAccessKeyIdType | None + UriEndpoint: XksProxyUriEndpointType | None + UriPath: XksProxyUriPathType | None + VpcEndpointServiceName: XksProxyVpcEndpointServiceNameType | None + VpcEndpointServiceOwner: AccountIdType | None class CustomKeyStoresListEntry(TypedDict, total=False): - CustomKeyStoreId: Optional[CustomKeyStoreIdType] - CustomKeyStoreName: Optional[CustomKeyStoreNameType] - CloudHsmClusterId: Optional[CloudHsmClusterIdType] - TrustAnchorCertificate: Optional[TrustAnchorCertificateType] - ConnectionState: Optional[ConnectionStateType] - ConnectionErrorCode: Optional[ConnectionErrorCodeType] - CreationDate: Optional[DateType] - CustomKeyStoreType: Optional[CustomKeyStoreType] - XksProxyConfiguration: Optional[XksProxyConfigurationType] + CustomKeyStoreId: CustomKeyStoreIdType | None + CustomKeyStoreName: CustomKeyStoreNameType | None + CloudHsmClusterId: CloudHsmClusterIdType | None + TrustAnchorCertificate: TrustAnchorCertificateType | None + ConnectionState: ConnectionStateType | None + ConnectionErrorCode: ConnectionErrorCodeType | None + CreationDate: DateType | None + CustomKeyStoreType: CustomKeyStoreType | None + XksProxyConfiguration: XksProxyConfigurationType | None -CustomKeyStoresList = List[CustomKeyStoresListEntry] +CustomKeyStoresList = list[CustomKeyStoresListEntry] +DryRunModifierList = list[DryRunModifierType] class RecipientInfo(TypedDict, total=False): - KeyEncryptionAlgorithm: Optional[KeyEncryptionMechanism] - AttestationDocument: Optional[AttestationDocumentType] + KeyEncryptionAlgorithm: KeyEncryptionMechanism | None + AttestationDocument: AttestationDocumentType | None class DecryptRequest(ServiceRequest): - CiphertextBlob: CiphertextType - EncryptionContext: Optional[EncryptionContextType] - GrantTokens: Optional[GrantTokenList] - KeyId: Optional[KeyIdType] - EncryptionAlgorithm: Optional[EncryptionAlgorithmSpec] - Recipient: Optional[RecipientInfo] - DryRun: Optional[NullableBooleanType] + CiphertextBlob: CiphertextType | None + EncryptionContext: EncryptionContextType | None + GrantTokens: GrantTokenList | None + KeyId: KeyIdType | None + EncryptionAlgorithm: EncryptionAlgorithmSpec | None + Recipient: RecipientInfo | None + DryRun: NullableBooleanType | None + DryRunModifiers: DryRunModifierList | None PlaintextType = bytes class DecryptResponse(TypedDict, total=False): - KeyId: Optional[KeyIdType] - Plaintext: Optional[PlaintextType] - EncryptionAlgorithm: Optional[EncryptionAlgorithmSpec] - CiphertextForRecipient: Optional[CiphertextType] - KeyMaterialId: Optional[BackingKeyIdType] + KeyId: KeyIdType | None + Plaintext: PlaintextType | None + EncryptionAlgorithm: EncryptionAlgorithmSpec | None + CiphertextForRecipient: CiphertextType | None + KeyMaterialId: BackingKeyIdType | None class DeleteAliasRequest(ServiceRequest): @@ -801,12 +815,12 @@ class DeleteCustomKeyStoreResponse(TypedDict, total=False): class DeleteImportedKeyMaterialRequest(ServiceRequest): KeyId: KeyIdType - KeyMaterialId: Optional[BackingKeyIdType] + KeyMaterialId: BackingKeyIdType | None class DeleteImportedKeyMaterialResponse(TypedDict, total=False): - KeyId: Optional[KeyIdType] - KeyMaterialId: Optional[BackingKeyIdResponseType] + KeyId: KeyIdType | None + KeyMaterialId: BackingKeyIdResponseType | None PublicKeyType = bytes @@ -816,39 +830,39 @@ class DeriveSharedSecretRequest(ServiceRequest): KeyId: KeyIdType KeyAgreementAlgorithm: KeyAgreementAlgorithmSpec PublicKey: PublicKeyType - GrantTokens: Optional[GrantTokenList] - DryRun: Optional[NullableBooleanType] - Recipient: Optional[RecipientInfo] + GrantTokens: GrantTokenList | None + DryRun: NullableBooleanType | None + Recipient: RecipientInfo | None class DeriveSharedSecretResponse(TypedDict, total=False): - KeyId: Optional[KeyIdType] - SharedSecret: Optional[PlaintextType] - CiphertextForRecipient: Optional[CiphertextType] - KeyAgreementAlgorithm: Optional[KeyAgreementAlgorithmSpec] - KeyOrigin: Optional[OriginType] + KeyId: KeyIdType | None + SharedSecret: PlaintextType | None + CiphertextForRecipient: CiphertextType | None + KeyAgreementAlgorithm: KeyAgreementAlgorithmSpec | None + KeyOrigin: OriginType | None class DescribeCustomKeyStoresRequest(ServiceRequest): - CustomKeyStoreId: Optional[CustomKeyStoreIdType] - CustomKeyStoreName: Optional[CustomKeyStoreNameType] - Limit: Optional[LimitType] - Marker: Optional[MarkerType] + CustomKeyStoreId: CustomKeyStoreIdType | None + CustomKeyStoreName: CustomKeyStoreNameType | None + Limit: LimitType | None + Marker: MarkerType | None class DescribeCustomKeyStoresResponse(TypedDict, total=False): - CustomKeyStores: Optional[CustomKeyStoresList] - NextMarker: Optional[MarkerType] - Truncated: Optional[BooleanType] + CustomKeyStores: CustomKeyStoresList | None + NextMarker: MarkerType | None + Truncated: BooleanType | None class DescribeKeyRequest(ServiceRequest): KeyId: KeyIdType - GrantTokens: Optional[GrantTokenList] + GrantTokens: GrantTokenList | None class DescribeKeyResponse(TypedDict, total=False): - KeyMetadata: Optional[KeyMetadata] + KeyMetadata: KeyMetadata | None class DisableKeyRequest(ServiceRequest): @@ -873,125 +887,125 @@ class EnableKeyRequest(ServiceRequest): class EnableKeyRotationRequest(ServiceRequest): KeyId: KeyIdType - RotationPeriodInDays: Optional[RotationPeriodInDaysType] + RotationPeriodInDays: RotationPeriodInDaysType | None class EncryptRequest(ServiceRequest): KeyId: KeyIdType Plaintext: PlaintextType - EncryptionContext: Optional[EncryptionContextType] - GrantTokens: Optional[GrantTokenList] - EncryptionAlgorithm: Optional[EncryptionAlgorithmSpec] - DryRun: Optional[NullableBooleanType] + EncryptionContext: EncryptionContextType | None + GrantTokens: GrantTokenList | None + EncryptionAlgorithm: EncryptionAlgorithmSpec | None + DryRun: NullableBooleanType | None class EncryptResponse(TypedDict, total=False): - CiphertextBlob: Optional[CiphertextType] - KeyId: Optional[KeyIdType] - EncryptionAlgorithm: Optional[EncryptionAlgorithmSpec] + CiphertextBlob: CiphertextType | None + KeyId: KeyIdType | None + EncryptionAlgorithm: EncryptionAlgorithmSpec | None class GenerateDataKeyPairRequest(ServiceRequest): - EncryptionContext: Optional[EncryptionContextType] + EncryptionContext: EncryptionContextType | None KeyId: KeyIdType KeyPairSpec: DataKeyPairSpec - GrantTokens: Optional[GrantTokenList] - Recipient: Optional[RecipientInfo] - DryRun: Optional[NullableBooleanType] + GrantTokens: GrantTokenList | None + Recipient: RecipientInfo | None + DryRun: NullableBooleanType | None class GenerateDataKeyPairResponse(TypedDict, total=False): - PrivateKeyCiphertextBlob: Optional[CiphertextType] - PrivateKeyPlaintext: Optional[PlaintextType] - PublicKey: Optional[PublicKeyType] - KeyId: Optional[KeyIdType] - KeyPairSpec: Optional[DataKeyPairSpec] - CiphertextForRecipient: Optional[CiphertextType] - KeyMaterialId: Optional[BackingKeyIdType] + PrivateKeyCiphertextBlob: CiphertextType | None + PrivateKeyPlaintext: PlaintextType | None + PublicKey: PublicKeyType | None + KeyId: KeyIdType | None + KeyPairSpec: DataKeyPairSpec | None + CiphertextForRecipient: CiphertextType | None + KeyMaterialId: BackingKeyIdType | None class GenerateDataKeyPairWithoutPlaintextRequest(ServiceRequest): - EncryptionContext: Optional[EncryptionContextType] + EncryptionContext: EncryptionContextType | None KeyId: KeyIdType KeyPairSpec: DataKeyPairSpec - GrantTokens: Optional[GrantTokenList] - DryRun: Optional[NullableBooleanType] + GrantTokens: GrantTokenList | None + DryRun: NullableBooleanType | None class GenerateDataKeyPairWithoutPlaintextResponse(TypedDict, total=False): - PrivateKeyCiphertextBlob: Optional[CiphertextType] - PublicKey: Optional[PublicKeyType] - KeyId: Optional[KeyIdType] - KeyPairSpec: Optional[DataKeyPairSpec] - KeyMaterialId: Optional[BackingKeyIdType] + PrivateKeyCiphertextBlob: CiphertextType | None + PublicKey: PublicKeyType | None + KeyId: KeyIdType | None + KeyPairSpec: DataKeyPairSpec | None + KeyMaterialId: BackingKeyIdType | None class GenerateDataKeyRequest(ServiceRequest): KeyId: KeyIdType - EncryptionContext: Optional[EncryptionContextType] - NumberOfBytes: Optional[NumberOfBytesType] - KeySpec: Optional[DataKeySpec] - GrantTokens: Optional[GrantTokenList] - Recipient: Optional[RecipientInfo] - DryRun: Optional[NullableBooleanType] + EncryptionContext: EncryptionContextType | None + NumberOfBytes: NumberOfBytesType | None + KeySpec: DataKeySpec | None + GrantTokens: GrantTokenList | None + Recipient: RecipientInfo | None + DryRun: NullableBooleanType | None class GenerateDataKeyResponse(TypedDict, total=False): - CiphertextBlob: Optional[CiphertextType] - Plaintext: Optional[PlaintextType] - KeyId: Optional[KeyIdType] - CiphertextForRecipient: Optional[CiphertextType] - KeyMaterialId: Optional[BackingKeyIdType] + CiphertextBlob: CiphertextType | None + Plaintext: PlaintextType | None + KeyId: KeyIdType | None + CiphertextForRecipient: CiphertextType | None + KeyMaterialId: BackingKeyIdType | None class GenerateDataKeyWithoutPlaintextRequest(ServiceRequest): KeyId: KeyIdType - EncryptionContext: Optional[EncryptionContextType] - KeySpec: Optional[DataKeySpec] - NumberOfBytes: Optional[NumberOfBytesType] - GrantTokens: Optional[GrantTokenList] - DryRun: Optional[NullableBooleanType] + EncryptionContext: EncryptionContextType | None + KeySpec: DataKeySpec | None + NumberOfBytes: NumberOfBytesType | None + GrantTokens: GrantTokenList | None + DryRun: NullableBooleanType | None class GenerateDataKeyWithoutPlaintextResponse(TypedDict, total=False): - CiphertextBlob: Optional[CiphertextType] - KeyId: Optional[KeyIdType] - KeyMaterialId: Optional[BackingKeyIdType] + CiphertextBlob: CiphertextType | None + KeyId: KeyIdType | None + KeyMaterialId: BackingKeyIdType | None class GenerateMacRequest(ServiceRequest): Message: PlaintextType KeyId: KeyIdType MacAlgorithm: MacAlgorithmSpec - GrantTokens: Optional[GrantTokenList] - DryRun: Optional[NullableBooleanType] + GrantTokens: GrantTokenList | None + DryRun: NullableBooleanType | None class GenerateMacResponse(TypedDict, total=False): - Mac: Optional[CiphertextType] - MacAlgorithm: Optional[MacAlgorithmSpec] - KeyId: Optional[KeyIdType] + Mac: CiphertextType | None + MacAlgorithm: MacAlgorithmSpec | None + KeyId: KeyIdType | None class GenerateRandomRequest(ServiceRequest): - NumberOfBytes: Optional[NumberOfBytesType] - CustomKeyStoreId: Optional[CustomKeyStoreIdType] - Recipient: Optional[RecipientInfo] + NumberOfBytes: NumberOfBytesType | None + CustomKeyStoreId: CustomKeyStoreIdType | None + Recipient: RecipientInfo | None class GenerateRandomResponse(TypedDict, total=False): - Plaintext: Optional[PlaintextType] - CiphertextForRecipient: Optional[CiphertextType] + Plaintext: PlaintextType | None + CiphertextForRecipient: CiphertextType | None class GetKeyPolicyRequest(ServiceRequest): KeyId: KeyIdType - PolicyName: Optional[PolicyNameType] + PolicyName: PolicyNameType | None class GetKeyPolicyResponse(TypedDict, total=False): - Policy: Optional[PolicyType] - PolicyName: Optional[PolicyNameType] + Policy: PolicyType | None + PolicyName: PolicyNameType | None class GetKeyRotationStatusRequest(ServiceRequest): @@ -999,11 +1013,11 @@ class GetKeyRotationStatusRequest(ServiceRequest): class GetKeyRotationStatusResponse(TypedDict, total=False): - KeyRotationEnabled: Optional[BooleanType] - KeyId: Optional[KeyIdType] - RotationPeriodInDays: Optional[RotationPeriodInDaysType] - NextRotationDate: Optional[DateType] - OnDemandRotationStartDate: Optional[DateType] + KeyRotationEnabled: BooleanType | None + KeyId: KeyIdType | None + RotationPeriodInDays: RotationPeriodInDaysType | None + NextRotationDate: DateType | None + OnDemandRotationStartDate: DateType | None class GetParametersForImportRequest(ServiceRequest): @@ -1013,220 +1027,221 @@ class GetParametersForImportRequest(ServiceRequest): class GetParametersForImportResponse(TypedDict, total=False): - KeyId: Optional[KeyIdType] - ImportToken: Optional[CiphertextType] - PublicKey: Optional[PlaintextType] - ParametersValidTo: Optional[DateType] + KeyId: KeyIdType | None + ImportToken: CiphertextType | None + PublicKey: PlaintextType | None + ParametersValidTo: DateType | None class GetPublicKeyRequest(ServiceRequest): KeyId: KeyIdType - GrantTokens: Optional[GrantTokenList] + GrantTokens: GrantTokenList | None class GetPublicKeyResponse(TypedDict, total=False): - KeyId: Optional[KeyIdType] - PublicKey: Optional[PublicKeyType] - CustomerMasterKeySpec: Optional[CustomerMasterKeySpec] - KeySpec: Optional[KeySpec] - KeyUsage: Optional[KeyUsageType] - EncryptionAlgorithms: Optional[EncryptionAlgorithmSpecList] - SigningAlgorithms: Optional[SigningAlgorithmSpecList] - KeyAgreementAlgorithms: Optional[KeyAgreementAlgorithmSpecList] + KeyId: KeyIdType | None + PublicKey: PublicKeyType | None + CustomerMasterKeySpec: CustomerMasterKeySpec | None + KeySpec: KeySpec | None + KeyUsage: KeyUsageType | None + EncryptionAlgorithms: EncryptionAlgorithmSpecList | None + SigningAlgorithms: SigningAlgorithmSpecList | None + KeyAgreementAlgorithms: KeyAgreementAlgorithmSpecList | None class GrantListEntry(TypedDict, total=False): - KeyId: Optional[KeyIdType] - GrantId: Optional[GrantIdType] - Name: Optional[GrantNameType] - CreationDate: Optional[DateType] - GranteePrincipal: Optional[PrincipalIdType] - RetiringPrincipal: Optional[PrincipalIdType] - IssuingAccount: Optional[PrincipalIdType] - Operations: Optional[GrantOperationList] - Constraints: Optional[GrantConstraints] + KeyId: KeyIdType | None + GrantId: GrantIdType | None + Name: GrantNameType | None + CreationDate: DateType | None + GranteePrincipal: PrincipalIdType | None + RetiringPrincipal: PrincipalIdType | None + IssuingAccount: PrincipalIdType | None + Operations: GrantOperationList | None + Constraints: GrantConstraints | None -GrantList = List[GrantListEntry] +GrantList = list[GrantListEntry] class ImportKeyMaterialRequest(ServiceRequest): KeyId: KeyIdType ImportToken: CiphertextType EncryptedKeyMaterial: CiphertextType - ValidTo: Optional[DateType] - ExpirationModel: Optional[ExpirationModelType] - ImportType: Optional[ImportType] - KeyMaterialDescription: Optional[KeyMaterialDescriptionType] - KeyMaterialId: Optional[BackingKeyIdType] + ValidTo: DateType | None + ExpirationModel: ExpirationModelType | None + ImportType: ImportType | None + KeyMaterialDescription: KeyMaterialDescriptionType | None + KeyMaterialId: BackingKeyIdType | None class ImportKeyMaterialResponse(TypedDict, total=False): - KeyId: Optional[KeyIdType] - KeyMaterialId: Optional[BackingKeyIdType] + KeyId: KeyIdType | None + KeyMaterialId: BackingKeyIdType | None class KeyListEntry(TypedDict, total=False): - KeyId: Optional[KeyIdType] - KeyArn: Optional[ArnType] + KeyId: KeyIdType | None + KeyArn: ArnType | None -KeyList = List[KeyListEntry] +KeyList = list[KeyListEntry] class ListAliasesRequest(ServiceRequest): - KeyId: Optional[KeyIdType] - Limit: Optional[LimitType] - Marker: Optional[MarkerType] + KeyId: KeyIdType | None + Limit: LimitType | None + Marker: MarkerType | None class ListAliasesResponse(TypedDict, total=False): - Aliases: Optional[AliasList] - NextMarker: Optional[MarkerType] - Truncated: Optional[BooleanType] + Aliases: AliasList | None + NextMarker: MarkerType | None + Truncated: BooleanType | None class ListGrantsRequest(ServiceRequest): - Limit: Optional[LimitType] - Marker: Optional[MarkerType] + Limit: LimitType | None + Marker: MarkerType | None KeyId: KeyIdType - GrantId: Optional[GrantIdType] - GranteePrincipal: Optional[PrincipalIdType] + GrantId: GrantIdType | None + GranteePrincipal: PrincipalIdType | None class ListGrantsResponse(TypedDict, total=False): - Grants: Optional[GrantList] - NextMarker: Optional[MarkerType] - Truncated: Optional[BooleanType] + Grants: GrantList | None + NextMarker: MarkerType | None + Truncated: BooleanType | None class ListKeyPoliciesRequest(ServiceRequest): KeyId: KeyIdType - Limit: Optional[LimitType] - Marker: Optional[MarkerType] + Limit: LimitType | None + Marker: MarkerType | None -PolicyNameList = List[PolicyNameType] +PolicyNameList = list[PolicyNameType] class ListKeyPoliciesResponse(TypedDict, total=False): - PolicyNames: Optional[PolicyNameList] - NextMarker: Optional[MarkerType] - Truncated: Optional[BooleanType] + PolicyNames: PolicyNameList | None + NextMarker: MarkerType | None + Truncated: BooleanType | None class ListKeyRotationsRequest(ServiceRequest): KeyId: KeyIdType - IncludeKeyMaterial: Optional[IncludeKeyMaterial] - Limit: Optional[LimitType] - Marker: Optional[MarkerType] + IncludeKeyMaterial: IncludeKeyMaterial | None + Limit: LimitType | None + Marker: MarkerType | None class RotationsListEntry(TypedDict, total=False): - KeyId: Optional[KeyIdType] - KeyMaterialId: Optional[BackingKeyIdType] - KeyMaterialDescription: Optional[KeyMaterialDescriptionType] - ImportState: Optional[ImportState] - KeyMaterialState: Optional[KeyMaterialState] - ExpirationModel: Optional[ExpirationModelType] - ValidTo: Optional[DateType] - RotationDate: Optional[DateType] - RotationType: Optional[RotationType] + KeyId: KeyIdType | None + KeyMaterialId: BackingKeyIdType | None + KeyMaterialDescription: KeyMaterialDescriptionType | None + ImportState: ImportState | None + KeyMaterialState: KeyMaterialState | None + ExpirationModel: ExpirationModelType | None + ValidTo: DateType | None + RotationDate: DateType | None + RotationType: RotationType | None -RotationsList = List[RotationsListEntry] +RotationsList = list[RotationsListEntry] class ListKeyRotationsResponse(TypedDict, total=False): - Rotations: Optional[RotationsList] - NextMarker: Optional[MarkerType] - Truncated: Optional[BooleanType] + Rotations: RotationsList | None + NextMarker: MarkerType | None + Truncated: BooleanType | None class ListKeysRequest(ServiceRequest): - Limit: Optional[LimitType] - Marker: Optional[MarkerType] + Limit: LimitType | None + Marker: MarkerType | None class ListKeysResponse(TypedDict, total=False): - Keys: Optional[KeyList] - NextMarker: Optional[MarkerType] - Truncated: Optional[BooleanType] + Keys: KeyList | None + NextMarker: MarkerType | None + Truncated: BooleanType | None class ListResourceTagsRequest(ServiceRequest): KeyId: KeyIdType - Limit: Optional[LimitType] - Marker: Optional[MarkerType] + Limit: LimitType | None + Marker: MarkerType | None class ListResourceTagsResponse(TypedDict, total=False): - Tags: Optional[TagList] - NextMarker: Optional[MarkerType] - Truncated: Optional[BooleanType] + Tags: TagList | None + NextMarker: MarkerType | None + Truncated: BooleanType | None class ListRetirableGrantsRequest(ServiceRequest): - Limit: Optional[LimitType] - Marker: Optional[MarkerType] + Limit: LimitType | None + Marker: MarkerType | None RetiringPrincipal: PrincipalIdType class PutKeyPolicyRequest(ServiceRequest): KeyId: KeyIdType - PolicyName: Optional[PolicyNameType] + PolicyName: PolicyNameType | None Policy: PolicyType - BypassPolicyLockoutSafetyCheck: Optional[BooleanType] + BypassPolicyLockoutSafetyCheck: BooleanType | None class ReEncryptRequest(ServiceRequest): - CiphertextBlob: CiphertextType - SourceEncryptionContext: Optional[EncryptionContextType] - SourceKeyId: Optional[KeyIdType] + CiphertextBlob: CiphertextType | None + SourceEncryptionContext: EncryptionContextType | None + SourceKeyId: KeyIdType | None DestinationKeyId: KeyIdType - DestinationEncryptionContext: Optional[EncryptionContextType] - SourceEncryptionAlgorithm: Optional[EncryptionAlgorithmSpec] - DestinationEncryptionAlgorithm: Optional[EncryptionAlgorithmSpec] - GrantTokens: Optional[GrantTokenList] - DryRun: Optional[NullableBooleanType] + DestinationEncryptionContext: EncryptionContextType | None + SourceEncryptionAlgorithm: EncryptionAlgorithmSpec | None + DestinationEncryptionAlgorithm: EncryptionAlgorithmSpec | None + GrantTokens: GrantTokenList | None + DryRun: NullableBooleanType | None + DryRunModifiers: DryRunModifierList | None class ReEncryptResponse(TypedDict, total=False): - CiphertextBlob: Optional[CiphertextType] - SourceKeyId: Optional[KeyIdType] - KeyId: Optional[KeyIdType] - SourceEncryptionAlgorithm: Optional[EncryptionAlgorithmSpec] - DestinationEncryptionAlgorithm: Optional[EncryptionAlgorithmSpec] - SourceKeyMaterialId: Optional[BackingKeyIdType] - DestinationKeyMaterialId: Optional[BackingKeyIdType] + CiphertextBlob: CiphertextType | None + SourceKeyId: KeyIdType | None + KeyId: KeyIdType | None + SourceEncryptionAlgorithm: EncryptionAlgorithmSpec | None + DestinationEncryptionAlgorithm: EncryptionAlgorithmSpec | None + SourceKeyMaterialId: BackingKeyIdType | None + DestinationKeyMaterialId: BackingKeyIdType | None class ReplicateKeyRequest(ServiceRequest): KeyId: KeyIdType ReplicaRegion: RegionType - Policy: Optional[PolicyType] - BypassPolicyLockoutSafetyCheck: Optional[BooleanType] - Description: Optional[DescriptionType] - Tags: Optional[TagList] + Policy: PolicyType | None + BypassPolicyLockoutSafetyCheck: BooleanType | None + Description: DescriptionType | None + Tags: TagList | None class ReplicateKeyResponse(TypedDict, total=False): - ReplicaKeyMetadata: Optional[KeyMetadata] - ReplicaPolicy: Optional[PolicyType] - ReplicaTags: Optional[TagList] + ReplicaKeyMetadata: KeyMetadata | None + ReplicaPolicy: PolicyType | None + ReplicaTags: TagList | None class RetireGrantRequest(ServiceRequest): - GrantToken: Optional[GrantTokenType] - KeyId: Optional[KeyIdType] - GrantId: Optional[GrantIdType] - DryRun: Optional[NullableBooleanType] + GrantToken: GrantTokenType | None + KeyId: KeyIdType | None + GrantId: GrantIdType | None + DryRun: NullableBooleanType | None class RevokeGrantRequest(ServiceRequest): KeyId: KeyIdType GrantId: GrantIdType - DryRun: Optional[NullableBooleanType] + DryRun: NullableBooleanType | None class RotateKeyOnDemandRequest(ServiceRequest): @@ -1234,37 +1249,37 @@ class RotateKeyOnDemandRequest(ServiceRequest): class RotateKeyOnDemandResponse(TypedDict, total=False): - KeyId: Optional[KeyIdType] + KeyId: KeyIdType | None class ScheduleKeyDeletionRequest(ServiceRequest): KeyId: KeyIdType - PendingWindowInDays: Optional[PendingWindowInDaysType] + PendingWindowInDays: PendingWindowInDaysType | None class ScheduleKeyDeletionResponse(TypedDict, total=False): - KeyId: Optional[KeyIdType] - DeletionDate: Optional[DateType] - KeyState: Optional[KeyState] - PendingWindowInDays: Optional[PendingWindowInDaysType] + KeyId: KeyIdType | None + DeletionDate: DateType | None + KeyState: KeyState | None + PendingWindowInDays: PendingWindowInDaysType | None class SignRequest(ServiceRequest): KeyId: KeyIdType Message: PlaintextType - MessageType: Optional[MessageType] - GrantTokens: Optional[GrantTokenList] + MessageType: MessageType | None + GrantTokens: GrantTokenList | None SigningAlgorithm: SigningAlgorithmSpec - DryRun: Optional[NullableBooleanType] + DryRun: NullableBooleanType | None class SignResponse(TypedDict, total=False): - KeyId: Optional[KeyIdType] - Signature: Optional[CiphertextType] - SigningAlgorithm: Optional[SigningAlgorithmSpec] + KeyId: KeyIdType | None + Signature: CiphertextType | None + SigningAlgorithm: SigningAlgorithmSpec | None -TagKeyList = List[TagKeyType] +TagKeyList = list[TagKeyType] class TagResourceRequest(ServiceRequest): @@ -1284,14 +1299,15 @@ class UpdateAliasRequest(ServiceRequest): class UpdateCustomKeyStoreRequest(ServiceRequest): CustomKeyStoreId: CustomKeyStoreIdType - NewCustomKeyStoreName: Optional[CustomKeyStoreNameType] - KeyStorePassword: Optional[KeyStorePasswordType] - CloudHsmClusterId: Optional[CloudHsmClusterIdType] - XksProxyUriEndpoint: Optional[XksProxyUriEndpointType] - XksProxyUriPath: Optional[XksProxyUriPathType] - XksProxyVpcEndpointServiceName: Optional[XksProxyVpcEndpointServiceNameType] - XksProxyAuthenticationCredential: Optional[XksProxyAuthenticationCredentialType] - XksProxyConnectivity: Optional[XksProxyConnectivityType] + NewCustomKeyStoreName: CustomKeyStoreNameType | None + KeyStorePassword: KeyStorePasswordType | None + CloudHsmClusterId: CloudHsmClusterIdType | None + XksProxyUriEndpoint: XksProxyUriEndpointType | None + XksProxyUriPath: XksProxyUriPathType | None + XksProxyVpcEndpointServiceName: XksProxyVpcEndpointServiceNameType | None + XksProxyVpcEndpointServiceOwner: AccountIdType | None + XksProxyAuthenticationCredential: XksProxyAuthenticationCredentialType | None + XksProxyConnectivity: XksProxyConnectivityType | None class UpdateCustomKeyStoreResponse(TypedDict, total=False): @@ -1313,35 +1329,35 @@ class VerifyMacRequest(ServiceRequest): KeyId: KeyIdType MacAlgorithm: MacAlgorithmSpec Mac: CiphertextType - GrantTokens: Optional[GrantTokenList] - DryRun: Optional[NullableBooleanType] + GrantTokens: GrantTokenList | None + DryRun: NullableBooleanType | None class VerifyMacResponse(TypedDict, total=False): - KeyId: Optional[KeyIdType] - MacValid: Optional[BooleanType] - MacAlgorithm: Optional[MacAlgorithmSpec] + KeyId: KeyIdType | None + MacValid: BooleanType | None + MacAlgorithm: MacAlgorithmSpec | None class VerifyRequest(ServiceRequest): KeyId: KeyIdType Message: PlaintextType - MessageType: Optional[MessageType] + MessageType: MessageType | None Signature: CiphertextType SigningAlgorithm: SigningAlgorithmSpec - GrantTokens: Optional[GrantTokenList] - DryRun: Optional[NullableBooleanType] + GrantTokens: GrantTokenList | None + DryRun: NullableBooleanType | None class VerifyResponse(TypedDict, total=False): - KeyId: Optional[KeyIdType] - SignatureValid: Optional[BooleanType] - SigningAlgorithm: Optional[SigningAlgorithmSpec] + KeyId: KeyIdType | None + SignatureValid: BooleanType | None + SigningAlgorithm: SigningAlgorithmSpec | None class KmsApi: - service = "kms" - version = "2014-11-01" + service: str = "kms" + version: str = "2014-11-01" @handler("CancelKeyDeletion") def cancel_key_deletion( @@ -1373,6 +1389,7 @@ def create_custom_key_store( xks_proxy_uri_endpoint: XksProxyUriEndpointType | None = None, xks_proxy_uri_path: XksProxyUriPathType | None = None, xks_proxy_vpc_endpoint_service_name: XksProxyVpcEndpointServiceNameType | None = None, + xks_proxy_vpc_endpoint_service_owner: AccountIdType | None = None, xks_proxy_authentication_credential: XksProxyAuthenticationCredentialType | None = None, xks_proxy_connectivity: XksProxyConnectivityType | None = None, **kwargs, @@ -1418,13 +1435,14 @@ def create_key( def decrypt( self, context: RequestContext, - ciphertext_blob: CiphertextType, + ciphertext_blob: CiphertextType | None = None, encryption_context: EncryptionContextType | None = None, grant_tokens: GrantTokenList | None = None, key_id: KeyIdType | None = None, encryption_algorithm: EncryptionAlgorithmSpec | None = None, recipient: RecipientInfo | None = None, dry_run: NullableBooleanType | None = None, + dry_run_modifiers: DryRunModifierList | None = None, **kwargs, ) -> DecryptResponse: raise NotImplementedError @@ -1755,8 +1773,8 @@ def put_key_policy( def re_encrypt( self, context: RequestContext, - ciphertext_blob: CiphertextType, destination_key_id: KeyIdType, + ciphertext_blob: CiphertextType | None = None, source_encryption_context: EncryptionContextType | None = None, source_key_id: KeyIdType | None = None, destination_encryption_context: EncryptionContextType | None = None, @@ -1764,6 +1782,7 @@ def re_encrypt( destination_encryption_algorithm: EncryptionAlgorithmSpec | None = None, grant_tokens: GrantTokenList | None = None, dry_run: NullableBooleanType | None = None, + dry_run_modifiers: DryRunModifierList | None = None, **kwargs, ) -> ReEncryptResponse: raise NotImplementedError @@ -1864,6 +1883,7 @@ def update_custom_key_store( xks_proxy_uri_endpoint: XksProxyUriEndpointType | None = None, xks_proxy_uri_path: XksProxyUriPathType | None = None, xks_proxy_vpc_endpoint_service_name: XksProxyVpcEndpointServiceNameType | None = None, + xks_proxy_vpc_endpoint_service_owner: AccountIdType | None = None, xks_proxy_authentication_credential: XksProxyAuthenticationCredentialType | None = None, xks_proxy_connectivity: XksProxyConnectivityType | None = None, **kwargs, diff --git a/localstack-core/localstack/aws/api/lambda_/__init__.py b/localstack-core/localstack/aws/api/lambda_/__init__.py index eda8ffb23ae23..78cd7159eb7f0 100644 --- a/localstack-core/localstack/aws/api/lambda_/__init__.py +++ b/localstack-core/localstack/aws/api/lambda_/__init__.py @@ -1,6 +1,7 @@ +from collections.abc import Iterable, Iterator from datetime import datetime from enum import StrEnum -from typing import IO, Dict, Iterable, Iterator, List, Optional, TypedDict, Union +from typing import IO, TypedDict from localstack.aws.api import RequestContext, ServiceException, ServiceRequest, handler @@ -9,34 +10,57 @@ Alias = str AllowCredentials = bool Arn = str +AttemptCount = int BatchSize = int BisectBatchOnFunctionError = bool Boolean = bool +CallbackId = str +CapacityProviderArn = str +CapacityProviderMaxVCpuCount = int +CapacityProviderName = str +CheckpointToken = str +ClientToken = str CodeSigningConfigArn = str CodeSigningConfigId = str CollectionName = str DatabaseName = str Description = str DestinationArn = str +DurableExecutionArn = str +DurableExecutionName = str +DurationSeconds = int Enabled = bool Endpoint = str EnvironmentVariableName = str EnvironmentVariableValue = str EphemeralStorageSize = int +ErrorData = str +ErrorMessage = str +ErrorType = str +EventId = int EventSourceMappingArn = str EventSourceToken = str +ExecutionEnvironmentMemoryGiBPerVCpu = float +ExecutionTimeout = int FileSystemArn = str FilterCriteriaErrorCode = str FilterCriteriaErrorMessage = str FunctionArn = str FunctionName = str +FunctionScalingConfigExecutionEnvironments = int FunctionUrl = str FunctionUrlQualifier = str Handler = str Header = str HttpStatus = int +IncludeExecutionData = bool +InputPayload = str +InstanceType = str Integer = int +InvokedViaFunctionUrl = bool +ItemCount = int KMSKeyArn = str +KMSKeyArnNonEmpty = str LastUpdateStatusReason = str LayerArn = str LayerName = str @@ -48,6 +72,7 @@ LogGroup = str MasterRegion = str MaxAge = int +MaxFiftyListItems = int MaxFunctionEventInvokeConfigListItems = int MaxItems = int MaxLayerListItems = int @@ -62,23 +87,36 @@ MaximumRetryAttemptsEventSourceMapping = int MemorySize = int Method = str +MetricTargetValue = float MinimumNumberOfPollers = int NameSpacedFunctionArn = str NamespacedFunctionName = str NamespacedStatementId = str NonNegativeInteger = int NullableBoolean = bool +NumericLatestPublishedOrAliasQualifier = str +OperationId = str +OperationName = str +OperationPayload = str +OperationSubType = str OrganizationId = str Origin = str +OutputPayload = str ParallelizationFactor = int Pattern = str +PerExecutionEnvironmentMaxConcurrency = int PositiveInteger = int Principal = str PrincipalOrgID = str +ProvisionedPollerGroupName = str +PublishedFunctionQualifier = str Qualifier = str Queue = str +ReplayChildren = bool ReservedConcurrentExecutions = int ResourceArn = str +RetentionPeriodInDays = int +ReverseOrder = bool RoleArn = str RuntimeVersionArn = str S3Bucket = str @@ -88,8 +126,10 @@ SecurityGroupId = str SensitiveString = str SourceOwner = str +StackTraceEntry = str StateReason = str StatementId = str +StepOptionsNextAttemptDelaySecondsInteger = int String = str SubnetId = str TagKey = str @@ -97,17 +137,22 @@ TaggableResource = str TagsErrorCode = str TagsErrorMessage = str +TenantId = str Timeout = int Timestamp = str Topic = str +Truncated = bool TumblingWindowInSeconds = int URI = str UnqualifiedFunctionName = str UnreservedConcurrentExecutions = int Version = str +VersionWithLatestPublished = str VpcId = str +WaitOptionsWaitSecondsInteger = int Weight = float WorkingDirectory = str +XAmznTraceId = str class ApplicationLogLevel(StrEnum): @@ -124,6 +169,22 @@ class Architecture(StrEnum): arm64 = "arm64" +class CapacityProviderPredefinedMetricType(StrEnum): + LambdaCapacityProviderAverageCPUUtilization = "LambdaCapacityProviderAverageCPUUtilization" + + +class CapacityProviderScalingMode(StrEnum): + Auto = "Auto" + Manual = "Manual" + + +class CapacityProviderState(StrEnum): + Pending = "Pending" + Active = "Active" + Failed = "Failed" + Deleting = "Deleting" + + class CodeSigningPolicy(StrEnum): Warn = "Warn" Enforce = "Enforce" @@ -135,6 +196,14 @@ class EndPointType(StrEnum): class EventSourceMappingMetric(StrEnum): EventCount = "EventCount" + ErrorCount = "ErrorCount" + KafkaMetrics = "KafkaMetrics" + + +class EventSourceMappingSystemLogLevel(StrEnum): + DEBUG = "DEBUG" + INFO = "INFO" + WARN = "WARN" class EventSourcePosition(StrEnum): @@ -143,6 +212,41 @@ class EventSourcePosition(StrEnum): AT_TIMESTAMP = "AT_TIMESTAMP" +class EventType(StrEnum): + ExecutionStarted = "ExecutionStarted" + ExecutionSucceeded = "ExecutionSucceeded" + ExecutionFailed = "ExecutionFailed" + ExecutionTimedOut = "ExecutionTimedOut" + ExecutionStopped = "ExecutionStopped" + ContextStarted = "ContextStarted" + ContextSucceeded = "ContextSucceeded" + ContextFailed = "ContextFailed" + WaitStarted = "WaitStarted" + WaitSucceeded = "WaitSucceeded" + WaitCancelled = "WaitCancelled" + StepStarted = "StepStarted" + StepSucceeded = "StepSucceeded" + StepFailed = "StepFailed" + ChainedInvokeStarted = "ChainedInvokeStarted" + ChainedInvokeSucceeded = "ChainedInvokeSucceeded" + ChainedInvokeFailed = "ChainedInvokeFailed" + ChainedInvokeTimedOut = "ChainedInvokeTimedOut" + ChainedInvokeStopped = "ChainedInvokeStopped" + CallbackStarted = "CallbackStarted" + CallbackSucceeded = "CallbackSucceeded" + CallbackFailed = "CallbackFailed" + CallbackTimedOut = "CallbackTimedOut" + InvocationCompleted = "InvocationCompleted" + + +class ExecutionStatus(StrEnum): + RUNNING = "RUNNING" + SUCCEEDED = "SUCCEEDED" + FAILED = "FAILED" + TIMED_OUT = "TIMED_OUT" + STOPPED = "STOPPED" + + class FullDocument(StrEnum): UpdateLookup = "UpdateLookup" Default = "Default" @@ -161,6 +265,10 @@ class FunctionVersion(StrEnum): ALL = "ALL" +class FunctionVersionLatestPublished(StrEnum): + LATEST_PUBLISHED = "LATEST_PUBLISHED" + + class InvocationType(StrEnum): Event = "Event" RequestResponse = "RequestResponse" @@ -211,6 +319,19 @@ class LastUpdateStatusReasonCode(StrEnum): InvalidRuntime = "InvalidRuntime" InvalidZipFileException = "InvalidZipFileException" FunctionError = "FunctionError" + VcpuLimitExceeded = "VcpuLimitExceeded" + CapacityProviderScalingLimitExceeded = "CapacityProviderScalingLimitExceeded" + InsufficientCapacity = "InsufficientCapacity" + EC2RequestLimitExceeded = "EC2RequestLimitExceeded" + FunctionError_InitTimeout = "FunctionError.InitTimeout" + FunctionError_RuntimeInitError = "FunctionError.RuntimeInitError" + FunctionError_ExtensionInitError = "FunctionError.ExtensionInitError" + FunctionError_InvalidEntryPoint = "FunctionError.InvalidEntryPoint" + FunctionError_InvalidWorkingDirectory = "FunctionError.InvalidWorkingDirectory" + FunctionError_PermissionDenied = "FunctionError.PermissionDenied" + FunctionError_TooManyExtensions = "FunctionError.TooManyExtensions" + FunctionError_InitResourceExhausted = "FunctionError.InitResourceExhausted" + DisallowedByVpcEncryptionControl = "DisallowedByVpcEncryptionControl" class LogFormat(StrEnum): @@ -223,6 +344,34 @@ class LogType(StrEnum): Tail = "Tail" +class OperationAction(StrEnum): + START = "START" + SUCCEED = "SUCCEED" + FAIL = "FAIL" + RETRY = "RETRY" + CANCEL = "CANCEL" + + +class OperationStatus(StrEnum): + STARTED = "STARTED" + PENDING = "PENDING" + READY = "READY" + SUCCEEDED = "SUCCEEDED" + FAILED = "FAILED" + CANCELLED = "CANCELLED" + TIMED_OUT = "TIMED_OUT" + STOPPED = "STOPPED" + + +class OperationType(StrEnum): + EXECUTION = "EXECUTION" + CONTEXT = "CONTEXT" + STEP = "STEP" + WAIT = "WAIT" + CALLBACK = "CALLBACK" + CHAINED_INVOKE = "CHAINED_INVOKE" + + class PackageType(StrEnum): Zip = "Zip" Image = "Image" @@ -286,6 +435,10 @@ class Runtime(StrEnum): java21 = "java21" python3_13 = "python3.13" nodejs22_x = "nodejs22.x" + nodejs24_x = "nodejs24.x" + python3_14 = "python3.14" + java25 = "java25" + dotnet10 = "dotnet10" class SchemaRegistryEventRecordFormat(StrEnum): @@ -319,6 +472,10 @@ class State(StrEnum): Active = "Active" Inactive = "Inactive" Failed = "Failed" + Deactivating = "Deactivating" + Deactivated = "Deactivated" + ActiveNonInvocable = "ActiveNonInvocable" + Deleting = "Deleting" class StateReasonCode(StrEnum): @@ -346,6 +503,20 @@ class StateReasonCode(StrEnum): InvalidRuntime = "InvalidRuntime" InvalidZipFileException = "InvalidZipFileException" FunctionError = "FunctionError" + DrainingDurableExecutions = "DrainingDurableExecutions" + VcpuLimitExceeded = "VcpuLimitExceeded" + CapacityProviderScalingLimitExceeded = "CapacityProviderScalingLimitExceeded" + InsufficientCapacity = "InsufficientCapacity" + EC2RequestLimitExceeded = "EC2RequestLimitExceeded" + FunctionError_InitTimeout = "FunctionError.InitTimeout" + FunctionError_RuntimeInitError = "FunctionError.RuntimeInitError" + FunctionError_ExtensionInitError = "FunctionError.ExtensionInitError" + FunctionError_InvalidEntryPoint = "FunctionError.InvalidEntryPoint" + FunctionError_InvalidWorkingDirectory = "FunctionError.InvalidWorkingDirectory" + FunctionError_PermissionDenied = "FunctionError.PermissionDenied" + FunctionError_TooManyExtensions = "FunctionError.TooManyExtensions" + FunctionError_InitResourceExhausted = "FunctionError.InitResourceExhausted" + DisallowedByVpcEncryptionControl = "DisallowedByVpcEncryptionControl" class SystemLogLevel(StrEnum): @@ -354,6 +525,10 @@ class SystemLogLevel(StrEnum): WARN = "WARN" +class TenantIsolationMode(StrEnum): + PER_TENANT = "PER_TENANT" + + class ThrottleReason(StrEnum): ConcurrentInvocationLimitExceeded = "ConcurrentInvocationLimitExceeded" FunctionInvocationRateLimitExceeded = "FunctionInvocationRateLimitExceeded" @@ -376,289 +551,331 @@ class UpdateRuntimeOn(StrEnum): FunctionUpdate = "FunctionUpdate" +class CallbackTimeoutException(ServiceException): + code: str = "CallbackTimeoutException" + sender_fault: bool = True + status_code: int = 400 + Type: String | None + + +class CapacityProviderLimitExceededException(ServiceException): + code: str = "CapacityProviderLimitExceededException" + sender_fault: bool = True + status_code: int = 400 + Type: String | None + + class CodeSigningConfigNotFoundException(ServiceException): code: str = "CodeSigningConfigNotFoundException" sender_fault: bool = True status_code: int = 404 - Type: Optional[String] + Type: String | None class CodeStorageExceededException(ServiceException): code: str = "CodeStorageExceededException" sender_fault: bool = True status_code: int = 400 - Type: Optional[String] + Type: String | None class CodeVerificationFailedException(ServiceException): code: str = "CodeVerificationFailedException" sender_fault: bool = True status_code: int = 400 - Type: Optional[String] + Type: String | None + + +class DurableExecutionAlreadyStartedException(ServiceException): + code: str = "DurableExecutionAlreadyStartedException" + sender_fault: bool = True + status_code: int = 409 + Type: String | None class EC2AccessDeniedException(ServiceException): code: str = "EC2AccessDeniedException" sender_fault: bool = False status_code: int = 502 - Type: Optional[String] + Type: String | None class EC2ThrottledException(ServiceException): code: str = "EC2ThrottledException" sender_fault: bool = False status_code: int = 502 - Type: Optional[String] + Type: String | None class EC2UnexpectedException(ServiceException): code: str = "EC2UnexpectedException" sender_fault: bool = False status_code: int = 502 - Type: Optional[String] - EC2ErrorCode: Optional[String] + Type: String | None + EC2ErrorCode: String | None class EFSIOException(ServiceException): code: str = "EFSIOException" sender_fault: bool = True status_code: int = 410 - Type: Optional[String] + Type: String | None class EFSMountConnectivityException(ServiceException): code: str = "EFSMountConnectivityException" sender_fault: bool = True status_code: int = 408 - Type: Optional[String] + Type: String | None class EFSMountFailureException(ServiceException): code: str = "EFSMountFailureException" sender_fault: bool = True status_code: int = 403 - Type: Optional[String] + Type: String | None class EFSMountTimeoutException(ServiceException): code: str = "EFSMountTimeoutException" sender_fault: bool = True status_code: int = 408 - Type: Optional[String] + Type: String | None class ENILimitReachedException(ServiceException): code: str = "ENILimitReachedException" sender_fault: bool = False status_code: int = 502 - Type: Optional[String] + Type: String | None + + +class FunctionVersionsPerCapacityProviderLimitExceededException(ServiceException): + code: str = "FunctionVersionsPerCapacityProviderLimitExceededException" + sender_fault: bool = True + status_code: int = 400 + Type: String | None class InvalidCodeSignatureException(ServiceException): code: str = "InvalidCodeSignatureException" sender_fault: bool = True status_code: int = 400 - Type: Optional[String] + Type: String | None class InvalidParameterValueException(ServiceException): code: str = "InvalidParameterValueException" sender_fault: bool = True status_code: int = 400 - Type: Optional[String] + Type: String | None class InvalidRequestContentException(ServiceException): code: str = "InvalidRequestContentException" sender_fault: bool = True status_code: int = 400 - Type: Optional[String] + Type: String | None class InvalidRuntimeException(ServiceException): code: str = "InvalidRuntimeException" sender_fault: bool = False status_code: int = 502 - Type: Optional[String] + Type: String | None class InvalidSecurityGroupIDException(ServiceException): code: str = "InvalidSecurityGroupIDException" sender_fault: bool = False status_code: int = 502 - Type: Optional[String] + Type: String | None class InvalidSubnetIDException(ServiceException): code: str = "InvalidSubnetIDException" sender_fault: bool = False status_code: int = 502 - Type: Optional[String] + Type: String | None class InvalidZipFileException(ServiceException): code: str = "InvalidZipFileException" sender_fault: bool = False status_code: int = 502 - Type: Optional[String] + Type: String | None class KMSAccessDeniedException(ServiceException): code: str = "KMSAccessDeniedException" sender_fault: bool = False status_code: int = 502 - Type: Optional[String] + Type: String | None class KMSDisabledException(ServiceException): code: str = "KMSDisabledException" sender_fault: bool = False status_code: int = 502 - Type: Optional[String] + Type: String | None class KMSInvalidStateException(ServiceException): code: str = "KMSInvalidStateException" sender_fault: bool = False status_code: int = 502 - Type: Optional[String] + Type: String | None class KMSNotFoundException(ServiceException): code: str = "KMSNotFoundException" sender_fault: bool = False status_code: int = 502 - Type: Optional[String] + Type: String | None + + +class NoPublishedVersionException(ServiceException): + code: str = "NoPublishedVersionException" + sender_fault: bool = True + status_code: int = 400 + Type: String | None class PolicyLengthExceededException(ServiceException): code: str = "PolicyLengthExceededException" sender_fault: bool = True status_code: int = 400 - Type: Optional[String] + Type: String | None class PreconditionFailedException(ServiceException): code: str = "PreconditionFailedException" sender_fault: bool = True status_code: int = 412 - Type: Optional[String] + Type: String | None class ProvisionedConcurrencyConfigNotFoundException(ServiceException): code: str = "ProvisionedConcurrencyConfigNotFoundException" sender_fault: bool = True status_code: int = 404 - Type: Optional[String] + Type: String | None class RecursiveInvocationException(ServiceException): code: str = "RecursiveInvocationException" sender_fault: bool = True status_code: int = 400 - Type: Optional[String] + Type: String | None class RequestTooLargeException(ServiceException): code: str = "RequestTooLargeException" sender_fault: bool = True status_code: int = 413 - Type: Optional[String] + Type: String | None class ResourceConflictException(ServiceException): code: str = "ResourceConflictException" sender_fault: bool = True status_code: int = 409 - Type: Optional[String] + Type: String | None class ResourceInUseException(ServiceException): code: str = "ResourceInUseException" sender_fault: bool = True status_code: int = 400 - Type: Optional[String] + Type: String | None class ResourceNotFoundException(ServiceException): code: str = "ResourceNotFoundException" sender_fault: bool = True status_code: int = 404 - Type: Optional[String] + Type: String | None class ResourceNotReadyException(ServiceException): code: str = "ResourceNotReadyException" sender_fault: bool = False status_code: int = 502 - Type: Optional[String] + Type: String | None + + +class SerializedRequestEntityTooLargeException(ServiceException): + code: str = "SerializedRequestEntityTooLargeException" + sender_fault: bool = True + status_code: int = 413 + Type: String | None class ServiceException(ServiceException): code: str = "ServiceException" sender_fault: bool = False status_code: int = 500 - Type: Optional[String] + Type: String | None class SnapStartException(ServiceException): code: str = "SnapStartException" sender_fault: bool = True status_code: int = 400 - Type: Optional[String] + Type: String | None class SnapStartNotReadyException(ServiceException): code: str = "SnapStartNotReadyException" sender_fault: bool = True status_code: int = 409 - Type: Optional[String] + Type: String | None class SnapStartTimeoutException(ServiceException): code: str = "SnapStartTimeoutException" sender_fault: bool = True status_code: int = 408 - Type: Optional[String] + Type: String | None class SubnetIPAddressLimitReachedException(ServiceException): code: str = "SubnetIPAddressLimitReachedException" sender_fault: bool = False status_code: int = 502 - Type: Optional[String] + Type: String | None class TooManyRequestsException(ServiceException): code: str = "TooManyRequestsException" sender_fault: bool = True status_code: int = 429 - retryAfterSeconds: Optional[String] - Type: Optional[String] - Reason: Optional[ThrottleReason] + retryAfterSeconds: String | None + Type: String | None + Reason: ThrottleReason | None class UnsupportedMediaTypeException(ServiceException): code: str = "UnsupportedMediaTypeException" sender_fault: bool = True status_code: int = 415 - Type: Optional[String] + Type: String | None Long = int class AccountLimit(TypedDict, total=False): - TotalCodeSize: Optional[Long] - CodeSizeUnzipped: Optional[Long] - CodeSizeZipped: Optional[Long] - ConcurrentExecutions: Optional[Integer] - UnreservedConcurrentExecutions: Optional[UnreservedConcurrentExecutions] + TotalCodeSize: Long | None + CodeSizeUnzipped: Long | None + CodeSizeZipped: Long | None + ConcurrentExecutions: Integer | None + UnreservedConcurrentExecutions: UnreservedConcurrentExecutions | None class AccountUsage(TypedDict, total=False): - TotalCodeSize: Optional[Long] - FunctionCount: Optional[Long] + TotalCodeSize: Long | None + FunctionCount: Long | None LayerVersionNumber = int @@ -670,53 +887,54 @@ class AddLayerVersionPermissionRequest(ServiceRequest): StatementId: StatementId Action: LayerPermissionAllowedAction Principal: LayerPermissionAllowedPrincipal - OrganizationId: Optional[OrganizationId] - RevisionId: Optional[String] + OrganizationId: OrganizationId | None + RevisionId: String | None class AddLayerVersionPermissionResponse(TypedDict, total=False): - Statement: Optional[String] - RevisionId: Optional[String] + Statement: String | None + RevisionId: String | None class AddPermissionRequest(ServiceRequest): - FunctionName: FunctionName + FunctionName: NamespacedFunctionName StatementId: StatementId Action: Action Principal: Principal - SourceArn: Optional[Arn] - SourceAccount: Optional[SourceOwner] - EventSourceToken: Optional[EventSourceToken] - Qualifier: Optional[Qualifier] - RevisionId: Optional[String] - PrincipalOrgID: Optional[PrincipalOrgID] - FunctionUrlAuthType: Optional[FunctionUrlAuthType] + SourceArn: Arn | None + SourceAccount: SourceOwner | None + EventSourceToken: EventSourceToken | None + Qualifier: NumericLatestPublishedOrAliasQualifier | None + RevisionId: String | None + PrincipalOrgID: PrincipalOrgID | None + FunctionUrlAuthType: FunctionUrlAuthType | None + InvokedViaFunctionUrl: InvokedViaFunctionUrl | None class AddPermissionResponse(TypedDict, total=False): - Statement: Optional[String] + Statement: String | None -AdditionalVersionWeights = Dict[AdditionalVersion, Weight] +AdditionalVersionWeights = dict[AdditionalVersion, Weight] class AliasRoutingConfiguration(TypedDict, total=False): - AdditionalVersionWeights: Optional[AdditionalVersionWeights] + AdditionalVersionWeights: AdditionalVersionWeights | None class AliasConfiguration(TypedDict, total=False): - AliasArn: Optional[FunctionArn] - Name: Optional[Alias] - FunctionVersion: Optional[Version] - Description: Optional[Description] - RoutingConfig: Optional[AliasRoutingConfiguration] - RevisionId: Optional[String] + AliasArn: FunctionArn | None + Name: Alias | None + FunctionVersion: Version | None + Description: Description | None + RoutingConfig: AliasRoutingConfiguration | None + RevisionId: String | None -AliasList = List[AliasConfiguration] -AllowMethodsList = List[Method] -AllowOriginsList = List[Origin] -SigningProfileVersionArns = List[Arn] +AliasList = list[AliasConfiguration] +AllowMethodsList = list[Method] +AllowOriginsList = list[Origin] +SigningProfileVersionArns = list[Arn] class AllowedPublishers(TypedDict, total=False): @@ -724,87 +942,352 @@ class AllowedPublishers(TypedDict, total=False): class KafkaSchemaValidationConfig(TypedDict, total=False): - Attribute: Optional[KafkaSchemaValidationAttribute] + Attribute: KafkaSchemaValidationAttribute | None -KafkaSchemaValidationConfigList = List[KafkaSchemaValidationConfig] +KafkaSchemaValidationConfigList = list[KafkaSchemaValidationConfig] class KafkaSchemaRegistryAccessConfig(TypedDict, total=False): - Type: Optional[KafkaSchemaRegistryAuthType] - URI: Optional[Arn] + Type: KafkaSchemaRegistryAuthType | None + URI: Arn | None -KafkaSchemaRegistryAccessConfigList = List[KafkaSchemaRegistryAccessConfig] +KafkaSchemaRegistryAccessConfigList = list[KafkaSchemaRegistryAccessConfig] class KafkaSchemaRegistryConfig(TypedDict, total=False): - SchemaRegistryURI: Optional[SchemaRegistryUri] - EventRecordFormat: Optional[SchemaRegistryEventRecordFormat] - AccessConfigs: Optional[KafkaSchemaRegistryAccessConfigList] - SchemaValidationConfigs: Optional[KafkaSchemaValidationConfigList] + SchemaRegistryURI: SchemaRegistryUri | None + EventRecordFormat: SchemaRegistryEventRecordFormat | None + AccessConfigs: KafkaSchemaRegistryAccessConfigList | None + SchemaValidationConfigs: KafkaSchemaValidationConfigList | None class AmazonManagedKafkaEventSourceConfig(TypedDict, total=False): - ConsumerGroupId: Optional[URI] - SchemaRegistryConfig: Optional[KafkaSchemaRegistryConfig] + ConsumerGroupId: URI | None + SchemaRegistryConfig: KafkaSchemaRegistryConfig | None -ArchitecturesList = List[Architecture] +ArchitecturesList = list[Architecture] +BinaryOperationPayload = bytes Blob = bytes BlobStream = bytes +StackTraceEntries = list[StackTraceEntry] + + +class ErrorObject(TypedDict, total=False): + ErrorMessage: ErrorMessage | None + ErrorType: ErrorType | None + ErrorData: ErrorData | None + StackTrace: StackTraceEntries | None + + +class CallbackDetails(TypedDict, total=False): + CallbackId: CallbackId | None + Result: OperationPayload | None + Error: ErrorObject | None + + +class EventError(TypedDict, total=False): + Payload: ErrorObject | None + Truncated: Truncated | None + + +class CallbackFailedDetails(TypedDict, total=False): + Error: EventError + + +class CallbackOptions(TypedDict, total=False): + TimeoutSeconds: DurationSeconds | None + HeartbeatTimeoutSeconds: DurationSeconds | None + + +class CallbackStartedDetails(TypedDict, total=False): + CallbackId: CallbackId + HeartbeatTimeout: DurationSeconds | None + Timeout: DurationSeconds | None + + +class EventResult(TypedDict, total=False): + Payload: OperationPayload | None + Truncated: Truncated | None + + +class CallbackSucceededDetails(TypedDict, total=False): + Result: EventResult + + +class CallbackTimedOutDetails(TypedDict, total=False): + Error: EventError + + +class TargetTrackingScalingPolicy(TypedDict, total=False): + PredefinedMetricType: CapacityProviderPredefinedMetricType + TargetValue: MetricTargetValue + + +CapacityProviderScalingPoliciesList = list[TargetTrackingScalingPolicy] + + +class CapacityProviderScalingConfig(TypedDict, total=False): + MaxVCpuCount: CapacityProviderMaxVCpuCount | None + ScalingMode: CapacityProviderScalingMode | None + ScalingPolicies: CapacityProviderScalingPoliciesList | None + + +InstanceTypeSet = list[InstanceType] + + +class InstanceRequirements(TypedDict, total=False): + Architectures: ArchitecturesList | None + AllowedInstanceTypes: InstanceTypeSet | None + ExcludedInstanceTypes: InstanceTypeSet | None + + +class CapacityProviderPermissionsConfig(TypedDict, total=False): + CapacityProviderOperatorRoleArn: RoleArn + + +CapacityProviderSecurityGroupIds = list[SecurityGroupId] +CapacityProviderSubnetIds = list[SubnetId] + + +class CapacityProviderVpcConfig(TypedDict, total=False): + SubnetIds: CapacityProviderSubnetIds + SecurityGroupIds: CapacityProviderSecurityGroupIds + + +class CapacityProvider(TypedDict, total=False): + CapacityProviderArn: CapacityProviderArn + State: CapacityProviderState + VpcConfig: CapacityProviderVpcConfig + PermissionsConfig: CapacityProviderPermissionsConfig + InstanceRequirements: InstanceRequirements | None + CapacityProviderScalingConfig: CapacityProviderScalingConfig | None + KmsKeyArn: KMSKeyArn | None + LastModified: Timestamp | None + + +class LambdaManagedInstancesCapacityProviderConfig(TypedDict, total=False): + CapacityProviderArn: CapacityProviderArn + PerExecutionEnvironmentMaxConcurrency: PerExecutionEnvironmentMaxConcurrency | None + ExecutionEnvironmentMemoryGiBPerVCpu: ExecutionEnvironmentMemoryGiBPerVCpu | None + + +class CapacityProviderConfig(TypedDict, total=False): + LambdaManagedInstancesCapacityProviderConfig: LambdaManagedInstancesCapacityProviderConfig + + +CapacityProvidersList = list[CapacityProvider] + + +class ChainedInvokeDetails(TypedDict, total=False): + Result: OperationPayload | None + Error: ErrorObject | None + + +class ChainedInvokeFailedDetails(TypedDict, total=False): + Error: EventError + + +class ChainedInvokeOptions(TypedDict, total=False): + FunctionName: NamespacedFunctionName + TenantId: TenantId | None + + +class EventInput(TypedDict, total=False): + Payload: InputPayload | None + Truncated: Truncated | None + + +class ChainedInvokeStartedDetails(TypedDict, total=False): + FunctionName: NamespacedFunctionName + TenantId: TenantId | None + Input: EventInput | None + ExecutedVersion: VersionWithLatestPublished | None + DurableExecutionArn: DurableExecutionArn | None + + +class ChainedInvokeStoppedDetails(TypedDict, total=False): + Error: EventError + + +class ChainedInvokeSucceededDetails(TypedDict, total=False): + Result: EventResult + + +class ChainedInvokeTimedOutDetails(TypedDict, total=False): + Error: EventError + + +class WaitOptions(TypedDict, total=False): + WaitSeconds: WaitOptionsWaitSecondsInteger | None + + +class StepOptions(TypedDict, total=False): + NextAttemptDelaySeconds: StepOptionsNextAttemptDelaySecondsInteger | None + + +class ContextOptions(TypedDict, total=False): + ReplayChildren: ReplayChildren | None + + +class OperationUpdate(TypedDict, total=False): + Id: OperationId + ParentId: OperationId | None + Name: OperationName | None + Type: OperationType + SubType: OperationSubType | None + Action: OperationAction + Payload: OperationPayload | None + Error: ErrorObject | None + ContextOptions: ContextOptions | None + StepOptions: StepOptions | None + WaitOptions: WaitOptions | None + CallbackOptions: CallbackOptions | None + ChainedInvokeOptions: ChainedInvokeOptions | None + + +OperationUpdates = list[OperationUpdate] + + +class CheckpointDurableExecutionRequest(ServiceRequest): + DurableExecutionArn: DurableExecutionArn + CheckpointToken: CheckpointToken + Updates: OperationUpdates | None + ClientToken: ClientToken | None + + +ExecutionTimestamp = datetime + + +class WaitDetails(TypedDict, total=False): + ScheduledEndTimestamp: ExecutionTimestamp | None + + +class StepDetails(TypedDict, total=False): + Attempt: AttemptCount | None + NextAttemptTimestamp: ExecutionTimestamp | None + Result: OperationPayload | None + Error: ErrorObject | None + + +class ContextDetails(TypedDict, total=False): + ReplayChildren: ReplayChildren | None + Result: OperationPayload | None + Error: ErrorObject | None + + +class ExecutionDetails(TypedDict, total=False): + InputPayload: InputPayload | None + + +class Operation(TypedDict, total=False): + Id: OperationId + ParentId: OperationId | None + Name: OperationName | None + Type: OperationType + SubType: OperationSubType | None + StartTimestamp: ExecutionTimestamp + EndTimestamp: ExecutionTimestamp | None + Status: OperationStatus + ExecutionDetails: ExecutionDetails | None + ContextDetails: ContextDetails | None + StepDetails: StepDetails | None + WaitDetails: WaitDetails | None + CallbackDetails: CallbackDetails | None + ChainedInvokeDetails: ChainedInvokeDetails | None + + +Operations = list[Operation] + + +class CheckpointUpdatedExecutionState(TypedDict, total=False): + Operations: Operations | None + NextMarker: String | None + + +class CheckpointDurableExecutionResponse(TypedDict, total=False): + CheckpointToken: CheckpointToken | None + NewExecutionState: CheckpointUpdatedExecutionState class CodeSigningPolicies(TypedDict, total=False): - UntrustedArtifactOnDeployment: Optional[CodeSigningPolicy] + UntrustedArtifactOnDeployment: CodeSigningPolicy | None class CodeSigningConfig(TypedDict, total=False): CodeSigningConfigId: CodeSigningConfigId CodeSigningConfigArn: CodeSigningConfigArn - Description: Optional[Description] + Description: Description | None AllowedPublishers: AllowedPublishers CodeSigningPolicies: CodeSigningPolicies LastModified: Timestamp -CodeSigningConfigList = List[CodeSigningConfig] -CompatibleArchitectures = List[Architecture] -CompatibleRuntimes = List[Runtime] +CodeSigningConfigList = list[CodeSigningConfig] +CompatibleArchitectures = list[Architecture] +CompatibleRuntimes = list[Runtime] class Concurrency(TypedDict, total=False): - ReservedConcurrentExecutions: Optional[ReservedConcurrentExecutions] + ReservedConcurrentExecutions: ReservedConcurrentExecutions | None + + +class ContextFailedDetails(TypedDict, total=False): + Error: EventError + + +class ContextStartedDetails(TypedDict, total=False): + pass + + +class ContextSucceededDetails(TypedDict, total=False): + Result: EventResult -HeadersList = List[Header] +HeadersList = list[Header] class Cors(TypedDict, total=False): - AllowCredentials: Optional[AllowCredentials] - AllowHeaders: Optional[HeadersList] - AllowMethods: Optional[AllowMethodsList] - AllowOrigins: Optional[AllowOriginsList] - ExposeHeaders: Optional[HeadersList] - MaxAge: Optional[MaxAge] + AllowCredentials: AllowCredentials | None + AllowHeaders: HeadersList | None + AllowMethods: AllowMethodsList | None + AllowOrigins: AllowOriginsList | None + ExposeHeaders: HeadersList | None + MaxAge: MaxAge | None class CreateAliasRequest(ServiceRequest): FunctionName: FunctionName Name: Alias - FunctionVersion: Version - Description: Optional[Description] - RoutingConfig: Optional[AliasRoutingConfiguration] + FunctionVersion: VersionWithLatestPublished + Description: Description | None + RoutingConfig: AliasRoutingConfiguration | None + + +Tags = dict[TagKey, TagValue] + +class CreateCapacityProviderRequest(ServiceRequest): + CapacityProviderName: CapacityProviderName + VpcConfig: CapacityProviderVpcConfig + PermissionsConfig: CapacityProviderPermissionsConfig + InstanceRequirements: InstanceRequirements | None + CapacityProviderScalingConfig: CapacityProviderScalingConfig | None + KmsKeyArn: KMSKeyArnNonEmpty | None + Tags: Tags | None -Tags = Dict[TagKey, TagValue] + +class CreateCapacityProviderResponse(TypedDict, total=False): + CapacityProvider: CapacityProvider class CreateCodeSigningConfigRequest(ServiceRequest): - Description: Optional[Description] + Description: Description | None AllowedPublishers: AllowedPublishers - CodeSigningPolicies: Optional[CodeSigningPolicies] - Tags: Optional[Tags] + CodeSigningPolicies: CodeSigningPolicies | None + Tags: Tags | None class CreateCodeSigningConfigResponse(TypedDict, total=False): @@ -812,130 +1295,145 @@ class CreateCodeSigningConfigResponse(TypedDict, total=False): class ProvisionedPollerConfig(TypedDict, total=False): - MinimumPollers: Optional[MinimumNumberOfPollers] - MaximumPollers: Optional[MaximumNumberOfPollers] + MinimumPollers: MinimumNumberOfPollers | None + MaximumPollers: MaximumNumberOfPollers | None + PollerGroupName: ProvisionedPollerGroupName | None + + +class EventSourceMappingLoggingConfig(TypedDict, total=False): + SystemLogLevel: EventSourceMappingSystemLogLevel | None -EventSourceMappingMetricList = List[EventSourceMappingMetric] +EventSourceMappingMetricList = list[EventSourceMappingMetric] class EventSourceMappingMetricsConfig(TypedDict, total=False): - Metrics: Optional[EventSourceMappingMetricList] + Metrics: EventSourceMappingMetricList | None class DocumentDBEventSourceConfig(TypedDict, total=False): - DatabaseName: Optional[DatabaseName] - CollectionName: Optional[CollectionName] - FullDocument: Optional[FullDocument] + DatabaseName: DatabaseName | None + CollectionName: CollectionName | None + FullDocument: FullDocument | None class ScalingConfig(TypedDict, total=False): - MaximumConcurrency: Optional[MaximumConcurrency] + MaximumConcurrency: MaximumConcurrency | None class SelfManagedKafkaEventSourceConfig(TypedDict, total=False): - ConsumerGroupId: Optional[URI] - SchemaRegistryConfig: Optional[KafkaSchemaRegistryConfig] + ConsumerGroupId: URI | None + SchemaRegistryConfig: KafkaSchemaRegistryConfig | None -FunctionResponseTypeList = List[FunctionResponseType] -EndpointLists = List[Endpoint] -Endpoints = Dict[EndPointType, EndpointLists] +FunctionResponseTypeList = list[FunctionResponseType] +EndpointLists = list[Endpoint] +Endpoints = dict[EndPointType, EndpointLists] class SelfManagedEventSource(TypedDict, total=False): - Endpoints: Optional[Endpoints] + Endpoints: Endpoints | None class SourceAccessConfiguration(TypedDict, total=False): - Type: Optional[SourceAccessType] - URI: Optional[URI] + Type: SourceAccessType | None + URI: URI | None -SourceAccessConfigurations = List[SourceAccessConfiguration] -Queues = List[Queue] -Topics = List[Topic] +SourceAccessConfigurations = list[SourceAccessConfiguration] +Queues = list[Queue] +Topics = list[Topic] class OnFailure(TypedDict, total=False): - Destination: Optional[DestinationArn] + Destination: DestinationArn | None class OnSuccess(TypedDict, total=False): - Destination: Optional[DestinationArn] + Destination: DestinationArn | None class DestinationConfig(TypedDict, total=False): - OnSuccess: Optional[OnSuccess] - OnFailure: Optional[OnFailure] + OnSuccess: OnSuccess | None + OnFailure: OnFailure | None Date = datetime class Filter(TypedDict, total=False): - Pattern: Optional[Pattern] + Pattern: Pattern | None -FilterList = List[Filter] +FilterList = list[Filter] class FilterCriteria(TypedDict, total=False): - Filters: Optional[FilterList] + Filters: FilterList | None class CreateEventSourceMappingRequest(ServiceRequest): - EventSourceArn: Optional[Arn] - FunctionName: FunctionName - Enabled: Optional[Enabled] - BatchSize: Optional[BatchSize] - FilterCriteria: Optional[FilterCriteria] - MaximumBatchingWindowInSeconds: Optional[MaximumBatchingWindowInSeconds] - ParallelizationFactor: Optional[ParallelizationFactor] - StartingPosition: Optional[EventSourcePosition] - StartingPositionTimestamp: Optional[Date] - DestinationConfig: Optional[DestinationConfig] - MaximumRecordAgeInSeconds: Optional[MaximumRecordAgeInSeconds] - BisectBatchOnFunctionError: Optional[BisectBatchOnFunctionError] - MaximumRetryAttempts: Optional[MaximumRetryAttemptsEventSourceMapping] - Tags: Optional[Tags] - TumblingWindowInSeconds: Optional[TumblingWindowInSeconds] - Topics: Optional[Topics] - Queues: Optional[Queues] - SourceAccessConfigurations: Optional[SourceAccessConfigurations] - SelfManagedEventSource: Optional[SelfManagedEventSource] - FunctionResponseTypes: Optional[FunctionResponseTypeList] - AmazonManagedKafkaEventSourceConfig: Optional[AmazonManagedKafkaEventSourceConfig] - SelfManagedKafkaEventSourceConfig: Optional[SelfManagedKafkaEventSourceConfig] - ScalingConfig: Optional[ScalingConfig] - DocumentDBEventSourceConfig: Optional[DocumentDBEventSourceConfig] - KMSKeyArn: Optional[KMSKeyArn] - MetricsConfig: Optional[EventSourceMappingMetricsConfig] - ProvisionedPollerConfig: Optional[ProvisionedPollerConfig] + EventSourceArn: Arn | None + FunctionName: NamespacedFunctionName + Enabled: Enabled | None + BatchSize: BatchSize | None + FilterCriteria: FilterCriteria | None + MaximumBatchingWindowInSeconds: MaximumBatchingWindowInSeconds | None + ParallelizationFactor: ParallelizationFactor | None + StartingPosition: EventSourcePosition | None + StartingPositionTimestamp: Date | None + DestinationConfig: DestinationConfig | None + MaximumRecordAgeInSeconds: MaximumRecordAgeInSeconds | None + BisectBatchOnFunctionError: BisectBatchOnFunctionError | None + MaximumRetryAttempts: MaximumRetryAttemptsEventSourceMapping | None + Tags: Tags | None + TumblingWindowInSeconds: TumblingWindowInSeconds | None + Topics: Topics | None + Queues: Queues | None + SourceAccessConfigurations: SourceAccessConfigurations | None + SelfManagedEventSource: SelfManagedEventSource | None + FunctionResponseTypes: FunctionResponseTypeList | None + AmazonManagedKafkaEventSourceConfig: AmazonManagedKafkaEventSourceConfig | None + SelfManagedKafkaEventSourceConfig: SelfManagedKafkaEventSourceConfig | None + ScalingConfig: ScalingConfig | None + DocumentDBEventSourceConfig: DocumentDBEventSourceConfig | None + KMSKeyArn: KMSKeyArn | None + MetricsConfig: EventSourceMappingMetricsConfig | None + LoggingConfig: EventSourceMappingLoggingConfig | None + ProvisionedPollerConfig: ProvisionedPollerConfig | None + + +class TenancyConfig(TypedDict, total=False): + TenantIsolationMode: TenantIsolationMode + + +class DurableConfig(TypedDict, total=False): + RetentionPeriodInDays: RetentionPeriodInDays | None + ExecutionTimeout: ExecutionTimeout | None class LoggingConfig(TypedDict, total=False): - LogFormat: Optional[LogFormat] - ApplicationLogLevel: Optional[ApplicationLogLevel] - SystemLogLevel: Optional[SystemLogLevel] - LogGroup: Optional[LogGroup] + LogFormat: LogFormat | None + ApplicationLogLevel: ApplicationLogLevel | None + SystemLogLevel: SystemLogLevel | None + LogGroup: LogGroup | None class SnapStart(TypedDict, total=False): - ApplyOn: Optional[SnapStartApplyOn] + ApplyOn: SnapStartApplyOn | None class EphemeralStorage(TypedDict, total=False): Size: EphemeralStorageSize -StringList = List[String] +StringList = list[String] class ImageConfig(TypedDict, total=False): - EntryPoint: Optional[StringList] - Command: Optional[StringList] - WorkingDirectory: Optional[WorkingDirectory] + EntryPoint: StringList | None + Command: StringList | None + WorkingDirectory: WorkingDirectory | None class FileSystemConfig(TypedDict, total=False): @@ -943,86 +1441,90 @@ class FileSystemConfig(TypedDict, total=False): LocalMountPath: LocalMountPath -FileSystemConfigList = List[FileSystemConfig] -LayerList = List[LayerVersionArn] +FileSystemConfigList = list[FileSystemConfig] +LayerList = list[LayerVersionArn] class TracingConfig(TypedDict, total=False): - Mode: Optional[TracingMode] + Mode: TracingMode | None -EnvironmentVariables = Dict[EnvironmentVariableName, EnvironmentVariableValue] +EnvironmentVariables = dict[EnvironmentVariableName, EnvironmentVariableValue] class Environment(TypedDict, total=False): - Variables: Optional[EnvironmentVariables] + Variables: EnvironmentVariables | None class DeadLetterConfig(TypedDict, total=False): - TargetArn: Optional[ResourceArn] + TargetArn: ResourceArn | None -SecurityGroupIds = List[SecurityGroupId] -SubnetIds = List[SubnetId] +SecurityGroupIds = list[SecurityGroupId] +SubnetIds = list[SubnetId] class VpcConfig(TypedDict, total=False): - SubnetIds: Optional[SubnetIds] - SecurityGroupIds: Optional[SecurityGroupIds] - Ipv6AllowedForDualStack: Optional[NullableBoolean] + SubnetIds: SubnetIds | None + SecurityGroupIds: SecurityGroupIds | None + Ipv6AllowedForDualStack: NullableBoolean | None class FunctionCode(TypedDict, total=False): - ZipFile: Optional[Blob] - S3Bucket: Optional[S3Bucket] - S3Key: Optional[S3Key] - S3ObjectVersion: Optional[S3ObjectVersion] - ImageUri: Optional[String] - SourceKMSKeyArn: Optional[KMSKeyArn] + ZipFile: Blob | None + S3Bucket: S3Bucket | None + S3Key: S3Key | None + S3ObjectVersion: S3ObjectVersion | None + ImageUri: String | None + SourceKMSKeyArn: KMSKeyArn | None class CreateFunctionRequest(ServiceRequest): FunctionName: FunctionName - Runtime: Optional[Runtime] + Runtime: Runtime | None Role: RoleArn - Handler: Optional[Handler] + Handler: Handler | None Code: FunctionCode - Description: Optional[Description] - Timeout: Optional[Timeout] - MemorySize: Optional[MemorySize] - Publish: Optional[Boolean] - VpcConfig: Optional[VpcConfig] - PackageType: Optional[PackageType] - DeadLetterConfig: Optional[DeadLetterConfig] - Environment: Optional[Environment] - KMSKeyArn: Optional[KMSKeyArn] - TracingConfig: Optional[TracingConfig] - Tags: Optional[Tags] - Layers: Optional[LayerList] - FileSystemConfigs: Optional[FileSystemConfigList] - ImageConfig: Optional[ImageConfig] - CodeSigningConfigArn: Optional[CodeSigningConfigArn] - Architectures: Optional[ArchitecturesList] - EphemeralStorage: Optional[EphemeralStorage] - SnapStart: Optional[SnapStart] - LoggingConfig: Optional[LoggingConfig] + Description: Description | None + Timeout: Timeout | None + MemorySize: MemorySize | None + Publish: Boolean | None + VpcConfig: VpcConfig | None + PackageType: PackageType | None + DeadLetterConfig: DeadLetterConfig | None + Environment: Environment | None + KMSKeyArn: KMSKeyArn | None + TracingConfig: TracingConfig | None + Tags: Tags | None + Layers: LayerList | None + FileSystemConfigs: FileSystemConfigList | None + ImageConfig: ImageConfig | None + CodeSigningConfigArn: CodeSigningConfigArn | None + Architectures: ArchitecturesList | None + EphemeralStorage: EphemeralStorage | None + SnapStart: SnapStart | None + LoggingConfig: LoggingConfig | None + CapacityProviderConfig: CapacityProviderConfig | None + PublishTo: FunctionVersionLatestPublished | None + DurableConfig: DurableConfig | None + TenancyConfig: TenancyConfig | None class CreateFunctionUrlConfigRequest(ServiceRequest): FunctionName: FunctionName - Qualifier: Optional[FunctionUrlQualifier] + Qualifier: FunctionUrlQualifier | None AuthType: FunctionUrlAuthType - Cors: Optional[Cors] - InvokeMode: Optional[InvokeMode] + Cors: Cors | None + InvokeMode: InvokeMode | None class CreateFunctionUrlConfigResponse(TypedDict, total=False): FunctionUrl: FunctionUrl FunctionArn: FunctionArn AuthType: FunctionUrlAuthType - Cors: Optional[Cors] + Cors: Cors | None CreationTime: Timestamp - InvokeMode: Optional[InvokeMode] + InvokeMode: InvokeMode | None class DeleteAliasRequest(ServiceRequest): @@ -1030,6 +1532,14 @@ class DeleteAliasRequest(ServiceRequest): Name: Alias +class DeleteCapacityProviderRequest(ServiceRequest): + CapacityProviderName: CapacityProviderName + + +class DeleteCapacityProviderResponse(TypedDict, total=False): + CapacityProvider: CapacityProvider + + class DeleteCodeSigningConfigRequest(ServiceRequest): CodeSigningConfigArn: CodeSigningConfigArn @@ -1043,7 +1553,7 @@ class DeleteEventSourceMappingRequest(ServiceRequest): class DeleteFunctionCodeSigningConfigRequest(ServiceRequest): - FunctionName: FunctionName + FunctionName: NamespacedFunctionName class DeleteFunctionConcurrencyRequest(ServiceRequest): @@ -1051,18 +1561,22 @@ class DeleteFunctionConcurrencyRequest(ServiceRequest): class DeleteFunctionEventInvokeConfigRequest(ServiceRequest): - FunctionName: FunctionName - Qualifier: Optional[Qualifier] + FunctionName: NamespacedFunctionName + Qualifier: NumericLatestPublishedOrAliasQualifier | None class DeleteFunctionRequest(ServiceRequest): - FunctionName: FunctionName - Qualifier: Optional[Qualifier] + FunctionName: NamespacedFunctionName + Qualifier: NumericLatestPublishedOrAliasQualifier | None + + +class DeleteFunctionResponse(TypedDict, total=False): + StatusCode: Integer | None class DeleteFunctionUrlConfigRequest(ServiceRequest): FunctionName: FunctionName - Qualifier: Optional[FunctionUrlQualifier] + Qualifier: FunctionUrlQualifier | None class DeleteLayerVersionRequest(ServiceRequest): @@ -1075,163 +1589,281 @@ class DeleteProvisionedConcurrencyConfigRequest(ServiceRequest): Qualifier: Qualifier +class Execution(TypedDict, total=False): + DurableExecutionArn: DurableExecutionArn + DurableExecutionName: DurableExecutionName + FunctionArn: NameSpacedFunctionArn + Status: ExecutionStatus + StartTimestamp: ExecutionTimestamp + EndTimestamp: ExecutionTimestamp | None + + +DurableExecutions = list[Execution] + + class EnvironmentError(TypedDict, total=False): - ErrorCode: Optional[String] - Message: Optional[SensitiveString] + ErrorCode: String | None + Message: SensitiveString | None class EnvironmentResponse(TypedDict, total=False): - Variables: Optional[EnvironmentVariables] - Error: Optional[EnvironmentError] + Variables: EnvironmentVariables | None + Error: EnvironmentError | None + + +class InvocationCompletedDetails(TypedDict, total=False): + StartTimestamp: ExecutionTimestamp + EndTimestamp: ExecutionTimestamp + RequestId: String + Error: EventError | None + + +class RetryDetails(TypedDict, total=False): + CurrentAttempt: AttemptCount | None + NextAttemptDelaySeconds: DurationSeconds | None + + +class StepFailedDetails(TypedDict, total=False): + Error: EventError + RetryDetails: RetryDetails + + +class StepSucceededDetails(TypedDict, total=False): + Result: EventResult + RetryDetails: RetryDetails + + +class StepStartedDetails(TypedDict, total=False): + pass + + +class WaitCancelledDetails(TypedDict, total=False): + Error: EventError | None + + +class WaitSucceededDetails(TypedDict, total=False): + Duration: DurationSeconds | None + + +class WaitStartedDetails(TypedDict, total=False): + Duration: DurationSeconds + ScheduledEndTimestamp: ExecutionTimestamp + + +class ExecutionStoppedDetails(TypedDict, total=False): + Error: EventError + + +class ExecutionTimedOutDetails(TypedDict, total=False): + Error: EventError | None + + +class ExecutionFailedDetails(TypedDict, total=False): + Error: EventError + + +class ExecutionSucceededDetails(TypedDict, total=False): + Result: EventResult + + +class ExecutionStartedDetails(TypedDict, total=False): + Input: EventInput + ExecutionTimeout: DurationSeconds + + +class Event(TypedDict, total=False): + EventType: EventType | None + SubType: OperationSubType | None + EventId: EventId | None + Id: OperationId | None + Name: OperationName | None + EventTimestamp: ExecutionTimestamp | None + ParentId: OperationId | None + ExecutionStartedDetails: ExecutionStartedDetails | None + ExecutionSucceededDetails: ExecutionSucceededDetails | None + ExecutionFailedDetails: ExecutionFailedDetails | None + ExecutionTimedOutDetails: ExecutionTimedOutDetails | None + ExecutionStoppedDetails: ExecutionStoppedDetails | None + ContextStartedDetails: ContextStartedDetails | None + ContextSucceededDetails: ContextSucceededDetails | None + ContextFailedDetails: ContextFailedDetails | None + WaitStartedDetails: WaitStartedDetails | None + WaitSucceededDetails: WaitSucceededDetails | None + WaitCancelledDetails: WaitCancelledDetails | None + StepStartedDetails: StepStartedDetails | None + StepSucceededDetails: StepSucceededDetails | None + StepFailedDetails: StepFailedDetails | None + ChainedInvokeStartedDetails: ChainedInvokeStartedDetails | None + ChainedInvokeSucceededDetails: ChainedInvokeSucceededDetails | None + ChainedInvokeFailedDetails: ChainedInvokeFailedDetails | None + ChainedInvokeTimedOutDetails: ChainedInvokeTimedOutDetails | None + ChainedInvokeStoppedDetails: ChainedInvokeStoppedDetails | None + CallbackStartedDetails: CallbackStartedDetails | None + CallbackSucceededDetails: CallbackSucceededDetails | None + CallbackFailedDetails: CallbackFailedDetails | None + CallbackTimedOutDetails: CallbackTimedOutDetails | None + InvocationCompletedDetails: InvocationCompletedDetails | None class FilterCriteriaError(TypedDict, total=False): - ErrorCode: Optional[FilterCriteriaErrorCode] - Message: Optional[FilterCriteriaErrorMessage] + ErrorCode: FilterCriteriaErrorCode | None + Message: FilterCriteriaErrorMessage | None class EventSourceMappingConfiguration(TypedDict, total=False): - UUID: Optional[String] - StartingPosition: Optional[EventSourcePosition] - StartingPositionTimestamp: Optional[Date] - BatchSize: Optional[BatchSize] - MaximumBatchingWindowInSeconds: Optional[MaximumBatchingWindowInSeconds] - ParallelizationFactor: Optional[ParallelizationFactor] - EventSourceArn: Optional[Arn] - FilterCriteria: Optional[FilterCriteria] - FunctionArn: Optional[FunctionArn] - LastModified: Optional[Date] - LastProcessingResult: Optional[String] - State: Optional[String] - StateTransitionReason: Optional[String] - DestinationConfig: Optional[DestinationConfig] - Topics: Optional[Topics] - Queues: Optional[Queues] - SourceAccessConfigurations: Optional[SourceAccessConfigurations] - SelfManagedEventSource: Optional[SelfManagedEventSource] - MaximumRecordAgeInSeconds: Optional[MaximumRecordAgeInSeconds] - BisectBatchOnFunctionError: Optional[BisectBatchOnFunctionError] - MaximumRetryAttempts: Optional[MaximumRetryAttemptsEventSourceMapping] - TumblingWindowInSeconds: Optional[TumblingWindowInSeconds] - FunctionResponseTypes: Optional[FunctionResponseTypeList] - AmazonManagedKafkaEventSourceConfig: Optional[AmazonManagedKafkaEventSourceConfig] - SelfManagedKafkaEventSourceConfig: Optional[SelfManagedKafkaEventSourceConfig] - ScalingConfig: Optional[ScalingConfig] - DocumentDBEventSourceConfig: Optional[DocumentDBEventSourceConfig] - KMSKeyArn: Optional[KMSKeyArn] - FilterCriteriaError: Optional[FilterCriteriaError] - EventSourceMappingArn: Optional[EventSourceMappingArn] - MetricsConfig: Optional[EventSourceMappingMetricsConfig] - ProvisionedPollerConfig: Optional[ProvisionedPollerConfig] - - -EventSourceMappingsList = List[EventSourceMappingConfiguration] -FunctionArnList = List[FunctionArn] + UUID: String | None + StartingPosition: EventSourcePosition | None + StartingPositionTimestamp: Date | None + BatchSize: BatchSize | None + MaximumBatchingWindowInSeconds: MaximumBatchingWindowInSeconds | None + ParallelizationFactor: ParallelizationFactor | None + EventSourceArn: Arn | None + FilterCriteria: FilterCriteria | None + FunctionArn: FunctionArn | None + LastModified: Date | None + LastProcessingResult: String | None + State: String | None + StateTransitionReason: String | None + DestinationConfig: DestinationConfig | None + Topics: Topics | None + Queues: Queues | None + SourceAccessConfigurations: SourceAccessConfigurations | None + SelfManagedEventSource: SelfManagedEventSource | None + MaximumRecordAgeInSeconds: MaximumRecordAgeInSeconds | None + BisectBatchOnFunctionError: BisectBatchOnFunctionError | None + MaximumRetryAttempts: MaximumRetryAttemptsEventSourceMapping | None + TumblingWindowInSeconds: TumblingWindowInSeconds | None + FunctionResponseTypes: FunctionResponseTypeList | None + AmazonManagedKafkaEventSourceConfig: AmazonManagedKafkaEventSourceConfig | None + SelfManagedKafkaEventSourceConfig: SelfManagedKafkaEventSourceConfig | None + ScalingConfig: ScalingConfig | None + DocumentDBEventSourceConfig: DocumentDBEventSourceConfig | None + KMSKeyArn: KMSKeyArn | None + FilterCriteriaError: FilterCriteriaError | None + EventSourceMappingArn: EventSourceMappingArn | None + MetricsConfig: EventSourceMappingMetricsConfig | None + LoggingConfig: EventSourceMappingLoggingConfig | None + ProvisionedPollerConfig: ProvisionedPollerConfig | None + + +EventSourceMappingsList = list[EventSourceMappingConfiguration] +Events = list[Event] +ExecutionStatusList = list[ExecutionStatus] +FunctionArnList = list[FunctionArn] class FunctionCodeLocation(TypedDict, total=False): - RepositoryType: Optional[String] - Location: Optional[String] - ImageUri: Optional[String] - ResolvedImageUri: Optional[String] - SourceKMSKeyArn: Optional[String] + RepositoryType: String | None + Location: String | None + ImageUri: String | None + ResolvedImageUri: String | None + SourceKMSKeyArn: String | None class RuntimeVersionError(TypedDict, total=False): - ErrorCode: Optional[String] - Message: Optional[SensitiveString] + ErrorCode: String | None + Message: SensitiveString | None class RuntimeVersionConfig(TypedDict, total=False): - RuntimeVersionArn: Optional[RuntimeVersionArn] - Error: Optional[RuntimeVersionError] + RuntimeVersionArn: RuntimeVersionArn | None + Error: RuntimeVersionError | None class SnapStartResponse(TypedDict, total=False): - ApplyOn: Optional[SnapStartApplyOn] - OptimizationStatus: Optional[SnapStartOptimizationStatus] + ApplyOn: SnapStartApplyOn | None + OptimizationStatus: SnapStartOptimizationStatus | None class ImageConfigError(TypedDict, total=False): - ErrorCode: Optional[String] - Message: Optional[SensitiveString] + ErrorCode: String | None + Message: SensitiveString | None class ImageConfigResponse(TypedDict, total=False): - ImageConfig: Optional[ImageConfig] - Error: Optional[ImageConfigError] + ImageConfig: ImageConfig | None + Error: ImageConfigError | None class Layer(TypedDict, total=False): - Arn: Optional[LayerVersionArn] - CodeSize: Optional[Long] - SigningProfileVersionArn: Optional[Arn] - SigningJobArn: Optional[Arn] + Arn: LayerVersionArn | None + CodeSize: Long | None + SigningProfileVersionArn: Arn | None + SigningJobArn: Arn | None -LayersReferenceList = List[Layer] +LayersReferenceList = list[Layer] class TracingConfigResponse(TypedDict, total=False): - Mode: Optional[TracingMode] + Mode: TracingMode | None class VpcConfigResponse(TypedDict, total=False): - SubnetIds: Optional[SubnetIds] - SecurityGroupIds: Optional[SecurityGroupIds] - VpcId: Optional[VpcId] - Ipv6AllowedForDualStack: Optional[NullableBoolean] + SubnetIds: SubnetIds | None + SecurityGroupIds: SecurityGroupIds | None + VpcId: VpcId | None + Ipv6AllowedForDualStack: NullableBoolean | None class FunctionConfiguration(TypedDict, total=False): - FunctionName: Optional[NamespacedFunctionName] - FunctionArn: Optional[NameSpacedFunctionArn] - Runtime: Optional[Runtime] - Role: Optional[RoleArn] - Handler: Optional[Handler] - CodeSize: Optional[Long] - Description: Optional[Description] - Timeout: Optional[Timeout] - MemorySize: Optional[MemorySize] - LastModified: Optional[Timestamp] - CodeSha256: Optional[String] - Version: Optional[Version] - VpcConfig: Optional[VpcConfigResponse] - DeadLetterConfig: Optional[DeadLetterConfig] - Environment: Optional[EnvironmentResponse] - KMSKeyArn: Optional[KMSKeyArn] - TracingConfig: Optional[TracingConfigResponse] - MasterArn: Optional[FunctionArn] - RevisionId: Optional[String] - Layers: Optional[LayersReferenceList] - State: Optional[State] - StateReason: Optional[StateReason] - StateReasonCode: Optional[StateReasonCode] - LastUpdateStatus: Optional[LastUpdateStatus] - LastUpdateStatusReason: Optional[LastUpdateStatusReason] - LastUpdateStatusReasonCode: Optional[LastUpdateStatusReasonCode] - FileSystemConfigs: Optional[FileSystemConfigList] - PackageType: Optional[PackageType] - ImageConfigResponse: Optional[ImageConfigResponse] - SigningProfileVersionArn: Optional[Arn] - SigningJobArn: Optional[Arn] - Architectures: Optional[ArchitecturesList] - EphemeralStorage: Optional[EphemeralStorage] - SnapStart: Optional[SnapStartResponse] - RuntimeVersionConfig: Optional[RuntimeVersionConfig] - LoggingConfig: Optional[LoggingConfig] + FunctionName: NamespacedFunctionName | None + FunctionArn: NameSpacedFunctionArn | None + Runtime: Runtime | None + Role: RoleArn | None + Handler: Handler | None + CodeSize: Long | None + Description: Description | None + Timeout: Timeout | None + MemorySize: MemorySize | None + LastModified: Timestamp | None + CodeSha256: String | None + Version: Version | None + VpcConfig: VpcConfigResponse | None + DeadLetterConfig: DeadLetterConfig | None + Environment: EnvironmentResponse | None + KMSKeyArn: KMSKeyArn | None + TracingConfig: TracingConfigResponse | None + MasterArn: FunctionArn | None + RevisionId: String | None + Layers: LayersReferenceList | None + State: State | None + StateReason: StateReason | None + StateReasonCode: StateReasonCode | None + LastUpdateStatus: LastUpdateStatus | None + LastUpdateStatusReason: LastUpdateStatusReason | None + LastUpdateStatusReasonCode: LastUpdateStatusReasonCode | None + FileSystemConfigs: FileSystemConfigList | None + PackageType: PackageType | None + ImageConfigResponse: ImageConfigResponse | None + SigningProfileVersionArn: Arn | None + SigningJobArn: Arn | None + Architectures: ArchitecturesList | None + EphemeralStorage: EphemeralStorage | None + SnapStart: SnapStartResponse | None + RuntimeVersionConfig: RuntimeVersionConfig | None + LoggingConfig: LoggingConfig | None + CapacityProviderConfig: CapacityProviderConfig | None + ConfigSha256: String | None + DurableConfig: DurableConfig | None + TenancyConfig: TenancyConfig | None class FunctionEventInvokeConfig(TypedDict, total=False): - LastModified: Optional[Date] - FunctionArn: Optional[FunctionArn] - MaximumRetryAttempts: Optional[MaximumRetryAttempts] - MaximumEventAgeInSeconds: Optional[MaximumEventAgeInSeconds] - DestinationConfig: Optional[DestinationConfig] + LastModified: Date | None + FunctionArn: FunctionArn | None + MaximumRetryAttempts: MaximumRetryAttempts | None + MaximumEventAgeInSeconds: MaximumEventAgeInSeconds | None + DestinationConfig: DestinationConfig | None -FunctionEventInvokeConfigList = List[FunctionEventInvokeConfig] -FunctionList = List[FunctionConfiguration] +FunctionEventInvokeConfigList = list[FunctionEventInvokeConfig] +FunctionList = list[FunctionConfiguration] + + +class FunctionScalingConfig(TypedDict, total=False): + MinExecutionEnvironments: FunctionScalingConfigExecutionEnvironments | None + MaxExecutionEnvironments: FunctionScalingConfigExecutionEnvironments | None class FunctionUrlConfig(TypedDict, total=False): @@ -1239,12 +1871,20 @@ class FunctionUrlConfig(TypedDict, total=False): FunctionArn: FunctionArn CreationTime: Timestamp LastModifiedTime: Timestamp - Cors: Optional[Cors] + Cors: Cors | None AuthType: FunctionUrlAuthType - InvokeMode: Optional[InvokeMode] + InvokeMode: InvokeMode | None + + +FunctionUrlConfigList = list[FunctionUrlConfig] + + +class FunctionVersionsByCapacityProviderListItem(TypedDict, total=False): + FunctionArn: NameSpacedFunctionArn + State: State -FunctionUrlConfigList = List[FunctionUrlConfig] +FunctionVersionsByCapacityProviderList = list[FunctionVersionsByCapacityProviderListItem] class GetAccountSettingsRequest(ServiceRequest): @@ -1252,8 +1892,8 @@ class GetAccountSettingsRequest(ServiceRequest): class GetAccountSettingsResponse(TypedDict, total=False): - AccountLimit: Optional[AccountLimit] - AccountUsage: Optional[AccountUsage] + AccountLimit: AccountLimit | None + AccountUsage: AccountUsage | None class GetAliasRequest(ServiceRequest): @@ -1261,6 +1901,14 @@ class GetAliasRequest(ServiceRequest): Name: Alias +class GetCapacityProviderRequest(ServiceRequest): + CapacityProviderName: CapacityProviderName + + +class GetCapacityProviderResponse(TypedDict, total=False): + CapacityProvider: CapacityProvider + + class GetCodeSigningConfigRequest(ServiceRequest): CodeSigningConfigArn: CodeSigningConfigArn @@ -1269,12 +1917,59 @@ class GetCodeSigningConfigResponse(TypedDict, total=False): CodeSigningConfig: CodeSigningConfig +class GetDurableExecutionHistoryRequest(ServiceRequest): + DurableExecutionArn: DurableExecutionArn + IncludeExecutionData: IncludeExecutionData | None + MaxItems: ItemCount | None + Marker: String | None + ReverseOrder: ReverseOrder | None + + +class GetDurableExecutionHistoryResponse(TypedDict, total=False): + Events: Events + NextMarker: String | None + + +class GetDurableExecutionRequest(ServiceRequest): + DurableExecutionArn: DurableExecutionArn + + +class TraceHeader(TypedDict, total=False): + XAmznTraceId: XAmznTraceId | None + + +class GetDurableExecutionResponse(TypedDict, total=False): + DurableExecutionArn: DurableExecutionArn + DurableExecutionName: DurableExecutionName + FunctionArn: NameSpacedFunctionArn + InputPayload: InputPayload | None + Result: OutputPayload | None + Error: ErrorObject | None + StartTimestamp: ExecutionTimestamp + Status: ExecutionStatus + EndTimestamp: ExecutionTimestamp | None + Version: VersionWithLatestPublished | None + TraceHeader: TraceHeader | None + + +class GetDurableExecutionStateRequest(ServiceRequest): + DurableExecutionArn: DurableExecutionArn + CheckpointToken: CheckpointToken + Marker: String | None + MaxItems: ItemCount | None + + +class GetDurableExecutionStateResponse(TypedDict, total=False): + Operations: Operations + NextMarker: String | None + + class GetEventSourceMappingRequest(ServiceRequest): UUID: String class GetFunctionCodeSigningConfigRequest(ServiceRequest): - FunctionName: FunctionName + FunctionName: NamespacedFunctionName class GetFunctionCodeSigningConfigResponse(TypedDict, total=False): @@ -1287,17 +1982,17 @@ class GetFunctionConcurrencyRequest(ServiceRequest): class GetFunctionConcurrencyResponse(TypedDict, total=False): - ReservedConcurrentExecutions: Optional[ReservedConcurrentExecutions] + ReservedConcurrentExecutions: ReservedConcurrentExecutions | None class GetFunctionConfigurationRequest(ServiceRequest): FunctionName: NamespacedFunctionName - Qualifier: Optional[Qualifier] + Qualifier: NumericLatestPublishedOrAliasQualifier | None class GetFunctionEventInvokeConfigRequest(ServiceRequest): - FunctionName: FunctionName - Qualifier: Optional[Qualifier] + FunctionName: NamespacedFunctionName + Qualifier: NumericLatestPublishedOrAliasQualifier | None class GetFunctionRecursionConfigRequest(ServiceRequest): @@ -1305,12 +2000,12 @@ class GetFunctionRecursionConfigRequest(ServiceRequest): class GetFunctionRecursionConfigResponse(TypedDict, total=False): - RecursiveLoop: Optional[RecursiveLoop] + RecursiveLoop: RecursiveLoop | None class GetFunctionRequest(ServiceRequest): FunctionName: NamespacedFunctionName - Qualifier: Optional[Qualifier] + Qualifier: NumericLatestPublishedOrAliasQualifier | None class TagsError(TypedDict, total=False): @@ -1319,26 +2014,37 @@ class TagsError(TypedDict, total=False): class GetFunctionResponse(TypedDict, total=False): - Configuration: Optional[FunctionConfiguration] - Code: Optional[FunctionCodeLocation] - Tags: Optional[Tags] - TagsError: Optional[TagsError] - Concurrency: Optional[Concurrency] + Configuration: FunctionConfiguration | None + Code: FunctionCodeLocation | None + Tags: Tags | None + TagsError: TagsError | None + Concurrency: Concurrency | None + + +class GetFunctionScalingConfigRequest(ServiceRequest): + FunctionName: UnqualifiedFunctionName + Qualifier: PublishedFunctionQualifier + + +class GetFunctionScalingConfigResponse(TypedDict, total=False): + FunctionArn: FunctionArn | None + AppliedFunctionScalingConfig: FunctionScalingConfig | None + RequestedFunctionScalingConfig: FunctionScalingConfig | None class GetFunctionUrlConfigRequest(ServiceRequest): FunctionName: FunctionName - Qualifier: Optional[FunctionUrlQualifier] + Qualifier: FunctionUrlQualifier | None class GetFunctionUrlConfigResponse(TypedDict, total=False): FunctionUrl: FunctionUrl FunctionArn: FunctionArn AuthType: FunctionUrlAuthType - Cors: Optional[Cors] + Cors: Cors | None CreationTime: Timestamp LastModifiedTime: Timestamp - InvokeMode: Optional[InvokeMode] + InvokeMode: InvokeMode | None class GetLayerVersionByArnRequest(ServiceRequest): @@ -1351,8 +2057,8 @@ class GetLayerVersionPolicyRequest(ServiceRequest): class GetLayerVersionPolicyResponse(TypedDict, total=False): - Policy: Optional[String] - RevisionId: Optional[String] + Policy: String | None + RevisionId: String | None class GetLayerVersionRequest(ServiceRequest): @@ -1361,33 +2067,33 @@ class GetLayerVersionRequest(ServiceRequest): class LayerVersionContentOutput(TypedDict, total=False): - Location: Optional[String] - CodeSha256: Optional[String] - CodeSize: Optional[Long] - SigningProfileVersionArn: Optional[String] - SigningJobArn: Optional[String] + Location: String | None + CodeSha256: String | None + CodeSize: Long | None + SigningProfileVersionArn: String | None + SigningJobArn: String | None class GetLayerVersionResponse(TypedDict, total=False): - Content: Optional[LayerVersionContentOutput] - LayerArn: Optional[LayerArn] - LayerVersionArn: Optional[LayerVersionArn] - Description: Optional[Description] - CreatedDate: Optional[Timestamp] - Version: Optional[LayerVersionNumber] - CompatibleRuntimes: Optional[CompatibleRuntimes] - LicenseInfo: Optional[LicenseInfo] - CompatibleArchitectures: Optional[CompatibleArchitectures] + Content: LayerVersionContentOutput | None + LayerArn: LayerArn | None + LayerVersionArn: LayerVersionArn | None + Description: Description | None + CreatedDate: Timestamp | None + Version: LayerVersionNumber | None + CompatibleRuntimes: CompatibleRuntimes | None + LicenseInfo: LicenseInfo | None + CompatibleArchitectures: CompatibleArchitectures | None class GetPolicyRequest(ServiceRequest): FunctionName: NamespacedFunctionName - Qualifier: Optional[Qualifier] + Qualifier: NumericLatestPublishedOrAliasQualifier | None class GetPolicyResponse(TypedDict, total=False): - Policy: Optional[String] - RevisionId: Optional[String] + Policy: String | None + RevisionId: String | None class GetProvisionedConcurrencyConfigRequest(ServiceRequest): @@ -1396,40 +2102,43 @@ class GetProvisionedConcurrencyConfigRequest(ServiceRequest): class GetProvisionedConcurrencyConfigResponse(TypedDict, total=False): - RequestedProvisionedConcurrentExecutions: Optional[PositiveInteger] - AvailableProvisionedConcurrentExecutions: Optional[NonNegativeInteger] - AllocatedProvisionedConcurrentExecutions: Optional[NonNegativeInteger] - Status: Optional[ProvisionedConcurrencyStatusEnum] - StatusReason: Optional[String] - LastModified: Optional[Timestamp] + RequestedProvisionedConcurrentExecutions: PositiveInteger | None + AvailableProvisionedConcurrentExecutions: NonNegativeInteger | None + AllocatedProvisionedConcurrentExecutions: NonNegativeInteger | None + Status: ProvisionedConcurrencyStatusEnum | None + StatusReason: String | None + LastModified: Timestamp | None class GetRuntimeManagementConfigRequest(ServiceRequest): FunctionName: NamespacedFunctionName - Qualifier: Optional[Qualifier] + Qualifier: NumericLatestPublishedOrAliasQualifier | None class GetRuntimeManagementConfigResponse(TypedDict, total=False): - UpdateRuntimeOn: Optional[UpdateRuntimeOn] - RuntimeVersionArn: Optional[RuntimeVersionArn] - FunctionArn: Optional[NameSpacedFunctionArn] + UpdateRuntimeOn: UpdateRuntimeOn | None + RuntimeVersionArn: RuntimeVersionArn | None + FunctionArn: NameSpacedFunctionArn | None class InvocationRequest(ServiceRequest): - Payload: Optional[IO[Blob]] + Payload: IO[Blob] | None FunctionName: NamespacedFunctionName - InvocationType: Optional[InvocationType] - LogType: Optional[LogType] - ClientContext: Optional[String] - Qualifier: Optional[Qualifier] + InvocationType: InvocationType | None + LogType: LogType | None + ClientContext: String | None + DurableExecutionName: DurableExecutionName | None + Qualifier: NumericLatestPublishedOrAliasQualifier | None + TenantId: TenantId | None class InvocationResponse(TypedDict, total=False): - Payload: Optional[Union[Blob, IO[Blob], Iterable[Blob]]] - StatusCode: Optional[Integer] - FunctionError: Optional[String] - LogResult: Optional[String] - ExecutedVersion: Optional[Version] + Payload: Blob | IO[Blob] | Iterable[Blob] | None + StatusCode: Integer | None + FunctionError: String | None + LogResult: String | None + ExecutedVersion: Version | None + DurableExecutionArn: DurableExecutionArn | None class InvokeAsyncRequest(ServiceRequest): @@ -1438,195 +2147,236 @@ class InvokeAsyncRequest(ServiceRequest): class InvokeAsyncResponse(TypedDict, total=False): - Status: Optional[HttpStatus] + Status: HttpStatus | None class InvokeResponseStreamUpdate(TypedDict, total=False): - Payload: Optional[Blob] + Payload: Blob | None class InvokeWithResponseStreamCompleteEvent(TypedDict, total=False): - ErrorCode: Optional[String] - ErrorDetails: Optional[String] - LogResult: Optional[String] + ErrorCode: String | None + ErrorDetails: String | None + LogResult: String | None class InvokeWithResponseStreamRequest(ServiceRequest): - Payload: Optional[IO[Blob]] + Payload: IO[Blob] | None FunctionName: NamespacedFunctionName - InvocationType: Optional[ResponseStreamingInvocationType] - LogType: Optional[LogType] - ClientContext: Optional[String] - Qualifier: Optional[Qualifier] + InvocationType: ResponseStreamingInvocationType | None + LogType: LogType | None + ClientContext: String | None + Qualifier: NumericLatestPublishedOrAliasQualifier | None + TenantId: TenantId | None class InvokeWithResponseStreamResponseEvent(TypedDict, total=False): - PayloadChunk: Optional[InvokeResponseStreamUpdate] - InvokeComplete: Optional[InvokeWithResponseStreamCompleteEvent] + PayloadChunk: InvokeResponseStreamUpdate | None + InvokeComplete: InvokeWithResponseStreamCompleteEvent | None class InvokeWithResponseStreamResponse(TypedDict, total=False): - StatusCode: Optional[Integer] - ExecutedVersion: Optional[Version] + StatusCode: Integer | None + ExecutedVersion: Version | None EventStream: Iterator[InvokeWithResponseStreamResponseEvent] - ResponseStreamContentType: Optional[String] + ResponseStreamContentType: String | None class LayerVersionContentInput(TypedDict, total=False): - S3Bucket: Optional[S3Bucket] - S3Key: Optional[S3Key] - S3ObjectVersion: Optional[S3ObjectVersion] - ZipFile: Optional[Blob] + S3Bucket: S3Bucket | None + S3Key: S3Key | None + S3ObjectVersion: S3ObjectVersion | None + ZipFile: Blob | None class LayerVersionsListItem(TypedDict, total=False): - LayerVersionArn: Optional[LayerVersionArn] - Version: Optional[LayerVersionNumber] - Description: Optional[Description] - CreatedDate: Optional[Timestamp] - CompatibleRuntimes: Optional[CompatibleRuntimes] - LicenseInfo: Optional[LicenseInfo] - CompatibleArchitectures: Optional[CompatibleArchitectures] + LayerVersionArn: LayerVersionArn | None + Version: LayerVersionNumber | None + Description: Description | None + CreatedDate: Timestamp | None + CompatibleRuntimes: CompatibleRuntimes | None + LicenseInfo: LicenseInfo | None + CompatibleArchitectures: CompatibleArchitectures | None -LayerVersionsList = List[LayerVersionsListItem] +LayerVersionsList = list[LayerVersionsListItem] class LayersListItem(TypedDict, total=False): - LayerName: Optional[LayerName] - LayerArn: Optional[LayerArn] - LatestMatchingVersion: Optional[LayerVersionsListItem] + LayerName: LayerName | None + LayerArn: LayerArn | None + LatestMatchingVersion: LayerVersionsListItem | None -LayersList = List[LayersListItem] +LayersList = list[LayersListItem] class ListAliasesRequest(ServiceRequest): FunctionName: FunctionName - FunctionVersion: Optional[Version] - Marker: Optional[String] - MaxItems: Optional[MaxListItems] + FunctionVersion: VersionWithLatestPublished | None + Marker: String | None + MaxItems: MaxListItems | None class ListAliasesResponse(TypedDict, total=False): - NextMarker: Optional[String] - Aliases: Optional[AliasList] + NextMarker: String | None + Aliases: AliasList | None + + +class ListCapacityProvidersRequest(ServiceRequest): + State: CapacityProviderState | None + Marker: String | None + MaxItems: MaxFiftyListItems | None + + +class ListCapacityProvidersResponse(TypedDict, total=False): + CapacityProviders: CapacityProvidersList + NextMarker: String | None class ListCodeSigningConfigsRequest(ServiceRequest): - Marker: Optional[String] - MaxItems: Optional[MaxListItems] + Marker: String | None + MaxItems: MaxListItems | None class ListCodeSigningConfigsResponse(TypedDict, total=False): - NextMarker: Optional[String] - CodeSigningConfigs: Optional[CodeSigningConfigList] + NextMarker: String | None + CodeSigningConfigs: CodeSigningConfigList | None + + +class ListDurableExecutionsByFunctionRequest(ServiceRequest): + FunctionName: NamespacedFunctionName + Qualifier: NumericLatestPublishedOrAliasQualifier | None + DurableExecutionName: DurableExecutionName | None + Statuses: ExecutionStatusList | None + StartedAfter: ExecutionTimestamp | None + StartedBefore: ExecutionTimestamp | None + ReverseOrder: ReverseOrder | None + Marker: String | None + MaxItems: ItemCount | None + + +class ListDurableExecutionsByFunctionResponse(TypedDict, total=False): + DurableExecutions: DurableExecutions | None + NextMarker: String | None class ListEventSourceMappingsRequest(ServiceRequest): - EventSourceArn: Optional[Arn] - FunctionName: Optional[FunctionName] - Marker: Optional[String] - MaxItems: Optional[MaxListItems] + EventSourceArn: Arn | None + FunctionName: NamespacedFunctionName | None + Marker: String | None + MaxItems: MaxListItems | None class ListEventSourceMappingsResponse(TypedDict, total=False): - NextMarker: Optional[String] - EventSourceMappings: Optional[EventSourceMappingsList] + NextMarker: String | None + EventSourceMappings: EventSourceMappingsList | None class ListFunctionEventInvokeConfigsRequest(ServiceRequest): - FunctionName: FunctionName - Marker: Optional[String] - MaxItems: Optional[MaxFunctionEventInvokeConfigListItems] + FunctionName: NamespacedFunctionName + Marker: String | None + MaxItems: MaxFunctionEventInvokeConfigListItems | None class ListFunctionEventInvokeConfigsResponse(TypedDict, total=False): - FunctionEventInvokeConfigs: Optional[FunctionEventInvokeConfigList] - NextMarker: Optional[String] + FunctionEventInvokeConfigs: FunctionEventInvokeConfigList | None + NextMarker: String | None class ListFunctionUrlConfigsRequest(ServiceRequest): FunctionName: FunctionName - Marker: Optional[String] - MaxItems: Optional[MaxItems] + Marker: String | None + MaxItems: MaxItems | None class ListFunctionUrlConfigsResponse(TypedDict, total=False): FunctionUrlConfigs: FunctionUrlConfigList - NextMarker: Optional[String] + NextMarker: String | None + + +class ListFunctionVersionsByCapacityProviderRequest(ServiceRequest): + CapacityProviderName: CapacityProviderName + Marker: String | None + MaxItems: MaxFiftyListItems | None + + +class ListFunctionVersionsByCapacityProviderResponse(TypedDict, total=False): + CapacityProviderArn: CapacityProviderArn + FunctionVersions: FunctionVersionsByCapacityProviderList + NextMarker: String | None class ListFunctionsByCodeSigningConfigRequest(ServiceRequest): CodeSigningConfigArn: CodeSigningConfigArn - Marker: Optional[String] - MaxItems: Optional[MaxListItems] + Marker: String | None + MaxItems: MaxListItems | None class ListFunctionsByCodeSigningConfigResponse(TypedDict, total=False): - NextMarker: Optional[String] - FunctionArns: Optional[FunctionArnList] + NextMarker: String | None + FunctionArns: FunctionArnList | None class ListFunctionsRequest(ServiceRequest): - MasterRegion: Optional[MasterRegion] - FunctionVersion: Optional[FunctionVersion] - Marker: Optional[String] - MaxItems: Optional[MaxListItems] + MasterRegion: MasterRegion | None + FunctionVersion: FunctionVersion | None + Marker: String | None + MaxItems: MaxListItems | None class ListFunctionsResponse(TypedDict, total=False): - NextMarker: Optional[String] - Functions: Optional[FunctionList] + NextMarker: String | None + Functions: FunctionList | None class ListLayerVersionsRequest(ServiceRequest): - CompatibleRuntime: Optional[Runtime] + CompatibleRuntime: Runtime | None LayerName: LayerName - Marker: Optional[String] - MaxItems: Optional[MaxLayerListItems] - CompatibleArchitecture: Optional[Architecture] + Marker: String | None + MaxItems: MaxLayerListItems | None + CompatibleArchitecture: Architecture | None class ListLayerVersionsResponse(TypedDict, total=False): - NextMarker: Optional[String] - LayerVersions: Optional[LayerVersionsList] + NextMarker: String | None + LayerVersions: LayerVersionsList | None class ListLayersRequest(ServiceRequest): - CompatibleRuntime: Optional[Runtime] - Marker: Optional[String] - MaxItems: Optional[MaxLayerListItems] - CompatibleArchitecture: Optional[Architecture] + CompatibleRuntime: Runtime | None + Marker: String | None + MaxItems: MaxLayerListItems | None + CompatibleArchitecture: Architecture | None class ListLayersResponse(TypedDict, total=False): - NextMarker: Optional[String] - Layers: Optional[LayersList] + NextMarker: String | None + Layers: LayersList | None class ListProvisionedConcurrencyConfigsRequest(ServiceRequest): FunctionName: FunctionName - Marker: Optional[String] - MaxItems: Optional[MaxProvisionedConcurrencyConfigListItems] + Marker: String | None + MaxItems: MaxProvisionedConcurrencyConfigListItems | None class ProvisionedConcurrencyConfigListItem(TypedDict, total=False): - FunctionArn: Optional[FunctionArn] - RequestedProvisionedConcurrentExecutions: Optional[PositiveInteger] - AvailableProvisionedConcurrentExecutions: Optional[NonNegativeInteger] - AllocatedProvisionedConcurrentExecutions: Optional[NonNegativeInteger] - Status: Optional[ProvisionedConcurrencyStatusEnum] - StatusReason: Optional[String] - LastModified: Optional[Timestamp] + FunctionArn: FunctionArn | None + RequestedProvisionedConcurrentExecutions: PositiveInteger | None + AvailableProvisionedConcurrentExecutions: NonNegativeInteger | None + AllocatedProvisionedConcurrentExecutions: NonNegativeInteger | None + Status: ProvisionedConcurrencyStatusEnum | None + StatusReason: String | None + LastModified: Timestamp | None -ProvisionedConcurrencyConfigList = List[ProvisionedConcurrencyConfigListItem] +ProvisionedConcurrencyConfigList = list[ProvisionedConcurrencyConfigListItem] class ListProvisionedConcurrencyConfigsResponse(TypedDict, total=False): - ProvisionedConcurrencyConfigs: Optional[ProvisionedConcurrencyConfigList] - NextMarker: Optional[String] + ProvisionedConcurrencyConfigs: ProvisionedConcurrencyConfigList | None + NextMarker: String | None class ListTagsRequest(ServiceRequest): @@ -1634,51 +2384,52 @@ class ListTagsRequest(ServiceRequest): class ListTagsResponse(TypedDict, total=False): - Tags: Optional[Tags] + Tags: Tags | None class ListVersionsByFunctionRequest(ServiceRequest): FunctionName: NamespacedFunctionName - Marker: Optional[String] - MaxItems: Optional[MaxListItems] + Marker: String | None + MaxItems: MaxListItems | None class ListVersionsByFunctionResponse(TypedDict, total=False): - NextMarker: Optional[String] - Versions: Optional[FunctionList] + NextMarker: String | None + Versions: FunctionList | None class PublishLayerVersionRequest(ServiceRequest): LayerName: LayerName - Description: Optional[Description] + Description: Description | None Content: LayerVersionContentInput - CompatibleRuntimes: Optional[CompatibleRuntimes] - LicenseInfo: Optional[LicenseInfo] - CompatibleArchitectures: Optional[CompatibleArchitectures] + CompatibleRuntimes: CompatibleRuntimes | None + LicenseInfo: LicenseInfo | None + CompatibleArchitectures: CompatibleArchitectures | None class PublishLayerVersionResponse(TypedDict, total=False): - Content: Optional[LayerVersionContentOutput] - LayerArn: Optional[LayerArn] - LayerVersionArn: Optional[LayerVersionArn] - Description: Optional[Description] - CreatedDate: Optional[Timestamp] - Version: Optional[LayerVersionNumber] - CompatibleRuntimes: Optional[CompatibleRuntimes] - LicenseInfo: Optional[LicenseInfo] - CompatibleArchitectures: Optional[CompatibleArchitectures] + Content: LayerVersionContentOutput | None + LayerArn: LayerArn | None + LayerVersionArn: LayerVersionArn | None + Description: Description | None + CreatedDate: Timestamp | None + Version: LayerVersionNumber | None + CompatibleRuntimes: CompatibleRuntimes | None + LicenseInfo: LicenseInfo | None + CompatibleArchitectures: CompatibleArchitectures | None class PublishVersionRequest(ServiceRequest): FunctionName: FunctionName - CodeSha256: Optional[String] - Description: Optional[Description] - RevisionId: Optional[String] + CodeSha256: String | None + Description: Description | None + RevisionId: String | None + PublishTo: FunctionVersionLatestPublished | None class PutFunctionCodeSigningConfigRequest(ServiceRequest): CodeSigningConfigArn: CodeSigningConfigArn - FunctionName: FunctionName + FunctionName: NamespacedFunctionName class PutFunctionCodeSigningConfigResponse(TypedDict, total=False): @@ -1692,11 +2443,11 @@ class PutFunctionConcurrencyRequest(ServiceRequest): class PutFunctionEventInvokeConfigRequest(ServiceRequest): - FunctionName: FunctionName - Qualifier: Optional[Qualifier] - MaximumRetryAttempts: Optional[MaximumRetryAttempts] - MaximumEventAgeInSeconds: Optional[MaximumEventAgeInSeconds] - DestinationConfig: Optional[DestinationConfig] + FunctionName: NamespacedFunctionName + Qualifier: NumericLatestPublishedOrAliasQualifier | None + MaximumRetryAttempts: MaximumRetryAttempts | None + MaximumEventAgeInSeconds: MaximumEventAgeInSeconds | None + DestinationConfig: DestinationConfig | None class PutFunctionRecursionConfigRequest(ServiceRequest): @@ -1705,7 +2456,17 @@ class PutFunctionRecursionConfigRequest(ServiceRequest): class PutFunctionRecursionConfigResponse(TypedDict, total=False): - RecursiveLoop: Optional[RecursiveLoop] + RecursiveLoop: RecursiveLoop | None + + +class PutFunctionScalingConfigRequest(ServiceRequest): + FunctionName: UnqualifiedFunctionName + Qualifier: PublishedFunctionQualifier + FunctionScalingConfig: FunctionScalingConfig | None + + +class PutFunctionScalingConfigResponse(TypedDict, total=False): + FunctionState: State | None class PutProvisionedConcurrencyConfigRequest(ServiceRequest): @@ -1715,42 +2476,77 @@ class PutProvisionedConcurrencyConfigRequest(ServiceRequest): class PutProvisionedConcurrencyConfigResponse(TypedDict, total=False): - RequestedProvisionedConcurrentExecutions: Optional[PositiveInteger] - AvailableProvisionedConcurrentExecutions: Optional[NonNegativeInteger] - AllocatedProvisionedConcurrentExecutions: Optional[NonNegativeInteger] - Status: Optional[ProvisionedConcurrencyStatusEnum] - StatusReason: Optional[String] - LastModified: Optional[Timestamp] + RequestedProvisionedConcurrentExecutions: PositiveInteger | None + AvailableProvisionedConcurrentExecutions: NonNegativeInteger | None + AllocatedProvisionedConcurrentExecutions: NonNegativeInteger | None + Status: ProvisionedConcurrencyStatusEnum | None + StatusReason: String | None + LastModified: Timestamp | None class PutRuntimeManagementConfigRequest(ServiceRequest): - FunctionName: FunctionName - Qualifier: Optional[Qualifier] + FunctionName: NamespacedFunctionName + Qualifier: NumericLatestPublishedOrAliasQualifier | None UpdateRuntimeOn: UpdateRuntimeOn - RuntimeVersionArn: Optional[RuntimeVersionArn] + RuntimeVersionArn: RuntimeVersionArn | None class PutRuntimeManagementConfigResponse(TypedDict, total=False): UpdateRuntimeOn: UpdateRuntimeOn FunctionArn: FunctionArn - RuntimeVersionArn: Optional[RuntimeVersionArn] + RuntimeVersionArn: RuntimeVersionArn | None class RemoveLayerVersionPermissionRequest(ServiceRequest): LayerName: LayerName VersionNumber: LayerVersionNumber StatementId: StatementId - RevisionId: Optional[String] + RevisionId: String | None class RemovePermissionRequest(ServiceRequest): - FunctionName: FunctionName + FunctionName: NamespacedFunctionName StatementId: NamespacedStatementId - Qualifier: Optional[Qualifier] - RevisionId: Optional[String] + Qualifier: NumericLatestPublishedOrAliasQualifier | None + RevisionId: String | None + + +class SendDurableExecutionCallbackFailureRequest(ServiceRequest): + CallbackId: CallbackId + Error: ErrorObject | None + + +class SendDurableExecutionCallbackFailureResponse(TypedDict, total=False): + pass + + +class SendDurableExecutionCallbackHeartbeatRequest(ServiceRequest): + CallbackId: CallbackId -TagKeyList = List[TagKey] +class SendDurableExecutionCallbackHeartbeatResponse(TypedDict, total=False): + pass + + +class SendDurableExecutionCallbackSuccessRequest(ServiceRequest): + Result: IO[BinaryOperationPayload] | None + CallbackId: CallbackId + + +class SendDurableExecutionCallbackSuccessResponse(TypedDict, total=False): + pass + + +class StopDurableExecutionRequest(ServiceRequest): + DurableExecutionArn: DurableExecutionArn + Error: ErrorObject | None + + +class StopDurableExecutionResponse(TypedDict, total=False): + StopTimestamp: ExecutionTimestamp + + +TagKeyList = list[TagKey] class TagResourceRequest(ServiceRequest): @@ -1766,17 +2562,26 @@ class UntagResourceRequest(ServiceRequest): class UpdateAliasRequest(ServiceRequest): FunctionName: FunctionName Name: Alias - FunctionVersion: Optional[Version] - Description: Optional[Description] - RoutingConfig: Optional[AliasRoutingConfiguration] - RevisionId: Optional[String] + FunctionVersion: VersionWithLatestPublished | None + Description: Description | None + RoutingConfig: AliasRoutingConfiguration | None + RevisionId: String | None + + +class UpdateCapacityProviderRequest(ServiceRequest): + CapacityProviderName: CapacityProviderName + CapacityProviderScalingConfig: CapacityProviderScalingConfig | None + + +class UpdateCapacityProviderResponse(TypedDict, total=False): + CapacityProvider: CapacityProvider class UpdateCodeSigningConfigRequest(ServiceRequest): CodeSigningConfigArn: CodeSigningConfigArn - Description: Optional[Description] - AllowedPublishers: Optional[AllowedPublishers] - CodeSigningPolicies: Optional[CodeSigningPolicies] + Description: Description | None + AllowedPublishers: AllowedPublishers | None + CodeSigningPolicies: CodeSigningPolicies | None class UpdateCodeSigningConfigResponse(TypedDict, total=False): @@ -1785,93 +2590,97 @@ class UpdateCodeSigningConfigResponse(TypedDict, total=False): class UpdateEventSourceMappingRequest(ServiceRequest): UUID: String - FunctionName: Optional[FunctionName] - Enabled: Optional[Enabled] - BatchSize: Optional[BatchSize] - FilterCriteria: Optional[FilterCriteria] - MaximumBatchingWindowInSeconds: Optional[MaximumBatchingWindowInSeconds] - DestinationConfig: Optional[DestinationConfig] - MaximumRecordAgeInSeconds: Optional[MaximumRecordAgeInSeconds] - BisectBatchOnFunctionError: Optional[BisectBatchOnFunctionError] - MaximumRetryAttempts: Optional[MaximumRetryAttemptsEventSourceMapping] - ParallelizationFactor: Optional[ParallelizationFactor] - SourceAccessConfigurations: Optional[SourceAccessConfigurations] - TumblingWindowInSeconds: Optional[TumblingWindowInSeconds] - FunctionResponseTypes: Optional[FunctionResponseTypeList] - ScalingConfig: Optional[ScalingConfig] - AmazonManagedKafkaEventSourceConfig: Optional[AmazonManagedKafkaEventSourceConfig] - SelfManagedKafkaEventSourceConfig: Optional[SelfManagedKafkaEventSourceConfig] - DocumentDBEventSourceConfig: Optional[DocumentDBEventSourceConfig] - KMSKeyArn: Optional[KMSKeyArn] - MetricsConfig: Optional[EventSourceMappingMetricsConfig] - ProvisionedPollerConfig: Optional[ProvisionedPollerConfig] + FunctionName: NamespacedFunctionName | None + Enabled: Enabled | None + BatchSize: BatchSize | None + FilterCriteria: FilterCriteria | None + MaximumBatchingWindowInSeconds: MaximumBatchingWindowInSeconds | None + DestinationConfig: DestinationConfig | None + MaximumRecordAgeInSeconds: MaximumRecordAgeInSeconds | None + BisectBatchOnFunctionError: BisectBatchOnFunctionError | None + MaximumRetryAttempts: MaximumRetryAttemptsEventSourceMapping | None + ParallelizationFactor: ParallelizationFactor | None + SourceAccessConfigurations: SourceAccessConfigurations | None + TumblingWindowInSeconds: TumblingWindowInSeconds | None + FunctionResponseTypes: FunctionResponseTypeList | None + ScalingConfig: ScalingConfig | None + AmazonManagedKafkaEventSourceConfig: AmazonManagedKafkaEventSourceConfig | None + SelfManagedKafkaEventSourceConfig: SelfManagedKafkaEventSourceConfig | None + DocumentDBEventSourceConfig: DocumentDBEventSourceConfig | None + KMSKeyArn: KMSKeyArn | None + MetricsConfig: EventSourceMappingMetricsConfig | None + LoggingConfig: EventSourceMappingLoggingConfig | None + ProvisionedPollerConfig: ProvisionedPollerConfig | None class UpdateFunctionCodeRequest(ServiceRequest): FunctionName: FunctionName - ZipFile: Optional[Blob] - S3Bucket: Optional[S3Bucket] - S3Key: Optional[S3Key] - S3ObjectVersion: Optional[S3ObjectVersion] - ImageUri: Optional[String] - Publish: Optional[Boolean] - DryRun: Optional[Boolean] - RevisionId: Optional[String] - Architectures: Optional[ArchitecturesList] - SourceKMSKeyArn: Optional[KMSKeyArn] + ZipFile: Blob | None + S3Bucket: S3Bucket | None + S3Key: S3Key | None + S3ObjectVersion: S3ObjectVersion | None + ImageUri: String | None + Publish: Boolean | None + DryRun: Boolean | None + RevisionId: String | None + Architectures: ArchitecturesList | None + SourceKMSKeyArn: KMSKeyArn | None + PublishTo: FunctionVersionLatestPublished | None class UpdateFunctionConfigurationRequest(ServiceRequest): FunctionName: FunctionName - Role: Optional[RoleArn] - Handler: Optional[Handler] - Description: Optional[Description] - Timeout: Optional[Timeout] - MemorySize: Optional[MemorySize] - VpcConfig: Optional[VpcConfig] - Environment: Optional[Environment] - Runtime: Optional[Runtime] - DeadLetterConfig: Optional[DeadLetterConfig] - KMSKeyArn: Optional[KMSKeyArn] - TracingConfig: Optional[TracingConfig] - RevisionId: Optional[String] - Layers: Optional[LayerList] - FileSystemConfigs: Optional[FileSystemConfigList] - ImageConfig: Optional[ImageConfig] - EphemeralStorage: Optional[EphemeralStorage] - SnapStart: Optional[SnapStart] - LoggingConfig: Optional[LoggingConfig] + Role: RoleArn | None + Handler: Handler | None + Description: Description | None + Timeout: Timeout | None + MemorySize: MemorySize | None + VpcConfig: VpcConfig | None + Environment: Environment | None + Runtime: Runtime | None + DeadLetterConfig: DeadLetterConfig | None + KMSKeyArn: KMSKeyArn | None + TracingConfig: TracingConfig | None + RevisionId: String | None + Layers: LayerList | None + FileSystemConfigs: FileSystemConfigList | None + ImageConfig: ImageConfig | None + EphemeralStorage: EphemeralStorage | None + SnapStart: SnapStart | None + LoggingConfig: LoggingConfig | None + CapacityProviderConfig: CapacityProviderConfig | None + DurableConfig: DurableConfig | None class UpdateFunctionEventInvokeConfigRequest(ServiceRequest): - FunctionName: FunctionName - Qualifier: Optional[Qualifier] - MaximumRetryAttempts: Optional[MaximumRetryAttempts] - MaximumEventAgeInSeconds: Optional[MaximumEventAgeInSeconds] - DestinationConfig: Optional[DestinationConfig] + FunctionName: NamespacedFunctionName + Qualifier: NumericLatestPublishedOrAliasQualifier | None + MaximumRetryAttempts: MaximumRetryAttempts | None + MaximumEventAgeInSeconds: MaximumEventAgeInSeconds | None + DestinationConfig: DestinationConfig | None class UpdateFunctionUrlConfigRequest(ServiceRequest): FunctionName: FunctionName - Qualifier: Optional[FunctionUrlQualifier] - AuthType: Optional[FunctionUrlAuthType] - Cors: Optional[Cors] - InvokeMode: Optional[InvokeMode] + Qualifier: FunctionUrlQualifier | None + AuthType: FunctionUrlAuthType | None + Cors: Cors | None + InvokeMode: InvokeMode | None class UpdateFunctionUrlConfigResponse(TypedDict, total=False): FunctionUrl: FunctionUrl FunctionArn: FunctionArn AuthType: FunctionUrlAuthType - Cors: Optional[Cors] + Cors: Cors | None CreationTime: Timestamp LastModifiedTime: Timestamp - InvokeMode: Optional[InvokeMode] + InvokeMode: InvokeMode | None class LambdaApi: - service = "lambda" - version = "2015-03-31" + service: str = "lambda" + version: str = "2015-03-31" @handler("AddLayerVersionPermission") def add_layer_version_permission( @@ -1892,34 +2701,62 @@ def add_layer_version_permission( def add_permission( self, context: RequestContext, - function_name: FunctionName, + function_name: NamespacedFunctionName, statement_id: StatementId, action: Action, principal: Principal, source_arn: Arn | None = None, source_account: SourceOwner | None = None, event_source_token: EventSourceToken | None = None, - qualifier: Qualifier | None = None, + qualifier: NumericLatestPublishedOrAliasQualifier | None = None, revision_id: String | None = None, principal_org_id: PrincipalOrgID | None = None, function_url_auth_type: FunctionUrlAuthType | None = None, + invoked_via_function_url: InvokedViaFunctionUrl | None = None, **kwargs, ) -> AddPermissionResponse: raise NotImplementedError + @handler("CheckpointDurableExecution") + def checkpoint_durable_execution( + self, + context: RequestContext, + durable_execution_arn: DurableExecutionArn, + checkpoint_token: CheckpointToken, + updates: OperationUpdates | None = None, + client_token: ClientToken | None = None, + **kwargs, + ) -> CheckpointDurableExecutionResponse: + raise NotImplementedError + @handler("CreateAlias") def create_alias( self, context: RequestContext, function_name: FunctionName, name: Alias, - function_version: Version, + function_version: VersionWithLatestPublished, description: Description | None = None, routing_config: AliasRoutingConfiguration | None = None, **kwargs, ) -> AliasConfiguration: raise NotImplementedError + @handler("CreateCapacityProvider") + def create_capacity_provider( + self, + context: RequestContext, + capacity_provider_name: CapacityProviderName, + vpc_config: CapacityProviderVpcConfig, + permissions_config: CapacityProviderPermissionsConfig, + instance_requirements: InstanceRequirements | None = None, + capacity_provider_scaling_config: CapacityProviderScalingConfig | None = None, + kms_key_arn: KMSKeyArnNonEmpty | None = None, + tags: Tags | None = None, + **kwargs, + ) -> CreateCapacityProviderResponse: + raise NotImplementedError + @handler("CreateCodeSigningConfig") def create_code_signing_config( self, @@ -1936,7 +2773,7 @@ def create_code_signing_config( def create_event_source_mapping( self, context: RequestContext, - function_name: FunctionName, + function_name: NamespacedFunctionName, event_source_arn: Arn | None = None, enabled: Enabled | None = None, batch_size: BatchSize | None = None, @@ -1962,6 +2799,7 @@ def create_event_source_mapping( document_db_event_source_config: DocumentDBEventSourceConfig | None = None, kms_key_arn: KMSKeyArn | None = None, metrics_config: EventSourceMappingMetricsConfig | None = None, + logging_config: EventSourceMappingLoggingConfig | None = None, provisioned_poller_config: ProvisionedPollerConfig | None = None, **kwargs, ) -> EventSourceMappingConfiguration: @@ -1995,6 +2833,10 @@ def create_function( ephemeral_storage: EphemeralStorage | None = None, snap_start: SnapStart | None = None, logging_config: LoggingConfig | None = None, + capacity_provider_config: CapacityProviderConfig | None = None, + publish_to: FunctionVersionLatestPublished | None = None, + durable_config: DurableConfig | None = None, + tenancy_config: TenancyConfig | None = None, **kwargs, ) -> FunctionConfiguration: raise NotImplementedError @@ -2018,6 +2860,12 @@ def delete_alias( ) -> None: raise NotImplementedError + @handler("DeleteCapacityProvider") + def delete_capacity_provider( + self, context: RequestContext, capacity_provider_name: CapacityProviderName, **kwargs + ) -> DeleteCapacityProviderResponse: + raise NotImplementedError + @handler("DeleteCodeSigningConfig") def delete_code_signing_config( self, context: RequestContext, code_signing_config_arn: CodeSigningConfigArn, **kwargs @@ -2034,15 +2882,15 @@ def delete_event_source_mapping( def delete_function( self, context: RequestContext, - function_name: FunctionName, - qualifier: Qualifier | None = None, + function_name: NamespacedFunctionName, + qualifier: NumericLatestPublishedOrAliasQualifier | None = None, **kwargs, - ) -> None: + ) -> DeleteFunctionResponse: raise NotImplementedError @handler("DeleteFunctionCodeSigningConfig") def delete_function_code_signing_config( - self, context: RequestContext, function_name: FunctionName, **kwargs + self, context: RequestContext, function_name: NamespacedFunctionName, **kwargs ) -> None: raise NotImplementedError @@ -2056,8 +2904,8 @@ def delete_function_concurrency( def delete_function_event_invoke_config( self, context: RequestContext, - function_name: FunctionName, - qualifier: Qualifier | None = None, + function_name: NamespacedFunctionName, + qualifier: NumericLatestPublishedOrAliasQualifier | None = None, **kwargs, ) -> None: raise NotImplementedError @@ -2098,12 +2946,49 @@ def get_alias( ) -> AliasConfiguration: raise NotImplementedError + @handler("GetCapacityProvider") + def get_capacity_provider( + self, context: RequestContext, capacity_provider_name: CapacityProviderName, **kwargs + ) -> GetCapacityProviderResponse: + raise NotImplementedError + @handler("GetCodeSigningConfig") def get_code_signing_config( self, context: RequestContext, code_signing_config_arn: CodeSigningConfigArn, **kwargs ) -> GetCodeSigningConfigResponse: raise NotImplementedError + @handler("GetDurableExecution") + def get_durable_execution( + self, context: RequestContext, durable_execution_arn: DurableExecutionArn, **kwargs + ) -> GetDurableExecutionResponse: + raise NotImplementedError + + @handler("GetDurableExecutionHistory") + def get_durable_execution_history( + self, + context: RequestContext, + durable_execution_arn: DurableExecutionArn, + include_execution_data: IncludeExecutionData | None = None, + max_items: ItemCount | None = None, + marker: String | None = None, + reverse_order: ReverseOrder | None = None, + **kwargs, + ) -> GetDurableExecutionHistoryResponse: + raise NotImplementedError + + @handler("GetDurableExecutionState") + def get_durable_execution_state( + self, + context: RequestContext, + durable_execution_arn: DurableExecutionArn, + checkpoint_token: CheckpointToken, + marker: String | None = None, + max_items: ItemCount | None = None, + **kwargs, + ) -> GetDurableExecutionStateResponse: + raise NotImplementedError + @handler("GetEventSourceMapping") def get_event_source_mapping( self, context: RequestContext, uuid: String, **kwargs @@ -2115,14 +3000,14 @@ def get_function( self, context: RequestContext, function_name: NamespacedFunctionName, - qualifier: Qualifier | None = None, + qualifier: NumericLatestPublishedOrAliasQualifier | None = None, **kwargs, ) -> GetFunctionResponse: raise NotImplementedError @handler("GetFunctionCodeSigningConfig") def get_function_code_signing_config( - self, context: RequestContext, function_name: FunctionName, **kwargs + self, context: RequestContext, function_name: NamespacedFunctionName, **kwargs ) -> GetFunctionCodeSigningConfigResponse: raise NotImplementedError @@ -2137,7 +3022,7 @@ def get_function_configuration( self, context: RequestContext, function_name: NamespacedFunctionName, - qualifier: Qualifier | None = None, + qualifier: NumericLatestPublishedOrAliasQualifier | None = None, **kwargs, ) -> FunctionConfiguration: raise NotImplementedError @@ -2146,8 +3031,8 @@ def get_function_configuration( def get_function_event_invoke_config( self, context: RequestContext, - function_name: FunctionName, - qualifier: Qualifier | None = None, + function_name: NamespacedFunctionName, + qualifier: NumericLatestPublishedOrAliasQualifier | None = None, **kwargs, ) -> FunctionEventInvokeConfig: raise NotImplementedError @@ -2158,6 +3043,16 @@ def get_function_recursion_config( ) -> GetFunctionRecursionConfigResponse: raise NotImplementedError + @handler("GetFunctionScalingConfig") + def get_function_scaling_config( + self, + context: RequestContext, + function_name: UnqualifiedFunctionName, + qualifier: PublishedFunctionQualifier, + **kwargs, + ) -> GetFunctionScalingConfigResponse: + raise NotImplementedError + @handler("GetFunctionUrlConfig") def get_function_url_config( self, @@ -2199,7 +3094,7 @@ def get_policy( self, context: RequestContext, function_name: NamespacedFunctionName, - qualifier: Qualifier | None = None, + qualifier: NumericLatestPublishedOrAliasQualifier | None = None, **kwargs, ) -> GetPolicyResponse: raise NotImplementedError @@ -2215,7 +3110,7 @@ def get_runtime_management_config( self, context: RequestContext, function_name: NamespacedFunctionName, - qualifier: Qualifier | None = None, + qualifier: NumericLatestPublishedOrAliasQualifier | None = None, **kwargs, ) -> GetRuntimeManagementConfigResponse: raise NotImplementedError @@ -2228,8 +3123,10 @@ def invoke( invocation_type: InvocationType | None = None, log_type: LogType | None = None, client_context: String | None = None, + durable_execution_name: DurableExecutionName | None = None, payload: IO[Blob] | None = None, - qualifier: Qualifier | None = None, + qualifier: NumericLatestPublishedOrAliasQualifier | None = None, + tenant_id: TenantId | None = None, **kwargs, ) -> InvocationResponse: raise NotImplementedError @@ -2252,8 +3149,9 @@ def invoke_with_response_stream( invocation_type: ResponseStreamingInvocationType | None = None, log_type: LogType | None = None, client_context: String | None = None, - qualifier: Qualifier | None = None, + qualifier: NumericLatestPublishedOrAliasQualifier | None = None, payload: IO[Blob] | None = None, + tenant_id: TenantId | None = None, **kwargs, ) -> InvokeWithResponseStreamResponse: raise NotImplementedError @@ -2263,13 +3161,24 @@ def list_aliases( self, context: RequestContext, function_name: FunctionName, - function_version: Version | None = None, + function_version: VersionWithLatestPublished | None = None, marker: String | None = None, max_items: MaxListItems | None = None, **kwargs, ) -> ListAliasesResponse: raise NotImplementedError + @handler("ListCapacityProviders") + def list_capacity_providers( + self, + context: RequestContext, + state: CapacityProviderState | None = None, + marker: String | None = None, + max_items: MaxFiftyListItems | None = None, + **kwargs, + ) -> ListCapacityProvidersResponse: + raise NotImplementedError + @handler("ListCodeSigningConfigs") def list_code_signing_configs( self, @@ -2280,12 +3189,29 @@ def list_code_signing_configs( ) -> ListCodeSigningConfigsResponse: raise NotImplementedError + @handler("ListDurableExecutionsByFunction") + def list_durable_executions_by_function( + self, + context: RequestContext, + function_name: NamespacedFunctionName, + qualifier: NumericLatestPublishedOrAliasQualifier | None = None, + durable_execution_name: DurableExecutionName | None = None, + statuses: ExecutionStatusList | None = None, + started_after: ExecutionTimestamp | None = None, + started_before: ExecutionTimestamp | None = None, + reverse_order: ReverseOrder | None = None, + marker: String | None = None, + max_items: ItemCount | None = None, + **kwargs, + ) -> ListDurableExecutionsByFunctionResponse: + raise NotImplementedError + @handler("ListEventSourceMappings") def list_event_source_mappings( self, context: RequestContext, event_source_arn: Arn | None = None, - function_name: FunctionName | None = None, + function_name: NamespacedFunctionName | None = None, marker: String | None = None, max_items: MaxListItems | None = None, **kwargs, @@ -2296,7 +3222,7 @@ def list_event_source_mappings( def list_function_event_invoke_configs( self, context: RequestContext, - function_name: FunctionName, + function_name: NamespacedFunctionName, marker: String | None = None, max_items: MaxFunctionEventInvokeConfigListItems | None = None, **kwargs, @@ -2314,6 +3240,17 @@ def list_function_url_configs( ) -> ListFunctionUrlConfigsResponse: raise NotImplementedError + @handler("ListFunctionVersionsByCapacityProvider") + def list_function_versions_by_capacity_provider( + self, + context: RequestContext, + capacity_provider_name: CapacityProviderName, + marker: String | None = None, + max_items: MaxFiftyListItems | None = None, + **kwargs, + ) -> ListFunctionVersionsByCapacityProviderResponse: + raise NotImplementedError + @handler("ListFunctions") def list_functions( self, @@ -2412,6 +3349,7 @@ def publish_version( code_sha256: String | None = None, description: Description | None = None, revision_id: String | None = None, + publish_to: FunctionVersionLatestPublished | None = None, **kwargs, ) -> FunctionConfiguration: raise NotImplementedError @@ -2421,7 +3359,7 @@ def put_function_code_signing_config( self, context: RequestContext, code_signing_config_arn: CodeSigningConfigArn, - function_name: FunctionName, + function_name: NamespacedFunctionName, **kwargs, ) -> PutFunctionCodeSigningConfigResponse: raise NotImplementedError @@ -2440,8 +3378,8 @@ def put_function_concurrency( def put_function_event_invoke_config( self, context: RequestContext, - function_name: FunctionName, - qualifier: Qualifier | None = None, + function_name: NamespacedFunctionName, + qualifier: NumericLatestPublishedOrAliasQualifier | None = None, maximum_retry_attempts: MaximumRetryAttempts | None = None, maximum_event_age_in_seconds: MaximumEventAgeInSeconds | None = None, destination_config: DestinationConfig | None = None, @@ -2459,6 +3397,17 @@ def put_function_recursion_config( ) -> PutFunctionRecursionConfigResponse: raise NotImplementedError + @handler("PutFunctionScalingConfig") + def put_function_scaling_config( + self, + context: RequestContext, + function_name: UnqualifiedFunctionName, + qualifier: PublishedFunctionQualifier, + function_scaling_config: FunctionScalingConfig | None = None, + **kwargs, + ) -> PutFunctionScalingConfigResponse: + raise NotImplementedError + @handler("PutProvisionedConcurrencyConfig") def put_provisioned_concurrency_config( self, @@ -2474,9 +3423,9 @@ def put_provisioned_concurrency_config( def put_runtime_management_config( self, context: RequestContext, - function_name: FunctionName, + function_name: NamespacedFunctionName, update_runtime_on: UpdateRuntimeOn, - qualifier: Qualifier | None = None, + qualifier: NumericLatestPublishedOrAliasQualifier | None = None, runtime_version_arn: RuntimeVersionArn | None = None, **kwargs, ) -> PutRuntimeManagementConfigResponse: @@ -2498,14 +3447,50 @@ def remove_layer_version_permission( def remove_permission( self, context: RequestContext, - function_name: FunctionName, + function_name: NamespacedFunctionName, statement_id: NamespacedStatementId, - qualifier: Qualifier | None = None, + qualifier: NumericLatestPublishedOrAliasQualifier | None = None, revision_id: String | None = None, **kwargs, ) -> None: raise NotImplementedError + @handler("SendDurableExecutionCallbackFailure") + def send_durable_execution_callback_failure( + self, + context: RequestContext, + callback_id: CallbackId, + error: ErrorObject | None = None, + **kwargs, + ) -> SendDurableExecutionCallbackFailureResponse: + raise NotImplementedError + + @handler("SendDurableExecutionCallbackHeartbeat") + def send_durable_execution_callback_heartbeat( + self, context: RequestContext, callback_id: CallbackId, **kwargs + ) -> SendDurableExecutionCallbackHeartbeatResponse: + raise NotImplementedError + + @handler("SendDurableExecutionCallbackSuccess") + def send_durable_execution_callback_success( + self, + context: RequestContext, + callback_id: CallbackId, + result: IO[BinaryOperationPayload] | None = None, + **kwargs, + ) -> SendDurableExecutionCallbackSuccessResponse: + raise NotImplementedError + + @handler("StopDurableExecution") + def stop_durable_execution( + self, + context: RequestContext, + durable_execution_arn: DurableExecutionArn, + error: ErrorObject | None = None, + **kwargs, + ) -> StopDurableExecutionResponse: + raise NotImplementedError + @handler("TagResource") def tag_resource( self, context: RequestContext, resource: TaggableResource, tags: Tags, **kwargs @@ -2524,7 +3509,7 @@ def update_alias( context: RequestContext, function_name: FunctionName, name: Alias, - function_version: Version | None = None, + function_version: VersionWithLatestPublished | None = None, description: Description | None = None, routing_config: AliasRoutingConfiguration | None = None, revision_id: String | None = None, @@ -2532,6 +3517,16 @@ def update_alias( ) -> AliasConfiguration: raise NotImplementedError + @handler("UpdateCapacityProvider") + def update_capacity_provider( + self, + context: RequestContext, + capacity_provider_name: CapacityProviderName, + capacity_provider_scaling_config: CapacityProviderScalingConfig | None = None, + **kwargs, + ) -> UpdateCapacityProviderResponse: + raise NotImplementedError + @handler("UpdateCodeSigningConfig") def update_code_signing_config( self, @@ -2549,7 +3544,7 @@ def update_event_source_mapping( self, context: RequestContext, uuid: String, - function_name: FunctionName | None = None, + function_name: NamespacedFunctionName | None = None, enabled: Enabled | None = None, batch_size: BatchSize | None = None, filter_criteria: FilterCriteria | None = None, @@ -2568,6 +3563,7 @@ def update_event_source_mapping( document_db_event_source_config: DocumentDBEventSourceConfig | None = None, kms_key_arn: KMSKeyArn | None = None, metrics_config: EventSourceMappingMetricsConfig | None = None, + logging_config: EventSourceMappingLoggingConfig | None = None, provisioned_poller_config: ProvisionedPollerConfig | None = None, **kwargs, ) -> EventSourceMappingConfiguration: @@ -2588,6 +3584,7 @@ def update_function_code( revision_id: String | None = None, architectures: ArchitecturesList | None = None, source_kms_key_arn: KMSKeyArn | None = None, + publish_to: FunctionVersionLatestPublished | None = None, **kwargs, ) -> FunctionConfiguration: raise NotImplementedError @@ -2615,6 +3612,8 @@ def update_function_configuration( ephemeral_storage: EphemeralStorage | None = None, snap_start: SnapStart | None = None, logging_config: LoggingConfig | None = None, + capacity_provider_config: CapacityProviderConfig | None = None, + durable_config: DurableConfig | None = None, **kwargs, ) -> FunctionConfiguration: raise NotImplementedError @@ -2623,8 +3622,8 @@ def update_function_configuration( def update_function_event_invoke_config( self, context: RequestContext, - function_name: FunctionName, - qualifier: Qualifier | None = None, + function_name: NamespacedFunctionName, + qualifier: NumericLatestPublishedOrAliasQualifier | None = None, maximum_retry_attempts: MaximumRetryAttempts | None = None, maximum_event_age_in_seconds: MaximumEventAgeInSeconds | None = None, destination_config: DestinationConfig | None = None, diff --git a/localstack-core/localstack/aws/api/logs/__init__.py b/localstack-core/localstack/aws/api/logs/__init__.py index bbc3a8d608d6d..aa641e6167225 100644 --- a/localstack-core/localstack/aws/api/logs/__init__.py +++ b/localstack-core/localstack/aws/api/logs/__init__.py @@ -1,5 +1,6 @@ +from collections.abc import Iterator from enum import StrEnum -from typing import Dict, Iterator, List, Optional, TypedDict +from typing import TypedDict from localstack.aws.api import RequestContext, ServiceException, ServiceRequest, handler @@ -14,13 +15,18 @@ ApplyOnTransformedLogs = bool Arn = str Baseline = bool +BatchId = str Boolean = bool ClientToken = str CollectionRetentionDays = int Column = str DataProtectionPolicyDocument = str +DataSourceName = str +DataSourceType = str +DataType = str Days = int DefaultValue = float +DeletionProtectionEnabled = bool Delimiter = str DeliveryDestinationName = str DeliveryDestinationPolicy = str @@ -44,6 +50,7 @@ EntityAttributesValue = str EntityKeyAttributesKey = str EntityKeyAttributesValue = str +ErrorMessage = str EventId = str EventMessage = str EventsLimit = int @@ -65,7 +72,11 @@ Force = bool ForceUpdate = bool FromKey = str +GetScheduledQueryHistoryMaxResults = int GrokMatch = str +GroupingIdentifierKey = str +GroupingIdentifierValue = str +ImportId = str IncludeLinkedAccounts = bool InferredTokenName = str Integer = int @@ -82,9 +93,14 @@ ListLimit = int ListLogAnomalyDetectorsLimit = int ListLogGroupsForQueryMaxResults = int +ListLogGroupsRequestLimit = int +ListScheduledQueriesMaxResults = int +ListSourcesForS3TableIntegrationMaxResults = int Locale = str LogEventIndex = int +LogFieldName = str LogGroupArn = str +LogGroupCount = int LogGroupIdentifier = str LogGroupName = str LogGroupNamePattern = str @@ -94,6 +110,7 @@ LogStreamName = str LogStreamSearchedCompletely = bool LogType = str +MappingVersion = str MatchPattern = str Message = str MetricName = str @@ -128,6 +145,14 @@ ResourceIdentifier = str ResourceType = str RoleArn = str +S3TableIntegrationSourceIdentifier = str +S3TableIntegrationSourceStatusReason = str +S3Uri = str +ScheduleExpression = str +ScheduleTimezone = str +ScheduledQueryDescription = str +ScheduledQueryIdentifier = str +ScheduledQueryName = str SelectionCriteria = str SequenceToken = str Service = str @@ -137,6 +162,7 @@ SplitStringDelimiter = str StartFromHead = bool StatsValue = float +String = str Success = bool SystemField = str TagKey = str @@ -156,6 +182,13 @@ WithKey = str +class ActionStatus(StrEnum): + IN_PROGRESS = "IN_PROGRESS" + CLIENT_ERROR = "CLIENT_ERROR" + FAILED = "FAILED" + COMPLETE = "COMPLETE" + + class AnomalyDetectorStatus(StrEnum): INITIALIZING = "INITIALIZING" TRAINING = "TRAINING" @@ -211,6 +244,14 @@ class EventSource(StrEnum): AWSWAF = "AWSWAF" +class ExecutionStatus(StrEnum): + Running = "Running" + InvalidQuery = "InvalidQuery" + Complete = "Complete" + Failed = "Failed" + Timeout = "Timeout" + + class ExportTaskStatusCode(StrEnum): CANCELLED = "CANCELLED" COMPLETED = "COMPLETED" @@ -225,11 +266,23 @@ class FlattenedElement(StrEnum): last = "last" +class ImportStatus(StrEnum): + IN_PROGRESS = "IN_PROGRESS" + CANCELLED = "CANCELLED" + COMPLETED = "COMPLETED" + FAILED = "FAILED" + + class IndexSource(StrEnum): ACCOUNT = "ACCOUNT" LOG_GROUP = "LOG_GROUP" +class IndexType(StrEnum): + FACET = "FACET" + FIELD_INDEX = "FIELD_INDEX" + + class InheritedProperty(StrEnum): ACCOUNT_DATA_PROTECTION = "ACCOUNT_DATA_PROTECTION" @@ -244,6 +297,11 @@ class IntegrationType(StrEnum): OPENSEARCH = "OPENSEARCH" +class ListAggregateLogGroupSummariesGroupBy(StrEnum): + DATA_SOURCE_NAME_TYPE_AND_FORMAT = "DATA_SOURCE_NAME_TYPE_AND_FORMAT" + DATA_SOURCE_NAME_AND_TYPE = "DATA_SOURCE_NAME_AND_TYPE" + + class LogGroupClass(StrEnum): STANDARD = "STANDARD" INFREQUENT_ACCESS = "INFREQUENT_ACCESS" @@ -252,6 +310,7 @@ class LogGroupClass(StrEnum): class OCSFVersion(StrEnum): V1_1 = "V1.1" + V1_5 = "V1.5" class OpenSearchResourceStatusType(StrEnum): @@ -302,6 +361,22 @@ class QueryStatus(StrEnum): Unknown = "Unknown" +class S3TableIntegrationSourceStatus(StrEnum): + ACTIVE = "ACTIVE" + UNHEALTHY = "UNHEALTHY" + FAILED = "FAILED" + DATA_SOURCE_DELETE_IN_PROGRESS = "DATA_SOURCE_DELETE_IN_PROGRESS" + + +class ScheduledQueryDestinationType(StrEnum): + S3 = "S3" + + +class ScheduledQueryState(StrEnum): + ENABLED = "ENABLED" + DISABLED = "DISABLED" + + class Scope(StrEnum): ALL = "ALL" @@ -381,7 +456,13 @@ class DataAlreadyAcceptedException(ServiceException): code: str = "DataAlreadyAcceptedException" sender_fault: bool = False status_code: int = 400 - expectedSequenceToken: Optional[SequenceToken] + expectedSequenceToken: SequenceToken | None + + +class InternalServerException(ServiceException): + code: str = "InternalServerException" + sender_fault: bool = False + status_code: int = 400 class InternalStreamingException(ServiceException): @@ -406,7 +487,7 @@ class InvalidSequenceTokenException(ServiceException): code: str = "InvalidSequenceTokenException" sender_fault: bool = False status_code: int = 400 - expectedSequenceToken: Optional[SequenceToken] + expectedSequenceToken: SequenceToken | None class LimitExceededException(ServiceException): @@ -416,20 +497,20 @@ class LimitExceededException(ServiceException): class QueryCompileErrorLocation(TypedDict, total=False): - startCharOffset: Optional[QueryCharOffset] - endCharOffset: Optional[QueryCharOffset] + startCharOffset: QueryCharOffset | None + endCharOffset: QueryCharOffset | None class QueryCompileError(TypedDict, total=False): - location: Optional[QueryCompileErrorLocation] - message: Optional[Message] + location: QueryCompileErrorLocation | None + message: Message | None class MalformedQueryException(ServiceException): code: str = "MalformedQueryException" sender_fault: bool = False status_code: int = 400 - queryCompileError: Optional[QueryCompileError] + queryCompileError: QueryCompileError | None class OperationAbortedException(ServiceException): @@ -484,7 +565,7 @@ class TooManyTagsException(ServiceException): code: str = "TooManyTagsException" sender_fault: bool = False status_code: int = 400 - resourceName: Optional[AmazonResourceName] + resourceName: AmazonResourceName | None class UnrecognizedClientException(ServiceException): @@ -499,70 +580,84 @@ class ValidationException(ServiceException): status_code: int = 400 -AccountIds = List[AccountId] +AccountIds = list[AccountId] Timestamp = int class AccountPolicy(TypedDict, total=False): - policyName: Optional[PolicyName] - policyDocument: Optional[AccountPolicyDocument] - lastUpdatedTime: Optional[Timestamp] - policyType: Optional[PolicyType] - scope: Optional[Scope] - selectionCriteria: Optional[SelectionCriteria] - accountId: Optional[AccountId] + policyName: PolicyName | None + policyDocument: AccountPolicyDocument | None + lastUpdatedTime: Timestamp | None + policyType: PolicyType | None + scope: Scope | None + selectionCriteria: SelectionCriteria | None + accountId: AccountId | None -AccountPolicies = List[AccountPolicy] +AccountPolicies = list[AccountPolicy] class AddKeyEntry(TypedDict, total=False): key: Key value: AddKeyValue - overwriteIfExists: Optional[OverwriteIfExists] + overwriteIfExists: OverwriteIfExists | None -AddKeyEntries = List[AddKeyEntry] +AddKeyEntries = list[AddKeyEntry] class AddKeys(TypedDict, total=False): entries: AddKeyEntries -AllowedFieldDelimiters = List[FieldDelimiter] +class GroupingIdentifier(TypedDict, total=False): + key: GroupingIdentifierKey | None + value: GroupingIdentifierValue | None + + +GroupingIdentifiers = list[GroupingIdentifier] + + +class AggregateLogGroupSummary(TypedDict, total=False): + logGroupCount: LogGroupCount | None + groupingIdentifiers: GroupingIdentifiers | None + + +AggregateLogGroupSummaries = list[AggregateLogGroupSummary] +AllowedFieldDelimiters = list[FieldDelimiter] class RecordField(TypedDict, total=False): - name: Optional[FieldHeader] - mandatory: Optional[Boolean] + name: FieldHeader | None + mandatory: Boolean | None -AllowedFields = List[RecordField] +AllowedFields = list[RecordField] EpochMillis = int -LogGroupArnList = List[LogGroupArn] +LogGroupArnList = list[LogGroupArn] TokenValue = int -Enumerations = Dict[TokenString, TokenValue] +Enumerations = dict[TokenString, TokenValue] class PatternToken(TypedDict, total=False): - dynamicTokenPosition: Optional[DynamicTokenPosition] - isDynamic: Optional[Boolean] - tokenString: Optional[TokenString] - enumerations: Optional[Enumerations] - inferredTokenName: Optional[InferredTokenName] + dynamicTokenPosition: DynamicTokenPosition | None + isDynamic: Boolean | None + tokenString: TokenString | None + enumerations: Enumerations | None + inferredTokenName: InferredTokenName | None -PatternTokens = List[PatternToken] +PatternTokens = list[PatternToken] class LogEvent(TypedDict, total=False): - timestamp: Optional[Timestamp] - message: Optional[EventMessage] + timestamp: Timestamp | None + message: EventMessage | None -LogSamples = List[LogEvent] +LogSamples = list[LogEvent] Count = int -Histogram = Dict[Time, Count] +Histogram = dict[Time, Count] class Anomaly(TypedDict, total=False): @@ -570,8 +665,8 @@ class Anomaly(TypedDict, total=False): patternId: PatternId anomalyDetectorArn: AnomalyDetectorArn patternString: PatternString - patternRegex: Optional[PatternRegex] - priority: Optional[Priority] + patternRegex: PatternRegex | None + priority: Priority | None firstSeen: EpochMillis lastSeen: EpochMillis description: Description @@ -581,164 +676,215 @@ class Anomaly(TypedDict, total=False): logSamples: LogSamples patternTokens: PatternTokens logGroupArnList: LogGroupArnList - suppressed: Optional[Boolean] - suppressedDate: Optional[EpochMillis] - suppressedUntil: Optional[EpochMillis] - isPatternLevelSuppression: Optional[Boolean] + suppressed: Boolean | None + suppressedDate: EpochMillis | None + suppressedUntil: EpochMillis | None + isPatternLevelSuppression: Boolean | None -Anomalies = List[Anomaly] +Anomalies = list[Anomaly] AnomalyVisibilityTime = int class AnomalyDetector(TypedDict, total=False): - anomalyDetectorArn: Optional[AnomalyDetectorArn] - detectorName: Optional[DetectorName] - logGroupArnList: Optional[LogGroupArnList] - evaluationFrequency: Optional[EvaluationFrequency] - filterPattern: Optional[FilterPattern] - anomalyDetectorStatus: Optional[AnomalyDetectorStatus] - kmsKeyId: Optional[KmsKeyId] - creationTimeStamp: Optional[EpochMillis] - lastModifiedTimeStamp: Optional[EpochMillis] - anomalyVisibilityTime: Optional[AnomalyVisibilityTime] + anomalyDetectorArn: AnomalyDetectorArn | None + detectorName: DetectorName | None + logGroupArnList: LogGroupArnList | None + evaluationFrequency: EvaluationFrequency | None + filterPattern: FilterPattern | None + anomalyDetectorStatus: AnomalyDetectorStatus | None + kmsKeyId: KmsKeyId | None + creationTimeStamp: EpochMillis | None + lastModifiedTimeStamp: EpochMillis | None + anomalyVisibilityTime: AnomalyVisibilityTime | None -AnomalyDetectors = List[AnomalyDetector] +AnomalyDetectors = list[AnomalyDetector] class AssociateKmsKeyRequest(ServiceRequest): - logGroupName: Optional[LogGroupName] + logGroupName: LogGroupName | None kmsKeyId: KmsKeyId - resourceIdentifier: Optional[ResourceIdentifier] + resourceIdentifier: ResourceIdentifier | None + +class DataSource(TypedDict, total=False): + name: DataSourceName + type: DataSourceType | None -Columns = List[Column] + +class AssociateSourceToS3TableIntegrationRequest(ServiceRequest): + integrationArn: Arn + dataSource: DataSource + + +class AssociateSourceToS3TableIntegrationResponse(TypedDict, total=False): + identifier: S3TableIntegrationSourceIdentifier | None + + +Columns = list[Column] class CSV(TypedDict, total=False): - quoteCharacter: Optional[QuoteCharacter] - delimiter: Optional[Delimiter] - columns: Optional[Columns] - source: Optional[Source] + quoteCharacter: QuoteCharacter | None + delimiter: Delimiter | None + columns: Columns | None + source: Source | None class CancelExportTaskRequest(ServiceRequest): taskId: ExportTaskId -RecordFields = List[FieldHeader] -OutputFormats = List[OutputFormat] +class CancelImportTaskRequest(ServiceRequest): + importId: ImportId + + +StoredBytes = int + + +class ImportStatistics(TypedDict, total=False): + bytesImported: StoredBytes | None + + +class CancelImportTaskResponse(TypedDict, total=False): + importId: ImportId | None + importStatistics: ImportStatistics | None + importStatus: ImportStatus | None + creationTime: Timestamp | None + lastUpdatedTime: Timestamp | None + + +RecordFields = list[FieldHeader] +OutputFormats = list[OutputFormat] class S3DeliveryConfiguration(TypedDict, total=False): - suffixPath: Optional[DeliverySuffixPath] - enableHiveCompatiblePath: Optional[Boolean] + suffixPath: DeliverySuffixPath | None + enableHiveCompatiblePath: Boolean | None class ConfigurationTemplateDeliveryConfigValues(TypedDict, total=False): - recordFields: Optional[RecordFields] - fieldDelimiter: Optional[FieldDelimiter] - s3DeliveryConfiguration: Optional[S3DeliveryConfiguration] + recordFields: RecordFields | None + fieldDelimiter: FieldDelimiter | None + s3DeliveryConfiguration: S3DeliveryConfiguration | None class ConfigurationTemplate(TypedDict, total=False): - service: Optional[Service] - logType: Optional[LogType] - resourceType: Optional[ResourceType] - deliveryDestinationType: Optional[DeliveryDestinationType] - defaultDeliveryConfigValues: Optional[ConfigurationTemplateDeliveryConfigValues] - allowedFields: Optional[AllowedFields] - allowedOutputFormats: Optional[OutputFormats] - allowedActionForAllowVendedLogsDeliveryForResource: Optional[ - AllowedActionForAllowVendedLogsDeliveryForResource - ] - allowedFieldDelimiters: Optional[AllowedFieldDelimiters] - allowedSuffixPathFields: Optional[RecordFields] + service: Service | None + logType: LogType | None + resourceType: ResourceType | None + deliveryDestinationType: DeliveryDestinationType | None + defaultDeliveryConfigValues: ConfigurationTemplateDeliveryConfigValues | None + allowedFields: AllowedFields | None + allowedOutputFormats: OutputFormats | None + allowedActionForAllowVendedLogsDeliveryForResource: ( + AllowedActionForAllowVendedLogsDeliveryForResource | None + ) + allowedFieldDelimiters: AllowedFieldDelimiters | None + allowedSuffixPathFields: RecordFields | None -ConfigurationTemplates = List[ConfigurationTemplate] +ConfigurationTemplates = list[ConfigurationTemplate] class CopyValueEntry(TypedDict, total=False): source: Source target: Target - overwriteIfExists: Optional[OverwriteIfExists] + overwriteIfExists: OverwriteIfExists | None -CopyValueEntries = List[CopyValueEntry] +CopyValueEntries = list[CopyValueEntry] class CopyValue(TypedDict, total=False): entries: CopyValueEntries -Tags = Dict[TagKey, TagValue] +Tags = dict[TagKey, TagValue] class CreateDeliveryRequest(ServiceRequest): deliverySourceName: DeliverySourceName deliveryDestinationArn: Arn - recordFields: Optional[RecordFields] - fieldDelimiter: Optional[FieldDelimiter] - s3DeliveryConfiguration: Optional[S3DeliveryConfiguration] - tags: Optional[Tags] + recordFields: RecordFields | None + fieldDelimiter: FieldDelimiter | None + s3DeliveryConfiguration: S3DeliveryConfiguration | None + tags: Tags | None class Delivery(TypedDict, total=False): - id: Optional[DeliveryId] - arn: Optional[Arn] - deliverySourceName: Optional[DeliverySourceName] - deliveryDestinationArn: Optional[Arn] - deliveryDestinationType: Optional[DeliveryDestinationType] - recordFields: Optional[RecordFields] - fieldDelimiter: Optional[FieldDelimiter] - s3DeliveryConfiguration: Optional[S3DeliveryConfiguration] - tags: Optional[Tags] + id: DeliveryId | None + arn: Arn | None + deliverySourceName: DeliverySourceName | None + deliveryDestinationArn: Arn | None + deliveryDestinationType: DeliveryDestinationType | None + recordFields: RecordFields | None + fieldDelimiter: FieldDelimiter | None + s3DeliveryConfiguration: S3DeliveryConfiguration | None + tags: Tags | None class CreateDeliveryResponse(TypedDict, total=False): - delivery: Optional[Delivery] + delivery: Delivery | None CreateExportTaskRequest = TypedDict( "CreateExportTaskRequest", { - "taskName": Optional[ExportTaskName], + "taskName": ExportTaskName | None, "logGroupName": LogGroupName, - "logStreamNamePrefix": Optional[LogStreamName], + "logStreamNamePrefix": LogStreamName | None, "from": Timestamp, "to": Timestamp, "destination": ExportDestinationBucket, - "destinationPrefix": Optional[ExportDestinationPrefix], + "destinationPrefix": ExportDestinationPrefix | None, }, total=False, ) class CreateExportTaskResponse(TypedDict, total=False): - taskId: Optional[ExportTaskId] + taskId: ExportTaskId | None + + +class ImportFilter(TypedDict, total=False): + startEventTime: Timestamp | None + endEventTime: Timestamp | None + + +class CreateImportTaskRequest(ServiceRequest): + importSourceArn: Arn + importRoleArn: RoleArn + importFilter: ImportFilter | None + + +class CreateImportTaskResponse(TypedDict, total=False): + importId: ImportId | None + importDestinationArn: Arn | None + creationTime: Timestamp | None class CreateLogAnomalyDetectorRequest(ServiceRequest): logGroupArnList: LogGroupArnList - detectorName: Optional[DetectorName] - evaluationFrequency: Optional[EvaluationFrequency] - filterPattern: Optional[FilterPattern] - kmsKeyId: Optional[DetectorKmsKeyArn] - anomalyVisibilityTime: Optional[AnomalyVisibilityTime] - tags: Optional[Tags] + detectorName: DetectorName | None + evaluationFrequency: EvaluationFrequency | None + filterPattern: FilterPattern | None + kmsKeyId: DetectorKmsKeyArn | None + anomalyVisibilityTime: AnomalyVisibilityTime | None + tags: Tags | None class CreateLogAnomalyDetectorResponse(TypedDict, total=False): - anomalyDetectorArn: Optional[AnomalyDetectorArn] + anomalyDetectorArn: AnomalyDetectorArn | None class CreateLogGroupRequest(ServiceRequest): logGroupName: LogGroupName - kmsKeyId: Optional[KmsKeyId] - tags: Optional[Tags] - logGroupClass: Optional[LogGroupClass] + kmsKeyId: KmsKeyId | None + tags: Tags | None + logGroupClass: LogGroupClass | None + deletionProtectionEnabled: DeletionProtectionEnabled | None class CreateLogStreamRequest(ServiceRequest): @@ -746,19 +892,62 @@ class CreateLogStreamRequest(ServiceRequest): logStreamName: LogStreamName -DashboardViewerPrincipals = List[Arn] +class S3Configuration(TypedDict, total=False): + destinationIdentifier: S3Uri + roleArn: RoleArn + + +class DestinationConfiguration(TypedDict, total=False): + s3Configuration: S3Configuration + + +StartTimeOffset = int +ScheduledQueryLogGroupIdentifiers = list[LogGroupIdentifier] + + +class CreateScheduledQueryRequest(ServiceRequest): + name: ScheduledQueryName + description: ScheduledQueryDescription | None + queryLanguage: QueryLanguage + queryString: QueryString + logGroupIdentifiers: ScheduledQueryLogGroupIdentifiers | None + scheduleExpression: ScheduleExpression + timezone: ScheduleTimezone | None + startTimeOffset: StartTimeOffset | None + destinationConfiguration: DestinationConfiguration | None + scheduleStartTime: Timestamp | None + scheduleEndTime: Timestamp | None + executionRoleArn: RoleArn + state: ScheduledQueryState | None + tags: Tags | None + + +class CreateScheduledQueryResponse(TypedDict, total=False): + scheduledQueryArn: Arn | None + state: ScheduledQueryState | None + + +DashboardViewerPrincipals = list[Arn] Data = bytes -MatchPatterns = List[MatchPattern] + + +class DataSourceFilter(TypedDict, total=False): + name: DataSourceName + type: DataSourceType | None + + +DataSourceFilters = list[DataSourceFilter] +MatchPatterns = list[MatchPattern] class DateTimeConverter(TypedDict, total=False): source: Source target: Target - targetFormat: Optional[TargetFormat] + targetFormat: TargetFormat | None matchPatterns: MatchPatterns - sourceTimezone: Optional[SourceTimezone] - targetTimezone: Optional[TargetTimezone] - locale: Optional[Locale] + sourceTimezone: SourceTimezone | None + targetTimezone: TargetTimezone | None + locale: Locale | None class DeleteAccountPolicyRequest(ServiceRequest): @@ -800,14 +989,14 @@ class DeleteIndexPolicyResponse(TypedDict, total=False): class DeleteIntegrationRequest(ServiceRequest): integrationName: IntegrationName - force: Optional[Force] + force: Force | None class DeleteIntegrationResponse(TypedDict, total=False): pass -DeleteWithKeys = List[WithKey] +DeleteWithKeys = list[WithKey] class DeleteKeys(TypedDict, total=False): @@ -837,19 +1026,27 @@ class DeleteQueryDefinitionRequest(ServiceRequest): class DeleteQueryDefinitionResponse(TypedDict, total=False): - success: Optional[Success] + success: Success | None class DeleteResourcePolicyRequest(ServiceRequest): - policyName: Optional[PolicyName] - resourceArn: Optional[Arn] - expectedRevisionId: Optional[ExpectedRevisionId] + policyName: PolicyName | None + resourceArn: Arn | None + expectedRevisionId: ExpectedRevisionId | None class DeleteRetentionPolicyRequest(ServiceRequest): logGroupName: LogGroupName +class DeleteScheduledQueryRequest(ServiceRequest): + identifier: ScheduledQueryIdentifier + + +class DeleteScheduledQueryResponse(TypedDict, total=False): + pass + + class DeleteSubscriptionFilterRequest(ServiceRequest): logGroupName: LogGroupName filterName: FilterName @@ -859,7 +1056,7 @@ class DeleteTransformerRequest(ServiceRequest): logGroupIdentifier: LogGroupIdentifier -Deliveries = List[Delivery] +Deliveries = list[Delivery] class DeliveryDestinationConfiguration(TypedDict, total=False): @@ -867,481 +1064,546 @@ class DeliveryDestinationConfiguration(TypedDict, total=False): class DeliveryDestination(TypedDict, total=False): - name: Optional[DeliveryDestinationName] - arn: Optional[Arn] - deliveryDestinationType: Optional[DeliveryDestinationType] - outputFormat: Optional[OutputFormat] - deliveryDestinationConfiguration: Optional[DeliveryDestinationConfiguration] - tags: Optional[Tags] + name: DeliveryDestinationName | None + arn: Arn | None + deliveryDestinationType: DeliveryDestinationType | None + outputFormat: OutputFormat | None + deliveryDestinationConfiguration: DeliveryDestinationConfiguration | None + tags: Tags | None -DeliveryDestinationTypes = List[DeliveryDestinationType] -DeliveryDestinations = List[DeliveryDestination] -ResourceArns = List[Arn] +DeliveryDestinationTypes = list[DeliveryDestinationType] +DeliveryDestinations = list[DeliveryDestination] +ResourceArns = list[Arn] class DeliverySource(TypedDict, total=False): - name: Optional[DeliverySourceName] - arn: Optional[Arn] - resourceArns: Optional[ResourceArns] - service: Optional[Service] - logType: Optional[LogType] - tags: Optional[Tags] + name: DeliverySourceName | None + arn: Arn | None + resourceArns: ResourceArns | None + service: Service | None + logType: LogType | None + tags: Tags | None -DeliverySources = List[DeliverySource] +DeliverySources = list[DeliverySource] class DescribeAccountPoliciesRequest(ServiceRequest): policyType: PolicyType - policyName: Optional[PolicyName] - accountIdentifiers: Optional[AccountIds] - nextToken: Optional[NextToken] + policyName: PolicyName | None + accountIdentifiers: AccountIds | None + nextToken: NextToken | None class DescribeAccountPoliciesResponse(TypedDict, total=False): - accountPolicies: Optional[AccountPolicies] - nextToken: Optional[NextToken] + accountPolicies: AccountPolicies | None + nextToken: NextToken | None -ResourceTypes = List[ResourceType] -LogTypes = List[LogType] +ResourceTypes = list[ResourceType] +LogTypes = list[LogType] class DescribeConfigurationTemplatesRequest(ServiceRequest): - service: Optional[Service] - logTypes: Optional[LogTypes] - resourceTypes: Optional[ResourceTypes] - deliveryDestinationTypes: Optional[DeliveryDestinationTypes] - nextToken: Optional[NextToken] - limit: Optional[DescribeLimit] + service: Service | None + logTypes: LogTypes | None + resourceTypes: ResourceTypes | None + deliveryDestinationTypes: DeliveryDestinationTypes | None + nextToken: NextToken | None + limit: DescribeLimit | None class DescribeConfigurationTemplatesResponse(TypedDict, total=False): - configurationTemplates: Optional[ConfigurationTemplates] - nextToken: Optional[NextToken] + configurationTemplates: ConfigurationTemplates | None + nextToken: NextToken | None class DescribeDeliveriesRequest(ServiceRequest): - nextToken: Optional[NextToken] - limit: Optional[DescribeLimit] + nextToken: NextToken | None + limit: DescribeLimit | None class DescribeDeliveriesResponse(TypedDict, total=False): - deliveries: Optional[Deliveries] - nextToken: Optional[NextToken] + deliveries: Deliveries | None + nextToken: NextToken | None class DescribeDeliveryDestinationsRequest(ServiceRequest): - nextToken: Optional[NextToken] - limit: Optional[DescribeLimit] + nextToken: NextToken | None + limit: DescribeLimit | None class DescribeDeliveryDestinationsResponse(TypedDict, total=False): - deliveryDestinations: Optional[DeliveryDestinations] - nextToken: Optional[NextToken] + deliveryDestinations: DeliveryDestinations | None + nextToken: NextToken | None class DescribeDeliverySourcesRequest(ServiceRequest): - nextToken: Optional[NextToken] - limit: Optional[DescribeLimit] + nextToken: NextToken | None + limit: DescribeLimit | None class DescribeDeliverySourcesResponse(TypedDict, total=False): - deliverySources: Optional[DeliverySources] - nextToken: Optional[NextToken] + deliverySources: DeliverySources | None + nextToken: NextToken | None class DescribeDestinationsRequest(ServiceRequest): - DestinationNamePrefix: Optional[DestinationName] - nextToken: Optional[NextToken] - limit: Optional[DescribeLimit] + DestinationNamePrefix: DestinationName | None + nextToken: NextToken | None + limit: DescribeLimit | None class Destination(TypedDict, total=False): - destinationName: Optional[DestinationName] - targetArn: Optional[TargetArn] - roleArn: Optional[RoleArn] - accessPolicy: Optional[AccessPolicy] - arn: Optional[Arn] - creationTime: Optional[Timestamp] + destinationName: DestinationName | None + targetArn: TargetArn | None + roleArn: RoleArn | None + accessPolicy: AccessPolicy | None + arn: Arn | None + creationTime: Timestamp | None -Destinations = List[Destination] +Destinations = list[Destination] class DescribeDestinationsResponse(TypedDict, total=False): - destinations: Optional[Destinations] - nextToken: Optional[NextToken] + destinations: Destinations | None + nextToken: NextToken | None class DescribeExportTasksRequest(ServiceRequest): - taskId: Optional[ExportTaskId] - statusCode: Optional[ExportTaskStatusCode] - nextToken: Optional[NextToken] - limit: Optional[DescribeLimit] + taskId: ExportTaskId | None + statusCode: ExportTaskStatusCode | None + nextToken: NextToken | None + limit: DescribeLimit | None class ExportTaskExecutionInfo(TypedDict, total=False): - creationTime: Optional[Timestamp] - completionTime: Optional[Timestamp] + creationTime: Timestamp | None + completionTime: Timestamp | None class ExportTaskStatus(TypedDict, total=False): - code: Optional[ExportTaskStatusCode] - message: Optional[ExportTaskStatusMessage] + code: ExportTaskStatusCode | None + message: ExportTaskStatusMessage | None ExportTask = TypedDict( "ExportTask", { - "taskId": Optional[ExportTaskId], - "taskName": Optional[ExportTaskName], - "logGroupName": Optional[LogGroupName], - "from": Optional[Timestamp], - "to": Optional[Timestamp], - "destination": Optional[ExportDestinationBucket], - "destinationPrefix": Optional[ExportDestinationPrefix], - "status": Optional[ExportTaskStatus], - "executionInfo": Optional[ExportTaskExecutionInfo], + "taskId": ExportTaskId | None, + "taskName": ExportTaskName | None, + "logGroupName": LogGroupName | None, + "from": Timestamp | None, + "to": Timestamp | None, + "destination": ExportDestinationBucket | None, + "destinationPrefix": ExportDestinationPrefix | None, + "status": ExportTaskStatus | None, + "executionInfo": ExportTaskExecutionInfo | None, }, total=False, ) -ExportTasks = List[ExportTask] +ExportTasks = list[ExportTask] class DescribeExportTasksResponse(TypedDict, total=False): - exportTasks: Optional[ExportTasks] - nextToken: Optional[NextToken] + exportTasks: ExportTasks | None + nextToken: NextToken | None -DescribeFieldIndexesLogGroupIdentifiers = List[LogGroupIdentifier] +DescribeFieldIndexesLogGroupIdentifiers = list[LogGroupIdentifier] class DescribeFieldIndexesRequest(ServiceRequest): logGroupIdentifiers: DescribeFieldIndexesLogGroupIdentifiers - nextToken: Optional[NextToken] + nextToken: NextToken | None class FieldIndex(TypedDict, total=False): - logGroupIdentifier: Optional[LogGroupIdentifier] - fieldIndexName: Optional[FieldIndexName] - lastScanTime: Optional[Timestamp] - firstEventTime: Optional[Timestamp] - lastEventTime: Optional[Timestamp] + logGroupIdentifier: LogGroupIdentifier | None + fieldIndexName: FieldIndexName | None + lastScanTime: Timestamp | None + firstEventTime: Timestamp | None + lastEventTime: Timestamp | None + type: IndexType | None -FieldIndexes = List[FieldIndex] +FieldIndexes = list[FieldIndex] class DescribeFieldIndexesResponse(TypedDict, total=False): - fieldIndexes: Optional[FieldIndexes] - nextToken: Optional[NextToken] + fieldIndexes: FieldIndexes | None + nextToken: NextToken | None + + +ImportStatusList = list[ImportStatus] + + +class DescribeImportTaskBatchesRequest(ServiceRequest): + importId: ImportId + batchImportStatus: ImportStatusList | None + limit: DescribeLimit | None + nextToken: NextToken | None + + +class ImportBatch(TypedDict, total=False): + batchId: BatchId + status: ImportStatus + errorMessage: ErrorMessage | None + + +ImportBatchList = list[ImportBatch] + + +class DescribeImportTaskBatchesResponse(TypedDict, total=False): + importSourceArn: Arn | None + importId: ImportId | None + importBatches: ImportBatchList | None + nextToken: NextToken | None + +class DescribeImportTasksRequest(ServiceRequest): + importId: ImportId | None + importStatus: ImportStatus | None + importSourceArn: Arn | None + limit: DescribeLimit | None + nextToken: NextToken | None -DescribeIndexPoliciesLogGroupIdentifiers = List[LogGroupIdentifier] + +class Import(TypedDict, total=False): + importId: ImportId | None + importSourceArn: Arn | None + importStatus: ImportStatus | None + importDestinationArn: Arn | None + importStatistics: ImportStatistics | None + importFilter: ImportFilter | None + creationTime: Timestamp | None + lastUpdatedTime: Timestamp | None + errorMessage: ErrorMessage | None + + +ImportList = list[Import] + + +class DescribeImportTasksResponse(TypedDict, total=False): + imports: ImportList | None + nextToken: NextToken | None + + +DescribeIndexPoliciesLogGroupIdentifiers = list[LogGroupIdentifier] class DescribeIndexPoliciesRequest(ServiceRequest): logGroupIdentifiers: DescribeIndexPoliciesLogGroupIdentifiers - nextToken: Optional[NextToken] + nextToken: NextToken | None class IndexPolicy(TypedDict, total=False): - logGroupIdentifier: Optional[LogGroupIdentifier] - lastUpdateTime: Optional[Timestamp] - policyDocument: Optional[PolicyDocument] - policyName: Optional[PolicyName] - source: Optional[IndexSource] + logGroupIdentifier: LogGroupIdentifier | None + lastUpdateTime: Timestamp | None + policyDocument: PolicyDocument | None + policyName: PolicyName | None + source: IndexSource | None -IndexPolicies = List[IndexPolicy] +IndexPolicies = list[IndexPolicy] class DescribeIndexPoliciesResponse(TypedDict, total=False): - indexPolicies: Optional[IndexPolicies] - nextToken: Optional[NextToken] + indexPolicies: IndexPolicies | None + nextToken: NextToken | None -DescribeLogGroupsLogGroupIdentifiers = List[LogGroupIdentifier] +DescribeLogGroupsLogGroupIdentifiers = list[LogGroupIdentifier] class DescribeLogGroupsRequest(ServiceRequest): - accountIdentifiers: Optional[AccountIds] - logGroupNamePrefix: Optional[LogGroupName] - logGroupNamePattern: Optional[LogGroupNamePattern] - nextToken: Optional[NextToken] - limit: Optional[DescribeLimit] - includeLinkedAccounts: Optional[IncludeLinkedAccounts] - logGroupClass: Optional[LogGroupClass] - logGroupIdentifiers: Optional[DescribeLogGroupsLogGroupIdentifiers] + accountIdentifiers: AccountIds | None + logGroupNamePrefix: LogGroupName | None + logGroupNamePattern: LogGroupNamePattern | None + nextToken: NextToken | None + limit: DescribeLimit | None + includeLinkedAccounts: IncludeLinkedAccounts | None + logGroupClass: LogGroupClass | None + logGroupIdentifiers: DescribeLogGroupsLogGroupIdentifiers | None -InheritedProperties = List[InheritedProperty] -StoredBytes = int +InheritedProperties = list[InheritedProperty] class LogGroup(TypedDict, total=False): - logGroupName: Optional[LogGroupName] - creationTime: Optional[Timestamp] - retentionInDays: Optional[Days] - metricFilterCount: Optional[FilterCount] - arn: Optional[Arn] - storedBytes: Optional[StoredBytes] - kmsKeyId: Optional[KmsKeyId] - dataProtectionStatus: Optional[DataProtectionStatus] - inheritedProperties: Optional[InheritedProperties] - logGroupClass: Optional[LogGroupClass] - logGroupArn: Optional[Arn] + logGroupName: LogGroupName | None + creationTime: Timestamp | None + retentionInDays: Days | None + metricFilterCount: FilterCount | None + arn: Arn | None + storedBytes: StoredBytes | None + kmsKeyId: KmsKeyId | None + dataProtectionStatus: DataProtectionStatus | None + inheritedProperties: InheritedProperties | None + logGroupClass: LogGroupClass | None + logGroupArn: Arn | None + deletionProtectionEnabled: DeletionProtectionEnabled | None -LogGroups = List[LogGroup] +LogGroups = list[LogGroup] class DescribeLogGroupsResponse(TypedDict, total=False): - logGroups: Optional[LogGroups] - nextToken: Optional[NextToken] + logGroups: LogGroups | None + nextToken: NextToken | None class DescribeLogStreamsRequest(ServiceRequest): - logGroupName: Optional[LogGroupName] - logGroupIdentifier: Optional[LogGroupIdentifier] - logStreamNamePrefix: Optional[LogStreamName] - orderBy: Optional[OrderBy] - descending: Optional[Descending] - nextToken: Optional[NextToken] - limit: Optional[DescribeLimit] + logGroupName: LogGroupName | None + logGroupIdentifier: LogGroupIdentifier | None + logStreamNamePrefix: LogStreamName | None + orderBy: OrderBy | None + descending: Descending | None + nextToken: NextToken | None + limit: DescribeLimit | None class LogStream(TypedDict, total=False): - logStreamName: Optional[LogStreamName] - creationTime: Optional[Timestamp] - firstEventTimestamp: Optional[Timestamp] - lastEventTimestamp: Optional[Timestamp] - lastIngestionTime: Optional[Timestamp] - uploadSequenceToken: Optional[SequenceToken] - arn: Optional[Arn] - storedBytes: Optional[StoredBytes] + logStreamName: LogStreamName | None + creationTime: Timestamp | None + firstEventTimestamp: Timestamp | None + lastEventTimestamp: Timestamp | None + lastIngestionTime: Timestamp | None + uploadSequenceToken: SequenceToken | None + arn: Arn | None + storedBytes: StoredBytes | None -LogStreams = List[LogStream] +LogStreams = list[LogStream] class DescribeLogStreamsResponse(TypedDict, total=False): - logStreams: Optional[LogStreams] - nextToken: Optional[NextToken] + logStreams: LogStreams | None + nextToken: NextToken | None class DescribeMetricFiltersRequest(ServiceRequest): - logGroupName: Optional[LogGroupName] - filterNamePrefix: Optional[FilterName] - nextToken: Optional[NextToken] - limit: Optional[DescribeLimit] - metricName: Optional[MetricName] - metricNamespace: Optional[MetricNamespace] + logGroupName: LogGroupName | None + filterNamePrefix: FilterName | None + nextToken: NextToken | None + limit: DescribeLimit | None + metricName: MetricName | None + metricNamespace: MetricNamespace | None -EmitSystemFields = List[SystemField] -Dimensions = Dict[DimensionsKey, DimensionsValue] +EmitSystemFields = list[SystemField] +Dimensions = dict[DimensionsKey, DimensionsValue] class MetricTransformation(TypedDict, total=False): metricName: MetricName metricNamespace: MetricNamespace metricValue: MetricValue - defaultValue: Optional[DefaultValue] - dimensions: Optional[Dimensions] - unit: Optional[StandardUnit] + defaultValue: DefaultValue | None + dimensions: Dimensions | None + unit: StandardUnit | None -MetricTransformations = List[MetricTransformation] +MetricTransformations = list[MetricTransformation] class MetricFilter(TypedDict, total=False): - filterName: Optional[FilterName] - filterPattern: Optional[FilterPattern] - metricTransformations: Optional[MetricTransformations] - creationTime: Optional[Timestamp] - logGroupName: Optional[LogGroupName] - applyOnTransformedLogs: Optional[ApplyOnTransformedLogs] - fieldSelectionCriteria: Optional[FieldSelectionCriteria] - emitSystemFieldDimensions: Optional[EmitSystemFields] + filterName: FilterName | None + filterPattern: FilterPattern | None + metricTransformations: MetricTransformations | None + creationTime: Timestamp | None + logGroupName: LogGroupName | None + applyOnTransformedLogs: ApplyOnTransformedLogs | None + fieldSelectionCriteria: FieldSelectionCriteria | None + emitSystemFieldDimensions: EmitSystemFields | None -MetricFilters = List[MetricFilter] +MetricFilters = list[MetricFilter] class DescribeMetricFiltersResponse(TypedDict, total=False): - metricFilters: Optional[MetricFilters] - nextToken: Optional[NextToken] + metricFilters: MetricFilters | None + nextToken: NextToken | None class DescribeQueriesRequest(ServiceRequest): - logGroupName: Optional[LogGroupName] - status: Optional[QueryStatus] - maxResults: Optional[DescribeQueriesMaxResults] - nextToken: Optional[NextToken] - queryLanguage: Optional[QueryLanguage] + logGroupName: LogGroupName | None + status: QueryStatus | None + maxResults: DescribeQueriesMaxResults | None + nextToken: NextToken | None + queryLanguage: QueryLanguage | None class QueryInfo(TypedDict, total=False): - queryLanguage: Optional[QueryLanguage] - queryId: Optional[QueryId] - queryString: Optional[QueryString] - status: Optional[QueryStatus] - createTime: Optional[Timestamp] - logGroupName: Optional[LogGroupName] + queryLanguage: QueryLanguage | None + queryId: QueryId | None + queryString: QueryString | None + status: QueryStatus | None + createTime: Timestamp | None + logGroupName: LogGroupName | None -QueryInfoList = List[QueryInfo] +QueryInfoList = list[QueryInfo] class DescribeQueriesResponse(TypedDict, total=False): - queries: Optional[QueryInfoList] - nextToken: Optional[NextToken] + queries: QueryInfoList | None + nextToken: NextToken | None class DescribeQueryDefinitionsRequest(ServiceRequest): - queryLanguage: Optional[QueryLanguage] - queryDefinitionNamePrefix: Optional[QueryDefinitionName] - maxResults: Optional[QueryListMaxResults] - nextToken: Optional[NextToken] + queryLanguage: QueryLanguage | None + queryDefinitionNamePrefix: QueryDefinitionName | None + maxResults: QueryListMaxResults | None + nextToken: NextToken | None -LogGroupNames = List[LogGroupName] +LogGroupNames = list[LogGroupName] class QueryDefinition(TypedDict, total=False): - queryLanguage: Optional[QueryLanguage] - queryDefinitionId: Optional[QueryId] - name: Optional[QueryDefinitionName] - queryString: Optional[QueryDefinitionString] - lastModified: Optional[Timestamp] - logGroupNames: Optional[LogGroupNames] + queryLanguage: QueryLanguage | None + queryDefinitionId: QueryId | None + name: QueryDefinitionName | None + queryString: QueryDefinitionString | None + lastModified: Timestamp | None + logGroupNames: LogGroupNames | None -QueryDefinitionList = List[QueryDefinition] +QueryDefinitionList = list[QueryDefinition] class DescribeQueryDefinitionsResponse(TypedDict, total=False): - queryDefinitions: Optional[QueryDefinitionList] - nextToken: Optional[NextToken] + queryDefinitions: QueryDefinitionList | None + nextToken: NextToken | None class DescribeResourcePoliciesRequest(ServiceRequest): - nextToken: Optional[NextToken] - limit: Optional[DescribeLimit] - resourceArn: Optional[Arn] - policyScope: Optional[PolicyScope] + nextToken: NextToken | None + limit: DescribeLimit | None + resourceArn: Arn | None + policyScope: PolicyScope | None class ResourcePolicy(TypedDict, total=False): - policyName: Optional[PolicyName] - policyDocument: Optional[PolicyDocument] - lastUpdatedTime: Optional[Timestamp] - policyScope: Optional[PolicyScope] - resourceArn: Optional[Arn] - revisionId: Optional[ExpectedRevisionId] + policyName: PolicyName | None + policyDocument: PolicyDocument | None + lastUpdatedTime: Timestamp | None + policyScope: PolicyScope | None + resourceArn: Arn | None + revisionId: ExpectedRevisionId | None -ResourcePolicies = List[ResourcePolicy] +ResourcePolicies = list[ResourcePolicy] class DescribeResourcePoliciesResponse(TypedDict, total=False): - resourcePolicies: Optional[ResourcePolicies] - nextToken: Optional[NextToken] + resourcePolicies: ResourcePolicies | None + nextToken: NextToken | None class DescribeSubscriptionFiltersRequest(ServiceRequest): logGroupName: LogGroupName - filterNamePrefix: Optional[FilterName] - nextToken: Optional[NextToken] - limit: Optional[DescribeLimit] + filterNamePrefix: FilterName | None + nextToken: NextToken | None + limit: DescribeLimit | None class SubscriptionFilter(TypedDict, total=False): - filterName: Optional[FilterName] - logGroupName: Optional[LogGroupName] - filterPattern: Optional[FilterPattern] - destinationArn: Optional[DestinationArn] - roleArn: Optional[RoleArn] - distribution: Optional[Distribution] - applyOnTransformedLogs: Optional[ApplyOnTransformedLogs] - creationTime: Optional[Timestamp] - fieldSelectionCriteria: Optional[FieldSelectionCriteria] - emitSystemFields: Optional[EmitSystemFields] + filterName: FilterName | None + logGroupName: LogGroupName | None + filterPattern: FilterPattern | None + destinationArn: DestinationArn | None + roleArn: RoleArn | None + distribution: Distribution | None + applyOnTransformedLogs: ApplyOnTransformedLogs | None + creationTime: Timestamp | None + fieldSelectionCriteria: FieldSelectionCriteria | None + emitSystemFields: EmitSystemFields | None -SubscriptionFilters = List[SubscriptionFilter] +SubscriptionFilters = list[SubscriptionFilter] class DescribeSubscriptionFiltersResponse(TypedDict, total=False): - subscriptionFilters: Optional[SubscriptionFilters] - nextToken: Optional[NextToken] + subscriptionFilters: SubscriptionFilters | None + nextToken: NextToken | None class DisassociateKmsKeyRequest(ServiceRequest): - logGroupName: Optional[LogGroupName] - resourceIdentifier: Optional[ResourceIdentifier] + logGroupName: LogGroupName | None + resourceIdentifier: ResourceIdentifier | None -EntityAttributes = Dict[EntityAttributesKey, EntityAttributesValue] -EntityKeyAttributes = Dict[EntityKeyAttributesKey, EntityKeyAttributesValue] +class DisassociateSourceFromS3TableIntegrationRequest(ServiceRequest): + identifier: S3TableIntegrationSourceIdentifier + + +class DisassociateSourceFromS3TableIntegrationResponse(TypedDict, total=False): + identifier: S3TableIntegrationSourceIdentifier | None + + +EntityAttributes = dict[EntityAttributesKey, EntityAttributesValue] +EntityKeyAttributes = dict[EntityKeyAttributesKey, EntityKeyAttributesValue] class Entity(TypedDict, total=False): - keyAttributes: Optional[EntityKeyAttributes] - attributes: Optional[EntityAttributes] + keyAttributes: EntityKeyAttributes | None + attributes: EntityAttributes | None EventNumber = int -ExtractedValues = Dict[Token, Value] +ExecutionStatusList = list[ExecutionStatus] +ExtractedValues = dict[Token, Value] +FieldIndexNames = list[FieldIndexName] class FieldsData(TypedDict, total=False): - data: Optional[Data] + data: Data | None -InputLogStreamNames = List[LogStreamName] +InputLogStreamNames = list[LogStreamName] class FilterLogEventsRequest(ServiceRequest): - logGroupName: Optional[LogGroupName] - logGroupIdentifier: Optional[LogGroupIdentifier] - logStreamNames: Optional[InputLogStreamNames] - logStreamNamePrefix: Optional[LogStreamName] - startTime: Optional[Timestamp] - endTime: Optional[Timestamp] - filterPattern: Optional[FilterPattern] - nextToken: Optional[NextToken] - limit: Optional[EventsLimit] - interleaved: Optional[Interleaved] - unmask: Optional[Unmask] + logGroupName: LogGroupName | None + logGroupIdentifier: LogGroupIdentifier | None + logStreamNames: InputLogStreamNames | None + logStreamNamePrefix: LogStreamName | None + startTime: Timestamp | None + endTime: Timestamp | None + filterPattern: FilterPattern | None + nextToken: NextToken | None + limit: EventsLimit | None + interleaved: Interleaved | None + unmask: Unmask | None class SearchedLogStream(TypedDict, total=False): - logStreamName: Optional[LogStreamName] - searchedCompletely: Optional[LogStreamSearchedCompletely] + logStreamName: LogStreamName | None + searchedCompletely: LogStreamSearchedCompletely | None -SearchedLogStreams = List[SearchedLogStream] +SearchedLogStreams = list[SearchedLogStream] class FilteredLogEvent(TypedDict, total=False): - logStreamName: Optional[LogStreamName] - timestamp: Optional[Timestamp] - message: Optional[EventMessage] - ingestionTime: Optional[Timestamp] - eventId: Optional[EventId] + logStreamName: LogStreamName | None + timestamp: Timestamp | None + message: EventMessage | None + ingestionTime: Timestamp | None + eventId: EventId | None -FilteredLogEvents = List[FilteredLogEvent] +FilteredLogEvents = list[FilteredLogEvent] class FilterLogEventsResponse(TypedDict, total=False): - events: Optional[FilteredLogEvents] - searchedLogStreams: Optional[SearchedLogStreams] - nextToken: Optional[NextToken] + events: FilteredLogEvents | None + searchedLogStreams: SearchedLogStreams | None + nextToken: NextToken | None class GetDataProtectionPolicyRequest(ServiceRequest): @@ -1349,9 +1611,9 @@ class GetDataProtectionPolicyRequest(ServiceRequest): class GetDataProtectionPolicyResponse(TypedDict, total=False): - logGroupIdentifier: Optional[LogGroupIdentifier] - policyDocument: Optional[DataProtectionPolicyDocument] - lastUpdatedTime: Optional[Timestamp] + logGroupIdentifier: LogGroupIdentifier | None + policyDocument: DataProtectionPolicyDocument | None + lastUpdatedTime: Timestamp | None class GetDeliveryDestinationPolicyRequest(ServiceRequest): @@ -1359,11 +1621,11 @@ class GetDeliveryDestinationPolicyRequest(ServiceRequest): class Policy(TypedDict, total=False): - deliveryDestinationPolicy: Optional[DeliveryDestinationPolicy] + deliveryDestinationPolicy: DeliveryDestinationPolicy | None class GetDeliveryDestinationPolicyResponse(TypedDict, total=False): - policy: Optional[Policy] + policy: Policy | None class GetDeliveryDestinationRequest(ServiceRequest): @@ -1371,7 +1633,7 @@ class GetDeliveryDestinationRequest(ServiceRequest): class GetDeliveryDestinationResponse(TypedDict, total=False): - deliveryDestination: Optional[DeliveryDestination] + deliveryDestination: DeliveryDestination | None class GetDeliveryRequest(ServiceRequest): @@ -1379,7 +1641,7 @@ class GetDeliveryRequest(ServiceRequest): class GetDeliveryResponse(TypedDict, total=False): - delivery: Optional[Delivery] + delivery: Delivery | None class GetDeliverySourceRequest(ServiceRequest): @@ -1387,7 +1649,7 @@ class GetDeliverySourceRequest(ServiceRequest): class GetDeliverySourceResponse(TypedDict, total=False): - deliverySource: Optional[DeliverySource] + deliverySource: DeliverySource | None class GetIntegrationRequest(ServiceRequest): @@ -1395,73 +1657,73 @@ class GetIntegrationRequest(ServiceRequest): class OpenSearchResourceStatus(TypedDict, total=False): - status: Optional[OpenSearchResourceStatusType] - statusMessage: Optional[IntegrationStatusMessage] + status: OpenSearchResourceStatusType | None + statusMessage: IntegrationStatusMessage | None class OpenSearchLifecyclePolicy(TypedDict, total=False): - policyName: Optional[OpenSearchPolicyName] - status: Optional[OpenSearchResourceStatus] + policyName: OpenSearchPolicyName | None + status: OpenSearchResourceStatus | None class OpenSearchDataAccessPolicy(TypedDict, total=False): - policyName: Optional[OpenSearchPolicyName] - status: Optional[OpenSearchResourceStatus] + policyName: OpenSearchPolicyName | None + status: OpenSearchResourceStatus | None class OpenSearchNetworkPolicy(TypedDict, total=False): - policyName: Optional[OpenSearchPolicyName] - status: Optional[OpenSearchResourceStatus] + policyName: OpenSearchPolicyName | None + status: OpenSearchResourceStatus | None class OpenSearchEncryptionPolicy(TypedDict, total=False): - policyName: Optional[OpenSearchPolicyName] - status: Optional[OpenSearchResourceStatus] + policyName: OpenSearchPolicyName | None + status: OpenSearchResourceStatus | None class OpenSearchWorkspace(TypedDict, total=False): - workspaceId: Optional[OpenSearchWorkspaceId] - status: Optional[OpenSearchResourceStatus] + workspaceId: OpenSearchWorkspaceId | None + status: OpenSearchResourceStatus | None class OpenSearchCollection(TypedDict, total=False): - collectionEndpoint: Optional[OpenSearchCollectionEndpoint] - collectionArn: Optional[Arn] - status: Optional[OpenSearchResourceStatus] + collectionEndpoint: OpenSearchCollectionEndpoint | None + collectionArn: Arn | None + status: OpenSearchResourceStatus | None class OpenSearchApplication(TypedDict, total=False): - applicationEndpoint: Optional[OpenSearchApplicationEndpoint] - applicationArn: Optional[Arn] - applicationId: Optional[OpenSearchApplicationId] - status: Optional[OpenSearchResourceStatus] + applicationEndpoint: OpenSearchApplicationEndpoint | None + applicationArn: Arn | None + applicationId: OpenSearchApplicationId | None + status: OpenSearchResourceStatus | None class OpenSearchDataSource(TypedDict, total=False): - dataSourceName: Optional[OpenSearchDataSourceName] - status: Optional[OpenSearchResourceStatus] + dataSourceName: OpenSearchDataSourceName | None + status: OpenSearchResourceStatus | None class OpenSearchIntegrationDetails(TypedDict, total=False): - dataSource: Optional[OpenSearchDataSource] - application: Optional[OpenSearchApplication] - collection: Optional[OpenSearchCollection] - workspace: Optional[OpenSearchWorkspace] - encryptionPolicy: Optional[OpenSearchEncryptionPolicy] - networkPolicy: Optional[OpenSearchNetworkPolicy] - accessPolicy: Optional[OpenSearchDataAccessPolicy] - lifecyclePolicy: Optional[OpenSearchLifecyclePolicy] + dataSource: OpenSearchDataSource | None + application: OpenSearchApplication | None + collection: OpenSearchCollection | None + workspace: OpenSearchWorkspace | None + encryptionPolicy: OpenSearchEncryptionPolicy | None + networkPolicy: OpenSearchNetworkPolicy | None + accessPolicy: OpenSearchDataAccessPolicy | None + lifecyclePolicy: OpenSearchLifecyclePolicy | None class IntegrationDetails(TypedDict, total=False): - openSearchIntegrationDetails: Optional[OpenSearchIntegrationDetails] + openSearchIntegrationDetails: OpenSearchIntegrationDetails | None class GetIntegrationResponse(TypedDict, total=False): - integrationName: Optional[IntegrationName] - integrationType: Optional[IntegrationType] - integrationStatus: Optional[IntegrationStatus] - integrationDetails: Optional[IntegrationDetails] + integrationName: IntegrationName | None + integrationType: IntegrationType | None + integrationStatus: IntegrationStatus | None + integrationDetails: IntegrationDetails | None class GetLogAnomalyDetectorRequest(ServiceRequest): @@ -1469,70 +1731,93 @@ class GetLogAnomalyDetectorRequest(ServiceRequest): class GetLogAnomalyDetectorResponse(TypedDict, total=False): - detectorName: Optional[DetectorName] - logGroupArnList: Optional[LogGroupArnList] - evaluationFrequency: Optional[EvaluationFrequency] - filterPattern: Optional[FilterPattern] - anomalyDetectorStatus: Optional[AnomalyDetectorStatus] - kmsKeyId: Optional[KmsKeyId] - creationTimeStamp: Optional[EpochMillis] - lastModifiedTimeStamp: Optional[EpochMillis] - anomalyVisibilityTime: Optional[AnomalyVisibilityTime] + detectorName: DetectorName | None + logGroupArnList: LogGroupArnList | None + evaluationFrequency: EvaluationFrequency | None + filterPattern: FilterPattern | None + anomalyDetectorStatus: AnomalyDetectorStatus | None + kmsKeyId: KmsKeyId | None + creationTimeStamp: EpochMillis | None + lastModifiedTimeStamp: EpochMillis | None + anomalyVisibilityTime: AnomalyVisibilityTime | None class GetLogEventsRequest(ServiceRequest): - logGroupName: Optional[LogGroupName] - logGroupIdentifier: Optional[LogGroupIdentifier] + logGroupName: LogGroupName | None + logGroupIdentifier: LogGroupIdentifier | None logStreamName: LogStreamName - startTime: Optional[Timestamp] - endTime: Optional[Timestamp] - nextToken: Optional[NextToken] - limit: Optional[EventsLimit] - startFromHead: Optional[StartFromHead] - unmask: Optional[Unmask] + startTime: Timestamp | None + endTime: Timestamp | None + nextToken: NextToken | None + limit: EventsLimit | None + startFromHead: StartFromHead | None + unmask: Unmask | None class OutputLogEvent(TypedDict, total=False): - timestamp: Optional[Timestamp] - message: Optional[EventMessage] - ingestionTime: Optional[Timestamp] + timestamp: Timestamp | None + message: EventMessage | None + ingestionTime: Timestamp | None -OutputLogEvents = List[OutputLogEvent] +OutputLogEvents = list[OutputLogEvent] class GetLogEventsResponse(TypedDict, total=False): - events: Optional[OutputLogEvents] - nextForwardToken: Optional[NextToken] - nextBackwardToken: Optional[NextToken] + events: OutputLogEvents | None + nextForwardToken: NextToken | None + nextBackwardToken: NextToken | None + + +class GetLogFieldsRequest(ServiceRequest): + dataSourceName: DataSourceName + dataSourceType: DataSourceType + + +LogFieldsList = list["LogFieldsListItem"] + + +class LogFieldType(TypedDict, total=False): + type: "DataType | None" + element: "LogFieldType | None" + fields: "LogFieldsList | None" + + +class LogFieldsListItem(TypedDict, total=False): + logFieldName: LogFieldName | None + logFieldType: LogFieldType | None + + +class GetLogFieldsResponse(TypedDict, total=False): + logFields: LogFieldsList | None class GetLogGroupFieldsRequest(ServiceRequest): - logGroupName: Optional[LogGroupName] - time: Optional[Timestamp] - logGroupIdentifier: Optional[LogGroupIdentifier] + logGroupName: LogGroupName | None + time: Timestamp | None + logGroupIdentifier: LogGroupIdentifier | None class LogGroupField(TypedDict, total=False): - name: Optional[Field] - percent: Optional[Percentage] + name: Field | None + percent: Percentage | None -LogGroupFieldList = List[LogGroupField] +LogGroupFieldList = list[LogGroupField] class GetLogGroupFieldsResponse(TypedDict, total=False): - logGroupFields: Optional[LogGroupFieldList] + logGroupFields: LogGroupFieldList | None class GetLogObjectRequest(ServiceRequest): - unmask: Optional[Unmask] + unmask: Unmask | None logObjectPointer: LogObjectPointer class GetLogObjectResponseStream(TypedDict, total=False): - fields: Optional[FieldsData] - InternalStreamingException: Optional[InternalStreamingException] + fields: FieldsData | None + InternalStreamingException: InternalStreamingException | None class GetLogObjectResponse(TypedDict, total=False): @@ -1541,14 +1826,14 @@ class GetLogObjectResponse(TypedDict, total=False): class GetLogRecordRequest(ServiceRequest): logRecordPointer: LogRecordPointer - unmask: Optional[Unmask] + unmask: Unmask | None -LogRecord = Dict[Field, Value] +LogRecord = dict[Field, Value] class GetLogRecordResponse(TypedDict, total=False): - logRecord: Optional[LogRecord] + logRecord: LogRecord | None class GetQueryResultsRequest(ServiceRequest): @@ -1556,36 +1841,99 @@ class GetQueryResultsRequest(ServiceRequest): class QueryStatistics(TypedDict, total=False): - recordsMatched: Optional[StatsValue] - recordsScanned: Optional[StatsValue] - estimatedRecordsSkipped: Optional[StatsValue] - bytesScanned: Optional[StatsValue] - estimatedBytesSkipped: Optional[StatsValue] - logGroupsScanned: Optional[StatsValue] + recordsMatched: StatsValue | None + recordsScanned: StatsValue | None + estimatedRecordsSkipped: StatsValue | None + bytesScanned: StatsValue | None + estimatedBytesSkipped: StatsValue | None + logGroupsScanned: StatsValue | None class ResultField(TypedDict, total=False): - field: Optional[Field] - value: Optional[Value] + field: Field | None + value: Value | None -ResultRows = List[ResultField] -QueryResults = List[ResultRows] +ResultRows = list[ResultField] +QueryResults = list[ResultRows] class GetQueryResultsResponse(TypedDict, total=False): - queryLanguage: Optional[QueryLanguage] - results: Optional[QueryResults] - statistics: Optional[QueryStatistics] - status: Optional[QueryStatus] - encryptionKey: Optional[EncryptionKey] + queryLanguage: QueryLanguage | None + results: QueryResults | None + statistics: QueryStatistics | None + status: QueryStatus | None + encryptionKey: EncryptionKey | None + + +class GetScheduledQueryHistoryRequest(ServiceRequest): + identifier: ScheduledQueryIdentifier + startTime: Timestamp + endTime: Timestamp + executionStatuses: ExecutionStatusList | None + maxResults: GetScheduledQueryHistoryMaxResults | None + nextToken: NextToken | None + + +class ScheduledQueryDestination(TypedDict, total=False): + destinationType: ScheduledQueryDestinationType | None + destinationIdentifier: String | None + status: ActionStatus | None + processedIdentifier: String | None + errorMessage: String | None + + +ScheduledQueryDestinationList = list[ScheduledQueryDestination] + + +class TriggerHistoryRecord(TypedDict, total=False): + queryId: QueryId | None + executionStatus: ExecutionStatus | None + triggeredTimestamp: Timestamp | None + errorMessage: String | None + destinations: ScheduledQueryDestinationList | None + + +TriggerHistoryRecordList = list[TriggerHistoryRecord] + + +class GetScheduledQueryHistoryResponse(TypedDict, total=False): + name: ScheduledQueryName | None + scheduledQueryArn: Arn | None + triggerHistory: TriggerHistoryRecordList | None + nextToken: NextToken | None + + +class GetScheduledQueryRequest(ServiceRequest): + identifier: ScheduledQueryIdentifier + + +class GetScheduledQueryResponse(TypedDict, total=False): + scheduledQueryArn: Arn | None + name: ScheduledQueryName | None + description: ScheduledQueryDescription | None + queryLanguage: QueryLanguage | None + queryString: QueryString | None + logGroupIdentifiers: ScheduledQueryLogGroupIdentifiers | None + scheduleExpression: ScheduleExpression | None + timezone: ScheduleTimezone | None + startTimeOffset: StartTimeOffset | None + destinationConfiguration: DestinationConfiguration | None + state: ScheduledQueryState | None + lastTriggeredTime: Timestamp | None + lastExecutionStatus: ExecutionStatus | None + scheduleStartTime: Timestamp | None + scheduleEndTime: Timestamp | None + executionRoleArn: RoleArn | None + creationTime: Timestamp | None + lastUpdatedTime: Timestamp | None class GetTransformerRequest(ServiceRequest): logGroupIdentifier: LogGroupIdentifier -UpperCaseStringWithKeys = List[WithKey] +UpperCaseStringWithKeys = list[WithKey] class UpperCaseString(TypedDict, total=False): @@ -1597,14 +1945,14 @@ class TypeConverterEntry(TypedDict, total=False): type: Type -TypeConverterEntries = List[TypeConverterEntry] +TypeConverterEntries = list[TypeConverterEntry] class TypeConverter(TypedDict, total=False): entries: TypeConverterEntries -TrimStringWithKeys = List[WithKey] +TrimStringWithKeys = list[WithKey] class TrimString(TypedDict, total=False): @@ -1620,7 +1968,7 @@ class TrimString(TypedDict, total=False): }, total=False, ) -SubstituteStringEntries = List[SubstituteStringEntry] +SubstituteStringEntries = list[SubstituteStringEntry] class SubstituteString(TypedDict, total=False): @@ -1632,7 +1980,7 @@ class SplitStringEntry(TypedDict, total=False): delimiter: SplitStringDelimiter -SplitStringEntries = List[SplitStringEntry] +SplitStringEntries = list[SplitStringEntry] class SplitString(TypedDict, total=False): @@ -1642,10 +1990,10 @@ class SplitString(TypedDict, total=False): class RenameKeyEntry(TypedDict, total=False): key: Key renameTo: RenameTo - overwriteIfExists: Optional[OverwriteIfExists] + overwriteIfExists: OverwriteIfExists | None -RenameKeyEntries = List[RenameKeyEntry] +RenameKeyEntries = list[RenameKeyEntry] class RenameKeys(TypedDict, total=False): @@ -1653,60 +2001,61 @@ class RenameKeys(TypedDict, total=False): class ParseWAF(TypedDict, total=False): - source: Optional[Source] + source: Source | None class ParseVPC(TypedDict, total=False): - source: Optional[Source] + source: Source | None class ParsePostgres(TypedDict, total=False): - source: Optional[Source] + source: Source | None class ParseToOCSF(TypedDict, total=False): - source: Optional[Source] + source: Source | None eventSource: EventSource ocsfVersion: OCSFVersion + mappingVersion: MappingVersion | None class ParseRoute53(TypedDict, total=False): - source: Optional[Source] + source: Source | None class ParseKeyValue(TypedDict, total=False): - source: Optional[Source] - destination: Optional[DestinationField] - fieldDelimiter: Optional[ParserFieldDelimiter] - keyValueDelimiter: Optional[KeyValueDelimiter] - keyPrefix: Optional[KeyPrefix] - nonMatchValue: Optional[NonMatchValue] - overwriteIfExists: Optional[OverwriteIfExists] + source: Source | None + destination: DestinationField | None + fieldDelimiter: ParserFieldDelimiter | None + keyValueDelimiter: KeyValueDelimiter | None + keyPrefix: KeyPrefix | None + nonMatchValue: NonMatchValue | None + overwriteIfExists: OverwriteIfExists | None class ParseJSON(TypedDict, total=False): - source: Optional[Source] - destination: Optional[DestinationField] + source: Source | None + destination: DestinationField | None class ParseCloudfront(TypedDict, total=False): - source: Optional[Source] + source: Source | None class MoveKeyEntry(TypedDict, total=False): source: Source target: Target - overwriteIfExists: Optional[OverwriteIfExists] + overwriteIfExists: OverwriteIfExists | None -MoveKeyEntries = List[MoveKeyEntry] +MoveKeyEntries = list[MoveKeyEntry] class MoveKeys(TypedDict, total=False): entries: MoveKeyEntries -LowerCaseStringWithKeys = List[WithKey] +LowerCaseStringWithKeys = list[WithKey] class LowerCaseString(TypedDict, total=False): @@ -1716,51 +2065,51 @@ class LowerCaseString(TypedDict, total=False): class ListToMap(TypedDict, total=False): source: Source key: Key - valueKey: Optional[ValueKey] - target: Optional[Target] - flatten: Optional[Flatten] - flattenedElement: Optional[FlattenedElement] + valueKey: ValueKey | None + target: Target | None + flatten: Flatten | None + flattenedElement: FlattenedElement | None class Grok(TypedDict, total=False): - source: Optional[Source] + source: Source | None match: GrokMatch class Processor(TypedDict, total=False): - addKeys: Optional[AddKeys] - copyValue: Optional[CopyValue] - csv: Optional[CSV] - dateTimeConverter: Optional[DateTimeConverter] - deleteKeys: Optional[DeleteKeys] - grok: Optional[Grok] - listToMap: Optional[ListToMap] - lowerCaseString: Optional[LowerCaseString] - moveKeys: Optional[MoveKeys] - parseCloudfront: Optional[ParseCloudfront] - parseJSON: Optional[ParseJSON] - parseKeyValue: Optional[ParseKeyValue] - parseRoute53: Optional[ParseRoute53] - parseToOCSF: Optional[ParseToOCSF] - parsePostgres: Optional[ParsePostgres] - parseVPC: Optional[ParseVPC] - parseWAF: Optional[ParseWAF] - renameKeys: Optional[RenameKeys] - splitString: Optional[SplitString] - substituteString: Optional[SubstituteString] - trimString: Optional[TrimString] - typeConverter: Optional[TypeConverter] - upperCaseString: Optional[UpperCaseString] - - -Processors = List[Processor] + addKeys: AddKeys | None + copyValue: CopyValue | None + csv: CSV | None + dateTimeConverter: DateTimeConverter | None + deleteKeys: DeleteKeys | None + grok: Grok | None + listToMap: ListToMap | None + lowerCaseString: LowerCaseString | None + moveKeys: MoveKeys | None + parseCloudfront: ParseCloudfront | None + parseJSON: ParseJSON | None + parseKeyValue: ParseKeyValue | None + parseRoute53: ParseRoute53 | None + parseToOCSF: ParseToOCSF | None + parsePostgres: ParsePostgres | None + parseVPC: ParseVPC | None + parseWAF: ParseWAF | None + renameKeys: RenameKeys | None + splitString: SplitString | None + substituteString: SubstituteString | None + trimString: TrimString | None + typeConverter: TypeConverter | None + upperCaseString: UpperCaseString | None + + +Processors = list[Processor] class GetTransformerResponse(TypedDict, total=False): - logGroupIdentifier: Optional[LogGroupIdentifier] - creationTime: Optional[Timestamp] - lastModifiedTime: Optional[Timestamp] - transformerConfig: Optional[Processors] + logGroupIdentifier: LogGroupIdentifier | None + creationTime: Timestamp | None + lastModifiedTime: Timestamp | None + transformerConfig: Processors | None class InputLogEvent(TypedDict, total=False): @@ -1768,86 +2117,153 @@ class InputLogEvent(TypedDict, total=False): message: EventMessage -InputLogEvents = List[InputLogEvent] +InputLogEvents = list[InputLogEvent] class IntegrationSummary(TypedDict, total=False): - integrationName: Optional[IntegrationName] - integrationType: Optional[IntegrationType] - integrationStatus: Optional[IntegrationStatus] + integrationName: IntegrationName | None + integrationType: IntegrationType | None + integrationStatus: IntegrationStatus | None + + +IntegrationSummaries = list[IntegrationSummary] -IntegrationSummaries = List[IntegrationSummary] +class ListAggregateLogGroupSummariesRequest(ServiceRequest): + accountIdentifiers: AccountIds | None + includeLinkedAccounts: IncludeLinkedAccounts | None + logGroupClass: LogGroupClass | None + logGroupNamePattern: LogGroupNameRegexPattern | None + dataSources: DataSourceFilters | None + groupBy: ListAggregateLogGroupSummariesGroupBy + nextToken: NextToken | None + limit: ListLogGroupsRequestLimit | None + + +class ListAggregateLogGroupSummariesResponse(TypedDict, total=False): + aggregateLogGroupSummaries: AggregateLogGroupSummaries | None + nextToken: NextToken | None class ListAnomaliesRequest(ServiceRequest): - anomalyDetectorArn: Optional[AnomalyDetectorArn] - suppressionState: Optional[SuppressionState] - limit: Optional[ListAnomaliesLimit] - nextToken: Optional[NextToken] + anomalyDetectorArn: AnomalyDetectorArn | None + suppressionState: SuppressionState | None + limit: ListAnomaliesLimit | None + nextToken: NextToken | None class ListAnomaliesResponse(TypedDict, total=False): - anomalies: Optional[Anomalies] - nextToken: Optional[NextToken] + anomalies: Anomalies | None + nextToken: NextToken | None class ListIntegrationsRequest(ServiceRequest): - integrationNamePrefix: Optional[IntegrationNamePrefix] - integrationType: Optional[IntegrationType] - integrationStatus: Optional[IntegrationStatus] + integrationNamePrefix: IntegrationNamePrefix | None + integrationType: IntegrationType | None + integrationStatus: IntegrationStatus | None class ListIntegrationsResponse(TypedDict, total=False): - integrationSummaries: Optional[IntegrationSummaries] + integrationSummaries: IntegrationSummaries | None class ListLogAnomalyDetectorsRequest(ServiceRequest): - filterLogGroupArn: Optional[LogGroupArn] - limit: Optional[ListLogAnomalyDetectorsLimit] - nextToken: Optional[NextToken] + filterLogGroupArn: LogGroupArn | None + limit: ListLogAnomalyDetectorsLimit | None + nextToken: NextToken | None class ListLogAnomalyDetectorsResponse(TypedDict, total=False): - anomalyDetectors: Optional[AnomalyDetectors] - nextToken: Optional[NextToken] + anomalyDetectors: AnomalyDetectors | None + nextToken: NextToken | None class ListLogGroupsForQueryRequest(ServiceRequest): queryId: QueryId - nextToken: Optional[NextToken] - maxResults: Optional[ListLogGroupsForQueryMaxResults] + nextToken: NextToken | None + maxResults: ListLogGroupsForQueryMaxResults | None -LogGroupIdentifiers = List[LogGroupIdentifier] +LogGroupIdentifiers = list[LogGroupIdentifier] class ListLogGroupsForQueryResponse(TypedDict, total=False): - logGroupIdentifiers: Optional[LogGroupIdentifiers] - nextToken: Optional[NextToken] + logGroupIdentifiers: LogGroupIdentifiers | None + nextToken: NextToken | None class ListLogGroupsRequest(ServiceRequest): - logGroupNamePattern: Optional[LogGroupNameRegexPattern] - logGroupClass: Optional[LogGroupClass] - includeLinkedAccounts: Optional[IncludeLinkedAccounts] - accountIdentifiers: Optional[AccountIds] - nextToken: Optional[NextToken] - limit: Optional[ListLimit] + logGroupNamePattern: LogGroupNameRegexPattern | None + logGroupClass: LogGroupClass | None + includeLinkedAccounts: IncludeLinkedAccounts | None + accountIdentifiers: AccountIds | None + nextToken: NextToken | None + limit: ListLimit | None + dataSources: DataSourceFilters | None + fieldIndexNames: FieldIndexNames | None class LogGroupSummary(TypedDict, total=False): - logGroupName: Optional[LogGroupName] - logGroupArn: Optional[Arn] - logGroupClass: Optional[LogGroupClass] + logGroupName: LogGroupName | None + logGroupArn: Arn | None + logGroupClass: LogGroupClass | None -LogGroupSummaries = List[LogGroupSummary] +LogGroupSummaries = list[LogGroupSummary] class ListLogGroupsResponse(TypedDict, total=False): - logGroups: Optional[LogGroupSummaries] - nextToken: Optional[NextToken] + logGroups: LogGroupSummaries | None + nextToken: NextToken | None + + +class ListScheduledQueriesRequest(ServiceRequest): + maxResults: ListScheduledQueriesMaxResults | None + nextToken: NextToken | None + state: ScheduledQueryState | None + + +class ScheduledQuerySummary(TypedDict, total=False): + scheduledQueryArn: Arn | None + name: ScheduledQueryName | None + state: ScheduledQueryState | None + lastTriggeredTime: Timestamp | None + lastExecutionStatus: ExecutionStatus | None + scheduleExpression: ScheduleExpression | None + timezone: ScheduleTimezone | None + destinationConfiguration: DestinationConfiguration | None + creationTime: Timestamp | None + lastUpdatedTime: Timestamp | None + + +ScheduledQuerySummaryList = list[ScheduledQuerySummary] + + +class ListScheduledQueriesResponse(TypedDict, total=False): + nextToken: NextToken | None + scheduledQueries: ScheduledQuerySummaryList | None + + +class ListSourcesForS3TableIntegrationRequest(ServiceRequest): + integrationArn: Arn + maxResults: ListSourcesForS3TableIntegrationMaxResults | None + nextToken: NextToken | None + + +class S3TableIntegrationSource(TypedDict, total=False): + identifier: S3TableIntegrationSourceIdentifier | None + dataSource: DataSource | None + status: S3TableIntegrationSourceStatus | None + statusReason: S3TableIntegrationSourceStatusReason | None + createdTimeStamp: Timestamp | None + + +S3TableIntegrationSources = list[S3TableIntegrationSource] + + +class ListSourcesForS3TableIntegrationResponse(TypedDict, total=False): + sources: S3TableIntegrationSources | None + nextToken: NextToken | None class ListTagsForResourceRequest(ServiceRequest): @@ -1855,7 +2271,7 @@ class ListTagsForResourceRequest(ServiceRequest): class ListTagsForResourceResponse(TypedDict, total=False): - tags: Optional[Tags] + tags: Tags | None class ListTagsLogGroupRequest(ServiceRequest): @@ -1863,53 +2279,53 @@ class ListTagsLogGroupRequest(ServiceRequest): class ListTagsLogGroupResponse(TypedDict, total=False): - tags: Optional[Tags] + tags: Tags | None class LiveTailSessionLogEvent(TypedDict, total=False): - logStreamName: Optional[LogStreamName] - logGroupIdentifier: Optional[LogGroupIdentifier] - message: Optional[EventMessage] - timestamp: Optional[Timestamp] - ingestionTime: Optional[Timestamp] + logStreamName: LogStreamName | None + logGroupIdentifier: LogGroupIdentifier | None + message: EventMessage | None + timestamp: Timestamp | None + ingestionTime: Timestamp | None class LiveTailSessionMetadata(TypedDict, total=False): - sampled: Optional[IsSampled] + sampled: IsSampled | None -LiveTailSessionResults = List[LiveTailSessionLogEvent] -StartLiveTailLogGroupIdentifiers = List[LogGroupIdentifier] +LiveTailSessionResults = list[LiveTailSessionLogEvent] +StartLiveTailLogGroupIdentifiers = list[LogGroupIdentifier] class LiveTailSessionStart(TypedDict, total=False): - requestId: Optional[RequestId] - sessionId: Optional[SessionId] - logGroupIdentifiers: Optional[StartLiveTailLogGroupIdentifiers] - logStreamNames: Optional[InputLogStreamNames] - logStreamNamePrefixes: Optional[InputLogStreamNames] - logEventFilterPattern: Optional[FilterPattern] + requestId: RequestId | None + sessionId: SessionId | None + logGroupIdentifiers: StartLiveTailLogGroupIdentifiers | None + logStreamNames: InputLogStreamNames | None + logStreamNamePrefixes: InputLogStreamNames | None + logEventFilterPattern: FilterPattern | None class LiveTailSessionUpdate(TypedDict, total=False): - sessionMetadata: Optional[LiveTailSessionMetadata] - sessionResults: Optional[LiveTailSessionResults] + sessionMetadata: LiveTailSessionMetadata | None + sessionResults: LiveTailSessionResults | None class MetricFilterMatchRecord(TypedDict, total=False): - eventNumber: Optional[EventNumber] - eventMessage: Optional[EventMessage] - extractedValues: Optional[ExtractedValues] + eventNumber: EventNumber | None + eventMessage: EventMessage | None + extractedValues: ExtractedValues | None -MetricFilterMatches = List[MetricFilterMatchRecord] +MetricFilterMatches = list[MetricFilterMatchRecord] class OpenSearchResourceConfig(TypedDict, total=False): - kmsKeyArn: Optional[Arn] + kmsKeyArn: Arn | None dataSourceRoleArn: Arn dashboardViewerPrincipals: DashboardViewerPrincipals - applicationArn: Optional[Arn] + applicationArn: Arn | None retentionDays: CollectionRetentionDays @@ -1917,12 +2333,12 @@ class PutAccountPolicyRequest(ServiceRequest): policyName: PolicyName policyDocument: AccountPolicyDocument policyType: PolicyType - scope: Optional[Scope] - selectionCriteria: Optional[SelectionCriteria] + scope: Scope | None + selectionCriteria: SelectionCriteria | None class PutAccountPolicyResponse(TypedDict, total=False): - accountPolicy: Optional[AccountPolicy] + accountPolicy: AccountPolicy | None class PutDataProtectionPolicyRequest(ServiceRequest): @@ -1931,9 +2347,9 @@ class PutDataProtectionPolicyRequest(ServiceRequest): class PutDataProtectionPolicyResponse(TypedDict, total=False): - logGroupIdentifier: Optional[LogGroupIdentifier] - policyDocument: Optional[DataProtectionPolicyDocument] - lastUpdatedTime: Optional[Timestamp] + logGroupIdentifier: LogGroupIdentifier | None + policyDocument: DataProtectionPolicyDocument | None + lastUpdatedTime: Timestamp | None class PutDeliveryDestinationPolicyRequest(ServiceRequest): @@ -1942,47 +2358,47 @@ class PutDeliveryDestinationPolicyRequest(ServiceRequest): class PutDeliveryDestinationPolicyResponse(TypedDict, total=False): - policy: Optional[Policy] + policy: Policy | None class PutDeliveryDestinationRequest(ServiceRequest): name: DeliveryDestinationName - outputFormat: Optional[OutputFormat] - deliveryDestinationConfiguration: Optional[DeliveryDestinationConfiguration] - deliveryDestinationType: Optional[DeliveryDestinationType] - tags: Optional[Tags] + outputFormat: OutputFormat | None + deliveryDestinationConfiguration: DeliveryDestinationConfiguration | None + deliveryDestinationType: DeliveryDestinationType | None + tags: Tags | None class PutDeliveryDestinationResponse(TypedDict, total=False): - deliveryDestination: Optional[DeliveryDestination] + deliveryDestination: DeliveryDestination | None class PutDeliverySourceRequest(ServiceRequest): name: DeliverySourceName resourceArn: Arn logType: LogType - tags: Optional[Tags] + tags: Tags | None class PutDeliverySourceResponse(TypedDict, total=False): - deliverySource: Optional[DeliverySource] + deliverySource: DeliverySource | None class PutDestinationPolicyRequest(ServiceRequest): destinationName: DestinationName accessPolicy: AccessPolicy - forceUpdate: Optional[ForceUpdate] + forceUpdate: ForceUpdate | None class PutDestinationRequest(ServiceRequest): destinationName: DestinationName targetArn: TargetArn roleArn: RoleArn - tags: Optional[Tags] + tags: Tags | None class PutDestinationResponse(TypedDict, total=False): - destination: Optional[Destination] + destination: Destination | None class PutIndexPolicyRequest(ServiceRequest): @@ -1991,11 +2407,11 @@ class PutIndexPolicyRequest(ServiceRequest): class PutIndexPolicyResponse(TypedDict, total=False): - indexPolicy: Optional[IndexPolicy] + indexPolicy: IndexPolicy | None class ResourceConfig(TypedDict, total=False): - openSearchResourceConfig: Optional[OpenSearchResourceConfig] + openSearchResourceConfig: OpenSearchResourceConfig | None class PutIntegrationRequest(ServiceRequest): @@ -2005,16 +2421,16 @@ class PutIntegrationRequest(ServiceRequest): class PutIntegrationResponse(TypedDict, total=False): - integrationName: Optional[IntegrationName] - integrationStatus: Optional[IntegrationStatus] + integrationName: IntegrationName | None + integrationStatus: IntegrationStatus | None class PutLogEventsRequest(ServiceRequest): logGroupName: LogGroupName logStreamName: LogStreamName logEvents: InputLogEvents - sequenceToken: Optional[SequenceToken] - entity: Optional[Entity] + sequenceToken: SequenceToken | None + entity: Entity | None class RejectedEntityInfo(TypedDict, total=False): @@ -2022,15 +2438,20 @@ class RejectedEntityInfo(TypedDict, total=False): class RejectedLogEventsInfo(TypedDict, total=False): - tooNewLogEventStartIndex: Optional[LogEventIndex] - tooOldLogEventEndIndex: Optional[LogEventIndex] - expiredLogEventEndIndex: Optional[LogEventIndex] + tooNewLogEventStartIndex: LogEventIndex | None + tooOldLogEventEndIndex: LogEventIndex | None + expiredLogEventEndIndex: LogEventIndex | None class PutLogEventsResponse(TypedDict, total=False): - nextSequenceToken: Optional[SequenceToken] - rejectedLogEventsInfo: Optional[RejectedLogEventsInfo] - rejectedEntityInfo: Optional[RejectedEntityInfo] + nextSequenceToken: SequenceToken | None + rejectedLogEventsInfo: RejectedLogEventsInfo | None + rejectedEntityInfo: RejectedEntityInfo | None + + +class PutLogGroupDeletionProtectionRequest(ServiceRequest): + logGroupIdentifier: LogGroupIdentifier + deletionProtectionEnabled: DeletionProtectionEnabled class PutMetricFilterRequest(ServiceRequest): @@ -2038,34 +2459,34 @@ class PutMetricFilterRequest(ServiceRequest): filterName: FilterName filterPattern: FilterPattern metricTransformations: MetricTransformations - applyOnTransformedLogs: Optional[ApplyOnTransformedLogs] - fieldSelectionCriteria: Optional[FieldSelectionCriteria] - emitSystemFieldDimensions: Optional[EmitSystemFields] + applyOnTransformedLogs: ApplyOnTransformedLogs | None + fieldSelectionCriteria: FieldSelectionCriteria | None + emitSystemFieldDimensions: EmitSystemFields | None class PutQueryDefinitionRequest(ServiceRequest): - queryLanguage: Optional[QueryLanguage] + queryLanguage: QueryLanguage | None name: QueryDefinitionName - queryDefinitionId: Optional[QueryId] - logGroupNames: Optional[LogGroupNames] + queryDefinitionId: QueryId | None + logGroupNames: LogGroupNames | None queryString: QueryDefinitionString - clientToken: Optional[ClientToken] + clientToken: ClientToken | None class PutQueryDefinitionResponse(TypedDict, total=False): - queryDefinitionId: Optional[QueryId] + queryDefinitionId: QueryId | None class PutResourcePolicyRequest(ServiceRequest): - policyName: Optional[PolicyName] - policyDocument: Optional[PolicyDocument] - resourceArn: Optional[Arn] - expectedRevisionId: Optional[ExpectedRevisionId] + policyName: PolicyName | None + policyDocument: PolicyDocument | None + resourceArn: Arn | None + expectedRevisionId: ExpectedRevisionId | None class PutResourcePolicyResponse(TypedDict, total=False): - resourcePolicy: Optional[ResourcePolicy] - revisionId: Optional[ExpectedRevisionId] + resourcePolicy: ResourcePolicy | None + revisionId: ExpectedRevisionId | None class PutRetentionPolicyRequest(ServiceRequest): @@ -2078,11 +2499,11 @@ class PutSubscriptionFilterRequest(ServiceRequest): filterName: FilterName filterPattern: FilterPattern destinationArn: DestinationArn - roleArn: Optional[RoleArn] - distribution: Optional[Distribution] - applyOnTransformedLogs: Optional[ApplyOnTransformedLogs] - fieldSelectionCriteria: Optional[FieldSelectionCriteria] - emitSystemFields: Optional[EmitSystemFields] + roleArn: RoleArn | None + distribution: Distribution | None + applyOnTransformedLogs: ApplyOnTransformedLogs | None + fieldSelectionCriteria: FieldSelectionCriteria | None + emitSystemFields: EmitSystemFields | None class PutTransformerRequest(ServiceRequest): @@ -2092,16 +2513,16 @@ class PutTransformerRequest(ServiceRequest): class StartLiveTailRequest(ServiceRequest): logGroupIdentifiers: StartLiveTailLogGroupIdentifiers - logStreamNames: Optional[InputLogStreamNames] - logStreamNamePrefixes: Optional[InputLogStreamNames] - logEventFilterPattern: Optional[FilterPattern] + logStreamNames: InputLogStreamNames | None + logStreamNamePrefixes: InputLogStreamNames | None + logEventFilterPattern: FilterPattern | None class StartLiveTailResponseStream(TypedDict, total=False): - sessionStart: Optional[LiveTailSessionStart] - sessionUpdate: Optional[LiveTailSessionUpdate] - SessionTimeoutException: Optional[SessionTimeoutException] - SessionStreamingException: Optional[SessionStreamingException] + sessionStart: LiveTailSessionStart | None + sessionUpdate: LiveTailSessionUpdate | None + SessionTimeoutException: SessionTimeoutException | None + SessionStreamingException: SessionStreamingException | None class StartLiveTailResponse(TypedDict, total=False): @@ -2109,18 +2530,18 @@ class StartLiveTailResponse(TypedDict, total=False): class StartQueryRequest(ServiceRequest): - queryLanguage: Optional[QueryLanguage] - logGroupName: Optional[LogGroupName] - logGroupNames: Optional[LogGroupNames] - logGroupIdentifiers: Optional[LogGroupIdentifiers] + queryLanguage: QueryLanguage | None + logGroupName: LogGroupName | None + logGroupNames: LogGroupNames | None + logGroupIdentifiers: LogGroupIdentifiers | None startTime: Timestamp endTime: Timestamp queryString: QueryString - limit: Optional[EventsLimit] + limit: EventsLimit | None class StartQueryResponse(TypedDict, total=False): - queryId: Optional[QueryId] + queryId: QueryId | None class StopQueryRequest(ServiceRequest): @@ -2128,16 +2549,16 @@ class StopQueryRequest(ServiceRequest): class StopQueryResponse(TypedDict, total=False): - success: Optional[Success] + success: Success | None class SuppressionPeriod(TypedDict, total=False): - value: Optional[Integer] - suppressionUnit: Optional[SuppressionUnit] + value: Integer | None + suppressionUnit: SuppressionUnit | None -TagKeyList = List[TagKey] -TagList = List[TagKey] +TagKeyList = list[TagKey] +TagList = list[TagKey] class TagLogGroupRequest(ServiceRequest): @@ -2150,7 +2571,7 @@ class TagResourceRequest(ServiceRequest): tags: Tags -TestEventMessages = List[EventMessage] +TestEventMessages = list[EventMessage] class TestMetricFilterRequest(ServiceRequest): @@ -2159,7 +2580,7 @@ class TestMetricFilterRequest(ServiceRequest): class TestMetricFilterResponse(TypedDict, total=False): - matches: Optional[MetricFilterMatches] + matches: MetricFilterMatches | None class TestTransformerRequest(ServiceRequest): @@ -2168,16 +2589,16 @@ class TestTransformerRequest(ServiceRequest): class TransformedLogRecord(TypedDict, total=False): - eventNumber: Optional[EventNumber] - eventMessage: Optional[EventMessage] - transformedEventMessage: Optional[TransformedEventMessage] + eventNumber: EventNumber | None + eventMessage: EventMessage | None + transformedEventMessage: TransformedEventMessage | None -TransformedLogs = List[TransformedLogRecord] +TransformedLogs = list[TransformedLogRecord] class TestTransformerResponse(TypedDict, total=False): - transformedLogs: Optional[TransformedLogs] + transformedLogs: TransformedLogs | None class UntagLogGroupRequest(ServiceRequest): @@ -2191,19 +2612,19 @@ class UntagResourceRequest(ServiceRequest): class UpdateAnomalyRequest(ServiceRequest): - anomalyId: Optional[AnomalyId] - patternId: Optional[PatternId] + anomalyId: AnomalyId | None + patternId: PatternId | None anomalyDetectorArn: AnomalyDetectorArn - suppressionType: Optional[SuppressionType] - suppressionPeriod: Optional[SuppressionPeriod] - baseline: Optional[Baseline] + suppressionType: SuppressionType | None + suppressionPeriod: SuppressionPeriod | None + baseline: Baseline | None class UpdateDeliveryConfigurationRequest(ServiceRequest): id: DeliveryId - recordFields: Optional[RecordFields] - fieldDelimiter: Optional[FieldDelimiter] - s3DeliveryConfiguration: Optional[S3DeliveryConfiguration] + recordFields: RecordFields | None + fieldDelimiter: FieldDelimiter | None + s3DeliveryConfiguration: S3DeliveryConfiguration | None class UpdateDeliveryConfigurationResponse(TypedDict, total=False): @@ -2212,15 +2633,52 @@ class UpdateDeliveryConfigurationResponse(TypedDict, total=False): class UpdateLogAnomalyDetectorRequest(ServiceRequest): anomalyDetectorArn: AnomalyDetectorArn - evaluationFrequency: Optional[EvaluationFrequency] - filterPattern: Optional[FilterPattern] - anomalyVisibilityTime: Optional[AnomalyVisibilityTime] + evaluationFrequency: EvaluationFrequency | None + filterPattern: FilterPattern | None + anomalyVisibilityTime: AnomalyVisibilityTime | None enabled: Boolean +class UpdateScheduledQueryRequest(ServiceRequest): + identifier: ScheduledQueryIdentifier + description: ScheduledQueryDescription | None + queryLanguage: QueryLanguage + queryString: QueryString + logGroupIdentifiers: ScheduledQueryLogGroupIdentifiers | None + scheduleExpression: ScheduleExpression + timezone: ScheduleTimezone | None + startTimeOffset: StartTimeOffset | None + destinationConfiguration: DestinationConfiguration | None + scheduleStartTime: Timestamp | None + scheduleEndTime: Timestamp | None + executionRoleArn: RoleArn + state: ScheduledQueryState | None + + +class UpdateScheduledQueryResponse(TypedDict, total=False): + scheduledQueryArn: Arn | None + name: ScheduledQueryName | None + description: ScheduledQueryDescription | None + queryLanguage: QueryLanguage | None + queryString: QueryString | None + logGroupIdentifiers: ScheduledQueryLogGroupIdentifiers | None + scheduleExpression: ScheduleExpression | None + timezone: ScheduleTimezone | None + startTimeOffset: StartTimeOffset | None + destinationConfiguration: DestinationConfiguration | None + state: ScheduledQueryState | None + lastTriggeredTime: Timestamp | None + lastExecutionStatus: ExecutionStatus | None + scheduleStartTime: Timestamp | None + scheduleEndTime: Timestamp | None + executionRoleArn: RoleArn | None + creationTime: Timestamp | None + lastUpdatedTime: Timestamp | None + + class LogsApi: - service = "logs" - version = "2014-03-28" + service: str = "logs" + version: str = "2014-03-28" @handler("AssociateKmsKey") def associate_kms_key( @@ -2233,10 +2691,22 @@ def associate_kms_key( ) -> None: raise NotImplementedError + @handler("AssociateSourceToS3TableIntegration") + def associate_source_to_s3_table_integration( + self, context: RequestContext, integration_arn: Arn, data_source: DataSource, **kwargs + ) -> AssociateSourceToS3TableIntegrationResponse: + raise NotImplementedError + @handler("CancelExportTask") def cancel_export_task(self, context: RequestContext, task_id: ExportTaskId, **kwargs) -> None: raise NotImplementedError + @handler("CancelImportTask") + def cancel_import_task( + self, context: RequestContext, import_id: ImportId, **kwargs + ) -> CancelImportTaskResponse: + raise NotImplementedError + @handler("CreateDelivery") def create_delivery( self, @@ -2257,6 +2727,17 @@ def create_export_task( ) -> CreateExportTaskResponse: raise NotImplementedError + @handler("CreateImportTask") + def create_import_task( + self, + context: RequestContext, + import_source_arn: Arn, + import_role_arn: RoleArn, + import_filter: ImportFilter | None = None, + **kwargs, + ) -> CreateImportTaskResponse: + raise NotImplementedError + @handler("CreateLogAnomalyDetector") def create_log_anomaly_detector( self, @@ -2280,6 +2761,7 @@ def create_log_group( kms_key_id: KmsKeyId | None = None, tags: Tags | None = None, log_group_class: LogGroupClass | None = None, + deletion_protection_enabled: DeletionProtectionEnabled | None = None, **kwargs, ) -> None: raise NotImplementedError @@ -2294,6 +2776,28 @@ def create_log_stream( ) -> None: raise NotImplementedError + @handler("CreateScheduledQuery") + def create_scheduled_query( + self, + context: RequestContext, + name: ScheduledQueryName, + query_language: QueryLanguage, + query_string: QueryString, + schedule_expression: ScheduleExpression, + execution_role_arn: RoleArn, + description: ScheduledQueryDescription | None = None, + log_group_identifiers: ScheduledQueryLogGroupIdentifiers | None = None, + timezone: ScheduleTimezone | None = None, + start_time_offset: StartTimeOffset | None = None, + destination_configuration: DestinationConfiguration | None = None, + schedule_start_time: Timestamp | None = None, + schedule_end_time: Timestamp | None = None, + state: ScheduledQueryState | None = None, + tags: Tags | None = None, + **kwargs, + ) -> CreateScheduledQueryResponse: + raise NotImplementedError + @handler("DeleteAccountPolicy") def delete_account_policy( self, context: RequestContext, policy_name: PolicyName, policy_type: PolicyType, **kwargs @@ -2405,6 +2909,12 @@ def delete_retention_policy( ) -> None: raise NotImplementedError + @handler("DeleteScheduledQuery") + def delete_scheduled_query( + self, context: RequestContext, identifier: ScheduledQueryIdentifier, **kwargs + ) -> DeleteScheduledQueryResponse: + raise NotImplementedError + @handler("DeleteSubscriptionFilter") def delete_subscription_filter( self, @@ -2510,6 +3020,31 @@ def describe_field_indexes( ) -> DescribeFieldIndexesResponse: raise NotImplementedError + @handler("DescribeImportTaskBatches") + def describe_import_task_batches( + self, + context: RequestContext, + import_id: ImportId, + batch_import_status: ImportStatusList | None = None, + limit: DescribeLimit | None = None, + next_token: NextToken | None = None, + **kwargs, + ) -> DescribeImportTaskBatchesResponse: + raise NotImplementedError + + @handler("DescribeImportTasks") + def describe_import_tasks( + self, + context: RequestContext, + import_id: ImportId | None = None, + import_status: ImportStatus | None = None, + import_source_arn: Arn | None = None, + limit: DescribeLimit | None = None, + next_token: NextToken | None = None, + **kwargs, + ) -> DescribeImportTasksResponse: + raise NotImplementedError + @handler("DescribeIndexPolicies") def describe_index_policies( self, @@ -2624,6 +3159,12 @@ def disassociate_kms_key( ) -> None: raise NotImplementedError + @handler("DisassociateSourceFromS3TableIntegration") + def disassociate_source_from_s3_table_integration( + self, context: RequestContext, identifier: S3TableIntegrationSourceIdentifier, **kwargs + ) -> DisassociateSourceFromS3TableIntegrationResponse: + raise NotImplementedError + @handler("FilterLogEvents") def filter_log_events( self, @@ -2702,6 +3243,16 @@ def get_log_events( ) -> GetLogEventsResponse: raise NotImplementedError + @handler("GetLogFields") + def get_log_fields( + self, + context: RequestContext, + data_source_name: DataSourceName, + data_source_type: DataSourceType, + **kwargs, + ) -> GetLogFieldsResponse: + raise NotImplementedError + @handler("GetLogGroupFields") def get_log_group_fields( self, @@ -2739,12 +3290,48 @@ def get_query_results( ) -> GetQueryResultsResponse: raise NotImplementedError + @handler("GetScheduledQuery") + def get_scheduled_query( + self, context: RequestContext, identifier: ScheduledQueryIdentifier, **kwargs + ) -> GetScheduledQueryResponse: + raise NotImplementedError + + @handler("GetScheduledQueryHistory") + def get_scheduled_query_history( + self, + context: RequestContext, + identifier: ScheduledQueryIdentifier, + start_time: Timestamp, + end_time: Timestamp, + execution_statuses: ExecutionStatusList | None = None, + max_results: GetScheduledQueryHistoryMaxResults | None = None, + next_token: NextToken | None = None, + **kwargs, + ) -> GetScheduledQueryHistoryResponse: + raise NotImplementedError + @handler("GetTransformer") def get_transformer( self, context: RequestContext, log_group_identifier: LogGroupIdentifier, **kwargs ) -> GetTransformerResponse: raise NotImplementedError + @handler("ListAggregateLogGroupSummaries") + def list_aggregate_log_group_summaries( + self, + context: RequestContext, + group_by: ListAggregateLogGroupSummariesGroupBy, + account_identifiers: AccountIds | None = None, + include_linked_accounts: IncludeLinkedAccounts | None = None, + log_group_class: LogGroupClass | None = None, + log_group_name_pattern: LogGroupNameRegexPattern | None = None, + data_sources: DataSourceFilters | None = None, + next_token: NextToken | None = None, + limit: ListLogGroupsRequestLimit | None = None, + **kwargs, + ) -> ListAggregateLogGroupSummariesResponse: + raise NotImplementedError + @handler("ListAnomalies") def list_anomalies( self, @@ -2789,6 +3376,8 @@ def list_log_groups( account_identifiers: AccountIds | None = None, next_token: NextToken | None = None, limit: ListLimit | None = None, + data_sources: DataSourceFilters | None = None, + field_index_names: FieldIndexNames | None = None, **kwargs, ) -> ListLogGroupsResponse: raise NotImplementedError @@ -2804,6 +3393,28 @@ def list_log_groups_for_query( ) -> ListLogGroupsForQueryResponse: raise NotImplementedError + @handler("ListScheduledQueries") + def list_scheduled_queries( + self, + context: RequestContext, + max_results: ListScheduledQueriesMaxResults | None = None, + next_token: NextToken | None = None, + state: ScheduledQueryState | None = None, + **kwargs, + ) -> ListScheduledQueriesResponse: + raise NotImplementedError + + @handler("ListSourcesForS3TableIntegration") + def list_sources_for_s3_table_integration( + self, + context: RequestContext, + integration_arn: Arn, + max_results: ListSourcesForS3TableIntegrationMaxResults | None = None, + next_token: NextToken | None = None, + **kwargs, + ) -> ListSourcesForS3TableIntegrationResponse: + raise NotImplementedError + @handler("ListTagsForResource") def list_tags_for_resource( self, context: RequestContext, resource_arn: AmazonResourceName, **kwargs @@ -2931,6 +3542,16 @@ def put_log_events( ) -> PutLogEventsResponse: raise NotImplementedError + @handler("PutLogGroupDeletionProtection") + def put_log_group_deletion_protection( + self, + context: RequestContext, + log_group_identifier: LogGroupIdentifier, + deletion_protection_enabled: DeletionProtectionEnabled, + **kwargs, + ) -> None: + raise NotImplementedError + @handler("PutMetricFilter") def put_metric_filter( self, @@ -3127,3 +3748,24 @@ def update_log_anomaly_detector( **kwargs, ) -> None: raise NotImplementedError + + @handler("UpdateScheduledQuery") + def update_scheduled_query( + self, + context: RequestContext, + identifier: ScheduledQueryIdentifier, + query_language: QueryLanguage, + query_string: QueryString, + schedule_expression: ScheduleExpression, + execution_role_arn: RoleArn, + description: ScheduledQueryDescription | None = None, + log_group_identifiers: ScheduledQueryLogGroupIdentifiers | None = None, + timezone: ScheduleTimezone | None = None, + start_time_offset: StartTimeOffset | None = None, + destination_configuration: DestinationConfiguration | None = None, + schedule_start_time: Timestamp | None = None, + schedule_end_time: Timestamp | None = None, + state: ScheduledQueryState | None = None, + **kwargs, + ) -> UpdateScheduledQueryResponse: + raise NotImplementedError diff --git a/localstack-core/localstack/aws/api/opensearch/__init__.py b/localstack-core/localstack/aws/api/opensearch/__init__.py index 2e97a7ad84e7e..40778ff3cb322 100644 --- a/localstack-core/localstack/aws/api/opensearch/__init__.py +++ b/localstack-core/localstack/aws/api/opensearch/__init__.py @@ -1,6 +1,6 @@ from datetime import datetime from enum import StrEnum -from typing import Dict, List, Optional, TypedDict +from typing import TypedDict from localstack.aws.api import RequestContext, ServiceException, ServiceRequest, handler @@ -46,12 +46,14 @@ IdentityCenterInstanceARN = str IdentityPoolId = str IdentityStoreId = str +IndexName = str InstanceCount = int InstanceRole = str InstanceTypeString = str Integer = int IntegerClass = int Issue = str +KmsKeyArn = str KmsKeyId = str LicenseFilepath = str LimitName = str @@ -262,6 +264,12 @@ class InboundConnectionStatusCode(StrEnum): DELETED = "DELETED" +class IndexStatus(StrEnum): + CREATED = "CREATED" + UPDATED = "UPDATED" + DELETED = "DELETED" + + class InitiatedBy(StrEnum): CUSTOMER = "CUSTOMER" SERVICE = "SERVICE" @@ -322,6 +330,7 @@ class NodeType(StrEnum): Data = "Data" Ultrawarm = "Ultrawarm" Master = "Master" + Warm = "Warm" class OpenSearchPartitionInstanceType(StrEnum): @@ -669,14 +678,20 @@ class ResourceNotFoundException(ServiceException): Long = int -SlotList = List[Long] +SlotList = list[Long] class SlotNotAvailableException(ServiceException): code: str = "SlotNotAvailableException" sender_fault: bool = False status_code: int = 409 - SlotSuggestions: Optional[SlotList] + SlotSuggestions: SlotList | None + + +class ThrottlingException(ServiceException): + code: str = "ThrottlingException" + sender_fault: bool = False + status_code: int = 429 class ValidationException(ServiceException): @@ -685,27 +700,33 @@ class ValidationException(ServiceException): status_code: int = 400 +class ServerlessVectorAcceleration(TypedDict, total=False): + Enabled: Boolean | None + + class S3VectorsEngine(TypedDict, total=False): - Enabled: Optional[Boolean] + Enabled: Boolean | None class NaturalLanguageQueryGenerationOptionsInput(TypedDict, total=False): - DesiredState: Optional[NaturalLanguageQueryGenerationDesiredState] + DesiredState: NaturalLanguageQueryGenerationDesiredState | None class AIMLOptionsInput(TypedDict, total=False): - NaturalLanguageQueryGenerationOptions: Optional[NaturalLanguageQueryGenerationOptionsInput] - S3VectorsEngine: Optional[S3VectorsEngine] + NaturalLanguageQueryGenerationOptions: NaturalLanguageQueryGenerationOptionsInput | None + S3VectorsEngine: S3VectorsEngine | None + ServerlessVectorAcceleration: ServerlessVectorAcceleration | None class NaturalLanguageQueryGenerationOptionsOutput(TypedDict, total=False): - DesiredState: Optional[NaturalLanguageQueryGenerationDesiredState] - CurrentState: Optional[NaturalLanguageQueryGenerationCurrentState] + DesiredState: NaturalLanguageQueryGenerationDesiredState | None + CurrentState: NaturalLanguageQueryGenerationCurrentState | None class AIMLOptionsOutput(TypedDict, total=False): - NaturalLanguageQueryGenerationOptions: Optional[NaturalLanguageQueryGenerationOptionsOutput] - S3VectorsEngine: Optional[S3VectorsEngine] + NaturalLanguageQueryGenerationOptions: NaturalLanguageQueryGenerationOptionsOutput | None + S3VectorsEngine: S3VectorsEngine | None + ServerlessVectorAcceleration: ServerlessVectorAcceleration | None UpdateTimestamp = datetime @@ -714,20 +735,20 @@ class AIMLOptionsOutput(TypedDict, total=False): class OptionStatus(TypedDict, total=False): CreationDate: UpdateTimestamp UpdateDate: UpdateTimestamp - UpdateVersion: Optional[UIntValue] + UpdateVersion: UIntValue | None State: OptionState - PendingDeletion: Optional[Boolean] + PendingDeletion: Boolean | None class AIMLOptionsStatus(TypedDict, total=False): - Options: Optional[AIMLOptionsOutput] - Status: Optional[OptionStatus] + Options: AIMLOptionsOutput | None + Status: OptionStatus | None class AWSDomainInformation(TypedDict, total=False): - OwnerId: Optional[OwnerId] + OwnerId: OwnerId | None DomainName: DomainName - Region: Optional[Region] + Region: Region | None class AcceptInboundConnectionRequest(ServiceRequest): @@ -735,24 +756,24 @@ class AcceptInboundConnectionRequest(ServiceRequest): class InboundConnectionStatus(TypedDict, total=False): - StatusCode: Optional[InboundConnectionStatusCode] - Message: Optional[ConnectionStatusMessage] + StatusCode: InboundConnectionStatusCode | None + Message: ConnectionStatusMessage | None class DomainInformationContainer(TypedDict, total=False): - AWSDomainInformation: Optional[AWSDomainInformation] + AWSDomainInformation: AWSDomainInformation | None class InboundConnection(TypedDict, total=False): - LocalDomainInfo: Optional[DomainInformationContainer] - RemoteDomainInfo: Optional[DomainInformationContainer] - ConnectionId: Optional[ConnectionId] - ConnectionStatus: Optional[InboundConnectionStatus] - ConnectionMode: Optional[ConnectionMode] + LocalDomainInfo: DomainInformationContainer | None + RemoteDomainInfo: DomainInformationContainer | None + ConnectionId: ConnectionId | None + ConnectionStatus: InboundConnectionStatus | None + ConnectionMode: ConnectionMode | None class AcceptInboundConnectionResponse(TypedDict, total=False): - Connection: Optional[InboundConnection] + Connection: InboundConnection | None class AccessPoliciesStatus(TypedDict, total=False): @@ -761,22 +782,22 @@ class AccessPoliciesStatus(TypedDict, total=False): class S3GlueDataCatalog(TypedDict, total=False): - RoleArn: Optional[RoleArn] + RoleArn: RoleArn | None class DataSourceType(TypedDict, total=False): - S3GlueDataCatalog: Optional[S3GlueDataCatalog] + S3GlueDataCatalog: S3GlueDataCatalog | None class AddDataSourceRequest(ServiceRequest): DomainName: DomainName Name: DataSourceName DataSourceType: DataSourceType - Description: Optional[DataSourceDescription] + Description: DataSourceDescription | None class AddDataSourceResponse(TypedDict, total=False): - Message: Optional[String] + Message: String | None class Tag(TypedDict, total=False): @@ -784,8 +805,8 @@ class Tag(TypedDict, total=False): Value: TagValue -TagList = List[Tag] -DirectQueryOpenSearchARNList = List[ARN] +TagList = list[Tag] +DirectQueryOpenSearchARNList = list[ARN] class SecurityLakeDirectQueryDataSource(TypedDict, total=False): @@ -797,20 +818,20 @@ class CloudWatchDirectQueryDataSource(TypedDict, total=False): class DirectQueryDataSourceType(TypedDict, total=False): - CloudWatchLog: Optional[CloudWatchDirectQueryDataSource] - SecurityLake: Optional[SecurityLakeDirectQueryDataSource] + CloudWatchLog: CloudWatchDirectQueryDataSource | None + SecurityLake: SecurityLakeDirectQueryDataSource | None class AddDirectQueryDataSourceRequest(ServiceRequest): DataSourceName: DirectQueryDataSourceName DataSourceType: DirectQueryDataSourceType - Description: Optional[DirectQueryDataSourceDescription] + Description: DirectQueryDataSourceDescription | None OpenSearchArns: DirectQueryOpenSearchARNList - TagList: Optional[TagList] + TagList: TagList | None class AddDirectQueryDataSourceResponse(TypedDict, total=False): - DataSourceArn: Optional[String] + DataSourceArn: String | None class AddTagsRequest(ServiceRequest): @@ -818,16 +839,16 @@ class AddTagsRequest(ServiceRequest): TagList: TagList -LimitValueList = List[LimitValue] +LimitValueList = list[LimitValue] class AdditionalLimit(TypedDict, total=False): - LimitName: Optional[LimitName] - LimitValues: Optional[LimitValueList] + LimitName: LimitName | None + LimitValues: LimitValueList | None -AdditionalLimitList = List[AdditionalLimit] -AdvancedOptions = Dict[String, String] +AdditionalLimitList = list[AdditionalLimit] +AdvancedOptions = dict[String, String] class AdvancedOptionsStatus(TypedDict, total=False): @@ -839,16 +860,16 @@ class AdvancedOptionsStatus(TypedDict, total=False): class IAMFederationOptionsOutput(TypedDict, total=False): - Enabled: Optional[Boolean] - SubjectKey: Optional[IAMFederationSubjectKey] - RolesKey: Optional[IAMFederationRolesKey] + Enabled: Boolean | None + SubjectKey: IAMFederationSubjectKey | None + RolesKey: IAMFederationRolesKey | None class JWTOptionsOutput(TypedDict, total=False): - Enabled: Optional[Boolean] - SubjectKey: Optional[String] - RolesKey: Optional[String] - PublicKey: Optional[String] + Enabled: Boolean | None + SubjectKey: String | None + RolesKey: String | None + PublicKey: String | None class SAMLIdp(TypedDict, total=False): @@ -857,60 +878,60 @@ class SAMLIdp(TypedDict, total=False): class SAMLOptionsOutput(TypedDict, total=False): - Enabled: Optional[Boolean] - Idp: Optional[SAMLIdp] - SubjectKey: Optional[String] - RolesKey: Optional[String] - SessionTimeoutMinutes: Optional[IntegerClass] + Enabled: Boolean | None + Idp: SAMLIdp | None + SubjectKey: String | None + RolesKey: String | None + SessionTimeoutMinutes: IntegerClass | None class AdvancedSecurityOptions(TypedDict, total=False): - Enabled: Optional[Boolean] - InternalUserDatabaseEnabled: Optional[Boolean] - SAMLOptions: Optional[SAMLOptionsOutput] - JWTOptions: Optional[JWTOptionsOutput] - IAMFederationOptions: Optional[IAMFederationOptionsOutput] - AnonymousAuthDisableDate: Optional[DisableTimestamp] - AnonymousAuthEnabled: Optional[Boolean] + Enabled: Boolean | None + InternalUserDatabaseEnabled: Boolean | None + SAMLOptions: SAMLOptionsOutput | None + JWTOptions: JWTOptionsOutput | None + IAMFederationOptions: IAMFederationOptionsOutput | None + AnonymousAuthDisableDate: DisableTimestamp | None + AnonymousAuthEnabled: Boolean | None class IAMFederationOptionsInput(TypedDict, total=False): - Enabled: Optional[Boolean] - SubjectKey: Optional[IAMFederationSubjectKey] - RolesKey: Optional[IAMFederationRolesKey] + Enabled: Boolean | None + SubjectKey: IAMFederationSubjectKey | None + RolesKey: IAMFederationRolesKey | None class JWTOptionsInput(TypedDict, total=False): - Enabled: Optional[Boolean] - SubjectKey: Optional[SubjectKey] - RolesKey: Optional[RolesKey] - PublicKey: Optional[String] + Enabled: Boolean | None + SubjectKey: SubjectKey | None + RolesKey: RolesKey | None + PublicKey: String | None class SAMLOptionsInput(TypedDict, total=False): - Enabled: Optional[Boolean] - Idp: Optional[SAMLIdp] - MasterUserName: Optional[Username] - MasterBackendRole: Optional[BackendRole] - SubjectKey: Optional[String] - RolesKey: Optional[String] - SessionTimeoutMinutes: Optional[IntegerClass] + Enabled: Boolean | None + Idp: SAMLIdp | None + MasterUserName: Username | None + MasterBackendRole: BackendRole | None + SubjectKey: String | None + RolesKey: String | None + SessionTimeoutMinutes: IntegerClass | None class MasterUserOptions(TypedDict, total=False): - MasterUserARN: Optional[ARN] - MasterUserName: Optional[Username] - MasterUserPassword: Optional[Password] + MasterUserARN: ARN | None + MasterUserName: Username | None + MasterUserPassword: Password | None class AdvancedSecurityOptionsInput(TypedDict, total=False): - Enabled: Optional[Boolean] - InternalUserDatabaseEnabled: Optional[Boolean] - MasterUserOptions: Optional[MasterUserOptions] - SAMLOptions: Optional[SAMLOptionsInput] - JWTOptions: Optional[JWTOptionsInput] - IAMFederationOptions: Optional[IAMFederationOptionsInput] - AnonymousAuthEnabled: Optional[Boolean] + Enabled: Boolean | None + InternalUserDatabaseEnabled: Boolean | None + MasterUserOptions: MasterUserOptions | None + SAMLOptions: SAMLOptionsInput | None + JWTOptions: JWTOptionsInput | None + IAMFederationOptions: IAMFederationOptionsInput | None + AnonymousAuthEnabled: Boolean | None class AdvancedSecurityOptionsStatus(TypedDict, total=False): @@ -919,80 +940,80 @@ class AdvancedSecurityOptionsStatus(TypedDict, total=False): class AppConfig(TypedDict, total=False): - key: Optional[AppConfigType] - value: Optional[AppConfigValue] + key: AppConfigType | None + value: AppConfigValue | None -AppConfigs = List[AppConfig] -ApplicationStatuses = List[ApplicationStatus] +AppConfigs = list[AppConfig] +ApplicationStatuses = list[ApplicationStatus] Timestamp = datetime class ApplicationSummary(TypedDict, total=False): - id: Optional[Id] - arn: Optional[ARN] - name: Optional[ApplicationName] - endpoint: Optional[String] - status: Optional[ApplicationStatus] - createdAt: Optional[Timestamp] - lastUpdatedAt: Optional[Timestamp] + id: Id | None + arn: ARN | None + name: ApplicationName | None + endpoint: String | None + status: ApplicationStatus | None + createdAt: Timestamp | None + lastUpdatedAt: Timestamp | None -ApplicationSummaries = List[ApplicationSummary] +ApplicationSummaries = list[ApplicationSummary] class KeyStoreAccessOption(TypedDict, total=False): - KeyAccessRoleArn: Optional[RoleArn] + KeyAccessRoleArn: RoleArn | None KeyStoreAccessEnabled: Boolean class PackageAssociationConfiguration(TypedDict, total=False): - KeyStoreAccessOption: Optional[KeyStoreAccessOption] + KeyStoreAccessOption: KeyStoreAccessOption | None -PackageIDList = List[PackageID] +PackageIDList = list[PackageID] class AssociatePackageRequest(ServiceRequest): PackageID: PackageID DomainName: DomainName - PrerequisitePackageIDList: Optional[PackageIDList] - AssociationConfiguration: Optional[PackageAssociationConfiguration] + PrerequisitePackageIDList: PackageIDList | None + AssociationConfiguration: PackageAssociationConfiguration | None class ErrorDetails(TypedDict, total=False): - ErrorType: Optional[ErrorType] - ErrorMessage: Optional[ErrorMessage] + ErrorType: ErrorType | None + ErrorMessage: ErrorMessage | None LastUpdated = datetime class DomainPackageDetails(TypedDict, total=False): - PackageID: Optional[PackageID] - PackageName: Optional[PackageName] - PackageType: Optional[PackageType] - LastUpdated: Optional[LastUpdated] - DomainName: Optional[DomainName] - DomainPackageStatus: Optional[DomainPackageStatus] - PackageVersion: Optional[PackageVersion] - PrerequisitePackageIDList: Optional[PackageIDList] - ReferencePath: Optional[ReferencePath] - ErrorDetails: Optional[ErrorDetails] - AssociationConfiguration: Optional[PackageAssociationConfiguration] + PackageID: PackageID | None + PackageName: PackageName | None + PackageType: PackageType | None + LastUpdated: LastUpdated | None + DomainName: DomainName | None + DomainPackageStatus: DomainPackageStatus | None + PackageVersion: PackageVersion | None + PrerequisitePackageIDList: PackageIDList | None + ReferencePath: ReferencePath | None + ErrorDetails: ErrorDetails | None + AssociationConfiguration: PackageAssociationConfiguration | None class AssociatePackageResponse(TypedDict, total=False): - DomainPackageDetails: Optional[DomainPackageDetails] + DomainPackageDetails: DomainPackageDetails | None class PackageDetailsForAssociation(TypedDict, total=False): PackageID: PackageID - PrerequisitePackageIDList: Optional[PackageIDList] - AssociationConfiguration: Optional[PackageAssociationConfiguration] + PrerequisitePackageIDList: PackageIDList | None + AssociationConfiguration: PackageAssociationConfiguration | None -PackageDetailsForAssociationList = List[PackageDetailsForAssociation] +PackageDetailsForAssociationList = list[PackageDetailsForAssociation] class AssociatePackagesRequest(ServiceRequest): @@ -1000,134 +1021,134 @@ class AssociatePackagesRequest(ServiceRequest): DomainName: DomainName -DomainPackageDetailsList = List[DomainPackageDetails] +DomainPackageDetailsList = list[DomainPackageDetails] class AssociatePackagesResponse(TypedDict, total=False): - DomainPackageDetailsList: Optional[DomainPackageDetailsList] + DomainPackageDetailsList: DomainPackageDetailsList | None class AuthorizeVpcEndpointAccessRequest(ServiceRequest): DomainName: DomainName - Account: Optional[AWSAccount] - Service: Optional[AWSServicePrincipal] + Account: AWSAccount | None + Service: AWSServicePrincipal | None class AuthorizedPrincipal(TypedDict, total=False): - PrincipalType: Optional[PrincipalType] - Principal: Optional[String] + PrincipalType: PrincipalType | None + Principal: String | None class AuthorizeVpcEndpointAccessResponse(TypedDict, total=False): AuthorizedPrincipal: AuthorizedPrincipal -AuthorizedPrincipalList = List[AuthorizedPrincipal] +AuthorizedPrincipalList = list[AuthorizedPrincipal] AutoTuneDate = datetime class ScheduledAutoTuneDetails(TypedDict, total=False): - Date: Optional[AutoTuneDate] - ActionType: Optional[ScheduledAutoTuneActionType] - Action: Optional[ScheduledAutoTuneDescription] - Severity: Optional[ScheduledAutoTuneSeverityType] + Date: AutoTuneDate | None + ActionType: ScheduledAutoTuneActionType | None + Action: ScheduledAutoTuneDescription | None + Severity: ScheduledAutoTuneSeverityType | None class AutoTuneDetails(TypedDict, total=False): - ScheduledAutoTuneDetails: Optional[ScheduledAutoTuneDetails] + ScheduledAutoTuneDetails: ScheduledAutoTuneDetails | None class AutoTune(TypedDict, total=False): - AutoTuneType: Optional[AutoTuneType] - AutoTuneDetails: Optional[AutoTuneDetails] + AutoTuneType: AutoTuneType | None + AutoTuneDetails: AutoTuneDetails | None -AutoTuneList = List[AutoTune] +AutoTuneList = list[AutoTune] DurationValue = int class Duration(TypedDict, total=False): - Value: Optional[DurationValue] - Unit: Optional[TimeUnit] + Value: DurationValue | None + Unit: TimeUnit | None StartAt = datetime class AutoTuneMaintenanceSchedule(TypedDict, total=False): - StartAt: Optional[StartAt] - Duration: Optional[Duration] - CronExpressionForRecurrence: Optional[String] + StartAt: StartAt | None + Duration: Duration | None + CronExpressionForRecurrence: String | None -AutoTuneMaintenanceScheduleList = List[AutoTuneMaintenanceSchedule] +AutoTuneMaintenanceScheduleList = list[AutoTuneMaintenanceSchedule] class AutoTuneOptions(TypedDict, total=False): - DesiredState: Optional[AutoTuneDesiredState] - RollbackOnDisable: Optional[RollbackOnDisable] - MaintenanceSchedules: Optional[AutoTuneMaintenanceScheduleList] - UseOffPeakWindow: Optional[Boolean] + DesiredState: AutoTuneDesiredState | None + RollbackOnDisable: RollbackOnDisable | None + MaintenanceSchedules: AutoTuneMaintenanceScheduleList | None + UseOffPeakWindow: Boolean | None class AutoTuneOptionsInput(TypedDict, total=False): - DesiredState: Optional[AutoTuneDesiredState] - MaintenanceSchedules: Optional[AutoTuneMaintenanceScheduleList] - UseOffPeakWindow: Optional[Boolean] + DesiredState: AutoTuneDesiredState | None + MaintenanceSchedules: AutoTuneMaintenanceScheduleList | None + UseOffPeakWindow: Boolean | None class AutoTuneOptionsOutput(TypedDict, total=False): - State: Optional[AutoTuneState] - ErrorMessage: Optional[String] - UseOffPeakWindow: Optional[Boolean] + State: AutoTuneState | None + ErrorMessage: String | None + UseOffPeakWindow: Boolean | None class AutoTuneStatus(TypedDict, total=False): CreationDate: UpdateTimestamp UpdateDate: UpdateTimestamp - UpdateVersion: Optional[UIntValue] + UpdateVersion: UIntValue | None State: AutoTuneState - ErrorMessage: Optional[String] - PendingDeletion: Optional[Boolean] + ErrorMessage: String | None + PendingDeletion: Boolean | None class AutoTuneOptionsStatus(TypedDict, total=False): - Options: Optional[AutoTuneOptions] - Status: Optional[AutoTuneStatus] + Options: AutoTuneOptions | None + Status: AutoTuneStatus | None class AvailabilityZoneInfo(TypedDict, total=False): - AvailabilityZoneName: Optional[AvailabilityZone] - ZoneStatus: Optional[ZoneStatus] - ConfiguredDataNodeCount: Optional[NumberOfNodes] - AvailableDataNodeCount: Optional[NumberOfNodes] - TotalShards: Optional[NumberOfShards] - TotalUnAssignedShards: Optional[NumberOfShards] + AvailabilityZoneName: AvailabilityZone | None + ZoneStatus: ZoneStatus | None + ConfiguredDataNodeCount: NumberOfNodes | None + AvailableDataNodeCount: NumberOfNodes | None + TotalShards: NumberOfShards | None + TotalUnAssignedShards: NumberOfShards | None -AvailabilityZoneInfoList = List[AvailabilityZoneInfo] -AvailabilityZoneList = List[AvailabilityZone] +AvailabilityZoneInfoList = list[AvailabilityZoneInfo] +AvailabilityZoneList = list[AvailabilityZone] class CancelDomainConfigChangeRequest(ServiceRequest): DomainName: DomainName - DryRun: Optional[DryRun] + DryRun: DryRun | None class CancelledChangeProperty(TypedDict, total=False): - PropertyName: Optional[String] - CancelledValue: Optional[String] - ActiveValue: Optional[String] + PropertyName: String | None + CancelledValue: String | None + ActiveValue: String | None -CancelledChangePropertyList = List[CancelledChangeProperty] -GUIDList = List[GUID] +CancelledChangePropertyList = list[CancelledChangeProperty] +GUIDList = list[GUID] class CancelDomainConfigChangeResponse(TypedDict, total=False): - CancelledChangeIds: Optional[GUIDList] - CancelledChangeProperties: Optional[CancelledChangePropertyList] - DryRun: Optional[DryRun] + CancelledChangeIds: GUIDList | None + CancelledChangeProperties: CancelledChangePropertyList | None + DryRun: DryRun | None class CancelServiceSoftwareUpdateRequest(ServiceRequest): @@ -1138,65 +1159,65 @@ class CancelServiceSoftwareUpdateRequest(ServiceRequest): class ServiceSoftwareOptions(TypedDict, total=False): - CurrentVersion: Optional[String] - NewVersion: Optional[String] - UpdateAvailable: Optional[Boolean] - Cancellable: Optional[Boolean] - UpdateStatus: Optional[DeploymentStatus] - Description: Optional[String] - AutomatedUpdateDate: Optional[DeploymentCloseDateTimeStamp] - OptionalDeployment: Optional[Boolean] + CurrentVersion: String | None + NewVersion: String | None + UpdateAvailable: Boolean | None + Cancellable: Boolean | None + UpdateStatus: DeploymentStatus | None + Description: String | None + AutomatedUpdateDate: DeploymentCloseDateTimeStamp | None + OptionalDeployment: Boolean | None class CancelServiceSoftwareUpdateResponse(TypedDict, total=False): - ServiceSoftwareOptions: Optional[ServiceSoftwareOptions] + ServiceSoftwareOptions: ServiceSoftwareOptions | None class ChangeProgressDetails(TypedDict, total=False): - ChangeId: Optional[GUID] - Message: Optional[Message] - ConfigChangeStatus: Optional[ConfigChangeStatus] - InitiatedBy: Optional[InitiatedBy] - StartTime: Optional[UpdateTimestamp] - LastUpdatedTime: Optional[UpdateTimestamp] + ChangeId: GUID | None + Message: Message | None + ConfigChangeStatus: ConfigChangeStatus | None + InitiatedBy: InitiatedBy | None + StartTime: UpdateTimestamp | None + LastUpdatedTime: UpdateTimestamp | None class ChangeProgressStage(TypedDict, total=False): - Name: Optional[ChangeProgressStageName] - Status: Optional[ChangeProgressStageStatus] - Description: Optional[Description] - LastUpdated: Optional[LastUpdated] + Name: ChangeProgressStageName | None + Status: ChangeProgressStageStatus | None + Description: Description | None + LastUpdated: LastUpdated | None -ChangeProgressStageList = List[ChangeProgressStage] -StringList = List[String] +ChangeProgressStageList = list[ChangeProgressStage] +StringList = list[String] class ChangeProgressStatusDetails(TypedDict, total=False): - ChangeId: Optional[GUID] - StartTime: Optional[UpdateTimestamp] - Status: Optional[OverallChangeStatus] - PendingProperties: Optional[StringList] - CompletedProperties: Optional[StringList] - TotalNumberOfStages: Optional[TotalNumberOfStages] - ChangeProgressStages: Optional[ChangeProgressStageList] - LastUpdatedTime: Optional[UpdateTimestamp] - ConfigChangeStatus: Optional[ConfigChangeStatus] - InitiatedBy: Optional[InitiatedBy] + ChangeId: GUID | None + StartTime: UpdateTimestamp | None + Status: OverallChangeStatus | None + PendingProperties: StringList | None + CompletedProperties: StringList | None + TotalNumberOfStages: TotalNumberOfStages | None + ChangeProgressStages: ChangeProgressStageList | None + LastUpdatedTime: UpdateTimestamp | None + ConfigChangeStatus: ConfigChangeStatus | None + InitiatedBy: InitiatedBy | None class NodeConfig(TypedDict, total=False): - Enabled: Optional[Boolean] - Type: Optional[OpenSearchPartitionInstanceType] - Count: Optional[IntegerClass] + Enabled: Boolean | None + Type: OpenSearchPartitionInstanceType | None + Count: IntegerClass | None class NodeOption(TypedDict, total=False): - NodeType: Optional[NodeOptionsNodeType] - NodeConfig: Optional[NodeConfig] + NodeType: NodeOptionsNodeType | None + NodeConfig: NodeConfig | None -NodeOptionsList = List[NodeOption] +NodeOptionsList = list[NodeOption] class ColdStorageOptions(TypedDict, total=False): @@ -1204,23 +1225,23 @@ class ColdStorageOptions(TypedDict, total=False): class ZoneAwarenessConfig(TypedDict, total=False): - AvailabilityZoneCount: Optional[IntegerClass] + AvailabilityZoneCount: IntegerClass | None class ClusterConfig(TypedDict, total=False): - InstanceType: Optional[OpenSearchPartitionInstanceType] - InstanceCount: Optional[IntegerClass] - DedicatedMasterEnabled: Optional[Boolean] - ZoneAwarenessEnabled: Optional[Boolean] - ZoneAwarenessConfig: Optional[ZoneAwarenessConfig] - DedicatedMasterType: Optional[OpenSearchPartitionInstanceType] - DedicatedMasterCount: Optional[IntegerClass] - WarmEnabled: Optional[Boolean] - WarmType: Optional[OpenSearchWarmPartitionInstanceType] - WarmCount: Optional[IntegerClass] - ColdStorageOptions: Optional[ColdStorageOptions] - MultiAZWithStandbyEnabled: Optional[Boolean] - NodeOptions: Optional[NodeOptionsList] + InstanceType: OpenSearchPartitionInstanceType | None + InstanceCount: IntegerClass | None + DedicatedMasterEnabled: Boolean | None + ZoneAwarenessEnabled: Boolean | None + ZoneAwarenessConfig: ZoneAwarenessConfig | None + DedicatedMasterType: OpenSearchPartitionInstanceType | None + DedicatedMasterCount: IntegerClass | None + WarmEnabled: Boolean | None + WarmType: OpenSearchWarmPartitionInstanceType | None + WarmCount: IntegerClass | None + ColdStorageOptions: ColdStorageOptions | None + MultiAZWithStandbyEnabled: Boolean | None + NodeOptions: NodeOptionsList | None class ClusterConfigStatus(TypedDict, total=False): @@ -1229,10 +1250,10 @@ class ClusterConfigStatus(TypedDict, total=False): class CognitoOptions(TypedDict, total=False): - Enabled: Optional[Boolean] - UserPoolId: Optional[UserPoolId] - IdentityPoolId: Optional[IdentityPoolId] - RoleArn: Optional[RoleArn] + Enabled: Boolean | None + UserPoolId: UserPoolId | None + IdentityPoolId: IdentityPoolId | None + RoleArn: RoleArn | None class CognitoOptionsStatus(TypedDict, total=False): @@ -1240,69 +1261,71 @@ class CognitoOptionsStatus(TypedDict, total=False): Status: OptionStatus -VersionList = List[VersionString] +VersionList = list[VersionString] class CompatibleVersionsMap(TypedDict, total=False): - SourceVersion: Optional[VersionString] - TargetVersions: Optional[VersionList] + SourceVersion: VersionString | None + TargetVersions: VersionList | None -CompatibleVersionsList = List[CompatibleVersionsMap] +CompatibleVersionsList = list[CompatibleVersionsMap] class CrossClusterSearchConnectionProperties(TypedDict, total=False): - SkipUnavailable: Optional[SkipUnavailableStatus] + SkipUnavailable: SkipUnavailableStatus | None class ConnectionProperties(TypedDict, total=False): - Endpoint: Optional[Endpoint] - CrossClusterSearch: Optional[CrossClusterSearchConnectionProperties] + Endpoint: Endpoint | None + CrossClusterSearch: CrossClusterSearchConnectionProperties | None class IamIdentityCenterOptionsInput(TypedDict, total=False): - enabled: Optional[Boolean] - iamIdentityCenterInstanceArn: Optional[ARN] - iamRoleForIdentityCenterApplicationArn: Optional[RoleArn] + enabled: Boolean | None + iamIdentityCenterInstanceArn: ARN | None + iamRoleForIdentityCenterApplicationArn: RoleArn | None class DataSource(TypedDict, total=False): - dataSourceArn: Optional[ARN] - dataSourceDescription: Optional[DataSourceDescription] + dataSourceArn: ARN | None + dataSourceDescription: DataSourceDescription | None -DataSources = List[DataSource] +DataSources = list[DataSource] class CreateApplicationRequest(ServiceRequest): - clientToken: Optional[ClientToken] + clientToken: ClientToken | None name: ApplicationName - dataSources: Optional[DataSources] - iamIdentityCenterOptions: Optional[IamIdentityCenterOptionsInput] - appConfigs: Optional[AppConfigs] - tagList: Optional[TagList] + dataSources: DataSources | None + iamIdentityCenterOptions: IamIdentityCenterOptionsInput | None + appConfigs: AppConfigs | None + tagList: TagList | None + kmsKeyArn: KmsKeyArn | None class IamIdentityCenterOptions(TypedDict, total=False): - enabled: Optional[Boolean] - iamIdentityCenterInstanceArn: Optional[ARN] - iamRoleForIdentityCenterApplicationArn: Optional[RoleArn] - iamIdentityCenterApplicationArn: Optional[ARN] + enabled: Boolean | None + iamIdentityCenterInstanceArn: ARN | None + iamRoleForIdentityCenterApplicationArn: RoleArn | None + iamIdentityCenterApplicationArn: ARN | None class CreateApplicationResponse(TypedDict, total=False): - id: Optional[Id] - name: Optional[ApplicationName] - arn: Optional[ARN] - dataSources: Optional[DataSources] - iamIdentityCenterOptions: Optional[IamIdentityCenterOptions] - appConfigs: Optional[AppConfigs] - tagList: Optional[TagList] - createdAt: Optional[Timestamp] + id: Id | None + name: ApplicationName | None + arn: ARN | None + dataSources: DataSources | None + iamIdentityCenterOptions: IamIdentityCenterOptions | None + appConfigs: AppConfigs | None + tagList: TagList | None + createdAt: Timestamp | None + kmsKeyArn: KmsKeyArn | None class SoftwareUpdateOptions(TypedDict, total=False): - AutoSoftwareUpdateEnabled: Optional[Boolean] + AutoSoftwareUpdateEnabled: Boolean | None StartTimeMinutes = int @@ -1315,182 +1338,196 @@ class WindowStartTime(TypedDict, total=False): class OffPeakWindow(TypedDict, total=False): - WindowStartTime: Optional[WindowStartTime] + WindowStartTime: WindowStartTime | None class OffPeakWindowOptions(TypedDict, total=False): - Enabled: Optional[Boolean] - OffPeakWindow: Optional[OffPeakWindow] + Enabled: Boolean | None + OffPeakWindow: OffPeakWindow | None class IdentityCenterOptionsInput(TypedDict, total=False): - EnabledAPIAccess: Optional[Boolean] - IdentityCenterInstanceARN: Optional[IdentityCenterInstanceARN] - SubjectKey: Optional[SubjectKeyIdCOption] - RolesKey: Optional[RolesKeyIdCOption] + EnabledAPIAccess: Boolean | None + IdentityCenterInstanceARN: IdentityCenterInstanceARN | None + SubjectKey: SubjectKeyIdCOption | None + RolesKey: RolesKeyIdCOption | None class DomainEndpointOptions(TypedDict, total=False): - EnforceHTTPS: Optional[Boolean] - TLSSecurityPolicy: Optional[TLSSecurityPolicy] - CustomEndpointEnabled: Optional[Boolean] - CustomEndpoint: Optional[DomainNameFqdn] - CustomEndpointCertificateArn: Optional[ARN] + EnforceHTTPS: Boolean | None + TLSSecurityPolicy: TLSSecurityPolicy | None + CustomEndpointEnabled: Boolean | None + CustomEndpoint: DomainNameFqdn | None + CustomEndpointCertificateArn: ARN | None class LogPublishingOption(TypedDict, total=False): - CloudWatchLogsLogGroupArn: Optional[CloudWatchLogsLogGroupArn] - Enabled: Optional[Boolean] + CloudWatchLogsLogGroupArn: CloudWatchLogsLogGroupArn | None + Enabled: Boolean | None -LogPublishingOptions = Dict[LogType, LogPublishingOption] +LogPublishingOptions = dict[LogType, LogPublishingOption] class NodeToNodeEncryptionOptions(TypedDict, total=False): - Enabled: Optional[Boolean] + Enabled: Boolean | None class EncryptionAtRestOptions(TypedDict, total=False): - Enabled: Optional[Boolean] - KmsKeyId: Optional[KmsKeyId] + Enabled: Boolean | None + KmsKeyId: KmsKeyId | None class VPCOptions(TypedDict, total=False): - SubnetIds: Optional[StringList] - SecurityGroupIds: Optional[StringList] + SubnetIds: StringList | None + SecurityGroupIds: StringList | None class SnapshotOptions(TypedDict, total=False): - AutomatedSnapshotStartHour: Optional[IntegerClass] + AutomatedSnapshotStartHour: IntegerClass | None class EBSOptions(TypedDict, total=False): - EBSEnabled: Optional[Boolean] - VolumeType: Optional[VolumeType] - VolumeSize: Optional[IntegerClass] - Iops: Optional[IntegerClass] - Throughput: Optional[IntegerClass] + EBSEnabled: Boolean | None + VolumeType: VolumeType | None + VolumeSize: IntegerClass | None + Iops: IntegerClass | None + Throughput: IntegerClass | None class CreateDomainRequest(ServiceRequest): DomainName: DomainName - EngineVersion: Optional[VersionString] - ClusterConfig: Optional[ClusterConfig] - EBSOptions: Optional[EBSOptions] - AccessPolicies: Optional[PolicyDocument] - IPAddressType: Optional[IPAddressType] - SnapshotOptions: Optional[SnapshotOptions] - VPCOptions: Optional[VPCOptions] - CognitoOptions: Optional[CognitoOptions] - EncryptionAtRestOptions: Optional[EncryptionAtRestOptions] - NodeToNodeEncryptionOptions: Optional[NodeToNodeEncryptionOptions] - AdvancedOptions: Optional[AdvancedOptions] - LogPublishingOptions: Optional[LogPublishingOptions] - DomainEndpointOptions: Optional[DomainEndpointOptions] - AdvancedSecurityOptions: Optional[AdvancedSecurityOptionsInput] - IdentityCenterOptions: Optional[IdentityCenterOptionsInput] - TagList: Optional[TagList] - AutoTuneOptions: Optional[AutoTuneOptionsInput] - OffPeakWindowOptions: Optional[OffPeakWindowOptions] - SoftwareUpdateOptions: Optional[SoftwareUpdateOptions] - AIMLOptions: Optional[AIMLOptionsInput] + EngineVersion: VersionString | None + ClusterConfig: ClusterConfig | None + EBSOptions: EBSOptions | None + AccessPolicies: PolicyDocument | None + IPAddressType: IPAddressType | None + SnapshotOptions: SnapshotOptions | None + VPCOptions: VPCOptions | None + CognitoOptions: CognitoOptions | None + EncryptionAtRestOptions: EncryptionAtRestOptions | None + NodeToNodeEncryptionOptions: NodeToNodeEncryptionOptions | None + AdvancedOptions: AdvancedOptions | None + LogPublishingOptions: LogPublishingOptions | None + DomainEndpointOptions: DomainEndpointOptions | None + AdvancedSecurityOptions: AdvancedSecurityOptionsInput | None + IdentityCenterOptions: IdentityCenterOptionsInput | None + TagList: TagList | None + AutoTuneOptions: AutoTuneOptionsInput | None + OffPeakWindowOptions: OffPeakWindowOptions | None + SoftwareUpdateOptions: SoftwareUpdateOptions | None + AIMLOptions: AIMLOptionsInput | None class ModifyingProperties(TypedDict, total=False): - Name: Optional[String] - ActiveValue: Optional[String] - PendingValue: Optional[String] - ValueType: Optional[PropertyValueType] + Name: String | None + ActiveValue: String | None + PendingValue: String | None + ValueType: PropertyValueType | None -ModifyingPropertiesList = List[ModifyingProperties] +ModifyingPropertiesList = list[ModifyingProperties] class IdentityCenterOptions(TypedDict, total=False): - EnabledAPIAccess: Optional[Boolean] - IdentityCenterInstanceARN: Optional[IdentityCenterInstanceARN] - SubjectKey: Optional[SubjectKeyIdCOption] - RolesKey: Optional[RolesKeyIdCOption] - IdentityCenterApplicationARN: Optional[IdentityCenterApplicationARN] - IdentityStoreId: Optional[IdentityStoreId] + EnabledAPIAccess: Boolean | None + IdentityCenterInstanceARN: IdentityCenterInstanceARN | None + SubjectKey: SubjectKeyIdCOption | None + RolesKey: RolesKeyIdCOption | None + IdentityCenterApplicationARN: IdentityCenterApplicationARN | None + IdentityStoreId: IdentityStoreId | None class VPCDerivedInfo(TypedDict, total=False): - VPCId: Optional[String] - SubnetIds: Optional[StringList] - AvailabilityZones: Optional[StringList] - SecurityGroupIds: Optional[StringList] + VPCId: String | None + SubnetIds: StringList | None + AvailabilityZones: StringList | None + SecurityGroupIds: StringList | None -EndpointsMap = Dict[String, ServiceUrl] +EndpointsMap = dict[String, ServiceUrl] class DomainStatus(TypedDict, total=False): DomainId: DomainId DomainName: DomainName ARN: ARN - Created: Optional[Boolean] - Deleted: Optional[Boolean] - Endpoint: Optional[ServiceUrl] - EndpointV2: Optional[ServiceUrl] - Endpoints: Optional[EndpointsMap] - DomainEndpointV2HostedZoneId: Optional[HostedZoneId] - Processing: Optional[Boolean] - UpgradeProcessing: Optional[Boolean] - EngineVersion: Optional[VersionString] + Created: Boolean | None + Deleted: Boolean | None + Endpoint: ServiceUrl | None + EndpointV2: ServiceUrl | None + Endpoints: EndpointsMap | None + DomainEndpointV2HostedZoneId: HostedZoneId | None + Processing: Boolean | None + UpgradeProcessing: Boolean | None + EngineVersion: VersionString | None ClusterConfig: ClusterConfig - EBSOptions: Optional[EBSOptions] - AccessPolicies: Optional[PolicyDocument] - IPAddressType: Optional[IPAddressType] - SnapshotOptions: Optional[SnapshotOptions] - VPCOptions: Optional[VPCDerivedInfo] - CognitoOptions: Optional[CognitoOptions] - EncryptionAtRestOptions: Optional[EncryptionAtRestOptions] - NodeToNodeEncryptionOptions: Optional[NodeToNodeEncryptionOptions] - AdvancedOptions: Optional[AdvancedOptions] - LogPublishingOptions: Optional[LogPublishingOptions] - ServiceSoftwareOptions: Optional[ServiceSoftwareOptions] - DomainEndpointOptions: Optional[DomainEndpointOptions] - AdvancedSecurityOptions: Optional[AdvancedSecurityOptions] - IdentityCenterOptions: Optional[IdentityCenterOptions] - AutoTuneOptions: Optional[AutoTuneOptionsOutput] - ChangeProgressDetails: Optional[ChangeProgressDetails] - OffPeakWindowOptions: Optional[OffPeakWindowOptions] - SoftwareUpdateOptions: Optional[SoftwareUpdateOptions] - DomainProcessingStatus: Optional[DomainProcessingStatusType] - ModifyingProperties: Optional[ModifyingPropertiesList] - AIMLOptions: Optional[AIMLOptionsOutput] + EBSOptions: EBSOptions | None + AccessPolicies: PolicyDocument | None + IPAddressType: IPAddressType | None + SnapshotOptions: SnapshotOptions | None + VPCOptions: VPCDerivedInfo | None + CognitoOptions: CognitoOptions | None + EncryptionAtRestOptions: EncryptionAtRestOptions | None + NodeToNodeEncryptionOptions: NodeToNodeEncryptionOptions | None + AdvancedOptions: AdvancedOptions | None + LogPublishingOptions: LogPublishingOptions | None + ServiceSoftwareOptions: ServiceSoftwareOptions | None + DomainEndpointOptions: DomainEndpointOptions | None + AdvancedSecurityOptions: AdvancedSecurityOptions | None + IdentityCenterOptions: IdentityCenterOptions | None + AutoTuneOptions: AutoTuneOptionsOutput | None + ChangeProgressDetails: ChangeProgressDetails | None + OffPeakWindowOptions: OffPeakWindowOptions | None + SoftwareUpdateOptions: SoftwareUpdateOptions | None + DomainProcessingStatus: DomainProcessingStatusType | None + ModifyingProperties: ModifyingPropertiesList | None + AIMLOptions: AIMLOptionsOutput | None class CreateDomainResponse(TypedDict, total=False): - DomainStatus: Optional[DomainStatus] + DomainStatus: DomainStatus | None + + +class IndexSchema(TypedDict, total=False): + pass + + +class CreateIndexRequest(ServiceRequest): + DomainName: DomainName + IndexName: IndexName + IndexSchema: IndexSchema + + +class CreateIndexResponse(TypedDict, total=False): + Status: IndexStatus class CreateOutboundConnectionRequest(ServiceRequest): LocalDomainInfo: DomainInformationContainer RemoteDomainInfo: DomainInformationContainer ConnectionAlias: ConnectionAlias - ConnectionMode: Optional[ConnectionMode] - ConnectionProperties: Optional[ConnectionProperties] + ConnectionMode: ConnectionMode | None + ConnectionProperties: ConnectionProperties | None class OutboundConnectionStatus(TypedDict, total=False): - StatusCode: Optional[OutboundConnectionStatusCode] - Message: Optional[ConnectionStatusMessage] + StatusCode: OutboundConnectionStatusCode | None + Message: ConnectionStatusMessage | None class CreateOutboundConnectionResponse(TypedDict, total=False): - LocalDomainInfo: Optional[DomainInformationContainer] - RemoteDomainInfo: Optional[DomainInformationContainer] - ConnectionAlias: Optional[ConnectionAlias] - ConnectionStatus: Optional[OutboundConnectionStatus] - ConnectionId: Optional[ConnectionId] - ConnectionMode: Optional[ConnectionMode] - ConnectionProperties: Optional[ConnectionProperties] + LocalDomainInfo: DomainInformationContainer | None + RemoteDomainInfo: DomainInformationContainer | None + ConnectionAlias: ConnectionAlias | None + ConnectionStatus: OutboundConnectionStatus | None + ConnectionId: ConnectionId | None + ConnectionMode: ConnectionMode | None + ConnectionProperties: ConnectionProperties | None class PackageEncryptionOptions(TypedDict, total=False): - KmsKeyIdentifier: Optional[KmsKeyId] + KmsKeyIdentifier: KmsKeyId | None EncryptionEnabled: Boolean @@ -1500,78 +1537,78 @@ class PackageVendingOptions(TypedDict, total=False): class PackageConfiguration(TypedDict, total=False): LicenseRequirement: RequirementLevel - LicenseFilepath: Optional[LicenseFilepath] + LicenseFilepath: LicenseFilepath | None ConfigurationRequirement: RequirementLevel - RequiresRestartForConfigurationUpdate: Optional[Boolean] + RequiresRestartForConfigurationUpdate: Boolean | None class PackageSource(TypedDict, total=False): - S3BucketName: Optional[S3BucketName] - S3Key: Optional[S3Key] + S3BucketName: S3BucketName | None + S3Key: S3Key | None class CreatePackageRequest(ServiceRequest): PackageName: PackageName PackageType: PackageType - PackageDescription: Optional[PackageDescription] + PackageDescription: PackageDescription | None PackageSource: PackageSource - PackageConfiguration: Optional[PackageConfiguration] - EngineVersion: Optional[EngineVersion] - PackageVendingOptions: Optional[PackageVendingOptions] - PackageEncryptionOptions: Optional[PackageEncryptionOptions] + PackageConfiguration: PackageConfiguration | None + EngineVersion: EngineVersion | None + PackageVendingOptions: PackageVendingOptions | None + PackageEncryptionOptions: PackageEncryptionOptions | None -PackageUserList = List[PackageUser] +PackageUserList = list[PackageUser] UncompressedPluginSizeInBytes = int class PluginProperties(TypedDict, total=False): - Name: Optional[PluginName] - Description: Optional[PluginDescription] - Version: Optional[PluginVersion] - ClassName: Optional[PluginClassName] - UncompressedSizeInBytes: Optional[UncompressedPluginSizeInBytes] + Name: PluginName | None + Description: PluginDescription | None + Version: PluginVersion | None + ClassName: PluginClassName | None + UncompressedSizeInBytes: UncompressedPluginSizeInBytes | None CreatedAt = datetime class PackageDetails(TypedDict, total=False): - PackageID: Optional[PackageID] - PackageName: Optional[PackageName] - PackageType: Optional[PackageType] - PackageDescription: Optional[PackageDescription] - PackageStatus: Optional[PackageStatus] - CreatedAt: Optional[CreatedAt] - LastUpdatedAt: Optional[LastUpdated] - AvailablePackageVersion: Optional[PackageVersion] - ErrorDetails: Optional[ErrorDetails] - EngineVersion: Optional[EngineVersion] - AvailablePluginProperties: Optional[PluginProperties] - AvailablePackageConfiguration: Optional[PackageConfiguration] - AllowListedUserList: Optional[PackageUserList] - PackageOwner: Optional[PackageOwner] - PackageVendingOptions: Optional[PackageVendingOptions] - PackageEncryptionOptions: Optional[PackageEncryptionOptions] + PackageID: PackageID | None + PackageName: PackageName | None + PackageType: PackageType | None + PackageDescription: PackageDescription | None + PackageStatus: PackageStatus | None + CreatedAt: CreatedAt | None + LastUpdatedAt: LastUpdated | None + AvailablePackageVersion: PackageVersion | None + ErrorDetails: ErrorDetails | None + EngineVersion: EngineVersion | None + AvailablePluginProperties: PluginProperties | None + AvailablePackageConfiguration: PackageConfiguration | None + AllowListedUserList: PackageUserList | None + PackageOwner: PackageOwner | None + PackageVendingOptions: PackageVendingOptions | None + PackageEncryptionOptions: PackageEncryptionOptions | None class CreatePackageResponse(TypedDict, total=False): - PackageDetails: Optional[PackageDetails] + PackageDetails: PackageDetails | None class CreateVpcEndpointRequest(ServiceRequest): DomainArn: DomainArn VpcOptions: VPCOptions - ClientToken: Optional[ClientToken] + ClientToken: ClientToken | None class VpcEndpoint(TypedDict, total=False): - VpcEndpointId: Optional[VpcEndpointId] - VpcEndpointOwner: Optional[AWSAccount] - DomainArn: Optional[DomainArn] - VpcOptions: Optional[VPCDerivedInfo] - Status: Optional[VpcEndpointStatus] - Endpoint: Optional[Endpoint] + VpcEndpointId: VpcEndpointId | None + VpcEndpointOwner: AWSAccount | None + DomainArn: DomainArn | None + VpcOptions: VPCDerivedInfo | None + Status: VpcEndpointStatus | None + Endpoint: Endpoint | None class CreateVpcEndpointResponse(TypedDict, total=False): @@ -1579,13 +1616,13 @@ class CreateVpcEndpointResponse(TypedDict, total=False): class DataSourceDetails(TypedDict, total=False): - DataSourceType: Optional[DataSourceType] - Name: Optional[DataSourceName] - Description: Optional[DataSourceDescription] - Status: Optional[DataSourceStatus] + DataSourceType: DataSourceType | None + Name: DataSourceName | None + Description: DataSourceDescription | None + Status: DataSourceStatus | None -DataSourceList = List[DataSourceDetails] +DataSourceList = list[DataSourceDetails] class DeleteApplicationRequest(ServiceRequest): @@ -1602,7 +1639,7 @@ class DeleteDataSourceRequest(ServiceRequest): class DeleteDataSourceResponse(TypedDict, total=False): - Message: Optional[String] + Message: String | None class DeleteDirectQueryDataSourceRequest(ServiceRequest): @@ -1614,7 +1651,7 @@ class DeleteDomainRequest(ServiceRequest): class DeleteDomainResponse(TypedDict, total=False): - DomainStatus: Optional[DomainStatus] + DomainStatus: DomainStatus | None class DeleteInboundConnectionRequest(ServiceRequest): @@ -1622,7 +1659,16 @@ class DeleteInboundConnectionRequest(ServiceRequest): class DeleteInboundConnectionResponse(TypedDict, total=False): - Connection: Optional[InboundConnection] + Connection: InboundConnection | None + + +class DeleteIndexRequest(ServiceRequest): + DomainName: DomainName + IndexName: IndexName + + +class DeleteIndexResponse(TypedDict, total=False): + Status: IndexStatus class DeleteOutboundConnectionRequest(ServiceRequest): @@ -1630,17 +1676,17 @@ class DeleteOutboundConnectionRequest(ServiceRequest): class OutboundConnection(TypedDict, total=False): - LocalDomainInfo: Optional[DomainInformationContainer] - RemoteDomainInfo: Optional[DomainInformationContainer] - ConnectionId: Optional[ConnectionId] - ConnectionAlias: Optional[ConnectionAlias] - ConnectionStatus: Optional[OutboundConnectionStatus] - ConnectionMode: Optional[ConnectionMode] - ConnectionProperties: Optional[ConnectionProperties] + LocalDomainInfo: DomainInformationContainer | None + RemoteDomainInfo: DomainInformationContainer | None + ConnectionId: ConnectionId | None + ConnectionAlias: ConnectionAlias | None + ConnectionStatus: OutboundConnectionStatus | None + ConnectionMode: ConnectionMode | None + ConnectionProperties: ConnectionProperties | None class DeleteOutboundConnectionResponse(TypedDict, total=False): - Connection: Optional[OutboundConnection] + Connection: OutboundConnection | None class DeletePackageRequest(ServiceRequest): @@ -1648,7 +1694,7 @@ class DeletePackageRequest(ServiceRequest): class DeletePackageResponse(TypedDict, total=False): - PackageDetails: Optional[PackageDetails] + PackageDetails: PackageDetails | None class DeleteVpcEndpointRequest(ServiceRequest): @@ -1656,10 +1702,10 @@ class DeleteVpcEndpointRequest(ServiceRequest): class VpcEndpointSummary(TypedDict, total=False): - VpcEndpointId: Optional[VpcEndpointId] - VpcEndpointOwner: Optional[String] - DomainArn: Optional[DomainArn] - Status: Optional[VpcEndpointStatus] + VpcEndpointId: VpcEndpointId | None + VpcEndpointOwner: String | None + DomainArn: DomainArn | None + Status: VpcEndpointStatus | None class DeleteVpcEndpointResponse(TypedDict, total=False): @@ -1668,22 +1714,22 @@ class DeleteVpcEndpointResponse(TypedDict, total=False): class DescribeDomainAutoTunesRequest(ServiceRequest): DomainName: DomainName - MaxResults: Optional[MaxResults] - NextToken: Optional[NextToken] + MaxResults: MaxResults | None + NextToken: NextToken | None class DescribeDomainAutoTunesResponse(TypedDict, total=False): - AutoTunes: Optional[AutoTuneList] - NextToken: Optional[NextToken] + AutoTunes: AutoTuneList | None + NextToken: NextToken | None class DescribeDomainChangeProgressRequest(ServiceRequest): DomainName: DomainName - ChangeId: Optional[GUID] + ChangeId: GUID | None class DescribeDomainChangeProgressResponse(TypedDict, total=False): - ChangeProgressStatus: Optional[ChangeProgressStatusDetails] + ChangeProgressStatus: ChangeProgressStatusDetails | None class DescribeDomainConfigRequest(ServiceRequest): @@ -1691,13 +1737,13 @@ class DescribeDomainConfigRequest(ServiceRequest): class SoftwareUpdateOptionsStatus(TypedDict, total=False): - Options: Optional[SoftwareUpdateOptions] - Status: Optional[OptionStatus] + Options: SoftwareUpdateOptions | None + Status: OptionStatus | None class OffPeakWindowOptionsStatus(TypedDict, total=False): - Options: Optional[OffPeakWindowOptions] - Status: Optional[OptionStatus] + Options: OffPeakWindowOptions | None + Status: OptionStatus | None class IdentityCenterOptionsStatus(TypedDict, total=False): @@ -1711,8 +1757,8 @@ class DomainEndpointOptionsStatus(TypedDict, total=False): class LogPublishingOptionsStatus(TypedDict, total=False): - Options: Optional[LogPublishingOptions] - Status: Optional[OptionStatus] + Options: LogPublishingOptions | None + Status: OptionStatus | None class NodeToNodeEncryptionOptionsStatus(TypedDict, total=False): @@ -1751,27 +1797,27 @@ class VersionStatus(TypedDict, total=False): class DomainConfig(TypedDict, total=False): - EngineVersion: Optional[VersionStatus] - ClusterConfig: Optional[ClusterConfigStatus] - EBSOptions: Optional[EBSOptionsStatus] - AccessPolicies: Optional[AccessPoliciesStatus] - IPAddressType: Optional[IPAddressTypeStatus] - SnapshotOptions: Optional[SnapshotOptionsStatus] - VPCOptions: Optional[VPCDerivedInfoStatus] - CognitoOptions: Optional[CognitoOptionsStatus] - EncryptionAtRestOptions: Optional[EncryptionAtRestOptionsStatus] - NodeToNodeEncryptionOptions: Optional[NodeToNodeEncryptionOptionsStatus] - AdvancedOptions: Optional[AdvancedOptionsStatus] - LogPublishingOptions: Optional[LogPublishingOptionsStatus] - DomainEndpointOptions: Optional[DomainEndpointOptionsStatus] - AdvancedSecurityOptions: Optional[AdvancedSecurityOptionsStatus] - IdentityCenterOptions: Optional[IdentityCenterOptionsStatus] - AutoTuneOptions: Optional[AutoTuneOptionsStatus] - ChangeProgressDetails: Optional[ChangeProgressDetails] - OffPeakWindowOptions: Optional[OffPeakWindowOptionsStatus] - SoftwareUpdateOptions: Optional[SoftwareUpdateOptionsStatus] - ModifyingProperties: Optional[ModifyingPropertiesList] - AIMLOptions: Optional[AIMLOptionsStatus] + EngineVersion: VersionStatus | None + ClusterConfig: ClusterConfigStatus | None + EBSOptions: EBSOptionsStatus | None + AccessPolicies: AccessPoliciesStatus | None + IPAddressType: IPAddressTypeStatus | None + SnapshotOptions: SnapshotOptionsStatus | None + VPCOptions: VPCDerivedInfoStatus | None + CognitoOptions: CognitoOptionsStatus | None + EncryptionAtRestOptions: EncryptionAtRestOptionsStatus | None + NodeToNodeEncryptionOptions: NodeToNodeEncryptionOptionsStatus | None + AdvancedOptions: AdvancedOptionsStatus | None + LogPublishingOptions: LogPublishingOptionsStatus | None + DomainEndpointOptions: DomainEndpointOptionsStatus | None + AdvancedSecurityOptions: AdvancedSecurityOptionsStatus | None + IdentityCenterOptions: IdentityCenterOptionsStatus | None + AutoTuneOptions: AutoTuneOptionsStatus | None + ChangeProgressDetails: ChangeProgressDetails | None + OffPeakWindowOptions: OffPeakWindowOptionsStatus | None + SoftwareUpdateOptions: SoftwareUpdateOptionsStatus | None + ModifyingProperties: ModifyingPropertiesList | None + AIMLOptions: AIMLOptionsStatus | None class DescribeDomainConfigResponse(TypedDict, total=False): @@ -1783,26 +1829,26 @@ class DescribeDomainHealthRequest(ServiceRequest): class EnvironmentInfo(TypedDict, total=False): - AvailabilityZoneInformation: Optional[AvailabilityZoneInfoList] + AvailabilityZoneInformation: AvailabilityZoneInfoList | None -EnvironmentInfoList = List[EnvironmentInfo] +EnvironmentInfoList = list[EnvironmentInfo] class DescribeDomainHealthResponse(TypedDict, total=False): - DomainState: Optional[DomainState] - AvailabilityZoneCount: Optional[NumberOfAZs] - ActiveAvailabilityZoneCount: Optional[NumberOfAZs] - StandByAvailabilityZoneCount: Optional[NumberOfAZs] - DataNodeCount: Optional[NumberOfNodes] - DedicatedMaster: Optional[Boolean] - MasterEligibleNodeCount: Optional[NumberOfNodes] - WarmNodeCount: Optional[NumberOfNodes] - MasterNode: Optional[MasterNodeStatus] - ClusterHealth: Optional[DomainHealth] - TotalShards: Optional[NumberOfShards] - TotalUnAssignedShards: Optional[NumberOfShards] - EnvironmentInformation: Optional[EnvironmentInfoList] + DomainState: DomainState | None + AvailabilityZoneCount: NumberOfAZs | None + ActiveAvailabilityZoneCount: NumberOfAZs | None + StandByAvailabilityZoneCount: NumberOfAZs | None + DataNodeCount: NumberOfNodes | None + DedicatedMaster: Boolean | None + MasterEligibleNodeCount: NumberOfNodes | None + WarmNodeCount: NumberOfNodes | None + MasterNode: MasterNodeStatus | None + ClusterHealth: DomainHealth | None + TotalShards: NumberOfShards | None + TotalUnAssignedShards: NumberOfShards | None + EnvironmentInformation: EnvironmentInfoList | None class DescribeDomainNodesRequest(ServiceRequest): @@ -1810,21 +1856,21 @@ class DescribeDomainNodesRequest(ServiceRequest): class DomainNodesStatus(TypedDict, total=False): - NodeId: Optional[NodeId] - NodeType: Optional[NodeType] - AvailabilityZone: Optional[AvailabilityZone] - InstanceType: Optional[OpenSearchPartitionInstanceType] - NodeStatus: Optional[NodeStatus] - StorageType: Optional[StorageTypeName] - StorageVolumeType: Optional[VolumeType] - StorageSize: Optional[VolumeSize] + NodeId: NodeId | None + NodeType: NodeType | None + AvailabilityZone: AvailabilityZone | None + InstanceType: OpenSearchPartitionInstanceType | None + NodeStatus: NodeStatus | None + StorageType: StorageTypeName | None + StorageVolumeType: VolumeType | None + StorageSize: VolumeSize | None -DomainNodesStatusList = List[DomainNodesStatus] +DomainNodesStatusList = list[DomainNodesStatus] class DescribeDomainNodesResponse(TypedDict, total=False): - DomainNodesStatusList: Optional[DomainNodesStatusList] + DomainNodesStatusList: DomainNodesStatusList | None class DescribeDomainRequest(ServiceRequest): @@ -1835,14 +1881,14 @@ class DescribeDomainResponse(TypedDict, total=False): DomainStatus: DomainStatus -DomainNameList = List[DomainName] +DomainNameList = list[DomainName] class DescribeDomainsRequest(ServiceRequest): DomainNames: DomainNameList -DomainStatusList = List[DomainStatus] +DomainStatusList = list[DomainStatus] class DescribeDomainsResponse(TypedDict, total=False): @@ -1851,21 +1897,21 @@ class DescribeDomainsResponse(TypedDict, total=False): class DescribeDryRunProgressRequest(ServiceRequest): DomainName: DomainName - DryRunId: Optional[GUID] - LoadDryRunConfig: Optional[Boolean] + DryRunId: GUID | None + LoadDryRunConfig: Boolean | None class DryRunResults(TypedDict, total=False): - DeploymentType: Optional[DeploymentType] - Message: Optional[Message] + DeploymentType: DeploymentType | None + Message: Message | None class ValidationFailure(TypedDict, total=False): - Code: Optional[String] - Message: Optional[String] + Code: String | None + Message: String | None -ValidationFailures = List[ValidationFailure] +ValidationFailures = list[ValidationFailure] class DryRunProgressStatus(TypedDict, total=False): @@ -1873,189 +1919,189 @@ class DryRunProgressStatus(TypedDict, total=False): DryRunStatus: String CreationDate: String UpdateDate: String - ValidationFailures: Optional[ValidationFailures] + ValidationFailures: ValidationFailures | None class DescribeDryRunProgressResponse(TypedDict, total=False): - DryRunProgressStatus: Optional[DryRunProgressStatus] - DryRunConfig: Optional[DomainStatus] - DryRunResults: Optional[DryRunResults] + DryRunProgressStatus: DryRunProgressStatus | None + DryRunConfig: DomainStatus | None + DryRunResults: DryRunResults | None -ValueStringList = List[NonEmptyString] +ValueStringList = list[NonEmptyString] class Filter(TypedDict, total=False): - Name: Optional[NonEmptyString] - Values: Optional[ValueStringList] + Name: NonEmptyString | None + Values: ValueStringList | None -FilterList = List[Filter] +FilterList = list[Filter] class DescribeInboundConnectionsRequest(ServiceRequest): - Filters: Optional[FilterList] - MaxResults: Optional[MaxResults] - NextToken: Optional[NextToken] + Filters: FilterList | None + MaxResults: MaxResults | None + NextToken: NextToken | None -InboundConnections = List[InboundConnection] +InboundConnections = list[InboundConnection] class DescribeInboundConnectionsResponse(TypedDict, total=False): - Connections: Optional[InboundConnections] - NextToken: Optional[NextToken] + Connections: InboundConnections | None + NextToken: NextToken | None class DescribeInstanceTypeLimitsRequest(ServiceRequest): - DomainName: Optional[DomainName] + DomainName: DomainName | None InstanceType: OpenSearchPartitionInstanceType EngineVersion: VersionString class InstanceCountLimits(TypedDict, total=False): - MinimumInstanceCount: Optional[MinimumInstanceCount] - MaximumInstanceCount: Optional[MaximumInstanceCount] + MinimumInstanceCount: MinimumInstanceCount | None + MaximumInstanceCount: MaximumInstanceCount | None class InstanceLimits(TypedDict, total=False): - InstanceCountLimits: Optional[InstanceCountLimits] + InstanceCountLimits: InstanceCountLimits | None class StorageTypeLimit(TypedDict, total=False): - LimitName: Optional[LimitName] - LimitValues: Optional[LimitValueList] + LimitName: LimitName | None + LimitValues: LimitValueList | None -StorageTypeLimitList = List[StorageTypeLimit] +StorageTypeLimitList = list[StorageTypeLimit] class StorageType(TypedDict, total=False): - StorageTypeName: Optional[StorageTypeName] - StorageSubTypeName: Optional[StorageSubTypeName] - StorageTypeLimits: Optional[StorageTypeLimitList] + StorageTypeName: StorageTypeName | None + StorageSubTypeName: StorageSubTypeName | None + StorageTypeLimits: StorageTypeLimitList | None -StorageTypeList = List[StorageType] +StorageTypeList = list[StorageType] class Limits(TypedDict, total=False): - StorageTypes: Optional[StorageTypeList] - InstanceLimits: Optional[InstanceLimits] - AdditionalLimits: Optional[AdditionalLimitList] + StorageTypes: StorageTypeList | None + InstanceLimits: InstanceLimits | None + AdditionalLimits: AdditionalLimitList | None -LimitsByRole = Dict[InstanceRole, Limits] +LimitsByRole = dict[InstanceRole, Limits] class DescribeInstanceTypeLimitsResponse(TypedDict, total=False): - LimitsByRole: Optional[LimitsByRole] + LimitsByRole: LimitsByRole | None class DescribeOutboundConnectionsRequest(ServiceRequest): - Filters: Optional[FilterList] - MaxResults: Optional[MaxResults] - NextToken: Optional[NextToken] + Filters: FilterList | None + MaxResults: MaxResults | None + NextToken: NextToken | None -OutboundConnections = List[OutboundConnection] +OutboundConnections = list[OutboundConnection] class DescribeOutboundConnectionsResponse(TypedDict, total=False): - Connections: Optional[OutboundConnections] - NextToken: Optional[NextToken] + Connections: OutboundConnections | None + NextToken: NextToken | None -DescribePackagesFilterValues = List[DescribePackagesFilterValue] +DescribePackagesFilterValues = list[DescribePackagesFilterValue] class DescribePackagesFilter(TypedDict, total=False): - Name: Optional[DescribePackagesFilterName] - Value: Optional[DescribePackagesFilterValues] + Name: DescribePackagesFilterName | None + Value: DescribePackagesFilterValues | None -DescribePackagesFilterList = List[DescribePackagesFilter] +DescribePackagesFilterList = list[DescribePackagesFilter] class DescribePackagesRequest(ServiceRequest): - Filters: Optional[DescribePackagesFilterList] - MaxResults: Optional[MaxResults] - NextToken: Optional[NextToken] + Filters: DescribePackagesFilterList | None + MaxResults: MaxResults | None + NextToken: NextToken | None -PackageDetailsList = List[PackageDetails] +PackageDetailsList = list[PackageDetails] class DescribePackagesResponse(TypedDict, total=False): - PackageDetailsList: Optional[PackageDetailsList] - NextToken: Optional[String] + PackageDetailsList: PackageDetailsList | None + NextToken: String | None class DescribeReservedInstanceOfferingsRequest(ServiceRequest): - ReservedInstanceOfferingId: Optional[GUID] - MaxResults: Optional[MaxResults] - NextToken: Optional[NextToken] + ReservedInstanceOfferingId: GUID | None + MaxResults: MaxResults | None + NextToken: NextToken | None class RecurringCharge(TypedDict, total=False): - RecurringChargeAmount: Optional[Double] - RecurringChargeFrequency: Optional[String] + RecurringChargeAmount: Double | None + RecurringChargeFrequency: String | None -RecurringChargeList = List[RecurringCharge] +RecurringChargeList = list[RecurringCharge] class ReservedInstanceOffering(TypedDict, total=False): - ReservedInstanceOfferingId: Optional[GUID] - InstanceType: Optional[OpenSearchPartitionInstanceType] - Duration: Optional[Integer] - FixedPrice: Optional[Double] - UsagePrice: Optional[Double] - CurrencyCode: Optional[String] - PaymentOption: Optional[ReservedInstancePaymentOption] - RecurringCharges: Optional[RecurringChargeList] + ReservedInstanceOfferingId: GUID | None + InstanceType: OpenSearchPartitionInstanceType | None + Duration: Integer | None + FixedPrice: Double | None + UsagePrice: Double | None + CurrencyCode: String | None + PaymentOption: ReservedInstancePaymentOption | None + RecurringCharges: RecurringChargeList | None -ReservedInstanceOfferingList = List[ReservedInstanceOffering] +ReservedInstanceOfferingList = list[ReservedInstanceOffering] class DescribeReservedInstanceOfferingsResponse(TypedDict, total=False): - NextToken: Optional[NextToken] - ReservedInstanceOfferings: Optional[ReservedInstanceOfferingList] + NextToken: NextToken | None + ReservedInstanceOfferings: ReservedInstanceOfferingList | None class DescribeReservedInstancesRequest(ServiceRequest): - ReservedInstanceId: Optional[GUID] - MaxResults: Optional[MaxResults] - NextToken: Optional[NextToken] + ReservedInstanceId: GUID | None + MaxResults: MaxResults | None + NextToken: NextToken | None class ReservedInstance(TypedDict, total=False): - ReservationName: Optional[ReservationToken] - ReservedInstanceId: Optional[GUID] - BillingSubscriptionId: Optional[Long] - ReservedInstanceOfferingId: Optional[String] - InstanceType: Optional[OpenSearchPartitionInstanceType] - StartTime: Optional[UpdateTimestamp] - Duration: Optional[Integer] - FixedPrice: Optional[Double] - UsagePrice: Optional[Double] - CurrencyCode: Optional[String] - InstanceCount: Optional[Integer] - State: Optional[String] - PaymentOption: Optional[ReservedInstancePaymentOption] - RecurringCharges: Optional[RecurringChargeList] + ReservationName: ReservationToken | None + ReservedInstanceId: GUID | None + BillingSubscriptionId: Long | None + ReservedInstanceOfferingId: String | None + InstanceType: OpenSearchPartitionInstanceType | None + StartTime: UpdateTimestamp | None + Duration: Integer | None + FixedPrice: Double | None + UsagePrice: Double | None + CurrencyCode: String | None + InstanceCount: Integer | None + State: String | None + PaymentOption: ReservedInstancePaymentOption | None + RecurringCharges: RecurringChargeList | None -ReservedInstanceList = List[ReservedInstance] +ReservedInstanceList = list[ReservedInstance] class DescribeReservedInstancesResponse(TypedDict, total=False): - NextToken: Optional[String] - ReservedInstances: Optional[ReservedInstanceList] + NextToken: String | None + ReservedInstances: ReservedInstanceList | None -VpcEndpointIdList = List[VpcEndpointId] +VpcEndpointIdList = list[VpcEndpointId] class DescribeVpcEndpointsRequest(ServiceRequest): @@ -2063,13 +2109,13 @@ class DescribeVpcEndpointsRequest(ServiceRequest): class VpcEndpointError(TypedDict, total=False): - VpcEndpointId: Optional[VpcEndpointId] - ErrorCode: Optional[VpcEndpointErrorCode] - ErrorMessage: Optional[String] + VpcEndpointId: VpcEndpointId | None + ErrorCode: VpcEndpointErrorCode | None + ErrorMessage: String | None -VpcEndpointErrorList = List[VpcEndpointError] -VpcEndpoints = List[VpcEndpoint] +VpcEndpointErrorList = list[VpcEndpointError] +VpcEndpoints = list[VpcEndpoint] class DescribeVpcEndpointsResponse(TypedDict, total=False): @@ -2078,15 +2124,15 @@ class DescribeVpcEndpointsResponse(TypedDict, total=False): class DirectQueryDataSource(TypedDict, total=False): - DataSourceName: Optional[DirectQueryDataSourceName] - DataSourceType: Optional[DirectQueryDataSourceType] - Description: Optional[DirectQueryDataSourceDescription] - OpenSearchArns: Optional[DirectQueryOpenSearchARNList] - DataSourceArn: Optional[String] - TagList: Optional[TagList] + DataSourceName: DirectQueryDataSourceName | None + DataSourceType: DirectQueryDataSourceType | None + Description: DirectQueryDataSourceDescription | None + OpenSearchArns: DirectQueryOpenSearchARNList | None + DataSourceArn: String | None + TagList: TagList | None -DirectQueryDataSourceList = List[DirectQueryDataSource] +DirectQueryDataSourceList = list[DirectQueryDataSource] class DissociatePackageRequest(ServiceRequest): @@ -2095,7 +2141,7 @@ class DissociatePackageRequest(ServiceRequest): class DissociatePackageResponse(TypedDict, total=False): - DomainPackageDetails: Optional[DomainPackageDetails] + DomainPackageDetails: DomainPackageDetails | None class DissociatePackagesRequest(ServiceRequest): @@ -2104,29 +2150,29 @@ class DissociatePackagesRequest(ServiceRequest): class DissociatePackagesResponse(TypedDict, total=False): - DomainPackageDetailsList: Optional[DomainPackageDetailsList] + DomainPackageDetailsList: DomainPackageDetailsList | None class DomainInfo(TypedDict, total=False): - DomainName: Optional[DomainName] - EngineType: Optional[EngineType] + DomainName: DomainName | None + EngineType: EngineType | None -DomainInfoList = List[DomainInfo] +DomainInfoList = list[DomainInfo] class DomainMaintenanceDetails(TypedDict, total=False): - MaintenanceId: Optional[RequestId] - DomainName: Optional[DomainName] - Action: Optional[MaintenanceType] - NodeId: Optional[NodeId] - Status: Optional[MaintenanceStatus] - StatusMessage: Optional[MaintenanceStatusMessage] - CreatedAt: Optional[UpdateTimestamp] - UpdatedAt: Optional[UpdateTimestamp] + MaintenanceId: RequestId | None + DomainName: DomainName | None + Action: MaintenanceType | None + NodeId: NodeId | None + Status: MaintenanceStatus | None + StatusMessage: MaintenanceStatusMessage | None + CreatedAt: UpdateTimestamp | None + UpdatedAt: UpdateTimestamp | None -DomainMaintenanceList = List[DomainMaintenanceDetails] +DomainMaintenanceList = list[DomainMaintenanceDetails] class GetApplicationRequest(ServiceRequest): @@ -2134,24 +2180,25 @@ class GetApplicationRequest(ServiceRequest): class GetApplicationResponse(TypedDict, total=False): - id: Optional[Id] - arn: Optional[ARN] - name: Optional[ApplicationName] - endpoint: Optional[String] - status: Optional[ApplicationStatus] - iamIdentityCenterOptions: Optional[IamIdentityCenterOptions] - dataSources: Optional[DataSources] - appConfigs: Optional[AppConfigs] - createdAt: Optional[Timestamp] - lastUpdatedAt: Optional[Timestamp] + id: Id | None + arn: ARN | None + name: ApplicationName | None + endpoint: String | None + status: ApplicationStatus | None + iamIdentityCenterOptions: IamIdentityCenterOptions | None + dataSources: DataSources | None + appConfigs: AppConfigs | None + createdAt: Timestamp | None + lastUpdatedAt: Timestamp | None + kmsKeyArn: KmsKeyArn | None class GetCompatibleVersionsRequest(ServiceRequest): - DomainName: Optional[DomainName] + DomainName: DomainName | None class GetCompatibleVersionsResponse(TypedDict, total=False): - CompatibleVersions: Optional[CompatibleVersionsList] + CompatibleVersions: CompatibleVersionsList | None class GetDataSourceRequest(ServiceRequest): @@ -2160,10 +2207,18 @@ class GetDataSourceRequest(ServiceRequest): class GetDataSourceResponse(TypedDict, total=False): - DataSourceType: Optional[DataSourceType] - Name: Optional[DataSourceName] - Description: Optional[DataSourceDescription] - Status: Optional[DataSourceStatus] + DataSourceType: DataSourceType | None + Name: DataSourceName | None + Description: DataSourceDescription | None + Status: DataSourceStatus | None + + +class GetDefaultApplicationSettingRequest(ServiceRequest): + pass + + +class GetDefaultApplicationSettingResponse(TypedDict, total=False): + applicationArn: ARN | None class GetDirectQueryDataSourceRequest(ServiceRequest): @@ -2171,11 +2226,11 @@ class GetDirectQueryDataSourceRequest(ServiceRequest): class GetDirectQueryDataSourceResponse(TypedDict, total=False): - DataSourceName: Optional[DirectQueryDataSourceName] - DataSourceType: Optional[DirectQueryDataSourceType] - Description: Optional[DirectQueryDataSourceDescription] - OpenSearchArns: Optional[DirectQueryOpenSearchARNList] - DataSourceArn: Optional[String] + DataSourceName: DirectQueryDataSourceName | None + DataSourceType: DirectQueryDataSourceType | None + Description: DirectQueryDataSourceDescription | None + OpenSearchArns: DirectQueryOpenSearchARNList | None + DataSourceArn: String | None class GetDomainMaintenanceStatusRequest(ServiceRequest): @@ -2184,70 +2239,79 @@ class GetDomainMaintenanceStatusRequest(ServiceRequest): class GetDomainMaintenanceStatusResponse(TypedDict, total=False): - Status: Optional[MaintenanceStatus] - StatusMessage: Optional[MaintenanceStatusMessage] - NodeId: Optional[NodeId] - Action: Optional[MaintenanceType] - CreatedAt: Optional[UpdateTimestamp] - UpdatedAt: Optional[UpdateTimestamp] + Status: MaintenanceStatus | None + StatusMessage: MaintenanceStatusMessage | None + NodeId: NodeId | None + Action: MaintenanceType | None + CreatedAt: UpdateTimestamp | None + UpdatedAt: UpdateTimestamp | None + + +class GetIndexRequest(ServiceRequest): + DomainName: DomainName + IndexName: IndexName + + +class GetIndexResponse(TypedDict, total=False): + IndexSchema: IndexSchema class GetPackageVersionHistoryRequest(ServiceRequest): PackageID: PackageID - MaxResults: Optional[MaxResults] - NextToken: Optional[NextToken] + MaxResults: MaxResults | None + NextToken: NextToken | None class PackageVersionHistory(TypedDict, total=False): - PackageVersion: Optional[PackageVersion] - CommitMessage: Optional[CommitMessage] - CreatedAt: Optional[CreatedAt] - PluginProperties: Optional[PluginProperties] - PackageConfiguration: Optional[PackageConfiguration] + PackageVersion: PackageVersion | None + CommitMessage: CommitMessage | None + CreatedAt: CreatedAt | None + PluginProperties: PluginProperties | None + PackageConfiguration: PackageConfiguration | None -PackageVersionHistoryList = List[PackageVersionHistory] +PackageVersionHistoryList = list[PackageVersionHistory] class GetPackageVersionHistoryResponse(TypedDict, total=False): - PackageID: Optional[PackageID] - PackageVersionHistoryList: Optional[PackageVersionHistoryList] - NextToken: Optional[String] + PackageID: PackageID | None + PackageVersionHistoryList: PackageVersionHistoryList | None + NextToken: String | None class GetUpgradeHistoryRequest(ServiceRequest): DomainName: DomainName - MaxResults: Optional[MaxResults] - NextToken: Optional[NextToken] + MaxResults: MaxResults | None + NextToken: NextToken | None -Issues = List[Issue] +Issues = list[Issue] class UpgradeStepItem(TypedDict, total=False): - UpgradeStep: Optional[UpgradeStep] - UpgradeStepStatus: Optional[UpgradeStatus] - Issues: Optional[Issues] - ProgressPercent: Optional[Double] + UpgradeStep: UpgradeStep | None + UpgradeStepStatus: UpgradeStatus | None + Issues: Issues | None + ProgressPercent: Double | None -UpgradeStepsList = List[UpgradeStepItem] +UpgradeStepsList = list[UpgradeStepItem] StartTimestamp = datetime class UpgradeHistory(TypedDict, total=False): - UpgradeName: Optional[UpgradeName] - StartTimestamp: Optional[StartTimestamp] - UpgradeStatus: Optional[UpgradeStatus] - StepsList: Optional[UpgradeStepsList] + UpgradeName: UpgradeName | None + StartTimestamp: StartTimestamp | None + UpgradeStatus: UpgradeStatus | None + StepsList: UpgradeStepsList | None -UpgradeHistoryList = List[UpgradeHistory] +UpgradeHistoryList = list[UpgradeHistory] class GetUpgradeHistoryResponse(TypedDict, total=False): - UpgradeHistories: Optional[UpgradeHistoryList] - NextToken: Optional[String] + UpgradeHistories: UpgradeHistoryList | None + NextToken: String | None class GetUpgradeStatusRequest(ServiceRequest): @@ -2255,37 +2319,37 @@ class GetUpgradeStatusRequest(ServiceRequest): class GetUpgradeStatusResponse(TypedDict, total=False): - UpgradeStep: Optional[UpgradeStep] - StepStatus: Optional[UpgradeStatus] - UpgradeName: Optional[UpgradeName] + UpgradeStep: UpgradeStep | None + StepStatus: UpgradeStatus | None + UpgradeName: UpgradeName | None -InstanceRoleList = List[InstanceRole] +InstanceRoleList = list[InstanceRole] class InstanceTypeDetails(TypedDict, total=False): - InstanceType: Optional[OpenSearchPartitionInstanceType] - EncryptionEnabled: Optional[Boolean] - CognitoEnabled: Optional[Boolean] - AppLogsEnabled: Optional[Boolean] - AdvancedSecurityEnabled: Optional[Boolean] - WarmEnabled: Optional[Boolean] - InstanceRole: Optional[InstanceRoleList] - AvailabilityZones: Optional[AvailabilityZoneList] + InstanceType: OpenSearchPartitionInstanceType | None + EncryptionEnabled: Boolean | None + CognitoEnabled: Boolean | None + AppLogsEnabled: Boolean | None + AdvancedSecurityEnabled: Boolean | None + WarmEnabled: Boolean | None + InstanceRole: InstanceRoleList | None + AvailabilityZones: AvailabilityZoneList | None -InstanceTypeDetailsList = List[InstanceTypeDetails] +InstanceTypeDetailsList = list[InstanceTypeDetails] class ListApplicationsRequest(ServiceRequest): - nextToken: Optional[NextToken] - statuses: Optional[ApplicationStatuses] - maxResults: Optional[MaxResults] + nextToken: NextToken | None + statuses: ApplicationStatuses | None + maxResults: MaxResults | None class ListApplicationsResponse(TypedDict, total=False): - ApplicationSummaries: Optional[ApplicationSummaries] - nextToken: Optional[NextToken] + ApplicationSummaries: ApplicationSummaries | None + nextToken: NextToken | None class ListDataSourcesRequest(ServiceRequest): @@ -2293,79 +2357,79 @@ class ListDataSourcesRequest(ServiceRequest): class ListDataSourcesResponse(TypedDict, total=False): - DataSources: Optional[DataSourceList] + DataSources: DataSourceList | None class ListDirectQueryDataSourcesRequest(ServiceRequest): - NextToken: Optional[NextToken] + NextToken: NextToken | None class ListDirectQueryDataSourcesResponse(TypedDict, total=False): - NextToken: Optional[NextToken] - DirectQueryDataSources: Optional[DirectQueryDataSourceList] + NextToken: NextToken | None + DirectQueryDataSources: DirectQueryDataSourceList | None class ListDomainMaintenancesRequest(ServiceRequest): DomainName: DomainName - Action: Optional[MaintenanceType] - Status: Optional[MaintenanceStatus] - MaxResults: Optional[MaxResults] - NextToken: Optional[NextToken] + Action: MaintenanceType | None + Status: MaintenanceStatus | None + MaxResults: MaxResults | None + NextToken: NextToken | None class ListDomainMaintenancesResponse(TypedDict, total=False): - DomainMaintenances: Optional[DomainMaintenanceList] - NextToken: Optional[NextToken] + DomainMaintenances: DomainMaintenanceList | None + NextToken: NextToken | None class ListDomainNamesRequest(ServiceRequest): - EngineType: Optional[EngineType] + EngineType: EngineType | None class ListDomainNamesResponse(TypedDict, total=False): - DomainNames: Optional[DomainInfoList] + DomainNames: DomainInfoList | None class ListDomainsForPackageRequest(ServiceRequest): PackageID: PackageID - MaxResults: Optional[MaxResults] - NextToken: Optional[NextToken] + MaxResults: MaxResults | None + NextToken: NextToken | None class ListDomainsForPackageResponse(TypedDict, total=False): - DomainPackageDetailsList: Optional[DomainPackageDetailsList] - NextToken: Optional[String] + DomainPackageDetailsList: DomainPackageDetailsList | None + NextToken: String | None class ListInstanceTypeDetailsRequest(ServiceRequest): EngineVersion: VersionString - DomainName: Optional[DomainName] - MaxResults: Optional[MaxResults] - NextToken: Optional[NextToken] - RetrieveAZs: Optional[Boolean] - InstanceType: Optional[InstanceTypeString] + DomainName: DomainName | None + MaxResults: MaxResults | None + NextToken: NextToken | None + RetrieveAZs: Boolean | None + InstanceType: InstanceTypeString | None class ListInstanceTypeDetailsResponse(TypedDict, total=False): - InstanceTypeDetails: Optional[InstanceTypeDetailsList] - NextToken: Optional[NextToken] + InstanceTypeDetails: InstanceTypeDetailsList | None + NextToken: NextToken | None class ListPackagesForDomainRequest(ServiceRequest): DomainName: DomainName - MaxResults: Optional[MaxResults] - NextToken: Optional[NextToken] + MaxResults: MaxResults | None + NextToken: NextToken | None class ListPackagesForDomainResponse(TypedDict, total=False): - DomainPackageDetailsList: Optional[DomainPackageDetailsList] - NextToken: Optional[String] + DomainPackageDetailsList: DomainPackageDetailsList | None + NextToken: String | None class ListScheduledActionsRequest(ServiceRequest): DomainName: DomainName - MaxResults: Optional[MaxResults] - NextToken: Optional[NextToken] + MaxResults: MaxResults | None + NextToken: NextToken | None class ScheduledAction(TypedDict, total=False): @@ -2373,19 +2437,19 @@ class ScheduledAction(TypedDict, total=False): Type: ActionType Severity: ActionSeverity ScheduledTime: Long - Description: Optional[String] - ScheduledBy: Optional[ScheduledBy] - Status: Optional[ActionStatus] - Mandatory: Optional[Boolean] - Cancellable: Optional[Boolean] + Description: String | None + ScheduledBy: ScheduledBy | None + Status: ActionStatus | None + Mandatory: Boolean | None + Cancellable: Boolean | None -ScheduledActionsList = List[ScheduledAction] +ScheduledActionsList = list[ScheduledAction] class ListScheduledActionsResponse(TypedDict, total=False): - ScheduledActions: Optional[ScheduledActionsList] - NextToken: Optional[NextToken] + ScheduledActions: ScheduledActionsList | None + NextToken: NextToken | None class ListTagsRequest(ServiceRequest): @@ -2393,22 +2457,22 @@ class ListTagsRequest(ServiceRequest): class ListTagsResponse(TypedDict, total=False): - TagList: Optional[TagList] + TagList: TagList | None class ListVersionsRequest(ServiceRequest): - MaxResults: Optional[MaxResults] - NextToken: Optional[NextToken] + MaxResults: MaxResults | None + NextToken: NextToken | None class ListVersionsResponse(TypedDict, total=False): - Versions: Optional[VersionList] - NextToken: Optional[NextToken] + Versions: VersionList | None + NextToken: NextToken | None class ListVpcEndpointAccessRequest(ServiceRequest): DomainName: DomainName - NextToken: Optional[NextToken] + NextToken: NextToken | None class ListVpcEndpointAccessResponse(TypedDict, total=False): @@ -2418,10 +2482,10 @@ class ListVpcEndpointAccessResponse(TypedDict, total=False): class ListVpcEndpointsForDomainRequest(ServiceRequest): DomainName: DomainName - NextToken: Optional[NextToken] + NextToken: NextToken | None -VpcEndpointSummaryList = List[VpcEndpointSummary] +VpcEndpointSummaryList = list[VpcEndpointSummary] class ListVpcEndpointsForDomainResponse(TypedDict, total=False): @@ -2430,7 +2494,7 @@ class ListVpcEndpointsForDomainResponse(TypedDict, total=False): class ListVpcEndpointsRequest(ServiceRequest): - NextToken: Optional[NextToken] + NextToken: NextToken | None class ListVpcEndpointsResponse(TypedDict, total=False): @@ -2441,12 +2505,21 @@ class ListVpcEndpointsResponse(TypedDict, total=False): class PurchaseReservedInstanceOfferingRequest(ServiceRequest): ReservedInstanceOfferingId: GUID ReservationName: ReservationToken - InstanceCount: Optional[InstanceCount] + InstanceCount: InstanceCount | None class PurchaseReservedInstanceOfferingResponse(TypedDict, total=False): - ReservedInstanceId: Optional[GUID] - ReservationName: Optional[ReservationToken] + ReservedInstanceId: GUID | None + ReservationName: ReservationToken | None + + +class PutDefaultApplicationSettingRequest(ServiceRequest): + applicationArn: ARN + setAsDefault: Boolean + + +class PutDefaultApplicationSettingResponse(TypedDict, total=False): + applicationArn: ARN | None class RejectInboundConnectionRequest(ServiceRequest): @@ -2454,7 +2527,7 @@ class RejectInboundConnectionRequest(ServiceRequest): class RejectInboundConnectionResponse(TypedDict, total=False): - Connection: Optional[InboundConnection] + Connection: InboundConnection | None class RemoveTagsRequest(ServiceRequest): @@ -2464,8 +2537,8 @@ class RemoveTagsRequest(ServiceRequest): class RevokeVpcEndpointAccessRequest(ServiceRequest): DomainName: DomainName - Account: Optional[AWSAccount] - Service: Optional[AWSServicePrincipal] + Account: AWSAccount | None + Service: AWSServicePrincipal | None class RevokeVpcEndpointAccessResponse(TypedDict, total=False): @@ -2475,104 +2548,114 @@ class RevokeVpcEndpointAccessResponse(TypedDict, total=False): class StartDomainMaintenanceRequest(ServiceRequest): DomainName: DomainName Action: MaintenanceType - NodeId: Optional[NodeId] + NodeId: NodeId | None class StartDomainMaintenanceResponse(TypedDict, total=False): - MaintenanceId: Optional[RequestId] + MaintenanceId: RequestId | None class StartServiceSoftwareUpdateRequest(ServiceRequest): DomainName: DomainName - ScheduleAt: Optional[ScheduleAt] - DesiredStartTime: Optional[Long] + ScheduleAt: ScheduleAt | None + DesiredStartTime: Long | None class StartServiceSoftwareUpdateResponse(TypedDict, total=False): - ServiceSoftwareOptions: Optional[ServiceSoftwareOptions] + ServiceSoftwareOptions: ServiceSoftwareOptions | None class UpdateApplicationRequest(ServiceRequest): id: Id - dataSources: Optional[DataSources] - appConfigs: Optional[AppConfigs] + dataSources: DataSources | None + appConfigs: AppConfigs | None class UpdateApplicationResponse(TypedDict, total=False): - id: Optional[Id] - name: Optional[ApplicationName] - arn: Optional[ARN] - dataSources: Optional[DataSources] - iamIdentityCenterOptions: Optional[IamIdentityCenterOptions] - appConfigs: Optional[AppConfigs] - createdAt: Optional[Timestamp] - lastUpdatedAt: Optional[Timestamp] + id: Id | None + name: ApplicationName | None + arn: ARN | None + dataSources: DataSources | None + iamIdentityCenterOptions: IamIdentityCenterOptions | None + appConfigs: AppConfigs | None + createdAt: Timestamp | None + lastUpdatedAt: Timestamp | None class UpdateDataSourceRequest(ServiceRequest): DomainName: DomainName Name: DataSourceName DataSourceType: DataSourceType - Description: Optional[DataSourceDescription] - Status: Optional[DataSourceStatus] + Description: DataSourceDescription | None + Status: DataSourceStatus | None class UpdateDataSourceResponse(TypedDict, total=False): - Message: Optional[String] + Message: String | None class UpdateDirectQueryDataSourceRequest(ServiceRequest): DataSourceName: DirectQueryDataSourceName DataSourceType: DirectQueryDataSourceType - Description: Optional[DirectQueryDataSourceDescription] + Description: DirectQueryDataSourceDescription | None OpenSearchArns: DirectQueryOpenSearchARNList class UpdateDirectQueryDataSourceResponse(TypedDict, total=False): - DataSourceArn: Optional[String] + DataSourceArn: String | None class UpdateDomainConfigRequest(ServiceRequest): DomainName: DomainName - ClusterConfig: Optional[ClusterConfig] - EBSOptions: Optional[EBSOptions] - SnapshotOptions: Optional[SnapshotOptions] - VPCOptions: Optional[VPCOptions] - CognitoOptions: Optional[CognitoOptions] - AdvancedOptions: Optional[AdvancedOptions] - AccessPolicies: Optional[PolicyDocument] - IPAddressType: Optional[IPAddressType] - LogPublishingOptions: Optional[LogPublishingOptions] - EncryptionAtRestOptions: Optional[EncryptionAtRestOptions] - DomainEndpointOptions: Optional[DomainEndpointOptions] - NodeToNodeEncryptionOptions: Optional[NodeToNodeEncryptionOptions] - AdvancedSecurityOptions: Optional[AdvancedSecurityOptionsInput] - IdentityCenterOptions: Optional[IdentityCenterOptionsInput] - AutoTuneOptions: Optional[AutoTuneOptions] - DryRun: Optional[DryRun] - DryRunMode: Optional[DryRunMode] - OffPeakWindowOptions: Optional[OffPeakWindowOptions] - SoftwareUpdateOptions: Optional[SoftwareUpdateOptions] - AIMLOptions: Optional[AIMLOptionsInput] + ClusterConfig: ClusterConfig | None + EBSOptions: EBSOptions | None + SnapshotOptions: SnapshotOptions | None + VPCOptions: VPCOptions | None + CognitoOptions: CognitoOptions | None + AdvancedOptions: AdvancedOptions | None + AccessPolicies: PolicyDocument | None + IPAddressType: IPAddressType | None + LogPublishingOptions: LogPublishingOptions | None + EncryptionAtRestOptions: EncryptionAtRestOptions | None + DomainEndpointOptions: DomainEndpointOptions | None + NodeToNodeEncryptionOptions: NodeToNodeEncryptionOptions | None + AdvancedSecurityOptions: AdvancedSecurityOptionsInput | None + IdentityCenterOptions: IdentityCenterOptionsInput | None + AutoTuneOptions: AutoTuneOptions | None + DryRun: DryRun | None + DryRunMode: DryRunMode | None + OffPeakWindowOptions: OffPeakWindowOptions | None + SoftwareUpdateOptions: SoftwareUpdateOptions | None + AIMLOptions: AIMLOptionsInput | None class UpdateDomainConfigResponse(TypedDict, total=False): DomainConfig: DomainConfig - DryRunResults: Optional[DryRunResults] - DryRunProgressStatus: Optional[DryRunProgressStatus] + DryRunResults: DryRunResults | None + DryRunProgressStatus: DryRunProgressStatus | None + + +class UpdateIndexRequest(ServiceRequest): + DomainName: DomainName + IndexName: IndexName + IndexSchema: IndexSchema + + +class UpdateIndexResponse(TypedDict, total=False): + Status: IndexStatus class UpdatePackageRequest(ServiceRequest): PackageID: PackageID PackageSource: PackageSource - PackageDescription: Optional[PackageDescription] - CommitMessage: Optional[CommitMessage] - PackageConfiguration: Optional[PackageConfiguration] - PackageEncryptionOptions: Optional[PackageEncryptionOptions] + PackageDescription: PackageDescription | None + CommitMessage: CommitMessage | None + PackageConfiguration: PackageConfiguration | None + PackageEncryptionOptions: PackageEncryptionOptions | None class UpdatePackageResponse(TypedDict, total=False): - PackageDetails: Optional[PackageDetails] + PackageDetails: PackageDetails | None class UpdatePackageScopeRequest(ServiceRequest): @@ -2582,9 +2665,9 @@ class UpdatePackageScopeRequest(ServiceRequest): class UpdatePackageScopeResponse(TypedDict, total=False): - PackageID: Optional[PackageID] - Operation: Optional[PackageScopeOperationEnum] - PackageUserList: Optional[PackageUserList] + PackageID: PackageID | None + Operation: PackageScopeOperationEnum | None + PackageUserList: PackageUserList | None class UpdateScheduledActionRequest(ServiceRequest): @@ -2592,11 +2675,11 @@ class UpdateScheduledActionRequest(ServiceRequest): ActionID: String ActionType: ActionType ScheduleAt: ScheduleAt - DesiredStartTime: Optional[Long] + DesiredStartTime: Long | None class UpdateScheduledActionResponse(TypedDict, total=False): - ScheduledAction: Optional[ScheduledAction] + ScheduledAction: ScheduledAction | None class UpdateVpcEndpointRequest(ServiceRequest): @@ -2611,22 +2694,22 @@ class UpdateVpcEndpointResponse(TypedDict, total=False): class UpgradeDomainRequest(ServiceRequest): DomainName: DomainName TargetVersion: VersionString - PerformCheckOnly: Optional[Boolean] - AdvancedOptions: Optional[AdvancedOptions] + PerformCheckOnly: Boolean | None + AdvancedOptions: AdvancedOptions | None class UpgradeDomainResponse(TypedDict, total=False): - UpgradeId: Optional[String] - DomainName: Optional[DomainName] - TargetVersion: Optional[VersionString] - PerformCheckOnly: Optional[Boolean] - AdvancedOptions: Optional[AdvancedOptions] - ChangeProgressDetails: Optional[ChangeProgressDetails] + UpgradeId: String | None + DomainName: DomainName | None + TargetVersion: VersionString | None + PerformCheckOnly: Boolean | None + AdvancedOptions: AdvancedOptions | None + ChangeProgressDetails: ChangeProgressDetails | None class OpensearchApi: - service = "opensearch" - version = "2021-01-01" + service: str = "opensearch" + version: str = "2021-01-01" @handler("AcceptInboundConnection") def accept_inbound_connection( @@ -2722,6 +2805,7 @@ def create_application( iam_identity_center_options: IamIdentityCenterOptionsInput | None = None, app_configs: AppConfigs | None = None, tag_list: TagList | None = None, + kms_key_arn: KmsKeyArn | None = None, **kwargs, ) -> CreateApplicationResponse: raise NotImplementedError @@ -2755,6 +2839,17 @@ def create_domain( ) -> CreateDomainResponse: raise NotImplementedError + @handler("CreateIndex") + def create_index( + self, + context: RequestContext, + domain_name: DomainName, + index_name: IndexName, + index_schema: IndexSchema, + **kwargs, + ) -> CreateIndexResponse: + raise NotImplementedError + @handler("CreateOutboundConnection") def create_outbound_connection( self, @@ -2825,6 +2920,12 @@ def delete_inbound_connection( ) -> DeleteInboundConnectionResponse: raise NotImplementedError + @handler("DeleteIndex") + def delete_index( + self, context: RequestContext, domain_name: DomainName, index_name: IndexName, **kwargs + ) -> DeleteIndexResponse: + raise NotImplementedError + @handler("DeleteOutboundConnection") def delete_outbound_connection( self, context: RequestContext, connection_id: ConnectionId, **kwargs @@ -3009,6 +3110,12 @@ def get_data_source( ) -> GetDataSourceResponse: raise NotImplementedError + @handler("GetDefaultApplicationSetting") + def get_default_application_setting( + self, context: RequestContext, **kwargs + ) -> GetDefaultApplicationSettingResponse: + raise NotImplementedError + @handler("GetDirectQueryDataSource") def get_direct_query_data_source( self, context: RequestContext, data_source_name: DirectQueryDataSourceName, **kwargs @@ -3021,6 +3128,12 @@ def get_domain_maintenance_status( ) -> GetDomainMaintenanceStatusResponse: raise NotImplementedError + @handler("GetIndex") + def get_index( + self, context: RequestContext, domain_name: DomainName, index_name: IndexName, **kwargs + ) -> GetIndexResponse: + raise NotImplementedError + @handler("GetPackageVersionHistory") def get_package_version_history( self, @@ -3189,6 +3302,12 @@ def purchase_reserved_instance_offering( ) -> PurchaseReservedInstanceOfferingResponse: raise NotImplementedError + @handler("PutDefaultApplicationSetting") + def put_default_application_setting( + self, context: RequestContext, application_arn: ARN, set_as_default: Boolean, **kwargs + ) -> PutDefaultApplicationSettingResponse: + raise NotImplementedError + @handler("RejectInboundConnection") def reject_inbound_connection( self, context: RequestContext, connection_id: ConnectionId, **kwargs @@ -3299,6 +3418,17 @@ def update_domain_config( ) -> UpdateDomainConfigResponse: raise NotImplementedError + @handler("UpdateIndex") + def update_index( + self, + context: RequestContext, + domain_name: DomainName, + index_name: IndexName, + index_schema: IndexSchema, + **kwargs, + ) -> UpdateIndexResponse: + raise NotImplementedError + @handler("UpdatePackage") def update_package( self, diff --git a/localstack-core/localstack/aws/api/pipes/__init__.py b/localstack-core/localstack/aws/api/pipes/__init__.py index 48ae582ede810..9ed5cf8467091 100644 --- a/localstack-core/localstack/aws/api/pipes/__init__.py +++ b/localstack-core/localstack/aws/api/pipes/__init__.py @@ -1,6 +1,6 @@ from datetime import datetime from enum import StrEnum -from typing import Dict, List, Optional, TypedDict +from typing import TypedDict from localstack.aws.api import RequestContext, ServiceException, ServiceRequest, handler @@ -243,7 +243,7 @@ class InternalException(ServiceException): code: str = "InternalException" sender_fault: bool = False status_code: int = 500 - retryAfterSeconds: Optional[Integer] + retryAfterSeconds: Integer | None class NotFoundException(ServiceException): @@ -266,9 +266,9 @@ class ThrottlingException(ServiceException): code: str = "ThrottlingException" sender_fault: bool = True status_code: int = 429 - serviceCode: Optional[String] - quotaCode: Optional[String] - retryAfterSeconds: Optional[Integer] + serviceCode: String | None + quotaCode: String | None + retryAfterSeconds: Integer | None class ValidationExceptionField(TypedDict, total=False): @@ -276,28 +276,28 @@ class ValidationExceptionField(TypedDict, total=False): message: ErrorMessage -ValidationExceptionFieldList = List[ValidationExceptionField] +ValidationExceptionFieldList = list[ValidationExceptionField] class ValidationException(ServiceException): code: str = "ValidationException" sender_fault: bool = True status_code: int = 400 - fieldList: Optional[ValidationExceptionFieldList] + fieldList: ValidationExceptionFieldList | None -SecurityGroups = List[SecurityGroup] -Subnets = List[Subnet] +SecurityGroups = list[SecurityGroup] +Subnets = list[Subnet] class AwsVpcConfiguration(TypedDict, total=False): Subnets: Subnets - SecurityGroups: Optional[SecurityGroups] - AssignPublicIp: Optional[AssignPublicIp] + SecurityGroups: SecurityGroups | None + AssignPublicIp: AssignPublicIp | None class BatchArrayProperties(TypedDict, total=False): - Size: Optional[BatchArraySize] + Size: BatchArraySize | None class BatchResourceRequirement(TypedDict, total=False): @@ -305,56 +305,56 @@ class BatchResourceRequirement(TypedDict, total=False): Value: String -BatchResourceRequirementsList = List[BatchResourceRequirement] +BatchResourceRequirementsList = list[BatchResourceRequirement] class BatchEnvironmentVariable(TypedDict, total=False): - Name: Optional[String] - Value: Optional[String] + Name: String | None + Value: String | None -BatchEnvironmentVariableList = List[BatchEnvironmentVariable] -StringList = List[String] +BatchEnvironmentVariableList = list[BatchEnvironmentVariable] +StringList = list[String] class BatchContainerOverrides(TypedDict, total=False): - Command: Optional[StringList] - Environment: Optional[BatchEnvironmentVariableList] - InstanceType: Optional[String] - ResourceRequirements: Optional[BatchResourceRequirementsList] + Command: StringList | None + Environment: BatchEnvironmentVariableList | None + InstanceType: String | None + ResourceRequirements: BatchResourceRequirementsList | None class BatchJobDependency(TypedDict, total=False): - JobId: Optional[String] - Type: Optional[BatchJobDependencyType] + JobId: String | None + Type: BatchJobDependencyType | None -BatchDependsOn = List[BatchJobDependency] -BatchParametersMap = Dict[String, String] +BatchDependsOn = list[BatchJobDependency] +BatchParametersMap = dict[String, String] class BatchRetryStrategy(TypedDict, total=False): - Attempts: Optional[BatchRetryAttempts] + Attempts: BatchRetryAttempts | None class CapacityProviderStrategyItem(TypedDict, total=False): capacityProvider: CapacityProvider - weight: Optional[CapacityProviderStrategyItemWeight] - base: Optional[CapacityProviderStrategyItemBase] + weight: CapacityProviderStrategyItemWeight | None + base: CapacityProviderStrategyItemBase | None -CapacityProviderStrategy = List[CapacityProviderStrategyItem] +CapacityProviderStrategy = list[CapacityProviderStrategyItem] class CloudwatchLogsLogDestination(TypedDict, total=False): - LogGroupArn: Optional[CloudwatchLogGroupArn] + LogGroupArn: CloudwatchLogGroupArn | None class CloudwatchLogsLogDestinationParameters(TypedDict, total=False): LogGroupArn: CloudwatchLogGroupArn -IncludeExecutionData = List[IncludeExecutionDataOption] +IncludeExecutionData = list[IncludeExecutionDataOption] class FirehoseLogDestinationParameters(TypedDict, total=False): @@ -364,19 +364,19 @@ class FirehoseLogDestinationParameters(TypedDict, total=False): class S3LogDestinationParameters(TypedDict, total=False): BucketName: S3LogDestinationParametersBucketNameString BucketOwner: S3LogDestinationParametersBucketOwnerString - OutputFormat: Optional[S3OutputFormat] - Prefix: Optional[S3LogDestinationParametersPrefixString] + OutputFormat: S3OutputFormat | None + Prefix: S3LogDestinationParametersPrefixString | None class PipeLogConfigurationParameters(TypedDict, total=False): - S3LogDestination: Optional[S3LogDestinationParameters] - FirehoseLogDestination: Optional[FirehoseLogDestinationParameters] - CloudwatchLogsLogDestination: Optional[CloudwatchLogsLogDestinationParameters] + S3LogDestination: S3LogDestinationParameters | None + FirehoseLogDestination: FirehoseLogDestinationParameters | None + CloudwatchLogsLogDestination: CloudwatchLogsLogDestinationParameters | None Level: LogLevel - IncludeExecutionData: Optional[IncludeExecutionData] + IncludeExecutionData: IncludeExecutionData | None -TagMap = Dict[TagKey, TagValue] +TagMap = dict[TagKey, TagValue] class MultiMeasureAttributeMapping(TypedDict, total=False): @@ -385,7 +385,7 @@ class MultiMeasureAttributeMapping(TypedDict, total=False): MultiMeasureAttributeName: MultiMeasureAttributeName -MultiMeasureAttributeMappings = List[MultiMeasureAttributeMapping] +MultiMeasureAttributeMappings = list[MultiMeasureAttributeMapping] class MultiMeasureMapping(TypedDict, total=False): @@ -393,7 +393,7 @@ class MultiMeasureMapping(TypedDict, total=False): MultiMeasureAttributeMappings: MultiMeasureAttributeMappings -MultiMeasureMappings = List[MultiMeasureMapping] +MultiMeasureMappings = list[MultiMeasureMapping] class SingleMeasureMapping(TypedDict, total=False): @@ -402,7 +402,7 @@ class SingleMeasureMapping(TypedDict, total=False): MeasureName: MeasureName -SingleMeasureMappings = List[SingleMeasureMapping] +SingleMeasureMappings = list[SingleMeasureMapping] class DimensionMapping(TypedDict, total=False): @@ -411,34 +411,34 @@ class DimensionMapping(TypedDict, total=False): DimensionName: DimensionName -DimensionMappings = List[DimensionMapping] +DimensionMappings = list[DimensionMapping] class PipeTargetTimestreamParameters(TypedDict, total=False): TimeValue: TimeValue - EpochTimeUnit: Optional[EpochTimeUnit] - TimeFieldType: Optional[TimeFieldType] - TimestampFormat: Optional[TimestampFormat] + EpochTimeUnit: EpochTimeUnit | None + TimeFieldType: TimeFieldType | None + TimestampFormat: TimestampFormat | None VersionValue: VersionValue DimensionMappings: DimensionMappings - SingleMeasureMappings: Optional[SingleMeasureMappings] - MultiMeasureMappings: Optional[MultiMeasureMappings] + SingleMeasureMappings: SingleMeasureMappings | None + MultiMeasureMappings: MultiMeasureMappings | None class PipeTargetCloudWatchLogsParameters(TypedDict, total=False): - LogStreamName: Optional[LogStreamName] - Timestamp: Optional[JsonPath] + LogStreamName: LogStreamName | None + Timestamp: JsonPath | None -EventBridgeEventResourceList = List[ArnOrJsonPath] +EventBridgeEventResourceList = list[ArnOrJsonPath] class PipeTargetEventBridgeEventBusParameters(TypedDict, total=False): - EndpointId: Optional[EventBridgeEndpointId] - DetailType: Optional[EventBridgeDetailType] - Source: Optional[EventBridgeEventSource] - Resources: Optional[EventBridgeEventResourceList] - Time: Optional[JsonPath] + EndpointId: EventBridgeEndpointId | None + DetailType: EventBridgeDetailType | None + Source: EventBridgeEventSource | None + Resources: EventBridgeEventResourceList | None + Time: JsonPath | None class SageMakerPipelineParameter(TypedDict, total=False): @@ -446,49 +446,49 @@ class SageMakerPipelineParameter(TypedDict, total=False): Value: SageMakerPipelineParameterValue -SageMakerPipelineParameterList = List[SageMakerPipelineParameter] +SageMakerPipelineParameterList = list[SageMakerPipelineParameter] class PipeTargetSageMakerPipelineParameters(TypedDict, total=False): - PipelineParameterList: Optional[SageMakerPipelineParameterList] + PipelineParameterList: SageMakerPipelineParameterList | None -Sqls = List[Sql] +Sqls = list[Sql] class PipeTargetRedshiftDataParameters(TypedDict, total=False): - SecretManagerArn: Optional[SecretManagerArnOrJsonPath] + SecretManagerArn: SecretManagerArnOrJsonPath | None Database: Database - DbUser: Optional[DbUser] - StatementName: Optional[StatementName] - WithEvent: Optional[Boolean] + DbUser: DbUser | None + StatementName: StatementName | None + WithEvent: Boolean | None Sqls: Sqls -QueryStringParametersMap = Dict[QueryStringKey, QueryStringValue] -HeaderParametersMap = Dict[HeaderKey, HeaderValue] -PathParameterList = List[PathParameter] +QueryStringParametersMap = dict[QueryStringKey, QueryStringValue] +HeaderParametersMap = dict[HeaderKey, HeaderValue] +PathParameterList = list[PathParameter] class PipeTargetHttpParameters(TypedDict, total=False): - PathParameterValues: Optional[PathParameterList] - HeaderParameters: Optional[HeaderParametersMap] - QueryStringParameters: Optional[QueryStringParametersMap] + PathParameterValues: PathParameterList | None + HeaderParameters: HeaderParametersMap | None + QueryStringParameters: QueryStringParametersMap | None class PipeTargetSqsQueueParameters(TypedDict, total=False): - MessageGroupId: Optional[MessageGroupId] - MessageDeduplicationId: Optional[MessageDeduplicationId] + MessageGroupId: MessageGroupId | None + MessageDeduplicationId: MessageDeduplicationId | None class PipeTargetBatchJobParameters(TypedDict, total=False): JobDefinition: String JobName: String - ArrayProperties: Optional[BatchArrayProperties] - RetryStrategy: Optional[BatchRetryStrategy] - ContainerOverrides: Optional[BatchContainerOverrides] - DependsOn: Optional[BatchDependsOn] - Parameters: Optional[BatchParametersMap] + ArrayProperties: BatchArrayProperties | None + RetryStrategy: BatchRetryStrategy | None + ContainerOverrides: BatchContainerOverrides | None + DependsOn: BatchDependsOn | None + Parameters: BatchParametersMap | None class Tag(TypedDict, total=False): @@ -496,15 +496,15 @@ class Tag(TypedDict, total=False): Value: TagValue -TagList = List[Tag] +TagList = list[Tag] class EcsInferenceAcceleratorOverride(TypedDict, total=False): - deviceName: Optional[String] - deviceType: Optional[String] + deviceName: String | None + deviceType: String | None -EcsInferenceAcceleratorOverrideList = List[EcsInferenceAcceleratorOverride] +EcsInferenceAcceleratorOverrideList = list[EcsInferenceAcceleratorOverride] class EcsEphemeralStorage(TypedDict, total=False): @@ -516,7 +516,7 @@ class EcsResourceRequirement(TypedDict, total=False): value: String -EcsResourceRequirementsList = List[EcsResourceRequirement] +EcsResourceRequirementsList = list[EcsResourceRequirement] class EcsEnvironmentFile(TypedDict, total=False): @@ -524,77 +524,77 @@ class EcsEnvironmentFile(TypedDict, total=False): value: String -EcsEnvironmentFileList = List[EcsEnvironmentFile] +EcsEnvironmentFileList = list[EcsEnvironmentFile] class EcsEnvironmentVariable(TypedDict, total=False): - name: Optional[String] - value: Optional[String] + name: String | None + value: String | None -EcsEnvironmentVariableList = List[EcsEnvironmentVariable] +EcsEnvironmentVariableList = list[EcsEnvironmentVariable] class EcsContainerOverride(TypedDict, total=False): - Command: Optional[StringList] - Cpu: Optional[Integer] - Environment: Optional[EcsEnvironmentVariableList] - EnvironmentFiles: Optional[EcsEnvironmentFileList] - Memory: Optional[Integer] - MemoryReservation: Optional[Integer] - Name: Optional[String] - ResourceRequirements: Optional[EcsResourceRequirementsList] + Command: StringList | None + Cpu: Integer | None + Environment: EcsEnvironmentVariableList | None + EnvironmentFiles: EcsEnvironmentFileList | None + Memory: Integer | None + MemoryReservation: Integer | None + Name: String | None + ResourceRequirements: EcsResourceRequirementsList | None -EcsContainerOverrideList = List[EcsContainerOverride] +EcsContainerOverrideList = list[EcsContainerOverride] class EcsTaskOverride(TypedDict, total=False): - ContainerOverrides: Optional[EcsContainerOverrideList] - Cpu: Optional[String] - EphemeralStorage: Optional[EcsEphemeralStorage] - ExecutionRoleArn: Optional[ArnOrJsonPath] - InferenceAcceleratorOverrides: Optional[EcsInferenceAcceleratorOverrideList] - Memory: Optional[String] - TaskRoleArn: Optional[ArnOrJsonPath] + ContainerOverrides: EcsContainerOverrideList | None + Cpu: String | None + EphemeralStorage: EcsEphemeralStorage | None + ExecutionRoleArn: ArnOrJsonPath | None + InferenceAcceleratorOverrides: EcsInferenceAcceleratorOverrideList | None + Memory: String | None + TaskRoleArn: ArnOrJsonPath | None class PlacementStrategy(TypedDict, total=False): - type: Optional[PlacementStrategyType] - field: Optional[PlacementStrategyField] + type: PlacementStrategyType | None + field: PlacementStrategyField | None -PlacementStrategies = List[PlacementStrategy] +PlacementStrategies = list[PlacementStrategy] class PlacementConstraint(TypedDict, total=False): - type: Optional[PlacementConstraintType] - expression: Optional[PlacementConstraintExpression] + type: PlacementConstraintType | None + expression: PlacementConstraintExpression | None -PlacementConstraints = List[PlacementConstraint] +PlacementConstraints = list[PlacementConstraint] class NetworkConfiguration(TypedDict, total=False): - awsvpcConfiguration: Optional[AwsVpcConfiguration] + awsvpcConfiguration: AwsVpcConfiguration | None class PipeTargetEcsTaskParameters(TypedDict, total=False): TaskDefinitionArn: ArnOrJsonPath - TaskCount: Optional[LimitMin1] - LaunchType: Optional[LaunchType] - NetworkConfiguration: Optional[NetworkConfiguration] - PlatformVersion: Optional[String] - Group: Optional[String] - CapacityProviderStrategy: Optional[CapacityProviderStrategy] - EnableECSManagedTags: Optional[Boolean] - EnableExecuteCommand: Optional[Boolean] - PlacementConstraints: Optional[PlacementConstraints] - PlacementStrategy: Optional[PlacementStrategies] - PropagateTags: Optional[PropagateTags] - ReferenceId: Optional[ReferenceId] - Overrides: Optional[EcsTaskOverride] - Tags: Optional[TagList] + TaskCount: LimitMin1 | None + LaunchType: LaunchType | None + NetworkConfiguration: NetworkConfiguration | None + PlatformVersion: String | None + Group: String | None + CapacityProviderStrategy: CapacityProviderStrategy | None + EnableECSManagedTags: Boolean | None + EnableExecuteCommand: Boolean | None + PlacementConstraints: PlacementConstraints | None + PlacementStrategy: PlacementStrategies | None + PropagateTags: PropagateTags | None + ReferenceId: ReferenceId | None + Overrides: EcsTaskOverride | None + Tags: TagList | None class PipeTargetKinesisStreamParameters(TypedDict, total=False): @@ -602,121 +602,121 @@ class PipeTargetKinesisStreamParameters(TypedDict, total=False): class PipeTargetStateMachineParameters(TypedDict, total=False): - InvocationType: Optional[PipeTargetInvocationType] + InvocationType: PipeTargetInvocationType | None class PipeTargetLambdaFunctionParameters(TypedDict, total=False): - InvocationType: Optional[PipeTargetInvocationType] + InvocationType: PipeTargetInvocationType | None class PipeTargetParameters(TypedDict, total=False): - InputTemplate: Optional[InputTemplate] - LambdaFunctionParameters: Optional[PipeTargetLambdaFunctionParameters] - StepFunctionStateMachineParameters: Optional[PipeTargetStateMachineParameters] - KinesisStreamParameters: Optional[PipeTargetKinesisStreamParameters] - EcsTaskParameters: Optional[PipeTargetEcsTaskParameters] - BatchJobParameters: Optional[PipeTargetBatchJobParameters] - SqsQueueParameters: Optional[PipeTargetSqsQueueParameters] - HttpParameters: Optional[PipeTargetHttpParameters] - RedshiftDataParameters: Optional[PipeTargetRedshiftDataParameters] - SageMakerPipelineParameters: Optional[PipeTargetSageMakerPipelineParameters] - EventBridgeEventBusParameters: Optional[PipeTargetEventBridgeEventBusParameters] - CloudWatchLogsParameters: Optional[PipeTargetCloudWatchLogsParameters] - TimestreamParameters: Optional[PipeTargetTimestreamParameters] + InputTemplate: InputTemplate | None + LambdaFunctionParameters: PipeTargetLambdaFunctionParameters | None + StepFunctionStateMachineParameters: PipeTargetStateMachineParameters | None + KinesisStreamParameters: PipeTargetKinesisStreamParameters | None + EcsTaskParameters: PipeTargetEcsTaskParameters | None + BatchJobParameters: PipeTargetBatchJobParameters | None + SqsQueueParameters: PipeTargetSqsQueueParameters | None + HttpParameters: PipeTargetHttpParameters | None + RedshiftDataParameters: PipeTargetRedshiftDataParameters | None + SageMakerPipelineParameters: PipeTargetSageMakerPipelineParameters | None + EventBridgeEventBusParameters: PipeTargetEventBridgeEventBusParameters | None + CloudWatchLogsParameters: PipeTargetCloudWatchLogsParameters | None + TimestreamParameters: PipeTargetTimestreamParameters | None class PipeEnrichmentHttpParameters(TypedDict, total=False): - PathParameterValues: Optional[PathParameterList] - HeaderParameters: Optional[HeaderParametersMap] - QueryStringParameters: Optional[QueryStringParametersMap] + PathParameterValues: PathParameterList | None + HeaderParameters: HeaderParametersMap | None + QueryStringParameters: QueryStringParametersMap | None class PipeEnrichmentParameters(TypedDict, total=False): - InputTemplate: Optional[InputTemplate] - HttpParameters: Optional[PipeEnrichmentHttpParameters] + InputTemplate: InputTemplate | None + HttpParameters: PipeEnrichmentHttpParameters | None -SecurityGroupIds = List[SecurityGroupId] -SubnetIds = List[SubnetId] +SecurityGroupIds = list[SecurityGroupId] +SubnetIds = list[SubnetId] class SelfManagedKafkaAccessConfigurationVpc(TypedDict, total=False): - Subnets: Optional[SubnetIds] - SecurityGroup: Optional[SecurityGroupIds] + Subnets: SubnetIds | None + SecurityGroup: SecurityGroupIds | None class SelfManagedKafkaAccessConfigurationCredentials(TypedDict, total=False): - BasicAuth: Optional[SecretManagerArn] - SaslScram512Auth: Optional[SecretManagerArn] - SaslScram256Auth: Optional[SecretManagerArn] - ClientCertificateTlsAuth: Optional[SecretManagerArn] + BasicAuth: SecretManagerArn | None + SaslScram512Auth: SecretManagerArn | None + SaslScram256Auth: SecretManagerArn | None + ClientCertificateTlsAuth: SecretManagerArn | None -KafkaBootstrapServers = List[EndpointString] +KafkaBootstrapServers = list[EndpointString] class PipeSourceSelfManagedKafkaParameters(TypedDict, total=False): TopicName: KafkaTopicName - StartingPosition: Optional[SelfManagedKafkaStartPosition] - AdditionalBootstrapServers: Optional[KafkaBootstrapServers] - BatchSize: Optional[LimitMax10000] - MaximumBatchingWindowInSeconds: Optional[MaximumBatchingWindowInSeconds] - ConsumerGroupID: Optional[URI] - Credentials: Optional[SelfManagedKafkaAccessConfigurationCredentials] - ServerRootCaCertificate: Optional[SecretManagerArn] - Vpc: Optional[SelfManagedKafkaAccessConfigurationVpc] + StartingPosition: SelfManagedKafkaStartPosition | None + AdditionalBootstrapServers: KafkaBootstrapServers | None + BatchSize: LimitMax10000 | None + MaximumBatchingWindowInSeconds: MaximumBatchingWindowInSeconds | None + ConsumerGroupID: URI | None + Credentials: SelfManagedKafkaAccessConfigurationCredentials | None + ServerRootCaCertificate: SecretManagerArn | None + Vpc: SelfManagedKafkaAccessConfigurationVpc | None class MSKAccessCredentials(TypedDict, total=False): - SaslScram512Auth: Optional[SecretManagerArn] - ClientCertificateTlsAuth: Optional[SecretManagerArn] + SaslScram512Auth: SecretManagerArn | None + ClientCertificateTlsAuth: SecretManagerArn | None class PipeSourceManagedStreamingKafkaParameters(TypedDict, total=False): TopicName: KafkaTopicName - StartingPosition: Optional[MSKStartPosition] - BatchSize: Optional[LimitMax10000] - MaximumBatchingWindowInSeconds: Optional[MaximumBatchingWindowInSeconds] - ConsumerGroupID: Optional[URI] - Credentials: Optional[MSKAccessCredentials] + StartingPosition: MSKStartPosition | None + BatchSize: LimitMax10000 | None + MaximumBatchingWindowInSeconds: MaximumBatchingWindowInSeconds | None + ConsumerGroupID: URI | None + Credentials: MSKAccessCredentials | None class MQBrokerAccessCredentials(TypedDict, total=False): - BasicAuth: Optional[SecretManagerArn] + BasicAuth: SecretManagerArn | None class PipeSourceRabbitMQBrokerParameters(TypedDict, total=False): Credentials: MQBrokerAccessCredentials QueueName: MQBrokerQueueName - VirtualHost: Optional[URI] - BatchSize: Optional[LimitMax10000] - MaximumBatchingWindowInSeconds: Optional[MaximumBatchingWindowInSeconds] + VirtualHost: URI | None + BatchSize: LimitMax10000 | None + MaximumBatchingWindowInSeconds: MaximumBatchingWindowInSeconds | None class PipeSourceActiveMQBrokerParameters(TypedDict, total=False): Credentials: MQBrokerAccessCredentials QueueName: MQBrokerQueueName - BatchSize: Optional[LimitMax10000] - MaximumBatchingWindowInSeconds: Optional[MaximumBatchingWindowInSeconds] + BatchSize: LimitMax10000 | None + MaximumBatchingWindowInSeconds: MaximumBatchingWindowInSeconds | None class PipeSourceSqsQueueParameters(TypedDict, total=False): - BatchSize: Optional[LimitMax10000] - MaximumBatchingWindowInSeconds: Optional[MaximumBatchingWindowInSeconds] + BatchSize: LimitMax10000 | None + MaximumBatchingWindowInSeconds: MaximumBatchingWindowInSeconds | None class DeadLetterConfig(TypedDict, total=False): - Arn: Optional[Arn] + Arn: Arn | None class PipeSourceDynamoDBStreamParameters(TypedDict, total=False): - BatchSize: Optional[LimitMax10000] - DeadLetterConfig: Optional[DeadLetterConfig] - OnPartialBatchItemFailure: Optional[OnPartialBatchItemFailureStreams] - MaximumBatchingWindowInSeconds: Optional[MaximumBatchingWindowInSeconds] - MaximumRecordAgeInSeconds: Optional[MaximumRecordAgeInSeconds] - MaximumRetryAttempts: Optional[MaximumRetryAttemptsESM] - ParallelizationFactor: Optional[LimitMax10] + BatchSize: LimitMax10000 | None + DeadLetterConfig: DeadLetterConfig | None + OnPartialBatchItemFailure: OnPartialBatchItemFailureStreams | None + MaximumBatchingWindowInSeconds: MaximumBatchingWindowInSeconds | None + MaximumRecordAgeInSeconds: MaximumRecordAgeInSeconds | None + MaximumRetryAttempts: MaximumRetryAttemptsESM | None + ParallelizationFactor: LimitMax10 | None StartingPosition: DynamoDBStreamStartPosition @@ -724,62 +724,62 @@ class PipeSourceDynamoDBStreamParameters(TypedDict, total=False): class PipeSourceKinesisStreamParameters(TypedDict, total=False): - BatchSize: Optional[LimitMax10000] - DeadLetterConfig: Optional[DeadLetterConfig] - OnPartialBatchItemFailure: Optional[OnPartialBatchItemFailureStreams] - MaximumBatchingWindowInSeconds: Optional[MaximumBatchingWindowInSeconds] - MaximumRecordAgeInSeconds: Optional[MaximumRecordAgeInSeconds] - MaximumRetryAttempts: Optional[MaximumRetryAttemptsESM] - ParallelizationFactor: Optional[LimitMax10] + BatchSize: LimitMax10000 | None + DeadLetterConfig: DeadLetterConfig | None + OnPartialBatchItemFailure: OnPartialBatchItemFailureStreams | None + MaximumBatchingWindowInSeconds: MaximumBatchingWindowInSeconds | None + MaximumRecordAgeInSeconds: MaximumRecordAgeInSeconds | None + MaximumRetryAttempts: MaximumRetryAttemptsESM | None + ParallelizationFactor: LimitMax10 | None StartingPosition: KinesisStreamStartPosition - StartingPositionTimestamp: Optional[Timestamp] + StartingPositionTimestamp: Timestamp | None class Filter(TypedDict, total=False): - Pattern: Optional[EventPattern] + Pattern: EventPattern | None -FilterList = List[Filter] +FilterList = list[Filter] class FilterCriteria(TypedDict, total=False): - Filters: Optional[FilterList] + Filters: FilterList | None class PipeSourceParameters(TypedDict, total=False): - FilterCriteria: Optional[FilterCriteria] - KinesisStreamParameters: Optional[PipeSourceKinesisStreamParameters] - DynamoDBStreamParameters: Optional[PipeSourceDynamoDBStreamParameters] - SqsQueueParameters: Optional[PipeSourceSqsQueueParameters] - ActiveMQBrokerParameters: Optional[PipeSourceActiveMQBrokerParameters] - RabbitMQBrokerParameters: Optional[PipeSourceRabbitMQBrokerParameters] - ManagedStreamingKafkaParameters: Optional[PipeSourceManagedStreamingKafkaParameters] - SelfManagedKafkaParameters: Optional[PipeSourceSelfManagedKafkaParameters] + FilterCriteria: FilterCriteria | None + KinesisStreamParameters: PipeSourceKinesisStreamParameters | None + DynamoDBStreamParameters: PipeSourceDynamoDBStreamParameters | None + SqsQueueParameters: PipeSourceSqsQueueParameters | None + ActiveMQBrokerParameters: PipeSourceActiveMQBrokerParameters | None + RabbitMQBrokerParameters: PipeSourceRabbitMQBrokerParameters | None + ManagedStreamingKafkaParameters: PipeSourceManagedStreamingKafkaParameters | None + SelfManagedKafkaParameters: PipeSourceSelfManagedKafkaParameters | None class CreatePipeRequest(ServiceRequest): Name: PipeName - Description: Optional[PipeDescription] - DesiredState: Optional[RequestedPipeState] + Description: PipeDescription | None + DesiredState: RequestedPipeState | None Source: ArnOrUrl - SourceParameters: Optional[PipeSourceParameters] - Enrichment: Optional[OptionalArn] - EnrichmentParameters: Optional[PipeEnrichmentParameters] + SourceParameters: PipeSourceParameters | None + Enrichment: OptionalArn | None + EnrichmentParameters: PipeEnrichmentParameters | None Target: Arn - TargetParameters: Optional[PipeTargetParameters] + TargetParameters: PipeTargetParameters | None RoleArn: RoleArn - Tags: Optional[TagMap] - LogConfiguration: Optional[PipeLogConfigurationParameters] - KmsKeyIdentifier: Optional[KmsKeyIdentifier] + Tags: TagMap | None + LogConfiguration: PipeLogConfigurationParameters | None + KmsKeyIdentifier: KmsKeyIdentifier | None class CreatePipeResponse(TypedDict, total=False): - Arn: Optional[PipeArn] - Name: Optional[PipeName] - DesiredState: Optional[RequestedPipeState] - CurrentState: Optional[PipeState] - CreationTime: Optional[Timestamp] - LastModifiedTime: Optional[Timestamp] + Arn: PipeArn | None + Name: PipeName | None + DesiredState: RequestedPipeState | None + CurrentState: PipeState | None + CreationTime: Timestamp | None + LastModifiedTime: Timestamp | None class DeletePipeRequest(ServiceRequest): @@ -787,12 +787,12 @@ class DeletePipeRequest(ServiceRequest): class DeletePipeResponse(TypedDict, total=False): - Arn: Optional[PipeArn] - Name: Optional[PipeName] - DesiredState: Optional[RequestedPipeStateDescribeResponse] - CurrentState: Optional[PipeState] - CreationTime: Optional[Timestamp] - LastModifiedTime: Optional[Timestamp] + Arn: PipeArn | None + Name: PipeName | None + DesiredState: RequestedPipeStateDescribeResponse | None + CurrentState: PipeState | None + CreationTime: Timestamp | None + LastModifiedTime: Timestamp | None class DescribePipeRequest(ServiceRequest): @@ -800,74 +800,74 @@ class DescribePipeRequest(ServiceRequest): class FirehoseLogDestination(TypedDict, total=False): - DeliveryStreamArn: Optional[FirehoseArn] + DeliveryStreamArn: FirehoseArn | None class S3LogDestination(TypedDict, total=False): - BucketName: Optional[String] - Prefix: Optional[String] - BucketOwner: Optional[String] - OutputFormat: Optional[S3OutputFormat] + BucketName: String | None + Prefix: String | None + BucketOwner: String | None + OutputFormat: S3OutputFormat | None class PipeLogConfiguration(TypedDict, total=False): - S3LogDestination: Optional[S3LogDestination] - FirehoseLogDestination: Optional[FirehoseLogDestination] - CloudwatchLogsLogDestination: Optional[CloudwatchLogsLogDestination] - Level: Optional[LogLevel] - IncludeExecutionData: Optional[IncludeExecutionData] + S3LogDestination: S3LogDestination | None + FirehoseLogDestination: FirehoseLogDestination | None + CloudwatchLogsLogDestination: CloudwatchLogsLogDestination | None + Level: LogLevel | None + IncludeExecutionData: IncludeExecutionData | None class DescribePipeResponse(TypedDict, total=False): - Arn: Optional[PipeArn] - Name: Optional[PipeName] - Description: Optional[PipeDescription] - DesiredState: Optional[RequestedPipeStateDescribeResponse] - CurrentState: Optional[PipeState] - StateReason: Optional[PipeStateReason] - Source: Optional[ArnOrUrl] - SourceParameters: Optional[PipeSourceParameters] - Enrichment: Optional[OptionalArn] - EnrichmentParameters: Optional[PipeEnrichmentParameters] - Target: Optional[Arn] - TargetParameters: Optional[PipeTargetParameters] - RoleArn: Optional[RoleArn] - Tags: Optional[TagMap] - CreationTime: Optional[Timestamp] - LastModifiedTime: Optional[Timestamp] - LogConfiguration: Optional[PipeLogConfiguration] - KmsKeyIdentifier: Optional[KmsKeyIdentifier] + Arn: PipeArn | None + Name: PipeName | None + Description: PipeDescription | None + DesiredState: RequestedPipeStateDescribeResponse | None + CurrentState: PipeState | None + StateReason: PipeStateReason | None + Source: ArnOrUrl | None + SourceParameters: PipeSourceParameters | None + Enrichment: OptionalArn | None + EnrichmentParameters: PipeEnrichmentParameters | None + Target: Arn | None + TargetParameters: PipeTargetParameters | None + RoleArn: RoleArn | None + Tags: TagMap | None + CreationTime: Timestamp | None + LastModifiedTime: Timestamp | None + LogConfiguration: PipeLogConfiguration | None + KmsKeyIdentifier: KmsKeyIdentifier | None class ListPipesRequest(ServiceRequest): - NamePrefix: Optional[PipeName] - DesiredState: Optional[RequestedPipeState] - CurrentState: Optional[PipeState] - SourcePrefix: Optional[ResourceArn] - TargetPrefix: Optional[ResourceArn] - NextToken: Optional[NextToken] - Limit: Optional[LimitMax100] + NamePrefix: PipeName | None + DesiredState: RequestedPipeState | None + CurrentState: PipeState | None + SourcePrefix: ResourceArn | None + TargetPrefix: ResourceArn | None + NextToken: NextToken | None + Limit: LimitMax100 | None class Pipe(TypedDict, total=False): - Name: Optional[PipeName] - Arn: Optional[PipeArn] - DesiredState: Optional[RequestedPipeState] - CurrentState: Optional[PipeState] - StateReason: Optional[PipeStateReason] - CreationTime: Optional[Timestamp] - LastModifiedTime: Optional[Timestamp] - Source: Optional[ArnOrUrl] - Target: Optional[Arn] - Enrichment: Optional[OptionalArn] + Name: PipeName | None + Arn: PipeArn | None + DesiredState: RequestedPipeState | None + CurrentState: PipeState | None + StateReason: PipeStateReason | None + CreationTime: Timestamp | None + LastModifiedTime: Timestamp | None + Source: ArnOrUrl | None + Target: Arn | None + Enrichment: OptionalArn | None -PipeList = List[Pipe] +PipeList = list[Pipe] class ListPipesResponse(TypedDict, total=False): - Pipes: Optional[PipeList] - NextToken: Optional[NextToken] + Pipes: PipeList | None + NextToken: NextToken | None class ListTagsForResourceRequest(ServiceRequest): @@ -875,7 +875,7 @@ class ListTagsForResourceRequest(ServiceRequest): class ListTagsForResourceResponse(TypedDict, total=False): - tags: Optional[TagMap] + tags: TagMap | None class StartPipeRequest(ServiceRequest): @@ -883,12 +883,12 @@ class StartPipeRequest(ServiceRequest): class StartPipeResponse(TypedDict, total=False): - Arn: Optional[PipeArn] - Name: Optional[PipeName] - DesiredState: Optional[RequestedPipeState] - CurrentState: Optional[PipeState] - CreationTime: Optional[Timestamp] - LastModifiedTime: Optional[Timestamp] + Arn: PipeArn | None + Name: PipeName | None + DesiredState: RequestedPipeState | None + CurrentState: PipeState | None + CreationTime: Timestamp | None + LastModifiedTime: Timestamp | None class StopPipeRequest(ServiceRequest): @@ -896,15 +896,15 @@ class StopPipeRequest(ServiceRequest): class StopPipeResponse(TypedDict, total=False): - Arn: Optional[PipeArn] - Name: Optional[PipeName] - DesiredState: Optional[RequestedPipeState] - CurrentState: Optional[PipeState] - CreationTime: Optional[Timestamp] - LastModifiedTime: Optional[Timestamp] + Arn: PipeArn | None + Name: PipeName | None + DesiredState: RequestedPipeState | None + CurrentState: PipeState | None + CreationTime: Timestamp | None + LastModifiedTime: Timestamp | None -TagKeyList = List[TagKey] +TagKeyList = list[TagKey] class TagResourceRequest(ServiceRequest): @@ -926,93 +926,93 @@ class UntagResourceResponse(TypedDict, total=False): class UpdatePipeSourceSelfManagedKafkaParameters(TypedDict, total=False): - BatchSize: Optional[LimitMax10000] - MaximumBatchingWindowInSeconds: Optional[MaximumBatchingWindowInSeconds] - Credentials: Optional[SelfManagedKafkaAccessConfigurationCredentials] - ServerRootCaCertificate: Optional[SecretManagerArn] - Vpc: Optional[SelfManagedKafkaAccessConfigurationVpc] + BatchSize: LimitMax10000 | None + MaximumBatchingWindowInSeconds: MaximumBatchingWindowInSeconds | None + Credentials: SelfManagedKafkaAccessConfigurationCredentials | None + ServerRootCaCertificate: SecretManagerArn | None + Vpc: SelfManagedKafkaAccessConfigurationVpc | None class UpdatePipeSourceManagedStreamingKafkaParameters(TypedDict, total=False): - BatchSize: Optional[LimitMax10000] - Credentials: Optional[MSKAccessCredentials] - MaximumBatchingWindowInSeconds: Optional[MaximumBatchingWindowInSeconds] + BatchSize: LimitMax10000 | None + Credentials: MSKAccessCredentials | None + MaximumBatchingWindowInSeconds: MaximumBatchingWindowInSeconds | None class UpdatePipeSourceRabbitMQBrokerParameters(TypedDict, total=False): Credentials: MQBrokerAccessCredentials - BatchSize: Optional[LimitMax10000] - MaximumBatchingWindowInSeconds: Optional[MaximumBatchingWindowInSeconds] + BatchSize: LimitMax10000 | None + MaximumBatchingWindowInSeconds: MaximumBatchingWindowInSeconds | None class UpdatePipeSourceActiveMQBrokerParameters(TypedDict, total=False): Credentials: MQBrokerAccessCredentials - BatchSize: Optional[LimitMax10000] - MaximumBatchingWindowInSeconds: Optional[MaximumBatchingWindowInSeconds] + BatchSize: LimitMax10000 | None + MaximumBatchingWindowInSeconds: MaximumBatchingWindowInSeconds | None class UpdatePipeSourceSqsQueueParameters(TypedDict, total=False): - BatchSize: Optional[LimitMax10000] - MaximumBatchingWindowInSeconds: Optional[MaximumBatchingWindowInSeconds] + BatchSize: LimitMax10000 | None + MaximumBatchingWindowInSeconds: MaximumBatchingWindowInSeconds | None class UpdatePipeSourceDynamoDBStreamParameters(TypedDict, total=False): - BatchSize: Optional[LimitMax10000] - DeadLetterConfig: Optional[DeadLetterConfig] - OnPartialBatchItemFailure: Optional[OnPartialBatchItemFailureStreams] - MaximumBatchingWindowInSeconds: Optional[MaximumBatchingWindowInSeconds] - MaximumRecordAgeInSeconds: Optional[MaximumRecordAgeInSeconds] - MaximumRetryAttempts: Optional[MaximumRetryAttemptsESM] - ParallelizationFactor: Optional[LimitMax10] + BatchSize: LimitMax10000 | None + DeadLetterConfig: DeadLetterConfig | None + OnPartialBatchItemFailure: OnPartialBatchItemFailureStreams | None + MaximumBatchingWindowInSeconds: MaximumBatchingWindowInSeconds | None + MaximumRecordAgeInSeconds: MaximumRecordAgeInSeconds | None + MaximumRetryAttempts: MaximumRetryAttemptsESM | None + ParallelizationFactor: LimitMax10 | None class UpdatePipeSourceKinesisStreamParameters(TypedDict, total=False): - BatchSize: Optional[LimitMax10000] - DeadLetterConfig: Optional[DeadLetterConfig] - OnPartialBatchItemFailure: Optional[OnPartialBatchItemFailureStreams] - MaximumBatchingWindowInSeconds: Optional[MaximumBatchingWindowInSeconds] - MaximumRecordAgeInSeconds: Optional[MaximumRecordAgeInSeconds] - MaximumRetryAttempts: Optional[MaximumRetryAttemptsESM] - ParallelizationFactor: Optional[LimitMax10] + BatchSize: LimitMax10000 | None + DeadLetterConfig: DeadLetterConfig | None + OnPartialBatchItemFailure: OnPartialBatchItemFailureStreams | None + MaximumBatchingWindowInSeconds: MaximumBatchingWindowInSeconds | None + MaximumRecordAgeInSeconds: MaximumRecordAgeInSeconds | None + MaximumRetryAttempts: MaximumRetryAttemptsESM | None + ParallelizationFactor: LimitMax10 | None class UpdatePipeSourceParameters(TypedDict, total=False): - FilterCriteria: Optional[FilterCriteria] - KinesisStreamParameters: Optional[UpdatePipeSourceKinesisStreamParameters] - DynamoDBStreamParameters: Optional[UpdatePipeSourceDynamoDBStreamParameters] - SqsQueueParameters: Optional[UpdatePipeSourceSqsQueueParameters] - ActiveMQBrokerParameters: Optional[UpdatePipeSourceActiveMQBrokerParameters] - RabbitMQBrokerParameters: Optional[UpdatePipeSourceRabbitMQBrokerParameters] - ManagedStreamingKafkaParameters: Optional[UpdatePipeSourceManagedStreamingKafkaParameters] - SelfManagedKafkaParameters: Optional[UpdatePipeSourceSelfManagedKafkaParameters] + FilterCriteria: FilterCriteria | None + KinesisStreamParameters: UpdatePipeSourceKinesisStreamParameters | None + DynamoDBStreamParameters: UpdatePipeSourceDynamoDBStreamParameters | None + SqsQueueParameters: UpdatePipeSourceSqsQueueParameters | None + ActiveMQBrokerParameters: UpdatePipeSourceActiveMQBrokerParameters | None + RabbitMQBrokerParameters: UpdatePipeSourceRabbitMQBrokerParameters | None + ManagedStreamingKafkaParameters: UpdatePipeSourceManagedStreamingKafkaParameters | None + SelfManagedKafkaParameters: UpdatePipeSourceSelfManagedKafkaParameters | None class UpdatePipeRequest(ServiceRequest): Name: PipeName - Description: Optional[PipeDescription] - DesiredState: Optional[RequestedPipeState] - SourceParameters: Optional[UpdatePipeSourceParameters] - Enrichment: Optional[OptionalArn] - EnrichmentParameters: Optional[PipeEnrichmentParameters] - Target: Optional[Arn] - TargetParameters: Optional[PipeTargetParameters] + Description: PipeDescription | None + DesiredState: RequestedPipeState | None + SourceParameters: UpdatePipeSourceParameters | None + Enrichment: OptionalArn | None + EnrichmentParameters: PipeEnrichmentParameters | None + Target: Arn | None + TargetParameters: PipeTargetParameters | None RoleArn: RoleArn - LogConfiguration: Optional[PipeLogConfigurationParameters] - KmsKeyIdentifier: Optional[KmsKeyIdentifier] + LogConfiguration: PipeLogConfigurationParameters | None + KmsKeyIdentifier: KmsKeyIdentifier | None class UpdatePipeResponse(TypedDict, total=False): - Arn: Optional[PipeArn] - Name: Optional[PipeName] - DesiredState: Optional[RequestedPipeState] - CurrentState: Optional[PipeState] - CreationTime: Optional[Timestamp] - LastModifiedTime: Optional[Timestamp] + Arn: PipeArn | None + Name: PipeName | None + DesiredState: RequestedPipeState | None + CurrentState: PipeState | None + CreationTime: Timestamp | None + LastModifiedTime: Timestamp | None class PipesApi: - service = "pipes" - version = "2015-10-07" + service: str = "pipes" + version: str = "2015-10-07" @handler("CreatePipe") def create_pipe( diff --git a/localstack-core/localstack/aws/api/redshift/__init__.py b/localstack-core/localstack/aws/api/redshift/__init__.py index a2d440b99b8e9..46576038b6aec 100644 --- a/localstack-core/localstack/aws/api/redshift/__init__.py +++ b/localstack-core/localstack/aws/api/redshift/__init__.py @@ -1,12 +1,13 @@ from datetime import datetime from enum import StrEnum -from typing import Dict, List, Optional, TypedDict +from typing import TypedDict from localstack.aws.api import RequestContext, ServiceException, ServiceRequest, handler AuthenticationProfileNameString = str Boolean = bool BooleanOptional = bool +CatalogNameString = str CustomDomainCertificateArnString = str CustomDomainNameString = str Description = str @@ -39,6 +40,11 @@ class ActionType(StrEnum): resize_cluster = "resize-cluster" +class ApplicationType(StrEnum): + None_ = "None" + Lakehouse = "Lakehouse" + + class AquaConfigurationStatus(StrEnum): enabled = "enabled" disabled = "disabled" @@ -95,6 +101,16 @@ class ImpactRankingType(StrEnum): LOW = "LOW" +class LakehouseIdcRegistration(StrEnum): + Associate = "Associate" + Disassociate = "Disassociate" + + +class LakehouseRegistration(StrEnum): + Register = "Register" + Deregister = "Deregister" + + class LogDestinationType(StrEnum): s3 = "s3" cloudwatch = "cloudwatch" @@ -227,6 +243,7 @@ class UsageLimitFeatureType(StrEnum): spectrum = "spectrum" concurrency_scaling = "concurrency-scaling" cross_region_datasharing = "cross-region-datasharing" + extra_compute_for_automatic_optimization = "extra-compute-for-automatic-optimization" class UsageLimitLimitType(StrEnum): @@ -844,6 +861,12 @@ class RedshiftIdcApplicationQuotaExceededFault(ServiceException): status_code: int = 400 +class RedshiftInvalidParameterFault(ServiceException): + code: str = "RedshiftInvalidParameter" + sender_fault: bool = True + status_code: int = 400 + + class ReservedNodeAlreadyExistsFault(ServiceException): code: str = "ReservedNodeAlreadyExists" sender_fault: bool = True @@ -1108,256 +1131,256 @@ class AcceptReservedNodeExchangeInputMessage(ServiceRequest): class RecurringCharge(TypedDict, total=False): - RecurringChargeAmount: Optional[Double] - RecurringChargeFrequency: Optional[String] + RecurringChargeAmount: Double | None + RecurringChargeFrequency: String | None -RecurringChargeList = List[RecurringCharge] +RecurringChargeList = list[RecurringCharge] TStamp = datetime class ReservedNode(TypedDict, total=False): - ReservedNodeId: Optional[String] - ReservedNodeOfferingId: Optional[String] - NodeType: Optional[String] - StartTime: Optional[TStamp] - Duration: Optional[Integer] - FixedPrice: Optional[Double] - UsagePrice: Optional[Double] - CurrencyCode: Optional[String] - NodeCount: Optional[Integer] - State: Optional[String] - OfferingType: Optional[String] - RecurringCharges: Optional[RecurringChargeList] - ReservedNodeOfferingType: Optional[ReservedNodeOfferingType] + ReservedNodeId: String | None + ReservedNodeOfferingId: String | None + NodeType: String | None + StartTime: TStamp | None + Duration: Integer | None + FixedPrice: Double | None + UsagePrice: Double | None + CurrencyCode: String | None + NodeCount: Integer | None + State: String | None + OfferingType: String | None + RecurringCharges: RecurringChargeList | None + ReservedNodeOfferingType: ReservedNodeOfferingType | None class AcceptReservedNodeExchangeOutputMessage(TypedDict, total=False): - ExchangedReservedNode: Optional[ReservedNode] + ExchangedReservedNode: ReservedNode | None class AttributeValueTarget(TypedDict, total=False): - AttributeValue: Optional[String] + AttributeValue: String | None -AttributeValueList = List[AttributeValueTarget] +AttributeValueList = list[AttributeValueTarget] class AccountAttribute(TypedDict, total=False): - AttributeName: Optional[String] - AttributeValues: Optional[AttributeValueList] + AttributeName: String | None + AttributeValues: AttributeValueList | None -AttributeList = List[AccountAttribute] +AttributeList = list[AccountAttribute] class AccountAttributeList(TypedDict, total=False): - AccountAttributes: Optional[AttributeList] + AccountAttributes: AttributeList | None class AccountWithRestoreAccess(TypedDict, total=False): - AccountId: Optional[String] - AccountAlias: Optional[String] + AccountId: String | None + AccountAlias: String | None -AccountsWithRestoreAccessList = List[AccountWithRestoreAccess] +AccountsWithRestoreAccessList = list[AccountWithRestoreAccess] class AquaConfiguration(TypedDict, total=False): - AquaStatus: Optional[AquaStatus] - AquaConfigurationStatus: Optional[AquaConfigurationStatus] + AquaStatus: AquaStatus | None + AquaConfigurationStatus: AquaConfigurationStatus | None class AssociateDataShareConsumerMessage(ServiceRequest): DataShareArn: String - AssociateEntireAccount: Optional[BooleanOptional] - ConsumerArn: Optional[String] - ConsumerRegion: Optional[String] - AllowWrites: Optional[BooleanOptional] + AssociateEntireAccount: BooleanOptional | None + ConsumerArn: String | None + ConsumerRegion: String | None + AllowWrites: BooleanOptional | None class ClusterAssociatedToSchedule(TypedDict, total=False): - ClusterIdentifier: Optional[String] - ScheduleAssociationState: Optional[ScheduleState] + ClusterIdentifier: String | None + ScheduleAssociationState: ScheduleState | None -AssociatedClusterList = List[ClusterAssociatedToSchedule] +AssociatedClusterList = list[ClusterAssociatedToSchedule] class CertificateAssociation(TypedDict, total=False): - CustomDomainName: Optional[String] - ClusterIdentifier: Optional[String] + CustomDomainName: String | None + ClusterIdentifier: String | None -CertificateAssociationList = List[CertificateAssociation] +CertificateAssociationList = list[CertificateAssociation] class Association(TypedDict, total=False): - CustomDomainCertificateArn: Optional[String] - CustomDomainCertificateExpiryDate: Optional[TStamp] - CertificateAssociations: Optional[CertificateAssociationList] + CustomDomainCertificateArn: String | None + CustomDomainCertificateExpiryDate: TStamp | None + CertificateAssociations: CertificateAssociationList | None -AssociationList = List[Association] -AttributeNameList = List[String] +AssociationList = list[Association] +AttributeNameList = list[String] class AuthenticationProfile(TypedDict, total=False): - AuthenticationProfileName: Optional[AuthenticationProfileNameString] - AuthenticationProfileContent: Optional[String] + AuthenticationProfileName: AuthenticationProfileNameString | None + AuthenticationProfileContent: String | None -AuthenticationProfileList = List[AuthenticationProfile] +AuthenticationProfileList = list[AuthenticationProfile] class AuthorizeClusterSecurityGroupIngressMessage(ServiceRequest): ClusterSecurityGroupName: String - CIDRIP: Optional[String] - EC2SecurityGroupName: Optional[String] - EC2SecurityGroupOwnerId: Optional[String] + CIDRIP: String | None + EC2SecurityGroupName: String | None + EC2SecurityGroupOwnerId: String | None class Tag(TypedDict, total=False): - Key: Optional[String] - Value: Optional[String] + Key: String | None + Value: String | None -TagList = List[Tag] +TagList = list[Tag] class IPRange(TypedDict, total=False): - Status: Optional[String] - CIDRIP: Optional[String] - Tags: Optional[TagList] + Status: String | None + CIDRIP: String | None + Tags: TagList | None -IPRangeList = List[IPRange] +IPRangeList = list[IPRange] class EC2SecurityGroup(TypedDict, total=False): - Status: Optional[String] - EC2SecurityGroupName: Optional[String] - EC2SecurityGroupOwnerId: Optional[String] - Tags: Optional[TagList] + Status: String | None + EC2SecurityGroupName: String | None + EC2SecurityGroupOwnerId: String | None + Tags: TagList | None -EC2SecurityGroupList = List[EC2SecurityGroup] +EC2SecurityGroupList = list[EC2SecurityGroup] class ClusterSecurityGroup(TypedDict, total=False): - ClusterSecurityGroupName: Optional[String] - Description: Optional[String] - EC2SecurityGroups: Optional[EC2SecurityGroupList] - IPRanges: Optional[IPRangeList] - Tags: Optional[TagList] + ClusterSecurityGroupName: String | None + Description: String | None + EC2SecurityGroups: EC2SecurityGroupList | None + IPRanges: IPRangeList | None + Tags: TagList | None class AuthorizeClusterSecurityGroupIngressResult(TypedDict, total=False): - ClusterSecurityGroup: Optional[ClusterSecurityGroup] + ClusterSecurityGroup: ClusterSecurityGroup | None class AuthorizeDataShareMessage(ServiceRequest): DataShareArn: String ConsumerIdentifier: String - AllowWrites: Optional[BooleanOptional] + AllowWrites: BooleanOptional | None -VpcIdentifierList = List[String] +VpcIdentifierList = list[String] class AuthorizeEndpointAccessMessage(ServiceRequest): - ClusterIdentifier: Optional[String] + ClusterIdentifier: String | None Account: String - VpcIds: Optional[VpcIdentifierList] + VpcIds: VpcIdentifierList | None class AuthorizeSnapshotAccessMessage(ServiceRequest): - SnapshotIdentifier: Optional[String] - SnapshotArn: Optional[String] - SnapshotClusterIdentifier: Optional[String] + SnapshotIdentifier: String | None + SnapshotArn: String | None + SnapshotClusterIdentifier: String | None AccountWithRestoreAccess: String -RestorableNodeTypeList = List[String] +RestorableNodeTypeList = list[String] Long = int class Snapshot(TypedDict, total=False): - SnapshotIdentifier: Optional[String] - ClusterIdentifier: Optional[String] - SnapshotCreateTime: Optional[TStamp] - Status: Optional[String] - Port: Optional[Integer] - AvailabilityZone: Optional[String] - ClusterCreateTime: Optional[TStamp] - MasterUsername: Optional[String] - ClusterVersion: Optional[String] - EngineFullVersion: Optional[String] - SnapshotType: Optional[String] - NodeType: Optional[String] - NumberOfNodes: Optional[Integer] - DBName: Optional[String] - VpcId: Optional[String] - Encrypted: Optional[Boolean] - KmsKeyId: Optional[String] - EncryptedWithHSM: Optional[Boolean] - AccountsWithRestoreAccess: Optional[AccountsWithRestoreAccessList] - OwnerAccount: Optional[String] - TotalBackupSizeInMegaBytes: Optional[Double] - ActualIncrementalBackupSizeInMegaBytes: Optional[Double] - BackupProgressInMegaBytes: Optional[Double] - CurrentBackupRateInMegaBytesPerSecond: Optional[Double] - EstimatedSecondsToCompletion: Optional[Long] - ElapsedTimeInSeconds: Optional[Long] - SourceRegion: Optional[String] - Tags: Optional[TagList] - RestorableNodeTypes: Optional[RestorableNodeTypeList] - EnhancedVpcRouting: Optional[Boolean] - MaintenanceTrackName: Optional[String] - ManualSnapshotRetentionPeriod: Optional[IntegerOptional] - ManualSnapshotRemainingDays: Optional[IntegerOptional] - SnapshotRetentionStartTime: Optional[TStamp] - MasterPasswordSecretArn: Optional[String] - MasterPasswordSecretKmsKeyId: Optional[String] - SnapshotArn: Optional[String] + SnapshotIdentifier: String | None + ClusterIdentifier: String | None + SnapshotCreateTime: TStamp | None + Status: String | None + Port: Integer | None + AvailabilityZone: String | None + ClusterCreateTime: TStamp | None + MasterUsername: String | None + ClusterVersion: String | None + EngineFullVersion: String | None + SnapshotType: String | None + NodeType: String | None + NumberOfNodes: Integer | None + DBName: String | None + VpcId: String | None + Encrypted: Boolean | None + KmsKeyId: String | None + EncryptedWithHSM: Boolean | None + AccountsWithRestoreAccess: AccountsWithRestoreAccessList | None + OwnerAccount: String | None + TotalBackupSizeInMegaBytes: Double | None + ActualIncrementalBackupSizeInMegaBytes: Double | None + BackupProgressInMegaBytes: Double | None + CurrentBackupRateInMegaBytesPerSecond: Double | None + EstimatedSecondsToCompletion: Long | None + ElapsedTimeInSeconds: Long | None + SourceRegion: String | None + Tags: TagList | None + RestorableNodeTypes: RestorableNodeTypeList | None + EnhancedVpcRouting: Boolean | None + MaintenanceTrackName: String | None + ManualSnapshotRetentionPeriod: IntegerOptional | None + ManualSnapshotRemainingDays: IntegerOptional | None + SnapshotRetentionStartTime: TStamp | None + MasterPasswordSecretArn: String | None + MasterPasswordSecretKmsKeyId: String | None + SnapshotArn: String | None class AuthorizeSnapshotAccessResult(TypedDict, total=False): - Snapshot: Optional[Snapshot] + Snapshot: Snapshot | None -AuthorizedAudienceList = List[String] +AuthorizedAudienceList = list[String] class AuthorizedTokenIssuer(TypedDict, total=False): - TrustedTokenIssuerArn: Optional[String] - AuthorizedAudiencesList: Optional[AuthorizedAudienceList] + TrustedTokenIssuerArn: String | None + AuthorizedAudiencesList: AuthorizedAudienceList | None -AuthorizedTokenIssuerList = List[AuthorizedTokenIssuer] +AuthorizedTokenIssuerList = list[AuthorizedTokenIssuer] class SupportedPlatform(TypedDict, total=False): - Name: Optional[String] + Name: String | None -SupportedPlatformsList = List[SupportedPlatform] +SupportedPlatformsList = list[SupportedPlatform] class AvailabilityZone(TypedDict, total=False): - Name: Optional[String] - SupportedPlatforms: Optional[SupportedPlatformsList] + Name: String | None + SupportedPlatforms: SupportedPlatformsList | None -AvailabilityZoneList = List[AvailabilityZone] +AvailabilityZoneList = list[AvailabilityZone] class DeleteClusterSnapshotMessage(ServiceRequest): SnapshotIdentifier: String - SnapshotClusterIdentifier: Optional[String] + SnapshotClusterIdentifier: String | None -DeleteClusterSnapshotMessageList = List[DeleteClusterSnapshotMessage] +DeleteClusterSnapshotMessageList = list[DeleteClusterSnapshotMessage] class BatchDeleteClusterSnapshotsRequest(ServiceRequest): @@ -1365,33 +1388,33 @@ class BatchDeleteClusterSnapshotsRequest(ServiceRequest): class SnapshotErrorMessage(TypedDict, total=False): - SnapshotIdentifier: Optional[String] - SnapshotClusterIdentifier: Optional[String] - FailureCode: Optional[String] - FailureReason: Optional[String] + SnapshotIdentifier: String | None + SnapshotClusterIdentifier: String | None + FailureCode: String | None + FailureReason: String | None -BatchSnapshotOperationErrorList = List[SnapshotErrorMessage] -SnapshotIdentifierList = List[String] +BatchSnapshotOperationErrorList = list[SnapshotErrorMessage] +SnapshotIdentifierList = list[String] class BatchDeleteClusterSnapshotsResult(TypedDict, total=False): - Resources: Optional[SnapshotIdentifierList] - Errors: Optional[BatchSnapshotOperationErrorList] + Resources: SnapshotIdentifierList | None + Errors: BatchSnapshotOperationErrorList | None class BatchModifyClusterSnapshotsMessage(ServiceRequest): SnapshotIdentifierList: SnapshotIdentifierList - ManualSnapshotRetentionPeriod: Optional[IntegerOptional] - Force: Optional[Boolean] + ManualSnapshotRetentionPeriod: IntegerOptional | None + Force: Boolean | None -BatchSnapshotOperationErrors = List[SnapshotErrorMessage] +BatchSnapshotOperationErrors = list[SnapshotErrorMessage] class BatchModifyClusterSnapshotsOutputMessage(TypedDict, total=False): - Resources: Optional[SnapshotIdentifierList] - Errors: Optional[BatchSnapshotOperationErrors] + Resources: SnapshotIdentifierList | None + Errors: BatchSnapshotOperationErrors | None class CancelResizeMessage(ServiceRequest): @@ -1399,380 +1422,388 @@ class CancelResizeMessage(ServiceRequest): class ClusterNode(TypedDict, total=False): - NodeRole: Optional[String] - PrivateIPAddress: Optional[String] - PublicIPAddress: Optional[String] + NodeRole: String | None + PrivateIPAddress: String | None + PublicIPAddress: String | None -ClusterNodesList = List[ClusterNode] +ClusterNodesList = list[ClusterNode] class SecondaryClusterInfo(TypedDict, total=False): - AvailabilityZone: Optional[String] - ClusterNodes: Optional[ClusterNodesList] + AvailabilityZone: String | None + ClusterNodes: ClusterNodesList | None class ReservedNodeExchangeStatus(TypedDict, total=False): - ReservedNodeExchangeRequestId: Optional[String] - Status: Optional[ReservedNodeExchangeStatusType] - RequestTime: Optional[TStamp] - SourceReservedNodeId: Optional[String] - SourceReservedNodeType: Optional[String] - SourceReservedNodeCount: Optional[Integer] - TargetReservedNodeOfferingId: Optional[String] - TargetReservedNodeType: Optional[String] - TargetReservedNodeCount: Optional[Integer] + ReservedNodeExchangeRequestId: String | None + Status: ReservedNodeExchangeStatusType | None + RequestTime: TStamp | None + SourceReservedNodeId: String | None + SourceReservedNodeType: String | None + SourceReservedNodeCount: Integer | None + TargetReservedNodeOfferingId: String | None + TargetReservedNodeType: String | None + TargetReservedNodeCount: Integer | None LongOptional = int class ResizeInfo(TypedDict, total=False): - ResizeType: Optional[String] - AllowCancelResize: Optional[Boolean] + ResizeType: String | None + AllowCancelResize: Boolean | None class DeferredMaintenanceWindow(TypedDict, total=False): - DeferMaintenanceIdentifier: Optional[String] - DeferMaintenanceStartTime: Optional[TStamp] - DeferMaintenanceEndTime: Optional[TStamp] + DeferMaintenanceIdentifier: String | None + DeferMaintenanceStartTime: TStamp | None + DeferMaintenanceEndTime: TStamp | None -DeferredMaintenanceWindowsList = List[DeferredMaintenanceWindow] -PendingActionsList = List[String] +DeferredMaintenanceWindowsList = list[DeferredMaintenanceWindow] +PendingActionsList = list[String] class ClusterIamRole(TypedDict, total=False): - IamRoleArn: Optional[String] - ApplyStatus: Optional[String] + IamRoleArn: String | None + ApplyStatus: String | None -ClusterIamRoleList = List[ClusterIamRole] +ClusterIamRoleList = list[ClusterIamRole] class ElasticIpStatus(TypedDict, total=False): - ElasticIp: Optional[String] - Status: Optional[String] + ElasticIp: String | None + Status: String | None class ClusterSnapshotCopyStatus(TypedDict, total=False): - DestinationRegion: Optional[String] - RetentionPeriod: Optional[Long] - ManualSnapshotRetentionPeriod: Optional[Integer] - SnapshotCopyGrantName: Optional[String] + DestinationRegion: String | None + RetentionPeriod: Long | None + ManualSnapshotRetentionPeriod: Integer | None + SnapshotCopyGrantName: String | None class HsmStatus(TypedDict, total=False): - HsmClientCertificateIdentifier: Optional[String] - HsmConfigurationIdentifier: Optional[String] - Status: Optional[String] + HsmClientCertificateIdentifier: String | None + HsmConfigurationIdentifier: String | None + Status: String | None class DataTransferProgress(TypedDict, total=False): - Status: Optional[String] - CurrentRateInMegaBytesPerSecond: Optional[DoubleOptional] - TotalDataInMegaBytes: Optional[Long] - DataTransferredInMegaBytes: Optional[Long] - EstimatedTimeToCompletionInSeconds: Optional[LongOptional] - ElapsedTimeInSeconds: Optional[LongOptional] + Status: String | None + CurrentRateInMegaBytesPerSecond: DoubleOptional | None + TotalDataInMegaBytes: Long | None + DataTransferredInMegaBytes: Long | None + EstimatedTimeToCompletionInSeconds: LongOptional | None + ElapsedTimeInSeconds: LongOptional | None class RestoreStatus(TypedDict, total=False): - Status: Optional[String] - CurrentRestoreRateInMegaBytesPerSecond: Optional[Double] - SnapshotSizeInMegaBytes: Optional[Long] - ProgressInMegaBytes: Optional[Long] - ElapsedTimeInSeconds: Optional[Long] - EstimatedTimeToCompletionInSeconds: Optional[Long] + Status: String | None + CurrentRestoreRateInMegaBytesPerSecond: Double | None + SnapshotSizeInMegaBytes: Long | None + ProgressInMegaBytes: Long | None + ElapsedTimeInSeconds: Long | None + EstimatedTimeToCompletionInSeconds: Long | None class PendingModifiedValues(TypedDict, total=False): - MasterUserPassword: Optional[SensitiveString] - NodeType: Optional[String] - NumberOfNodes: Optional[IntegerOptional] - ClusterType: Optional[String] - ClusterVersion: Optional[String] - AutomatedSnapshotRetentionPeriod: Optional[IntegerOptional] - ClusterIdentifier: Optional[String] - PubliclyAccessible: Optional[BooleanOptional] - EnhancedVpcRouting: Optional[BooleanOptional] - MaintenanceTrackName: Optional[String] - EncryptionType: Optional[String] + MasterUserPassword: SensitiveString | None + NodeType: String | None + NumberOfNodes: IntegerOptional | None + ClusterType: String | None + ClusterVersion: String | None + AutomatedSnapshotRetentionPeriod: IntegerOptional | None + ClusterIdentifier: String | None + PubliclyAccessible: BooleanOptional | None + EnhancedVpcRouting: BooleanOptional | None + MaintenanceTrackName: String | None + EncryptionType: String | None class ClusterParameterStatus(TypedDict, total=False): - ParameterName: Optional[String] - ParameterApplyStatus: Optional[String] - ParameterApplyErrorDescription: Optional[String] + ParameterName: String | None + ParameterApplyStatus: String | None + ParameterApplyErrorDescription: String | None -ClusterParameterStatusList = List[ClusterParameterStatus] +ClusterParameterStatusList = list[ClusterParameterStatus] class ClusterParameterGroupStatus(TypedDict, total=False): - ParameterGroupName: Optional[String] - ParameterApplyStatus: Optional[String] - ClusterParameterStatusList: Optional[ClusterParameterStatusList] + ParameterGroupName: String | None + ParameterApplyStatus: String | None + ClusterParameterStatusList: ClusterParameterStatusList | None -ClusterParameterGroupStatusList = List[ClusterParameterGroupStatus] +ClusterParameterGroupStatusList = list[ClusterParameterGroupStatus] class VpcSecurityGroupMembership(TypedDict, total=False): - VpcSecurityGroupId: Optional[String] - Status: Optional[String] + VpcSecurityGroupId: String | None + Status: String | None -VpcSecurityGroupMembershipList = List[VpcSecurityGroupMembership] +VpcSecurityGroupMembershipList = list[VpcSecurityGroupMembership] class ClusterSecurityGroupMembership(TypedDict, total=False): - ClusterSecurityGroupName: Optional[String] - Status: Optional[String] + ClusterSecurityGroupName: String | None + Status: String | None -ClusterSecurityGroupMembershipList = List[ClusterSecurityGroupMembership] +ClusterSecurityGroupMembershipList = list[ClusterSecurityGroupMembership] class NetworkInterface(TypedDict, total=False): - NetworkInterfaceId: Optional[String] - SubnetId: Optional[String] - PrivateIpAddress: Optional[String] - AvailabilityZone: Optional[String] - Ipv6Address: Optional[String] + NetworkInterfaceId: String | None + SubnetId: String | None + PrivateIpAddress: String | None + AvailabilityZone: String | None + Ipv6Address: String | None -NetworkInterfaceList = List[NetworkInterface] +NetworkInterfaceList = list[NetworkInterface] class VpcEndpoint(TypedDict, total=False): - VpcEndpointId: Optional[String] - VpcId: Optional[String] - NetworkInterfaces: Optional[NetworkInterfaceList] + VpcEndpointId: String | None + VpcId: String | None + NetworkInterfaces: NetworkInterfaceList | None -VpcEndpointsList = List[VpcEndpoint] +VpcEndpointsList = list[VpcEndpoint] class Endpoint(TypedDict, total=False): - Address: Optional[String] - Port: Optional[Integer] - VpcEndpoints: Optional[VpcEndpointsList] + Address: String | None + Port: Integer | None + VpcEndpoints: VpcEndpointsList | None class Cluster(TypedDict, total=False): - ClusterIdentifier: Optional[String] - NodeType: Optional[String] - ClusterStatus: Optional[String] - ClusterAvailabilityStatus: Optional[String] - ModifyStatus: Optional[String] - MasterUsername: Optional[String] - DBName: Optional[String] - Endpoint: Optional[Endpoint] - ClusterCreateTime: Optional[TStamp] - AutomatedSnapshotRetentionPeriod: Optional[Integer] - ManualSnapshotRetentionPeriod: Optional[Integer] - ClusterSecurityGroups: Optional[ClusterSecurityGroupMembershipList] - VpcSecurityGroups: Optional[VpcSecurityGroupMembershipList] - ClusterParameterGroups: Optional[ClusterParameterGroupStatusList] - ClusterSubnetGroupName: Optional[String] - VpcId: Optional[String] - AvailabilityZone: Optional[String] - PreferredMaintenanceWindow: Optional[String] - PendingModifiedValues: Optional[PendingModifiedValues] - ClusterVersion: Optional[String] - AllowVersionUpgrade: Optional[Boolean] - NumberOfNodes: Optional[Integer] - PubliclyAccessible: Optional[Boolean] - Encrypted: Optional[Boolean] - RestoreStatus: Optional[RestoreStatus] - DataTransferProgress: Optional[DataTransferProgress] - HsmStatus: Optional[HsmStatus] - ClusterSnapshotCopyStatus: Optional[ClusterSnapshotCopyStatus] - ClusterPublicKey: Optional[String] - ClusterNodes: Optional[ClusterNodesList] - ElasticIpStatus: Optional[ElasticIpStatus] - ClusterRevisionNumber: Optional[String] - Tags: Optional[TagList] - KmsKeyId: Optional[String] - EnhancedVpcRouting: Optional[Boolean] - IamRoles: Optional[ClusterIamRoleList] - PendingActions: Optional[PendingActionsList] - MaintenanceTrackName: Optional[String] - ElasticResizeNumberOfNodeOptions: Optional[String] - DeferredMaintenanceWindows: Optional[DeferredMaintenanceWindowsList] - SnapshotScheduleIdentifier: Optional[String] - SnapshotScheduleState: Optional[ScheduleState] - ExpectedNextSnapshotScheduleTime: Optional[TStamp] - ExpectedNextSnapshotScheduleTimeStatus: Optional[String] - NextMaintenanceWindowStartTime: Optional[TStamp] - ResizeInfo: Optional[ResizeInfo] - AvailabilityZoneRelocationStatus: Optional[String] - ClusterNamespaceArn: Optional[String] - TotalStorageCapacityInMegaBytes: Optional[LongOptional] - AquaConfiguration: Optional[AquaConfiguration] - DefaultIamRoleArn: Optional[String] - ReservedNodeExchangeStatus: Optional[ReservedNodeExchangeStatus] - CustomDomainName: Optional[String] - CustomDomainCertificateArn: Optional[String] - CustomDomainCertificateExpiryDate: Optional[TStamp] - MasterPasswordSecretArn: Optional[String] - MasterPasswordSecretKmsKeyId: Optional[String] - IpAddressType: Optional[String] - MultiAZ: Optional[String] - MultiAZSecondary: Optional[SecondaryClusterInfo] + ClusterIdentifier: String | None + NodeType: String | None + ClusterStatus: String | None + ClusterAvailabilityStatus: String | None + ModifyStatus: String | None + MasterUsername: String | None + DBName: String | None + Endpoint: Endpoint | None + ClusterCreateTime: TStamp | None + AutomatedSnapshotRetentionPeriod: Integer | None + ManualSnapshotRetentionPeriod: Integer | None + ClusterSecurityGroups: ClusterSecurityGroupMembershipList | None + VpcSecurityGroups: VpcSecurityGroupMembershipList | None + ClusterParameterGroups: ClusterParameterGroupStatusList | None + ClusterSubnetGroupName: String | None + VpcId: String | None + AvailabilityZone: String | None + PreferredMaintenanceWindow: String | None + PendingModifiedValues: PendingModifiedValues | None + ClusterVersion: String | None + AllowVersionUpgrade: Boolean | None + NumberOfNodes: Integer | None + PubliclyAccessible: Boolean | None + Encrypted: Boolean | None + RestoreStatus: RestoreStatus | None + DataTransferProgress: DataTransferProgress | None + HsmStatus: HsmStatus | None + ClusterSnapshotCopyStatus: ClusterSnapshotCopyStatus | None + ClusterPublicKey: String | None + ClusterNodes: ClusterNodesList | None + ElasticIpStatus: ElasticIpStatus | None + ClusterRevisionNumber: String | None + Tags: TagList | None + KmsKeyId: String | None + EnhancedVpcRouting: Boolean | None + IamRoles: ClusterIamRoleList | None + PendingActions: PendingActionsList | None + MaintenanceTrackName: String | None + ElasticResizeNumberOfNodeOptions: String | None + DeferredMaintenanceWindows: DeferredMaintenanceWindowsList | None + SnapshotScheduleIdentifier: String | None + SnapshotScheduleState: ScheduleState | None + ExpectedNextSnapshotScheduleTime: TStamp | None + ExpectedNextSnapshotScheduleTimeStatus: String | None + NextMaintenanceWindowStartTime: TStamp | None + ResizeInfo: ResizeInfo | None + AvailabilityZoneRelocationStatus: String | None + ClusterNamespaceArn: String | None + TotalStorageCapacityInMegaBytes: LongOptional | None + AquaConfiguration: AquaConfiguration | None + DefaultIamRoleArn: String | None + ReservedNodeExchangeStatus: ReservedNodeExchangeStatus | None + CustomDomainName: String | None + CustomDomainCertificateArn: String | None + CustomDomainCertificateExpiryDate: TStamp | None + MasterPasswordSecretArn: String | None + MasterPasswordSecretKmsKeyId: String | None + IpAddressType: String | None + MultiAZ: String | None + MultiAZSecondary: SecondaryClusterInfo | None + LakehouseRegistrationStatus: String | None + CatalogArn: String | None + ExtraComputeForAutomaticOptimization: String | None class ClusterCredentials(TypedDict, total=False): - DbUser: Optional[String] - DbPassword: Optional[SensitiveString] - Expiration: Optional[TStamp] + DbUser: String | None + DbPassword: SensitiveString | None + Expiration: TStamp | None class RevisionTarget(TypedDict, total=False): - DatabaseRevision: Optional[String] - Description: Optional[String] - DatabaseRevisionReleaseDate: Optional[TStamp] + DatabaseRevision: String | None + Description: String | None + DatabaseRevisionReleaseDate: TStamp | None -RevisionTargetsList = List[RevisionTarget] +RevisionTargetsList = list[RevisionTarget] class ClusterDbRevision(TypedDict, total=False): - ClusterIdentifier: Optional[String] - CurrentDatabaseRevision: Optional[String] - DatabaseRevisionReleaseDate: Optional[TStamp] - RevisionTargets: Optional[RevisionTargetsList] + ClusterIdentifier: String | None + CurrentDatabaseRevision: String | None + DatabaseRevisionReleaseDate: TStamp | None + RevisionTargets: RevisionTargetsList | None -ClusterDbRevisionsList = List[ClusterDbRevision] +ClusterDbRevisionsList = list[ClusterDbRevision] class ClusterDbRevisionsMessage(TypedDict, total=False): - Marker: Optional[String] - ClusterDbRevisions: Optional[ClusterDbRevisionsList] + Marker: String | None + ClusterDbRevisions: ClusterDbRevisionsList | None class ClusterExtendedCredentials(TypedDict, total=False): - DbUser: Optional[String] - DbPassword: Optional[SensitiveString] - Expiration: Optional[TStamp] - NextRefreshTime: Optional[TStamp] + DbUser: String | None + DbPassword: SensitiveString | None + Expiration: TStamp | None + NextRefreshTime: TStamp | None -ClusterList = List[Cluster] +ClusterIdentifierList = list[String] +ClusterList = list[Cluster] class ClusterParameterGroup(TypedDict, total=False): - ParameterGroupName: Optional[String] - ParameterGroupFamily: Optional[String] - Description: Optional[String] - Tags: Optional[TagList] + ParameterGroupName: String | None + ParameterGroupFamily: String | None + Description: String | None + Tags: TagList | None class Parameter(TypedDict, total=False): - ParameterName: Optional[String] - ParameterValue: Optional[String] - Description: Optional[String] - Source: Optional[String] - DataType: Optional[String] - AllowedValues: Optional[String] - ApplyType: Optional[ParameterApplyType] - IsModifiable: Optional[Boolean] - MinimumEngineVersion: Optional[String] + ParameterName: String | None + ParameterValue: String | None + Description: String | None + Source: String | None + DataType: String | None + AllowedValues: String | None + ApplyType: ParameterApplyType | None + IsModifiable: Boolean | None + MinimumEngineVersion: String | None -ParametersList = List[Parameter] +ParametersList = list[Parameter] class ClusterParameterGroupDetails(TypedDict, total=False): - Parameters: Optional[ParametersList] - Marker: Optional[String] + Parameters: ParametersList | None + Marker: String | None class ClusterParameterGroupNameMessage(TypedDict, total=False): - ParameterGroupName: Optional[String] - ParameterGroupStatus: Optional[String] + ParameterGroupName: String | None + ParameterGroupStatus: String | None -ParameterGroupList = List[ClusterParameterGroup] +ParameterGroupList = list[ClusterParameterGroup] class ClusterParameterGroupsMessage(TypedDict, total=False): - Marker: Optional[String] - ParameterGroups: Optional[ParameterGroupList] + Marker: String | None + ParameterGroups: ParameterGroupList | None -ClusterSecurityGroups = List[ClusterSecurityGroup] +ClusterSecurityGroups = list[ClusterSecurityGroup] class ClusterSecurityGroupMessage(TypedDict, total=False): - Marker: Optional[String] - ClusterSecurityGroups: Optional[ClusterSecurityGroups] + Marker: String | None + ClusterSecurityGroups: ClusterSecurityGroups | None -ClusterSecurityGroupNameList = List[String] -ValueStringList = List[String] +ClusterSecurityGroupNameList = list[String] +ValueStringList = list[String] class Subnet(TypedDict, total=False): - SubnetIdentifier: Optional[String] - SubnetAvailabilityZone: Optional[AvailabilityZone] - SubnetStatus: Optional[String] + SubnetIdentifier: String | None + SubnetAvailabilityZone: AvailabilityZone | None + SubnetStatus: String | None -SubnetList = List[Subnet] +SubnetList = list[Subnet] class ClusterSubnetGroup(TypedDict, total=False): - ClusterSubnetGroupName: Optional[String] - Description: Optional[String] - VpcId: Optional[String] - SubnetGroupStatus: Optional[String] - Subnets: Optional[SubnetList] - Tags: Optional[TagList] - SupportedClusterIpAddressTypes: Optional[ValueStringList] + ClusterSubnetGroupName: String | None + Description: String | None + VpcId: String | None + SubnetGroupStatus: String | None + Subnets: SubnetList | None + Tags: TagList | None + SupportedClusterIpAddressTypes: ValueStringList | None -ClusterSubnetGroups = List[ClusterSubnetGroup] +ClusterSubnetGroups = list[ClusterSubnetGroup] class ClusterSubnetGroupMessage(TypedDict, total=False): - Marker: Optional[String] - ClusterSubnetGroups: Optional[ClusterSubnetGroups] + Marker: String | None + ClusterSubnetGroups: ClusterSubnetGroups | None class ClusterVersion(TypedDict, total=False): - ClusterVersion: Optional[String] - ClusterParameterGroupFamily: Optional[String] - Description: Optional[String] + ClusterVersion: String | None + ClusterParameterGroupFamily: String | None + Description: String | None -ClusterVersionList = List[ClusterVersion] +ClusterVersionList = list[ClusterVersion] class ClusterVersionsMessage(TypedDict, total=False): - Marker: Optional[String] - ClusterVersions: Optional[ClusterVersionList] + Marker: String | None + ClusterVersions: ClusterVersionList | None class ClustersMessage(TypedDict, total=False): - Marker: Optional[String] - Clusters: Optional[ClusterList] + Marker: String | None + Clusters: ClusterList | None + +class Connect(TypedDict, total=False): + Authorization: ServiceAuthorization -ConsumerIdentifierList = List[String] + +ConsumerIdentifierList = list[String] class CopyClusterSnapshotMessage(ServiceRequest): SourceSnapshotIdentifier: String - SourceSnapshotClusterIdentifier: Optional[String] + SourceSnapshotClusterIdentifier: String | None TargetSnapshotIdentifier: String - ManualSnapshotRetentionPeriod: Optional[IntegerOptional] + ManualSnapshotRetentionPeriod: IntegerOptional | None class CopyClusterSnapshotResult(TypedDict, total=False): - Snapshot: Optional[Snapshot] + Snapshot: Snapshot | None class CreateAuthenticationProfileMessage(ServiceRequest): @@ -1781,104 +1812,106 @@ class CreateAuthenticationProfileMessage(ServiceRequest): class CreateAuthenticationProfileResult(TypedDict, total=False): - AuthenticationProfileName: Optional[AuthenticationProfileNameString] - AuthenticationProfileContent: Optional[String] + AuthenticationProfileName: AuthenticationProfileNameString | None + AuthenticationProfileContent: String | None -IamRoleArnList = List[String] -VpcSecurityGroupIdList = List[String] +IamRoleArnList = list[String] +VpcSecurityGroupIdList = list[String] class CreateClusterMessage(ServiceRequest): - DBName: Optional[String] + DBName: String | None ClusterIdentifier: String - ClusterType: Optional[String] + ClusterType: String | None NodeType: String MasterUsername: String - MasterUserPassword: Optional[SensitiveString] - ClusterSecurityGroups: Optional[ClusterSecurityGroupNameList] - VpcSecurityGroupIds: Optional[VpcSecurityGroupIdList] - ClusterSubnetGroupName: Optional[String] - AvailabilityZone: Optional[String] - PreferredMaintenanceWindow: Optional[String] - ClusterParameterGroupName: Optional[String] - AutomatedSnapshotRetentionPeriod: Optional[IntegerOptional] - ManualSnapshotRetentionPeriod: Optional[IntegerOptional] - Port: Optional[IntegerOptional] - ClusterVersion: Optional[String] - AllowVersionUpgrade: Optional[BooleanOptional] - NumberOfNodes: Optional[IntegerOptional] - PubliclyAccessible: Optional[BooleanOptional] - Encrypted: Optional[BooleanOptional] - HsmClientCertificateIdentifier: Optional[String] - HsmConfigurationIdentifier: Optional[String] - ElasticIp: Optional[String] - Tags: Optional[TagList] - KmsKeyId: Optional[String] - EnhancedVpcRouting: Optional[BooleanOptional] - AdditionalInfo: Optional[String] - IamRoles: Optional[IamRoleArnList] - MaintenanceTrackName: Optional[String] - SnapshotScheduleIdentifier: Optional[String] - AvailabilityZoneRelocation: Optional[BooleanOptional] - AquaConfigurationStatus: Optional[AquaConfigurationStatus] - DefaultIamRoleArn: Optional[String] - LoadSampleData: Optional[String] - ManageMasterPassword: Optional[BooleanOptional] - MasterPasswordSecretKmsKeyId: Optional[String] - IpAddressType: Optional[String] - MultiAZ: Optional[BooleanOptional] - RedshiftIdcApplicationArn: Optional[String] + MasterUserPassword: SensitiveString | None + ClusterSecurityGroups: ClusterSecurityGroupNameList | None + VpcSecurityGroupIds: VpcSecurityGroupIdList | None + ClusterSubnetGroupName: String | None + AvailabilityZone: String | None + PreferredMaintenanceWindow: String | None + ClusterParameterGroupName: String | None + AutomatedSnapshotRetentionPeriod: IntegerOptional | None + ManualSnapshotRetentionPeriod: IntegerOptional | None + Port: IntegerOptional | None + ClusterVersion: String | None + AllowVersionUpgrade: BooleanOptional | None + NumberOfNodes: IntegerOptional | None + PubliclyAccessible: BooleanOptional | None + Encrypted: BooleanOptional | None + HsmClientCertificateIdentifier: String | None + HsmConfigurationIdentifier: String | None + ElasticIp: String | None + Tags: TagList | None + KmsKeyId: String | None + EnhancedVpcRouting: BooleanOptional | None + AdditionalInfo: String | None + IamRoles: IamRoleArnList | None + MaintenanceTrackName: String | None + SnapshotScheduleIdentifier: String | None + AvailabilityZoneRelocation: BooleanOptional | None + AquaConfigurationStatus: AquaConfigurationStatus | None + DefaultIamRoleArn: String | None + LoadSampleData: String | None + ManageMasterPassword: BooleanOptional | None + MasterPasswordSecretKmsKeyId: String | None + IpAddressType: String | None + MultiAZ: BooleanOptional | None + RedshiftIdcApplicationArn: String | None + CatalogName: CatalogNameString | None + ExtraComputeForAutomaticOptimization: BooleanOptional | None class CreateClusterParameterGroupMessage(ServiceRequest): ParameterGroupName: String ParameterGroupFamily: String Description: String - Tags: Optional[TagList] + Tags: TagList | None class CreateClusterParameterGroupResult(TypedDict, total=False): - ClusterParameterGroup: Optional[ClusterParameterGroup] + ClusterParameterGroup: ClusterParameterGroup | None class CreateClusterResult(TypedDict, total=False): - Cluster: Optional[Cluster] + Cluster: Cluster | None class CreateClusterSecurityGroupMessage(ServiceRequest): ClusterSecurityGroupName: String Description: String - Tags: Optional[TagList] + Tags: TagList | None class CreateClusterSecurityGroupResult(TypedDict, total=False): - ClusterSecurityGroup: Optional[ClusterSecurityGroup] + ClusterSecurityGroup: ClusterSecurityGroup | None class CreateClusterSnapshotMessage(ServiceRequest): SnapshotIdentifier: String ClusterIdentifier: String - ManualSnapshotRetentionPeriod: Optional[IntegerOptional] - Tags: Optional[TagList] + ManualSnapshotRetentionPeriod: IntegerOptional | None + Tags: TagList | None class CreateClusterSnapshotResult(TypedDict, total=False): - Snapshot: Optional[Snapshot] + Snapshot: Snapshot | None -SubnetIdentifierList = List[String] +SubnetIdentifierList = list[String] class CreateClusterSubnetGroupMessage(ServiceRequest): ClusterSubnetGroupName: String Description: String SubnetIds: SubnetIdentifierList - Tags: Optional[TagList] + Tags: TagList | None class CreateClusterSubnetGroupResult(TypedDict, total=False): - ClusterSubnetGroup: Optional[ClusterSubnetGroup] + ClusterSubnetGroup: ClusterSubnetGroup | None class CreateCustomDomainAssociationMessage(ServiceRequest): @@ -1888,66 +1921,66 @@ class CreateCustomDomainAssociationMessage(ServiceRequest): class CreateCustomDomainAssociationResult(TypedDict, total=False): - CustomDomainName: Optional[CustomDomainNameString] - CustomDomainCertificateArn: Optional[CustomDomainCertificateArnString] - ClusterIdentifier: Optional[String] - CustomDomainCertExpiryTime: Optional[String] + CustomDomainName: CustomDomainNameString | None + CustomDomainCertificateArn: CustomDomainCertificateArnString | None + ClusterIdentifier: String | None + CustomDomainCertExpiryTime: String | None class CreateEndpointAccessMessage(ServiceRequest): - ClusterIdentifier: Optional[String] - ResourceOwner: Optional[String] + ClusterIdentifier: String | None + ResourceOwner: String | None EndpointName: String SubnetGroupName: String - VpcSecurityGroupIds: Optional[VpcSecurityGroupIdList] + VpcSecurityGroupIds: VpcSecurityGroupIdList | None -EventCategoriesList = List[String] -SourceIdsList = List[String] +EventCategoriesList = list[String] +SourceIdsList = list[String] class CreateEventSubscriptionMessage(ServiceRequest): SubscriptionName: String SnsTopicArn: String - SourceType: Optional[String] - SourceIds: Optional[SourceIdsList] - EventCategories: Optional[EventCategoriesList] - Severity: Optional[String] - Enabled: Optional[BooleanOptional] - Tags: Optional[TagList] + SourceType: String | None + SourceIds: SourceIdsList | None + EventCategories: EventCategoriesList | None + Severity: String | None + Enabled: BooleanOptional | None + Tags: TagList | None class EventSubscription(TypedDict, total=False): - CustomerAwsId: Optional[String] - CustSubscriptionId: Optional[String] - SnsTopicArn: Optional[String] - Status: Optional[String] - SubscriptionCreationTime: Optional[TStamp] - SourceType: Optional[String] - SourceIdsList: Optional[SourceIdsList] - EventCategoriesList: Optional[EventCategoriesList] - Severity: Optional[String] - Enabled: Optional[Boolean] - Tags: Optional[TagList] + CustomerAwsId: String | None + CustSubscriptionId: String | None + SnsTopicArn: String | None + Status: String | None + SubscriptionCreationTime: TStamp | None + SourceType: String | None + SourceIdsList: SourceIdsList | None + EventCategoriesList: EventCategoriesList | None + Severity: String | None + Enabled: Boolean | None + Tags: TagList | None class CreateEventSubscriptionResult(TypedDict, total=False): - EventSubscription: Optional[EventSubscription] + EventSubscription: EventSubscription | None class CreateHsmClientCertificateMessage(ServiceRequest): HsmClientCertificateIdentifier: String - Tags: Optional[TagList] + Tags: TagList | None class HsmClientCertificate(TypedDict, total=False): - HsmClientCertificateIdentifier: Optional[String] - HsmClientCertificatePublicKey: Optional[String] - Tags: Optional[TagList] + HsmClientCertificateIdentifier: String | None + HsmClientCertificatePublicKey: String | None + Tags: TagList | None class CreateHsmClientCertificateResult(TypedDict, total=False): - HsmClientCertificate: Optional[HsmClientCertificate] + HsmClientCertificate: HsmClientCertificate | None class CreateHsmConfigurationMessage(ServiceRequest): @@ -1957,35 +1990,42 @@ class CreateHsmConfigurationMessage(ServiceRequest): HsmPartitionName: String HsmPartitionPassword: String HsmServerPublicCertificate: String - Tags: Optional[TagList] + Tags: TagList | None class HsmConfiguration(TypedDict, total=False): - HsmConfigurationIdentifier: Optional[String] - Description: Optional[String] - HsmIpAddress: Optional[String] - HsmPartitionName: Optional[String] - Tags: Optional[TagList] + HsmConfigurationIdentifier: String | None + Description: String | None + HsmIpAddress: String | None + HsmPartitionName: String | None + Tags: TagList | None class CreateHsmConfigurationResult(TypedDict, total=False): - HsmConfiguration: Optional[HsmConfiguration] + HsmConfiguration: HsmConfiguration | None -EncryptionContextMap = Dict[String, String] +EncryptionContextMap = dict[String, String] class CreateIntegrationMessage(ServiceRequest): SourceArn: SourceArn TargetArn: TargetArn IntegrationName: IntegrationName - KMSKeyId: Optional[String] - TagList: Optional[TagList] - AdditionalEncryptionContext: Optional[EncryptionContextMap] - Description: Optional[IntegrationDescription] + KMSKeyId: String | None + TagList: TagList | None + AdditionalEncryptionContext: EncryptionContextMap | None + Description: IntegrationDescription | None + +TagKeyList = list[String] -TagKeyList = List[String] + +class RedshiftScopeUnion(TypedDict, total=False): + Connect: Connect | None + + +RedshiftServiceIntegrations = list[RedshiftScopeUnion] class ReadWriteAccess(TypedDict, total=False): @@ -1993,10 +2033,10 @@ class ReadWriteAccess(TypedDict, total=False): class S3AccessGrantsScopeUnion(TypedDict, total=False): - ReadWriteAccess: Optional[ReadWriteAccess] + ReadWriteAccess: ReadWriteAccess | None -S3AccessGrantsServiceIntegrations = List[S3AccessGrantsScopeUnion] +S3AccessGrantsServiceIntegrations = list[S3AccessGrantsScopeUnion] class LakeFormationQuery(TypedDict, total=False): @@ -2004,49 +2044,52 @@ class LakeFormationQuery(TypedDict, total=False): class LakeFormationScopeUnion(TypedDict, total=False): - LakeFormationQuery: Optional[LakeFormationQuery] + LakeFormationQuery: LakeFormationQuery | None -LakeFormationServiceIntegrations = List[LakeFormationScopeUnion] +LakeFormationServiceIntegrations = list[LakeFormationScopeUnion] class ServiceIntegrationsUnion(TypedDict, total=False): - LakeFormation: Optional[LakeFormationServiceIntegrations] - S3AccessGrants: Optional[S3AccessGrantsServiceIntegrations] + LakeFormation: LakeFormationServiceIntegrations | None + S3AccessGrants: S3AccessGrantsServiceIntegrations | None + Redshift: RedshiftServiceIntegrations | None -ServiceIntegrationList = List[ServiceIntegrationsUnion] +ServiceIntegrationList = list[ServiceIntegrationsUnion] class CreateRedshiftIdcApplicationMessage(ServiceRequest): IdcInstanceArn: String RedshiftIdcApplicationName: RedshiftIdcApplicationName - IdentityNamespace: Optional[IdentityNamespaceString] + IdentityNamespace: IdentityNamespaceString | None IdcDisplayName: IdcDisplayNameString IamRoleArn: String - AuthorizedTokenIssuerList: Optional[AuthorizedTokenIssuerList] - ServiceIntegrations: Optional[ServiceIntegrationList] - Tags: Optional[TagList] - SsoTagKeys: Optional[TagKeyList] + AuthorizedTokenIssuerList: AuthorizedTokenIssuerList | None + ServiceIntegrations: ServiceIntegrationList | None + ApplicationType: ApplicationType | None + Tags: TagList | None + SsoTagKeys: TagKeyList | None class RedshiftIdcApplication(TypedDict, total=False): - IdcInstanceArn: Optional[String] - RedshiftIdcApplicationName: Optional[RedshiftIdcApplicationName] - RedshiftIdcApplicationArn: Optional[String] - IdentityNamespace: Optional[IdentityNamespaceString] - IdcDisplayName: Optional[IdcDisplayNameString] - IamRoleArn: Optional[String] - IdcManagedApplicationArn: Optional[String] - IdcOnboardStatus: Optional[String] - AuthorizedTokenIssuerList: Optional[AuthorizedTokenIssuerList] - ServiceIntegrations: Optional[ServiceIntegrationList] - Tags: Optional[TagList] - SsoTagKeys: Optional[TagKeyList] + IdcInstanceArn: String | None + RedshiftIdcApplicationName: RedshiftIdcApplicationName | None + RedshiftIdcApplicationArn: String | None + IdentityNamespace: IdentityNamespaceString | None + IdcDisplayName: IdcDisplayNameString | None + IamRoleArn: String | None + IdcManagedApplicationArn: String | None + IdcOnboardStatus: String | None + AuthorizedTokenIssuerList: AuthorizedTokenIssuerList | None + ServiceIntegrations: ServiceIntegrationList | None + ApplicationType: ApplicationType | None + Tags: TagList | None + SsoTagKeys: TagKeyList | None class CreateRedshiftIdcApplicationResult(TypedDict, total=False): - RedshiftIdcApplication: Optional[RedshiftIdcApplication] + RedshiftIdcApplication: RedshiftIdcApplication | None class ResumeClusterMessage(ServiceRequest): @@ -2059,18 +2102,18 @@ class PauseClusterMessage(ServiceRequest): class ResizeClusterMessage(ServiceRequest): ClusterIdentifier: String - ClusterType: Optional[String] - NodeType: Optional[String] - NumberOfNodes: Optional[IntegerOptional] - Classic: Optional[BooleanOptional] - ReservedNodeId: Optional[String] - TargetReservedNodeOfferingId: Optional[String] + ClusterType: String | None + NodeType: String | None + NumberOfNodes: IntegerOptional | None + Classic: BooleanOptional | None + ReservedNodeId: String | None + TargetReservedNodeOfferingId: String | None class ScheduledActionType(TypedDict, total=False): - ResizeCluster: Optional[ResizeClusterMessage] - PauseCluster: Optional[PauseClusterMessage] - ResumeCluster: Optional[ResumeClusterMessage] + ResizeCluster: ResizeClusterMessage | None + PauseCluster: PauseClusterMessage | None + ResumeCluster: ResumeClusterMessage | None class CreateScheduledActionMessage(ServiceRequest): @@ -2078,38 +2121,38 @@ class CreateScheduledActionMessage(ServiceRequest): TargetAction: ScheduledActionType Schedule: String IamRole: String - ScheduledActionDescription: Optional[String] - StartTime: Optional[TStamp] - EndTime: Optional[TStamp] - Enable: Optional[BooleanOptional] + ScheduledActionDescription: String | None + StartTime: TStamp | None + EndTime: TStamp | None + Enable: BooleanOptional | None class CreateSnapshotCopyGrantMessage(ServiceRequest): SnapshotCopyGrantName: String - KmsKeyId: Optional[String] - Tags: Optional[TagList] + KmsKeyId: String | None + Tags: TagList | None class SnapshotCopyGrant(TypedDict, total=False): - SnapshotCopyGrantName: Optional[String] - KmsKeyId: Optional[String] - Tags: Optional[TagList] + SnapshotCopyGrantName: String | None + KmsKeyId: String | None + Tags: TagList | None class CreateSnapshotCopyGrantResult(TypedDict, total=False): - SnapshotCopyGrant: Optional[SnapshotCopyGrant] + SnapshotCopyGrant: SnapshotCopyGrant | None -ScheduleDefinitionList = List[String] +ScheduleDefinitionList = list[String] class CreateSnapshotScheduleMessage(ServiceRequest): - ScheduleDefinitions: Optional[ScheduleDefinitionList] - ScheduleIdentifier: Optional[String] - ScheduleDescription: Optional[String] - Tags: Optional[TagList] - DryRun: Optional[BooleanOptional] - NextInvocations: Optional[IntegerOptional] + ScheduleDefinitions: ScheduleDefinitionList | None + ScheduleIdentifier: String | None + ScheduleDescription: String | None + Tags: TagList | None + DryRun: BooleanOptional | None + NextInvocations: IntegerOptional | None class CreateTagsMessage(ServiceRequest): @@ -2122,45 +2165,45 @@ class CreateUsageLimitMessage(ServiceRequest): FeatureType: UsageLimitFeatureType LimitType: UsageLimitLimitType Amount: Long - Period: Optional[UsageLimitPeriod] - BreachAction: Optional[UsageLimitBreachAction] - Tags: Optional[TagList] + Period: UsageLimitPeriod | None + BreachAction: UsageLimitBreachAction | None + Tags: TagList | None class CustomDomainAssociationsMessage(TypedDict, total=False): - Marker: Optional[String] - Associations: Optional[AssociationList] + Marker: String | None + Associations: AssociationList | None class CustomerStorageMessage(TypedDict, total=False): - TotalBackupSizeInMegaBytes: Optional[Double] - TotalProvisionedStorageInMegaBytes: Optional[Double] + TotalBackupSizeInMegaBytes: Double | None + TotalProvisionedStorageInMegaBytes: Double | None class DataShareAssociation(TypedDict, total=False): - ConsumerIdentifier: Optional[String] - Status: Optional[DataShareStatus] - ConsumerRegion: Optional[String] - CreatedDate: Optional[TStamp] - StatusChangeDate: Optional[TStamp] - ProducerAllowedWrites: Optional[BooleanOptional] - ConsumerAcceptedWrites: Optional[BooleanOptional] + ConsumerIdentifier: String | None + Status: DataShareStatus | None + ConsumerRegion: String | None + CreatedDate: TStamp | None + StatusChangeDate: TStamp | None + ProducerAllowedWrites: BooleanOptional | None + ConsumerAcceptedWrites: BooleanOptional | None -DataShareAssociationList = List[DataShareAssociation] +DataShareAssociationList = list[DataShareAssociation] class DataShare(TypedDict, total=False): - DataShareArn: Optional[String] - ProducerArn: Optional[String] - AllowPubliclyAccessibleConsumers: Optional[Boolean] - DataShareAssociations: Optional[DataShareAssociationList] - ManagedBy: Optional[String] - DataShareType: Optional[DataShareType] + DataShareArn: String | None + ProducerArn: String | None + AllowPubliclyAccessibleConsumers: Boolean | None + DataShareAssociations: DataShareAssociationList | None + ManagedBy: String | None + DataShareType: DataShareType | None -DataShareList = List[DataShare] -DbGroupList = List[String] +DataShareList = list[DataShare] +DbGroupList = list[String] class DeauthorizeDataShareMessage(ServiceRequest): @@ -2169,9 +2212,9 @@ class DeauthorizeDataShareMessage(ServiceRequest): class DefaultClusterParameters(TypedDict, total=False): - ParameterGroupFamily: Optional[String] - Marker: Optional[String] - Parameters: Optional[ParametersList] + ParameterGroupFamily: String | None + Marker: String | None + Parameters: ParametersList | None class DeleteAuthenticationProfileMessage(ServiceRequest): @@ -2179,14 +2222,14 @@ class DeleteAuthenticationProfileMessage(ServiceRequest): class DeleteAuthenticationProfileResult(TypedDict, total=False): - AuthenticationProfileName: Optional[AuthenticationProfileNameString] + AuthenticationProfileName: AuthenticationProfileNameString | None class DeleteClusterMessage(ServiceRequest): ClusterIdentifier: String - SkipFinalClusterSnapshot: Optional[Boolean] - FinalClusterSnapshotIdentifier: Optional[String] - FinalClusterSnapshotRetentionPeriod: Optional[IntegerOptional] + SkipFinalClusterSnapshot: Boolean | None + FinalClusterSnapshotIdentifier: String | None + FinalClusterSnapshotRetentionPeriod: IntegerOptional | None class DeleteClusterParameterGroupMessage(ServiceRequest): @@ -2194,7 +2237,7 @@ class DeleteClusterParameterGroupMessage(ServiceRequest): class DeleteClusterResult(TypedDict, total=False): - Cluster: Optional[Cluster] + Cluster: Cluster | None class DeleteClusterSecurityGroupMessage(ServiceRequest): @@ -2202,7 +2245,7 @@ class DeleteClusterSecurityGroupMessage(ServiceRequest): class DeleteClusterSnapshotResult(TypedDict, total=False): - Snapshot: Optional[Snapshot] + Snapshot: Snapshot | None class DeleteClusterSubnetGroupMessage(ServiceRequest): @@ -2273,8 +2316,8 @@ class ServerlessIdentifier(TypedDict, total=False): class NamespaceIdentifierUnion(TypedDict, total=False): - ServerlessIdentifier: Optional[ServerlessIdentifier] - ProvisionedIdentifier: Optional[ProvisionedIdentifier] + ServerlessIdentifier: ServerlessIdentifier | None + ProvisionedIdentifier: ProvisionedIdentifier | None class DeregisterNamespaceInputMessage(ServiceRequest): @@ -2283,221 +2326,221 @@ class DeregisterNamespaceInputMessage(ServiceRequest): class DeregisterNamespaceOutputMessage(TypedDict, total=False): - Status: Optional[NamespaceRegistrationStatus] + Status: NamespaceRegistrationStatus | None class DescribeAccountAttributesMessage(ServiceRequest): - AttributeNames: Optional[AttributeNameList] + AttributeNames: AttributeNameList | None class DescribeAuthenticationProfilesMessage(ServiceRequest): - AuthenticationProfileName: Optional[AuthenticationProfileNameString] + AuthenticationProfileName: AuthenticationProfileNameString | None class DescribeAuthenticationProfilesResult(TypedDict, total=False): - AuthenticationProfiles: Optional[AuthenticationProfileList] + AuthenticationProfiles: AuthenticationProfileList | None class DescribeClusterDbRevisionsMessage(ServiceRequest): - ClusterIdentifier: Optional[String] - MaxRecords: Optional[IntegerOptional] - Marker: Optional[String] + ClusterIdentifier: String | None + MaxRecords: IntegerOptional | None + Marker: String | None -TagValueList = List[String] +TagValueList = list[String] class DescribeClusterParameterGroupsMessage(ServiceRequest): - ParameterGroupName: Optional[String] - MaxRecords: Optional[IntegerOptional] - Marker: Optional[String] - TagKeys: Optional[TagKeyList] - TagValues: Optional[TagValueList] + ParameterGroupName: String | None + MaxRecords: IntegerOptional | None + Marker: String | None + TagKeys: TagKeyList | None + TagValues: TagValueList | None class DescribeClusterParametersMessage(ServiceRequest): ParameterGroupName: String - Source: Optional[String] - MaxRecords: Optional[IntegerOptional] - Marker: Optional[String] + Source: String | None + MaxRecords: IntegerOptional | None + Marker: String | None class DescribeClusterSecurityGroupsMessage(ServiceRequest): - ClusterSecurityGroupName: Optional[String] - MaxRecords: Optional[IntegerOptional] - Marker: Optional[String] - TagKeys: Optional[TagKeyList] - TagValues: Optional[TagValueList] + ClusterSecurityGroupName: String | None + MaxRecords: IntegerOptional | None + Marker: String | None + TagKeys: TagKeyList | None + TagValues: TagValueList | None class SnapshotSortingEntity(TypedDict, total=False): Attribute: SnapshotAttributeToSortBy - SortOrder: Optional[SortByOrder] + SortOrder: SortByOrder | None -SnapshotSortingEntityList = List[SnapshotSortingEntity] +SnapshotSortingEntityList = list[SnapshotSortingEntity] class DescribeClusterSnapshotsMessage(ServiceRequest): - ClusterIdentifier: Optional[String] - SnapshotIdentifier: Optional[String] - SnapshotArn: Optional[String] - SnapshotType: Optional[String] - StartTime: Optional[TStamp] - EndTime: Optional[TStamp] - MaxRecords: Optional[IntegerOptional] - Marker: Optional[String] - OwnerAccount: Optional[String] - TagKeys: Optional[TagKeyList] - TagValues: Optional[TagValueList] - ClusterExists: Optional[BooleanOptional] - SortingEntities: Optional[SnapshotSortingEntityList] + ClusterIdentifier: String | None + SnapshotIdentifier: String | None + SnapshotArn: String | None + SnapshotType: String | None + StartTime: TStamp | None + EndTime: TStamp | None + MaxRecords: IntegerOptional | None + Marker: String | None + OwnerAccount: String | None + TagKeys: TagKeyList | None + TagValues: TagValueList | None + ClusterExists: BooleanOptional | None + SortingEntities: SnapshotSortingEntityList | None class DescribeClusterSubnetGroupsMessage(ServiceRequest): - ClusterSubnetGroupName: Optional[String] - MaxRecords: Optional[IntegerOptional] - Marker: Optional[String] - TagKeys: Optional[TagKeyList] - TagValues: Optional[TagValueList] + ClusterSubnetGroupName: String | None + MaxRecords: IntegerOptional | None + Marker: String | None + TagKeys: TagKeyList | None + TagValues: TagValueList | None class DescribeClusterTracksMessage(ServiceRequest): - MaintenanceTrackName: Optional[String] - MaxRecords: Optional[IntegerOptional] - Marker: Optional[String] + MaintenanceTrackName: String | None + MaxRecords: IntegerOptional | None + Marker: String | None class DescribeClusterVersionsMessage(ServiceRequest): - ClusterVersion: Optional[String] - ClusterParameterGroupFamily: Optional[String] - MaxRecords: Optional[IntegerOptional] - Marker: Optional[String] + ClusterVersion: String | None + ClusterParameterGroupFamily: String | None + MaxRecords: IntegerOptional | None + Marker: String | None class DescribeClustersMessage(ServiceRequest): - ClusterIdentifier: Optional[String] - MaxRecords: Optional[IntegerOptional] - Marker: Optional[String] - TagKeys: Optional[TagKeyList] - TagValues: Optional[TagValueList] + ClusterIdentifier: String | None + MaxRecords: IntegerOptional | None + Marker: String | None + TagKeys: TagKeyList | None + TagValues: TagValueList | None class DescribeCustomDomainAssociationsMessage(ServiceRequest): - CustomDomainName: Optional[CustomDomainNameString] - CustomDomainCertificateArn: Optional[CustomDomainCertificateArnString] - MaxRecords: Optional[IntegerOptional] - Marker: Optional[String] + CustomDomainName: CustomDomainNameString | None + CustomDomainCertificateArn: CustomDomainCertificateArnString | None + MaxRecords: IntegerOptional | None + Marker: String | None class DescribeDataSharesForConsumerMessage(ServiceRequest): - ConsumerArn: Optional[String] - Status: Optional[DataShareStatusForConsumer] - MaxRecords: Optional[IntegerOptional] - Marker: Optional[String] + ConsumerArn: String | None + Status: DataShareStatusForConsumer | None + MaxRecords: IntegerOptional | None + Marker: String | None class DescribeDataSharesForConsumerResult(TypedDict, total=False): - DataShares: Optional[DataShareList] - Marker: Optional[String] + DataShares: DataShareList | None + Marker: String | None class DescribeDataSharesForProducerMessage(ServiceRequest): - ProducerArn: Optional[String] - Status: Optional[DataShareStatusForProducer] - MaxRecords: Optional[IntegerOptional] - Marker: Optional[String] + ProducerArn: String | None + Status: DataShareStatusForProducer | None + MaxRecords: IntegerOptional | None + Marker: String | None class DescribeDataSharesForProducerResult(TypedDict, total=False): - DataShares: Optional[DataShareList] - Marker: Optional[String] + DataShares: DataShareList | None + Marker: String | None class DescribeDataSharesMessage(ServiceRequest): - DataShareArn: Optional[String] - MaxRecords: Optional[IntegerOptional] - Marker: Optional[String] + DataShareArn: String | None + MaxRecords: IntegerOptional | None + Marker: String | None class DescribeDataSharesResult(TypedDict, total=False): - DataShares: Optional[DataShareList] - Marker: Optional[String] + DataShares: DataShareList | None + Marker: String | None class DescribeDefaultClusterParametersMessage(ServiceRequest): ParameterGroupFamily: String - MaxRecords: Optional[IntegerOptional] - Marker: Optional[String] + MaxRecords: IntegerOptional | None + Marker: String | None class DescribeDefaultClusterParametersResult(TypedDict, total=False): - DefaultClusterParameters: Optional[DefaultClusterParameters] + DefaultClusterParameters: DefaultClusterParameters | None class DescribeEndpointAccessMessage(ServiceRequest): - ClusterIdentifier: Optional[String] - ResourceOwner: Optional[String] - EndpointName: Optional[String] - VpcId: Optional[String] - MaxRecords: Optional[IntegerOptional] - Marker: Optional[String] + ClusterIdentifier: String | None + ResourceOwner: String | None + EndpointName: String | None + VpcId: String | None + MaxRecords: IntegerOptional | None + Marker: String | None class DescribeEndpointAuthorizationMessage(ServiceRequest): - ClusterIdentifier: Optional[String] - Account: Optional[String] - Grantee: Optional[BooleanOptional] - MaxRecords: Optional[IntegerOptional] - Marker: Optional[String] + ClusterIdentifier: String | None + Account: String | None + Grantee: BooleanOptional | None + MaxRecords: IntegerOptional | None + Marker: String | None class DescribeEventCategoriesMessage(ServiceRequest): - SourceType: Optional[String] + SourceType: String | None class DescribeEventSubscriptionsMessage(ServiceRequest): - SubscriptionName: Optional[String] - MaxRecords: Optional[IntegerOptional] - Marker: Optional[String] - TagKeys: Optional[TagKeyList] - TagValues: Optional[TagValueList] + SubscriptionName: String | None + MaxRecords: IntegerOptional | None + Marker: String | None + TagKeys: TagKeyList | None + TagValues: TagValueList | None class DescribeEventsMessage(ServiceRequest): - SourceIdentifier: Optional[String] - SourceType: Optional[SourceType] - StartTime: Optional[TStamp] - EndTime: Optional[TStamp] - Duration: Optional[IntegerOptional] - MaxRecords: Optional[IntegerOptional] - Marker: Optional[String] + SourceIdentifier: String | None + SourceType: SourceType | None + StartTime: TStamp | None + EndTime: TStamp | None + Duration: IntegerOptional | None + MaxRecords: IntegerOptional | None + Marker: String | None class DescribeHsmClientCertificatesMessage(ServiceRequest): - HsmClientCertificateIdentifier: Optional[String] - MaxRecords: Optional[IntegerOptional] - Marker: Optional[String] - TagKeys: Optional[TagKeyList] - TagValues: Optional[TagValueList] + HsmClientCertificateIdentifier: String | None + MaxRecords: IntegerOptional | None + Marker: String | None + TagKeys: TagKeyList | None + TagValues: TagValueList | None class DescribeHsmConfigurationsMessage(ServiceRequest): - HsmConfigurationIdentifier: Optional[String] - MaxRecords: Optional[IntegerOptional] - Marker: Optional[String] - TagKeys: Optional[TagKeyList] - TagValues: Optional[TagValueList] + HsmConfigurationIdentifier: String | None + MaxRecords: IntegerOptional | None + Marker: String | None + TagKeys: TagKeyList | None + TagValues: TagValueList | None class DescribeInboundIntegrationsMessage(ServiceRequest): - IntegrationArn: Optional[InboundIntegrationArn] - TargetArn: Optional[TargetArn] - MaxRecords: Optional[IntegerOptional] - Marker: Optional[String] + IntegrationArn: InboundIntegrationArn | None + TargetArn: TargetArn | None + MaxRecords: IntegerOptional | None + Marker: String | None -DescribeIntegrationsFilterValueList = List[String] +DescribeIntegrationsFilterValueList = list[String] class DescribeIntegrationsFilter(TypedDict, total=False): @@ -2505,14 +2548,14 @@ class DescribeIntegrationsFilter(TypedDict, total=False): Values: DescribeIntegrationsFilterValueList -DescribeIntegrationsFilterList = List[DescribeIntegrationsFilter] +DescribeIntegrationsFilterList = list[DescribeIntegrationsFilter] class DescribeIntegrationsMessage(ServiceRequest): - IntegrationArn: Optional[IntegrationArn] - MaxRecords: Optional[IntegerOptional] - Marker: Optional[String] - Filters: Optional[DescribeIntegrationsFilterList] + IntegrationArn: IntegrationArn | None + MaxRecords: IntegerOptional | None + Marker: String | None + Filters: DescribeIntegrationsFilterList | None class DescribeLoggingStatusMessage(ServiceRequest): @@ -2520,94 +2563,94 @@ class DescribeLoggingStatusMessage(ServiceRequest): class NodeConfigurationOptionsFilter(TypedDict, total=False): - Name: Optional[NodeConfigurationOptionsFilterName] - Operator: Optional[OperatorType] - Values: Optional[ValueStringList] + Name: NodeConfigurationOptionsFilterName | None + Operator: OperatorType | None + Values: ValueStringList | None -NodeConfigurationOptionsFilterList = List[NodeConfigurationOptionsFilter] +NodeConfigurationOptionsFilterList = list[NodeConfigurationOptionsFilter] class DescribeNodeConfigurationOptionsMessage(ServiceRequest): ActionType: ActionType - ClusterIdentifier: Optional[String] - SnapshotIdentifier: Optional[String] - SnapshotArn: Optional[String] - OwnerAccount: Optional[String] - Filters: Optional[NodeConfigurationOptionsFilterList] - Marker: Optional[String] - MaxRecords: Optional[IntegerOptional] + ClusterIdentifier: String | None + SnapshotIdentifier: String | None + SnapshotArn: String | None + OwnerAccount: String | None + Filters: NodeConfigurationOptionsFilterList | None + Marker: String | None + MaxRecords: IntegerOptional | None class DescribeOrderableClusterOptionsMessage(ServiceRequest): - ClusterVersion: Optional[String] - NodeType: Optional[String] - MaxRecords: Optional[IntegerOptional] - Marker: Optional[String] + ClusterVersion: String | None + NodeType: String | None + MaxRecords: IntegerOptional | None + Marker: String | None class DescribePartnersInputMessage(ServiceRequest): AccountId: PartnerIntegrationAccountId ClusterIdentifier: PartnerIntegrationClusterIdentifier - DatabaseName: Optional[PartnerIntegrationDatabaseName] - PartnerName: Optional[PartnerIntegrationPartnerName] + DatabaseName: PartnerIntegrationDatabaseName | None + PartnerName: PartnerIntegrationPartnerName | None class PartnerIntegrationInfo(TypedDict, total=False): - DatabaseName: Optional[PartnerIntegrationDatabaseName] - PartnerName: Optional[PartnerIntegrationPartnerName] - Status: Optional[PartnerIntegrationStatus] - StatusMessage: Optional[PartnerIntegrationStatusMessage] - CreatedAt: Optional[TStamp] - UpdatedAt: Optional[TStamp] + DatabaseName: PartnerIntegrationDatabaseName | None + PartnerName: PartnerIntegrationPartnerName | None + Status: PartnerIntegrationStatus | None + StatusMessage: PartnerIntegrationStatusMessage | None + CreatedAt: TStamp | None + UpdatedAt: TStamp | None -PartnerIntegrationInfoList = List[PartnerIntegrationInfo] +PartnerIntegrationInfoList = list[PartnerIntegrationInfo] class DescribePartnersOutputMessage(TypedDict, total=False): - PartnerIntegrationInfoList: Optional[PartnerIntegrationInfoList] + PartnerIntegrationInfoList: PartnerIntegrationInfoList | None class DescribeRedshiftIdcApplicationsMessage(ServiceRequest): - RedshiftIdcApplicationArn: Optional[String] - MaxRecords: Optional[IntegerOptional] - Marker: Optional[String] + RedshiftIdcApplicationArn: String | None + MaxRecords: IntegerOptional | None + Marker: String | None -RedshiftIdcApplicationList = List[RedshiftIdcApplication] +RedshiftIdcApplicationList = list[RedshiftIdcApplication] class DescribeRedshiftIdcApplicationsResult(TypedDict, total=False): - RedshiftIdcApplications: Optional[RedshiftIdcApplicationList] - Marker: Optional[String] + RedshiftIdcApplications: RedshiftIdcApplicationList | None + Marker: String | None class DescribeReservedNodeExchangeStatusInputMessage(ServiceRequest): - ReservedNodeId: Optional[String] - ReservedNodeExchangeRequestId: Optional[String] - MaxRecords: Optional[IntegerOptional] - Marker: Optional[String] + ReservedNodeId: String | None + ReservedNodeExchangeRequestId: String | None + MaxRecords: IntegerOptional | None + Marker: String | None -ReservedNodeExchangeStatusList = List[ReservedNodeExchangeStatus] +ReservedNodeExchangeStatusList = list[ReservedNodeExchangeStatus] class DescribeReservedNodeExchangeStatusOutputMessage(TypedDict, total=False): - ReservedNodeExchangeStatusDetails: Optional[ReservedNodeExchangeStatusList] - Marker: Optional[String] + ReservedNodeExchangeStatusDetails: ReservedNodeExchangeStatusList | None + Marker: String | None class DescribeReservedNodeOfferingsMessage(ServiceRequest): - ReservedNodeOfferingId: Optional[String] - MaxRecords: Optional[IntegerOptional] - Marker: Optional[String] + ReservedNodeOfferingId: String | None + MaxRecords: IntegerOptional | None + Marker: String | None class DescribeReservedNodesMessage(ServiceRequest): - ReservedNodeId: Optional[String] - MaxRecords: Optional[IntegerOptional] - Marker: Optional[String] + ReservedNodeId: String | None + MaxRecords: IntegerOptional | None + Marker: String | None class DescribeResizeMessage(ServiceRequest): @@ -2619,82 +2662,82 @@ class ScheduledActionFilter(TypedDict, total=False): Values: ValueStringList -ScheduledActionFilterList = List[ScheduledActionFilter] +ScheduledActionFilterList = list[ScheduledActionFilter] class DescribeScheduledActionsMessage(ServiceRequest): - ScheduledActionName: Optional[String] - TargetActionType: Optional[ScheduledActionTypeValues] - StartTime: Optional[TStamp] - EndTime: Optional[TStamp] - Active: Optional[BooleanOptional] - Filters: Optional[ScheduledActionFilterList] - Marker: Optional[String] - MaxRecords: Optional[IntegerOptional] + ScheduledActionName: String | None + TargetActionType: ScheduledActionTypeValues | None + StartTime: TStamp | None + EndTime: TStamp | None + Active: BooleanOptional | None + Filters: ScheduledActionFilterList | None + Marker: String | None + MaxRecords: IntegerOptional | None class DescribeSnapshotCopyGrantsMessage(ServiceRequest): - SnapshotCopyGrantName: Optional[String] - MaxRecords: Optional[IntegerOptional] - Marker: Optional[String] - TagKeys: Optional[TagKeyList] - TagValues: Optional[TagValueList] + SnapshotCopyGrantName: String | None + MaxRecords: IntegerOptional | None + Marker: String | None + TagKeys: TagKeyList | None + TagValues: TagValueList | None class DescribeSnapshotSchedulesMessage(ServiceRequest): - ClusterIdentifier: Optional[String] - ScheduleIdentifier: Optional[String] - TagKeys: Optional[TagKeyList] - TagValues: Optional[TagValueList] - Marker: Optional[String] - MaxRecords: Optional[IntegerOptional] + ClusterIdentifier: String | None + ScheduleIdentifier: String | None + TagKeys: TagKeyList | None + TagValues: TagValueList | None + Marker: String | None + MaxRecords: IntegerOptional | None -ScheduledSnapshotTimeList = List[TStamp] +ScheduledSnapshotTimeList = list[TStamp] class SnapshotSchedule(TypedDict, total=False): - ScheduleDefinitions: Optional[ScheduleDefinitionList] - ScheduleIdentifier: Optional[String] - ScheduleDescription: Optional[String] - Tags: Optional[TagList] - NextInvocations: Optional[ScheduledSnapshotTimeList] - AssociatedClusterCount: Optional[IntegerOptional] - AssociatedClusters: Optional[AssociatedClusterList] + ScheduleDefinitions: ScheduleDefinitionList | None + ScheduleIdentifier: String | None + ScheduleDescription: String | None + Tags: TagList | None + NextInvocations: ScheduledSnapshotTimeList | None + AssociatedClusterCount: IntegerOptional | None + AssociatedClusters: AssociatedClusterList | None -SnapshotScheduleList = List[SnapshotSchedule] +SnapshotScheduleList = list[SnapshotSchedule] class DescribeSnapshotSchedulesOutputMessage(TypedDict, total=False): - SnapshotSchedules: Optional[SnapshotScheduleList] - Marker: Optional[String] + SnapshotSchedules: SnapshotScheduleList | None + Marker: String | None class DescribeTableRestoreStatusMessage(ServiceRequest): - ClusterIdentifier: Optional[String] - TableRestoreRequestId: Optional[String] - MaxRecords: Optional[IntegerOptional] - Marker: Optional[String] + ClusterIdentifier: String | None + TableRestoreRequestId: String | None + MaxRecords: IntegerOptional | None + Marker: String | None class DescribeTagsMessage(ServiceRequest): - ResourceName: Optional[String] - ResourceType: Optional[String] - MaxRecords: Optional[IntegerOptional] - Marker: Optional[String] - TagKeys: Optional[TagKeyList] - TagValues: Optional[TagValueList] + ResourceName: String | None + ResourceType: String | None + MaxRecords: IntegerOptional | None + Marker: String | None + TagKeys: TagKeyList | None + TagValues: TagValueList | None class DescribeUsageLimitsMessage(ServiceRequest): - UsageLimitId: Optional[String] - ClusterIdentifier: Optional[String] - FeatureType: Optional[UsageLimitFeatureType] - MaxRecords: Optional[IntegerOptional] - Marker: Optional[String] - TagKeys: Optional[TagKeyList] - TagValues: Optional[TagValueList] + UsageLimitId: String | None + ClusterIdentifier: String | None + FeatureType: UsageLimitFeatureType | None + MaxRecords: IntegerOptional | None + Marker: String | None + TagKeys: TagKeyList | None + TagValues: TagValueList | None class DisableLoggingMessage(ServiceRequest): @@ -2706,138 +2749,138 @@ class DisableSnapshotCopyMessage(ServiceRequest): class DisableSnapshotCopyResult(TypedDict, total=False): - Cluster: Optional[Cluster] + Cluster: Cluster | None class DisassociateDataShareConsumerMessage(ServiceRequest): DataShareArn: String - DisassociateEntireAccount: Optional[BooleanOptional] - ConsumerArn: Optional[String] - ConsumerRegion: Optional[String] + DisassociateEntireAccount: BooleanOptional | None + ConsumerArn: String | None + ConsumerRegion: String | None class SupportedOperation(TypedDict, total=False): - OperationName: Optional[String] + OperationName: String | None -SupportedOperationList = List[SupportedOperation] +SupportedOperationList = list[SupportedOperation] class UpdateTarget(TypedDict, total=False): - MaintenanceTrackName: Optional[String] - DatabaseVersion: Optional[String] - SupportedOperations: Optional[SupportedOperationList] + MaintenanceTrackName: String | None + DatabaseVersion: String | None + SupportedOperations: SupportedOperationList | None -EligibleTracksToUpdateList = List[UpdateTarget] -LogTypeList = List[String] +EligibleTracksToUpdateList = list[UpdateTarget] +LogTypeList = list[String] class EnableLoggingMessage(ServiceRequest): ClusterIdentifier: String - BucketName: Optional[String] - S3KeyPrefix: Optional[S3KeyPrefixValue] - LogDestinationType: Optional[LogDestinationType] - LogExports: Optional[LogTypeList] + BucketName: String | None + S3KeyPrefix: S3KeyPrefixValue | None + LogDestinationType: LogDestinationType | None + LogExports: LogTypeList | None class EnableSnapshotCopyMessage(ServiceRequest): ClusterIdentifier: String DestinationRegion: String - RetentionPeriod: Optional[IntegerOptional] - SnapshotCopyGrantName: Optional[String] - ManualSnapshotRetentionPeriod: Optional[IntegerOptional] + RetentionPeriod: IntegerOptional | None + SnapshotCopyGrantName: String | None + ManualSnapshotRetentionPeriod: IntegerOptional | None class EnableSnapshotCopyResult(TypedDict, total=False): - Cluster: Optional[Cluster] + Cluster: Cluster | None class EndpointAccess(TypedDict, total=False): - ClusterIdentifier: Optional[String] - ResourceOwner: Optional[String] - SubnetGroupName: Optional[String] - EndpointStatus: Optional[String] - EndpointName: Optional[String] - EndpointCreateTime: Optional[TStamp] - Port: Optional[Integer] - Address: Optional[String] - VpcSecurityGroups: Optional[VpcSecurityGroupMembershipList] - VpcEndpoint: Optional[VpcEndpoint] + ClusterIdentifier: String | None + ResourceOwner: String | None + SubnetGroupName: String | None + EndpointStatus: String | None + EndpointName: String | None + EndpointCreateTime: TStamp | None + Port: Integer | None + Address: String | None + VpcSecurityGroups: VpcSecurityGroupMembershipList | None + VpcEndpoint: VpcEndpoint | None -EndpointAccesses = List[EndpointAccess] +EndpointAccesses = list[EndpointAccess] class EndpointAccessList(TypedDict, total=False): - EndpointAccessList: Optional[EndpointAccesses] - Marker: Optional[String] + EndpointAccessList: EndpointAccesses | None + Marker: String | None class EndpointAuthorization(TypedDict, total=False): - Grantor: Optional[String] - Grantee: Optional[String] - ClusterIdentifier: Optional[String] - AuthorizeTime: Optional[TStamp] - ClusterStatus: Optional[String] - Status: Optional[AuthorizationStatus] - AllowedAllVPCs: Optional[Boolean] - AllowedVPCs: Optional[VpcIdentifierList] - EndpointCount: Optional[Integer] + Grantor: String | None + Grantee: String | None + ClusterIdentifier: String | None + AuthorizeTime: TStamp | None + ClusterStatus: String | None + Status: AuthorizationStatus | None + AllowedAllVPCs: Boolean | None + AllowedVPCs: VpcIdentifierList | None + EndpointCount: Integer | None -EndpointAuthorizations = List[EndpointAuthorization] +EndpointAuthorizations = list[EndpointAuthorization] class EndpointAuthorizationList(TypedDict, total=False): - EndpointAuthorizationList: Optional[EndpointAuthorizations] - Marker: Optional[String] + EndpointAuthorizationList: EndpointAuthorizations | None + Marker: String | None class Event(TypedDict, total=False): - SourceIdentifier: Optional[String] - SourceType: Optional[SourceType] - Message: Optional[String] - EventCategories: Optional[EventCategoriesList] - Severity: Optional[String] - Date: Optional[TStamp] - EventId: Optional[String] + SourceIdentifier: String | None + SourceType: SourceType | None + Message: String | None + EventCategories: EventCategoriesList | None + Severity: String | None + Date: TStamp | None + EventId: String | None class EventInfoMap(TypedDict, total=False): - EventId: Optional[String] - EventCategories: Optional[EventCategoriesList] - EventDescription: Optional[String] - Severity: Optional[String] + EventId: String | None + EventCategories: EventCategoriesList | None + EventDescription: String | None + Severity: String | None -EventInfoMapList = List[EventInfoMap] +EventInfoMapList = list[EventInfoMap] class EventCategoriesMap(TypedDict, total=False): - SourceType: Optional[String] - Events: Optional[EventInfoMapList] + SourceType: String | None + Events: EventInfoMapList | None -EventCategoriesMapList = List[EventCategoriesMap] +EventCategoriesMapList = list[EventCategoriesMap] class EventCategoriesMessage(TypedDict, total=False): - EventCategoriesMapList: Optional[EventCategoriesMapList] + EventCategoriesMapList: EventCategoriesMapList | None -EventList = List[Event] -EventSubscriptionsList = List[EventSubscription] +EventList = list[Event] +EventSubscriptionsList = list[EventSubscription] class EventSubscriptionsMessage(TypedDict, total=False): - Marker: Optional[String] - EventSubscriptionsList: Optional[EventSubscriptionsList] + Marker: String | None + EventSubscriptionsList: EventSubscriptionsList | None class EventsMessage(TypedDict, total=False): - Marker: Optional[String] - Events: Optional[EventList] + Marker: String | None + Events: EventList | None class FailoverPrimaryComputeInputMessage(ServiceRequest): @@ -2845,72 +2888,81 @@ class FailoverPrimaryComputeInputMessage(ServiceRequest): class FailoverPrimaryComputeResult(TypedDict, total=False): - Cluster: Optional[Cluster] + Cluster: Cluster | None class GetClusterCredentialsMessage(ServiceRequest): DbUser: String - DbName: Optional[String] - ClusterIdentifier: Optional[String] - DurationSeconds: Optional[IntegerOptional] - AutoCreate: Optional[BooleanOptional] - DbGroups: Optional[DbGroupList] - CustomDomainName: Optional[String] + DbName: String | None + ClusterIdentifier: String | None + DurationSeconds: IntegerOptional | None + AutoCreate: BooleanOptional | None + DbGroups: DbGroupList | None + CustomDomainName: String | None class GetClusterCredentialsWithIAMMessage(ServiceRequest): - DbName: Optional[String] - ClusterIdentifier: Optional[String] - DurationSeconds: Optional[IntegerOptional] - CustomDomainName: Optional[String] + DbName: String | None + ClusterIdentifier: String | None + DurationSeconds: IntegerOptional | None + CustomDomainName: String | None + + +class GetIdentityCenterAuthTokenRequest(ServiceRequest): + ClusterIds: ClusterIdentifierList + + +class GetIdentityCenterAuthTokenResponse(TypedDict, total=False): + Token: SensitiveString | None + ExpirationTime: TStamp | None class GetReservedNodeExchangeConfigurationOptionsInputMessage(ServiceRequest): ActionType: ReservedNodeExchangeActionType - ClusterIdentifier: Optional[String] - SnapshotIdentifier: Optional[String] - MaxRecords: Optional[IntegerOptional] - Marker: Optional[String] + ClusterIdentifier: String | None + SnapshotIdentifier: String | None + MaxRecords: IntegerOptional | None + Marker: String | None class ReservedNodeOffering(TypedDict, total=False): - ReservedNodeOfferingId: Optional[String] - NodeType: Optional[String] - Duration: Optional[Integer] - FixedPrice: Optional[Double] - UsagePrice: Optional[Double] - CurrencyCode: Optional[String] - OfferingType: Optional[String] - RecurringCharges: Optional[RecurringChargeList] - ReservedNodeOfferingType: Optional[ReservedNodeOfferingType] + ReservedNodeOfferingId: String | None + NodeType: String | None + Duration: Integer | None + FixedPrice: Double | None + UsagePrice: Double | None + CurrencyCode: String | None + OfferingType: String | None + RecurringCharges: RecurringChargeList | None + ReservedNodeOfferingType: ReservedNodeOfferingType | None class ReservedNodeConfigurationOption(TypedDict, total=False): - SourceReservedNode: Optional[ReservedNode] - TargetReservedNodeCount: Optional[Integer] - TargetReservedNodeOffering: Optional[ReservedNodeOffering] + SourceReservedNode: ReservedNode | None + TargetReservedNodeCount: Integer | None + TargetReservedNodeOffering: ReservedNodeOffering | None -ReservedNodeConfigurationOptionList = List[ReservedNodeConfigurationOption] +ReservedNodeConfigurationOptionList = list[ReservedNodeConfigurationOption] class GetReservedNodeExchangeConfigurationOptionsOutputMessage(TypedDict, total=False): - Marker: Optional[String] - ReservedNodeConfigurationOptionList: Optional[ReservedNodeConfigurationOptionList] + Marker: String | None + ReservedNodeConfigurationOptionList: ReservedNodeConfigurationOptionList | None class GetReservedNodeExchangeOfferingsInputMessage(ServiceRequest): ReservedNodeId: String - MaxRecords: Optional[IntegerOptional] - Marker: Optional[String] + MaxRecords: IntegerOptional | None + Marker: String | None -ReservedNodeOfferingList = List[ReservedNodeOffering] +ReservedNodeOfferingList = list[ReservedNodeOffering] class GetReservedNodeExchangeOfferingsOutputMessage(TypedDict, total=False): - Marker: Optional[String] - ReservedNodeOfferings: Optional[ReservedNodeOfferingList] + Marker: String | None + ReservedNodeOfferings: ReservedNodeOfferingList | None class GetResourcePolicyMessage(ServiceRequest): @@ -2918,154 +2970,161 @@ class GetResourcePolicyMessage(ServiceRequest): class ResourcePolicy(TypedDict, total=False): - ResourceArn: Optional[String] - Policy: Optional[String] + ResourceArn: String | None + Policy: String | None class GetResourcePolicyResult(TypedDict, total=False): - ResourcePolicy: Optional[ResourcePolicy] + ResourcePolicy: ResourcePolicy | None -HsmClientCertificateList = List[HsmClientCertificate] +HsmClientCertificateList = list[HsmClientCertificate] class HsmClientCertificateMessage(TypedDict, total=False): - Marker: Optional[String] - HsmClientCertificates: Optional[HsmClientCertificateList] + Marker: String | None + HsmClientCertificates: HsmClientCertificateList | None -HsmConfigurationList = List[HsmConfiguration] +HsmConfigurationList = list[HsmConfiguration] class HsmConfigurationMessage(TypedDict, total=False): - Marker: Optional[String] - HsmConfigurations: Optional[HsmConfigurationList] + Marker: String | None + HsmConfigurations: HsmConfigurationList | None -ImportTablesCompleted = List[String] -ImportTablesInProgress = List[String] -ImportTablesNotStarted = List[String] +ImportTablesCompleted = list[String] +ImportTablesInProgress = list[String] +ImportTablesNotStarted = list[String] class IntegrationError(TypedDict, total=False): ErrorCode: String - ErrorMessage: Optional[String] + ErrorMessage: String | None -IntegrationErrorList = List[IntegrationError] +IntegrationErrorList = list[IntegrationError] class InboundIntegration(TypedDict, total=False): - IntegrationArn: Optional[InboundIntegrationArn] - SourceArn: Optional[String] - TargetArn: Optional[TargetArn] - Status: Optional[ZeroETLIntegrationStatus] - Errors: Optional[IntegrationErrorList] - CreateTime: Optional[TStamp] + IntegrationArn: InboundIntegrationArn | None + SourceArn: String | None + TargetArn: TargetArn | None + Status: ZeroETLIntegrationStatus | None + Errors: IntegrationErrorList | None + CreateTime: TStamp | None -InboundIntegrationList = List[InboundIntegration] +InboundIntegrationList = list[InboundIntegration] class InboundIntegrationsMessage(TypedDict, total=False): - Marker: Optional[String] - InboundIntegrations: Optional[InboundIntegrationList] + Marker: String | None + InboundIntegrations: InboundIntegrationList | None class Integration(TypedDict, total=False): - IntegrationArn: Optional[IntegrationArn] - IntegrationName: Optional[IntegrationName] - SourceArn: Optional[SourceArn] - TargetArn: Optional[TargetArn] - Status: Optional[ZeroETLIntegrationStatus] - Errors: Optional[IntegrationErrorList] - CreateTime: Optional[TStamp] - Description: Optional[Description] - KMSKeyId: Optional[String] - AdditionalEncryptionContext: Optional[EncryptionContextMap] - Tags: Optional[TagList] + IntegrationArn: IntegrationArn | None + IntegrationName: IntegrationName | None + SourceArn: SourceArn | None + TargetArn: TargetArn | None + Status: ZeroETLIntegrationStatus | None + Errors: IntegrationErrorList | None + CreateTime: TStamp | None + Description: Description | None + KMSKeyId: String | None + AdditionalEncryptionContext: EncryptionContextMap | None + Tags: TagList | None -IntegrationList = List[Integration] +IntegrationList = list[Integration] class IntegrationsMessage(TypedDict, total=False): - Marker: Optional[String] - Integrations: Optional[IntegrationList] + Marker: String | None + Integrations: IntegrationList | None + + +class LakehouseConfiguration(TypedDict, total=False): + ClusterIdentifier: String | None + LakehouseIdcApplicationArn: String | None + LakehouseRegistrationStatus: String | None + CatalogArn: String | None class ListRecommendationsMessage(ServiceRequest): - ClusterIdentifier: Optional[String] - NamespaceArn: Optional[String] - MaxRecords: Optional[IntegerOptional] - Marker: Optional[String] + ClusterIdentifier: String | None + NamespaceArn: String | None + MaxRecords: IntegerOptional | None + Marker: String | None class ReferenceLink(TypedDict, total=False): - Text: Optional[String] - Link: Optional[String] + Text: String | None + Link: String | None -ReferenceLinkList = List[ReferenceLink] +ReferenceLinkList = list[ReferenceLink] class RecommendedAction(TypedDict, total=False): - Text: Optional[String] - Database: Optional[String] - Command: Optional[String] - Type: Optional[RecommendedActionType] + Text: String | None + Database: String | None + Command: String | None + Type: RecommendedActionType | None -RecommendedActionList = List[RecommendedAction] +RecommendedActionList = list[RecommendedAction] class Recommendation(TypedDict, total=False): - Id: Optional[String] - ClusterIdentifier: Optional[String] - NamespaceArn: Optional[String] - CreatedAt: Optional[TStamp] - RecommendationType: Optional[String] - Title: Optional[String] - Description: Optional[String] - Observation: Optional[String] - ImpactRanking: Optional[ImpactRankingType] - RecommendationText: Optional[String] - RecommendedActions: Optional[RecommendedActionList] - ReferenceLinks: Optional[ReferenceLinkList] + Id: String | None + ClusterIdentifier: String | None + NamespaceArn: String | None + CreatedAt: TStamp | None + RecommendationType: String | None + Title: String | None + Description: String | None + Observation: String | None + ImpactRanking: ImpactRankingType | None + RecommendationText: String | None + RecommendedActions: RecommendedActionList | None + ReferenceLinks: ReferenceLinkList | None -RecommendationList = List[Recommendation] +RecommendationList = list[Recommendation] class ListRecommendationsResult(TypedDict, total=False): - Recommendations: Optional[RecommendationList] - Marker: Optional[String] + Recommendations: RecommendationList | None + Marker: String | None class LoggingStatus(TypedDict, total=False): - LoggingEnabled: Optional[Boolean] - BucketName: Optional[String] - S3KeyPrefix: Optional[S3KeyPrefixValue] - LastSuccessfulDeliveryTime: Optional[TStamp] - LastFailureTime: Optional[TStamp] - LastFailureMessage: Optional[String] - LogDestinationType: Optional[LogDestinationType] - LogExports: Optional[LogTypeList] + LoggingEnabled: Boolean | None + BucketName: String | None + S3KeyPrefix: S3KeyPrefixValue | None + LastSuccessfulDeliveryTime: TStamp | None + LastFailureTime: TStamp | None + LastFailureMessage: String | None + LogDestinationType: LogDestinationType | None + LogExports: LogTypeList | None class MaintenanceTrack(TypedDict, total=False): - MaintenanceTrackName: Optional[String] - DatabaseVersion: Optional[String] - UpdateTargets: Optional[EligibleTracksToUpdateList] + MaintenanceTrackName: String | None + DatabaseVersion: String | None + UpdateTargets: EligibleTracksToUpdateList | None class ModifyAquaInputMessage(ServiceRequest): ClusterIdentifier: String - AquaConfigurationStatus: Optional[AquaConfigurationStatus] + AquaConfigurationStatus: AquaConfigurationStatus | None class ModifyAquaOutputMessage(TypedDict, total=False): - AquaConfiguration: Optional[AquaConfiguration] + AquaConfiguration: AquaConfiguration | None class ModifyAuthenticationProfileMessage(ServiceRequest): @@ -3074,8 +3133,8 @@ class ModifyAuthenticationProfileMessage(ServiceRequest): class ModifyAuthenticationProfileResult(TypedDict, total=False): - AuthenticationProfileName: Optional[AuthenticationProfileNameString] - AuthenticationProfileContent: Optional[String] + AuthenticationProfileName: AuthenticationProfileNameString | None + AuthenticationProfileContent: String | None class ModifyClusterDbRevisionMessage(ServiceRequest): @@ -3084,63 +3143,64 @@ class ModifyClusterDbRevisionMessage(ServiceRequest): class ModifyClusterDbRevisionResult(TypedDict, total=False): - Cluster: Optional[Cluster] + Cluster: Cluster | None class ModifyClusterIamRolesMessage(ServiceRequest): ClusterIdentifier: String - AddIamRoles: Optional[IamRoleArnList] - RemoveIamRoles: Optional[IamRoleArnList] - DefaultIamRoleArn: Optional[String] + AddIamRoles: IamRoleArnList | None + RemoveIamRoles: IamRoleArnList | None + DefaultIamRoleArn: String | None class ModifyClusterIamRolesResult(TypedDict, total=False): - Cluster: Optional[Cluster] + Cluster: Cluster | None class ModifyClusterMaintenanceMessage(ServiceRequest): ClusterIdentifier: String - DeferMaintenance: Optional[BooleanOptional] - DeferMaintenanceIdentifier: Optional[String] - DeferMaintenanceStartTime: Optional[TStamp] - DeferMaintenanceEndTime: Optional[TStamp] - DeferMaintenanceDuration: Optional[IntegerOptional] + DeferMaintenance: BooleanOptional | None + DeferMaintenanceIdentifier: String | None + DeferMaintenanceStartTime: TStamp | None + DeferMaintenanceEndTime: TStamp | None + DeferMaintenanceDuration: IntegerOptional | None class ModifyClusterMaintenanceResult(TypedDict, total=False): - Cluster: Optional[Cluster] + Cluster: Cluster | None class ModifyClusterMessage(ServiceRequest): ClusterIdentifier: String - ClusterType: Optional[String] - NodeType: Optional[String] - NumberOfNodes: Optional[IntegerOptional] - ClusterSecurityGroups: Optional[ClusterSecurityGroupNameList] - VpcSecurityGroupIds: Optional[VpcSecurityGroupIdList] - MasterUserPassword: Optional[SensitiveString] - ClusterParameterGroupName: Optional[String] - AutomatedSnapshotRetentionPeriod: Optional[IntegerOptional] - ManualSnapshotRetentionPeriod: Optional[IntegerOptional] - PreferredMaintenanceWindow: Optional[String] - ClusterVersion: Optional[String] - AllowVersionUpgrade: Optional[BooleanOptional] - HsmClientCertificateIdentifier: Optional[String] - HsmConfigurationIdentifier: Optional[String] - NewClusterIdentifier: Optional[String] - PubliclyAccessible: Optional[BooleanOptional] - ElasticIp: Optional[String] - EnhancedVpcRouting: Optional[BooleanOptional] - MaintenanceTrackName: Optional[String] - Encrypted: Optional[BooleanOptional] - KmsKeyId: Optional[String] - AvailabilityZoneRelocation: Optional[BooleanOptional] - AvailabilityZone: Optional[String] - Port: Optional[IntegerOptional] - ManageMasterPassword: Optional[BooleanOptional] - MasterPasswordSecretKmsKeyId: Optional[String] - IpAddressType: Optional[String] - MultiAZ: Optional[BooleanOptional] + ClusterType: String | None + NodeType: String | None + NumberOfNodes: IntegerOptional | None + ClusterSecurityGroups: ClusterSecurityGroupNameList | None + VpcSecurityGroupIds: VpcSecurityGroupIdList | None + MasterUserPassword: SensitiveString | None + ClusterParameterGroupName: String | None + AutomatedSnapshotRetentionPeriod: IntegerOptional | None + ManualSnapshotRetentionPeriod: IntegerOptional | None + PreferredMaintenanceWindow: String | None + ClusterVersion: String | None + AllowVersionUpgrade: BooleanOptional | None + HsmClientCertificateIdentifier: String | None + HsmConfigurationIdentifier: String | None + NewClusterIdentifier: String | None + PubliclyAccessible: BooleanOptional | None + ElasticIp: String | None + EnhancedVpcRouting: BooleanOptional | None + MaintenanceTrackName: String | None + Encrypted: BooleanOptional | None + KmsKeyId: String | None + AvailabilityZoneRelocation: BooleanOptional | None + AvailabilityZone: String | None + Port: IntegerOptional | None + ManageMasterPassword: BooleanOptional | None + MasterPasswordSecretKmsKeyId: String | None + IpAddressType: String | None + MultiAZ: BooleanOptional | None + ExtraComputeForAutomaticOptimization: BooleanOptional | None class ModifyClusterParameterGroupMessage(ServiceRequest): @@ -3149,33 +3209,33 @@ class ModifyClusterParameterGroupMessage(ServiceRequest): class ModifyClusterResult(TypedDict, total=False): - Cluster: Optional[Cluster] + Cluster: Cluster | None class ModifyClusterSnapshotMessage(ServiceRequest): SnapshotIdentifier: String - ManualSnapshotRetentionPeriod: Optional[IntegerOptional] - Force: Optional[Boolean] + ManualSnapshotRetentionPeriod: IntegerOptional | None + Force: Boolean | None class ModifyClusterSnapshotResult(TypedDict, total=False): - Snapshot: Optional[Snapshot] + Snapshot: Snapshot | None class ModifyClusterSnapshotScheduleMessage(ServiceRequest): ClusterIdentifier: String - ScheduleIdentifier: Optional[String] - DisassociateSchedule: Optional[BooleanOptional] + ScheduleIdentifier: String | None + DisassociateSchedule: BooleanOptional | None class ModifyClusterSubnetGroupMessage(ServiceRequest): ClusterSubnetGroupName: String - Description: Optional[String] + Description: String | None SubnetIds: SubnetIdentifierList class ModifyClusterSubnetGroupResult(TypedDict, total=False): - ClusterSubnetGroup: Optional[ClusterSubnetGroup] + ClusterSubnetGroup: ClusterSubnetGroup | None class ModifyCustomDomainAssociationMessage(ServiceRequest): @@ -3185,69 +3245,78 @@ class ModifyCustomDomainAssociationMessage(ServiceRequest): class ModifyCustomDomainAssociationResult(TypedDict, total=False): - CustomDomainName: Optional[CustomDomainNameString] - CustomDomainCertificateArn: Optional[CustomDomainCertificateArnString] - ClusterIdentifier: Optional[String] - CustomDomainCertExpiryTime: Optional[String] + CustomDomainName: CustomDomainNameString | None + CustomDomainCertificateArn: CustomDomainCertificateArnString | None + ClusterIdentifier: String | None + CustomDomainCertExpiryTime: String | None class ModifyEndpointAccessMessage(ServiceRequest): EndpointName: String - VpcSecurityGroupIds: Optional[VpcSecurityGroupIdList] + VpcSecurityGroupIds: VpcSecurityGroupIdList | None class ModifyEventSubscriptionMessage(ServiceRequest): SubscriptionName: String - SnsTopicArn: Optional[String] - SourceType: Optional[String] - SourceIds: Optional[SourceIdsList] - EventCategories: Optional[EventCategoriesList] - Severity: Optional[String] - Enabled: Optional[BooleanOptional] + SnsTopicArn: String | None + SourceType: String | None + SourceIds: SourceIdsList | None + EventCategories: EventCategoriesList | None + Severity: String | None + Enabled: BooleanOptional | None class ModifyEventSubscriptionResult(TypedDict, total=False): - EventSubscription: Optional[EventSubscription] + EventSubscription: EventSubscription | None class ModifyIntegrationMessage(ServiceRequest): IntegrationArn: IntegrationArn - Description: Optional[IntegrationDescription] - IntegrationName: Optional[IntegrationName] + Description: IntegrationDescription | None + IntegrationName: IntegrationName | None + + +class ModifyLakehouseConfigurationMessage(ServiceRequest): + ClusterIdentifier: String + LakehouseRegistration: LakehouseRegistration | None + CatalogName: CatalogNameString | None + LakehouseIdcRegistration: LakehouseIdcRegistration | None + LakehouseIdcApplicationArn: String | None + DryRun: BooleanOptional | None class ModifyRedshiftIdcApplicationMessage(ServiceRequest): RedshiftIdcApplicationArn: String - IdentityNamespace: Optional[IdentityNamespaceString] - IamRoleArn: Optional[String] - IdcDisplayName: Optional[IdcDisplayNameString] - AuthorizedTokenIssuerList: Optional[AuthorizedTokenIssuerList] - ServiceIntegrations: Optional[ServiceIntegrationList] + IdentityNamespace: IdentityNamespaceString | None + IamRoleArn: String | None + IdcDisplayName: IdcDisplayNameString | None + AuthorizedTokenIssuerList: AuthorizedTokenIssuerList | None + ServiceIntegrations: ServiceIntegrationList | None class ModifyRedshiftIdcApplicationResult(TypedDict, total=False): - RedshiftIdcApplication: Optional[RedshiftIdcApplication] + RedshiftIdcApplication: RedshiftIdcApplication | None class ModifyScheduledActionMessage(ServiceRequest): ScheduledActionName: String - TargetAction: Optional[ScheduledActionType] - Schedule: Optional[String] - IamRole: Optional[String] - ScheduledActionDescription: Optional[String] - StartTime: Optional[TStamp] - EndTime: Optional[TStamp] - Enable: Optional[BooleanOptional] + TargetAction: ScheduledActionType | None + Schedule: String | None + IamRole: String | None + ScheduledActionDescription: String | None + StartTime: TStamp | None + EndTime: TStamp | None + Enable: BooleanOptional | None class ModifySnapshotCopyRetentionPeriodMessage(ServiceRequest): ClusterIdentifier: String RetentionPeriod: Integer - Manual: Optional[Boolean] + Manual: Boolean | None class ModifySnapshotCopyRetentionPeriodResult(TypedDict, total=False): - Cluster: Optional[Cluster] + Cluster: Cluster | None class ModifySnapshotScheduleMessage(ServiceRequest): @@ -3257,38 +3326,38 @@ class ModifySnapshotScheduleMessage(ServiceRequest): class ModifyUsageLimitMessage(ServiceRequest): UsageLimitId: String - Amount: Optional[LongOptional] - BreachAction: Optional[UsageLimitBreachAction] + Amount: LongOptional | None + BreachAction: UsageLimitBreachAction | None class NodeConfigurationOption(TypedDict, total=False): - NodeType: Optional[String] - NumberOfNodes: Optional[Integer] - EstimatedDiskUtilizationPercent: Optional[DoubleOptional] - Mode: Optional[Mode] + NodeType: String | None + NumberOfNodes: Integer | None + EstimatedDiskUtilizationPercent: DoubleOptional | None + Mode: Mode | None -NodeConfigurationOptionList = List[NodeConfigurationOption] +NodeConfigurationOptionList = list[NodeConfigurationOption] class NodeConfigurationOptionsMessage(TypedDict, total=False): - NodeConfigurationOptionList: Optional[NodeConfigurationOptionList] - Marker: Optional[String] + NodeConfigurationOptionList: NodeConfigurationOptionList | None + Marker: String | None class OrderableClusterOption(TypedDict, total=False): - ClusterVersion: Optional[String] - ClusterType: Optional[String] - NodeType: Optional[String] - AvailabilityZones: Optional[AvailabilityZoneList] + ClusterVersion: String | None + ClusterType: String | None + NodeType: String | None + AvailabilityZones: AvailabilityZoneList | None -OrderableClusterOptionsList = List[OrderableClusterOption] +OrderableClusterOptionsList = list[OrderableClusterOption] class OrderableClusterOptionsMessage(TypedDict, total=False): - OrderableClusterOptions: Optional[OrderableClusterOptionsList] - Marker: Optional[String] + OrderableClusterOptions: OrderableClusterOptionsList | None + Marker: String | None class PartnerIntegrationInputMessage(ServiceRequest): @@ -3299,21 +3368,21 @@ class PartnerIntegrationInputMessage(ServiceRequest): class PartnerIntegrationOutputMessage(TypedDict, total=False): - DatabaseName: Optional[PartnerIntegrationDatabaseName] - PartnerName: Optional[PartnerIntegrationPartnerName] + DatabaseName: PartnerIntegrationDatabaseName | None + PartnerName: PartnerIntegrationPartnerName | None class PauseClusterResult(TypedDict, total=False): - Cluster: Optional[Cluster] + Cluster: Cluster | None class PurchaseReservedNodeOfferingMessage(ServiceRequest): ReservedNodeOfferingId: String - NodeCount: Optional[IntegerOptional] + NodeCount: IntegerOptional | None class PurchaseReservedNodeOfferingResult(TypedDict, total=False): - ReservedNode: Optional[ReservedNode] + ReservedNode: ReservedNode | None class PutResourcePolicyMessage(ServiceRequest): @@ -3322,7 +3391,7 @@ class PutResourcePolicyMessage(ServiceRequest): class PutResourcePolicyResult(TypedDict, total=False): - ResourcePolicy: Optional[ResourcePolicy] + ResourcePolicy: ResourcePolicy | None class RebootClusterMessage(ServiceRequest): @@ -3330,7 +3399,7 @@ class RebootClusterMessage(ServiceRequest): class RebootClusterResult(TypedDict, total=False): - Cluster: Optional[Cluster] + Cluster: Cluster | None class RegisterNamespaceInputMessage(ServiceRequest): @@ -3339,163 +3408,165 @@ class RegisterNamespaceInputMessage(ServiceRequest): class RegisterNamespaceOutputMessage(TypedDict, total=False): - Status: Optional[NamespaceRegistrationStatus] + Status: NamespaceRegistrationStatus | None class RejectDataShareMessage(ServiceRequest): DataShareArn: String -ReservedNodeList = List[ReservedNode] +ReservedNodeList = list[ReservedNode] class ReservedNodeOfferingsMessage(TypedDict, total=False): - Marker: Optional[String] - ReservedNodeOfferings: Optional[ReservedNodeOfferingList] + Marker: String | None + ReservedNodeOfferings: ReservedNodeOfferingList | None class ReservedNodesMessage(TypedDict, total=False): - Marker: Optional[String] - ReservedNodes: Optional[ReservedNodeList] + Marker: String | None + ReservedNodes: ReservedNodeList | None class ResetClusterParameterGroupMessage(ServiceRequest): ParameterGroupName: String - ResetAllParameters: Optional[Boolean] - Parameters: Optional[ParametersList] + ResetAllParameters: Boolean | None + Parameters: ParametersList | None class ResizeClusterResult(TypedDict, total=False): - Cluster: Optional[Cluster] + Cluster: Cluster | None class ResizeProgressMessage(TypedDict, total=False): - TargetNodeType: Optional[String] - TargetNumberOfNodes: Optional[IntegerOptional] - TargetClusterType: Optional[String] - Status: Optional[String] - ImportTablesCompleted: Optional[ImportTablesCompleted] - ImportTablesInProgress: Optional[ImportTablesInProgress] - ImportTablesNotStarted: Optional[ImportTablesNotStarted] - AvgResizeRateInMegaBytesPerSecond: Optional[DoubleOptional] - TotalResizeDataInMegaBytes: Optional[LongOptional] - ProgressInMegaBytes: Optional[LongOptional] - ElapsedTimeInSeconds: Optional[LongOptional] - EstimatedTimeToCompletionInSeconds: Optional[LongOptional] - ResizeType: Optional[String] - Message: Optional[String] - TargetEncryptionType: Optional[String] - DataTransferProgressPercent: Optional[DoubleOptional] + TargetNodeType: String | None + TargetNumberOfNodes: IntegerOptional | None + TargetClusterType: String | None + Status: String | None + ImportTablesCompleted: ImportTablesCompleted | None + ImportTablesInProgress: ImportTablesInProgress | None + ImportTablesNotStarted: ImportTablesNotStarted | None + AvgResizeRateInMegaBytesPerSecond: DoubleOptional | None + TotalResizeDataInMegaBytes: LongOptional | None + ProgressInMegaBytes: LongOptional | None + ElapsedTimeInSeconds: LongOptional | None + EstimatedTimeToCompletionInSeconds: LongOptional | None + ResizeType: String | None + Message: String | None + TargetEncryptionType: String | None + DataTransferProgressPercent: DoubleOptional | None class RestoreFromClusterSnapshotMessage(ServiceRequest): ClusterIdentifier: String - SnapshotIdentifier: Optional[String] - SnapshotArn: Optional[String] - SnapshotClusterIdentifier: Optional[String] - Port: Optional[IntegerOptional] - AvailabilityZone: Optional[String] - AllowVersionUpgrade: Optional[BooleanOptional] - ClusterSubnetGroupName: Optional[String] - PubliclyAccessible: Optional[BooleanOptional] - OwnerAccount: Optional[String] - HsmClientCertificateIdentifier: Optional[String] - HsmConfigurationIdentifier: Optional[String] - ElasticIp: Optional[String] - ClusterParameterGroupName: Optional[String] - ClusterSecurityGroups: Optional[ClusterSecurityGroupNameList] - VpcSecurityGroupIds: Optional[VpcSecurityGroupIdList] - PreferredMaintenanceWindow: Optional[String] - AutomatedSnapshotRetentionPeriod: Optional[IntegerOptional] - ManualSnapshotRetentionPeriod: Optional[IntegerOptional] - KmsKeyId: Optional[String] - NodeType: Optional[String] - EnhancedVpcRouting: Optional[BooleanOptional] - AdditionalInfo: Optional[String] - IamRoles: Optional[IamRoleArnList] - MaintenanceTrackName: Optional[String] - SnapshotScheduleIdentifier: Optional[String] - NumberOfNodes: Optional[IntegerOptional] - AvailabilityZoneRelocation: Optional[BooleanOptional] - AquaConfigurationStatus: Optional[AquaConfigurationStatus] - DefaultIamRoleArn: Optional[String] - ReservedNodeId: Optional[String] - TargetReservedNodeOfferingId: Optional[String] - Encrypted: Optional[BooleanOptional] - ManageMasterPassword: Optional[BooleanOptional] - MasterPasswordSecretKmsKeyId: Optional[String] - IpAddressType: Optional[String] - MultiAZ: Optional[BooleanOptional] + SnapshotIdentifier: String | None + SnapshotArn: String | None + SnapshotClusterIdentifier: String | None + Port: IntegerOptional | None + AvailabilityZone: String | None + AllowVersionUpgrade: BooleanOptional | None + ClusterSubnetGroupName: String | None + PubliclyAccessible: BooleanOptional | None + OwnerAccount: String | None + HsmClientCertificateIdentifier: String | None + HsmConfigurationIdentifier: String | None + ElasticIp: String | None + ClusterParameterGroupName: String | None + ClusterSecurityGroups: ClusterSecurityGroupNameList | None + VpcSecurityGroupIds: VpcSecurityGroupIdList | None + PreferredMaintenanceWindow: String | None + AutomatedSnapshotRetentionPeriod: IntegerOptional | None + ManualSnapshotRetentionPeriod: IntegerOptional | None + KmsKeyId: String | None + NodeType: String | None + EnhancedVpcRouting: BooleanOptional | None + AdditionalInfo: String | None + IamRoles: IamRoleArnList | None + MaintenanceTrackName: String | None + SnapshotScheduleIdentifier: String | None + NumberOfNodes: IntegerOptional | None + AvailabilityZoneRelocation: BooleanOptional | None + AquaConfigurationStatus: AquaConfigurationStatus | None + DefaultIamRoleArn: String | None + ReservedNodeId: String | None + TargetReservedNodeOfferingId: String | None + Encrypted: BooleanOptional | None + ManageMasterPassword: BooleanOptional | None + MasterPasswordSecretKmsKeyId: String | None + IpAddressType: String | None + MultiAZ: BooleanOptional | None + CatalogName: CatalogNameString | None + RedshiftIdcApplicationArn: String | None class RestoreFromClusterSnapshotResult(TypedDict, total=False): - Cluster: Optional[Cluster] + Cluster: Cluster | None class RestoreTableFromClusterSnapshotMessage(ServiceRequest): ClusterIdentifier: String SnapshotIdentifier: String SourceDatabaseName: String - SourceSchemaName: Optional[String] + SourceSchemaName: String | None SourceTableName: String - TargetDatabaseName: Optional[String] - TargetSchemaName: Optional[String] + TargetDatabaseName: String | None + TargetSchemaName: String | None NewTableName: String - EnableCaseSensitiveIdentifier: Optional[BooleanOptional] + EnableCaseSensitiveIdentifier: BooleanOptional | None class TableRestoreStatus(TypedDict, total=False): - TableRestoreRequestId: Optional[String] - Status: Optional[TableRestoreStatusType] - Message: Optional[String] - RequestTime: Optional[TStamp] - ProgressInMegaBytes: Optional[LongOptional] - TotalDataInMegaBytes: Optional[LongOptional] - ClusterIdentifier: Optional[String] - SnapshotIdentifier: Optional[String] - SourceDatabaseName: Optional[String] - SourceSchemaName: Optional[String] - SourceTableName: Optional[String] - TargetDatabaseName: Optional[String] - TargetSchemaName: Optional[String] - NewTableName: Optional[String] + TableRestoreRequestId: String | None + Status: TableRestoreStatusType | None + Message: String | None + RequestTime: TStamp | None + ProgressInMegaBytes: LongOptional | None + TotalDataInMegaBytes: LongOptional | None + ClusterIdentifier: String | None + SnapshotIdentifier: String | None + SourceDatabaseName: String | None + SourceSchemaName: String | None + SourceTableName: String | None + TargetDatabaseName: String | None + TargetSchemaName: String | None + NewTableName: String | None class RestoreTableFromClusterSnapshotResult(TypedDict, total=False): - TableRestoreStatus: Optional[TableRestoreStatus] + TableRestoreStatus: TableRestoreStatus | None class ResumeClusterResult(TypedDict, total=False): - Cluster: Optional[Cluster] + Cluster: Cluster | None class RevokeClusterSecurityGroupIngressMessage(ServiceRequest): ClusterSecurityGroupName: String - CIDRIP: Optional[String] - EC2SecurityGroupName: Optional[String] - EC2SecurityGroupOwnerId: Optional[String] + CIDRIP: String | None + EC2SecurityGroupName: String | None + EC2SecurityGroupOwnerId: String | None class RevokeClusterSecurityGroupIngressResult(TypedDict, total=False): - ClusterSecurityGroup: Optional[ClusterSecurityGroup] + ClusterSecurityGroup: ClusterSecurityGroup | None class RevokeEndpointAccessMessage(ServiceRequest): - ClusterIdentifier: Optional[String] - Account: Optional[String] - VpcIds: Optional[VpcIdentifierList] - Force: Optional[Boolean] + ClusterIdentifier: String | None + Account: String | None + VpcIds: VpcIdentifierList | None + Force: Boolean | None class RevokeSnapshotAccessMessage(ServiceRequest): - SnapshotIdentifier: Optional[String] - SnapshotArn: Optional[String] - SnapshotClusterIdentifier: Optional[String] + SnapshotIdentifier: String | None + SnapshotArn: String | None + SnapshotClusterIdentifier: String | None AccountWithRestoreAccess: String class RevokeSnapshotAccessResult(TypedDict, total=False): - Snapshot: Optional[Snapshot] + Snapshot: Snapshot | None class RotateEncryptionKeyMessage(ServiceRequest): @@ -3503,76 +3574,76 @@ class RotateEncryptionKeyMessage(ServiceRequest): class RotateEncryptionKeyResult(TypedDict, total=False): - Cluster: Optional[Cluster] + Cluster: Cluster | None -ScheduledActionTimeList = List[TStamp] +ScheduledActionTimeList = list[TStamp] class ScheduledAction(TypedDict, total=False): - ScheduledActionName: Optional[String] - TargetAction: Optional[ScheduledActionType] - Schedule: Optional[String] - IamRole: Optional[String] - ScheduledActionDescription: Optional[String] - State: Optional[ScheduledActionState] - NextInvocations: Optional[ScheduledActionTimeList] - StartTime: Optional[TStamp] - EndTime: Optional[TStamp] + ScheduledActionName: String | None + TargetAction: ScheduledActionType | None + Schedule: String | None + IamRole: String | None + ScheduledActionDescription: String | None + State: ScheduledActionState | None + NextInvocations: ScheduledActionTimeList | None + StartTime: TStamp | None + EndTime: TStamp | None -ScheduledActionList = List[ScheduledAction] +ScheduledActionList = list[ScheduledAction] class ScheduledActionsMessage(TypedDict, total=False): - Marker: Optional[String] - ScheduledActions: Optional[ScheduledActionList] + Marker: String | None + ScheduledActions: ScheduledActionList | None -SnapshotCopyGrantList = List[SnapshotCopyGrant] +SnapshotCopyGrantList = list[SnapshotCopyGrant] class SnapshotCopyGrantMessage(TypedDict, total=False): - Marker: Optional[String] - SnapshotCopyGrants: Optional[SnapshotCopyGrantList] + Marker: String | None + SnapshotCopyGrants: SnapshotCopyGrantList | None -SnapshotList = List[Snapshot] +SnapshotList = list[Snapshot] class SnapshotMessage(TypedDict, total=False): - Marker: Optional[String] - Snapshots: Optional[SnapshotList] + Marker: String | None + Snapshots: SnapshotList | None -TableRestoreStatusList = List[TableRestoreStatus] +TableRestoreStatusList = list[TableRestoreStatus] class TableRestoreStatusMessage(TypedDict, total=False): - TableRestoreStatusDetails: Optional[TableRestoreStatusList] - Marker: Optional[String] + TableRestoreStatusDetails: TableRestoreStatusList | None + Marker: String | None class TaggedResource(TypedDict, total=False): - Tag: Optional[Tag] - ResourceName: Optional[String] - ResourceType: Optional[String] + Tag: Tag | None + ResourceName: String | None + ResourceType: String | None -TaggedResourceList = List[TaggedResource] +TaggedResourceList = list[TaggedResource] class TaggedResourceListMessage(TypedDict, total=False): - TaggedResources: Optional[TaggedResourceList] - Marker: Optional[String] + TaggedResources: TaggedResourceList | None + Marker: String | None -TrackList = List[MaintenanceTrack] +TrackList = list[MaintenanceTrack] class TrackListMessage(TypedDict, total=False): - MaintenanceTracks: Optional[TrackList] - Marker: Optional[String] + MaintenanceTracks: TrackList | None + Marker: String | None class UpdatePartnerStatusInputMessage(ServiceRequest): @@ -3581,31 +3652,31 @@ class UpdatePartnerStatusInputMessage(ServiceRequest): DatabaseName: PartnerIntegrationDatabaseName PartnerName: PartnerIntegrationPartnerName Status: PartnerIntegrationStatus - StatusMessage: Optional[PartnerIntegrationStatusMessage] + StatusMessage: PartnerIntegrationStatusMessage | None class UsageLimit(TypedDict, total=False): - UsageLimitId: Optional[String] - ClusterIdentifier: Optional[String] - FeatureType: Optional[UsageLimitFeatureType] - LimitType: Optional[UsageLimitLimitType] - Amount: Optional[Long] - Period: Optional[UsageLimitPeriod] - BreachAction: Optional[UsageLimitBreachAction] - Tags: Optional[TagList] + UsageLimitId: String | None + ClusterIdentifier: String | None + FeatureType: UsageLimitFeatureType | None + LimitType: UsageLimitLimitType | None + Amount: Long | None + Period: UsageLimitPeriod | None + BreachAction: UsageLimitBreachAction | None + Tags: TagList | None -UsageLimits = List[UsageLimit] +UsageLimits = list[UsageLimit] class UsageLimitList(TypedDict, total=False): - UsageLimits: Optional[UsageLimits] - Marker: Optional[String] + UsageLimits: UsageLimits | None + Marker: String | None class RedshiftApi: - service = "redshift" - version = "2012-12-01" + service: str = "redshift" + version: str = "2012-12-01" @handler("AcceptReservedNodeExchange") def accept_reserved_node_exchange( @@ -3776,6 +3847,8 @@ def create_cluster( ip_address_type: String | None = None, multi_az: BooleanOptional | None = None, redshift_idc_application_arn: String | None = None, + catalog_name: CatalogNameString | None = None, + extra_compute_for_automatic_optimization: BooleanOptional | None = None, **kwargs, ) -> CreateClusterResult: raise NotImplementedError @@ -3918,6 +3991,7 @@ def create_redshift_idc_application( identity_namespace: IdentityNamespaceString | None = None, authorized_token_issuer_list: AuthorizedTokenIssuerList | None = None, service_integrations: ServiceIntegrationList | None = None, + application_type: ApplicationType | None = None, tags: TagList | None = None, sso_tag_keys: TagKeyList | None = None, **kwargs, @@ -4714,6 +4788,12 @@ def get_cluster_credentials_with_iam( ) -> ClusterExtendedCredentials: raise NotImplementedError + @handler("GetIdentityCenterAuthToken") + def get_identity_center_auth_token( + self, context: RequestContext, cluster_ids: ClusterIdentifierList, **kwargs + ) -> GetIdentityCenterAuthTokenResponse: + raise NotImplementedError + @handler("GetReservedNodeExchangeConfigurationOptions") def get_reserved_node_exchange_configuration_options( self, @@ -4809,6 +4889,7 @@ def modify_cluster( master_password_secret_kms_key_id: String | None = None, ip_address_type: String | None = None, multi_az: BooleanOptional | None = None, + extra_compute_for_automatic_optimization: BooleanOptional | None = None, **kwargs, ) -> ModifyClusterResult: raise NotImplementedError @@ -4935,6 +5016,20 @@ def modify_integration( ) -> Integration: raise NotImplementedError + @handler("ModifyLakehouseConfiguration") + def modify_lakehouse_configuration( + self, + context: RequestContext, + cluster_identifier: String, + lakehouse_registration: LakehouseRegistration | None = None, + catalog_name: CatalogNameString | None = None, + lakehouse_idc_registration: LakehouseIdcRegistration | None = None, + lakehouse_idc_application_arn: String | None = None, + dry_run: BooleanOptional | None = None, + **kwargs, + ) -> LakehouseConfiguration: + raise NotImplementedError + @handler("ModifyRedshiftIdcApplication") def modify_redshift_idc_application( self, @@ -5108,6 +5203,8 @@ def restore_from_cluster_snapshot( master_password_secret_kms_key_id: String | None = None, ip_address_type: String | None = None, multi_az: BooleanOptional | None = None, + catalog_name: CatalogNameString | None = None, + redshift_idc_application_arn: String | None = None, **kwargs, ) -> RestoreFromClusterSnapshotResult: raise NotImplementedError diff --git a/localstack-core/localstack/aws/api/resource_groups/__init__.py b/localstack-core/localstack/aws/api/resource_groups/__init__.py index b7511726ef579..efcc162678feb 100644 --- a/localstack-core/localstack/aws/api/resource_groups/__init__.py +++ b/localstack-core/localstack/aws/api/resource_groups/__init__.py @@ -1,6 +1,6 @@ from datetime import datetime from enum import StrEnum -from typing import Dict, List, Optional, TypedDict +from typing import TypedDict from localstack.aws.api import RequestContext, ServiceException, ServiceRequest, handler @@ -149,36 +149,36 @@ class UnauthorizedException(ServiceException): class AccountSettings(TypedDict, total=False): - GroupLifecycleEventsDesiredStatus: Optional[GroupLifecycleEventsDesiredStatus] - GroupLifecycleEventsStatus: Optional[GroupLifecycleEventsStatus] - GroupLifecycleEventsStatusMessage: Optional[GroupLifecycleEventsStatusMessage] + GroupLifecycleEventsDesiredStatus: GroupLifecycleEventsDesiredStatus | None + GroupLifecycleEventsStatus: GroupLifecycleEventsStatus | None + GroupLifecycleEventsStatusMessage: GroupLifecycleEventsStatusMessage | None -ApplicationTag = Dict[ApplicationTagKey, ApplicationArn] +ApplicationTag = dict[ApplicationTagKey, ApplicationArn] class CancelTagSyncTaskInput(ServiceRequest): TaskArn: TagSyncTaskArn -GroupConfigurationParameterValueList = List[GroupConfigurationParameterValue] +GroupConfigurationParameterValueList = list[GroupConfigurationParameterValue] class GroupConfigurationParameter(TypedDict, total=False): Name: GroupConfigurationParameterName - Values: Optional[GroupConfigurationParameterValueList] + Values: GroupConfigurationParameterValueList | None -GroupParameterList = List[GroupConfigurationParameter] +GroupParameterList = list[GroupConfigurationParameter] class GroupConfigurationItem(TypedDict, total=False): Type: GroupConfigurationType - Parameters: Optional[GroupParameterList] + Parameters: GroupParameterList | None -GroupConfigurationList = List[GroupConfigurationItem] -Tags = Dict[TagKey, TagValue] +GroupConfigurationList = list[GroupConfigurationItem] +Tags = dict[TagKey, TagValue] class ResourceQuery(TypedDict, total=False): @@ -188,81 +188,81 @@ class ResourceQuery(TypedDict, total=False): class CreateGroupInput(ServiceRequest): Name: CreateGroupName - Description: Optional[Description] - ResourceQuery: Optional[ResourceQuery] - Tags: Optional[Tags] - Configuration: Optional[GroupConfigurationList] - Criticality: Optional[Criticality] - Owner: Optional[Owner] - DisplayName: Optional[DisplayName] + Description: Description | None + ResourceQuery: ResourceQuery | None + Tags: Tags | None + Configuration: GroupConfigurationList | None + Criticality: Criticality | None + Owner: Owner | None + DisplayName: DisplayName | None class GroupConfiguration(TypedDict, total=False): - Configuration: Optional[GroupConfigurationList] - ProposedConfiguration: Optional[GroupConfigurationList] - Status: Optional[GroupConfigurationStatus] - FailureReason: Optional[GroupConfigurationFailureReason] + Configuration: GroupConfigurationList | None + ProposedConfiguration: GroupConfigurationList | None + Status: GroupConfigurationStatus | None + FailureReason: GroupConfigurationFailureReason | None class Group(TypedDict, total=False): GroupArn: GroupArnV2 Name: GroupName - Description: Optional[Description] - Criticality: Optional[Criticality] - Owner: Optional[Owner] - DisplayName: Optional[DisplayName] - ApplicationTag: Optional[ApplicationTag] + Description: Description | None + Criticality: Criticality | None + Owner: Owner | None + DisplayName: DisplayName | None + ApplicationTag: ApplicationTag | None class CreateGroupOutput(TypedDict, total=False): - Group: Optional[Group] - ResourceQuery: Optional[ResourceQuery] - Tags: Optional[Tags] - GroupConfiguration: Optional[GroupConfiguration] + Group: Group | None + ResourceQuery: ResourceQuery | None + Tags: Tags | None + GroupConfiguration: GroupConfiguration | None class DeleteGroupInput(ServiceRequest): - GroupName: Optional[GroupName] - Group: Optional[GroupStringV2] + GroupName: GroupName | None + Group: GroupStringV2 | None class DeleteGroupOutput(TypedDict, total=False): - Group: Optional[Group] + Group: Group | None class FailedResource(TypedDict, total=False): - ResourceArn: Optional[ResourceArn] - ErrorMessage: Optional[ErrorMessage] - ErrorCode: Optional[ErrorCode] + ResourceArn: ResourceArn | None + ErrorMessage: ErrorMessage | None + ErrorCode: ErrorCode | None -FailedResourceList = List[FailedResource] +FailedResourceList = list[FailedResource] class GetAccountSettingsOutput(TypedDict, total=False): - AccountSettings: Optional[AccountSettings] + AccountSettings: AccountSettings | None class GetGroupConfigurationInput(ServiceRequest): - Group: Optional[GroupString] + Group: GroupString | None class GetGroupConfigurationOutput(TypedDict, total=False): - GroupConfiguration: Optional[GroupConfiguration] + GroupConfiguration: GroupConfiguration | None class GetGroupInput(ServiceRequest): - GroupName: Optional[GroupName] - Group: Optional[GroupStringV2] + GroupName: GroupName | None + Group: GroupStringV2 | None class GetGroupOutput(TypedDict, total=False): - Group: Optional[Group] + Group: Group | None class GetGroupQueryInput(ServiceRequest): - GroupName: Optional[GroupName] - Group: Optional[GroupString] + GroupName: GroupName | None + Group: GroupString | None class GroupQuery(TypedDict, total=False): @@ -271,7 +271,7 @@ class GroupQuery(TypedDict, total=False): class GetGroupQueryOutput(TypedDict, total=False): - GroupQuery: Optional[GroupQuery] + GroupQuery: GroupQuery | None class GetTagSyncTaskInput(ServiceRequest): @@ -282,16 +282,16 @@ class GetTagSyncTaskInput(ServiceRequest): class GetTagSyncTaskOutput(TypedDict, total=False): - GroupArn: Optional[GroupArnV2] - GroupName: Optional[GroupName] - TaskArn: Optional[TagSyncTaskArn] - TagKey: Optional[TagKey] - TagValue: Optional[TagValue] - ResourceQuery: Optional[ResourceQuery] - RoleArn: Optional[RoleArn] - Status: Optional[TagSyncTaskStatus] - ErrorMessage: Optional[ErrorMessage] - CreatedAt: Optional[timestamp] + GroupArn: GroupArnV2 | None + GroupName: GroupName | None + TaskArn: TagSyncTaskArn | None + TagKey: TagKey | None + TagValue: TagValue | None + ResourceQuery: ResourceQuery | None + RoleArn: RoleArn | None + Status: TagSyncTaskStatus | None + ErrorMessage: ErrorMessage | None + CreatedAt: timestamp | None class GetTagsInput(ServiceRequest): @@ -299,11 +299,11 @@ class GetTagsInput(ServiceRequest): class GetTagsOutput(TypedDict, total=False): - Arn: Optional[GroupArnV2] - Tags: Optional[Tags] + Arn: GroupArnV2 | None + Tags: Tags | None -GroupFilterValues = List[GroupFilterValue] +GroupFilterValues = list[GroupFilterValue] class GroupFilter(TypedDict, total=False): @@ -311,21 +311,21 @@ class GroupFilter(TypedDict, total=False): Values: GroupFilterValues -GroupFilterList = List[GroupFilter] +GroupFilterList = list[GroupFilter] class GroupIdentifier(TypedDict, total=False): - GroupName: Optional[GroupName] - GroupArn: Optional[GroupArn] - Description: Optional[Description] - Criticality: Optional[Criticality] - Owner: Optional[Owner] - DisplayName: Optional[DisplayName] + GroupName: GroupName | None + GroupArn: GroupArn | None + Description: Description | None + Criticality: Criticality | None + Owner: Owner | None + DisplayName: DisplayName | None -GroupIdentifierList = List[GroupIdentifier] -GroupList = List[Group] -ResourceArnList = List[ResourceArn] +GroupIdentifierList = list[GroupIdentifier] +GroupList = list[Group] +ResourceArnList = list[ResourceArn] class GroupResourcesInput(ServiceRequest): @@ -334,29 +334,29 @@ class GroupResourcesInput(ServiceRequest): class PendingResource(TypedDict, total=False): - ResourceArn: Optional[ResourceArn] + ResourceArn: ResourceArn | None -PendingResourceList = List[PendingResource] +PendingResourceList = list[PendingResource] class GroupResourcesOutput(TypedDict, total=False): - Succeeded: Optional[ResourceArnList] - Failed: Optional[FailedResourceList] - Pending: Optional[PendingResourceList] + Succeeded: ResourceArnList | None + Failed: FailedResourceList | None + Pending: PendingResourceList | None class GroupingStatusesItem(TypedDict, total=False): - ResourceArn: Optional[ResourceArn] - Action: Optional[GroupingType] - Status: Optional[GroupingStatus] - ErrorMessage: Optional[ErrorMessage] - ErrorCode: Optional[ErrorCode] - UpdatedAt: Optional[timestamp] + ResourceArn: ResourceArn | None + Action: GroupingType | None + Status: GroupingStatus | None + ErrorMessage: ErrorMessage | None + ErrorCode: ErrorCode | None + UpdatedAt: timestamp | None -GroupingStatusesList = List[GroupingStatusesItem] -ResourceFilterValues = List[ResourceFilterValue] +GroupingStatusesList = list[GroupingStatusesItem] +ResourceFilterValues = list[ResourceFilterValue] class ResourceFilter(TypedDict, total=False): @@ -364,51 +364,51 @@ class ResourceFilter(TypedDict, total=False): Values: ResourceFilterValues -ResourceFilterList = List[ResourceFilter] +ResourceFilterList = list[ResourceFilter] class ListGroupResourcesInput(ServiceRequest): - GroupName: Optional[GroupName] - Group: Optional[GroupStringV2] - Filters: Optional[ResourceFilterList] - MaxResults: Optional[MaxResults] - NextToken: Optional[NextToken] + GroupName: GroupName | None + Group: GroupStringV2 | None + Filters: ResourceFilterList | None + MaxResults: MaxResults | None + NextToken: NextToken | None class ResourceStatus(TypedDict, total=False): - Name: Optional[ResourceStatusValue] + Name: ResourceStatusValue | None class ResourceIdentifier(TypedDict, total=False): - ResourceArn: Optional[ResourceArn] - ResourceType: Optional[ResourceType] + ResourceArn: ResourceArn | None + ResourceType: ResourceType | None class ListGroupResourcesItem(TypedDict, total=False): - Identifier: Optional[ResourceIdentifier] - Status: Optional[ResourceStatus] + Identifier: ResourceIdentifier | None + Status: ResourceStatus | None -ListGroupResourcesItemList = List[ListGroupResourcesItem] +ListGroupResourcesItemList = list[ListGroupResourcesItem] class QueryError(TypedDict, total=False): - ErrorCode: Optional[QueryErrorCode] - Message: Optional[QueryErrorMessage] + ErrorCode: QueryErrorCode | None + Message: QueryErrorMessage | None -QueryErrorList = List[QueryError] -ResourceIdentifierList = List[ResourceIdentifier] +QueryErrorList = list[QueryError] +ResourceIdentifierList = list[ResourceIdentifier] class ListGroupResourcesOutput(TypedDict, total=False): - Resources: Optional[ListGroupResourcesItemList] - ResourceIdentifiers: Optional[ResourceIdentifierList] - NextToken: Optional[NextToken] - QueryErrors: Optional[QueryErrorList] + Resources: ListGroupResourcesItemList | None + ResourceIdentifiers: ResourceIdentifierList | None + NextToken: NextToken | None + QueryErrors: QueryErrorList | None -ListGroupingStatusesFilterValues = List[ListGroupingStatusesFilterValue] +ListGroupingStatusesFilterValues = list[ListGroupingStatusesFilterValue] class ListGroupingStatusesFilter(TypedDict, total=False): @@ -416,72 +416,72 @@ class ListGroupingStatusesFilter(TypedDict, total=False): Values: ListGroupingStatusesFilterValues -ListGroupingStatusesFilterList = List[ListGroupingStatusesFilter] +ListGroupingStatusesFilterList = list[ListGroupingStatusesFilter] class ListGroupingStatusesInput(ServiceRequest): Group: GroupStringV2 - MaxResults: Optional[MaxResults] - Filters: Optional[ListGroupingStatusesFilterList] - NextToken: Optional[NextToken] + MaxResults: MaxResults | None + Filters: ListGroupingStatusesFilterList | None + NextToken: NextToken | None class ListGroupingStatusesOutput(TypedDict, total=False): - Group: Optional[GroupStringV2] - GroupingStatuses: Optional[GroupingStatusesList] - NextToken: Optional[NextToken] + Group: GroupStringV2 | None + GroupingStatuses: GroupingStatusesList | None + NextToken: NextToken | None class ListGroupsInput(ServiceRequest): - Filters: Optional[GroupFilterList] - MaxResults: Optional[MaxResults] - NextToken: Optional[NextToken] + Filters: GroupFilterList | None + MaxResults: MaxResults | None + NextToken: NextToken | None class ListGroupsOutput(TypedDict, total=False): - GroupIdentifiers: Optional[GroupIdentifierList] - Groups: Optional[GroupList] - NextToken: Optional[NextToken] + GroupIdentifiers: GroupIdentifierList | None + Groups: GroupList | None + NextToken: NextToken | None class ListTagSyncTasksFilter(TypedDict, total=False): - GroupArn: Optional[GroupArnV2] - GroupName: Optional[GroupName] + GroupArn: GroupArnV2 | None + GroupName: GroupName | None -ListTagSyncTasksFilterList = List[ListTagSyncTasksFilter] +ListTagSyncTasksFilterList = list[ListTagSyncTasksFilter] class ListTagSyncTasksInput(ServiceRequest): - Filters: Optional[ListTagSyncTasksFilterList] - MaxResults: Optional[MaxResults] - NextToken: Optional[NextToken] + Filters: ListTagSyncTasksFilterList | None + MaxResults: MaxResults | None + NextToken: NextToken | None class TagSyncTaskItem(TypedDict, total=False): - GroupArn: Optional[GroupArnV2] - GroupName: Optional[GroupName] - TaskArn: Optional[TagSyncTaskArn] - TagKey: Optional[TagKey] - TagValue: Optional[TagValue] - ResourceQuery: Optional[ResourceQuery] - RoleArn: Optional[RoleArn] - Status: Optional[TagSyncTaskStatus] - ErrorMessage: Optional[ErrorMessage] - CreatedAt: Optional[timestamp] + GroupArn: GroupArnV2 | None + GroupName: GroupName | None + TaskArn: TagSyncTaskArn | None + TagKey: TagKey | None + TagValue: TagValue | None + ResourceQuery: ResourceQuery | None + RoleArn: RoleArn | None + Status: TagSyncTaskStatus | None + ErrorMessage: ErrorMessage | None + CreatedAt: timestamp | None -TagSyncTaskList = List[TagSyncTaskItem] +TagSyncTaskList = list[TagSyncTaskItem] class ListTagSyncTasksOutput(TypedDict, total=False): - TagSyncTasks: Optional[TagSyncTaskList] - NextToken: Optional[NextToken] + TagSyncTasks: TagSyncTaskList | None + NextToken: NextToken | None class PutGroupConfigurationInput(ServiceRequest): - Group: Optional[GroupString] - Configuration: Optional[GroupConfigurationList] + Group: GroupString | None + Configuration: GroupConfigurationList | None class PutGroupConfigurationOutput(TypedDict, total=False): @@ -490,32 +490,32 @@ class PutGroupConfigurationOutput(TypedDict, total=False): class SearchResourcesInput(ServiceRequest): ResourceQuery: ResourceQuery - MaxResults: Optional[MaxResults] - NextToken: Optional[NextToken] + MaxResults: MaxResults | None + NextToken: NextToken | None class SearchResourcesOutput(TypedDict, total=False): - ResourceIdentifiers: Optional[ResourceIdentifierList] - NextToken: Optional[NextToken] - QueryErrors: Optional[QueryErrorList] + ResourceIdentifiers: ResourceIdentifierList | None + NextToken: NextToken | None + QueryErrors: QueryErrorList | None class StartTagSyncTaskInput(ServiceRequest): Group: GroupStringV2 - TagKey: Optional[TagKey] - TagValue: Optional[TagValue] - ResourceQuery: Optional[ResourceQuery] + TagKey: TagKey | None + TagValue: TagValue | None + ResourceQuery: ResourceQuery | None RoleArn: RoleArn class StartTagSyncTaskOutput(TypedDict, total=False): - GroupArn: Optional[GroupArnV2] - GroupName: Optional[GroupName] - TaskArn: Optional[TagSyncTaskArn] - TagKey: Optional[TagKey] - TagValue: Optional[TagValue] - ResourceQuery: Optional[ResourceQuery] - RoleArn: Optional[RoleArn] + GroupArn: GroupArnV2 | None + GroupName: GroupName | None + TaskArn: TagSyncTaskArn | None + TagKey: TagKey | None + TagValue: TagValue | None + ResourceQuery: ResourceQuery | None + RoleArn: RoleArn | None class TagInput(ServiceRequest): @@ -523,12 +523,12 @@ class TagInput(ServiceRequest): Tags: Tags -TagKeyList = List[TagKey] +TagKeyList = list[TagKey] class TagOutput(TypedDict, total=False): - Arn: Optional[GroupArnV2] - Tags: Optional[Tags] + Arn: GroupArnV2 | None + Tags: Tags | None class UngroupResourcesInput(ServiceRequest): @@ -537,9 +537,9 @@ class UngroupResourcesInput(ServiceRequest): class UngroupResourcesOutput(TypedDict, total=False): - Succeeded: Optional[ResourceArnList] - Failed: Optional[FailedResourceList] - Pending: Optional[PendingResourceList] + Succeeded: ResourceArnList | None + Failed: FailedResourceList | None + Pending: PendingResourceList | None class UntagInput(ServiceRequest): @@ -548,44 +548,44 @@ class UntagInput(ServiceRequest): class UntagOutput(TypedDict, total=False): - Arn: Optional[GroupArnV2] - Keys: Optional[TagKeyList] + Arn: GroupArnV2 | None + Keys: TagKeyList | None class UpdateAccountSettingsInput(ServiceRequest): - GroupLifecycleEventsDesiredStatus: Optional[GroupLifecycleEventsDesiredStatus] + GroupLifecycleEventsDesiredStatus: GroupLifecycleEventsDesiredStatus | None class UpdateAccountSettingsOutput(TypedDict, total=False): - AccountSettings: Optional[AccountSettings] + AccountSettings: AccountSettings | None class UpdateGroupInput(ServiceRequest): - GroupName: Optional[GroupName] - Group: Optional[GroupStringV2] - Description: Optional[Description] - Criticality: Optional[Criticality] - Owner: Optional[Owner] - DisplayName: Optional[DisplayName] + GroupName: GroupName | None + Group: GroupStringV2 | None + Description: Description | None + Criticality: Criticality | None + Owner: Owner | None + DisplayName: DisplayName | None class UpdateGroupOutput(TypedDict, total=False): - Group: Optional[Group] + Group: Group | None class UpdateGroupQueryInput(ServiceRequest): - GroupName: Optional[GroupName] - Group: Optional[GroupString] + GroupName: GroupName | None + Group: GroupString | None ResourceQuery: ResourceQuery class UpdateGroupQueryOutput(TypedDict, total=False): - GroupQuery: Optional[GroupQuery] + GroupQuery: GroupQuery | None class ResourceGroupsApi: - service = "resource-groups" - version = "2017-11-27" + service: str = "resource-groups" + version: str = "2017-11-27" @handler("CancelTagSyncTask") def cancel_tag_sync_task( diff --git a/localstack-core/localstack/aws/api/resourcegroupstaggingapi/__init__.py b/localstack-core/localstack/aws/api/resourcegroupstaggingapi/__init__.py index cc496818d3120..9c6df7705bd36 100644 --- a/localstack-core/localstack/aws/api/resourcegroupstaggingapi/__init__.py +++ b/localstack-core/localstack/aws/api/resourcegroupstaggingapi/__init__.py @@ -1,19 +1,22 @@ from enum import StrEnum -from typing import Dict, List, Optional, TypedDict +from typing import TypedDict from localstack.aws.api import RequestContext, ServiceException, ServiceRequest, handler AmazonResourceType = str +CloudFormationResourceType = str ComplianceStatus = bool ErrorMessage = str ExceptionMessage = str ExcludeCompliantResources = bool IncludeComplianceDetails = bool LastUpdated = str +MaxResultsForListRequiredTags = int MaxResultsGetComplianceSummary = int PaginationToken = str Region = str ResourceARN = str +ResourceType = str ResourcesPerPage = int S3Bucket = str S3Location = str @@ -78,13 +81,14 @@ class ThrottledException(ServiceException): status_code: int = 400 -TagKeyList = List[TagKey] +CloudFormationResourceTypes = list[CloudFormationResourceType] +TagKeyList = list[TagKey] class ComplianceDetails(TypedDict, total=False): - NoncompliantKeys: Optional[TagKeyList] - KeysWithNoncompliantValues: Optional[TagKeyList] - ComplianceStatus: Optional[ComplianceStatus] + NoncompliantKeys: TagKeyList | None + KeysWithNoncompliantValues: TagKeyList | None + ComplianceStatus: ComplianceStatus | None class DescribeReportCreationInput(ServiceRequest): @@ -92,76 +96,76 @@ class DescribeReportCreationInput(ServiceRequest): class DescribeReportCreationOutput(TypedDict, total=False): - Status: Optional[Status] - S3Location: Optional[S3Location] - ErrorMessage: Optional[ErrorMessage] + Status: Status | None + S3Location: S3Location | None + ErrorMessage: ErrorMessage | None class FailureInfo(TypedDict, total=False): - StatusCode: Optional[StatusCode] - ErrorCode: Optional[ErrorCode] - ErrorMessage: Optional[ErrorMessage] + StatusCode: StatusCode | None + ErrorCode: ErrorCode | None + ErrorMessage: ErrorMessage | None -FailedResourcesMap = Dict[ResourceARN, FailureInfo] -GroupBy = List[GroupByAttribute] -TagKeyFilterList = List[TagKey] -ResourceTypeFilterList = List[AmazonResourceType] -RegionFilterList = List[Region] -TargetIdFilterList = List[TargetId] +FailedResourcesMap = dict[ResourceARN, FailureInfo] +GroupBy = list[GroupByAttribute] +TagKeyFilterList = list[TagKey] +ResourceTypeFilterList = list[AmazonResourceType] +RegionFilterList = list[Region] +TargetIdFilterList = list[TargetId] class GetComplianceSummaryInput(ServiceRequest): - TargetIdFilters: Optional[TargetIdFilterList] - RegionFilters: Optional[RegionFilterList] - ResourceTypeFilters: Optional[ResourceTypeFilterList] - TagKeyFilters: Optional[TagKeyFilterList] - GroupBy: Optional[GroupBy] - MaxResults: Optional[MaxResultsGetComplianceSummary] - PaginationToken: Optional[PaginationToken] + TargetIdFilters: TargetIdFilterList | None + RegionFilters: RegionFilterList | None + ResourceTypeFilters: ResourceTypeFilterList | None + TagKeyFilters: TagKeyFilterList | None + GroupBy: GroupBy | None + MaxResults: MaxResultsGetComplianceSummary | None + PaginationToken: PaginationToken | None NonCompliantResources = int class Summary(TypedDict, total=False): - LastUpdated: Optional[LastUpdated] - TargetId: Optional[TargetId] - TargetIdType: Optional[TargetIdType] - Region: Optional[Region] - ResourceType: Optional[AmazonResourceType] - NonCompliantResources: Optional[NonCompliantResources] + LastUpdated: LastUpdated | None + TargetId: TargetId | None + TargetIdType: TargetIdType | None + Region: Region | None + ResourceType: AmazonResourceType | None + NonCompliantResources: NonCompliantResources | None -SummaryList = List[Summary] +SummaryList = list[Summary] class GetComplianceSummaryOutput(TypedDict, total=False): - SummaryList: Optional[SummaryList] - PaginationToken: Optional[PaginationToken] + SummaryList: SummaryList | None + PaginationToken: PaginationToken | None -ResourceARNListForGet = List[ResourceARN] -TagValueList = List[TagValue] +ResourceARNListForGet = list[ResourceARN] +TagValueList = list[TagValue] class TagFilter(TypedDict, total=False): - Key: Optional[TagKey] - Values: Optional[TagValueList] + Key: TagKey | None + Values: TagValueList | None -TagFilterList = List[TagFilter] +TagFilterList = list[TagFilter] class GetResourcesInput(ServiceRequest): - PaginationToken: Optional[PaginationToken] - TagFilters: Optional[TagFilterList] - ResourcesPerPage: Optional[ResourcesPerPage] - TagsPerPage: Optional[TagsPerPage] - ResourceTypeFilters: Optional[ResourceTypeFilterList] - IncludeComplianceDetails: Optional[IncludeComplianceDetails] - ExcludeCompliantResources: Optional[ExcludeCompliantResources] - ResourceARNList: Optional[ResourceARNListForGet] + PaginationToken: PaginationToken | None + TagFilters: TagFilterList | None + ResourcesPerPage: ResourcesPerPage | None + TagsPerPage: TagsPerPage | None + ResourceTypeFilters: ResourceTypeFilterList | None + IncludeComplianceDetails: IncludeComplianceDetails | None + ExcludeCompliantResources: ExcludeCompliantResources | None + ResourceARNList: ResourceARNListForGet | None class Tag(TypedDict, total=False): @@ -169,46 +173,68 @@ class Tag(TypedDict, total=False): Value: TagValue -TagList = List[Tag] +TagList = list[Tag] class ResourceTagMapping(TypedDict, total=False): - ResourceARN: Optional[ResourceARN] - Tags: Optional[TagList] - ComplianceDetails: Optional[ComplianceDetails] + ResourceARN: ResourceARN | None + Tags: TagList | None + ComplianceDetails: ComplianceDetails | None -ResourceTagMappingList = List[ResourceTagMapping] +ResourceTagMappingList = list[ResourceTagMapping] class GetResourcesOutput(TypedDict, total=False): - PaginationToken: Optional[PaginationToken] - ResourceTagMappingList: Optional[ResourceTagMappingList] + PaginationToken: PaginationToken | None + ResourceTagMappingList: ResourceTagMappingList | None class GetTagKeysInput(ServiceRequest): - PaginationToken: Optional[PaginationToken] + PaginationToken: PaginationToken | None class GetTagKeysOutput(TypedDict, total=False): - PaginationToken: Optional[PaginationToken] - TagKeys: Optional[TagKeyList] + PaginationToken: PaginationToken | None + TagKeys: TagKeyList | None class GetTagValuesInput(ServiceRequest): - PaginationToken: Optional[PaginationToken] + PaginationToken: PaginationToken | None Key: TagKey -TagValuesOutputList = List[TagValue] +TagValuesOutputList = list[TagValue] class GetTagValuesOutput(TypedDict, total=False): - PaginationToken: Optional[PaginationToken] - TagValues: Optional[TagValuesOutputList] + PaginationToken: PaginationToken | None + TagValues: TagValuesOutputList | None -ResourceARNListForTagUntag = List[ResourceARN] +class ListRequiredTagsInput(ServiceRequest): + NextToken: PaginationToken | None + MaxResults: MaxResultsForListRequiredTags | None + + +ReportingTagKeys = list[TagKey] + + +class RequiredTag(TypedDict, total=False): + ResourceType: ResourceType | None + CloudFormationResourceTypes: CloudFormationResourceTypes | None + ReportingTagKeys: ReportingTagKeys | None + + +RequiredTagsForListRequiredTags = list[RequiredTag] + + +class ListRequiredTagsOutput(TypedDict, total=False): + RequiredTags: RequiredTagsForListRequiredTags | None + NextToken: PaginationToken | None + + +ResourceARNListForTagUntag = list[ResourceARN] class StartReportCreationInput(ServiceRequest): @@ -219,8 +245,8 @@ class StartReportCreationOutput(TypedDict, total=False): pass -TagKeyListForUntag = List[TagKey] -TagMap = Dict[TagKey, TagValue] +TagKeyListForUntag = list[TagKey] +TagMap = dict[TagKey, TagValue] class TagResourcesInput(ServiceRequest): @@ -229,7 +255,7 @@ class TagResourcesInput(ServiceRequest): class TagResourcesOutput(TypedDict, total=False): - FailedResourcesMap: Optional[FailedResourcesMap] + FailedResourcesMap: FailedResourcesMap | None class UntagResourcesInput(ServiceRequest): @@ -238,12 +264,12 @@ class UntagResourcesInput(ServiceRequest): class UntagResourcesOutput(TypedDict, total=False): - FailedResourcesMap: Optional[FailedResourcesMap] + FailedResourcesMap: FailedResourcesMap | None class ResourcegroupstaggingapiApi: - service = "resourcegroupstaggingapi" - version = "2017-01-26" + service: str = "resourcegroupstaggingapi" + version: str = "2017-01-26" @handler("DescribeReportCreation") def describe_report_creation( @@ -298,6 +324,16 @@ def get_tag_values( ) -> GetTagValuesOutput: raise NotImplementedError + @handler("ListRequiredTags") + def list_required_tags( + self, + context: RequestContext, + next_token: PaginationToken | None = None, + max_results: MaxResultsForListRequiredTags | None = None, + **kwargs, + ) -> ListRequiredTagsOutput: + raise NotImplementedError + @handler("StartReportCreation") def start_report_creation( self, context: RequestContext, s3_bucket: S3Bucket, **kwargs diff --git a/localstack-core/localstack/aws/api/route53/__init__.py b/localstack-core/localstack/aws/api/route53/__init__.py index 2c1f6ee9d5ad5..f00029280b2e6 100644 --- a/localstack-core/localstack/aws/api/route53/__init__.py +++ b/localstack-core/localstack/aws/api/route53/__init__.py @@ -1,12 +1,13 @@ from datetime import datetime from enum import StrEnum -from typing import List, Optional, TypedDict +from typing import TypedDict from localstack.aws.api import RequestContext, ServiceException, ServiceRequest, handler ARN = str AWSAccountID = str AWSRegion = str +AcceleratedRecoveryEnabled = bool AlarmName = str AliasHealthEnabled = bool AssociateVPCComment = str @@ -26,6 +27,7 @@ EnableSNI = bool ErrorMessage = str EvaluationPeriods = int +FailureReason = str FailureThreshold = int FullyQualifiedDomainName = str GeoLocationContinentCode = str @@ -98,6 +100,17 @@ VPCId = str +class AcceleratedRecoveryStatus(StrEnum): + ENABLING = "ENABLING" + ENABLE_FAILED = "ENABLE_FAILED" + ENABLING_HOSTED_ZONE_LOCKED = "ENABLING_HOSTED_ZONE_LOCKED" + ENABLED = "ENABLED" + DISABLING = "DISABLING" + DISABLE_FAILED = "DISABLE_FAILED" + DISABLED = "DISABLED" + DISABLING_HOSTED_ZONE_LOCKED = "DISABLING_HOSTED_ZONE_LOCKED" + + class AccountLimitType(StrEnum): MAX_HEALTH_CHECKS_BY_OWNER = "MAX_HEALTH_CHECKS_BY_OWNER" MAX_HOSTED_ZONES_BY_OWNER = "MAX_HOSTED_ZONES_BY_OWNER" @@ -167,6 +180,8 @@ class CloudWatchRegion(StrEnum): ap_east_2 = "ap-east-2" eu_isoe_west_1 = "eu-isoe-west-1" ap_southeast_6 = "ap-southeast-6" + us_isob_west_1 = "us-isob-west-1" + eusc_de_east_1 = "eusc-de-east-1" class ComparisonOperator(StrEnum): @@ -284,6 +299,7 @@ class ResourceRecordSetRegion(StrEnum): us_gov_west_1 = "us-gov-west-1" ap_east_2 = "ap-east-2" ap_southeast_6 = "ap-southeast-6" + eusc_de_east_1 = "eusc-de-east-1" class ReusableDelegationSetLimitType(StrEnum): @@ -348,6 +364,8 @@ class VPCRegion(StrEnum): ap_east_2 = "ap-east-2" eu_isoe_west_1 = "eu-isoe-west-1" ap_southeast_6 = "ap-southeast-6" + us_isob_west_1 = "us-isob-west-1" + eusc_de_east_1 = "eusc-de-east-1" class CidrBlockInUseException(ServiceException): @@ -494,14 +512,14 @@ class InvalidArgument(ServiceException): status_code: int = 400 -ErrorMessages = List[ErrorMessage] +ErrorMessages = list[ErrorMessage] class InvalidChangeBatch(ServiceException): code: str = "InvalidChangeBatch" sender_fault: bool = False status_code: int = 400 - messages: Optional[ErrorMessages] + messages: ErrorMessages | None class InvalidDomainName(ServiceException): @@ -788,7 +806,7 @@ class ChangeInfo(TypedDict, total=False): Id: ResourceId Status: ChangeStatus SubmittedAt: TimeStamp - Comment: Optional[ResourceDescription] + Comment: ResourceDescription | None class ActivateKeySigningKeyResponse(TypedDict, total=False): @@ -807,14 +825,14 @@ class AliasTarget(TypedDict, total=False): class VPC(TypedDict, total=False): - VPCRegion: Optional[VPCRegion] - VPCId: Optional[VPCId] + VPCRegion: VPCRegion | None + VPCId: VPCId | None class AssociateVPCWithHostedZoneRequest(ServiceRequest): HostedZoneId: ResourceId VPC: VPC - Comment: Optional[AssociateVPCComment] + Comment: AssociateVPCComment | None class AssociateVPCWithHostedZoneResponse(TypedDict, total=False): @@ -827,10 +845,10 @@ class Coordinates(TypedDict, total=False): class GeoProximityLocation(TypedDict, total=False): - AWSRegion: Optional[AWSRegion] - LocalZoneGroup: Optional[LocalZoneGroup] - Coordinates: Optional[Coordinates] - Bias: Optional[Bias] + AWSRegion: AWSRegion | None + LocalZoneGroup: LocalZoneGroup | None + Coordinates: Coordinates | None + Bias: Bias | None class CidrRoutingConfig(TypedDict, total=False): @@ -842,14 +860,14 @@ class ResourceRecord(TypedDict, total=False): Value: RData -ResourceRecords = List[ResourceRecord] +ResourceRecords = list[ResourceRecord] TTL = int class GeoLocation(TypedDict, total=False): - ContinentCode: Optional[GeoLocationContinentCode] - CountryCode: Optional[GeoLocationCountryCode] - SubdivisionCode: Optional[GeoLocationSubdivisionCode] + ContinentCode: GeoLocationContinentCode | None + CountryCode: GeoLocationCountryCode | None + SubdivisionCode: GeoLocationSubdivisionCode | None ResourceRecordSetWeight = int @@ -858,19 +876,19 @@ class GeoLocation(TypedDict, total=False): class ResourceRecordSet(TypedDict, total=False): Name: DNSName Type: RRType - SetIdentifier: Optional[ResourceRecordSetIdentifier] - Weight: Optional[ResourceRecordSetWeight] - Region: Optional[ResourceRecordSetRegion] - GeoLocation: Optional[GeoLocation] - Failover: Optional[ResourceRecordSetFailover] - MultiValueAnswer: Optional[ResourceRecordSetMultiValueAnswer] - TTL: Optional[TTL] - ResourceRecords: Optional[ResourceRecords] - AliasTarget: Optional[AliasTarget] - HealthCheckId: Optional[HealthCheckId] - TrafficPolicyInstanceId: Optional[TrafficPolicyInstanceId] - CidrRoutingConfig: Optional[CidrRoutingConfig] - GeoProximityLocation: Optional[GeoProximityLocation] + SetIdentifier: ResourceRecordSetIdentifier | None + Weight: ResourceRecordSetWeight | None + Region: ResourceRecordSetRegion | None + GeoLocation: GeoLocation | None + Failover: ResourceRecordSetFailover | None + MultiValueAnswer: ResourceRecordSetMultiValueAnswer | None + TTL: TTL | None + ResourceRecords: ResourceRecords | None + AliasTarget: AliasTarget | None + HealthCheckId: HealthCheckId | None + TrafficPolicyInstanceId: TrafficPolicyInstanceId | None + CidrRoutingConfig: CidrRoutingConfig | None + GeoProximityLocation: GeoProximityLocation | None class Change(TypedDict, total=False): @@ -878,15 +896,15 @@ class Change(TypedDict, total=False): ResourceRecordSet: ResourceRecordSet -Changes = List[Change] +Changes = list[Change] class ChangeBatch(TypedDict, total=False): - Comment: Optional[ResourceDescription] + Comment: ResourceDescription | None Changes: Changes -CidrList = List[Cidr] +CidrList = list[Cidr] class CidrCollectionChange(TypedDict, total=False): @@ -895,13 +913,13 @@ class CidrCollectionChange(TypedDict, total=False): CidrList: CidrList -CidrCollectionChanges = List[CidrCollectionChange] +CidrCollectionChanges = list[CidrCollectionChange] CollectionVersion = int class ChangeCidrCollectionRequest(ServiceRequest): Id: UUID - CollectionVersion: Optional[CollectionVersion] + CollectionVersion: CollectionVersion | None Changes: CidrCollectionChanges @@ -918,45 +936,45 @@ class ChangeResourceRecordSetsResponse(TypedDict, total=False): ChangeInfo: ChangeInfo -TagKeyList = List[TagKey] +TagKeyList = list[TagKey] class Tag(TypedDict, total=False): - Key: Optional[TagKey] - Value: Optional[TagValue] + Key: TagKey | None + Value: TagValue | None -TagList = List[Tag] +TagList = list[Tag] class ChangeTagsForResourceRequest(ServiceRequest): ResourceType: TagResourceType ResourceId: TagResourceId - AddTags: Optional[TagList] - RemoveTagKeys: Optional[TagKeyList] + AddTags: TagList | None + RemoveTagKeys: TagKeyList | None class ChangeTagsForResourceResponse(TypedDict, total=False): pass -CheckerIpRanges = List[IPAddressCidr] -ChildHealthCheckList = List[HealthCheckId] +CheckerIpRanges = list[IPAddressCidr] +ChildHealthCheckList = list[HealthCheckId] class CidrBlockSummary(TypedDict, total=False): - CidrBlock: Optional[Cidr] - LocationName: Optional[CidrLocationNameDefaultNotAllowed] + CidrBlock: Cidr | None + LocationName: CidrLocationNameDefaultNotAllowed | None -CidrBlockSummaries = List[CidrBlockSummary] +CidrBlockSummaries = list[CidrBlockSummary] class CidrCollection(TypedDict, total=False): - Arn: Optional[ARN] - Id: Optional[UUID] - Name: Optional[CollectionName] - Version: Optional[CollectionVersion] + Arn: ARN | None + Id: UUID | None + Name: CollectionName | None + Version: CollectionVersion | None class Dimension(TypedDict, total=False): @@ -964,7 +982,7 @@ class Dimension(TypedDict, total=False): Value: DimensionField -DimensionList = List[Dimension] +DimensionList = list[Dimension] class CloudWatchAlarmConfiguration(TypedDict, total=False): @@ -975,17 +993,17 @@ class CloudWatchAlarmConfiguration(TypedDict, total=False): MetricName: MetricName Namespace: Namespace Statistic: Statistic - Dimensions: Optional[DimensionList] + Dimensions: DimensionList | None class CollectionSummary(TypedDict, total=False): - Arn: Optional[ARN] - Id: Optional[UUID] - Name: Optional[CollectionName] - Version: Optional[CollectionVersion] + Arn: ARN | None + Id: UUID | None + Name: CollectionName | None + Version: CollectionVersion | None -CollectionSummaries = List[CollectionSummary] +CollectionSummaries = list[CollectionSummary] class CreateCidrCollectionRequest(ServiceRequest): @@ -994,32 +1012,32 @@ class CreateCidrCollectionRequest(ServiceRequest): class CreateCidrCollectionResponse(TypedDict, total=False): - Collection: Optional[CidrCollection] - Location: Optional[ResourceURI] + Collection: CidrCollection | None + Location: ResourceURI | None -HealthCheckRegionList = List[HealthCheckRegion] +HealthCheckRegionList = list[HealthCheckRegion] class HealthCheckConfig(TypedDict, total=False): - IPAddress: Optional[IPAddress] - Port: Optional[Port] + IPAddress: IPAddress | None + Port: Port | None Type: HealthCheckType - ResourcePath: Optional[ResourcePath] - FullyQualifiedDomainName: Optional[FullyQualifiedDomainName] - SearchString: Optional[SearchString] - RequestInterval: Optional[RequestInterval] - FailureThreshold: Optional[FailureThreshold] - MeasureLatency: Optional[MeasureLatency] - Inverted: Optional[Inverted] - Disabled: Optional[Disabled] - HealthThreshold: Optional[HealthThreshold] - ChildHealthChecks: Optional[ChildHealthCheckList] - EnableSNI: Optional[EnableSNI] - Regions: Optional[HealthCheckRegionList] - AlarmIdentifier: Optional[AlarmIdentifier] - InsufficientDataHealthStatus: Optional[InsufficientDataHealthStatus] - RoutingControlArn: Optional[RoutingControlArn] + ResourcePath: ResourcePath | None + FullyQualifiedDomainName: FullyQualifiedDomainName | None + SearchString: SearchString | None + RequestInterval: RequestInterval | None + FailureThreshold: FailureThreshold | None + MeasureLatency: MeasureLatency | None + Inverted: Inverted | None + Disabled: Disabled | None + HealthThreshold: HealthThreshold | None + ChildHealthChecks: ChildHealthCheckList | None + EnableSNI: EnableSNI | None + Regions: HealthCheckRegionList | None + AlarmIdentifier: AlarmIdentifier | None + InsufficientDataHealthStatus: InsufficientDataHealthStatus | None + RoutingControlArn: RoutingControlArn | None class CreateHealthCheckRequest(ServiceRequest): @@ -1031,17 +1049,17 @@ class CreateHealthCheckRequest(ServiceRequest): class LinkedService(TypedDict, total=False): - ServicePrincipal: Optional[ServicePrincipal] - Description: Optional[ResourceDescription] + ServicePrincipal: ServicePrincipal | None + Description: ResourceDescription | None class HealthCheck(TypedDict, total=False): Id: HealthCheckId CallerReference: HealthCheckNonce - LinkedService: Optional[LinkedService] + LinkedService: LinkedService | None HealthCheckConfig: HealthCheckConfig HealthCheckVersion: HealthCheckVersion - CloudWatchAlarmConfiguration: Optional[CloudWatchAlarmConfiguration] + CloudWatchAlarmConfiguration: CloudWatchAlarmConfiguration | None class CreateHealthCheckResponse(TypedDict, total=False): @@ -1050,27 +1068,36 @@ class CreateHealthCheckResponse(TypedDict, total=False): class HostedZoneConfig(TypedDict, total=False): - Comment: Optional[ResourceDescription] - PrivateZone: Optional[IsPrivateZone] + Comment: ResourceDescription | None + PrivateZone: IsPrivateZone | None class CreateHostedZoneRequest(ServiceRequest): Name: DNSName - VPC: Optional[VPC] + VPC: VPC | None CallerReference: Nonce - HostedZoneConfig: Optional[HostedZoneConfig] - DelegationSetId: Optional[ResourceId] + HostedZoneConfig: HostedZoneConfig | None + DelegationSetId: ResourceId | None -DelegationSetNameServers = List[DNSName] +DelegationSetNameServers = list[DNSName] class DelegationSet(TypedDict, total=False): - Id: Optional[ResourceId] - CallerReference: Optional[Nonce] + Id: ResourceId | None + CallerReference: Nonce | None NameServers: DelegationSetNameServers +class HostedZoneFailureReasons(TypedDict, total=False): + AcceleratedRecovery: FailureReason | None + + +class HostedZoneFeatures(TypedDict, total=False): + AcceleratedRecoveryStatus: AcceleratedRecoveryStatus | None + FailureReasons: HostedZoneFailureReasons | None + + HostedZoneRRSetCount = int @@ -1078,16 +1105,17 @@ class HostedZone(TypedDict, total=False): Id: ResourceId Name: DNSName CallerReference: Nonce - Config: Optional[HostedZoneConfig] - ResourceRecordSetCount: Optional[HostedZoneRRSetCount] - LinkedService: Optional[LinkedService] + Config: HostedZoneConfig | None + ResourceRecordSetCount: HostedZoneRRSetCount | None + LinkedService: LinkedService | None + Features: HostedZoneFeatures | None class CreateHostedZoneResponse(TypedDict, total=False): HostedZone: HostedZone ChangeInfo: ChangeInfo DelegationSet: DelegationSet - VPC: Optional[VPC] + VPC: VPC | None Location: ResourceURI @@ -1100,22 +1128,22 @@ class CreateKeySigningKeyRequest(ServiceRequest): class KeySigningKey(TypedDict, total=False): - Name: Optional[SigningKeyName] - KmsArn: Optional[SigningKeyString] - Flag: Optional[SigningKeyInteger] - SigningAlgorithmMnemonic: Optional[SigningKeyString] - SigningAlgorithmType: Optional[SigningKeyInteger] - DigestAlgorithmMnemonic: Optional[SigningKeyString] - DigestAlgorithmType: Optional[SigningKeyInteger] - KeyTag: Optional[SigningKeyTag] - DigestValue: Optional[SigningKeyString] - PublicKey: Optional[SigningKeyString] - DSRecord: Optional[SigningKeyString] - DNSKEYRecord: Optional[SigningKeyString] - Status: Optional[SigningKeyStatus] - StatusMessage: Optional[SigningKeyStatusMessage] - CreatedDate: Optional[TimeStamp] - LastModifiedDate: Optional[TimeStamp] + Name: SigningKeyName | None + KmsArn: SigningKeyString | None + Flag: SigningKeyInteger | None + SigningAlgorithmMnemonic: SigningKeyString | None + SigningAlgorithmType: SigningKeyInteger | None + DigestAlgorithmMnemonic: SigningKeyString | None + DigestAlgorithmType: SigningKeyInteger | None + KeyTag: SigningKeyTag | None + DigestValue: SigningKeyString | None + PublicKey: SigningKeyString | None + DSRecord: SigningKeyString | None + DNSKEYRecord: SigningKeyString | None + Status: SigningKeyStatus | None + StatusMessage: SigningKeyStatusMessage | None + CreatedDate: TimeStamp | None + LastModifiedDate: TimeStamp | None class CreateKeySigningKeyResponse(TypedDict, total=False): @@ -1142,7 +1170,7 @@ class CreateQueryLoggingConfigResponse(TypedDict, total=False): class CreateReusableDelegationSetRequest(ServiceRequest): CallerReference: Nonce - HostedZoneId: Optional[ResourceId] + HostedZoneId: ResourceId | None class CreateReusableDelegationSetResponse(TypedDict, total=False): @@ -1178,7 +1206,7 @@ class CreateTrafficPolicyInstanceResponse(TypedDict, total=False): class CreateTrafficPolicyRequest(ServiceRequest): Name: TrafficPolicyName Document: TrafficPolicyDocument - Comment: Optional[TrafficPolicyComment] + Comment: TrafficPolicyComment | None class TrafficPolicy(TypedDict, total=False): @@ -1187,7 +1215,7 @@ class TrafficPolicy(TypedDict, total=False): Name: TrafficPolicyName Type: RRType Document: TrafficPolicyDocument - Comment: Optional[TrafficPolicyComment] + Comment: TrafficPolicyComment | None class CreateTrafficPolicyResponse(TypedDict, total=False): @@ -1198,7 +1226,7 @@ class CreateTrafficPolicyResponse(TypedDict, total=False): class CreateTrafficPolicyVersionRequest(ServiceRequest): Id: TrafficPolicyId Document: TrafficPolicyDocument - Comment: Optional[TrafficPolicyComment] + Comment: TrafficPolicyComment | None class CreateTrafficPolicyVersionResponse(TypedDict, total=False): @@ -1217,8 +1245,8 @@ class CreateVPCAssociationAuthorizationResponse(TypedDict, total=False): class DNSSECStatus(TypedDict, total=False): - ServeSignature: Optional[ServeSignature] - StatusMessage: Optional[SigningKeyStatusMessage] + ServeSignature: ServeSignature | None + StatusMessage: SigningKeyStatusMessage | None class DeactivateKeySigningKeyRequest(ServiceRequest): @@ -1230,7 +1258,7 @@ class DeactivateKeySigningKeyResponse(TypedDict, total=False): ChangeInfo: ChangeInfo -DelegationSets = List[DelegationSet] +DelegationSets = list[DelegationSet] class DeleteCidrCollectionRequest(ServiceRequest): @@ -1319,7 +1347,7 @@ class DisableHostedZoneDNSSECResponse(TypedDict, total=False): class DisassociateVPCFromHostedZoneRequest(ServiceRequest): HostedZoneId: ResourceId VPC: VPC - Comment: Optional[DisassociateVPCComment] + Comment: DisassociateVPCComment | None class DisassociateVPCFromHostedZoneResponse(TypedDict, total=False): @@ -1335,15 +1363,15 @@ class EnableHostedZoneDNSSECResponse(TypedDict, total=False): class GeoLocationDetails(TypedDict, total=False): - ContinentCode: Optional[GeoLocationContinentCode] - ContinentName: Optional[GeoLocationContinentName] - CountryCode: Optional[GeoLocationCountryCode] - CountryName: Optional[GeoLocationCountryName] - SubdivisionCode: Optional[GeoLocationSubdivisionCode] - SubdivisionName: Optional[GeoLocationSubdivisionName] + ContinentCode: GeoLocationContinentCode | None + ContinentName: GeoLocationContinentName | None + CountryCode: GeoLocationCountryCode | None + CountryName: GeoLocationCountryName | None + SubdivisionCode: GeoLocationSubdivisionCode | None + SubdivisionName: GeoLocationSubdivisionName | None -GeoLocationDetailsList = List[GeoLocationDetails] +GeoLocationDetailsList = list[GeoLocationDetails] class GetAccountLimitRequest(ServiceRequest): @@ -1378,7 +1406,7 @@ class GetDNSSECRequest(ServiceRequest): HostedZoneId: ResourceId -KeySigningKeys = List[KeySigningKey] +KeySigningKeys = list[KeySigningKey] class GetDNSSECResponse(TypedDict, total=False): @@ -1387,9 +1415,9 @@ class GetDNSSECResponse(TypedDict, total=False): class GetGeoLocationRequest(ServiceRequest): - ContinentCode: Optional[GeoLocationContinentCode] - CountryCode: Optional[GeoLocationCountryCode] - SubdivisionCode: Optional[GeoLocationSubdivisionCode] + ContinentCode: GeoLocationContinentCode | None + CountryCode: GeoLocationCountryCode | None + SubdivisionCode: GeoLocationSubdivisionCode | None class GetGeoLocationResponse(TypedDict, total=False): @@ -1412,17 +1440,17 @@ class GetHealthCheckLastFailureReasonRequest(ServiceRequest): class StatusReport(TypedDict, total=False): - Status: Optional[Status] - CheckedTime: Optional[TimeStamp] + Status: Status | None + CheckedTime: TimeStamp | None class HealthCheckObservation(TypedDict, total=False): - Region: Optional[HealthCheckRegion] - IPAddress: Optional[IPAddress] - StatusReport: Optional[StatusReport] + Region: HealthCheckRegion | None + IPAddress: IPAddress | None + StatusReport: StatusReport | None -HealthCheckObservations = List[HealthCheckObservation] +HealthCheckObservations = list[HealthCheckObservation] class GetHealthCheckLastFailureReasonResponse(TypedDict, total=False): @@ -1475,13 +1503,13 @@ class GetHostedZoneRequest(ServiceRequest): Id: ResourceId -VPCs = List[VPC] +VPCs = list[VPC] class GetHostedZoneResponse(TypedDict, total=False): HostedZone: HostedZone - DelegationSet: Optional[DelegationSet] - VPCs: Optional[VPCs] + DelegationSet: DelegationSet | None + VPCs: VPCs | None class GetQueryLoggingConfigRequest(ServiceRequest): @@ -1540,12 +1568,12 @@ class GetTrafficPolicyResponse(TypedDict, total=False): TrafficPolicy: TrafficPolicy -HealthChecks = List[HealthCheck] +HealthChecks = list[HealthCheck] class HostedZoneOwner(TypedDict, total=False): - OwningAccount: Optional[AWSAccountID] - OwningService: Optional[HostedZoneOwningService] + OwningAccount: AWSAccountID | None + OwningService: HostedZoneOwningService | None class HostedZoneSummary(TypedDict, total=False): @@ -1554,167 +1582,167 @@ class HostedZoneSummary(TypedDict, total=False): Owner: HostedZoneOwner -HostedZoneSummaries = List[HostedZoneSummary] -HostedZones = List[HostedZone] +HostedZoneSummaries = list[HostedZoneSummary] +HostedZones = list[HostedZone] class ListCidrBlocksRequest(ServiceRequest): CollectionId: UUID - LocationName: Optional[CidrLocationNameDefaultNotAllowed] - NextToken: Optional[PaginationToken] - MaxResults: Optional[MaxResults] + LocationName: CidrLocationNameDefaultNotAllowed | None + NextToken: PaginationToken | None + MaxResults: MaxResults | None class ListCidrBlocksResponse(TypedDict, total=False): - NextToken: Optional[PaginationToken] - CidrBlocks: Optional[CidrBlockSummaries] + NextToken: PaginationToken | None + CidrBlocks: CidrBlockSummaries | None class ListCidrCollectionsRequest(ServiceRequest): - NextToken: Optional[PaginationToken] - MaxResults: Optional[MaxResults] + NextToken: PaginationToken | None + MaxResults: MaxResults | None class ListCidrCollectionsResponse(TypedDict, total=False): - NextToken: Optional[PaginationToken] - CidrCollections: Optional[CollectionSummaries] + NextToken: PaginationToken | None + CidrCollections: CollectionSummaries | None class ListCidrLocationsRequest(ServiceRequest): CollectionId: UUID - NextToken: Optional[PaginationToken] - MaxResults: Optional[MaxResults] + NextToken: PaginationToken | None + MaxResults: MaxResults | None class LocationSummary(TypedDict, total=False): - LocationName: Optional[CidrLocationNameDefaultAllowed] + LocationName: CidrLocationNameDefaultAllowed | None -LocationSummaries = List[LocationSummary] +LocationSummaries = list[LocationSummary] class ListCidrLocationsResponse(TypedDict, total=False): - NextToken: Optional[PaginationToken] - CidrLocations: Optional[LocationSummaries] + NextToken: PaginationToken | None + CidrLocations: LocationSummaries | None class ListGeoLocationsRequest(ServiceRequest): - StartContinentCode: Optional[GeoLocationContinentCode] - StartCountryCode: Optional[GeoLocationCountryCode] - StartSubdivisionCode: Optional[GeoLocationSubdivisionCode] - MaxItems: Optional[PageMaxItems] + StartContinentCode: GeoLocationContinentCode | None + StartCountryCode: GeoLocationCountryCode | None + StartSubdivisionCode: GeoLocationSubdivisionCode | None + MaxItems: PageMaxItems | None class ListGeoLocationsResponse(TypedDict, total=False): GeoLocationDetailsList: GeoLocationDetailsList IsTruncated: PageTruncated - NextContinentCode: Optional[GeoLocationContinentCode] - NextCountryCode: Optional[GeoLocationCountryCode] - NextSubdivisionCode: Optional[GeoLocationSubdivisionCode] + NextContinentCode: GeoLocationContinentCode | None + NextCountryCode: GeoLocationCountryCode | None + NextSubdivisionCode: GeoLocationSubdivisionCode | None MaxItems: PageMaxItems class ListHealthChecksRequest(ServiceRequest): - Marker: Optional[PageMarker] - MaxItems: Optional[PageMaxItems] + Marker: PageMarker | None + MaxItems: PageMaxItems | None class ListHealthChecksResponse(TypedDict, total=False): HealthChecks: HealthChecks Marker: PageMarker IsTruncated: PageTruncated - NextMarker: Optional[PageMarker] + NextMarker: PageMarker | None MaxItems: PageMaxItems class ListHostedZonesByNameRequest(ServiceRequest): - DNSName: Optional[DNSName] - HostedZoneId: Optional[ResourceId] - MaxItems: Optional[PageMaxItems] + DNSName: DNSName | None + HostedZoneId: ResourceId | None + MaxItems: PageMaxItems | None class ListHostedZonesByNameResponse(TypedDict, total=False): HostedZones: HostedZones - DNSName: Optional[DNSName] - HostedZoneId: Optional[ResourceId] + DNSName: DNSName | None + HostedZoneId: ResourceId | None IsTruncated: PageTruncated - NextDNSName: Optional[DNSName] - NextHostedZoneId: Optional[ResourceId] + NextDNSName: DNSName | None + NextHostedZoneId: ResourceId | None MaxItems: PageMaxItems class ListHostedZonesByVPCRequest(ServiceRequest): VPCId: VPCId VPCRegion: VPCRegion - MaxItems: Optional[PageMaxItems] - NextToken: Optional[PaginationToken] + MaxItems: PageMaxItems | None + NextToken: PaginationToken | None class ListHostedZonesByVPCResponse(TypedDict, total=False): HostedZoneSummaries: HostedZoneSummaries MaxItems: PageMaxItems - NextToken: Optional[PaginationToken] + NextToken: PaginationToken | None class ListHostedZonesRequest(ServiceRequest): - Marker: Optional[PageMarker] - MaxItems: Optional[PageMaxItems] - DelegationSetId: Optional[ResourceId] - HostedZoneType: Optional[HostedZoneType] + Marker: PageMarker | None + MaxItems: PageMaxItems | None + DelegationSetId: ResourceId | None + HostedZoneType: HostedZoneType | None class ListHostedZonesResponse(TypedDict, total=False): HostedZones: HostedZones Marker: PageMarker IsTruncated: PageTruncated - NextMarker: Optional[PageMarker] + NextMarker: PageMarker | None MaxItems: PageMaxItems class ListQueryLoggingConfigsRequest(ServiceRequest): - HostedZoneId: Optional[ResourceId] - NextToken: Optional[PaginationToken] - MaxResults: Optional[MaxResults] + HostedZoneId: ResourceId | None + NextToken: PaginationToken | None + MaxResults: MaxResults | None -QueryLoggingConfigs = List[QueryLoggingConfig] +QueryLoggingConfigs = list[QueryLoggingConfig] class ListQueryLoggingConfigsResponse(TypedDict, total=False): QueryLoggingConfigs: QueryLoggingConfigs - NextToken: Optional[PaginationToken] + NextToken: PaginationToken | None class ListResourceRecordSetsRequest(ServiceRequest): HostedZoneId: ResourceId - StartRecordName: Optional[DNSName] - StartRecordType: Optional[RRType] - StartRecordIdentifier: Optional[ResourceRecordSetIdentifier] - MaxItems: Optional[PageMaxItems] + StartRecordName: DNSName | None + StartRecordType: RRType | None + StartRecordIdentifier: ResourceRecordSetIdentifier | None + MaxItems: PageMaxItems | None -ResourceRecordSets = List[ResourceRecordSet] +ResourceRecordSets = list[ResourceRecordSet] class ListResourceRecordSetsResponse(TypedDict, total=False): ResourceRecordSets: ResourceRecordSets IsTruncated: PageTruncated - NextRecordName: Optional[DNSName] - NextRecordType: Optional[RRType] - NextRecordIdentifier: Optional[ResourceRecordSetIdentifier] + NextRecordName: DNSName | None + NextRecordType: RRType | None + NextRecordIdentifier: ResourceRecordSetIdentifier | None MaxItems: PageMaxItems class ListReusableDelegationSetsRequest(ServiceRequest): - Marker: Optional[PageMarker] - MaxItems: Optional[PageMaxItems] + Marker: PageMarker | None + MaxItems: PageMaxItems | None class ListReusableDelegationSetsResponse(TypedDict, total=False): DelegationSets: DelegationSets Marker: PageMarker IsTruncated: PageTruncated - NextMarker: Optional[PageMarker] + NextMarker: PageMarker | None MaxItems: PageMaxItems @@ -1724,16 +1752,16 @@ class ListTagsForResourceRequest(ServiceRequest): class ResourceTagSet(TypedDict, total=False): - ResourceType: Optional[TagResourceType] - ResourceId: Optional[TagResourceId] - Tags: Optional[TagList] + ResourceType: TagResourceType | None + ResourceId: TagResourceId | None + Tags: TagList | None class ListTagsForResourceResponse(TypedDict, total=False): ResourceTagSet: ResourceTagSet -TagResourceIdList = List[TagResourceId] +TagResourceIdList = list[TagResourceId] class ListTagsForResourcesRequest(ServiceRequest): @@ -1741,7 +1769,7 @@ class ListTagsForResourcesRequest(ServiceRequest): ResourceIds: TagResourceIdList -ResourceTagSetList = List[ResourceTagSet] +ResourceTagSetList = list[ResourceTagSet] class ListTagsForResourcesResponse(TypedDict, total=False): @@ -1749,8 +1777,8 @@ class ListTagsForResourcesResponse(TypedDict, total=False): class ListTrafficPoliciesRequest(ServiceRequest): - TrafficPolicyIdMarker: Optional[TrafficPolicyId] - MaxItems: Optional[PageMaxItems] + TrafficPolicyIdMarker: TrafficPolicyId | None + MaxItems: PageMaxItems | None class TrafficPolicySummary(TypedDict, total=False): @@ -1761,7 +1789,7 @@ class TrafficPolicySummary(TypedDict, total=False): TrafficPolicyCount: TrafficPolicyVersion -TrafficPolicySummaries = List[TrafficPolicySummary] +TrafficPolicySummaries = list[TrafficPolicySummary] class ListTrafficPoliciesResponse(TypedDict, total=False): @@ -1773,18 +1801,18 @@ class ListTrafficPoliciesResponse(TypedDict, total=False): class ListTrafficPolicyInstancesByHostedZoneRequest(ServiceRequest): HostedZoneId: ResourceId - TrafficPolicyInstanceNameMarker: Optional[DNSName] - TrafficPolicyInstanceTypeMarker: Optional[RRType] - MaxItems: Optional[PageMaxItems] + TrafficPolicyInstanceNameMarker: DNSName | None + TrafficPolicyInstanceTypeMarker: RRType | None + MaxItems: PageMaxItems | None -TrafficPolicyInstances = List[TrafficPolicyInstance] +TrafficPolicyInstances = list[TrafficPolicyInstance] class ListTrafficPolicyInstancesByHostedZoneResponse(TypedDict, total=False): TrafficPolicyInstances: TrafficPolicyInstances - TrafficPolicyInstanceNameMarker: Optional[DNSName] - TrafficPolicyInstanceTypeMarker: Optional[RRType] + TrafficPolicyInstanceNameMarker: DNSName | None + TrafficPolicyInstanceTypeMarker: RRType | None IsTruncated: PageTruncated MaxItems: PageMaxItems @@ -1792,44 +1820,44 @@ class ListTrafficPolicyInstancesByHostedZoneResponse(TypedDict, total=False): class ListTrafficPolicyInstancesByPolicyRequest(ServiceRequest): TrafficPolicyId: TrafficPolicyId TrafficPolicyVersion: TrafficPolicyVersion - HostedZoneIdMarker: Optional[ResourceId] - TrafficPolicyInstanceNameMarker: Optional[DNSName] - TrafficPolicyInstanceTypeMarker: Optional[RRType] - MaxItems: Optional[PageMaxItems] + HostedZoneIdMarker: ResourceId | None + TrafficPolicyInstanceNameMarker: DNSName | None + TrafficPolicyInstanceTypeMarker: RRType | None + MaxItems: PageMaxItems | None class ListTrafficPolicyInstancesByPolicyResponse(TypedDict, total=False): TrafficPolicyInstances: TrafficPolicyInstances - HostedZoneIdMarker: Optional[ResourceId] - TrafficPolicyInstanceNameMarker: Optional[DNSName] - TrafficPolicyInstanceTypeMarker: Optional[RRType] + HostedZoneIdMarker: ResourceId | None + TrafficPolicyInstanceNameMarker: DNSName | None + TrafficPolicyInstanceTypeMarker: RRType | None IsTruncated: PageTruncated MaxItems: PageMaxItems class ListTrafficPolicyInstancesRequest(ServiceRequest): - HostedZoneIdMarker: Optional[ResourceId] - TrafficPolicyInstanceNameMarker: Optional[DNSName] - TrafficPolicyInstanceTypeMarker: Optional[RRType] - MaxItems: Optional[PageMaxItems] + HostedZoneIdMarker: ResourceId | None + TrafficPolicyInstanceNameMarker: DNSName | None + TrafficPolicyInstanceTypeMarker: RRType | None + MaxItems: PageMaxItems | None class ListTrafficPolicyInstancesResponse(TypedDict, total=False): TrafficPolicyInstances: TrafficPolicyInstances - HostedZoneIdMarker: Optional[ResourceId] - TrafficPolicyInstanceNameMarker: Optional[DNSName] - TrafficPolicyInstanceTypeMarker: Optional[RRType] + HostedZoneIdMarker: ResourceId | None + TrafficPolicyInstanceNameMarker: DNSName | None + TrafficPolicyInstanceTypeMarker: RRType | None IsTruncated: PageTruncated MaxItems: PageMaxItems class ListTrafficPolicyVersionsRequest(ServiceRequest): Id: TrafficPolicyId - TrafficPolicyVersionMarker: Optional[TrafficPolicyVersionMarker] - MaxItems: Optional[PageMaxItems] + TrafficPolicyVersionMarker: TrafficPolicyVersionMarker | None + MaxItems: PageMaxItems | None -TrafficPolicies = List[TrafficPolicy] +TrafficPolicies = list[TrafficPolicy] class ListTrafficPolicyVersionsResponse(TypedDict, total=False): @@ -1841,27 +1869,27 @@ class ListTrafficPolicyVersionsResponse(TypedDict, total=False): class ListVPCAssociationAuthorizationsRequest(ServiceRequest): HostedZoneId: ResourceId - NextToken: Optional[PaginationToken] - MaxResults: Optional[MaxResults] + NextToken: PaginationToken | None + MaxResults: MaxResults | None class ListVPCAssociationAuthorizationsResponse(TypedDict, total=False): HostedZoneId: ResourceId - NextToken: Optional[PaginationToken] + NextToken: PaginationToken | None VPCs: VPCs -RecordData = List[RecordDataEntry] -ResettableElementNameList = List[ResettableElementName] +RecordData = list[RecordDataEntry] +ResettableElementNameList = list[ResettableElementName] class TestDNSAnswerRequest(ServiceRequest): HostedZoneId: ResourceId RecordName: DNSName RecordType: RRType - ResolverIP: Optional[IPAddress] - EDNS0ClientSubnetIP: Optional[IPAddress] - EDNS0ClientSubnetMask: Optional[SubnetMask] + ResolverIP: IPAddress | None + EDNS0ClientSubnetIP: IPAddress | None + EDNS0ClientSubnetMask: SubnetMask | None class TestDNSAnswerResponse(TypedDict, total=False): @@ -1875,22 +1903,22 @@ class TestDNSAnswerResponse(TypedDict, total=False): class UpdateHealthCheckRequest(ServiceRequest): HealthCheckId: HealthCheckId - HealthCheckVersion: Optional[HealthCheckVersion] - IPAddress: Optional[IPAddress] - Port: Optional[Port] - ResourcePath: Optional[ResourcePath] - FullyQualifiedDomainName: Optional[FullyQualifiedDomainName] - SearchString: Optional[SearchString] - FailureThreshold: Optional[FailureThreshold] - Inverted: Optional[Inverted] - Disabled: Optional[Disabled] - HealthThreshold: Optional[HealthThreshold] - ChildHealthChecks: Optional[ChildHealthCheckList] - EnableSNI: Optional[EnableSNI] - Regions: Optional[HealthCheckRegionList] - AlarmIdentifier: Optional[AlarmIdentifier] - InsufficientDataHealthStatus: Optional[InsufficientDataHealthStatus] - ResetElements: Optional[ResettableElementNameList] + HealthCheckVersion: HealthCheckVersion | None + IPAddress: IPAddress | None + Port: Port | None + ResourcePath: ResourcePath | None + FullyQualifiedDomainName: FullyQualifiedDomainName | None + SearchString: SearchString | None + FailureThreshold: FailureThreshold | None + Inverted: Inverted | None + Disabled: Disabled | None + HealthThreshold: HealthThreshold | None + ChildHealthChecks: ChildHealthCheckList | None + EnableSNI: EnableSNI | None + Regions: HealthCheckRegionList | None + AlarmIdentifier: AlarmIdentifier | None + InsufficientDataHealthStatus: InsufficientDataHealthStatus | None + ResetElements: ResettableElementNameList | None class UpdateHealthCheckResponse(TypedDict, total=False): @@ -1899,13 +1927,22 @@ class UpdateHealthCheckResponse(TypedDict, total=False): class UpdateHostedZoneCommentRequest(ServiceRequest): Id: ResourceId - Comment: Optional[ResourceDescription] + Comment: ResourceDescription | None class UpdateHostedZoneCommentResponse(TypedDict, total=False): HostedZone: HostedZone +class UpdateHostedZoneFeaturesRequest(ServiceRequest): + HostedZoneId: ResourceId + EnableAcceleratedRecovery: AcceleratedRecoveryEnabled | None + + +class UpdateHostedZoneFeaturesResponse(TypedDict, total=False): + pass + + class UpdateTrafficPolicyCommentRequest(ServiceRequest): Id: TrafficPolicyId Version: TrafficPolicyVersion @@ -1928,8 +1965,8 @@ class UpdateTrafficPolicyInstanceResponse(TypedDict, total=False): class Route53Api: - service = "route53" - version = "2013-04-01" + service: str = "route53" + version: str = "2013-04-01" @handler("ActivateKeySigningKey") def activate_key_signing_key( @@ -2541,6 +2578,16 @@ def update_hosted_zone_comment( ) -> UpdateHostedZoneCommentResponse: raise NotImplementedError + @handler("UpdateHostedZoneFeatures") + def update_hosted_zone_features( + self, + context: RequestContext, + hosted_zone_id: ResourceId, + enable_accelerated_recovery: AcceleratedRecoveryEnabled | None = None, + **kwargs, + ) -> UpdateHostedZoneFeaturesResponse: + raise NotImplementedError + @handler("UpdateTrafficPolicyComment") def update_traffic_policy_comment( self, diff --git a/localstack-core/localstack/aws/api/route53resolver/__init__.py b/localstack-core/localstack/aws/api/route53resolver/__init__.py index 35e718630ef4b..947399623f555 100644 --- a/localstack-core/localstack/aws/api/route53resolver/__init__.py +++ b/localstack-core/localstack/aws/api/route53resolver/__init__.py @@ -1,5 +1,5 @@ from enum import StrEnum -from typing import List, Optional, TypedDict +from typing import TypedDict from localstack.aws.api import RequestContext, ServiceException, ServiceRequest, handler @@ -42,6 +42,7 @@ ResolverRulePolicy = str ResourceId = str Rfc3339TimeString = str +RniEnhancedMetricsEnabled = bool ServerNameIndication = str ServicePrinciple = str SortByKey = str @@ -50,6 +51,7 @@ SubnetId = str TagKey = str TagValue = str +TargetNameServerMetricsEnabled = bool Unsigned = int @@ -84,6 +86,7 @@ class ConfidenceThreshold(StrEnum): class DnsThreatProtection(StrEnum): DGA = "DGA" DNS_TUNNELING = "DNS_TUNNELING" + DICTIONARY_DGA = "DICTIONARY_DGA" class FirewallDomainImportOperation(StrEnum): @@ -292,7 +295,7 @@ class InvalidParameterException(ServiceException): code: str = "InvalidParameterException" sender_fault: bool = False status_code: int = 400 - FieldName: Optional[String] + FieldName: String | None class InvalidPolicyDocument(ServiceException): @@ -317,35 +320,35 @@ class LimitExceededException(ServiceException): code: str = "LimitExceededException" sender_fault: bool = False status_code: int = 400 - ResourceType: Optional[String] + ResourceType: String | None class ResourceExistsException(ServiceException): code: str = "ResourceExistsException" sender_fault: bool = False status_code: int = 400 - ResourceType: Optional[String] + ResourceType: String | None class ResourceInUseException(ServiceException): code: str = "ResourceInUseException" sender_fault: bool = False status_code: int = 400 - ResourceType: Optional[String] + ResourceType: String | None class ResourceNotFoundException(ServiceException): code: str = "ResourceNotFoundException" sender_fault: bool = False status_code: int = 400 - ResourceType: Optional[String] + ResourceType: String | None class ResourceUnavailableException(ServiceException): code: str = "ResourceUnavailableException" sender_fault: bool = False status_code: int = 400 - ResourceType: Optional[String] + ResourceType: String | None class ServiceQuotaExceededException(ServiceException): @@ -377,7 +380,7 @@ class Tag(TypedDict, total=False): Value: TagValue -TagList = List[Tag] +TagList = list[Tag] class AssociateFirewallRuleGroupRequest(ServiceRequest): @@ -386,35 +389,35 @@ class AssociateFirewallRuleGroupRequest(ServiceRequest): VpcId: ResourceId Priority: Priority Name: Name - MutationProtection: Optional[MutationProtectionStatus] - Tags: Optional[TagList] + MutationProtection: MutationProtectionStatus | None + Tags: TagList | None class FirewallRuleGroupAssociation(TypedDict, total=False): - Id: Optional[ResourceId] - Arn: Optional[Arn] - FirewallRuleGroupId: Optional[ResourceId] - VpcId: Optional[ResourceId] - Name: Optional[Name] - Priority: Optional[Priority] - MutationProtection: Optional[MutationProtectionStatus] - ManagedOwnerName: Optional[ServicePrinciple] - Status: Optional[FirewallRuleGroupAssociationStatus] - StatusMessage: Optional[StatusMessage] - CreatorRequestId: Optional[CreatorRequestId] - CreationTime: Optional[Rfc3339TimeString] - ModificationTime: Optional[Rfc3339TimeString] + Id: ResourceId | None + Arn: Arn | None + FirewallRuleGroupId: ResourceId | None + VpcId: ResourceId | None + Name: Name | None + Priority: Priority | None + MutationProtection: MutationProtectionStatus | None + ManagedOwnerName: ServicePrinciple | None + Status: FirewallRuleGroupAssociationStatus | None + StatusMessage: StatusMessage | None + CreatorRequestId: CreatorRequestId | None + CreationTime: Rfc3339TimeString | None + ModificationTime: Rfc3339TimeString | None class AssociateFirewallRuleGroupResponse(TypedDict, total=False): - FirewallRuleGroupAssociation: Optional[FirewallRuleGroupAssociation] + FirewallRuleGroupAssociation: FirewallRuleGroupAssociation | None class IpAddressUpdate(TypedDict, total=False): - IpId: Optional[ResourceId] - SubnetId: Optional[SubnetId] - Ip: Optional[Ip] - Ipv6: Optional[Ipv6] + IpId: ResourceId | None + SubnetId: SubnetId | None + Ip: Ip | None + Ipv6: Ipv6 | None class AssociateResolverEndpointIpAddressRequest(ServiceRequest): @@ -422,31 +425,33 @@ class AssociateResolverEndpointIpAddressRequest(ServiceRequest): IpAddress: IpAddressUpdate -ProtocolList = List[Protocol] -SecurityGroupIds = List[ResourceId] +ProtocolList = list[Protocol] +SecurityGroupIds = list[ResourceId] class ResolverEndpoint(TypedDict, total=False): - Id: Optional[ResourceId] - CreatorRequestId: Optional[CreatorRequestId] - Arn: Optional[Arn] - Name: Optional[Name] - SecurityGroupIds: Optional[SecurityGroupIds] - Direction: Optional[ResolverEndpointDirection] - IpAddressCount: Optional[IpAddressCount] - HostVPCId: Optional[ResourceId] - Status: Optional[ResolverEndpointStatus] - StatusMessage: Optional[StatusMessage] - CreationTime: Optional[Rfc3339TimeString] - ModificationTime: Optional[Rfc3339TimeString] - OutpostArn: Optional[OutpostArn] - PreferredInstanceType: Optional[OutpostInstanceType] - ResolverEndpointType: Optional[ResolverEndpointType] - Protocols: Optional[ProtocolList] + Id: ResourceId | None + CreatorRequestId: CreatorRequestId | None + Arn: Arn | None + Name: Name | None + SecurityGroupIds: SecurityGroupIds | None + Direction: ResolverEndpointDirection | None + IpAddressCount: IpAddressCount | None + HostVPCId: ResourceId | None + Status: ResolverEndpointStatus | None + StatusMessage: StatusMessage | None + CreationTime: Rfc3339TimeString | None + ModificationTime: Rfc3339TimeString | None + OutpostArn: OutpostArn | None + PreferredInstanceType: OutpostInstanceType | None + ResolverEndpointType: ResolverEndpointType | None + Protocols: ProtocolList | None + RniEnhancedMetricsEnabled: RniEnhancedMetricsEnabled | None + TargetNameServerMetricsEnabled: TargetNameServerMetricsEnabled | None class AssociateResolverEndpointIpAddressResponse(TypedDict, total=False): - ResolverEndpoint: Optional[ResolverEndpoint] + ResolverEndpoint: ResolverEndpoint | None class AssociateResolverQueryLogConfigRequest(ServiceRequest): @@ -455,245 +460,247 @@ class AssociateResolverQueryLogConfigRequest(ServiceRequest): class ResolverQueryLogConfigAssociation(TypedDict, total=False): - Id: Optional[ResourceId] - ResolverQueryLogConfigId: Optional[ResourceId] - ResourceId: Optional[ResourceId] - Status: Optional[ResolverQueryLogConfigAssociationStatus] - Error: Optional[ResolverQueryLogConfigAssociationError] - ErrorMessage: Optional[ResolverQueryLogConfigAssociationErrorMessage] - CreationTime: Optional[Rfc3339TimeString] + Id: ResourceId | None + ResolverQueryLogConfigId: ResourceId | None + ResourceId: ResourceId | None + Status: ResolverQueryLogConfigAssociationStatus | None + Error: ResolverQueryLogConfigAssociationError | None + ErrorMessage: ResolverQueryLogConfigAssociationErrorMessage | None + CreationTime: Rfc3339TimeString | None class AssociateResolverQueryLogConfigResponse(TypedDict, total=False): - ResolverQueryLogConfigAssociation: Optional[ResolverQueryLogConfigAssociation] + ResolverQueryLogConfigAssociation: ResolverQueryLogConfigAssociation | None class AssociateResolverRuleRequest(ServiceRequest): ResolverRuleId: ResourceId - Name: Optional[Name] + Name: Name | None VPCId: ResourceId class ResolverRuleAssociation(TypedDict, total=False): - Id: Optional[ResourceId] - ResolverRuleId: Optional[ResourceId] - Name: Optional[Name] - VPCId: Optional[ResourceId] - Status: Optional[ResolverRuleAssociationStatus] - StatusMessage: Optional[StatusMessage] + Id: ResourceId | None + ResolverRuleId: ResourceId | None + Name: Name | None + VPCId: ResourceId | None + Status: ResolverRuleAssociationStatus | None + StatusMessage: StatusMessage | None class AssociateResolverRuleResponse(TypedDict, total=False): - ResolverRuleAssociation: Optional[ResolverRuleAssociation] + ResolverRuleAssociation: ResolverRuleAssociation | None class CreateFirewallDomainListRequest(ServiceRequest): CreatorRequestId: CreatorRequestId Name: Name - Tags: Optional[TagList] + Tags: TagList | None class FirewallDomainList(TypedDict, total=False): - Id: Optional[ResourceId] - Arn: Optional[Arn] - Name: Optional[Name] - DomainCount: Optional[Unsigned] - Status: Optional[FirewallDomainListStatus] - StatusMessage: Optional[StatusMessage] - ManagedOwnerName: Optional[ServicePrinciple] - CreatorRequestId: Optional[CreatorRequestId] - CreationTime: Optional[Rfc3339TimeString] - ModificationTime: Optional[Rfc3339TimeString] + Id: ResourceId | None + Arn: Arn | None + Name: Name | None + DomainCount: Unsigned | None + Status: FirewallDomainListStatus | None + StatusMessage: StatusMessage | None + ManagedOwnerName: ServicePrinciple | None + CreatorRequestId: CreatorRequestId | None + CreationTime: Rfc3339TimeString | None + ModificationTime: Rfc3339TimeString | None class CreateFirewallDomainListResponse(TypedDict, total=False): - FirewallDomainList: Optional[FirewallDomainList] + FirewallDomainList: FirewallDomainList | None class CreateFirewallRuleGroupRequest(ServiceRequest): CreatorRequestId: CreatorRequestId Name: Name - Tags: Optional[TagList] + Tags: TagList | None class FirewallRuleGroup(TypedDict, total=False): - Id: Optional[ResourceId] - Arn: Optional[Arn] - Name: Optional[Name] - RuleCount: Optional[Unsigned] - Status: Optional[FirewallRuleGroupStatus] - StatusMessage: Optional[StatusMessage] - OwnerId: Optional[AccountId] - CreatorRequestId: Optional[CreatorRequestId] - ShareStatus: Optional[ShareStatus] - CreationTime: Optional[Rfc3339TimeString] - ModificationTime: Optional[Rfc3339TimeString] + Id: ResourceId | None + Arn: Arn | None + Name: Name | None + RuleCount: Unsigned | None + Status: FirewallRuleGroupStatus | None + StatusMessage: StatusMessage | None + OwnerId: AccountId | None + CreatorRequestId: CreatorRequestId | None + ShareStatus: ShareStatus | None + CreationTime: Rfc3339TimeString | None + ModificationTime: Rfc3339TimeString | None class CreateFirewallRuleGroupResponse(TypedDict, total=False): - FirewallRuleGroup: Optional[FirewallRuleGroup] + FirewallRuleGroup: FirewallRuleGroup | None class CreateFirewallRuleRequest(ServiceRequest): CreatorRequestId: CreatorRequestId FirewallRuleGroupId: ResourceId - FirewallDomainListId: Optional[ResourceId] + FirewallDomainListId: ResourceId | None Priority: Priority Action: Action - BlockResponse: Optional[BlockResponse] - BlockOverrideDomain: Optional[BlockOverrideDomain] - BlockOverrideDnsType: Optional[BlockOverrideDnsType] - BlockOverrideTtl: Optional[BlockOverrideTtl] + BlockResponse: BlockResponse | None + BlockOverrideDomain: BlockOverrideDomain | None + BlockOverrideDnsType: BlockOverrideDnsType | None + BlockOverrideTtl: BlockOverrideTtl | None Name: Name - FirewallDomainRedirectionAction: Optional[FirewallDomainRedirectionAction] - Qtype: Optional[Qtype] - DnsThreatProtection: Optional[DnsThreatProtection] - ConfidenceThreshold: Optional[ConfidenceThreshold] + FirewallDomainRedirectionAction: FirewallDomainRedirectionAction | None + Qtype: Qtype | None + DnsThreatProtection: DnsThreatProtection | None + ConfidenceThreshold: ConfidenceThreshold | None class FirewallRule(TypedDict, total=False): - FirewallRuleGroupId: Optional[ResourceId] - FirewallDomainListId: Optional[ResourceId] - FirewallThreatProtectionId: Optional[ResourceId] - Name: Optional[Name] - Priority: Optional[Priority] - Action: Optional[Action] - BlockResponse: Optional[BlockResponse] - BlockOverrideDomain: Optional[BlockOverrideDomain] - BlockOverrideDnsType: Optional[BlockOverrideDnsType] - BlockOverrideTtl: Optional[Unsigned] - CreatorRequestId: Optional[CreatorRequestId] - CreationTime: Optional[Rfc3339TimeString] - ModificationTime: Optional[Rfc3339TimeString] - FirewallDomainRedirectionAction: Optional[FirewallDomainRedirectionAction] - Qtype: Optional[Qtype] - DnsThreatProtection: Optional[DnsThreatProtection] - ConfidenceThreshold: Optional[ConfidenceThreshold] + FirewallRuleGroupId: ResourceId | None + FirewallDomainListId: ResourceId | None + FirewallThreatProtectionId: ResourceId | None + Name: Name | None + Priority: Priority | None + Action: Action | None + BlockResponse: BlockResponse | None + BlockOverrideDomain: BlockOverrideDomain | None + BlockOverrideDnsType: BlockOverrideDnsType | None + BlockOverrideTtl: Unsigned | None + CreatorRequestId: CreatorRequestId | None + CreationTime: Rfc3339TimeString | None + ModificationTime: Rfc3339TimeString | None + FirewallDomainRedirectionAction: FirewallDomainRedirectionAction | None + Qtype: Qtype | None + DnsThreatProtection: DnsThreatProtection | None + ConfidenceThreshold: ConfidenceThreshold | None class CreateFirewallRuleResponse(TypedDict, total=False): - FirewallRule: Optional[FirewallRule] + FirewallRule: FirewallRule | None class CreateOutpostResolverRequest(ServiceRequest): CreatorRequestId: CreatorRequestId Name: OutpostResolverName - InstanceCount: Optional[InstanceCount] + InstanceCount: InstanceCount | None PreferredInstanceType: OutpostInstanceType OutpostArn: OutpostArn - Tags: Optional[TagList] + Tags: TagList | None class OutpostResolver(TypedDict, total=False): - Arn: Optional[Arn] - CreationTime: Optional[Rfc3339TimeString] - ModificationTime: Optional[Rfc3339TimeString] - CreatorRequestId: Optional[CreatorRequestId] - Id: Optional[ResourceId] - InstanceCount: Optional[InstanceCount] - PreferredInstanceType: Optional[OutpostInstanceType] - Name: Optional[OutpostResolverName] - Status: Optional[OutpostResolverStatus] - StatusMessage: Optional[OutpostResolverStatusMessage] - OutpostArn: Optional[OutpostArn] + Arn: Arn | None + CreationTime: Rfc3339TimeString | None + ModificationTime: Rfc3339TimeString | None + CreatorRequestId: CreatorRequestId | None + Id: ResourceId | None + InstanceCount: InstanceCount | None + PreferredInstanceType: OutpostInstanceType | None + Name: OutpostResolverName | None + Status: OutpostResolverStatus | None + StatusMessage: OutpostResolverStatusMessage | None + OutpostArn: OutpostArn | None class CreateOutpostResolverResponse(TypedDict, total=False): - OutpostResolver: Optional[OutpostResolver] + OutpostResolver: OutpostResolver | None class IpAddressRequest(TypedDict, total=False): SubnetId: SubnetId - Ip: Optional[Ip] - Ipv6: Optional[Ipv6] + Ip: Ip | None + Ipv6: Ipv6 | None -IpAddressesRequest = List[IpAddressRequest] +IpAddressesRequest = list[IpAddressRequest] class CreateResolverEndpointRequest(ServiceRequest): CreatorRequestId: CreatorRequestId - Name: Optional[Name] + Name: Name | None SecurityGroupIds: SecurityGroupIds Direction: ResolverEndpointDirection IpAddresses: IpAddressesRequest - OutpostArn: Optional[OutpostArn] - PreferredInstanceType: Optional[OutpostInstanceType] - Tags: Optional[TagList] - ResolverEndpointType: Optional[ResolverEndpointType] - Protocols: Optional[ProtocolList] + OutpostArn: OutpostArn | None + PreferredInstanceType: OutpostInstanceType | None + Tags: TagList | None + ResolverEndpointType: ResolverEndpointType | None + Protocols: ProtocolList | None + RniEnhancedMetricsEnabled: RniEnhancedMetricsEnabled | None + TargetNameServerMetricsEnabled: TargetNameServerMetricsEnabled | None class CreateResolverEndpointResponse(TypedDict, total=False): - ResolverEndpoint: Optional[ResolverEndpoint] + ResolverEndpoint: ResolverEndpoint | None class CreateResolverQueryLogConfigRequest(ServiceRequest): Name: ResolverQueryLogConfigName DestinationArn: DestinationArn CreatorRequestId: CreatorRequestId - Tags: Optional[TagList] + Tags: TagList | None class ResolverQueryLogConfig(TypedDict, total=False): - Id: Optional[ResourceId] - OwnerId: Optional[AccountId] - Status: Optional[ResolverQueryLogConfigStatus] - ShareStatus: Optional[ShareStatus] - AssociationCount: Optional[Count] - Arn: Optional[Arn] - Name: Optional[ResolverQueryLogConfigName] - DestinationArn: Optional[DestinationArn] - CreatorRequestId: Optional[CreatorRequestId] - CreationTime: Optional[Rfc3339TimeString] + Id: ResourceId | None + OwnerId: AccountId | None + Status: ResolverQueryLogConfigStatus | None + ShareStatus: ShareStatus | None + AssociationCount: Count | None + Arn: Arn | None + Name: ResolverQueryLogConfigName | None + DestinationArn: DestinationArn | None + CreatorRequestId: CreatorRequestId | None + CreationTime: Rfc3339TimeString | None class CreateResolverQueryLogConfigResponse(TypedDict, total=False): - ResolverQueryLogConfig: Optional[ResolverQueryLogConfig] + ResolverQueryLogConfig: ResolverQueryLogConfig | None class TargetAddress(TypedDict, total=False): - Ip: Optional[Ip] - Port: Optional[Port] - Ipv6: Optional[Ipv6] - Protocol: Optional[Protocol] - ServerNameIndication: Optional[ServerNameIndication] + Ip: Ip | None + Port: Port | None + Ipv6: Ipv6 | None + Protocol: Protocol | None + ServerNameIndication: ServerNameIndication | None -TargetList = List[TargetAddress] +TargetList = list[TargetAddress] class CreateResolverRuleRequest(ServiceRequest): CreatorRequestId: CreatorRequestId - Name: Optional[Name] + Name: Name | None RuleType: RuleTypeOption - DomainName: Optional[DomainName] - TargetIps: Optional[TargetList] - ResolverEndpointId: Optional[ResourceId] - Tags: Optional[TagList] - DelegationRecord: Optional[DelegationRecord] + DomainName: DomainName | None + TargetIps: TargetList | None + ResolverEndpointId: ResourceId | None + Tags: TagList | None + DelegationRecord: DelegationRecord | None class ResolverRule(TypedDict, total=False): - Id: Optional[ResourceId] - CreatorRequestId: Optional[CreatorRequestId] - Arn: Optional[Arn] - DomainName: Optional[DomainName] - Status: Optional[ResolverRuleStatus] - StatusMessage: Optional[StatusMessage] - RuleType: Optional[RuleTypeOption] - Name: Optional[Name] - TargetIps: Optional[TargetList] - ResolverEndpointId: Optional[ResourceId] - OwnerId: Optional[AccountId] - ShareStatus: Optional[ShareStatus] - CreationTime: Optional[Rfc3339TimeString] - ModificationTime: Optional[Rfc3339TimeString] - DelegationRecord: Optional[DelegationRecord] + Id: ResourceId | None + CreatorRequestId: CreatorRequestId | None + Arn: Arn | None + DomainName: DomainName | None + Status: ResolverRuleStatus | None + StatusMessage: StatusMessage | None + RuleType: RuleTypeOption | None + Name: Name | None + TargetIps: TargetList | None + ResolverEndpointId: ResourceId | None + OwnerId: AccountId | None + ShareStatus: ShareStatus | None + CreationTime: Rfc3339TimeString | None + ModificationTime: Rfc3339TimeString | None + DelegationRecord: DelegationRecord | None class CreateResolverRuleResponse(TypedDict, total=False): - ResolverRule: Optional[ResolverRule] + ResolverRule: ResolverRule | None class DeleteFirewallDomainListRequest(ServiceRequest): @@ -701,7 +708,7 @@ class DeleteFirewallDomainListRequest(ServiceRequest): class DeleteFirewallDomainListResponse(TypedDict, total=False): - FirewallDomainList: Optional[FirewallDomainList] + FirewallDomainList: FirewallDomainList | None class DeleteFirewallRuleGroupRequest(ServiceRequest): @@ -709,18 +716,18 @@ class DeleteFirewallRuleGroupRequest(ServiceRequest): class DeleteFirewallRuleGroupResponse(TypedDict, total=False): - FirewallRuleGroup: Optional[FirewallRuleGroup] + FirewallRuleGroup: FirewallRuleGroup | None class DeleteFirewallRuleRequest(ServiceRequest): FirewallRuleGroupId: ResourceId - FirewallDomainListId: Optional[ResourceId] - FirewallThreatProtectionId: Optional[ResourceId] - Qtype: Optional[Qtype] + FirewallDomainListId: ResourceId | None + FirewallThreatProtectionId: ResourceId | None + Qtype: Qtype | None class DeleteFirewallRuleResponse(TypedDict, total=False): - FirewallRule: Optional[FirewallRule] + FirewallRule: FirewallRule | None class DeleteOutpostResolverRequest(ServiceRequest): @@ -728,7 +735,7 @@ class DeleteOutpostResolverRequest(ServiceRequest): class DeleteOutpostResolverResponse(TypedDict, total=False): - OutpostResolver: Optional[OutpostResolver] + OutpostResolver: OutpostResolver | None class DeleteResolverEndpointRequest(ServiceRequest): @@ -736,7 +743,7 @@ class DeleteResolverEndpointRequest(ServiceRequest): class DeleteResolverEndpointResponse(TypedDict, total=False): - ResolverEndpoint: Optional[ResolverEndpoint] + ResolverEndpoint: ResolverEndpoint | None class DeleteResolverQueryLogConfigRequest(ServiceRequest): @@ -744,7 +751,7 @@ class DeleteResolverQueryLogConfigRequest(ServiceRequest): class DeleteResolverQueryLogConfigResponse(TypedDict, total=False): - ResolverQueryLogConfig: Optional[ResolverQueryLogConfig] + ResolverQueryLogConfig: ResolverQueryLogConfig | None class DeleteResolverRuleRequest(ServiceRequest): @@ -752,7 +759,7 @@ class DeleteResolverRuleRequest(ServiceRequest): class DeleteResolverRuleResponse(TypedDict, total=False): - ResolverRule: Optional[ResolverRule] + ResolverRule: ResolverRule | None class DisassociateFirewallRuleGroupRequest(ServiceRequest): @@ -760,7 +767,7 @@ class DisassociateFirewallRuleGroupRequest(ServiceRequest): class DisassociateFirewallRuleGroupResponse(TypedDict, total=False): - FirewallRuleGroupAssociation: Optional[FirewallRuleGroupAssociation] + FirewallRuleGroupAssociation: FirewallRuleGroupAssociation | None class DisassociateResolverEndpointIpAddressRequest(ServiceRequest): @@ -769,7 +776,7 @@ class DisassociateResolverEndpointIpAddressRequest(ServiceRequest): class DisassociateResolverEndpointIpAddressResponse(TypedDict, total=False): - ResolverEndpoint: Optional[ResolverEndpoint] + ResolverEndpoint: ResolverEndpoint | None class DisassociateResolverQueryLogConfigRequest(ServiceRequest): @@ -778,7 +785,7 @@ class DisassociateResolverQueryLogConfigRequest(ServiceRequest): class DisassociateResolverQueryLogConfigResponse(TypedDict, total=False): - ResolverQueryLogConfigAssociation: Optional[ResolverQueryLogConfigAssociation] + ResolverQueryLogConfigAssociation: ResolverQueryLogConfigAssociation | None class DisassociateResolverRuleRequest(ServiceRequest): @@ -787,54 +794,54 @@ class DisassociateResolverRuleRequest(ServiceRequest): class DisassociateResolverRuleResponse(TypedDict, total=False): - ResolverRuleAssociation: Optional[ResolverRuleAssociation] + ResolverRuleAssociation: ResolverRuleAssociation | None -FilterValues = List[FilterValue] +FilterValues = list[FilterValue] class Filter(TypedDict, total=False): - Name: Optional[FilterName] - Values: Optional[FilterValues] + Name: FilterName | None + Values: FilterValues | None -Filters = List[Filter] +Filters = list[Filter] class FirewallConfig(TypedDict, total=False): - Id: Optional[ResourceId] - ResourceId: Optional[ResourceId] - OwnerId: Optional[AccountId] - FirewallFailOpen: Optional[FirewallFailOpenStatus] + Id: ResourceId | None + ResourceId: ResourceId | None + OwnerId: AccountId | None + FirewallFailOpen: FirewallFailOpenStatus | None -FirewallConfigList = List[FirewallConfig] +FirewallConfigList = list[FirewallConfig] class FirewallDomainListMetadata(TypedDict, total=False): - Id: Optional[ResourceId] - Arn: Optional[Arn] - Name: Optional[Name] - CreatorRequestId: Optional[CreatorRequestId] - ManagedOwnerName: Optional[ServicePrinciple] + Id: ResourceId | None + Arn: Arn | None + Name: Name | None + CreatorRequestId: CreatorRequestId | None + ManagedOwnerName: ServicePrinciple | None -FirewallDomainListMetadataList = List[FirewallDomainListMetadata] -FirewallDomains = List[FirewallDomainName] -FirewallRuleGroupAssociations = List[FirewallRuleGroupAssociation] +FirewallDomainListMetadataList = list[FirewallDomainListMetadata] +FirewallDomains = list[FirewallDomainName] +FirewallRuleGroupAssociations = list[FirewallRuleGroupAssociation] class FirewallRuleGroupMetadata(TypedDict, total=False): - Id: Optional[ResourceId] - Arn: Optional[Arn] - Name: Optional[Name] - OwnerId: Optional[AccountId] - CreatorRequestId: Optional[CreatorRequestId] - ShareStatus: Optional[ShareStatus] + Id: ResourceId | None + Arn: Arn | None + Name: Name | None + OwnerId: AccountId | None + CreatorRequestId: CreatorRequestId | None + ShareStatus: ShareStatus | None -FirewallRuleGroupMetadataList = List[FirewallRuleGroupMetadata] -FirewallRules = List[FirewallRule] +FirewallRuleGroupMetadataList = list[FirewallRuleGroupMetadata] +FirewallRules = list[FirewallRule] class GetFirewallConfigRequest(ServiceRequest): @@ -842,7 +849,7 @@ class GetFirewallConfigRequest(ServiceRequest): class GetFirewallConfigResponse(TypedDict, total=False): - FirewallConfig: Optional[FirewallConfig] + FirewallConfig: FirewallConfig | None class GetFirewallDomainListRequest(ServiceRequest): @@ -850,7 +857,7 @@ class GetFirewallDomainListRequest(ServiceRequest): class GetFirewallDomainListResponse(TypedDict, total=False): - FirewallDomainList: Optional[FirewallDomainList] + FirewallDomainList: FirewallDomainList | None class GetFirewallRuleGroupAssociationRequest(ServiceRequest): @@ -858,7 +865,7 @@ class GetFirewallRuleGroupAssociationRequest(ServiceRequest): class GetFirewallRuleGroupAssociationResponse(TypedDict, total=False): - FirewallRuleGroupAssociation: Optional[FirewallRuleGroupAssociation] + FirewallRuleGroupAssociation: FirewallRuleGroupAssociation | None class GetFirewallRuleGroupPolicyRequest(ServiceRequest): @@ -866,7 +873,7 @@ class GetFirewallRuleGroupPolicyRequest(ServiceRequest): class GetFirewallRuleGroupPolicyResponse(TypedDict, total=False): - FirewallRuleGroupPolicy: Optional[FirewallRuleGroupPolicy] + FirewallRuleGroupPolicy: FirewallRuleGroupPolicy | None class GetFirewallRuleGroupRequest(ServiceRequest): @@ -874,7 +881,7 @@ class GetFirewallRuleGroupRequest(ServiceRequest): class GetFirewallRuleGroupResponse(TypedDict, total=False): - FirewallRuleGroup: Optional[FirewallRuleGroup] + FirewallRuleGroup: FirewallRuleGroup | None class GetOutpostResolverRequest(ServiceRequest): @@ -882,7 +889,7 @@ class GetOutpostResolverRequest(ServiceRequest): class GetOutpostResolverResponse(TypedDict, total=False): - OutpostResolver: Optional[OutpostResolver] + OutpostResolver: OutpostResolver | None class GetResolverConfigRequest(ServiceRequest): @@ -890,14 +897,14 @@ class GetResolverConfigRequest(ServiceRequest): class ResolverConfig(TypedDict, total=False): - Id: Optional[ResourceId] - ResourceId: Optional[ResourceId] - OwnerId: Optional[AccountId] - AutodefinedReverse: Optional[ResolverAutodefinedReverseStatus] + Id: ResourceId | None + ResourceId: ResourceId | None + OwnerId: AccountId | None + AutodefinedReverse: ResolverAutodefinedReverseStatus | None class GetResolverConfigResponse(TypedDict, total=False): - ResolverConfig: Optional[ResolverConfig] + ResolverConfig: ResolverConfig | None class GetResolverDnssecConfigRequest(ServiceRequest): @@ -905,14 +912,14 @@ class GetResolverDnssecConfigRequest(ServiceRequest): class ResolverDnssecConfig(TypedDict, total=False): - Id: Optional[ResourceId] - OwnerId: Optional[AccountId] - ResourceId: Optional[ResourceId] - ValidationStatus: Optional[ResolverDNSSECValidationStatus] + Id: ResourceId | None + OwnerId: AccountId | None + ResourceId: ResourceId | None + ValidationStatus: ResolverDNSSECValidationStatus | None class GetResolverDnssecConfigResponse(TypedDict, total=False): - ResolverDNSSECConfig: Optional[ResolverDnssecConfig] + ResolverDNSSECConfig: ResolverDnssecConfig | None class GetResolverEndpointRequest(ServiceRequest): @@ -920,7 +927,7 @@ class GetResolverEndpointRequest(ServiceRequest): class GetResolverEndpointResponse(TypedDict, total=False): - ResolverEndpoint: Optional[ResolverEndpoint] + ResolverEndpoint: ResolverEndpoint | None class GetResolverQueryLogConfigAssociationRequest(ServiceRequest): @@ -928,7 +935,7 @@ class GetResolverQueryLogConfigAssociationRequest(ServiceRequest): class GetResolverQueryLogConfigAssociationResponse(TypedDict, total=False): - ResolverQueryLogConfigAssociation: Optional[ResolverQueryLogConfigAssociation] + ResolverQueryLogConfigAssociation: ResolverQueryLogConfigAssociation | None class GetResolverQueryLogConfigPolicyRequest(ServiceRequest): @@ -936,7 +943,7 @@ class GetResolverQueryLogConfigPolicyRequest(ServiceRequest): class GetResolverQueryLogConfigPolicyResponse(TypedDict, total=False): - ResolverQueryLogConfigPolicy: Optional[ResolverQueryLogConfigPolicy] + ResolverQueryLogConfigPolicy: ResolverQueryLogConfigPolicy | None class GetResolverQueryLogConfigRequest(ServiceRequest): @@ -944,7 +951,7 @@ class GetResolverQueryLogConfigRequest(ServiceRequest): class GetResolverQueryLogConfigResponse(TypedDict, total=False): - ResolverQueryLogConfig: Optional[ResolverQueryLogConfig] + ResolverQueryLogConfig: ResolverQueryLogConfig | None class GetResolverRuleAssociationRequest(ServiceRequest): @@ -952,7 +959,7 @@ class GetResolverRuleAssociationRequest(ServiceRequest): class GetResolverRuleAssociationResponse(TypedDict, total=False): - ResolverRuleAssociation: Optional[ResolverRuleAssociation] + ResolverRuleAssociation: ResolverRuleAssociation | None class GetResolverRulePolicyRequest(ServiceRequest): @@ -960,7 +967,7 @@ class GetResolverRulePolicyRequest(ServiceRequest): class GetResolverRulePolicyResponse(TypedDict, total=False): - ResolverRulePolicy: Optional[ResolverRulePolicy] + ResolverRulePolicy: ResolverRulePolicy | None class GetResolverRuleRequest(ServiceRequest): @@ -968,7 +975,7 @@ class GetResolverRuleRequest(ServiceRequest): class GetResolverRuleResponse(TypedDict, total=False): - ResolverRule: Optional[ResolverRule] + ResolverRule: ResolverRule | None class ImportFirewallDomainsRequest(ServiceRequest): @@ -978,237 +985,237 @@ class ImportFirewallDomainsRequest(ServiceRequest): class ImportFirewallDomainsResponse(TypedDict, total=False): - Id: Optional[ResourceId] - Name: Optional[Name] - Status: Optional[FirewallDomainListStatus] - StatusMessage: Optional[StatusMessage] + Id: ResourceId | None + Name: Name | None + Status: FirewallDomainListStatus | None + StatusMessage: StatusMessage | None class IpAddressResponse(TypedDict, total=False): - IpId: Optional[ResourceId] - SubnetId: Optional[SubnetId] - Ip: Optional[Ip] - Ipv6: Optional[Ipv6] - Status: Optional[IpAddressStatus] - StatusMessage: Optional[StatusMessage] - CreationTime: Optional[Rfc3339TimeString] - ModificationTime: Optional[Rfc3339TimeString] + IpId: ResourceId | None + SubnetId: SubnetId | None + Ip: Ip | None + Ipv6: Ipv6 | None + Status: IpAddressStatus | None + StatusMessage: StatusMessage | None + CreationTime: Rfc3339TimeString | None + ModificationTime: Rfc3339TimeString | None -IpAddressesResponse = List[IpAddressResponse] +IpAddressesResponse = list[IpAddressResponse] class ListFirewallConfigsRequest(ServiceRequest): - MaxResults: Optional[ListFirewallConfigsMaxResult] - NextToken: Optional[NextToken] + MaxResults: ListFirewallConfigsMaxResult | None + NextToken: NextToken | None class ListFirewallConfigsResponse(TypedDict, total=False): - NextToken: Optional[NextToken] - FirewallConfigs: Optional[FirewallConfigList] + NextToken: NextToken | None + FirewallConfigs: FirewallConfigList | None class ListFirewallDomainListsRequest(ServiceRequest): - MaxResults: Optional[MaxResults] - NextToken: Optional[NextToken] + MaxResults: MaxResults | None + NextToken: NextToken | None class ListFirewallDomainListsResponse(TypedDict, total=False): - NextToken: Optional[NextToken] - FirewallDomainLists: Optional[FirewallDomainListMetadataList] + NextToken: NextToken | None + FirewallDomainLists: FirewallDomainListMetadataList | None class ListFirewallDomainsRequest(ServiceRequest): FirewallDomainListId: ResourceId - MaxResults: Optional[ListDomainMaxResults] - NextToken: Optional[NextToken] + MaxResults: ListDomainMaxResults | None + NextToken: NextToken | None class ListFirewallDomainsResponse(TypedDict, total=False): - NextToken: Optional[NextToken] - Domains: Optional[FirewallDomains] + NextToken: NextToken | None + Domains: FirewallDomains | None class ListFirewallRuleGroupAssociationsRequest(ServiceRequest): - FirewallRuleGroupId: Optional[ResourceId] - VpcId: Optional[ResourceId] - Priority: Optional[Priority] - Status: Optional[FirewallRuleGroupAssociationStatus] - MaxResults: Optional[MaxResults] - NextToken: Optional[NextToken] + FirewallRuleGroupId: ResourceId | None + VpcId: ResourceId | None + Priority: Priority | None + Status: FirewallRuleGroupAssociationStatus | None + MaxResults: MaxResults | None + NextToken: NextToken | None class ListFirewallRuleGroupAssociationsResponse(TypedDict, total=False): - NextToken: Optional[NextToken] - FirewallRuleGroupAssociations: Optional[FirewallRuleGroupAssociations] + NextToken: NextToken | None + FirewallRuleGroupAssociations: FirewallRuleGroupAssociations | None class ListFirewallRuleGroupsRequest(ServiceRequest): - MaxResults: Optional[MaxResults] - NextToken: Optional[NextToken] + MaxResults: MaxResults | None + NextToken: NextToken | None class ListFirewallRuleGroupsResponse(TypedDict, total=False): - NextToken: Optional[NextToken] - FirewallRuleGroups: Optional[FirewallRuleGroupMetadataList] + NextToken: NextToken | None + FirewallRuleGroups: FirewallRuleGroupMetadataList | None class ListFirewallRulesRequest(ServiceRequest): FirewallRuleGroupId: ResourceId - Priority: Optional[Priority] - Action: Optional[Action] - MaxResults: Optional[MaxResults] - NextToken: Optional[NextToken] + Priority: Priority | None + Action: Action | None + MaxResults: MaxResults | None + NextToken: NextToken | None class ListFirewallRulesResponse(TypedDict, total=False): - NextToken: Optional[NextToken] - FirewallRules: Optional[FirewallRules] + NextToken: NextToken | None + FirewallRules: FirewallRules | None class ListOutpostResolversRequest(ServiceRequest): - OutpostArn: Optional[OutpostArn] - MaxResults: Optional[MaxResults] - NextToken: Optional[NextToken] + OutpostArn: OutpostArn | None + MaxResults: MaxResults | None + NextToken: NextToken | None -OutpostResolverList = List[OutpostResolver] +OutpostResolverList = list[OutpostResolver] class ListOutpostResolversResponse(TypedDict, total=False): - OutpostResolvers: Optional[OutpostResolverList] - NextToken: Optional[NextToken] + OutpostResolvers: OutpostResolverList | None + NextToken: NextToken | None class ListResolverConfigsRequest(ServiceRequest): - MaxResults: Optional[ListResolverConfigsMaxResult] - NextToken: Optional[NextToken] + MaxResults: ListResolverConfigsMaxResult | None + NextToken: NextToken | None -ResolverConfigList = List[ResolverConfig] +ResolverConfigList = list[ResolverConfig] class ListResolverConfigsResponse(TypedDict, total=False): - NextToken: Optional[NextToken] - ResolverConfigs: Optional[ResolverConfigList] + NextToken: NextToken | None + ResolverConfigs: ResolverConfigList | None class ListResolverDnssecConfigsRequest(ServiceRequest): - MaxResults: Optional[MaxResults] - NextToken: Optional[NextToken] - Filters: Optional[Filters] + MaxResults: MaxResults | None + NextToken: NextToken | None + Filters: Filters | None -ResolverDnssecConfigList = List[ResolverDnssecConfig] +ResolverDnssecConfigList = list[ResolverDnssecConfig] class ListResolverDnssecConfigsResponse(TypedDict, total=False): - NextToken: Optional[NextToken] - ResolverDnssecConfigs: Optional[ResolverDnssecConfigList] + NextToken: NextToken | None + ResolverDnssecConfigs: ResolverDnssecConfigList | None class ListResolverEndpointIpAddressesRequest(ServiceRequest): ResolverEndpointId: ResourceId - MaxResults: Optional[MaxResults] - NextToken: Optional[NextToken] + MaxResults: MaxResults | None + NextToken: NextToken | None class ListResolverEndpointIpAddressesResponse(TypedDict, total=False): - NextToken: Optional[NextToken] - MaxResults: Optional[MaxResults] - IpAddresses: Optional[IpAddressesResponse] + NextToken: NextToken | None + MaxResults: MaxResults | None + IpAddresses: IpAddressesResponse | None class ListResolverEndpointsRequest(ServiceRequest): - MaxResults: Optional[MaxResults] - NextToken: Optional[NextToken] - Filters: Optional[Filters] + MaxResults: MaxResults | None + NextToken: NextToken | None + Filters: Filters | None -ResolverEndpoints = List[ResolverEndpoint] +ResolverEndpoints = list[ResolverEndpoint] class ListResolverEndpointsResponse(TypedDict, total=False): - NextToken: Optional[NextToken] - MaxResults: Optional[MaxResults] - ResolverEndpoints: Optional[ResolverEndpoints] + NextToken: NextToken | None + MaxResults: MaxResults | None + ResolverEndpoints: ResolverEndpoints | None class ListResolverQueryLogConfigAssociationsRequest(ServiceRequest): - MaxResults: Optional[MaxResults] - NextToken: Optional[NextToken] - Filters: Optional[Filters] - SortBy: Optional[SortByKey] - SortOrder: Optional[SortOrder] + MaxResults: MaxResults | None + NextToken: NextToken | None + Filters: Filters | None + SortBy: SortByKey | None + SortOrder: SortOrder | None -ResolverQueryLogConfigAssociationList = List[ResolverQueryLogConfigAssociation] +ResolverQueryLogConfigAssociationList = list[ResolverQueryLogConfigAssociation] class ListResolverQueryLogConfigAssociationsResponse(TypedDict, total=False): - NextToken: Optional[NextToken] - TotalCount: Optional[Count] - TotalFilteredCount: Optional[Count] - ResolverQueryLogConfigAssociations: Optional[ResolverQueryLogConfigAssociationList] + NextToken: NextToken | None + TotalCount: Count | None + TotalFilteredCount: Count | None + ResolverQueryLogConfigAssociations: ResolverQueryLogConfigAssociationList | None class ListResolverQueryLogConfigsRequest(ServiceRequest): - MaxResults: Optional[MaxResults] - NextToken: Optional[NextToken] - Filters: Optional[Filters] - SortBy: Optional[SortByKey] - SortOrder: Optional[SortOrder] + MaxResults: MaxResults | None + NextToken: NextToken | None + Filters: Filters | None + SortBy: SortByKey | None + SortOrder: SortOrder | None -ResolverQueryLogConfigList = List[ResolverQueryLogConfig] +ResolverQueryLogConfigList = list[ResolverQueryLogConfig] class ListResolverQueryLogConfigsResponse(TypedDict, total=False): - NextToken: Optional[NextToken] - TotalCount: Optional[Count] - TotalFilteredCount: Optional[Count] - ResolverQueryLogConfigs: Optional[ResolverQueryLogConfigList] + NextToken: NextToken | None + TotalCount: Count | None + TotalFilteredCount: Count | None + ResolverQueryLogConfigs: ResolverQueryLogConfigList | None class ListResolverRuleAssociationsRequest(ServiceRequest): - MaxResults: Optional[MaxResults] - NextToken: Optional[NextToken] - Filters: Optional[Filters] + MaxResults: MaxResults | None + NextToken: NextToken | None + Filters: Filters | None -ResolverRuleAssociations = List[ResolverRuleAssociation] +ResolverRuleAssociations = list[ResolverRuleAssociation] class ListResolverRuleAssociationsResponse(TypedDict, total=False): - NextToken: Optional[NextToken] - MaxResults: Optional[MaxResults] - ResolverRuleAssociations: Optional[ResolverRuleAssociations] + NextToken: NextToken | None + MaxResults: MaxResults | None + ResolverRuleAssociations: ResolverRuleAssociations | None class ListResolverRulesRequest(ServiceRequest): - MaxResults: Optional[MaxResults] - NextToken: Optional[NextToken] - Filters: Optional[Filters] + MaxResults: MaxResults | None + NextToken: NextToken | None + Filters: Filters | None -ResolverRules = List[ResolverRule] +ResolverRules = list[ResolverRule] class ListResolverRulesResponse(TypedDict, total=False): - NextToken: Optional[NextToken] - MaxResults: Optional[MaxResults] - ResolverRules: Optional[ResolverRules] + NextToken: NextToken | None + MaxResults: MaxResults | None + ResolverRules: ResolverRules | None class ListTagsForResourceRequest(ServiceRequest): ResourceArn: Arn - MaxResults: Optional[MaxResults] - NextToken: Optional[NextToken] + MaxResults: MaxResults | None + NextToken: NextToken | None class ListTagsForResourceResponse(TypedDict, total=False): - Tags: Optional[TagList] - NextToken: Optional[NextToken] + Tags: TagList | None + NextToken: NextToken | None class PutFirewallRuleGroupPolicyRequest(ServiceRequest): @@ -1217,7 +1224,7 @@ class PutFirewallRuleGroupPolicyRequest(ServiceRequest): class PutFirewallRuleGroupPolicyResponse(TypedDict, total=False): - ReturnValue: Optional[Boolean] + ReturnValue: Boolean | None class PutResolverQueryLogConfigPolicyRequest(ServiceRequest): @@ -1226,7 +1233,7 @@ class PutResolverQueryLogConfigPolicyRequest(ServiceRequest): class PutResolverQueryLogConfigPolicyResponse(TypedDict, total=False): - ReturnValue: Optional[Boolean] + ReturnValue: Boolean | None class PutResolverRulePolicyRequest(ServiceRequest): @@ -1235,16 +1242,16 @@ class PutResolverRulePolicyRequest(ServiceRequest): class PutResolverRulePolicyResponse(TypedDict, total=False): - ReturnValue: Optional[Boolean] + ReturnValue: Boolean | None class ResolverRuleConfig(TypedDict, total=False): - Name: Optional[Name] - TargetIps: Optional[TargetList] - ResolverEndpointId: Optional[ResourceId] + Name: Name | None + TargetIps: TargetList | None + ResolverEndpointId: ResourceId | None -TagKeyList = List[TagKey] +TagKeyList = list[TagKey] class TagResourceRequest(ServiceRequest): @@ -1271,7 +1278,7 @@ class UpdateFirewallConfigRequest(ServiceRequest): class UpdateFirewallConfigResponse(TypedDict, total=False): - FirewallConfig: Optional[FirewallConfig] + FirewallConfig: FirewallConfig | None class UpdateFirewallDomainsRequest(ServiceRequest): @@ -1281,42 +1288,42 @@ class UpdateFirewallDomainsRequest(ServiceRequest): class UpdateFirewallDomainsResponse(TypedDict, total=False): - Id: Optional[ResourceId] - Name: Optional[Name] - Status: Optional[FirewallDomainListStatus] - StatusMessage: Optional[StatusMessage] + Id: ResourceId | None + Name: Name | None + Status: FirewallDomainListStatus | None + StatusMessage: StatusMessage | None class UpdateFirewallRuleGroupAssociationRequest(ServiceRequest): FirewallRuleGroupAssociationId: ResourceId - Priority: Optional[Priority] - MutationProtection: Optional[MutationProtectionStatus] - Name: Optional[Name] + Priority: Priority | None + MutationProtection: MutationProtectionStatus | None + Name: Name | None class UpdateFirewallRuleGroupAssociationResponse(TypedDict, total=False): - FirewallRuleGroupAssociation: Optional[FirewallRuleGroupAssociation] + FirewallRuleGroupAssociation: FirewallRuleGroupAssociation | None class UpdateFirewallRuleRequest(ServiceRequest): FirewallRuleGroupId: ResourceId - FirewallDomainListId: Optional[ResourceId] - FirewallThreatProtectionId: Optional[ResourceId] - Priority: Optional[Priority] - Action: Optional[Action] - BlockResponse: Optional[BlockResponse] - BlockOverrideDomain: Optional[BlockOverrideDomain] - BlockOverrideDnsType: Optional[BlockOverrideDnsType] - BlockOverrideTtl: Optional[BlockOverrideTtl] - Name: Optional[Name] - FirewallDomainRedirectionAction: Optional[FirewallDomainRedirectionAction] - Qtype: Optional[Qtype] - DnsThreatProtection: Optional[DnsThreatProtection] - ConfidenceThreshold: Optional[ConfidenceThreshold] + FirewallDomainListId: ResourceId | None + FirewallThreatProtectionId: ResourceId | None + Priority: Priority | None + Action: Action | None + BlockResponse: BlockResponse | None + BlockOverrideDomain: BlockOverrideDomain | None + BlockOverrideDnsType: BlockOverrideDnsType | None + BlockOverrideTtl: BlockOverrideTtl | None + Name: Name | None + FirewallDomainRedirectionAction: FirewallDomainRedirectionAction | None + Qtype: Qtype | None + DnsThreatProtection: DnsThreatProtection | None + ConfidenceThreshold: ConfidenceThreshold | None class UpdateFirewallRuleResponse(TypedDict, total=False): - FirewallRule: Optional[FirewallRule] + FirewallRule: FirewallRule | None class UpdateIpAddress(TypedDict, total=False): @@ -1324,18 +1331,18 @@ class UpdateIpAddress(TypedDict, total=False): Ipv6: Ipv6 -UpdateIpAddresses = List[UpdateIpAddress] +UpdateIpAddresses = list[UpdateIpAddress] class UpdateOutpostResolverRequest(ServiceRequest): Id: ResourceId - Name: Optional[OutpostResolverName] - InstanceCount: Optional[InstanceCount] - PreferredInstanceType: Optional[OutpostInstanceType] + Name: OutpostResolverName | None + InstanceCount: InstanceCount | None + PreferredInstanceType: OutpostInstanceType | None class UpdateOutpostResolverResponse(TypedDict, total=False): - OutpostResolver: Optional[OutpostResolver] + OutpostResolver: OutpostResolver | None class UpdateResolverConfigRequest(ServiceRequest): @@ -1344,7 +1351,7 @@ class UpdateResolverConfigRequest(ServiceRequest): class UpdateResolverConfigResponse(TypedDict, total=False): - ResolverConfig: Optional[ResolverConfig] + ResolverConfig: ResolverConfig | None class UpdateResolverDnssecConfigRequest(ServiceRequest): @@ -1353,19 +1360,21 @@ class UpdateResolverDnssecConfigRequest(ServiceRequest): class UpdateResolverDnssecConfigResponse(TypedDict, total=False): - ResolverDNSSECConfig: Optional[ResolverDnssecConfig] + ResolverDNSSECConfig: ResolverDnssecConfig | None class UpdateResolverEndpointRequest(ServiceRequest): ResolverEndpointId: ResourceId - Name: Optional[Name] - ResolverEndpointType: Optional[ResolverEndpointType] - UpdateIpAddresses: Optional[UpdateIpAddresses] - Protocols: Optional[ProtocolList] + Name: Name | None + ResolverEndpointType: ResolverEndpointType | None + UpdateIpAddresses: UpdateIpAddresses | None + Protocols: ProtocolList | None + RniEnhancedMetricsEnabled: RniEnhancedMetricsEnabled | None + TargetNameServerMetricsEnabled: TargetNameServerMetricsEnabled | None class UpdateResolverEndpointResponse(TypedDict, total=False): - ResolverEndpoint: Optional[ResolverEndpoint] + ResolverEndpoint: ResolverEndpoint | None class UpdateResolverRuleRequest(ServiceRequest): @@ -1374,12 +1383,12 @@ class UpdateResolverRuleRequest(ServiceRequest): class UpdateResolverRuleResponse(TypedDict, total=False): - ResolverRule: Optional[ResolverRule] + ResolverRule: ResolverRule | None class Route53ResolverApi: - service = "route53resolver" - version = "2018-04-01" + service: str = "route53resolver" + version: str = "2018-04-01" @handler("AssociateFirewallRuleGroup") def associate_firewall_rule_group( @@ -1499,6 +1508,8 @@ def create_resolver_endpoint( tags: TagList | None = None, resolver_endpoint_type: ResolverEndpointType | None = None, protocols: ProtocolList | None = None, + rni_enhanced_metrics_enabled: RniEnhancedMetricsEnabled | None = None, + target_name_server_metrics_enabled: TargetNameServerMetricsEnabled | None = None, **kwargs, ) -> CreateResolverEndpointResponse: raise NotImplementedError @@ -2026,6 +2037,8 @@ def update_resolver_endpoint( resolver_endpoint_type: ResolverEndpointType | None = None, update_ip_addresses: UpdateIpAddresses | None = None, protocols: ProtocolList | None = None, + rni_enhanced_metrics_enabled: RniEnhancedMetricsEnabled | None = None, + target_name_server_metrics_enabled: TargetNameServerMetricsEnabled | None = None, **kwargs, ) -> UpdateResolverEndpointResponse: raise NotImplementedError diff --git a/localstack-core/localstack/aws/api/s3/__init__.py b/localstack-core/localstack/aws/api/s3/__init__.py index c6691aa8feb80..36a6133339162 100644 --- a/localstack-core/localstack/aws/api/s3/__init__.py +++ b/localstack-core/localstack/aws/api/s3/__init__.py @@ -1,6 +1,7 @@ +from collections.abc import Iterable, Iterator from datetime import datetime from enum import StrEnum -from typing import IO, Dict, Iterable, Iterator, List, Optional, TypedDict, Union +from typing import IO, TypedDict from localstack.aws.api import RequestContext, ServiceException, ServiceRequest, handler @@ -117,6 +118,7 @@ NextToken = str NextUploadIdMarker = str NextVersionIdMarker = str +NonEmptyKmsKeyArnString = str NotificationId = str ObjectKey = str ObjectLockEnabledForBucket = bool @@ -211,6 +213,11 @@ class ArchiveStatus(StrEnum): DEEP_ARCHIVE_ACCESS = "DEEP_ARCHIVE_ACCESS" +class BucketAbacStatus(StrEnum): + Enabled = "Enabled" + Disabled = "Disabled" + + class BucketAccelerateStatus(StrEnum): Enabled = "Enabled" Suspended = "Suspended" @@ -312,6 +319,11 @@ class EncodingType(StrEnum): url = "url" +class EncryptionType(StrEnum): + NONE = "NONE" + SSE_C = "SSE-C" + + class Event(StrEnum): s3_ReducedRedundancyLostObject = "s3:ReducedRedundancyLostObject" s3_ObjectCreated_ = "s3:ObjectCreated:*" @@ -421,6 +433,7 @@ class InventoryOptionalField(StrEnum): ChecksumAlgorithm = "ChecksumAlgorithm" ObjectAccessControlList = "ObjectAccessControlList" ObjectOwner = "ObjectOwner" + LifecycleExpirationDate = "LifecycleExpirationDate" class JSONType(StrEnum): @@ -509,6 +522,7 @@ class ObjectStorageClass(StrEnum): SNOW = "SNOW" EXPRESS_ONEZONE = "EXPRESS_ONEZONE" FSX_OPENZFS = "FSX_OPENZFS" + FSX_ONTAP = "FSX_ONTAP" class ObjectVersionStorageClass(StrEnum): @@ -621,6 +635,7 @@ class StorageClass(StrEnum): SNOW = "SNOW" EXPRESS_ONEZONE = "EXPRESS_ONEZONE" FSX_OPENZFS = "FSX_OPENZFS" + FSX_ONTAP = "FSX_ONTAP" class StorageClassAnalysisSchemaVersion(StrEnum): @@ -663,6 +678,21 @@ class Type(StrEnum): Group = "Group" +ServerTime = datetime +Expires = datetime + + +class AccessDenied(ServiceException): + code: str = "AccessDenied" + sender_fault: bool = False + status_code: int = 403 + Expires: Expires | None + ServerTime: ServerTime | None + X_Amz_Expires: X_Amz_Expires | None + HostId: HostId | None + HeadersNotSigned: HeadersNotSigned | None + + class BucketAlreadyExists(ServiceException): code: str = "BucketAlreadyExists" sender_fault: bool = False @@ -673,7 +703,7 @@ class BucketAlreadyOwnedByYou(ServiceException): code: str = "BucketAlreadyOwnedByYou" sender_fault: bool = False status_code: int = 409 - BucketName: Optional[BucketName] + BucketName: BucketName | None class EncryptionTypeMismatch(ServiceException): @@ -692,8 +722,8 @@ class InvalidObjectState(ServiceException): code: str = "InvalidObjectState" sender_fault: bool = False status_code: int = 403 - StorageClass: Optional[StorageClass] - AccessTier: Optional[IntelligentTieringAccessTier] + StorageClass: StorageClass | None + AccessTier: IntelligentTieringAccessTier | None class InvalidRequest(ServiceException): @@ -712,23 +742,23 @@ class NoSuchBucket(ServiceException): code: str = "NoSuchBucket" sender_fault: bool = False status_code: int = 404 - BucketName: Optional[BucketName] + BucketName: BucketName | None class NoSuchKey(ServiceException): code: str = "NoSuchKey" sender_fault: bool = False status_code: int = 404 - Key: Optional[ObjectKey] - DeleteMarker: Optional[DeleteMarker] - VersionId: Optional[ObjectVersionId] + Key: ObjectKey | None + DeleteMarker: DeleteMarker | None + VersionId: ObjectVersionId | None class NoSuchUpload(ServiceException): code: str = "NoSuchUpload" sender_fault: bool = False status_code: int = 404 - UploadId: Optional[MultipartUploadId] + UploadId: MultipartUploadId | None class ObjectAlreadyInActiveTierError(ServiceException): @@ -753,29 +783,29 @@ class NoSuchLifecycleConfiguration(ServiceException): code: str = "NoSuchLifecycleConfiguration" sender_fault: bool = False status_code: int = 404 - BucketName: Optional[BucketName] + BucketName: BucketName | None class InvalidBucketName(ServiceException): code: str = "InvalidBucketName" sender_fault: bool = False status_code: int = 400 - BucketName: Optional[BucketName] + BucketName: BucketName | None class NoSuchVersion(ServiceException): code: str = "NoSuchVersion" sender_fault: bool = False status_code: int = 404 - VersionId: Optional[ObjectVersionId] - Key: Optional[ObjectKey] + VersionId: ObjectVersionId | None + Key: ObjectKey | None class PreconditionFailed(ServiceException): code: str = "PreconditionFailed" sender_fault: bool = False status_code: int = 412 - Condition: Optional[IfCondition] + Condition: IfCondition | None ObjectSize = int @@ -785,143 +815,128 @@ class InvalidRange(ServiceException): code: str = "InvalidRange" sender_fault: bool = False status_code: int = 416 - ActualObjectSize: Optional[ObjectSize] - RangeRequested: Optional[ContentRange] + ActualObjectSize: ObjectSize | None + RangeRequested: ContentRange | None class InvalidArgument(ServiceException): code: str = "InvalidArgument" sender_fault: bool = False status_code: int = 400 - ArgumentName: Optional[ArgumentName] - ArgumentValue: Optional[ArgumentValue] - HostId: Optional[HostId] + ArgumentName: ArgumentName | None + ArgumentValue: ArgumentValue | None + HostId: HostId | None class SignatureDoesNotMatch(ServiceException): code: str = "SignatureDoesNotMatch" sender_fault: bool = False status_code: int = 403 - AWSAccessKeyId: Optional[AWSAccessKeyId] - CanonicalRequest: Optional[CanonicalRequest] - CanonicalRequestBytes: Optional[CanonicalRequestBytes] - HostId: Optional[HostId] - SignatureProvided: Optional[SignatureProvided] - StringToSign: Optional[StringToSign] - StringToSignBytes: Optional[StringToSignBytes] - - -ServerTime = datetime -Expires = datetime - - -class AccessDenied(ServiceException): - code: str = "AccessDenied" - sender_fault: bool = False - status_code: int = 403 - Expires: Optional[Expires] - ServerTime: Optional[ServerTime] - X_Amz_Expires: Optional[X_Amz_Expires] - HostId: Optional[HostId] - HeadersNotSigned: Optional[HeadersNotSigned] + AWSAccessKeyId: AWSAccessKeyId | None + CanonicalRequest: CanonicalRequest | None + CanonicalRequestBytes: CanonicalRequestBytes | None + HostId: HostId | None + SignatureProvided: SignatureProvided | None + StringToSign: StringToSign | None + StringToSignBytes: StringToSignBytes | None class AuthorizationQueryParametersError(ServiceException): code: str = "AuthorizationQueryParametersError" sender_fault: bool = False status_code: int = 400 - HostId: Optional[HostId] + HostId: HostId | None class NoSuchWebsiteConfiguration(ServiceException): code: str = "NoSuchWebsiteConfiguration" sender_fault: bool = False status_code: int = 404 - BucketName: Optional[BucketName] + BucketName: BucketName | None class ReplicationConfigurationNotFoundError(ServiceException): code: str = "ReplicationConfigurationNotFoundError" sender_fault: bool = False status_code: int = 404 - BucketName: Optional[BucketName] + BucketName: BucketName | None class BadRequest(ServiceException): code: str = "BadRequest" sender_fault: bool = False status_code: int = 400 - HostId: Optional[HostId] + HostId: HostId | None class AccessForbidden(ServiceException): code: str = "AccessForbidden" sender_fault: bool = False status_code: int = 403 - HostId: Optional[HostId] - Method: Optional[HttpMethod] - ResourceType: Optional[ResourceType] + HostId: HostId | None + Method: HttpMethod | None + ResourceType: ResourceType | None class NoSuchCORSConfiguration(ServiceException): code: str = "NoSuchCORSConfiguration" sender_fault: bool = False status_code: int = 404 - BucketName: Optional[BucketName] + BucketName: BucketName | None class MissingSecurityHeader(ServiceException): code: str = "MissingSecurityHeader" sender_fault: bool = False status_code: int = 400 - MissingHeaderName: Optional[MissingHeaderName] + MissingHeaderName: MissingHeaderName | None class InvalidPartOrder(ServiceException): code: str = "InvalidPartOrder" sender_fault: bool = False status_code: int = 400 - UploadId: Optional[MultipartUploadId] + UploadId: MultipartUploadId | None class InvalidStorageClass(ServiceException): code: str = "InvalidStorageClass" sender_fault: bool = False status_code: int = 400 - StorageClassRequested: Optional[StorageClass] + StorageClassRequested: StorageClass | None class MethodNotAllowed(ServiceException): code: str = "MethodNotAllowed" sender_fault: bool = False status_code: int = 405 - Method: Optional[HttpMethod] - ResourceType: Optional[ResourceType] - DeleteMarker: Optional[DeleteMarker] - VersionId: Optional[ObjectVersionId] - Allow: Optional[HttpMethod] + Method: HttpMethod | None + ResourceType: ResourceType | None + DeleteMarker: DeleteMarker | None + VersionId: ObjectVersionId | None + Allow: HttpMethod | None class CrossLocationLoggingProhibitted(ServiceException): code: str = "CrossLocationLoggingProhibitted" sender_fault: bool = False status_code: int = 403 - TargetBucketLocation: Optional[BucketRegion] - SourceBucketLocation: Optional[BucketRegion] + TargetBucketLocation: BucketRegion | None + SourceBucketLocation: BucketRegion | None class InvalidTargetBucketForLogging(ServiceException): code: str = "InvalidTargetBucketForLogging" sender_fault: bool = False status_code: int = 400 - TargetBucket: Optional[BucketName] + TargetBucket: BucketName | None class BucketNotEmpty(ServiceException): code: str = "BucketNotEmpty" sender_fault: bool = False status_code: int = 409 - BucketName: Optional[BucketName] + BucketName: BucketName | None ProposedSize = int @@ -932,144 +947,156 @@ class EntityTooSmall(ServiceException): code: str = "EntityTooSmall" sender_fault: bool = False status_code: int = 400 - ETag: Optional[ETag] - MinSizeAllowed: Optional[MinSizeAllowed] - PartNumber: Optional[PartNumber] - ProposedSize: Optional[ProposedSize] + ETag: ETag | None + MinSizeAllowed: MinSizeAllowed | None + PartNumber: PartNumber | None + ProposedSize: ProposedSize | None class InvalidPart(ServiceException): code: str = "InvalidPart" sender_fault: bool = False status_code: int = 400 - ETag: Optional[ETag] - UploadId: Optional[MultipartUploadId] - PartNumber: Optional[PartNumber] + ETag: ETag | None + UploadId: MultipartUploadId | None + PartNumber: PartNumber | None class NoSuchTagSet(ServiceException): code: str = "NoSuchTagSet" sender_fault: bool = False status_code: int = 404 - BucketName: Optional[BucketName] + BucketName: BucketName | None class InvalidTag(ServiceException): code: str = "InvalidTag" sender_fault: bool = False status_code: int = 400 - TagKey: Optional[ObjectKey] - TagValue: Optional[Value] + TagKey: ObjectKey | None + TagValue: Value | None class ObjectLockConfigurationNotFoundError(ServiceException): code: str = "ObjectLockConfigurationNotFoundError" sender_fault: bool = False status_code: int = 404 - BucketName: Optional[BucketName] + BucketName: BucketName | None class InvalidPartNumber(ServiceException): code: str = "InvalidPartNumber" sender_fault: bool = False status_code: int = 416 - PartNumberRequested: Optional[PartNumber] - ActualPartCount: Optional[PartNumber] + PartNumberRequested: PartNumber | None + ActualPartCount: PartNumber | None class OwnershipControlsNotFoundError(ServiceException): code: str = "OwnershipControlsNotFoundError" sender_fault: bool = False status_code: int = 404 - BucketName: Optional[BucketName] + BucketName: BucketName | None class NoSuchPublicAccessBlockConfiguration(ServiceException): code: str = "NoSuchPublicAccessBlockConfiguration" sender_fault: bool = False status_code: int = 404 - BucketName: Optional[BucketName] + BucketName: BucketName | None class NoSuchBucketPolicy(ServiceException): code: str = "NoSuchBucketPolicy" sender_fault: bool = False status_code: int = 404 - BucketName: Optional[BucketName] + BucketName: BucketName | None class InvalidDigest(ServiceException): code: str = "InvalidDigest" sender_fault: bool = False status_code: int = 400 - Content_MD5: Optional[ContentMD5] + Content_MD5: ContentMD5 | None class KeyTooLongError(ServiceException): code: str = "KeyTooLongError" sender_fault: bool = False status_code: int = 400 - MaxSizeAllowed: Optional[KeyLength] - Size: Optional[KeyLength] + MaxSizeAllowed: KeyLength | None + Size: KeyLength | None class InvalidLocationConstraint(ServiceException): code: str = "InvalidLocationConstraint" sender_fault: bool = False status_code: int = 400 - LocationConstraint: Optional[BucketRegion] + LocationConstraint: BucketRegion | None class EntityTooLarge(ServiceException): code: str = "EntityTooLarge" sender_fault: bool = False status_code: int = 400 - MaxSizeAllowed: Optional[KeyLength] - HostId: Optional[HostId] - ProposedSize: Optional[ProposedSize] + MaxSizeAllowed: KeyLength | None + HostId: HostId | None + ProposedSize: ProposedSize | None class InvalidEncryptionAlgorithmError(ServiceException): code: str = "InvalidEncryptionAlgorithmError" sender_fault: bool = False status_code: int = 400 - ArgumentName: Optional[ArgumentName] - ArgumentValue: Optional[ArgumentValue] + ArgumentName: ArgumentName | None + ArgumentValue: ArgumentValue | None class NotImplemented(ServiceException): code: str = "NotImplemented" sender_fault: bool = False status_code: int = 501 - Header: Optional[Header] - additionalMessage: Optional[additionalMessage] + Header: Header | None + additionalMessage: additionalMessage | None class ConditionalRequestConflict(ServiceException): code: str = "ConditionalRequestConflict" sender_fault: bool = False status_code: int = 409 - Condition: Optional[IfCondition] - Key: Optional[ObjectKey] + Condition: IfCondition | None + Key: ObjectKey | None class BadDigest(ServiceException): code: str = "BadDigest" sender_fault: bool = False status_code: int = 400 - ExpectedDigest: Optional[ContentMD5] - CalculatedDigest: Optional[ContentMD5] + ExpectedDigest: ContentMD5 | None + CalculatedDigest: ContentMD5 | None + + +class AuthorizationHeaderMalformed(ServiceException): + code: str = "AuthorizationHeaderMalformed" + sender_fault: bool = False + status_code: int = 400 + Region: BucketRegion | None + HostId: HostId | None + + +class AbacStatus(TypedDict, total=False): + Status: BucketAbacStatus | None AbortDate = datetime class AbortIncompleteMultipartUpload(TypedDict, total=False): - DaysAfterInitiation: Optional[DaysAfterInitiation] + DaysAfterInitiation: DaysAfterInitiation | None class AbortMultipartUploadOutput(TypedDict, total=False): - RequestCharged: Optional[RequestCharged] + RequestCharged: RequestCharged | None IfMatchInitiatedTime = datetime @@ -1079,48 +1106,48 @@ class AbortMultipartUploadRequest(ServiceRequest): Bucket: BucketName Key: ObjectKey UploadId: MultipartUploadId - RequestPayer: Optional[RequestPayer] - ExpectedBucketOwner: Optional[AccountId] - IfMatchInitiatedTime: Optional[IfMatchInitiatedTime] + RequestPayer: RequestPayer | None + ExpectedBucketOwner: AccountId | None + IfMatchInitiatedTime: IfMatchInitiatedTime | None class AccelerateConfiguration(TypedDict, total=False): - Status: Optional[BucketAccelerateStatus] + Status: BucketAccelerateStatus | None class Owner(TypedDict, total=False): - DisplayName: Optional[DisplayName] - ID: Optional[ID] + DisplayName: DisplayName | None + ID: ID | None class Grantee(TypedDict, total=False): - DisplayName: Optional[DisplayName] - EmailAddress: Optional[EmailAddress] - ID: Optional[ID] + DisplayName: DisplayName | None + EmailAddress: EmailAddress | None + ID: ID | None Type: Type - URI: Optional[URI] + URI: URI | None class Grant(TypedDict, total=False): - Grantee: Optional[Grantee] - Permission: Optional[Permission] + Grantee: Grantee | None + Permission: Permission | None -Grants = List[Grant] +Grants = list[Grant] class AccessControlPolicy(TypedDict, total=False): - Grants: Optional[Grants] - Owner: Optional[Owner] + Grants: Grants | None + Owner: Owner | None class AccessControlTranslation(TypedDict, total=False): Owner: OwnerOverride -AllowedHeaders = List[AllowedHeader] -AllowedMethods = List[AllowedMethod] -AllowedOrigins = List[AllowedOrigin] +AllowedHeaders = list[AllowedHeader] +AllowedMethods = list[AllowedMethod] +AllowedOrigins = list[AllowedOrigin] class Tag(TypedDict, total=False): @@ -1128,19 +1155,19 @@ class Tag(TypedDict, total=False): Value: Value -TagSet = List[Tag] +TagSet = list[Tag] class AnalyticsAndOperator(TypedDict, total=False): - Prefix: Optional[Prefix] - Tags: Optional[TagSet] + Prefix: Prefix | None + Tags: TagSet | None class AnalyticsS3BucketDestination(TypedDict, total=False): Format: AnalyticsS3ExportFileFormat - BucketAccountId: Optional[AccountId] + BucketAccountId: AccountId | None Bucket: BucketName - Prefix: Optional[Prefix] + Prefix: Prefix | None class AnalyticsExportDestination(TypedDict, total=False): @@ -1153,98 +1180,105 @@ class StorageClassAnalysisDataExport(TypedDict, total=False): class StorageClassAnalysis(TypedDict, total=False): - DataExport: Optional[StorageClassAnalysisDataExport] + DataExport: StorageClassAnalysisDataExport | None class AnalyticsFilter(TypedDict, total=False): - Prefix: Optional[Prefix] - Tag: Optional[Tag] - And: Optional[AnalyticsAndOperator] + Prefix: Prefix | None + Tag: Tag | None + And: AnalyticsAndOperator | None class AnalyticsConfiguration(TypedDict, total=False): Id: AnalyticsId - Filter: Optional[AnalyticsFilter] + Filter: AnalyticsFilter | None StorageClassAnalysis: StorageClassAnalysis -AnalyticsConfigurationList = List[AnalyticsConfiguration] +AnalyticsConfigurationList = list[AnalyticsConfiguration] +EncryptionTypeList = list[EncryptionType] + + +class BlockedEncryptionTypes(TypedDict, total=False): + EncryptionType: EncryptionTypeList | None + + Body = bytes CreationDate = datetime class Bucket(TypedDict, total=False): - Name: Optional[BucketName] - CreationDate: Optional[CreationDate] - BucketRegion: Optional[BucketRegion] - BucketArn: Optional[S3RegionalOrS3ExpressBucketArnString] + Name: BucketName | None + CreationDate: CreationDate | None + BucketRegion: BucketRegion | None + BucketArn: S3RegionalOrS3ExpressBucketArnString | None class BucketInfo(TypedDict, total=False): - DataRedundancy: Optional[DataRedundancy] - Type: Optional[BucketType] + DataRedundancy: DataRedundancy | None + Type: BucketType | None class NoncurrentVersionExpiration(TypedDict, total=False): - NoncurrentDays: Optional[Days] - NewerNoncurrentVersions: Optional[VersionCount] + NoncurrentDays: Days | None + NewerNoncurrentVersions: VersionCount | None class NoncurrentVersionTransition(TypedDict, total=False): - NoncurrentDays: Optional[Days] - StorageClass: Optional[TransitionStorageClass] - NewerNoncurrentVersions: Optional[VersionCount] + NoncurrentDays: Days | None + StorageClass: TransitionStorageClass | None + NewerNoncurrentVersions: VersionCount | None -NoncurrentVersionTransitionList = List[NoncurrentVersionTransition] +NoncurrentVersionTransitionList = list[NoncurrentVersionTransition] Date = datetime class Transition(TypedDict, total=False): - Date: Optional[Date] - Days: Optional[Days] - StorageClass: Optional[TransitionStorageClass] + Date: Date | None + Days: Days | None + StorageClass: TransitionStorageClass | None -TransitionList = List[Transition] +TransitionList = list[Transition] ObjectSizeLessThanBytes = int ObjectSizeGreaterThanBytes = int class LifecycleRuleAndOperator(TypedDict, total=False): - Prefix: Optional[Prefix] - Tags: Optional[TagSet] - ObjectSizeGreaterThan: Optional[ObjectSizeGreaterThanBytes] - ObjectSizeLessThan: Optional[ObjectSizeLessThanBytes] + Prefix: Prefix | None + Tags: TagSet | None + ObjectSizeGreaterThan: ObjectSizeGreaterThanBytes | None + ObjectSizeLessThan: ObjectSizeLessThanBytes | None class LifecycleRuleFilter(TypedDict, total=False): - Prefix: Optional[Prefix] - Tag: Optional[Tag] - ObjectSizeGreaterThan: Optional[ObjectSizeGreaterThanBytes] - ObjectSizeLessThan: Optional[ObjectSizeLessThanBytes] - And: Optional[LifecycleRuleAndOperator] + Prefix: Prefix | None + Tag: Tag | None + ObjectSizeGreaterThan: ObjectSizeGreaterThanBytes | None + ObjectSizeLessThan: ObjectSizeLessThanBytes | None + And: LifecycleRuleAndOperator | None class LifecycleExpiration(TypedDict, total=False): - Date: Optional[Date] - Days: Optional[Days] - ExpiredObjectDeleteMarker: Optional[ExpiredObjectDeleteMarker] + Date: Date | None + Days: Days | None + ExpiredObjectDeleteMarker: ExpiredObjectDeleteMarker | None class LifecycleRule(TypedDict, total=False): - Expiration: Optional[LifecycleExpiration] - ID: Optional[ID] - Prefix: Optional[Prefix] - Filter: Optional[LifecycleRuleFilter] + Expiration: LifecycleExpiration | None + ID: ID | None + Prefix: Prefix | None + Filter: LifecycleRuleFilter | None Status: ExpirationStatus - Transitions: Optional[TransitionList] - NoncurrentVersionTransitions: Optional[NoncurrentVersionTransitionList] - NoncurrentVersionExpiration: Optional[NoncurrentVersionExpiration] - AbortIncompleteMultipartUpload: Optional[AbortIncompleteMultipartUpload] + Transitions: TransitionList | None + NoncurrentVersionTransitions: NoncurrentVersionTransitionList | None + NoncurrentVersionExpiration: NoncurrentVersionExpiration | None + AbortIncompleteMultipartUpload: AbortIncompleteMultipartUpload | None -LifecycleRules = List[LifecycleRule] +LifecycleRules = list[LifecycleRule] class BucketLifecycleConfiguration(TypedDict, total=False): @@ -1252,7 +1286,7 @@ class BucketLifecycleConfiguration(TypedDict, total=False): class PartitionedPrefix(TypedDict, total=False): - PartitionDateSource: Optional[PartitionDateSource] + PartitionDateSource: PartitionDateSource | None class SimplePrefix(TypedDict, total=False): @@ -1260,46 +1294,46 @@ class SimplePrefix(TypedDict, total=False): class TargetObjectKeyFormat(TypedDict, total=False): - SimplePrefix: Optional[SimplePrefix] - PartitionedPrefix: Optional[PartitionedPrefix] + SimplePrefix: SimplePrefix | None + PartitionedPrefix: PartitionedPrefix | None class TargetGrant(TypedDict, total=False): - Grantee: Optional[Grantee] - Permission: Optional[BucketLogsPermission] + Grantee: Grantee | None + Permission: BucketLogsPermission | None -TargetGrants = List[TargetGrant] +TargetGrants = list[TargetGrant] class LoggingEnabled(TypedDict, total=False): TargetBucket: TargetBucket - TargetGrants: Optional[TargetGrants] + TargetGrants: TargetGrants | None TargetPrefix: TargetPrefix - TargetObjectKeyFormat: Optional[TargetObjectKeyFormat] + TargetObjectKeyFormat: TargetObjectKeyFormat | None class BucketLoggingStatus(TypedDict, total=False): - LoggingEnabled: Optional[LoggingEnabled] + LoggingEnabled: LoggingEnabled | None -Buckets = List[Bucket] +Buckets = list[Bucket] BytesProcessed = int BytesReturned = int BytesScanned = int -ExposeHeaders = List[ExposeHeader] +ExposeHeaders = list[ExposeHeader] class CORSRule(TypedDict, total=False): - ID: Optional[ID] - AllowedHeaders: Optional[AllowedHeaders] + ID: ID | None + AllowedHeaders: AllowedHeaders | None AllowedMethods: AllowedMethods AllowedOrigins: AllowedOrigins - ExposeHeaders: Optional[ExposeHeaders] - MaxAgeSeconds: Optional[MaxAgeSeconds] + ExposeHeaders: ExposeHeaders | None + MaxAgeSeconds: MaxAgeSeconds | None -CORSRules = List[CORSRule] +CORSRules = list[CORSRule] class CORSConfiguration(TypedDict, total=False): @@ -1307,114 +1341,114 @@ class CORSConfiguration(TypedDict, total=False): class CSVInput(TypedDict, total=False): - FileHeaderInfo: Optional[FileHeaderInfo] - Comments: Optional[Comments] - QuoteEscapeCharacter: Optional[QuoteEscapeCharacter] - RecordDelimiter: Optional[RecordDelimiter] - FieldDelimiter: Optional[FieldDelimiter] - QuoteCharacter: Optional[QuoteCharacter] - AllowQuotedRecordDelimiter: Optional[AllowQuotedRecordDelimiter] + FileHeaderInfo: FileHeaderInfo | None + Comments: Comments | None + QuoteEscapeCharacter: QuoteEscapeCharacter | None + RecordDelimiter: RecordDelimiter | None + FieldDelimiter: FieldDelimiter | None + QuoteCharacter: QuoteCharacter | None + AllowQuotedRecordDelimiter: AllowQuotedRecordDelimiter | None class CSVOutput(TypedDict, total=False): - QuoteFields: Optional[QuoteFields] - QuoteEscapeCharacter: Optional[QuoteEscapeCharacter] - RecordDelimiter: Optional[RecordDelimiter] - FieldDelimiter: Optional[FieldDelimiter] - QuoteCharacter: Optional[QuoteCharacter] + QuoteFields: QuoteFields | None + QuoteEscapeCharacter: QuoteEscapeCharacter | None + RecordDelimiter: RecordDelimiter | None + FieldDelimiter: FieldDelimiter | None + QuoteCharacter: QuoteCharacter | None class Checksum(TypedDict, total=False): - ChecksumCRC32: Optional[ChecksumCRC32] - ChecksumCRC32C: Optional[ChecksumCRC32C] - ChecksumCRC64NVME: Optional[ChecksumCRC64NVME] - ChecksumSHA1: Optional[ChecksumSHA1] - ChecksumSHA256: Optional[ChecksumSHA256] - ChecksumType: Optional[ChecksumType] + ChecksumCRC32: ChecksumCRC32 | None + ChecksumCRC32C: ChecksumCRC32C | None + ChecksumCRC64NVME: ChecksumCRC64NVME | None + ChecksumSHA1: ChecksumSHA1 | None + ChecksumSHA256: ChecksumSHA256 | None + ChecksumType: ChecksumType | None -ChecksumAlgorithmList = List[ChecksumAlgorithm] -EventList = List[Event] +ChecksumAlgorithmList = list[ChecksumAlgorithm] +EventList = list[Event] class CloudFunctionConfiguration(TypedDict, total=False): - Id: Optional[NotificationId] - Event: Optional[Event] - Events: Optional[EventList] - CloudFunction: Optional[CloudFunction] - InvocationRole: Optional[CloudFunctionInvocationRole] + Id: NotificationId | None + Event: Event | None + Events: EventList | None + CloudFunction: CloudFunction | None + InvocationRole: CloudFunctionInvocationRole | None class CommonPrefix(TypedDict, total=False): - Prefix: Optional[Prefix] + Prefix: Prefix | None -CommonPrefixList = List[CommonPrefix] +CommonPrefixList = list[CommonPrefix] class CompleteMultipartUploadOutput(TypedDict, total=False): - Location: Optional[Location] - Bucket: Optional[BucketName] - Key: Optional[ObjectKey] - Expiration: Optional[Expiration] - ETag: Optional[ETag] - ChecksumCRC32: Optional[ChecksumCRC32] - ChecksumCRC32C: Optional[ChecksumCRC32C] - ChecksumCRC64NVME: Optional[ChecksumCRC64NVME] - ChecksumSHA1: Optional[ChecksumSHA1] - ChecksumSHA256: Optional[ChecksumSHA256] - ChecksumType: Optional[ChecksumType] - ServerSideEncryption: Optional[ServerSideEncryption] - VersionId: Optional[ObjectVersionId] - SSEKMSKeyId: Optional[SSEKMSKeyId] - BucketKeyEnabled: Optional[BucketKeyEnabled] - RequestCharged: Optional[RequestCharged] + Location: Location | None + Bucket: BucketName | None + Key: ObjectKey | None + Expiration: Expiration | None + ETag: ETag | None + ChecksumCRC32: ChecksumCRC32 | None + ChecksumCRC32C: ChecksumCRC32C | None + ChecksumCRC64NVME: ChecksumCRC64NVME | None + ChecksumSHA1: ChecksumSHA1 | None + ChecksumSHA256: ChecksumSHA256 | None + ChecksumType: ChecksumType | None + ServerSideEncryption: ServerSideEncryption | None + VersionId: ObjectVersionId | None + SSEKMSKeyId: SSEKMSKeyId | None + BucketKeyEnabled: BucketKeyEnabled | None + RequestCharged: RequestCharged | None MpuObjectSize = int class CompletedPart(TypedDict, total=False): - ETag: Optional[ETag] - ChecksumCRC32: Optional[ChecksumCRC32] - ChecksumCRC32C: Optional[ChecksumCRC32C] - ChecksumCRC64NVME: Optional[ChecksumCRC64NVME] - ChecksumSHA1: Optional[ChecksumSHA1] - ChecksumSHA256: Optional[ChecksumSHA256] - PartNumber: Optional[PartNumber] + ETag: ETag | None + ChecksumCRC32: ChecksumCRC32 | None + ChecksumCRC32C: ChecksumCRC32C | None + ChecksumCRC64NVME: ChecksumCRC64NVME | None + ChecksumSHA1: ChecksumSHA1 | None + ChecksumSHA256: ChecksumSHA256 | None + PartNumber: PartNumber | None -CompletedPartList = List[CompletedPart] +CompletedPartList = list[CompletedPart] class CompletedMultipartUpload(TypedDict, total=False): - Parts: Optional[CompletedPartList] + Parts: CompletedPartList | None class CompleteMultipartUploadRequest(ServiceRequest): Bucket: BucketName Key: ObjectKey - MultipartUpload: Optional[CompletedMultipartUpload] + MultipartUpload: CompletedMultipartUpload | None UploadId: MultipartUploadId - ChecksumCRC32: Optional[ChecksumCRC32] - ChecksumCRC32C: Optional[ChecksumCRC32C] - ChecksumCRC64NVME: Optional[ChecksumCRC64NVME] - ChecksumSHA1: Optional[ChecksumSHA1] - ChecksumSHA256: Optional[ChecksumSHA256] - ChecksumType: Optional[ChecksumType] - MpuObjectSize: Optional[MpuObjectSize] - RequestPayer: Optional[RequestPayer] - ExpectedBucketOwner: Optional[AccountId] - IfMatch: Optional[IfMatch] - IfNoneMatch: Optional[IfNoneMatch] - SSECustomerAlgorithm: Optional[SSECustomerAlgorithm] - SSECustomerKey: Optional[SSECustomerKey] - SSECustomerKeyMD5: Optional[SSECustomerKeyMD5] + ChecksumCRC32: ChecksumCRC32 | None + ChecksumCRC32C: ChecksumCRC32C | None + ChecksumCRC64NVME: ChecksumCRC64NVME | None + ChecksumSHA1: ChecksumSHA1 | None + ChecksumSHA256: ChecksumSHA256 | None + ChecksumType: ChecksumType | None + MpuObjectSize: MpuObjectSize | None + RequestPayer: RequestPayer | None + ExpectedBucketOwner: AccountId | None + IfMatch: IfMatch | None + IfNoneMatch: IfNoneMatch | None + SSECustomerAlgorithm: SSECustomerAlgorithm | None + SSECustomerKey: SSECustomerKey | None + SSECustomerKeyMD5: SSECustomerKeyMD5 | None class Condition(TypedDict, total=False): - HttpErrorCodeReturnedEquals: Optional[HttpErrorCodeReturnedEquals] - KeyPrefixEquals: Optional[KeyPrefixEquals] + HttpErrorCodeReturnedEquals: HttpErrorCodeReturnedEquals | None + KeyPrefixEquals: KeyPrefixEquals | None ContentLength = int @@ -1428,133 +1462,135 @@ class ContinuationEvent(TypedDict, total=False): class CopyObjectResult(TypedDict, total=False): - ETag: Optional[ETag] - LastModified: Optional[LastModified] - ChecksumType: Optional[ChecksumType] - ChecksumCRC32: Optional[ChecksumCRC32] - ChecksumCRC32C: Optional[ChecksumCRC32C] - ChecksumCRC64NVME: Optional[ChecksumCRC64NVME] - ChecksumSHA1: Optional[ChecksumSHA1] - ChecksumSHA256: Optional[ChecksumSHA256] + ETag: ETag | None + LastModified: LastModified | None + ChecksumType: ChecksumType | None + ChecksumCRC32: ChecksumCRC32 | None + ChecksumCRC32C: ChecksumCRC32C | None + ChecksumCRC64NVME: ChecksumCRC64NVME | None + ChecksumSHA1: ChecksumSHA1 | None + ChecksumSHA256: ChecksumSHA256 | None class CopyObjectOutput(TypedDict, total=False): - CopyObjectResult: Optional[CopyObjectResult] - Expiration: Optional[Expiration] - CopySourceVersionId: Optional[CopySourceVersionId] - VersionId: Optional[ObjectVersionId] - ServerSideEncryption: Optional[ServerSideEncryption] - SSECustomerAlgorithm: Optional[SSECustomerAlgorithm] - SSECustomerKeyMD5: Optional[SSECustomerKeyMD5] - SSEKMSKeyId: Optional[SSEKMSKeyId] - SSEKMSEncryptionContext: Optional[SSEKMSEncryptionContext] - BucketKeyEnabled: Optional[BucketKeyEnabled] - RequestCharged: Optional[RequestCharged] + CopyObjectResult: CopyObjectResult | None + Expiration: Expiration | None + CopySourceVersionId: CopySourceVersionId | None + VersionId: ObjectVersionId | None + ServerSideEncryption: ServerSideEncryption | None + SSECustomerAlgorithm: SSECustomerAlgorithm | None + SSECustomerKeyMD5: SSECustomerKeyMD5 | None + SSEKMSKeyId: SSEKMSKeyId | None + SSEKMSEncryptionContext: SSEKMSEncryptionContext | None + BucketKeyEnabled: BucketKeyEnabled | None + RequestCharged: RequestCharged | None ObjectLockRetainUntilDate = datetime -Metadata = Dict[MetadataKey, MetadataValue] +Metadata = dict[MetadataKey, MetadataValue] CopySourceIfUnmodifiedSince = datetime CopySourceIfModifiedSince = datetime class CopyObjectRequest(ServiceRequest): - ACL: Optional[ObjectCannedACL] + ACL: ObjectCannedACL | None Bucket: BucketName - CacheControl: Optional[CacheControl] - ChecksumAlgorithm: Optional[ChecksumAlgorithm] - ContentDisposition: Optional[ContentDisposition] - ContentEncoding: Optional[ContentEncoding] - ContentLanguage: Optional[ContentLanguage] - ContentType: Optional[ContentType] + CacheControl: CacheControl | None + ChecksumAlgorithm: ChecksumAlgorithm | None + ContentDisposition: ContentDisposition | None + ContentEncoding: ContentEncoding | None + ContentLanguage: ContentLanguage | None + ContentType: ContentType | None CopySource: CopySource - CopySourceIfMatch: Optional[CopySourceIfMatch] - CopySourceIfModifiedSince: Optional[CopySourceIfModifiedSince] - CopySourceIfNoneMatch: Optional[CopySourceIfNoneMatch] - CopySourceIfUnmodifiedSince: Optional[CopySourceIfUnmodifiedSince] - Expires: Optional[Expires] - GrantFullControl: Optional[GrantFullControl] - GrantRead: Optional[GrantRead] - GrantReadACP: Optional[GrantReadACP] - GrantWriteACP: Optional[GrantWriteACP] + CopySourceIfMatch: CopySourceIfMatch | None + CopySourceIfModifiedSince: CopySourceIfModifiedSince | None + CopySourceIfNoneMatch: CopySourceIfNoneMatch | None + CopySourceIfUnmodifiedSince: CopySourceIfUnmodifiedSince | None + Expires: Expires | None + GrantFullControl: GrantFullControl | None + GrantRead: GrantRead | None + GrantReadACP: GrantReadACP | None + GrantWriteACP: GrantWriteACP | None + IfMatch: IfMatch | None + IfNoneMatch: IfNoneMatch | None Key: ObjectKey - Metadata: Optional[Metadata] - MetadataDirective: Optional[MetadataDirective] - TaggingDirective: Optional[TaggingDirective] - ServerSideEncryption: Optional[ServerSideEncryption] - StorageClass: Optional[StorageClass] - WebsiteRedirectLocation: Optional[WebsiteRedirectLocation] - SSECustomerAlgorithm: Optional[SSECustomerAlgorithm] - SSECustomerKey: Optional[SSECustomerKey] - SSECustomerKeyMD5: Optional[SSECustomerKeyMD5] - SSEKMSKeyId: Optional[SSEKMSKeyId] - SSEKMSEncryptionContext: Optional[SSEKMSEncryptionContext] - BucketKeyEnabled: Optional[BucketKeyEnabled] - CopySourceSSECustomerAlgorithm: Optional[CopySourceSSECustomerAlgorithm] - CopySourceSSECustomerKey: Optional[CopySourceSSECustomerKey] - CopySourceSSECustomerKeyMD5: Optional[CopySourceSSECustomerKeyMD5] - RequestPayer: Optional[RequestPayer] - Tagging: Optional[TaggingHeader] - ObjectLockMode: Optional[ObjectLockMode] - ObjectLockRetainUntilDate: Optional[ObjectLockRetainUntilDate] - ObjectLockLegalHoldStatus: Optional[ObjectLockLegalHoldStatus] - ExpectedBucketOwner: Optional[AccountId] - ExpectedSourceBucketOwner: Optional[AccountId] + Metadata: Metadata | None + MetadataDirective: MetadataDirective | None + TaggingDirective: TaggingDirective | None + ServerSideEncryption: ServerSideEncryption | None + StorageClass: StorageClass | None + WebsiteRedirectLocation: WebsiteRedirectLocation | None + SSECustomerAlgorithm: SSECustomerAlgorithm | None + SSECustomerKey: SSECustomerKey | None + SSECustomerKeyMD5: SSECustomerKeyMD5 | None + SSEKMSKeyId: SSEKMSKeyId | None + SSEKMSEncryptionContext: SSEKMSEncryptionContext | None + BucketKeyEnabled: BucketKeyEnabled | None + CopySourceSSECustomerAlgorithm: CopySourceSSECustomerAlgorithm | None + CopySourceSSECustomerKey: CopySourceSSECustomerKey | None + CopySourceSSECustomerKeyMD5: CopySourceSSECustomerKeyMD5 | None + RequestPayer: RequestPayer | None + Tagging: TaggingHeader | None + ObjectLockMode: ObjectLockMode | None + ObjectLockRetainUntilDate: ObjectLockRetainUntilDate | None + ObjectLockLegalHoldStatus: ObjectLockLegalHoldStatus | None + ExpectedBucketOwner: AccountId | None + ExpectedSourceBucketOwner: AccountId | None class CopyPartResult(TypedDict, total=False): - ETag: Optional[ETag] - LastModified: Optional[LastModified] - ChecksumCRC32: Optional[ChecksumCRC32] - ChecksumCRC32C: Optional[ChecksumCRC32C] - ChecksumCRC64NVME: Optional[ChecksumCRC64NVME] - ChecksumSHA1: Optional[ChecksumSHA1] - ChecksumSHA256: Optional[ChecksumSHA256] + ETag: ETag | None + LastModified: LastModified | None + ChecksumCRC32: ChecksumCRC32 | None + ChecksumCRC32C: ChecksumCRC32C | None + ChecksumCRC64NVME: ChecksumCRC64NVME | None + ChecksumSHA1: ChecksumSHA1 | None + ChecksumSHA256: ChecksumSHA256 | None class LocationInfo(TypedDict, total=False): - Type: Optional[LocationType] - Name: Optional[LocationNameAsString] + Type: LocationType | None + Name: LocationNameAsString | None class CreateBucketConfiguration(TypedDict, total=False): - LocationConstraint: Optional[BucketLocationConstraint] - Location: Optional[LocationInfo] - Bucket: Optional[BucketInfo] - Tags: Optional[TagSet] + LocationConstraint: BucketLocationConstraint | None + Location: LocationInfo | None + Bucket: BucketInfo | None + Tags: TagSet | None class MetadataTableEncryptionConfiguration(TypedDict, total=False): SseAlgorithm: TableSseAlgorithm - KmsKeyArn: Optional[KmsKeyArn] + KmsKeyArn: KmsKeyArn | None class InventoryTableConfiguration(TypedDict, total=False): ConfigurationState: InventoryConfigurationState - EncryptionConfiguration: Optional[MetadataTableEncryptionConfiguration] + EncryptionConfiguration: MetadataTableEncryptionConfiguration | None class RecordExpiration(TypedDict, total=False): Expiration: ExpirationState - Days: Optional[RecordExpirationDays] + Days: RecordExpirationDays | None class JournalTableConfiguration(TypedDict, total=False): RecordExpiration: RecordExpiration - EncryptionConfiguration: Optional[MetadataTableEncryptionConfiguration] + EncryptionConfiguration: MetadataTableEncryptionConfiguration | None class MetadataConfiguration(TypedDict, total=False): JournalTableConfiguration: JournalTableConfiguration - InventoryTableConfiguration: Optional[InventoryTableConfiguration] + InventoryTableConfiguration: InventoryTableConfiguration | None class CreateBucketMetadataConfigurationRequest(ServiceRequest): Bucket: BucketName - ContentMD5: Optional[ContentMD5] - ChecksumAlgorithm: Optional[ChecksumAlgorithm] + ContentMD5: ContentMD5 | None + ChecksumAlgorithm: ChecksumAlgorithm | None MetadataConfiguration: MetadataConfiguration - ExpectedBucketOwner: Optional[AccountId] + ExpectedBucketOwner: AccountId | None class S3TablesDestination(TypedDict, total=False): @@ -1568,79 +1604,79 @@ class MetadataTableConfiguration(TypedDict, total=False): class CreateBucketMetadataTableConfigurationRequest(ServiceRequest): Bucket: BucketName - ContentMD5: Optional[ContentMD5] - ChecksumAlgorithm: Optional[ChecksumAlgorithm] + ContentMD5: ContentMD5 | None + ChecksumAlgorithm: ChecksumAlgorithm | None MetadataTableConfiguration: MetadataTableConfiguration - ExpectedBucketOwner: Optional[AccountId] + ExpectedBucketOwner: AccountId | None class CreateBucketOutput(TypedDict, total=False): - Location: Optional[Location] - BucketArn: Optional[S3RegionalOrS3ExpressBucketArnString] + Location: Location | None + BucketArn: S3RegionalOrS3ExpressBucketArnString | None class CreateBucketRequest(ServiceRequest): - ACL: Optional[BucketCannedACL] + ACL: BucketCannedACL | None Bucket: BucketName - CreateBucketConfiguration: Optional[CreateBucketConfiguration] - GrantFullControl: Optional[GrantFullControl] - GrantRead: Optional[GrantRead] - GrantReadACP: Optional[GrantReadACP] - GrantWrite: Optional[GrantWrite] - GrantWriteACP: Optional[GrantWriteACP] - ObjectLockEnabledForBucket: Optional[ObjectLockEnabledForBucket] - ObjectOwnership: Optional[ObjectOwnership] + CreateBucketConfiguration: CreateBucketConfiguration | None + GrantFullControl: GrantFullControl | None + GrantRead: GrantRead | None + GrantReadACP: GrantReadACP | None + GrantWrite: GrantWrite | None + GrantWriteACP: GrantWriteACP | None + ObjectLockEnabledForBucket: ObjectLockEnabledForBucket | None + ObjectOwnership: ObjectOwnership | None class CreateMultipartUploadOutput(TypedDict, total=False): - AbortDate: Optional[AbortDate] - AbortRuleId: Optional[AbortRuleId] - Bucket: Optional[BucketName] - Key: Optional[ObjectKey] - UploadId: Optional[MultipartUploadId] - ServerSideEncryption: Optional[ServerSideEncryption] - SSECustomerAlgorithm: Optional[SSECustomerAlgorithm] - SSECustomerKeyMD5: Optional[SSECustomerKeyMD5] - SSEKMSKeyId: Optional[SSEKMSKeyId] - SSEKMSEncryptionContext: Optional[SSEKMSEncryptionContext] - BucketKeyEnabled: Optional[BucketKeyEnabled] - RequestCharged: Optional[RequestCharged] - ChecksumAlgorithm: Optional[ChecksumAlgorithm] - ChecksumType: Optional[ChecksumType] + AbortDate: AbortDate | None + AbortRuleId: AbortRuleId | None + Bucket: BucketName | None + Key: ObjectKey | None + UploadId: MultipartUploadId | None + ServerSideEncryption: ServerSideEncryption | None + SSECustomerAlgorithm: SSECustomerAlgorithm | None + SSECustomerKeyMD5: SSECustomerKeyMD5 | None + SSEKMSKeyId: SSEKMSKeyId | None + SSEKMSEncryptionContext: SSEKMSEncryptionContext | None + BucketKeyEnabled: BucketKeyEnabled | None + RequestCharged: RequestCharged | None + ChecksumAlgorithm: ChecksumAlgorithm | None + ChecksumType: ChecksumType | None class CreateMultipartUploadRequest(ServiceRequest): - ACL: Optional[ObjectCannedACL] + ACL: ObjectCannedACL | None Bucket: BucketName - CacheControl: Optional[CacheControl] - ContentDisposition: Optional[ContentDisposition] - ContentEncoding: Optional[ContentEncoding] - ContentLanguage: Optional[ContentLanguage] - ContentType: Optional[ContentType] - Expires: Optional[Expires] - GrantFullControl: Optional[GrantFullControl] - GrantRead: Optional[GrantRead] - GrantReadACP: Optional[GrantReadACP] - GrantWriteACP: Optional[GrantWriteACP] + CacheControl: CacheControl | None + ContentDisposition: ContentDisposition | None + ContentEncoding: ContentEncoding | None + ContentLanguage: ContentLanguage | None + ContentType: ContentType | None + Expires: Expires | None + GrantFullControl: GrantFullControl | None + GrantRead: GrantRead | None + GrantReadACP: GrantReadACP | None + GrantWriteACP: GrantWriteACP | None Key: ObjectKey - Metadata: Optional[Metadata] - ServerSideEncryption: Optional[ServerSideEncryption] - StorageClass: Optional[StorageClass] - WebsiteRedirectLocation: Optional[WebsiteRedirectLocation] - SSECustomerAlgorithm: Optional[SSECustomerAlgorithm] - SSECustomerKey: Optional[SSECustomerKey] - SSECustomerKeyMD5: Optional[SSECustomerKeyMD5] - SSEKMSKeyId: Optional[SSEKMSKeyId] - SSEKMSEncryptionContext: Optional[SSEKMSEncryptionContext] - BucketKeyEnabled: Optional[BucketKeyEnabled] - RequestPayer: Optional[RequestPayer] - Tagging: Optional[TaggingHeader] - ObjectLockMode: Optional[ObjectLockMode] - ObjectLockRetainUntilDate: Optional[ObjectLockRetainUntilDate] - ObjectLockLegalHoldStatus: Optional[ObjectLockLegalHoldStatus] - ExpectedBucketOwner: Optional[AccountId] - ChecksumAlgorithm: Optional[ChecksumAlgorithm] - ChecksumType: Optional[ChecksumType] + Metadata: Metadata | None + ServerSideEncryption: ServerSideEncryption | None + StorageClass: StorageClass | None + WebsiteRedirectLocation: WebsiteRedirectLocation | None + SSECustomerAlgorithm: SSECustomerAlgorithm | None + SSECustomerKey: SSECustomerKey | None + SSECustomerKeyMD5: SSECustomerKeyMD5 | None + SSEKMSKeyId: SSEKMSKeyId | None + SSEKMSEncryptionContext: SSEKMSEncryptionContext | None + BucketKeyEnabled: BucketKeyEnabled | None + RequestPayer: RequestPayer | None + Tagging: TaggingHeader | None + ObjectLockMode: ObjectLockMode | None + ObjectLockRetainUntilDate: ObjectLockRetainUntilDate | None + ObjectLockLegalHoldStatus: ObjectLockLegalHoldStatus | None + ExpectedBucketOwner: AccountId | None + ChecksumAlgorithm: ChecksumAlgorithm | None + ChecksumType: ChecksumType | None SessionExpiration = datetime @@ -1654,26 +1690,26 @@ class SessionCredentials(TypedDict, total=False): class CreateSessionOutput(TypedDict, total=False): - ServerSideEncryption: Optional[ServerSideEncryption] - SSEKMSKeyId: Optional[SSEKMSKeyId] - SSEKMSEncryptionContext: Optional[SSEKMSEncryptionContext] - BucketKeyEnabled: Optional[BucketKeyEnabled] + ServerSideEncryption: ServerSideEncryption | None + SSEKMSKeyId: SSEKMSKeyId | None + SSEKMSEncryptionContext: SSEKMSEncryptionContext | None + BucketKeyEnabled: BucketKeyEnabled | None Credentials: SessionCredentials class CreateSessionRequest(ServiceRequest): - SessionMode: Optional[SessionMode] + SessionMode: SessionMode | None Bucket: BucketName - ServerSideEncryption: Optional[ServerSideEncryption] - SSEKMSKeyId: Optional[SSEKMSKeyId] - SSEKMSEncryptionContext: Optional[SSEKMSEncryptionContext] - BucketKeyEnabled: Optional[BucketKeyEnabled] + ServerSideEncryption: ServerSideEncryption | None + SSEKMSKeyId: SSEKMSKeyId | None + SSEKMSEncryptionContext: SSEKMSEncryptionContext | None + BucketKeyEnabled: BucketKeyEnabled | None class DefaultRetention(TypedDict, total=False): - Mode: Optional[ObjectLockRetentionMode] - Days: Optional[Days] - Years: Optional[Years] + Mode: ObjectLockRetentionMode | None + Days: Days | None + Years: Years | None Size = int @@ -1682,118 +1718,118 @@ class DefaultRetention(TypedDict, total=False): class ObjectIdentifier(TypedDict, total=False): Key: ObjectKey - VersionId: Optional[ObjectVersionId] - ETag: Optional[ETag] - LastModifiedTime: Optional[LastModifiedTime] - Size: Optional[Size] + VersionId: ObjectVersionId | None + ETag: ETag | None + LastModifiedTime: LastModifiedTime | None + Size: Size | None -ObjectIdentifierList = List[ObjectIdentifier] +ObjectIdentifierList = list[ObjectIdentifier] class Delete(TypedDict, total=False): Objects: ObjectIdentifierList - Quiet: Optional[Quiet] + Quiet: Quiet | None class DeleteBucketAnalyticsConfigurationRequest(ServiceRequest): Bucket: BucketName Id: AnalyticsId - ExpectedBucketOwner: Optional[AccountId] + ExpectedBucketOwner: AccountId | None class DeleteBucketCorsRequest(ServiceRequest): Bucket: BucketName - ExpectedBucketOwner: Optional[AccountId] + ExpectedBucketOwner: AccountId | None class DeleteBucketEncryptionRequest(ServiceRequest): Bucket: BucketName - ExpectedBucketOwner: Optional[AccountId] + ExpectedBucketOwner: AccountId | None class DeleteBucketIntelligentTieringConfigurationRequest(ServiceRequest): Bucket: BucketName Id: IntelligentTieringId - ExpectedBucketOwner: Optional[AccountId] + ExpectedBucketOwner: AccountId | None class DeleteBucketInventoryConfigurationRequest(ServiceRequest): Bucket: BucketName Id: InventoryId - ExpectedBucketOwner: Optional[AccountId] + ExpectedBucketOwner: AccountId | None class DeleteBucketLifecycleRequest(ServiceRequest): Bucket: BucketName - ExpectedBucketOwner: Optional[AccountId] + ExpectedBucketOwner: AccountId | None class DeleteBucketMetadataConfigurationRequest(ServiceRequest): Bucket: BucketName - ExpectedBucketOwner: Optional[AccountId] + ExpectedBucketOwner: AccountId | None class DeleteBucketMetadataTableConfigurationRequest(ServiceRequest): Bucket: BucketName - ExpectedBucketOwner: Optional[AccountId] + ExpectedBucketOwner: AccountId | None class DeleteBucketMetricsConfigurationRequest(ServiceRequest): Bucket: BucketName Id: MetricsId - ExpectedBucketOwner: Optional[AccountId] + ExpectedBucketOwner: AccountId | None class DeleteBucketOwnershipControlsRequest(ServiceRequest): Bucket: BucketName - ExpectedBucketOwner: Optional[AccountId] + ExpectedBucketOwner: AccountId | None class DeleteBucketPolicyRequest(ServiceRequest): Bucket: BucketName - ExpectedBucketOwner: Optional[AccountId] + ExpectedBucketOwner: AccountId | None class DeleteBucketReplicationRequest(ServiceRequest): Bucket: BucketName - ExpectedBucketOwner: Optional[AccountId] + ExpectedBucketOwner: AccountId | None class DeleteBucketRequest(ServiceRequest): Bucket: BucketName - ExpectedBucketOwner: Optional[AccountId] + ExpectedBucketOwner: AccountId | None class DeleteBucketTaggingRequest(ServiceRequest): Bucket: BucketName - ExpectedBucketOwner: Optional[AccountId] + ExpectedBucketOwner: AccountId | None class DeleteBucketWebsiteRequest(ServiceRequest): Bucket: BucketName - ExpectedBucketOwner: Optional[AccountId] + ExpectedBucketOwner: AccountId | None class DeleteMarkerEntry(TypedDict, total=False): - Owner: Optional[Owner] - Key: Optional[ObjectKey] - VersionId: Optional[ObjectVersionId] - IsLatest: Optional[IsLatest] - LastModified: Optional[LastModified] + Owner: Owner | None + Key: ObjectKey | None + VersionId: ObjectVersionId | None + IsLatest: IsLatest | None + LastModified: LastModified | None class DeleteMarkerReplication(TypedDict, total=False): - Status: Optional[DeleteMarkerReplicationStatus] + Status: DeleteMarkerReplicationStatus | None -DeleteMarkers = List[DeleteMarkerEntry] +DeleteMarkers = list[DeleteMarkerEntry] class DeleteObjectOutput(TypedDict, total=False): - DeleteMarker: Optional[DeleteMarker] - VersionId: Optional[ObjectVersionId] - RequestCharged: Optional[RequestCharged] + DeleteMarker: DeleteMarker | None + VersionId: ObjectVersionId | None + RequestCharged: RequestCharged | None IfMatchSize = int @@ -1803,75 +1839,75 @@ class DeleteObjectOutput(TypedDict, total=False): class DeleteObjectRequest(ServiceRequest): Bucket: BucketName Key: ObjectKey - MFA: Optional[MFA] - VersionId: Optional[ObjectVersionId] - RequestPayer: Optional[RequestPayer] - BypassGovernanceRetention: Optional[BypassGovernanceRetention] - ExpectedBucketOwner: Optional[AccountId] - IfMatch: Optional[IfMatch] - IfMatchLastModifiedTime: Optional[IfMatchLastModifiedTime] - IfMatchSize: Optional[IfMatchSize] + MFA: MFA | None + VersionId: ObjectVersionId | None + RequestPayer: RequestPayer | None + BypassGovernanceRetention: BypassGovernanceRetention | None + ExpectedBucketOwner: AccountId | None + IfMatch: IfMatch | None + IfMatchLastModifiedTime: IfMatchLastModifiedTime | None + IfMatchSize: IfMatchSize | None class DeleteObjectTaggingOutput(TypedDict, total=False): - VersionId: Optional[ObjectVersionId] + VersionId: ObjectVersionId | None class DeleteObjectTaggingRequest(ServiceRequest): Bucket: BucketName Key: ObjectKey - VersionId: Optional[ObjectVersionId] - ExpectedBucketOwner: Optional[AccountId] + VersionId: ObjectVersionId | None + ExpectedBucketOwner: AccountId | None class Error(TypedDict, total=False): - Key: Optional[ObjectKey] - VersionId: Optional[ObjectVersionId] - Code: Optional[Code] - Message: Optional[Message] + Key: ObjectKey | None + VersionId: ObjectVersionId | None + Code: Code | None + Message: Message | None -Errors = List[Error] +Errors = list[Error] class DeletedObject(TypedDict, total=False): - Key: Optional[ObjectKey] - VersionId: Optional[ObjectVersionId] - DeleteMarker: Optional[DeleteMarker] - DeleteMarkerVersionId: Optional[DeleteMarkerVersionId] + Key: ObjectKey | None + VersionId: ObjectVersionId | None + DeleteMarker: DeleteMarker | None + DeleteMarkerVersionId: DeleteMarkerVersionId | None -DeletedObjects = List[DeletedObject] +DeletedObjects = list[DeletedObject] class DeleteObjectsOutput(TypedDict, total=False): - Deleted: Optional[DeletedObjects] - RequestCharged: Optional[RequestCharged] - Errors: Optional[Errors] + Deleted: DeletedObjects | None + RequestCharged: RequestCharged | None + Errors: Errors | None class DeleteObjectsRequest(ServiceRequest): Bucket: BucketName Delete: Delete - MFA: Optional[MFA] - RequestPayer: Optional[RequestPayer] - BypassGovernanceRetention: Optional[BypassGovernanceRetention] - ExpectedBucketOwner: Optional[AccountId] - ChecksumAlgorithm: Optional[ChecksumAlgorithm] + MFA: MFA | None + RequestPayer: RequestPayer | None + BypassGovernanceRetention: BypassGovernanceRetention | None + ExpectedBucketOwner: AccountId | None + ChecksumAlgorithm: ChecksumAlgorithm | None class DeletePublicAccessBlockRequest(ServiceRequest): Bucket: BucketName - ExpectedBucketOwner: Optional[AccountId] + ExpectedBucketOwner: AccountId | None class ReplicationTimeValue(TypedDict, total=False): - Minutes: Optional[Minutes] + Minutes: Minutes | None class Metrics(TypedDict, total=False): Status: MetricsStatus - EventThreshold: Optional[ReplicationTimeValue] + EventThreshold: ReplicationTimeValue | None class ReplicationTime(TypedDict, total=False): @@ -1880,29 +1916,29 @@ class ReplicationTime(TypedDict, total=False): class EncryptionConfiguration(TypedDict, total=False): - ReplicaKmsKeyID: Optional[ReplicaKmsKeyID] + ReplicaKmsKeyID: ReplicaKmsKeyID | None class Destination(TypedDict, total=False): Bucket: BucketName - Account: Optional[AccountId] - StorageClass: Optional[StorageClass] - AccessControlTranslation: Optional[AccessControlTranslation] - EncryptionConfiguration: Optional[EncryptionConfiguration] - ReplicationTime: Optional[ReplicationTime] - Metrics: Optional[Metrics] + Account: AccountId | None + StorageClass: StorageClass | None + AccessControlTranslation: AccessControlTranslation | None + EncryptionConfiguration: EncryptionConfiguration | None + ReplicationTime: ReplicationTime | None + Metrics: Metrics | None class DestinationResult(TypedDict, total=False): - TableBucketType: Optional[S3TablesBucketType] - TableBucketArn: Optional[S3TablesBucketArn] - TableNamespace: Optional[S3TablesNamespace] + TableBucketType: S3TablesBucketType | None + TableBucketArn: S3TablesBucketArn | None + TableNamespace: S3TablesNamespace | None class Encryption(TypedDict, total=False): EncryptionType: ServerSideEncryption - KMSKeyId: Optional[SSEKMSKeyId] - KMSContext: Optional[KMSContext] + KMSKeyId: SSEKMSKeyId | None + KMSContext: KMSContext | None End = int @@ -1913,8 +1949,8 @@ class EndEvent(TypedDict, total=False): class ErrorDetails(TypedDict, total=False): - ErrorCode: Optional[ErrorCode] - ErrorMessage: Optional[ErrorMessage] + ErrorCode: ErrorCode | None + ErrorMessage: ErrorMessage | None class ErrorDocument(TypedDict, total=False): @@ -1930,64 +1966,74 @@ class ExistingObjectReplication(TypedDict, total=False): class FilterRule(TypedDict, total=False): - Name: Optional[FilterRuleName] - Value: Optional[FilterRuleValue] + Name: FilterRuleName | None + Value: FilterRuleValue | None + +FilterRuleList = list[FilterRule] -FilterRuleList = List[FilterRule] + +class GetBucketAbacOutput(TypedDict, total=False): + AbacStatus: AbacStatus | None + + +class GetBucketAbacRequest(ServiceRequest): + Bucket: BucketName + ExpectedBucketOwner: AccountId | None class GetBucketAccelerateConfigurationOutput(TypedDict, total=False): - Status: Optional[BucketAccelerateStatus] - RequestCharged: Optional[RequestCharged] + Status: BucketAccelerateStatus | None + RequestCharged: RequestCharged | None class GetBucketAccelerateConfigurationRequest(ServiceRequest): Bucket: BucketName - ExpectedBucketOwner: Optional[AccountId] - RequestPayer: Optional[RequestPayer] + ExpectedBucketOwner: AccountId | None + RequestPayer: RequestPayer | None class GetBucketAclOutput(TypedDict, total=False): - Owner: Optional[Owner] - Grants: Optional[Grants] + Owner: Owner | None + Grants: Grants | None class GetBucketAclRequest(ServiceRequest): Bucket: BucketName - ExpectedBucketOwner: Optional[AccountId] + ExpectedBucketOwner: AccountId | None class GetBucketAnalyticsConfigurationOutput(TypedDict, total=False): - AnalyticsConfiguration: Optional[AnalyticsConfiguration] + AnalyticsConfiguration: AnalyticsConfiguration | None class GetBucketAnalyticsConfigurationRequest(ServiceRequest): Bucket: BucketName Id: AnalyticsId - ExpectedBucketOwner: Optional[AccountId] + ExpectedBucketOwner: AccountId | None class GetBucketCorsOutput(TypedDict, total=False): - CORSRules: Optional[CORSRules] + CORSRules: CORSRules | None class GetBucketCorsRequest(ServiceRequest): Bucket: BucketName - ExpectedBucketOwner: Optional[AccountId] + ExpectedBucketOwner: AccountId | None class ServerSideEncryptionByDefault(TypedDict, total=False): SSEAlgorithm: ServerSideEncryption - KMSMasterKeyID: Optional[SSEKMSKeyId] + KMSMasterKeyID: SSEKMSKeyId | None class ServerSideEncryptionRule(TypedDict, total=False): - ApplyServerSideEncryptionByDefault: Optional[ServerSideEncryptionByDefault] - BucketKeyEnabled: Optional[BucketKeyEnabled] + ApplyServerSideEncryptionByDefault: ServerSideEncryptionByDefault | None + BucketKeyEnabled: BucketKeyEnabled | None + BlockedEncryptionTypes: BlockedEncryptionTypes | None -ServerSideEncryptionRules = List[ServerSideEncryptionRule] +ServerSideEncryptionRules = list[ServerSideEncryptionRule] class ServerSideEncryptionConfiguration(TypedDict, total=False): @@ -1995,12 +2041,12 @@ class ServerSideEncryptionConfiguration(TypedDict, total=False): class GetBucketEncryptionOutput(TypedDict, total=False): - ServerSideEncryptionConfiguration: Optional[ServerSideEncryptionConfiguration] + ServerSideEncryptionConfiguration: ServerSideEncryptionConfiguration | None class GetBucketEncryptionRequest(ServiceRequest): Bucket: BucketName - ExpectedBucketOwner: Optional[AccountId] + ExpectedBucketOwner: AccountId | None class Tiering(TypedDict, total=False): @@ -2008,42 +2054,42 @@ class Tiering(TypedDict, total=False): AccessTier: IntelligentTieringAccessTier -TieringList = List[Tiering] +TieringList = list[Tiering] class IntelligentTieringAndOperator(TypedDict, total=False): - Prefix: Optional[Prefix] - Tags: Optional[TagSet] + Prefix: Prefix | None + Tags: TagSet | None class IntelligentTieringFilter(TypedDict, total=False): - Prefix: Optional[Prefix] - Tag: Optional[Tag] - And: Optional[IntelligentTieringAndOperator] + Prefix: Prefix | None + Tag: Tag | None + And: IntelligentTieringAndOperator | None class IntelligentTieringConfiguration(TypedDict, total=False): Id: IntelligentTieringId - Filter: Optional[IntelligentTieringFilter] + Filter: IntelligentTieringFilter | None Status: IntelligentTieringStatus Tierings: TieringList class GetBucketIntelligentTieringConfigurationOutput(TypedDict, total=False): - IntelligentTieringConfiguration: Optional[IntelligentTieringConfiguration] + IntelligentTieringConfiguration: IntelligentTieringConfiguration | None class GetBucketIntelligentTieringConfigurationRequest(ServiceRequest): Bucket: BucketName Id: IntelligentTieringId - ExpectedBucketOwner: Optional[AccountId] + ExpectedBucketOwner: AccountId | None class InventorySchedule(TypedDict, total=False): Frequency: InventoryFrequency -InventoryOptionalFields = List[InventoryOptionalField] +InventoryOptionalFields = list[InventoryOptionalField] class InventoryFilter(TypedDict, total=False): @@ -2059,16 +2105,16 @@ class SSES3(TypedDict, total=False): class InventoryEncryption(TypedDict, total=False): - SSES3: Optional[SSES3] - SSEKMS: Optional[SSEKMS] + SSES3: SSES3 | None + SSEKMS: SSEKMS | None class InventoryS3BucketDestination(TypedDict, total=False): - AccountId: Optional[AccountId] + AccountId: AccountId | None Bucket: BucketName Format: InventoryFormat - Prefix: Optional[Prefix] - Encryption: Optional[InventoryEncryption] + Prefix: Prefix | None + Encryption: InventoryEncryption | None class InventoryDestination(TypedDict, total=False): @@ -2078,94 +2124,94 @@ class InventoryDestination(TypedDict, total=False): class InventoryConfiguration(TypedDict, total=False): Destination: InventoryDestination IsEnabled: IsEnabled - Filter: Optional[InventoryFilter] + Filter: InventoryFilter | None Id: InventoryId IncludedObjectVersions: InventoryIncludedObjectVersions - OptionalFields: Optional[InventoryOptionalFields] + OptionalFields: InventoryOptionalFields | None Schedule: InventorySchedule class GetBucketInventoryConfigurationOutput(TypedDict, total=False): - InventoryConfiguration: Optional[InventoryConfiguration] + InventoryConfiguration: InventoryConfiguration | None class GetBucketInventoryConfigurationRequest(ServiceRequest): Bucket: BucketName Id: InventoryId - ExpectedBucketOwner: Optional[AccountId] + ExpectedBucketOwner: AccountId | None class GetBucketLifecycleConfigurationOutput(TypedDict, total=False): - Rules: Optional[LifecycleRules] - TransitionDefaultMinimumObjectSize: Optional[TransitionDefaultMinimumObjectSize] + Rules: LifecycleRules | None + TransitionDefaultMinimumObjectSize: TransitionDefaultMinimumObjectSize | None class GetBucketLifecycleConfigurationRequest(ServiceRequest): Bucket: BucketName - ExpectedBucketOwner: Optional[AccountId] + ExpectedBucketOwner: AccountId | None class Rule(TypedDict, total=False): - Expiration: Optional[LifecycleExpiration] - ID: Optional[ID] + Expiration: LifecycleExpiration | None + ID: ID | None Prefix: Prefix Status: ExpirationStatus - Transition: Optional[Transition] - NoncurrentVersionTransition: Optional[NoncurrentVersionTransition] - NoncurrentVersionExpiration: Optional[NoncurrentVersionExpiration] - AbortIncompleteMultipartUpload: Optional[AbortIncompleteMultipartUpload] + Transition: Transition | None + NoncurrentVersionTransition: NoncurrentVersionTransition | None + NoncurrentVersionExpiration: NoncurrentVersionExpiration | None + AbortIncompleteMultipartUpload: AbortIncompleteMultipartUpload | None -Rules = List[Rule] +Rules = list[Rule] class GetBucketLifecycleOutput(TypedDict, total=False): - Rules: Optional[Rules] + Rules: Rules | None class GetBucketLifecycleRequest(ServiceRequest): Bucket: BucketName - ExpectedBucketOwner: Optional[AccountId] + ExpectedBucketOwner: AccountId | None class GetBucketLocationOutput(TypedDict, total=False): - LocationConstraint: Optional[BucketLocationConstraint] + LocationConstraint: BucketLocationConstraint | None class GetBucketLocationRequest(ServiceRequest): Bucket: BucketName - ExpectedBucketOwner: Optional[AccountId] + ExpectedBucketOwner: AccountId | None class GetBucketLoggingOutput(TypedDict, total=False): - LoggingEnabled: Optional[LoggingEnabled] + LoggingEnabled: LoggingEnabled | None class GetBucketLoggingRequest(ServiceRequest): Bucket: BucketName - ExpectedBucketOwner: Optional[AccountId] + ExpectedBucketOwner: AccountId | None class InventoryTableConfigurationResult(TypedDict, total=False): ConfigurationState: InventoryConfigurationState - TableStatus: Optional[MetadataTableStatus] - Error: Optional[ErrorDetails] - TableName: Optional[S3TablesName] - TableArn: Optional[S3TablesArn] + TableStatus: MetadataTableStatus | None + Error: ErrorDetails | None + TableName: S3TablesName | None + TableArn: S3TablesArn | None class JournalTableConfigurationResult(TypedDict, total=False): TableStatus: MetadataTableStatus - Error: Optional[ErrorDetails] + Error: ErrorDetails | None TableName: S3TablesName - TableArn: Optional[S3TablesArn] + TableArn: S3TablesArn | None RecordExpiration: RecordExpiration class MetadataConfigurationResult(TypedDict, total=False): DestinationResult: DestinationResult - JournalTableConfigurationResult: Optional[JournalTableConfigurationResult] - InventoryTableConfigurationResult: Optional[InventoryTableConfigurationResult] + JournalTableConfigurationResult: JournalTableConfigurationResult | None + InventoryTableConfigurationResult: InventoryTableConfigurationResult | None class GetBucketMetadataConfigurationResult(TypedDict, total=False): @@ -2173,12 +2219,12 @@ class GetBucketMetadataConfigurationResult(TypedDict, total=False): class GetBucketMetadataConfigurationOutput(TypedDict, total=False): - GetBucketMetadataConfigurationResult: Optional[GetBucketMetadataConfigurationResult] + GetBucketMetadataConfigurationResult: GetBucketMetadataConfigurationResult | None class GetBucketMetadataConfigurationRequest(ServiceRequest): Bucket: BucketName - ExpectedBucketOwner: Optional[AccountId] + ExpectedBucketOwner: AccountId | None class S3TablesDestinationResult(TypedDict, total=False): @@ -2195,56 +2241,56 @@ class MetadataTableConfigurationResult(TypedDict, total=False): class GetBucketMetadataTableConfigurationResult(TypedDict, total=False): MetadataTableConfigurationResult: MetadataTableConfigurationResult Status: MetadataTableStatus - Error: Optional[ErrorDetails] + Error: ErrorDetails | None class GetBucketMetadataTableConfigurationOutput(TypedDict, total=False): - GetBucketMetadataTableConfigurationResult: Optional[GetBucketMetadataTableConfigurationResult] + GetBucketMetadataTableConfigurationResult: GetBucketMetadataTableConfigurationResult | None class GetBucketMetadataTableConfigurationRequest(ServiceRequest): Bucket: BucketName - ExpectedBucketOwner: Optional[AccountId] + ExpectedBucketOwner: AccountId | None class MetricsAndOperator(TypedDict, total=False): - Prefix: Optional[Prefix] - Tags: Optional[TagSet] - AccessPointArn: Optional[AccessPointArn] + Prefix: Prefix | None + Tags: TagSet | None + AccessPointArn: AccessPointArn | None class MetricsFilter(TypedDict, total=False): - Prefix: Optional[Prefix] - Tag: Optional[Tag] - AccessPointArn: Optional[AccessPointArn] - And: Optional[MetricsAndOperator] + Prefix: Prefix | None + Tag: Tag | None + AccessPointArn: AccessPointArn | None + And: MetricsAndOperator | None class MetricsConfiguration(TypedDict, total=False): Id: MetricsId - Filter: Optional[MetricsFilter] + Filter: MetricsFilter | None class GetBucketMetricsConfigurationOutput(TypedDict, total=False): - MetricsConfiguration: Optional[MetricsConfiguration] + MetricsConfiguration: MetricsConfiguration | None class GetBucketMetricsConfigurationRequest(ServiceRequest): Bucket: BucketName Id: MetricsId - ExpectedBucketOwner: Optional[AccountId] + ExpectedBucketOwner: AccountId | None class GetBucketNotificationConfigurationRequest(ServiceRequest): Bucket: BucketName - ExpectedBucketOwner: Optional[AccountId] + ExpectedBucketOwner: AccountId | None class OwnershipControlsRule(TypedDict, total=False): ObjectOwnership: ObjectOwnership -OwnershipControlsRules = List[OwnershipControlsRule] +OwnershipControlsRules = list[OwnershipControlsRule] class OwnershipControls(TypedDict, total=False): @@ -2252,34 +2298,34 @@ class OwnershipControls(TypedDict, total=False): class GetBucketOwnershipControlsOutput(TypedDict, total=False): - OwnershipControls: Optional[OwnershipControls] + OwnershipControls: OwnershipControls | None class GetBucketOwnershipControlsRequest(ServiceRequest): Bucket: BucketName - ExpectedBucketOwner: Optional[AccountId] + ExpectedBucketOwner: AccountId | None class GetBucketPolicyOutput(TypedDict, total=False): - Policy: Optional[Policy] + Policy: Policy | None class GetBucketPolicyRequest(ServiceRequest): Bucket: BucketName - ExpectedBucketOwner: Optional[AccountId] + ExpectedBucketOwner: AccountId | None class PolicyStatus(TypedDict, total=False): - IsPublic: Optional[IsPublic] + IsPublic: IsPublic | None class GetBucketPolicyStatusOutput(TypedDict, total=False): - PolicyStatus: Optional[PolicyStatus] + PolicyStatus: PolicyStatus | None class GetBucketPolicyStatusRequest(ServiceRequest): Bucket: BucketName - ExpectedBucketOwner: Optional[AccountId] + ExpectedBucketOwner: AccountId | None class ReplicaModifications(TypedDict, total=False): @@ -2291,34 +2337,34 @@ class SseKmsEncryptedObjects(TypedDict, total=False): class SourceSelectionCriteria(TypedDict, total=False): - SseKmsEncryptedObjects: Optional[SseKmsEncryptedObjects] - ReplicaModifications: Optional[ReplicaModifications] + SseKmsEncryptedObjects: SseKmsEncryptedObjects | None + ReplicaModifications: ReplicaModifications | None class ReplicationRuleAndOperator(TypedDict, total=False): - Prefix: Optional[Prefix] - Tags: Optional[TagSet] + Prefix: Prefix | None + Tags: TagSet | None class ReplicationRuleFilter(TypedDict, total=False): - Prefix: Optional[Prefix] - Tag: Optional[Tag] - And: Optional[ReplicationRuleAndOperator] + Prefix: Prefix | None + Tag: Tag | None + And: ReplicationRuleAndOperator | None class ReplicationRule(TypedDict, total=False): - ID: Optional[ID] - Priority: Optional[Priority] - Prefix: Optional[Prefix] - Filter: Optional[ReplicationRuleFilter] + ID: ID | None + Priority: Priority | None + Prefix: Prefix | None + Filter: ReplicationRuleFilter | None Status: ReplicationRuleStatus - SourceSelectionCriteria: Optional[SourceSelectionCriteria] - ExistingObjectReplication: Optional[ExistingObjectReplication] + SourceSelectionCriteria: SourceSelectionCriteria | None + ExistingObjectReplication: ExistingObjectReplication | None Destination: Destination - DeleteMarkerReplication: Optional[DeleteMarkerReplication] + DeleteMarkerReplication: DeleteMarkerReplication | None -ReplicationRules = List[ReplicationRule] +ReplicationRules = list[ReplicationRule] class ReplicationConfiguration(TypedDict, total=False): @@ -2327,21 +2373,21 @@ class ReplicationConfiguration(TypedDict, total=False): class GetBucketReplicationOutput(TypedDict, total=False): - ReplicationConfiguration: Optional[ReplicationConfiguration] + ReplicationConfiguration: ReplicationConfiguration | None class GetBucketReplicationRequest(ServiceRequest): Bucket: BucketName - ExpectedBucketOwner: Optional[AccountId] + ExpectedBucketOwner: AccountId | None class GetBucketRequestPaymentOutput(TypedDict, total=False): - Payer: Optional[Payer] + Payer: Payer | None class GetBucketRequestPaymentRequest(ServiceRequest): Bucket: BucketName - ExpectedBucketOwner: Optional[AccountId] + ExpectedBucketOwner: AccountId | None class GetBucketTaggingOutput(TypedDict, total=False): @@ -2350,33 +2396,33 @@ class GetBucketTaggingOutput(TypedDict, total=False): class GetBucketTaggingRequest(ServiceRequest): Bucket: BucketName - ExpectedBucketOwner: Optional[AccountId] + ExpectedBucketOwner: AccountId | None class GetBucketVersioningOutput(TypedDict, total=False): - Status: Optional[BucketVersioningStatus] - MFADelete: Optional[MFADeleteStatus] + Status: BucketVersioningStatus | None + MFADelete: MFADeleteStatus | None class GetBucketVersioningRequest(ServiceRequest): Bucket: BucketName - ExpectedBucketOwner: Optional[AccountId] + ExpectedBucketOwner: AccountId | None class Redirect(TypedDict, total=False): - HostName: Optional[HostName] - HttpRedirectCode: Optional[HttpRedirectCode] - Protocol: Optional[Protocol] - ReplaceKeyPrefixWith: Optional[ReplaceKeyPrefixWith] - ReplaceKeyWith: Optional[ReplaceKeyWith] + HostName: HostName | None + HttpRedirectCode: HttpRedirectCode | None + Protocol: Protocol | None + ReplaceKeyPrefixWith: ReplaceKeyPrefixWith | None + ReplaceKeyWith: ReplaceKeyWith | None class RoutingRule(TypedDict, total=False): - Condition: Optional[Condition] + Condition: Condition | None Redirect: Redirect -RoutingRules = List[RoutingRule] +RoutingRules = list[RoutingRule] class IndexDocument(TypedDict, total=False): @@ -2385,160 +2431,160 @@ class IndexDocument(TypedDict, total=False): class RedirectAllRequestsTo(TypedDict, total=False): HostName: HostName - Protocol: Optional[Protocol] + Protocol: Protocol | None class GetBucketWebsiteOutput(TypedDict, total=False): - RedirectAllRequestsTo: Optional[RedirectAllRequestsTo] - IndexDocument: Optional[IndexDocument] - ErrorDocument: Optional[ErrorDocument] - RoutingRules: Optional[RoutingRules] + RedirectAllRequestsTo: RedirectAllRequestsTo | None + IndexDocument: IndexDocument | None + ErrorDocument: ErrorDocument | None + RoutingRules: RoutingRules | None class GetBucketWebsiteRequest(ServiceRequest): Bucket: BucketName - ExpectedBucketOwner: Optional[AccountId] + ExpectedBucketOwner: AccountId | None class GetObjectAclOutput(TypedDict, total=False): - Owner: Optional[Owner] - Grants: Optional[Grants] - RequestCharged: Optional[RequestCharged] + Owner: Owner | None + Grants: Grants | None + RequestCharged: RequestCharged | None class GetObjectAclRequest(ServiceRequest): Bucket: BucketName Key: ObjectKey - VersionId: Optional[ObjectVersionId] - RequestPayer: Optional[RequestPayer] - ExpectedBucketOwner: Optional[AccountId] + VersionId: ObjectVersionId | None + RequestPayer: RequestPayer | None + ExpectedBucketOwner: AccountId | None class ObjectPart(TypedDict, total=False): - PartNumber: Optional[PartNumber] - Size: Optional[Size] - ChecksumCRC32: Optional[ChecksumCRC32] - ChecksumCRC32C: Optional[ChecksumCRC32C] - ChecksumCRC64NVME: Optional[ChecksumCRC64NVME] - ChecksumSHA1: Optional[ChecksumSHA1] - ChecksumSHA256: Optional[ChecksumSHA256] + PartNumber: PartNumber | None + Size: Size | None + ChecksumCRC32: ChecksumCRC32 | None + ChecksumCRC32C: ChecksumCRC32C | None + ChecksumCRC64NVME: ChecksumCRC64NVME | None + ChecksumSHA1: ChecksumSHA1 | None + ChecksumSHA256: ChecksumSHA256 | None -PartsList = List[ObjectPart] +PartsList = list[ObjectPart] class GetObjectAttributesParts(TypedDict, total=False): - TotalPartsCount: Optional[PartsCount] - PartNumberMarker: Optional[PartNumberMarker] - NextPartNumberMarker: Optional[NextPartNumberMarker] - MaxParts: Optional[MaxParts] - IsTruncated: Optional[IsTruncated] - Parts: Optional[PartsList] + TotalPartsCount: PartsCount | None + PartNumberMarker: PartNumberMarker | None + NextPartNumberMarker: NextPartNumberMarker | None + MaxParts: MaxParts | None + IsTruncated: IsTruncated | None + Parts: PartsList | None class GetObjectAttributesOutput(TypedDict, total=False): - DeleteMarker: Optional[DeleteMarker] - LastModified: Optional[LastModified] - VersionId: Optional[ObjectVersionId] - RequestCharged: Optional[RequestCharged] - ETag: Optional[ETag] - Checksum: Optional[Checksum] - ObjectParts: Optional[GetObjectAttributesParts] - StorageClass: Optional[StorageClass] - ObjectSize: Optional[ObjectSize] + DeleteMarker: DeleteMarker | None + LastModified: LastModified | None + VersionId: ObjectVersionId | None + RequestCharged: RequestCharged | None + ETag: ETag | None + Checksum: Checksum | None + ObjectParts: GetObjectAttributesParts | None + StorageClass: StorageClass | None + ObjectSize: ObjectSize | None -ObjectAttributesList = List[ObjectAttributes] +ObjectAttributesList = list[ObjectAttributes] class GetObjectAttributesRequest(ServiceRequest): Bucket: BucketName Key: ObjectKey - VersionId: Optional[ObjectVersionId] - MaxParts: Optional[MaxParts] - PartNumberMarker: Optional[PartNumberMarker] - SSECustomerAlgorithm: Optional[SSECustomerAlgorithm] - SSECustomerKey: Optional[SSECustomerKey] - SSECustomerKeyMD5: Optional[SSECustomerKeyMD5] - RequestPayer: Optional[RequestPayer] - ExpectedBucketOwner: Optional[AccountId] + VersionId: ObjectVersionId | None + MaxParts: MaxParts | None + PartNumberMarker: PartNumberMarker | None + SSECustomerAlgorithm: SSECustomerAlgorithm | None + SSECustomerKey: SSECustomerKey | None + SSECustomerKeyMD5: SSECustomerKeyMD5 | None + RequestPayer: RequestPayer | None + ExpectedBucketOwner: AccountId | None ObjectAttributes: ObjectAttributesList class ObjectLockLegalHold(TypedDict, total=False): - Status: Optional[ObjectLockLegalHoldStatus] + Status: ObjectLockLegalHoldStatus | None class GetObjectLegalHoldOutput(TypedDict, total=False): - LegalHold: Optional[ObjectLockLegalHold] + LegalHold: ObjectLockLegalHold | None class GetObjectLegalHoldRequest(ServiceRequest): Bucket: BucketName Key: ObjectKey - VersionId: Optional[ObjectVersionId] - RequestPayer: Optional[RequestPayer] - ExpectedBucketOwner: Optional[AccountId] + VersionId: ObjectVersionId | None + RequestPayer: RequestPayer | None + ExpectedBucketOwner: AccountId | None class ObjectLockRule(TypedDict, total=False): - DefaultRetention: Optional[DefaultRetention] + DefaultRetention: DefaultRetention | None class ObjectLockConfiguration(TypedDict, total=False): - ObjectLockEnabled: Optional[ObjectLockEnabled] - Rule: Optional[ObjectLockRule] + ObjectLockEnabled: ObjectLockEnabled | None + Rule: ObjectLockRule | None class GetObjectLockConfigurationOutput(TypedDict, total=False): - ObjectLockConfiguration: Optional[ObjectLockConfiguration] + ObjectLockConfiguration: ObjectLockConfiguration | None class GetObjectLockConfigurationRequest(ServiceRequest): Bucket: BucketName - ExpectedBucketOwner: Optional[AccountId] + ExpectedBucketOwner: AccountId | None class GetObjectOutput(TypedDict, total=False): - Body: Optional[Union[Body, IO[Body], Iterable[Body]]] - DeleteMarker: Optional[DeleteMarker] - AcceptRanges: Optional[AcceptRanges] - Expiration: Optional[Expiration] - Restore: Optional[Restore] - LastModified: Optional[LastModified] - ContentLength: Optional[ContentLength] - ETag: Optional[ETag] - ChecksumCRC32: Optional[ChecksumCRC32] - ChecksumCRC32C: Optional[ChecksumCRC32C] - ChecksumCRC64NVME: Optional[ChecksumCRC64NVME] - ChecksumSHA1: Optional[ChecksumSHA1] - ChecksumSHA256: Optional[ChecksumSHA256] - ChecksumType: Optional[ChecksumType] - MissingMeta: Optional[MissingMeta] - VersionId: Optional[ObjectVersionId] - CacheControl: Optional[CacheControl] - ContentDisposition: Optional[ContentDisposition] - ContentEncoding: Optional[ContentEncoding] - ContentLanguage: Optional[ContentLanguage] - ContentRange: Optional[ContentRange] - ContentType: Optional[ContentType] - Expires: Optional[Expires] - WebsiteRedirectLocation: Optional[WebsiteRedirectLocation] - ServerSideEncryption: Optional[ServerSideEncryption] - Metadata: Optional[Metadata] - SSECustomerAlgorithm: Optional[SSECustomerAlgorithm] - SSECustomerKeyMD5: Optional[SSECustomerKeyMD5] - SSEKMSKeyId: Optional[SSEKMSKeyId] - BucketKeyEnabled: Optional[BucketKeyEnabled] - StorageClass: Optional[StorageClass] - RequestCharged: Optional[RequestCharged] - ReplicationStatus: Optional[ReplicationStatus] - PartsCount: Optional[PartsCount] - TagCount: Optional[TagCount] - ObjectLockMode: Optional[ObjectLockMode] - ObjectLockRetainUntilDate: Optional[ObjectLockRetainUntilDate] - ObjectLockLegalHoldStatus: Optional[ObjectLockLegalHoldStatus] - StatusCode: Optional[GetObjectResponseStatusCode] + Body: Body | IO[Body] | Iterable[Body] | None + DeleteMarker: DeleteMarker | None + AcceptRanges: AcceptRanges | None + Expiration: Expiration | None + Restore: Restore | None + LastModified: LastModified | None + ContentLength: ContentLength | None + ETag: ETag | None + ChecksumCRC32: ChecksumCRC32 | None + ChecksumCRC32C: ChecksumCRC32C | None + ChecksumCRC64NVME: ChecksumCRC64NVME | None + ChecksumSHA1: ChecksumSHA1 | None + ChecksumSHA256: ChecksumSHA256 | None + ChecksumType: ChecksumType | None + MissingMeta: MissingMeta | None + VersionId: ObjectVersionId | None + CacheControl: CacheControl | None + ContentDisposition: ContentDisposition | None + ContentEncoding: ContentEncoding | None + ContentLanguage: ContentLanguage | None + ContentRange: ContentRange | None + ContentType: ContentType | None + Expires: Expires | None + WebsiteRedirectLocation: WebsiteRedirectLocation | None + ServerSideEncryption: ServerSideEncryption | None + Metadata: Metadata | None + SSECustomerAlgorithm: SSECustomerAlgorithm | None + SSECustomerKeyMD5: SSECustomerKeyMD5 | None + SSEKMSKeyId: SSEKMSKeyId | None + BucketKeyEnabled: BucketKeyEnabled | None + StorageClass: StorageClass | None + RequestCharged: RequestCharged | None + ReplicationStatus: ReplicationStatus | None + PartsCount: PartsCount | None + TagCount: TagCount | None + ObjectLockMode: ObjectLockMode | None + ObjectLockRetainUntilDate: ObjectLockRetainUntilDate | None + ObjectLockLegalHoldStatus: ObjectLockLegalHoldStatus | None + StatusCode: GetObjectResponseStatusCode | None ResponseExpires = datetime @@ -2548,84 +2594,84 @@ class GetObjectOutput(TypedDict, total=False): class GetObjectRequest(ServiceRequest): Bucket: BucketName - IfMatch: Optional[IfMatch] - IfModifiedSince: Optional[IfModifiedSince] - IfNoneMatch: Optional[IfNoneMatch] - IfUnmodifiedSince: Optional[IfUnmodifiedSince] + IfMatch: IfMatch | None + IfModifiedSince: IfModifiedSince | None + IfNoneMatch: IfNoneMatch | None + IfUnmodifiedSince: IfUnmodifiedSince | None Key: ObjectKey - Range: Optional[Range] - ResponseCacheControl: Optional[ResponseCacheControl] - ResponseContentDisposition: Optional[ResponseContentDisposition] - ResponseContentEncoding: Optional[ResponseContentEncoding] - ResponseContentLanguage: Optional[ResponseContentLanguage] - ResponseContentType: Optional[ResponseContentType] - ResponseExpires: Optional[ResponseExpires] - VersionId: Optional[ObjectVersionId] - SSECustomerAlgorithm: Optional[SSECustomerAlgorithm] - SSECustomerKey: Optional[SSECustomerKey] - SSECustomerKeyMD5: Optional[SSECustomerKeyMD5] - RequestPayer: Optional[RequestPayer] - PartNumber: Optional[PartNumber] - ExpectedBucketOwner: Optional[AccountId] - ChecksumMode: Optional[ChecksumMode] + Range: Range | None + ResponseCacheControl: ResponseCacheControl | None + ResponseContentDisposition: ResponseContentDisposition | None + ResponseContentEncoding: ResponseContentEncoding | None + ResponseContentLanguage: ResponseContentLanguage | None + ResponseContentType: ResponseContentType | None + ResponseExpires: ResponseExpires | None + VersionId: ObjectVersionId | None + SSECustomerAlgorithm: SSECustomerAlgorithm | None + SSECustomerKey: SSECustomerKey | None + SSECustomerKeyMD5: SSECustomerKeyMD5 | None + RequestPayer: RequestPayer | None + PartNumber: PartNumber | None + ExpectedBucketOwner: AccountId | None + ChecksumMode: ChecksumMode | None class ObjectLockRetention(TypedDict, total=False): - Mode: Optional[ObjectLockRetentionMode] - RetainUntilDate: Optional[Date] + Mode: ObjectLockRetentionMode | None + RetainUntilDate: Date | None class GetObjectRetentionOutput(TypedDict, total=False): - Retention: Optional[ObjectLockRetention] + Retention: ObjectLockRetention | None class GetObjectRetentionRequest(ServiceRequest): Bucket: BucketName Key: ObjectKey - VersionId: Optional[ObjectVersionId] - RequestPayer: Optional[RequestPayer] - ExpectedBucketOwner: Optional[AccountId] + VersionId: ObjectVersionId | None + RequestPayer: RequestPayer | None + ExpectedBucketOwner: AccountId | None class GetObjectTaggingOutput(TypedDict, total=False): - VersionId: Optional[ObjectVersionId] + VersionId: ObjectVersionId | None TagSet: TagSet class GetObjectTaggingRequest(ServiceRequest): Bucket: BucketName Key: ObjectKey - VersionId: Optional[ObjectVersionId] - ExpectedBucketOwner: Optional[AccountId] - RequestPayer: Optional[RequestPayer] + VersionId: ObjectVersionId | None + ExpectedBucketOwner: AccountId | None + RequestPayer: RequestPayer | None class GetObjectTorrentOutput(TypedDict, total=False): - Body: Optional[Union[Body, IO[Body], Iterable[Body]]] - RequestCharged: Optional[RequestCharged] + Body: Body | IO[Body] | Iterable[Body] | None + RequestCharged: RequestCharged | None class GetObjectTorrentRequest(ServiceRequest): Bucket: BucketName Key: ObjectKey - RequestPayer: Optional[RequestPayer] - ExpectedBucketOwner: Optional[AccountId] + RequestPayer: RequestPayer | None + ExpectedBucketOwner: AccountId | None class PublicAccessBlockConfiguration(TypedDict, total=False): - BlockPublicAcls: Optional[Setting] - IgnorePublicAcls: Optional[Setting] - BlockPublicPolicy: Optional[Setting] - RestrictPublicBuckets: Optional[Setting] + BlockPublicAcls: Setting | None + IgnorePublicAcls: Setting | None + BlockPublicPolicy: Setting | None + RestrictPublicBuckets: Setting | None class GetPublicAccessBlockOutput(TypedDict, total=False): - PublicAccessBlockConfiguration: Optional[PublicAccessBlockConfiguration] + PublicAccessBlockConfiguration: PublicAccessBlockConfiguration | None class GetPublicAccessBlockRequest(ServiceRequest): Bucket: BucketName - ExpectedBucketOwner: Optional[AccountId] + ExpectedBucketOwner: AccountId | None class GlacierJobParameters(TypedDict, total=False): @@ -2633,87 +2679,90 @@ class GlacierJobParameters(TypedDict, total=False): class HeadBucketOutput(TypedDict, total=False): - BucketRegion: Optional[BucketRegion] - BucketContentType: Optional[BucketContentType] + BucketArn: S3RegionalOrS3ExpressBucketArnString | None + BucketLocationType: LocationType | None + BucketLocationName: BucketLocationName | None + BucketRegion: Region | None + AccessPointAlias: AccessPointAlias | None class HeadBucketRequest(ServiceRequest): Bucket: BucketName - ExpectedBucketOwner: Optional[AccountId] + ExpectedBucketOwner: AccountId | None class HeadObjectOutput(TypedDict, total=False): - DeleteMarker: Optional[DeleteMarker] - AcceptRanges: Optional[AcceptRanges] - Expiration: Optional[Expiration] - Restore: Optional[Restore] - ArchiveStatus: Optional[ArchiveStatus] - LastModified: Optional[LastModified] - ContentLength: Optional[ContentLength] - ChecksumCRC32: Optional[ChecksumCRC32] - ChecksumCRC32C: Optional[ChecksumCRC32C] - ChecksumCRC64NVME: Optional[ChecksumCRC64NVME] - ChecksumSHA1: Optional[ChecksumSHA1] - ChecksumSHA256: Optional[ChecksumSHA256] - ChecksumType: Optional[ChecksumType] - ETag: Optional[ETag] - MissingMeta: Optional[MissingMeta] - VersionId: Optional[ObjectVersionId] - CacheControl: Optional[CacheControl] - ContentDisposition: Optional[ContentDisposition] - ContentEncoding: Optional[ContentEncoding] - ContentLanguage: Optional[ContentLanguage] - ContentType: Optional[ContentType] - ContentRange: Optional[ContentRange] - Expires: Optional[Expires] - WebsiteRedirectLocation: Optional[WebsiteRedirectLocation] - ServerSideEncryption: Optional[ServerSideEncryption] - Metadata: Optional[Metadata] - SSECustomerAlgorithm: Optional[SSECustomerAlgorithm] - SSECustomerKeyMD5: Optional[SSECustomerKeyMD5] - SSEKMSKeyId: Optional[SSEKMSKeyId] - BucketKeyEnabled: Optional[BucketKeyEnabled] - StorageClass: Optional[StorageClass] - RequestCharged: Optional[RequestCharged] - ReplicationStatus: Optional[ReplicationStatus] - PartsCount: Optional[PartsCount] - TagCount: Optional[TagCount] - ObjectLockMode: Optional[ObjectLockMode] - ObjectLockRetainUntilDate: Optional[ObjectLockRetainUntilDate] - ObjectLockLegalHoldStatus: Optional[ObjectLockLegalHoldStatus] - StatusCode: Optional[GetObjectResponseStatusCode] + DeleteMarker: DeleteMarker | None + AcceptRanges: AcceptRanges | None + Expiration: Expiration | None + Restore: Restore | None + ArchiveStatus: ArchiveStatus | None + LastModified: LastModified | None + ContentLength: ContentLength | None + ChecksumCRC32: ChecksumCRC32 | None + ChecksumCRC32C: ChecksumCRC32C | None + ChecksumCRC64NVME: ChecksumCRC64NVME | None + ChecksumSHA1: ChecksumSHA1 | None + ChecksumSHA256: ChecksumSHA256 | None + ChecksumType: ChecksumType | None + ETag: ETag | None + MissingMeta: MissingMeta | None + VersionId: ObjectVersionId | None + CacheControl: CacheControl | None + ContentDisposition: ContentDisposition | None + ContentEncoding: ContentEncoding | None + ContentLanguage: ContentLanguage | None + ContentType: ContentType | None + ContentRange: ContentRange | None + Expires: Expires | None + WebsiteRedirectLocation: WebsiteRedirectLocation | None + ServerSideEncryption: ServerSideEncryption | None + Metadata: Metadata | None + SSECustomerAlgorithm: SSECustomerAlgorithm | None + SSECustomerKeyMD5: SSECustomerKeyMD5 | None + SSEKMSKeyId: SSEKMSKeyId | None + BucketKeyEnabled: BucketKeyEnabled | None + StorageClass: StorageClass | None + RequestCharged: RequestCharged | None + ReplicationStatus: ReplicationStatus | None + PartsCount: PartsCount | None + TagCount: TagCount | None + ObjectLockMode: ObjectLockMode | None + ObjectLockRetainUntilDate: ObjectLockRetainUntilDate | None + ObjectLockLegalHoldStatus: ObjectLockLegalHoldStatus | None + StatusCode: GetObjectResponseStatusCode | None class HeadObjectRequest(ServiceRequest): Bucket: BucketName - IfMatch: Optional[IfMatch] - IfModifiedSince: Optional[IfModifiedSince] - IfNoneMatch: Optional[IfNoneMatch] - IfUnmodifiedSince: Optional[IfUnmodifiedSince] + IfMatch: IfMatch | None + IfModifiedSince: IfModifiedSince | None + IfNoneMatch: IfNoneMatch | None + IfUnmodifiedSince: IfUnmodifiedSince | None Key: ObjectKey - Range: Optional[Range] - ResponseCacheControl: Optional[ResponseCacheControl] - ResponseContentDisposition: Optional[ResponseContentDisposition] - ResponseContentEncoding: Optional[ResponseContentEncoding] - ResponseContentLanguage: Optional[ResponseContentLanguage] - ResponseContentType: Optional[ResponseContentType] - ResponseExpires: Optional[ResponseExpires] - VersionId: Optional[ObjectVersionId] - SSECustomerAlgorithm: Optional[SSECustomerAlgorithm] - SSECustomerKey: Optional[SSECustomerKey] - SSECustomerKeyMD5: Optional[SSECustomerKeyMD5] - RequestPayer: Optional[RequestPayer] - PartNumber: Optional[PartNumber] - ExpectedBucketOwner: Optional[AccountId] - ChecksumMode: Optional[ChecksumMode] + Range: Range | None + ResponseCacheControl: ResponseCacheControl | None + ResponseContentDisposition: ResponseContentDisposition | None + ResponseContentEncoding: ResponseContentEncoding | None + ResponseContentLanguage: ResponseContentLanguage | None + ResponseContentType: ResponseContentType | None + ResponseExpires: ResponseExpires | None + VersionId: ObjectVersionId | None + SSECustomerAlgorithm: SSECustomerAlgorithm | None + SSECustomerKey: SSECustomerKey | None + SSECustomerKeyMD5: SSECustomerKeyMD5 | None + RequestPayer: RequestPayer | None + PartNumber: PartNumber | None + ExpectedBucketOwner: AccountId | None + ChecksumMode: ChecksumMode | None Initiated = datetime class Initiator(TypedDict, total=False): - ID: Optional[ID] - DisplayName: Optional[DisplayName] + ID: ID | None + DisplayName: DisplayName | None class ParquetInput(TypedDict, total=False): @@ -2721,27 +2770,27 @@ class ParquetInput(TypedDict, total=False): class JSONInput(TypedDict, total=False): - Type: Optional[JSONType] + Type: JSONType | None class InputSerialization(TypedDict, total=False): - CSV: Optional[CSVInput] - CompressionType: Optional[CompressionType] - JSON: Optional[JSONInput] - Parquet: Optional[ParquetInput] + CSV: CSVInput | None + CompressionType: CompressionType | None + JSON: JSONInput | None + Parquet: ParquetInput | None -IntelligentTieringConfigurationList = List[IntelligentTieringConfiguration] -InventoryConfigurationList = List[InventoryConfiguration] +IntelligentTieringConfigurationList = list[IntelligentTieringConfiguration] +InventoryConfigurationList = list[InventoryConfiguration] class InventoryTableConfigurationUpdates(TypedDict, total=False): ConfigurationState: InventoryConfigurationState - EncryptionConfiguration: Optional[MetadataTableEncryptionConfiguration] + EncryptionConfiguration: MetadataTableEncryptionConfiguration | None class JSONOutput(TypedDict, total=False): - RecordDelimiter: Optional[RecordDelimiter] + RecordDelimiter: RecordDelimiter | None class JournalTableConfigurationUpdates(TypedDict, total=False): @@ -2749,21 +2798,21 @@ class JournalTableConfigurationUpdates(TypedDict, total=False): class S3KeyFilter(TypedDict, total=False): - FilterRules: Optional[FilterRuleList] + FilterRules: FilterRuleList | None class NotificationConfigurationFilter(TypedDict, total=False): - Key: Optional[S3KeyFilter] + Key: S3KeyFilter | None class LambdaFunctionConfiguration(TypedDict, total=False): - Id: Optional[NotificationId] + Id: NotificationId | None LambdaFunctionArn: LambdaFunctionArn Events: EventList - Filter: Optional[NotificationConfigurationFilter] + Filter: NotificationConfigurationFilter | None -LambdaFunctionConfigurationList = List[LambdaFunctionConfiguration] +LambdaFunctionConfigurationList = list[LambdaFunctionConfiguration] class LifecycleConfiguration(TypedDict, total=False): @@ -2771,357 +2820,366 @@ class LifecycleConfiguration(TypedDict, total=False): class ListBucketAnalyticsConfigurationsOutput(TypedDict, total=False): - IsTruncated: Optional[IsTruncated] - ContinuationToken: Optional[Token] - NextContinuationToken: Optional[NextToken] - AnalyticsConfigurationList: Optional[AnalyticsConfigurationList] + IsTruncated: IsTruncated | None + ContinuationToken: Token | None + NextContinuationToken: NextToken | None + AnalyticsConfigurationList: AnalyticsConfigurationList | None class ListBucketAnalyticsConfigurationsRequest(ServiceRequest): Bucket: BucketName - ContinuationToken: Optional[Token] - ExpectedBucketOwner: Optional[AccountId] + ContinuationToken: Token | None + ExpectedBucketOwner: AccountId | None class ListBucketIntelligentTieringConfigurationsOutput(TypedDict, total=False): - IsTruncated: Optional[IsTruncated] - ContinuationToken: Optional[Token] - NextContinuationToken: Optional[NextToken] - IntelligentTieringConfigurationList: Optional[IntelligentTieringConfigurationList] + IsTruncated: IsTruncated | None + ContinuationToken: Token | None + NextContinuationToken: NextToken | None + IntelligentTieringConfigurationList: IntelligentTieringConfigurationList | None class ListBucketIntelligentTieringConfigurationsRequest(ServiceRequest): Bucket: BucketName - ContinuationToken: Optional[Token] - ExpectedBucketOwner: Optional[AccountId] + ContinuationToken: Token | None + ExpectedBucketOwner: AccountId | None class ListBucketInventoryConfigurationsOutput(TypedDict, total=False): - ContinuationToken: Optional[Token] - InventoryConfigurationList: Optional[InventoryConfigurationList] - IsTruncated: Optional[IsTruncated] - NextContinuationToken: Optional[NextToken] + ContinuationToken: Token | None + InventoryConfigurationList: InventoryConfigurationList | None + IsTruncated: IsTruncated | None + NextContinuationToken: NextToken | None class ListBucketInventoryConfigurationsRequest(ServiceRequest): Bucket: BucketName - ContinuationToken: Optional[Token] - ExpectedBucketOwner: Optional[AccountId] + ContinuationToken: Token | None + ExpectedBucketOwner: AccountId | None -MetricsConfigurationList = List[MetricsConfiguration] +MetricsConfigurationList = list[MetricsConfiguration] class ListBucketMetricsConfigurationsOutput(TypedDict, total=False): - IsTruncated: Optional[IsTruncated] - ContinuationToken: Optional[Token] - NextContinuationToken: Optional[NextToken] - MetricsConfigurationList: Optional[MetricsConfigurationList] + IsTruncated: IsTruncated | None + ContinuationToken: Token | None + NextContinuationToken: NextToken | None + MetricsConfigurationList: MetricsConfigurationList | None class ListBucketMetricsConfigurationsRequest(ServiceRequest): Bucket: BucketName - ContinuationToken: Optional[Token] - ExpectedBucketOwner: Optional[AccountId] + ContinuationToken: Token | None + ExpectedBucketOwner: AccountId | None class ListBucketsOutput(TypedDict, total=False): - Owner: Optional[Owner] - ContinuationToken: Optional[NextToken] - Prefix: Optional[Prefix] - Buckets: Optional[Buckets] + Owner: Owner | None + ContinuationToken: NextToken | None + Prefix: Prefix | None + Buckets: Buckets | None class ListBucketsRequest(ServiceRequest): - MaxBuckets: Optional[MaxBuckets] - ContinuationToken: Optional[Token] - Prefix: Optional[Prefix] - BucketRegion: Optional[BucketRegion] + MaxBuckets: MaxBuckets | None + ContinuationToken: Token | None + Prefix: Prefix | None + BucketRegion: BucketRegion | None class ListDirectoryBucketsOutput(TypedDict, total=False): - Buckets: Optional[Buckets] - ContinuationToken: Optional[DirectoryBucketToken] + Buckets: Buckets | None + ContinuationToken: DirectoryBucketToken | None class ListDirectoryBucketsRequest(ServiceRequest): - ContinuationToken: Optional[DirectoryBucketToken] - MaxDirectoryBuckets: Optional[MaxDirectoryBuckets] + ContinuationToken: DirectoryBucketToken | None + MaxDirectoryBuckets: MaxDirectoryBuckets | None class MultipartUpload(TypedDict, total=False): - UploadId: Optional[MultipartUploadId] - Key: Optional[ObjectKey] - Initiated: Optional[Initiated] - StorageClass: Optional[StorageClass] - Owner: Optional[Owner] - Initiator: Optional[Initiator] - ChecksumAlgorithm: Optional[ChecksumAlgorithm] - ChecksumType: Optional[ChecksumType] + UploadId: MultipartUploadId | None + Key: ObjectKey | None + Initiated: Initiated | None + StorageClass: StorageClass | None + Owner: Owner | None + Initiator: Initiator | None + ChecksumAlgorithm: ChecksumAlgorithm | None + ChecksumType: ChecksumType | None -MultipartUploadList = List[MultipartUpload] +MultipartUploadList = list[MultipartUpload] class ListMultipartUploadsOutput(TypedDict, total=False): - Bucket: Optional[BucketName] - KeyMarker: Optional[KeyMarker] - UploadIdMarker: Optional[UploadIdMarker] - NextKeyMarker: Optional[NextKeyMarker] - Prefix: Optional[Prefix] - Delimiter: Optional[Delimiter] - NextUploadIdMarker: Optional[NextUploadIdMarker] - MaxUploads: Optional[MaxUploads] - IsTruncated: Optional[IsTruncated] - Uploads: Optional[MultipartUploadList] - CommonPrefixes: Optional[CommonPrefixList] - EncodingType: Optional[EncodingType] - RequestCharged: Optional[RequestCharged] + Bucket: BucketName | None + KeyMarker: KeyMarker | None + UploadIdMarker: UploadIdMarker | None + NextKeyMarker: NextKeyMarker | None + Prefix: Prefix | None + Delimiter: Delimiter | None + NextUploadIdMarker: NextUploadIdMarker | None + MaxUploads: MaxUploads | None + IsTruncated: IsTruncated | None + Uploads: MultipartUploadList | None + CommonPrefixes: CommonPrefixList | None + EncodingType: EncodingType | None + RequestCharged: RequestCharged | None class ListMultipartUploadsRequest(ServiceRequest): Bucket: BucketName - Delimiter: Optional[Delimiter] - EncodingType: Optional[EncodingType] - KeyMarker: Optional[KeyMarker] - MaxUploads: Optional[MaxUploads] - Prefix: Optional[Prefix] - UploadIdMarker: Optional[UploadIdMarker] - ExpectedBucketOwner: Optional[AccountId] - RequestPayer: Optional[RequestPayer] + Delimiter: Delimiter | None + EncodingType: EncodingType | None + KeyMarker: KeyMarker | None + MaxUploads: MaxUploads | None + Prefix: Prefix | None + UploadIdMarker: UploadIdMarker | None + ExpectedBucketOwner: AccountId | None + RequestPayer: RequestPayer | None RestoreExpiryDate = datetime class RestoreStatus(TypedDict, total=False): - IsRestoreInProgress: Optional[IsRestoreInProgress] - RestoreExpiryDate: Optional[RestoreExpiryDate] + IsRestoreInProgress: IsRestoreInProgress | None + RestoreExpiryDate: RestoreExpiryDate | None class ObjectVersion(TypedDict, total=False): - ETag: Optional[ETag] - ChecksumAlgorithm: Optional[ChecksumAlgorithmList] - ChecksumType: Optional[ChecksumType] - Size: Optional[Size] - StorageClass: Optional[ObjectVersionStorageClass] - Key: Optional[ObjectKey] - VersionId: Optional[ObjectVersionId] - IsLatest: Optional[IsLatest] - LastModified: Optional[LastModified] - Owner: Optional[Owner] - RestoreStatus: Optional[RestoreStatus] + ETag: ETag | None + ChecksumAlgorithm: ChecksumAlgorithmList | None + ChecksumType: ChecksumType | None + Size: Size | None + StorageClass: ObjectVersionStorageClass | None + Key: ObjectKey | None + VersionId: ObjectVersionId | None + IsLatest: IsLatest | None + LastModified: LastModified | None + Owner: Owner | None + RestoreStatus: RestoreStatus | None -ObjectVersionList = List[ObjectVersion] +ObjectVersionList = list[ObjectVersion] class ListObjectVersionsOutput(TypedDict, total=False): - IsTruncated: Optional[IsTruncated] - KeyMarker: Optional[KeyMarker] - VersionIdMarker: Optional[VersionIdMarker] - NextKeyMarker: Optional[NextKeyMarker] - NextVersionIdMarker: Optional[NextVersionIdMarker] - DeleteMarkers: Optional[DeleteMarkers] - Name: Optional[BucketName] - Prefix: Optional[Prefix] - Delimiter: Optional[Delimiter] - MaxKeys: Optional[MaxKeys] - CommonPrefixes: Optional[CommonPrefixList] - EncodingType: Optional[EncodingType] - RequestCharged: Optional[RequestCharged] - Versions: Optional[ObjectVersionList] + IsTruncated: IsTruncated | None + KeyMarker: KeyMarker | None + VersionIdMarker: VersionIdMarker | None + NextKeyMarker: NextKeyMarker | None + NextVersionIdMarker: NextVersionIdMarker | None + DeleteMarkers: DeleteMarkers | None + Name: BucketName | None + Prefix: Prefix | None + Delimiter: Delimiter | None + MaxKeys: MaxKeys | None + CommonPrefixes: CommonPrefixList | None + EncodingType: EncodingType | None + RequestCharged: RequestCharged | None + Versions: ObjectVersionList | None -OptionalObjectAttributesList = List[OptionalObjectAttributes] +OptionalObjectAttributesList = list[OptionalObjectAttributes] class ListObjectVersionsRequest(ServiceRequest): Bucket: BucketName - Delimiter: Optional[Delimiter] - EncodingType: Optional[EncodingType] - KeyMarker: Optional[KeyMarker] - MaxKeys: Optional[MaxKeys] - Prefix: Optional[Prefix] - VersionIdMarker: Optional[VersionIdMarker] - ExpectedBucketOwner: Optional[AccountId] - RequestPayer: Optional[RequestPayer] - OptionalObjectAttributes: Optional[OptionalObjectAttributesList] + Delimiter: Delimiter | None + EncodingType: EncodingType | None + KeyMarker: KeyMarker | None + MaxKeys: MaxKeys | None + Prefix: Prefix | None + VersionIdMarker: VersionIdMarker | None + ExpectedBucketOwner: AccountId | None + RequestPayer: RequestPayer | None + OptionalObjectAttributes: OptionalObjectAttributesList | None class Object(TypedDict, total=False): - Key: Optional[ObjectKey] - LastModified: Optional[LastModified] - ETag: Optional[ETag] - ChecksumAlgorithm: Optional[ChecksumAlgorithmList] - ChecksumType: Optional[ChecksumType] - Size: Optional[Size] - StorageClass: Optional[ObjectStorageClass] - Owner: Optional[Owner] - RestoreStatus: Optional[RestoreStatus] + Key: ObjectKey | None + LastModified: LastModified | None + ETag: ETag | None + ChecksumAlgorithm: ChecksumAlgorithmList | None + ChecksumType: ChecksumType | None + Size: Size | None + StorageClass: ObjectStorageClass | None + Owner: Owner | None + RestoreStatus: RestoreStatus | None -ObjectList = List[Object] +ObjectList = list[Object] class ListObjectsOutput(TypedDict, total=False): - IsTruncated: Optional[IsTruncated] - Marker: Optional[Marker] - NextMarker: Optional[NextMarker] - Name: Optional[BucketName] - Prefix: Optional[Prefix] - Delimiter: Optional[Delimiter] - MaxKeys: Optional[MaxKeys] - CommonPrefixes: Optional[CommonPrefixList] - EncodingType: Optional[EncodingType] - RequestCharged: Optional[RequestCharged] - BucketRegion: Optional[BucketRegion] - Contents: Optional[ObjectList] + IsTruncated: IsTruncated | None + Marker: Marker | None + NextMarker: NextMarker | None + Name: BucketName | None + Prefix: Prefix | None + Delimiter: Delimiter | None + MaxKeys: MaxKeys | None + CommonPrefixes: CommonPrefixList | None + EncodingType: EncodingType | None + RequestCharged: RequestCharged | None + BucketRegion: BucketRegion | None + Contents: ObjectList | None class ListObjectsRequest(ServiceRequest): Bucket: BucketName - Delimiter: Optional[Delimiter] - EncodingType: Optional[EncodingType] - Marker: Optional[Marker] - MaxKeys: Optional[MaxKeys] - Prefix: Optional[Prefix] - RequestPayer: Optional[RequestPayer] - ExpectedBucketOwner: Optional[AccountId] - OptionalObjectAttributes: Optional[OptionalObjectAttributesList] + Delimiter: Delimiter | None + EncodingType: EncodingType | None + Marker: Marker | None + MaxKeys: MaxKeys | None + Prefix: Prefix | None + RequestPayer: RequestPayer | None + ExpectedBucketOwner: AccountId | None + OptionalObjectAttributes: OptionalObjectAttributesList | None class ListObjectsV2Output(TypedDict, total=False): - IsTruncated: Optional[IsTruncated] - Name: Optional[BucketName] - Prefix: Optional[Prefix] - Delimiter: Optional[Delimiter] - MaxKeys: Optional[MaxKeys] - CommonPrefixes: Optional[CommonPrefixList] - EncodingType: Optional[EncodingType] - KeyCount: Optional[KeyCount] - ContinuationToken: Optional[Token] - NextContinuationToken: Optional[NextToken] - StartAfter: Optional[StartAfter] - RequestCharged: Optional[RequestCharged] - BucketRegion: Optional[BucketRegion] - Contents: Optional[ObjectList] + IsTruncated: IsTruncated | None + Name: BucketName | None + Prefix: Prefix | None + Delimiter: Delimiter | None + MaxKeys: MaxKeys | None + CommonPrefixes: CommonPrefixList | None + EncodingType: EncodingType | None + KeyCount: KeyCount | None + ContinuationToken: Token | None + NextContinuationToken: NextToken | None + StartAfter: StartAfter | None + RequestCharged: RequestCharged | None + BucketRegion: BucketRegion | None + Contents: ObjectList | None class ListObjectsV2Request(ServiceRequest): Bucket: BucketName - Delimiter: Optional[Delimiter] - EncodingType: Optional[EncodingType] - MaxKeys: Optional[MaxKeys] - Prefix: Optional[Prefix] - ContinuationToken: Optional[Token] - FetchOwner: Optional[FetchOwner] - StartAfter: Optional[StartAfter] - RequestPayer: Optional[RequestPayer] - ExpectedBucketOwner: Optional[AccountId] - OptionalObjectAttributes: Optional[OptionalObjectAttributesList] + Delimiter: Delimiter | None + EncodingType: EncodingType | None + MaxKeys: MaxKeys | None + Prefix: Prefix | None + ContinuationToken: Token | None + FetchOwner: FetchOwner | None + StartAfter: StartAfter | None + RequestPayer: RequestPayer | None + ExpectedBucketOwner: AccountId | None + OptionalObjectAttributes: OptionalObjectAttributesList | None class Part(TypedDict, total=False): - PartNumber: Optional[PartNumber] - LastModified: Optional[LastModified] - ETag: Optional[ETag] - Size: Optional[Size] - ChecksumCRC32: Optional[ChecksumCRC32] - ChecksumCRC32C: Optional[ChecksumCRC32C] - ChecksumCRC64NVME: Optional[ChecksumCRC64NVME] - ChecksumSHA1: Optional[ChecksumSHA1] - ChecksumSHA256: Optional[ChecksumSHA256] + PartNumber: PartNumber | None + LastModified: LastModified | None + ETag: ETag | None + Size: Size | None + ChecksumCRC32: ChecksumCRC32 | None + ChecksumCRC32C: ChecksumCRC32C | None + ChecksumCRC64NVME: ChecksumCRC64NVME | None + ChecksumSHA1: ChecksumSHA1 | None + ChecksumSHA256: ChecksumSHA256 | None -Parts = List[Part] +Parts = list[Part] class ListPartsOutput(TypedDict, total=False): - AbortDate: Optional[AbortDate] - AbortRuleId: Optional[AbortRuleId] - Bucket: Optional[BucketName] - Key: Optional[ObjectKey] - UploadId: Optional[MultipartUploadId] - PartNumberMarker: Optional[PartNumberMarker] - NextPartNumberMarker: Optional[NextPartNumberMarker] - MaxParts: Optional[MaxParts] - IsTruncated: Optional[IsTruncated] - Parts: Optional[Parts] - Initiator: Optional[Initiator] - Owner: Optional[Owner] - StorageClass: Optional[StorageClass] - RequestCharged: Optional[RequestCharged] - ChecksumAlgorithm: Optional[ChecksumAlgorithm] - ChecksumType: Optional[ChecksumType] + AbortDate: AbortDate | None + AbortRuleId: AbortRuleId | None + Bucket: BucketName | None + Key: ObjectKey | None + UploadId: MultipartUploadId | None + PartNumberMarker: PartNumberMarker | None + NextPartNumberMarker: NextPartNumberMarker | None + MaxParts: MaxParts | None + IsTruncated: IsTruncated | None + Parts: Parts | None + Initiator: Initiator | None + Owner: Owner | None + StorageClass: StorageClass | None + RequestCharged: RequestCharged | None + ChecksumAlgorithm: ChecksumAlgorithm | None + ChecksumType: ChecksumType | None class ListPartsRequest(ServiceRequest): Bucket: BucketName Key: ObjectKey - MaxParts: Optional[MaxParts] - PartNumberMarker: Optional[PartNumberMarker] + MaxParts: MaxParts | None + PartNumberMarker: PartNumberMarker | None UploadId: MultipartUploadId - RequestPayer: Optional[RequestPayer] - ExpectedBucketOwner: Optional[AccountId] - SSECustomerAlgorithm: Optional[SSECustomerAlgorithm] - SSECustomerKey: Optional[SSECustomerKey] - SSECustomerKeyMD5: Optional[SSECustomerKeyMD5] + RequestPayer: RequestPayer | None + ExpectedBucketOwner: AccountId | None + SSECustomerAlgorithm: SSECustomerAlgorithm | None + SSECustomerKey: SSECustomerKey | None + SSECustomerKeyMD5: SSECustomerKeyMD5 | None class MetadataEntry(TypedDict, total=False): - Name: Optional[MetadataKey] - Value: Optional[MetadataValue] + Name: MetadataKey | None + Value: MetadataValue | None class QueueConfiguration(TypedDict, total=False): - Id: Optional[NotificationId] + Id: NotificationId | None QueueArn: QueueArn Events: EventList - Filter: Optional[NotificationConfigurationFilter] + Filter: NotificationConfigurationFilter | None -QueueConfigurationList = List[QueueConfiguration] +QueueConfigurationList = list[QueueConfiguration] class TopicConfiguration(TypedDict, total=False): - Id: Optional[NotificationId] + Id: NotificationId | None TopicArn: TopicArn Events: EventList - Filter: Optional[NotificationConfigurationFilter] + Filter: NotificationConfigurationFilter | None -TopicConfigurationList = List[TopicConfiguration] +TopicConfigurationList = list[TopicConfiguration] class NotificationConfiguration(TypedDict, total=False): - TopicConfigurations: Optional[TopicConfigurationList] - QueueConfigurations: Optional[QueueConfigurationList] - LambdaFunctionConfigurations: Optional[LambdaFunctionConfigurationList] - EventBridgeConfiguration: Optional[EventBridgeConfiguration] + TopicConfigurations: TopicConfigurationList | None + QueueConfigurations: QueueConfigurationList | None + LambdaFunctionConfigurations: LambdaFunctionConfigurationList | None + EventBridgeConfiguration: EventBridgeConfiguration | None class QueueConfigurationDeprecated(TypedDict, total=False): - Id: Optional[NotificationId] - Event: Optional[Event] - Events: Optional[EventList] - Queue: Optional[QueueArn] + Id: NotificationId | None + Event: Event | None + Events: EventList | None + Queue: QueueArn | None class TopicConfigurationDeprecated(TypedDict, total=False): - Id: Optional[NotificationId] - Events: Optional[EventList] - Event: Optional[Event] - Topic: Optional[TopicArn] + Id: NotificationId | None + Events: EventList | None + Event: Event | None + Topic: TopicArn | None class NotificationConfigurationDeprecated(TypedDict, total=False): - TopicConfiguration: Optional[TopicConfigurationDeprecated] - QueueConfiguration: Optional[QueueConfigurationDeprecated] - CloudFunctionConfiguration: Optional[CloudFunctionConfiguration] + TopicConfiguration: TopicConfigurationDeprecated | None + QueueConfiguration: QueueConfigurationDeprecated | None + CloudFunctionConfiguration: CloudFunctionConfiguration | None + +class SSEKMSEncryption(TypedDict, total=False): + KMSKeyArn: NonEmptyKmsKeyArnString + BucketKeyEnabled: BucketKeyEnabled | None -UserMetadata = List[MetadataEntry] + +class ObjectEncryption(TypedDict, total=False): + SSEKMS: SSEKMSEncryption | None + + +UserMetadata = list[MetadataEntry] class Tagging(TypedDict, total=False): @@ -3131,81 +3189,89 @@ class Tagging(TypedDict, total=False): class S3Location(TypedDict, total=False): BucketName: BucketName Prefix: LocationPrefix - Encryption: Optional[Encryption] - CannedACL: Optional[ObjectCannedACL] - AccessControlList: Optional[Grants] - Tagging: Optional[Tagging] - UserMetadata: Optional[UserMetadata] - StorageClass: Optional[StorageClass] + Encryption: Encryption | None + CannedACL: ObjectCannedACL | None + AccessControlList: Grants | None + Tagging: Tagging | None + UserMetadata: UserMetadata | None + StorageClass: StorageClass | None class OutputLocation(TypedDict, total=False): - S3: Optional[S3Location] + S3: S3Location | None class OutputSerialization(TypedDict, total=False): - CSV: Optional[CSVOutput] - JSON: Optional[JSONOutput] + CSV: CSVOutput | None + JSON: JSONOutput | None class Progress(TypedDict, total=False): - BytesScanned: Optional[BytesScanned] - BytesProcessed: Optional[BytesProcessed] - BytesReturned: Optional[BytesReturned] + BytesScanned: BytesScanned | None + BytesProcessed: BytesProcessed | None + BytesReturned: BytesReturned | None class ProgressEvent(TypedDict, total=False): - Details: Optional[Progress] + Details: Progress | None + + +class PutBucketAbacRequest(ServiceRequest): + Bucket: BucketName + ContentMD5: ContentMD5 | None + ChecksumAlgorithm: ChecksumAlgorithm | None + ExpectedBucketOwner: AccountId | None + AbacStatus: AbacStatus class PutBucketAccelerateConfigurationRequest(ServiceRequest): Bucket: BucketName AccelerateConfiguration: AccelerateConfiguration - ExpectedBucketOwner: Optional[AccountId] - ChecksumAlgorithm: Optional[ChecksumAlgorithm] + ExpectedBucketOwner: AccountId | None + ChecksumAlgorithm: ChecksumAlgorithm | None class PutBucketAclRequest(ServiceRequest): - ACL: Optional[BucketCannedACL] - AccessControlPolicy: Optional[AccessControlPolicy] + ACL: BucketCannedACL | None + AccessControlPolicy: AccessControlPolicy | None Bucket: BucketName - ContentMD5: Optional[ContentMD5] - ChecksumAlgorithm: Optional[ChecksumAlgorithm] - GrantFullControl: Optional[GrantFullControl] - GrantRead: Optional[GrantRead] - GrantReadACP: Optional[GrantReadACP] - GrantWrite: Optional[GrantWrite] - GrantWriteACP: Optional[GrantWriteACP] - ExpectedBucketOwner: Optional[AccountId] + ContentMD5: ContentMD5 | None + ChecksumAlgorithm: ChecksumAlgorithm | None + GrantFullControl: GrantFullControl | None + GrantRead: GrantRead | None + GrantReadACP: GrantReadACP | None + GrantWrite: GrantWrite | None + GrantWriteACP: GrantWriteACP | None + ExpectedBucketOwner: AccountId | None class PutBucketAnalyticsConfigurationRequest(ServiceRequest): Bucket: BucketName Id: AnalyticsId AnalyticsConfiguration: AnalyticsConfiguration - ExpectedBucketOwner: Optional[AccountId] + ExpectedBucketOwner: AccountId | None class PutBucketCorsRequest(ServiceRequest): Bucket: BucketName CORSConfiguration: CORSConfiguration - ContentMD5: Optional[ContentMD5] - ChecksumAlgorithm: Optional[ChecksumAlgorithm] - ExpectedBucketOwner: Optional[AccountId] + ContentMD5: ContentMD5 | None + ChecksumAlgorithm: ChecksumAlgorithm | None + ExpectedBucketOwner: AccountId | None class PutBucketEncryptionRequest(ServiceRequest): Bucket: BucketName - ContentMD5: Optional[ContentMD5] - ChecksumAlgorithm: Optional[ChecksumAlgorithm] + ContentMD5: ContentMD5 | None + ChecksumAlgorithm: ChecksumAlgorithm | None ServerSideEncryptionConfiguration: ServerSideEncryptionConfiguration - ExpectedBucketOwner: Optional[AccountId] + ExpectedBucketOwner: AccountId | None class PutBucketIntelligentTieringConfigurationRequest(ServiceRequest): Bucket: BucketName Id: IntelligentTieringId - ExpectedBucketOwner: Optional[AccountId] + ExpectedBucketOwner: AccountId | None IntelligentTieringConfiguration: IntelligentTieringConfiguration @@ -3213,83 +3279,83 @@ class PutBucketInventoryConfigurationRequest(ServiceRequest): Bucket: BucketName Id: InventoryId InventoryConfiguration: InventoryConfiguration - ExpectedBucketOwner: Optional[AccountId] + ExpectedBucketOwner: AccountId | None class PutBucketLifecycleConfigurationOutput(TypedDict, total=False): - TransitionDefaultMinimumObjectSize: Optional[TransitionDefaultMinimumObjectSize] + TransitionDefaultMinimumObjectSize: TransitionDefaultMinimumObjectSize | None class PutBucketLifecycleConfigurationRequest(ServiceRequest): Bucket: BucketName - ChecksumAlgorithm: Optional[ChecksumAlgorithm] - LifecycleConfiguration: Optional[BucketLifecycleConfiguration] - ExpectedBucketOwner: Optional[AccountId] - TransitionDefaultMinimumObjectSize: Optional[TransitionDefaultMinimumObjectSize] + ChecksumAlgorithm: ChecksumAlgorithm | None + LifecycleConfiguration: BucketLifecycleConfiguration | None + ExpectedBucketOwner: AccountId | None + TransitionDefaultMinimumObjectSize: TransitionDefaultMinimumObjectSize | None class PutBucketLifecycleRequest(ServiceRequest): Bucket: BucketName - ContentMD5: Optional[ContentMD5] - ChecksumAlgorithm: Optional[ChecksumAlgorithm] - LifecycleConfiguration: Optional[LifecycleConfiguration] - ExpectedBucketOwner: Optional[AccountId] + ContentMD5: ContentMD5 | None + ChecksumAlgorithm: ChecksumAlgorithm | None + LifecycleConfiguration: LifecycleConfiguration | None + ExpectedBucketOwner: AccountId | None class PutBucketLoggingRequest(ServiceRequest): Bucket: BucketName BucketLoggingStatus: BucketLoggingStatus - ContentMD5: Optional[ContentMD5] - ChecksumAlgorithm: Optional[ChecksumAlgorithm] - ExpectedBucketOwner: Optional[AccountId] + ContentMD5: ContentMD5 | None + ChecksumAlgorithm: ChecksumAlgorithm | None + ExpectedBucketOwner: AccountId | None class PutBucketMetricsConfigurationRequest(ServiceRequest): Bucket: BucketName Id: MetricsId MetricsConfiguration: MetricsConfiguration - ExpectedBucketOwner: Optional[AccountId] + ExpectedBucketOwner: AccountId | None class PutBucketNotificationConfigurationRequest(ServiceRequest): Bucket: BucketName NotificationConfiguration: NotificationConfiguration - ExpectedBucketOwner: Optional[AccountId] - SkipDestinationValidation: Optional[SkipValidation] + ExpectedBucketOwner: AccountId | None + SkipDestinationValidation: SkipValidation | None class PutBucketNotificationRequest(ServiceRequest): Bucket: BucketName - ContentMD5: Optional[ContentMD5] - ChecksumAlgorithm: Optional[ChecksumAlgorithm] + ContentMD5: ContentMD5 | None + ChecksumAlgorithm: ChecksumAlgorithm | None NotificationConfiguration: NotificationConfigurationDeprecated - ExpectedBucketOwner: Optional[AccountId] + ExpectedBucketOwner: AccountId | None class PutBucketOwnershipControlsRequest(ServiceRequest): Bucket: BucketName - ContentMD5: Optional[ContentMD5] - ExpectedBucketOwner: Optional[AccountId] + ContentMD5: ContentMD5 | None + ExpectedBucketOwner: AccountId | None OwnershipControls: OwnershipControls - ChecksumAlgorithm: Optional[ChecksumAlgorithm] + ChecksumAlgorithm: ChecksumAlgorithm | None class PutBucketPolicyRequest(ServiceRequest): Bucket: BucketName - ContentMD5: Optional[ContentMD5] - ChecksumAlgorithm: Optional[ChecksumAlgorithm] - ConfirmRemoveSelfBucketAccess: Optional[ConfirmRemoveSelfBucketAccess] + ContentMD5: ContentMD5 | None + ChecksumAlgorithm: ChecksumAlgorithm | None + ConfirmRemoveSelfBucketAccess: ConfirmRemoveSelfBucketAccess | None Policy: Policy - ExpectedBucketOwner: Optional[AccountId] + ExpectedBucketOwner: AccountId | None class PutBucketReplicationRequest(ServiceRequest): Bucket: BucketName - ContentMD5: Optional[ContentMD5] - ChecksumAlgorithm: Optional[ChecksumAlgorithm] + ContentMD5: ContentMD5 | None + ChecksumAlgorithm: ChecksumAlgorithm | None ReplicationConfiguration: ReplicationConfiguration - Token: Optional[ObjectLockToken] - ExpectedBucketOwner: Optional[AccountId] + Token: ObjectLockToken | None + ExpectedBucketOwner: AccountId | None class RequestPaymentConfiguration(TypedDict, total=False): @@ -3298,207 +3364,207 @@ class RequestPaymentConfiguration(TypedDict, total=False): class PutBucketRequestPaymentRequest(ServiceRequest): Bucket: BucketName - ContentMD5: Optional[ContentMD5] - ChecksumAlgorithm: Optional[ChecksumAlgorithm] + ContentMD5: ContentMD5 | None + ChecksumAlgorithm: ChecksumAlgorithm | None RequestPaymentConfiguration: RequestPaymentConfiguration - ExpectedBucketOwner: Optional[AccountId] + ExpectedBucketOwner: AccountId | None class PutBucketTaggingRequest(ServiceRequest): Bucket: BucketName - ContentMD5: Optional[ContentMD5] - ChecksumAlgorithm: Optional[ChecksumAlgorithm] + ContentMD5: ContentMD5 | None + ChecksumAlgorithm: ChecksumAlgorithm | None Tagging: Tagging - ExpectedBucketOwner: Optional[AccountId] + ExpectedBucketOwner: AccountId | None class VersioningConfiguration(TypedDict, total=False): - MFADelete: Optional[MFADelete] - Status: Optional[BucketVersioningStatus] + MFADelete: MFADelete | None + Status: BucketVersioningStatus | None class PutBucketVersioningRequest(ServiceRequest): Bucket: BucketName - ContentMD5: Optional[ContentMD5] - ChecksumAlgorithm: Optional[ChecksumAlgorithm] - MFA: Optional[MFA] + ContentMD5: ContentMD5 | None + ChecksumAlgorithm: ChecksumAlgorithm | None + MFA: MFA | None VersioningConfiguration: VersioningConfiguration - ExpectedBucketOwner: Optional[AccountId] + ExpectedBucketOwner: AccountId | None class WebsiteConfiguration(TypedDict, total=False): - ErrorDocument: Optional[ErrorDocument] - IndexDocument: Optional[IndexDocument] - RedirectAllRequestsTo: Optional[RedirectAllRequestsTo] - RoutingRules: Optional[RoutingRules] + ErrorDocument: ErrorDocument | None + IndexDocument: IndexDocument | None + RedirectAllRequestsTo: RedirectAllRequestsTo | None + RoutingRules: RoutingRules | None class PutBucketWebsiteRequest(ServiceRequest): Bucket: BucketName - ContentMD5: Optional[ContentMD5] - ChecksumAlgorithm: Optional[ChecksumAlgorithm] + ContentMD5: ContentMD5 | None + ChecksumAlgorithm: ChecksumAlgorithm | None WebsiteConfiguration: WebsiteConfiguration - ExpectedBucketOwner: Optional[AccountId] + ExpectedBucketOwner: AccountId | None class PutObjectAclOutput(TypedDict, total=False): - RequestCharged: Optional[RequestCharged] + RequestCharged: RequestCharged | None class PutObjectAclRequest(ServiceRequest): - ACL: Optional[ObjectCannedACL] - AccessControlPolicy: Optional[AccessControlPolicy] + ACL: ObjectCannedACL | None + AccessControlPolicy: AccessControlPolicy | None Bucket: BucketName - ContentMD5: Optional[ContentMD5] - ChecksumAlgorithm: Optional[ChecksumAlgorithm] - GrantFullControl: Optional[GrantFullControl] - GrantRead: Optional[GrantRead] - GrantReadACP: Optional[GrantReadACP] - GrantWrite: Optional[GrantWrite] - GrantWriteACP: Optional[GrantWriteACP] + ContentMD5: ContentMD5 | None + ChecksumAlgorithm: ChecksumAlgorithm | None + GrantFullControl: GrantFullControl | None + GrantRead: GrantRead | None + GrantReadACP: GrantReadACP | None + GrantWrite: GrantWrite | None + GrantWriteACP: GrantWriteACP | None Key: ObjectKey - RequestPayer: Optional[RequestPayer] - VersionId: Optional[ObjectVersionId] - ExpectedBucketOwner: Optional[AccountId] + RequestPayer: RequestPayer | None + VersionId: ObjectVersionId | None + ExpectedBucketOwner: AccountId | None class PutObjectLegalHoldOutput(TypedDict, total=False): - RequestCharged: Optional[RequestCharged] + RequestCharged: RequestCharged | None class PutObjectLegalHoldRequest(ServiceRequest): Bucket: BucketName Key: ObjectKey - LegalHold: Optional[ObjectLockLegalHold] - RequestPayer: Optional[RequestPayer] - VersionId: Optional[ObjectVersionId] - ContentMD5: Optional[ContentMD5] - ChecksumAlgorithm: Optional[ChecksumAlgorithm] - ExpectedBucketOwner: Optional[AccountId] + LegalHold: ObjectLockLegalHold | None + RequestPayer: RequestPayer | None + VersionId: ObjectVersionId | None + ContentMD5: ContentMD5 | None + ChecksumAlgorithm: ChecksumAlgorithm | None + ExpectedBucketOwner: AccountId | None class PutObjectLockConfigurationOutput(TypedDict, total=False): - RequestCharged: Optional[RequestCharged] + RequestCharged: RequestCharged | None class PutObjectLockConfigurationRequest(ServiceRequest): Bucket: BucketName - ObjectLockConfiguration: Optional[ObjectLockConfiguration] - RequestPayer: Optional[RequestPayer] - Token: Optional[ObjectLockToken] - ContentMD5: Optional[ContentMD5] - ChecksumAlgorithm: Optional[ChecksumAlgorithm] - ExpectedBucketOwner: Optional[AccountId] + ObjectLockConfiguration: ObjectLockConfiguration | None + RequestPayer: RequestPayer | None + Token: ObjectLockToken | None + ContentMD5: ContentMD5 | None + ChecksumAlgorithm: ChecksumAlgorithm | None + ExpectedBucketOwner: AccountId | None class PutObjectOutput(TypedDict, total=False): - Expiration: Optional[Expiration] - ETag: Optional[ETag] - ChecksumCRC32: Optional[ChecksumCRC32] - ChecksumCRC32C: Optional[ChecksumCRC32C] - ChecksumCRC64NVME: Optional[ChecksumCRC64NVME] - ChecksumSHA1: Optional[ChecksumSHA1] - ChecksumSHA256: Optional[ChecksumSHA256] - ChecksumType: Optional[ChecksumType] - ServerSideEncryption: Optional[ServerSideEncryption] - VersionId: Optional[ObjectVersionId] - SSECustomerAlgorithm: Optional[SSECustomerAlgorithm] - SSECustomerKeyMD5: Optional[SSECustomerKeyMD5] - SSEKMSKeyId: Optional[SSEKMSKeyId] - SSEKMSEncryptionContext: Optional[SSEKMSEncryptionContext] - BucketKeyEnabled: Optional[BucketKeyEnabled] - Size: Optional[Size] - RequestCharged: Optional[RequestCharged] + Expiration: Expiration | None + ETag: ETag | None + ChecksumCRC32: ChecksumCRC32 | None + ChecksumCRC32C: ChecksumCRC32C | None + ChecksumCRC64NVME: ChecksumCRC64NVME | None + ChecksumSHA1: ChecksumSHA1 | None + ChecksumSHA256: ChecksumSHA256 | None + ChecksumType: ChecksumType | None + ServerSideEncryption: ServerSideEncryption | None + VersionId: ObjectVersionId | None + SSECustomerAlgorithm: SSECustomerAlgorithm | None + SSECustomerKeyMD5: SSECustomerKeyMD5 | None + SSEKMSKeyId: SSEKMSKeyId | None + SSEKMSEncryptionContext: SSEKMSEncryptionContext | None + BucketKeyEnabled: BucketKeyEnabled | None + Size: Size | None + RequestCharged: RequestCharged | None WriteOffsetBytes = int class PutObjectRequest(ServiceRequest): - Body: Optional[IO[Body]] - ACL: Optional[ObjectCannedACL] + Body: IO[Body] | None + ACL: ObjectCannedACL | None Bucket: BucketName - CacheControl: Optional[CacheControl] - ContentDisposition: Optional[ContentDisposition] - ContentEncoding: Optional[ContentEncoding] - ContentLanguage: Optional[ContentLanguage] - ContentLength: Optional[ContentLength] - ContentMD5: Optional[ContentMD5] - ContentType: Optional[ContentType] - ChecksumAlgorithm: Optional[ChecksumAlgorithm] - ChecksumCRC32: Optional[ChecksumCRC32] - ChecksumCRC32C: Optional[ChecksumCRC32C] - ChecksumCRC64NVME: Optional[ChecksumCRC64NVME] - ChecksumSHA1: Optional[ChecksumSHA1] - ChecksumSHA256: Optional[ChecksumSHA256] - Expires: Optional[Expires] - IfMatch: Optional[IfMatch] - IfNoneMatch: Optional[IfNoneMatch] - GrantFullControl: Optional[GrantFullControl] - GrantRead: Optional[GrantRead] - GrantReadACP: Optional[GrantReadACP] - GrantWriteACP: Optional[GrantWriteACP] + CacheControl: CacheControl | None + ContentDisposition: ContentDisposition | None + ContentEncoding: ContentEncoding | None + ContentLanguage: ContentLanguage | None + ContentLength: ContentLength | None + ContentMD5: ContentMD5 | None + ContentType: ContentType | None + ChecksumAlgorithm: ChecksumAlgorithm | None + ChecksumCRC32: ChecksumCRC32 | None + ChecksumCRC32C: ChecksumCRC32C | None + ChecksumCRC64NVME: ChecksumCRC64NVME | None + ChecksumSHA1: ChecksumSHA1 | None + ChecksumSHA256: ChecksumSHA256 | None + Expires: Expires | None + IfMatch: IfMatch | None + IfNoneMatch: IfNoneMatch | None + GrantFullControl: GrantFullControl | None + GrantRead: GrantRead | None + GrantReadACP: GrantReadACP | None + GrantWriteACP: GrantWriteACP | None Key: ObjectKey - WriteOffsetBytes: Optional[WriteOffsetBytes] - Metadata: Optional[Metadata] - ServerSideEncryption: Optional[ServerSideEncryption] - StorageClass: Optional[StorageClass] - WebsiteRedirectLocation: Optional[WebsiteRedirectLocation] - SSECustomerAlgorithm: Optional[SSECustomerAlgorithm] - SSECustomerKey: Optional[SSECustomerKey] - SSECustomerKeyMD5: Optional[SSECustomerKeyMD5] - SSEKMSKeyId: Optional[SSEKMSKeyId] - SSEKMSEncryptionContext: Optional[SSEKMSEncryptionContext] - BucketKeyEnabled: Optional[BucketKeyEnabled] - RequestPayer: Optional[RequestPayer] - Tagging: Optional[TaggingHeader] - ObjectLockMode: Optional[ObjectLockMode] - ObjectLockRetainUntilDate: Optional[ObjectLockRetainUntilDate] - ObjectLockLegalHoldStatus: Optional[ObjectLockLegalHoldStatus] - ExpectedBucketOwner: Optional[AccountId] + WriteOffsetBytes: WriteOffsetBytes | None + Metadata: Metadata | None + ServerSideEncryption: ServerSideEncryption | None + StorageClass: StorageClass | None + WebsiteRedirectLocation: WebsiteRedirectLocation | None + SSECustomerAlgorithm: SSECustomerAlgorithm | None + SSECustomerKey: SSECustomerKey | None + SSECustomerKeyMD5: SSECustomerKeyMD5 | None + SSEKMSKeyId: SSEKMSKeyId | None + SSEKMSEncryptionContext: SSEKMSEncryptionContext | None + BucketKeyEnabled: BucketKeyEnabled | None + RequestPayer: RequestPayer | None + Tagging: TaggingHeader | None + ObjectLockMode: ObjectLockMode | None + ObjectLockRetainUntilDate: ObjectLockRetainUntilDate | None + ObjectLockLegalHoldStatus: ObjectLockLegalHoldStatus | None + ExpectedBucketOwner: AccountId | None class PutObjectRetentionOutput(TypedDict, total=False): - RequestCharged: Optional[RequestCharged] + RequestCharged: RequestCharged | None class PutObjectRetentionRequest(ServiceRequest): Bucket: BucketName Key: ObjectKey - Retention: Optional[ObjectLockRetention] - RequestPayer: Optional[RequestPayer] - VersionId: Optional[ObjectVersionId] - BypassGovernanceRetention: Optional[BypassGovernanceRetention] - ContentMD5: Optional[ContentMD5] - ChecksumAlgorithm: Optional[ChecksumAlgorithm] - ExpectedBucketOwner: Optional[AccountId] + Retention: ObjectLockRetention | None + RequestPayer: RequestPayer | None + VersionId: ObjectVersionId | None + BypassGovernanceRetention: BypassGovernanceRetention | None + ContentMD5: ContentMD5 | None + ChecksumAlgorithm: ChecksumAlgorithm | None + ExpectedBucketOwner: AccountId | None class PutObjectTaggingOutput(TypedDict, total=False): - VersionId: Optional[ObjectVersionId] + VersionId: ObjectVersionId | None class PutObjectTaggingRequest(ServiceRequest): Bucket: BucketName Key: ObjectKey - VersionId: Optional[ObjectVersionId] - ContentMD5: Optional[ContentMD5] - ChecksumAlgorithm: Optional[ChecksumAlgorithm] + VersionId: ObjectVersionId | None + ContentMD5: ContentMD5 | None + ChecksumAlgorithm: ChecksumAlgorithm | None Tagging: Tagging - ExpectedBucketOwner: Optional[AccountId] - RequestPayer: Optional[RequestPayer] + ExpectedBucketOwner: AccountId | None + RequestPayer: RequestPayer | None class PutPublicAccessBlockRequest(ServiceRequest): Bucket: BucketName - ContentMD5: Optional[ContentMD5] - ChecksumAlgorithm: Optional[ChecksumAlgorithm] + ContentMD5: ContentMD5 | None + ChecksumAlgorithm: ChecksumAlgorithm | None PublicAccessBlockConfiguration: PublicAccessBlockConfiguration - ExpectedBucketOwner: Optional[AccountId] + ExpectedBucketOwner: AccountId | None class RecordsEvent(TypedDict, total=False): - Payload: Optional[Body] + Payload: Body | None class RenameObjectOutput(TypedDict, total=False): @@ -3513,25 +3579,25 @@ class RenameObjectRequest(ServiceRequest): Bucket: BucketName Key: ObjectKey RenameSource: RenameSource - DestinationIfMatch: Optional[IfMatch] - DestinationIfNoneMatch: Optional[IfNoneMatch] - DestinationIfModifiedSince: Optional[IfModifiedSince] - DestinationIfUnmodifiedSince: Optional[IfUnmodifiedSince] - SourceIfMatch: Optional[RenameSourceIfMatch] - SourceIfNoneMatch: Optional[RenameSourceIfNoneMatch] - SourceIfModifiedSince: Optional[RenameSourceIfModifiedSince] - SourceIfUnmodifiedSince: Optional[RenameSourceIfUnmodifiedSince] - ClientToken: Optional[ClientToken] + DestinationIfMatch: IfMatch | None + DestinationIfNoneMatch: IfNoneMatch | None + DestinationIfModifiedSince: IfModifiedSince | None + DestinationIfUnmodifiedSince: IfUnmodifiedSince | None + SourceIfMatch: RenameSourceIfMatch | None + SourceIfNoneMatch: RenameSourceIfNoneMatch | None + SourceIfModifiedSince: RenameSourceIfModifiedSince | None + SourceIfUnmodifiedSince: RenameSourceIfUnmodifiedSince | None + ClientToken: ClientToken | None class RequestProgress(TypedDict, total=False): - Enabled: Optional[EnableRequestProgress] + Enabled: EnableRequestProgress | None class RestoreObjectOutput(TypedDict, total=False): - RequestCharged: Optional[RequestCharged] - RestoreOutputPath: Optional[RestoreOutputPath] - StatusCode: Optional[RestoreObjectOutputStatusCode] + RequestCharged: RequestCharged | None + RestoreOutputPath: RestoreOutputPath | None + StatusCode: RestoreObjectOutputStatusCode | None class SelectParameters(TypedDict, total=False): @@ -3542,49 +3608,49 @@ class SelectParameters(TypedDict, total=False): class RestoreRequest(TypedDict, total=False): - Days: Optional[Days] - GlacierJobParameters: Optional[GlacierJobParameters] - Type: Optional[RestoreRequestType] - Tier: Optional[Tier] - Description: Optional[Description] - SelectParameters: Optional[SelectParameters] - OutputLocation: Optional[OutputLocation] + Days: Days | None + GlacierJobParameters: GlacierJobParameters | None + Type: RestoreRequestType | None + Tier: Tier | None + Description: Description | None + SelectParameters: SelectParameters | None + OutputLocation: OutputLocation | None class RestoreObjectRequest(ServiceRequest): Bucket: BucketName Key: ObjectKey - VersionId: Optional[ObjectVersionId] - RestoreRequest: Optional[RestoreRequest] - RequestPayer: Optional[RequestPayer] - ChecksumAlgorithm: Optional[ChecksumAlgorithm] - ExpectedBucketOwner: Optional[AccountId] + VersionId: ObjectVersionId | None + RestoreRequest: RestoreRequest | None + RequestPayer: RequestPayer | None + ChecksumAlgorithm: ChecksumAlgorithm | None + ExpectedBucketOwner: AccountId | None Start = int class ScanRange(TypedDict, total=False): - Start: Optional[Start] - End: Optional[End] + Start: Start | None + End: End | None class Stats(TypedDict, total=False): - BytesScanned: Optional[BytesScanned] - BytesProcessed: Optional[BytesProcessed] - BytesReturned: Optional[BytesReturned] + BytesScanned: BytesScanned | None + BytesProcessed: BytesProcessed | None + BytesReturned: BytesReturned | None class StatsEvent(TypedDict, total=False): - Details: Optional[Stats] + Details: Stats | None class SelectObjectContentEventStream(TypedDict, total=False): - Records: Optional[RecordsEvent] - Stats: Optional[StatsEvent] - Progress: Optional[ProgressEvent] - Cont: Optional[ContinuationEvent] - End: Optional[EndEvent] + Records: RecordsEvent | None + Stats: StatsEvent | None + Progress: ProgressEvent | None + Cont: ContinuationEvent | None + End: EndEvent | None class SelectObjectContentOutput(TypedDict, total=False): @@ -3594,180 +3660,195 @@ class SelectObjectContentOutput(TypedDict, total=False): class SelectObjectContentRequest(ServiceRequest): Bucket: BucketName Key: ObjectKey - SSECustomerAlgorithm: Optional[SSECustomerAlgorithm] - SSECustomerKey: Optional[SSECustomerKey] - SSECustomerKeyMD5: Optional[SSECustomerKeyMD5] + SSECustomerAlgorithm: SSECustomerAlgorithm | None + SSECustomerKey: SSECustomerKey | None + SSECustomerKeyMD5: SSECustomerKeyMD5 | None Expression: Expression ExpressionType: ExpressionType - RequestProgress: Optional[RequestProgress] + RequestProgress: RequestProgress | None InputSerialization: InputSerialization OutputSerialization: OutputSerialization - ScanRange: Optional[ScanRange] - ExpectedBucketOwner: Optional[AccountId] + ScanRange: ScanRange | None + ExpectedBucketOwner: AccountId | None class UpdateBucketMetadataInventoryTableConfigurationRequest(ServiceRequest): Bucket: BucketName - ContentMD5: Optional[ContentMD5] - ChecksumAlgorithm: Optional[ChecksumAlgorithm] + ContentMD5: ContentMD5 | None + ChecksumAlgorithm: ChecksumAlgorithm | None InventoryTableConfiguration: InventoryTableConfigurationUpdates - ExpectedBucketOwner: Optional[AccountId] + ExpectedBucketOwner: AccountId | None class UpdateBucketMetadataJournalTableConfigurationRequest(ServiceRequest): Bucket: BucketName - ContentMD5: Optional[ContentMD5] - ChecksumAlgorithm: Optional[ChecksumAlgorithm] + ContentMD5: ContentMD5 | None + ChecksumAlgorithm: ChecksumAlgorithm | None JournalTableConfiguration: JournalTableConfigurationUpdates - ExpectedBucketOwner: Optional[AccountId] + ExpectedBucketOwner: AccountId | None + + +class UpdateObjectEncryptionRequest(ServiceRequest): + Bucket: BucketName + Key: ObjectKey + VersionId: ObjectVersionId | None + ObjectEncryption: ObjectEncryption + RequestPayer: RequestPayer | None + ExpectedBucketOwner: AccountId | None + ContentMD5: ContentMD5 | None + ChecksumAlgorithm: ChecksumAlgorithm | None + + +class UpdateObjectEncryptionResponse(TypedDict, total=False): + RequestCharged: RequestCharged | None class UploadPartCopyOutput(TypedDict, total=False): - CopySourceVersionId: Optional[CopySourceVersionId] - CopyPartResult: Optional[CopyPartResult] - ServerSideEncryption: Optional[ServerSideEncryption] - SSECustomerAlgorithm: Optional[SSECustomerAlgorithm] - SSECustomerKeyMD5: Optional[SSECustomerKeyMD5] - SSEKMSKeyId: Optional[SSEKMSKeyId] - BucketKeyEnabled: Optional[BucketKeyEnabled] - RequestCharged: Optional[RequestCharged] + CopySourceVersionId: CopySourceVersionId | None + CopyPartResult: CopyPartResult | None + ServerSideEncryption: ServerSideEncryption | None + SSECustomerAlgorithm: SSECustomerAlgorithm | None + SSECustomerKeyMD5: SSECustomerKeyMD5 | None + SSEKMSKeyId: SSEKMSKeyId | None + BucketKeyEnabled: BucketKeyEnabled | None + RequestCharged: RequestCharged | None class UploadPartCopyRequest(ServiceRequest): Bucket: BucketName CopySource: CopySource - CopySourceIfMatch: Optional[CopySourceIfMatch] - CopySourceIfModifiedSince: Optional[CopySourceIfModifiedSince] - CopySourceIfNoneMatch: Optional[CopySourceIfNoneMatch] - CopySourceIfUnmodifiedSince: Optional[CopySourceIfUnmodifiedSince] - CopySourceRange: Optional[CopySourceRange] + CopySourceIfMatch: CopySourceIfMatch | None + CopySourceIfModifiedSince: CopySourceIfModifiedSince | None + CopySourceIfNoneMatch: CopySourceIfNoneMatch | None + CopySourceIfUnmodifiedSince: CopySourceIfUnmodifiedSince | None + CopySourceRange: CopySourceRange | None Key: ObjectKey PartNumber: PartNumber UploadId: MultipartUploadId - SSECustomerAlgorithm: Optional[SSECustomerAlgorithm] - SSECustomerKey: Optional[SSECustomerKey] - SSECustomerKeyMD5: Optional[SSECustomerKeyMD5] - CopySourceSSECustomerAlgorithm: Optional[CopySourceSSECustomerAlgorithm] - CopySourceSSECustomerKey: Optional[CopySourceSSECustomerKey] - CopySourceSSECustomerKeyMD5: Optional[CopySourceSSECustomerKeyMD5] - RequestPayer: Optional[RequestPayer] - ExpectedBucketOwner: Optional[AccountId] - ExpectedSourceBucketOwner: Optional[AccountId] + SSECustomerAlgorithm: SSECustomerAlgorithm | None + SSECustomerKey: SSECustomerKey | None + SSECustomerKeyMD5: SSECustomerKeyMD5 | None + CopySourceSSECustomerAlgorithm: CopySourceSSECustomerAlgorithm | None + CopySourceSSECustomerKey: CopySourceSSECustomerKey | None + CopySourceSSECustomerKeyMD5: CopySourceSSECustomerKeyMD5 | None + RequestPayer: RequestPayer | None + ExpectedBucketOwner: AccountId | None + ExpectedSourceBucketOwner: AccountId | None class UploadPartOutput(TypedDict, total=False): - ServerSideEncryption: Optional[ServerSideEncryption] - ETag: Optional[ETag] - ChecksumCRC32: Optional[ChecksumCRC32] - ChecksumCRC32C: Optional[ChecksumCRC32C] - ChecksumCRC64NVME: Optional[ChecksumCRC64NVME] - ChecksumSHA1: Optional[ChecksumSHA1] - ChecksumSHA256: Optional[ChecksumSHA256] - SSECustomerAlgorithm: Optional[SSECustomerAlgorithm] - SSECustomerKeyMD5: Optional[SSECustomerKeyMD5] - SSEKMSKeyId: Optional[SSEKMSKeyId] - BucketKeyEnabled: Optional[BucketKeyEnabled] - RequestCharged: Optional[RequestCharged] + ServerSideEncryption: ServerSideEncryption | None + ETag: ETag | None + ChecksumCRC32: ChecksumCRC32 | None + ChecksumCRC32C: ChecksumCRC32C | None + ChecksumCRC64NVME: ChecksumCRC64NVME | None + ChecksumSHA1: ChecksumSHA1 | None + ChecksumSHA256: ChecksumSHA256 | None + SSECustomerAlgorithm: SSECustomerAlgorithm | None + SSECustomerKeyMD5: SSECustomerKeyMD5 | None + SSEKMSKeyId: SSEKMSKeyId | None + BucketKeyEnabled: BucketKeyEnabled | None + RequestCharged: RequestCharged | None class UploadPartRequest(ServiceRequest): - Body: Optional[IO[Body]] + Body: IO[Body] | None Bucket: BucketName - ContentLength: Optional[ContentLength] - ContentMD5: Optional[ContentMD5] - ChecksumAlgorithm: Optional[ChecksumAlgorithm] - ChecksumCRC32: Optional[ChecksumCRC32] - ChecksumCRC32C: Optional[ChecksumCRC32C] - ChecksumCRC64NVME: Optional[ChecksumCRC64NVME] - ChecksumSHA1: Optional[ChecksumSHA1] - ChecksumSHA256: Optional[ChecksumSHA256] + ContentLength: ContentLength | None + ContentMD5: ContentMD5 | None + ChecksumAlgorithm: ChecksumAlgorithm | None + ChecksumCRC32: ChecksumCRC32 | None + ChecksumCRC32C: ChecksumCRC32C | None + ChecksumCRC64NVME: ChecksumCRC64NVME | None + ChecksumSHA1: ChecksumSHA1 | None + ChecksumSHA256: ChecksumSHA256 | None Key: ObjectKey PartNumber: PartNumber UploadId: MultipartUploadId - SSECustomerAlgorithm: Optional[SSECustomerAlgorithm] - SSECustomerKey: Optional[SSECustomerKey] - SSECustomerKeyMD5: Optional[SSECustomerKeyMD5] - RequestPayer: Optional[RequestPayer] - ExpectedBucketOwner: Optional[AccountId] + SSECustomerAlgorithm: SSECustomerAlgorithm | None + SSECustomerKey: SSECustomerKey | None + SSECustomerKeyMD5: SSECustomerKeyMD5 | None + RequestPayer: RequestPayer | None + ExpectedBucketOwner: AccountId | None class WriteGetObjectResponseRequest(ServiceRequest): - Body: Optional[IO[Body]] + Body: IO[Body] | None RequestRoute: RequestRoute RequestToken: RequestToken - StatusCode: Optional[GetObjectResponseStatusCode] - ErrorCode: Optional[ErrorCode] - ErrorMessage: Optional[ErrorMessage] - AcceptRanges: Optional[AcceptRanges] - CacheControl: Optional[CacheControl] - ContentDisposition: Optional[ContentDisposition] - ContentEncoding: Optional[ContentEncoding] - ContentLanguage: Optional[ContentLanguage] - ContentLength: Optional[ContentLength] - ContentRange: Optional[ContentRange] - ContentType: Optional[ContentType] - ChecksumCRC32: Optional[ChecksumCRC32] - ChecksumCRC32C: Optional[ChecksumCRC32C] - ChecksumCRC64NVME: Optional[ChecksumCRC64NVME] - ChecksumSHA1: Optional[ChecksumSHA1] - ChecksumSHA256: Optional[ChecksumSHA256] - DeleteMarker: Optional[DeleteMarker] - ETag: Optional[ETag] - Expires: Optional[Expires] - Expiration: Optional[Expiration] - LastModified: Optional[LastModified] - MissingMeta: Optional[MissingMeta] - Metadata: Optional[Metadata] - ObjectLockMode: Optional[ObjectLockMode] - ObjectLockLegalHoldStatus: Optional[ObjectLockLegalHoldStatus] - ObjectLockRetainUntilDate: Optional[ObjectLockRetainUntilDate] - PartsCount: Optional[PartsCount] - ReplicationStatus: Optional[ReplicationStatus] - RequestCharged: Optional[RequestCharged] - Restore: Optional[Restore] - ServerSideEncryption: Optional[ServerSideEncryption] - SSECustomerAlgorithm: Optional[SSECustomerAlgorithm] - SSEKMSKeyId: Optional[SSEKMSKeyId] - SSECustomerKeyMD5: Optional[SSECustomerKeyMD5] - StorageClass: Optional[StorageClass] - TagCount: Optional[TagCount] - VersionId: Optional[ObjectVersionId] - BucketKeyEnabled: Optional[BucketKeyEnabled] + StatusCode: GetObjectResponseStatusCode | None + ErrorCode: ErrorCode | None + ErrorMessage: ErrorMessage | None + AcceptRanges: AcceptRanges | None + CacheControl: CacheControl | None + ContentDisposition: ContentDisposition | None + ContentEncoding: ContentEncoding | None + ContentLanguage: ContentLanguage | None + ContentLength: ContentLength | None + ContentRange: ContentRange | None + ContentType: ContentType | None + ChecksumCRC32: ChecksumCRC32 | None + ChecksumCRC32C: ChecksumCRC32C | None + ChecksumCRC64NVME: ChecksumCRC64NVME | None + ChecksumSHA1: ChecksumSHA1 | None + ChecksumSHA256: ChecksumSHA256 | None + DeleteMarker: DeleteMarker | None + ETag: ETag | None + Expires: Expires | None + Expiration: Expiration | None + LastModified: LastModified | None + MissingMeta: MissingMeta | None + Metadata: Metadata | None + ObjectLockMode: ObjectLockMode | None + ObjectLockLegalHoldStatus: ObjectLockLegalHoldStatus | None + ObjectLockRetainUntilDate: ObjectLockRetainUntilDate | None + PartsCount: PartsCount | None + ReplicationStatus: ReplicationStatus | None + RequestCharged: RequestCharged | None + Restore: Restore | None + ServerSideEncryption: ServerSideEncryption | None + SSECustomerAlgorithm: SSECustomerAlgorithm | None + SSEKMSKeyId: SSEKMSKeyId | None + SSECustomerKeyMD5: SSECustomerKeyMD5 | None + StorageClass: StorageClass | None + TagCount: TagCount | None + VersionId: ObjectVersionId | None + BucketKeyEnabled: BucketKeyEnabled | None class PostObjectRequest(ServiceRequest): - Body: Optional[IO[Body]] + Body: IO[Body] | None Bucket: BucketName class PostResponse(TypedDict, total=False): - StatusCode: Optional[GetObjectResponseStatusCode] - Location: Optional[Location] - LocationHeader: Optional[Location] - Bucket: Optional[BucketName] - Key: Optional[ObjectKey] - Expiration: Optional[Expiration] - ETag: Optional[ETag] - ETagHeader: Optional[ETag] - ChecksumCRC32: Optional[ChecksumCRC32] - ChecksumCRC32C: Optional[ChecksumCRC32C] - ChecksumCRC64NVME: Optional[ChecksumCRC64NVME] - ChecksumSHA1: Optional[ChecksumSHA1] - ChecksumSHA256: Optional[ChecksumSHA256] - ChecksumType: Optional[ChecksumType] - ServerSideEncryption: Optional[ServerSideEncryption] - VersionId: Optional[ObjectVersionId] - SSECustomerAlgorithm: Optional[SSECustomerAlgorithm] - SSECustomerKeyMD5: Optional[SSECustomerKeyMD5] - SSEKMSKeyId: Optional[SSEKMSKeyId] - SSEKMSEncryptionContext: Optional[SSEKMSEncryptionContext] - BucketKeyEnabled: Optional[BucketKeyEnabled] - RequestCharged: Optional[RequestCharged] + StatusCode: GetObjectResponseStatusCode | None + Location: Location | None + LocationHeader: Location | None + Bucket: BucketName | None + Key: ObjectKey | None + Expiration: Expiration | None + ETag: ETag | None + ETagHeader: ETag | None + ChecksumCRC32: ChecksumCRC32 | None + ChecksumCRC32C: ChecksumCRC32C | None + ChecksumCRC64NVME: ChecksumCRC64NVME | None + ChecksumSHA1: ChecksumSHA1 | None + ChecksumSHA256: ChecksumSHA256 | None + ChecksumType: ChecksumType | None + ServerSideEncryption: ServerSideEncryption | None + VersionId: ObjectVersionId | None + SSECustomerAlgorithm: SSECustomerAlgorithm | None + SSECustomerKeyMD5: SSECustomerKeyMD5 | None + SSEKMSKeyId: SSEKMSKeyId | None + SSEKMSEncryptionContext: SSEKMSEncryptionContext | None + BucketKeyEnabled: BucketKeyEnabled | None + RequestCharged: RequestCharged | None class S3Api: - service = "s3" - version = "2006-03-01" + service: str = "s3" + version: str = "2006-03-01" @handler("AbortMultipartUpload") def abort_multipart_upload( @@ -3832,6 +3913,8 @@ def copy_object( grant_read: GrantRead | None = None, grant_read_acp: GrantReadACP | None = None, grant_write_acp: GrantWriteACP | None = None, + if_match: IfMatch | None = None, + if_none_match: IfNoneMatch | None = None, metadata: Metadata | None = None, metadata_directive: MetadataDirective | None = None, tagging_directive: TaggingDirective | None = None, @@ -4164,6 +4247,16 @@ def delete_public_access_block( ) -> None: raise NotImplementedError + @handler("GetBucketAbac") + def get_bucket_abac( + self, + context: RequestContext, + bucket: BucketName, + expected_bucket_owner: AccountId | None = None, + **kwargs, + ) -> GetBucketAbacOutput: + raise NotImplementedError + @handler("GetBucketAccelerateConfiguration") def get_bucket_accelerate_configuration( self, @@ -4735,6 +4828,19 @@ def list_parts( ) -> ListPartsOutput: raise NotImplementedError + @handler("PutBucketAbac") + def put_bucket_abac( + self, + context: RequestContext, + bucket: BucketName, + abac_status: AbacStatus, + content_md5: ContentMD5 | None = None, + checksum_algorithm: ChecksumAlgorithm | None = None, + expected_bucket_owner: AccountId | None = None, + **kwargs, + ) -> None: + raise NotImplementedError + @handler("PutBucketAccelerateConfiguration") def put_bucket_accelerate_configuration( self, @@ -5227,6 +5333,22 @@ def update_bucket_metadata_journal_table_configuration( ) -> None: raise NotImplementedError + @handler("UpdateObjectEncryption") + def update_object_encryption( + self, + context: RequestContext, + bucket: BucketName, + key: ObjectKey, + object_encryption: ObjectEncryption, + version_id: ObjectVersionId | None = None, + request_payer: RequestPayer | None = None, + expected_bucket_owner: AccountId | None = None, + content_md5: ContentMD5 | None = None, + checksum_algorithm: ChecksumAlgorithm | None = None, + **kwargs, + ) -> UpdateObjectEncryptionResponse: + raise NotImplementedError + @handler("UploadPart") def upload_part( self, diff --git a/localstack-core/localstack/aws/api/s3control/__init__.py b/localstack-core/localstack/aws/api/s3control/__init__.py index 84490dc574503..b5b1972471567 100644 --- a/localstack-core/localstack/aws/api/s3control/__init__.py +++ b/localstack-core/localstack/aws/api/s3control/__init__.py @@ -1,6 +1,6 @@ from datetime import datetime from enum import StrEnum -from typing import Dict, List, Optional, TypedDict +from typing import TypedDict from localstack.aws.api import RequestContext, ServiceException, ServiceRequest, handler @@ -288,6 +288,7 @@ class OperationName(StrEnum): S3PutObjectRetention = "S3PutObjectRetention" S3ReplicateObject = "S3ReplicateObject" S3ComputeObjectChecksum = "S3ComputeObjectChecksum" + S3UpdateObjectEncryption = "S3UpdateObjectEncryption" class OutputSchemaVersion(StrEnum): @@ -521,7 +522,7 @@ class TooManyTagsException(ServiceException): class AbortIncompleteMultipartUpload(TypedDict, total=False): - DaysAfterInitiation: Optional[DaysAfterInitiation] + DaysAfterInitiation: DaysAfterInitiation | None class AccessControlTranslation(TypedDict, total=False): @@ -532,50 +533,50 @@ class AccessControlTranslation(TypedDict, total=False): class ListAccessGrantsInstanceEntry(TypedDict, total=False): - AccessGrantsInstanceId: Optional[AccessGrantsInstanceId] - AccessGrantsInstanceArn: Optional[AccessGrantsInstanceArn] - CreatedAt: Optional[CreationTimestamp] - IdentityCenterArn: Optional[IdentityCenterArn] - IdentityCenterInstanceArn: Optional[IdentityCenterArn] - IdentityCenterApplicationArn: Optional[IdentityCenterApplicationArn] + AccessGrantsInstanceId: AccessGrantsInstanceId | None + AccessGrantsInstanceArn: AccessGrantsInstanceArn | None + CreatedAt: CreationTimestamp | None + IdentityCenterArn: IdentityCenterArn | None + IdentityCenterInstanceArn: IdentityCenterArn | None + IdentityCenterApplicationArn: IdentityCenterApplicationArn | None -AccessGrantsInstancesList = List[ListAccessGrantsInstanceEntry] +AccessGrantsInstancesList = list[ListAccessGrantsInstanceEntry] class AccessGrantsLocationConfiguration(TypedDict, total=False): - S3SubPrefix: Optional[S3Prefix] + S3SubPrefix: S3Prefix | None class Grantee(TypedDict, total=False): - GranteeType: Optional[GranteeType] - GranteeIdentifier: Optional[GranteeIdentifier] + GranteeType: GranteeType | None + GranteeIdentifier: GranteeIdentifier | None class ListAccessGrantEntry(TypedDict, total=False): - CreatedAt: Optional[CreationTimestamp] - AccessGrantId: Optional[AccessGrantId] - AccessGrantArn: Optional[AccessGrantArn] - Grantee: Optional[Grantee] - Permission: Optional[Permission] - AccessGrantsLocationId: Optional[AccessGrantsLocationId] - AccessGrantsLocationConfiguration: Optional[AccessGrantsLocationConfiguration] - GrantScope: Optional[S3Prefix] - ApplicationArn: Optional[IdentityCenterApplicationArn] + CreatedAt: CreationTimestamp | None + AccessGrantId: AccessGrantId | None + AccessGrantArn: AccessGrantArn | None + Grantee: Grantee | None + Permission: Permission | None + AccessGrantsLocationId: AccessGrantsLocationId | None + AccessGrantsLocationConfiguration: AccessGrantsLocationConfiguration | None + GrantScope: S3Prefix | None + ApplicationArn: IdentityCenterApplicationArn | None -AccessGrantsList = List[ListAccessGrantEntry] +AccessGrantsList = list[ListAccessGrantEntry] class ListAccessGrantsLocationsEntry(TypedDict, total=False): - CreatedAt: Optional[CreationTimestamp] - AccessGrantsLocationId: Optional[AccessGrantsLocationId] - AccessGrantsLocationArn: Optional[AccessGrantsLocationArn] - LocationScope: Optional[S3Prefix] - IAMRoleArn: Optional[IAMRoleArn] + CreatedAt: CreationTimestamp | None + AccessGrantsLocationId: AccessGrantsLocationId | None + AccessGrantsLocationArn: AccessGrantsLocationArn | None + LocationScope: S3Prefix | None + IAMRoleArn: IAMRoleArn | None -AccessGrantsLocationsList = List[ListAccessGrantsLocationsEntry] +AccessGrantsLocationsList = list[ListAccessGrantsLocationsEntry] class VpcConfiguration(TypedDict, total=False): @@ -585,50 +586,54 @@ class VpcConfiguration(TypedDict, total=False): class AccessPoint(TypedDict, total=False): Name: AccessPointName NetworkOrigin: NetworkOrigin - VpcConfiguration: Optional[VpcConfiguration] + VpcConfiguration: VpcConfiguration | None Bucket: AccessPointBucketName - AccessPointArn: Optional[S3AccessPointArn] - Alias: Optional[Alias] - BucketAccountId: Optional[AccountId] - DataSourceId: Optional[DataSourceId] - DataSourceType: Optional[DataSourceType] + AccessPointArn: S3AccessPointArn | None + Alias: Alias | None + BucketAccountId: AccountId | None + DataSourceId: DataSourceId | None + DataSourceType: DataSourceType | None -AccessPointList = List[AccessPoint] -StorageLensGroupLevelExclude = List[StorageLensGroupArn] -StorageLensGroupLevelInclude = List[StorageLensGroupArn] +AccessPointList = list[AccessPoint] +StorageLensGroupLevelExclude = list[StorageLensGroupArn] +StorageLensGroupLevelInclude = list[StorageLensGroupArn] class StorageLensGroupLevelSelectionCriteria(TypedDict, total=False): - Include: Optional[StorageLensGroupLevelInclude] - Exclude: Optional[StorageLensGroupLevelExclude] + Include: StorageLensGroupLevelInclude | None + Exclude: StorageLensGroupLevelExclude | None class StorageLensGroupLevel(TypedDict, total=False): - SelectionCriteria: Optional[StorageLensGroupLevelSelectionCriteria] + SelectionCriteria: StorageLensGroupLevelSelectionCriteria | None + + +class AdvancedPerformanceMetrics(TypedDict, total=False): + IsEnabled: IsEnabled | None class DetailedStatusCodesMetrics(TypedDict, total=False): - IsEnabled: Optional[IsEnabled] + IsEnabled: IsEnabled | None class AdvancedDataProtectionMetrics(TypedDict, total=False): - IsEnabled: Optional[IsEnabled] + IsEnabled: IsEnabled | None class AdvancedCostOptimizationMetrics(TypedDict, total=False): - IsEnabled: Optional[IsEnabled] + IsEnabled: IsEnabled | None class SelectionCriteria(TypedDict, total=False): - Delimiter: Optional[StorageLensPrefixLevelDelimiter] - MaxDepth: Optional[StorageLensPrefixLevelMaxDepth] - MinStorageBytesPercentage: Optional[MinStorageBytesPercentage] + Delimiter: StorageLensPrefixLevelDelimiter | None + MaxDepth: StorageLensPrefixLevelMaxDepth | None + MinStorageBytesPercentage: MinStorageBytesPercentage | None class PrefixLevelStorageMetrics(TypedDict, total=False): - IsEnabled: Optional[IsEnabled] - SelectionCriteria: Optional[SelectionCriteria] + IsEnabled: IsEnabled | None + SelectionCriteria: SelectionCriteria | None class PrefixLevel(TypedDict, total=False): @@ -636,24 +641,26 @@ class PrefixLevel(TypedDict, total=False): class ActivityMetrics(TypedDict, total=False): - IsEnabled: Optional[IsEnabled] + IsEnabled: IsEnabled | None class BucketLevel(TypedDict, total=False): - ActivityMetrics: Optional[ActivityMetrics] - PrefixLevel: Optional[PrefixLevel] - AdvancedCostOptimizationMetrics: Optional[AdvancedCostOptimizationMetrics] - AdvancedDataProtectionMetrics: Optional[AdvancedDataProtectionMetrics] - DetailedStatusCodesMetrics: Optional[DetailedStatusCodesMetrics] + ActivityMetrics: ActivityMetrics | None + PrefixLevel: PrefixLevel | None + AdvancedCostOptimizationMetrics: AdvancedCostOptimizationMetrics | None + AdvancedDataProtectionMetrics: AdvancedDataProtectionMetrics | None + DetailedStatusCodesMetrics: DetailedStatusCodesMetrics | None + AdvancedPerformanceMetrics: AdvancedPerformanceMetrics | None class AccountLevel(TypedDict, total=False): - ActivityMetrics: Optional[ActivityMetrics] + ActivityMetrics: ActivityMetrics | None BucketLevel: BucketLevel - AdvancedCostOptimizationMetrics: Optional[AdvancedCostOptimizationMetrics] - AdvancedDataProtectionMetrics: Optional[AdvancedDataProtectionMetrics] - DetailedStatusCodesMetrics: Optional[DetailedStatusCodesMetrics] - StorageLensGroupLevel: Optional[StorageLensGroupLevel] + AdvancedCostOptimizationMetrics: AdvancedCostOptimizationMetrics | None + AdvancedDataProtectionMetrics: AdvancedDataProtectionMetrics | None + DetailedStatusCodesMetrics: DetailedStatusCodesMetrics | None + AdvancedPerformanceMetrics: AdvancedPerformanceMetrics | None + StorageLensGroupLevel: StorageLensGroupLevel | None class AssociateAccessGrantsIdentityCenterRequest(ServiceRequest): @@ -665,27 +672,27 @@ class AssociateAccessGrantsIdentityCenterRequest(ServiceRequest): class AsyncErrorDetails(TypedDict, total=False): - Code: Optional[MaxLength1024String] - Message: Optional[MaxLength1024String] - Resource: Optional[MaxLength1024String] - RequestId: Optional[MaxLength1024String] + Code: MaxLength1024String | None + Message: MaxLength1024String | None + Resource: MaxLength1024String | None + RequestId: MaxLength1024String | None class MultiRegionAccessPointRegionalResponse(TypedDict, total=False): - Name: Optional[RegionName] - RequestStatus: Optional[AsyncRequestStatus] + Name: RegionName | None + RequestStatus: AsyncRequestStatus | None -MultiRegionAccessPointRegionalResponseList = List[MultiRegionAccessPointRegionalResponse] +MultiRegionAccessPointRegionalResponseList = list[MultiRegionAccessPointRegionalResponse] class MultiRegionAccessPointsAsyncResponse(TypedDict, total=False): - Regions: Optional[MultiRegionAccessPointRegionalResponseList] + Regions: MultiRegionAccessPointRegionalResponseList | None class AsyncResponseDetails(TypedDict, total=False): - MultiRegionAccessPointDetails: Optional[MultiRegionAccessPointsAsyncResponse] - ErrorDetails: Optional[AsyncErrorDetails] + MultiRegionAccessPointDetails: MultiRegionAccessPointsAsyncResponse | None + ErrorDetails: AsyncErrorDetails | None class PutMultiRegionAccessPointPolicyInput(TypedDict, total=False): @@ -699,55 +706,55 @@ class DeleteMultiRegionAccessPointInput(TypedDict, total=False): class Region(TypedDict, total=False): Bucket: BucketName - BucketAccountId: Optional[AccountId] + BucketAccountId: AccountId | None -RegionCreationList = List[Region] +RegionCreationList = list[Region] class PublicAccessBlockConfiguration(TypedDict, total=False): - BlockPublicAcls: Optional[Setting] - IgnorePublicAcls: Optional[Setting] - BlockPublicPolicy: Optional[Setting] - RestrictPublicBuckets: Optional[Setting] + BlockPublicAcls: Setting | None + IgnorePublicAcls: Setting | None + BlockPublicPolicy: Setting | None + RestrictPublicBuckets: Setting | None class CreateMultiRegionAccessPointInput(TypedDict, total=False): Name: MultiRegionAccessPointName - PublicAccessBlock: Optional[PublicAccessBlockConfiguration] + PublicAccessBlock: PublicAccessBlockConfiguration | None Regions: RegionCreationList class AsyncRequestParameters(TypedDict, total=False): - CreateMultiRegionAccessPointRequest: Optional[CreateMultiRegionAccessPointInput] - DeleteMultiRegionAccessPointRequest: Optional[DeleteMultiRegionAccessPointInput] - PutMultiRegionAccessPointPolicyRequest: Optional[PutMultiRegionAccessPointPolicyInput] + CreateMultiRegionAccessPointRequest: CreateMultiRegionAccessPointInput | None + DeleteMultiRegionAccessPointRequest: DeleteMultiRegionAccessPointInput | None + PutMultiRegionAccessPointPolicyRequest: PutMultiRegionAccessPointPolicyInput | None class AsyncOperation(TypedDict, total=False): - CreationTime: Optional[AsyncCreationTimestamp] - Operation: Optional[AsyncOperationName] - RequestTokenARN: Optional[AsyncRequestTokenARN] - RequestParameters: Optional[AsyncRequestParameters] - RequestStatus: Optional[AsyncRequestStatus] - ResponseDetails: Optional[AsyncResponseDetails] + CreationTime: AsyncCreationTimestamp | None + Operation: AsyncOperationName | None + RequestTokenARN: AsyncRequestTokenARN | None + RequestParameters: AsyncRequestParameters | None + RequestStatus: AsyncRequestStatus | None + ResponseDetails: AsyncResponseDetails | None class AwsLambdaTransformation(TypedDict, total=False): FunctionArn: FunctionArnString - FunctionPayload: Optional[AwsLambdaTransformationPayload] + FunctionPayload: AwsLambdaTransformationPayload | None -Buckets = List[S3BucketArnString] +Buckets = list[S3BucketArnString] class ListCallerAccessGrantsEntry(TypedDict, total=False): - Permission: Optional[Permission] - GrantScope: Optional[S3Prefix] - ApplicationArn: Optional[IdentityCenterApplicationArn] + Permission: Permission | None + GrantScope: S3Prefix | None + ApplicationArn: IdentityCenterApplicationArn | None -CallerAccessGrantsList = List[ListCallerAccessGrantsEntry] +CallerAccessGrantsList = list[ListCallerAccessGrantsEntry] class CloudWatchMetrics(TypedDict, total=False): @@ -759,67 +766,67 @@ class Tag(TypedDict, total=False): Value: TagValueString -TagList = List[Tag] +TagList = list[Tag] class CreateAccessGrantRequest(ServiceRequest): AccountId: AccountId AccessGrantsLocationId: AccessGrantsLocationId - AccessGrantsLocationConfiguration: Optional[AccessGrantsLocationConfiguration] + AccessGrantsLocationConfiguration: AccessGrantsLocationConfiguration | None Grantee: Grantee Permission: Permission - ApplicationArn: Optional[IdentityCenterApplicationArn] - S3PrefixType: Optional[S3PrefixType] - Tags: Optional[TagList] + ApplicationArn: IdentityCenterApplicationArn | None + S3PrefixType: S3PrefixType | None + Tags: TagList | None class CreateAccessGrantResult(TypedDict, total=False): - CreatedAt: Optional[CreationTimestamp] - AccessGrantId: Optional[AccessGrantId] - AccessGrantArn: Optional[AccessGrantArn] - Grantee: Optional[Grantee] - AccessGrantsLocationId: Optional[AccessGrantsLocationId] - AccessGrantsLocationConfiguration: Optional[AccessGrantsLocationConfiguration] - Permission: Optional[Permission] - ApplicationArn: Optional[IdentityCenterApplicationArn] - GrantScope: Optional[S3Prefix] + CreatedAt: CreationTimestamp | None + AccessGrantId: AccessGrantId | None + AccessGrantArn: AccessGrantArn | None + Grantee: Grantee | None + AccessGrantsLocationId: AccessGrantsLocationId | None + AccessGrantsLocationConfiguration: AccessGrantsLocationConfiguration | None + Permission: Permission | None + ApplicationArn: IdentityCenterApplicationArn | None + GrantScope: S3Prefix | None class CreateAccessGrantsInstanceRequest(ServiceRequest): AccountId: AccountId - IdentityCenterArn: Optional[IdentityCenterArn] - Tags: Optional[TagList] + IdentityCenterArn: IdentityCenterArn | None + Tags: TagList | None class CreateAccessGrantsInstanceResult(TypedDict, total=False): - CreatedAt: Optional[CreationTimestamp] - AccessGrantsInstanceId: Optional[AccessGrantsInstanceId] - AccessGrantsInstanceArn: Optional[AccessGrantsInstanceArn] - IdentityCenterArn: Optional[IdentityCenterArn] - IdentityCenterInstanceArn: Optional[IdentityCenterArn] - IdentityCenterApplicationArn: Optional[IdentityCenterApplicationArn] + CreatedAt: CreationTimestamp | None + AccessGrantsInstanceId: AccessGrantsInstanceId | None + AccessGrantsInstanceArn: AccessGrantsInstanceArn | None + IdentityCenterArn: IdentityCenterArn | None + IdentityCenterInstanceArn: IdentityCenterArn | None + IdentityCenterApplicationArn: IdentityCenterApplicationArn | None class CreateAccessGrantsLocationRequest(ServiceRequest): AccountId: AccountId LocationScope: S3Prefix IAMRoleArn: IAMRoleArn - Tags: Optional[TagList] + Tags: TagList | None class CreateAccessGrantsLocationResult(TypedDict, total=False): - CreatedAt: Optional[CreationTimestamp] - AccessGrantsLocationId: Optional[AccessGrantsLocationId] - AccessGrantsLocationArn: Optional[AccessGrantsLocationArn] - LocationScope: Optional[S3Prefix] - IAMRoleArn: Optional[IAMRoleArn] + CreatedAt: CreationTimestamp | None + AccessGrantsLocationId: AccessGrantsLocationId | None + AccessGrantsLocationArn: AccessGrantsLocationArn | None + LocationScope: S3Prefix | None + IAMRoleArn: IAMRoleArn | None class ObjectLambdaContentTransformation(TypedDict, total=False): - AwsLambda: Optional[AwsLambdaTransformation] + AwsLambda: AwsLambdaTransformation | None -ObjectLambdaTransformationConfigurationActionsList = List[ +ObjectLambdaTransformationConfigurationActionsList = list[ ObjectLambdaTransformationConfigurationAction ] @@ -829,14 +836,14 @@ class ObjectLambdaTransformationConfiguration(TypedDict, total=False): ContentTransformation: ObjectLambdaContentTransformation -ObjectLambdaTransformationConfigurationsList = List[ObjectLambdaTransformationConfiguration] -ObjectLambdaAllowedFeaturesList = List[ObjectLambdaAllowedFeature] +ObjectLambdaTransformationConfigurationsList = list[ObjectLambdaTransformationConfiguration] +ObjectLambdaAllowedFeaturesList = list[ObjectLambdaAllowedFeature] class ObjectLambdaConfiguration(TypedDict, total=False): SupportingAccessPoint: ObjectLambdaSupportingAccessPointArn - CloudWatchMetricsEnabled: Optional[Boolean] - AllowedFeatures: Optional[ObjectLambdaAllowedFeaturesList] + CloudWatchMetricsEnabled: Boolean | None + AllowedFeatures: ObjectLambdaAllowedFeaturesList | None TransformationConfigurations: ObjectLambdaTransformationConfigurationsList @@ -847,60 +854,60 @@ class CreateAccessPointForObjectLambdaRequest(ServiceRequest): class ObjectLambdaAccessPointAlias(TypedDict, total=False): - Value: Optional[ObjectLambdaAccessPointAliasValue] - Status: Optional[ObjectLambdaAccessPointAliasStatus] + Value: ObjectLambdaAccessPointAliasValue | None + Status: ObjectLambdaAccessPointAliasStatus | None class CreateAccessPointForObjectLambdaResult(TypedDict, total=False): - ObjectLambdaAccessPointArn: Optional[ObjectLambdaAccessPointArn] - Alias: Optional[ObjectLambdaAccessPointAlias] + ObjectLambdaAccessPointArn: ObjectLambdaAccessPointArn | None + Alias: ObjectLambdaAccessPointAlias | None -ScopePermissionList = List[ScopePermission] -PrefixesList = List[Prefix] +ScopePermissionList = list[ScopePermission] +PrefixesList = list[Prefix] class Scope(TypedDict, total=False): - Prefixes: Optional[PrefixesList] - Permissions: Optional[ScopePermissionList] + Prefixes: PrefixesList | None + Permissions: ScopePermissionList | None class CreateAccessPointRequest(ServiceRequest): AccountId: AccountId Name: AccessPointName Bucket: BucketName - VpcConfiguration: Optional[VpcConfiguration] - PublicAccessBlockConfiguration: Optional[PublicAccessBlockConfiguration] - BucketAccountId: Optional[AccountId] - Scope: Optional[Scope] - Tags: Optional[TagList] + VpcConfiguration: VpcConfiguration | None + PublicAccessBlockConfiguration: PublicAccessBlockConfiguration | None + BucketAccountId: AccountId | None + Scope: Scope | None + Tags: TagList | None class CreateAccessPointResult(TypedDict, total=False): - AccessPointArn: Optional[S3AccessPointArn] - Alias: Optional[Alias] + AccessPointArn: S3AccessPointArn | None + Alias: Alias | None class CreateBucketConfiguration(TypedDict, total=False): - LocationConstraint: Optional[BucketLocationConstraint] + LocationConstraint: BucketLocationConstraint | None class CreateBucketRequest(ServiceRequest): - ACL: Optional[BucketCannedACL] + ACL: BucketCannedACL | None Bucket: BucketName - CreateBucketConfiguration: Optional[CreateBucketConfiguration] - GrantFullControl: Optional[GrantFullControl] - GrantRead: Optional[GrantRead] - GrantReadACP: Optional[GrantReadACP] - GrantWrite: Optional[GrantWrite] - GrantWriteACP: Optional[GrantWriteACP] - ObjectLockEnabledForBucket: Optional[ObjectLockEnabledForBucket] - OutpostId: Optional[NonEmptyMaxLength64String] + CreateBucketConfiguration: CreateBucketConfiguration | None + GrantFullControl: GrantFullControl | None + GrantRead: GrantRead | None + GrantReadACP: GrantReadACP | None + GrantWrite: GrantWrite | None + GrantWriteACP: GrantWriteACP | None + ObjectLockEnabledForBucket: ObjectLockEnabledForBucket | None + OutpostId: NonEmptyMaxLength64String | None class CreateBucketResult(TypedDict, total=False): - Location: Optional[Location] - BucketArn: Optional[S3RegionalBucketArn] + Location: Location | None + BucketArn: S3RegionalBucketArn | None class NotSSEFilter(TypedDict, total=False): @@ -912,12 +919,12 @@ class SSECFilter(TypedDict, total=False): class DSSEKMSFilter(TypedDict, total=False): - KmsKeyArn: Optional[NonEmptyKmsKeyArnString] + KmsKeyArn: NonEmptyKmsKeyArnString | None class SSEKMSFilter(TypedDict, total=False): - KmsKeyArn: Optional[NonEmptyKmsKeyArnString] - BucketKeyEnabled: Optional[Boolean] + KmsKeyArn: NonEmptyKmsKeyArnString | None + BucketKeyEnabled: Boolean | None class SSES3Filter(TypedDict, total=False): @@ -925,40 +932,40 @@ class SSES3Filter(TypedDict, total=False): class ObjectEncryptionFilter(TypedDict, total=False): - SSES3: Optional[SSES3Filter] - SSEKMS: Optional[SSEKMSFilter] - DSSEKMS: Optional[DSSEKMSFilter] - SSEC: Optional[SSECFilter] - NOTSSE: Optional[NotSSEFilter] + SSES3: SSES3Filter | None + SSEKMS: SSEKMSFilter | None + DSSEKMS: DSSEKMSFilter | None + SSEC: SSECFilter | None + NOTSSE: NotSSEFilter | None -ObjectEncryptionFilterList = List[ObjectEncryptionFilter] -StorageClassList = List[S3StorageClass] +ObjectEncryptionFilterList = list[ObjectEncryptionFilter] +StorageClassList = list[S3StorageClass] ObjectSizeLessThanBytes = int ObjectSizeGreaterThanBytes = int -NonEmptyMaxLength1024StringList = List[NonEmptyMaxLength1024String] +NonEmptyMaxLength1024StringList = list[NonEmptyMaxLength1024String] class KeyNameConstraint(TypedDict, total=False): - MatchAnyPrefix: Optional[NonEmptyMaxLength1024StringList] - MatchAnySuffix: Optional[NonEmptyMaxLength1024StringList] - MatchAnySubstring: Optional[NonEmptyMaxLength1024StringList] + MatchAnyPrefix: NonEmptyMaxLength1024StringList | None + MatchAnySuffix: NonEmptyMaxLength1024StringList | None + MatchAnySubstring: NonEmptyMaxLength1024StringList | None -ReplicationStatusFilterList = List[ReplicationStatus] +ReplicationStatusFilterList = list[ReplicationStatus] ObjectCreationTime = datetime class JobManifestGeneratorFilter(TypedDict, total=False): - EligibleForReplication: Optional[Boolean] - CreatedAfter: Optional[ObjectCreationTime] - CreatedBefore: Optional[ObjectCreationTime] - ObjectReplicationStatuses: Optional[ReplicationStatusFilterList] - KeyNameConstraint: Optional[KeyNameConstraint] - ObjectSizeGreaterThanBytes: Optional[ObjectSizeGreaterThanBytes] - ObjectSizeLessThanBytes: Optional[ObjectSizeLessThanBytes] - MatchAnyStorageClass: Optional[StorageClassList] - MatchAnyObjectEncryption: Optional[ObjectEncryptionFilterList] + EligibleForReplication: Boolean | None + CreatedAfter: ObjectCreationTime | None + CreatedBefore: ObjectCreationTime | None + ObjectReplicationStatuses: ReplicationStatusFilterList | None + KeyNameConstraint: KeyNameConstraint | None + ObjectSizeGreaterThanBytes: ObjectSizeGreaterThanBytes | None + ObjectSizeLessThanBytes: ObjectSizeLessThanBytes | None + MatchAnyStorageClass: StorageClassList | None + MatchAnyObjectEncryption: ObjectEncryptionFilterList | None class SSEKMSEncryption(TypedDict, total=False): @@ -970,28 +977,28 @@ class SSES3Encryption(TypedDict, total=False): class GeneratedManifestEncryption(TypedDict, total=False): - SSES3: Optional[SSES3Encryption] - SSEKMS: Optional[SSEKMSEncryption] + SSES3: SSES3Encryption | None + SSEKMS: SSEKMSEncryption | None class S3ManifestOutputLocation(TypedDict, total=False): - ExpectedManifestBucketOwner: Optional[AccountId] + ExpectedManifestBucketOwner: AccountId | None Bucket: S3BucketArnString - ManifestPrefix: Optional[ManifestPrefixString] - ManifestEncryption: Optional[GeneratedManifestEncryption] + ManifestPrefix: ManifestPrefixString | None + ManifestEncryption: GeneratedManifestEncryption | None ManifestFormat: GeneratedManifestFormat class S3JobManifestGenerator(TypedDict, total=False): - ExpectedBucketOwner: Optional[AccountId] + ExpectedBucketOwner: AccountId | None SourceBucket: S3BucketArnString - ManifestOutputLocation: Optional[S3ManifestOutputLocation] - Filter: Optional[JobManifestGeneratorFilter] + ManifestOutputLocation: S3ManifestOutputLocation | None + Filter: JobManifestGeneratorFilter | None EnableManifestOutput: Boolean class JobManifestGenerator(TypedDict, total=False): - S3JobManifestGenerator: Optional[S3JobManifestGenerator] + S3JobManifestGenerator: S3JobManifestGenerator | None class S3Tag(TypedDict, total=False): @@ -999,21 +1006,21 @@ class S3Tag(TypedDict, total=False): Value: TagValueString -S3TagSet = List[S3Tag] +S3TagSet = list[S3Tag] class JobManifestLocation(TypedDict, total=False): ObjectArn: S3KeyArnString - ObjectVersionId: Optional[S3ObjectVersionId] + ObjectVersionId: S3ObjectVersionId | None ETag: NonEmptyMaxLength1024String -JobManifestFieldList = List[JobManifestFieldName] +JobManifestFieldList = list[JobManifestFieldName] class JobManifestSpec(TypedDict, total=False): Format: JobManifestFormat - Fields: Optional[JobManifestFieldList] + Fields: JobManifestFieldList | None class JobManifest(TypedDict, total=False): @@ -1022,17 +1029,30 @@ class JobManifest(TypedDict, total=False): class JobReport(TypedDict, total=False): - Bucket: Optional[S3BucketArnString] - Format: Optional[JobReportFormat] + Bucket: S3BucketArnString | None + Format: JobReportFormat | None Enabled: Boolean - Prefix: Optional[ReportPrefixString] - ReportScope: Optional[JobReportScope] - ExpectedBucketOwner: Optional[AccountId] + Prefix: ReportPrefixString | None + ReportScope: JobReportScope | None + ExpectedBucketOwner: AccountId | None + + +class S3UpdateObjectEncryptionSSEKMS(TypedDict, total=False): + KMSKeyArn: NonEmptyKmsKeyArnString + BucketKeyEnabled: Boolean | None + + +class ObjectEncryption(TypedDict, total=False): + SSEKMS: S3UpdateObjectEncryptionSSEKMS | None + + +class S3UpdateObjectEncryptionOperation(TypedDict, total=False): + ObjectEncryption: ObjectEncryption | None class S3ComputeObjectChecksumOperation(TypedDict, total=False): - ChecksumAlgorithm: Optional[ComputeObjectChecksumAlgorithm] - ChecksumType: Optional[ComputeObjectChecksumType] + ChecksumAlgorithm: ComputeObjectChecksumAlgorithm | None + ChecksumType: ComputeObjectChecksumType | None class S3ReplicateObjectOperation(TypedDict, total=False): @@ -1043,12 +1063,12 @@ class S3ReplicateObjectOperation(TypedDict, total=False): class S3Retention(TypedDict, total=False): - RetainUntilDate: Optional[TimeStamp] - Mode: Optional[S3ObjectLockRetentionMode] + RetainUntilDate: TimeStamp | None + Mode: S3ObjectLockRetentionMode | None class S3SetObjectRetentionOperation(TypedDict, total=False): - BypassGovernanceRetention: Optional[Boolean] + BypassGovernanceRetention: Boolean | None Retention: S3Retention @@ -1061,8 +1081,8 @@ class S3SetObjectLegalHoldOperation(TypedDict, total=False): class S3InitiateRestoreObjectOperation(TypedDict, total=False): - ExpirationInDays: Optional[S3ExpirationInDays] - GlacierJobTier: Optional[S3GlacierJobTier] + ExpirationInDays: S3ExpirationInDays | None + GlacierJobTier: S3GlacierJobTier | None class S3DeleteObjectTaggingOperation(TypedDict, total=False): @@ -1070,119 +1090,120 @@ class S3DeleteObjectTaggingOperation(TypedDict, total=False): class S3SetObjectTaggingOperation(TypedDict, total=False): - TagSet: Optional[S3TagSet] + TagSet: S3TagSet | None class S3Grantee(TypedDict, total=False): - TypeIdentifier: Optional[S3GranteeTypeIdentifier] - Identifier: Optional[NonEmptyMaxLength1024String] - DisplayName: Optional[NonEmptyMaxLength1024String] + TypeIdentifier: S3GranteeTypeIdentifier | None + Identifier: NonEmptyMaxLength1024String | None + DisplayName: NonEmptyMaxLength1024String | None class S3Grant(TypedDict, total=False): - Grantee: Optional[S3Grantee] - Permission: Optional[S3Permission] + Grantee: S3Grantee | None + Permission: S3Permission | None -S3GrantList = List[S3Grant] +S3GrantList = list[S3Grant] class S3ObjectOwner(TypedDict, total=False): - ID: Optional[NonEmptyMaxLength1024String] - DisplayName: Optional[NonEmptyMaxLength1024String] + ID: NonEmptyMaxLength1024String | None + DisplayName: NonEmptyMaxLength1024String | None class S3AccessControlList(TypedDict, total=False): Owner: S3ObjectOwner - Grants: Optional[S3GrantList] + Grants: S3GrantList | None class S3AccessControlPolicy(TypedDict, total=False): - AccessControlList: Optional[S3AccessControlList] - CannedAccessControlList: Optional[S3CannedAccessControlList] + AccessControlList: S3AccessControlList | None + CannedAccessControlList: S3CannedAccessControlList | None class S3SetObjectAclOperation(TypedDict, total=False): - AccessControlPolicy: Optional[S3AccessControlPolicy] + AccessControlPolicy: S3AccessControlPolicy | None S3ContentLength = int -S3UserMetadata = Dict[NonEmptyMaxLength1024String, MaxLength1024String] +S3UserMetadata = dict[NonEmptyMaxLength1024String, MaxLength1024String] class S3ObjectMetadata(TypedDict, total=False): - CacheControl: Optional[NonEmptyMaxLength1024String] - ContentDisposition: Optional[NonEmptyMaxLength1024String] - ContentEncoding: Optional[NonEmptyMaxLength1024String] - ContentLanguage: Optional[NonEmptyMaxLength1024String] - UserMetadata: Optional[S3UserMetadata] - ContentLength: Optional[S3ContentLength] - ContentMD5: Optional[NonEmptyMaxLength1024String] - ContentType: Optional[NonEmptyMaxLength1024String] - HttpExpiresDate: Optional[TimeStamp] - RequesterCharged: Optional[Boolean] - SSEAlgorithm: Optional[S3SSEAlgorithm] + CacheControl: NonEmptyMaxLength1024String | None + ContentDisposition: NonEmptyMaxLength1024String | None + ContentEncoding: NonEmptyMaxLength1024String | None + ContentLanguage: NonEmptyMaxLength1024String | None + UserMetadata: S3UserMetadata | None + ContentLength: S3ContentLength | None + ContentMD5: NonEmptyMaxLength1024String | None + ContentType: NonEmptyMaxLength1024String | None + HttpExpiresDate: TimeStamp | None + RequesterCharged: Boolean | None + SSEAlgorithm: S3SSEAlgorithm | None class S3CopyObjectOperation(TypedDict, total=False): - TargetResource: Optional[S3RegionalOrS3ExpressBucketArnString] - CannedAccessControlList: Optional[S3CannedAccessControlList] - AccessControlGrants: Optional[S3GrantList] - MetadataDirective: Optional[S3MetadataDirective] - ModifiedSinceConstraint: Optional[TimeStamp] - NewObjectMetadata: Optional[S3ObjectMetadata] - NewObjectTagging: Optional[S3TagSet] - RedirectLocation: Optional[NonEmptyMaxLength2048String] - RequesterPays: Optional[Boolean] - StorageClass: Optional[S3StorageClass] - UnModifiedSinceConstraint: Optional[TimeStamp] - SSEAwsKmsKeyId: Optional[KmsKeyArnString] - TargetKeyPrefix: Optional[NonEmptyMaxLength1024String] - ObjectLockLegalHoldStatus: Optional[S3ObjectLockLegalHoldStatus] - ObjectLockMode: Optional[S3ObjectLockMode] - ObjectLockRetainUntilDate: Optional[TimeStamp] - BucketKeyEnabled: Optional[Boolean] - ChecksumAlgorithm: Optional[S3ChecksumAlgorithm] - - -UserArguments = Dict[NonEmptyMaxLength64String, MaxLength1024String] + TargetResource: S3RegionalOrS3ExpressBucketArnString | None + CannedAccessControlList: S3CannedAccessControlList | None + AccessControlGrants: S3GrantList | None + MetadataDirective: S3MetadataDirective | None + ModifiedSinceConstraint: TimeStamp | None + NewObjectMetadata: S3ObjectMetadata | None + NewObjectTagging: S3TagSet | None + RedirectLocation: NonEmptyMaxLength2048String | None + RequesterPays: Boolean | None + StorageClass: S3StorageClass | None + UnModifiedSinceConstraint: TimeStamp | None + SSEAwsKmsKeyId: KmsKeyArnString | None + TargetKeyPrefix: NonEmptyMaxLength1024String | None + ObjectLockLegalHoldStatus: S3ObjectLockLegalHoldStatus | None + ObjectLockMode: S3ObjectLockMode | None + ObjectLockRetainUntilDate: TimeStamp | None + BucketKeyEnabled: Boolean | None + ChecksumAlgorithm: S3ChecksumAlgorithm | None + + +UserArguments = dict[NonEmptyMaxLength64String, MaxLength1024String] class LambdaInvokeOperation(TypedDict, total=False): - FunctionArn: Optional[FunctionArnString] - InvocationSchemaVersion: Optional[NonEmptyMaxLength64String] - UserArguments: Optional[UserArguments] + FunctionArn: FunctionArnString | None + InvocationSchemaVersion: NonEmptyMaxLength64String | None + UserArguments: UserArguments | None class JobOperation(TypedDict, total=False): - LambdaInvoke: Optional[LambdaInvokeOperation] - S3PutObjectCopy: Optional[S3CopyObjectOperation] - S3PutObjectAcl: Optional[S3SetObjectAclOperation] - S3PutObjectTagging: Optional[S3SetObjectTaggingOperation] - S3DeleteObjectTagging: Optional[S3DeleteObjectTaggingOperation] - S3InitiateRestoreObject: Optional[S3InitiateRestoreObjectOperation] - S3PutObjectLegalHold: Optional[S3SetObjectLegalHoldOperation] - S3PutObjectRetention: Optional[S3SetObjectRetentionOperation] - S3ReplicateObject: Optional[S3ReplicateObjectOperation] - S3ComputeObjectChecksum: Optional[S3ComputeObjectChecksumOperation] + LambdaInvoke: LambdaInvokeOperation | None + S3PutObjectCopy: S3CopyObjectOperation | None + S3PutObjectAcl: S3SetObjectAclOperation | None + S3PutObjectTagging: S3SetObjectTaggingOperation | None + S3DeleteObjectTagging: S3DeleteObjectTaggingOperation | None + S3InitiateRestoreObject: S3InitiateRestoreObjectOperation | None + S3PutObjectLegalHold: S3SetObjectLegalHoldOperation | None + S3PutObjectRetention: S3SetObjectRetentionOperation | None + S3ReplicateObject: S3ReplicateObjectOperation | None + S3ComputeObjectChecksum: S3ComputeObjectChecksumOperation | None + S3UpdateObjectEncryption: S3UpdateObjectEncryptionOperation | None class CreateJobRequest(ServiceRequest): AccountId: AccountId - ConfirmationRequired: Optional[ConfirmationRequired] + ConfirmationRequired: ConfirmationRequired | None Operation: JobOperation Report: JobReport ClientRequestToken: NonEmptyMaxLength64String - Manifest: Optional[JobManifest] - Description: Optional[NonEmptyMaxLength256String] + Manifest: JobManifest | None + Description: NonEmptyMaxLength256String | None Priority: JobPriority RoleArn: IAMRoleArn - Tags: Optional[S3TagSet] - ManifestGenerator: Optional[JobManifestGenerator] + Tags: S3TagSet | None + ManifestGenerator: JobManifestGenerator | None class CreateJobResult(TypedDict, total=False): - JobId: Optional[JobId] + JobId: JobId | None class CreateMultiRegionAccessPointRequest(ServiceRequest): @@ -1192,63 +1213,63 @@ class CreateMultiRegionAccessPointRequest(ServiceRequest): class CreateMultiRegionAccessPointResult(TypedDict, total=False): - RequestTokenARN: Optional[AsyncRequestTokenARN] + RequestTokenARN: AsyncRequestTokenARN | None ObjectSizeValue = int class MatchObjectSize(TypedDict, total=False): - BytesGreaterThan: Optional[ObjectSizeValue] - BytesLessThan: Optional[ObjectSizeValue] + BytesGreaterThan: ObjectSizeValue | None + BytesLessThan: ObjectSizeValue | None class MatchObjectAge(TypedDict, total=False): - DaysGreaterThan: Optional[ObjectAgeValue] - DaysLessThan: Optional[ObjectAgeValue] + DaysGreaterThan: ObjectAgeValue | None + DaysLessThan: ObjectAgeValue | None -MatchAnyTag = List[S3Tag] -MatchAnySuffix = List[Suffix] -MatchAnyPrefix = List[Prefix] +MatchAnyTag = list[S3Tag] +MatchAnySuffix = list[Suffix] +MatchAnyPrefix = list[Prefix] class StorageLensGroupOrOperator(TypedDict, total=False): - MatchAnyPrefix: Optional[MatchAnyPrefix] - MatchAnySuffix: Optional[MatchAnySuffix] - MatchAnyTag: Optional[MatchAnyTag] - MatchObjectAge: Optional[MatchObjectAge] - MatchObjectSize: Optional[MatchObjectSize] + MatchAnyPrefix: MatchAnyPrefix | None + MatchAnySuffix: MatchAnySuffix | None + MatchAnyTag: MatchAnyTag | None + MatchObjectAge: MatchObjectAge | None + MatchObjectSize: MatchObjectSize | None class StorageLensGroupAndOperator(TypedDict, total=False): - MatchAnyPrefix: Optional[MatchAnyPrefix] - MatchAnySuffix: Optional[MatchAnySuffix] - MatchAnyTag: Optional[MatchAnyTag] - MatchObjectAge: Optional[MatchObjectAge] - MatchObjectSize: Optional[MatchObjectSize] + MatchAnyPrefix: MatchAnyPrefix | None + MatchAnySuffix: MatchAnySuffix | None + MatchAnyTag: MatchAnyTag | None + MatchObjectAge: MatchObjectAge | None + MatchObjectSize: MatchObjectSize | None class StorageLensGroupFilter(TypedDict, total=False): - MatchAnyPrefix: Optional[MatchAnyPrefix] - MatchAnySuffix: Optional[MatchAnySuffix] - MatchAnyTag: Optional[MatchAnyTag] - MatchObjectAge: Optional[MatchObjectAge] - MatchObjectSize: Optional[MatchObjectSize] - And: Optional[StorageLensGroupAndOperator] - Or: Optional[StorageLensGroupOrOperator] + MatchAnyPrefix: MatchAnyPrefix | None + MatchAnySuffix: MatchAnySuffix | None + MatchAnyTag: MatchAnyTag | None + MatchObjectAge: MatchObjectAge | None + MatchObjectSize: MatchObjectSize | None + And: StorageLensGroupAndOperator | None + Or: StorageLensGroupOrOperator | None class StorageLensGroup(TypedDict, total=False): Name: StorageLensGroupName Filter: StorageLensGroupFilter - StorageLensGroupArn: Optional[StorageLensGroupArn] + StorageLensGroupArn: StorageLensGroupArn | None class CreateStorageLensGroupRequest(ServiceRequest): AccountId: AccountId StorageLensGroup: StorageLensGroup - Tags: Optional[TagList] + Tags: TagList | None CreationDate = datetime @@ -1256,10 +1277,10 @@ class CreateStorageLensGroupRequest(ServiceRequest): class Credentials(TypedDict, total=False): - AccessKeyId: Optional[AccessKeyId] - SecretAccessKey: Optional[SecretAccessKey] - SessionToken: Optional[SessionToken] - Expiration: Optional[Expiration] + AccessKeyId: AccessKeyId | None + SecretAccessKey: SecretAccessKey | None + SessionToken: SessionToken | None + Expiration: Expiration | None Date = datetime @@ -1353,7 +1374,7 @@ class DeleteMultiRegionAccessPointRequest(ServiceRequest): class DeleteMultiRegionAccessPointResult(TypedDict, total=False): - RequestTokenARN: Optional[AsyncRequestTokenARN] + RequestTokenARN: AsyncRequestTokenARN | None class DeletePublicAccessBlockRequest(ServiceRequest): @@ -1385,8 +1406,8 @@ class DescribeJobRequest(ServiceRequest): class S3GeneratedManifestDescriptor(TypedDict, total=False): - Format: Optional[GeneratedManifestFormat] - Location: Optional[JobManifestLocation] + Format: GeneratedManifestFormat | None + Location: JobManifestLocation | None SuspendedDate = datetime @@ -1395,16 +1416,16 @@ class S3GeneratedManifestDescriptor(TypedDict, total=False): class JobFailure(TypedDict, total=False): - FailureCode: Optional[JobFailureCode] - FailureReason: Optional[JobFailureReason] + FailureCode: JobFailureCode | None + FailureReason: JobFailureReason | None -JobFailureList = List[JobFailure] +JobFailureList = list[JobFailure] JobTimeInStateSeconds = int class JobTimers(TypedDict, total=False): - ElapsedTimeInActiveSeconds: Optional[JobTimeInStateSeconds] + ElapsedTimeInActiveSeconds: JobTimeInStateSeconds | None JobNumberOfTasksFailed = int @@ -1413,36 +1434,36 @@ class JobTimers(TypedDict, total=False): class JobProgressSummary(TypedDict, total=False): - TotalNumberOfTasks: Optional[JobTotalNumberOfTasks] - NumberOfTasksSucceeded: Optional[JobNumberOfTasksSucceeded] - NumberOfTasksFailed: Optional[JobNumberOfTasksFailed] - Timers: Optional[JobTimers] + TotalNumberOfTasks: JobTotalNumberOfTasks | None + NumberOfTasksSucceeded: JobNumberOfTasksSucceeded | None + NumberOfTasksFailed: JobNumberOfTasksFailed | None + Timers: JobTimers | None class JobDescriptor(TypedDict, total=False): - JobId: Optional[JobId] - ConfirmationRequired: Optional[ConfirmationRequired] - Description: Optional[NonEmptyMaxLength256String] - JobArn: Optional[JobArn] - Status: Optional[JobStatus] - Manifest: Optional[JobManifest] - Operation: Optional[JobOperation] - Priority: Optional[JobPriority] - ProgressSummary: Optional[JobProgressSummary] - StatusUpdateReason: Optional[JobStatusUpdateReason] - FailureReasons: Optional[JobFailureList] - Report: Optional[JobReport] - CreationTime: Optional[JobCreationTime] - TerminationDate: Optional[JobTerminationDate] - RoleArn: Optional[IAMRoleArn] - SuspendedDate: Optional[SuspendedDate] - SuspendedCause: Optional[SuspendedCause] - ManifestGenerator: Optional[JobManifestGenerator] - GeneratedManifestDescriptor: Optional[S3GeneratedManifestDescriptor] + JobId: JobId | None + ConfirmationRequired: ConfirmationRequired | None + Description: NonEmptyMaxLength256String | None + JobArn: JobArn | None + Status: JobStatus | None + Manifest: JobManifest | None + Operation: JobOperation | None + Priority: JobPriority | None + ProgressSummary: JobProgressSummary | None + StatusUpdateReason: JobStatusUpdateReason | None + FailureReasons: JobFailureList | None + Report: JobReport | None + CreationTime: JobCreationTime | None + TerminationDate: JobTerminationDate | None + RoleArn: IAMRoleArn | None + SuspendedDate: SuspendedDate | None + SuspendedCause: SuspendedCause | None + ManifestGenerator: JobManifestGenerator | None + GeneratedManifestDescriptor: S3GeneratedManifestDescriptor | None class DescribeJobResult(TypedDict, total=False): - Job: Optional[JobDescriptor] + Job: JobDescriptor | None class DescribeMultiRegionAccessPointOperationRequest(ServiceRequest): @@ -1451,20 +1472,20 @@ class DescribeMultiRegionAccessPointOperationRequest(ServiceRequest): class DescribeMultiRegionAccessPointOperationResult(TypedDict, total=False): - AsyncOperation: Optional[AsyncOperation] + AsyncOperation: AsyncOperation | None class ReplicationTimeValue(TypedDict, total=False): - Minutes: Optional[Minutes] + Minutes: Minutes | None class Metrics(TypedDict, total=False): Status: MetricsStatus - EventThreshold: Optional[ReplicationTimeValue] + EventThreshold: ReplicationTimeValue | None class EncryptionConfiguration(TypedDict, total=False): - ReplicaKmsKeyID: Optional[ReplicaKmsKeyID] + ReplicaKmsKeyID: ReplicaKmsKeyID | None class ReplicationTime(TypedDict, total=False): @@ -1473,32 +1494,32 @@ class ReplicationTime(TypedDict, total=False): class Destination(TypedDict, total=False): - Account: Optional[AccountId] + Account: AccountId | None Bucket: BucketIdentifierString - ReplicationTime: Optional[ReplicationTime] - AccessControlTranslation: Optional[AccessControlTranslation] - EncryptionConfiguration: Optional[EncryptionConfiguration] - Metrics: Optional[Metrics] - StorageClass: Optional[ReplicationStorageClass] + ReplicationTime: ReplicationTime | None + AccessControlTranslation: AccessControlTranslation | None + EncryptionConfiguration: EncryptionConfiguration | None + Metrics: Metrics | None + StorageClass: ReplicationStorageClass | None class DissociateAccessGrantsIdentityCenterRequest(ServiceRequest): AccountId: AccountId -Endpoints = Dict[NonEmptyMaxLength64String, NonEmptyMaxLength1024String] +Endpoints = dict[NonEmptyMaxLength64String, NonEmptyMaxLength1024String] class EstablishedMultiRegionAccessPointPolicy(TypedDict, total=False): - Policy: Optional[Policy] + Policy: Policy | None -Regions = List[S3AWSRegion] +Regions = list[S3AWSRegion] class Exclude(TypedDict, total=False): - Buckets: Optional[Buckets] - Regions: Optional[Regions] + Buckets: Buckets | None + Regions: Regions | None class ExistingObjectReplication(TypedDict, total=False): @@ -1511,15 +1532,15 @@ class GetAccessGrantRequest(ServiceRequest): class GetAccessGrantResult(TypedDict, total=False): - CreatedAt: Optional[CreationTimestamp] - AccessGrantId: Optional[AccessGrantId] - AccessGrantArn: Optional[AccessGrantArn] - Grantee: Optional[Grantee] - Permission: Optional[Permission] - AccessGrantsLocationId: Optional[AccessGrantsLocationId] - AccessGrantsLocationConfiguration: Optional[AccessGrantsLocationConfiguration] - GrantScope: Optional[S3Prefix] - ApplicationArn: Optional[IdentityCenterApplicationArn] + CreatedAt: CreationTimestamp | None + AccessGrantId: AccessGrantId | None + AccessGrantArn: AccessGrantArn | None + Grantee: Grantee | None + Permission: Permission | None + AccessGrantsLocationId: AccessGrantsLocationId | None + AccessGrantsLocationConfiguration: AccessGrantsLocationConfiguration | None + GrantScope: S3Prefix | None + ApplicationArn: IdentityCenterApplicationArn | None class GetAccessGrantsInstanceForPrefixRequest(ServiceRequest): @@ -1528,8 +1549,8 @@ class GetAccessGrantsInstanceForPrefixRequest(ServiceRequest): class GetAccessGrantsInstanceForPrefixResult(TypedDict, total=False): - AccessGrantsInstanceArn: Optional[AccessGrantsInstanceArn] - AccessGrantsInstanceId: Optional[AccessGrantsInstanceId] + AccessGrantsInstanceArn: AccessGrantsInstanceArn | None + AccessGrantsInstanceId: AccessGrantsInstanceId | None class GetAccessGrantsInstanceRequest(ServiceRequest): @@ -1541,18 +1562,18 @@ class GetAccessGrantsInstanceResourcePolicyRequest(ServiceRequest): class GetAccessGrantsInstanceResourcePolicyResult(TypedDict, total=False): - Policy: Optional[PolicyDocument] - Organization: Optional[Organization] - CreatedAt: Optional[CreationTimestamp] + Policy: PolicyDocument | None + Organization: Organization | None + CreatedAt: CreationTimestamp | None class GetAccessGrantsInstanceResult(TypedDict, total=False): - AccessGrantsInstanceArn: Optional[AccessGrantsInstanceArn] - AccessGrantsInstanceId: Optional[AccessGrantsInstanceId] - IdentityCenterArn: Optional[IdentityCenterArn] - IdentityCenterInstanceArn: Optional[IdentityCenterArn] - IdentityCenterApplicationArn: Optional[IdentityCenterApplicationArn] - CreatedAt: Optional[CreationTimestamp] + AccessGrantsInstanceArn: AccessGrantsInstanceArn | None + AccessGrantsInstanceId: AccessGrantsInstanceId | None + IdentityCenterArn: IdentityCenterArn | None + IdentityCenterInstanceArn: IdentityCenterArn | None + IdentityCenterApplicationArn: IdentityCenterApplicationArn | None + CreatedAt: CreationTimestamp | None class GetAccessGrantsLocationRequest(ServiceRequest): @@ -1561,11 +1582,11 @@ class GetAccessGrantsLocationRequest(ServiceRequest): class GetAccessGrantsLocationResult(TypedDict, total=False): - CreatedAt: Optional[CreationTimestamp] - AccessGrantsLocationId: Optional[AccessGrantsLocationId] - AccessGrantsLocationArn: Optional[AccessGrantsLocationArn] - LocationScope: Optional[S3Prefix] - IAMRoleArn: Optional[IAMRoleArn] + CreatedAt: CreationTimestamp | None + AccessGrantsLocationId: AccessGrantsLocationId | None + AccessGrantsLocationArn: AccessGrantsLocationArn | None + LocationScope: S3Prefix | None + IAMRoleArn: IAMRoleArn | None class GetAccessPointConfigurationForObjectLambdaRequest(ServiceRequest): @@ -1574,7 +1595,7 @@ class GetAccessPointConfigurationForObjectLambdaRequest(ServiceRequest): class GetAccessPointConfigurationForObjectLambdaResult(TypedDict, total=False): - Configuration: Optional[ObjectLambdaConfiguration] + Configuration: ObjectLambdaConfiguration | None class GetAccessPointForObjectLambdaRequest(ServiceRequest): @@ -1583,10 +1604,10 @@ class GetAccessPointForObjectLambdaRequest(ServiceRequest): class GetAccessPointForObjectLambdaResult(TypedDict, total=False): - Name: Optional[ObjectLambdaAccessPointName] - PublicAccessBlockConfiguration: Optional[PublicAccessBlockConfiguration] - CreationDate: Optional[CreationDate] - Alias: Optional[ObjectLambdaAccessPointAlias] + Name: ObjectLambdaAccessPointName | None + PublicAccessBlockConfiguration: PublicAccessBlockConfiguration | None + CreationDate: CreationDate | None + Alias: ObjectLambdaAccessPointAlias | None class GetAccessPointPolicyForObjectLambdaRequest(ServiceRequest): @@ -1595,7 +1616,7 @@ class GetAccessPointPolicyForObjectLambdaRequest(ServiceRequest): class GetAccessPointPolicyForObjectLambdaResult(TypedDict, total=False): - Policy: Optional[ObjectLambdaPolicy] + Policy: ObjectLambdaPolicy | None class GetAccessPointPolicyRequest(ServiceRequest): @@ -1604,7 +1625,7 @@ class GetAccessPointPolicyRequest(ServiceRequest): class GetAccessPointPolicyResult(TypedDict, total=False): - Policy: Optional[Policy] + Policy: Policy | None class GetAccessPointPolicyStatusForObjectLambdaRequest(ServiceRequest): @@ -1613,11 +1634,11 @@ class GetAccessPointPolicyStatusForObjectLambdaRequest(ServiceRequest): class PolicyStatus(TypedDict, total=False): - IsPublic: Optional[IsPublic] + IsPublic: IsPublic | None class GetAccessPointPolicyStatusForObjectLambdaResult(TypedDict, total=False): - PolicyStatus: Optional[PolicyStatus] + PolicyStatus: PolicyStatus | None class GetAccessPointPolicyStatusRequest(ServiceRequest): @@ -1626,7 +1647,7 @@ class GetAccessPointPolicyStatusRequest(ServiceRequest): class GetAccessPointPolicyStatusResult(TypedDict, total=False): - PolicyStatus: Optional[PolicyStatus] + PolicyStatus: PolicyStatus | None class GetAccessPointRequest(ServiceRequest): @@ -1635,18 +1656,18 @@ class GetAccessPointRequest(ServiceRequest): class GetAccessPointResult(TypedDict, total=False): - Name: Optional[AccessPointName] - Bucket: Optional[AccessPointBucketName] - NetworkOrigin: Optional[NetworkOrigin] - VpcConfiguration: Optional[VpcConfiguration] - PublicAccessBlockConfiguration: Optional[PublicAccessBlockConfiguration] - CreationDate: Optional[CreationDate] - Alias: Optional[Alias] - AccessPointArn: Optional[S3AccessPointArn] - Endpoints: Optional[Endpoints] - BucketAccountId: Optional[AccountId] - DataSourceId: Optional[DataSourceId] - DataSourceType: Optional[DataSourceType] + Name: AccessPointName | None + Bucket: AccessPointBucketName | None + NetworkOrigin: NetworkOrigin | None + VpcConfiguration: VpcConfiguration | None + PublicAccessBlockConfiguration: PublicAccessBlockConfiguration | None + CreationDate: CreationDate | None + Alias: Alias | None + AccessPointArn: S3AccessPointArn | None + Endpoints: Endpoints | None + BucketAccountId: AccountId | None + DataSourceId: DataSourceId | None + DataSourceType: DataSourceType | None class GetAccessPointScopeRequest(ServiceRequest): @@ -1655,7 +1676,7 @@ class GetAccessPointScopeRequest(ServiceRequest): class GetAccessPointScopeResult(TypedDict, total=False): - Scope: Optional[Scope] + Scope: Scope | None class GetBucketLifecycleConfigurationRequest(ServiceRequest): @@ -1664,64 +1685,64 @@ class GetBucketLifecycleConfigurationRequest(ServiceRequest): class NoncurrentVersionExpiration(TypedDict, total=False): - NoncurrentDays: Optional[Days] - NewerNoncurrentVersions: Optional[NoncurrentVersionCount] + NoncurrentDays: Days | None + NewerNoncurrentVersions: NoncurrentVersionCount | None class NoncurrentVersionTransition(TypedDict, total=False): - NoncurrentDays: Optional[Days] - StorageClass: Optional[TransitionStorageClass] + NoncurrentDays: Days | None + StorageClass: TransitionStorageClass | None -NoncurrentVersionTransitionList = List[NoncurrentVersionTransition] +NoncurrentVersionTransitionList = list[NoncurrentVersionTransition] class Transition(TypedDict, total=False): - Date: Optional[Date] - Days: Optional[Days] - StorageClass: Optional[TransitionStorageClass] + Date: Date | None + Days: Days | None + StorageClass: TransitionStorageClass | None -TransitionList = List[Transition] +TransitionList = list[Transition] class LifecycleRuleAndOperator(TypedDict, total=False): - Prefix: Optional[Prefix] - Tags: Optional[S3TagSet] - ObjectSizeGreaterThan: Optional[ObjectSizeGreaterThanBytes] - ObjectSizeLessThan: Optional[ObjectSizeLessThanBytes] + Prefix: Prefix | None + Tags: S3TagSet | None + ObjectSizeGreaterThan: ObjectSizeGreaterThanBytes | None + ObjectSizeLessThan: ObjectSizeLessThanBytes | None class LifecycleRuleFilter(TypedDict, total=False): - Prefix: Optional[Prefix] - Tag: Optional[S3Tag] - And: Optional[LifecycleRuleAndOperator] - ObjectSizeGreaterThan: Optional[ObjectSizeGreaterThanBytes] - ObjectSizeLessThan: Optional[ObjectSizeLessThanBytes] + Prefix: Prefix | None + Tag: S3Tag | None + And: LifecycleRuleAndOperator | None + ObjectSizeGreaterThan: ObjectSizeGreaterThanBytes | None + ObjectSizeLessThan: ObjectSizeLessThanBytes | None class LifecycleExpiration(TypedDict, total=False): - Date: Optional[Date] - Days: Optional[Days] - ExpiredObjectDeleteMarker: Optional[ExpiredObjectDeleteMarker] + Date: Date | None + Days: Days | None + ExpiredObjectDeleteMarker: ExpiredObjectDeleteMarker | None class LifecycleRule(TypedDict, total=False): - Expiration: Optional[LifecycleExpiration] - ID: Optional[ID] - Filter: Optional[LifecycleRuleFilter] + Expiration: LifecycleExpiration | None + ID: ID | None + Filter: LifecycleRuleFilter | None Status: ExpirationStatus - Transitions: Optional[TransitionList] - NoncurrentVersionTransitions: Optional[NoncurrentVersionTransitionList] - NoncurrentVersionExpiration: Optional[NoncurrentVersionExpiration] - AbortIncompleteMultipartUpload: Optional[AbortIncompleteMultipartUpload] + Transitions: TransitionList | None + NoncurrentVersionTransitions: NoncurrentVersionTransitionList | None + NoncurrentVersionExpiration: NoncurrentVersionExpiration | None + AbortIncompleteMultipartUpload: AbortIncompleteMultipartUpload | None -LifecycleRules = List[LifecycleRule] +LifecycleRules = list[LifecycleRule] class GetBucketLifecycleConfigurationResult(TypedDict, total=False): - Rules: Optional[LifecycleRules] + Rules: LifecycleRules | None class GetBucketPolicyRequest(ServiceRequest): @@ -1730,7 +1751,7 @@ class GetBucketPolicyRequest(ServiceRequest): class GetBucketPolicyResult(TypedDict, total=False): - Policy: Optional[Policy] + Policy: Policy | None class GetBucketReplicationRequest(ServiceRequest): @@ -1747,35 +1768,35 @@ class SseKmsEncryptedObjects(TypedDict, total=False): class SourceSelectionCriteria(TypedDict, total=False): - SseKmsEncryptedObjects: Optional[SseKmsEncryptedObjects] - ReplicaModifications: Optional[ReplicaModifications] + SseKmsEncryptedObjects: SseKmsEncryptedObjects | None + ReplicaModifications: ReplicaModifications | None class ReplicationRuleAndOperator(TypedDict, total=False): - Prefix: Optional[Prefix] - Tags: Optional[S3TagSet] + Prefix: Prefix | None + Tags: S3TagSet | None class ReplicationRuleFilter(TypedDict, total=False): - Prefix: Optional[Prefix] - Tag: Optional[S3Tag] - And: Optional[ReplicationRuleAndOperator] + Prefix: Prefix | None + Tag: S3Tag | None + And: ReplicationRuleAndOperator | None class ReplicationRule(TypedDict, total=False): - ID: Optional[ID] - Priority: Optional[Priority] - Prefix: Optional[Prefix] - Filter: Optional[ReplicationRuleFilter] + ID: ID | None + Priority: Priority | None + Prefix: Prefix | None + Filter: ReplicationRuleFilter | None Status: ReplicationRuleStatus - SourceSelectionCriteria: Optional[SourceSelectionCriteria] - ExistingObjectReplication: Optional[ExistingObjectReplication] + SourceSelectionCriteria: SourceSelectionCriteria | None + ExistingObjectReplication: ExistingObjectReplication | None Destination: Destination - DeleteMarkerReplication: Optional[DeleteMarkerReplication] + DeleteMarkerReplication: DeleteMarkerReplication | None Bucket: BucketIdentifierString -ReplicationRules = List[ReplicationRule] +ReplicationRules = list[ReplicationRule] class ReplicationConfiguration(TypedDict, total=False): @@ -1784,7 +1805,7 @@ class ReplicationConfiguration(TypedDict, total=False): class GetBucketReplicationResult(TypedDict, total=False): - ReplicationConfiguration: Optional[ReplicationConfiguration] + ReplicationConfiguration: ReplicationConfiguration | None class GetBucketRequest(ServiceRequest): @@ -1793,9 +1814,9 @@ class GetBucketRequest(ServiceRequest): class GetBucketResult(TypedDict, total=False): - Bucket: Optional[BucketName] - PublicAccessBlockEnabled: Optional[PublicAccessBlockEnabled] - CreationDate: Optional[CreationDate] + Bucket: BucketName | None + PublicAccessBlockEnabled: PublicAccessBlockEnabled | None + CreationDate: CreationDate | None class GetBucketTaggingRequest(ServiceRequest): @@ -1813,23 +1834,23 @@ class GetBucketVersioningRequest(ServiceRequest): class GetBucketVersioningResult(TypedDict, total=False): - Status: Optional[BucketVersioningStatus] - MFADelete: Optional[MFADeleteStatus] + Status: BucketVersioningStatus | None + MFADelete: MFADeleteStatus | None class GetDataAccessRequest(ServiceRequest): AccountId: AccountId Target: S3Prefix Permission: Permission - DurationSeconds: Optional[DurationSeconds] - Privilege: Optional[Privilege] - TargetType: Optional[S3PrefixType] + DurationSeconds: DurationSeconds | None + Privilege: Privilege | None + TargetType: S3PrefixType | None class GetDataAccessResult(TypedDict, total=False): - Credentials: Optional[Credentials] - MatchedGrantTarget: Optional[S3Prefix] - Grantee: Optional[Grantee] + Credentials: Credentials | None + MatchedGrantTarget: S3Prefix | None + Grantee: Grantee | None class GetJobTaggingRequest(ServiceRequest): @@ -1838,7 +1859,7 @@ class GetJobTaggingRequest(ServiceRequest): class GetJobTaggingResult(TypedDict, total=False): - Tags: Optional[S3TagSet] + Tags: S3TagSet | None class GetMultiRegionAccessPointPolicyRequest(ServiceRequest): @@ -1847,16 +1868,16 @@ class GetMultiRegionAccessPointPolicyRequest(ServiceRequest): class ProposedMultiRegionAccessPointPolicy(TypedDict, total=False): - Policy: Optional[Policy] + Policy: Policy | None class MultiRegionAccessPointPolicyDocument(TypedDict, total=False): - Established: Optional[EstablishedMultiRegionAccessPointPolicy] - Proposed: Optional[ProposedMultiRegionAccessPointPolicy] + Established: EstablishedMultiRegionAccessPointPolicy | None + Proposed: ProposedMultiRegionAccessPointPolicy | None class GetMultiRegionAccessPointPolicyResult(TypedDict, total=False): - Policy: Optional[MultiRegionAccessPointPolicyDocument] + Policy: MultiRegionAccessPointPolicyDocument | None class GetMultiRegionAccessPointPolicyStatusRequest(ServiceRequest): @@ -1865,7 +1886,7 @@ class GetMultiRegionAccessPointPolicyStatusRequest(ServiceRequest): class GetMultiRegionAccessPointPolicyStatusResult(TypedDict, total=False): - Established: Optional[PolicyStatus] + Established: PolicyStatus | None class GetMultiRegionAccessPointRequest(ServiceRequest): @@ -1874,25 +1895,25 @@ class GetMultiRegionAccessPointRequest(ServiceRequest): class RegionReport(TypedDict, total=False): - Bucket: Optional[BucketName] - Region: Optional[RegionName] - BucketAccountId: Optional[AccountId] + Bucket: BucketName | None + Region: RegionName | None + BucketAccountId: AccountId | None -RegionReportList = List[RegionReport] +RegionReportList = list[RegionReport] class MultiRegionAccessPointReport(TypedDict, total=False): - Name: Optional[MultiRegionAccessPointName] - Alias: Optional[MultiRegionAccessPointAlias] - CreatedAt: Optional[CreationTimestamp] - PublicAccessBlock: Optional[PublicAccessBlockConfiguration] - Status: Optional[MultiRegionAccessPointStatus] - Regions: Optional[RegionReportList] + Name: MultiRegionAccessPointName | None + Alias: MultiRegionAccessPointAlias | None + CreatedAt: CreationTimestamp | None + PublicAccessBlock: PublicAccessBlockConfiguration | None + Status: MultiRegionAccessPointStatus | None + Regions: RegionReportList | None class GetMultiRegionAccessPointResult(TypedDict, total=False): - AccessPoint: Optional[MultiRegionAccessPointReport] + AccessPoint: MultiRegionAccessPointReport | None class GetMultiRegionAccessPointRoutesRequest(ServiceRequest): @@ -1901,21 +1922,21 @@ class GetMultiRegionAccessPointRoutesRequest(ServiceRequest): class MultiRegionAccessPointRoute(TypedDict, total=False): - Bucket: Optional[BucketName] - Region: Optional[RegionName] + Bucket: BucketName | None + Region: RegionName | None TrafficDialPercentage: TrafficDialPercentage -RouteList = List[MultiRegionAccessPointRoute] +RouteList = list[MultiRegionAccessPointRoute] class GetMultiRegionAccessPointRoutesResult(TypedDict, total=False): - Mrap: Optional[MultiRegionAccessPointId] - Routes: Optional[RouteList] + Mrap: MultiRegionAccessPointId | None + Routes: RouteList | None class GetPublicAccessBlockOutput(TypedDict, total=False): - PublicAccessBlockConfiguration: Optional[PublicAccessBlockConfiguration] + PublicAccessBlockConfiguration: PublicAccessBlockConfiguration | None class GetPublicAccessBlockRequest(ServiceRequest): @@ -1940,8 +1961,13 @@ class SSES3(TypedDict, total=False): class StorageLensDataExportEncryption(TypedDict, total=False): - SSES3: Optional[SSES3] - SSEKMS: Optional[SSEKMS] + SSES3: SSES3 | None + SSEKMS: SSEKMS | None + + +class StorageLensTableDestination(TypedDict, total=False): + IsEnabled: IsEnabled + Encryption: StorageLensDataExportEncryption | None class S3BucketDestination(TypedDict, total=False): @@ -1949,33 +1975,41 @@ class S3BucketDestination(TypedDict, total=False): OutputSchemaVersion: OutputSchemaVersion AccountId: AccountId Arn: S3BucketArnString - Prefix: Optional[Prefix] - Encryption: Optional[StorageLensDataExportEncryption] + Prefix: Prefix | None + Encryption: StorageLensDataExportEncryption | None + + +class StorageLensExpandedPrefixesDataExport(TypedDict, total=False): + S3BucketDestination: S3BucketDestination | None + StorageLensTableDestination: StorageLensTableDestination | None class StorageLensDataExport(TypedDict, total=False): - S3BucketDestination: Optional[S3BucketDestination] - CloudWatchMetrics: Optional[CloudWatchMetrics] + S3BucketDestination: S3BucketDestination | None + CloudWatchMetrics: CloudWatchMetrics | None + StorageLensTableDestination: StorageLensTableDestination | None class Include(TypedDict, total=False): - Buckets: Optional[Buckets] - Regions: Optional[Regions] + Buckets: Buckets | None + Regions: Regions | None class StorageLensConfiguration(TypedDict, total=False): Id: ConfigId AccountLevel: AccountLevel - Include: Optional[Include] - Exclude: Optional[Exclude] - DataExport: Optional[StorageLensDataExport] + Include: Include | None + Exclude: Exclude | None + DataExport: StorageLensDataExport | None + ExpandedPrefixesDataExport: StorageLensExpandedPrefixesDataExport | None IsEnabled: IsEnabled - AwsOrg: Optional[StorageLensAwsOrg] - StorageLensArn: Optional[StorageLensArn] + AwsOrg: StorageLensAwsOrg | None + StorageLensArn: StorageLensArn | None + PrefixDelimiter: StorageLensPrefixLevelDelimiter | None class GetStorageLensConfigurationResult(TypedDict, total=False): - StorageLensConfiguration: Optional[StorageLensConfiguration] + StorageLensConfiguration: StorageLensConfiguration | None class GetStorageLensConfigurationTaggingRequest(ServiceRequest): @@ -1988,11 +2022,11 @@ class StorageLensTag(TypedDict, total=False): Value: TagValueString -StorageLensTags = List[StorageLensTag] +StorageLensTags = list[StorageLensTag] class GetStorageLensConfigurationTaggingResult(TypedDict, total=False): - Tags: Optional[StorageLensTags] + Tags: StorageLensTags | None class GetStorageLensGroupRequest(ServiceRequest): @@ -2001,193 +2035,193 @@ class GetStorageLensGroupRequest(ServiceRequest): class GetStorageLensGroupResult(TypedDict, total=False): - StorageLensGroup: Optional[StorageLensGroup] + StorageLensGroup: StorageLensGroup | None class JobListDescriptor(TypedDict, total=False): - JobId: Optional[JobId] - Description: Optional[NonEmptyMaxLength256String] - Operation: Optional[OperationName] - Priority: Optional[JobPriority] - Status: Optional[JobStatus] - CreationTime: Optional[JobCreationTime] - TerminationDate: Optional[JobTerminationDate] - ProgressSummary: Optional[JobProgressSummary] + JobId: JobId | None + Description: NonEmptyMaxLength256String | None + Operation: OperationName | None + Priority: JobPriority | None + Status: JobStatus | None + CreationTime: JobCreationTime | None + TerminationDate: JobTerminationDate | None + ProgressSummary: JobProgressSummary | None -JobListDescriptorList = List[JobListDescriptor] -JobStatusList = List[JobStatus] +JobListDescriptorList = list[JobListDescriptor] +JobStatusList = list[JobStatus] class LifecycleConfiguration(TypedDict, total=False): - Rules: Optional[LifecycleRules] + Rules: LifecycleRules | None class ListAccessGrantsInstancesRequest(ServiceRequest): AccountId: AccountId - NextToken: Optional[ContinuationToken] - MaxResults: Optional[MaxResults] + NextToken: ContinuationToken | None + MaxResults: MaxResults | None class ListAccessGrantsInstancesResult(TypedDict, total=False): - NextToken: Optional[ContinuationToken] - AccessGrantsInstancesList: Optional[AccessGrantsInstancesList] + NextToken: ContinuationToken | None + AccessGrantsInstancesList: AccessGrantsInstancesList | None class ListAccessGrantsLocationsRequest(ServiceRequest): AccountId: AccountId - NextToken: Optional[ContinuationToken] - MaxResults: Optional[MaxResults] - LocationScope: Optional[S3Prefix] + NextToken: ContinuationToken | None + MaxResults: MaxResults | None + LocationScope: S3Prefix | None class ListAccessGrantsLocationsResult(TypedDict, total=False): - NextToken: Optional[ContinuationToken] - AccessGrantsLocationsList: Optional[AccessGrantsLocationsList] + NextToken: ContinuationToken | None + AccessGrantsLocationsList: AccessGrantsLocationsList | None class ListAccessGrantsRequest(ServiceRequest): AccountId: AccountId - NextToken: Optional[ContinuationToken] - MaxResults: Optional[MaxResults] - GranteeType: Optional[GranteeType] - GranteeIdentifier: Optional[GranteeIdentifier] - Permission: Optional[Permission] - GrantScope: Optional[S3Prefix] - ApplicationArn: Optional[IdentityCenterApplicationArn] + NextToken: ContinuationToken | None + MaxResults: MaxResults | None + GranteeType: GranteeType | None + GranteeIdentifier: GranteeIdentifier | None + Permission: Permission | None + GrantScope: S3Prefix | None + ApplicationArn: IdentityCenterApplicationArn | None class ListAccessGrantsResult(TypedDict, total=False): - NextToken: Optional[ContinuationToken] - AccessGrantsList: Optional[AccessGrantsList] + NextToken: ContinuationToken | None + AccessGrantsList: AccessGrantsList | None class ListAccessPointsForDirectoryBucketsRequest(ServiceRequest): AccountId: AccountId - DirectoryBucket: Optional[BucketName] - NextToken: Optional[NonEmptyMaxLength1024String] - MaxResults: Optional[MaxResults] + DirectoryBucket: BucketName | None + NextToken: NonEmptyMaxLength1024String | None + MaxResults: MaxResults | None class ListAccessPointsForDirectoryBucketsResult(TypedDict, total=False): - AccessPointList: Optional[AccessPointList] - NextToken: Optional[NonEmptyMaxLength1024String] + AccessPointList: AccessPointList | None + NextToken: NonEmptyMaxLength1024String | None class ListAccessPointsForObjectLambdaRequest(ServiceRequest): AccountId: AccountId - NextToken: Optional[NonEmptyMaxLength1024String] - MaxResults: Optional[MaxResults] + NextToken: NonEmptyMaxLength1024String | None + MaxResults: MaxResults | None class ObjectLambdaAccessPoint(TypedDict, total=False): Name: ObjectLambdaAccessPointName - ObjectLambdaAccessPointArn: Optional[ObjectLambdaAccessPointArn] - Alias: Optional[ObjectLambdaAccessPointAlias] + ObjectLambdaAccessPointArn: ObjectLambdaAccessPointArn | None + Alias: ObjectLambdaAccessPointAlias | None -ObjectLambdaAccessPointList = List[ObjectLambdaAccessPoint] +ObjectLambdaAccessPointList = list[ObjectLambdaAccessPoint] class ListAccessPointsForObjectLambdaResult(TypedDict, total=False): - ObjectLambdaAccessPointList: Optional[ObjectLambdaAccessPointList] - NextToken: Optional[NonEmptyMaxLength1024String] + ObjectLambdaAccessPointList: ObjectLambdaAccessPointList | None + NextToken: NonEmptyMaxLength1024String | None class ListAccessPointsRequest(ServiceRequest): AccountId: AccountId - Bucket: Optional[BucketName] - NextToken: Optional[NonEmptyMaxLength1024String] - MaxResults: Optional[MaxResults] - DataSourceId: Optional[DataSourceId] - DataSourceType: Optional[DataSourceType] + Bucket: BucketName | None + NextToken: NonEmptyMaxLength1024String | None + MaxResults: MaxResults | None + DataSourceId: DataSourceId | None + DataSourceType: DataSourceType | None class ListAccessPointsResult(TypedDict, total=False): - AccessPointList: Optional[AccessPointList] - NextToken: Optional[NonEmptyMaxLength1024String] + AccessPointList: AccessPointList | None + NextToken: NonEmptyMaxLength1024String | None class ListCallerAccessGrantsRequest(ServiceRequest): AccountId: AccountId - GrantScope: Optional[S3Prefix] - NextToken: Optional[ContinuationToken] - MaxResults: Optional[MaxResults] - AllowedByApplication: Optional[Boolean] + GrantScope: S3Prefix | None + NextToken: ContinuationToken | None + MaxResults: MaxResults | None + AllowedByApplication: Boolean | None class ListCallerAccessGrantsResult(TypedDict, total=False): - NextToken: Optional[ContinuationToken] - CallerAccessGrantsList: Optional[CallerAccessGrantsList] + NextToken: ContinuationToken | None + CallerAccessGrantsList: CallerAccessGrantsList | None class ListJobsRequest(ServiceRequest): AccountId: AccountId - JobStatuses: Optional[JobStatusList] - NextToken: Optional[StringForNextToken] - MaxResults: Optional[MaxResults] + JobStatuses: JobStatusList | None + NextToken: StringForNextToken | None + MaxResults: MaxResults | None class ListJobsResult(TypedDict, total=False): - NextToken: Optional[StringForNextToken] - Jobs: Optional[JobListDescriptorList] + NextToken: StringForNextToken | None + Jobs: JobListDescriptorList | None class ListMultiRegionAccessPointsRequest(ServiceRequest): AccountId: AccountId - NextToken: Optional[NonEmptyMaxLength1024String] - MaxResults: Optional[MaxResults] + NextToken: NonEmptyMaxLength1024String | None + MaxResults: MaxResults | None -MultiRegionAccessPointReportList = List[MultiRegionAccessPointReport] +MultiRegionAccessPointReportList = list[MultiRegionAccessPointReport] class ListMultiRegionAccessPointsResult(TypedDict, total=False): - AccessPoints: Optional[MultiRegionAccessPointReportList] - NextToken: Optional[NonEmptyMaxLength1024String] + AccessPoints: MultiRegionAccessPointReportList | None + NextToken: NonEmptyMaxLength1024String | None class ListRegionalBucketsRequest(ServiceRequest): AccountId: AccountId - NextToken: Optional[NonEmptyMaxLength1024String] - MaxResults: Optional[MaxResults] - OutpostId: Optional[NonEmptyMaxLength64String] + NextToken: NonEmptyMaxLength1024String | None + MaxResults: MaxResults | None + OutpostId: NonEmptyMaxLength64String | None class RegionalBucket(TypedDict, total=False): Bucket: BucketName - BucketArn: Optional[S3RegionalBucketArn] + BucketArn: S3RegionalBucketArn | None PublicAccessBlockEnabled: PublicAccessBlockEnabled CreationDate: CreationDate - OutpostId: Optional[NonEmptyMaxLength64String] + OutpostId: NonEmptyMaxLength64String | None -RegionalBucketList = List[RegionalBucket] +RegionalBucketList = list[RegionalBucket] class ListRegionalBucketsResult(TypedDict, total=False): - RegionalBucketList: Optional[RegionalBucketList] - NextToken: Optional[NonEmptyMaxLength1024String] + RegionalBucketList: RegionalBucketList | None + NextToken: NonEmptyMaxLength1024String | None class ListStorageLensConfigurationEntry(TypedDict, total=False): Id: ConfigId StorageLensArn: StorageLensArn HomeRegion: S3AWSRegion - IsEnabled: Optional[IsEnabled] + IsEnabled: IsEnabled | None class ListStorageLensConfigurationsRequest(ServiceRequest): AccountId: AccountId - NextToken: Optional[ContinuationToken] + NextToken: ContinuationToken | None -StorageLensConfigurationList = List[ListStorageLensConfigurationEntry] +StorageLensConfigurationList = list[ListStorageLensConfigurationEntry] class ListStorageLensConfigurationsResult(TypedDict, total=False): - NextToken: Optional[ContinuationToken] - StorageLensConfigurationList: Optional[StorageLensConfigurationList] + NextToken: ContinuationToken | None + StorageLensConfigurationList: StorageLensConfigurationList | None class ListStorageLensGroupEntry(TypedDict, total=False): @@ -2198,15 +2232,15 @@ class ListStorageLensGroupEntry(TypedDict, total=False): class ListStorageLensGroupsRequest(ServiceRequest): AccountId: AccountId - NextToken: Optional[ContinuationToken] + NextToken: ContinuationToken | None -StorageLensGroupList = List[ListStorageLensGroupEntry] +StorageLensGroupList = list[ListStorageLensGroupEntry] class ListStorageLensGroupsResult(TypedDict, total=False): - NextToken: Optional[ContinuationToken] - StorageLensGroupList: Optional[StorageLensGroupList] + NextToken: ContinuationToken | None + StorageLensGroupList: StorageLensGroupList | None class ListTagsForResourceRequest(ServiceRequest): @@ -2215,19 +2249,19 @@ class ListTagsForResourceRequest(ServiceRequest): class ListTagsForResourceResult(TypedDict, total=False): - Tags: Optional[TagList] + Tags: TagList | None class PutAccessGrantsInstanceResourcePolicyRequest(ServiceRequest): AccountId: AccountId Policy: PolicyDocument - Organization: Optional[Organization] + Organization: Organization | None class PutAccessGrantsInstanceResourcePolicyResult(TypedDict, total=False): - Policy: Optional[PolicyDocument] - Organization: Optional[Organization] - CreatedAt: Optional[CreationTimestamp] + Policy: PolicyDocument | None + Organization: Organization | None + CreatedAt: CreationTimestamp | None class PutAccessPointConfigurationForObjectLambdaRequest(ServiceRequest): @@ -2257,13 +2291,13 @@ class PutAccessPointScopeRequest(ServiceRequest): class PutBucketLifecycleConfigurationRequest(ServiceRequest): AccountId: AccountId Bucket: BucketName - LifecycleConfiguration: Optional[LifecycleConfiguration] + LifecycleConfiguration: LifecycleConfiguration | None class PutBucketPolicyRequest(ServiceRequest): AccountId: AccountId Bucket: BucketName - ConfirmRemoveSelfBucketAccess: Optional[ConfirmRemoveSelfBucketAccess] + ConfirmRemoveSelfBucketAccess: ConfirmRemoveSelfBucketAccess | None Policy: Policy @@ -2284,14 +2318,14 @@ class PutBucketTaggingRequest(ServiceRequest): class VersioningConfiguration(TypedDict, total=False): - MFADelete: Optional[MFADelete] - Status: Optional[BucketVersioningStatus] + MFADelete: MFADelete | None + Status: BucketVersioningStatus | None class PutBucketVersioningRequest(ServiceRequest): AccountId: AccountId Bucket: BucketName - MFA: Optional[MFA] + MFA: MFA | None VersioningConfiguration: VersioningConfiguration @@ -2312,7 +2346,7 @@ class PutMultiRegionAccessPointPolicyRequest(ServiceRequest): class PutMultiRegionAccessPointPolicyResult(TypedDict, total=False): - RequestTokenARN: Optional[AsyncRequestTokenARN] + RequestTokenARN: AsyncRequestTokenARN | None class PutPublicAccessBlockRequest(ServiceRequest): @@ -2324,7 +2358,7 @@ class PutStorageLensConfigurationRequest(ServiceRequest): ConfigId: ConfigId AccountId: AccountId StorageLensConfiguration: StorageLensConfiguration - Tags: Optional[StorageLensTags] + Tags: StorageLensTags | None class PutStorageLensConfigurationTaggingRequest(ServiceRequest): @@ -2347,7 +2381,7 @@ class SubmitMultiRegionAccessPointRoutesResult(TypedDict, total=False): pass -TagKeyList = List[TagKeyString] +TagKeyList = list[TagKeyString] class TagResourceRequest(ServiceRequest): @@ -2377,11 +2411,11 @@ class UpdateAccessGrantsLocationRequest(ServiceRequest): class UpdateAccessGrantsLocationResult(TypedDict, total=False): - CreatedAt: Optional[CreationTimestamp] - AccessGrantsLocationId: Optional[AccessGrantsLocationId] - AccessGrantsLocationArn: Optional[AccessGrantsLocationArn] - LocationScope: Optional[S3Prefix] - IAMRoleArn: Optional[IAMRoleArn] + CreatedAt: CreationTimestamp | None + AccessGrantsLocationId: AccessGrantsLocationId | None + AccessGrantsLocationArn: AccessGrantsLocationArn | None + LocationScope: S3Prefix | None + IAMRoleArn: IAMRoleArn | None class UpdateJobPriorityRequest(ServiceRequest): @@ -2399,13 +2433,13 @@ class UpdateJobStatusRequest(ServiceRequest): AccountId: AccountId JobId: JobId RequestedJobStatus: RequestedJobStatus - StatusUpdateReason: Optional[JobStatusUpdateReason] + StatusUpdateReason: JobStatusUpdateReason | None class UpdateJobStatusResult(TypedDict, total=False): - JobId: Optional[JobId] - Status: Optional[JobStatus] - StatusUpdateReason: Optional[JobStatusUpdateReason] + JobId: JobId | None + Status: JobStatus | None + StatusUpdateReason: JobStatusUpdateReason | None class UpdateStorageLensGroupRequest(ServiceRequest): @@ -2415,8 +2449,8 @@ class UpdateStorageLensGroupRequest(ServiceRequest): class S3ControlApi: - service = "s3control" - version = "2018-08-20" + service: str = "s3control" + version: str = "2018-08-20" @handler("AssociateAccessGrantsIdentityCenter") def associate_access_grants_identity_center( diff --git a/localstack-core/localstack/aws/api/scheduler/__init__.py b/localstack-core/localstack/aws/api/scheduler/__init__.py index 829a895bd4a06..d1695b15f6ff3 100644 --- a/localstack-core/localstack/aws/api/scheduler/__init__.py +++ b/localstack-core/localstack/aws/api/scheduler/__init__.py @@ -1,6 +1,6 @@ from datetime import datetime from enum import StrEnum -from typing import Dict, List, Optional, TypedDict +from typing import TypedDict from localstack.aws.api import RequestContext, ServiceException, ServiceRequest, handler @@ -132,23 +132,23 @@ class ValidationException(ServiceException): status_code: int = 400 -Subnets = List[Subnet] -SecurityGroups = List[SecurityGroup] +Subnets = list[Subnet] +SecurityGroups = list[SecurityGroup] class AwsVpcConfiguration(TypedDict, total=False): - AssignPublicIp: Optional[AssignPublicIp] - SecurityGroups: Optional[SecurityGroups] + AssignPublicIp: AssignPublicIp | None + SecurityGroups: SecurityGroups | None Subnets: Subnets class CapacityProviderStrategyItem(TypedDict, total=False): - base: Optional[CapacityProviderStrategyItemBase] + base: CapacityProviderStrategyItemBase | None capacityProvider: CapacityProvider - weight: Optional[CapacityProviderStrategyItemWeight] + weight: CapacityProviderStrategyItemWeight | None -CapacityProviderStrategy = List[CapacityProviderStrategyItem] +CapacityProviderStrategy = list[CapacityProviderStrategyItem] class Tag(TypedDict, total=False): @@ -156,13 +156,13 @@ class Tag(TypedDict, total=False): Value: TagValue -TagList = List[Tag] +TagList = list[Tag] class CreateScheduleGroupInput(ServiceRequest): - ClientToken: Optional[ClientToken] + ClientToken: ClientToken | None Name: ScheduleGroupName - Tags: Optional[TagList] + Tags: TagList | None class CreateScheduleGroupOutput(TypedDict, total=False): @@ -170,7 +170,7 @@ class CreateScheduleGroupOutput(TypedDict, total=False): class SqsParameters(TypedDict, total=False): - MessageGroupId: Optional[MessageGroupId] + MessageGroupId: MessageGroupId | None class SageMakerPipelineParameter(TypedDict, total=False): @@ -178,16 +178,16 @@ class SageMakerPipelineParameter(TypedDict, total=False): Value: SageMakerPipelineParameterValue -SageMakerPipelineParameterList = List[SageMakerPipelineParameter] +SageMakerPipelineParameterList = list[SageMakerPipelineParameter] class SageMakerPipelineParameters(TypedDict, total=False): - PipelineParameterList: Optional[SageMakerPipelineParameterList] + PipelineParameterList: SageMakerPipelineParameterList | None class RetryPolicy(TypedDict, total=False): - MaximumEventAgeInSeconds: Optional[MaximumEventAgeInSeconds] - MaximumRetryAttempts: Optional[MaximumRetryAttempts] + MaximumEventAgeInSeconds: MaximumEventAgeInSeconds | None + MaximumRetryAttempts: MaximumRetryAttempts | None class KinesisParameters(TypedDict, total=False): @@ -199,69 +199,69 @@ class EventBridgeParameters(TypedDict, total=False): Source: Source -TagMap = Dict[TagKey, TagValue] -Tags = List[TagMap] +TagMap = dict[TagKey, TagValue] +Tags = list[TagMap] class PlacementStrategy(TypedDict, total=False): - field: Optional[PlacementStrategyField] - type: Optional[PlacementStrategyType] + field: PlacementStrategyField | None + type: PlacementStrategyType | None -PlacementStrategies = List[PlacementStrategy] +PlacementStrategies = list[PlacementStrategy] class PlacementConstraint(TypedDict, total=False): - expression: Optional[PlacementConstraintExpression] - type: Optional[PlacementConstraintType] + expression: PlacementConstraintExpression | None + type: PlacementConstraintType | None -PlacementConstraints = List[PlacementConstraint] +PlacementConstraints = list[PlacementConstraint] class NetworkConfiguration(TypedDict, total=False): - awsvpcConfiguration: Optional[AwsVpcConfiguration] + awsvpcConfiguration: AwsVpcConfiguration | None class EcsParameters(TypedDict, total=False): - CapacityProviderStrategy: Optional[CapacityProviderStrategy] - EnableECSManagedTags: Optional[EnableECSManagedTags] - EnableExecuteCommand: Optional[EnableExecuteCommand] - Group: Optional[Group] - LaunchType: Optional[LaunchType] - NetworkConfiguration: Optional[NetworkConfiguration] - PlacementConstraints: Optional[PlacementConstraints] - PlacementStrategy: Optional[PlacementStrategies] - PlatformVersion: Optional[PlatformVersion] - PropagateTags: Optional[PropagateTags] - ReferenceId: Optional[ReferenceId] - Tags: Optional[Tags] - TaskCount: Optional[TaskCount] + CapacityProviderStrategy: CapacityProviderStrategy | None + EnableECSManagedTags: EnableECSManagedTags | None + EnableExecuteCommand: EnableExecuteCommand | None + Group: Group | None + LaunchType: LaunchType | None + NetworkConfiguration: NetworkConfiguration | None + PlacementConstraints: PlacementConstraints | None + PlacementStrategy: PlacementStrategies | None + PlatformVersion: PlatformVersion | None + PropagateTags: PropagateTags | None + ReferenceId: ReferenceId | None + Tags: Tags | None + TaskCount: TaskCount | None TaskDefinitionArn: TaskDefinitionArn class DeadLetterConfig(TypedDict, total=False): - Arn: Optional[DeadLetterConfigArnString] + Arn: DeadLetterConfigArnString | None class Target(TypedDict, total=False): Arn: TargetArn - DeadLetterConfig: Optional[DeadLetterConfig] - EcsParameters: Optional[EcsParameters] - EventBridgeParameters: Optional[EventBridgeParameters] - Input: Optional[TargetInput] - KinesisParameters: Optional[KinesisParameters] - RetryPolicy: Optional[RetryPolicy] + DeadLetterConfig: DeadLetterConfig | None + EcsParameters: EcsParameters | None + EventBridgeParameters: EventBridgeParameters | None + Input: TargetInput | None + KinesisParameters: KinesisParameters | None + RetryPolicy: RetryPolicy | None RoleArn: RoleArn - SageMakerPipelineParameters: Optional[SageMakerPipelineParameters] - SqsParameters: Optional[SqsParameters] + SageMakerPipelineParameters: SageMakerPipelineParameters | None + SqsParameters: SqsParameters | None StartDate = datetime class FlexibleTimeWindow(TypedDict, total=False): - MaximumWindowInMinutes: Optional[MaximumWindowInMinutes] + MaximumWindowInMinutes: MaximumWindowInMinutes | None Mode: FlexibleTimeWindowMode @@ -269,18 +269,18 @@ class FlexibleTimeWindow(TypedDict, total=False): class CreateScheduleInput(ServiceRequest): - ActionAfterCompletion: Optional[ActionAfterCompletion] - ClientToken: Optional[ClientToken] - Description: Optional[Description] - EndDate: Optional[EndDate] + ActionAfterCompletion: ActionAfterCompletion | None + ClientToken: ClientToken | None + Description: Description | None + EndDate: EndDate | None FlexibleTimeWindow: FlexibleTimeWindow - GroupName: Optional[ScheduleGroupName] - KmsKeyArn: Optional[KmsKeyArn] + GroupName: ScheduleGroupName | None + KmsKeyArn: KmsKeyArn | None Name: Name ScheduleExpression: ScheduleExpression - ScheduleExpressionTimezone: Optional[ScheduleExpressionTimezone] - StartDate: Optional[StartDate] - State: Optional[ScheduleState] + ScheduleExpressionTimezone: ScheduleExpressionTimezone | None + StartDate: StartDate | None + State: ScheduleState | None Target: Target @@ -292,7 +292,7 @@ class CreateScheduleOutput(TypedDict, total=False): class DeleteScheduleGroupInput(ServiceRequest): - ClientToken: Optional[ClientToken] + ClientToken: ClientToken | None Name: ScheduleGroupName @@ -301,8 +301,8 @@ class DeleteScheduleGroupOutput(TypedDict, total=False): class DeleteScheduleInput(ServiceRequest): - ClientToken: Optional[ClientToken] - GroupName: Optional[ScheduleGroupName] + ClientToken: ClientToken | None + GroupName: ScheduleGroupName | None Name: Name @@ -318,64 +318,64 @@ class GetScheduleGroupInput(ServiceRequest): class GetScheduleGroupOutput(TypedDict, total=False): - Arn: Optional[ScheduleGroupArn] - CreationDate: Optional[CreationDate] - LastModificationDate: Optional[LastModificationDate] - Name: Optional[ScheduleGroupName] - State: Optional[ScheduleGroupState] + Arn: ScheduleGroupArn | None + CreationDate: CreationDate | None + LastModificationDate: LastModificationDate | None + Name: ScheduleGroupName | None + State: ScheduleGroupState | None class GetScheduleInput(ServiceRequest): - GroupName: Optional[ScheduleGroupName] + GroupName: ScheduleGroupName | None Name: Name class GetScheduleOutput(TypedDict, total=False): - ActionAfterCompletion: Optional[ActionAfterCompletion] - Arn: Optional[ScheduleArn] - CreationDate: Optional[CreationDate] - Description: Optional[Description] - EndDate: Optional[EndDate] - FlexibleTimeWindow: Optional[FlexibleTimeWindow] - GroupName: Optional[ScheduleGroupName] - KmsKeyArn: Optional[KmsKeyArn] - LastModificationDate: Optional[LastModificationDate] - Name: Optional[Name] - ScheduleExpression: Optional[ScheduleExpression] - ScheduleExpressionTimezone: Optional[ScheduleExpressionTimezone] - StartDate: Optional[StartDate] - State: Optional[ScheduleState] - Target: Optional[Target] + ActionAfterCompletion: ActionAfterCompletion | None + Arn: ScheduleArn | None + CreationDate: CreationDate | None + Description: Description | None + EndDate: EndDate | None + FlexibleTimeWindow: FlexibleTimeWindow | None + GroupName: ScheduleGroupName | None + KmsKeyArn: KmsKeyArn | None + LastModificationDate: LastModificationDate | None + Name: Name | None + ScheduleExpression: ScheduleExpression | None + ScheduleExpressionTimezone: ScheduleExpressionTimezone | None + StartDate: StartDate | None + State: ScheduleState | None + Target: Target | None class ListScheduleGroupsInput(ServiceRequest): - MaxResults: Optional[MaxResults] - NamePrefix: Optional[ScheduleGroupNamePrefix] - NextToken: Optional[NextToken] + MaxResults: MaxResults | None + NamePrefix: ScheduleGroupNamePrefix | None + NextToken: NextToken | None class ScheduleGroupSummary(TypedDict, total=False): - Arn: Optional[ScheduleGroupArn] - CreationDate: Optional[CreationDate] - LastModificationDate: Optional[LastModificationDate] - Name: Optional[ScheduleGroupName] - State: Optional[ScheduleGroupState] + Arn: ScheduleGroupArn | None + CreationDate: CreationDate | None + LastModificationDate: LastModificationDate | None + Name: ScheduleGroupName | None + State: ScheduleGroupState | None -ScheduleGroupList = List[ScheduleGroupSummary] +ScheduleGroupList = list[ScheduleGroupSummary] class ListScheduleGroupsOutput(TypedDict, total=False): - NextToken: Optional[NextToken] + NextToken: NextToken | None ScheduleGroups: ScheduleGroupList class ListSchedulesInput(ServiceRequest): - GroupName: Optional[ScheduleGroupName] - MaxResults: Optional[MaxResults] - NamePrefix: Optional[NamePrefix] - NextToken: Optional[NextToken] - State: Optional[ScheduleState] + GroupName: ScheduleGroupName | None + MaxResults: MaxResults | None + NamePrefix: NamePrefix | None + NextToken: NextToken | None + State: ScheduleState | None class TargetSummary(TypedDict, total=False): @@ -383,20 +383,20 @@ class TargetSummary(TypedDict, total=False): class ScheduleSummary(TypedDict, total=False): - Arn: Optional[ScheduleArn] - CreationDate: Optional[CreationDate] - GroupName: Optional[ScheduleGroupName] - LastModificationDate: Optional[LastModificationDate] - Name: Optional[Name] - State: Optional[ScheduleState] - Target: Optional[TargetSummary] + Arn: ScheduleArn | None + CreationDate: CreationDate | None + GroupName: ScheduleGroupName | None + LastModificationDate: LastModificationDate | None + Name: Name | None + State: ScheduleState | None + Target: TargetSummary | None -ScheduleList = List[ScheduleSummary] +ScheduleList = list[ScheduleSummary] class ListSchedulesOutput(TypedDict, total=False): - NextToken: Optional[NextToken] + NextToken: NextToken | None Schedules: ScheduleList @@ -405,10 +405,10 @@ class ListTagsForResourceInput(ServiceRequest): class ListTagsForResourceOutput(TypedDict, total=False): - Tags: Optional[TagList] + Tags: TagList | None -TagKeyList = List[TagKey] +TagKeyList = list[TagKey] class TagResourceInput(ServiceRequest): @@ -430,18 +430,18 @@ class UntagResourceOutput(TypedDict, total=False): class UpdateScheduleInput(ServiceRequest): - ActionAfterCompletion: Optional[ActionAfterCompletion] - ClientToken: Optional[ClientToken] - Description: Optional[Description] - EndDate: Optional[EndDate] + ActionAfterCompletion: ActionAfterCompletion | None + ClientToken: ClientToken | None + Description: Description | None + EndDate: EndDate | None FlexibleTimeWindow: FlexibleTimeWindow - GroupName: Optional[ScheduleGroupName] - KmsKeyArn: Optional[KmsKeyArn] + GroupName: ScheduleGroupName | None + KmsKeyArn: KmsKeyArn | None Name: Name ScheduleExpression: ScheduleExpression - ScheduleExpressionTimezone: Optional[ScheduleExpressionTimezone] - StartDate: Optional[StartDate] - State: Optional[ScheduleState] + ScheduleExpressionTimezone: ScheduleExpressionTimezone | None + StartDate: StartDate | None + State: ScheduleState | None Target: Target @@ -450,8 +450,8 @@ class UpdateScheduleOutput(TypedDict, total=False): class SchedulerApi: - service = "scheduler" - version = "2021-06-30" + service: str = "scheduler" + version: str = "2021-06-30" @handler("CreateSchedule") def create_schedule( diff --git a/localstack-core/localstack/aws/api/secretsmanager/__init__.py b/localstack-core/localstack/aws/api/secretsmanager/__init__.py index 7e4704d8f34ac..296220683a614 100644 --- a/localstack-core/localstack/aws/api/secretsmanager/__init__.py +++ b/localstack-core/localstack/aws/api/secretsmanager/__init__.py @@ -1,6 +1,6 @@ from datetime import datetime from enum import StrEnum -from typing import Dict, List, Optional, TypedDict +from typing import TypedDict from localstack.aws.api import RequestContext, ServiceException, ServiceRequest, handler @@ -15,11 +15,14 @@ ExcludeNumbersType = bool ExcludePunctuationType = bool ExcludeUppercaseType = bool +ExternalSecretRotationMetadataItemKeyType = str +ExternalSecretRotationMetadataItemValueType = str FilterValueStringType = str IncludeSpaceType = bool KmsKeyIdType = str MaxResultsBatchType = int MaxResultsType = int +MedeaTypeType = str NameType = str NextTokenType = str NonEmptyResourcePolicyType = str @@ -27,6 +30,7 @@ RandomPasswordType = str RegionType = str RequireEachIncludedTypeType = bool +RoleARNType = str RotationEnabledType = bool RotationLambdaARNType = str RotationTokenType = str @@ -52,6 +56,13 @@ class FilterNameStringType(StrEnum): all = "all" +class SortByType(StrEnum): + created_date = "created-date" + last_accessed_date = "last-accessed-date" + last_changed_date = "last-changed-date" + name = "name" + + class SortOrderType(StrEnum): asc = "asc" desc = "desc" @@ -136,62 +147,62 @@ class ResourceNotFoundException(ServiceException): class APIErrorType(TypedDict, total=False): - SecretId: Optional[SecretIdType] - ErrorCode: Optional[ErrorCode] - Message: Optional[ErrorMessage] + SecretId: SecretIdType | None + ErrorCode: ErrorCode | None + Message: ErrorMessage | None -APIErrorListType = List[APIErrorType] +APIErrorListType = list[APIErrorType] class ReplicaRegionType(TypedDict, total=False): - Region: Optional[RegionType] - KmsKeyId: Optional[KmsKeyIdType] + Region: RegionType | None + KmsKeyId: KmsKeyIdType | None -AddReplicaRegionListType = List[ReplicaRegionType] +AddReplicaRegionListType = list[ReplicaRegionType] AutomaticallyRotateAfterDaysType = int -FilterValuesStringList = List[FilterValueStringType] +FilterValuesStringList = list[FilterValueStringType] class Filter(TypedDict, total=False): - Key: Optional[FilterNameStringType] - Values: Optional[FilterValuesStringList] + Key: FilterNameStringType | None + Values: FilterValuesStringList | None -FiltersListType = List[Filter] -SecretIdListType = List[SecretIdType] +FiltersListType = list[Filter] +SecretIdListType = list[SecretIdType] class BatchGetSecretValueRequest(ServiceRequest): - SecretIdList: Optional[SecretIdListType] - Filters: Optional[FiltersListType] - MaxResults: Optional[MaxResultsBatchType] - NextToken: Optional[NextTokenType] + SecretIdList: SecretIdListType | None + Filters: FiltersListType | None + MaxResults: MaxResultsBatchType | None + NextToken: NextTokenType | None CreatedDateType = datetime -SecretVersionStagesType = List[SecretVersionStageType] +SecretVersionStagesType = list[SecretVersionStageType] SecretBinaryType = bytes class SecretValueEntry(TypedDict, total=False): - ARN: Optional[SecretARNType] - Name: Optional[SecretNameType] - VersionId: Optional[SecretVersionIdType] - SecretBinary: Optional[SecretBinaryType] - SecretString: Optional[SecretStringType] - VersionStages: Optional[SecretVersionStagesType] - CreatedDate: Optional[CreatedDateType] + ARN: SecretARNType | None + Name: SecretNameType | None + VersionId: SecretVersionIdType | None + SecretBinary: SecretBinaryType | None + SecretString: SecretStringType | None + VersionStages: SecretVersionStagesType | None + CreatedDate: CreatedDateType | None -SecretValuesType = List[SecretValueEntry] +SecretValuesType = list[SecretValueEntry] class BatchGetSecretValueResponse(TypedDict, total=False): - SecretValues: Optional[SecretValuesType] - NextToken: Optional[NextTokenType] - Errors: Optional[APIErrorListType] + SecretValues: SecretValuesType | None + NextToken: NextTokenType | None + Errors: APIErrorListType | None class CancelRotateSecretRequest(ServiceRequest): @@ -199,50 +210,51 @@ class CancelRotateSecretRequest(ServiceRequest): class CancelRotateSecretResponse(TypedDict, total=False): - ARN: Optional[SecretARNType] - Name: Optional[SecretNameType] - VersionId: Optional[SecretVersionIdType] + ARN: SecretARNType | None + Name: SecretNameType | None + VersionId: SecretVersionIdType | None class Tag(TypedDict, total=False): - Key: Optional[TagKeyType] - Value: Optional[TagValueType] + Key: TagKeyType | None + Value: TagValueType | None -TagListType = List[Tag] +TagListType = list[Tag] class CreateSecretRequest(ServiceRequest): Name: NameType - ClientRequestToken: Optional[ClientRequestTokenType] - Description: Optional[DescriptionType] - KmsKeyId: Optional[KmsKeyIdType] - SecretBinary: Optional[SecretBinaryType] - SecretString: Optional[SecretStringType] - Tags: Optional[TagListType] - AddReplicaRegions: Optional[AddReplicaRegionListType] - ForceOverwriteReplicaSecret: Optional[BooleanType] + ClientRequestToken: ClientRequestTokenType | None + Description: DescriptionType | None + KmsKeyId: KmsKeyIdType | None + SecretBinary: SecretBinaryType | None + SecretString: SecretStringType | None + Tags: TagListType | None + AddReplicaRegions: AddReplicaRegionListType | None + ForceOverwriteReplicaSecret: BooleanType | None + Type: MedeaTypeType | None LastAccessedDateType = datetime class ReplicationStatusType(TypedDict, total=False): - Region: Optional[RegionType] - KmsKeyId: Optional[KmsKeyIdType] - Status: Optional[StatusType] - StatusMessage: Optional[StatusMessageType] - LastAccessedDate: Optional[LastAccessedDateType] + Region: RegionType | None + KmsKeyId: KmsKeyIdType | None + Status: StatusType | None + StatusMessage: StatusMessageType | None + LastAccessedDate: LastAccessedDateType | None -ReplicationStatusListType = List[ReplicationStatusType] +ReplicationStatusListType = list[ReplicationStatusType] class CreateSecretResponse(TypedDict, total=False): - ARN: Optional[SecretARNType] - Name: Optional[SecretNameType] - VersionId: Optional[SecretVersionIdType] - ReplicationStatus: Optional[ReplicationStatusListType] + ARN: SecretARNType | None + Name: SecretNameType | None + VersionId: SecretVersionIdType | None + ReplicationStatus: ReplicationStatusListType | None class DeleteResourcePolicyRequest(ServiceRequest): @@ -250,8 +262,8 @@ class DeleteResourcePolicyRequest(ServiceRequest): class DeleteResourcePolicyResponse(TypedDict, total=False): - ARN: Optional[SecretARNType] - Name: Optional[NameType] + ARN: SecretARNType | None + Name: NameType | None RecoveryWindowInDaysType = int @@ -259,17 +271,17 @@ class DeleteResourcePolicyResponse(TypedDict, total=False): class DeleteSecretRequest(ServiceRequest): SecretId: SecretIdType - RecoveryWindowInDays: Optional[RecoveryWindowInDaysType] - ForceDeleteWithoutRecovery: Optional[BooleanType] + RecoveryWindowInDays: RecoveryWindowInDaysType | None + ForceDeleteWithoutRecovery: BooleanType | None DeletionDateType = datetime class DeleteSecretResponse(TypedDict, total=False): - ARN: Optional[SecretARNType] - Name: Optional[SecretNameType] - DeletionDate: Optional[DeletionDateType] + ARN: SecretARNType | None + Name: SecretNameType | None + DeletionDate: DeletionDateType | None DeletedDateType = datetime @@ -280,55 +292,66 @@ class DescribeSecretRequest(ServiceRequest): TimestampType = datetime -SecretVersionsToStagesMapType = Dict[SecretVersionIdType, SecretVersionStagesType] +SecretVersionsToStagesMapType = dict[SecretVersionIdType, SecretVersionStagesType] NextRotationDateType = datetime LastChangedDateType = datetime LastRotatedDateType = datetime +class ExternalSecretRotationMetadataItem(TypedDict, total=False): + Key: ExternalSecretRotationMetadataItemKeyType | None + Value: ExternalSecretRotationMetadataItemValueType | None + + +ExternalSecretRotationMetadataType = list[ExternalSecretRotationMetadataItem] + + class RotationRulesType(TypedDict, total=False): - AutomaticallyAfterDays: Optional[AutomaticallyRotateAfterDaysType] - Duration: Optional[DurationType] - ScheduleExpression: Optional[ScheduleExpressionType] + AutomaticallyAfterDays: AutomaticallyRotateAfterDaysType | None + Duration: DurationType | None + ScheduleExpression: ScheduleExpressionType | None class DescribeSecretResponse(TypedDict, total=False): - ARN: Optional[SecretARNType] - Name: Optional[SecretNameType] - Description: Optional[DescriptionType] - KmsKeyId: Optional[KmsKeyIdType] - RotationEnabled: Optional[RotationEnabledType] - RotationLambdaARN: Optional[RotationLambdaARNType] - RotationRules: Optional[RotationRulesType] - LastRotatedDate: Optional[LastRotatedDateType] - LastChangedDate: Optional[LastChangedDateType] - LastAccessedDate: Optional[LastAccessedDateType] - DeletedDate: Optional[DeletedDateType] - NextRotationDate: Optional[NextRotationDateType] - Tags: Optional[TagListType] - VersionIdsToStages: Optional[SecretVersionsToStagesMapType] - OwningService: Optional[OwningServiceType] - CreatedDate: Optional[TimestampType] - PrimaryRegion: Optional[RegionType] - ReplicationStatus: Optional[ReplicationStatusListType] + ARN: SecretARNType | None + Name: SecretNameType | None + Type: MedeaTypeType | None + Description: DescriptionType | None + KmsKeyId: KmsKeyIdType | None + RotationEnabled: RotationEnabledType | None + RotationLambdaARN: RotationLambdaARNType | None + RotationRules: RotationRulesType | None + ExternalSecretRotationMetadata: ExternalSecretRotationMetadataType | None + ExternalSecretRotationRoleArn: RoleARNType | None + LastRotatedDate: LastRotatedDateType | None + LastChangedDate: LastChangedDateType | None + LastAccessedDate: LastAccessedDateType | None + DeletedDate: DeletedDateType | None + NextRotationDate: NextRotationDateType | None + Tags: TagListType | None + VersionIdsToStages: SecretVersionsToStagesMapType | None + OwningService: OwningServiceType | None + CreatedDate: TimestampType | None + PrimaryRegion: RegionType | None + ReplicationStatus: ReplicationStatusListType | None PasswordLengthType = int class GetRandomPasswordRequest(ServiceRequest): - PasswordLength: Optional[PasswordLengthType] - ExcludeCharacters: Optional[ExcludeCharactersType] - ExcludeNumbers: Optional[ExcludeNumbersType] - ExcludePunctuation: Optional[ExcludePunctuationType] - ExcludeUppercase: Optional[ExcludeUppercaseType] - ExcludeLowercase: Optional[ExcludeLowercaseType] - IncludeSpace: Optional[IncludeSpaceType] - RequireEachIncludedType: Optional[RequireEachIncludedTypeType] + PasswordLength: PasswordLengthType | None + ExcludeCharacters: ExcludeCharactersType | None + ExcludeNumbers: ExcludeNumbersType | None + ExcludePunctuation: ExcludePunctuationType | None + ExcludeUppercase: ExcludeUppercaseType | None + ExcludeLowercase: ExcludeLowercaseType | None + IncludeSpace: IncludeSpaceType | None + RequireEachIncludedType: RequireEachIncludedTypeType | None class GetRandomPasswordResponse(TypedDict, total=False): - RandomPassword: Optional[RandomPasswordType] + RandomPassword: RandomPasswordType | None class GetResourcePolicyRequest(ServiceRequest): @@ -336,119 +359,123 @@ class GetResourcePolicyRequest(ServiceRequest): class GetResourcePolicyResponse(TypedDict, total=False): - ARN: Optional[SecretARNType] - Name: Optional[NameType] - ResourcePolicy: Optional[NonEmptyResourcePolicyType] + ARN: SecretARNType | None + Name: NameType | None + ResourcePolicy: NonEmptyResourcePolicyType | None class GetSecretValueRequest(ServiceRequest): SecretId: SecretIdType - VersionId: Optional[SecretVersionIdType] - VersionStage: Optional[SecretVersionStageType] + VersionId: SecretVersionIdType | None + VersionStage: SecretVersionStageType | None class GetSecretValueResponse(TypedDict, total=False): - ARN: Optional[SecretARNType] - Name: Optional[SecretNameType] - VersionId: Optional[SecretVersionIdType] - SecretBinary: Optional[SecretBinaryType] - SecretString: Optional[SecretStringType] - VersionStages: Optional[SecretVersionStagesType] - CreatedDate: Optional[CreatedDateType] + ARN: SecretARNType | None + Name: SecretNameType | None + VersionId: SecretVersionIdType | None + SecretBinary: SecretBinaryType | None + SecretString: SecretStringType | None + VersionStages: SecretVersionStagesType | None + CreatedDate: CreatedDateType | None -KmsKeyIdListType = List[KmsKeyIdType] +KmsKeyIdListType = list[KmsKeyIdType] class ListSecretVersionIdsRequest(ServiceRequest): SecretId: SecretIdType - MaxResults: Optional[MaxResultsType] - NextToken: Optional[NextTokenType] - IncludeDeprecated: Optional[BooleanType] + MaxResults: MaxResultsType | None + NextToken: NextTokenType | None + IncludeDeprecated: BooleanType | None class SecretVersionsListEntry(TypedDict, total=False): - VersionId: Optional[SecretVersionIdType] - VersionStages: Optional[SecretVersionStagesType] - LastAccessedDate: Optional[LastAccessedDateType] - CreatedDate: Optional[CreatedDateType] - KmsKeyIds: Optional[KmsKeyIdListType] + VersionId: SecretVersionIdType | None + VersionStages: SecretVersionStagesType | None + LastAccessedDate: LastAccessedDateType | None + CreatedDate: CreatedDateType | None + KmsKeyIds: KmsKeyIdListType | None -SecretVersionsListType = List[SecretVersionsListEntry] +SecretVersionsListType = list[SecretVersionsListEntry] class ListSecretVersionIdsResponse(TypedDict, total=False): - Versions: Optional[SecretVersionsListType] - NextToken: Optional[NextTokenType] - ARN: Optional[SecretARNType] - Name: Optional[SecretNameType] + Versions: SecretVersionsListType | None + NextToken: NextTokenType | None + ARN: SecretARNType | None + Name: SecretNameType | None class ListSecretsRequest(ServiceRequest): - IncludePlannedDeletion: Optional[BooleanType] - MaxResults: Optional[MaxResultsType] - NextToken: Optional[NextTokenType] - Filters: Optional[FiltersListType] - SortOrder: Optional[SortOrderType] + IncludePlannedDeletion: BooleanType | None + MaxResults: MaxResultsType | None + NextToken: NextTokenType | None + Filters: FiltersListType | None + SortOrder: SortOrderType | None + SortBy: SortByType | None class SecretListEntry(TypedDict, total=False): - ARN: Optional[SecretARNType] - Name: Optional[SecretNameType] - Description: Optional[DescriptionType] - KmsKeyId: Optional[KmsKeyIdType] - RotationEnabled: Optional[RotationEnabledType] - RotationLambdaARN: Optional[RotationLambdaARNType] - RotationRules: Optional[RotationRulesType] - LastRotatedDate: Optional[LastRotatedDateType] - LastChangedDate: Optional[LastChangedDateType] - LastAccessedDate: Optional[LastAccessedDateType] - DeletedDate: Optional[DeletedDateType] - NextRotationDate: Optional[NextRotationDateType] - Tags: Optional[TagListType] - SecretVersionsToStages: Optional[SecretVersionsToStagesMapType] - OwningService: Optional[OwningServiceType] - CreatedDate: Optional[TimestampType] - PrimaryRegion: Optional[RegionType] - - -SecretListType = List[SecretListEntry] + ARN: SecretARNType | None + Name: SecretNameType | None + Type: MedeaTypeType | None + Description: DescriptionType | None + KmsKeyId: KmsKeyIdType | None + RotationEnabled: RotationEnabledType | None + RotationLambdaARN: RotationLambdaARNType | None + RotationRules: RotationRulesType | None + ExternalSecretRotationMetadata: ExternalSecretRotationMetadataType | None + ExternalSecretRotationRoleArn: RoleARNType | None + LastRotatedDate: LastRotatedDateType | None + LastChangedDate: LastChangedDateType | None + LastAccessedDate: LastAccessedDateType | None + DeletedDate: DeletedDateType | None + NextRotationDate: NextRotationDateType | None + Tags: TagListType | None + SecretVersionsToStages: SecretVersionsToStagesMapType | None + OwningService: OwningServiceType | None + CreatedDate: TimestampType | None + PrimaryRegion: RegionType | None + + +SecretListType = list[SecretListEntry] class ListSecretsResponse(TypedDict, total=False): - SecretList: Optional[SecretListType] - NextToken: Optional[NextTokenType] + SecretList: SecretListType | None + NextToken: NextTokenType | None class PutResourcePolicyRequest(ServiceRequest): SecretId: SecretIdType ResourcePolicy: NonEmptyResourcePolicyType - BlockPublicPolicy: Optional[BooleanType] + BlockPublicPolicy: BooleanType | None class PutResourcePolicyResponse(TypedDict, total=False): - ARN: Optional[SecretARNType] - Name: Optional[NameType] + ARN: SecretARNType | None + Name: NameType | None class PutSecretValueRequest(ServiceRequest): SecretId: SecretIdType - ClientRequestToken: Optional[ClientRequestTokenType] - SecretBinary: Optional[SecretBinaryType] - SecretString: Optional[SecretStringType] - VersionStages: Optional[SecretVersionStagesType] - RotationToken: Optional[RotationTokenType] + ClientRequestToken: ClientRequestTokenType | None + SecretBinary: SecretBinaryType | None + SecretString: SecretStringType | None + VersionStages: SecretVersionStagesType | None + RotationToken: RotationTokenType | None class PutSecretValueResponse(TypedDict, total=False): - ARN: Optional[SecretARNType] - Name: Optional[SecretNameType] - VersionId: Optional[SecretVersionIdType] - VersionStages: Optional[SecretVersionStagesType] + ARN: SecretARNType | None + Name: SecretNameType | None + VersionId: SecretVersionIdType | None + VersionStages: SecretVersionStagesType | None -RemoveReplicaRegionListType = List[RegionType] +RemoveReplicaRegionListType = list[RegionType] class RemoveRegionsFromReplicationRequest(ServiceRequest): @@ -457,19 +484,19 @@ class RemoveRegionsFromReplicationRequest(ServiceRequest): class RemoveRegionsFromReplicationResponse(TypedDict, total=False): - ARN: Optional[SecretARNType] - ReplicationStatus: Optional[ReplicationStatusListType] + ARN: SecretARNType | None + ReplicationStatus: ReplicationStatusListType | None class ReplicateSecretToRegionsRequest(ServiceRequest): SecretId: SecretIdType AddReplicaRegions: AddReplicaRegionListType - ForceOverwriteReplicaSecret: Optional[BooleanType] + ForceOverwriteReplicaSecret: BooleanType | None class ReplicateSecretToRegionsResponse(TypedDict, total=False): - ARN: Optional[SecretARNType] - ReplicationStatus: Optional[ReplicationStatusListType] + ARN: SecretARNType | None + ReplicationStatus: ReplicationStatusListType | None class RestoreSecretRequest(ServiceRequest): @@ -477,22 +504,24 @@ class RestoreSecretRequest(ServiceRequest): class RestoreSecretResponse(TypedDict, total=False): - ARN: Optional[SecretARNType] - Name: Optional[SecretNameType] + ARN: SecretARNType | None + Name: SecretNameType | None class RotateSecretRequest(ServiceRequest): SecretId: SecretIdType - ClientRequestToken: Optional[ClientRequestTokenType] - RotationLambdaARN: Optional[RotationLambdaARNType] - RotationRules: Optional[RotationRulesType] - RotateImmediately: Optional[BooleanType] + ClientRequestToken: ClientRequestTokenType | None + RotationLambdaARN: RotationLambdaARNType | None + RotationRules: RotationRulesType | None + ExternalSecretRotationMetadata: ExternalSecretRotationMetadataType | None + ExternalSecretRotationRoleArn: RoleARNType | None + RotateImmediately: BooleanType | None class RotateSecretResponse(TypedDict, total=False): - ARN: Optional[SecretARNType] - Name: Optional[SecretNameType] - VersionId: Optional[SecretVersionIdType] + ARN: SecretARNType | None + Name: SecretNameType | None + VersionId: SecretVersionIdType | None class StopReplicationToReplicaRequest(ServiceRequest): @@ -500,10 +529,10 @@ class StopReplicationToReplicaRequest(ServiceRequest): class StopReplicationToReplicaResponse(TypedDict, total=False): - ARN: Optional[SecretARNType] + ARN: SecretARNType | None -TagKeyListType = List[TagKeyType] +TagKeyListType = list[TagKeyType] class TagResourceRequest(ServiceRequest): @@ -518,52 +547,53 @@ class UntagResourceRequest(ServiceRequest): class UpdateSecretRequest(ServiceRequest): SecretId: SecretIdType - ClientRequestToken: Optional[ClientRequestTokenType] - Description: Optional[DescriptionType] - KmsKeyId: Optional[KmsKeyIdType] - SecretBinary: Optional[SecretBinaryType] - SecretString: Optional[SecretStringType] + ClientRequestToken: ClientRequestTokenType | None + Description: DescriptionType | None + KmsKeyId: KmsKeyIdType | None + SecretBinary: SecretBinaryType | None + SecretString: SecretStringType | None + Type: MedeaTypeType | None class UpdateSecretResponse(TypedDict, total=False): - ARN: Optional[SecretARNType] - Name: Optional[SecretNameType] - VersionId: Optional[SecretVersionIdType] + ARN: SecretARNType | None + Name: SecretNameType | None + VersionId: SecretVersionIdType | None class UpdateSecretVersionStageRequest(ServiceRequest): SecretId: SecretIdType VersionStage: SecretVersionStageType - RemoveFromVersionId: Optional[SecretVersionIdType] - MoveToVersionId: Optional[SecretVersionIdType] + RemoveFromVersionId: SecretVersionIdType | None + MoveToVersionId: SecretVersionIdType | None class UpdateSecretVersionStageResponse(TypedDict, total=False): - ARN: Optional[SecretARNType] - Name: Optional[SecretNameType] + ARN: SecretARNType | None + Name: SecretNameType | None class ValidateResourcePolicyRequest(ServiceRequest): - SecretId: Optional[SecretIdType] + SecretId: SecretIdType | None ResourcePolicy: NonEmptyResourcePolicyType class ValidationErrorsEntry(TypedDict, total=False): - CheckName: Optional[NameType] - ErrorMessage: Optional[ErrorMessage] + CheckName: NameType | None + ErrorMessage: ErrorMessage | None -ValidationErrorsType = List[ValidationErrorsEntry] +ValidationErrorsType = list[ValidationErrorsEntry] class ValidateResourcePolicyResponse(TypedDict, total=False): - PolicyValidationPassed: Optional[BooleanType] - ValidationErrors: Optional[ValidationErrorsType] + PolicyValidationPassed: BooleanType | None + ValidationErrors: ValidationErrorsType | None class SecretsmanagerApi: - service = "secretsmanager" - version = "2017-10-17" + service: str = "secretsmanager" + version: str = "2017-10-17" @handler("BatchGetSecretValue") def batch_get_secret_value( @@ -583,20 +613,9 @@ def cancel_rotate_secret( ) -> CancelRotateSecretResponse: raise NotImplementedError - @handler("CreateSecret") + @handler("CreateSecret", expand=False) def create_secret( - self, - context: RequestContext, - name: NameType, - client_request_token: ClientRequestTokenType | None = None, - description: DescriptionType | None = None, - kms_key_id: KmsKeyIdType | None = None, - secret_binary: SecretBinaryType | None = None, - secret_string: SecretStringType | None = None, - tags: TagListType | None = None, - add_replica_regions: AddReplicaRegionListType | None = None, - force_overwrite_replica_secret: BooleanType | None = None, - **kwargs, + self, context: RequestContext, request: CreateSecretRequest, **kwargs ) -> CreateSecretResponse: raise NotImplementedError @@ -677,6 +696,7 @@ def list_secrets( next_token: NextTokenType | None = None, filters: FiltersListType | None = None, sort_order: SortOrderType | None = None, + sort_by: SortByType | None = None, **kwargs, ) -> ListSecretsResponse: raise NotImplementedError @@ -741,6 +761,8 @@ def rotate_secret( client_request_token: ClientRequestTokenType | None = None, rotation_lambda_arn: RotationLambdaARNType | None = None, rotation_rules: RotationRulesType | None = None, + external_secret_rotation_metadata: ExternalSecretRotationMetadataType | None = None, + external_secret_rotation_role_arn: RoleARNType | None = None, rotate_immediately: BooleanType | None = None, **kwargs, ) -> RotateSecretResponse: @@ -764,17 +786,9 @@ def untag_resource( ) -> None: raise NotImplementedError - @handler("UpdateSecret") + @handler("UpdateSecret", expand=False) def update_secret( - self, - context: RequestContext, - secret_id: SecretIdType, - client_request_token: ClientRequestTokenType | None = None, - description: DescriptionType | None = None, - kms_key_id: KmsKeyIdType | None = None, - secret_binary: SecretBinaryType | None = None, - secret_string: SecretStringType | None = None, - **kwargs, + self, context: RequestContext, request: UpdateSecretRequest, **kwargs ) -> UpdateSecretResponse: raise NotImplementedError diff --git a/localstack-core/localstack/aws/api/ses/__init__.py b/localstack-core/localstack/aws/api/ses/__init__.py index 26e3b38f45cf1..6c62e8045f15e 100644 --- a/localstack-core/localstack/aws/api/ses/__init__.py +++ b/localstack-core/localstack/aws/api/ses/__init__.py @@ -1,6 +1,6 @@ from datetime import datetime from enum import StrEnum -from typing import Dict, List, Optional, TypedDict +from typing import TypedDict from localstack.aws.api import RequestContext, ServiceException, ServiceRequest, handler @@ -189,35 +189,35 @@ class AlreadyExistsException(ServiceException): code: str = "AlreadyExists" sender_fault: bool = True status_code: int = 400 - Name: Optional[RuleOrRuleSetName] + Name: RuleOrRuleSetName | None class CannotDeleteException(ServiceException): code: str = "CannotDelete" sender_fault: bool = True status_code: int = 400 - Name: Optional[RuleOrRuleSetName] + Name: RuleOrRuleSetName | None class ConfigurationSetAlreadyExistsException(ServiceException): code: str = "ConfigurationSetAlreadyExists" sender_fault: bool = True status_code: int = 400 - ConfigurationSetName: Optional[ConfigurationSetName] + ConfigurationSetName: ConfigurationSetName | None class ConfigurationSetDoesNotExistException(ServiceException): code: str = "ConfigurationSetDoesNotExist" sender_fault: bool = True status_code: int = 400 - ConfigurationSetName: Optional[ConfigurationSetName] + ConfigurationSetName: ConfigurationSetName | None class ConfigurationSetSendingPausedException(ServiceException): code: str = "ConfigurationSetSendingPausedException" sender_fault: bool = True status_code: int = 400 - ConfigurationSetName: Optional[ConfigurationSetName] + ConfigurationSetName: ConfigurationSetName | None class CustomVerificationEmailInvalidContentException(ServiceException): @@ -230,45 +230,45 @@ class CustomVerificationEmailTemplateAlreadyExistsException(ServiceException): code: str = "CustomVerificationEmailTemplateAlreadyExists" sender_fault: bool = True status_code: int = 400 - CustomVerificationEmailTemplateName: Optional[TemplateName] + CustomVerificationEmailTemplateName: TemplateName | None class CustomVerificationEmailTemplateDoesNotExistException(ServiceException): code: str = "CustomVerificationEmailTemplateDoesNotExist" sender_fault: bool = True status_code: int = 400 - CustomVerificationEmailTemplateName: Optional[TemplateName] + CustomVerificationEmailTemplateName: TemplateName | None class EventDestinationAlreadyExistsException(ServiceException): code: str = "EventDestinationAlreadyExists" sender_fault: bool = True status_code: int = 400 - ConfigurationSetName: Optional[ConfigurationSetName] - EventDestinationName: Optional[EventDestinationName] + ConfigurationSetName: ConfigurationSetName | None + EventDestinationName: EventDestinationName | None class EventDestinationDoesNotExistException(ServiceException): code: str = "EventDestinationDoesNotExist" sender_fault: bool = True status_code: int = 400 - ConfigurationSetName: Optional[ConfigurationSetName] - EventDestinationName: Optional[EventDestinationName] + ConfigurationSetName: ConfigurationSetName | None + EventDestinationName: EventDestinationName | None class FromEmailAddressNotVerifiedException(ServiceException): code: str = "FromEmailAddressNotVerified" sender_fault: bool = True status_code: int = 400 - FromEmailAddress: Optional[FromAddress] + FromEmailAddress: FromAddress | None class InvalidCloudWatchDestinationException(ServiceException): code: str = "InvalidCloudWatchDestination" sender_fault: bool = True status_code: int = 400 - ConfigurationSetName: Optional[ConfigurationSetName] - EventDestinationName: Optional[EventDestinationName] + ConfigurationSetName: ConfigurationSetName | None + EventDestinationName: EventDestinationName | None class InvalidConfigurationSetException(ServiceException): @@ -287,15 +287,15 @@ class InvalidFirehoseDestinationException(ServiceException): code: str = "InvalidFirehoseDestination" sender_fault: bool = True status_code: int = 400 - ConfigurationSetName: Optional[ConfigurationSetName] - EventDestinationName: Optional[EventDestinationName] + ConfigurationSetName: ConfigurationSetName | None + EventDestinationName: EventDestinationName | None class InvalidLambdaFunctionException(ServiceException): code: str = "InvalidLambdaFunction" sender_fault: bool = True status_code: int = 400 - FunctionArn: Optional[AmazonResourceName] + FunctionArn: AmazonResourceName | None class InvalidPolicyException(ServiceException): @@ -308,36 +308,36 @@ class InvalidRenderingParameterException(ServiceException): code: str = "InvalidRenderingParameter" sender_fault: bool = True status_code: int = 400 - TemplateName: Optional[TemplateName] + TemplateName: TemplateName | None class InvalidS3ConfigurationException(ServiceException): code: str = "InvalidS3Configuration" sender_fault: bool = True status_code: int = 400 - Bucket: Optional[S3BucketName] + Bucket: S3BucketName | None class InvalidSNSDestinationException(ServiceException): code: str = "InvalidSNSDestination" sender_fault: bool = True status_code: int = 400 - ConfigurationSetName: Optional[ConfigurationSetName] - EventDestinationName: Optional[EventDestinationName] + ConfigurationSetName: ConfigurationSetName | None + EventDestinationName: EventDestinationName | None class InvalidSnsTopicException(ServiceException): code: str = "InvalidSnsTopic" sender_fault: bool = True status_code: int = 400 - Topic: Optional[AmazonResourceName] + Topic: AmazonResourceName | None class InvalidTemplateException(ServiceException): code: str = "InvalidTemplate" sender_fault: bool = True status_code: int = 400 - TemplateName: Optional[TemplateName] + TemplateName: TemplateName | None class InvalidTrackingOptionsException(ServiceException): @@ -368,7 +368,7 @@ class MissingRenderingAttributeException(ServiceException): code: str = "MissingRenderingAttribute" sender_fault: bool = True status_code: int = 400 - TemplateName: Optional[TemplateName] + TemplateName: TemplateName | None class ProductionAccessNotGrantedException(ServiceException): @@ -381,35 +381,35 @@ class RuleDoesNotExistException(ServiceException): code: str = "RuleDoesNotExist" sender_fault: bool = True status_code: int = 400 - Name: Optional[RuleOrRuleSetName] + Name: RuleOrRuleSetName | None class RuleSetDoesNotExistException(ServiceException): code: str = "RuleSetDoesNotExist" sender_fault: bool = True status_code: int = 400 - Name: Optional[RuleOrRuleSetName] + Name: RuleOrRuleSetName | None class TemplateDoesNotExistException(ServiceException): code: str = "TemplateDoesNotExist" sender_fault: bool = True status_code: int = 400 - TemplateName: Optional[TemplateName] + TemplateName: TemplateName | None class TrackingOptionsAlreadyExistsException(ServiceException): code: str = "TrackingOptionsAlreadyExistsException" sender_fault: bool = True status_code: int = 400 - ConfigurationSetName: Optional[ConfigurationSetName] + ConfigurationSetName: ConfigurationSetName | None class TrackingOptionsDoesNotExistException(ServiceException): code: str = "TrackingOptionsDoesNotExistException" sender_fault: bool = True status_code: int = 400 - ConfigurationSetName: Optional[ConfigurationSetName] + ConfigurationSetName: ConfigurationSetName | None class AddHeaderAction(TypedDict, total=False): @@ -417,24 +417,24 @@ class AddHeaderAction(TypedDict, total=False): HeaderValue: HeaderValue -AddressList = List[Address] +AddressList = list[Address] ArrivalDate = datetime class Content(TypedDict, total=False): Data: MessageData - Charset: Optional[Charset] + Charset: Charset | None class Body(TypedDict, total=False): - Text: Optional[Content] - Html: Optional[Content] + Text: Content | None + Html: Content | None class BounceAction(TypedDict, total=False): - TopicArn: Optional[AmazonResourceName] + TopicArn: AmazonResourceName | None SmtpReplyCode: BounceSmtpReplyCode - StatusCode: Optional[BounceStatusCode] + StatusCode: BounceStatusCode | None Message: BounceMessage Sender: Address @@ -444,28 +444,28 @@ class ExtensionField(TypedDict, total=False): Value: ExtensionFieldValue -ExtensionFieldList = List[ExtensionField] +ExtensionFieldList = list[ExtensionField] LastAttemptDate = datetime class RecipientDsnFields(TypedDict, total=False): - FinalRecipient: Optional[Address] + FinalRecipient: Address | None Action: DsnAction - RemoteMta: Optional[RemoteMta] + RemoteMta: RemoteMta | None Status: DsnStatus - DiagnosticCode: Optional[DiagnosticCode] - LastAttemptDate: Optional[LastAttemptDate] - ExtensionFields: Optional[ExtensionFieldList] + DiagnosticCode: DiagnosticCode | None + LastAttemptDate: LastAttemptDate | None + ExtensionFields: ExtensionFieldList | None class BouncedRecipientInfo(TypedDict, total=False): Recipient: Address - RecipientArn: Optional[AmazonResourceName] - BounceType: Optional[BounceType] - RecipientDsnFields: Optional[RecipientDsnFields] + RecipientArn: AmazonResourceName | None + BounceType: BounceType | None + RecipientDsnFields: RecipientDsnFields | None -BouncedRecipientInfoList = List[BouncedRecipientInfo] +BouncedRecipientInfoList = list[BouncedRecipientInfo] class MessageTag(TypedDict, total=False): @@ -473,31 +473,31 @@ class MessageTag(TypedDict, total=False): Value: MessageTagValue -MessageTagList = List[MessageTag] +MessageTagList = list[MessageTag] class Destination(TypedDict, total=False): - ToAddresses: Optional[AddressList] - CcAddresses: Optional[AddressList] - BccAddresses: Optional[AddressList] + ToAddresses: AddressList | None + CcAddresses: AddressList | None + BccAddresses: AddressList | None class BulkEmailDestination(TypedDict, total=False): Destination: Destination - ReplacementTags: Optional[MessageTagList] - ReplacementTemplateData: Optional[TemplateData] + ReplacementTags: MessageTagList | None + ReplacementTemplateData: TemplateData | None -BulkEmailDestinationList = List[BulkEmailDestination] +BulkEmailDestinationList = list[BulkEmailDestination] class BulkEmailDestinationStatus(TypedDict, total=False): - Status: Optional[BulkEmailStatus] - Error: Optional[Error] - MessageId: Optional[MessageId] + Status: BulkEmailStatus | None + Error: Error | None + MessageId: MessageId | None -BulkEmailDestinationStatusList = List[BulkEmailDestinationStatus] +BulkEmailDestinationStatusList = list[BulkEmailDestinationStatus] class CloneReceiptRuleSetRequest(ServiceRequest): @@ -515,7 +515,7 @@ class CloudWatchDimensionConfiguration(TypedDict, total=False): DefaultDimensionValue: DefaultDimensionValue -CloudWatchDimensionConfigurations = List[CloudWatchDimensionConfiguration] +CloudWatchDimensionConfigurations = list[CloudWatchDimensionConfiguration] class CloudWatchDestination(TypedDict, total=False): @@ -526,8 +526,8 @@ class ConfigurationSet(TypedDict, total=False): Name: ConfigurationSetName -ConfigurationSetAttributeList = List[ConfigurationSetAttribute] -ConfigurationSets = List[ConfigurationSet] +ConfigurationSetAttributeList = list[ConfigurationSetAttribute] +ConfigurationSets = list[ConfigurationSet] class ConnectAction(TypedDict, total=False): @@ -547,16 +547,16 @@ class KinesisFirehoseDestination(TypedDict, total=False): DeliveryStreamARN: AmazonResourceName -EventTypes = List[EventType] +EventTypes = list[EventType] class EventDestination(TypedDict, total=False): Name: EventDestinationName - Enabled: Optional[Enabled] + Enabled: Enabled | None MatchingEventTypes: EventTypes - KinesisFirehoseDestination: Optional[KinesisFirehoseDestination] - CloudWatchDestination: Optional[CloudWatchDestination] - SNSDestination: Optional[SNSDestination] + KinesisFirehoseDestination: KinesisFirehoseDestination | None + CloudWatchDestination: CloudWatchDestination | None + SNSDestination: SNSDestination | None class CreateConfigurationSetEventDestinationRequest(ServiceRequest): @@ -577,7 +577,7 @@ class CreateConfigurationSetResponse(TypedDict, total=False): class TrackingOptions(TypedDict, total=False): - CustomRedirectDomain: Optional[CustomRedirectDomain] + CustomRedirectDomain: CustomRedirectDomain | None class CreateConfigurationSetTrackingOptionsRequest(ServiceRequest): @@ -618,60 +618,60 @@ class CreateReceiptFilterResponse(TypedDict, total=False): class SNSAction(TypedDict, total=False): TopicArn: AmazonResourceName - Encoding: Optional[SNSActionEncoding] + Encoding: SNSActionEncoding | None class StopAction(TypedDict, total=False): Scope: StopScope - TopicArn: Optional[AmazonResourceName] + TopicArn: AmazonResourceName | None class LambdaAction(TypedDict, total=False): - TopicArn: Optional[AmazonResourceName] + TopicArn: AmazonResourceName | None FunctionArn: AmazonResourceName - InvocationType: Optional[InvocationType] + InvocationType: InvocationType | None class WorkmailAction(TypedDict, total=False): - TopicArn: Optional[AmazonResourceName] + TopicArn: AmazonResourceName | None OrganizationArn: AmazonResourceName class S3Action(TypedDict, total=False): - TopicArn: Optional[AmazonResourceName] + TopicArn: AmazonResourceName | None BucketName: S3BucketName - ObjectKeyPrefix: Optional[S3KeyPrefix] - KmsKeyArn: Optional[AmazonResourceName] - IamRoleArn: Optional[IAMRoleARN] + ObjectKeyPrefix: S3KeyPrefix | None + KmsKeyArn: AmazonResourceName | None + IamRoleArn: IAMRoleARN | None class ReceiptAction(TypedDict, total=False): - S3Action: Optional[S3Action] - BounceAction: Optional[BounceAction] - WorkmailAction: Optional[WorkmailAction] - LambdaAction: Optional[LambdaAction] - StopAction: Optional[StopAction] - AddHeaderAction: Optional[AddHeaderAction] - SNSAction: Optional[SNSAction] - ConnectAction: Optional[ConnectAction] + S3Action: S3Action | None + BounceAction: BounceAction | None + WorkmailAction: WorkmailAction | None + LambdaAction: LambdaAction | None + StopAction: StopAction | None + AddHeaderAction: AddHeaderAction | None + SNSAction: SNSAction | None + ConnectAction: ConnectAction | None -ReceiptActionsList = List[ReceiptAction] -RecipientsList = List[Recipient] +ReceiptActionsList = list[ReceiptAction] +RecipientsList = list[Recipient] class ReceiptRule(TypedDict, total=False): Name: ReceiptRuleName - Enabled: Optional[Enabled] - TlsPolicy: Optional[TlsPolicy] - Recipients: Optional[RecipientsList] - Actions: Optional[ReceiptActionsList] - ScanEnabled: Optional[Enabled] + Enabled: Enabled | None + TlsPolicy: TlsPolicy | None + Recipients: RecipientsList | None + Actions: ReceiptActionsList | None + ScanEnabled: Enabled | None class CreateReceiptRuleRequest(ServiceRequest): RuleSetName: ReceiptRuleSetName - After: Optional[ReceiptRuleName] + After: ReceiptRuleName | None Rule: ReceiptRule @@ -689,9 +689,9 @@ class CreateReceiptRuleSetResponse(TypedDict, total=False): class Template(TypedDict, total=False): TemplateName: TemplateName - SubjectPart: Optional[SubjectPart] - TextPart: Optional[TextPart] - HtmlPart: Optional[HtmlPart] + SubjectPart: SubjectPart | None + TextPart: TextPart | None + HtmlPart: HtmlPart | None class CreateTemplateRequest(ServiceRequest): @@ -703,14 +703,14 @@ class CreateTemplateResponse(TypedDict, total=False): class CustomVerificationEmailTemplate(TypedDict, total=False): - TemplateName: Optional[TemplateName] - FromEmailAddress: Optional[FromAddress] - TemplateSubject: Optional[Subject] - SuccessRedirectionURL: Optional[SuccessRedirectionURL] - FailureRedirectionURL: Optional[FailureRedirectionURL] + TemplateName: TemplateName | None + FromEmailAddress: FromAddress | None + TemplateSubject: Subject | None + SuccessRedirectionURL: SuccessRedirectionURL | None + FailureRedirectionURL: FailureRedirectionURL | None -CustomVerificationEmailTemplates = List[CustomVerificationEmailTemplate] +CustomVerificationEmailTemplates = list[CustomVerificationEmailTemplate] class DeleteConfigurationSetEventDestinationRequest(ServiceRequest): @@ -797,50 +797,50 @@ class DeleteVerifiedEmailAddressRequest(ServiceRequest): class DeliveryOptions(TypedDict, total=False): - TlsPolicy: Optional[TlsPolicy] + TlsPolicy: TlsPolicy | None class DescribeActiveReceiptRuleSetRequest(ServiceRequest): pass -ReceiptRulesList = List[ReceiptRule] +ReceiptRulesList = list[ReceiptRule] Timestamp = datetime class ReceiptRuleSetMetadata(TypedDict, total=False): - Name: Optional[ReceiptRuleSetName] - CreatedTimestamp: Optional[Timestamp] + Name: ReceiptRuleSetName | None + CreatedTimestamp: Timestamp | None class DescribeActiveReceiptRuleSetResponse(TypedDict, total=False): - Metadata: Optional[ReceiptRuleSetMetadata] - Rules: Optional[ReceiptRulesList] + Metadata: ReceiptRuleSetMetadata | None + Rules: ReceiptRulesList | None class DescribeConfigurationSetRequest(ServiceRequest): ConfigurationSetName: ConfigurationSetName - ConfigurationSetAttributeNames: Optional[ConfigurationSetAttributeList] + ConfigurationSetAttributeNames: ConfigurationSetAttributeList | None LastFreshStart = datetime class ReputationOptions(TypedDict, total=False): - SendingEnabled: Optional[Enabled] - ReputationMetricsEnabled: Optional[Enabled] - LastFreshStart: Optional[LastFreshStart] + SendingEnabled: Enabled | None + ReputationMetricsEnabled: Enabled | None + LastFreshStart: LastFreshStart | None -EventDestinations = List[EventDestination] +EventDestinations = list[EventDestination] class DescribeConfigurationSetResponse(TypedDict, total=False): - ConfigurationSet: Optional[ConfigurationSet] - EventDestinations: Optional[EventDestinations] - TrackingOptions: Optional[TrackingOptions] - DeliveryOptions: Optional[DeliveryOptions] - ReputationOptions: Optional[ReputationOptions] + ConfigurationSet: ConfigurationSet | None + EventDestinations: EventDestinations | None + TrackingOptions: TrackingOptions | None + DeliveryOptions: DeliveryOptions | None + ReputationOptions: ReputationOptions | None class DescribeReceiptRuleRequest(ServiceRequest): @@ -849,7 +849,7 @@ class DescribeReceiptRuleRequest(ServiceRequest): class DescribeReceiptRuleResponse(TypedDict, total=False): - Rule: Optional[ReceiptRule] + Rule: ReceiptRule | None class DescribeReceiptRuleSetRequest(ServiceRequest): @@ -857,24 +857,24 @@ class DescribeReceiptRuleSetRequest(ServiceRequest): class DescribeReceiptRuleSetResponse(TypedDict, total=False): - Metadata: Optional[ReceiptRuleSetMetadata] - Rules: Optional[ReceiptRulesList] + Metadata: ReceiptRuleSetMetadata | None + Rules: ReceiptRulesList | None -VerificationTokenList = List[VerificationToken] +VerificationTokenList = list[VerificationToken] class IdentityDkimAttributes(TypedDict, total=False): DkimEnabled: Enabled DkimVerificationStatus: VerificationStatus - DkimTokens: Optional[VerificationTokenList] + DkimTokens: VerificationTokenList | None -DkimAttributes = Dict[Identity, IdentityDkimAttributes] +DkimAttributes = dict[Identity, IdentityDkimAttributes] class GetAccountSendingEnabledResponse(TypedDict, total=False): - Enabled: Optional[Enabled] + Enabled: Enabled | None class GetCustomVerificationEmailTemplateRequest(ServiceRequest): @@ -882,15 +882,15 @@ class GetCustomVerificationEmailTemplateRequest(ServiceRequest): class GetCustomVerificationEmailTemplateResponse(TypedDict, total=False): - TemplateName: Optional[TemplateName] - FromEmailAddress: Optional[FromAddress] - TemplateSubject: Optional[Subject] - TemplateContent: Optional[TemplateContent] - SuccessRedirectionURL: Optional[SuccessRedirectionURL] - FailureRedirectionURL: Optional[FailureRedirectionURL] + TemplateName: TemplateName | None + FromEmailAddress: FromAddress | None + TemplateSubject: Subject | None + TemplateContent: TemplateContent | None + SuccessRedirectionURL: SuccessRedirectionURL | None + FailureRedirectionURL: FailureRedirectionURL | None -IdentityList = List[Identity] +IdentityList = list[Identity] class GetIdentityDkimAttributesRequest(ServiceRequest): @@ -911,7 +911,7 @@ class IdentityMailFromDomainAttributes(TypedDict, total=False): BehaviorOnMXFailure: BehaviorOnMXFailure -MailFromDomainAttributes = Dict[Identity, IdentityMailFromDomainAttributes] +MailFromDomainAttributes = dict[Identity, IdentityMailFromDomainAttributes] class GetIdentityMailFromDomainAttributesResponse(TypedDict, total=False): @@ -927,19 +927,19 @@ class IdentityNotificationAttributes(TypedDict, total=False): ComplaintTopic: NotificationTopic DeliveryTopic: NotificationTopic ForwardingEnabled: Enabled - HeadersInBounceNotificationsEnabled: Optional[Enabled] - HeadersInComplaintNotificationsEnabled: Optional[Enabled] - HeadersInDeliveryNotificationsEnabled: Optional[Enabled] + HeadersInBounceNotificationsEnabled: Enabled | None + HeadersInComplaintNotificationsEnabled: Enabled | None + HeadersInDeliveryNotificationsEnabled: Enabled | None -NotificationAttributes = Dict[Identity, IdentityNotificationAttributes] +NotificationAttributes = dict[Identity, IdentityNotificationAttributes] class GetIdentityNotificationAttributesResponse(TypedDict, total=False): NotificationAttributes: NotificationAttributes -PolicyNameList = List[PolicyName] +PolicyNameList = list[PolicyName] class GetIdentityPoliciesRequest(ServiceRequest): @@ -947,7 +947,7 @@ class GetIdentityPoliciesRequest(ServiceRequest): PolicyNames: PolicyNameList -PolicyMap = Dict[PolicyName, Policy] +PolicyMap = dict[PolicyName, Policy] class GetIdentityPoliciesResponse(TypedDict, total=False): @@ -960,10 +960,10 @@ class GetIdentityVerificationAttributesRequest(ServiceRequest): class IdentityVerificationAttributes(TypedDict, total=False): VerificationStatus: VerificationStatus - VerificationToken: Optional[VerificationToken] + VerificationToken: VerificationToken | None -VerificationAttributes = Dict[Identity, IdentityVerificationAttributes] +VerificationAttributes = dict[Identity, IdentityVerificationAttributes] class GetIdentityVerificationAttributesResponse(TypedDict, total=False): @@ -971,24 +971,24 @@ class GetIdentityVerificationAttributesResponse(TypedDict, total=False): class GetSendQuotaResponse(TypedDict, total=False): - Max24HourSend: Optional[Max24HourSend] - MaxSendRate: Optional[MaxSendRate] - SentLast24Hours: Optional[SentLast24Hours] + Max24HourSend: Max24HourSend | None + MaxSendRate: MaxSendRate | None + SentLast24Hours: SentLast24Hours | None class SendDataPoint(TypedDict, total=False): - Timestamp: Optional[Timestamp] - DeliveryAttempts: Optional[Counter] - Bounces: Optional[Counter] - Complaints: Optional[Counter] - Rejects: Optional[Counter] + Timestamp: Timestamp | None + DeliveryAttempts: Counter | None + Bounces: Counter | None + Complaints: Counter | None + Rejects: Counter | None -SendDataPointList = List[SendDataPoint] +SendDataPointList = list[SendDataPoint] class GetSendStatisticsResponse(TypedDict, total=False): - SendDataPoints: Optional[SendDataPointList] + SendDataPoints: SendDataPointList | None class GetTemplateRequest(ServiceRequest): @@ -996,38 +996,38 @@ class GetTemplateRequest(ServiceRequest): class GetTemplateResponse(TypedDict, total=False): - Template: Optional[Template] + Template: Template | None class ListConfigurationSetsRequest(ServiceRequest): - NextToken: Optional[NextToken] - MaxItems: Optional[MaxItems] + NextToken: NextToken | None + MaxItems: MaxItems | None class ListConfigurationSetsResponse(TypedDict, total=False): - ConfigurationSets: Optional[ConfigurationSets] - NextToken: Optional[NextToken] + ConfigurationSets: ConfigurationSets | None + NextToken: NextToken | None class ListCustomVerificationEmailTemplatesRequest(ServiceRequest): - NextToken: Optional[NextToken] - MaxResults: Optional[MaxResults] + NextToken: NextToken | None + MaxResults: MaxResults | None class ListCustomVerificationEmailTemplatesResponse(TypedDict, total=False): - CustomVerificationEmailTemplates: Optional[CustomVerificationEmailTemplates] - NextToken: Optional[NextToken] + CustomVerificationEmailTemplates: CustomVerificationEmailTemplates | None + NextToken: NextToken | None class ListIdentitiesRequest(ServiceRequest): - IdentityType: Optional[IdentityType] - NextToken: Optional[NextToken] - MaxItems: Optional[MaxItems] + IdentityType: IdentityType | None + NextToken: NextToken | None + MaxItems: MaxItems | None class ListIdentitiesResponse(TypedDict, total=False): Identities: IdentityList - NextToken: Optional[NextToken] + NextToken: NextToken | None class ListIdentityPoliciesRequest(ServiceRequest): @@ -1042,45 +1042,45 @@ class ListReceiptFiltersRequest(ServiceRequest): pass -ReceiptFilterList = List[ReceiptFilter] +ReceiptFilterList = list[ReceiptFilter] class ListReceiptFiltersResponse(TypedDict, total=False): - Filters: Optional[ReceiptFilterList] + Filters: ReceiptFilterList | None class ListReceiptRuleSetsRequest(ServiceRequest): - NextToken: Optional[NextToken] + NextToken: NextToken | None -ReceiptRuleSetsLists = List[ReceiptRuleSetMetadata] +ReceiptRuleSetsLists = list[ReceiptRuleSetMetadata] class ListReceiptRuleSetsResponse(TypedDict, total=False): - RuleSets: Optional[ReceiptRuleSetsLists] - NextToken: Optional[NextToken] + RuleSets: ReceiptRuleSetsLists | None + NextToken: NextToken | None class ListTemplatesRequest(ServiceRequest): - NextToken: Optional[NextToken] - MaxItems: Optional[MaxItems] + NextToken: NextToken | None + MaxItems: MaxItems | None class TemplateMetadata(TypedDict, total=False): - Name: Optional[TemplateName] - CreatedTimestamp: Optional[Timestamp] + Name: TemplateName | None + CreatedTimestamp: Timestamp | None -TemplateMetadataList = List[TemplateMetadata] +TemplateMetadataList = list[TemplateMetadata] class ListTemplatesResponse(TypedDict, total=False): - TemplatesMetadata: Optional[TemplateMetadataList] - NextToken: Optional[NextToken] + TemplatesMetadata: TemplateMetadataList | None + NextToken: NextToken | None class ListVerifiedEmailAddressesResponse(TypedDict, total=False): - VerifiedEmailAddresses: Optional[AddressList] + VerifiedEmailAddresses: AddressList | None class Message(TypedDict, total=False): @@ -1090,13 +1090,13 @@ class Message(TypedDict, total=False): class MessageDsn(TypedDict, total=False): ReportingMta: ReportingMta - ArrivalDate: Optional[ArrivalDate] - ExtensionFields: Optional[ExtensionFieldList] + ArrivalDate: ArrivalDate | None + ExtensionFields: ExtensionFieldList | None class PutConfigurationSetDeliveryOptionsRequest(ServiceRequest): ConfigurationSetName: ConfigurationSetName - DeliveryOptions: Optional[DeliveryOptions] + DeliveryOptions: DeliveryOptions | None class PutConfigurationSetDeliveryOptionsResponse(TypedDict, total=False): @@ -1120,7 +1120,7 @@ class RawMessage(TypedDict, total=False): Data: RawMessageData -ReceiptRuleNamesList = List[ReceiptRuleName] +ReceiptRuleNamesList = list[ReceiptRuleName] class ReorderReceiptRuleSetRequest(ServiceRequest): @@ -1135,26 +1135,26 @@ class ReorderReceiptRuleSetResponse(TypedDict, total=False): class SendBounceRequest(ServiceRequest): OriginalMessageId: MessageId BounceSender: Address - Explanation: Optional[Explanation] - MessageDsn: Optional[MessageDsn] + Explanation: Explanation | None + MessageDsn: MessageDsn | None BouncedRecipientInfoList: BouncedRecipientInfoList - BounceSenderArn: Optional[AmazonResourceName] + BounceSenderArn: AmazonResourceName | None class SendBounceResponse(TypedDict, total=False): - MessageId: Optional[MessageId] + MessageId: MessageId | None class SendBulkTemplatedEmailRequest(ServiceRequest): Source: Address - SourceArn: Optional[AmazonResourceName] - ReplyToAddresses: Optional[AddressList] - ReturnPath: Optional[Address] - ReturnPathArn: Optional[AmazonResourceName] - ConfigurationSetName: Optional[ConfigurationSetName] - DefaultTags: Optional[MessageTagList] + SourceArn: AmazonResourceName | None + ReplyToAddresses: AddressList | None + ReturnPath: Address | None + ReturnPathArn: AmazonResourceName | None + ConfigurationSetName: ConfigurationSetName | None + DefaultTags: MessageTagList | None Template: TemplateName - TemplateArn: Optional[AmazonResourceName] + TemplateArn: AmazonResourceName | None DefaultTemplateData: TemplateData Destinations: BulkEmailDestinationList @@ -1166,23 +1166,23 @@ class SendBulkTemplatedEmailResponse(TypedDict, total=False): class SendCustomVerificationEmailRequest(ServiceRequest): EmailAddress: Address TemplateName: TemplateName - ConfigurationSetName: Optional[ConfigurationSetName] + ConfigurationSetName: ConfigurationSetName | None class SendCustomVerificationEmailResponse(TypedDict, total=False): - MessageId: Optional[MessageId] + MessageId: MessageId | None class SendEmailRequest(ServiceRequest): Source: Address Destination: Destination Message: Message - ReplyToAddresses: Optional[AddressList] - ReturnPath: Optional[Address] - SourceArn: Optional[AmazonResourceName] - ReturnPathArn: Optional[AmazonResourceName] - Tags: Optional[MessageTagList] - ConfigurationSetName: Optional[ConfigurationSetName] + ReplyToAddresses: AddressList | None + ReturnPath: Address | None + SourceArn: AmazonResourceName | None + ReturnPathArn: AmazonResourceName | None + Tags: MessageTagList | None + ConfigurationSetName: ConfigurationSetName | None class SendEmailResponse(TypedDict, total=False): @@ -1190,14 +1190,14 @@ class SendEmailResponse(TypedDict, total=False): class SendRawEmailRequest(ServiceRequest): - Source: Optional[Address] - Destinations: Optional[AddressList] + Source: Address | None + Destinations: AddressList | None RawMessage: RawMessage - FromArn: Optional[AmazonResourceName] - SourceArn: Optional[AmazonResourceName] - ReturnPathArn: Optional[AmazonResourceName] - Tags: Optional[MessageTagList] - ConfigurationSetName: Optional[ConfigurationSetName] + FromArn: AmazonResourceName | None + SourceArn: AmazonResourceName | None + ReturnPathArn: AmazonResourceName | None + Tags: MessageTagList | None + ConfigurationSetName: ConfigurationSetName | None class SendRawEmailResponse(TypedDict, total=False): @@ -1207,14 +1207,14 @@ class SendRawEmailResponse(TypedDict, total=False): class SendTemplatedEmailRequest(ServiceRequest): Source: Address Destination: Destination - ReplyToAddresses: Optional[AddressList] - ReturnPath: Optional[Address] - SourceArn: Optional[AmazonResourceName] - ReturnPathArn: Optional[AmazonResourceName] - Tags: Optional[MessageTagList] - ConfigurationSetName: Optional[ConfigurationSetName] + ReplyToAddresses: AddressList | None + ReturnPath: Address | None + SourceArn: AmazonResourceName | None + ReturnPathArn: AmazonResourceName | None + Tags: MessageTagList | None + ConfigurationSetName: ConfigurationSetName | None Template: TemplateName - TemplateArn: Optional[AmazonResourceName] + TemplateArn: AmazonResourceName | None TemplateData: TemplateData @@ -1223,7 +1223,7 @@ class SendTemplatedEmailResponse(TypedDict, total=False): class SetActiveReceiptRuleSetRequest(ServiceRequest): - RuleSetName: Optional[ReceiptRuleSetName] + RuleSetName: ReceiptRuleSetName | None class SetActiveReceiptRuleSetResponse(TypedDict, total=False): @@ -1260,8 +1260,8 @@ class SetIdentityHeadersInNotificationsEnabledResponse(TypedDict, total=False): class SetIdentityMailFromDomainRequest(ServiceRequest): Identity: Identity - MailFromDomain: Optional[MailFromDomainName] - BehaviorOnMXFailure: Optional[BehaviorOnMXFailure] + MailFromDomain: MailFromDomainName | None + BehaviorOnMXFailure: BehaviorOnMXFailure | None class SetIdentityMailFromDomainResponse(TypedDict, total=False): @@ -1271,7 +1271,7 @@ class SetIdentityMailFromDomainResponse(TypedDict, total=False): class SetIdentityNotificationTopicRequest(ServiceRequest): Identity: Identity NotificationType: NotificationType - SnsTopic: Optional[NotificationTopic] + SnsTopic: NotificationTopic | None class SetIdentityNotificationTopicResponse(TypedDict, total=False): @@ -1281,7 +1281,7 @@ class SetIdentityNotificationTopicResponse(TypedDict, total=False): class SetReceiptRulePositionRequest(ServiceRequest): RuleSetName: ReceiptRuleSetName RuleName: ReceiptRuleName - After: Optional[ReceiptRuleName] + After: ReceiptRuleName | None class SetReceiptRulePositionResponse(TypedDict, total=False): @@ -1294,11 +1294,11 @@ class TestRenderTemplateRequest(ServiceRequest): class TestRenderTemplateResponse(TypedDict, total=False): - RenderedTemplate: Optional[RenderedTemplate] + RenderedTemplate: RenderedTemplate | None class UpdateAccountSendingEnabledRequest(ServiceRequest): - Enabled: Optional[Enabled] + Enabled: Enabled | None class UpdateConfigurationSetEventDestinationRequest(ServiceRequest): @@ -1331,11 +1331,11 @@ class UpdateConfigurationSetTrackingOptionsResponse(TypedDict, total=False): class UpdateCustomVerificationEmailTemplateRequest(ServiceRequest): TemplateName: TemplateName - FromEmailAddress: Optional[FromAddress] - TemplateSubject: Optional[Subject] - TemplateContent: Optional[TemplateContent] - SuccessRedirectionURL: Optional[SuccessRedirectionURL] - FailureRedirectionURL: Optional[FailureRedirectionURL] + FromEmailAddress: FromAddress | None + TemplateSubject: Subject | None + TemplateContent: TemplateContent | None + SuccessRedirectionURL: SuccessRedirectionURL | None + FailureRedirectionURL: FailureRedirectionURL | None class UpdateReceiptRuleRequest(ServiceRequest): @@ -1384,8 +1384,8 @@ class VerifyEmailIdentityResponse(TypedDict, total=False): class SesApi: - service = "ses" - version = "2010-12-01" + service: str = "ses" + version: str = "2010-12-01" @handler("CloneReceiptRuleSet") def clone_receipt_rule_set( diff --git a/localstack-core/localstack/aws/api/sns/__init__.py b/localstack-core/localstack/aws/api/sns/__init__.py index df5f5618138b5..d09e8f8259848 100644 --- a/localstack-core/localstack/aws/api/sns/__init__.py +++ b/localstack-core/localstack/aws/api/sns/__init__.py @@ -1,6 +1,6 @@ from datetime import datetime from enum import StrEnum -from typing import Dict, List, Optional, TypedDict +from typing import TypedDict from localstack.aws.api import RequestContext, ServiceException, ServiceRequest, handler @@ -274,8 +274,8 @@ class VerificationException(ServiceException): Status: string -ActionsList = List[action] -DelegatesList = List[delegate] +ActionsList = list[action] +DelegatesList = list[delegate] class AddPermissionInput(ServiceRequest): @@ -288,11 +288,11 @@ class AddPermissionInput(ServiceRequest): class BatchResultErrorEntry(TypedDict, total=False): Id: String Code: String - Message: Optional[String] + Message: String | None SenderFault: boolean -BatchResultErrorEntryList = List[BatchResultErrorEntry] +BatchResultErrorEntryList = list[BatchResultErrorEntry] Binary = bytes @@ -301,24 +301,24 @@ class CheckIfPhoneNumberIsOptedOutInput(ServiceRequest): class CheckIfPhoneNumberIsOptedOutResponse(TypedDict, total=False): - isOptedOut: Optional[boolean] + isOptedOut: boolean | None class ConfirmSubscriptionInput(ServiceRequest): TopicArn: topicARN Token: token - AuthenticateOnUnsubscribe: Optional[authenticateOnUnsubscribe] + AuthenticateOnUnsubscribe: authenticateOnUnsubscribe | None class ConfirmSubscriptionResponse(TypedDict, total=False): - SubscriptionArn: Optional[subscriptionARN] + SubscriptionArn: subscriptionARN | None class CreateEndpointResponse(TypedDict, total=False): - EndpointArn: Optional[String] + EndpointArn: String | None -MapStringToString = Dict[String, String] +MapStringToString = dict[String, String] class CreatePlatformApplicationInput(ServiceRequest): @@ -328,19 +328,19 @@ class CreatePlatformApplicationInput(ServiceRequest): class CreatePlatformApplicationResponse(TypedDict, total=False): - PlatformApplicationArn: Optional[String] + PlatformApplicationArn: String | None class CreatePlatformEndpointInput(ServiceRequest): PlatformApplicationArn: String Token: String - CustomUserData: Optional[String] - Attributes: Optional[MapStringToString] + CustomUserData: String | None + Attributes: MapStringToString | None class CreateSMSSandboxPhoneNumberInput(ServiceRequest): PhoneNumber: PhoneNumberString - LanguageCode: Optional[LanguageCodeString] + LanguageCode: LanguageCodeString | None class CreateSMSSandboxPhoneNumberResult(TypedDict, total=False): @@ -352,19 +352,19 @@ class Tag(TypedDict, total=False): Value: TagValue -TagList = List[Tag] -TopicAttributesMap = Dict[attributeName, attributeValue] +TagList = list[Tag] +TopicAttributesMap = dict[attributeName, attributeValue] class CreateTopicInput(ServiceRequest): Name: topicName - Attributes: Optional[TopicAttributesMap] - Tags: Optional[TagList] - DataProtectionPolicy: Optional[attributeValue] + Attributes: TopicAttributesMap | None + Tags: TagList | None + DataProtectionPolicy: attributeValue | None class CreateTopicResponse(TypedDict, total=False): - TopicArn: Optional[topicARN] + TopicArn: topicARN | None class DeleteEndpointInput(ServiceRequest): @@ -388,8 +388,8 @@ class DeleteTopicInput(ServiceRequest): class Endpoint(TypedDict, total=False): - EndpointArn: Optional[String] - Attributes: Optional[MapStringToString] + EndpointArn: String | None + Attributes: MapStringToString | None class GetDataProtectionPolicyInput(ServiceRequest): @@ -397,7 +397,7 @@ class GetDataProtectionPolicyInput(ServiceRequest): class GetDataProtectionPolicyResponse(TypedDict, total=False): - DataProtectionPolicy: Optional[attributeValue] + DataProtectionPolicy: attributeValue | None class GetEndpointAttributesInput(ServiceRequest): @@ -405,7 +405,7 @@ class GetEndpointAttributesInput(ServiceRequest): class GetEndpointAttributesResponse(TypedDict, total=False): - Attributes: Optional[MapStringToString] + Attributes: MapStringToString | None class GetPlatformApplicationAttributesInput(ServiceRequest): @@ -413,18 +413,18 @@ class GetPlatformApplicationAttributesInput(ServiceRequest): class GetPlatformApplicationAttributesResponse(TypedDict, total=False): - Attributes: Optional[MapStringToString] + Attributes: MapStringToString | None -ListString = List[String] +ListString = list[String] class GetSMSAttributesInput(ServiceRequest): - attributes: Optional[ListString] + attributes: ListString | None class GetSMSAttributesResponse(TypedDict, total=False): - attributes: Optional[MapStringToString] + attributes: MapStringToString | None class GetSMSSandboxAccountStatusInput(ServiceRequest): @@ -439,11 +439,11 @@ class GetSubscriptionAttributesInput(ServiceRequest): SubscriptionArn: subscriptionARN -SubscriptionAttributesMap = Dict[attributeName, attributeValue] +SubscriptionAttributesMap = dict[attributeName, attributeValue] class GetSubscriptionAttributesResponse(TypedDict, total=False): - Attributes: Optional[SubscriptionAttributesMap] + Attributes: SubscriptionAttributesMap | None class GetTopicAttributesInput(ServiceRequest): @@ -451,123 +451,123 @@ class GetTopicAttributesInput(ServiceRequest): class GetTopicAttributesResponse(TypedDict, total=False): - Attributes: Optional[TopicAttributesMap] + Attributes: TopicAttributesMap | None class ListEndpointsByPlatformApplicationInput(ServiceRequest): PlatformApplicationArn: String - NextToken: Optional[String] + NextToken: String | None -ListOfEndpoints = List[Endpoint] +ListOfEndpoints = list[Endpoint] class ListEndpointsByPlatformApplicationResponse(TypedDict, total=False): - Endpoints: Optional[ListOfEndpoints] - NextToken: Optional[String] + Endpoints: ListOfEndpoints | None + NextToken: String | None class PlatformApplication(TypedDict, total=False): - PlatformApplicationArn: Optional[String] - Attributes: Optional[MapStringToString] + PlatformApplicationArn: String | None + Attributes: MapStringToString | None -ListOfPlatformApplications = List[PlatformApplication] +ListOfPlatformApplications = list[PlatformApplication] class ListOriginationNumbersRequest(ServiceRequest): - NextToken: Optional[nextToken] - MaxResults: Optional[MaxItemsListOriginationNumbers] + NextToken: nextToken | None + MaxResults: MaxItemsListOriginationNumbers | None -NumberCapabilityList = List[NumberCapability] +NumberCapabilityList = list[NumberCapability] Timestamp = datetime class PhoneNumberInformation(TypedDict, total=False): - CreatedAt: Optional[Timestamp] - PhoneNumber: Optional[PhoneNumber] - Status: Optional[String] - Iso2CountryCode: Optional[Iso2CountryCode] - RouteType: Optional[RouteType] - NumberCapabilities: Optional[NumberCapabilityList] + CreatedAt: Timestamp | None + PhoneNumber: PhoneNumber | None + Status: String | None + Iso2CountryCode: Iso2CountryCode | None + RouteType: RouteType | None + NumberCapabilities: NumberCapabilityList | None -PhoneNumberInformationList = List[PhoneNumberInformation] +PhoneNumberInformationList = list[PhoneNumberInformation] class ListOriginationNumbersResult(TypedDict, total=False): - NextToken: Optional[nextToken] - PhoneNumbers: Optional[PhoneNumberInformationList] + NextToken: nextToken | None + PhoneNumbers: PhoneNumberInformationList | None class ListPhoneNumbersOptedOutInput(ServiceRequest): - nextToken: Optional[string] + nextToken: string | None -PhoneNumberList = List[PhoneNumber] +PhoneNumberList = list[PhoneNumber] class ListPhoneNumbersOptedOutResponse(TypedDict, total=False): - phoneNumbers: Optional[PhoneNumberList] - nextToken: Optional[string] + phoneNumbers: PhoneNumberList | None + nextToken: string | None class ListPlatformApplicationsInput(ServiceRequest): - NextToken: Optional[String] + NextToken: String | None class ListPlatformApplicationsResponse(TypedDict, total=False): - PlatformApplications: Optional[ListOfPlatformApplications] - NextToken: Optional[String] + PlatformApplications: ListOfPlatformApplications | None + NextToken: String | None class ListSMSSandboxPhoneNumbersInput(ServiceRequest): - NextToken: Optional[nextToken] - MaxResults: Optional[MaxItems] + NextToken: nextToken | None + MaxResults: MaxItems | None class SMSSandboxPhoneNumber(TypedDict, total=False): - PhoneNumber: Optional[PhoneNumberString] - Status: Optional[SMSSandboxPhoneNumberVerificationStatus] + PhoneNumber: PhoneNumberString | None + Status: SMSSandboxPhoneNumberVerificationStatus | None -SMSSandboxPhoneNumberList = List[SMSSandboxPhoneNumber] +SMSSandboxPhoneNumberList = list[SMSSandboxPhoneNumber] class ListSMSSandboxPhoneNumbersResult(TypedDict, total=False): PhoneNumbers: SMSSandboxPhoneNumberList - NextToken: Optional[string] + NextToken: string | None class ListSubscriptionsByTopicInput(ServiceRequest): TopicArn: topicARN - NextToken: Optional[nextToken] + NextToken: nextToken | None class Subscription(TypedDict, total=False): - SubscriptionArn: Optional[subscriptionARN] - Owner: Optional[account] - Protocol: Optional[protocol] - Endpoint: Optional[endpoint] - TopicArn: Optional[topicARN] + SubscriptionArn: subscriptionARN | None + Owner: account | None + Protocol: protocol | None + Endpoint: endpoint | None + TopicArn: topicARN | None -SubscriptionsList = List[Subscription] +SubscriptionsList = list[Subscription] class ListSubscriptionsByTopicResponse(TypedDict, total=False): - Subscriptions: Optional[SubscriptionsList] - NextToken: Optional[nextToken] + Subscriptions: SubscriptionsList | None + NextToken: nextToken | None class ListSubscriptionsInput(ServiceRequest): - NextToken: Optional[nextToken] + NextToken: nextToken | None class ListSubscriptionsResponse(TypedDict, total=False): - Subscriptions: Optional[SubscriptionsList] - NextToken: Optional[nextToken] + Subscriptions: SubscriptionsList | None + NextToken: nextToken | None class ListTagsForResourceRequest(ServiceRequest): @@ -575,32 +575,32 @@ class ListTagsForResourceRequest(ServiceRequest): class ListTagsForResourceResponse(TypedDict, total=False): - Tags: Optional[TagList] + Tags: TagList | None class ListTopicsInput(ServiceRequest): - NextToken: Optional[nextToken] + NextToken: nextToken | None class Topic(TypedDict, total=False): - TopicArn: Optional[topicARN] + TopicArn: topicARN | None -TopicsList = List[Topic] +TopicsList = list[Topic] class ListTopicsResponse(TypedDict, total=False): - Topics: Optional[TopicsList] - NextToken: Optional[nextToken] + Topics: TopicsList | None + NextToken: nextToken | None class MessageAttributeValue(TypedDict, total=False): DataType: String - StringValue: Optional[String] - BinaryValue: Optional[Binary] + StringValue: String | None + BinaryValue: Binary | None -MessageAttributeMap = Dict[String, MessageAttributeValue] +MessageAttributeMap = dict[String, MessageAttributeValue] class OptInPhoneNumberInput(ServiceRequest): @@ -614,14 +614,14 @@ class OptInPhoneNumberResponse(TypedDict, total=False): class PublishBatchRequestEntry(TypedDict, total=False): Id: String Message: message - Subject: Optional[subject] - MessageStructure: Optional[messageStructure] - MessageAttributes: Optional[MessageAttributeMap] - MessageDeduplicationId: Optional[String] - MessageGroupId: Optional[String] + Subject: subject | None + MessageStructure: messageStructure | None + MessageAttributes: MessageAttributeMap | None + MessageDeduplicationId: String | None + MessageGroupId: String | None -PublishBatchRequestEntryList = List[PublishBatchRequestEntry] +PublishBatchRequestEntryList = list[PublishBatchRequestEntry] class PublishBatchInput(ServiceRequest): @@ -630,34 +630,34 @@ class PublishBatchInput(ServiceRequest): class PublishBatchResultEntry(TypedDict, total=False): - Id: Optional[String] - MessageId: Optional[messageId] - SequenceNumber: Optional[String] + Id: String | None + MessageId: messageId | None + SequenceNumber: String | None -PublishBatchResultEntryList = List[PublishBatchResultEntry] +PublishBatchResultEntryList = list[PublishBatchResultEntry] class PublishBatchResponse(TypedDict, total=False): - Successful: Optional[PublishBatchResultEntryList] - Failed: Optional[BatchResultErrorEntryList] + Successful: PublishBatchResultEntryList | None + Failed: BatchResultErrorEntryList | None class PublishInput(ServiceRequest): - TopicArn: Optional[topicARN] - TargetArn: Optional[String] - PhoneNumber: Optional[PhoneNumber] + TopicArn: topicARN | None + TargetArn: String | None + PhoneNumber: PhoneNumber | None Message: message - Subject: Optional[subject] - MessageStructure: Optional[messageStructure] - MessageAttributes: Optional[MessageAttributeMap] - MessageDeduplicationId: Optional[String] - MessageGroupId: Optional[String] + Subject: subject | None + MessageStructure: messageStructure | None + MessageAttributes: MessageAttributeMap | None + MessageDeduplicationId: String | None + MessageGroupId: String | None class PublishResponse(TypedDict, total=False): - MessageId: Optional[messageId] - SequenceNumber: Optional[String] + MessageId: messageId | None + SequenceNumber: String | None class PutDataProtectionPolicyInput(ServiceRequest): @@ -691,28 +691,28 @@ class SetSMSAttributesResponse(TypedDict, total=False): class SetSubscriptionAttributesInput(ServiceRequest): SubscriptionArn: subscriptionARN AttributeName: attributeName - AttributeValue: Optional[attributeValue] + AttributeValue: attributeValue | None class SetTopicAttributesInput(ServiceRequest): TopicArn: topicARN AttributeName: attributeName - AttributeValue: Optional[attributeValue] + AttributeValue: attributeValue | None class SubscribeInput(ServiceRequest): TopicArn: topicARN Protocol: protocol - Endpoint: Optional[endpoint] - Attributes: Optional[SubscriptionAttributesMap] - ReturnSubscriptionArn: Optional[boolean] + Endpoint: endpoint | None + Attributes: SubscriptionAttributesMap | None + ReturnSubscriptionArn: boolean | None class SubscribeResponse(TypedDict, total=False): - SubscriptionArn: Optional[subscriptionARN] + SubscriptionArn: subscriptionARN | None -TagKeyList = List[TagKey] +TagKeyList = list[TagKey] class TagResourceRequest(ServiceRequest): @@ -747,8 +747,8 @@ class VerifySMSSandboxPhoneNumberResult(TypedDict, total=False): class SnsApi: - service = "sns" - version = "2010-03-31" + service: str = "sns" + version: str = "2010-03-31" @handler("AddPermission") def add_permission( diff --git a/localstack-core/localstack/aws/api/sqs/__init__.py b/localstack-core/localstack/aws/api/sqs/__init__.py index a09978ffe8046..23580370cfb90 100644 --- a/localstack-core/localstack/aws/api/sqs/__init__.py +++ b/localstack-core/localstack/aws/api/sqs/__init__.py @@ -1,5 +1,5 @@ from enum import StrEnum -from typing import Dict, List, Optional, TypedDict +from typing import TypedDict from localstack.aws.api import RequestContext, ServiceException, ServiceRequest, handler @@ -224,8 +224,8 @@ class UnsupportedOperation(ServiceException): status_code: int = 400 -AWSAccountIdList = List[String] -ActionNameList = List[String] +AWSAccountIdList = list[String] +ActionNameList = list[String] class AddPermissionRequest(ServiceRequest): @@ -235,19 +235,19 @@ class AddPermissionRequest(ServiceRequest): Actions: ActionNameList -AttributeNameList = List[QueueAttributeName] +AttributeNameList = list[QueueAttributeName] class BatchResultErrorEntry(TypedDict, total=False): Id: String SenderFault: Boolean Code: String - Message: Optional[String] + Message: String | None -BatchResultErrorEntryList = List[BatchResultErrorEntry] +BatchResultErrorEntryList = list[BatchResultErrorEntry] Binary = bytes -BinaryList = List[Binary] +BinaryList = list[Binary] class CancelMessageMoveTaskRequest(ServiceRequest): @@ -258,16 +258,16 @@ class CancelMessageMoveTaskRequest(ServiceRequest): class CancelMessageMoveTaskResult(TypedDict, total=False): - ApproximateNumberOfMessagesMoved: Optional[Long] + ApproximateNumberOfMessagesMoved: Long | None class ChangeMessageVisibilityBatchRequestEntry(TypedDict, total=False): Id: String ReceiptHandle: String - VisibilityTimeout: Optional[NullableInteger] + VisibilityTimeout: NullableInteger | None -ChangeMessageVisibilityBatchRequestEntryList = List[ChangeMessageVisibilityBatchRequestEntry] +ChangeMessageVisibilityBatchRequestEntryList = list[ChangeMessageVisibilityBatchRequestEntry] class ChangeMessageVisibilityBatchRequest(ServiceRequest): @@ -279,7 +279,7 @@ class ChangeMessageVisibilityBatchResultEntry(TypedDict, total=False): Id: String -ChangeMessageVisibilityBatchResultEntryList = List[ChangeMessageVisibilityBatchResultEntry] +ChangeMessageVisibilityBatchResultEntryList = list[ChangeMessageVisibilityBatchResultEntry] class ChangeMessageVisibilityBatchResult(TypedDict, total=False): @@ -293,18 +293,18 @@ class ChangeMessageVisibilityRequest(ServiceRequest): VisibilityTimeout: NullableInteger -TagMap = Dict[TagKey, TagValue] -QueueAttributeMap = Dict[QueueAttributeName, String] +TagMap = dict[TagKey, TagValue] +QueueAttributeMap = dict[QueueAttributeName, String] class CreateQueueRequest(ServiceRequest): QueueName: String - Attributes: Optional[QueueAttributeMap] - tags: Optional[TagMap] + Attributes: QueueAttributeMap | None + tags: TagMap | None class CreateQueueResult(TypedDict, total=False): - QueueUrl: Optional[String] + QueueUrl: String | None class DeleteMessageBatchRequestEntry(TypedDict, total=False): @@ -312,7 +312,7 @@ class DeleteMessageBatchRequestEntry(TypedDict, total=False): ReceiptHandle: String -DeleteMessageBatchRequestEntryList = List[DeleteMessageBatchRequestEntry] +DeleteMessageBatchRequestEntryList = list[DeleteMessageBatchRequestEntry] class DeleteMessageBatchRequest(ServiceRequest): @@ -324,7 +324,7 @@ class DeleteMessageBatchResultEntry(TypedDict, total=False): Id: String -DeleteMessageBatchResultEntryList = List[DeleteMessageBatchResultEntry] +DeleteMessageBatchResultEntryList = list[DeleteMessageBatchResultEntry] class DeleteMessageBatchResult(TypedDict, total=False): @@ -343,61 +343,61 @@ class DeleteQueueRequest(ServiceRequest): class GetQueueAttributesRequest(ServiceRequest): QueueUrl: String - AttributeNames: Optional[AttributeNameList] + AttributeNames: AttributeNameList | None class GetQueueAttributesResult(TypedDict, total=False): - Attributes: Optional[QueueAttributeMap] + Attributes: QueueAttributeMap | None class GetQueueUrlRequest(ServiceRequest): QueueName: String - QueueOwnerAWSAccountId: Optional[String] + QueueOwnerAWSAccountId: String | None class GetQueueUrlResult(TypedDict, total=False): - QueueUrl: Optional[String] + QueueUrl: String | None class ListDeadLetterSourceQueuesRequest(ServiceRequest): QueueUrl: String - NextToken: Optional[Token] - MaxResults: Optional[BoxedInteger] + NextToken: Token | None + MaxResults: BoxedInteger | None -QueueUrlList = List[String] +QueueUrlList = list[String] class ListDeadLetterSourceQueuesResult(TypedDict, total=False): queueUrls: QueueUrlList - NextToken: Optional[Token] + NextToken: Token | None class ListMessageMoveTasksRequest(ServiceRequest): SourceArn: String - MaxResults: Optional[NullableInteger] + MaxResults: NullableInteger | None NullableLong = int class ListMessageMoveTasksResultEntry(TypedDict, total=False): - TaskHandle: Optional[String] - Status: Optional[String] - SourceArn: Optional[String] - DestinationArn: Optional[String] - MaxNumberOfMessagesPerSecond: Optional[NullableInteger] - ApproximateNumberOfMessagesMoved: Optional[Long] - ApproximateNumberOfMessagesToMove: Optional[NullableLong] - FailureReason: Optional[String] - StartedTimestamp: Optional[Long] + TaskHandle: String | None + Status: String | None + SourceArn: String | None + DestinationArn: String | None + MaxNumberOfMessagesPerSecond: NullableInteger | None + ApproximateNumberOfMessagesMoved: Long | None + ApproximateNumberOfMessagesToMove: NullableLong | None + FailureReason: String | None + StartedTimestamp: Long | None -ListMessageMoveTasksResultEntryList = List[ListMessageMoveTasksResultEntry] +ListMessageMoveTasksResultEntryList = list[ListMessageMoveTasksResultEntry] class ListMessageMoveTasksResult(TypedDict, total=False): - Results: Optional[ListMessageMoveTasksResultEntryList] + Results: ListMessageMoveTasksResultEntryList | None class ListQueueTagsRequest(ServiceRequest): @@ -405,61 +405,61 @@ class ListQueueTagsRequest(ServiceRequest): class ListQueueTagsResult(TypedDict, total=False): - Tags: Optional[TagMap] + Tags: TagMap | None class ListQueuesRequest(ServiceRequest): - QueueNamePrefix: Optional[String] - NextToken: Optional[Token] - MaxResults: Optional[BoxedInteger] + QueueNamePrefix: String | None + NextToken: Token | None + MaxResults: BoxedInteger | None class ListQueuesResult(TypedDict, total=False): - QueueUrls: Optional[QueueUrlList] - NextToken: Optional[Token] + QueueUrls: QueueUrlList | None + NextToken: Token | None -StringList = List[String] +StringList = list[String] class MessageAttributeValue(TypedDict, total=False): - StringValue: Optional[String] - BinaryValue: Optional[Binary] - StringListValues: Optional[StringList] - BinaryListValues: Optional[BinaryList] + StringValue: String | None + BinaryValue: Binary | None + StringListValues: StringList | None + BinaryListValues: BinaryList | None DataType: String -MessageBodyAttributeMap = Dict[String, MessageAttributeValue] -MessageSystemAttributeMap = Dict[MessageSystemAttributeName, String] +MessageBodyAttributeMap = dict[String, MessageAttributeValue] +MessageSystemAttributeMap = dict[MessageSystemAttributeName, String] class Message(TypedDict, total=False): - MessageId: Optional[String] - ReceiptHandle: Optional[String] - MD5OfBody: Optional[String] - Body: Optional[String] - Attributes: Optional[MessageSystemAttributeMap] - MD5OfMessageAttributes: Optional[String] - MessageAttributes: Optional[MessageBodyAttributeMap] + MessageId: String | None + ReceiptHandle: String | None + MD5OfBody: String | None + Body: String | None + Attributes: MessageSystemAttributeMap | None + MD5OfMessageAttributes: String | None + MessageAttributes: MessageBodyAttributeMap | None -MessageAttributeNameList = List[MessageAttributeName] +MessageAttributeNameList = list[MessageAttributeName] class MessageSystemAttributeValue(TypedDict, total=False): - StringValue: Optional[String] - BinaryValue: Optional[Binary] - StringListValues: Optional[StringList] - BinaryListValues: Optional[BinaryList] + StringValue: String | None + BinaryValue: Binary | None + StringListValues: StringList | None + BinaryListValues: BinaryList | None DataType: String -MessageBodySystemAttributeMap = Dict[ +MessageBodySystemAttributeMap = dict[ MessageSystemAttributeNameForSends, MessageSystemAttributeValue ] -MessageList = List[Message] -MessageSystemAttributeList = List[MessageSystemAttributeName] +MessageList = list[Message] +MessageSystemAttributeList = list[MessageSystemAttributeName] class PurgeQueueRequest(ServiceRequest): @@ -468,17 +468,17 @@ class PurgeQueueRequest(ServiceRequest): class ReceiveMessageRequest(ServiceRequest): QueueUrl: String - AttributeNames: Optional[AttributeNameList] - MessageSystemAttributeNames: Optional[MessageSystemAttributeList] - MessageAttributeNames: Optional[MessageAttributeNameList] - MaxNumberOfMessages: Optional[NullableInteger] - VisibilityTimeout: Optional[NullableInteger] - WaitTimeSeconds: Optional[NullableInteger] - ReceiveRequestAttemptId: Optional[String] + AttributeNames: AttributeNameList | None + MessageSystemAttributeNames: MessageSystemAttributeList | None + MessageAttributeNames: MessageAttributeNameList | None + MaxNumberOfMessages: NullableInteger | None + VisibilityTimeout: NullableInteger | None + WaitTimeSeconds: NullableInteger | None + ReceiveRequestAttemptId: String | None class ReceiveMessageResult(TypedDict, total=False): - Messages: Optional[MessageList] + Messages: MessageList | None class RemovePermissionRequest(ServiceRequest): @@ -489,14 +489,14 @@ class RemovePermissionRequest(ServiceRequest): class SendMessageBatchRequestEntry(TypedDict, total=False): Id: String MessageBody: String - DelaySeconds: Optional[NullableInteger] - MessageAttributes: Optional[MessageBodyAttributeMap] - MessageSystemAttributes: Optional[MessageBodySystemAttributeMap] - MessageDeduplicationId: Optional[String] - MessageGroupId: Optional[String] + DelaySeconds: NullableInteger | None + MessageAttributes: MessageBodyAttributeMap | None + MessageSystemAttributes: MessageBodySystemAttributeMap | None + MessageDeduplicationId: String | None + MessageGroupId: String | None -SendMessageBatchRequestEntryList = List[SendMessageBatchRequestEntry] +SendMessageBatchRequestEntryList = list[SendMessageBatchRequestEntry] class SendMessageBatchRequest(ServiceRequest): @@ -508,12 +508,12 @@ class SendMessageBatchResultEntry(TypedDict, total=False): Id: String MessageId: String MD5OfMessageBody: String - MD5OfMessageAttributes: Optional[String] - MD5OfMessageSystemAttributes: Optional[String] - SequenceNumber: Optional[String] + MD5OfMessageAttributes: String | None + MD5OfMessageSystemAttributes: String | None + SequenceNumber: String | None -SendMessageBatchResultEntryList = List[SendMessageBatchResultEntry] +SendMessageBatchResultEntryList = list[SendMessageBatchResultEntry] class SendMessageBatchResult(TypedDict, total=False): @@ -524,19 +524,19 @@ class SendMessageBatchResult(TypedDict, total=False): class SendMessageRequest(ServiceRequest): QueueUrl: String MessageBody: String - DelaySeconds: Optional[NullableInteger] - MessageAttributes: Optional[MessageBodyAttributeMap] - MessageSystemAttributes: Optional[MessageBodySystemAttributeMap] - MessageDeduplicationId: Optional[String] - MessageGroupId: Optional[String] + DelaySeconds: NullableInteger | None + MessageAttributes: MessageBodyAttributeMap | None + MessageSystemAttributes: MessageBodySystemAttributeMap | None + MessageDeduplicationId: String | None + MessageGroupId: String | None class SendMessageResult(TypedDict, total=False): - MD5OfMessageBody: Optional[String] - MD5OfMessageAttributes: Optional[String] - MD5OfMessageSystemAttributes: Optional[String] - MessageId: Optional[String] - SequenceNumber: Optional[String] + MD5OfMessageBody: String | None + MD5OfMessageAttributes: String | None + MD5OfMessageSystemAttributes: String | None + MessageId: String | None + SequenceNumber: String | None class SetQueueAttributesRequest(ServiceRequest): @@ -546,15 +546,15 @@ class SetQueueAttributesRequest(ServiceRequest): class StartMessageMoveTaskRequest(ServiceRequest): SourceArn: String - DestinationArn: Optional[String] - MaxNumberOfMessagesPerSecond: Optional[NullableInteger] + DestinationArn: String | None + MaxNumberOfMessagesPerSecond: NullableInteger | None class StartMessageMoveTaskResult(TypedDict, total=False): - TaskHandle: Optional[String] + TaskHandle: String | None -TagKeyList = List[TagKey] +TagKeyList = list[TagKey] class TagQueueRequest(ServiceRequest): @@ -568,8 +568,8 @@ class UntagQueueRequest(ServiceRequest): class SqsApi: - service = "sqs" - version = "2012-11-05" + service: str = "sqs" + version: str = "2012-11-05" @handler("AddPermission") def add_permission( diff --git a/localstack-core/localstack/aws/api/ssm/__init__.py b/localstack-core/localstack/aws/api/ssm/__init__.py index 5955484431472..6ff21b9f728ae 100644 --- a/localstack-core/localstack/aws/api/ssm/__init__.py +++ b/localstack-core/localstack/aws/api/ssm/__init__.py @@ -1,6 +1,6 @@ from datetime import datetime from enum import StrEnum -from typing import Dict, List, Optional, TypedDict +from typing import TypedDict from localstack.aws.api import RequestContext, ServiceException, ServiceRequest, handler @@ -21,6 +21,7 @@ ApplyOnlyAtCronInterval = bool ApproveAfterDays = int Architecture = str +AssociationDispatchAssumeRoleArn = str AssociationExecutionFilterValue = str AssociationExecutionId = str AssociationExecutionTargetsFilterValue = str @@ -1510,7 +1511,7 @@ class InvalidItemContentException(ServiceException): code: str = "InvalidItemContentException" sender_fault: bool = False status_code: int = 400 - TypeName: Optional[InventoryItemTypeName] + TypeName: InventoryItemTypeName | None class InvalidKeyId(ServiceException): @@ -1649,14 +1650,14 @@ class ItemContentMismatchException(ServiceException): code: str = "ItemContentMismatchException" sender_fault: bool = False status_code: int = 400 - TypeName: Optional[InventoryItemTypeName] + TypeName: InventoryItemTypeName | None class ItemSizeLimitExceededException(ServiceException): code: str = "ItemSizeLimitExceededException" sender_fault: bool = False status_code: int = 400 - TypeName: Optional[InventoryItemTypeName] + TypeName: InventoryItemTypeName | None class MalformedResourcePolicyDocumentException(ServiceException): @@ -1671,6 +1672,12 @@ class MaxDocumentSizeExceeded(ServiceException): status_code: int = 400 +class NoLongerSupportedException(ServiceException): + code: str = "NoLongerSupportedException" + sender_fault: bool = False + status_code: int = 400 + + class OpsItemAccessDeniedException(ServiceException): code: str = "OpsItemAccessDeniedException" sender_fault: bool = False @@ -1681,7 +1688,7 @@ class OpsItemAlreadyExistsException(ServiceException): code: str = "OpsItemAlreadyExistsException" sender_fault: bool = False status_code: int = 400 - OpsItemId: Optional[String] + OpsItemId: String | None class OpsItemConflictException(ServiceException): @@ -1690,23 +1697,23 @@ class OpsItemConflictException(ServiceException): status_code: int = 400 -OpsItemParameterNamesList = List[String] +OpsItemParameterNamesList = list[String] class OpsItemInvalidParameterException(ServiceException): code: str = "OpsItemInvalidParameterException" sender_fault: bool = False status_code: int = 400 - ParameterNames: Optional[OpsItemParameterNamesList] + ParameterNames: OpsItemParameterNamesList | None class OpsItemLimitExceededException(ServiceException): code: str = "OpsItemLimitExceededException" sender_fault: bool = False status_code: int = 400 - ResourceTypes: Optional[OpsItemParameterNamesList] - Limit: Optional[Integer] - LimitType: Optional[String] + ResourceTypes: OpsItemParameterNamesList | None + Limit: Integer | None + LimitType: String | None class OpsItemNotFoundException(ServiceException): @@ -1719,8 +1726,8 @@ class OpsItemRelatedItemAlreadyExistsException(ServiceException): code: str = "OpsItemRelatedItemAlreadyExistsException" sender_fault: bool = False status_code: int = 400 - ResourceUri: Optional[OpsItemRelatedItemAssociationResourceUri] - OpsItemId: Optional[OpsItemId] + ResourceUri: OpsItemRelatedItemAssociationResourceUri | None + OpsItemId: OpsItemId | None class OpsItemRelatedItemAssociationNotFoundException(ServiceException): @@ -1817,7 +1824,7 @@ class ResourceDataSyncAlreadyExistsException(ServiceException): code: str = "ResourceDataSyncAlreadyExistsException" sender_fault: bool = False status_code: int = 400 - SyncName: Optional[ResourceDataSyncName] + SyncName: ResourceDataSyncName | None class ResourceDataSyncConflictException(ServiceException): @@ -1842,8 +1849,8 @@ class ResourceDataSyncNotFoundException(ServiceException): code: str = "ResourceDataSyncNotFoundException" sender_fault: bool = False status_code: int = 400 - SyncName: Optional[ResourceDataSyncName] - SyncType: Optional[ResourceDataSyncType] + SyncName: ResourceDataSyncName | None + SyncType: ResourceDataSyncType | None class ResourceInUseException(ServiceException): @@ -1870,22 +1877,22 @@ class ResourcePolicyConflictException(ServiceException): status_code: int = 400 -ResourcePolicyParameterNamesList = List[String] +ResourcePolicyParameterNamesList = list[String] class ResourcePolicyInvalidParameterException(ServiceException): code: str = "ResourcePolicyInvalidParameterException" sender_fault: bool = False status_code: int = 400 - ParameterNames: Optional[ResourcePolicyParameterNamesList] + ParameterNames: ResourcePolicyParameterNamesList | None class ResourcePolicyLimitExceededException(ServiceException): code: str = "ResourcePolicyLimitExceededException" sender_fault: bool = False status_code: int = 400 - Limit: Optional[Integer] - LimitType: Optional[String] + Limit: Integer | None + LimitType: String | None class ResourcePolicyNotFoundException(ServiceException): @@ -1898,8 +1905,8 @@ class ServiceQuotaExceededException(ServiceException): code: str = "ServiceQuotaExceededException" sender_fault: bool = False status_code: int = 400 - ResourceId: Optional[String] - ResourceType: Optional[String] + ResourceId: String | None + ResourceType: String | None QuotaCode: String ServiceCode: String @@ -1938,8 +1945,8 @@ class ThrottlingException(ServiceException): code: str = "ThrottlingException" sender_fault: bool = False status_code: int = 400 - QuotaCode: Optional[String] - ServiceCode: Optional[String] + QuotaCode: String | None + ServiceCode: String | None class TooManyTagsError(ServiceException): @@ -1976,7 +1983,7 @@ class UnsupportedInventoryItemContextException(ServiceException): code: str = "UnsupportedInventoryItemContextException" sender_fault: bool = False status_code: int = 400 - TypeName: Optional[InventoryItemTypeName] + TypeName: InventoryItemTypeName | None class UnsupportedInventorySchemaVersionException(ServiceException): @@ -2013,19 +2020,19 @@ class ValidationException(ServiceException): code: str = "ValidationException" sender_fault: bool = False status_code: int = 400 - ReasonCode: Optional[String] + ReasonCode: String | None -AccountIdList = List[AccountId] +AccountIdList = list[AccountId] class AccountSharingInfo(TypedDict, total=False): - AccountId: Optional[AccountId] - SharedDocumentVersion: Optional[SharedDocumentVersion] + AccountId: AccountId | None + SharedDocumentVersion: SharedDocumentVersion | None -AccountSharingInfoList = List[AccountSharingInfo] -Accounts = List[Account] +AccountSharingInfoList = list[AccountSharingInfo] +Accounts = list[Account] class Tag(TypedDict, total=False): @@ -2033,25 +2040,25 @@ class Tag(TypedDict, total=False): Value: TagValue -TagList = List[Tag] +TagList = list[Tag] CreatedDate = datetime ExpirationDate = datetime class Activation(TypedDict, total=False): - ActivationId: Optional[ActivationId] - Description: Optional[ActivationDescription] - DefaultInstanceName: Optional[DefaultInstanceName] - IamRole: Optional[IamRole] - RegistrationLimit: Optional[RegistrationLimit] - RegistrationsCount: Optional[RegistrationsCount] - ExpirationDate: Optional[ExpirationDate] - Expired: Optional[Boolean] - CreatedDate: Optional[CreatedDate] - Tags: Optional[TagList] + ActivationId: ActivationId | None + Description: ActivationDescription | None + DefaultInstanceName: DefaultInstanceName | None + IamRole: IamRole | None + RegistrationLimit: RegistrationLimit | None + RegistrationsCount: RegistrationsCount | None + ExpirationDate: ExpirationDate | None + Expired: Boolean | None + CreatedDate: CreatedDate | None + Tags: TagList | None -ActivationList = List[Activation] +ActivationList = list[Activation] class AddTagsToResourceRequest(ServiceRequest): @@ -2068,11 +2075,11 @@ class Alarm(TypedDict, total=False): Name: AlarmName -AlarmList = List[Alarm] +AlarmList = list[Alarm] class AlarmConfiguration(TypedDict, total=False): - IgnorePollAlarmFailure: Optional[Boolean] + IgnorePollAlarmFailure: Boolean | None Alarms: AlarmList @@ -2081,7 +2088,7 @@ class AlarmStateInformation(TypedDict, total=False): State: ExternalAlarmState -AlarmStateInformationList = List[AlarmStateInformation] +AlarmStateInformationList = list[AlarmStateInformation] class AssociateOpsItemRelatedItemRequest(ServiceRequest): @@ -2092,138 +2099,139 @@ class AssociateOpsItemRelatedItemRequest(ServiceRequest): class AssociateOpsItemRelatedItemResponse(TypedDict, total=False): - AssociationId: Optional[OpsItemRelatedItemAssociationId] + AssociationId: OpsItemRelatedItemAssociationId | None -TargetMapValueList = List[TargetMapValue] -TargetMap = Dict[TargetMapKey, TargetMapValueList] -TargetMaps = List[TargetMap] -AssociationStatusAggregatedCount = Dict[StatusName, InstanceCount] +TargetMapValueList = list[TargetMapValue] +TargetMap = dict[TargetMapKey, TargetMapValueList] +TargetMaps = list[TargetMap] +AssociationStatusAggregatedCount = dict[StatusName, InstanceCount] class AssociationOverview(TypedDict, total=False): - Status: Optional[StatusName] - DetailedStatus: Optional[StatusName] - AssociationStatusAggregatedCount: Optional[AssociationStatusAggregatedCount] + Status: StatusName | None + DetailedStatus: StatusName | None + AssociationStatusAggregatedCount: AssociationStatusAggregatedCount | None DateTime = datetime -TargetValues = List[TargetValue] +TargetValues = list[TargetValue] class Target(TypedDict, total=False): - Key: Optional[TargetKey] - Values: Optional[TargetValues] + Key: TargetKey | None + Values: TargetValues | None -Targets = List[Target] +Targets = list[Target] class Association(TypedDict, total=False): - Name: Optional[DocumentARN] - InstanceId: Optional[InstanceId] - AssociationId: Optional[AssociationId] - AssociationVersion: Optional[AssociationVersion] - DocumentVersion: Optional[DocumentVersion] - Targets: Optional[Targets] - LastExecutionDate: Optional[DateTime] - Overview: Optional[AssociationOverview] - ScheduleExpression: Optional[ScheduleExpression] - AssociationName: Optional[AssociationName] - ScheduleOffset: Optional[ScheduleOffset] - Duration: Optional[Duration] - TargetMaps: Optional[TargetMaps] + Name: DocumentARN | None + InstanceId: InstanceId | None + AssociationId: AssociationId | None + AssociationVersion: AssociationVersion | None + DocumentVersion: DocumentVersion | None + Targets: Targets | None + LastExecutionDate: DateTime | None + Overview: AssociationOverview | None + ScheduleExpression: ScheduleExpression | None + AssociationName: AssociationName | None + ScheduleOffset: ScheduleOffset | None + Duration: Duration | None + TargetMaps: TargetMaps | None -ExcludeAccounts = List[ExcludeAccount] -Regions = List[Region] +ExcludeAccounts = list[ExcludeAccount] +Regions = list[Region] class TargetLocation(TypedDict, total=False): - Accounts: Optional[Accounts] - Regions: Optional[Regions] - TargetLocationMaxConcurrency: Optional[MaxConcurrency] - TargetLocationMaxErrors: Optional[MaxErrors] - ExecutionRoleName: Optional[ExecutionRoleName] - TargetLocationAlarmConfiguration: Optional[AlarmConfiguration] - IncludeChildOrganizationUnits: Optional[Boolean] - ExcludeAccounts: Optional[ExcludeAccounts] - Targets: Optional[Targets] - TargetsMaxConcurrency: Optional[MaxConcurrency] - TargetsMaxErrors: Optional[MaxErrors] + Accounts: Accounts | None + Regions: Regions | None + TargetLocationMaxConcurrency: MaxConcurrency | None + TargetLocationMaxErrors: MaxErrors | None + ExecutionRoleName: ExecutionRoleName | None + TargetLocationAlarmConfiguration: AlarmConfiguration | None + IncludeChildOrganizationUnits: Boolean | None + ExcludeAccounts: ExcludeAccounts | None + Targets: Targets | None + TargetsMaxConcurrency: MaxConcurrency | None + TargetsMaxErrors: MaxErrors | None -TargetLocations = List[TargetLocation] -CalendarNameOrARNList = List[CalendarNameOrARN] +TargetLocations = list[TargetLocation] +CalendarNameOrARNList = list[CalendarNameOrARN] class S3OutputLocation(TypedDict, total=False): - OutputS3Region: Optional[S3Region] - OutputS3BucketName: Optional[S3BucketName] - OutputS3KeyPrefix: Optional[S3KeyPrefix] + OutputS3Region: S3Region | None + OutputS3BucketName: S3BucketName | None + OutputS3KeyPrefix: S3KeyPrefix | None class InstanceAssociationOutputLocation(TypedDict, total=False): - S3Location: Optional[S3OutputLocation] + S3Location: S3OutputLocation | None -ParameterValueList = List[ParameterValue] -Parameters = Dict[ParameterName, ParameterValueList] +ParameterValueList = list[ParameterValue] +Parameters = dict[ParameterName, ParameterValueList] class AssociationStatus(TypedDict, total=False): Date: DateTime Name: AssociationStatusName Message: StatusMessage - AdditionalInfo: Optional[StatusAdditionalInfo] + AdditionalInfo: StatusAdditionalInfo | None class AssociationDescription(TypedDict, total=False): - Name: Optional[DocumentARN] - InstanceId: Optional[InstanceId] - AssociationVersion: Optional[AssociationVersion] - Date: Optional[DateTime] - LastUpdateAssociationDate: Optional[DateTime] - Status: Optional[AssociationStatus] - Overview: Optional[AssociationOverview] - DocumentVersion: Optional[DocumentVersion] - AutomationTargetParameterName: Optional[AutomationTargetParameterName] - Parameters: Optional[Parameters] - AssociationId: Optional[AssociationId] - Targets: Optional[Targets] - ScheduleExpression: Optional[ScheduleExpression] - OutputLocation: Optional[InstanceAssociationOutputLocation] - LastExecutionDate: Optional[DateTime] - LastSuccessfulExecutionDate: Optional[DateTime] - AssociationName: Optional[AssociationName] - MaxErrors: Optional[MaxErrors] - MaxConcurrency: Optional[MaxConcurrency] - ComplianceSeverity: Optional[AssociationComplianceSeverity] - SyncCompliance: Optional[AssociationSyncCompliance] - ApplyOnlyAtCronInterval: Optional[ApplyOnlyAtCronInterval] - CalendarNames: Optional[CalendarNameOrARNList] - TargetLocations: Optional[TargetLocations] - ScheduleOffset: Optional[ScheduleOffset] - Duration: Optional[Duration] - TargetMaps: Optional[TargetMaps] - AlarmConfiguration: Optional[AlarmConfiguration] - TriggeredAlarms: Optional[AlarmStateInformationList] - - -AssociationDescriptionList = List[AssociationDescription] + Name: DocumentARN | None + InstanceId: InstanceId | None + AssociationVersion: AssociationVersion | None + Date: DateTime | None + LastUpdateAssociationDate: DateTime | None + Status: AssociationStatus | None + Overview: AssociationOverview | None + DocumentVersion: DocumentVersion | None + AutomationTargetParameterName: AutomationTargetParameterName | None + Parameters: Parameters | None + AssociationId: AssociationId | None + Targets: Targets | None + ScheduleExpression: ScheduleExpression | None + OutputLocation: InstanceAssociationOutputLocation | None + LastExecutionDate: DateTime | None + LastSuccessfulExecutionDate: DateTime | None + AssociationName: AssociationName | None + MaxErrors: MaxErrors | None + MaxConcurrency: MaxConcurrency | None + ComplianceSeverity: AssociationComplianceSeverity | None + SyncCompliance: AssociationSyncCompliance | None + ApplyOnlyAtCronInterval: ApplyOnlyAtCronInterval | None + CalendarNames: CalendarNameOrARNList | None + TargetLocations: TargetLocations | None + ScheduleOffset: ScheduleOffset | None + Duration: Duration | None + TargetMaps: TargetMaps | None + AlarmConfiguration: AlarmConfiguration | None + TriggeredAlarms: AlarmStateInformationList | None + AssociationDispatchAssumeRole: AssociationDispatchAssumeRoleArn | None + + +AssociationDescriptionList = list[AssociationDescription] class AssociationExecution(TypedDict, total=False): - AssociationId: Optional[AssociationId] - AssociationVersion: Optional[AssociationVersion] - ExecutionId: Optional[AssociationExecutionId] - Status: Optional[StatusName] - DetailedStatus: Optional[StatusName] - CreatedTime: Optional[DateTime] - LastExecutionDate: Optional[DateTime] - ResourceCountByStatus: Optional[ResourceCountByStatus] - AlarmConfiguration: Optional[AlarmConfiguration] - TriggeredAlarms: Optional[AlarmStateInformationList] + AssociationId: AssociationId | None + AssociationVersion: AssociationVersion | None + ExecutionId: AssociationExecutionId | None + Status: StatusName | None + DetailedStatus: StatusName | None + CreatedTime: DateTime | None + LastExecutionDate: DateTime | None + ResourceCountByStatus: ResourceCountByStatus | None + AlarmConfiguration: AlarmConfiguration | None + TriggeredAlarms: AlarmStateInformationList | None class AssociationExecutionFilter(TypedDict, total=False): @@ -2232,24 +2240,24 @@ class AssociationExecutionFilter(TypedDict, total=False): Type: AssociationFilterOperatorType -AssociationExecutionFilterList = List[AssociationExecutionFilter] +AssociationExecutionFilterList = list[AssociationExecutionFilter] class OutputSource(TypedDict, total=False): - OutputSourceId: Optional[OutputSourceId] - OutputSourceType: Optional[OutputSourceType] + OutputSourceId: OutputSourceId | None + OutputSourceType: OutputSourceType | None class AssociationExecutionTarget(TypedDict, total=False): - AssociationId: Optional[AssociationId] - AssociationVersion: Optional[AssociationVersion] - ExecutionId: Optional[AssociationExecutionId] - ResourceId: Optional[AssociationResourceId] - ResourceType: Optional[AssociationResourceType] - Status: Optional[StatusName] - DetailedStatus: Optional[StatusName] - LastExecutionDate: Optional[DateTime] - OutputSource: Optional[OutputSource] + AssociationId: AssociationId | None + AssociationVersion: AssociationVersion | None + ExecutionId: AssociationExecutionId | None + ResourceId: AssociationResourceId | None + ResourceType: AssociationResourceType | None + Status: StatusName | None + DetailedStatus: StatusName | None + LastExecutionDate: DateTime | None + OutputSource: OutputSource | None class AssociationExecutionTargetsFilter(TypedDict, total=False): @@ -2257,9 +2265,9 @@ class AssociationExecutionTargetsFilter(TypedDict, total=False): Value: AssociationExecutionTargetsFilterValue -AssociationExecutionTargetsFilterList = List[AssociationExecutionTargetsFilter] -AssociationExecutionTargetsList = List[AssociationExecutionTarget] -AssociationExecutionsList = List[AssociationExecution] +AssociationExecutionTargetsFilterList = list[AssociationExecutionTargetsFilter] +AssociationExecutionTargetsList = list[AssociationExecutionTarget] +AssociationExecutionsList = list[AssociationExecution] class AssociationFilter(TypedDict, total=False): @@ -2267,189 +2275,190 @@ class AssociationFilter(TypedDict, total=False): value: AssociationFilterValue -AssociationFilterList = List[AssociationFilter] -AssociationIdList = List[AssociationId] -AssociationList = List[Association] +AssociationFilterList = list[AssociationFilter] +AssociationIdList = list[AssociationId] +AssociationList = list[Association] class AssociationVersionInfo(TypedDict, total=False): - AssociationId: Optional[AssociationId] - AssociationVersion: Optional[AssociationVersion] - CreatedDate: Optional[DateTime] - Name: Optional[DocumentARN] - DocumentVersion: Optional[DocumentVersion] - Parameters: Optional[Parameters] - Targets: Optional[Targets] - ScheduleExpression: Optional[ScheduleExpression] - OutputLocation: Optional[InstanceAssociationOutputLocation] - AssociationName: Optional[AssociationName] - MaxErrors: Optional[MaxErrors] - MaxConcurrency: Optional[MaxConcurrency] - ComplianceSeverity: Optional[AssociationComplianceSeverity] - SyncCompliance: Optional[AssociationSyncCompliance] - ApplyOnlyAtCronInterval: Optional[ApplyOnlyAtCronInterval] - CalendarNames: Optional[CalendarNameOrARNList] - TargetLocations: Optional[TargetLocations] - ScheduleOffset: Optional[ScheduleOffset] - Duration: Optional[Duration] - TargetMaps: Optional[TargetMaps] - - -AssociationVersionList = List[AssociationVersionInfo] + AssociationId: AssociationId | None + AssociationVersion: AssociationVersion | None + CreatedDate: DateTime | None + Name: DocumentARN | None + DocumentVersion: DocumentVersion | None + Parameters: Parameters | None + Targets: Targets | None + ScheduleExpression: ScheduleExpression | None + OutputLocation: InstanceAssociationOutputLocation | None + AssociationName: AssociationName | None + MaxErrors: MaxErrors | None + MaxConcurrency: MaxConcurrency | None + ComplianceSeverity: AssociationComplianceSeverity | None + SyncCompliance: AssociationSyncCompliance | None + ApplyOnlyAtCronInterval: ApplyOnlyAtCronInterval | None + CalendarNames: CalendarNameOrARNList | None + TargetLocations: TargetLocations | None + ScheduleOffset: ScheduleOffset | None + Duration: Duration | None + TargetMaps: TargetMaps | None + AssociationDispatchAssumeRole: AssociationDispatchAssumeRoleArn | None + + +AssociationVersionList = list[AssociationVersionInfo] ContentLength = int class AttachmentContent(TypedDict, total=False): - Name: Optional[AttachmentName] - Size: Optional[ContentLength] - Hash: Optional[AttachmentHash] - HashType: Optional[AttachmentHashType] - Url: Optional[AttachmentUrl] + Name: AttachmentName | None + Size: ContentLength | None + Hash: AttachmentHash | None + HashType: AttachmentHashType | None + Url: AttachmentUrl | None -AttachmentContentList = List[AttachmentContent] +AttachmentContentList = list[AttachmentContent] class AttachmentInformation(TypedDict, total=False): - Name: Optional[AttachmentName] + Name: AttachmentName | None -AttachmentInformationList = List[AttachmentInformation] -AttachmentsSourceValues = List[AttachmentsSourceValue] +AttachmentInformationList = list[AttachmentInformation] +AttachmentsSourceValues = list[AttachmentsSourceValue] class AttachmentsSource(TypedDict, total=False): - Key: Optional[AttachmentsSourceKey] - Values: Optional[AttachmentsSourceValues] - Name: Optional[AttachmentIdentifier] + Key: AttachmentsSourceKey | None + Values: AttachmentsSourceValues | None + Name: AttachmentIdentifier | None -AttachmentsSourceList = List[AttachmentsSource] -AutomationParameterValueList = List[AutomationParameterValue] -AutomationParameterMap = Dict[AutomationParameterKey, AutomationParameterValueList] +AttachmentsSourceList = list[AttachmentsSource] +AutomationParameterValueList = list[AutomationParameterValue] +AutomationParameterMap = dict[AutomationParameterKey, AutomationParameterValueList] class Runbook(TypedDict, total=False): DocumentName: DocumentARN - DocumentVersion: Optional[DocumentVersion] - Parameters: Optional[AutomationParameterMap] - TargetParameterName: Optional[AutomationParameterKey] - Targets: Optional[Targets] - TargetMaps: Optional[TargetMaps] - MaxConcurrency: Optional[MaxConcurrency] - MaxErrors: Optional[MaxErrors] - TargetLocations: Optional[TargetLocations] + DocumentVersion: DocumentVersion | None + Parameters: AutomationParameterMap | None + TargetParameterName: AutomationParameterKey | None + Targets: Targets | None + TargetMaps: TargetMaps | None + MaxConcurrency: MaxConcurrency | None + MaxErrors: MaxErrors | None + TargetLocations: TargetLocations | None -Runbooks = List[Runbook] +Runbooks = list[Runbook] class ProgressCounters(TypedDict, total=False): - TotalSteps: Optional[Integer] - SuccessSteps: Optional[Integer] - FailedSteps: Optional[Integer] - CancelledSteps: Optional[Integer] - TimedOutSteps: Optional[Integer] + TotalSteps: Integer | None + SuccessSteps: Integer | None + FailedSteps: Integer | None + CancelledSteps: Integer | None + TimedOutSteps: Integer | None -TargetParameterList = List[ParameterValue] +TargetParameterList = list[ParameterValue] class ResolvedTargets(TypedDict, total=False): - ParameterValues: Optional[TargetParameterList] - Truncated: Optional[Boolean] + ParameterValues: TargetParameterList | None + Truncated: Boolean | None class ParentStepDetails(TypedDict, total=False): - StepExecutionId: Optional[String] - StepName: Optional[String] - Action: Optional[AutomationActionName] - Iteration: Optional[Integer] - IteratorValue: Optional[String] + StepExecutionId: String | None + StepName: String | None + Action: AutomationActionName | None + Iteration: Integer | None + IteratorValue: String | None -ValidNextStepList = List[ValidNextStep] +ValidNextStepList = list[ValidNextStep] class FailureDetails(TypedDict, total=False): - FailureStage: Optional[String] - FailureType: Optional[String] - Details: Optional[AutomationParameterMap] + FailureStage: String | None + FailureType: String | None + Details: AutomationParameterMap | None -NormalStringMap = Dict[String, String] +NormalStringMap = dict[String, String] Long = int class StepExecution(TypedDict, total=False): - StepName: Optional[String] - Action: Optional[AutomationActionName] - TimeoutSeconds: Optional[Long] - OnFailure: Optional[String] - MaxAttempts: Optional[Integer] - ExecutionStartTime: Optional[DateTime] - ExecutionEndTime: Optional[DateTime] - StepStatus: Optional[AutomationExecutionStatus] - ResponseCode: Optional[String] - Inputs: Optional[NormalStringMap] - Outputs: Optional[AutomationParameterMap] - Response: Optional[String] - FailureMessage: Optional[String] - FailureDetails: Optional[FailureDetails] - StepExecutionId: Optional[String] - OverriddenParameters: Optional[AutomationParameterMap] - IsEnd: Optional[Boolean] - NextStep: Optional[String] - IsCritical: Optional[Boolean] - ValidNextSteps: Optional[ValidNextStepList] - Targets: Optional[Targets] - TargetLocation: Optional[TargetLocation] - TriggeredAlarms: Optional[AlarmStateInformationList] - ParentStepDetails: Optional[ParentStepDetails] - - -StepExecutionList = List[StepExecution] + StepName: String | None + Action: AutomationActionName | None + TimeoutSeconds: Long | None + OnFailure: String | None + MaxAttempts: Integer | None + ExecutionStartTime: DateTime | None + ExecutionEndTime: DateTime | None + StepStatus: AutomationExecutionStatus | None + ResponseCode: String | None + Inputs: NormalStringMap | None + Outputs: AutomationParameterMap | None + Response: String | None + FailureMessage: String | None + FailureDetails: FailureDetails | None + StepExecutionId: String | None + OverriddenParameters: AutomationParameterMap | None + IsEnd: Boolean | None + NextStep: String | None + IsCritical: Boolean | None + ValidNextSteps: ValidNextStepList | None + Targets: Targets | None + TargetLocation: TargetLocation | None + TriggeredAlarms: AlarmStateInformationList | None + ParentStepDetails: ParentStepDetails | None + + +StepExecutionList = list[StepExecution] class AutomationExecution(TypedDict, total=False): - AutomationExecutionId: Optional[AutomationExecutionId] - DocumentName: Optional[DocumentName] - DocumentVersion: Optional[DocumentVersion] - ExecutionStartTime: Optional[DateTime] - ExecutionEndTime: Optional[DateTime] - AutomationExecutionStatus: Optional[AutomationExecutionStatus] - StepExecutions: Optional[StepExecutionList] - StepExecutionsTruncated: Optional[Boolean] - Parameters: Optional[AutomationParameterMap] - Outputs: Optional[AutomationParameterMap] - FailureMessage: Optional[String] - Mode: Optional[ExecutionMode] - ParentAutomationExecutionId: Optional[AutomationExecutionId] - ExecutedBy: Optional[String] - CurrentStepName: Optional[String] - CurrentAction: Optional[String] - TargetParameterName: Optional[AutomationParameterKey] - Targets: Optional[Targets] - TargetMaps: Optional[TargetMaps] - ResolvedTargets: Optional[ResolvedTargets] - MaxConcurrency: Optional[MaxConcurrency] - MaxErrors: Optional[MaxErrors] - Target: Optional[String] - TargetLocations: Optional[TargetLocations] - ProgressCounters: Optional[ProgressCounters] - AlarmConfiguration: Optional[AlarmConfiguration] - TriggeredAlarms: Optional[AlarmStateInformationList] - TargetLocationsURL: Optional[TargetLocationsURL] - AutomationSubtype: Optional[AutomationSubtype] - ScheduledTime: Optional[DateTime] - Runbooks: Optional[Runbooks] - OpsItemId: Optional[String] - AssociationId: Optional[String] - ChangeRequestName: Optional[ChangeRequestName] - Variables: Optional[AutomationParameterMap] - - -AutomationExecutionFilterValueList = List[AutomationExecutionFilterValue] + AutomationExecutionId: AutomationExecutionId | None + DocumentName: DocumentName | None + DocumentVersion: DocumentVersion | None + ExecutionStartTime: DateTime | None + ExecutionEndTime: DateTime | None + AutomationExecutionStatus: AutomationExecutionStatus | None + StepExecutions: StepExecutionList | None + StepExecutionsTruncated: Boolean | None + Parameters: AutomationParameterMap | None + Outputs: AutomationParameterMap | None + FailureMessage: String | None + Mode: ExecutionMode | None + ParentAutomationExecutionId: AutomationExecutionId | None + ExecutedBy: String | None + CurrentStepName: String | None + CurrentAction: String | None + TargetParameterName: AutomationParameterKey | None + Targets: Targets | None + TargetMaps: TargetMaps | None + ResolvedTargets: ResolvedTargets | None + MaxConcurrency: MaxConcurrency | None + MaxErrors: MaxErrors | None + Target: String | None + TargetLocations: TargetLocations | None + ProgressCounters: ProgressCounters | None + AlarmConfiguration: AlarmConfiguration | None + TriggeredAlarms: AlarmStateInformationList | None + TargetLocationsURL: TargetLocationsURL | None + AutomationSubtype: AutomationSubtype | None + ScheduledTime: DateTime | None + Runbooks: Runbooks | None + OpsItemId: String | None + AssociationId: String | None + ChangeRequestName: ChangeRequestName | None + Variables: AutomationParameterMap | None + + +AutomationExecutionFilterValueList = list[AutomationExecutionFilterValue] class AutomationExecutionFilter(TypedDict, total=False): @@ -2457,73 +2466,73 @@ class AutomationExecutionFilter(TypedDict, total=False): Values: AutomationExecutionFilterValueList -AutomationExecutionFilterList = List[AutomationExecutionFilter] +AutomationExecutionFilterList = list[AutomationExecutionFilter] class AutomationExecutionInputs(TypedDict, total=False): - Parameters: Optional[AutomationParameterMap] - TargetParameterName: Optional[AutomationParameterKey] - Targets: Optional[Targets] - TargetMaps: Optional[TargetMaps] - TargetLocations: Optional[TargetLocations] - TargetLocationsURL: Optional[TargetLocationsURL] + Parameters: AutomationParameterMap | None + TargetParameterName: AutomationParameterKey | None + Targets: Targets | None + TargetMaps: TargetMaps | None + TargetLocations: TargetLocations | None + TargetLocationsURL: TargetLocationsURL | None class AutomationExecutionMetadata(TypedDict, total=False): - AutomationExecutionId: Optional[AutomationExecutionId] - DocumentName: Optional[DocumentName] - DocumentVersion: Optional[DocumentVersion] - AutomationExecutionStatus: Optional[AutomationExecutionStatus] - ExecutionStartTime: Optional[DateTime] - ExecutionEndTime: Optional[DateTime] - ExecutedBy: Optional[String] - LogFile: Optional[String] - Outputs: Optional[AutomationParameterMap] - Mode: Optional[ExecutionMode] - ParentAutomationExecutionId: Optional[AutomationExecutionId] - CurrentStepName: Optional[String] - CurrentAction: Optional[String] - FailureMessage: Optional[String] - TargetParameterName: Optional[AutomationParameterKey] - Targets: Optional[Targets] - TargetMaps: Optional[TargetMaps] - ResolvedTargets: Optional[ResolvedTargets] - MaxConcurrency: Optional[MaxConcurrency] - MaxErrors: Optional[MaxErrors] - Target: Optional[String] - AutomationType: Optional[AutomationType] - AlarmConfiguration: Optional[AlarmConfiguration] - TriggeredAlarms: Optional[AlarmStateInformationList] - TargetLocationsURL: Optional[TargetLocationsURL] - AutomationSubtype: Optional[AutomationSubtype] - ScheduledTime: Optional[DateTime] - Runbooks: Optional[Runbooks] - OpsItemId: Optional[String] - AssociationId: Optional[String] - ChangeRequestName: Optional[ChangeRequestName] - - -AutomationExecutionMetadataList = List[AutomationExecutionMetadata] + AutomationExecutionId: AutomationExecutionId | None + DocumentName: DocumentName | None + DocumentVersion: DocumentVersion | None + AutomationExecutionStatus: AutomationExecutionStatus | None + ExecutionStartTime: DateTime | None + ExecutionEndTime: DateTime | None + ExecutedBy: String | None + LogFile: String | None + Outputs: AutomationParameterMap | None + Mode: ExecutionMode | None + ParentAutomationExecutionId: AutomationExecutionId | None + CurrentStepName: String | None + CurrentAction: String | None + FailureMessage: String | None + TargetParameterName: AutomationParameterKey | None + Targets: Targets | None + TargetMaps: TargetMaps | None + ResolvedTargets: ResolvedTargets | None + MaxConcurrency: MaxConcurrency | None + MaxErrors: MaxErrors | None + Target: String | None + AutomationType: AutomationType | None + AlarmConfiguration: AlarmConfiguration | None + TriggeredAlarms: AlarmStateInformationList | None + TargetLocationsURL: TargetLocationsURL | None + AutomationSubtype: AutomationSubtype | None + ScheduledTime: DateTime | None + Runbooks: Runbooks | None + OpsItemId: String | None + AssociationId: String | None + ChangeRequestName: ChangeRequestName | None + + +AutomationExecutionMetadataList = list[AutomationExecutionMetadata] class TargetPreview(TypedDict, total=False): - Count: Optional[Integer] - TargetType: Optional[String] + Count: Integer | None + TargetType: String | None -TargetPreviewList = List[TargetPreview] -RegionList = List[Region] -StepPreviewMap = Dict[ImpactType, Integer] +TargetPreviewList = list[TargetPreview] +RegionList = list[Region] +StepPreviewMap = dict[ImpactType, Integer] class AutomationExecutionPreview(TypedDict, total=False): - StepPreviews: Optional[StepPreviewMap] - Regions: Optional[RegionList] - TargetPreviews: Optional[TargetPreviewList] - TotalAccounts: Optional[Integer] + StepPreviews: StepPreviewMap | None + Regions: RegionList | None + TargetPreviews: TargetPreviewList | None + TotalAccounts: Integer | None -PatchSourceProductList = List[PatchSourceProduct] +PatchSourceProductList = list[PatchSourceProduct] class PatchSource(TypedDict, total=False): @@ -2532,9 +2541,9 @@ class PatchSource(TypedDict, total=False): Configuration: PatchSourceConfiguration -PatchSourceList = List[PatchSource] -PatchIdList = List[PatchId] -PatchFilterValueList = List[PatchFilterValue] +PatchSourceList = list[PatchSource] +PatchIdList = list[PatchId] +PatchFilterValueList = list[PatchFilterValue] class PatchFilter(TypedDict, total=False): @@ -2542,7 +2551,7 @@ class PatchFilter(TypedDict, total=False): Values: PatchFilterValueList -PatchFilterList = List[PatchFilter] +PatchFilterList = list[PatchFilter] class PatchFilterGroup(TypedDict, total=False): @@ -2551,13 +2560,13 @@ class PatchFilterGroup(TypedDict, total=False): class PatchRule(TypedDict, total=False): PatchFilterGroup: PatchFilterGroup - ComplianceLevel: Optional[PatchComplianceLevel] - ApproveAfterDays: Optional[ApproveAfterDays] - ApproveUntilDate: Optional[PatchStringDateTime] - EnableNonSecurity: Optional[Boolean] + ComplianceLevel: PatchComplianceLevel | None + ApproveAfterDays: ApproveAfterDays | None + ApproveUntilDate: PatchStringDateTime | None + EnableNonSecurity: Boolean | None -PatchRuleList = List[PatchRule] +PatchRuleList = list[PatchRule] class PatchRuleGroup(TypedDict, total=False): @@ -2565,24 +2574,24 @@ class PatchRuleGroup(TypedDict, total=False): class BaselineOverride(TypedDict, total=False): - OperatingSystem: Optional[OperatingSystem] - GlobalFilters: Optional[PatchFilterGroup] - ApprovalRules: Optional[PatchRuleGroup] - ApprovedPatches: Optional[PatchIdList] - ApprovedPatchesComplianceLevel: Optional[PatchComplianceLevel] - RejectedPatches: Optional[PatchIdList] - RejectedPatchesAction: Optional[PatchAction] - ApprovedPatchesEnableNonSecurity: Optional[Boolean] - Sources: Optional[PatchSourceList] - AvailableSecurityUpdatesComplianceStatus: Optional[PatchComplianceStatus] + OperatingSystem: OperatingSystem | None + GlobalFilters: PatchFilterGroup | None + ApprovalRules: PatchRuleGroup | None + ApprovedPatches: PatchIdList | None + ApprovedPatchesComplianceLevel: PatchComplianceLevel | None + RejectedPatches: PatchIdList | None + RejectedPatchesAction: PatchAction | None + ApprovedPatchesEnableNonSecurity: Boolean | None + Sources: PatchSourceList | None + AvailableSecurityUpdatesComplianceStatus: PatchComplianceStatus | None -InstanceIdList = List[InstanceId] +InstanceIdList = list[InstanceId] class CancelCommandRequest(ServiceRequest): CommandId: CommandId - InstanceIds: Optional[InstanceIdList] + InstanceIds: InstanceIdList | None class CancelCommandResult(TypedDict, total=False): @@ -2594,54 +2603,54 @@ class CancelMaintenanceWindowExecutionRequest(ServiceRequest): class CancelMaintenanceWindowExecutionResult(TypedDict, total=False): - WindowExecutionId: Optional[MaintenanceWindowExecutionId] + WindowExecutionId: MaintenanceWindowExecutionId | None -CategoryEnumList = List[Category] -CategoryList = List[Category] +CategoryEnumList = list[Category] +CategoryList = list[Category] class CloudWatchOutputConfig(TypedDict, total=False): - CloudWatchLogGroupName: Optional[CloudWatchLogGroupName] - CloudWatchOutputEnabled: Optional[CloudWatchOutputEnabled] + CloudWatchLogGroupName: CloudWatchLogGroupName | None + CloudWatchOutputEnabled: CloudWatchOutputEnabled | None -NotificationEventList = List[NotificationEvent] +NotificationEventList = list[NotificationEvent] class NotificationConfig(TypedDict, total=False): - NotificationArn: Optional[NotificationArn] - NotificationEvents: Optional[NotificationEventList] - NotificationType: Optional[NotificationType] + NotificationArn: NotificationArn | None + NotificationEvents: NotificationEventList | None + NotificationType: NotificationType | None class Command(TypedDict, total=False): - CommandId: Optional[CommandId] - DocumentName: Optional[DocumentName] - DocumentVersion: Optional[DocumentVersion] - Comment: Optional[Comment] - ExpiresAfter: Optional[DateTime] - Parameters: Optional[Parameters] - InstanceIds: Optional[InstanceIdList] - Targets: Optional[Targets] - RequestedDateTime: Optional[DateTime] - Status: Optional[CommandStatus] - StatusDetails: Optional[StatusDetails] - OutputS3Region: Optional[S3Region] - OutputS3BucketName: Optional[S3BucketName] - OutputS3KeyPrefix: Optional[S3KeyPrefix] - MaxConcurrency: Optional[MaxConcurrency] - MaxErrors: Optional[MaxErrors] - TargetCount: Optional[TargetCount] - CompletedCount: Optional[CompletedCount] - ErrorCount: Optional[ErrorCount] - DeliveryTimedOutCount: Optional[DeliveryTimedOutCount] - ServiceRole: Optional[ServiceRole] - NotificationConfig: Optional[NotificationConfig] - CloudWatchOutputConfig: Optional[CloudWatchOutputConfig] - TimeoutSeconds: Optional[TimeoutSeconds] - AlarmConfiguration: Optional[AlarmConfiguration] - TriggeredAlarms: Optional[AlarmStateInformationList] + CommandId: CommandId | None + DocumentName: DocumentName | None + DocumentVersion: DocumentVersion | None + Comment: Comment | None + ExpiresAfter: DateTime | None + Parameters: Parameters | None + InstanceIds: InstanceIdList | None + Targets: Targets | None + RequestedDateTime: DateTime | None + Status: CommandStatus | None + StatusDetails: StatusDetails | None + OutputS3Region: S3Region | None + OutputS3BucketName: S3BucketName | None + OutputS3KeyPrefix: S3KeyPrefix | None + MaxConcurrency: MaxConcurrency | None + MaxErrors: MaxErrors | None + TargetCount: TargetCount | None + CompletedCount: CompletedCount | None + ErrorCount: ErrorCount | None + DeliveryTimedOutCount: DeliveryTimedOutCount | None + ServiceRole: ServiceRole | None + NotificationConfig: NotificationConfig | None + CloudWatchOutputConfig: CloudWatchOutputConfig | None + TimeoutSeconds: TimeoutSeconds | None + AlarmConfiguration: AlarmConfiguration | None + TriggeredAlarms: AlarmStateInformationList | None class CommandFilter(TypedDict, total=False): @@ -2649,121 +2658,121 @@ class CommandFilter(TypedDict, total=False): value: CommandFilterValue -CommandFilterList = List[CommandFilter] +CommandFilterList = list[CommandFilter] class CommandPlugin(TypedDict, total=False): - Name: Optional[CommandPluginName] - Status: Optional[CommandPluginStatus] - StatusDetails: Optional[StatusDetails] - ResponseCode: Optional[ResponseCode] - ResponseStartDateTime: Optional[DateTime] - ResponseFinishDateTime: Optional[DateTime] - Output: Optional[CommandPluginOutput] - StandardOutputUrl: Optional[Url] - StandardErrorUrl: Optional[Url] - OutputS3Region: Optional[S3Region] - OutputS3BucketName: Optional[S3BucketName] - OutputS3KeyPrefix: Optional[S3KeyPrefix] + Name: CommandPluginName | None + Status: CommandPluginStatus | None + StatusDetails: StatusDetails | None + ResponseCode: ResponseCode | None + ResponseStartDateTime: DateTime | None + ResponseFinishDateTime: DateTime | None + Output: CommandPluginOutput | None + StandardOutputUrl: Url | None + StandardErrorUrl: Url | None + OutputS3Region: S3Region | None + OutputS3BucketName: S3BucketName | None + OutputS3KeyPrefix: S3KeyPrefix | None -CommandPluginList = List[CommandPlugin] +CommandPluginList = list[CommandPlugin] class CommandInvocation(TypedDict, total=False): - CommandId: Optional[CommandId] - InstanceId: Optional[InstanceId] - InstanceName: Optional[InstanceTagName] - Comment: Optional[Comment] - DocumentName: Optional[DocumentName] - DocumentVersion: Optional[DocumentVersion] - RequestedDateTime: Optional[DateTime] - Status: Optional[CommandInvocationStatus] - StatusDetails: Optional[StatusDetails] - TraceOutput: Optional[InvocationTraceOutput] - StandardOutputUrl: Optional[Url] - StandardErrorUrl: Optional[Url] - CommandPlugins: Optional[CommandPluginList] - ServiceRole: Optional[ServiceRole] - NotificationConfig: Optional[NotificationConfig] - CloudWatchOutputConfig: Optional[CloudWatchOutputConfig] - - -CommandInvocationList = List[CommandInvocation] -CommandList = List[Command] + CommandId: CommandId | None + InstanceId: InstanceId | None + InstanceName: InstanceTagName | None + Comment: Comment | None + DocumentName: DocumentName | None + DocumentVersion: DocumentVersion | None + RequestedDateTime: DateTime | None + Status: CommandInvocationStatus | None + StatusDetails: StatusDetails | None + TraceOutput: InvocationTraceOutput | None + StandardOutputUrl: Url | None + StandardErrorUrl: Url | None + CommandPlugins: CommandPluginList | None + ServiceRole: ServiceRole | None + NotificationConfig: NotificationConfig | None + CloudWatchOutputConfig: CloudWatchOutputConfig | None + + +CommandInvocationList = list[CommandInvocation] +CommandList = list[Command] class ComplianceExecutionSummary(TypedDict, total=False): ExecutionTime: DateTime - ExecutionId: Optional[ComplianceExecutionId] - ExecutionType: Optional[ComplianceExecutionType] + ExecutionId: ComplianceExecutionId | None + ExecutionType: ComplianceExecutionType | None -ComplianceItemDetails = Dict[AttributeName, AttributeValue] +ComplianceItemDetails = dict[AttributeName, AttributeValue] class ComplianceItem(TypedDict, total=False): - ComplianceType: Optional[ComplianceTypeName] - ResourceType: Optional[ComplianceResourceType] - ResourceId: Optional[ComplianceResourceId] - Id: Optional[ComplianceItemId] - Title: Optional[ComplianceItemTitle] - Status: Optional[ComplianceStatus] - Severity: Optional[ComplianceSeverity] - ExecutionSummary: Optional[ComplianceExecutionSummary] - Details: Optional[ComplianceItemDetails] + ComplianceType: ComplianceTypeName | None + ResourceType: ComplianceResourceType | None + ResourceId: ComplianceResourceId | None + Id: ComplianceItemId | None + Title: ComplianceItemTitle | None + Status: ComplianceStatus | None + Severity: ComplianceSeverity | None + ExecutionSummary: ComplianceExecutionSummary | None + Details: ComplianceItemDetails | None class ComplianceItemEntry(TypedDict, total=False): - Id: Optional[ComplianceItemId] - Title: Optional[ComplianceItemTitle] + Id: ComplianceItemId | None + Title: ComplianceItemTitle | None Severity: ComplianceSeverity Status: ComplianceStatus - Details: Optional[ComplianceItemDetails] + Details: ComplianceItemDetails | None -ComplianceItemEntryList = List[ComplianceItemEntry] -ComplianceItemList = List[ComplianceItem] -ComplianceResourceIdList = List[ComplianceResourceId] -ComplianceResourceTypeList = List[ComplianceResourceType] -ComplianceStringFilterValueList = List[ComplianceFilterValue] +ComplianceItemEntryList = list[ComplianceItemEntry] +ComplianceItemList = list[ComplianceItem] +ComplianceResourceIdList = list[ComplianceResourceId] +ComplianceResourceTypeList = list[ComplianceResourceType] +ComplianceStringFilterValueList = list[ComplianceFilterValue] class ComplianceStringFilter(TypedDict, total=False): - Key: Optional[ComplianceStringFilterKey] - Values: Optional[ComplianceStringFilterValueList] - Type: Optional[ComplianceQueryOperatorType] + Key: ComplianceStringFilterKey | None + Values: ComplianceStringFilterValueList | None + Type: ComplianceQueryOperatorType | None -ComplianceStringFilterList = List[ComplianceStringFilter] +ComplianceStringFilterList = list[ComplianceStringFilter] class SeveritySummary(TypedDict, total=False): - CriticalCount: Optional[ComplianceSummaryCount] - HighCount: Optional[ComplianceSummaryCount] - MediumCount: Optional[ComplianceSummaryCount] - LowCount: Optional[ComplianceSummaryCount] - InformationalCount: Optional[ComplianceSummaryCount] - UnspecifiedCount: Optional[ComplianceSummaryCount] + CriticalCount: ComplianceSummaryCount | None + HighCount: ComplianceSummaryCount | None + MediumCount: ComplianceSummaryCount | None + LowCount: ComplianceSummaryCount | None + InformationalCount: ComplianceSummaryCount | None + UnspecifiedCount: ComplianceSummaryCount | None class NonCompliantSummary(TypedDict, total=False): - NonCompliantCount: Optional[ComplianceSummaryCount] - SeveritySummary: Optional[SeveritySummary] + NonCompliantCount: ComplianceSummaryCount | None + SeveritySummary: SeveritySummary | None class CompliantSummary(TypedDict, total=False): - CompliantCount: Optional[ComplianceSummaryCount] - SeveritySummary: Optional[SeveritySummary] + CompliantCount: ComplianceSummaryCount | None + SeveritySummary: SeveritySummary | None class ComplianceSummaryItem(TypedDict, total=False): - ComplianceType: Optional[ComplianceTypeName] - CompliantSummary: Optional[CompliantSummary] - NonCompliantSummary: Optional[NonCompliantSummary] + ComplianceType: ComplianceTypeName | None + CompliantSummary: CompliantSummary | None + NonCompliantSummary: NonCompliantSummary | None -ComplianceSummaryItemList = List[ComplianceSummaryItem] +ComplianceSummaryItemList = list[ComplianceSummaryItem] class RegistrationMetadataItem(TypedDict, total=False): @@ -2771,320 +2780,322 @@ class RegistrationMetadataItem(TypedDict, total=False): Value: RegistrationMetadataValue -RegistrationMetadataList = List[RegistrationMetadataItem] +RegistrationMetadataList = list[RegistrationMetadataItem] class CreateActivationRequest(ServiceRequest): - Description: Optional[ActivationDescription] - DefaultInstanceName: Optional[DefaultInstanceName] + Description: ActivationDescription | None + DefaultInstanceName: DefaultInstanceName | None IamRole: IamRole - RegistrationLimit: Optional[RegistrationLimit] - ExpirationDate: Optional[ExpirationDate] - Tags: Optional[TagList] - RegistrationMetadata: Optional[RegistrationMetadataList] + RegistrationLimit: RegistrationLimit | None + ExpirationDate: ExpirationDate | None + Tags: TagList | None + RegistrationMetadata: RegistrationMetadataList | None class CreateActivationResult(TypedDict, total=False): - ActivationId: Optional[ActivationId] - ActivationCode: Optional[ActivationCode] + ActivationId: ActivationId | None + ActivationCode: ActivationCode | None class CreateAssociationBatchRequestEntry(TypedDict, total=False): Name: DocumentARN - InstanceId: Optional[InstanceId] - Parameters: Optional[Parameters] - AutomationTargetParameterName: Optional[AutomationTargetParameterName] - DocumentVersion: Optional[DocumentVersion] - Targets: Optional[Targets] - ScheduleExpression: Optional[ScheduleExpression] - OutputLocation: Optional[InstanceAssociationOutputLocation] - AssociationName: Optional[AssociationName] - MaxErrors: Optional[MaxErrors] - MaxConcurrency: Optional[MaxConcurrency] - ComplianceSeverity: Optional[AssociationComplianceSeverity] - SyncCompliance: Optional[AssociationSyncCompliance] - ApplyOnlyAtCronInterval: Optional[ApplyOnlyAtCronInterval] - CalendarNames: Optional[CalendarNameOrARNList] - TargetLocations: Optional[TargetLocations] - ScheduleOffset: Optional[ScheduleOffset] - Duration: Optional[Duration] - TargetMaps: Optional[TargetMaps] - AlarmConfiguration: Optional[AlarmConfiguration] - - -CreateAssociationBatchRequestEntries = List[CreateAssociationBatchRequestEntry] + InstanceId: InstanceId | None + Parameters: Parameters | None + AutomationTargetParameterName: AutomationTargetParameterName | None + DocumentVersion: DocumentVersion | None + Targets: Targets | None + ScheduleExpression: ScheduleExpression | None + OutputLocation: InstanceAssociationOutputLocation | None + AssociationName: AssociationName | None + MaxErrors: MaxErrors | None + MaxConcurrency: MaxConcurrency | None + ComplianceSeverity: AssociationComplianceSeverity | None + SyncCompliance: AssociationSyncCompliance | None + ApplyOnlyAtCronInterval: ApplyOnlyAtCronInterval | None + CalendarNames: CalendarNameOrARNList | None + TargetLocations: TargetLocations | None + ScheduleOffset: ScheduleOffset | None + Duration: Duration | None + TargetMaps: TargetMaps | None + AlarmConfiguration: AlarmConfiguration | None + + +CreateAssociationBatchRequestEntries = list[CreateAssociationBatchRequestEntry] class CreateAssociationBatchRequest(ServiceRequest): Entries: CreateAssociationBatchRequestEntries + AssociationDispatchAssumeRole: AssociationDispatchAssumeRoleArn | None class FailedCreateAssociation(TypedDict, total=False): - Entry: Optional[CreateAssociationBatchRequestEntry] - Message: Optional[BatchErrorMessage] - Fault: Optional[Fault] + Entry: CreateAssociationBatchRequestEntry | None + Message: BatchErrorMessage | None + Fault: Fault | None -FailedCreateAssociationList = List[FailedCreateAssociation] +FailedCreateAssociationList = list[FailedCreateAssociation] class CreateAssociationBatchResult(TypedDict, total=False): - Successful: Optional[AssociationDescriptionList] - Failed: Optional[FailedCreateAssociationList] + Successful: AssociationDescriptionList | None + Failed: FailedCreateAssociationList | None class CreateAssociationRequest(ServiceRequest): Name: DocumentARN - DocumentVersion: Optional[DocumentVersion] - InstanceId: Optional[InstanceId] - Parameters: Optional[Parameters] - Targets: Optional[Targets] - ScheduleExpression: Optional[ScheduleExpression] - OutputLocation: Optional[InstanceAssociationOutputLocation] - AssociationName: Optional[AssociationName] - AutomationTargetParameterName: Optional[AutomationTargetParameterName] - MaxErrors: Optional[MaxErrors] - MaxConcurrency: Optional[MaxConcurrency] - ComplianceSeverity: Optional[AssociationComplianceSeverity] - SyncCompliance: Optional[AssociationSyncCompliance] - ApplyOnlyAtCronInterval: Optional[ApplyOnlyAtCronInterval] - CalendarNames: Optional[CalendarNameOrARNList] - TargetLocations: Optional[TargetLocations] - ScheduleOffset: Optional[ScheduleOffset] - Duration: Optional[Duration] - TargetMaps: Optional[TargetMaps] - Tags: Optional[TagList] - AlarmConfiguration: Optional[AlarmConfiguration] + DocumentVersion: DocumentVersion | None + InstanceId: InstanceId | None + Parameters: Parameters | None + Targets: Targets | None + ScheduleExpression: ScheduleExpression | None + OutputLocation: InstanceAssociationOutputLocation | None + AssociationName: AssociationName | None + AutomationTargetParameterName: AutomationTargetParameterName | None + MaxErrors: MaxErrors | None + MaxConcurrency: MaxConcurrency | None + ComplianceSeverity: AssociationComplianceSeverity | None + SyncCompliance: AssociationSyncCompliance | None + ApplyOnlyAtCronInterval: ApplyOnlyAtCronInterval | None + CalendarNames: CalendarNameOrARNList | None + TargetLocations: TargetLocations | None + ScheduleOffset: ScheduleOffset | None + Duration: Duration | None + TargetMaps: TargetMaps | None + Tags: TagList | None + AlarmConfiguration: AlarmConfiguration | None + AssociationDispatchAssumeRole: AssociationDispatchAssumeRoleArn | None class CreateAssociationResult(TypedDict, total=False): - AssociationDescription: Optional[AssociationDescription] + AssociationDescription: AssociationDescription | None class DocumentRequires(TypedDict, total=False): Name: DocumentARN - Version: Optional[DocumentVersion] - RequireType: Optional[RequireType] - VersionName: Optional[DocumentVersionName] + Version: DocumentVersion | None + RequireType: RequireType | None + VersionName: DocumentVersionName | None -DocumentRequiresList = List[DocumentRequires] +DocumentRequiresList = list[DocumentRequires] class CreateDocumentRequest(ServiceRequest): Content: DocumentContent - Requires: Optional[DocumentRequiresList] - Attachments: Optional[AttachmentsSourceList] + Requires: DocumentRequiresList | None + Attachments: AttachmentsSourceList | None Name: DocumentName - DisplayName: Optional[DocumentDisplayName] - VersionName: Optional[DocumentVersionName] - DocumentType: Optional[DocumentType] - DocumentFormat: Optional[DocumentFormat] - TargetType: Optional[TargetType] - Tags: Optional[TagList] + DisplayName: DocumentDisplayName | None + VersionName: DocumentVersionName | None + DocumentType: DocumentType | None + DocumentFormat: DocumentFormat | None + TargetType: TargetType | None + Tags: TagList | None class ReviewInformation(TypedDict, total=False): - ReviewedTime: Optional[DateTime] - Status: Optional[ReviewStatus] - Reviewer: Optional[Reviewer] + ReviewedTime: DateTime | None + Status: ReviewStatus | None + Reviewer: Reviewer | None -ReviewInformationList = List[ReviewInformation] -PlatformTypeList = List[PlatformType] +ReviewInformationList = list[ReviewInformation] +PlatformTypeList = list[PlatformType] class DocumentParameter(TypedDict, total=False): - Name: Optional[DocumentParameterName] - Type: Optional[DocumentParameterType] - Description: Optional[DocumentParameterDescrption] - DefaultValue: Optional[DocumentParameterDefaultValue] + Name: DocumentParameterName | None + Type: DocumentParameterType | None + Description: DocumentParameterDescrption | None + DefaultValue: DocumentParameterDefaultValue | None -DocumentParameterList = List[DocumentParameter] +DocumentParameterList = list[DocumentParameter] class DocumentDescription(TypedDict, total=False): - Sha1: Optional[DocumentSha1] - Hash: Optional[DocumentHash] - HashType: Optional[DocumentHashType] - Name: Optional[DocumentARN] - DisplayName: Optional[DocumentDisplayName] - VersionName: Optional[DocumentVersionName] - Owner: Optional[DocumentOwner] - CreatedDate: Optional[DateTime] - Status: Optional[DocumentStatus] - StatusInformation: Optional[DocumentStatusInformation] - DocumentVersion: Optional[DocumentVersion] - Description: Optional[DescriptionInDocument] - Parameters: Optional[DocumentParameterList] - PlatformTypes: Optional[PlatformTypeList] - DocumentType: Optional[DocumentType] - SchemaVersion: Optional[DocumentSchemaVersion] - LatestVersion: Optional[DocumentVersion] - DefaultVersion: Optional[DocumentVersion] - DocumentFormat: Optional[DocumentFormat] - TargetType: Optional[TargetType] - Tags: Optional[TagList] - AttachmentsInformation: Optional[AttachmentInformationList] - Requires: Optional[DocumentRequiresList] - Author: Optional[DocumentAuthor] - ReviewInformation: Optional[ReviewInformationList] - ApprovedVersion: Optional[DocumentVersion] - PendingReviewVersion: Optional[DocumentVersion] - ReviewStatus: Optional[ReviewStatus] - Category: Optional[CategoryList] - CategoryEnum: Optional[CategoryEnumList] + Sha1: DocumentSha1 | None + Hash: DocumentHash | None + HashType: DocumentHashType | None + Name: DocumentARN | None + DisplayName: DocumentDisplayName | None + VersionName: DocumentVersionName | None + Owner: DocumentOwner | None + CreatedDate: DateTime | None + Status: DocumentStatus | None + StatusInformation: DocumentStatusInformation | None + DocumentVersion: DocumentVersion | None + Description: DescriptionInDocument | None + Parameters: DocumentParameterList | None + PlatformTypes: PlatformTypeList | None + DocumentType: DocumentType | None + SchemaVersion: DocumentSchemaVersion | None + LatestVersion: DocumentVersion | None + DefaultVersion: DocumentVersion | None + DocumentFormat: DocumentFormat | None + TargetType: TargetType | None + Tags: TagList | None + AttachmentsInformation: AttachmentInformationList | None + Requires: DocumentRequiresList | None + Author: DocumentAuthor | None + ReviewInformation: ReviewInformationList | None + ApprovedVersion: DocumentVersion | None + PendingReviewVersion: DocumentVersion | None + ReviewStatus: ReviewStatus | None + Category: CategoryList | None + CategoryEnum: CategoryEnumList | None class CreateDocumentResult(TypedDict, total=False): - DocumentDescription: Optional[DocumentDescription] + DocumentDescription: DocumentDescription | None class CreateMaintenanceWindowRequest(ServiceRequest): Name: MaintenanceWindowName - Description: Optional[MaintenanceWindowDescription] - StartDate: Optional[MaintenanceWindowStringDateTime] - EndDate: Optional[MaintenanceWindowStringDateTime] + Description: MaintenanceWindowDescription | None + StartDate: MaintenanceWindowStringDateTime | None + EndDate: MaintenanceWindowStringDateTime | None Schedule: MaintenanceWindowSchedule - ScheduleTimezone: Optional[MaintenanceWindowTimezone] - ScheduleOffset: Optional[MaintenanceWindowOffset] + ScheduleTimezone: MaintenanceWindowTimezone | None + ScheduleOffset: MaintenanceWindowOffset | None Duration: MaintenanceWindowDurationHours Cutoff: MaintenanceWindowCutoff AllowUnassociatedTargets: MaintenanceWindowAllowUnassociatedTargets - ClientToken: Optional[ClientToken] - Tags: Optional[TagList] + ClientToken: ClientToken | None + Tags: TagList | None class CreateMaintenanceWindowResult(TypedDict, total=False): - WindowId: Optional[MaintenanceWindowId] + WindowId: MaintenanceWindowId | None class RelatedOpsItem(TypedDict, total=False): OpsItemId: String -RelatedOpsItems = List[RelatedOpsItem] +RelatedOpsItems = list[RelatedOpsItem] class OpsItemNotification(TypedDict, total=False): - Arn: Optional[String] + Arn: String | None -OpsItemNotifications = List[OpsItemNotification] +OpsItemNotifications = list[OpsItemNotification] class OpsItemDataValue(TypedDict, total=False): - Value: Optional[OpsItemDataValueString] - Type: Optional[OpsItemDataType] + Value: OpsItemDataValueString | None + Type: OpsItemDataType | None -OpsItemOperationalData = Dict[OpsItemDataKey, OpsItemDataValue] +OpsItemOperationalData = dict[OpsItemDataKey, OpsItemDataValue] class CreateOpsItemRequest(ServiceRequest): Description: OpsItemDescription - OpsItemType: Optional[OpsItemType] - OperationalData: Optional[OpsItemOperationalData] - Notifications: Optional[OpsItemNotifications] - Priority: Optional[OpsItemPriority] - RelatedOpsItems: Optional[RelatedOpsItems] + OpsItemType: OpsItemType | None + OperationalData: OpsItemOperationalData | None + Notifications: OpsItemNotifications | None + Priority: OpsItemPriority | None + RelatedOpsItems: RelatedOpsItems | None Source: OpsItemSource Title: OpsItemTitle - Tags: Optional[TagList] - Category: Optional[OpsItemCategory] - Severity: Optional[OpsItemSeverity] - ActualStartTime: Optional[DateTime] - ActualEndTime: Optional[DateTime] - PlannedStartTime: Optional[DateTime] - PlannedEndTime: Optional[DateTime] - AccountId: Optional[OpsItemAccountId] + Tags: TagList | None + Category: OpsItemCategory | None + Severity: OpsItemSeverity | None + ActualStartTime: DateTime | None + ActualEndTime: DateTime | None + PlannedStartTime: DateTime | None + PlannedEndTime: DateTime | None + AccountId: OpsItemAccountId | None class CreateOpsItemResponse(TypedDict, total=False): - OpsItemId: Optional[String] - OpsItemArn: Optional[OpsItemArn] + OpsItemId: String | None + OpsItemArn: OpsItemArn | None class MetadataValue(TypedDict, total=False): - Value: Optional[MetadataValueString] + Value: MetadataValueString | None -MetadataMap = Dict[MetadataKey, MetadataValue] +MetadataMap = dict[MetadataKey, MetadataValue] class CreateOpsMetadataRequest(ServiceRequest): ResourceId: OpsMetadataResourceId - Metadata: Optional[MetadataMap] - Tags: Optional[TagList] + Metadata: MetadataMap | None + Tags: TagList | None class CreateOpsMetadataResult(TypedDict, total=False): - OpsMetadataArn: Optional[OpsMetadataArn] + OpsMetadataArn: OpsMetadataArn | None class CreatePatchBaselineRequest(ServiceRequest): - OperatingSystem: Optional[OperatingSystem] + OperatingSystem: OperatingSystem | None Name: BaselineName - GlobalFilters: Optional[PatchFilterGroup] - ApprovalRules: Optional[PatchRuleGroup] - ApprovedPatches: Optional[PatchIdList] - ApprovedPatchesComplianceLevel: Optional[PatchComplianceLevel] - ApprovedPatchesEnableNonSecurity: Optional[Boolean] - RejectedPatches: Optional[PatchIdList] - RejectedPatchesAction: Optional[PatchAction] - Description: Optional[BaselineDescription] - Sources: Optional[PatchSourceList] - AvailableSecurityUpdatesComplianceStatus: Optional[PatchComplianceStatus] - ClientToken: Optional[ClientToken] - Tags: Optional[TagList] + GlobalFilters: PatchFilterGroup | None + ApprovalRules: PatchRuleGroup | None + ApprovedPatches: PatchIdList | None + ApprovedPatchesComplianceLevel: PatchComplianceLevel | None + ApprovedPatchesEnableNonSecurity: Boolean | None + RejectedPatches: PatchIdList | None + RejectedPatchesAction: PatchAction | None + Description: BaselineDescription | None + Sources: PatchSourceList | None + AvailableSecurityUpdatesComplianceStatus: PatchComplianceStatus | None + ClientToken: ClientToken | None + Tags: TagList | None class CreatePatchBaselineResult(TypedDict, total=False): - BaselineId: Optional[BaselineId] + BaselineId: BaselineId | None -ResourceDataSyncSourceRegionList = List[ResourceDataSyncSourceRegion] +ResourceDataSyncSourceRegionList = list[ResourceDataSyncSourceRegion] class ResourceDataSyncOrganizationalUnit(TypedDict, total=False): - OrganizationalUnitId: Optional[ResourceDataSyncOrganizationalUnitId] + OrganizationalUnitId: ResourceDataSyncOrganizationalUnitId | None -ResourceDataSyncOrganizationalUnitList = List[ResourceDataSyncOrganizationalUnit] +ResourceDataSyncOrganizationalUnitList = list[ResourceDataSyncOrganizationalUnit] class ResourceDataSyncAwsOrganizationsSource(TypedDict, total=False): OrganizationSourceType: ResourceDataSyncOrganizationSourceType - OrganizationalUnits: Optional[ResourceDataSyncOrganizationalUnitList] + OrganizationalUnits: ResourceDataSyncOrganizationalUnitList | None class ResourceDataSyncSource(TypedDict, total=False): SourceType: ResourceDataSyncSourceType - AwsOrganizationsSource: Optional[ResourceDataSyncAwsOrganizationsSource] + AwsOrganizationsSource: ResourceDataSyncAwsOrganizationsSource | None SourceRegions: ResourceDataSyncSourceRegionList - IncludeFutureRegions: Optional[ResourceDataSyncIncludeFutureRegions] - EnableAllOpsDataSources: Optional[ResourceDataSyncEnableAllOpsDataSources] + IncludeFutureRegions: ResourceDataSyncIncludeFutureRegions | None + EnableAllOpsDataSources: ResourceDataSyncEnableAllOpsDataSources | None class ResourceDataSyncDestinationDataSharing(TypedDict, total=False): - DestinationDataSharingType: Optional[ResourceDataSyncDestinationDataSharingType] + DestinationDataSharingType: ResourceDataSyncDestinationDataSharingType | None class ResourceDataSyncS3Destination(TypedDict, total=False): BucketName: ResourceDataSyncS3BucketName - Prefix: Optional[ResourceDataSyncS3Prefix] + Prefix: ResourceDataSyncS3Prefix | None SyncFormat: ResourceDataSyncS3Format Region: ResourceDataSyncS3Region - AWSKMSKeyARN: Optional[ResourceDataSyncAWSKMSKeyARN] - DestinationDataSharing: Optional[ResourceDataSyncDestinationDataSharing] + AWSKMSKeyARN: ResourceDataSyncAWSKMSKeyARN | None + DestinationDataSharing: ResourceDataSyncDestinationDataSharing | None class CreateResourceDataSyncRequest(ServiceRequest): SyncName: ResourceDataSyncName - S3Destination: Optional[ResourceDataSyncS3Destination] - SyncType: Optional[ResourceDataSyncType] - SyncSource: Optional[ResourceDataSyncSource] + S3Destination: ResourceDataSyncS3Destination | None + SyncType: ResourceDataSyncType | None + SyncSource: ResourceDataSyncSource | None class CreateResourceDataSyncResult(TypedDict, total=False): @@ -3107,9 +3118,9 @@ class DeleteActivationResult(TypedDict, total=False): class DeleteAssociationRequest(ServiceRequest): - Name: Optional[DocumentARN] - InstanceId: Optional[InstanceId] - AssociationId: Optional[AssociationId] + Name: DocumentARN | None + InstanceId: InstanceId | None + AssociationId: AssociationId | None class DeleteAssociationResult(TypedDict, total=False): @@ -3118,9 +3129,9 @@ class DeleteAssociationResult(TypedDict, total=False): class DeleteDocumentRequest(ServiceRequest): Name: DocumentName - DocumentVersion: Optional[DocumentVersion] - VersionName: Optional[DocumentVersionName] - Force: Optional[Boolean] + DocumentVersion: DocumentVersion | None + VersionName: DocumentVersionName | None + Force: Boolean | None class DeleteDocumentResult(TypedDict, total=False): @@ -3129,30 +3140,30 @@ class DeleteDocumentResult(TypedDict, total=False): class DeleteInventoryRequest(ServiceRequest): TypeName: InventoryItemTypeName - SchemaDeleteOption: Optional[InventorySchemaDeleteOption] - DryRun: Optional[DryRun] - ClientToken: Optional[UUID] + SchemaDeleteOption: InventorySchemaDeleteOption | None + DryRun: DryRun | None + ClientToken: UUID | None class InventoryDeletionSummaryItem(TypedDict, total=False): - Version: Optional[InventoryItemSchemaVersion] - Count: Optional[ResourceCount] - RemainingCount: Optional[RemainingCount] + Version: InventoryItemSchemaVersion | None + Count: ResourceCount | None + RemainingCount: RemainingCount | None -InventoryDeletionSummaryItems = List[InventoryDeletionSummaryItem] +InventoryDeletionSummaryItems = list[InventoryDeletionSummaryItem] class InventoryDeletionSummary(TypedDict, total=False): - TotalCount: Optional[TotalCount] - RemainingCount: Optional[RemainingCount] - SummaryItems: Optional[InventoryDeletionSummaryItems] + TotalCount: TotalCount | None + RemainingCount: RemainingCount | None + SummaryItems: InventoryDeletionSummaryItems | None class DeleteInventoryResult(TypedDict, total=False): - DeletionId: Optional[UUID] - TypeName: Optional[InventoryItemTypeName] - DeletionSummary: Optional[InventoryDeletionSummary] + DeletionId: UUID | None + TypeName: InventoryItemTypeName | None + DeletionSummary: InventoryDeletionSummary | None class DeleteMaintenanceWindowRequest(ServiceRequest): @@ -3160,7 +3171,7 @@ class DeleteMaintenanceWindowRequest(ServiceRequest): class DeleteMaintenanceWindowResult(TypedDict, total=False): - WindowId: Optional[MaintenanceWindowId] + WindowId: MaintenanceWindowId | None class DeleteOpsItemRequest(ServiceRequest): @@ -3187,7 +3198,7 @@ class DeleteParameterResult(TypedDict, total=False): pass -ParameterNameList = List[PSParameterName] +ParameterNameList = list[PSParameterName] class DeleteParametersRequest(ServiceRequest): @@ -3195,8 +3206,8 @@ class DeleteParametersRequest(ServiceRequest): class DeleteParametersResult(TypedDict, total=False): - DeletedParameters: Optional[ParameterNameList] - InvalidParameters: Optional[ParameterNameList] + DeletedParameters: ParameterNameList | None + InvalidParameters: ParameterNameList | None class DeletePatchBaselineRequest(ServiceRequest): @@ -3204,12 +3215,12 @@ class DeletePatchBaselineRequest(ServiceRequest): class DeletePatchBaselineResult(TypedDict, total=False): - BaselineId: Optional[BaselineId] + BaselineId: BaselineId | None class DeleteResourceDataSyncRequest(ServiceRequest): SyncName: ResourceDataSyncName - SyncType: Optional[ResourceDataSyncType] + SyncType: ResourceDataSyncType | None class DeleteResourceDataSyncResult(TypedDict, total=False): @@ -3240,19 +3251,19 @@ class DeregisterPatchBaselineForPatchGroupRequest(ServiceRequest): class DeregisterPatchBaselineForPatchGroupResult(TypedDict, total=False): - BaselineId: Optional[BaselineId] - PatchGroup: Optional[PatchGroup] + BaselineId: BaselineId | None + PatchGroup: PatchGroup | None class DeregisterTargetFromMaintenanceWindowRequest(ServiceRequest): WindowId: MaintenanceWindowId WindowTargetId: MaintenanceWindowTargetId - Safe: Optional[Boolean] + Safe: Boolean | None class DeregisterTargetFromMaintenanceWindowResult(TypedDict, total=False): - WindowId: Optional[MaintenanceWindowId] - WindowTargetId: Optional[MaintenanceWindowTargetId] + WindowId: MaintenanceWindowId | None + WindowTargetId: MaintenanceWindowTargetId | None class DeregisterTaskFromMaintenanceWindowRequest(ServiceRequest): @@ -3261,80 +3272,80 @@ class DeregisterTaskFromMaintenanceWindowRequest(ServiceRequest): class DeregisterTaskFromMaintenanceWindowResult(TypedDict, total=False): - WindowId: Optional[MaintenanceWindowId] - WindowTaskId: Optional[MaintenanceWindowTaskId] + WindowId: MaintenanceWindowId | None + WindowTaskId: MaintenanceWindowTaskId | None -StringList = List[String] +StringList = list[String] class DescribeActivationsFilter(TypedDict, total=False): - FilterKey: Optional[DescribeActivationsFilterKeys] - FilterValues: Optional[StringList] + FilterKey: DescribeActivationsFilterKeys | None + FilterValues: StringList | None -DescribeActivationsFilterList = List[DescribeActivationsFilter] +DescribeActivationsFilterList = list[DescribeActivationsFilter] class DescribeActivationsRequest(ServiceRequest): - Filters: Optional[DescribeActivationsFilterList] - MaxResults: Optional[MaxResults] - NextToken: Optional[NextToken] + Filters: DescribeActivationsFilterList | None + MaxResults: MaxResults | None + NextToken: NextToken | None class DescribeActivationsResult(TypedDict, total=False): - ActivationList: Optional[ActivationList] - NextToken: Optional[NextToken] + ActivationList: ActivationList | None + NextToken: NextToken | None class DescribeAssociationExecutionTargetsRequest(ServiceRequest): AssociationId: AssociationId ExecutionId: AssociationExecutionId - Filters: Optional[AssociationExecutionTargetsFilterList] - MaxResults: Optional[MaxResults] - NextToken: Optional[NextToken] + Filters: AssociationExecutionTargetsFilterList | None + MaxResults: MaxResults | None + NextToken: NextToken | None class DescribeAssociationExecutionTargetsResult(TypedDict, total=False): - AssociationExecutionTargets: Optional[AssociationExecutionTargetsList] - NextToken: Optional[NextToken] + AssociationExecutionTargets: AssociationExecutionTargetsList | None + NextToken: NextToken | None class DescribeAssociationExecutionsRequest(ServiceRequest): AssociationId: AssociationId - Filters: Optional[AssociationExecutionFilterList] - MaxResults: Optional[MaxResults] - NextToken: Optional[NextToken] + Filters: AssociationExecutionFilterList | None + MaxResults: MaxResults | None + NextToken: NextToken | None class DescribeAssociationExecutionsResult(TypedDict, total=False): - AssociationExecutions: Optional[AssociationExecutionsList] - NextToken: Optional[NextToken] + AssociationExecutions: AssociationExecutionsList | None + NextToken: NextToken | None class DescribeAssociationRequest(ServiceRequest): - Name: Optional[DocumentARN] - InstanceId: Optional[InstanceId] - AssociationId: Optional[AssociationId] - AssociationVersion: Optional[AssociationVersion] + Name: DocumentARN | None + InstanceId: InstanceId | None + AssociationId: AssociationId | None + AssociationVersion: AssociationVersion | None class DescribeAssociationResult(TypedDict, total=False): - AssociationDescription: Optional[AssociationDescription] + AssociationDescription: AssociationDescription | None class DescribeAutomationExecutionsRequest(ServiceRequest): - Filters: Optional[AutomationExecutionFilterList] - MaxResults: Optional[MaxResults] - NextToken: Optional[NextToken] + Filters: AutomationExecutionFilterList | None + MaxResults: MaxResults | None + NextToken: NextToken | None class DescribeAutomationExecutionsResult(TypedDict, total=False): - AutomationExecutionMetadataList: Optional[AutomationExecutionMetadataList] - NextToken: Optional[NextToken] + AutomationExecutionMetadataList: AutomationExecutionMetadataList | None + NextToken: NextToken | None -StepExecutionFilterValueList = List[StepExecutionFilterValue] +StepExecutionFilterValueList = list[StepExecutionFilterValue] class StepExecutionFilter(TypedDict, total=False): @@ -3342,185 +3353,185 @@ class StepExecutionFilter(TypedDict, total=False): Values: StepExecutionFilterValueList -StepExecutionFilterList = List[StepExecutionFilter] +StepExecutionFilterList = list[StepExecutionFilter] class DescribeAutomationStepExecutionsRequest(ServiceRequest): AutomationExecutionId: AutomationExecutionId - Filters: Optional[StepExecutionFilterList] - NextToken: Optional[NextToken] - MaxResults: Optional[MaxResults] - ReverseOrder: Optional[Boolean] + Filters: StepExecutionFilterList | None + NextToken: NextToken | None + MaxResults: MaxResults | None + ReverseOrder: Boolean | None class DescribeAutomationStepExecutionsResult(TypedDict, total=False): - StepExecutions: Optional[StepExecutionList] - NextToken: Optional[NextToken] + StepExecutions: StepExecutionList | None + NextToken: NextToken | None -PatchOrchestratorFilterValues = List[PatchOrchestratorFilterValue] +PatchOrchestratorFilterValues = list[PatchOrchestratorFilterValue] class PatchOrchestratorFilter(TypedDict, total=False): - Key: Optional[PatchOrchestratorFilterKey] - Values: Optional[PatchOrchestratorFilterValues] + Key: PatchOrchestratorFilterKey | None + Values: PatchOrchestratorFilterValues | None -PatchOrchestratorFilterList = List[PatchOrchestratorFilter] +PatchOrchestratorFilterList = list[PatchOrchestratorFilter] class DescribeAvailablePatchesRequest(ServiceRequest): - Filters: Optional[PatchOrchestratorFilterList] - MaxResults: Optional[PatchBaselineMaxResults] - NextToken: Optional[NextToken] + Filters: PatchOrchestratorFilterList | None + MaxResults: PatchBaselineMaxResults | None + NextToken: NextToken | None -PatchCVEIdList = List[PatchCVEId] -PatchBugzillaIdList = List[PatchBugzillaId] -PatchAdvisoryIdList = List[PatchAdvisoryId] +PatchCVEIdList = list[PatchCVEId] +PatchBugzillaIdList = list[PatchBugzillaId] +PatchAdvisoryIdList = list[PatchAdvisoryId] class Patch(TypedDict, total=False): - Id: Optional[PatchId] - ReleaseDate: Optional[DateTime] - Title: Optional[PatchTitle] - Description: Optional[PatchDescription] - ContentUrl: Optional[PatchContentUrl] - Vendor: Optional[PatchVendor] - ProductFamily: Optional[PatchProductFamily] - Product: Optional[PatchProduct] - Classification: Optional[PatchClassification] - MsrcSeverity: Optional[PatchMsrcSeverity] - KbNumber: Optional[PatchKbNumber] - MsrcNumber: Optional[PatchMsrcNumber] - Language: Optional[PatchLanguage] - AdvisoryIds: Optional[PatchAdvisoryIdList] - BugzillaIds: Optional[PatchBugzillaIdList] - CVEIds: Optional[PatchCVEIdList] - Name: Optional[PatchName] - Epoch: Optional[PatchEpoch] - Version: Optional[PatchVersion] - Release: Optional[PatchRelease] - Arch: Optional[PatchArch] - Severity: Optional[PatchSeverity] - Repository: Optional[PatchRepository] - - -PatchList = List[Patch] + Id: PatchId | None + ReleaseDate: DateTime | None + Title: PatchTitle | None + Description: PatchDescription | None + ContentUrl: PatchContentUrl | None + Vendor: PatchVendor | None + ProductFamily: PatchProductFamily | None + Product: PatchProduct | None + Classification: PatchClassification | None + MsrcSeverity: PatchMsrcSeverity | None + KbNumber: PatchKbNumber | None + MsrcNumber: PatchMsrcNumber | None + Language: PatchLanguage | None + AdvisoryIds: PatchAdvisoryIdList | None + BugzillaIds: PatchBugzillaIdList | None + CVEIds: PatchCVEIdList | None + Name: PatchName | None + Epoch: PatchEpoch | None + Version: PatchVersion | None + Release: PatchRelease | None + Arch: PatchArch | None + Severity: PatchSeverity | None + Repository: PatchRepository | None + + +PatchList = list[Patch] class DescribeAvailablePatchesResult(TypedDict, total=False): - Patches: Optional[PatchList] - NextToken: Optional[NextToken] + Patches: PatchList | None + NextToken: NextToken | None class DescribeDocumentPermissionRequest(ServiceRequest): Name: DocumentName PermissionType: DocumentPermissionType - MaxResults: Optional[DocumentPermissionMaxResults] - NextToken: Optional[NextToken] + MaxResults: DocumentPermissionMaxResults | None + NextToken: NextToken | None class DescribeDocumentPermissionResponse(TypedDict, total=False): - AccountIds: Optional[AccountIdList] - AccountSharingInfoList: Optional[AccountSharingInfoList] - NextToken: Optional[NextToken] + AccountIds: AccountIdList | None + AccountSharingInfoList: AccountSharingInfoList | None + NextToken: NextToken | None class DescribeDocumentRequest(ServiceRequest): Name: DocumentARN - DocumentVersion: Optional[DocumentVersion] - VersionName: Optional[DocumentVersionName] + DocumentVersion: DocumentVersion | None + VersionName: DocumentVersionName | None class DescribeDocumentResult(TypedDict, total=False): - Document: Optional[DocumentDescription] + Document: DocumentDescription | None class DescribeEffectiveInstanceAssociationsRequest(ServiceRequest): InstanceId: InstanceId - MaxResults: Optional[EffectiveInstanceAssociationMaxResults] - NextToken: Optional[NextToken] + MaxResults: EffectiveInstanceAssociationMaxResults | None + NextToken: NextToken | None class InstanceAssociation(TypedDict, total=False): - AssociationId: Optional[AssociationId] - InstanceId: Optional[InstanceId] - Content: Optional[DocumentContent] - AssociationVersion: Optional[AssociationVersion] + AssociationId: AssociationId | None + InstanceId: InstanceId | None + Content: DocumentContent | None + AssociationVersion: AssociationVersion | None -InstanceAssociationList = List[InstanceAssociation] +InstanceAssociationList = list[InstanceAssociation] class DescribeEffectiveInstanceAssociationsResult(TypedDict, total=False): - Associations: Optional[InstanceAssociationList] - NextToken: Optional[NextToken] + Associations: InstanceAssociationList | None + NextToken: NextToken | None class DescribeEffectivePatchesForPatchBaselineRequest(ServiceRequest): BaselineId: BaselineId - MaxResults: Optional[PatchBaselineMaxResults] - NextToken: Optional[NextToken] + MaxResults: PatchBaselineMaxResults | None + NextToken: NextToken | None class PatchStatus(TypedDict, total=False): - DeploymentStatus: Optional[PatchDeploymentStatus] - ComplianceLevel: Optional[PatchComplianceLevel] - ApprovalDate: Optional[DateTime] + DeploymentStatus: PatchDeploymentStatus | None + ComplianceLevel: PatchComplianceLevel | None + ApprovalDate: DateTime | None class EffectivePatch(TypedDict, total=False): - Patch: Optional[Patch] - PatchStatus: Optional[PatchStatus] + Patch: Patch | None + PatchStatus: PatchStatus | None -EffectivePatchList = List[EffectivePatch] +EffectivePatchList = list[EffectivePatch] class DescribeEffectivePatchesForPatchBaselineResult(TypedDict, total=False): - EffectivePatches: Optional[EffectivePatchList] - NextToken: Optional[NextToken] + EffectivePatches: EffectivePatchList | None + NextToken: NextToken | None class DescribeInstanceAssociationsStatusRequest(ServiceRequest): InstanceId: InstanceId - MaxResults: Optional[MaxResults] - NextToken: Optional[NextToken] + MaxResults: MaxResults | None + NextToken: NextToken | None class S3OutputUrl(TypedDict, total=False): - OutputUrl: Optional[Url] + OutputUrl: Url | None class InstanceAssociationOutputUrl(TypedDict, total=False): - S3OutputUrl: Optional[S3OutputUrl] + S3OutputUrl: S3OutputUrl | None class InstanceAssociationStatusInfo(TypedDict, total=False): - AssociationId: Optional[AssociationId] - Name: Optional[DocumentARN] - DocumentVersion: Optional[DocumentVersion] - AssociationVersion: Optional[AssociationVersion] - InstanceId: Optional[InstanceId] - ExecutionDate: Optional[DateTime] - Status: Optional[StatusName] - DetailedStatus: Optional[StatusName] - ExecutionSummary: Optional[InstanceAssociationExecutionSummary] - ErrorCode: Optional[AgentErrorCode] - OutputUrl: Optional[InstanceAssociationOutputUrl] - AssociationName: Optional[AssociationName] + AssociationId: AssociationId | None + Name: DocumentARN | None + DocumentVersion: DocumentVersion | None + AssociationVersion: AssociationVersion | None + InstanceId: InstanceId | None + ExecutionDate: DateTime | None + Status: StatusName | None + DetailedStatus: StatusName | None + ExecutionSummary: InstanceAssociationExecutionSummary | None + ErrorCode: AgentErrorCode | None + OutputUrl: InstanceAssociationOutputUrl | None + AssociationName: AssociationName | None -InstanceAssociationStatusInfos = List[InstanceAssociationStatusInfo] +InstanceAssociationStatusInfos = list[InstanceAssociationStatusInfo] class DescribeInstanceAssociationsStatusResult(TypedDict, total=False): - InstanceAssociationStatusInfos: Optional[InstanceAssociationStatusInfos] - NextToken: Optional[NextToken] + InstanceAssociationStatusInfos: InstanceAssociationStatusInfos | None + NextToken: NextToken | None -InstanceInformationFilterValueSet = List[InstanceInformationFilterValue] +InstanceInformationFilterValueSet = list[InstanceInformationFilterValue] class InstanceInformationStringFilter(TypedDict, total=False): @@ -3528,7 +3539,7 @@ class InstanceInformationStringFilter(TypedDict, total=False): Values: InstanceInformationFilterValueSet -InstanceInformationStringFilterList = List[InstanceInformationStringFilter] +InstanceInformationStringFilterList = list[InstanceInformationStringFilter] class InstanceInformationFilter(TypedDict, total=False): @@ -3536,57 +3547,57 @@ class InstanceInformationFilter(TypedDict, total=False): valueSet: InstanceInformationFilterValueSet -InstanceInformationFilterList = List[InstanceInformationFilter] +InstanceInformationFilterList = list[InstanceInformationFilter] class DescribeInstanceInformationRequest(ServiceRequest): - InstanceInformationFilterList: Optional[InstanceInformationFilterList] - Filters: Optional[InstanceInformationStringFilterList] - MaxResults: Optional[MaxResultsEC2Compatible] - NextToken: Optional[NextToken] + InstanceInformationFilterList: InstanceInformationFilterList | None + Filters: InstanceInformationStringFilterList | None + MaxResults: MaxResultsEC2Compatible | None + NextToken: NextToken | None -InstanceAssociationStatusAggregatedCount = Dict[StatusName, InstanceCount] +InstanceAssociationStatusAggregatedCount = dict[StatusName, InstanceCount] class InstanceAggregatedAssociationOverview(TypedDict, total=False): - DetailedStatus: Optional[StatusName] - InstanceAssociationStatusAggregatedCount: Optional[InstanceAssociationStatusAggregatedCount] + DetailedStatus: StatusName | None + InstanceAssociationStatusAggregatedCount: InstanceAssociationStatusAggregatedCount | None class InstanceInformation(TypedDict, total=False): - InstanceId: Optional[InstanceId] - PingStatus: Optional[PingStatus] - LastPingDateTime: Optional[DateTime] - AgentVersion: Optional[Version] - IsLatestVersion: Optional[Boolean] - PlatformType: Optional[PlatformType] - PlatformName: Optional[String] - PlatformVersion: Optional[String] - ActivationId: Optional[ActivationId] - IamRole: Optional[IamRole] - RegistrationDate: Optional[DateTime] - ResourceType: Optional[ResourceType] - Name: Optional[String] - IPAddress: Optional[IPAddress] - ComputerName: Optional[ComputerName] - AssociationStatus: Optional[StatusName] - LastAssociationExecutionDate: Optional[DateTime] - LastSuccessfulAssociationExecutionDate: Optional[DateTime] - AssociationOverview: Optional[InstanceAggregatedAssociationOverview] - SourceId: Optional[SourceId] - SourceType: Optional[SourceType] - - -InstanceInformationList = List[InstanceInformation] + InstanceId: InstanceId | None + PingStatus: PingStatus | None + LastPingDateTime: DateTime | None + AgentVersion: Version | None + IsLatestVersion: Boolean | None + PlatformType: PlatformType | None + PlatformName: String | None + PlatformVersion: String | None + ActivationId: ActivationId | None + IamRole: IamRole | None + RegistrationDate: DateTime | None + ResourceType: ResourceType | None + Name: String | None + IPAddress: IPAddress | None + ComputerName: ComputerName | None + AssociationStatus: StatusName | None + LastAssociationExecutionDate: DateTime | None + LastSuccessfulAssociationExecutionDate: DateTime | None + AssociationOverview: InstanceAggregatedAssociationOverview | None + SourceId: SourceId | None + SourceType: SourceType | None + + +InstanceInformationList = list[InstanceInformation] class DescribeInstanceInformationResult(TypedDict, total=False): - InstanceInformationList: Optional[InstanceInformationList] - NextToken: Optional[NextToken] + InstanceInformationList: InstanceInformationList | None + NextToken: NextToken | None -InstancePatchStateFilterValues = List[InstancePatchStateFilterValue] +InstancePatchStateFilterValues = list[InstancePatchStateFilterValue] class InstancePatchStateFilter(TypedDict, total=False): @@ -3595,69 +3606,69 @@ class InstancePatchStateFilter(TypedDict, total=False): Type: InstancePatchStateOperatorType -InstancePatchStateFilterList = List[InstancePatchStateFilter] +InstancePatchStateFilterList = list[InstancePatchStateFilter] class DescribeInstancePatchStatesForPatchGroupRequest(ServiceRequest): PatchGroup: PatchGroup - Filters: Optional[InstancePatchStateFilterList] - NextToken: Optional[NextToken] - MaxResults: Optional[PatchComplianceMaxResults] + Filters: InstancePatchStateFilterList | None + NextToken: NextToken | None + MaxResults: PatchComplianceMaxResults | None class InstancePatchState(TypedDict, total=False): InstanceId: InstanceId PatchGroup: PatchGroup BaselineId: BaselineId - SnapshotId: Optional[SnapshotId] - InstallOverrideList: Optional[InstallOverrideList] - OwnerInformation: Optional[OwnerInformation] - InstalledCount: Optional[PatchInstalledCount] - InstalledOtherCount: Optional[PatchInstalledOtherCount] - InstalledPendingRebootCount: Optional[PatchInstalledPendingRebootCount] - InstalledRejectedCount: Optional[PatchInstalledRejectedCount] - MissingCount: Optional[PatchMissingCount] - FailedCount: Optional[PatchFailedCount] - UnreportedNotApplicableCount: Optional[PatchUnreportedNotApplicableCount] - NotApplicableCount: Optional[PatchNotApplicableCount] - AvailableSecurityUpdateCount: Optional[PatchAvailableSecurityUpdateCount] + SnapshotId: SnapshotId | None + InstallOverrideList: InstallOverrideList | None + OwnerInformation: OwnerInformation | None + InstalledCount: PatchInstalledCount | None + InstalledOtherCount: PatchInstalledOtherCount | None + InstalledPendingRebootCount: PatchInstalledPendingRebootCount | None + InstalledRejectedCount: PatchInstalledRejectedCount | None + MissingCount: PatchMissingCount | None + FailedCount: PatchFailedCount | None + UnreportedNotApplicableCount: PatchUnreportedNotApplicableCount | None + NotApplicableCount: PatchNotApplicableCount | None + AvailableSecurityUpdateCount: PatchAvailableSecurityUpdateCount | None OperationStartTime: DateTime OperationEndTime: DateTime Operation: PatchOperationType - LastNoRebootInstallOperationTime: Optional[DateTime] - RebootOption: Optional[RebootOption] - CriticalNonCompliantCount: Optional[PatchCriticalNonCompliantCount] - SecurityNonCompliantCount: Optional[PatchSecurityNonCompliantCount] - OtherNonCompliantCount: Optional[PatchOtherNonCompliantCount] + LastNoRebootInstallOperationTime: DateTime | None + RebootOption: RebootOption | None + CriticalNonCompliantCount: PatchCriticalNonCompliantCount | None + SecurityNonCompliantCount: PatchSecurityNonCompliantCount | None + OtherNonCompliantCount: PatchOtherNonCompliantCount | None -InstancePatchStatesList = List[InstancePatchState] +InstancePatchStatesList = list[InstancePatchState] class DescribeInstancePatchStatesForPatchGroupResult(TypedDict, total=False): - InstancePatchStates: Optional[InstancePatchStatesList] - NextToken: Optional[NextToken] + InstancePatchStates: InstancePatchStatesList | None + NextToken: NextToken | None class DescribeInstancePatchStatesRequest(ServiceRequest): InstanceIds: InstanceIdList - NextToken: Optional[NextToken] - MaxResults: Optional[PatchComplianceMaxResults] + NextToken: NextToken | None + MaxResults: PatchComplianceMaxResults | None -InstancePatchStateList = List[InstancePatchState] +InstancePatchStateList = list[InstancePatchState] class DescribeInstancePatchStatesResult(TypedDict, total=False): - InstancePatchStates: Optional[InstancePatchStateList] - NextToken: Optional[NextToken] + InstancePatchStates: InstancePatchStateList | None + NextToken: NextToken | None class DescribeInstancePatchesRequest(ServiceRequest): InstanceId: InstanceId - Filters: Optional[PatchOrchestratorFilterList] - NextToken: Optional[NextToken] - MaxResults: Optional[PatchComplianceMaxResults] + Filters: PatchOrchestratorFilterList | None + NextToken: NextToken | None + MaxResults: PatchComplianceMaxResults | None class PatchComplianceData(TypedDict, total=False): @@ -3667,27 +3678,27 @@ class PatchComplianceData(TypedDict, total=False): Severity: PatchSeverity State: PatchComplianceDataState InstalledTime: DateTime - CVEIds: Optional[PatchCVEIds] + CVEIds: PatchCVEIds | None -PatchComplianceDataList = List[PatchComplianceData] +PatchComplianceDataList = list[PatchComplianceData] class DescribeInstancePatchesResult(TypedDict, total=False): - Patches: Optional[PatchComplianceDataList] - NextToken: Optional[NextToken] + Patches: PatchComplianceDataList | None + NextToken: NextToken | None -InstancePropertyFilterValueSet = List[InstancePropertyFilterValue] +InstancePropertyFilterValueSet = list[InstancePropertyFilterValue] class InstancePropertyStringFilter(TypedDict, total=False): Key: InstancePropertyStringFilterKey Values: InstancePropertyFilterValueSet - Operator: Optional[InstancePropertyFilterOperator] + Operator: InstancePropertyFilterOperator | None -InstancePropertyStringFilterList = List[InstancePropertyStringFilter] +InstancePropertyStringFilterList = list[InstancePropertyStringFilter] class InstancePropertyFilter(TypedDict, total=False): @@ -3695,57 +3706,57 @@ class InstancePropertyFilter(TypedDict, total=False): valueSet: InstancePropertyFilterValueSet -InstancePropertyFilterList = List[InstancePropertyFilter] +InstancePropertyFilterList = list[InstancePropertyFilter] class DescribeInstancePropertiesRequest(ServiceRequest): - InstancePropertyFilterList: Optional[InstancePropertyFilterList] - FiltersWithOperator: Optional[InstancePropertyStringFilterList] - MaxResults: Optional[DescribeInstancePropertiesMaxResults] - NextToken: Optional[NextToken] + InstancePropertyFilterList: InstancePropertyFilterList | None + FiltersWithOperator: InstancePropertyStringFilterList | None + MaxResults: DescribeInstancePropertiesMaxResults | None + NextToken: NextToken | None class InstanceProperty(TypedDict, total=False): - Name: Optional[InstanceName] - InstanceId: Optional[InstanceId] - InstanceType: Optional[InstanceType] - InstanceRole: Optional[InstanceRole] - KeyName: Optional[KeyName] - InstanceState: Optional[InstanceState] - Architecture: Optional[Architecture] - IPAddress: Optional[IPAddress] - LaunchTime: Optional[DateTime] - PingStatus: Optional[PingStatus] - LastPingDateTime: Optional[DateTime] - AgentVersion: Optional[Version] - PlatformType: Optional[PlatformType] - PlatformName: Optional[PlatformName] - PlatformVersion: Optional[PlatformVersion] - ActivationId: Optional[ActivationId] - IamRole: Optional[IamRole] - RegistrationDate: Optional[DateTime] - ResourceType: Optional[String] - ComputerName: Optional[ComputerName] - AssociationStatus: Optional[StatusName] - LastAssociationExecutionDate: Optional[DateTime] - LastSuccessfulAssociationExecutionDate: Optional[DateTime] - AssociationOverview: Optional[InstanceAggregatedAssociationOverview] - SourceId: Optional[SourceId] - SourceType: Optional[SourceType] - - -InstanceProperties = List[InstanceProperty] + Name: InstanceName | None + InstanceId: InstanceId | None + InstanceType: InstanceType | None + InstanceRole: InstanceRole | None + KeyName: KeyName | None + InstanceState: InstanceState | None + Architecture: Architecture | None + IPAddress: IPAddress | None + LaunchTime: DateTime | None + PingStatus: PingStatus | None + LastPingDateTime: DateTime | None + AgentVersion: Version | None + PlatformType: PlatformType | None + PlatformName: PlatformName | None + PlatformVersion: PlatformVersion | None + ActivationId: ActivationId | None + IamRole: IamRole | None + RegistrationDate: DateTime | None + ResourceType: String | None + ComputerName: ComputerName | None + AssociationStatus: StatusName | None + LastAssociationExecutionDate: DateTime | None + LastSuccessfulAssociationExecutionDate: DateTime | None + AssociationOverview: InstanceAggregatedAssociationOverview | None + SourceId: SourceId | None + SourceType: SourceType | None + + +InstanceProperties = list[InstanceProperty] class DescribeInstancePropertiesResult(TypedDict, total=False): - InstanceProperties: Optional[InstanceProperties] - NextToken: Optional[NextToken] + InstanceProperties: InstanceProperties | None + NextToken: NextToken | None class DescribeInventoryDeletionsRequest(ServiceRequest): - DeletionId: Optional[UUID] - NextToken: Optional[NextToken] - MaxResults: Optional[MaxResults] + DeletionId: UUID | None + NextToken: NextToken | None + MaxResults: MaxResults | None InventoryDeletionLastStatusUpdateTime = datetime @@ -3753,270 +3764,270 @@ class DescribeInventoryDeletionsRequest(ServiceRequest): class InventoryDeletionStatusItem(TypedDict, total=False): - DeletionId: Optional[UUID] - TypeName: Optional[InventoryItemTypeName] - DeletionStartTime: Optional[InventoryDeletionStartTime] - LastStatus: Optional[InventoryDeletionStatus] - LastStatusMessage: Optional[InventoryDeletionLastStatusMessage] - DeletionSummary: Optional[InventoryDeletionSummary] - LastStatusUpdateTime: Optional[InventoryDeletionLastStatusUpdateTime] + DeletionId: UUID | None + TypeName: InventoryItemTypeName | None + DeletionStartTime: InventoryDeletionStartTime | None + LastStatus: InventoryDeletionStatus | None + LastStatusMessage: InventoryDeletionLastStatusMessage | None + DeletionSummary: InventoryDeletionSummary | None + LastStatusUpdateTime: InventoryDeletionLastStatusUpdateTime | None -InventoryDeletionsList = List[InventoryDeletionStatusItem] +InventoryDeletionsList = list[InventoryDeletionStatusItem] class DescribeInventoryDeletionsResult(TypedDict, total=False): - InventoryDeletions: Optional[InventoryDeletionsList] - NextToken: Optional[NextToken] + InventoryDeletions: InventoryDeletionsList | None + NextToken: NextToken | None -MaintenanceWindowFilterValues = List[MaintenanceWindowFilterValue] +MaintenanceWindowFilterValues = list[MaintenanceWindowFilterValue] class MaintenanceWindowFilter(TypedDict, total=False): - Key: Optional[MaintenanceWindowFilterKey] - Values: Optional[MaintenanceWindowFilterValues] + Key: MaintenanceWindowFilterKey | None + Values: MaintenanceWindowFilterValues | None -MaintenanceWindowFilterList = List[MaintenanceWindowFilter] +MaintenanceWindowFilterList = list[MaintenanceWindowFilter] class DescribeMaintenanceWindowExecutionTaskInvocationsRequest(ServiceRequest): WindowExecutionId: MaintenanceWindowExecutionId TaskId: MaintenanceWindowExecutionTaskId - Filters: Optional[MaintenanceWindowFilterList] - MaxResults: Optional[MaintenanceWindowMaxResults] - NextToken: Optional[NextToken] + Filters: MaintenanceWindowFilterList | None + MaxResults: MaintenanceWindowMaxResults | None + NextToken: NextToken | None class MaintenanceWindowExecutionTaskInvocationIdentity(TypedDict, total=False): - WindowExecutionId: Optional[MaintenanceWindowExecutionId] - TaskExecutionId: Optional[MaintenanceWindowExecutionTaskId] - InvocationId: Optional[MaintenanceWindowExecutionTaskInvocationId] - ExecutionId: Optional[MaintenanceWindowExecutionTaskExecutionId] - TaskType: Optional[MaintenanceWindowTaskType] - Parameters: Optional[MaintenanceWindowExecutionTaskInvocationParameters] - Status: Optional[MaintenanceWindowExecutionStatus] - StatusDetails: Optional[MaintenanceWindowExecutionStatusDetails] - StartTime: Optional[DateTime] - EndTime: Optional[DateTime] - OwnerInformation: Optional[OwnerInformation] - WindowTargetId: Optional[MaintenanceWindowTaskTargetId] - - -MaintenanceWindowExecutionTaskInvocationIdentityList = List[ + WindowExecutionId: MaintenanceWindowExecutionId | None + TaskExecutionId: MaintenanceWindowExecutionTaskId | None + InvocationId: MaintenanceWindowExecutionTaskInvocationId | None + ExecutionId: MaintenanceWindowExecutionTaskExecutionId | None + TaskType: MaintenanceWindowTaskType | None + Parameters: MaintenanceWindowExecutionTaskInvocationParameters | None + Status: MaintenanceWindowExecutionStatus | None + StatusDetails: MaintenanceWindowExecutionStatusDetails | None + StartTime: DateTime | None + EndTime: DateTime | None + OwnerInformation: OwnerInformation | None + WindowTargetId: MaintenanceWindowTaskTargetId | None + + +MaintenanceWindowExecutionTaskInvocationIdentityList = list[ MaintenanceWindowExecutionTaskInvocationIdentity ] class DescribeMaintenanceWindowExecutionTaskInvocationsResult(TypedDict, total=False): - WindowExecutionTaskInvocationIdentities: Optional[ - MaintenanceWindowExecutionTaskInvocationIdentityList - ] - NextToken: Optional[NextToken] + WindowExecutionTaskInvocationIdentities: ( + MaintenanceWindowExecutionTaskInvocationIdentityList | None + ) + NextToken: NextToken | None class DescribeMaintenanceWindowExecutionTasksRequest(ServiceRequest): WindowExecutionId: MaintenanceWindowExecutionId - Filters: Optional[MaintenanceWindowFilterList] - MaxResults: Optional[MaintenanceWindowMaxResults] - NextToken: Optional[NextToken] + Filters: MaintenanceWindowFilterList | None + MaxResults: MaintenanceWindowMaxResults | None + NextToken: NextToken | None class MaintenanceWindowExecutionTaskIdentity(TypedDict, total=False): - WindowExecutionId: Optional[MaintenanceWindowExecutionId] - TaskExecutionId: Optional[MaintenanceWindowExecutionTaskId] - Status: Optional[MaintenanceWindowExecutionStatus] - StatusDetails: Optional[MaintenanceWindowExecutionStatusDetails] - StartTime: Optional[DateTime] - EndTime: Optional[DateTime] - TaskArn: Optional[MaintenanceWindowTaskArn] - TaskType: Optional[MaintenanceWindowTaskType] - AlarmConfiguration: Optional[AlarmConfiguration] - TriggeredAlarms: Optional[AlarmStateInformationList] + WindowExecutionId: MaintenanceWindowExecutionId | None + TaskExecutionId: MaintenanceWindowExecutionTaskId | None + Status: MaintenanceWindowExecutionStatus | None + StatusDetails: MaintenanceWindowExecutionStatusDetails | None + StartTime: DateTime | None + EndTime: DateTime | None + TaskArn: MaintenanceWindowTaskArn | None + TaskType: MaintenanceWindowTaskType | None + AlarmConfiguration: AlarmConfiguration | None + TriggeredAlarms: AlarmStateInformationList | None -MaintenanceWindowExecutionTaskIdentityList = List[MaintenanceWindowExecutionTaskIdentity] +MaintenanceWindowExecutionTaskIdentityList = list[MaintenanceWindowExecutionTaskIdentity] class DescribeMaintenanceWindowExecutionTasksResult(TypedDict, total=False): - WindowExecutionTaskIdentities: Optional[MaintenanceWindowExecutionTaskIdentityList] - NextToken: Optional[NextToken] + WindowExecutionTaskIdentities: MaintenanceWindowExecutionTaskIdentityList | None + NextToken: NextToken | None class DescribeMaintenanceWindowExecutionsRequest(ServiceRequest): WindowId: MaintenanceWindowId - Filters: Optional[MaintenanceWindowFilterList] - MaxResults: Optional[MaintenanceWindowMaxResults] - NextToken: Optional[NextToken] + Filters: MaintenanceWindowFilterList | None + MaxResults: MaintenanceWindowMaxResults | None + NextToken: NextToken | None class MaintenanceWindowExecution(TypedDict, total=False): - WindowId: Optional[MaintenanceWindowId] - WindowExecutionId: Optional[MaintenanceWindowExecutionId] - Status: Optional[MaintenanceWindowExecutionStatus] - StatusDetails: Optional[MaintenanceWindowExecutionStatusDetails] - StartTime: Optional[DateTime] - EndTime: Optional[DateTime] + WindowId: MaintenanceWindowId | None + WindowExecutionId: MaintenanceWindowExecutionId | None + Status: MaintenanceWindowExecutionStatus | None + StatusDetails: MaintenanceWindowExecutionStatusDetails | None + StartTime: DateTime | None + EndTime: DateTime | None -MaintenanceWindowExecutionList = List[MaintenanceWindowExecution] +MaintenanceWindowExecutionList = list[MaintenanceWindowExecution] class DescribeMaintenanceWindowExecutionsResult(TypedDict, total=False): - WindowExecutions: Optional[MaintenanceWindowExecutionList] - NextToken: Optional[NextToken] + WindowExecutions: MaintenanceWindowExecutionList | None + NextToken: NextToken | None class DescribeMaintenanceWindowScheduleRequest(ServiceRequest): - WindowId: Optional[MaintenanceWindowId] - Targets: Optional[Targets] - ResourceType: Optional[MaintenanceWindowResourceType] - Filters: Optional[PatchOrchestratorFilterList] - MaxResults: Optional[MaintenanceWindowSearchMaxResults] - NextToken: Optional[NextToken] + WindowId: MaintenanceWindowId | None + Targets: Targets | None + ResourceType: MaintenanceWindowResourceType | None + Filters: PatchOrchestratorFilterList | None + MaxResults: MaintenanceWindowSearchMaxResults | None + NextToken: NextToken | None class ScheduledWindowExecution(TypedDict, total=False): - WindowId: Optional[MaintenanceWindowId] - Name: Optional[MaintenanceWindowName] - ExecutionTime: Optional[MaintenanceWindowStringDateTime] + WindowId: MaintenanceWindowId | None + Name: MaintenanceWindowName | None + ExecutionTime: MaintenanceWindowStringDateTime | None -ScheduledWindowExecutionList = List[ScheduledWindowExecution] +ScheduledWindowExecutionList = list[ScheduledWindowExecution] class DescribeMaintenanceWindowScheduleResult(TypedDict, total=False): - ScheduledWindowExecutions: Optional[ScheduledWindowExecutionList] - NextToken: Optional[NextToken] + ScheduledWindowExecutions: ScheduledWindowExecutionList | None + NextToken: NextToken | None class DescribeMaintenanceWindowTargetsRequest(ServiceRequest): WindowId: MaintenanceWindowId - Filters: Optional[MaintenanceWindowFilterList] - MaxResults: Optional[MaintenanceWindowMaxResults] - NextToken: Optional[NextToken] + Filters: MaintenanceWindowFilterList | None + MaxResults: MaintenanceWindowMaxResults | None + NextToken: NextToken | None class MaintenanceWindowTarget(TypedDict, total=False): - WindowId: Optional[MaintenanceWindowId] - WindowTargetId: Optional[MaintenanceWindowTargetId] - ResourceType: Optional[MaintenanceWindowResourceType] - Targets: Optional[Targets] - OwnerInformation: Optional[OwnerInformation] - Name: Optional[MaintenanceWindowName] - Description: Optional[MaintenanceWindowDescription] + WindowId: MaintenanceWindowId | None + WindowTargetId: MaintenanceWindowTargetId | None + ResourceType: MaintenanceWindowResourceType | None + Targets: Targets | None + OwnerInformation: OwnerInformation | None + Name: MaintenanceWindowName | None + Description: MaintenanceWindowDescription | None -MaintenanceWindowTargetList = List[MaintenanceWindowTarget] +MaintenanceWindowTargetList = list[MaintenanceWindowTarget] class DescribeMaintenanceWindowTargetsResult(TypedDict, total=False): - Targets: Optional[MaintenanceWindowTargetList] - NextToken: Optional[NextToken] + Targets: MaintenanceWindowTargetList | None + NextToken: NextToken | None class DescribeMaintenanceWindowTasksRequest(ServiceRequest): WindowId: MaintenanceWindowId - Filters: Optional[MaintenanceWindowFilterList] - MaxResults: Optional[MaintenanceWindowMaxResults] - NextToken: Optional[NextToken] + Filters: MaintenanceWindowFilterList | None + MaxResults: MaintenanceWindowMaxResults | None + NextToken: NextToken | None class LoggingInfo(TypedDict, total=False): S3BucketName: S3BucketName - S3KeyPrefix: Optional[S3KeyPrefix] + S3KeyPrefix: S3KeyPrefix | None S3Region: S3Region -MaintenanceWindowTaskParameterValueList = List[MaintenanceWindowTaskParameterValue] +MaintenanceWindowTaskParameterValueList = list[MaintenanceWindowTaskParameterValue] class MaintenanceWindowTaskParameterValueExpression(TypedDict, total=False): - Values: Optional[MaintenanceWindowTaskParameterValueList] + Values: MaintenanceWindowTaskParameterValueList | None -MaintenanceWindowTaskParameters = Dict[ +MaintenanceWindowTaskParameters = dict[ MaintenanceWindowTaskParameterName, MaintenanceWindowTaskParameterValueExpression ] class MaintenanceWindowTask(TypedDict, total=False): - WindowId: Optional[MaintenanceWindowId] - WindowTaskId: Optional[MaintenanceWindowTaskId] - TaskArn: Optional[MaintenanceWindowTaskArn] - Type: Optional[MaintenanceWindowTaskType] - Targets: Optional[Targets] - TaskParameters: Optional[MaintenanceWindowTaskParameters] - Priority: Optional[MaintenanceWindowTaskPriority] - LoggingInfo: Optional[LoggingInfo] - ServiceRoleArn: Optional[ServiceRole] - MaxConcurrency: Optional[MaxConcurrency] - MaxErrors: Optional[MaxErrors] - Name: Optional[MaintenanceWindowName] - Description: Optional[MaintenanceWindowDescription] - CutoffBehavior: Optional[MaintenanceWindowTaskCutoffBehavior] - AlarmConfiguration: Optional[AlarmConfiguration] - - -MaintenanceWindowTaskList = List[MaintenanceWindowTask] + WindowId: MaintenanceWindowId | None + WindowTaskId: MaintenanceWindowTaskId | None + TaskArn: MaintenanceWindowTaskArn | None + Type: MaintenanceWindowTaskType | None + Targets: Targets | None + TaskParameters: MaintenanceWindowTaskParameters | None + Priority: MaintenanceWindowTaskPriority | None + LoggingInfo: LoggingInfo | None + ServiceRoleArn: ServiceRole | None + MaxConcurrency: MaxConcurrency | None + MaxErrors: MaxErrors | None + Name: MaintenanceWindowName | None + Description: MaintenanceWindowDescription | None + CutoffBehavior: MaintenanceWindowTaskCutoffBehavior | None + AlarmConfiguration: AlarmConfiguration | None + + +MaintenanceWindowTaskList = list[MaintenanceWindowTask] class DescribeMaintenanceWindowTasksResult(TypedDict, total=False): - Tasks: Optional[MaintenanceWindowTaskList] - NextToken: Optional[NextToken] + Tasks: MaintenanceWindowTaskList | None + NextToken: NextToken | None class DescribeMaintenanceWindowsForTargetRequest(ServiceRequest): Targets: Targets ResourceType: MaintenanceWindowResourceType - MaxResults: Optional[MaintenanceWindowSearchMaxResults] - NextToken: Optional[NextToken] + MaxResults: MaintenanceWindowSearchMaxResults | None + NextToken: NextToken | None class MaintenanceWindowIdentityForTarget(TypedDict, total=False): - WindowId: Optional[MaintenanceWindowId] - Name: Optional[MaintenanceWindowName] + WindowId: MaintenanceWindowId | None + Name: MaintenanceWindowName | None -MaintenanceWindowsForTargetList = List[MaintenanceWindowIdentityForTarget] +MaintenanceWindowsForTargetList = list[MaintenanceWindowIdentityForTarget] class DescribeMaintenanceWindowsForTargetResult(TypedDict, total=False): - WindowIdentities: Optional[MaintenanceWindowsForTargetList] - NextToken: Optional[NextToken] + WindowIdentities: MaintenanceWindowsForTargetList | None + NextToken: NextToken | None class DescribeMaintenanceWindowsRequest(ServiceRequest): - Filters: Optional[MaintenanceWindowFilterList] - MaxResults: Optional[MaintenanceWindowMaxResults] - NextToken: Optional[NextToken] + Filters: MaintenanceWindowFilterList | None + MaxResults: MaintenanceWindowMaxResults | None + NextToken: NextToken | None class MaintenanceWindowIdentity(TypedDict, total=False): - WindowId: Optional[MaintenanceWindowId] - Name: Optional[MaintenanceWindowName] - Description: Optional[MaintenanceWindowDescription] - Enabled: Optional[MaintenanceWindowEnabled] - Duration: Optional[MaintenanceWindowDurationHours] - Cutoff: Optional[MaintenanceWindowCutoff] - Schedule: Optional[MaintenanceWindowSchedule] - ScheduleTimezone: Optional[MaintenanceWindowTimezone] - ScheduleOffset: Optional[MaintenanceWindowOffset] - EndDate: Optional[MaintenanceWindowStringDateTime] - StartDate: Optional[MaintenanceWindowStringDateTime] - NextExecutionTime: Optional[MaintenanceWindowStringDateTime] + WindowId: MaintenanceWindowId | None + Name: MaintenanceWindowName | None + Description: MaintenanceWindowDescription | None + Enabled: MaintenanceWindowEnabled | None + Duration: MaintenanceWindowDurationHours | None + Cutoff: MaintenanceWindowCutoff | None + Schedule: MaintenanceWindowSchedule | None + ScheduleTimezone: MaintenanceWindowTimezone | None + ScheduleOffset: MaintenanceWindowOffset | None + EndDate: MaintenanceWindowStringDateTime | None + StartDate: MaintenanceWindowStringDateTime | None + NextExecutionTime: MaintenanceWindowStringDateTime | None -MaintenanceWindowIdentityList = List[MaintenanceWindowIdentity] +MaintenanceWindowIdentityList = list[MaintenanceWindowIdentity] class DescribeMaintenanceWindowsResult(TypedDict, total=False): - WindowIdentities: Optional[MaintenanceWindowIdentityList] - NextToken: Optional[NextToken] + WindowIdentities: MaintenanceWindowIdentityList | None + NextToken: NextToken | None -OpsItemFilterValues = List[OpsItemFilterValue] +OpsItemFilterValues = list[OpsItemFilterValue] class OpsItemFilter(TypedDict, total=False): @@ -4025,54 +4036,54 @@ class OpsItemFilter(TypedDict, total=False): Operator: OpsItemFilterOperator -OpsItemFilters = List[OpsItemFilter] +OpsItemFilters = list[OpsItemFilter] class DescribeOpsItemsRequest(ServiceRequest): - OpsItemFilters: Optional[OpsItemFilters] - MaxResults: Optional[OpsItemMaxResults] - NextToken: Optional[String] + OpsItemFilters: OpsItemFilters | None + MaxResults: OpsItemMaxResults | None + NextToken: String | None class OpsItemSummary(TypedDict, total=False): - CreatedBy: Optional[String] - CreatedTime: Optional[DateTime] - LastModifiedBy: Optional[String] - LastModifiedTime: Optional[DateTime] - Priority: Optional[OpsItemPriority] - Source: Optional[OpsItemSource] - Status: Optional[OpsItemStatus] - OpsItemId: Optional[OpsItemId] - Title: Optional[OpsItemTitle] - OperationalData: Optional[OpsItemOperationalData] - Category: Optional[OpsItemCategory] - Severity: Optional[OpsItemSeverity] - OpsItemType: Optional[OpsItemType] - ActualStartTime: Optional[DateTime] - ActualEndTime: Optional[DateTime] - PlannedStartTime: Optional[DateTime] - PlannedEndTime: Optional[DateTime] - - -OpsItemSummaries = List[OpsItemSummary] + CreatedBy: String | None + CreatedTime: DateTime | None + LastModifiedBy: String | None + LastModifiedTime: DateTime | None + Priority: OpsItemPriority | None + Source: OpsItemSource | None + Status: OpsItemStatus | None + OpsItemId: OpsItemId | None + Title: OpsItemTitle | None + OperationalData: OpsItemOperationalData | None + Category: OpsItemCategory | None + Severity: OpsItemSeverity | None + OpsItemType: OpsItemType | None + ActualStartTime: DateTime | None + ActualEndTime: DateTime | None + PlannedStartTime: DateTime | None + PlannedEndTime: DateTime | None + + +OpsItemSummaries = list[OpsItemSummary] class DescribeOpsItemsResponse(TypedDict, total=False): - NextToken: Optional[String] - OpsItemSummaries: Optional[OpsItemSummaries] + NextToken: String | None + OpsItemSummaries: OpsItemSummaries | None -ParameterStringFilterValueList = List[ParameterStringFilterValue] +ParameterStringFilterValueList = list[ParameterStringFilterValue] class ParameterStringFilter(TypedDict, total=False): Key: ParameterStringFilterKey - Option: Optional[ParameterStringQueryOption] - Values: Optional[ParameterStringFilterValueList] + Option: ParameterStringQueryOption | None + Values: ParameterStringFilterValueList | None -ParameterStringFilterList = List[ParameterStringFilter] -ParametersFilterValueList = List[ParametersFilterValue] +ParameterStringFilterList = list[ParameterStringFilter] +ParametersFilterValueList = list[ParametersFilterValue] class ParametersFilter(TypedDict, total=False): @@ -4080,70 +4091,70 @@ class ParametersFilter(TypedDict, total=False): Values: ParametersFilterValueList -ParametersFilterList = List[ParametersFilter] +ParametersFilterList = list[ParametersFilter] class DescribeParametersRequest(ServiceRequest): - Filters: Optional[ParametersFilterList] - ParameterFilters: Optional[ParameterStringFilterList] - MaxResults: Optional[MaxResults] - NextToken: Optional[NextToken] - Shared: Optional[Boolean] + Filters: ParametersFilterList | None + ParameterFilters: ParameterStringFilterList | None + MaxResults: MaxResults | None + NextToken: NextToken | None + Shared: Boolean | None class ParameterInlinePolicy(TypedDict, total=False): - PolicyText: Optional[String] - PolicyType: Optional[String] - PolicyStatus: Optional[String] + PolicyText: String | None + PolicyType: String | None + PolicyStatus: String | None -ParameterPolicyList = List[ParameterInlinePolicy] +ParameterPolicyList = list[ParameterInlinePolicy] PSParameterVersion = int class ParameterMetadata(TypedDict, total=False): - Name: Optional[PSParameterName] - ARN: Optional[String] - Type: Optional[ParameterType] - KeyId: Optional[ParameterKeyId] - LastModifiedDate: Optional[DateTime] - LastModifiedUser: Optional[String] - Description: Optional[ParameterDescription] - AllowedPattern: Optional[AllowedPattern] - Version: Optional[PSParameterVersion] - Tier: Optional[ParameterTier] - Policies: Optional[ParameterPolicyList] - DataType: Optional[ParameterDataType] + Name: PSParameterName | None + ARN: String | None + Type: ParameterType | None + KeyId: ParameterKeyId | None + LastModifiedDate: DateTime | None + LastModifiedUser: String | None + Description: ParameterDescription | None + AllowedPattern: AllowedPattern | None + Version: PSParameterVersion | None + Tier: ParameterTier | None + Policies: ParameterPolicyList | None + DataType: ParameterDataType | None -ParameterMetadataList = List[ParameterMetadata] +ParameterMetadataList = list[ParameterMetadata] class DescribeParametersResult(TypedDict, total=False): - Parameters: Optional[ParameterMetadataList] - NextToken: Optional[NextToken] + Parameters: ParameterMetadataList | None + NextToken: NextToken | None class DescribePatchBaselinesRequest(ServiceRequest): - Filters: Optional[PatchOrchestratorFilterList] - MaxResults: Optional[PatchBaselineMaxResults] - NextToken: Optional[NextToken] + Filters: PatchOrchestratorFilterList | None + MaxResults: PatchBaselineMaxResults | None + NextToken: NextToken | None class PatchBaselineIdentity(TypedDict, total=False): - BaselineId: Optional[BaselineId] - BaselineName: Optional[BaselineName] - OperatingSystem: Optional[OperatingSystem] - BaselineDescription: Optional[BaselineDescription] - DefaultBaseline: Optional[DefaultBaseline] + BaselineId: BaselineId | None + BaselineName: BaselineName | None + OperatingSystem: OperatingSystem | None + BaselineDescription: BaselineDescription | None + DefaultBaseline: DefaultBaseline | None -PatchBaselineIdentityList = List[PatchBaselineIdentity] +PatchBaselineIdentityList = list[PatchBaselineIdentity] class DescribePatchBaselinesResult(TypedDict, total=False): - BaselineIdentities: Optional[PatchBaselineIdentityList] - NextToken: Optional[NextToken] + BaselineIdentities: PatchBaselineIdentityList | None + NextToken: NextToken | None class DescribePatchGroupStateRequest(ServiceRequest): @@ -4151,55 +4162,55 @@ class DescribePatchGroupStateRequest(ServiceRequest): class DescribePatchGroupStateResult(TypedDict, total=False): - Instances: Optional[Integer] - InstancesWithInstalledPatches: Optional[Integer] - InstancesWithInstalledOtherPatches: Optional[Integer] - InstancesWithInstalledPendingRebootPatches: Optional[InstancesCount] - InstancesWithInstalledRejectedPatches: Optional[InstancesCount] - InstancesWithMissingPatches: Optional[Integer] - InstancesWithFailedPatches: Optional[Integer] - InstancesWithNotApplicablePatches: Optional[Integer] - InstancesWithUnreportedNotApplicablePatches: Optional[Integer] - InstancesWithCriticalNonCompliantPatches: Optional[InstancesCount] - InstancesWithSecurityNonCompliantPatches: Optional[InstancesCount] - InstancesWithOtherNonCompliantPatches: Optional[InstancesCount] - InstancesWithAvailableSecurityUpdates: Optional[Integer] + Instances: Integer | None + InstancesWithInstalledPatches: Integer | None + InstancesWithInstalledOtherPatches: Integer | None + InstancesWithInstalledPendingRebootPatches: InstancesCount | None + InstancesWithInstalledRejectedPatches: InstancesCount | None + InstancesWithMissingPatches: Integer | None + InstancesWithFailedPatches: Integer | None + InstancesWithNotApplicablePatches: Integer | None + InstancesWithUnreportedNotApplicablePatches: Integer | None + InstancesWithCriticalNonCompliantPatches: InstancesCount | None + InstancesWithSecurityNonCompliantPatches: InstancesCount | None + InstancesWithOtherNonCompliantPatches: InstancesCount | None + InstancesWithAvailableSecurityUpdates: Integer | None class DescribePatchGroupsRequest(ServiceRequest): - MaxResults: Optional[PatchBaselineMaxResults] - Filters: Optional[PatchOrchestratorFilterList] - NextToken: Optional[NextToken] + MaxResults: PatchBaselineMaxResults | None + Filters: PatchOrchestratorFilterList | None + NextToken: NextToken | None class PatchGroupPatchBaselineMapping(TypedDict, total=False): - PatchGroup: Optional[PatchGroup] - BaselineIdentity: Optional[PatchBaselineIdentity] + PatchGroup: PatchGroup | None + BaselineIdentity: PatchBaselineIdentity | None -PatchGroupPatchBaselineMappingList = List[PatchGroupPatchBaselineMapping] +PatchGroupPatchBaselineMappingList = list[PatchGroupPatchBaselineMapping] class DescribePatchGroupsResult(TypedDict, total=False): - Mappings: Optional[PatchGroupPatchBaselineMappingList] - NextToken: Optional[NextToken] + Mappings: PatchGroupPatchBaselineMappingList | None + NextToken: NextToken | None class DescribePatchPropertiesRequest(ServiceRequest): OperatingSystem: OperatingSystem Property: PatchProperty - PatchSet: Optional[PatchSet] - MaxResults: Optional[MaxResults] - NextToken: Optional[NextToken] + PatchSet: PatchSet | None + MaxResults: MaxResults | None + NextToken: NextToken | None -PatchPropertyEntry = Dict[AttributeName, AttributeValue] -PatchPropertiesList = List[PatchPropertyEntry] +PatchPropertyEntry = dict[AttributeName, AttributeValue] +PatchPropertiesList = list[PatchPropertyEntry] class DescribePatchPropertiesResult(TypedDict, total=False): - Properties: Optional[PatchPropertiesList] - NextToken: Optional[NextToken] + Properties: PatchPropertiesList | None + NextToken: NextToken | None class SessionFilter(TypedDict, total=False): @@ -4207,42 +4218,42 @@ class SessionFilter(TypedDict, total=False): value: SessionFilterValue -SessionFilterList = List[SessionFilter] +SessionFilterList = list[SessionFilter] class DescribeSessionsRequest(ServiceRequest): State: SessionState - MaxResults: Optional[SessionMaxResults] - NextToken: Optional[NextToken] - Filters: Optional[SessionFilterList] + MaxResults: SessionMaxResults | None + NextToken: NextToken | None + Filters: SessionFilterList | None class SessionManagerOutputUrl(TypedDict, total=False): - S3OutputUrl: Optional[SessionManagerS3OutputUrl] - CloudWatchOutputUrl: Optional[SessionManagerCloudWatchOutputUrl] + S3OutputUrl: SessionManagerS3OutputUrl | None + CloudWatchOutputUrl: SessionManagerCloudWatchOutputUrl | None class Session(TypedDict, total=False): - SessionId: Optional[SessionId] - Target: Optional[SessionTarget] - Status: Optional[SessionStatus] - StartDate: Optional[DateTime] - EndDate: Optional[DateTime] - DocumentName: Optional[DocumentName] - Owner: Optional[SessionOwner] - Reason: Optional[SessionReason] - Details: Optional[SessionDetails] - OutputUrl: Optional[SessionManagerOutputUrl] - MaxSessionDuration: Optional[MaxSessionDuration] - AccessType: Optional[AccessType] + SessionId: SessionId | None + Target: SessionTarget | None + Status: SessionStatus | None + StartDate: DateTime | None + EndDate: DateTime | None + DocumentName: DocumentName | None + Owner: SessionOwner | None + Reason: SessionReason | None + Details: SessionDetails | None + OutputUrl: SessionManagerOutputUrl | None + MaxSessionDuration: MaxSessionDuration | None + AccessType: AccessType | None -SessionList = List[Session] +SessionList = list[Session] class DescribeSessionsResponse(TypedDict, total=False): - Sessions: Optional[SessionList] - NextToken: Optional[NextToken] + Sessions: SessionList | None + NextToken: NextToken | None class DisassociateOpsItemRelatedItemRequest(ServiceRequest): @@ -4255,9 +4266,9 @@ class DisassociateOpsItemRelatedItemResponse(TypedDict, total=False): class DocumentDefaultVersionDescription(TypedDict, total=False): - Name: Optional[DocumentName] - DefaultVersion: Optional[DocumentVersion] - DefaultVersionName: Optional[DocumentVersionName] + Name: DocumentName | None + DefaultVersion: DocumentVersion | None + DefaultVersionName: DocumentVersionName | None class DocumentFilter(TypedDict, total=False): @@ -4265,89 +4276,89 @@ class DocumentFilter(TypedDict, total=False): value: DocumentFilterValue -DocumentFilterList = List[DocumentFilter] +DocumentFilterList = list[DocumentFilter] class DocumentIdentifier(TypedDict, total=False): - Name: Optional[DocumentARN] - CreatedDate: Optional[DateTime] - DisplayName: Optional[DocumentDisplayName] - Owner: Optional[DocumentOwner] - VersionName: Optional[DocumentVersionName] - PlatformTypes: Optional[PlatformTypeList] - DocumentVersion: Optional[DocumentVersion] - DocumentType: Optional[DocumentType] - SchemaVersion: Optional[DocumentSchemaVersion] - DocumentFormat: Optional[DocumentFormat] - TargetType: Optional[TargetType] - Tags: Optional[TagList] - Requires: Optional[DocumentRequiresList] - ReviewStatus: Optional[ReviewStatus] - Author: Optional[DocumentAuthor] - - -DocumentIdentifierList = List[DocumentIdentifier] -DocumentKeyValuesFilterValues = List[DocumentKeyValuesFilterValue] + Name: DocumentARN | None + CreatedDate: DateTime | None + DisplayName: DocumentDisplayName | None + Owner: DocumentOwner | None + VersionName: DocumentVersionName | None + PlatformTypes: PlatformTypeList | None + DocumentVersion: DocumentVersion | None + DocumentType: DocumentType | None + SchemaVersion: DocumentSchemaVersion | None + DocumentFormat: DocumentFormat | None + TargetType: TargetType | None + Tags: TagList | None + Requires: DocumentRequiresList | None + ReviewStatus: ReviewStatus | None + Author: DocumentAuthor | None + + +DocumentIdentifierList = list[DocumentIdentifier] +DocumentKeyValuesFilterValues = list[DocumentKeyValuesFilterValue] class DocumentKeyValuesFilter(TypedDict, total=False): - Key: Optional[DocumentKeyValuesFilterKey] - Values: Optional[DocumentKeyValuesFilterValues] + Key: DocumentKeyValuesFilterKey | None + Values: DocumentKeyValuesFilterValues | None -DocumentKeyValuesFilterList = List[DocumentKeyValuesFilter] +DocumentKeyValuesFilterList = list[DocumentKeyValuesFilter] class DocumentReviewCommentSource(TypedDict, total=False): - Type: Optional[DocumentReviewCommentType] - Content: Optional[DocumentReviewComment] + Type: DocumentReviewCommentType | None + Content: DocumentReviewComment | None -DocumentReviewCommentList = List[DocumentReviewCommentSource] +DocumentReviewCommentList = list[DocumentReviewCommentSource] class DocumentReviewerResponseSource(TypedDict, total=False): - CreateTime: Optional[DateTime] - UpdatedTime: Optional[DateTime] - ReviewStatus: Optional[ReviewStatus] - Comment: Optional[DocumentReviewCommentList] - Reviewer: Optional[Reviewer] + CreateTime: DateTime | None + UpdatedTime: DateTime | None + ReviewStatus: ReviewStatus | None + Comment: DocumentReviewCommentList | None + Reviewer: Reviewer | None -DocumentReviewerResponseList = List[DocumentReviewerResponseSource] +DocumentReviewerResponseList = list[DocumentReviewerResponseSource] class DocumentMetadataResponseInfo(TypedDict, total=False): - ReviewerResponse: Optional[DocumentReviewerResponseList] + ReviewerResponse: DocumentReviewerResponseList | None class DocumentReviews(TypedDict, total=False): Action: DocumentReviewAction - Comment: Optional[DocumentReviewCommentList] + Comment: DocumentReviewCommentList | None class DocumentVersionInfo(TypedDict, total=False): - Name: Optional[DocumentName] - DisplayName: Optional[DocumentDisplayName] - DocumentVersion: Optional[DocumentVersion] - VersionName: Optional[DocumentVersionName] - CreatedDate: Optional[DateTime] - IsDefaultVersion: Optional[Boolean] - DocumentFormat: Optional[DocumentFormat] - Status: Optional[DocumentStatus] - StatusInformation: Optional[DocumentStatusInformation] - ReviewStatus: Optional[ReviewStatus] + Name: DocumentName | None + DisplayName: DocumentDisplayName | None + DocumentVersion: DocumentVersion | None + VersionName: DocumentVersionName | None + CreatedDate: DateTime | None + IsDefaultVersion: Boolean | None + DocumentFormat: DocumentFormat | None + Status: DocumentStatus | None + StatusInformation: DocumentStatusInformation | None + ReviewStatus: ReviewStatus | None -DocumentVersionList = List[DocumentVersionInfo] +DocumentVersionList = list[DocumentVersionInfo] class ExecutionInputs(TypedDict, total=False): - Automation: Optional[AutomationExecutionInputs] + Automation: AutomationExecutionInputs | None class ExecutionPreview(TypedDict, total=False): - Automation: Optional[AutomationExecutionPreview] + Automation: AutomationExecutionPreview | None class GetAccessTokenRequest(ServiceRequest): @@ -4355,8 +4366,8 @@ class GetAccessTokenRequest(ServiceRequest): class GetAccessTokenResponse(TypedDict, total=False): - Credentials: Optional[Credentials] - AccessRequestStatus: Optional[AccessRequestStatus] + Credentials: Credentials | None + AccessRequestStatus: AccessRequestStatus | None class GetAutomationExecutionRequest(ServiceRequest): @@ -4364,44 +4375,44 @@ class GetAutomationExecutionRequest(ServiceRequest): class GetAutomationExecutionResult(TypedDict, total=False): - AutomationExecution: Optional[AutomationExecution] + AutomationExecution: AutomationExecution | None class GetCalendarStateRequest(ServiceRequest): CalendarNames: CalendarNameOrARNList - AtTime: Optional[ISO8601String] + AtTime: ISO8601String | None class GetCalendarStateResponse(TypedDict, total=False): - State: Optional[CalendarState] - AtTime: Optional[ISO8601String] - NextTransitionTime: Optional[ISO8601String] + State: CalendarState | None + AtTime: ISO8601String | None + NextTransitionTime: ISO8601String | None class GetCommandInvocationRequest(ServiceRequest): CommandId: CommandId InstanceId: InstanceId - PluginName: Optional[CommandPluginName] + PluginName: CommandPluginName | None class GetCommandInvocationResult(TypedDict, total=False): - CommandId: Optional[CommandId] - InstanceId: Optional[InstanceId] - Comment: Optional[Comment] - DocumentName: Optional[DocumentName] - DocumentVersion: Optional[DocumentVersion] - PluginName: Optional[CommandPluginName] - ResponseCode: Optional[ResponseCode] - ExecutionStartDateTime: Optional[StringDateTime] - ExecutionElapsedTime: Optional[StringDateTime] - ExecutionEndDateTime: Optional[StringDateTime] - Status: Optional[CommandInvocationStatus] - StatusDetails: Optional[StatusDetails] - StandardOutputContent: Optional[StandardOutputContent] - StandardOutputUrl: Optional[Url] - StandardErrorContent: Optional[StandardErrorContent] - StandardErrorUrl: Optional[Url] - CloudWatchOutputConfig: Optional[CloudWatchOutputConfig] + CommandId: CommandId | None + InstanceId: InstanceId | None + Comment: Comment | None + DocumentName: DocumentName | None + DocumentVersion: DocumentVersion | None + PluginName: CommandPluginName | None + ResponseCode: ResponseCode | None + ExecutionStartDateTime: StringDateTime | None + ExecutionElapsedTime: StringDateTime | None + ExecutionEndDateTime: StringDateTime | None + Status: CommandInvocationStatus | None + StatusDetails: StatusDetails | None + StandardOutputContent: StandardOutputContent | None + StandardOutputUrl: Url | None + StandardErrorContent: StandardErrorContent | None + StandardErrorUrl: Url | None + CloudWatchOutputConfig: CloudWatchOutputConfig | None class GetConnectionStatusRequest(ServiceRequest): @@ -4409,54 +4420,54 @@ class GetConnectionStatusRequest(ServiceRequest): class GetConnectionStatusResponse(TypedDict, total=False): - Target: Optional[SessionTarget] - Status: Optional[ConnectionStatus] + Target: SessionTarget | None + Status: ConnectionStatus | None class GetDefaultPatchBaselineRequest(ServiceRequest): - OperatingSystem: Optional[OperatingSystem] + OperatingSystem: OperatingSystem | None class GetDefaultPatchBaselineResult(TypedDict, total=False): - BaselineId: Optional[BaselineId] - OperatingSystem: Optional[OperatingSystem] + BaselineId: BaselineId | None + OperatingSystem: OperatingSystem | None class GetDeployablePatchSnapshotForInstanceRequest(ServiceRequest): InstanceId: InstanceId SnapshotId: SnapshotId - BaselineOverride: Optional[BaselineOverride] - UseS3DualStackEndpoint: Optional[Boolean] + BaselineOverride: BaselineOverride | None + UseS3DualStackEndpoint: Boolean | None class GetDeployablePatchSnapshotForInstanceResult(TypedDict, total=False): - InstanceId: Optional[InstanceId] - SnapshotId: Optional[SnapshotId] - SnapshotDownloadUrl: Optional[SnapshotDownloadUrl] - Product: Optional[Product] + InstanceId: InstanceId | None + SnapshotId: SnapshotId | None + SnapshotDownloadUrl: SnapshotDownloadUrl | None + Product: Product | None class GetDocumentRequest(ServiceRequest): Name: DocumentARN - VersionName: Optional[DocumentVersionName] - DocumentVersion: Optional[DocumentVersion] - DocumentFormat: Optional[DocumentFormat] + VersionName: DocumentVersionName | None + DocumentVersion: DocumentVersion | None + DocumentFormat: DocumentFormat | None class GetDocumentResult(TypedDict, total=False): - Name: Optional[DocumentARN] - CreatedDate: Optional[DateTime] - DisplayName: Optional[DocumentDisplayName] - VersionName: Optional[DocumentVersionName] - DocumentVersion: Optional[DocumentVersion] - Status: Optional[DocumentStatus] - StatusInformation: Optional[DocumentStatusInformation] - Content: Optional[DocumentContent] - DocumentType: Optional[DocumentType] - DocumentFormat: Optional[DocumentFormat] - Requires: Optional[DocumentRequiresList] - AttachmentsContent: Optional[AttachmentContentList] - ReviewStatus: Optional[ReviewStatus] + Name: DocumentARN | None + CreatedDate: DateTime | None + DisplayName: DocumentDisplayName | None + VersionName: DocumentVersionName | None + DocumentVersion: DocumentVersion | None + Status: DocumentStatus | None + StatusInformation: DocumentStatusInformation | None + Content: DocumentContent | None + DocumentType: DocumentType | None + DocumentFormat: DocumentFormat | None + Requires: DocumentRequiresList | None + AttachmentsContent: AttachmentContentList | None + ReviewStatus: ReviewStatus | None class GetExecutionPreviewRequest(ServiceRequest): @@ -4464,28 +4475,28 @@ class GetExecutionPreviewRequest(ServiceRequest): class GetExecutionPreviewResponse(TypedDict, total=False): - ExecutionPreviewId: Optional[ExecutionPreviewId] - EndedAt: Optional[DateTime] - Status: Optional[ExecutionPreviewStatus] - StatusMessage: Optional[String] - ExecutionPreview: Optional[ExecutionPreview] + ExecutionPreviewId: ExecutionPreviewId | None + EndedAt: DateTime | None + Status: ExecutionPreviewStatus | None + StatusMessage: String | None + ExecutionPreview: ExecutionPreview | None class ResultAttribute(TypedDict, total=False): TypeName: InventoryItemTypeName -ResultAttributeList = List[ResultAttribute] -InventoryFilterValueList = List[InventoryFilterValue] +ResultAttributeList = list[ResultAttribute] +InventoryFilterValueList = list[InventoryFilterValue] class InventoryFilter(TypedDict, total=False): Key: InventoryFilterKey Values: InventoryFilterValueList - Type: Optional[InventoryQueryOperatorType] + Type: InventoryQueryOperatorType | None -InventoryFilterList = List[InventoryFilter] +InventoryFilterList = list[InventoryFilter] class InventoryGroup(TypedDict, total=False): @@ -4493,58 +4504,58 @@ class InventoryGroup(TypedDict, total=False): Filters: InventoryFilterList -InventoryGroupList = List[InventoryGroup] -InventoryAggregatorList = List["InventoryAggregator"] +InventoryGroupList = list[InventoryGroup] +InventoryAggregatorList = list["InventoryAggregator"] class InventoryAggregator(TypedDict, total=False): - Expression: Optional[InventoryAggregatorExpression] - Aggregators: Optional[InventoryAggregatorList] - Groups: Optional[InventoryGroupList] + Expression: InventoryAggregatorExpression | None + Aggregators: InventoryAggregatorList | None + Groups: InventoryGroupList | None class GetInventoryRequest(ServiceRequest): - Filters: Optional[InventoryFilterList] - Aggregators: Optional[InventoryAggregatorList] - ResultAttributes: Optional[ResultAttributeList] - NextToken: Optional[NextToken] - MaxResults: Optional[MaxResults] + Filters: InventoryFilterList | None + Aggregators: InventoryAggregatorList | None + ResultAttributes: ResultAttributeList | None + NextToken: NextToken | None + MaxResults: MaxResults | None -InventoryItemEntry = Dict[AttributeName, AttributeValue] -InventoryItemEntryList = List[InventoryItemEntry] +InventoryItemEntry = dict[AttributeName, AttributeValue] +InventoryItemEntryList = list[InventoryItemEntry] class InventoryResultItem(TypedDict, total=False): TypeName: InventoryItemTypeName SchemaVersion: InventoryItemSchemaVersion - CaptureTime: Optional[InventoryItemCaptureTime] - ContentHash: Optional[InventoryItemContentHash] + CaptureTime: InventoryItemCaptureTime | None + ContentHash: InventoryItemContentHash | None Content: InventoryItemEntryList -InventoryResultItemMap = Dict[InventoryResultItemKey, InventoryResultItem] +InventoryResultItemMap = dict[InventoryResultItemKey, InventoryResultItem] class InventoryResultEntity(TypedDict, total=False): - Id: Optional[InventoryResultEntityId] - Data: Optional[InventoryResultItemMap] + Id: InventoryResultEntityId | None + Data: InventoryResultItemMap | None -InventoryResultEntityList = List[InventoryResultEntity] +InventoryResultEntityList = list[InventoryResultEntity] class GetInventoryResult(TypedDict, total=False): - Entities: Optional[InventoryResultEntityList] - NextToken: Optional[NextToken] + Entities: InventoryResultEntityList | None + NextToken: NextToken | None class GetInventorySchemaRequest(ServiceRequest): - TypeName: Optional[InventoryItemTypeNameFilter] - NextToken: Optional[NextToken] - MaxResults: Optional[GetInventorySchemaMaxResults] - Aggregator: Optional[AggregatorSchemaOnly] - SubType: Optional[IsSubTypeSchema] + TypeName: InventoryItemTypeNameFilter | None + NextToken: NextToken | None + MaxResults: GetInventorySchemaMaxResults | None + Aggregator: AggregatorSchemaOnly | None + SubType: IsSubTypeSchema | None class InventoryItemAttribute(TypedDict, total=False): @@ -4552,38 +4563,38 @@ class InventoryItemAttribute(TypedDict, total=False): DataType: InventoryAttributeDataType -InventoryItemAttributeList = List[InventoryItemAttribute] +InventoryItemAttributeList = list[InventoryItemAttribute] class InventoryItemSchema(TypedDict, total=False): TypeName: InventoryItemTypeName - Version: Optional[InventoryItemSchemaVersion] + Version: InventoryItemSchemaVersion | None Attributes: InventoryItemAttributeList - DisplayName: Optional[InventoryTypeDisplayName] + DisplayName: InventoryTypeDisplayName | None -InventoryItemSchemaResultList = List[InventoryItemSchema] +InventoryItemSchemaResultList = list[InventoryItemSchema] class GetInventorySchemaResult(TypedDict, total=False): - Schemas: Optional[InventoryItemSchemaResultList] - NextToken: Optional[NextToken] + Schemas: InventoryItemSchemaResultList | None + NextToken: NextToken | None class GetMaintenanceWindowExecutionRequest(ServiceRequest): WindowExecutionId: MaintenanceWindowExecutionId -MaintenanceWindowExecutionTaskIdList = List[MaintenanceWindowExecutionTaskId] +MaintenanceWindowExecutionTaskIdList = list[MaintenanceWindowExecutionTaskId] class GetMaintenanceWindowExecutionResult(TypedDict, total=False): - WindowExecutionId: Optional[MaintenanceWindowExecutionId] - TaskIds: Optional[MaintenanceWindowExecutionTaskIdList] - Status: Optional[MaintenanceWindowExecutionStatus] - StatusDetails: Optional[MaintenanceWindowExecutionStatusDetails] - StartTime: Optional[DateTime] - EndTime: Optional[DateTime] + WindowExecutionId: MaintenanceWindowExecutionId | None + TaskIds: MaintenanceWindowExecutionTaskIdList | None + Status: MaintenanceWindowExecutionStatus | None + StatusDetails: MaintenanceWindowExecutionStatusDetails | None + StartTime: DateTime | None + EndTime: DateTime | None class GetMaintenanceWindowExecutionTaskInvocationRequest(ServiceRequest): @@ -4593,18 +4604,18 @@ class GetMaintenanceWindowExecutionTaskInvocationRequest(ServiceRequest): class GetMaintenanceWindowExecutionTaskInvocationResult(TypedDict, total=False): - WindowExecutionId: Optional[MaintenanceWindowExecutionId] - TaskExecutionId: Optional[MaintenanceWindowExecutionTaskId] - InvocationId: Optional[MaintenanceWindowExecutionTaskInvocationId] - ExecutionId: Optional[MaintenanceWindowExecutionTaskExecutionId] - TaskType: Optional[MaintenanceWindowTaskType] - Parameters: Optional[MaintenanceWindowExecutionTaskInvocationParameters] - Status: Optional[MaintenanceWindowExecutionStatus] - StatusDetails: Optional[MaintenanceWindowExecutionStatusDetails] - StartTime: Optional[DateTime] - EndTime: Optional[DateTime] - OwnerInformation: Optional[OwnerInformation] - WindowTargetId: Optional[MaintenanceWindowTaskTargetId] + WindowExecutionId: MaintenanceWindowExecutionId | None + TaskExecutionId: MaintenanceWindowExecutionTaskId | None + InvocationId: MaintenanceWindowExecutionTaskInvocationId | None + ExecutionId: MaintenanceWindowExecutionTaskExecutionId | None + TaskType: MaintenanceWindowTaskType | None + Parameters: MaintenanceWindowExecutionTaskInvocationParameters | None + Status: MaintenanceWindowExecutionStatus | None + StatusDetails: MaintenanceWindowExecutionStatusDetails | None + StartTime: DateTime | None + EndTime: DateTime | None + OwnerInformation: OwnerInformation | None + WindowTargetId: MaintenanceWindowTaskTargetId | None class GetMaintenanceWindowExecutionTaskRequest(ServiceRequest): @@ -4612,25 +4623,25 @@ class GetMaintenanceWindowExecutionTaskRequest(ServiceRequest): TaskId: MaintenanceWindowExecutionTaskId -MaintenanceWindowTaskParametersList = List[MaintenanceWindowTaskParameters] +MaintenanceWindowTaskParametersList = list[MaintenanceWindowTaskParameters] class GetMaintenanceWindowExecutionTaskResult(TypedDict, total=False): - WindowExecutionId: Optional[MaintenanceWindowExecutionId] - TaskExecutionId: Optional[MaintenanceWindowExecutionTaskId] - TaskArn: Optional[MaintenanceWindowTaskArn] - ServiceRole: Optional[ServiceRole] - Type: Optional[MaintenanceWindowTaskType] - TaskParameters: Optional[MaintenanceWindowTaskParametersList] - Priority: Optional[MaintenanceWindowTaskPriority] - MaxConcurrency: Optional[MaxConcurrency] - MaxErrors: Optional[MaxErrors] - Status: Optional[MaintenanceWindowExecutionStatus] - StatusDetails: Optional[MaintenanceWindowExecutionStatusDetails] - StartTime: Optional[DateTime] - EndTime: Optional[DateTime] - AlarmConfiguration: Optional[AlarmConfiguration] - TriggeredAlarms: Optional[AlarmStateInformationList] + WindowExecutionId: MaintenanceWindowExecutionId | None + TaskExecutionId: MaintenanceWindowExecutionTaskId | None + TaskArn: MaintenanceWindowTaskArn | None + ServiceRole: ServiceRole | None + Type: MaintenanceWindowTaskType | None + TaskParameters: MaintenanceWindowTaskParametersList | None + Priority: MaintenanceWindowTaskPriority | None + MaxConcurrency: MaxConcurrency | None + MaxErrors: MaxErrors | None + Status: MaintenanceWindowExecutionStatus | None + StatusDetails: MaintenanceWindowExecutionStatusDetails | None + StartTime: DateTime | None + EndTime: DateTime | None + AlarmConfiguration: AlarmConfiguration | None + TriggeredAlarms: AlarmStateInformationList | None class GetMaintenanceWindowRequest(ServiceRequest): @@ -4638,21 +4649,21 @@ class GetMaintenanceWindowRequest(ServiceRequest): class GetMaintenanceWindowResult(TypedDict, total=False): - WindowId: Optional[MaintenanceWindowId] - Name: Optional[MaintenanceWindowName] - Description: Optional[MaintenanceWindowDescription] - StartDate: Optional[MaintenanceWindowStringDateTime] - EndDate: Optional[MaintenanceWindowStringDateTime] - Schedule: Optional[MaintenanceWindowSchedule] - ScheduleTimezone: Optional[MaintenanceWindowTimezone] - ScheduleOffset: Optional[MaintenanceWindowOffset] - NextExecutionTime: Optional[MaintenanceWindowStringDateTime] - Duration: Optional[MaintenanceWindowDurationHours] - Cutoff: Optional[MaintenanceWindowCutoff] - AllowUnassociatedTargets: Optional[MaintenanceWindowAllowUnassociatedTargets] - Enabled: Optional[MaintenanceWindowEnabled] - CreatedDate: Optional[DateTime] - ModifiedDate: Optional[DateTime] + WindowId: MaintenanceWindowId | None + Name: MaintenanceWindowName | None + Description: MaintenanceWindowDescription | None + StartDate: MaintenanceWindowStringDateTime | None + EndDate: MaintenanceWindowStringDateTime | None + Schedule: MaintenanceWindowSchedule | None + ScheduleTimezone: MaintenanceWindowTimezone | None + ScheduleOffset: MaintenanceWindowOffset | None + NextExecutionTime: MaintenanceWindowStringDateTime | None + Duration: MaintenanceWindowDurationHours | None + Cutoff: MaintenanceWindowCutoff | None + AllowUnassociatedTargets: MaintenanceWindowAllowUnassociatedTargets | None + Enabled: MaintenanceWindowEnabled | None + CreatedDate: DateTime | None + ModifiedDate: DateTime | None class GetMaintenanceWindowTaskRequest(ServiceRequest): @@ -4664,306 +4675,306 @@ class GetMaintenanceWindowTaskRequest(ServiceRequest): class MaintenanceWindowLambdaParameters(TypedDict, total=False): - ClientContext: Optional[MaintenanceWindowLambdaClientContext] - Qualifier: Optional[MaintenanceWindowLambdaQualifier] - Payload: Optional[MaintenanceWindowLambdaPayload] + ClientContext: MaintenanceWindowLambdaClientContext | None + Qualifier: MaintenanceWindowLambdaQualifier | None + Payload: MaintenanceWindowLambdaPayload | None class MaintenanceWindowStepFunctionsParameters(TypedDict, total=False): - Input: Optional[MaintenanceWindowStepFunctionsInput] - Name: Optional[MaintenanceWindowStepFunctionsName] + Input: MaintenanceWindowStepFunctionsInput | None + Name: MaintenanceWindowStepFunctionsName | None class MaintenanceWindowAutomationParameters(TypedDict, total=False): - DocumentVersion: Optional[DocumentVersion] - Parameters: Optional[AutomationParameterMap] + DocumentVersion: DocumentVersion | None + Parameters: AutomationParameterMap | None class MaintenanceWindowRunCommandParameters(TypedDict, total=False): - Comment: Optional[Comment] - CloudWatchOutputConfig: Optional[CloudWatchOutputConfig] - DocumentHash: Optional[DocumentHash] - DocumentHashType: Optional[DocumentHashType] - DocumentVersion: Optional[DocumentVersion] - NotificationConfig: Optional[NotificationConfig] - OutputS3BucketName: Optional[S3BucketName] - OutputS3KeyPrefix: Optional[S3KeyPrefix] - Parameters: Optional[Parameters] - ServiceRoleArn: Optional[ServiceRole] - TimeoutSeconds: Optional[TimeoutSeconds] + Comment: Comment | None + CloudWatchOutputConfig: CloudWatchOutputConfig | None + DocumentHash: DocumentHash | None + DocumentHashType: DocumentHashType | None + DocumentVersion: DocumentVersion | None + NotificationConfig: NotificationConfig | None + OutputS3BucketName: S3BucketName | None + OutputS3KeyPrefix: S3KeyPrefix | None + Parameters: Parameters | None + ServiceRoleArn: ServiceRole | None + TimeoutSeconds: TimeoutSeconds | None class MaintenanceWindowTaskInvocationParameters(TypedDict, total=False): - RunCommand: Optional[MaintenanceWindowRunCommandParameters] - Automation: Optional[MaintenanceWindowAutomationParameters] - StepFunctions: Optional[MaintenanceWindowStepFunctionsParameters] - Lambda: Optional[MaintenanceWindowLambdaParameters] + RunCommand: MaintenanceWindowRunCommandParameters | None + Automation: MaintenanceWindowAutomationParameters | None + StepFunctions: MaintenanceWindowStepFunctionsParameters | None + Lambda: MaintenanceWindowLambdaParameters | None class GetMaintenanceWindowTaskResult(TypedDict, total=False): - WindowId: Optional[MaintenanceWindowId] - WindowTaskId: Optional[MaintenanceWindowTaskId] - Targets: Optional[Targets] - TaskArn: Optional[MaintenanceWindowTaskArn] - ServiceRoleArn: Optional[ServiceRole] - TaskType: Optional[MaintenanceWindowTaskType] - TaskParameters: Optional[MaintenanceWindowTaskParameters] - TaskInvocationParameters: Optional[MaintenanceWindowTaskInvocationParameters] - Priority: Optional[MaintenanceWindowTaskPriority] - MaxConcurrency: Optional[MaxConcurrency] - MaxErrors: Optional[MaxErrors] - LoggingInfo: Optional[LoggingInfo] - Name: Optional[MaintenanceWindowName] - Description: Optional[MaintenanceWindowDescription] - CutoffBehavior: Optional[MaintenanceWindowTaskCutoffBehavior] - AlarmConfiguration: Optional[AlarmConfiguration] + WindowId: MaintenanceWindowId | None + WindowTaskId: MaintenanceWindowTaskId | None + Targets: Targets | None + TaskArn: MaintenanceWindowTaskArn | None + ServiceRoleArn: ServiceRole | None + TaskType: MaintenanceWindowTaskType | None + TaskParameters: MaintenanceWindowTaskParameters | None + TaskInvocationParameters: MaintenanceWindowTaskInvocationParameters | None + Priority: MaintenanceWindowTaskPriority | None + MaxConcurrency: MaxConcurrency | None + MaxErrors: MaxErrors | None + LoggingInfo: LoggingInfo | None + Name: MaintenanceWindowName | None + Description: MaintenanceWindowDescription | None + CutoffBehavior: MaintenanceWindowTaskCutoffBehavior | None + AlarmConfiguration: AlarmConfiguration | None class GetOpsItemRequest(ServiceRequest): OpsItemId: OpsItemId - OpsItemArn: Optional[OpsItemArn] + OpsItemArn: OpsItemArn | None class OpsItem(TypedDict, total=False): - CreatedBy: Optional[String] - OpsItemType: Optional[OpsItemType] - CreatedTime: Optional[DateTime] - Description: Optional[OpsItemDescription] - LastModifiedBy: Optional[String] - LastModifiedTime: Optional[DateTime] - Notifications: Optional[OpsItemNotifications] - Priority: Optional[OpsItemPriority] - RelatedOpsItems: Optional[RelatedOpsItems] - Status: Optional[OpsItemStatus] - OpsItemId: Optional[OpsItemId] - Version: Optional[String] - Title: Optional[OpsItemTitle] - Source: Optional[OpsItemSource] - OperationalData: Optional[OpsItemOperationalData] - Category: Optional[OpsItemCategory] - Severity: Optional[OpsItemSeverity] - ActualStartTime: Optional[DateTime] - ActualEndTime: Optional[DateTime] - PlannedStartTime: Optional[DateTime] - PlannedEndTime: Optional[DateTime] - OpsItemArn: Optional[OpsItemArn] + CreatedBy: String | None + OpsItemType: OpsItemType | None + CreatedTime: DateTime | None + Description: OpsItemDescription | None + LastModifiedBy: String | None + LastModifiedTime: DateTime | None + Notifications: OpsItemNotifications | None + Priority: OpsItemPriority | None + RelatedOpsItems: RelatedOpsItems | None + Status: OpsItemStatus | None + OpsItemId: OpsItemId | None + Version: String | None + Title: OpsItemTitle | None + Source: OpsItemSource | None + OperationalData: OpsItemOperationalData | None + Category: OpsItemCategory | None + Severity: OpsItemSeverity | None + ActualStartTime: DateTime | None + ActualEndTime: DateTime | None + PlannedStartTime: DateTime | None + PlannedEndTime: DateTime | None + OpsItemArn: OpsItemArn | None class GetOpsItemResponse(TypedDict, total=False): - OpsItem: Optional[OpsItem] + OpsItem: OpsItem | None class GetOpsMetadataRequest(ServiceRequest): OpsMetadataArn: OpsMetadataArn - MaxResults: Optional[GetOpsMetadataMaxResults] - NextToken: Optional[NextToken] + MaxResults: GetOpsMetadataMaxResults | None + NextToken: NextToken | None class GetOpsMetadataResult(TypedDict, total=False): - ResourceId: Optional[OpsMetadataResourceId] - Metadata: Optional[MetadataMap] - NextToken: Optional[NextToken] + ResourceId: OpsMetadataResourceId | None + Metadata: MetadataMap | None + NextToken: NextToken | None class OpsResultAttribute(TypedDict, total=False): TypeName: OpsDataTypeName -OpsResultAttributeList = List[OpsResultAttribute] -OpsAggregatorList = List["OpsAggregator"] -OpsFilterValueList = List[OpsFilterValue] +OpsResultAttributeList = list[OpsResultAttribute] +OpsAggregatorList = list["OpsAggregator"] +OpsFilterValueList = list[OpsFilterValue] class OpsFilter(TypedDict, total=False): Key: OpsFilterKey Values: OpsFilterValueList - Type: Optional[OpsFilterOperatorType] + Type: OpsFilterOperatorType | None -OpsFilterList = List[OpsFilter] -OpsAggregatorValueMap = Dict[OpsAggregatorValueKey, OpsAggregatorValue] +OpsFilterList = list[OpsFilter] +OpsAggregatorValueMap = dict[OpsAggregatorValueKey, OpsAggregatorValue] class OpsAggregator(TypedDict, total=False): - AggregatorType: Optional[OpsAggregatorType] - TypeName: Optional[OpsDataTypeName] - AttributeName: Optional[OpsDataAttributeName] - Values: Optional[OpsAggregatorValueMap] - Filters: Optional[OpsFilterList] - Aggregators: Optional[OpsAggregatorList] + AggregatorType: OpsAggregatorType | None + TypeName: OpsDataTypeName | None + AttributeName: OpsDataAttributeName | None + Values: OpsAggregatorValueMap | None + Filters: OpsFilterList | None + Aggregators: OpsAggregatorList | None class GetOpsSummaryRequest(ServiceRequest): - SyncName: Optional[ResourceDataSyncName] - Filters: Optional[OpsFilterList] - Aggregators: Optional[OpsAggregatorList] - ResultAttributes: Optional[OpsResultAttributeList] - NextToken: Optional[NextToken] - MaxResults: Optional[MaxResults] + SyncName: ResourceDataSyncName | None + Filters: OpsFilterList | None + Aggregators: OpsAggregatorList | None + ResultAttributes: OpsResultAttributeList | None + NextToken: NextToken | None + MaxResults: MaxResults | None -OpsEntityItemEntry = Dict[AttributeName, AttributeValue] -OpsEntityItemEntryList = List[OpsEntityItemEntry] +OpsEntityItemEntry = dict[AttributeName, AttributeValue] +OpsEntityItemEntryList = list[OpsEntityItemEntry] class OpsEntityItem(TypedDict, total=False): - CaptureTime: Optional[OpsEntityItemCaptureTime] - Content: Optional[OpsEntityItemEntryList] + CaptureTime: OpsEntityItemCaptureTime | None + Content: OpsEntityItemEntryList | None -OpsEntityItemMap = Dict[OpsEntityItemKey, OpsEntityItem] +OpsEntityItemMap = dict[OpsEntityItemKey, OpsEntityItem] class OpsEntity(TypedDict, total=False): - Id: Optional[OpsEntityId] - Data: Optional[OpsEntityItemMap] + Id: OpsEntityId | None + Data: OpsEntityItemMap | None -OpsEntityList = List[OpsEntity] +OpsEntityList = list[OpsEntity] class GetOpsSummaryResult(TypedDict, total=False): - Entities: Optional[OpsEntityList] - NextToken: Optional[NextToken] + Entities: OpsEntityList | None + NextToken: NextToken | None class GetParameterHistoryRequest(ServiceRequest): Name: PSParameterName - WithDecryption: Optional[Boolean] - MaxResults: Optional[MaxResults] - NextToken: Optional[NextToken] + WithDecryption: Boolean | None + MaxResults: MaxResults | None + NextToken: NextToken | None -ParameterLabelList = List[ParameterLabel] +ParameterLabelList = list[ParameterLabel] class ParameterHistory(TypedDict, total=False): - Name: Optional[PSParameterName] - Type: Optional[ParameterType] - KeyId: Optional[ParameterKeyId] - LastModifiedDate: Optional[DateTime] - LastModifiedUser: Optional[String] - Description: Optional[ParameterDescription] - Value: Optional[PSParameterValue] - AllowedPattern: Optional[AllowedPattern] - Version: Optional[PSParameterVersion] - Labels: Optional[ParameterLabelList] - Tier: Optional[ParameterTier] - Policies: Optional[ParameterPolicyList] - DataType: Optional[ParameterDataType] + Name: PSParameterName | None + Type: ParameterType | None + KeyId: ParameterKeyId | None + LastModifiedDate: DateTime | None + LastModifiedUser: String | None + Description: ParameterDescription | None + Value: PSParameterValue | None + AllowedPattern: AllowedPattern | None + Version: PSParameterVersion | None + Labels: ParameterLabelList | None + Tier: ParameterTier | None + Policies: ParameterPolicyList | None + DataType: ParameterDataType | None -ParameterHistoryList = List[ParameterHistory] +ParameterHistoryList = list[ParameterHistory] class GetParameterHistoryResult(TypedDict, total=False): - Parameters: Optional[ParameterHistoryList] - NextToken: Optional[NextToken] + Parameters: ParameterHistoryList | None + NextToken: NextToken | None class GetParameterRequest(ServiceRequest): Name: PSParameterName - WithDecryption: Optional[Boolean] + WithDecryption: Boolean | None class Parameter(TypedDict, total=False): - Name: Optional[PSParameterName] - Type: Optional[ParameterType] - Value: Optional[PSParameterValue] - Version: Optional[PSParameterVersion] - Selector: Optional[PSParameterSelector] - SourceResult: Optional[String] - LastModifiedDate: Optional[DateTime] - ARN: Optional[String] - DataType: Optional[ParameterDataType] + Name: PSParameterName | None + Type: ParameterType | None + Value: PSParameterValue | None + Version: PSParameterVersion | None + Selector: PSParameterSelector | None + SourceResult: String | None + LastModifiedDate: DateTime | None + ARN: String | None + DataType: ParameterDataType | None class GetParameterResult(TypedDict, total=False): - Parameter: Optional[Parameter] + Parameter: Parameter | None class GetParametersByPathRequest(ServiceRequest): Path: PSParameterName - Recursive: Optional[Boolean] - ParameterFilters: Optional[ParameterStringFilterList] - WithDecryption: Optional[Boolean] - MaxResults: Optional[GetParametersByPathMaxResults] - NextToken: Optional[NextToken] + Recursive: Boolean | None + ParameterFilters: ParameterStringFilterList | None + WithDecryption: Boolean | None + MaxResults: GetParametersByPathMaxResults | None + NextToken: NextToken | None -ParameterList = List[Parameter] +ParameterList = list[Parameter] class GetParametersByPathResult(TypedDict, total=False): - Parameters: Optional[ParameterList] - NextToken: Optional[NextToken] + Parameters: ParameterList | None + NextToken: NextToken | None class GetParametersRequest(ServiceRequest): Names: ParameterNameList - WithDecryption: Optional[Boolean] + WithDecryption: Boolean | None class GetParametersResult(TypedDict, total=False): - Parameters: Optional[ParameterList] - InvalidParameters: Optional[ParameterNameList] + Parameters: ParameterList | None + InvalidParameters: ParameterNameList | None class GetPatchBaselineForPatchGroupRequest(ServiceRequest): PatchGroup: PatchGroup - OperatingSystem: Optional[OperatingSystem] + OperatingSystem: OperatingSystem | None class GetPatchBaselineForPatchGroupResult(TypedDict, total=False): - BaselineId: Optional[BaselineId] - PatchGroup: Optional[PatchGroup] - OperatingSystem: Optional[OperatingSystem] + BaselineId: BaselineId | None + PatchGroup: PatchGroup | None + OperatingSystem: OperatingSystem | None class GetPatchBaselineRequest(ServiceRequest): BaselineId: BaselineId -PatchGroupList = List[PatchGroup] +PatchGroupList = list[PatchGroup] class GetPatchBaselineResult(TypedDict, total=False): - BaselineId: Optional[BaselineId] - Name: Optional[BaselineName] - OperatingSystem: Optional[OperatingSystem] - GlobalFilters: Optional[PatchFilterGroup] - ApprovalRules: Optional[PatchRuleGroup] - ApprovedPatches: Optional[PatchIdList] - ApprovedPatchesComplianceLevel: Optional[PatchComplianceLevel] - ApprovedPatchesEnableNonSecurity: Optional[Boolean] - RejectedPatches: Optional[PatchIdList] - RejectedPatchesAction: Optional[PatchAction] - PatchGroups: Optional[PatchGroupList] - CreatedDate: Optional[DateTime] - ModifiedDate: Optional[DateTime] - Description: Optional[BaselineDescription] - Sources: Optional[PatchSourceList] - AvailableSecurityUpdatesComplianceStatus: Optional[PatchComplianceStatus] + BaselineId: BaselineId | None + Name: BaselineName | None + OperatingSystem: OperatingSystem | None + GlobalFilters: PatchFilterGroup | None + ApprovalRules: PatchRuleGroup | None + ApprovedPatches: PatchIdList | None + ApprovedPatchesComplianceLevel: PatchComplianceLevel | None + ApprovedPatchesEnableNonSecurity: Boolean | None + RejectedPatches: PatchIdList | None + RejectedPatchesAction: PatchAction | None + PatchGroups: PatchGroupList | None + CreatedDate: DateTime | None + ModifiedDate: DateTime | None + Description: BaselineDescription | None + Sources: PatchSourceList | None + AvailableSecurityUpdatesComplianceStatus: PatchComplianceStatus | None class GetResourcePoliciesRequest(ServiceRequest): ResourceArn: ResourceArnString - NextToken: Optional[String] - MaxResults: Optional[ResourcePolicyMaxResults] + NextToken: String | None + MaxResults: ResourcePolicyMaxResults | None class GetResourcePoliciesResponseEntry(TypedDict, total=False): - PolicyId: Optional[PolicyId] - PolicyHash: Optional[PolicyHash] - Policy: Optional[Policy] + PolicyId: PolicyId | None + PolicyHash: PolicyHash | None + Policy: Policy | None -GetResourcePoliciesResponseEntries = List[GetResourcePoliciesResponseEntry] +GetResourcePoliciesResponseEntries = list[GetResourcePoliciesResponseEntry] class GetResourcePoliciesResponse(TypedDict, total=False): - NextToken: Optional[String] - Policies: Optional[GetResourcePoliciesResponseEntries] + NextToken: String | None + Policies: GetResourcePoliciesResponseEntries | None class GetServiceSettingRequest(ServiceRequest): @@ -4971,56 +4982,56 @@ class GetServiceSettingRequest(ServiceRequest): class ServiceSetting(TypedDict, total=False): - SettingId: Optional[ServiceSettingId] - SettingValue: Optional[ServiceSettingValue] - LastModifiedDate: Optional[DateTime] - LastModifiedUser: Optional[String] - ARN: Optional[String] - Status: Optional[String] + SettingId: ServiceSettingId | None + SettingValue: ServiceSettingValue | None + LastModifiedDate: DateTime | None + LastModifiedUser: String | None + ARN: String | None + Status: String | None class GetServiceSettingResult(TypedDict, total=False): - ServiceSetting: Optional[ServiceSetting] + ServiceSetting: ServiceSetting | None class InstanceInfo(TypedDict, total=False): - AgentType: Optional[AgentType] - AgentVersion: Optional[AgentVersion] - ComputerName: Optional[ComputerName] - InstanceStatus: Optional[InstanceStatus] - IpAddress: Optional[IpAddress] - ManagedStatus: Optional[ManagedStatus] - PlatformType: Optional[PlatformType] - PlatformName: Optional[PlatformName] - PlatformVersion: Optional[PlatformVersion] - ResourceType: Optional[ResourceType] + AgentType: AgentType | None + AgentVersion: AgentVersion | None + ComputerName: ComputerName | None + InstanceStatus: InstanceStatus | None + IpAddress: IpAddress | None + ManagedStatus: ManagedStatus | None + PlatformType: PlatformType | None + PlatformName: PlatformName | None + PlatformVersion: PlatformVersion | None + ResourceType: ResourceType | None -InventoryItemContentContext = Dict[AttributeName, AttributeValue] +InventoryItemContentContext = dict[AttributeName, AttributeValue] class InventoryItem(TypedDict, total=False): TypeName: InventoryItemTypeName SchemaVersion: InventoryItemSchemaVersion CaptureTime: InventoryItemCaptureTime - ContentHash: Optional[InventoryItemContentHash] - Content: Optional[InventoryItemEntryList] - Context: Optional[InventoryItemContentContext] + ContentHash: InventoryItemContentHash | None + Content: InventoryItemEntryList | None + Context: InventoryItemContentContext | None -InventoryItemList = List[InventoryItem] -KeyList = List[TagKey] +InventoryItemList = list[InventoryItem] +KeyList = list[TagKey] class LabelParameterVersionRequest(ServiceRequest): Name: PSParameterName - ParameterVersion: Optional[PSParameterVersion] + ParameterVersion: PSParameterVersion | None Labels: ParameterLabelList class LabelParameterVersionResult(TypedDict, total=False): - InvalidLabels: Optional[ParameterLabelList] - ParameterVersion: Optional[PSParameterVersion] + InvalidLabels: ParameterLabelList | None + ParameterVersion: PSParameterVersion | None LastResourceDataSyncTime = datetime @@ -5029,209 +5040,209 @@ class LabelParameterVersionResult(TypedDict, total=False): class ListAssociationVersionsRequest(ServiceRequest): AssociationId: AssociationId - MaxResults: Optional[MaxResults] - NextToken: Optional[NextToken] + MaxResults: MaxResults | None + NextToken: NextToken | None class ListAssociationVersionsResult(TypedDict, total=False): - AssociationVersions: Optional[AssociationVersionList] - NextToken: Optional[NextToken] + AssociationVersions: AssociationVersionList | None + NextToken: NextToken | None class ListAssociationsRequest(ServiceRequest): - AssociationFilterList: Optional[AssociationFilterList] - MaxResults: Optional[MaxResults] - NextToken: Optional[NextToken] + AssociationFilterList: AssociationFilterList | None + MaxResults: MaxResults | None + NextToken: NextToken | None class ListAssociationsResult(TypedDict, total=False): - Associations: Optional[AssociationList] - NextToken: Optional[NextToken] + Associations: AssociationList | None + NextToken: NextToken | None class ListCommandInvocationsRequest(ServiceRequest): - CommandId: Optional[CommandId] - InstanceId: Optional[InstanceId] - MaxResults: Optional[CommandMaxResults] - NextToken: Optional[NextToken] - Filters: Optional[CommandFilterList] - Details: Optional[Boolean] + CommandId: CommandId | None + InstanceId: InstanceId | None + MaxResults: CommandMaxResults | None + NextToken: NextToken | None + Filters: CommandFilterList | None + Details: Boolean | None class ListCommandInvocationsResult(TypedDict, total=False): - CommandInvocations: Optional[CommandInvocationList] - NextToken: Optional[NextToken] + CommandInvocations: CommandInvocationList | None + NextToken: NextToken | None class ListCommandsRequest(ServiceRequest): - CommandId: Optional[CommandId] - InstanceId: Optional[InstanceId] - MaxResults: Optional[CommandMaxResults] - NextToken: Optional[NextToken] - Filters: Optional[CommandFilterList] + CommandId: CommandId | None + InstanceId: InstanceId | None + MaxResults: CommandMaxResults | None + NextToken: NextToken | None + Filters: CommandFilterList | None class ListCommandsResult(TypedDict, total=False): - Commands: Optional[CommandList] - NextToken: Optional[NextToken] + Commands: CommandList | None + NextToken: NextToken | None class ListComplianceItemsRequest(ServiceRequest): - Filters: Optional[ComplianceStringFilterList] - ResourceIds: Optional[ComplianceResourceIdList] - ResourceTypes: Optional[ComplianceResourceTypeList] - NextToken: Optional[NextToken] - MaxResults: Optional[MaxResults] + Filters: ComplianceStringFilterList | None + ResourceIds: ComplianceResourceIdList | None + ResourceTypes: ComplianceResourceTypeList | None + NextToken: NextToken | None + MaxResults: MaxResults | None class ListComplianceItemsResult(TypedDict, total=False): - ComplianceItems: Optional[ComplianceItemList] - NextToken: Optional[NextToken] + ComplianceItems: ComplianceItemList | None + NextToken: NextToken | None class ListComplianceSummariesRequest(ServiceRequest): - Filters: Optional[ComplianceStringFilterList] - NextToken: Optional[NextToken] - MaxResults: Optional[MaxResults] + Filters: ComplianceStringFilterList | None + NextToken: NextToken | None + MaxResults: MaxResults | None class ListComplianceSummariesResult(TypedDict, total=False): - ComplianceSummaryItems: Optional[ComplianceSummaryItemList] - NextToken: Optional[NextToken] + ComplianceSummaryItems: ComplianceSummaryItemList | None + NextToken: NextToken | None class ListDocumentMetadataHistoryRequest(ServiceRequest): Name: DocumentName - DocumentVersion: Optional[DocumentVersion] + DocumentVersion: DocumentVersion | None Metadata: DocumentMetadataEnum - NextToken: Optional[NextToken] - MaxResults: Optional[MaxResults] + NextToken: NextToken | None + MaxResults: MaxResults | None class ListDocumentMetadataHistoryResponse(TypedDict, total=False): - Name: Optional[DocumentName] - DocumentVersion: Optional[DocumentVersion] - Author: Optional[DocumentAuthor] - Metadata: Optional[DocumentMetadataResponseInfo] - NextToken: Optional[NextToken] + Name: DocumentName | None + DocumentVersion: DocumentVersion | None + Author: DocumentAuthor | None + Metadata: DocumentMetadataResponseInfo | None + NextToken: NextToken | None class ListDocumentVersionsRequest(ServiceRequest): Name: DocumentARN - MaxResults: Optional[MaxResults] - NextToken: Optional[NextToken] + MaxResults: MaxResults | None + NextToken: NextToken | None class ListDocumentVersionsResult(TypedDict, total=False): - DocumentVersions: Optional[DocumentVersionList] - NextToken: Optional[NextToken] + DocumentVersions: DocumentVersionList | None + NextToken: NextToken | None class ListDocumentsRequest(ServiceRequest): - DocumentFilterList: Optional[DocumentFilterList] - Filters: Optional[DocumentKeyValuesFilterList] - MaxResults: Optional[MaxResults] - NextToken: Optional[NextToken] + DocumentFilterList: DocumentFilterList | None + Filters: DocumentKeyValuesFilterList | None + MaxResults: MaxResults | None + NextToken: NextToken | None class ListDocumentsResult(TypedDict, total=False): - DocumentIdentifiers: Optional[DocumentIdentifierList] - NextToken: Optional[NextToken] + DocumentIdentifiers: DocumentIdentifierList | None + NextToken: NextToken | None class ListInventoryEntriesRequest(ServiceRequest): InstanceId: InstanceId TypeName: InventoryItemTypeName - Filters: Optional[InventoryFilterList] - NextToken: Optional[NextToken] - MaxResults: Optional[MaxResults] + Filters: InventoryFilterList | None + NextToken: NextToken | None + MaxResults: MaxResults | None class ListInventoryEntriesResult(TypedDict, total=False): - TypeName: Optional[InventoryItemTypeName] - InstanceId: Optional[InstanceId] - SchemaVersion: Optional[InventoryItemSchemaVersion] - CaptureTime: Optional[InventoryItemCaptureTime] - Entries: Optional[InventoryItemEntryList] - NextToken: Optional[NextToken] + TypeName: InventoryItemTypeName | None + InstanceId: InstanceId | None + SchemaVersion: InventoryItemSchemaVersion | None + CaptureTime: InventoryItemCaptureTime | None + Entries: InventoryItemEntryList | None + NextToken: NextToken | None -NodeFilterValueList = List[NodeFilterValue] +NodeFilterValueList = list[NodeFilterValue] class NodeFilter(TypedDict, total=False): Key: NodeFilterKey Values: NodeFilterValueList - Type: Optional[NodeFilterOperatorType] + Type: NodeFilterOperatorType | None -NodeFilterList = List[NodeFilter] +NodeFilterList = list[NodeFilter] class ListNodesRequest(ServiceRequest): - SyncName: Optional[ResourceDataSyncName] - Filters: Optional[NodeFilterList] - NextToken: Optional[NextToken] - MaxResults: Optional[MaxResults] + SyncName: ResourceDataSyncName | None + Filters: NodeFilterList | None + NextToken: NextToken | None + MaxResults: MaxResults | None class NodeType(TypedDict, total=False): - Instance: Optional[InstanceInfo] + Instance: InstanceInfo | None class NodeOwnerInfo(TypedDict, total=False): - AccountId: Optional[NodeAccountId] - OrganizationalUnitId: Optional[NodeOrganizationalUnitId] - OrganizationalUnitPath: Optional[NodeOrganizationalUnitPath] + AccountId: NodeAccountId | None + OrganizationalUnitId: NodeOrganizationalUnitId | None + OrganizationalUnitPath: NodeOrganizationalUnitPath | None NodeCaptureTime = datetime class Node(TypedDict, total=False): - CaptureTime: Optional[NodeCaptureTime] - Id: Optional[NodeId] - Owner: Optional[NodeOwnerInfo] - Region: Optional[NodeRegion] - NodeType: Optional[NodeType] + CaptureTime: NodeCaptureTime | None + Id: NodeId | None + Owner: NodeOwnerInfo | None + Region: NodeRegion | None + NodeType: NodeType | None -NodeList = List[Node] +NodeList = list[Node] class ListNodesResult(TypedDict, total=False): - Nodes: Optional[NodeList] - NextToken: Optional[NextToken] + Nodes: NodeList | None + NextToken: NextToken | None -NodeAggregatorList = List["NodeAggregator"] +NodeAggregatorList = list["NodeAggregator"] class NodeAggregator(TypedDict, total=False): AggregatorType: NodeAggregatorType TypeName: NodeTypeName AttributeName: NodeAttributeName - Aggregators: Optional[NodeAggregatorList] + Aggregators: NodeAggregatorList | None class ListNodesSummaryRequest(ServiceRequest): - SyncName: Optional[ResourceDataSyncName] - Filters: Optional[NodeFilterList] + SyncName: ResourceDataSyncName | None + Filters: NodeFilterList | None Aggregators: NodeAggregatorList - NextToken: Optional[NextToken] - MaxResults: Optional[MaxResults] + NextToken: NextToken | None + MaxResults: MaxResults | None -NodeSummary = Dict[AttributeName, AttributeValue] -NodeSummaryList = List[NodeSummary] +NodeSummary = dict[AttributeName, AttributeValue] +NodeSummaryList = list[NodeSummary] class ListNodesSummaryResult(TypedDict, total=False): - Summary: Optional[NodeSummaryList] - NextToken: Optional[NextToken] + Summary: NodeSummaryList | None + NextToken: NextToken | None -OpsItemEventFilterValues = List[OpsItemEventFilterValue] +OpsItemEventFilterValues = list[OpsItemEventFilterValue] class OpsItemEventFilter(TypedDict, total=False): @@ -5240,38 +5251,38 @@ class OpsItemEventFilter(TypedDict, total=False): Operator: OpsItemEventFilterOperator -OpsItemEventFilters = List[OpsItemEventFilter] +OpsItemEventFilters = list[OpsItemEventFilter] class ListOpsItemEventsRequest(ServiceRequest): - Filters: Optional[OpsItemEventFilters] - MaxResults: Optional[OpsItemEventMaxResults] - NextToken: Optional[String] + Filters: OpsItemEventFilters | None + MaxResults: OpsItemEventMaxResults | None + NextToken: String | None class OpsItemIdentity(TypedDict, total=False): - Arn: Optional[String] + Arn: String | None class OpsItemEventSummary(TypedDict, total=False): - OpsItemId: Optional[String] - EventId: Optional[String] - Source: Optional[String] - DetailType: Optional[String] - Detail: Optional[String] - CreatedBy: Optional[OpsItemIdentity] - CreatedTime: Optional[DateTime] + OpsItemId: String | None + EventId: String | None + Source: String | None + DetailType: String | None + Detail: String | None + CreatedBy: OpsItemIdentity | None + CreatedTime: DateTime | None -OpsItemEventSummaries = List[OpsItemEventSummary] +OpsItemEventSummaries = list[OpsItemEventSummary] class ListOpsItemEventsResponse(TypedDict, total=False): - NextToken: Optional[String] - Summaries: Optional[OpsItemEventSummaries] + NextToken: String | None + Summaries: OpsItemEventSummaries | None -OpsItemRelatedItemsFilterValues = List[OpsItemRelatedItemsFilterValue] +OpsItemRelatedItemsFilterValues = list[OpsItemRelatedItemsFilterValue] class OpsItemRelatedItemsFilter(TypedDict, total=False): @@ -5280,37 +5291,37 @@ class OpsItemRelatedItemsFilter(TypedDict, total=False): Operator: OpsItemRelatedItemsFilterOperator -OpsItemRelatedItemsFilters = List[OpsItemRelatedItemsFilter] +OpsItemRelatedItemsFilters = list[OpsItemRelatedItemsFilter] class ListOpsItemRelatedItemsRequest(ServiceRequest): - OpsItemId: Optional[OpsItemId] - Filters: Optional[OpsItemRelatedItemsFilters] - MaxResults: Optional[OpsItemRelatedItemsMaxResults] - NextToken: Optional[String] + OpsItemId: OpsItemId | None + Filters: OpsItemRelatedItemsFilters | None + MaxResults: OpsItemRelatedItemsMaxResults | None + NextToken: String | None class OpsItemRelatedItemSummary(TypedDict, total=False): - OpsItemId: Optional[OpsItemId] - AssociationId: Optional[OpsItemRelatedItemAssociationId] - ResourceType: Optional[OpsItemRelatedItemAssociationResourceType] - AssociationType: Optional[OpsItemRelatedItemAssociationType] - ResourceUri: Optional[OpsItemRelatedItemAssociationResourceUri] - CreatedBy: Optional[OpsItemIdentity] - CreatedTime: Optional[DateTime] - LastModifiedBy: Optional[OpsItemIdentity] - LastModifiedTime: Optional[DateTime] + OpsItemId: OpsItemId | None + AssociationId: OpsItemRelatedItemAssociationId | None + ResourceType: OpsItemRelatedItemAssociationResourceType | None + AssociationType: OpsItemRelatedItemAssociationType | None + ResourceUri: OpsItemRelatedItemAssociationResourceUri | None + CreatedBy: OpsItemIdentity | None + CreatedTime: DateTime | None + LastModifiedBy: OpsItemIdentity | None + LastModifiedTime: DateTime | None -OpsItemRelatedItemSummaries = List[OpsItemRelatedItemSummary] +OpsItemRelatedItemSummaries = list[OpsItemRelatedItemSummary] class ListOpsItemRelatedItemsResponse(TypedDict, total=False): - NextToken: Optional[String] - Summaries: Optional[OpsItemRelatedItemSummaries] + NextToken: String | None + Summaries: OpsItemRelatedItemSummaries | None -OpsMetadataFilterValueList = List[OpsMetadataFilterValue] +OpsMetadataFilterValueList = list[OpsMetadataFilterValue] class OpsMetadataFilter(TypedDict, total=False): @@ -5318,60 +5329,60 @@ class OpsMetadataFilter(TypedDict, total=False): Values: OpsMetadataFilterValueList -OpsMetadataFilterList = List[OpsMetadataFilter] +OpsMetadataFilterList = list[OpsMetadataFilter] class ListOpsMetadataRequest(ServiceRequest): - Filters: Optional[OpsMetadataFilterList] - MaxResults: Optional[ListOpsMetadataMaxResults] - NextToken: Optional[NextToken] + Filters: OpsMetadataFilterList | None + MaxResults: ListOpsMetadataMaxResults | None + NextToken: NextToken | None class OpsMetadata(TypedDict, total=False): - ResourceId: Optional[OpsMetadataResourceId] - OpsMetadataArn: Optional[OpsMetadataArn] - LastModifiedDate: Optional[DateTime] - LastModifiedUser: Optional[String] - CreationDate: Optional[DateTime] + ResourceId: OpsMetadataResourceId | None + OpsMetadataArn: OpsMetadataArn | None + LastModifiedDate: DateTime | None + LastModifiedUser: String | None + CreationDate: DateTime | None -OpsMetadataList = List[OpsMetadata] +OpsMetadataList = list[OpsMetadata] class ListOpsMetadataResult(TypedDict, total=False): - OpsMetadataList: Optional[OpsMetadataList] - NextToken: Optional[NextToken] + OpsMetadataList: OpsMetadataList | None + NextToken: NextToken | None class ListResourceComplianceSummariesRequest(ServiceRequest): - Filters: Optional[ComplianceStringFilterList] - NextToken: Optional[NextToken] - MaxResults: Optional[MaxResults] + Filters: ComplianceStringFilterList | None + NextToken: NextToken | None + MaxResults: MaxResults | None class ResourceComplianceSummaryItem(TypedDict, total=False): - ComplianceType: Optional[ComplianceTypeName] - ResourceType: Optional[ComplianceResourceType] - ResourceId: Optional[ComplianceResourceId] - Status: Optional[ComplianceStatus] - OverallSeverity: Optional[ComplianceSeverity] - ExecutionSummary: Optional[ComplianceExecutionSummary] - CompliantSummary: Optional[CompliantSummary] - NonCompliantSummary: Optional[NonCompliantSummary] + ComplianceType: ComplianceTypeName | None + ResourceType: ComplianceResourceType | None + ResourceId: ComplianceResourceId | None + Status: ComplianceStatus | None + OverallSeverity: ComplianceSeverity | None + ExecutionSummary: ComplianceExecutionSummary | None + CompliantSummary: CompliantSummary | None + NonCompliantSummary: NonCompliantSummary | None -ResourceComplianceSummaryItemList = List[ResourceComplianceSummaryItem] +ResourceComplianceSummaryItemList = list[ResourceComplianceSummaryItem] class ListResourceComplianceSummariesResult(TypedDict, total=False): - ResourceComplianceSummaryItems: Optional[ResourceComplianceSummaryItemList] - NextToken: Optional[NextToken] + ResourceComplianceSummaryItems: ResourceComplianceSummaryItemList | None + NextToken: NextToken | None class ListResourceDataSyncRequest(ServiceRequest): - SyncType: Optional[ResourceDataSyncType] - NextToken: Optional[NextToken] - MaxResults: Optional[MaxResults] + SyncType: ResourceDataSyncType | None + NextToken: NextToken | None + MaxResults: MaxResults | None ResourceDataSyncCreatedTime = datetime @@ -5379,33 +5390,33 @@ class ListResourceDataSyncRequest(ServiceRequest): class ResourceDataSyncSourceWithState(TypedDict, total=False): - SourceType: Optional[ResourceDataSyncSourceType] - AwsOrganizationsSource: Optional[ResourceDataSyncAwsOrganizationsSource] - SourceRegions: Optional[ResourceDataSyncSourceRegionList] - IncludeFutureRegions: Optional[ResourceDataSyncIncludeFutureRegions] - State: Optional[ResourceDataSyncState] - EnableAllOpsDataSources: Optional[ResourceDataSyncEnableAllOpsDataSources] + SourceType: ResourceDataSyncSourceType | None + AwsOrganizationsSource: ResourceDataSyncAwsOrganizationsSource | None + SourceRegions: ResourceDataSyncSourceRegionList | None + IncludeFutureRegions: ResourceDataSyncIncludeFutureRegions | None + State: ResourceDataSyncState | None + EnableAllOpsDataSources: ResourceDataSyncEnableAllOpsDataSources | None class ResourceDataSyncItem(TypedDict, total=False): - SyncName: Optional[ResourceDataSyncName] - SyncType: Optional[ResourceDataSyncType] - SyncSource: Optional[ResourceDataSyncSourceWithState] - S3Destination: Optional[ResourceDataSyncS3Destination] - LastSyncTime: Optional[LastResourceDataSyncTime] - LastSuccessfulSyncTime: Optional[LastSuccessfulResourceDataSyncTime] - SyncLastModifiedTime: Optional[ResourceDataSyncLastModifiedTime] - LastStatus: Optional[LastResourceDataSyncStatus] - SyncCreatedTime: Optional[ResourceDataSyncCreatedTime] - LastSyncStatusMessage: Optional[LastResourceDataSyncMessage] + SyncName: ResourceDataSyncName | None + SyncType: ResourceDataSyncType | None + SyncSource: ResourceDataSyncSourceWithState | None + S3Destination: ResourceDataSyncS3Destination | None + LastSyncTime: LastResourceDataSyncTime | None + LastSuccessfulSyncTime: LastSuccessfulResourceDataSyncTime | None + SyncLastModifiedTime: ResourceDataSyncLastModifiedTime | None + LastStatus: LastResourceDataSyncStatus | None + SyncCreatedTime: ResourceDataSyncCreatedTime | None + LastSyncStatusMessage: LastResourceDataSyncMessage | None -ResourceDataSyncItemList = List[ResourceDataSyncItem] +ResourceDataSyncItemList = list[ResourceDataSyncItem] class ListResourceDataSyncResult(TypedDict, total=False): - ResourceDataSyncItems: Optional[ResourceDataSyncItemList] - NextToken: Optional[NextToken] + ResourceDataSyncItems: ResourceDataSyncItemList | None + NextToken: NextToken | None class ListTagsForResourceRequest(ServiceRequest): @@ -5414,25 +5425,25 @@ class ListTagsForResourceRequest(ServiceRequest): class ListTagsForResourceResult(TypedDict, total=False): - TagList: Optional[TagList] + TagList: TagList | None -MetadataKeysToDeleteList = List[MetadataKey] +MetadataKeysToDeleteList = list[MetadataKey] class ModifyDocumentPermissionRequest(ServiceRequest): Name: DocumentName PermissionType: DocumentPermissionType - AccountIdsToAdd: Optional[AccountIdList] - AccountIdsToRemove: Optional[AccountIdList] - SharedDocumentVersion: Optional[SharedDocumentVersion] + AccountIdsToAdd: AccountIdList | None + AccountIdsToRemove: AccountIdList | None + SharedDocumentVersion: SharedDocumentVersion | None class ModifyDocumentPermissionResponse(TypedDict, total=False): pass -OpsItemOpsDataKeysList = List[String] +OpsItemOpsDataKeysList = list[String] class PutComplianceItemsRequest(ServiceRequest): @@ -5441,8 +5452,8 @@ class PutComplianceItemsRequest(ServiceRequest): ComplianceType: ComplianceTypeName ExecutionSummary: ComplianceExecutionSummary Items: ComplianceItemEntryList - ItemContentHash: Optional[ComplianceItemContentHash] - UploadType: Optional[ComplianceUploadType] + ItemContentHash: ComplianceItemContentHash | None + UploadType: ComplianceUploadType | None class PutComplianceItemsResult(TypedDict, total=False): @@ -5455,38 +5466,38 @@ class PutInventoryRequest(ServiceRequest): class PutInventoryResult(TypedDict, total=False): - Message: Optional[PutInventoryMessage] + Message: PutInventoryMessage | None class PutParameterRequest(ServiceRequest): Name: PSParameterName - Description: Optional[ParameterDescription] + Description: ParameterDescription | None Value: PSParameterValue - Type: Optional[ParameterType] - KeyId: Optional[ParameterKeyId] - Overwrite: Optional[Boolean] - AllowedPattern: Optional[AllowedPattern] - Tags: Optional[TagList] - Tier: Optional[ParameterTier] - Policies: Optional[ParameterPolicies] - DataType: Optional[ParameterDataType] + Type: ParameterType | None + KeyId: ParameterKeyId | None + Overwrite: Boolean | None + AllowedPattern: AllowedPattern | None + Tags: TagList | None + Tier: ParameterTier | None + Policies: ParameterPolicies | None + DataType: ParameterDataType | None class PutParameterResult(TypedDict, total=False): - Version: Optional[PSParameterVersion] - Tier: Optional[ParameterTier] + Version: PSParameterVersion | None + Tier: ParameterTier | None class PutResourcePolicyRequest(ServiceRequest): ResourceArn: ResourceArnString Policy: Policy - PolicyId: Optional[PolicyId] - PolicyHash: Optional[PolicyHash] + PolicyId: PolicyId | None + PolicyHash: PolicyHash | None class PutResourcePolicyResponse(TypedDict, total=False): - PolicyId: Optional[PolicyId] - PolicyHash: Optional[PolicyHash] + PolicyId: PolicyId | None + PolicyHash: PolicyHash | None class RegisterDefaultPatchBaselineRequest(ServiceRequest): @@ -5494,7 +5505,7 @@ class RegisterDefaultPatchBaselineRequest(ServiceRequest): class RegisterDefaultPatchBaselineResult(TypedDict, total=False): - BaselineId: Optional[BaselineId] + BaselineId: BaselineId | None class RegisterPatchBaselineForPatchGroupRequest(ServiceRequest): @@ -5503,45 +5514,45 @@ class RegisterPatchBaselineForPatchGroupRequest(ServiceRequest): class RegisterPatchBaselineForPatchGroupResult(TypedDict, total=False): - BaselineId: Optional[BaselineId] - PatchGroup: Optional[PatchGroup] + BaselineId: BaselineId | None + PatchGroup: PatchGroup | None class RegisterTargetWithMaintenanceWindowRequest(ServiceRequest): WindowId: MaintenanceWindowId ResourceType: MaintenanceWindowResourceType Targets: Targets - OwnerInformation: Optional[OwnerInformation] - Name: Optional[MaintenanceWindowName] - Description: Optional[MaintenanceWindowDescription] - ClientToken: Optional[ClientToken] + OwnerInformation: OwnerInformation | None + Name: MaintenanceWindowName | None + Description: MaintenanceWindowDescription | None + ClientToken: ClientToken | None class RegisterTargetWithMaintenanceWindowResult(TypedDict, total=False): - WindowTargetId: Optional[MaintenanceWindowTargetId] + WindowTargetId: MaintenanceWindowTargetId | None class RegisterTaskWithMaintenanceWindowRequest(ServiceRequest): WindowId: MaintenanceWindowId - Targets: Optional[Targets] + Targets: Targets | None TaskArn: MaintenanceWindowTaskArn - ServiceRoleArn: Optional[ServiceRole] + ServiceRoleArn: ServiceRole | None TaskType: MaintenanceWindowTaskType - TaskParameters: Optional[MaintenanceWindowTaskParameters] - TaskInvocationParameters: Optional[MaintenanceWindowTaskInvocationParameters] - Priority: Optional[MaintenanceWindowTaskPriority] - MaxConcurrency: Optional[MaxConcurrency] - MaxErrors: Optional[MaxErrors] - LoggingInfo: Optional[LoggingInfo] - Name: Optional[MaintenanceWindowName] - Description: Optional[MaintenanceWindowDescription] - ClientToken: Optional[ClientToken] - CutoffBehavior: Optional[MaintenanceWindowTaskCutoffBehavior] - AlarmConfiguration: Optional[AlarmConfiguration] + TaskParameters: MaintenanceWindowTaskParameters | None + TaskInvocationParameters: MaintenanceWindowTaskInvocationParameters | None + Priority: MaintenanceWindowTaskPriority | None + MaxConcurrency: MaxConcurrency | None + MaxErrors: MaxErrors | None + LoggingInfo: LoggingInfo | None + Name: MaintenanceWindowName | None + Description: MaintenanceWindowDescription | None + ClientToken: ClientToken | None + CutoffBehavior: MaintenanceWindowTaskCutoffBehavior | None + AlarmConfiguration: AlarmConfiguration | None class RegisterTaskWithMaintenanceWindowResult(TypedDict, total=False): - WindowTaskId: Optional[MaintenanceWindowTaskId] + WindowTaskId: MaintenanceWindowTaskId | None class RemoveTagsFromResourceRequest(ServiceRequest): @@ -5559,7 +5570,7 @@ class ResetServiceSettingRequest(ServiceRequest): class ResetServiceSettingResult(TypedDict, total=False): - ServiceSetting: Optional[ServiceSetting] + ServiceSetting: ServiceSetting | None class ResumeSessionRequest(ServiceRequest): @@ -5567,15 +5578,15 @@ class ResumeSessionRequest(ServiceRequest): class ResumeSessionResponse(TypedDict, total=False): - SessionId: Optional[SessionId] - TokenValue: Optional[TokenValue] - StreamUrl: Optional[StreamUrl] + SessionId: SessionId | None + TokenValue: TokenValue | None + StreamUrl: StreamUrl | None class SendAutomationSignalRequest(ServiceRequest): AutomationExecutionId: AutomationExecutionId SignalType: SignalType - Payload: Optional[AutomationParameterMap] + Payload: AutomationParameterMap | None class SendAutomationSignalResult(TypedDict, total=False): @@ -5583,42 +5594,42 @@ class SendAutomationSignalResult(TypedDict, total=False): class SendCommandRequest(ServiceRequest): - InstanceIds: Optional[InstanceIdList] - Targets: Optional[Targets] + InstanceIds: InstanceIdList | None + Targets: Targets | None DocumentName: DocumentARN - DocumentVersion: Optional[DocumentVersion] - DocumentHash: Optional[DocumentHash] - DocumentHashType: Optional[DocumentHashType] - TimeoutSeconds: Optional[TimeoutSeconds] - Comment: Optional[Comment] - Parameters: Optional[Parameters] - OutputS3Region: Optional[S3Region] - OutputS3BucketName: Optional[S3BucketName] - OutputS3KeyPrefix: Optional[S3KeyPrefix] - MaxConcurrency: Optional[MaxConcurrency] - MaxErrors: Optional[MaxErrors] - ServiceRoleArn: Optional[ServiceRole] - NotificationConfig: Optional[NotificationConfig] - CloudWatchOutputConfig: Optional[CloudWatchOutputConfig] - AlarmConfiguration: Optional[AlarmConfiguration] + DocumentVersion: DocumentVersion | None + DocumentHash: DocumentHash | None + DocumentHashType: DocumentHashType | None + TimeoutSeconds: TimeoutSeconds | None + Comment: Comment | None + Parameters: Parameters | None + OutputS3Region: S3Region | None + OutputS3BucketName: S3BucketName | None + OutputS3KeyPrefix: S3KeyPrefix | None + MaxConcurrency: MaxConcurrency | None + MaxErrors: MaxErrors | None + ServiceRoleArn: ServiceRole | None + NotificationConfig: NotificationConfig | None + CloudWatchOutputConfig: CloudWatchOutputConfig | None + AlarmConfiguration: AlarmConfiguration | None class SendCommandResult(TypedDict, total=False): - Command: Optional[Command] + Command: Command | None -SessionManagerParameterValueList = List[SessionManagerParameterValue] -SessionManagerParameters = Dict[SessionManagerParameterName, SessionManagerParameterValueList] +SessionManagerParameterValueList = list[SessionManagerParameterValue] +SessionManagerParameters = dict[SessionManagerParameterName, SessionManagerParameterValueList] class StartAccessRequestRequest(ServiceRequest): Reason: String1to256 Targets: Targets - Tags: Optional[TagList] + Tags: TagList | None class StartAccessRequestResponse(TypedDict, total=False): - AccessRequestId: Optional[AccessRequestId] + AccessRequestId: AccessRequestId | None class StartAssociationsOnceRequest(ServiceRequest): @@ -5631,69 +5642,69 @@ class StartAssociationsOnceResult(TypedDict, total=False): class StartAutomationExecutionRequest(ServiceRequest): DocumentName: DocumentARN - DocumentVersion: Optional[DocumentVersion] - Parameters: Optional[AutomationParameterMap] - ClientToken: Optional[IdempotencyToken] - Mode: Optional[ExecutionMode] - TargetParameterName: Optional[AutomationParameterKey] - Targets: Optional[Targets] - TargetMaps: Optional[TargetMaps] - MaxConcurrency: Optional[MaxConcurrency] - MaxErrors: Optional[MaxErrors] - TargetLocations: Optional[TargetLocations] - Tags: Optional[TagList] - AlarmConfiguration: Optional[AlarmConfiguration] - TargetLocationsURL: Optional[TargetLocationsURL] + DocumentVersion: DocumentVersion | None + Parameters: AutomationParameterMap | None + ClientToken: IdempotencyToken | None + Mode: ExecutionMode | None + TargetParameterName: AutomationParameterKey | None + Targets: Targets | None + TargetMaps: TargetMaps | None + MaxConcurrency: MaxConcurrency | None + MaxErrors: MaxErrors | None + TargetLocations: TargetLocations | None + Tags: TagList | None + AlarmConfiguration: AlarmConfiguration | None + TargetLocationsURL: TargetLocationsURL | None class StartAutomationExecutionResult(TypedDict, total=False): - AutomationExecutionId: Optional[AutomationExecutionId] + AutomationExecutionId: AutomationExecutionId | None class StartChangeRequestExecutionRequest(ServiceRequest): - ScheduledTime: Optional[DateTime] + ScheduledTime: DateTime | None DocumentName: DocumentARN - DocumentVersion: Optional[DocumentVersion] - Parameters: Optional[AutomationParameterMap] - ChangeRequestName: Optional[ChangeRequestName] - ClientToken: Optional[IdempotencyToken] - AutoApprove: Optional[Boolean] + DocumentVersion: DocumentVersion | None + Parameters: AutomationParameterMap | None + ChangeRequestName: ChangeRequestName | None + ClientToken: IdempotencyToken | None + AutoApprove: Boolean | None Runbooks: Runbooks - Tags: Optional[TagList] - ScheduledEndTime: Optional[DateTime] - ChangeDetails: Optional[ChangeDetailsValue] + Tags: TagList | None + ScheduledEndTime: DateTime | None + ChangeDetails: ChangeDetailsValue | None class StartChangeRequestExecutionResult(TypedDict, total=False): - AutomationExecutionId: Optional[AutomationExecutionId] + AutomationExecutionId: AutomationExecutionId | None class StartExecutionPreviewRequest(ServiceRequest): DocumentName: DocumentName - DocumentVersion: Optional[DocumentVersion] - ExecutionInputs: Optional[ExecutionInputs] + DocumentVersion: DocumentVersion | None + ExecutionInputs: ExecutionInputs | None class StartExecutionPreviewResponse(TypedDict, total=False): - ExecutionPreviewId: Optional[ExecutionPreviewId] + ExecutionPreviewId: ExecutionPreviewId | None class StartSessionRequest(ServiceRequest): Target: SessionTarget - DocumentName: Optional[DocumentARN] - Reason: Optional[SessionReason] - Parameters: Optional[SessionManagerParameters] + DocumentName: DocumentARN | None + Reason: SessionReason | None + Parameters: SessionManagerParameters | None class StartSessionResponse(TypedDict, total=False): - SessionId: Optional[SessionId] - TokenValue: Optional[TokenValue] - StreamUrl: Optional[StreamUrl] + SessionId: SessionId | None + TokenValue: TokenValue | None + StreamUrl: StreamUrl | None class StopAutomationExecutionRequest(ServiceRequest): AutomationExecutionId: AutomationExecutionId - Type: Optional[StopType] + Type: StopType | None class StopAutomationExecutionResult(TypedDict, total=False): @@ -5705,7 +5716,7 @@ class TerminateSessionRequest(ServiceRequest): class TerminateSessionResponse(TypedDict, total=False): - SessionId: Optional[SessionId] + SessionId: SessionId | None class UnlabelParameterVersionRequest(ServiceRequest): @@ -5715,36 +5726,37 @@ class UnlabelParameterVersionRequest(ServiceRequest): class UnlabelParameterVersionResult(TypedDict, total=False): - RemovedLabels: Optional[ParameterLabelList] - InvalidLabels: Optional[ParameterLabelList] + RemovedLabels: ParameterLabelList | None + InvalidLabels: ParameterLabelList | None class UpdateAssociationRequest(ServiceRequest): AssociationId: AssociationId - Parameters: Optional[Parameters] - DocumentVersion: Optional[DocumentVersion] - ScheduleExpression: Optional[ScheduleExpression] - OutputLocation: Optional[InstanceAssociationOutputLocation] - Name: Optional[DocumentARN] - Targets: Optional[Targets] - AssociationName: Optional[AssociationName] - AssociationVersion: Optional[AssociationVersion] - AutomationTargetParameterName: Optional[AutomationTargetParameterName] - MaxErrors: Optional[MaxErrors] - MaxConcurrency: Optional[MaxConcurrency] - ComplianceSeverity: Optional[AssociationComplianceSeverity] - SyncCompliance: Optional[AssociationSyncCompliance] - ApplyOnlyAtCronInterval: Optional[ApplyOnlyAtCronInterval] - CalendarNames: Optional[CalendarNameOrARNList] - TargetLocations: Optional[TargetLocations] - ScheduleOffset: Optional[ScheduleOffset] - Duration: Optional[Duration] - TargetMaps: Optional[TargetMaps] - AlarmConfiguration: Optional[AlarmConfiguration] + Parameters: Parameters | None + DocumentVersion: DocumentVersion | None + ScheduleExpression: ScheduleExpression | None + OutputLocation: InstanceAssociationOutputLocation | None + Name: DocumentARN | None + Targets: Targets | None + AssociationName: AssociationName | None + AssociationVersion: AssociationVersion | None + AutomationTargetParameterName: AutomationTargetParameterName | None + MaxErrors: MaxErrors | None + MaxConcurrency: MaxConcurrency | None + ComplianceSeverity: AssociationComplianceSeverity | None + SyncCompliance: AssociationSyncCompliance | None + ApplyOnlyAtCronInterval: ApplyOnlyAtCronInterval | None + CalendarNames: CalendarNameOrARNList | None + TargetLocations: TargetLocations | None + ScheduleOffset: ScheduleOffset | None + Duration: Duration | None + TargetMaps: TargetMaps | None + AlarmConfiguration: AlarmConfiguration | None + AssociationDispatchAssumeRole: AssociationDispatchAssumeRoleArn | None class UpdateAssociationResult(TypedDict, total=False): - AssociationDescription: Optional[AssociationDescription] + AssociationDescription: AssociationDescription | None class UpdateAssociationStatusRequest(ServiceRequest): @@ -5754,7 +5766,7 @@ class UpdateAssociationStatusRequest(ServiceRequest): class UpdateAssociationStatusResult(TypedDict, total=False): - AssociationDescription: Optional[AssociationDescription] + AssociationDescription: AssociationDescription | None class UpdateDocumentDefaultVersionRequest(ServiceRequest): @@ -5763,12 +5775,12 @@ class UpdateDocumentDefaultVersionRequest(ServiceRequest): class UpdateDocumentDefaultVersionResult(TypedDict, total=False): - Description: Optional[DocumentDefaultVersionDescription] + Description: DocumentDefaultVersionDescription | None class UpdateDocumentMetadataRequest(ServiceRequest): Name: DocumentName - DocumentVersion: Optional[DocumentVersion] + DocumentVersion: DocumentVersion | None DocumentReviews: DocumentReviews @@ -5778,104 +5790,104 @@ class UpdateDocumentMetadataResponse(TypedDict, total=False): class UpdateDocumentRequest(ServiceRequest): Content: DocumentContent - Attachments: Optional[AttachmentsSourceList] + Attachments: AttachmentsSourceList | None Name: DocumentName - DisplayName: Optional[DocumentDisplayName] - VersionName: Optional[DocumentVersionName] - DocumentVersion: Optional[DocumentVersion] - DocumentFormat: Optional[DocumentFormat] - TargetType: Optional[TargetType] + DisplayName: DocumentDisplayName | None + VersionName: DocumentVersionName | None + DocumentVersion: DocumentVersion | None + DocumentFormat: DocumentFormat | None + TargetType: TargetType | None class UpdateDocumentResult(TypedDict, total=False): - DocumentDescription: Optional[DocumentDescription] + DocumentDescription: DocumentDescription | None class UpdateMaintenanceWindowRequest(ServiceRequest): WindowId: MaintenanceWindowId - Name: Optional[MaintenanceWindowName] - Description: Optional[MaintenanceWindowDescription] - StartDate: Optional[MaintenanceWindowStringDateTime] - EndDate: Optional[MaintenanceWindowStringDateTime] - Schedule: Optional[MaintenanceWindowSchedule] - ScheduleTimezone: Optional[MaintenanceWindowTimezone] - ScheduleOffset: Optional[MaintenanceWindowOffset] - Duration: Optional[MaintenanceWindowDurationHours] - Cutoff: Optional[MaintenanceWindowCutoff] - AllowUnassociatedTargets: Optional[MaintenanceWindowAllowUnassociatedTargets] - Enabled: Optional[MaintenanceWindowEnabled] - Replace: Optional[Boolean] + Name: MaintenanceWindowName | None + Description: MaintenanceWindowDescription | None + StartDate: MaintenanceWindowStringDateTime | None + EndDate: MaintenanceWindowStringDateTime | None + Schedule: MaintenanceWindowSchedule | None + ScheduleTimezone: MaintenanceWindowTimezone | None + ScheduleOffset: MaintenanceWindowOffset | None + Duration: MaintenanceWindowDurationHours | None + Cutoff: MaintenanceWindowCutoff | None + AllowUnassociatedTargets: MaintenanceWindowAllowUnassociatedTargets | None + Enabled: MaintenanceWindowEnabled | None + Replace: Boolean | None class UpdateMaintenanceWindowResult(TypedDict, total=False): - WindowId: Optional[MaintenanceWindowId] - Name: Optional[MaintenanceWindowName] - Description: Optional[MaintenanceWindowDescription] - StartDate: Optional[MaintenanceWindowStringDateTime] - EndDate: Optional[MaintenanceWindowStringDateTime] - Schedule: Optional[MaintenanceWindowSchedule] - ScheduleTimezone: Optional[MaintenanceWindowTimezone] - ScheduleOffset: Optional[MaintenanceWindowOffset] - Duration: Optional[MaintenanceWindowDurationHours] - Cutoff: Optional[MaintenanceWindowCutoff] - AllowUnassociatedTargets: Optional[MaintenanceWindowAllowUnassociatedTargets] - Enabled: Optional[MaintenanceWindowEnabled] + WindowId: MaintenanceWindowId | None + Name: MaintenanceWindowName | None + Description: MaintenanceWindowDescription | None + StartDate: MaintenanceWindowStringDateTime | None + EndDate: MaintenanceWindowStringDateTime | None + Schedule: MaintenanceWindowSchedule | None + ScheduleTimezone: MaintenanceWindowTimezone | None + ScheduleOffset: MaintenanceWindowOffset | None + Duration: MaintenanceWindowDurationHours | None + Cutoff: MaintenanceWindowCutoff | None + AllowUnassociatedTargets: MaintenanceWindowAllowUnassociatedTargets | None + Enabled: MaintenanceWindowEnabled | None class UpdateMaintenanceWindowTargetRequest(ServiceRequest): WindowId: MaintenanceWindowId WindowTargetId: MaintenanceWindowTargetId - Targets: Optional[Targets] - OwnerInformation: Optional[OwnerInformation] - Name: Optional[MaintenanceWindowName] - Description: Optional[MaintenanceWindowDescription] - Replace: Optional[Boolean] + Targets: Targets | None + OwnerInformation: OwnerInformation | None + Name: MaintenanceWindowName | None + Description: MaintenanceWindowDescription | None + Replace: Boolean | None class UpdateMaintenanceWindowTargetResult(TypedDict, total=False): - WindowId: Optional[MaintenanceWindowId] - WindowTargetId: Optional[MaintenanceWindowTargetId] - Targets: Optional[Targets] - OwnerInformation: Optional[OwnerInformation] - Name: Optional[MaintenanceWindowName] - Description: Optional[MaintenanceWindowDescription] + WindowId: MaintenanceWindowId | None + WindowTargetId: MaintenanceWindowTargetId | None + Targets: Targets | None + OwnerInformation: OwnerInformation | None + Name: MaintenanceWindowName | None + Description: MaintenanceWindowDescription | None class UpdateMaintenanceWindowTaskRequest(ServiceRequest): WindowId: MaintenanceWindowId WindowTaskId: MaintenanceWindowTaskId - Targets: Optional[Targets] - TaskArn: Optional[MaintenanceWindowTaskArn] - ServiceRoleArn: Optional[ServiceRole] - TaskParameters: Optional[MaintenanceWindowTaskParameters] - TaskInvocationParameters: Optional[MaintenanceWindowTaskInvocationParameters] - Priority: Optional[MaintenanceWindowTaskPriority] - MaxConcurrency: Optional[MaxConcurrency] - MaxErrors: Optional[MaxErrors] - LoggingInfo: Optional[LoggingInfo] - Name: Optional[MaintenanceWindowName] - Description: Optional[MaintenanceWindowDescription] - Replace: Optional[Boolean] - CutoffBehavior: Optional[MaintenanceWindowTaskCutoffBehavior] - AlarmConfiguration: Optional[AlarmConfiguration] + Targets: Targets | None + TaskArn: MaintenanceWindowTaskArn | None + ServiceRoleArn: ServiceRole | None + TaskParameters: MaintenanceWindowTaskParameters | None + TaskInvocationParameters: MaintenanceWindowTaskInvocationParameters | None + Priority: MaintenanceWindowTaskPriority | None + MaxConcurrency: MaxConcurrency | None + MaxErrors: MaxErrors | None + LoggingInfo: LoggingInfo | None + Name: MaintenanceWindowName | None + Description: MaintenanceWindowDescription | None + Replace: Boolean | None + CutoffBehavior: MaintenanceWindowTaskCutoffBehavior | None + AlarmConfiguration: AlarmConfiguration | None class UpdateMaintenanceWindowTaskResult(TypedDict, total=False): - WindowId: Optional[MaintenanceWindowId] - WindowTaskId: Optional[MaintenanceWindowTaskId] - Targets: Optional[Targets] - TaskArn: Optional[MaintenanceWindowTaskArn] - ServiceRoleArn: Optional[ServiceRole] - TaskParameters: Optional[MaintenanceWindowTaskParameters] - TaskInvocationParameters: Optional[MaintenanceWindowTaskInvocationParameters] - Priority: Optional[MaintenanceWindowTaskPriority] - MaxConcurrency: Optional[MaxConcurrency] - MaxErrors: Optional[MaxErrors] - LoggingInfo: Optional[LoggingInfo] - Name: Optional[MaintenanceWindowName] - Description: Optional[MaintenanceWindowDescription] - CutoffBehavior: Optional[MaintenanceWindowTaskCutoffBehavior] - AlarmConfiguration: Optional[AlarmConfiguration] + WindowId: MaintenanceWindowId | None + WindowTaskId: MaintenanceWindowTaskId | None + Targets: Targets | None + TaskArn: MaintenanceWindowTaskArn | None + ServiceRoleArn: ServiceRole | None + TaskParameters: MaintenanceWindowTaskParameters | None + TaskInvocationParameters: MaintenanceWindowTaskInvocationParameters | None + Priority: MaintenanceWindowTaskPriority | None + MaxConcurrency: MaxConcurrency | None + MaxErrors: MaxErrors | None + LoggingInfo: LoggingInfo | None + Name: MaintenanceWindowName | None + Description: MaintenanceWindowDescription | None + CutoffBehavior: MaintenanceWindowTaskCutoffBehavior | None + AlarmConfiguration: AlarmConfiguration | None class UpdateManagedInstanceRoleRequest(ServiceRequest): @@ -5888,22 +5900,22 @@ class UpdateManagedInstanceRoleResult(TypedDict, total=False): class UpdateOpsItemRequest(ServiceRequest): - Description: Optional[OpsItemDescription] - OperationalData: Optional[OpsItemOperationalData] - OperationalDataToDelete: Optional[OpsItemOpsDataKeysList] - Notifications: Optional[OpsItemNotifications] - Priority: Optional[OpsItemPriority] - RelatedOpsItems: Optional[RelatedOpsItems] - Status: Optional[OpsItemStatus] + Description: OpsItemDescription | None + OperationalData: OpsItemOperationalData | None + OperationalDataToDelete: OpsItemOpsDataKeysList | None + Notifications: OpsItemNotifications | None + Priority: OpsItemPriority | None + RelatedOpsItems: RelatedOpsItems | None + Status: OpsItemStatus | None OpsItemId: OpsItemId - Title: Optional[OpsItemTitle] - Category: Optional[OpsItemCategory] - Severity: Optional[OpsItemSeverity] - ActualStartTime: Optional[DateTime] - ActualEndTime: Optional[DateTime] - PlannedStartTime: Optional[DateTime] - PlannedEndTime: Optional[DateTime] - OpsItemArn: Optional[OpsItemArn] + Title: OpsItemTitle | None + Category: OpsItemCategory | None + Severity: OpsItemSeverity | None + ActualStartTime: DateTime | None + ActualEndTime: DateTime | None + PlannedStartTime: DateTime | None + PlannedEndTime: DateTime | None + OpsItemArn: OpsItemArn | None class UpdateOpsItemResponse(TypedDict, total=False): @@ -5912,46 +5924,46 @@ class UpdateOpsItemResponse(TypedDict, total=False): class UpdateOpsMetadataRequest(ServiceRequest): OpsMetadataArn: OpsMetadataArn - MetadataToUpdate: Optional[MetadataMap] - KeysToDelete: Optional[MetadataKeysToDeleteList] + MetadataToUpdate: MetadataMap | None + KeysToDelete: MetadataKeysToDeleteList | None class UpdateOpsMetadataResult(TypedDict, total=False): - OpsMetadataArn: Optional[OpsMetadataArn] + OpsMetadataArn: OpsMetadataArn | None class UpdatePatchBaselineRequest(ServiceRequest): BaselineId: BaselineId - Name: Optional[BaselineName] - GlobalFilters: Optional[PatchFilterGroup] - ApprovalRules: Optional[PatchRuleGroup] - ApprovedPatches: Optional[PatchIdList] - ApprovedPatchesComplianceLevel: Optional[PatchComplianceLevel] - ApprovedPatchesEnableNonSecurity: Optional[Boolean] - RejectedPatches: Optional[PatchIdList] - RejectedPatchesAction: Optional[PatchAction] - Description: Optional[BaselineDescription] - Sources: Optional[PatchSourceList] - AvailableSecurityUpdatesComplianceStatus: Optional[PatchComplianceStatus] - Replace: Optional[Boolean] + Name: BaselineName | None + GlobalFilters: PatchFilterGroup | None + ApprovalRules: PatchRuleGroup | None + ApprovedPatches: PatchIdList | None + ApprovedPatchesComplianceLevel: PatchComplianceLevel | None + ApprovedPatchesEnableNonSecurity: Boolean | None + RejectedPatches: PatchIdList | None + RejectedPatchesAction: PatchAction | None + Description: BaselineDescription | None + Sources: PatchSourceList | None + AvailableSecurityUpdatesComplianceStatus: PatchComplianceStatus | None + Replace: Boolean | None class UpdatePatchBaselineResult(TypedDict, total=False): - BaselineId: Optional[BaselineId] - Name: Optional[BaselineName] - OperatingSystem: Optional[OperatingSystem] - GlobalFilters: Optional[PatchFilterGroup] - ApprovalRules: Optional[PatchRuleGroup] - ApprovedPatches: Optional[PatchIdList] - ApprovedPatchesComplianceLevel: Optional[PatchComplianceLevel] - ApprovedPatchesEnableNonSecurity: Optional[Boolean] - RejectedPatches: Optional[PatchIdList] - RejectedPatchesAction: Optional[PatchAction] - CreatedDate: Optional[DateTime] - ModifiedDate: Optional[DateTime] - Description: Optional[BaselineDescription] - Sources: Optional[PatchSourceList] - AvailableSecurityUpdatesComplianceStatus: Optional[PatchComplianceStatus] + BaselineId: BaselineId | None + Name: BaselineName | None + OperatingSystem: OperatingSystem | None + GlobalFilters: PatchFilterGroup | None + ApprovalRules: PatchRuleGroup | None + ApprovedPatches: PatchIdList | None + ApprovedPatchesComplianceLevel: PatchComplianceLevel | None + ApprovedPatchesEnableNonSecurity: Boolean | None + RejectedPatches: PatchIdList | None + RejectedPatchesAction: PatchAction | None + CreatedDate: DateTime | None + ModifiedDate: DateTime | None + Description: BaselineDescription | None + Sources: PatchSourceList | None + AvailableSecurityUpdatesComplianceStatus: PatchComplianceStatus | None class UpdateResourceDataSyncRequest(ServiceRequest): @@ -5974,8 +5986,8 @@ class UpdateServiceSettingResult(TypedDict, total=False): class SsmApi: - service = "ssm" - version = "2014-11-06" + service: str = "ssm" + version: str = "2014-11-06" @handler("AddTagsToResource") def add_tags_to_resource( @@ -6056,13 +6068,18 @@ def create_association( target_maps: TargetMaps | None = None, tags: TagList | None = None, alarm_configuration: AlarmConfiguration | None = None, + association_dispatch_assume_role: AssociationDispatchAssumeRoleArn | None = None, **kwargs, ) -> CreateAssociationResult: raise NotImplementedError @handler("CreateAssociationBatch") def create_association_batch( - self, context: RequestContext, entries: CreateAssociationBatchRequestEntries, **kwargs + self, + context: RequestContext, + entries: CreateAssociationBatchRequestEntries, + association_dispatch_assume_role: AssociationDispatchAssumeRoleArn | None = None, + **kwargs, ) -> CreateAssociationBatchResult: raise NotImplementedError @@ -7472,6 +7489,7 @@ def update_association( duration: Duration | None = None, target_maps: TargetMaps | None = None, alarm_configuration: AlarmConfiguration | None = None, + association_dispatch_assume_role: AssociationDispatchAssumeRoleArn | None = None, **kwargs, ) -> UpdateAssociationResult: raise NotImplementedError diff --git a/localstack-core/localstack/aws/api/stepfunctions/__init__.py b/localstack-core/localstack/aws/api/stepfunctions/__init__.py index ee3c57177ab95..dabc70829aeaf 100644 --- a/localstack-core/localstack/aws/api/stepfunctions/__init__.py +++ b/localstack-core/localstack/aws/api/stepfunctions/__init__.py @@ -1,6 +1,6 @@ from datetime import datetime from enum import StrEnum -from typing import Dict, List, Optional, TypedDict +from typing import TypedDict from localstack.aws.api import RequestContext, ServiceException, ServiceRequest, handler @@ -13,6 +13,7 @@ Enabled = bool ErrorMessage = str EvaluationFailureLocation = str +ExceptionHandlerIndex = int HTTPBody = str HTTPHeaders = str HTTPMethod = str @@ -22,10 +23,14 @@ Identity = str IncludeExecutionData = bool IncludeExecutionDataGetExecutionHistory = bool +InspectionMaxConcurrency = int +InspectionToleratedFailureCount = int +InspectionToleratedFailurePercentage = float KmsDataKeyReusePeriodSeconds = int KmsKeyId = str ListExecutionsPageToken = str LongArn = str +MapIterationFailureCount = int MapRunLabel = str MaxConcurrency = int Name = str @@ -33,6 +38,8 @@ PageToken = str Publish = bool RedriveCount = int +RetrierRetryCount = int +RetryBackoffIntervalSeconds = int RevealSecrets = bool ReverseOrder = bool RevisionId = str @@ -44,6 +51,7 @@ TagKey = str TagValue = str TaskToken = str +TestStateStateName = str ToleratedFailurePercentage = float TraceHeader = str URL = str @@ -184,6 +192,12 @@ class MapRunStatus(StrEnum): ABORTED = "ABORTED" +class MockResponseValidationMode(StrEnum): + STRICT = "STRICT" + PRESENT = "PRESENT" + NONE = "NONE" + + class StateMachineStatus(StrEnum): ACTIVE = "ACTIVE" DELETING = "DELETING" @@ -342,7 +356,7 @@ class KmsInvalidStateException(ServiceException): code: str = "KmsInvalidStateException" sender_fault: bool = False status_code: int = 400 - kmsKeyState: Optional[KmsKeyState] + kmsKeyState: KmsKeyState | None class KmsThrottlingException(ServiceException): @@ -361,7 +375,7 @@ class ResourceNotFound(ServiceException): code: str = "ResourceNotFound" sender_fault: bool = False status_code: int = 400 - resourceName: Optional[Arn] + resourceName: Arn | None class ServiceQuotaExceededException(ServiceException): @@ -416,19 +430,19 @@ class TooManyTags(ServiceException): code: str = "TooManyTags" sender_fault: bool = False status_code: int = 400 - resourceName: Optional[Arn] + resourceName: Arn | None class ValidationException(ServiceException): code: str = "ValidationException" sender_fault: bool = False status_code: int = 400 - reason: Optional[ValidationExceptionReason] + reason: ValidationExceptionReason | None class ActivityFailedEventDetails(TypedDict, total=False): - error: Optional[SensitiveError] - cause: Optional[SensitiveCause] + error: SensitiveError | None + cause: SensitiveCause | None Timestamp = datetime @@ -440,48 +454,48 @@ class ActivityListItem(TypedDict, total=False): creationDate: Timestamp -ActivityList = List[ActivityListItem] +ActivityList = list[ActivityListItem] class ActivityScheduleFailedEventDetails(TypedDict, total=False): - error: Optional[SensitiveError] - cause: Optional[SensitiveCause] + error: SensitiveError | None + cause: SensitiveCause | None TimeoutInSeconds = int class HistoryEventExecutionDataDetails(TypedDict, total=False): - truncated: Optional[truncated] + truncated: truncated | None class ActivityScheduledEventDetails(TypedDict, total=False): resource: Arn - input: Optional[SensitiveData] - inputDetails: Optional[HistoryEventExecutionDataDetails] - timeoutInSeconds: Optional[TimeoutInSeconds] - heartbeatInSeconds: Optional[TimeoutInSeconds] + input: SensitiveData | None + inputDetails: HistoryEventExecutionDataDetails | None + timeoutInSeconds: TimeoutInSeconds | None + heartbeatInSeconds: TimeoutInSeconds | None class ActivityStartedEventDetails(TypedDict, total=False): - workerName: Optional[Identity] + workerName: Identity | None class ActivitySucceededEventDetails(TypedDict, total=False): - output: Optional[SensitiveData] - outputDetails: Optional[HistoryEventExecutionDataDetails] + output: SensitiveData | None + outputDetails: HistoryEventExecutionDataDetails | None class ActivityTimedOutEventDetails(TypedDict, total=False): - error: Optional[SensitiveError] - cause: Optional[SensitiveCause] + error: SensitiveError | None + cause: SensitiveCause | None -AssignedVariables = Dict[VariableName, VariableValue] +AssignedVariables = dict[VariableName, VariableValue] class AssignedVariablesDetails(TypedDict, total=False): - truncated: Optional[truncated] + truncated: truncated | None BilledDuration = int @@ -489,36 +503,36 @@ class AssignedVariablesDetails(TypedDict, total=False): class BillingDetails(TypedDict, total=False): - billedMemoryUsedInMB: Optional[BilledMemoryUsed] - billedDurationInMilliseconds: Optional[BilledDuration] + billedMemoryUsedInMB: BilledMemoryUsed | None + billedDurationInMilliseconds: BilledDuration | None class CloudWatchEventsExecutionDataDetails(TypedDict, total=False): - included: Optional[includedDetails] + included: includedDetails | None class CloudWatchLogsLogGroup(TypedDict, total=False): - logGroupArn: Optional[Arn] + logGroupArn: Arn | None class EncryptionConfiguration(TypedDict, total=False): - kmsKeyId: Optional[KmsKeyId] - kmsDataKeyReusePeriodSeconds: Optional[KmsDataKeyReusePeriodSeconds] + kmsKeyId: KmsKeyId | None + kmsDataKeyReusePeriodSeconds: KmsDataKeyReusePeriodSeconds | None type: EncryptionType class Tag(TypedDict, total=False): - key: Optional[TagKey] - value: Optional[TagValue] + key: TagKey | None + value: TagValue | None -TagList = List[Tag] +TagList = list[Tag] class CreateActivityInput(ServiceRequest): name: Name - tags: Optional[TagList] - encryptionConfiguration: Optional[EncryptionConfiguration] + tags: TagList | None + encryptionConfiguration: EncryptionConfiguration | None class CreateActivityOutput(TypedDict, total=False): @@ -531,11 +545,11 @@ class RoutingConfigurationListItem(TypedDict, total=False): weight: VersionWeight -RoutingConfigurationList = List[RoutingConfigurationListItem] +RoutingConfigurationList = list[RoutingConfigurationListItem] class CreateStateMachineAliasInput(ServiceRequest): - description: Optional[AliasDescription] + description: AliasDescription | None name: CharacterRestrictedName routingConfiguration: RoutingConfigurationList @@ -546,39 +560,39 @@ class CreateStateMachineAliasOutput(TypedDict, total=False): class TracingConfiguration(TypedDict, total=False): - enabled: Optional[Enabled] + enabled: Enabled | None class LogDestination(TypedDict, total=False): - cloudWatchLogsLogGroup: Optional[CloudWatchLogsLogGroup] + cloudWatchLogsLogGroup: CloudWatchLogsLogGroup | None -LogDestinationList = List[LogDestination] +LogDestinationList = list[LogDestination] class LoggingConfiguration(TypedDict, total=False): - level: Optional[LogLevel] - includeExecutionData: Optional[IncludeExecutionData] - destinations: Optional[LogDestinationList] + level: LogLevel | None + includeExecutionData: IncludeExecutionData | None + destinations: LogDestinationList | None class CreateStateMachineInput(TypedDict, total=False): name: Name definition: Definition roleArn: Arn - type: Optional[StateMachineType] - loggingConfiguration: Optional[LoggingConfiguration] - tags: Optional[TagList] - tracingConfiguration: Optional[TracingConfiguration] - publish: Optional[Publish] - versionDescription: Optional[VersionDescription] - encryptionConfiguration: Optional[EncryptionConfiguration] + type: StateMachineType | None + loggingConfiguration: LoggingConfiguration | None + tags: TagList | None + tracingConfiguration: TracingConfiguration | None + publish: Publish | None + versionDescription: VersionDescription | None + encryptionConfiguration: EncryptionConfiguration | None class CreateStateMachineOutput(TypedDict, total=False): stateMachineArn: Arn creationDate: Timestamp - stateMachineVersionArn: Optional[Arn] + stateMachineVersionArn: Arn | None class DeleteActivityInput(ServiceRequest): @@ -621,35 +635,35 @@ class DescribeActivityOutput(TypedDict, total=False): activityArn: Arn name: Name creationDate: Timestamp - encryptionConfiguration: Optional[EncryptionConfiguration] + encryptionConfiguration: EncryptionConfiguration | None class DescribeExecutionInput(ServiceRequest): executionArn: Arn - includedData: Optional[IncludedData] + includedData: IncludedData | None class DescribeExecutionOutput(TypedDict, total=False): executionArn: Arn stateMachineArn: Arn - name: Optional[Name] + name: Name | None status: ExecutionStatus startDate: Timestamp - stopDate: Optional[Timestamp] - input: Optional[SensitiveData] - inputDetails: Optional[CloudWatchEventsExecutionDataDetails] - output: Optional[SensitiveData] - outputDetails: Optional[CloudWatchEventsExecutionDataDetails] - traceHeader: Optional[TraceHeader] - mapRunArn: Optional[LongArn] - error: Optional[SensitiveError] - cause: Optional[SensitiveCause] - stateMachineVersionArn: Optional[Arn] - stateMachineAliasArn: Optional[Arn] - redriveCount: Optional[RedriveCount] - redriveDate: Optional[Timestamp] - redriveStatus: Optional[ExecutionRedriveStatus] - redriveStatusReason: Optional[SensitiveData] + stopDate: Timestamp | None + input: SensitiveData | None + inputDetails: CloudWatchEventsExecutionDataDetails | None + output: SensitiveData | None + outputDetails: CloudWatchEventsExecutionDataDetails | None + traceHeader: TraceHeader | None + mapRunArn: LongArn | None + error: SensitiveError | None + cause: SensitiveCause | None + stateMachineVersionArn: Arn | None + stateMachineAliasArn: Arn | None + redriveCount: RedriveCount | None + redriveDate: Timestamp | None + redriveStatus: ExecutionRedriveStatus | None + redriveStatusReason: SensitiveData | None class DescribeMapRunInput(ServiceRequest): @@ -669,8 +683,8 @@ class MapRunExecutionCounts(TypedDict, total=False): aborted: UnsignedLong total: UnsignedLong resultsWritten: UnsignedLong - failuresNotRedrivable: Optional[LongObject] - pendingRedrive: Optional[LongObject] + failuresNotRedrivable: LongObject | None + pendingRedrive: LongObject | None class MapRunItemCounts(TypedDict, total=False): @@ -682,8 +696,8 @@ class MapRunItemCounts(TypedDict, total=False): aborted: UnsignedLong total: UnsignedLong resultsWritten: UnsignedLong - failuresNotRedrivable: Optional[LongObject] - pendingRedrive: Optional[LongObject] + failuresNotRedrivable: LongObject | None + pendingRedrive: LongObject | None ToleratedFailureCount = int @@ -694,14 +708,14 @@ class DescribeMapRunOutput(TypedDict, total=False): executionArn: Arn status: MapRunStatus startDate: Timestamp - stopDate: Optional[Timestamp] + stopDate: Timestamp | None maxConcurrency: MaxConcurrency toleratedFailurePercentage: ToleratedFailurePercentage toleratedFailureCount: ToleratedFailureCount itemCounts: MapRunItemCounts executionCounts: MapRunExecutionCounts - redriveCount: Optional[RedriveCount] - redriveDate: Optional[Timestamp] + redriveCount: RedriveCount | None + redriveDate: Timestamp | None class DescribeStateMachineAliasInput(ServiceRequest): @@ -709,21 +723,21 @@ class DescribeStateMachineAliasInput(ServiceRequest): class DescribeStateMachineAliasOutput(TypedDict, total=False): - stateMachineAliasArn: Optional[Arn] - name: Optional[Name] - description: Optional[AliasDescription] - routingConfiguration: Optional[RoutingConfigurationList] - creationDate: Optional[Timestamp] - updateDate: Optional[Timestamp] + stateMachineAliasArn: Arn | None + name: Name | None + description: AliasDescription | None + routingConfiguration: RoutingConfigurationList | None + creationDate: Timestamp | None + updateDate: Timestamp | None class DescribeStateMachineForExecutionInput(ServiceRequest): executionArn: Arn - includedData: Optional[IncludedData] + includedData: IncludedData | None -VariableNameList = List[VariableName] -VariableReferences = Dict[StateName, VariableNameList] +VariableNameList = list[VariableName] +VariableReferences = dict[StateName, VariableNameList] class DescribeStateMachineForExecutionOutput(TypedDict, total=False): @@ -732,41 +746,41 @@ class DescribeStateMachineForExecutionOutput(TypedDict, total=False): definition: Definition roleArn: Arn updateDate: Timestamp - loggingConfiguration: Optional[LoggingConfiguration] - tracingConfiguration: Optional[TracingConfiguration] - mapRunArn: Optional[LongArn] - label: Optional[MapRunLabel] - revisionId: Optional[RevisionId] - encryptionConfiguration: Optional[EncryptionConfiguration] - variableReferences: Optional[VariableReferences] + loggingConfiguration: LoggingConfiguration | None + tracingConfiguration: TracingConfiguration | None + mapRunArn: LongArn | None + label: MapRunLabel | None + revisionId: RevisionId | None + encryptionConfiguration: EncryptionConfiguration | None + variableReferences: VariableReferences | None class DescribeStateMachineInput(ServiceRequest): stateMachineArn: Arn - includedData: Optional[IncludedData] + includedData: IncludedData | None class DescribeStateMachineOutput(TypedDict, total=False): stateMachineArn: Arn name: Name - status: Optional[StateMachineStatus] + status: StateMachineStatus | None definition: Definition roleArn: Arn type: StateMachineType creationDate: Timestamp - loggingConfiguration: Optional[LoggingConfiguration] - tracingConfiguration: Optional[TracingConfiguration] - label: Optional[MapRunLabel] - revisionId: Optional[RevisionId] - description: Optional[VersionDescription] - encryptionConfiguration: Optional[EncryptionConfiguration] - variableReferences: Optional[VariableReferences] + loggingConfiguration: LoggingConfiguration | None + tracingConfiguration: TracingConfiguration | None + label: MapRunLabel | None + revisionId: RevisionId | None + description: VersionDescription | None + encryptionConfiguration: EncryptionConfiguration | None + variableReferences: VariableReferences | None class EvaluationFailedEventDetails(TypedDict, total=False): - error: Optional[SensitiveError] - cause: Optional[SensitiveCause] - location: Optional[EvaluationFailureLocation] + error: SensitiveError | None + cause: SensitiveCause | None + location: EvaluationFailureLocation | None state: StateName @@ -774,13 +788,13 @@ class EvaluationFailedEventDetails(TypedDict, total=False): class ExecutionAbortedEventDetails(TypedDict, total=False): - error: Optional[SensitiveError] - cause: Optional[SensitiveCause] + error: SensitiveError | None + cause: SensitiveCause | None class ExecutionFailedEventDetails(TypedDict, total=False): - error: Optional[SensitiveError] - cause: Optional[SensitiveCause] + error: SensitiveError | None + cause: SensitiveCause | None class ExecutionListItem(TypedDict, total=False): @@ -789,158 +803,158 @@ class ExecutionListItem(TypedDict, total=False): name: Name status: ExecutionStatus startDate: Timestamp - stopDate: Optional[Timestamp] - mapRunArn: Optional[LongArn] - itemCount: Optional[UnsignedInteger] - stateMachineVersionArn: Optional[Arn] - stateMachineAliasArn: Optional[Arn] - redriveCount: Optional[RedriveCount] - redriveDate: Optional[Timestamp] + stopDate: Timestamp | None + mapRunArn: LongArn | None + itemCount: UnsignedInteger | None + stateMachineVersionArn: Arn | None + stateMachineAliasArn: Arn | None + redriveCount: RedriveCount | None + redriveDate: Timestamp | None -ExecutionList = List[ExecutionListItem] +ExecutionList = list[ExecutionListItem] class ExecutionRedrivenEventDetails(TypedDict, total=False): - redriveCount: Optional[RedriveCount] + redriveCount: RedriveCount | None class ExecutionStartedEventDetails(TypedDict, total=False): - input: Optional[SensitiveData] - inputDetails: Optional[HistoryEventExecutionDataDetails] - roleArn: Optional[Arn] - stateMachineAliasArn: Optional[Arn] - stateMachineVersionArn: Optional[Arn] + input: SensitiveData | None + inputDetails: HistoryEventExecutionDataDetails | None + roleArn: Arn | None + stateMachineAliasArn: Arn | None + stateMachineVersionArn: Arn | None class ExecutionSucceededEventDetails(TypedDict, total=False): - output: Optional[SensitiveData] - outputDetails: Optional[HistoryEventExecutionDataDetails] + output: SensitiveData | None + outputDetails: HistoryEventExecutionDataDetails | None class ExecutionTimedOutEventDetails(TypedDict, total=False): - error: Optional[SensitiveError] - cause: Optional[SensitiveCause] + error: SensitiveError | None + cause: SensitiveCause | None class GetActivityTaskInput(ServiceRequest): activityArn: Arn - workerName: Optional[Name] + workerName: Name | None class GetActivityTaskOutput(TypedDict, total=False): - taskToken: Optional[TaskToken] - input: Optional[SensitiveDataJobInput] + taskToken: TaskToken | None + input: SensitiveDataJobInput | None class GetExecutionHistoryInput(ServiceRequest): executionArn: Arn - maxResults: Optional[PageSize] - reverseOrder: Optional[ReverseOrder] - nextToken: Optional[PageToken] - includeExecutionData: Optional[IncludeExecutionDataGetExecutionHistory] + maxResults: PageSize | None + reverseOrder: ReverseOrder | None + nextToken: PageToken | None + includeExecutionData: IncludeExecutionDataGetExecutionHistory | None class MapRunRedrivenEventDetails(TypedDict, total=False): - mapRunArn: Optional[LongArn] - redriveCount: Optional[RedriveCount] + mapRunArn: LongArn | None + redriveCount: RedriveCount | None class MapRunFailedEventDetails(TypedDict, total=False): - error: Optional[SensitiveError] - cause: Optional[SensitiveCause] + error: SensitiveError | None + cause: SensitiveCause | None class MapRunStartedEventDetails(TypedDict, total=False): - mapRunArn: Optional[LongArn] + mapRunArn: LongArn | None class StateExitedEventDetails(TypedDict, total=False): name: Name - output: Optional[SensitiveData] - outputDetails: Optional[HistoryEventExecutionDataDetails] - assignedVariables: Optional[AssignedVariables] - assignedVariablesDetails: Optional[AssignedVariablesDetails] + output: SensitiveData | None + outputDetails: HistoryEventExecutionDataDetails | None + assignedVariables: AssignedVariables | None + assignedVariablesDetails: AssignedVariablesDetails | None class StateEnteredEventDetails(TypedDict, total=False): name: Name - input: Optional[SensitiveData] - inputDetails: Optional[HistoryEventExecutionDataDetails] + input: SensitiveData | None + inputDetails: HistoryEventExecutionDataDetails | None class LambdaFunctionTimedOutEventDetails(TypedDict, total=False): - error: Optional[SensitiveError] - cause: Optional[SensitiveCause] + error: SensitiveError | None + cause: SensitiveCause | None class LambdaFunctionSucceededEventDetails(TypedDict, total=False): - output: Optional[SensitiveData] - outputDetails: Optional[HistoryEventExecutionDataDetails] + output: SensitiveData | None + outputDetails: HistoryEventExecutionDataDetails | None class LambdaFunctionStartFailedEventDetails(TypedDict, total=False): - error: Optional[SensitiveError] - cause: Optional[SensitiveCause] + error: SensitiveError | None + cause: SensitiveCause | None class TaskCredentials(TypedDict, total=False): - roleArn: Optional[LongArn] + roleArn: LongArn | None class LambdaFunctionScheduledEventDetails(TypedDict, total=False): resource: Arn - input: Optional[SensitiveData] - inputDetails: Optional[HistoryEventExecutionDataDetails] - timeoutInSeconds: Optional[TimeoutInSeconds] - taskCredentials: Optional[TaskCredentials] + input: SensitiveData | None + inputDetails: HistoryEventExecutionDataDetails | None + timeoutInSeconds: TimeoutInSeconds | None + taskCredentials: TaskCredentials | None class LambdaFunctionScheduleFailedEventDetails(TypedDict, total=False): - error: Optional[SensitiveError] - cause: Optional[SensitiveCause] + error: SensitiveError | None + cause: SensitiveCause | None class LambdaFunctionFailedEventDetails(TypedDict, total=False): - error: Optional[SensitiveError] - cause: Optional[SensitiveCause] + error: SensitiveError | None + cause: SensitiveCause | None class MapIterationEventDetails(TypedDict, total=False): - name: Optional[Name] - index: Optional[UnsignedInteger] + name: Name | None + index: UnsignedInteger | None class MapStateStartedEventDetails(TypedDict, total=False): - length: Optional[UnsignedInteger] + length: UnsignedInteger | None class TaskTimedOutEventDetails(TypedDict, total=False): resourceType: Name resource: Name - error: Optional[SensitiveError] - cause: Optional[SensitiveCause] + error: SensitiveError | None + cause: SensitiveCause | None class TaskSucceededEventDetails(TypedDict, total=False): resourceType: Name resource: Name - output: Optional[SensitiveData] - outputDetails: Optional[HistoryEventExecutionDataDetails] + output: SensitiveData | None + outputDetails: HistoryEventExecutionDataDetails | None class TaskSubmittedEventDetails(TypedDict, total=False): resourceType: Name resource: Name - output: Optional[SensitiveData] - outputDetails: Optional[HistoryEventExecutionDataDetails] + output: SensitiveData | None + outputDetails: HistoryEventExecutionDataDetails | None class TaskSubmitFailedEventDetails(TypedDict, total=False): resourceType: Name resource: Name - error: Optional[SensitiveError] - cause: Optional[SensitiveCause] + error: SensitiveError | None + cause: SensitiveCause | None class TaskStartedEventDetails(TypedDict, total=False): @@ -951,8 +965,8 @@ class TaskStartedEventDetails(TypedDict, total=False): class TaskStartFailedEventDetails(TypedDict, total=False): resourceType: Name resource: Name - error: Optional[SensitiveError] - cause: Optional[SensitiveCause] + error: SensitiveError | None + cause: SensitiveCause | None class TaskScheduledEventDetails(TypedDict, total=False): @@ -960,127 +974,141 @@ class TaskScheduledEventDetails(TypedDict, total=False): resource: Name region: Name parameters: ConnectorParameters - timeoutInSeconds: Optional[TimeoutInSeconds] - heartbeatInSeconds: Optional[TimeoutInSeconds] - taskCredentials: Optional[TaskCredentials] + timeoutInSeconds: TimeoutInSeconds | None + heartbeatInSeconds: TimeoutInSeconds | None + taskCredentials: TaskCredentials | None class TaskFailedEventDetails(TypedDict, total=False): resourceType: Name resource: Name - error: Optional[SensitiveError] - cause: Optional[SensitiveCause] + error: SensitiveError | None + cause: SensitiveCause | None class HistoryEvent(TypedDict, total=False): timestamp: Timestamp type: HistoryEventType id: EventId - previousEventId: Optional[EventId] - activityFailedEventDetails: Optional[ActivityFailedEventDetails] - activityScheduleFailedEventDetails: Optional[ActivityScheduleFailedEventDetails] - activityScheduledEventDetails: Optional[ActivityScheduledEventDetails] - activityStartedEventDetails: Optional[ActivityStartedEventDetails] - activitySucceededEventDetails: Optional[ActivitySucceededEventDetails] - activityTimedOutEventDetails: Optional[ActivityTimedOutEventDetails] - taskFailedEventDetails: Optional[TaskFailedEventDetails] - taskScheduledEventDetails: Optional[TaskScheduledEventDetails] - taskStartFailedEventDetails: Optional[TaskStartFailedEventDetails] - taskStartedEventDetails: Optional[TaskStartedEventDetails] - taskSubmitFailedEventDetails: Optional[TaskSubmitFailedEventDetails] - taskSubmittedEventDetails: Optional[TaskSubmittedEventDetails] - taskSucceededEventDetails: Optional[TaskSucceededEventDetails] - taskTimedOutEventDetails: Optional[TaskTimedOutEventDetails] - executionFailedEventDetails: Optional[ExecutionFailedEventDetails] - executionStartedEventDetails: Optional[ExecutionStartedEventDetails] - executionSucceededEventDetails: Optional[ExecutionSucceededEventDetails] - executionAbortedEventDetails: Optional[ExecutionAbortedEventDetails] - executionTimedOutEventDetails: Optional[ExecutionTimedOutEventDetails] - executionRedrivenEventDetails: Optional[ExecutionRedrivenEventDetails] - mapStateStartedEventDetails: Optional[MapStateStartedEventDetails] - mapIterationStartedEventDetails: Optional[MapIterationEventDetails] - mapIterationSucceededEventDetails: Optional[MapIterationEventDetails] - mapIterationFailedEventDetails: Optional[MapIterationEventDetails] - mapIterationAbortedEventDetails: Optional[MapIterationEventDetails] - lambdaFunctionFailedEventDetails: Optional[LambdaFunctionFailedEventDetails] - lambdaFunctionScheduleFailedEventDetails: Optional[LambdaFunctionScheduleFailedEventDetails] - lambdaFunctionScheduledEventDetails: Optional[LambdaFunctionScheduledEventDetails] - lambdaFunctionStartFailedEventDetails: Optional[LambdaFunctionStartFailedEventDetails] - lambdaFunctionSucceededEventDetails: Optional[LambdaFunctionSucceededEventDetails] - lambdaFunctionTimedOutEventDetails: Optional[LambdaFunctionTimedOutEventDetails] - stateEnteredEventDetails: Optional[StateEnteredEventDetails] - stateExitedEventDetails: Optional[StateExitedEventDetails] - mapRunStartedEventDetails: Optional[MapRunStartedEventDetails] - mapRunFailedEventDetails: Optional[MapRunFailedEventDetails] - mapRunRedrivenEventDetails: Optional[MapRunRedrivenEventDetails] - evaluationFailedEventDetails: Optional[EvaluationFailedEventDetails] - - -HistoryEventList = List[HistoryEvent] + previousEventId: EventId | None + activityFailedEventDetails: ActivityFailedEventDetails | None + activityScheduleFailedEventDetails: ActivityScheduleFailedEventDetails | None + activityScheduledEventDetails: ActivityScheduledEventDetails | None + activityStartedEventDetails: ActivityStartedEventDetails | None + activitySucceededEventDetails: ActivitySucceededEventDetails | None + activityTimedOutEventDetails: ActivityTimedOutEventDetails | None + taskFailedEventDetails: TaskFailedEventDetails | None + taskScheduledEventDetails: TaskScheduledEventDetails | None + taskStartFailedEventDetails: TaskStartFailedEventDetails | None + taskStartedEventDetails: TaskStartedEventDetails | None + taskSubmitFailedEventDetails: TaskSubmitFailedEventDetails | None + taskSubmittedEventDetails: TaskSubmittedEventDetails | None + taskSucceededEventDetails: TaskSucceededEventDetails | None + taskTimedOutEventDetails: TaskTimedOutEventDetails | None + executionFailedEventDetails: ExecutionFailedEventDetails | None + executionStartedEventDetails: ExecutionStartedEventDetails | None + executionSucceededEventDetails: ExecutionSucceededEventDetails | None + executionAbortedEventDetails: ExecutionAbortedEventDetails | None + executionTimedOutEventDetails: ExecutionTimedOutEventDetails | None + executionRedrivenEventDetails: ExecutionRedrivenEventDetails | None + mapStateStartedEventDetails: MapStateStartedEventDetails | None + mapIterationStartedEventDetails: MapIterationEventDetails | None + mapIterationSucceededEventDetails: MapIterationEventDetails | None + mapIterationFailedEventDetails: MapIterationEventDetails | None + mapIterationAbortedEventDetails: MapIterationEventDetails | None + lambdaFunctionFailedEventDetails: LambdaFunctionFailedEventDetails | None + lambdaFunctionScheduleFailedEventDetails: LambdaFunctionScheduleFailedEventDetails | None + lambdaFunctionScheduledEventDetails: LambdaFunctionScheduledEventDetails | None + lambdaFunctionStartFailedEventDetails: LambdaFunctionStartFailedEventDetails | None + lambdaFunctionSucceededEventDetails: LambdaFunctionSucceededEventDetails | None + lambdaFunctionTimedOutEventDetails: LambdaFunctionTimedOutEventDetails | None + stateEnteredEventDetails: StateEnteredEventDetails | None + stateExitedEventDetails: StateExitedEventDetails | None + mapRunStartedEventDetails: MapRunStartedEventDetails | None + mapRunFailedEventDetails: MapRunFailedEventDetails | None + mapRunRedrivenEventDetails: MapRunRedrivenEventDetails | None + evaluationFailedEventDetails: EvaluationFailedEventDetails | None + + +HistoryEventList = list[HistoryEvent] class GetExecutionHistoryOutput(TypedDict, total=False): events: HistoryEventList - nextToken: Optional[PageToken] + nextToken: PageToken | None + + +class InspectionErrorDetails(TypedDict, total=False): + catchIndex: ExceptionHandlerIndex | None + retryIndex: ExceptionHandlerIndex | None + retryBackoffIntervalSeconds: RetryBackoffIntervalSeconds | None class InspectionDataResponse(TypedDict, total=False): - protocol: Optional[HTTPProtocol] - statusCode: Optional[HTTPStatusCode] - statusMessage: Optional[HTTPStatusMessage] - headers: Optional[HTTPHeaders] - body: Optional[HTTPBody] + protocol: HTTPProtocol | None + statusCode: HTTPStatusCode | None + statusMessage: HTTPStatusMessage | None + headers: HTTPHeaders | None + body: HTTPBody | None class InspectionDataRequest(TypedDict, total=False): - protocol: Optional[HTTPProtocol] - method: Optional[HTTPMethod] - url: Optional[URL] - headers: Optional[HTTPHeaders] - body: Optional[HTTPBody] + protocol: HTTPProtocol | None + method: HTTPMethod | None + url: URL | None + headers: HTTPHeaders | None + body: HTTPBody | None class InspectionData(TypedDict, total=False): - input: Optional[SensitiveData] - afterArguments: Optional[SensitiveData] - afterInputPath: Optional[SensitiveData] - afterParameters: Optional[SensitiveData] - result: Optional[SensitiveData] - afterResultSelector: Optional[SensitiveData] - afterResultPath: Optional[SensitiveData] - request: Optional[InspectionDataRequest] - response: Optional[InspectionDataResponse] - variables: Optional[SensitiveData] + input: SensitiveData | None + afterArguments: SensitiveData | None + afterInputPath: SensitiveData | None + afterParameters: SensitiveData | None + result: SensitiveData | None + afterResultSelector: SensitiveData | None + afterResultPath: SensitiveData | None + request: InspectionDataRequest | None + response: InspectionDataResponse | None + variables: SensitiveData | None + errorDetails: InspectionErrorDetails | None + afterItemsPath: SensitiveData | None + afterItemSelector: SensitiveData | None + afterItemBatcher: SensitiveData | None + afterItemsPointer: SensitiveData | None + toleratedFailureCount: InspectionToleratedFailureCount | None + toleratedFailurePercentage: InspectionToleratedFailurePercentage | None + maxConcurrency: InspectionMaxConcurrency | None class ListActivitiesInput(ServiceRequest): - maxResults: Optional[PageSize] - nextToken: Optional[PageToken] + maxResults: PageSize | None + nextToken: PageToken | None class ListActivitiesOutput(TypedDict, total=False): activities: ActivityList - nextToken: Optional[PageToken] + nextToken: PageToken | None class ListExecutionsInput(ServiceRequest): - stateMachineArn: Optional[Arn] - statusFilter: Optional[ExecutionStatus] - maxResults: Optional[PageSize] - nextToken: Optional[ListExecutionsPageToken] - mapRunArn: Optional[LongArn] - redriveFilter: Optional[ExecutionRedriveFilter] + stateMachineArn: Arn | None + statusFilter: ExecutionStatus | None + maxResults: PageSize | None + nextToken: ListExecutionsPageToken | None + mapRunArn: LongArn | None + redriveFilter: ExecutionRedriveFilter | None class ListExecutionsOutput(TypedDict, total=False): executions: ExecutionList - nextToken: Optional[ListExecutionsPageToken] + nextToken: ListExecutionsPageToken | None class ListMapRunsInput(ServiceRequest): executionArn: Arn - maxResults: Optional[PageSize] - nextToken: Optional[PageToken] + maxResults: PageSize | None + nextToken: PageToken | None class MapRunListItem(TypedDict, total=False): @@ -1088,21 +1116,21 @@ class MapRunListItem(TypedDict, total=False): mapRunArn: LongArn stateMachineArn: Arn startDate: Timestamp - stopDate: Optional[Timestamp] + stopDate: Timestamp | None -MapRunList = List[MapRunListItem] +MapRunList = list[MapRunListItem] class ListMapRunsOutput(TypedDict, total=False): mapRuns: MapRunList - nextToken: Optional[PageToken] + nextToken: PageToken | None class ListStateMachineAliasesInput(ServiceRequest): stateMachineArn: Arn - nextToken: Optional[PageToken] - maxResults: Optional[PageSize] + nextToken: PageToken | None + maxResults: PageSize | None class StateMachineAliasListItem(TypedDict, total=False): @@ -1110,18 +1138,18 @@ class StateMachineAliasListItem(TypedDict, total=False): creationDate: Timestamp -StateMachineAliasList = List[StateMachineAliasListItem] +StateMachineAliasList = list[StateMachineAliasListItem] class ListStateMachineAliasesOutput(TypedDict, total=False): stateMachineAliases: StateMachineAliasList - nextToken: Optional[PageToken] + nextToken: PageToken | None class ListStateMachineVersionsInput(ServiceRequest): stateMachineArn: Arn - nextToken: Optional[PageToken] - maxResults: Optional[PageSize] + nextToken: PageToken | None + maxResults: PageSize | None class StateMachineVersionListItem(TypedDict, total=False): @@ -1129,17 +1157,17 @@ class StateMachineVersionListItem(TypedDict, total=False): creationDate: Timestamp -StateMachineVersionList = List[StateMachineVersionListItem] +StateMachineVersionList = list[StateMachineVersionListItem] class ListStateMachineVersionsOutput(TypedDict, total=False): stateMachineVersions: StateMachineVersionList - nextToken: Optional[PageToken] + nextToken: PageToken | None class ListStateMachinesInput(ServiceRequest): - maxResults: Optional[PageSize] - nextToken: Optional[PageToken] + maxResults: PageSize | None + nextToken: PageToken | None class StateMachineListItem(TypedDict, total=False): @@ -1149,12 +1177,12 @@ class StateMachineListItem(TypedDict, total=False): creationDate: Timestamp -StateMachineList = List[StateMachineListItem] +StateMachineList = list[StateMachineListItem] class ListStateMachinesOutput(TypedDict, total=False): stateMachines: StateMachineList - nextToken: Optional[PageToken] + nextToken: PageToken | None class ListTagsForResourceInput(ServiceRequest): @@ -1162,13 +1190,24 @@ class ListTagsForResourceInput(ServiceRequest): class ListTagsForResourceOutput(TypedDict, total=False): - tags: Optional[TagList] + tags: TagList | None + + +class MockErrorOutput(TypedDict, total=False): + error: SensitiveError | None + cause: SensitiveCause | None + + +class MockInput(TypedDict, total=False): + result: SensitiveData | None + errorOutput: MockErrorOutput | None + fieldValidationMode: MockResponseValidationMode | None class PublishStateMachineVersionInput(ServiceRequest): stateMachineArn: Arn - revisionId: Optional[RevisionId] - description: Optional[VersionDescription] + revisionId: RevisionId | None + description: VersionDescription | None class PublishStateMachineVersionOutput(TypedDict, total=False): @@ -1178,7 +1217,7 @@ class PublishStateMachineVersionOutput(TypedDict, total=False): class RedriveExecutionInput(ServiceRequest): executionArn: Arn - clientToken: Optional[ClientToken] + clientToken: ClientToken | None class RedriveExecutionOutput(TypedDict, total=False): @@ -1187,8 +1226,8 @@ class RedriveExecutionOutput(TypedDict, total=False): class SendTaskFailureInput(ServiceRequest): taskToken: TaskToken - error: Optional[SensitiveError] - cause: Optional[SensitiveCause] + error: SensitiveError | None + cause: SensitiveCause | None class SendTaskFailureOutput(TypedDict, total=False): @@ -1214,9 +1253,9 @@ class SendTaskSuccessOutput(TypedDict, total=False): class StartExecutionInput(ServiceRequest): stateMachineArn: Arn - name: Optional[Name] - input: Optional[SensitiveData] - traceHeader: Optional[TraceHeader] + name: Name | None + input: SensitiveData | None + traceHeader: TraceHeader | None class StartExecutionOutput(TypedDict, total=False): @@ -1226,40 +1265,40 @@ class StartExecutionOutput(TypedDict, total=False): class StartSyncExecutionInput(ServiceRequest): stateMachineArn: Arn - name: Optional[Name] - input: Optional[SensitiveData] - traceHeader: Optional[TraceHeader] - includedData: Optional[IncludedData] + name: Name | None + input: SensitiveData | None + traceHeader: TraceHeader | None + includedData: IncludedData | None class StartSyncExecutionOutput(TypedDict, total=False): executionArn: Arn - stateMachineArn: Optional[Arn] - name: Optional[Name] + stateMachineArn: Arn | None + name: Name | None startDate: Timestamp stopDate: Timestamp status: SyncExecutionStatus - error: Optional[SensitiveError] - cause: Optional[SensitiveCause] - input: Optional[SensitiveData] - inputDetails: Optional[CloudWatchEventsExecutionDataDetails] - output: Optional[SensitiveData] - outputDetails: Optional[CloudWatchEventsExecutionDataDetails] - traceHeader: Optional[TraceHeader] - billingDetails: Optional[BillingDetails] + error: SensitiveError | None + cause: SensitiveCause | None + input: SensitiveData | None + inputDetails: CloudWatchEventsExecutionDataDetails | None + output: SensitiveData | None + outputDetails: CloudWatchEventsExecutionDataDetails | None + traceHeader: TraceHeader | None + billingDetails: BillingDetails | None class StopExecutionInput(ServiceRequest): executionArn: Arn - error: Optional[SensitiveError] - cause: Optional[SensitiveCause] + error: SensitiveError | None + cause: SensitiveCause | None class StopExecutionOutput(TypedDict, total=False): stopDate: Timestamp -TagKeyList = List[TagKey] +TagKeyList = list[TagKey] class TagResourceInput(ServiceRequest): @@ -1271,22 +1310,33 @@ class TagResourceOutput(TypedDict, total=False): pass +class TestStateConfiguration(TypedDict, total=False): + retrierRetryCount: RetrierRetryCount | None + errorCausedByState: TestStateStateName | None + mapIterationFailureCount: MapIterationFailureCount | None + mapItemReaderData: SensitiveData | None + + class TestStateInput(ServiceRequest): definition: Definition - roleArn: Optional[Arn] - input: Optional[SensitiveData] - inspectionLevel: Optional[InspectionLevel] - revealSecrets: Optional[RevealSecrets] - variables: Optional[SensitiveData] + roleArn: Arn | None + input: SensitiveData | None + inspectionLevel: InspectionLevel | None + revealSecrets: RevealSecrets | None + variables: SensitiveData | None + stateName: TestStateStateName | None + mock: MockInput | None + context: SensitiveData | None + stateConfiguration: TestStateConfiguration | None class TestStateOutput(TypedDict, total=False): - output: Optional[SensitiveData] - error: Optional[SensitiveError] - cause: Optional[SensitiveCause] - inspectionData: Optional[InspectionData] - nextState: Optional[StateName] - status: Optional[TestExecutionStatus] + output: SensitiveData | None + error: SensitiveError | None + cause: SensitiveCause | None + inspectionData: InspectionData | None + nextState: StateName | None + status: TestExecutionStatus | None class UntagResourceInput(ServiceRequest): @@ -1300,9 +1350,9 @@ class UntagResourceOutput(TypedDict, total=False): class UpdateMapRunInput(ServiceRequest): mapRunArn: LongArn - maxConcurrency: Optional[MaxConcurrency] - toleratedFailurePercentage: Optional[ToleratedFailurePercentage] - toleratedFailureCount: Optional[ToleratedFailureCount] + maxConcurrency: MaxConcurrency | None + toleratedFailurePercentage: ToleratedFailurePercentage | None + toleratedFailureCount: ToleratedFailureCount | None class UpdateMapRunOutput(TypedDict, total=False): @@ -1311,8 +1361,8 @@ class UpdateMapRunOutput(TypedDict, total=False): class UpdateStateMachineAliasInput(ServiceRequest): stateMachineAliasArn: Arn - description: Optional[AliasDescription] - routingConfiguration: Optional[RoutingConfigurationList] + description: AliasDescription | None + routingConfiguration: RoutingConfigurationList | None class UpdateStateMachineAliasOutput(TypedDict, total=False): @@ -1321,47 +1371,47 @@ class UpdateStateMachineAliasOutput(TypedDict, total=False): class UpdateStateMachineInput(ServiceRequest): stateMachineArn: Arn - definition: Optional[Definition] - roleArn: Optional[Arn] - loggingConfiguration: Optional[LoggingConfiguration] - tracingConfiguration: Optional[TracingConfiguration] - publish: Optional[Publish] - versionDescription: Optional[VersionDescription] - encryptionConfiguration: Optional[EncryptionConfiguration] + definition: Definition | None + roleArn: Arn | None + loggingConfiguration: LoggingConfiguration | None + tracingConfiguration: TracingConfiguration | None + publish: Publish | None + versionDescription: VersionDescription | None + encryptionConfiguration: EncryptionConfiguration | None class UpdateStateMachineOutput(TypedDict, total=False): updateDate: Timestamp - revisionId: Optional[RevisionId] - stateMachineVersionArn: Optional[Arn] + revisionId: RevisionId | None + stateMachineVersionArn: Arn | None class ValidateStateMachineDefinitionDiagnostic(TypedDict, total=False): severity: ValidateStateMachineDefinitionSeverity code: ValidateStateMachineDefinitionCode message: ValidateStateMachineDefinitionMessage - location: Optional[ValidateStateMachineDefinitionLocation] + location: ValidateStateMachineDefinitionLocation | None -ValidateStateMachineDefinitionDiagnosticList = List[ValidateStateMachineDefinitionDiagnostic] +ValidateStateMachineDefinitionDiagnosticList = list[ValidateStateMachineDefinitionDiagnostic] class ValidateStateMachineDefinitionInput(TypedDict, total=False): definition: Definition - type: Optional[StateMachineType] - severity: Optional[ValidateStateMachineDefinitionSeverity] - maxResults: Optional[ValidateStateMachineDefinitionMaxResult] + type: StateMachineType | None + severity: ValidateStateMachineDefinitionSeverity | None + maxResults: ValidateStateMachineDefinitionMaxResult | None class ValidateStateMachineDefinitionOutput(TypedDict, total=False): result: ValidateStateMachineDefinitionResultCode diagnostics: ValidateStateMachineDefinitionDiagnosticList - truncated: Optional[ValidateStateMachineDefinitionTruncated] + truncated: ValidateStateMachineDefinitionTruncated | None class StepfunctionsApi: - service = "stepfunctions" - version = "2016-11-23" + service: str = "stepfunctions" + version: str = "2016-11-23" @handler("CreateActivity") def create_activity( @@ -1641,17 +1691,9 @@ def tag_resource( ) -> TagResourceOutput: raise NotImplementedError - @handler("TestState") + @handler("TestState", expand=False) def test_state( - self, - context: RequestContext, - definition: Definition, - role_arn: Arn | None = None, - input: SensitiveData | None = None, - inspection_level: InspectionLevel | None = None, - reveal_secrets: RevealSecrets | None = None, - variables: SensitiveData | None = None, - **kwargs, + self, context: RequestContext, request: TestStateInput, **kwargs ) -> TestStateOutput: raise NotImplementedError diff --git a/localstack-core/localstack/aws/api/sts/__init__.py b/localstack-core/localstack/aws/api/sts/__init__.py index 3a5e4c337c738..99abc13d132d2 100644 --- a/localstack-core/localstack/aws/api/sts/__init__.py +++ b/localstack-core/localstack/aws/api/sts/__init__.py @@ -1,5 +1,5 @@ from datetime import datetime -from typing import List, Optional, TypedDict +from typing import TypedDict from localstack.aws.api import RequestContext, ServiceException, ServiceRequest, handler @@ -22,30 +22,39 @@ durationSecondsType = int encodedMessageType = str expiredIdentityTokenMessage = str +expiredTradeInTokenExceptionMessage = str externalIdType = str federatedIdType = str idpCommunicationErrorMessage = str idpRejectedClaimMessage = str invalidAuthorizationMessage = str invalidIdentityTokenMessage = str +jwtAlgorithmType = str +jwtPayloadSizeExceededException = str malformedPolicyDocumentMessage = str nonNegativeIntegerType = int +outboundWebIdentityFederationDisabledException = str packedPolicyTooLargeMessage = str regionDisabledMessage = str roleDurationSecondsType = int roleSessionNameType = str serialNumberType = str +sessionDurationEscalationException = str sessionPolicyDocumentType = str sourceIdentityType = str tagKeyType = str tagValueType = str tokenCodeType = str tokenType = str +tradeInTokenType = str unrestrictedSessionPolicyDocumentType = str urlType = str userIdType = str userNameType = str webIdentitySubjectType = str +webIdentityTokenAudienceStringType = str +webIdentityTokenDurationSecondsType = int +webIdentityTokenType = str class ExpiredTokenException(ServiceException): @@ -54,6 +63,12 @@ class ExpiredTokenException(ServiceException): status_code: int = 400 +class ExpiredTradeInTokenException(ServiceException): + code: str = "ExpiredTradeInTokenException" + sender_fault: bool = True + status_code: int = 400 + + class IDPCommunicationErrorException(ServiceException): code: str = "IDPCommunicationError" sender_fault: bool = True @@ -78,12 +93,24 @@ class InvalidIdentityTokenException(ServiceException): status_code: int = 400 +class JWTPayloadSizeExceededException(ServiceException): + code: str = "JWTPayloadSizeExceededException" + sender_fault: bool = True + status_code: int = 400 + + class MalformedPolicyDocumentException(ServiceException): code: str = "MalformedPolicyDocument" sender_fault: bool = True status_code: int = 400 +class OutboundWebIdentityFederationDisabledException(ServiceException): + code: str = "OutboundWebIdentityFederationDisabledException" + sender_fault: bool = True + status_code: int = 403 + + class PackedPolicyTooLargeException(ServiceException): code: str = "PackedPolicyTooLarge" sender_fault: bool = True @@ -96,13 +123,19 @@ class RegionDisabledException(ServiceException): status_code: int = 403 +class SessionDurationEscalationException(ServiceException): + code: str = "SessionDurationEscalationException" + sender_fault: bool = True + status_code: int = 403 + + class ProvidedContext(TypedDict, total=False): - ProviderArn: Optional[arnType] - ContextAssertion: Optional[contextAssertionType] + ProviderArn: arnType | None + ContextAssertion: contextAssertionType | None -ProvidedContextsListType = List[ProvidedContext] -tagKeyListType = List[tagKeyType] +ProvidedContextsListType = list[ProvidedContext] +tagKeyListType = list[tagKeyType] class Tag(TypedDict, total=False): @@ -110,29 +143,29 @@ class Tag(TypedDict, total=False): Value: tagValueType -tagListType = List[Tag] +tagListType = list[Tag] class PolicyDescriptorType(TypedDict, total=False): - arn: Optional[arnType] + arn: arnType | None -policyDescriptorListType = List[PolicyDescriptorType] +policyDescriptorListType = list[PolicyDescriptorType] class AssumeRoleRequest(ServiceRequest): RoleArn: arnType RoleSessionName: roleSessionNameType - PolicyArns: Optional[policyDescriptorListType] - Policy: Optional[unrestrictedSessionPolicyDocumentType] - DurationSeconds: Optional[roleDurationSecondsType] - Tags: Optional[tagListType] - TransitiveTagKeys: Optional[tagKeyListType] - ExternalId: Optional[externalIdType] - SerialNumber: Optional[serialNumberType] - TokenCode: Optional[tokenCodeType] - SourceIdentity: Optional[sourceIdentityType] - ProvidedContexts: Optional[ProvidedContextsListType] + PolicyArns: policyDescriptorListType | None + Policy: unrestrictedSessionPolicyDocumentType | None + DurationSeconds: roleDurationSecondsType | None + Tags: tagListType | None + TransitiveTagKeys: tagKeyListType | None + ExternalId: externalIdType | None + SerialNumber: serialNumberType | None + TokenCode: tokenCodeType | None + SourceIdentity: sourceIdentityType | None + ProvidedContexts: ProvidedContextsListType | None class AssumedRoleUser(TypedDict, total=False): @@ -151,62 +184,62 @@ class Credentials(TypedDict, total=False): class AssumeRoleResponse(TypedDict, total=False): - Credentials: Optional[Credentials] - AssumedRoleUser: Optional[AssumedRoleUser] - PackedPolicySize: Optional[nonNegativeIntegerType] - SourceIdentity: Optional[sourceIdentityType] + Credentials: Credentials | None + AssumedRoleUser: AssumedRoleUser | None + PackedPolicySize: nonNegativeIntegerType | None + SourceIdentity: sourceIdentityType | None class AssumeRoleWithSAMLRequest(ServiceRequest): RoleArn: arnType PrincipalArn: arnType SAMLAssertion: SAMLAssertionType - PolicyArns: Optional[policyDescriptorListType] - Policy: Optional[sessionPolicyDocumentType] - DurationSeconds: Optional[roleDurationSecondsType] + PolicyArns: policyDescriptorListType | None + Policy: sessionPolicyDocumentType | None + DurationSeconds: roleDurationSecondsType | None class AssumeRoleWithSAMLResponse(TypedDict, total=False): - Credentials: Optional[Credentials] - AssumedRoleUser: Optional[AssumedRoleUser] - PackedPolicySize: Optional[nonNegativeIntegerType] - Subject: Optional[Subject] - SubjectType: Optional[SubjectType] - Issuer: Optional[Issuer] - Audience: Optional[Audience] - NameQualifier: Optional[NameQualifier] - SourceIdentity: Optional[sourceIdentityType] + Credentials: Credentials | None + AssumedRoleUser: AssumedRoleUser | None + PackedPolicySize: nonNegativeIntegerType | None + Subject: Subject | None + SubjectType: SubjectType | None + Issuer: Issuer | None + Audience: Audience | None + NameQualifier: NameQualifier | None + SourceIdentity: sourceIdentityType | None class AssumeRoleWithWebIdentityRequest(ServiceRequest): RoleArn: arnType RoleSessionName: roleSessionNameType WebIdentityToken: clientTokenType - ProviderId: Optional[urlType] - PolicyArns: Optional[policyDescriptorListType] - Policy: Optional[sessionPolicyDocumentType] - DurationSeconds: Optional[roleDurationSecondsType] + ProviderId: urlType | None + PolicyArns: policyDescriptorListType | None + Policy: sessionPolicyDocumentType | None + DurationSeconds: roleDurationSecondsType | None class AssumeRoleWithWebIdentityResponse(TypedDict, total=False): - Credentials: Optional[Credentials] - SubjectFromWebIdentityToken: Optional[webIdentitySubjectType] - AssumedRoleUser: Optional[AssumedRoleUser] - PackedPolicySize: Optional[nonNegativeIntegerType] - Provider: Optional[Issuer] - Audience: Optional[Audience] - SourceIdentity: Optional[sourceIdentityType] + Credentials: Credentials | None + SubjectFromWebIdentityToken: webIdentitySubjectType | None + AssumedRoleUser: AssumedRoleUser | None + PackedPolicySize: nonNegativeIntegerType | None + Provider: Issuer | None + Audience: Audience | None + SourceIdentity: sourceIdentityType | None class AssumeRootRequest(ServiceRequest): TargetPrincipal: TargetPrincipalType TaskPolicyArn: PolicyDescriptorType - DurationSeconds: Optional[RootDurationSecondsType] + DurationSeconds: RootDurationSecondsType | None class AssumeRootResponse(TypedDict, total=False): - Credentials: Optional[Credentials] - SourceIdentity: Optional[sourceIdentityType] + Credentials: Credentials | None + SourceIdentity: sourceIdentityType | None class DecodeAuthorizationMessageRequest(ServiceRequest): @@ -214,7 +247,7 @@ class DecodeAuthorizationMessageRequest(ServiceRequest): class DecodeAuthorizationMessageResponse(TypedDict, total=False): - DecodedMessage: Optional[decodedMessageType] + DecodedMessage: decodedMessageType | None class FederatedUser(TypedDict, total=False): @@ -227,7 +260,7 @@ class GetAccessKeyInfoRequest(ServiceRequest): class GetAccessKeyInfoResponse(TypedDict, total=False): - Account: Optional[accountType] + Account: accountType | None class GetCallerIdentityRequest(ServiceRequest): @@ -235,38 +268,63 @@ class GetCallerIdentityRequest(ServiceRequest): class GetCallerIdentityResponse(TypedDict, total=False): - UserId: Optional[userIdType] - Account: Optional[accountType] - Arn: Optional[arnType] + UserId: userIdType | None + Account: accountType | None + Arn: arnType | None + + +class GetDelegatedAccessTokenRequest(ServiceRequest): + TradeInToken: tradeInTokenType + + +class GetDelegatedAccessTokenResponse(TypedDict, total=False): + Credentials: Credentials | None + PackedPolicySize: nonNegativeIntegerType | None + AssumedPrincipal: arnType | None class GetFederationTokenRequest(ServiceRequest): Name: userNameType - Policy: Optional[sessionPolicyDocumentType] - PolicyArns: Optional[policyDescriptorListType] - DurationSeconds: Optional[durationSecondsType] - Tags: Optional[tagListType] + Policy: sessionPolicyDocumentType | None + PolicyArns: policyDescriptorListType | None + DurationSeconds: durationSecondsType | None + Tags: tagListType | None class GetFederationTokenResponse(TypedDict, total=False): - Credentials: Optional[Credentials] - FederatedUser: Optional[FederatedUser] - PackedPolicySize: Optional[nonNegativeIntegerType] + Credentials: Credentials | None + FederatedUser: FederatedUser | None + PackedPolicySize: nonNegativeIntegerType | None class GetSessionTokenRequest(ServiceRequest): - DurationSeconds: Optional[durationSecondsType] - SerialNumber: Optional[serialNumberType] - TokenCode: Optional[tokenCodeType] + DurationSeconds: durationSecondsType | None + SerialNumber: serialNumberType | None + TokenCode: tokenCodeType | None class GetSessionTokenResponse(TypedDict, total=False): - Credentials: Optional[Credentials] + Credentials: Credentials | None + + +webIdentityTokenAudienceListType = list[webIdentityTokenAudienceStringType] + + +class GetWebIdentityTokenRequest(ServiceRequest): + Audience: webIdentityTokenAudienceListType + DurationSeconds: webIdentityTokenDurationSecondsType | None + SigningAlgorithm: jwtAlgorithmType + Tags: tagListType | None + + +class GetWebIdentityTokenResponse(TypedDict, total=False): + WebIdentityToken: webIdentityTokenType | None + Expiration: dateType | None class StsApi: - service = "sts" - version = "2011-06-15" + service: str = "sts" + version: str = "2011-06-15" @handler("AssumeRole") def assume_role( @@ -344,6 +402,12 @@ def get_access_key_info( def get_caller_identity(self, context: RequestContext, **kwargs) -> GetCallerIdentityResponse: raise NotImplementedError + @handler("GetDelegatedAccessToken") + def get_delegated_access_token( + self, context: RequestContext, trade_in_token: tradeInTokenType, **kwargs + ) -> GetDelegatedAccessTokenResponse: + raise NotImplementedError + @handler("GetFederationToken") def get_federation_token( self, @@ -367,3 +431,15 @@ def get_session_token( **kwargs, ) -> GetSessionTokenResponse: raise NotImplementedError + + @handler("GetWebIdentityToken") + def get_web_identity_token( + self, + context: RequestContext, + audience: webIdentityTokenAudienceListType, + signing_algorithm: jwtAlgorithmType, + duration_seconds: webIdentityTokenDurationSecondsType | None = None, + tags: tagListType | None = None, + **kwargs, + ) -> GetWebIdentityTokenResponse: + raise NotImplementedError diff --git a/localstack-core/localstack/aws/api/support/__init__.py b/localstack-core/localstack/aws/api/support/__init__.py index af48bc4abd8a4..7dfa181267e33 100644 --- a/localstack-core/localstack/aws/api/support/__init__.py +++ b/localstack-core/localstack/aws/api/support/__init__.py @@ -1,4 +1,4 @@ -from typing import List, Optional, TypedDict +from typing import TypedDict from localstack.aws.api import RequestContext, ServiceException, ServiceRequest, handler @@ -113,127 +113,127 @@ class ThrottlingException(ServiceException): class Attachment(TypedDict, total=False): - fileName: Optional[FileName] - data: Optional[Data] + fileName: FileName | None + data: Data | None -Attachments = List[Attachment] +Attachments = list[Attachment] class AddAttachmentsToSetRequest(ServiceRequest): - attachmentSetId: Optional[AttachmentSetId] + attachmentSetId: AttachmentSetId | None attachments: Attachments class AddAttachmentsToSetResponse(TypedDict, total=False): - attachmentSetId: Optional[AttachmentSetId] - expiryTime: Optional[ExpiryTime] + attachmentSetId: AttachmentSetId | None + expiryTime: ExpiryTime | None -CcEmailAddressList = List[CcEmailAddress] +CcEmailAddressList = list[CcEmailAddress] class AddCommunicationToCaseRequest(ServiceRequest): - caseId: Optional[CaseId] + caseId: CaseId | None communicationBody: CommunicationBody - ccEmailAddresses: Optional[CcEmailAddressList] - attachmentSetId: Optional[AttachmentSetId] + ccEmailAddresses: CcEmailAddressList | None + attachmentSetId: AttachmentSetId | None class AddCommunicationToCaseResponse(TypedDict, total=False): - result: Optional[Result] + result: Result | None class AttachmentDetails(TypedDict, total=False): - attachmentId: Optional[AttachmentId] - fileName: Optional[FileName] + attachmentId: AttachmentId | None + fileName: FileName | None -AttachmentSet = List[AttachmentDetails] +AttachmentSet = list[AttachmentDetails] class Communication(TypedDict, total=False): - caseId: Optional[CaseId] - body: Optional[ValidatedCommunicationBody] - submittedBy: Optional[SubmittedBy] - timeCreated: Optional[TimeCreated] - attachmentSet: Optional[AttachmentSet] + caseId: CaseId | None + body: ValidatedCommunicationBody | None + submittedBy: SubmittedBy | None + timeCreated: TimeCreated | None + attachmentSet: AttachmentSet | None -CommunicationList = List[Communication] +CommunicationList = list[Communication] class RecentCaseCommunications(TypedDict, total=False): - communications: Optional[CommunicationList] - nextToken: Optional[NextToken] + communications: CommunicationList | None + nextToken: NextToken | None class CaseDetails(TypedDict, total=False): - caseId: Optional[CaseId] - displayId: Optional[DisplayId] - subject: Optional[Subject] - status: Optional[Status] - serviceCode: Optional[ServiceCode] - categoryCode: Optional[CategoryCode] - severityCode: Optional[SeverityCode] - submittedBy: Optional[SubmittedBy] - timeCreated: Optional[TimeCreated] - recentCommunications: Optional[RecentCaseCommunications] - ccEmailAddresses: Optional[CcEmailAddressList] - language: Optional[Language] + caseId: CaseId | None + displayId: DisplayId | None + subject: Subject | None + status: Status | None + serviceCode: ServiceCode | None + categoryCode: CategoryCode | None + severityCode: SeverityCode | None + submittedBy: SubmittedBy | None + timeCreated: TimeCreated | None + recentCommunications: RecentCaseCommunications | None + ccEmailAddresses: CcEmailAddressList | None + language: Language | None -CaseIdList = List[CaseId] -CaseList = List[CaseDetails] +CaseIdList = list[CaseId] +CaseList = list[CaseDetails] class Category(TypedDict, total=False): - code: Optional[CategoryCode] - name: Optional[CategoryName] + code: CategoryCode | None + name: CategoryName | None -CategoryList = List[Category] +CategoryList = list[Category] class DateInterval(TypedDict, total=False): - startDateTime: Optional[ValidatedDateTime] - endDateTime: Optional[ValidatedDateTime] + startDateTime: ValidatedDateTime | None + endDateTime: ValidatedDateTime | None -DatesWithoutSupportList = List[DateInterval] +DatesWithoutSupportList = list[DateInterval] class SupportedHour(TypedDict, total=False): - startTime: Optional[StartTime] - endTime: Optional[EndTime] + startTime: StartTime | None + endTime: EndTime | None -SupportedHoursList = List[SupportedHour] +SupportedHoursList = list[SupportedHour] class CommunicationTypeOptions(TypedDict, total=False): - type: Optional[Type] - supportedHours: Optional[SupportedHoursList] - datesWithoutSupport: Optional[DatesWithoutSupportList] + type: Type | None + supportedHours: SupportedHoursList | None + datesWithoutSupport: DatesWithoutSupportList | None -CommunicationTypeOptionsList = List[CommunicationTypeOptions] +CommunicationTypeOptionsList = list[CommunicationTypeOptions] class CreateCaseRequest(ServiceRequest): subject: Subject - serviceCode: Optional[ServiceCode] - severityCode: Optional[SeverityCode] - categoryCode: Optional[CategoryCode] + serviceCode: ServiceCode | None + severityCode: SeverityCode | None + categoryCode: CategoryCode | None communicationBody: CommunicationBody - ccEmailAddresses: Optional[CcEmailAddressList] - language: Optional[Language] - issueType: Optional[IssueType] - attachmentSetId: Optional[AttachmentSetId] + ccEmailAddresses: CcEmailAddressList | None + language: Language | None + issueType: IssueType | None + attachmentSetId: AttachmentSetId | None class CreateCaseResponse(TypedDict, total=False): - caseId: Optional[CaseId] + caseId: CaseId | None class DescribeAttachmentRequest(ServiceRequest): @@ -241,37 +241,37 @@ class DescribeAttachmentRequest(ServiceRequest): class DescribeAttachmentResponse(TypedDict, total=False): - attachment: Optional[Attachment] + attachment: Attachment | None class DescribeCasesRequest(ServiceRequest): - caseIdList: Optional[CaseIdList] - displayId: Optional[DisplayId] - afterTime: Optional[AfterTime] - beforeTime: Optional[BeforeTime] - includeResolvedCases: Optional[IncludeResolvedCases] - nextToken: Optional[NextToken] - maxResults: Optional[MaxResults] - language: Optional[Language] - includeCommunications: Optional[IncludeCommunications] + caseIdList: CaseIdList | None + displayId: DisplayId | None + afterTime: AfterTime | None + beforeTime: BeforeTime | None + includeResolvedCases: IncludeResolvedCases | None + nextToken: NextToken | None + maxResults: MaxResults | None + language: Language | None + includeCommunications: IncludeCommunications | None class DescribeCasesResponse(TypedDict, total=False): - cases: Optional[CaseList] - nextToken: Optional[NextToken] + cases: CaseList | None + nextToken: NextToken | None class DescribeCommunicationsRequest(ServiceRequest): caseId: CaseId - beforeTime: Optional[BeforeTime] - afterTime: Optional[AfterTime] - nextToken: Optional[NextToken] - maxResults: Optional[MaxResults] + beforeTime: BeforeTime | None + afterTime: AfterTime | None + nextToken: NextToken | None + maxResults: MaxResults | None class DescribeCommunicationsResponse(TypedDict, total=False): - communications: Optional[CommunicationList] - nextToken: Optional[NextToken] + communications: CommunicationList | None + nextToken: NextToken | None class DescribeCreateCaseOptionsRequest(ServiceRequest): @@ -282,45 +282,45 @@ class DescribeCreateCaseOptionsRequest(ServiceRequest): class DescribeCreateCaseOptionsResponse(TypedDict, total=False): - languageAvailability: Optional[ValidatedLanguageAvailability] - communicationTypes: Optional[CommunicationTypeOptionsList] + languageAvailability: ValidatedLanguageAvailability | None + communicationTypes: CommunicationTypeOptionsList | None -ServiceCodeList = List[ServiceCode] +ServiceCodeList = list[ServiceCode] class DescribeServicesRequest(ServiceRequest): - serviceCodeList: Optional[ServiceCodeList] - language: Optional[Language] + serviceCodeList: ServiceCodeList | None + language: Language | None class Service(TypedDict, total=False): - code: Optional[ServiceCode] - name: Optional[ServiceName] - categories: Optional[CategoryList] + code: ServiceCode | None + name: ServiceName | None + categories: CategoryList | None -ServiceList = List[Service] +ServiceList = list[Service] class DescribeServicesResponse(TypedDict, total=False): - services: Optional[ServiceList] + services: ServiceList | None class DescribeSeverityLevelsRequest(ServiceRequest): - language: Optional[Language] + language: Language | None class SeverityLevel(TypedDict, total=False): - code: Optional[SeverityLevelCode] - name: Optional[SeverityLevelName] + code: SeverityLevelCode | None + name: SeverityLevelName | None -SeverityLevelsList = List[SeverityLevel] +SeverityLevelsList = list[SeverityLevel] class DescribeSeverityLevelsResponse(TypedDict, total=False): - severityLevels: Optional[SeverityLevelsList] + severityLevels: SeverityLevelsList | None class DescribeSupportedLanguagesRequest(ServiceRequest): @@ -330,19 +330,19 @@ class DescribeSupportedLanguagesRequest(ServiceRequest): class SupportedLanguage(TypedDict, total=False): - code: Optional[Code] - language: Optional[Language] - display: Optional[Display] + code: Code | None + language: Language | None + display: Display | None -SupportedLanguagesList = List[SupportedLanguage] +SupportedLanguagesList = list[SupportedLanguage] class DescribeSupportedLanguagesResponse(TypedDict, total=False): - supportedLanguages: Optional[SupportedLanguagesList] + supportedLanguages: SupportedLanguagesList | None -StringList = List[String] +StringList = list[String] class DescribeTrustedAdvisorCheckRefreshStatusesRequest(ServiceRequest): @@ -358,7 +358,7 @@ class TrustedAdvisorCheckRefreshStatus(TypedDict, total=False): millisUntilNextRefreshable: Long -TrustedAdvisorCheckRefreshStatusList = List[TrustedAdvisorCheckRefreshStatus] +TrustedAdvisorCheckRefreshStatusList = list[TrustedAdvisorCheckRefreshStatus] class DescribeTrustedAdvisorCheckRefreshStatusesResponse(TypedDict, total=False): @@ -367,18 +367,18 @@ class DescribeTrustedAdvisorCheckRefreshStatusesResponse(TypedDict, total=False) class DescribeTrustedAdvisorCheckResultRequest(ServiceRequest): checkId: String - language: Optional[String] + language: String | None class TrustedAdvisorResourceDetail(TypedDict, total=False): status: String - region: Optional[String] + region: String | None resourceId: String - isSuppressed: Optional[Boolean] + isSuppressed: Boolean | None metadata: StringList -TrustedAdvisorResourceDetailList = List[TrustedAdvisorResourceDetail] +TrustedAdvisorResourceDetailList = list[TrustedAdvisorResourceDetail] class TrustedAdvisorCostOptimizingSummary(TypedDict, total=False): @@ -387,7 +387,7 @@ class TrustedAdvisorCostOptimizingSummary(TypedDict, total=False): class TrustedAdvisorCategorySpecificSummary(TypedDict, total=False): - costOptimizing: Optional[TrustedAdvisorCostOptimizingSummary] + costOptimizing: TrustedAdvisorCostOptimizingSummary | None class TrustedAdvisorResourcesSummary(TypedDict, total=False): @@ -407,7 +407,7 @@ class TrustedAdvisorCheckResult(TypedDict, total=False): class DescribeTrustedAdvisorCheckResultResponse(TypedDict, total=False): - result: Optional[TrustedAdvisorCheckResult] + result: TrustedAdvisorCheckResult | None class DescribeTrustedAdvisorCheckSummariesRequest(ServiceRequest): @@ -418,12 +418,12 @@ class TrustedAdvisorCheckSummary(TypedDict, total=False): checkId: String timestamp: String status: String - hasFlaggedResources: Optional[Boolean] + hasFlaggedResources: Boolean | None resourcesSummary: TrustedAdvisorResourcesSummary categorySpecificSummary: TrustedAdvisorCategorySpecificSummary -TrustedAdvisorCheckSummaryList = List[TrustedAdvisorCheckSummary] +TrustedAdvisorCheckSummaryList = list[TrustedAdvisorCheckSummary] class DescribeTrustedAdvisorCheckSummariesResponse(TypedDict, total=False): @@ -442,7 +442,7 @@ class TrustedAdvisorCheckDescription(TypedDict, total=False): metadata: StringList -TrustedAdvisorCheckList = List[TrustedAdvisorCheckDescription] +TrustedAdvisorCheckList = list[TrustedAdvisorCheckDescription] class DescribeTrustedAdvisorChecksResponse(TypedDict, total=False): @@ -458,17 +458,17 @@ class RefreshTrustedAdvisorCheckResponse(TypedDict, total=False): class ResolveCaseRequest(ServiceRequest): - caseId: Optional[CaseId] + caseId: CaseId | None class ResolveCaseResponse(TypedDict, total=False): - initialCaseStatus: Optional[CaseStatus] - finalCaseStatus: Optional[CaseStatus] + initialCaseStatus: CaseStatus | None + finalCaseStatus: CaseStatus | None class SupportApi: - service = "support" - version = "2013-04-15" + service: str = "support" + version: str = "2013-04-15" @handler("AddAttachmentsToSet") def add_attachments_to_set( diff --git a/localstack-core/localstack/aws/api/swf/__init__.py b/localstack-core/localstack/aws/api/swf/__init__.py index 23653779f7e9f..1c35461750559 100644 --- a/localstack-core/localstack/aws/api/swf/__init__.py +++ b/localstack-core/localstack/aws/api/swf/__init__.py @@ -1,6 +1,6 @@ from datetime import datetime from enum import StrEnum -from typing import List, Optional, TypedDict +from typing import TypedDict from localstack.aws.api import RequestContext, ServiceException, ServiceRequest, handler @@ -369,7 +369,7 @@ class ActivityTask(TypedDict, total=False): startedEventId: EventId workflowExecution: WorkflowExecution activityType: ActivityType - input: Optional[Data] + input: Data | None class ActivityTaskCancelRequestedEventAttributes(TypedDict, total=False): @@ -378,21 +378,21 @@ class ActivityTaskCancelRequestedEventAttributes(TypedDict, total=False): class ActivityTaskCanceledEventAttributes(TypedDict, total=False): - details: Optional[Data] + details: Data | None scheduledEventId: EventId startedEventId: EventId - latestCancelRequestedEventId: Optional[EventId] + latestCancelRequestedEventId: EventId | None class ActivityTaskCompletedEventAttributes(TypedDict, total=False): - result: Optional[Data] + result: Data | None scheduledEventId: EventId startedEventId: EventId class ActivityTaskFailedEventAttributes(TypedDict, total=False): - reason: Optional[FailureReason] - details: Optional[Data] + reason: FailureReason | None + details: Data | None scheduledEventId: EventId startedEventId: EventId @@ -404,19 +404,19 @@ class TaskList(TypedDict, total=False): class ActivityTaskScheduledEventAttributes(TypedDict, total=False): activityType: ActivityType activityId: ActivityId - input: Optional[Data] - control: Optional[Data] - scheduleToStartTimeout: Optional[DurationInSecondsOptional] - scheduleToCloseTimeout: Optional[DurationInSecondsOptional] - startToCloseTimeout: Optional[DurationInSecondsOptional] + input: Data | None + control: Data | None + scheduleToStartTimeout: DurationInSecondsOptional | None + scheduleToCloseTimeout: DurationInSecondsOptional | None + startToCloseTimeout: DurationInSecondsOptional | None taskList: TaskList - taskPriority: Optional[TaskPriority] + taskPriority: TaskPriority | None decisionTaskCompletedEventId: EventId - heartbeatTimeout: Optional[DurationInSecondsOptional] + heartbeatTimeout: DurationInSecondsOptional | None class ActivityTaskStartedEventAttributes(TypedDict, total=False): - identity: Optional[Identity] + identity: Identity | None scheduledEventId: EventId @@ -428,16 +428,16 @@ class ActivityTaskTimedOutEventAttributes(TypedDict, total=False): timeoutType: ActivityTaskTimeoutType scheduledEventId: EventId startedEventId: EventId - details: Optional[LimitedData] + details: LimitedData | None class ActivityTypeConfiguration(TypedDict, total=False): - defaultTaskStartToCloseTimeout: Optional[DurationInSecondsOptional] - defaultTaskHeartbeatTimeout: Optional[DurationInSecondsOptional] - defaultTaskList: Optional[TaskList] - defaultTaskPriority: Optional[TaskPriority] - defaultTaskScheduleToStartTimeout: Optional[DurationInSecondsOptional] - defaultTaskScheduleToCloseTimeout: Optional[DurationInSecondsOptional] + defaultTaskStartToCloseTimeout: DurationInSecondsOptional | None + defaultTaskHeartbeatTimeout: DurationInSecondsOptional | None + defaultTaskList: TaskList | None + defaultTaskPriority: TaskPriority | None + defaultTaskScheduleToStartTimeout: DurationInSecondsOptional | None + defaultTaskScheduleToCloseTimeout: DurationInSecondsOptional | None Timestamp = datetime @@ -446,9 +446,9 @@ class ActivityTypeConfiguration(TypedDict, total=False): class ActivityTypeInfo(TypedDict, total=False): activityType: ActivityType status: RegistrationStatus - description: Optional[Description] + description: Description | None creationDate: Timestamp - deprecationDate: Optional[Timestamp] + deprecationDate: Timestamp | None class ActivityTypeDetail(TypedDict, total=False): @@ -456,12 +456,12 @@ class ActivityTypeDetail(TypedDict, total=False): configuration: ActivityTypeConfiguration -ActivityTypeInfoList = List[ActivityTypeInfo] +ActivityTypeInfoList = list[ActivityTypeInfo] class ActivityTypeInfos(TypedDict, total=False): typeInfos: ActivityTypeInfoList - nextPageToken: Optional[PageToken] + nextPageToken: PageToken | None class CancelTimerDecisionAttributes(TypedDict, total=False): @@ -475,7 +475,7 @@ class CancelTimerFailedEventAttributes(TypedDict, total=False): class CancelWorkflowExecutionDecisionAttributes(TypedDict, total=False): - details: Optional[Data] + details: Data | None class CancelWorkflowExecutionFailedEventAttributes(TypedDict, total=False): @@ -491,7 +491,7 @@ class WorkflowType(TypedDict, total=False): class ChildWorkflowExecutionCanceledEventAttributes(TypedDict, total=False): workflowExecution: WorkflowExecution workflowType: WorkflowType - details: Optional[Data] + details: Data | None initiatedEventId: EventId startedEventId: EventId @@ -499,7 +499,7 @@ class ChildWorkflowExecutionCanceledEventAttributes(TypedDict, total=False): class ChildWorkflowExecutionCompletedEventAttributes(TypedDict, total=False): workflowExecution: WorkflowExecution workflowType: WorkflowType - result: Optional[Data] + result: Data | None initiatedEventId: EventId startedEventId: EventId @@ -507,8 +507,8 @@ class ChildWorkflowExecutionCompletedEventAttributes(TypedDict, total=False): class ChildWorkflowExecutionFailedEventAttributes(TypedDict, total=False): workflowExecution: WorkflowExecution workflowType: WorkflowType - reason: Optional[FailureReason] - details: Optional[Data] + reason: FailureReason | None + details: Data | None initiatedEventId: EventId startedEventId: EventId @@ -539,7 +539,7 @@ class CloseStatusFilter(TypedDict, total=False): class CompleteWorkflowExecutionDecisionAttributes(TypedDict, total=False): - result: Optional[Data] + result: Data | None class CompleteWorkflowExecutionFailedEventAttributes(TypedDict, total=False): @@ -547,19 +547,19 @@ class CompleteWorkflowExecutionFailedEventAttributes(TypedDict, total=False): decisionTaskCompletedEventId: EventId -TagList = List[Tag] +TagList = list[Tag] class ContinueAsNewWorkflowExecutionDecisionAttributes(TypedDict, total=False): - input: Optional[Data] - executionStartToCloseTimeout: Optional[DurationInSecondsOptional] - taskList: Optional[TaskList] - taskPriority: Optional[TaskPriority] - taskStartToCloseTimeout: Optional[DurationInSecondsOptional] - childPolicy: Optional[ChildPolicy] - tagList: Optional[TagList] - workflowTypeVersion: Optional[Version] - lambdaRole: Optional[Arn] + input: Data | None + executionStartToCloseTimeout: DurationInSecondsOptional | None + taskList: TaskList | None + taskPriority: TaskPriority | None + taskStartToCloseTimeout: DurationInSecondsOptional | None + childPolicy: ChildPolicy | None + tagList: TagList | None + workflowTypeVersion: Version | None + lambdaRole: Arn | None class ContinueAsNewWorkflowExecutionFailedEventAttributes(TypedDict, total=False): @@ -573,7 +573,7 @@ class TagFilter(TypedDict, total=False): class WorkflowTypeFilter(TypedDict, total=False): name: Name - version: Optional[VersionOptional] + version: VersionOptional | None class WorkflowExecutionFilter(TypedDict, total=False): @@ -582,25 +582,25 @@ class WorkflowExecutionFilter(TypedDict, total=False): class ExecutionTimeFilter(TypedDict, total=False): oldestDate: Timestamp - latestDate: Optional[Timestamp] + latestDate: Timestamp | None class CountClosedWorkflowExecutionsInput(ServiceRequest): domain: DomainName - startTimeFilter: Optional[ExecutionTimeFilter] - closeTimeFilter: Optional[ExecutionTimeFilter] - executionFilter: Optional[WorkflowExecutionFilter] - typeFilter: Optional[WorkflowTypeFilter] - tagFilter: Optional[TagFilter] - closeStatusFilter: Optional[CloseStatusFilter] + startTimeFilter: ExecutionTimeFilter | None + closeTimeFilter: ExecutionTimeFilter | None + executionFilter: WorkflowExecutionFilter | None + typeFilter: WorkflowTypeFilter | None + tagFilter: TagFilter | None + closeStatusFilter: CloseStatusFilter | None class CountOpenWorkflowExecutionsInput(ServiceRequest): domain: DomainName startTimeFilter: ExecutionTimeFilter - typeFilter: Optional[WorkflowTypeFilter] - tagFilter: Optional[TagFilter] - executionFilter: Optional[WorkflowExecutionFilter] + typeFilter: WorkflowTypeFilter | None + tagFilter: TagFilter | None + executionFilter: WorkflowExecutionFilter | None class CountPendingActivityTasksInput(ServiceRequest): @@ -616,53 +616,53 @@ class CountPendingDecisionTasksInput(ServiceRequest): class ScheduleLambdaFunctionDecisionAttributes(TypedDict, total=False): id: FunctionId name: FunctionName - control: Optional[Data] - input: Optional[FunctionInput] - startToCloseTimeout: Optional[DurationInSecondsOptional] + control: Data | None + input: FunctionInput | None + startToCloseTimeout: DurationInSecondsOptional | None class StartChildWorkflowExecutionDecisionAttributes(TypedDict, total=False): workflowType: WorkflowType workflowId: WorkflowId - control: Optional[Data] - input: Optional[Data] - executionStartToCloseTimeout: Optional[DurationInSecondsOptional] - taskList: Optional[TaskList] - taskPriority: Optional[TaskPriority] - taskStartToCloseTimeout: Optional[DurationInSecondsOptional] - childPolicy: Optional[ChildPolicy] - tagList: Optional[TagList] - lambdaRole: Optional[Arn] + control: Data | None + input: Data | None + executionStartToCloseTimeout: DurationInSecondsOptional | None + taskList: TaskList | None + taskPriority: TaskPriority | None + taskStartToCloseTimeout: DurationInSecondsOptional | None + childPolicy: ChildPolicy | None + tagList: TagList | None + lambdaRole: Arn | None class RequestCancelExternalWorkflowExecutionDecisionAttributes(TypedDict, total=False): workflowId: WorkflowId - runId: Optional[WorkflowRunIdOptional] - control: Optional[Data] + runId: WorkflowRunIdOptional | None + control: Data | None class SignalExternalWorkflowExecutionDecisionAttributes(TypedDict, total=False): workflowId: WorkflowId - runId: Optional[WorkflowRunIdOptional] + runId: WorkflowRunIdOptional | None signalName: SignalName - input: Optional[Data] - control: Optional[Data] + input: Data | None + control: Data | None class StartTimerDecisionAttributes(TypedDict, total=False): timerId: TimerId - control: Optional[Data] + control: Data | None startToFireTimeout: DurationInSeconds class RecordMarkerDecisionAttributes(TypedDict, total=False): markerName: MarkerName - details: Optional[Data] + details: Data | None class FailWorkflowExecutionDecisionAttributes(TypedDict, total=False): - reason: Optional[FailureReason] - details: Optional[Data] + reason: FailureReason | None + details: Data | None class RequestCancelActivityTaskDecisionAttributes(TypedDict, total=False): @@ -672,52 +672,48 @@ class RequestCancelActivityTaskDecisionAttributes(TypedDict, total=False): class ScheduleActivityTaskDecisionAttributes(TypedDict, total=False): activityType: ActivityType activityId: ActivityId - control: Optional[Data] - input: Optional[Data] - scheduleToCloseTimeout: Optional[DurationInSecondsOptional] - taskList: Optional[TaskList] - taskPriority: Optional[TaskPriority] - scheduleToStartTimeout: Optional[DurationInSecondsOptional] - startToCloseTimeout: Optional[DurationInSecondsOptional] - heartbeatTimeout: Optional[DurationInSecondsOptional] + control: Data | None + input: Data | None + scheduleToCloseTimeout: DurationInSecondsOptional | None + taskList: TaskList | None + taskPriority: TaskPriority | None + scheduleToStartTimeout: DurationInSecondsOptional | None + startToCloseTimeout: DurationInSecondsOptional | None + heartbeatTimeout: DurationInSecondsOptional | None class Decision(TypedDict, total=False): decisionType: DecisionType - scheduleActivityTaskDecisionAttributes: Optional[ScheduleActivityTaskDecisionAttributes] - requestCancelActivityTaskDecisionAttributes: Optional[ - RequestCancelActivityTaskDecisionAttributes - ] - completeWorkflowExecutionDecisionAttributes: Optional[ - CompleteWorkflowExecutionDecisionAttributes - ] - failWorkflowExecutionDecisionAttributes: Optional[FailWorkflowExecutionDecisionAttributes] - cancelWorkflowExecutionDecisionAttributes: Optional[CancelWorkflowExecutionDecisionAttributes] - continueAsNewWorkflowExecutionDecisionAttributes: Optional[ - ContinueAsNewWorkflowExecutionDecisionAttributes - ] - recordMarkerDecisionAttributes: Optional[RecordMarkerDecisionAttributes] - startTimerDecisionAttributes: Optional[StartTimerDecisionAttributes] - cancelTimerDecisionAttributes: Optional[CancelTimerDecisionAttributes] - signalExternalWorkflowExecutionDecisionAttributes: Optional[ - SignalExternalWorkflowExecutionDecisionAttributes - ] - requestCancelExternalWorkflowExecutionDecisionAttributes: Optional[ - RequestCancelExternalWorkflowExecutionDecisionAttributes - ] - startChildWorkflowExecutionDecisionAttributes: Optional[ - StartChildWorkflowExecutionDecisionAttributes - ] - scheduleLambdaFunctionDecisionAttributes: Optional[ScheduleLambdaFunctionDecisionAttributes] - - -DecisionList = List[Decision] + scheduleActivityTaskDecisionAttributes: ScheduleActivityTaskDecisionAttributes | None + requestCancelActivityTaskDecisionAttributes: RequestCancelActivityTaskDecisionAttributes | None + completeWorkflowExecutionDecisionAttributes: CompleteWorkflowExecutionDecisionAttributes | None + failWorkflowExecutionDecisionAttributes: FailWorkflowExecutionDecisionAttributes | None + cancelWorkflowExecutionDecisionAttributes: CancelWorkflowExecutionDecisionAttributes | None + continueAsNewWorkflowExecutionDecisionAttributes: ( + ContinueAsNewWorkflowExecutionDecisionAttributes | None + ) + recordMarkerDecisionAttributes: RecordMarkerDecisionAttributes | None + startTimerDecisionAttributes: StartTimerDecisionAttributes | None + cancelTimerDecisionAttributes: CancelTimerDecisionAttributes | None + signalExternalWorkflowExecutionDecisionAttributes: ( + SignalExternalWorkflowExecutionDecisionAttributes | None + ) + requestCancelExternalWorkflowExecutionDecisionAttributes: ( + RequestCancelExternalWorkflowExecutionDecisionAttributes | None + ) + startChildWorkflowExecutionDecisionAttributes: ( + StartChildWorkflowExecutionDecisionAttributes | None + ) + scheduleLambdaFunctionDecisionAttributes: ScheduleLambdaFunctionDecisionAttributes | None + + +DecisionList = list[Decision] class StartLambdaFunctionFailedEventAttributes(TypedDict, total=False): - scheduledEventId: Optional[EventId] - cause: Optional[StartLambdaFunctionFailedCause] - message: Optional[CauseMessage] + scheduledEventId: EventId | None + cause: StartLambdaFunctionFailedCause | None + message: CauseMessage | None class ScheduleLambdaFunctionFailedEventAttributes(TypedDict, total=False): @@ -730,20 +726,20 @@ class ScheduleLambdaFunctionFailedEventAttributes(TypedDict, total=False): class LambdaFunctionTimedOutEventAttributes(TypedDict, total=False): scheduledEventId: EventId startedEventId: EventId - timeoutType: Optional[LambdaFunctionTimeoutType] + timeoutType: LambdaFunctionTimeoutType | None class LambdaFunctionFailedEventAttributes(TypedDict, total=False): scheduledEventId: EventId startedEventId: EventId - reason: Optional[FailureReason] - details: Optional[Data] + reason: FailureReason | None + details: Data | None class LambdaFunctionCompletedEventAttributes(TypedDict, total=False): scheduledEventId: EventId startedEventId: EventId - result: Optional[Data] + result: Data | None class LambdaFunctionStartedEventAttributes(TypedDict, total=False): @@ -753,9 +749,9 @@ class LambdaFunctionStartedEventAttributes(TypedDict, total=False): class LambdaFunctionScheduledEventAttributes(TypedDict, total=False): id: FunctionId name: FunctionName - control: Optional[Data] - input: Optional[FunctionInput] - startToCloseTimeout: Optional[DurationInSecondsOptional] + control: Data | None + input: FunctionInput | None + startToCloseTimeout: DurationInSecondsOptional | None decisionTaskCompletedEventId: EventId @@ -765,7 +761,7 @@ class StartChildWorkflowExecutionFailedEventAttributes(TypedDict, total=False): workflowId: WorkflowId initiatedEventId: EventId decisionTaskCompletedEventId: EventId - control: Optional[Data] + control: Data | None class StartTimerFailedEventAttributes(TypedDict, total=False): @@ -789,18 +785,18 @@ class ScheduleActivityTaskFailedEventAttributes(TypedDict, total=False): class RequestCancelExternalWorkflowExecutionFailedEventAttributes(TypedDict, total=False): workflowId: WorkflowId - runId: Optional[WorkflowRunIdOptional] + runId: WorkflowRunIdOptional | None cause: RequestCancelExternalWorkflowExecutionFailedCause initiatedEventId: EventId decisionTaskCompletedEventId: EventId - control: Optional[Data] + control: Data | None class RequestCancelExternalWorkflowExecutionInitiatedEventAttributes(TypedDict, total=False): workflowId: WorkflowId - runId: Optional[WorkflowRunIdOptional] + runId: WorkflowRunIdOptional | None decisionTaskCompletedEventId: EventId - control: Optional[Data] + control: Data | None class ExternalWorkflowExecutionCancelRequestedEventAttributes(TypedDict, total=False): @@ -810,11 +806,11 @@ class ExternalWorkflowExecutionCancelRequestedEventAttributes(TypedDict, total=F class SignalExternalWorkflowExecutionFailedEventAttributes(TypedDict, total=False): workflowId: WorkflowId - runId: Optional[WorkflowRunIdOptional] + runId: WorkflowRunIdOptional | None cause: SignalExternalWorkflowExecutionFailedCause initiatedEventId: EventId decisionTaskCompletedEventId: EventId - control: Optional[Data] + control: Data | None class ExternalWorkflowExecutionSignaledEventAttributes(TypedDict, total=False): @@ -824,26 +820,26 @@ class ExternalWorkflowExecutionSignaledEventAttributes(TypedDict, total=False): class SignalExternalWorkflowExecutionInitiatedEventAttributes(TypedDict, total=False): workflowId: WorkflowId - runId: Optional[WorkflowRunIdOptional] + runId: WorkflowRunIdOptional | None signalName: SignalName - input: Optional[Data] + input: Data | None decisionTaskCompletedEventId: EventId - control: Optional[Data] + control: Data | None class StartChildWorkflowExecutionInitiatedEventAttributes(TypedDict, total=False): workflowId: WorkflowId workflowType: WorkflowType - control: Optional[Data] - input: Optional[Data] - executionStartToCloseTimeout: Optional[DurationInSecondsOptional] + control: Data | None + input: Data | None + executionStartToCloseTimeout: DurationInSecondsOptional | None taskList: TaskList - taskPriority: Optional[TaskPriority] + taskPriority: TaskPriority | None decisionTaskCompletedEventId: EventId childPolicy: ChildPolicy - taskStartToCloseTimeout: Optional[DurationInSecondsOptional] - tagList: Optional[TagList] - lambdaRole: Optional[Arn] + taskStartToCloseTimeout: DurationInSecondsOptional | None + tagList: TagList | None + lambdaRole: Arn | None class TimerCanceledEventAttributes(TypedDict, total=False): @@ -859,7 +855,7 @@ class TimerFiredEventAttributes(TypedDict, total=False): class TimerStartedEventAttributes(TypedDict, total=False): timerId: TimerId - control: Optional[Data] + control: Data | None startToFireTimeout: DurationInSeconds decisionTaskCompletedEventId: EventId @@ -872,15 +868,15 @@ class RecordMarkerFailedEventAttributes(TypedDict, total=False): class MarkerRecordedEventAttributes(TypedDict, total=False): markerName: MarkerName - details: Optional[Data] + details: Data | None decisionTaskCompletedEventId: EventId class WorkflowExecutionSignaledEventAttributes(TypedDict, total=False): signalName: SignalName - input: Optional[Data] - externalWorkflowExecution: Optional[WorkflowExecution] - externalInitiatedEventId: Optional[EventId] + input: Data | None + externalWorkflowExecution: WorkflowExecution | None + externalInitiatedEventId: EventId | None class DecisionTaskTimedOutEventAttributes(TypedDict, total=False): @@ -890,54 +886,54 @@ class DecisionTaskTimedOutEventAttributes(TypedDict, total=False): class DecisionTaskCompletedEventAttributes(TypedDict, total=False): - executionContext: Optional[Data] + executionContext: Data | None scheduledEventId: EventId startedEventId: EventId - taskList: Optional[TaskList] - taskListScheduleToStartTimeout: Optional[DurationInSecondsOptional] + taskList: TaskList | None + taskListScheduleToStartTimeout: DurationInSecondsOptional | None class DecisionTaskStartedEventAttributes(TypedDict, total=False): - identity: Optional[Identity] + identity: Identity | None scheduledEventId: EventId class DecisionTaskScheduledEventAttributes(TypedDict, total=False): taskList: TaskList - taskPriority: Optional[TaskPriority] - startToCloseTimeout: Optional[DurationInSecondsOptional] - scheduleToStartTimeout: Optional[DurationInSecondsOptional] + taskPriority: TaskPriority | None + startToCloseTimeout: DurationInSecondsOptional | None + scheduleToStartTimeout: DurationInSecondsOptional | None class WorkflowExecutionCancelRequestedEventAttributes(TypedDict, total=False): - externalWorkflowExecution: Optional[WorkflowExecution] - externalInitiatedEventId: Optional[EventId] - cause: Optional[WorkflowExecutionCancelRequestedCause] + externalWorkflowExecution: WorkflowExecution | None + externalInitiatedEventId: EventId | None + cause: WorkflowExecutionCancelRequestedCause | None class WorkflowExecutionTerminatedEventAttributes(TypedDict, total=False): - reason: Optional[TerminateReason] - details: Optional[Data] + reason: TerminateReason | None + details: Data | None childPolicy: ChildPolicy - cause: Optional[WorkflowExecutionTerminatedCause] + cause: WorkflowExecutionTerminatedCause | None class WorkflowExecutionContinuedAsNewEventAttributes(TypedDict, total=False): - input: Optional[Data] + input: Data | None decisionTaskCompletedEventId: EventId newExecutionRunId: WorkflowRunId - executionStartToCloseTimeout: Optional[DurationInSecondsOptional] + executionStartToCloseTimeout: DurationInSecondsOptional | None taskList: TaskList - taskPriority: Optional[TaskPriority] - taskStartToCloseTimeout: Optional[DurationInSecondsOptional] + taskPriority: TaskPriority | None + taskStartToCloseTimeout: DurationInSecondsOptional | None childPolicy: ChildPolicy - tagList: Optional[TagList] + tagList: TagList | None workflowType: WorkflowType - lambdaRole: Optional[Arn] + lambdaRole: Arn | None class WorkflowExecutionCanceledEventAttributes(TypedDict, total=False): - details: Optional[Data] + details: Data | None decisionTaskCompletedEventId: EventId @@ -952,134 +948,130 @@ class FailWorkflowExecutionFailedEventAttributes(TypedDict, total=False): class WorkflowExecutionFailedEventAttributes(TypedDict, total=False): - reason: Optional[FailureReason] - details: Optional[Data] + reason: FailureReason | None + details: Data | None decisionTaskCompletedEventId: EventId class WorkflowExecutionCompletedEventAttributes(TypedDict, total=False): - result: Optional[Data] + result: Data | None decisionTaskCompletedEventId: EventId class WorkflowExecutionStartedEventAttributes(TypedDict, total=False): - input: Optional[Data] - executionStartToCloseTimeout: Optional[DurationInSecondsOptional] - taskStartToCloseTimeout: Optional[DurationInSecondsOptional] + input: Data | None + executionStartToCloseTimeout: DurationInSecondsOptional | None + taskStartToCloseTimeout: DurationInSecondsOptional | None childPolicy: ChildPolicy taskList: TaskList - taskPriority: Optional[TaskPriority] + taskPriority: TaskPriority | None workflowType: WorkflowType - tagList: Optional[TagList] - continuedExecutionRunId: Optional[WorkflowRunIdOptional] - parentWorkflowExecution: Optional[WorkflowExecution] - parentInitiatedEventId: Optional[EventId] - lambdaRole: Optional[Arn] + tagList: TagList | None + continuedExecutionRunId: WorkflowRunIdOptional | None + parentWorkflowExecution: WorkflowExecution | None + parentInitiatedEventId: EventId | None + lambdaRole: Arn | None class HistoryEvent(TypedDict, total=False): eventTimestamp: Timestamp eventType: EventType eventId: EventId - workflowExecutionStartedEventAttributes: Optional[WorkflowExecutionStartedEventAttributes] - workflowExecutionCompletedEventAttributes: Optional[WorkflowExecutionCompletedEventAttributes] - completeWorkflowExecutionFailedEventAttributes: Optional[ - CompleteWorkflowExecutionFailedEventAttributes - ] - workflowExecutionFailedEventAttributes: Optional[WorkflowExecutionFailedEventAttributes] - failWorkflowExecutionFailedEventAttributes: Optional[FailWorkflowExecutionFailedEventAttributes] - workflowExecutionTimedOutEventAttributes: Optional[WorkflowExecutionTimedOutEventAttributes] - workflowExecutionCanceledEventAttributes: Optional[WorkflowExecutionCanceledEventAttributes] - cancelWorkflowExecutionFailedEventAttributes: Optional[ - CancelWorkflowExecutionFailedEventAttributes - ] - workflowExecutionContinuedAsNewEventAttributes: Optional[ - WorkflowExecutionContinuedAsNewEventAttributes - ] - continueAsNewWorkflowExecutionFailedEventAttributes: Optional[ - ContinueAsNewWorkflowExecutionFailedEventAttributes - ] - workflowExecutionTerminatedEventAttributes: Optional[WorkflowExecutionTerminatedEventAttributes] - workflowExecutionCancelRequestedEventAttributes: Optional[ - WorkflowExecutionCancelRequestedEventAttributes - ] - decisionTaskScheduledEventAttributes: Optional[DecisionTaskScheduledEventAttributes] - decisionTaskStartedEventAttributes: Optional[DecisionTaskStartedEventAttributes] - decisionTaskCompletedEventAttributes: Optional[DecisionTaskCompletedEventAttributes] - decisionTaskTimedOutEventAttributes: Optional[DecisionTaskTimedOutEventAttributes] - activityTaskScheduledEventAttributes: Optional[ActivityTaskScheduledEventAttributes] - activityTaskStartedEventAttributes: Optional[ActivityTaskStartedEventAttributes] - activityTaskCompletedEventAttributes: Optional[ActivityTaskCompletedEventAttributes] - activityTaskFailedEventAttributes: Optional[ActivityTaskFailedEventAttributes] - activityTaskTimedOutEventAttributes: Optional[ActivityTaskTimedOutEventAttributes] - activityTaskCanceledEventAttributes: Optional[ActivityTaskCanceledEventAttributes] - activityTaskCancelRequestedEventAttributes: Optional[ActivityTaskCancelRequestedEventAttributes] - workflowExecutionSignaledEventAttributes: Optional[WorkflowExecutionSignaledEventAttributes] - markerRecordedEventAttributes: Optional[MarkerRecordedEventAttributes] - recordMarkerFailedEventAttributes: Optional[RecordMarkerFailedEventAttributes] - timerStartedEventAttributes: Optional[TimerStartedEventAttributes] - timerFiredEventAttributes: Optional[TimerFiredEventAttributes] - timerCanceledEventAttributes: Optional[TimerCanceledEventAttributes] - startChildWorkflowExecutionInitiatedEventAttributes: Optional[ - StartChildWorkflowExecutionInitiatedEventAttributes - ] - childWorkflowExecutionStartedEventAttributes: Optional[ - ChildWorkflowExecutionStartedEventAttributes - ] - childWorkflowExecutionCompletedEventAttributes: Optional[ - ChildWorkflowExecutionCompletedEventAttributes - ] - childWorkflowExecutionFailedEventAttributes: Optional[ - ChildWorkflowExecutionFailedEventAttributes - ] - childWorkflowExecutionTimedOutEventAttributes: Optional[ - ChildWorkflowExecutionTimedOutEventAttributes - ] - childWorkflowExecutionCanceledEventAttributes: Optional[ - ChildWorkflowExecutionCanceledEventAttributes - ] - childWorkflowExecutionTerminatedEventAttributes: Optional[ - ChildWorkflowExecutionTerminatedEventAttributes - ] - signalExternalWorkflowExecutionInitiatedEventAttributes: Optional[ - SignalExternalWorkflowExecutionInitiatedEventAttributes - ] - externalWorkflowExecutionSignaledEventAttributes: Optional[ - ExternalWorkflowExecutionSignaledEventAttributes - ] - signalExternalWorkflowExecutionFailedEventAttributes: Optional[ - SignalExternalWorkflowExecutionFailedEventAttributes - ] - externalWorkflowExecutionCancelRequestedEventAttributes: Optional[ - ExternalWorkflowExecutionCancelRequestedEventAttributes - ] - requestCancelExternalWorkflowExecutionInitiatedEventAttributes: Optional[ - RequestCancelExternalWorkflowExecutionInitiatedEventAttributes - ] - requestCancelExternalWorkflowExecutionFailedEventAttributes: Optional[ - RequestCancelExternalWorkflowExecutionFailedEventAttributes - ] - scheduleActivityTaskFailedEventAttributes: Optional[ScheduleActivityTaskFailedEventAttributes] - requestCancelActivityTaskFailedEventAttributes: Optional[ - RequestCancelActivityTaskFailedEventAttributes - ] - startTimerFailedEventAttributes: Optional[StartTimerFailedEventAttributes] - cancelTimerFailedEventAttributes: Optional[CancelTimerFailedEventAttributes] - startChildWorkflowExecutionFailedEventAttributes: Optional[ - StartChildWorkflowExecutionFailedEventAttributes - ] - lambdaFunctionScheduledEventAttributes: Optional[LambdaFunctionScheduledEventAttributes] - lambdaFunctionStartedEventAttributes: Optional[LambdaFunctionStartedEventAttributes] - lambdaFunctionCompletedEventAttributes: Optional[LambdaFunctionCompletedEventAttributes] - lambdaFunctionFailedEventAttributes: Optional[LambdaFunctionFailedEventAttributes] - lambdaFunctionTimedOutEventAttributes: Optional[LambdaFunctionTimedOutEventAttributes] - scheduleLambdaFunctionFailedEventAttributes: Optional[ - ScheduleLambdaFunctionFailedEventAttributes - ] - startLambdaFunctionFailedEventAttributes: Optional[StartLambdaFunctionFailedEventAttributes] - - -HistoryEventList = List[HistoryEvent] + workflowExecutionStartedEventAttributes: WorkflowExecutionStartedEventAttributes | None + workflowExecutionCompletedEventAttributes: WorkflowExecutionCompletedEventAttributes | None + completeWorkflowExecutionFailedEventAttributes: ( + CompleteWorkflowExecutionFailedEventAttributes | None + ) + workflowExecutionFailedEventAttributes: WorkflowExecutionFailedEventAttributes | None + failWorkflowExecutionFailedEventAttributes: FailWorkflowExecutionFailedEventAttributes | None + workflowExecutionTimedOutEventAttributes: WorkflowExecutionTimedOutEventAttributes | None + workflowExecutionCanceledEventAttributes: WorkflowExecutionCanceledEventAttributes | None + cancelWorkflowExecutionFailedEventAttributes: ( + CancelWorkflowExecutionFailedEventAttributes | None + ) + workflowExecutionContinuedAsNewEventAttributes: ( + WorkflowExecutionContinuedAsNewEventAttributes | None + ) + continueAsNewWorkflowExecutionFailedEventAttributes: ( + ContinueAsNewWorkflowExecutionFailedEventAttributes | None + ) + workflowExecutionTerminatedEventAttributes: WorkflowExecutionTerminatedEventAttributes | None + workflowExecutionCancelRequestedEventAttributes: ( + WorkflowExecutionCancelRequestedEventAttributes | None + ) + decisionTaskScheduledEventAttributes: DecisionTaskScheduledEventAttributes | None + decisionTaskStartedEventAttributes: DecisionTaskStartedEventAttributes | None + decisionTaskCompletedEventAttributes: DecisionTaskCompletedEventAttributes | None + decisionTaskTimedOutEventAttributes: DecisionTaskTimedOutEventAttributes | None + activityTaskScheduledEventAttributes: ActivityTaskScheduledEventAttributes | None + activityTaskStartedEventAttributes: ActivityTaskStartedEventAttributes | None + activityTaskCompletedEventAttributes: ActivityTaskCompletedEventAttributes | None + activityTaskFailedEventAttributes: ActivityTaskFailedEventAttributes | None + activityTaskTimedOutEventAttributes: ActivityTaskTimedOutEventAttributes | None + activityTaskCanceledEventAttributes: ActivityTaskCanceledEventAttributes | None + activityTaskCancelRequestedEventAttributes: ActivityTaskCancelRequestedEventAttributes | None + workflowExecutionSignaledEventAttributes: WorkflowExecutionSignaledEventAttributes | None + markerRecordedEventAttributes: MarkerRecordedEventAttributes | None + recordMarkerFailedEventAttributes: RecordMarkerFailedEventAttributes | None + timerStartedEventAttributes: TimerStartedEventAttributes | None + timerFiredEventAttributes: TimerFiredEventAttributes | None + timerCanceledEventAttributes: TimerCanceledEventAttributes | None + startChildWorkflowExecutionInitiatedEventAttributes: ( + StartChildWorkflowExecutionInitiatedEventAttributes | None + ) + childWorkflowExecutionStartedEventAttributes: ( + ChildWorkflowExecutionStartedEventAttributes | None + ) + childWorkflowExecutionCompletedEventAttributes: ( + ChildWorkflowExecutionCompletedEventAttributes | None + ) + childWorkflowExecutionFailedEventAttributes: ChildWorkflowExecutionFailedEventAttributes | None + childWorkflowExecutionTimedOutEventAttributes: ( + ChildWorkflowExecutionTimedOutEventAttributes | None + ) + childWorkflowExecutionCanceledEventAttributes: ( + ChildWorkflowExecutionCanceledEventAttributes | None + ) + childWorkflowExecutionTerminatedEventAttributes: ( + ChildWorkflowExecutionTerminatedEventAttributes | None + ) + signalExternalWorkflowExecutionInitiatedEventAttributes: ( + SignalExternalWorkflowExecutionInitiatedEventAttributes | None + ) + externalWorkflowExecutionSignaledEventAttributes: ( + ExternalWorkflowExecutionSignaledEventAttributes | None + ) + signalExternalWorkflowExecutionFailedEventAttributes: ( + SignalExternalWorkflowExecutionFailedEventAttributes | None + ) + externalWorkflowExecutionCancelRequestedEventAttributes: ( + ExternalWorkflowExecutionCancelRequestedEventAttributes | None + ) + requestCancelExternalWorkflowExecutionInitiatedEventAttributes: ( + RequestCancelExternalWorkflowExecutionInitiatedEventAttributes | None + ) + requestCancelExternalWorkflowExecutionFailedEventAttributes: ( + RequestCancelExternalWorkflowExecutionFailedEventAttributes | None + ) + scheduleActivityTaskFailedEventAttributes: ScheduleActivityTaskFailedEventAttributes | None + requestCancelActivityTaskFailedEventAttributes: ( + RequestCancelActivityTaskFailedEventAttributes | None + ) + startTimerFailedEventAttributes: StartTimerFailedEventAttributes | None + cancelTimerFailedEventAttributes: CancelTimerFailedEventAttributes | None + startChildWorkflowExecutionFailedEventAttributes: ( + StartChildWorkflowExecutionFailedEventAttributes | None + ) + lambdaFunctionScheduledEventAttributes: LambdaFunctionScheduledEventAttributes | None + lambdaFunctionStartedEventAttributes: LambdaFunctionStartedEventAttributes | None + lambdaFunctionCompletedEventAttributes: LambdaFunctionCompletedEventAttributes | None + lambdaFunctionFailedEventAttributes: LambdaFunctionFailedEventAttributes | None + lambdaFunctionTimedOutEventAttributes: LambdaFunctionTimedOutEventAttributes | None + scheduleLambdaFunctionFailedEventAttributes: ScheduleLambdaFunctionFailedEventAttributes | None + startLambdaFunctionFailedEventAttributes: StartLambdaFunctionFailedEventAttributes | None + + +HistoryEventList = list[HistoryEvent] class DecisionTask(TypedDict, total=False): @@ -1088,8 +1080,8 @@ class DecisionTask(TypedDict, total=False): workflowExecution: WorkflowExecution workflowType: WorkflowType events: HistoryEventList - nextPageToken: Optional[PageToken] - previousStartedEventId: Optional[EventId] + nextPageToken: PageToken | None + previousStartedEventId: EventId | None class DeleteActivityTypeInput(ServiceRequest): @@ -1142,8 +1134,8 @@ class DomainConfiguration(TypedDict, total=False): class DomainInfo(TypedDict, total=False): name: DomainName status: RegistrationStatus - description: Optional[Description] - arn: Optional[Arn] + description: Description | None + arn: Arn | None class DomainDetail(TypedDict, total=False): @@ -1151,65 +1143,65 @@ class DomainDetail(TypedDict, total=False): configuration: DomainConfiguration -DomainInfoList = List[DomainInfo] +DomainInfoList = list[DomainInfo] class DomainInfos(TypedDict, total=False): domainInfos: DomainInfoList - nextPageToken: Optional[PageToken] + nextPageToken: PageToken | None class GetWorkflowExecutionHistoryInput(ServiceRequest): domain: DomainName execution: WorkflowExecution - nextPageToken: Optional[PageToken] - maximumPageSize: Optional[PageSize] - reverseOrder: Optional[ReverseOrder] + nextPageToken: PageToken | None + maximumPageSize: PageSize | None + reverseOrder: ReverseOrder | None class History(TypedDict, total=False): events: HistoryEventList - nextPageToken: Optional[PageToken] + nextPageToken: PageToken | None class ListActivityTypesInput(ServiceRequest): domain: DomainName - name: Optional[Name] + name: Name | None registrationStatus: RegistrationStatus - nextPageToken: Optional[PageToken] - maximumPageSize: Optional[PageSize] - reverseOrder: Optional[ReverseOrder] + nextPageToken: PageToken | None + maximumPageSize: PageSize | None + reverseOrder: ReverseOrder | None class ListClosedWorkflowExecutionsInput(ServiceRequest): domain: DomainName - startTimeFilter: Optional[ExecutionTimeFilter] - closeTimeFilter: Optional[ExecutionTimeFilter] - executionFilter: Optional[WorkflowExecutionFilter] - closeStatusFilter: Optional[CloseStatusFilter] - typeFilter: Optional[WorkflowTypeFilter] - tagFilter: Optional[TagFilter] - nextPageToken: Optional[PageToken] - maximumPageSize: Optional[PageSize] - reverseOrder: Optional[ReverseOrder] + startTimeFilter: ExecutionTimeFilter | None + closeTimeFilter: ExecutionTimeFilter | None + executionFilter: WorkflowExecutionFilter | None + closeStatusFilter: CloseStatusFilter | None + typeFilter: WorkflowTypeFilter | None + tagFilter: TagFilter | None + nextPageToken: PageToken | None + maximumPageSize: PageSize | None + reverseOrder: ReverseOrder | None class ListDomainsInput(ServiceRequest): - nextPageToken: Optional[PageToken] + nextPageToken: PageToken | None registrationStatus: RegistrationStatus - maximumPageSize: Optional[PageSize] - reverseOrder: Optional[ReverseOrder] + maximumPageSize: PageSize | None + reverseOrder: ReverseOrder | None class ListOpenWorkflowExecutionsInput(ServiceRequest): domain: DomainName startTimeFilter: ExecutionTimeFilter - typeFilter: Optional[WorkflowTypeFilter] - tagFilter: Optional[TagFilter] - nextPageToken: Optional[PageToken] - maximumPageSize: Optional[PageSize] - reverseOrder: Optional[ReverseOrder] - executionFilter: Optional[WorkflowExecutionFilter] + typeFilter: WorkflowTypeFilter | None + tagFilter: TagFilter | None + nextPageToken: PageToken | None + maximumPageSize: PageSize | None + reverseOrder: ReverseOrder | None + executionFilter: WorkflowExecutionFilter | None class ListTagsForResourceInput(ServiceRequest): @@ -1218,141 +1210,141 @@ class ListTagsForResourceInput(ServiceRequest): class ResourceTag(TypedDict, total=False): key: ResourceTagKey - value: Optional[ResourceTagValue] + value: ResourceTagValue | None -ResourceTagList = List[ResourceTag] +ResourceTagList = list[ResourceTag] class ListTagsForResourceOutput(TypedDict, total=False): - tags: Optional[ResourceTagList] + tags: ResourceTagList | None class ListWorkflowTypesInput(ServiceRequest): domain: DomainName - name: Optional[Name] + name: Name | None registrationStatus: RegistrationStatus - nextPageToken: Optional[PageToken] - maximumPageSize: Optional[PageSize] - reverseOrder: Optional[ReverseOrder] + nextPageToken: PageToken | None + maximumPageSize: PageSize | None + reverseOrder: ReverseOrder | None class PendingTaskCount(TypedDict, total=False): count: Count - truncated: Optional[Truncated] + truncated: Truncated | None class PollForActivityTaskInput(ServiceRequest): domain: DomainName taskList: TaskList - identity: Optional[Identity] + identity: Identity | None class PollForDecisionTaskInput(ServiceRequest): domain: DomainName taskList: TaskList - identity: Optional[Identity] - nextPageToken: Optional[PageToken] - maximumPageSize: Optional[PageSize] - reverseOrder: Optional[ReverseOrder] - startAtPreviousStartedEvent: Optional[StartAtPreviousStartedEvent] + identity: Identity | None + nextPageToken: PageToken | None + maximumPageSize: PageSize | None + reverseOrder: ReverseOrder | None + startAtPreviousStartedEvent: StartAtPreviousStartedEvent | None class RecordActivityTaskHeartbeatInput(ServiceRequest): taskToken: TaskToken - details: Optional[LimitedData] + details: LimitedData | None class RegisterActivityTypeInput(ServiceRequest): domain: DomainName name: Name version: Version - description: Optional[Description] - defaultTaskStartToCloseTimeout: Optional[DurationInSecondsOptional] - defaultTaskHeartbeatTimeout: Optional[DurationInSecondsOptional] - defaultTaskList: Optional[TaskList] - defaultTaskPriority: Optional[TaskPriority] - defaultTaskScheduleToStartTimeout: Optional[DurationInSecondsOptional] - defaultTaskScheduleToCloseTimeout: Optional[DurationInSecondsOptional] + description: Description | None + defaultTaskStartToCloseTimeout: DurationInSecondsOptional | None + defaultTaskHeartbeatTimeout: DurationInSecondsOptional | None + defaultTaskList: TaskList | None + defaultTaskPriority: TaskPriority | None + defaultTaskScheduleToStartTimeout: DurationInSecondsOptional | None + defaultTaskScheduleToCloseTimeout: DurationInSecondsOptional | None class RegisterDomainInput(ServiceRequest): name: DomainName - description: Optional[Description] + description: Description | None workflowExecutionRetentionPeriodInDays: DurationInDays - tags: Optional[ResourceTagList] + tags: ResourceTagList | None class RegisterWorkflowTypeInput(ServiceRequest): domain: DomainName name: Name version: Version - description: Optional[Description] - defaultTaskStartToCloseTimeout: Optional[DurationInSecondsOptional] - defaultExecutionStartToCloseTimeout: Optional[DurationInSecondsOptional] - defaultTaskList: Optional[TaskList] - defaultTaskPriority: Optional[TaskPriority] - defaultChildPolicy: Optional[ChildPolicy] - defaultLambdaRole: Optional[Arn] + description: Description | None + defaultTaskStartToCloseTimeout: DurationInSecondsOptional | None + defaultExecutionStartToCloseTimeout: DurationInSecondsOptional | None + defaultTaskList: TaskList | None + defaultTaskPriority: TaskPriority | None + defaultChildPolicy: ChildPolicy | None + defaultLambdaRole: Arn | None class RequestCancelWorkflowExecutionInput(ServiceRequest): domain: DomainName workflowId: WorkflowId - runId: Optional[WorkflowRunIdOptional] + runId: WorkflowRunIdOptional | None -ResourceTagKeyList = List[ResourceTagKey] +ResourceTagKeyList = list[ResourceTagKey] class RespondActivityTaskCanceledInput(ServiceRequest): taskToken: TaskToken - details: Optional[Data] + details: Data | None class RespondActivityTaskCompletedInput(ServiceRequest): taskToken: TaskToken - result: Optional[Data] + result: Data | None class RespondActivityTaskFailedInput(ServiceRequest): taskToken: TaskToken - reason: Optional[FailureReason] - details: Optional[Data] + reason: FailureReason | None + details: Data | None class RespondDecisionTaskCompletedInput(ServiceRequest): taskToken: TaskToken - decisions: Optional[DecisionList] - executionContext: Optional[Data] - taskList: Optional[TaskList] - taskListScheduleToStartTimeout: Optional[DurationInSecondsOptional] + decisions: DecisionList | None + executionContext: Data | None + taskList: TaskList | None + taskListScheduleToStartTimeout: DurationInSecondsOptional | None class Run(TypedDict, total=False): - runId: Optional[WorkflowRunId] + runId: WorkflowRunId | None class SignalWorkflowExecutionInput(ServiceRequest): domain: DomainName workflowId: WorkflowId - runId: Optional[WorkflowRunIdOptional] + runId: WorkflowRunIdOptional | None signalName: SignalName - input: Optional[Data] + input: Data | None class StartWorkflowExecutionInput(ServiceRequest): domain: DomainName workflowId: WorkflowId workflowType: WorkflowType - taskList: Optional[TaskList] - taskPriority: Optional[TaskPriority] - input: Optional[Data] - executionStartToCloseTimeout: Optional[DurationInSecondsOptional] - tagList: Optional[TagList] - taskStartToCloseTimeout: Optional[DurationInSecondsOptional] - childPolicy: Optional[ChildPolicy] - lambdaRole: Optional[Arn] + taskList: TaskList | None + taskPriority: TaskPriority | None + input: Data | None + executionStartToCloseTimeout: DurationInSecondsOptional | None + tagList: TagList | None + taskStartToCloseTimeout: DurationInSecondsOptional | None + childPolicy: ChildPolicy | None + lambdaRole: Arn | None class TagResourceInput(ServiceRequest): @@ -1363,10 +1355,10 @@ class TagResourceInput(ServiceRequest): class TerminateWorkflowExecutionInput(ServiceRequest): domain: DomainName workflowId: WorkflowId - runId: Optional[WorkflowRunIdOptional] - reason: Optional[TerminateReason] - details: Optional[Data] - childPolicy: Optional[ChildPolicy] + runId: WorkflowRunIdOptional | None + reason: TerminateReason | None + details: Data | None + childPolicy: ChildPolicy | None class UndeprecateActivityTypeInput(ServiceRequest): @@ -1392,14 +1384,14 @@ class WorkflowExecutionConfiguration(TypedDict, total=False): taskStartToCloseTimeout: DurationInSeconds executionStartToCloseTimeout: DurationInSeconds taskList: TaskList - taskPriority: Optional[TaskPriority] + taskPriority: TaskPriority | None childPolicy: ChildPolicy - lambdaRole: Optional[Arn] + lambdaRole: Arn | None class WorkflowExecutionCount(TypedDict, total=False): count: Count - truncated: Optional[Truncated] + truncated: Truncated | None class WorkflowExecutionOpenCounts(TypedDict, total=False): @@ -1407,52 +1399,52 @@ class WorkflowExecutionOpenCounts(TypedDict, total=False): openDecisionTasks: OpenDecisionTasksCount openTimers: Count openChildWorkflowExecutions: Count - openLambdaFunctions: Optional[Count] + openLambdaFunctions: Count | None class WorkflowExecutionInfo(TypedDict, total=False): execution: WorkflowExecution workflowType: WorkflowType startTimestamp: Timestamp - closeTimestamp: Optional[Timestamp] + closeTimestamp: Timestamp | None executionStatus: ExecutionStatus - closeStatus: Optional[CloseStatus] - parent: Optional[WorkflowExecution] - tagList: Optional[TagList] - cancelRequested: Optional[Canceled] + closeStatus: CloseStatus | None + parent: WorkflowExecution | None + tagList: TagList | None + cancelRequested: Canceled | None class WorkflowExecutionDetail(TypedDict, total=False): executionInfo: WorkflowExecutionInfo executionConfiguration: WorkflowExecutionConfiguration openCounts: WorkflowExecutionOpenCounts - latestActivityTaskTimestamp: Optional[Timestamp] - latestExecutionContext: Optional[Data] + latestActivityTaskTimestamp: Timestamp | None + latestExecutionContext: Data | None -WorkflowExecutionInfoList = List[WorkflowExecutionInfo] +WorkflowExecutionInfoList = list[WorkflowExecutionInfo] class WorkflowExecutionInfos(TypedDict, total=False): executionInfos: WorkflowExecutionInfoList - nextPageToken: Optional[PageToken] + nextPageToken: PageToken | None class WorkflowTypeConfiguration(TypedDict, total=False): - defaultTaskStartToCloseTimeout: Optional[DurationInSecondsOptional] - defaultExecutionStartToCloseTimeout: Optional[DurationInSecondsOptional] - defaultTaskList: Optional[TaskList] - defaultTaskPriority: Optional[TaskPriority] - defaultChildPolicy: Optional[ChildPolicy] - defaultLambdaRole: Optional[Arn] + defaultTaskStartToCloseTimeout: DurationInSecondsOptional | None + defaultExecutionStartToCloseTimeout: DurationInSecondsOptional | None + defaultTaskList: TaskList | None + defaultTaskPriority: TaskPriority | None + defaultChildPolicy: ChildPolicy | None + defaultLambdaRole: Arn | None class WorkflowTypeInfo(TypedDict, total=False): workflowType: WorkflowType status: RegistrationStatus - description: Optional[Description] + description: Description | None creationDate: Timestamp - deprecationDate: Optional[Timestamp] + deprecationDate: Timestamp | None class WorkflowTypeDetail(TypedDict, total=False): @@ -1460,17 +1452,17 @@ class WorkflowTypeDetail(TypedDict, total=False): configuration: WorkflowTypeConfiguration -WorkflowTypeInfoList = List[WorkflowTypeInfo] +WorkflowTypeInfoList = list[WorkflowTypeInfo] class WorkflowTypeInfos(TypedDict, total=False): typeInfos: WorkflowTypeInfoList - nextPageToken: Optional[PageToken] + nextPageToken: PageToken | None class SwfApi: - service = "swf" - version = "2012-01-25" + service: str = "swf" + version: str = "2012-01-25" @handler("CountClosedWorkflowExecutions") def count_closed_workflow_executions( diff --git a/localstack-core/localstack/aws/api/transcribe/__init__.py b/localstack-core/localstack/aws/api/transcribe/__init__.py index 7592ae32518d1..00923bfceb551 100644 --- a/localstack-core/localstack/aws/api/transcribe/__init__.py +++ b/localstack-core/localstack/aws/api/transcribe/__init__.py @@ -1,6 +1,6 @@ from datetime import datetime from enum import StrEnum -from typing import Dict, List, Optional, TypedDict +from typing import TypedDict from localstack.aws.api import RequestContext, ServiceException, ServiceRequest, handler @@ -351,10 +351,10 @@ class NotFoundException(ServiceException): class AbsoluteTimeRange(TypedDict, total=False): - StartTime: Optional[TimestampMilliseconds] - EndTime: Optional[TimestampMilliseconds] - First: Optional[TimestampMilliseconds] - Last: Optional[TimestampMilliseconds] + StartTime: TimestampMilliseconds | None + EndTime: TimestampMilliseconds | None + First: TimestampMilliseconds | None + Last: TimestampMilliseconds | None class Tag(TypedDict, total=False): @@ -362,15 +362,15 @@ class Tag(TypedDict, total=False): Value: TagValue -TagList = List[Tag] +TagList = list[Tag] class ChannelDefinition(TypedDict, total=False): - ChannelId: Optional[ChannelId] - ParticipantRole: Optional[ParticipantRole] + ChannelId: ChannelId | None + ParticipantRole: ParticipantRole | None -ChannelDefinitions = List[ChannelDefinition] +ChannelDefinitions = list[ChannelDefinition] class Summarization(TypedDict, total=False): @@ -378,178 +378,178 @@ class Summarization(TypedDict, total=False): class LanguageIdSettings(TypedDict, total=False): - VocabularyName: Optional[VocabularyName] - VocabularyFilterName: Optional[VocabularyFilterName] - LanguageModelName: Optional[ModelName] + VocabularyName: VocabularyName | None + VocabularyFilterName: VocabularyFilterName | None + LanguageModelName: ModelName | None -LanguageIdSettingsMap = Dict[LanguageCode, LanguageIdSettings] -LanguageOptions = List[LanguageCode] -PiiEntityTypes = List[PiiEntityType] +LanguageIdSettingsMap = dict[LanguageCode, LanguageIdSettings] +LanguageOptions = list[LanguageCode] +PiiEntityTypes = list[PiiEntityType] class ContentRedaction(TypedDict, total=False): RedactionType: RedactionType RedactionOutput: RedactionOutput - PiiEntityTypes: Optional[PiiEntityTypes] + PiiEntityTypes: PiiEntityTypes | None class CallAnalyticsJobSettings(TypedDict, total=False): - VocabularyName: Optional[VocabularyName] - VocabularyFilterName: Optional[VocabularyFilterName] - VocabularyFilterMethod: Optional[VocabularyFilterMethod] - LanguageModelName: Optional[ModelName] - ContentRedaction: Optional[ContentRedaction] - LanguageOptions: Optional[LanguageOptions] - LanguageIdSettings: Optional[LanguageIdSettingsMap] - Summarization: Optional[Summarization] + VocabularyName: VocabularyName | None + VocabularyFilterName: VocabularyFilterName | None + VocabularyFilterMethod: VocabularyFilterMethod | None + LanguageModelName: ModelName | None + ContentRedaction: ContentRedaction | None + LanguageOptions: LanguageOptions | None + LanguageIdSettings: LanguageIdSettingsMap | None + Summarization: Summarization | None DateTime = datetime class Transcript(TypedDict, total=False): - TranscriptFileUri: Optional[Uri] - RedactedTranscriptFileUri: Optional[Uri] + TranscriptFileUri: Uri | None + RedactedTranscriptFileUri: Uri | None class Media(TypedDict, total=False): - MediaFileUri: Optional[Uri] - RedactedMediaFileUri: Optional[Uri] + MediaFileUri: Uri | None + RedactedMediaFileUri: Uri | None class CallAnalyticsSkippedFeature(TypedDict, total=False): - Feature: Optional[CallAnalyticsFeature] - ReasonCode: Optional[CallAnalyticsSkippedReasonCode] - Message: Optional[String] + Feature: CallAnalyticsFeature | None + ReasonCode: CallAnalyticsSkippedReasonCode | None + Message: String | None -CallAnalyticsSkippedFeatureList = List[CallAnalyticsSkippedFeature] +CallAnalyticsSkippedFeatureList = list[CallAnalyticsSkippedFeature] class CallAnalyticsJobDetails(TypedDict, total=False): - Skipped: Optional[CallAnalyticsSkippedFeatureList] + Skipped: CallAnalyticsSkippedFeatureList | None class CallAnalyticsJob(TypedDict, total=False): - CallAnalyticsJobName: Optional[CallAnalyticsJobName] - CallAnalyticsJobStatus: Optional[CallAnalyticsJobStatus] - CallAnalyticsJobDetails: Optional[CallAnalyticsJobDetails] - LanguageCode: Optional[LanguageCode] - MediaSampleRateHertz: Optional[MediaSampleRateHertz] - MediaFormat: Optional[MediaFormat] - Media: Optional[Media] - Transcript: Optional[Transcript] - StartTime: Optional[DateTime] - CreationTime: Optional[DateTime] - CompletionTime: Optional[DateTime] - FailureReason: Optional[FailureReason] - DataAccessRoleArn: Optional[DataAccessRoleArn] - IdentifiedLanguageScore: Optional[IdentifiedLanguageScore] - Settings: Optional[CallAnalyticsJobSettings] - ChannelDefinitions: Optional[ChannelDefinitions] - Tags: Optional[TagList] + CallAnalyticsJobName: CallAnalyticsJobName | None + CallAnalyticsJobStatus: CallAnalyticsJobStatus | None + CallAnalyticsJobDetails: CallAnalyticsJobDetails | None + LanguageCode: LanguageCode | None + MediaSampleRateHertz: MediaSampleRateHertz | None + MediaFormat: MediaFormat | None + Media: Media | None + Transcript: Transcript | None + StartTime: DateTime | None + CreationTime: DateTime | None + CompletionTime: DateTime | None + FailureReason: FailureReason | None + DataAccessRoleArn: DataAccessRoleArn | None + IdentifiedLanguageScore: IdentifiedLanguageScore | None + Settings: CallAnalyticsJobSettings | None + ChannelDefinitions: ChannelDefinitions | None + Tags: TagList | None class CallAnalyticsJobSummary(TypedDict, total=False): - CallAnalyticsJobName: Optional[CallAnalyticsJobName] - CreationTime: Optional[DateTime] - StartTime: Optional[DateTime] - CompletionTime: Optional[DateTime] - LanguageCode: Optional[LanguageCode] - CallAnalyticsJobStatus: Optional[CallAnalyticsJobStatus] - CallAnalyticsJobDetails: Optional[CallAnalyticsJobDetails] - FailureReason: Optional[FailureReason] + CallAnalyticsJobName: CallAnalyticsJobName | None + CreationTime: DateTime | None + StartTime: DateTime | None + CompletionTime: DateTime | None + LanguageCode: LanguageCode | None + CallAnalyticsJobStatus: CallAnalyticsJobStatus | None + CallAnalyticsJobDetails: CallAnalyticsJobDetails | None + FailureReason: FailureReason | None -CallAnalyticsJobSummaries = List[CallAnalyticsJobSummary] +CallAnalyticsJobSummaries = list[CallAnalyticsJobSummary] class RelativeTimeRange(TypedDict, total=False): - StartPercentage: Optional[Percentage] - EndPercentage: Optional[Percentage] - First: Optional[Percentage] - Last: Optional[Percentage] + StartPercentage: Percentage | None + EndPercentage: Percentage | None + First: Percentage | None + Last: Percentage | None -SentimentValueList = List[SentimentValue] +SentimentValueList = list[SentimentValue] class SentimentFilter(TypedDict, total=False): Sentiments: SentimentValueList - AbsoluteTimeRange: Optional[AbsoluteTimeRange] - RelativeTimeRange: Optional[RelativeTimeRange] - ParticipantRole: Optional[ParticipantRole] - Negate: Optional[Boolean] + AbsoluteTimeRange: AbsoluteTimeRange | None + RelativeTimeRange: RelativeTimeRange | None + ParticipantRole: ParticipantRole | None + Negate: Boolean | None -StringTargetList = List[NonEmptyString] +StringTargetList = list[NonEmptyString] class TranscriptFilter(TypedDict, total=False): TranscriptFilterType: TranscriptFilterType - AbsoluteTimeRange: Optional[AbsoluteTimeRange] - RelativeTimeRange: Optional[RelativeTimeRange] - ParticipantRole: Optional[ParticipantRole] - Negate: Optional[Boolean] + AbsoluteTimeRange: AbsoluteTimeRange | None + RelativeTimeRange: RelativeTimeRange | None + ParticipantRole: ParticipantRole | None + Negate: Boolean | None Targets: StringTargetList class InterruptionFilter(TypedDict, total=False): - Threshold: Optional[TimestampMilliseconds] - ParticipantRole: Optional[ParticipantRole] - AbsoluteTimeRange: Optional[AbsoluteTimeRange] - RelativeTimeRange: Optional[RelativeTimeRange] - Negate: Optional[Boolean] + Threshold: TimestampMilliseconds | None + ParticipantRole: ParticipantRole | None + AbsoluteTimeRange: AbsoluteTimeRange | None + RelativeTimeRange: RelativeTimeRange | None + Negate: Boolean | None class NonTalkTimeFilter(TypedDict, total=False): - Threshold: Optional[TimestampMilliseconds] - AbsoluteTimeRange: Optional[AbsoluteTimeRange] - RelativeTimeRange: Optional[RelativeTimeRange] - Negate: Optional[Boolean] + Threshold: TimestampMilliseconds | None + AbsoluteTimeRange: AbsoluteTimeRange | None + RelativeTimeRange: RelativeTimeRange | None + Negate: Boolean | None class Rule(TypedDict, total=False): - NonTalkTimeFilter: Optional[NonTalkTimeFilter] - InterruptionFilter: Optional[InterruptionFilter] - TranscriptFilter: Optional[TranscriptFilter] - SentimentFilter: Optional[SentimentFilter] + NonTalkTimeFilter: NonTalkTimeFilter | None + InterruptionFilter: InterruptionFilter | None + TranscriptFilter: TranscriptFilter | None + SentimentFilter: SentimentFilter | None -RuleList = List[Rule] +RuleList = list[Rule] class CategoryProperties(TypedDict, total=False): - CategoryName: Optional[CategoryName] - Rules: Optional[RuleList] - CreateTime: Optional[DateTime] - LastUpdateTime: Optional[DateTime] - Tags: Optional[TagList] - InputType: Optional[InputType] + CategoryName: CategoryName | None + Rules: RuleList | None + CreateTime: DateTime | None + LastUpdateTime: DateTime | None + Tags: TagList | None + InputType: InputType | None -CategoryPropertiesList = List[CategoryProperties] +CategoryPropertiesList = list[CategoryProperties] class ClinicalNoteGenerationSettings(TypedDict, total=False): - NoteTemplate: Optional[MedicalScribeNoteTemplate] + NoteTemplate: MedicalScribeNoteTemplate | None class CreateCallAnalyticsCategoryRequest(ServiceRequest): CategoryName: CategoryName Rules: RuleList - Tags: Optional[TagList] - InputType: Optional[InputType] + Tags: TagList | None + InputType: InputType | None class CreateCallAnalyticsCategoryResponse(TypedDict, total=False): - CategoryProperties: Optional[CategoryProperties] + CategoryProperties: CategoryProperties | None class InputDataConfig(TypedDict, total=False): S3Uri: Uri - TuningDataS3Uri: Optional[Uri] + TuningDataS3Uri: Uri | None DataAccessRoleArn: DataAccessRoleArn @@ -558,68 +558,68 @@ class CreateLanguageModelRequest(ServiceRequest): BaseModelName: BaseModelName ModelName: ModelName InputDataConfig: InputDataConfig - Tags: Optional[TagList] + Tags: TagList | None class CreateLanguageModelResponse(TypedDict, total=False): - LanguageCode: Optional[CLMLanguageCode] - BaseModelName: Optional[BaseModelName] - ModelName: Optional[ModelName] - InputDataConfig: Optional[InputDataConfig] - ModelStatus: Optional[ModelStatus] + LanguageCode: CLMLanguageCode | None + BaseModelName: BaseModelName | None + ModelName: ModelName | None + InputDataConfig: InputDataConfig | None + ModelStatus: ModelStatus | None class CreateMedicalVocabularyRequest(ServiceRequest): VocabularyName: VocabularyName LanguageCode: LanguageCode VocabularyFileUri: Uri - Tags: Optional[TagList] + Tags: TagList | None class CreateMedicalVocabularyResponse(TypedDict, total=False): - VocabularyName: Optional[VocabularyName] - LanguageCode: Optional[LanguageCode] - VocabularyState: Optional[VocabularyState] - LastModifiedTime: Optional[DateTime] - FailureReason: Optional[FailureReason] + VocabularyName: VocabularyName | None + LanguageCode: LanguageCode | None + VocabularyState: VocabularyState | None + LastModifiedTime: DateTime | None + FailureReason: FailureReason | None -Words = List[Word] +Words = list[Word] class CreateVocabularyFilterRequest(ServiceRequest): VocabularyFilterName: VocabularyFilterName LanguageCode: LanguageCode - Words: Optional[Words] - VocabularyFilterFileUri: Optional[Uri] - Tags: Optional[TagList] - DataAccessRoleArn: Optional[DataAccessRoleArn] + Words: Words | None + VocabularyFilterFileUri: Uri | None + Tags: TagList | None + DataAccessRoleArn: DataAccessRoleArn | None class CreateVocabularyFilterResponse(TypedDict, total=False): - VocabularyFilterName: Optional[VocabularyFilterName] - LanguageCode: Optional[LanguageCode] - LastModifiedTime: Optional[DateTime] + VocabularyFilterName: VocabularyFilterName | None + LanguageCode: LanguageCode | None + LastModifiedTime: DateTime | None -Phrases = List[Phrase] +Phrases = list[Phrase] class CreateVocabularyRequest(ServiceRequest): VocabularyName: VocabularyName LanguageCode: LanguageCode - Phrases: Optional[Phrases] - VocabularyFileUri: Optional[Uri] - Tags: Optional[TagList] - DataAccessRoleArn: Optional[DataAccessRoleArn] + Phrases: Phrases | None + VocabularyFileUri: Uri | None + Tags: TagList | None + DataAccessRoleArn: DataAccessRoleArn | None class CreateVocabularyResponse(TypedDict, total=False): - VocabularyName: Optional[VocabularyName] - LanguageCode: Optional[LanguageCode] - VocabularyState: Optional[VocabularyState] - LastModifiedTime: Optional[DateTime] - FailureReason: Optional[FailureReason] + VocabularyName: VocabularyName | None + LanguageCode: LanguageCode | None + VocabularyState: VocabularyState | None + LastModifiedTime: DateTime | None + FailureReason: FailureReason | None class DeleteCallAnalyticsCategoryRequest(ServiceRequest): @@ -671,19 +671,19 @@ class DescribeLanguageModelRequest(ServiceRequest): class LanguageModel(TypedDict, total=False): - ModelName: Optional[ModelName] - CreateTime: Optional[DateTime] - LastModifiedTime: Optional[DateTime] - LanguageCode: Optional[CLMLanguageCode] - BaseModelName: Optional[BaseModelName] - ModelStatus: Optional[ModelStatus] - UpgradeAvailability: Optional[Boolean] - FailureReason: Optional[FailureReason] - InputDataConfig: Optional[InputDataConfig] + ModelName: ModelName | None + CreateTime: DateTime | None + LastModifiedTime: DateTime | None + LanguageCode: CLMLanguageCode | None + BaseModelName: BaseModelName | None + ModelStatus: ModelStatus | None + UpgradeAvailability: Boolean | None + FailureReason: FailureReason | None + InputDataConfig: InputDataConfig | None class DescribeLanguageModelResponse(TypedDict, total=False): - LanguageModel: Optional[LanguageModel] + LanguageModel: LanguageModel | None class GetCallAnalyticsCategoryRequest(ServiceRequest): @@ -691,7 +691,7 @@ class GetCallAnalyticsCategoryRequest(ServiceRequest): class GetCallAnalyticsCategoryResponse(TypedDict, total=False): - CategoryProperties: Optional[CategoryProperties] + CategoryProperties: CategoryProperties | None class GetCallAnalyticsJobRequest(ServiceRequest): @@ -699,7 +699,7 @@ class GetCallAnalyticsJobRequest(ServiceRequest): class GetCallAnalyticsJobResponse(TypedDict, total=False): - CallAnalyticsJob: Optional[CallAnalyticsJob] + CallAnalyticsJob: CallAnalyticsJob | None class GetMedicalScribeJobRequest(ServiceRequest): @@ -711,17 +711,17 @@ class MedicalScribeChannelDefinition(TypedDict, total=False): ParticipantRole: MedicalScribeParticipantRole -MedicalScribeChannelDefinitions = List[MedicalScribeChannelDefinition] +MedicalScribeChannelDefinitions = list[MedicalScribeChannelDefinition] class MedicalScribeSettings(TypedDict, total=False): - ShowSpeakerLabels: Optional[Boolean] - MaxSpeakerLabels: Optional[MaxSpeakers] - ChannelIdentification: Optional[Boolean] - VocabularyName: Optional[VocabularyName] - VocabularyFilterName: Optional[VocabularyFilterName] - VocabularyFilterMethod: Optional[VocabularyFilterMethod] - ClinicalNoteGenerationSettings: Optional[ClinicalNoteGenerationSettings] + ShowSpeakerLabels: Boolean | None + MaxSpeakerLabels: MaxSpeakers | None + ChannelIdentification: Boolean | None + VocabularyName: VocabularyName | None + VocabularyFilterName: VocabularyFilterName | None + VocabularyFilterMethod: VocabularyFilterMethod | None + ClinicalNoteGenerationSettings: ClinicalNoteGenerationSettings | None class MedicalScribeOutput(TypedDict, total=False): @@ -730,24 +730,24 @@ class MedicalScribeOutput(TypedDict, total=False): class MedicalScribeJob(TypedDict, total=False): - MedicalScribeJobName: Optional[TranscriptionJobName] - MedicalScribeJobStatus: Optional[MedicalScribeJobStatus] - LanguageCode: Optional[MedicalScribeLanguageCode] - Media: Optional[Media] - MedicalScribeOutput: Optional[MedicalScribeOutput] - StartTime: Optional[DateTime] - CreationTime: Optional[DateTime] - CompletionTime: Optional[DateTime] - FailureReason: Optional[FailureReason] - Settings: Optional[MedicalScribeSettings] - DataAccessRoleArn: Optional[DataAccessRoleArn] - ChannelDefinitions: Optional[MedicalScribeChannelDefinitions] - MedicalScribeContextProvided: Optional[Boolean] - Tags: Optional[TagList] + MedicalScribeJobName: TranscriptionJobName | None + MedicalScribeJobStatus: MedicalScribeJobStatus | None + LanguageCode: MedicalScribeLanguageCode | None + Media: Media | None + MedicalScribeOutput: MedicalScribeOutput | None + StartTime: DateTime | None + CreationTime: DateTime | None + CompletionTime: DateTime | None + FailureReason: FailureReason | None + Settings: MedicalScribeSettings | None + DataAccessRoleArn: DataAccessRoleArn | None + ChannelDefinitions: MedicalScribeChannelDefinitions | None + MedicalScribeContextProvided: Boolean | None + Tags: TagList | None class GetMedicalScribeJobResponse(TypedDict, total=False): - MedicalScribeJob: Optional[MedicalScribeJob] + MedicalScribeJob: MedicalScribeJob | None class GetMedicalTranscriptionJobRequest(ServiceRequest): @@ -755,39 +755,39 @@ class GetMedicalTranscriptionJobRequest(ServiceRequest): class MedicalTranscriptionSetting(TypedDict, total=False): - ShowSpeakerLabels: Optional[Boolean] - MaxSpeakerLabels: Optional[MaxSpeakers] - ChannelIdentification: Optional[Boolean] - ShowAlternatives: Optional[Boolean] - MaxAlternatives: Optional[MaxAlternatives] - VocabularyName: Optional[VocabularyName] + ShowSpeakerLabels: Boolean | None + MaxSpeakerLabels: MaxSpeakers | None + ChannelIdentification: Boolean | None + ShowAlternatives: Boolean | None + MaxAlternatives: MaxAlternatives | None + VocabularyName: VocabularyName | None class MedicalTranscript(TypedDict, total=False): - TranscriptFileUri: Optional[Uri] + TranscriptFileUri: Uri | None class MedicalTranscriptionJob(TypedDict, total=False): - MedicalTranscriptionJobName: Optional[TranscriptionJobName] - TranscriptionJobStatus: Optional[TranscriptionJobStatus] - LanguageCode: Optional[LanguageCode] - MediaSampleRateHertz: Optional[MedicalMediaSampleRateHertz] - MediaFormat: Optional[MediaFormat] - Media: Optional[Media] - Transcript: Optional[MedicalTranscript] - StartTime: Optional[DateTime] - CreationTime: Optional[DateTime] - CompletionTime: Optional[DateTime] - FailureReason: Optional[FailureReason] - Settings: Optional[MedicalTranscriptionSetting] - ContentIdentificationType: Optional[MedicalContentIdentificationType] - Specialty: Optional[Specialty] - Type: Optional[Type] - Tags: Optional[TagList] + MedicalTranscriptionJobName: TranscriptionJobName | None + TranscriptionJobStatus: TranscriptionJobStatus | None + LanguageCode: LanguageCode | None + MediaSampleRateHertz: MedicalMediaSampleRateHertz | None + MediaFormat: MediaFormat | None + Media: Media | None + Transcript: MedicalTranscript | None + StartTime: DateTime | None + CreationTime: DateTime | None + CompletionTime: DateTime | None + FailureReason: FailureReason | None + Settings: MedicalTranscriptionSetting | None + ContentIdentificationType: MedicalContentIdentificationType | None + Specialty: Specialty | None + Type: Type | None + Tags: TagList | None class GetMedicalTranscriptionJobResponse(TypedDict, total=False): - MedicalTranscriptionJob: Optional[MedicalTranscriptionJob] + MedicalTranscriptionJob: MedicalTranscriptionJob | None class GetMedicalVocabularyRequest(ServiceRequest): @@ -795,93 +795,93 @@ class GetMedicalVocabularyRequest(ServiceRequest): class GetMedicalVocabularyResponse(TypedDict, total=False): - VocabularyName: Optional[VocabularyName] - LanguageCode: Optional[LanguageCode] - VocabularyState: Optional[VocabularyState] - LastModifiedTime: Optional[DateTime] - FailureReason: Optional[FailureReason] - DownloadUri: Optional[Uri] + VocabularyName: VocabularyName | None + LanguageCode: LanguageCode | None + VocabularyState: VocabularyState | None + LastModifiedTime: DateTime | None + FailureReason: FailureReason | None + DownloadUri: Uri | None class GetTranscriptionJobRequest(ServiceRequest): TranscriptionJobName: TranscriptionJobName -ToxicityCategories = List[ToxicityCategory] +ToxicityCategories = list[ToxicityCategory] class ToxicityDetectionSettings(TypedDict, total=False): ToxicityCategories: ToxicityCategories -ToxicityDetection = List[ToxicityDetectionSettings] -SubtitleFileUris = List[Uri] -SubtitleFormats = List[SubtitleFormat] +ToxicityDetection = list[ToxicityDetectionSettings] +SubtitleFileUris = list[Uri] +SubtitleFormats = list[SubtitleFormat] class SubtitlesOutput(TypedDict, total=False): - Formats: Optional[SubtitleFormats] - SubtitleFileUris: Optional[SubtitleFileUris] - OutputStartIndex: Optional[SubtitleOutputStartIndex] + Formats: SubtitleFormats | None + SubtitleFileUris: SubtitleFileUris | None + OutputStartIndex: SubtitleOutputStartIndex | None class LanguageCodeItem(TypedDict, total=False): - LanguageCode: Optional[LanguageCode] - DurationInSeconds: Optional[DurationInSeconds] + LanguageCode: LanguageCode | None + DurationInSeconds: DurationInSeconds | None -LanguageCodeList = List[LanguageCodeItem] +LanguageCodeList = list[LanguageCodeItem] class JobExecutionSettings(TypedDict, total=False): - AllowDeferredExecution: Optional[Boolean] - DataAccessRoleArn: Optional[DataAccessRoleArn] + AllowDeferredExecution: Boolean | None + DataAccessRoleArn: DataAccessRoleArn | None class ModelSettings(TypedDict, total=False): - LanguageModelName: Optional[ModelName] + LanguageModelName: ModelName | None class Settings(TypedDict, total=False): - VocabularyName: Optional[VocabularyName] - ShowSpeakerLabels: Optional[Boolean] - MaxSpeakerLabels: Optional[MaxSpeakers] - ChannelIdentification: Optional[Boolean] - ShowAlternatives: Optional[Boolean] - MaxAlternatives: Optional[MaxAlternatives] - VocabularyFilterName: Optional[VocabularyFilterName] - VocabularyFilterMethod: Optional[VocabularyFilterMethod] + VocabularyName: VocabularyName | None + ShowSpeakerLabels: Boolean | None + MaxSpeakerLabels: MaxSpeakers | None + ChannelIdentification: Boolean | None + ShowAlternatives: Boolean | None + MaxAlternatives: MaxAlternatives | None + VocabularyFilterName: VocabularyFilterName | None + VocabularyFilterMethod: VocabularyFilterMethod | None class TranscriptionJob(TypedDict, total=False): - TranscriptionJobName: Optional[TranscriptionJobName] - TranscriptionJobStatus: Optional[TranscriptionJobStatus] - LanguageCode: Optional[LanguageCode] - MediaSampleRateHertz: Optional[MediaSampleRateHertz] - MediaFormat: Optional[MediaFormat] - Media: Optional[Media] - Transcript: Optional[Transcript] - StartTime: Optional[DateTime] - CreationTime: Optional[DateTime] - CompletionTime: Optional[DateTime] - FailureReason: Optional[FailureReason] - Settings: Optional[Settings] - ModelSettings: Optional[ModelSettings] - JobExecutionSettings: Optional[JobExecutionSettings] - ContentRedaction: Optional[ContentRedaction] - IdentifyLanguage: Optional[Boolean] - IdentifyMultipleLanguages: Optional[Boolean] - LanguageOptions: Optional[LanguageOptions] - IdentifiedLanguageScore: Optional[IdentifiedLanguageScore] - LanguageCodes: Optional[LanguageCodeList] - Tags: Optional[TagList] - Subtitles: Optional[SubtitlesOutput] - LanguageIdSettings: Optional[LanguageIdSettingsMap] - ToxicityDetection: Optional[ToxicityDetection] + TranscriptionJobName: TranscriptionJobName | None + TranscriptionJobStatus: TranscriptionJobStatus | None + LanguageCode: LanguageCode | None + MediaSampleRateHertz: MediaSampleRateHertz | None + MediaFormat: MediaFormat | None + Media: Media | None + Transcript: Transcript | None + StartTime: DateTime | None + CreationTime: DateTime | None + CompletionTime: DateTime | None + FailureReason: FailureReason | None + Settings: Settings | None + ModelSettings: ModelSettings | None + JobExecutionSettings: JobExecutionSettings | None + ContentRedaction: ContentRedaction | None + IdentifyLanguage: Boolean | None + IdentifyMultipleLanguages: Boolean | None + LanguageOptions: LanguageOptions | None + IdentifiedLanguageScore: IdentifiedLanguageScore | None + LanguageCodes: LanguageCodeList | None + Tags: TagList | None + Subtitles: SubtitlesOutput | None + LanguageIdSettings: LanguageIdSettingsMap | None + ToxicityDetection: ToxicityDetection | None class GetTranscriptionJobResponse(TypedDict, total=False): - TranscriptionJob: Optional[TranscriptionJob] + TranscriptionJob: TranscriptionJob | None class GetVocabularyFilterRequest(ServiceRequest): @@ -889,10 +889,10 @@ class GetVocabularyFilterRequest(ServiceRequest): class GetVocabularyFilterResponse(TypedDict, total=False): - VocabularyFilterName: Optional[VocabularyFilterName] - LanguageCode: Optional[LanguageCode] - LastModifiedTime: Optional[DateTime] - DownloadUri: Optional[Uri] + VocabularyFilterName: VocabularyFilterName | None + LanguageCode: LanguageCode | None + LastModifiedTime: DateTime | None + DownloadUri: Uri | None class GetVocabularyRequest(ServiceRequest): @@ -900,132 +900,132 @@ class GetVocabularyRequest(ServiceRequest): class GetVocabularyResponse(TypedDict, total=False): - VocabularyName: Optional[VocabularyName] - LanguageCode: Optional[LanguageCode] - VocabularyState: Optional[VocabularyState] - LastModifiedTime: Optional[DateTime] - FailureReason: Optional[FailureReason] - DownloadUri: Optional[Uri] + VocabularyName: VocabularyName | None + LanguageCode: LanguageCode | None + VocabularyState: VocabularyState | None + LastModifiedTime: DateTime | None + FailureReason: FailureReason | None + DownloadUri: Uri | None -KMSEncryptionContextMap = Dict[NonEmptyString, NonEmptyString] +KMSEncryptionContextMap = dict[NonEmptyString, NonEmptyString] class ListCallAnalyticsCategoriesRequest(ServiceRequest): - NextToken: Optional[NextToken] - MaxResults: Optional[MaxResults] + NextToken: NextToken | None + MaxResults: MaxResults | None class ListCallAnalyticsCategoriesResponse(TypedDict, total=False): - NextToken: Optional[NextToken] - Categories: Optional[CategoryPropertiesList] + NextToken: NextToken | None + Categories: CategoryPropertiesList | None class ListCallAnalyticsJobsRequest(ServiceRequest): - Status: Optional[CallAnalyticsJobStatus] - JobNameContains: Optional[CallAnalyticsJobName] - NextToken: Optional[NextToken] - MaxResults: Optional[MaxResults] + Status: CallAnalyticsJobStatus | None + JobNameContains: CallAnalyticsJobName | None + NextToken: NextToken | None + MaxResults: MaxResults | None class ListCallAnalyticsJobsResponse(TypedDict, total=False): - Status: Optional[CallAnalyticsJobStatus] - NextToken: Optional[NextToken] - CallAnalyticsJobSummaries: Optional[CallAnalyticsJobSummaries] + Status: CallAnalyticsJobStatus | None + NextToken: NextToken | None + CallAnalyticsJobSummaries: CallAnalyticsJobSummaries | None class ListLanguageModelsRequest(ServiceRequest): - StatusEquals: Optional[ModelStatus] - NameContains: Optional[ModelName] - NextToken: Optional[NextToken] - MaxResults: Optional[MaxResults] + StatusEquals: ModelStatus | None + NameContains: ModelName | None + NextToken: NextToken | None + MaxResults: MaxResults | None -Models = List[LanguageModel] +Models = list[LanguageModel] class ListLanguageModelsResponse(TypedDict, total=False): - NextToken: Optional[NextToken] - Models: Optional[Models] + NextToken: NextToken | None + Models: Models | None class ListMedicalScribeJobsRequest(ServiceRequest): - Status: Optional[MedicalScribeJobStatus] - JobNameContains: Optional[TranscriptionJobName] - NextToken: Optional[NextToken] - MaxResults: Optional[MaxResults] + Status: MedicalScribeJobStatus | None + JobNameContains: TranscriptionJobName | None + NextToken: NextToken | None + MaxResults: MaxResults | None class MedicalScribeJobSummary(TypedDict, total=False): - MedicalScribeJobName: Optional[TranscriptionJobName] - CreationTime: Optional[DateTime] - StartTime: Optional[DateTime] - CompletionTime: Optional[DateTime] - LanguageCode: Optional[MedicalScribeLanguageCode] - MedicalScribeJobStatus: Optional[MedicalScribeJobStatus] - FailureReason: Optional[FailureReason] + MedicalScribeJobName: TranscriptionJobName | None + CreationTime: DateTime | None + StartTime: DateTime | None + CompletionTime: DateTime | None + LanguageCode: MedicalScribeLanguageCode | None + MedicalScribeJobStatus: MedicalScribeJobStatus | None + FailureReason: FailureReason | None -MedicalScribeJobSummaries = List[MedicalScribeJobSummary] +MedicalScribeJobSummaries = list[MedicalScribeJobSummary] class ListMedicalScribeJobsResponse(TypedDict, total=False): - Status: Optional[MedicalScribeJobStatus] - NextToken: Optional[NextToken] - MedicalScribeJobSummaries: Optional[MedicalScribeJobSummaries] + Status: MedicalScribeJobStatus | None + NextToken: NextToken | None + MedicalScribeJobSummaries: MedicalScribeJobSummaries | None class ListMedicalTranscriptionJobsRequest(ServiceRequest): - Status: Optional[TranscriptionJobStatus] - JobNameContains: Optional[TranscriptionJobName] - NextToken: Optional[NextToken] - MaxResults: Optional[MaxResults] + Status: TranscriptionJobStatus | None + JobNameContains: TranscriptionJobName | None + NextToken: NextToken | None + MaxResults: MaxResults | None class MedicalTranscriptionJobSummary(TypedDict, total=False): - MedicalTranscriptionJobName: Optional[TranscriptionJobName] - CreationTime: Optional[DateTime] - StartTime: Optional[DateTime] - CompletionTime: Optional[DateTime] - LanguageCode: Optional[LanguageCode] - TranscriptionJobStatus: Optional[TranscriptionJobStatus] - FailureReason: Optional[FailureReason] - OutputLocationType: Optional[OutputLocationType] - Specialty: Optional[Specialty] - ContentIdentificationType: Optional[MedicalContentIdentificationType] - Type: Optional[Type] + MedicalTranscriptionJobName: TranscriptionJobName | None + CreationTime: DateTime | None + StartTime: DateTime | None + CompletionTime: DateTime | None + LanguageCode: LanguageCode | None + TranscriptionJobStatus: TranscriptionJobStatus | None + FailureReason: FailureReason | None + OutputLocationType: OutputLocationType | None + Specialty: Specialty | None + ContentIdentificationType: MedicalContentIdentificationType | None + Type: Type | None -MedicalTranscriptionJobSummaries = List[MedicalTranscriptionJobSummary] +MedicalTranscriptionJobSummaries = list[MedicalTranscriptionJobSummary] class ListMedicalTranscriptionJobsResponse(TypedDict, total=False): - Status: Optional[TranscriptionJobStatus] - NextToken: Optional[NextToken] - MedicalTranscriptionJobSummaries: Optional[MedicalTranscriptionJobSummaries] + Status: TranscriptionJobStatus | None + NextToken: NextToken | None + MedicalTranscriptionJobSummaries: MedicalTranscriptionJobSummaries | None class ListMedicalVocabulariesRequest(ServiceRequest): - NextToken: Optional[NextToken] - MaxResults: Optional[MaxResults] - StateEquals: Optional[VocabularyState] - NameContains: Optional[VocabularyName] + NextToken: NextToken | None + MaxResults: MaxResults | None + StateEquals: VocabularyState | None + NameContains: VocabularyName | None class VocabularyInfo(TypedDict, total=False): - VocabularyName: Optional[VocabularyName] - LanguageCode: Optional[LanguageCode] - LastModifiedTime: Optional[DateTime] - VocabularyState: Optional[VocabularyState] + VocabularyName: VocabularyName | None + LanguageCode: LanguageCode | None + LastModifiedTime: DateTime | None + VocabularyState: VocabularyState | None -Vocabularies = List[VocabularyInfo] +Vocabularies = list[VocabularyInfo] class ListMedicalVocabulariesResponse(TypedDict, total=False): - Status: Optional[VocabularyState] - NextToken: Optional[NextToken] - Vocabularies: Optional[Vocabularies] + Status: VocabularyState | None + NextToken: NextToken | None + Vocabularies: Vocabularies | None class ListTagsForResourceRequest(ServiceRequest): @@ -1033,171 +1033,171 @@ class ListTagsForResourceRequest(ServiceRequest): class ListTagsForResourceResponse(TypedDict, total=False): - ResourceArn: Optional[TranscribeArn] - Tags: Optional[TagList] + ResourceArn: TranscribeArn | None + Tags: TagList | None class ListTranscriptionJobsRequest(ServiceRequest): - Status: Optional[TranscriptionJobStatus] - JobNameContains: Optional[TranscriptionJobName] - NextToken: Optional[NextToken] - MaxResults: Optional[MaxResults] + Status: TranscriptionJobStatus | None + JobNameContains: TranscriptionJobName | None + NextToken: NextToken | None + MaxResults: MaxResults | None class TranscriptionJobSummary(TypedDict, total=False): - TranscriptionJobName: Optional[TranscriptionJobName] - CreationTime: Optional[DateTime] - StartTime: Optional[DateTime] - CompletionTime: Optional[DateTime] - LanguageCode: Optional[LanguageCode] - TranscriptionJobStatus: Optional[TranscriptionJobStatus] - FailureReason: Optional[FailureReason] - OutputLocationType: Optional[OutputLocationType] - ContentRedaction: Optional[ContentRedaction] - ModelSettings: Optional[ModelSettings] - IdentifyLanguage: Optional[Boolean] - IdentifyMultipleLanguages: Optional[Boolean] - IdentifiedLanguageScore: Optional[IdentifiedLanguageScore] - LanguageCodes: Optional[LanguageCodeList] - ToxicityDetection: Optional[ToxicityDetection] - - -TranscriptionJobSummaries = List[TranscriptionJobSummary] + TranscriptionJobName: TranscriptionJobName | None + CreationTime: DateTime | None + StartTime: DateTime | None + CompletionTime: DateTime | None + LanguageCode: LanguageCode | None + TranscriptionJobStatus: TranscriptionJobStatus | None + FailureReason: FailureReason | None + OutputLocationType: OutputLocationType | None + ContentRedaction: ContentRedaction | None + ModelSettings: ModelSettings | None + IdentifyLanguage: Boolean | None + IdentifyMultipleLanguages: Boolean | None + IdentifiedLanguageScore: IdentifiedLanguageScore | None + LanguageCodes: LanguageCodeList | None + ToxicityDetection: ToxicityDetection | None + + +TranscriptionJobSummaries = list[TranscriptionJobSummary] class ListTranscriptionJobsResponse(TypedDict, total=False): - Status: Optional[TranscriptionJobStatus] - NextToken: Optional[NextToken] - TranscriptionJobSummaries: Optional[TranscriptionJobSummaries] + Status: TranscriptionJobStatus | None + NextToken: NextToken | None + TranscriptionJobSummaries: TranscriptionJobSummaries | None class ListVocabulariesRequest(ServiceRequest): - NextToken: Optional[NextToken] - MaxResults: Optional[MaxResults] - StateEquals: Optional[VocabularyState] - NameContains: Optional[VocabularyName] + NextToken: NextToken | None + MaxResults: MaxResults | None + StateEquals: VocabularyState | None + NameContains: VocabularyName | None class ListVocabulariesResponse(TypedDict, total=False): - Status: Optional[VocabularyState] - NextToken: Optional[NextToken] - Vocabularies: Optional[Vocabularies] + Status: VocabularyState | None + NextToken: NextToken | None + Vocabularies: Vocabularies | None class ListVocabularyFiltersRequest(ServiceRequest): - NextToken: Optional[NextToken] - MaxResults: Optional[MaxResults] - NameContains: Optional[VocabularyFilterName] + NextToken: NextToken | None + MaxResults: MaxResults | None + NameContains: VocabularyFilterName | None class VocabularyFilterInfo(TypedDict, total=False): - VocabularyFilterName: Optional[VocabularyFilterName] - LanguageCode: Optional[LanguageCode] - LastModifiedTime: Optional[DateTime] + VocabularyFilterName: VocabularyFilterName | None + LanguageCode: LanguageCode | None + LastModifiedTime: DateTime | None -VocabularyFilters = List[VocabularyFilterInfo] +VocabularyFilters = list[VocabularyFilterInfo] class ListVocabularyFiltersResponse(TypedDict, total=False): - NextToken: Optional[NextToken] - VocabularyFilters: Optional[VocabularyFilters] + NextToken: NextToken | None + VocabularyFilters: VocabularyFilters | None class MedicalScribePatientContext(TypedDict, total=False): - Pronouns: Optional[Pronouns] + Pronouns: Pronouns | None class MedicalScribeContext(TypedDict, total=False): - PatientContext: Optional[MedicalScribePatientContext] + PatientContext: MedicalScribePatientContext | None class StartCallAnalyticsJobRequest(ServiceRequest): CallAnalyticsJobName: CallAnalyticsJobName Media: Media - OutputLocation: Optional[Uri] - OutputEncryptionKMSKeyId: Optional[KMSKeyId] - DataAccessRoleArn: Optional[DataAccessRoleArn] - Settings: Optional[CallAnalyticsJobSettings] - Tags: Optional[TagList] - ChannelDefinitions: Optional[ChannelDefinitions] + OutputLocation: Uri | None + OutputEncryptionKMSKeyId: KMSKeyId | None + DataAccessRoleArn: DataAccessRoleArn | None + Settings: CallAnalyticsJobSettings | None + Tags: TagList | None + ChannelDefinitions: ChannelDefinitions | None class StartCallAnalyticsJobResponse(TypedDict, total=False): - CallAnalyticsJob: Optional[CallAnalyticsJob] + CallAnalyticsJob: CallAnalyticsJob | None class StartMedicalScribeJobRequest(ServiceRequest): MedicalScribeJobName: TranscriptionJobName Media: Media OutputBucketName: OutputBucketName - OutputEncryptionKMSKeyId: Optional[KMSKeyId] - KMSEncryptionContext: Optional[KMSEncryptionContextMap] + OutputEncryptionKMSKeyId: KMSKeyId | None + KMSEncryptionContext: KMSEncryptionContextMap | None DataAccessRoleArn: DataAccessRoleArn Settings: MedicalScribeSettings - ChannelDefinitions: Optional[MedicalScribeChannelDefinitions] - Tags: Optional[TagList] - MedicalScribeContext: Optional[MedicalScribeContext] + ChannelDefinitions: MedicalScribeChannelDefinitions | None + Tags: TagList | None + MedicalScribeContext: MedicalScribeContext | None class StartMedicalScribeJobResponse(TypedDict, total=False): - MedicalScribeJob: Optional[MedicalScribeJob] + MedicalScribeJob: MedicalScribeJob | None class StartMedicalTranscriptionJobRequest(ServiceRequest): MedicalTranscriptionJobName: TranscriptionJobName LanguageCode: LanguageCode - MediaSampleRateHertz: Optional[MedicalMediaSampleRateHertz] - MediaFormat: Optional[MediaFormat] + MediaSampleRateHertz: MedicalMediaSampleRateHertz | None + MediaFormat: MediaFormat | None Media: Media OutputBucketName: OutputBucketName - OutputKey: Optional[OutputKey] - OutputEncryptionKMSKeyId: Optional[KMSKeyId] - KMSEncryptionContext: Optional[KMSEncryptionContextMap] - Settings: Optional[MedicalTranscriptionSetting] - ContentIdentificationType: Optional[MedicalContentIdentificationType] + OutputKey: OutputKey | None + OutputEncryptionKMSKeyId: KMSKeyId | None + KMSEncryptionContext: KMSEncryptionContextMap | None + Settings: MedicalTranscriptionSetting | None + ContentIdentificationType: MedicalContentIdentificationType | None Specialty: Specialty Type: Type - Tags: Optional[TagList] + Tags: TagList | None class StartMedicalTranscriptionJobResponse(TypedDict, total=False): - MedicalTranscriptionJob: Optional[MedicalTranscriptionJob] + MedicalTranscriptionJob: MedicalTranscriptionJob | None class Subtitles(TypedDict, total=False): - Formats: Optional[SubtitleFormats] - OutputStartIndex: Optional[SubtitleOutputStartIndex] + Formats: SubtitleFormats | None + OutputStartIndex: SubtitleOutputStartIndex | None class StartTranscriptionJobRequest(ServiceRequest): TranscriptionJobName: TranscriptionJobName - LanguageCode: Optional[LanguageCode] - MediaSampleRateHertz: Optional[MediaSampleRateHertz] - MediaFormat: Optional[MediaFormat] + LanguageCode: LanguageCode | None + MediaSampleRateHertz: MediaSampleRateHertz | None + MediaFormat: MediaFormat | None Media: Media - OutputBucketName: Optional[OutputBucketName] - OutputKey: Optional[OutputKey] - OutputEncryptionKMSKeyId: Optional[KMSKeyId] - KMSEncryptionContext: Optional[KMSEncryptionContextMap] - Settings: Optional[Settings] - ModelSettings: Optional[ModelSettings] - JobExecutionSettings: Optional[JobExecutionSettings] - ContentRedaction: Optional[ContentRedaction] - IdentifyLanguage: Optional[Boolean] - IdentifyMultipleLanguages: Optional[Boolean] - LanguageOptions: Optional[LanguageOptions] - Subtitles: Optional[Subtitles] - Tags: Optional[TagList] - LanguageIdSettings: Optional[LanguageIdSettingsMap] - ToxicityDetection: Optional[ToxicityDetection] + OutputBucketName: OutputBucketName | None + OutputKey: OutputKey | None + OutputEncryptionKMSKeyId: KMSKeyId | None + KMSEncryptionContext: KMSEncryptionContextMap | None + Settings: Settings | None + ModelSettings: ModelSettings | None + JobExecutionSettings: JobExecutionSettings | None + ContentRedaction: ContentRedaction | None + IdentifyLanguage: Boolean | None + IdentifyMultipleLanguages: Boolean | None + LanguageOptions: LanguageOptions | None + Subtitles: Subtitles | None + Tags: TagList | None + LanguageIdSettings: LanguageIdSettingsMap | None + ToxicityDetection: ToxicityDetection | None class StartTranscriptionJobResponse(TypedDict, total=False): - TranscriptionJob: Optional[TranscriptionJob] + TranscriptionJob: TranscriptionJob | None -TagKeyList = List[TagKey] +TagKeyList = list[TagKey] class TagResourceRequest(ServiceRequest): @@ -1221,11 +1221,11 @@ class UntagResourceResponse(TypedDict, total=False): class UpdateCallAnalyticsCategoryRequest(ServiceRequest): CategoryName: CategoryName Rules: RuleList - InputType: Optional[InputType] + InputType: InputType | None class UpdateCallAnalyticsCategoryResponse(TypedDict, total=False): - CategoryProperties: Optional[CategoryProperties] + CategoryProperties: CategoryProperties | None class UpdateMedicalVocabularyRequest(ServiceRequest): @@ -1235,43 +1235,43 @@ class UpdateMedicalVocabularyRequest(ServiceRequest): class UpdateMedicalVocabularyResponse(TypedDict, total=False): - VocabularyName: Optional[VocabularyName] - LanguageCode: Optional[LanguageCode] - LastModifiedTime: Optional[DateTime] - VocabularyState: Optional[VocabularyState] + VocabularyName: VocabularyName | None + LanguageCode: LanguageCode | None + LastModifiedTime: DateTime | None + VocabularyState: VocabularyState | None class UpdateVocabularyFilterRequest(ServiceRequest): VocabularyFilterName: VocabularyFilterName - Words: Optional[Words] - VocabularyFilterFileUri: Optional[Uri] - DataAccessRoleArn: Optional[DataAccessRoleArn] + Words: Words | None + VocabularyFilterFileUri: Uri | None + DataAccessRoleArn: DataAccessRoleArn | None class UpdateVocabularyFilterResponse(TypedDict, total=False): - VocabularyFilterName: Optional[VocabularyFilterName] - LanguageCode: Optional[LanguageCode] - LastModifiedTime: Optional[DateTime] + VocabularyFilterName: VocabularyFilterName | None + LanguageCode: LanguageCode | None + LastModifiedTime: DateTime | None class UpdateVocabularyRequest(ServiceRequest): VocabularyName: VocabularyName LanguageCode: LanguageCode - Phrases: Optional[Phrases] - VocabularyFileUri: Optional[Uri] - DataAccessRoleArn: Optional[DataAccessRoleArn] + Phrases: Phrases | None + VocabularyFileUri: Uri | None + DataAccessRoleArn: DataAccessRoleArn | None class UpdateVocabularyResponse(TypedDict, total=False): - VocabularyName: Optional[VocabularyName] - LanguageCode: Optional[LanguageCode] - LastModifiedTime: Optional[DateTime] - VocabularyState: Optional[VocabularyState] + VocabularyName: VocabularyName | None + LanguageCode: LanguageCode | None + LastModifiedTime: DateTime | None + VocabularyState: VocabularyState | None class TranscribeApi: - service = "transcribe" - version = "2017-10-26" + service: str = "transcribe" + version: str = "2017-10-26" @handler("CreateCallAnalyticsCategory") def create_call_analytics_category( diff --git a/localstack-core/localstack/aws/catalog_exceptions.py b/localstack-core/localstack/aws/catalog_exceptions.py new file mode 100644 index 0000000000000..236549d8d3ae1 --- /dev/null +++ b/localstack-core/localstack/aws/catalog_exceptions.py @@ -0,0 +1,73 @@ +from localstack.aws.api import CommonServiceException +from localstack.utils.catalog.common import ( + AwsServiceOperationsSupportInLatest, + AwsServicesSupportInLatest, + AwsServiceSupportAtRuntime, +) + +_DOCS_COVERAGE_URL = "https://docs.localstack.cloud/references/coverage" + + +class AwsServiceAvailabilityException(CommonServiceException): + def __init__(self, message: str, error_code: int): + super().__init__(code="InternalFailure", message=message, status_code=501) + self.error_code = error_code + + +class ServiceOrOperationNotSupportedException(AwsServiceAvailabilityException): + def __init__(self, service_name: str, operation_name: str | None = None): + if operation_name is None: + message = f"Sorry, the {service_name} service is not currently supported by LocalStack." + error_code = 3 + else: + message = f"Sorry, the {operation_name} operation on the {service_name} service is not currently supported by LocalStack." + error_code = 8 + super().__init__(message, error_code) + + +class LatestVersionRequiredException(AwsServiceAvailabilityException): + def __init__(self, service_name: str, operation_name: str | None = None): + if operation_name is None: + message = f"Sorry, the {service_name} service is not supported by this version of LocalStack, but is available if you upgrade to the latest stable version." + error_code = 2 + else: + message = f"Sorry, the {operation_name} operation on the {service_name} service is not supported by this version of LocalStack, but is available if you upgrade to the latest stable version." + error_code = 6 + super().__init__(message, error_code) + + +class LicenseUpgradeRequiredException(AwsServiceAvailabilityException): + def __init__(self, service_name: str, operation_name: str | None = None): + if operation_name is None: + message = f"Sorry, the {service_name} service is not included within your LocalStack license, but is available in an upgraded license. Please refer to {_DOCS_COVERAGE_URL} for more details." + error_code = 1 + else: + message = f"Sorry, the {operation_name} operation on the {service_name} service is not supported with your LocalStack license. Please refer to {_DOCS_COVERAGE_URL} for more details." + error_code = 5 + super().__init__(message, error_code) + + +def get_service_availability_exception( + service_name: str, + operation_name: str | None, + status: AwsServicesSupportInLatest | AwsServiceOperationsSupportInLatest | None, +) -> AwsServiceAvailabilityException: + match status: + case AwsServicesSupportInLatest.SUPPORTED: + return LatestVersionRequiredException(service_name) + case AwsServiceOperationsSupportInLatest.SUPPORTED: + return LatestVersionRequiredException(service_name, operation_name) + case ( + AwsServicesSupportInLatest.SUPPORTED_WITH_LICENSE_UPGRADE + | AwsServiceSupportAtRuntime.AVAILABLE_WITH_LICENSE_UPGRADE + ): + return LicenseUpgradeRequiredException(service_name) + case AwsServiceOperationsSupportInLatest.SUPPORTED_WITH_LICENSE_UPGRADE: + return LicenseUpgradeRequiredException(service_name, operation_name) + case AwsServicesSupportInLatest.NOT_SUPPORTED | AwsServiceSupportAtRuntime.NOT_IMPLEMENTED: + return ServiceOrOperationNotSupportedException(service_name, operation_name) + case _: + return AwsServiceAvailabilityException( + message=f"The API for service {service_name} is either not included in your current license plan or has not yet been emulated by LocalStack.", + error_code=4, + ) diff --git a/localstack-core/localstack/aws/connect.py b/localstack-core/localstack/aws/connect.py index 7c7aeb22282f4..f1775e6343001 100644 --- a/localstack-core/localstack/aws/connect.py +++ b/localstack-core/localstack/aws/connect.py @@ -7,6 +7,7 @@ import json import logging +import os import re import threading from abc import ABC, abstractmethod @@ -250,9 +251,10 @@ class ClientFactory(ABC): def __init__( self, use_ssl: bool = False, - verify: bool = False, + verify: bool | str = False, session: Session = None, config: Config = None, + endpoint: str = None, ): """ :param use_ssl: Whether to use SSL @@ -268,6 +270,7 @@ def __init__( self._verify = verify self._config: Config = config or Config(max_pool_connections=MAX_POOL_CONNECTIONS) self._session: Session = session or Session() + self._endpoint = endpoint # make sure we consider our custom data paths for legacy specs (like SQS query protocol) if LOCALSTACK_BUILTIN_DATA_PATH not in self._session._loader.search_paths: @@ -514,10 +517,13 @@ def get_client( else: config = self._config.merge(config) - endpoint_url = endpoint_url or get_service_endpoint() - if service_name == "s3" and endpoint_url: - if re.match(r"https?://localhost(:[0-9]+)?", endpoint_url): - endpoint_url = endpoint_url.replace("://localhost", f"://{get_s3_hostname()}") + endpoint_url = endpoint_url or self._endpoint or get_service_endpoint() + if ( + endpoint_url + and service_name == "s3" + and re.match(r"https?://localhost(:[0-9]+)?", endpoint_url) + ): + endpoint_url = endpoint_url.replace("://localhost", f"://{get_s3_hostname()}") return self._get_client( service_name=service_name, @@ -574,14 +580,20 @@ def get_client( # If the region in arg is non-default, it gives the arg the precedence # But if the region in arg is default (us-east-1), it gives precedence to one in config # Below: always give precedence to arg region - if config and config.region_name != AWS_REGION_US_EAST_1: - if region_name == AWS_REGION_US_EAST_1: - config = config.merge(Config(region_name=region_name)) - - endpoint_url = endpoint_url or get_service_endpoint() - if service_name == "s3": - if re.match(r"https?://localhost(:[0-9]+)?", endpoint_url): - endpoint_url = endpoint_url.replace("://localhost", f"://{get_s3_hostname()}") + if ( + config + and config.region_name != AWS_REGION_US_EAST_1 + and region_name == AWS_REGION_US_EAST_1 + ): + config = config.merge(Config(region_name=region_name)) + + endpoint_url = endpoint_url or self._endpoint or get_service_endpoint() + if ( + endpoint_url + and service_name == "s3" + and re.match(r"https?://localhost(:[0-9]+)?", endpoint_url) + ): + endpoint_url = endpoint_url.replace("://localhost", f"://{get_s3_hostname()}") # Prevent `PartialCredentialsError` when only access key ID is provided # The value of secret access key is insignificant and can be set to anything @@ -683,11 +695,28 @@ def __init__( session: Session = None, config: Config = None, ): - super().__init__(use_ssl=True, verify=True, session=session, config=config) + if ca_cert := os.getenv("REQUESTS_CA_BUNDLE"): + LOG.debug("Creating External AWS Client with REQUESTS_CA_BUNDLE=%s", ca_cert) + + proxy_config = Config( + proxies={ + "http": localstack_config.OUTBOUND_HTTP_PROXY, + "https": localstack_config.OUTBOUND_HTTPS_PROXY, + } + ) + + super().__init__( + use_ssl=localstack_config.is_env_not_false("USE_SSL"), + verify=ca_cert or True, + session=session, + config=config.merge(proxy_config) if config else proxy_config, + ) def _get_client_post_hook(self, client: BaseClient) -> BaseClient: client = super()._get_client_post_hook(client) - client._endpoint.http_session = ExternalBypassDnsSession() + client._endpoint.http_session = ExternalBypassDnsSession( + verify=self._verify, proxies=self._config.proxies + ) return client diff --git a/localstack-core/localstack/aws/handlers/exceptions.py b/localstack-core/localstack/aws/handlers/exceptions.py new file mode 100644 index 0000000000000..54c65d493c0ba --- /dev/null +++ b/localstack-core/localstack/aws/handlers/exceptions.py @@ -0,0 +1,2 @@ +class PluginNotIncludedInUserLicenseError(NotImplementedError): + pass diff --git a/localstack-core/localstack/aws/handlers/logging.py b/localstack-core/localstack/aws/handlers/logging.py index 4904603325f19..3100ab5df3451 100644 --- a/localstack-core/localstack/aws/handlers/logging.py +++ b/localstack-core/localstack/aws/handlers/logging.py @@ -21,6 +21,18 @@ class ExceptionLogger(ExceptionHandler): def __init__(self, logger=None): self.logger = logger or LOG + try: + import moto.core.exceptions + + self._skip_exceptions( + ServiceException, + moto.core.exceptions.ServiceException, + moto.core.exceptions.RESTError, + ) + except (ModuleNotFoundError, AttributeError): + # Moto may not be available in stripped-down versions of LocalStack, like LocalStack S3 image. + self._skip_exceptions = (ServiceException,) + def __call__( self, chain: HandlerChain, @@ -28,10 +40,12 @@ def __call__( context: RequestContext, response: Response, ): - if isinstance(exception, ServiceException): + if isinstance(exception, self._skip_exceptions): # We do not want to log an error/stacktrace if the handler is working as expected, but chooses to throw - # a service exception + # a service exception. It may also throw a Moto ServiceException, which should not be logged either + # because ServiceExceptionHandler understands it. return + if self.logger.isEnabledFor(level=logging.DEBUG): self.logger.exception("exception during call chain", exc_info=exception) else: diff --git a/localstack-core/localstack/aws/handlers/metric_handler.py b/localstack-core/localstack/aws/handlers/metric_handler.py index 6bd16b2f43016..0dd921a2d0a7c 100644 --- a/localstack-core/localstack/aws/handlers/metric_handler.py +++ b/localstack-core/localstack/aws/handlers/metric_handler.py @@ -1,9 +1,15 @@ +import csv import logging +import os +from datetime import datetime +from pathlib import Path from localstack import config from localstack.aws.api import RequestContext from localstack.aws.chain import HandlerChain +from localstack.constants import ENV_INTERNAL_TEST_STORE_METRICS_PATH from localstack.http import Response +from localstack.utils.strings import short_uid LOG = logging.getLogger(__name__) @@ -137,6 +143,32 @@ class MetricHandler: def __init__(self) -> None: self.metrics_handler_items = {} + self.local_filename = None + + if self.should_store_metric_locally(): + self.local_filename = self.create_local_file() + + @staticmethod + def should_store_metric_locally() -> bool: + return config.is_collect_metrics_mode() and config.store_test_metrics_in_local_filesystem() + + @staticmethod + def create_local_file(): + folder = Path( + os.environ.get(ENV_INTERNAL_TEST_STORE_METRICS_PATH, "/tmp/localstack-metrics") + ) + if not folder.exists(): + folder.mkdir(parents=True, exist_ok=True) + LOG.debug("Metric reports will be stored in %s", folder) + filename = ( + folder + / f"metric-report-raw-data-{datetime.utcnow().strftime('%Y-%m-%d__%H_%M_%S')}-{short_uid()}.csv" + ) + with open(filename, "w") as fd: + LOG.debug("Creating new metric data file %s", filename) + writer = csv.writer(fd) + writer.writerow(Metric.RAW_DATA_HEADER) + return filename def create_metric_handler_item( self, chain: HandlerChain, context: RequestContext, response: Response @@ -194,7 +226,15 @@ def update_metric_collection( ) # refrain from adding duplicates if metric not in MetricHandler.metric_data: - MetricHandler.metric_data.append(metric) + self.append_metric(metric) # cleanup del self.metrics_handler_items[context] + + def append_metric(self, metric: Metric): + if self.should_store_metric_locally(): + with open(self.local_filename, "a") as fd: + writer = csv.writer(fd) + writer.writerow(metric) + else: + MetricHandler.metric_data.append(metric) diff --git a/localstack-core/localstack/aws/handlers/service.py b/localstack-core/localstack/aws/handlers/service.py index 4009f720386c7..21cb228d9ab2c 100644 --- a/localstack-core/localstack/aws/handlers/service.py +++ b/localstack-core/localstack/aws/handlers/service.py @@ -2,6 +2,7 @@ import logging import traceback +import types from collections import defaultdict from typing import Any @@ -10,15 +11,17 @@ from localstack import config from localstack.http import Response -from ...utils.coverage_docs import get_coverage_link_for_service +from ...utils.catalog.plugins import get_aws_catalog from ..api import CommonServiceException, RequestContext, ServiceException from ..api.core import ServiceOperation +from ..catalog_exceptions import get_service_availability_exception from ..chain import CompositeResponseHandler, ExceptionHandler, Handler, HandlerChain from ..client import parse_response, parse_service_exception from ..protocol.parser import RequestParser, create_parser from ..protocol.serializer import create_serializer from ..protocol.service_router import determine_aws_protocol, determine_aws_service_model from ..skeleton import Skeleton, create_skeleton +from .exceptions import PluginNotIncludedInUserLicenseError LOG = logging.getLogger(__name__) @@ -156,6 +159,18 @@ class ServiceExceptionSerializer(ExceptionHandler): def __init__(self): self.handle_internal_failures = True + self._moto_service_exception = types.EllipsisType + self._moto_rest_error = types.EllipsisType + + try: + import moto.core.exceptions + + self._moto_service_exception = moto.core.exceptions.ServiceException + self._moto_rest_error = moto.core.exceptions.RESTError + except (ModuleNotFoundError, AttributeError) as exc: + # Moto may not be available in stripped-down versions of LocalStack, like LocalStack S3 image. + LOG.debug("Unable to set up Moto exception translation: %s", exc) + def __call__( self, chain: HandlerChain, @@ -176,12 +191,40 @@ def create_exception_response(self, exception: Exception, context: RequestContex error = exception if operation and isinstance(exception, NotImplementedError): - action_name = operation.name + operation_name = operation.name exception_message: str | None = exception.args[0] if exception.args else None - message = exception_message or get_coverage_link_for_service(service_name, action_name) - error = CommonServiceException("InternalFailure", message, status_code=501) + if exception_message: + message = exception_message + error = CommonServiceException("InternalFailure", message, status_code=501) + else: + catalog = get_aws_catalog() + if isinstance(exception, PluginNotIncludedInUserLicenseError): + # Operation name is provided when a plugin fails to load, although it is not relevant. + # In such cases, we should return an error without the operation name + service_status = catalog.get_aws_service_status( + service_name, operation_name=None + ) + else: + service_status = catalog.get_aws_service_status(service_name, operation_name) + error = get_service_availability_exception( + service_name, operation_name, service_status + ) + message = error.message LOG.info(message) context.service_exception = error + elif isinstance(exception, self._moto_service_exception): + # Translate Moto ServiceException to native ServiceException if Moto is available. + # This allows handler chain to gracefully handles Moto errors when provider handlers invoke Moto methods directly. + error = CommonServiceException( + code=exception.code, + message=exception.message, + ) + elif isinstance(exception, self._moto_rest_error): + # Some Moto exceptions (like ones raised by EC2) are of type RESTError. + error = CommonServiceException( + code=exception.error_type, + message=exception.message, + ) elif not isinstance(exception, ServiceException): if not self.handle_internal_failures: @@ -210,7 +253,8 @@ def create_exception_response(self, exception: Exception, context: RequestContex error = CommonServiceException( "InternalError", msg, status_code=status_code ).with_traceback(exception.__traceback__) - context.service_exception = error + + context.service_exception = error serializer = create_serializer(context.service, context.protocol) return serializer.serialize_error_to_response( diff --git a/localstack-core/localstack/aws/handlers/service_plugin.py b/localstack-core/localstack/aws/handlers/service_plugin.py index c28bbb7e341c1..dac5e483eee67 100644 --- a/localstack-core/localstack/aws/handlers/service_plugin.py +++ b/localstack-core/localstack/aws/handlers/service_plugin.py @@ -3,6 +3,8 @@ import logging import threading +from plux import PluginDisabled + from localstack.http import Response from localstack.services.plugins import Service, ServiceManager from localstack.utils.sync import SynchronizedDefaultDict @@ -11,7 +13,7 @@ from ..api import RequestContext from ..chain import Handler, HandlerChain from ..protocol.service_router import determine_aws_service_model_for_data_plane -from .service import ServiceRequestRouter +from .service import PluginNotIncludedInUserLicenseError, ServiceRequestRouter LOG = logging.getLogger(__name__) @@ -51,9 +53,13 @@ def require_service(self, _: HandlerChain, context: RequestContext, response: Re ) request_router = self.service_request_router - - # Ensure the Service is loaded and set to ServiceState.RUNNING if not in an erroneous state. - service_plugin: Service = self.service_manager.require(service_name) + try: + # Ensure the Service is loaded and set to ServiceState.RUNNING if not in an erroneous state. + service_plugin: Service = self.service_manager.require(service_name) + except PluginDisabled as e: + if e.reason == "This feature is not part of the active license agreement": + raise PluginNotIncludedInUserLicenseError() + raise with self.service_locks[context.service.service_name]: # try again to avoid race conditions diff --git a/localstack-core/localstack/aws/protocol/parser.py b/localstack-core/localstack/aws/protocol/parser.py index a2c7482898a88..6bbd7d0edcc8d 100644 --- a/localstack-core/localstack/aws/protocol/parser.py +++ b/localstack-core/localstack/aws/protocol/parser.py @@ -1032,7 +1032,7 @@ def parse_data_item(self, stream: io.BufferedReader) -> Any: return method(stream, additional_info) else: raise ProtocolParserError( - f"Unsupported inital byte found for data item- " + f"Unsupported initial byte found for data item- " f"Major type:{major_type}, Additional info: " f"{additional_info}" ) @@ -1124,8 +1124,13 @@ def _parse_type_tag(self, stream: io.BufferedReader, additional_info: int): raise ProtocolParserError(f"Found CBOR tag not supported by botocore: {tag}") def _parse_type_datetime(self, value: int | float) -> datetime.datetime: + # CBOR overrides any timestamp format defined in the spec: + # https://smithy.io/2.0/additional-specs/protocols/smithy-rpc-v2.html#timestamp-type-serialization + # > This protocol uses epoch-seconds, also known as Unix timestamps, with millisecond (1/1000th of a second) + # > resolution. The timestampFormat MUST NOT be respected to customize timestamp serialization. if isinstance(value, (int, float)): - return self._convert_str_to_timestamp(str(value)) + milli_precision_ts = int(value * 1000) / 1000 + return datetime.datetime.fromtimestamp(milli_precision_ts, tz=datetime.UTC) else: raise ProtocolParserError(f"Unable to parse datetime value: {value}") diff --git a/localstack-core/localstack/aws/protocol/routing.py b/localstack-core/localstack/aws/protocol/routing.py index f793bd051ec27..4150bbd8a51c6 100644 --- a/localstack-core/localstack/aws/protocol/routing.py +++ b/localstack-core/localstack/aws/protocol/routing.py @@ -1,5 +1,4 @@ import re -from typing import AnyStr from werkzeug.routing import Rule @@ -30,7 +29,7 @@ def __init__(self, string: str, method: str, **kwargs) -> None: self.methods = {method.upper()} -def transform_path_params_to_rule_vars(match: re.Match[AnyStr]) -> str: +def transform_path_params_to_rule_vars(match: re.Match[str]) -> str: """ Transforms a request URI path param to a valid Werkzeug Rule string variable placeholder. This transformation function should be used in combination with _path_param_regex on the request URIs (without any diff --git a/localstack-core/localstack/aws/protocol/serializer.py b/localstack-core/localstack/aws/protocol/serializer.py index 5816f0395522d..752680d02d55d 100644 --- a/localstack-core/localstack/aws/protocol/serializer.py +++ b/localstack-core/localstack/aws/protocol/serializer.py @@ -1228,6 +1228,15 @@ def _prepare_additional_traits_in_xml(self, root: ETree.Element | None, request_ request_id_element = ETree.SubElement(response_metadata, "RequestId") request_id_element.text = request_id + def _prepare_additional_traits_in_response( + self, response: Response, operation_model: OperationModel, request_id: str + ): + response.headers["x-amzn-RequestId"] = request_id + response = super()._prepare_additional_traits_in_response( + response, operation_model, request_id + ) + return response + class EC2ResponseSerializer(QueryResponseSerializer): """ @@ -1495,7 +1504,7 @@ def _serialize_type_blob(self, body: dict, value: str | bytes, _, key: str, mime def _prepare_additional_traits_in_response( self, response: Response, operation_model: OperationModel, request_id: str ): - response.headers["x-amzn-requestid"] = request_id + response.headers.setdefault("x-amzn-RequestId", request_id) response = super()._prepare_additional_traits_in_response( response, operation_model, request_id ) @@ -1524,6 +1533,17 @@ def _serialize_content_type( if has_body and not has_content_type: serialized.headers["Content-Type"] = mime_type + def _serialize_type_map( + self, body: dict, value: dict, shape: MapShape, key: str, mime_type: str + ): + # REST JSON is different from regular JSON, it returns None values in Map + if value is None: + return + map_obj = {} + body[key] = map_obj + for sub_key, sub_value in value.items(): + self._serialize(map_obj, sub_value, shape.value, sub_key, mime_type) + class BaseCBORResponseSerializer(ResponseSerializer): """ @@ -1921,7 +1941,7 @@ def _serialize_body_params( def _prepare_additional_traits_in_response( self, response: Response, operation_model: OperationModel, request_id: str ) -> Response: - response.headers["x-amzn-requestid"] = request_id + response.headers["x-amzn-RequestId"] = request_id response = super()._prepare_additional_traits_in_response( response, operation_model, request_id ) @@ -2015,7 +2035,7 @@ def _serialize_error( def _prepare_additional_traits_in_response( self, response: Response, operation_model: OperationModel, request_id: str ): - response.headers["x-amzn-requestid"] = request_id + response.headers["x-amzn-RequestId"] = request_id response.headers["Smithy-Protocol"] = "rpc-v2-cbor" response = super()._prepare_additional_traits_in_response( response, operation_model, request_id @@ -2183,7 +2203,7 @@ def _create_empty_node(xmlnode: ETree.Element, name: str) -> None: def _prepare_additional_traits_in_xml(self, root: ETree.Element | None, request_id: str): # some tools (Serverless) require a newline after the "\n" preamble line, e.g., for LocationConstraint - if root and not root.tail: + if root is not None and not root.tail: root.tail = "\n" root.attrib["xmlns"] = self.XML_NAMESPACE diff --git a/localstack-core/localstack/aws/scaffold.py b/localstack-core/localstack/aws/scaffold.py index 2a5100ecb597e..7f16539a658c7 100644 --- a/localstack-core/localstack/aws/scaffold.py +++ b/localstack-core/localstack/aws/scaffold.py @@ -64,6 +64,14 @@ def html_to_rst(html: str): return rst +def is_sparse_shape(shape: ListShape | MapShape): + # see https://smithy.io/2.0/spec/type-refinement-traits.html#sparse-trait + # this is needed for generating Map that can have nullable values + # We need to access `_shape_model` directly, because `sparse` is not used by Botocore, so it is not picked in + # `metadata`: see ``botocore.model.Shape.METADATA_ATTRS`` and ``botocore.model.Shape.metadata`` + return getattr(shape, "_shape_model", {}).get("sparse") + + class ShapeNode: service: ServiceModel shape: Shape @@ -188,9 +196,7 @@ def _print_as_class(self, output, base: str, doc=True, quote_types=False): if member in self.shape.required_members: output.write(f" {member}: IO[{q}{to_valid_python_name(shape.name)}{q}]\n") else: - output.write( - f" {member}: Optional[IO[{q}{to_valid_python_name(shape.name)}{q}]]\n" - ) + output.write(f" {member}: {q}IO[{to_valid_python_name(shape.name)}] | None{q}\n") del remaining_members[member] # render the streaming payload first if self.is_response and self.response_operation.has_streaming_output: @@ -199,25 +205,26 @@ def _print_as_class(self, output, base: str, doc=True, quote_types=False): shape_name = to_valid_python_name(shape.name) if member in self.shape.required_members: output.write( - f" {member}: Union[{q}{shape_name}{q}, IO[{q}{shape_name}{q}], Iterable[{q}{shape_name}{q}]]\n" + f" {member}: {q}{shape_name} | IO[{shape_name}] | Iterable[{shape_name}]{q}\n" ) else: output.write( - f" {member}: Optional[Union[{q}{shape_name}{q}, IO[{q}{shape_name}{q}], Iterable[{q}{shape_name}{q}]]]\n" + f" {member}: {q}{shape_name} | IO[{shape_name}] | Iterable[{shape_name}] | None{q}\n" ) del remaining_members[member] for k, v in remaining_members.items(): + shape_name = to_valid_python_name(v.name) if k in self.shape.required_members: if v.serialization.get("eventstream"): - output.write(f" {k}: Iterator[{q}{to_valid_python_name(v.name)}{q}]\n") + output.write(f" {k}: Iterator[{q}{shape_name}{q}]\n") else: - output.write(f" {k}: {q}{to_valid_python_name(v.name)}{q}\n") + output.write(f" {k}: {q}{shape_name}{q}\n") else: if v.serialization.get("eventstream"): - output.write(f" {k}: Iterator[{q}{to_valid_python_name(v.name)}{q}]\n") + output.write(f" {k}: Iterator[{q}{shape_name}{q}]\n") else: - output.write(f" {k}: Optional[{q}{to_valid_python_name(v.name)}{q}]\n") + output.write(f" {k}: {q}{shape_name} | None{q}\n") def _print_as_typed_dict(self, output, doc=True, quote_types=False): name = to_valid_python_name(self.shape.name) @@ -236,7 +243,7 @@ def _print_as_typed_dict(self, output, doc=True, quote_types=False): if v.serialization.get("eventstream"): output.write(f' "{k}": Iterator[{q}{member_name}{q}],\n') else: - output.write(f' "{k}": Optional[{q}{member_name}{q}],\n') + output.write(f' "{k}": {q}{member_name} | None{q},\n') output.write("}, total=False)") def print_shape_doc(self, output, shape): @@ -256,11 +263,15 @@ def print_declaration(self, output, doc=True, quote_types=False): self._print_structure_declaration(output, doc, quote_types) elif isinstance(shape, ListShape): output.write( - f"{to_valid_python_name(shape.name)} = List[{q}{to_valid_python_name(shape.member.name)}{q}]" + f"{to_valid_python_name(shape.name)} = list[{q}{to_valid_python_name(shape.member.name)}{q}]" ) elif isinstance(shape, MapShape): + if is_sparse_shape(shape): + value_key = f"{q}{to_valid_python_name(shape.value.name)} | None{q}" + else: + value_key = f"{q}{to_valid_python_name(shape.value.name)}{q}" output.write( - f"{to_valid_python_name(shape.name)} = Dict[{q}{to_valid_python_name(shape.key.name)}{q}, {q}{to_valid_python_name(shape.value.name)}{q}]" + f"{to_valid_python_name(shape.name)} = dict[{q}{to_valid_python_name(shape.key.name)}{q}, {value_key}]" ) elif isinstance(shape, StringShape): if shape.enum: @@ -316,9 +327,8 @@ def get_order(self): def generate_service_types(output, service: ServiceModel, doc=True): output.write("from datetime import datetime\n") output.write("from enum import StrEnum\n") - output.write( - "from typing import Dict, List, Optional, Iterator, Iterable, IO, Union, TypedDict\n" - ) + output.write("from typing import IO, TypedDict\n") + output.write("from collections.abc import Iterable, Iterator\n") output.write("\n") output.write( "from localstack.aws.api import handler, RequestContext, ServiceException, ServiceRequest" @@ -372,8 +382,8 @@ def generate_service_api(output, service: ServiceModel, doc=True): output.write(f"class {class_name}:\n") output.write("\n") - output.write(f' service = "{service.service_name}"\n') - output.write(f' version = "{service.api_version}"\n') + output.write(f' service: str = "{service.service_name}"\n') + output.write(f' version: str = "{service.api_version}"\n') for op_name in service.operation_names: operation: OperationModel = service.operation_model(op_name) diff --git a/localstack-core/localstack/aws/skeleton.py b/localstack-core/localstack/aws/skeleton.py index 2e15595787cb7..faae3a49ce13c 100644 --- a/localstack-core/localstack/aws/skeleton.py +++ b/localstack-core/localstack/aws/skeleton.py @@ -12,12 +12,13 @@ ServiceException, ) from localstack.aws.api.core import ServiceRequest, ServiceRequestHandler, ServiceResponse +from localstack.aws.catalog_exceptions import get_service_availability_exception from localstack.aws.protocol.parser import create_parser from localstack.aws.protocol.serializer import ResponseSerializer, create_serializer from localstack.aws.spec import load_service from localstack.http import Response from localstack.utils import analytics -from localstack.utils.coverage_docs import get_coverage_link_for_service +from localstack.utils.catalog.plugins import get_aws_catalog LOG = logging.getLogger(__name__) @@ -212,16 +213,30 @@ def on_not_implemented_error( """ operation = context.operation - action_name = operation.name + operation_name = operation.name service_name = operation.service_model.service_name exception_message: str | None = exception.args[0] if exception.args else None - message = exception_message or get_coverage_link_for_service(service_name, action_name) + if exception_message is not None: + message = exception_message + error = CommonServiceException("InternalFailure", message, status_code=501) + # record event + analytics.log.event( + "services_notimplemented", payload={"s": service_name, "a": operation_name} + ) + else: + service_status = get_aws_catalog().get_aws_service_status(service_name, operation_name) + error = get_service_availability_exception(service_name, operation_name, service_status) + message = error.message + analytics.log.event( + "services_notimplemented", + payload={ + "s": service_name, + "a": operation_name, + "c": error.error_code, + }, + ) + LOG.info(message) - error = CommonServiceException("InternalFailure", message, status_code=501) - # record event - analytics.log.event( - "services_notimplemented", payload={"s": service_name, "a": action_name} - ) context.service_exception = error return serializer.serialize_error_to_response( diff --git a/localstack-core/localstack/aws/spec-patches.json b/localstack-core/localstack/aws/spec-patches.json index c1ebb922cfb38..1004603cb0579 100644 --- a/localstack-core/localstack/aws/spec-patches.json +++ b/localstack-core/localstack/aws/spec-patches.json @@ -62,32 +62,6 @@ "type": "string" } }, - { - "op": "add", - "path": "/shapes/HeadBucketOutput", - "value": { - "type": "structure", - "members": { - "BucketRegion": { - "shape": "BucketRegion", - "location": "header", - "locationName": "x-amz-bucket-region" - }, - "BucketContentType": { - "shape": "BucketContentType", - "location": "header", - "locationName": "content-type" - } - } - } - }, - { - "op": "add", - "path": "/operations/HeadBucket/output", - "value": { - "shape": "HeadBucketOutput" - } - }, { "op": "add", "path": "/operations/PutBucketPolicy/http/responseCode", @@ -1329,6 +1303,26 @@ "documentation": "

The Content-MD5 you specified did not match what we received.

", "exception": true } + }, + { + "op": "add", + "path": "/shapes/AuthorizationHeaderMalformed", + "value": { + "type": "structure", + "members": { + "Region": { + "shape": "BucketRegion" + }, + "HostId": { + "shape": "HostId" + } + }, + "error": { + "httpStatusCode": 400 + }, + "documentation": "

The authorization header is malformed.

", + "exception": true + } } ], "apigatewayv2/2018-11-29/service-2": [ @@ -1353,42 +1347,21 @@ "value": 200 } ], - "cloudwatch/2010-08-01/service-2": [ - { - "op": "add", - "path": "/metadata/awsQueryCompatible", - "value": {} - }, + "apigateway/2015-07-09/service-2": [ { "op": "add", - "path": "/metadata/jsonVersion", - "value": "1.0" - }, - { - "op": "add", - "path": "/metadata/targetPrefix", - "value": "GraniteServiceVersion20100801" - }, - { - "op": "replace", - "path": "/metadata/protocol", - "value": "smithy-rpc-v2-cbor" + "path": "/shapes/MapOfStringToNullableString", + "value": { + "type":"map", + "key":{"shape":"String"}, + "value":{"shape":"String"}, + "sparse": true + } }, { "op": "replace", - "path": "/metadata/protocols", - "value": [ - "smithy-rpc-v2-cbor", - "json", - "query" - ] - }, - { - "op": "add", - "path": "/shapes/ConflictException/error", - "value": { - "httpStatusCode": 409 - } + "path": "/shapes/IntegrationResponse/members/responseTemplates/shape", + "value": "MapOfStringToNullableString" } ] } diff --git a/localstack-core/localstack/aws/spec.py b/localstack-core/localstack/aws/spec.py index f6d60dbe5de42..53cb303db3bc4 100644 --- a/localstack-core/localstack/aws/spec.py +++ b/localstack-core/localstack/aws/spec.py @@ -142,7 +142,7 @@ def load_service( return ServiceModel(service_description, service) -def iterate_service_operations() -> Generator[tuple[ServiceModel, OperationModel], None, None]: +def iterate_service_operations() -> Generator[tuple[ServiceModel, OperationModel]]: """ Returns one record per operation in the AWS service spec, where the first item is the service model the operation belongs to, and the second is the operation model. diff --git a/localstack-core/localstack/cli/__init__.py b/localstack-core/localstack/cli/__init__.py index fb0407e19e65e..e69de29bb2d1d 100644 --- a/localstack-core/localstack/cli/__init__.py +++ b/localstack-core/localstack/cli/__init__.py @@ -1,10 +0,0 @@ -from .console import console -from .plugin import LocalstackCli, LocalstackCliPlugin - -name = "cli" - -__all__ = [ - "console", - "LocalstackCli", - "LocalstackCliPlugin", -] diff --git a/localstack-core/localstack/cli/console.py b/localstack-core/localstack/cli/console.py deleted file mode 100644 index 24bda10813744..0000000000000 --- a/localstack-core/localstack/cli/console.py +++ /dev/null @@ -1,11 +0,0 @@ -from rich.console import Console - -BANNER = r""" - __ _______ __ __ - / / ____ _________ _/ / ___// /_____ ______/ /__ - / / / __ \/ ___/ __ `/ /\__ \/ __/ __ `/ ___/ //_/ - / /___/ /_/ / /__/ /_/ / /___/ / /_/ /_/ / /__/ ,< - /_____/\____/\___/\__,_/_//____/\__/\__,_/\___/_/|_| -""" - -console = Console() diff --git a/localstack-core/localstack/cli/exceptions.py b/localstack-core/localstack/cli/exceptions.py index cd65d2ee13d26..eb077c97c0ef7 100644 --- a/localstack-core/localstack/cli/exceptions.py +++ b/localstack-core/localstack/cli/exceptions.py @@ -12,7 +12,7 @@ class CLIError(ClickException): def format_message(self) -> str: return click.style(f"❌ Error: {self.message}", fg="red") - def show(self, file: t.Optional[t.IO[t.Any]] = None) -> None: + def show(self, file: t.IO[t.Any] | None = None) -> None: if file is None: file = get_text_stderr() diff --git a/localstack-core/localstack/cli/localstack.py b/localstack-core/localstack/cli/localstack.py deleted file mode 100644 index 103bd642d81ef..0000000000000 --- a/localstack-core/localstack/cli/localstack.py +++ /dev/null @@ -1,946 +0,0 @@ -import json -import logging -import os -import sys -import traceback -from typing import Optional, TypedDict - -import click -import requests - -from localstack import config -from localstack.cli.exceptions import CLIError -from localstack.constants import VERSION -from localstack.utils.analytics.cli import publish_invocation -from localstack.utils.bootstrap import get_container_default_logfile_location -from localstack.utils.json import CustomEncoder - -from .console import BANNER, console -from .plugin import LocalstackCli, load_cli_plugins - - -class LocalStackCliGroup(click.Group): - """ - A Click group used for the top-level ``localstack`` command group. It implements global exception handling - by: - - - Ignoring click exceptions (already handled) - - Handling common exceptions (like DockerNotAvailable) - - Wrapping all unexpected exceptions in a ClickException (for a unified error message) - - It also implements a custom help formatter to build more fine-grained groups. - """ - - # FIXME: find a way to communicate this from the actual command - advanced_commands = [ - "aws", - "dns", - "extensions", - "license", - "login", - "logout", - "pod", - "state", - "ephemeral", - "replicator", - ] - - def invoke(self, ctx: click.Context): - try: - return super().invoke(ctx) - except click.exceptions.Exit: - # raise Exit exceptions unmodified (e.g., raised on --help) - raise - except click.ClickException: - # don't handle ClickExceptions, just reraise - if ctx and ctx.params.get("debug"): - click.echo(traceback.format_exc()) - raise - except Exception as e: - if ctx and ctx.params.get("debug"): - click.echo(traceback.format_exc()) - from localstack.utils.container_utils.container_client import ( - ContainerException, - DockerNotAvailable, - ) - - if isinstance(e, DockerNotAvailable): - raise CLIError( - "Docker could not be found on the system.\n" - "Please make sure that you have a working docker environment on your machine." - ) - elif isinstance(e, ContainerException): - raise CLIError(e.message) - else: - # If we have a generic exception, we wrap it in a ClickException - raise CLIError(str(e)) from e - - def format_commands(self, ctx: click.Context, formatter: click.HelpFormatter) -> None: - """Extra format methods for multi methods that adds all the commands after the options. It also - groups commands into command categories.""" - categories = {"Commands": [], "Advanced": [], "Deprecated": []} - - commands = [] - for subcommand in self.list_commands(ctx): - cmd = self.get_command(ctx, subcommand) - # What is this, the tool lied about a command. Ignore it - if cmd is None: - continue - if cmd.hidden: - continue - - commands.append((subcommand, cmd)) - - # allow for 3 times the default spacing - if len(commands): - limit = formatter.width - 6 - max(len(cmd[0]) for cmd in commands) - - for subcommand, cmd in commands: - help = cmd.get_short_help_str(limit) - categories[self._get_category(cmd)].append((subcommand, help)) - - for category, rows in categories.items(): - if rows: - with formatter.section(category): - formatter.write_dl(rows) - - def _get_category(self, cmd) -> str: - if cmd.deprecated: - return "Deprecated" - - if cmd.name in self.advanced_commands: - return "Advanced" - - return "Commands" - - -def create_with_plugins() -> LocalstackCli: - """ - Creates a LocalstackCli instance with all cli plugins loaded. - :return: a LocalstackCli instance - """ - cli = LocalstackCli() - cli.group = localstack - load_cli_plugins(cli) - return cli - - -def _setup_cli_debug() -> None: - from localstack.logging.setup import setup_logging_for_cli - - config.DEBUG = True - os.environ["DEBUG"] = "1" - - setup_logging_for_cli(logging.DEBUG if config.DEBUG else logging.INFO) - - -# Re-usable format option decorator which can be used across multiple commands -_click_format_option = click.option( - "-f", - "--format", - "format_", - type=click.Choice(["table", "plain", "dict", "json"]), - default="table", - help="The formatting style for the command output.", -) - - -@click.group( - name="localstack", - help="The LocalStack Command Line Interface (CLI)", - cls=LocalStackCliGroup, - context_settings={ - # add "-h" as a synonym for "--help" - # https://click.palletsprojects.com/en/8.1.x/documentation/#help-parameter-customization - "help_option_names": ["-h", "--help"], - # show default values for options by default - https://github.com/pallets/click/pull/1225 - "show_default": True, - }, -) -@click.version_option( - VERSION, - "--version", - "-v", - message="LocalStack CLI %(version)s", - help="Show the version of the LocalStack CLI and exit", -) -@click.option("-d", "--debug", is_flag=True, help="Enable CLI debugging mode") -@click.option("-p", "--profile", type=str, help="Set the configuration profile") -def localstack(debug, profile) -> None: - # --profile is read manually in localstack.cli.main because it needs to be read before localstack.config is read - - if debug: - _setup_cli_debug() - - from localstack.utils.files import cache_dir - - # overwrite the config variable here to defer import of cache_dir - if not os.environ.get("LOCALSTACK_VOLUME_DIR", "").strip(): - config.VOLUME_DIR = str(cache_dir() / "volume") - - # FIXME: at some point we should remove the use of `config.dirs` for the CLI, - # see https://github.com/localstack/localstack/pull/7906 - config.dirs.for_cli().mkdirs() - - -@localstack.group( - name="config", - short_help="Manage your LocalStack config", -) -def localstack_config() -> None: - """ - Inspect and validate your LocalStack configuration. - """ - pass - - -@localstack_config.command(name="show", short_help="Show your config") -@_click_format_option -@publish_invocation -def cmd_config_show(format_: str) -> None: - """ - Print the current LocalStack config values. - - This command prints the LocalStack configuration values from your environment. - It analyzes the environment variables as well as the LocalStack CLI profile. - It does _not_ analyze a specific file (like a docker-compose-yml). - """ - # TODO: parse values from potential docker-compose file? - assert config - - try: - # only load the pro config if it's available - from localstack.pro.core import config as pro_config - - assert pro_config - except ImportError: - # the pro package is not available - return None - - if format_ == "table": - _print_config_table() - elif format_ == "plain": - _print_config_pairs() - elif format_ == "dict": - _print_config_dict() - elif format_ == "json": - _print_config_json() - else: - _print_config_pairs() # fall back to plain - - -@localstack_config.command(name="validate", short_help="Validate your config") -@click.option( - "-f", - "--file", - help="Path to compose file", - default="docker-compose.yml", - type=click.Path(exists=True, file_okay=True, readable=True), -) -@publish_invocation -def cmd_config_validate(file: str) -> None: - """ - Validate your LocalStack configuration (docker compose). - - This command inspects the given docker-compose file (by default docker-compose.yml in the current working - directory) and validates if the configuration is valid. - - \b - It will show an error and return a non-zero exit code if: - - The docker-compose file is syntactically incorrect. - - If the file contains common issues when configuring LocalStack. - """ - - from localstack.utils import bootstrap - - if bootstrap.validate_localstack_config(file): - console.print("[green]:heavy_check_mark:[/green] config valid") - sys.exit(0) - else: - console.print("[red]:heavy_multiplication_x:[/red] validation error") - sys.exit(1) - - -def _print_config_json() -> None: - import json - - console.print(json.dumps(dict(config.collect_config_items()), cls=CustomEncoder)) - - -def _print_config_pairs() -> None: - for key, value in config.collect_config_items(): - console.print(f"{key}={value}") - - -def _print_config_dict() -> None: - console.print(dict(config.collect_config_items())) - - -def _print_config_table() -> None: - from rich.table import Table - - grid = Table(show_header=True) - grid.add_column("Key") - grid.add_column("Value") - - for key, value in config.collect_config_items(): - grid.add_row(key, str(value)) - - console.print(grid) - - -@localstack.group( - name="status", - short_help="Query status info", - invoke_without_command=True, -) -@click.pass_context -def localstack_status(ctx: click.Context) -> None: - """ - Query status information about the currently running LocalStack instance. - """ - if ctx.invoked_subcommand is None: - ctx.invoke(localstack_status.get_command(ctx, "docker")) - - -@localstack_status.command(name="docker", short_help="Query LocalStack Docker status") -@_click_format_option -def cmd_status_docker(format_: str) -> None: - """ - Query information about the currently running LocalStack Docker image, its container, - and the LocalStack runtime. - """ - with console.status("Querying Docker status"): - _print_docker_status(format_) - - -class DockerStatus(TypedDict, total=False): - running: bool - runtime_version: str - image_tag: str - image_id: str - image_created: str - container_name: Optional[str] - container_ip: Optional[str] - - -def _print_docker_status(format_: str) -> None: - from localstack.utils import docker_utils - from localstack.utils.bootstrap import get_docker_image_details, get_server_version - from localstack.utils.container_networking import get_main_container_ip, get_main_container_name - - img = get_docker_image_details() - cont_name = config.MAIN_CONTAINER_NAME - running = docker_utils.DOCKER_CLIENT.is_container_running(cont_name) - status = DockerStatus( - runtime_version=get_server_version(), - image_tag=img["tag"], - image_id=img["id"], - image_created=img["created"], - running=running, - ) - if running: - status["container_name"] = get_main_container_name() - status["container_ip"] = get_main_container_ip() - - if format_ == "dict": - console.print(status) - if format_ == "table": - _print_docker_status_table(status) - if format_ == "json": - console.print(json.dumps(status)) - if format_ == "plain": - for key, value in status.items(): - console.print(f"{key}={value}") - - -def _print_docker_status_table(status: DockerStatus) -> None: - from rich.table import Table - - grid = Table(show_header=False) - grid.add_column() - grid.add_column() - - grid.add_row("Runtime version", f"[bold]{status['runtime_version']}[/bold]") - grid.add_row( - "Docker image", - f"tag: {status['image_tag']}, " - f"id: {status['image_id']}, " - f":calendar: {status['image_created']}", - ) - cont_status = "[bold][red]:heavy_multiplication_x: stopped" - if status["running"]: - cont_status = ( - f"[bold][green]:heavy_check_mark: running[/green][/bold] " - f'(name: "[italic]{status["container_name"]}[/italic]", IP: {status["container_ip"]})' - ) - grid.add_row("Runtime status", cont_status) - console.print(grid) - - -@localstack_status.command(name="services", short_help="Query LocalStack services status") -@_click_format_option -def cmd_status_services(format_: str) -> None: - """ - Query information about the services of the currently running LocalStack instance. - """ - url = config.external_service_url() - - try: - health = requests.get(f"{url}/_localstack/health", timeout=2) - doc = health.json() - services = doc.get("services", []) - if format_ == "table": - _print_service_table(services) - if format_ == "plain": - for service, status in services.items(): - console.print(f"{service}={status}") - if format_ == "dict": - console.print(services) - if format_ == "json": - console.print(json.dumps(services)) - except requests.ConnectionError: - if config.DEBUG: - console.print_exception() - raise CLIError(f"could not connect to LocalStack health endpoint at {url}") - - -def _print_service_table(services: dict[str, str]) -> None: - from rich.table import Table - - status_display = { - "running": "[green]:heavy_check_mark:[/green] running", - "starting": ":hourglass_flowing_sand: starting", - "available": "[grey]:heavy_check_mark:[/grey] available", - "error": "[red]:heavy_multiplication_x:[/red] error", - } - - table = Table() - table.add_column("Service") - table.add_column("Status") - - services = list(services.items()) - services.sort(key=lambda item: item[0]) - - for service, status in services: - if status in status_display: - status = status_display[status] - - table.add_row(service, status) - - console.print(table) - - -@localstack.command(name="start", short_help="Start LocalStack") -@click.option("--docker", is_flag=True, help="Start LocalStack in a docker container [default]") -@click.option("--host", is_flag=True, help="Start LocalStack directly on the host") -@click.option("--no-banner", is_flag=True, help="Disable LocalStack banner", default=False) -@click.option( - "-d", "--detached", is_flag=True, help="Start LocalStack in the background", default=False -) -@click.option( - "--network", - type=str, - help="The container network the LocalStack container should be started in. By default, the default docker bridge network is used.", - required=False, -) -@click.option( - "--env", - "-e", - help="Additional environment variables that are passed to the LocalStack container", - multiple=True, - required=False, -) -@click.option( - "--publish", - "-p", - help="Additional port mappings that are passed to the LocalStack container", - multiple=True, - required=False, -) -@click.option( - "--volume", - "-v", - help="Additional volume mounts that are passed to the LocalStack container", - multiple=True, - required=False, -) -@click.option( - "--host-dns", - help="Expose the LocalStack DNS server to the host using port bindings.", - required=False, - is_flag=True, - default=False, -) -@click.option( - "--stack", - "-s", - type=str, - help="Use a specific stack with optional version. Examples: [localstack:4.5, snowflake]", - required=False, -) -@publish_invocation -def cmd_start( - docker: bool, - host: bool, - no_banner: bool, - detached: bool, - network: str = None, - env: tuple = (), - publish: tuple = (), - volume: tuple = (), - host_dns: bool = False, - stack: str = None, -) -> None: - """ - Start the LocalStack runtime. - - This command starts the LocalStack runtime with your current configuration. - By default, it will start a new Docker container from the latest LocalStack(-Pro) Docker image - with best-practice volume mounts and port mappings. - """ - if docker and host: - raise CLIError("Please specify either --docker or --host") - if host and detached: - raise CLIError("Cannot start detached in host mode") - - if stack: - # Validate allowed stacks - stack_name = stack.split(":")[0] - allowed_stacks = ("localstack", "localstack-pro", "snowflake") - if stack_name.lower() not in allowed_stacks: - raise CLIError(f"Invalid stack '{stack_name}'. Allowed stacks: {allowed_stacks}.") - - # Set IMAGE_NAME, defaulting to :latest if no version specified - if ":" not in stack: - stack = f"{stack}:latest" - os.environ["IMAGE_NAME"] = f"localstack/{stack}" - - if not no_banner: - print_banner() - print_version() - print_profile() - print_app() - console.line() - - from localstack.utils import bootstrap - - if not no_banner: - if host: - console.log("starting LocalStack in host mode :laptop_computer:") - else: - console.log("starting LocalStack in Docker mode :whale:") - - if host: - # call hooks to prepare host - bootstrap.prepare_host(console) - - # from here we abandon the regular CLI control path and start treating the process like a localstack - # runtime process - os.environ["LOCALSTACK_CLI"] = "0" - config.dirs = config.init_directories() - - try: - bootstrap.start_infra_locally() - except ImportError: - if config.DEBUG: - console.print_exception() - raise CLIError( - "It appears you have a light install of localstack which only supports running in docker.\n" - "If you would like to use --host, please install localstack with Python using " - "`pip install localstack[runtime]` instead." - ) - else: - # make sure to initialize the bootstrap environment and directories for the host (even if we're executing - # in Docker), to allow starting the container from within other containers (e.g., Github Codespaces). - config.OVERRIDE_IN_DOCKER = False - config.is_in_docker = False - config.dirs = config.init_directories() - - # call hooks to prepare host (note that this call should stay below the config overrides above) - bootstrap.prepare_host(console) - - # pass the parsed cli params to the start infra command - params = click.get_current_context().params - - if network: - # reconciles the network config and makes sure that MAIN_DOCKER_NETWORK is set automatically if - # `--network` is set. - if config.MAIN_DOCKER_NETWORK: - if config.MAIN_DOCKER_NETWORK != network: - raise CLIError( - f"Values of MAIN_DOCKER_NETWORK={config.MAIN_DOCKER_NETWORK} and --network={network} " - f"do not match" - ) - else: - config.MAIN_DOCKER_NETWORK = network - os.environ["MAIN_DOCKER_NETWORK"] = network - - if detached: - bootstrap.start_infra_in_docker_detached(console, params) - else: - bootstrap.start_infra_in_docker(console, params) - - -@localstack.command(name="stop", short_help="Stop LocalStack") -@publish_invocation -def cmd_stop() -> None: - """ - Stops the current LocalStack runtime. - - This command stops the currently running LocalStack docker container. - By default, this command looks for a container named `localstack-main` (which is the default - container name used by the `localstack start` command). - If your LocalStack container has a different name, set the config variable - `MAIN_CONTAINER_NAME`. - """ - from localstack.utils.docker_utils import DOCKER_CLIENT - - from ..utils.container_utils.container_client import NoSuchContainer - - container_name = config.MAIN_CONTAINER_NAME - - try: - DOCKER_CLIENT.stop_container(container_name) - console.print(f"container stopped: {container_name}") - except NoSuchContainer: - raise CLIError( - f'Expected a running LocalStack container named "{container_name}", but found none' - ) - - -@localstack.command(name="restart", short_help="Restart LocalStack") -@publish_invocation -def cmd_restart() -> None: - """ - Restarts the current LocalStack runtime. - """ - url = config.external_service_url() - - try: - response = requests.post( - f"{url}/_localstack/health", - json={"action": "restart"}, - ) - response.raise_for_status() - console.print("LocalStack restarted within the container.") - except requests.ConnectionError: - if config.DEBUG: - console.print_exception() - raise CLIError("could not restart the LocalStack container") - - -@localstack.command( - name="logs", - short_help="Show LocalStack logs", -) -@click.option( - "-f", - "--follow", - is_flag=True, - help="Block the terminal and follow the log output", - default=False, -) -@click.option( - "-n", - "--tail", - type=int, - help="Print only the last lines of the log output", - default=None, - metavar="N", -) -@publish_invocation -def cmd_logs(follow: bool, tail: int) -> None: - """ - Show the logs of the current LocalStack runtime. - - This command shows the logs of the currently running LocalStack docker container. - By default, this command looks for a container named `localstack-main` (which is the default - container name used by the `localstack start` command). - If your LocalStack container has a different name, set the config variable - `MAIN_CONTAINER_NAME`. - """ - from localstack.utils.docker_utils import DOCKER_CLIENT - - container_name = config.MAIN_CONTAINER_NAME - logfile = get_container_default_logfile_location(container_name) - - if not DOCKER_CLIENT.is_container_running(container_name): - console.print("localstack container not running") - if os.path.exists(logfile): - console.print("printing logs from previous run") - with open(logfile) as fd: - for line in fd: - click.echo(line, nl=False) - sys.exit(1) - - if follow: - num_lines = 0 - for line in DOCKER_CLIENT.stream_container_logs(container_name): - print(line.decode("utf-8").rstrip("\r\n")) - num_lines += 1 - if tail is not None and num_lines >= tail: - break - - else: - logs = DOCKER_CLIENT.get_container_logs(container_name) - if tail is not None: - logs = "\n".join(logs.split("\n")[-tail:]) - print(logs) - - -@localstack.command(name="wait", short_help="Wait for LocalStack") -@click.option( - "-t", - "--timeout", - type=float, - help="Only wait for seconds before raising a timeout error", - default=None, - metavar="N", -) -@publish_invocation -def cmd_wait(timeout: Optional[float] = None) -> None: - """ - Wait for the LocalStack runtime to be up and running. - - This commands waits for a started LocalStack runtime to be up and running, ready to serve - requests. - By default, this command looks for a container named `localstack-main` (which is the default - container name used by the `localstack start` command). - If your LocalStack container has a different name, set the config variable - `MAIN_CONTAINER_NAME`. - """ - from localstack.utils.bootstrap import wait_container_is_ready - - if not wait_container_is_ready(timeout=timeout): - raise CLIError("timeout") - - -@localstack.command(name="ssh", short_help="Obtain a shell in LocalStack") -@publish_invocation -def cmd_ssh() -> None: - """ - Obtain a shell in the current LocalStack runtime. - - This command starts a new interactive shell in the currently running LocalStack container. - By default, this command looks for a container named `localstack-main` (which is the default - container name used by the `localstack start` command). - If your LocalStack container has a different name, set the config variable - `MAIN_CONTAINER_NAME`. - """ - from localstack.utils.docker_utils import DOCKER_CLIENT - - if not DOCKER_CLIENT.is_container_running(config.MAIN_CONTAINER_NAME): - raise CLIError( - f'Expected a running LocalStack container named "{config.MAIN_CONTAINER_NAME}", but found none' - ) - os.execlp("docker", "docker", "exec", "-it", config.MAIN_CONTAINER_NAME, "bash") - - -@localstack.group(name="update", short_help="Update LocalStack") -def localstack_update() -> None: - """ - Update different LocalStack components. - """ - pass - - -@localstack_update.command(name="all", short_help="Update all LocalStack components") -@click.pass_context -@publish_invocation -def cmd_update_all(ctx: click.Context) -> None: - """ - Update all LocalStack components. - - This is the same as executing `localstack update localstack-cli` and - `localstack update docker-images`. - Updating the LocalStack CLI is currently only supported if the CLI - is installed and run via Python / PIP. If you used a different installation method, - please follow the instructions on https://docs.localstack.cloud/. - """ - ctx.invoke(localstack_update.get_command(ctx, "localstack-cli")) - ctx.invoke(localstack_update.get_command(ctx, "docker-images")) - - -@localstack_update.command(name="localstack-cli", short_help="Update LocalStack CLI") -@publish_invocation -def cmd_update_localstack_cli() -> None: - """ - Update the LocalStack CLI. - - This command updates the LocalStack CLI. This is currently only supported if the CLI - is installed and run via Python / PIP. If you used a different installation method, - please follow the instructions on https://docs.localstack.cloud/. - """ - if is_frozen_bundle(): - # "update" can only be performed if running from source / in a non-frozen interpreter - raise CLIError( - "The LocalStack CLI can only update itself if installed via PIP. " - "Please follow the instructions on https://docs.localstack.cloud/ to update your CLI." - ) - - import subprocess - from subprocess import CalledProcessError - - console.rule("Updating LocalStack CLI") - with console.status("Updating LocalStack CLI..."): - try: - subprocess.check_output( - [sys.executable, "-m", "pip", "install", "--upgrade", "localstack"] - ) - console.print(":heavy_check_mark: LocalStack CLI updated") - except CalledProcessError: - console.print(":heavy_multiplication_x: LocalStack CLI update failed", style="bold red") - - -@localstack_update.command( - name="docker-images", short_help="Update docker images LocalStack depends on" -) -@publish_invocation -def cmd_update_docker_images() -> None: - """ - Update all Docker images LocalStack depends on. - - This command updates all Docker LocalStack docker images, as well as other Docker images - LocalStack depends on (and which have been used before / are present on the machine). - """ - from localstack.utils.docker_utils import DOCKER_CLIENT - - console.rule("Updating docker images") - - all_images = DOCKER_CLIENT.get_docker_image_names(strip_latest=False) - image_prefixes = [ - "localstack/", - "public.ecr.aws/lambda", - ] - localstack_images = [ - image - for image in all_images - if any( - image.startswith(image_prefix) or image.startswith(f"docker.io/{image_prefix}") - for image_prefix in image_prefixes - ) - and not image.endswith(":") # ignore dangling images - ] - update_images(localstack_images) - - -def update_images(image_list: list[str]) -> None: - from rich.markup import escape - from rich.progress import MofNCompleteColumn, Progress - - from localstack.utils.container_utils.container_client import ContainerException - from localstack.utils.docker_utils import DOCKER_CLIENT - - updated_count = 0 - failed_count = 0 - progress = Progress( - *Progress.get_default_columns(), MofNCompleteColumn(), transient=True, console=console - ) - with progress: - for image in progress.track(image_list, description="Processing image..."): - try: - updated = False - hash_before_pull = DOCKER_CLIENT.inspect_image(image_name=image, pull=False)["Id"] - DOCKER_CLIENT.pull_image(image) - if ( - hash_before_pull - != DOCKER_CLIENT.inspect_image(image_name=image, pull=False)["Id"] - ): - updated = True - updated_count += 1 - console.print( - f":heavy_check_mark: Image {escape(image)} {'updated' if updated else 'up-to-date'}.", - style="bold" if updated else None, - highlight=False, - ) - except ContainerException as e: - console.print( - f":heavy_multiplication_x: Image {escape(image)} pull failed: {e.message}", - style="bold red", - highlight=False, - ) - failed_count += 1 - console.rule() - console.print( - f"Images updated: {updated_count}, Images failed: {failed_count}, total images processed: {len(image_list)}." - ) - - -@localstack.command(name="completion", short_help="CLI shell completion") -@click.pass_context -@click.argument( - "shell", required=True, type=click.Choice(["bash", "zsh", "fish"], case_sensitive=False) -) -@publish_invocation -def localstack_completion(ctx: click.Context, shell: str) -> None: - """ - Print shell completion code for the specified shell (bash, zsh, or fish). - The shell code must be evaluated to enable the interactive shell completion of LocalStack CLI commands. - This is usually done by sourcing it from the .bash_profile. - - \b - Examples: - # Bash - ## Bash completion on Linux depends on the 'bash-completion' package. - ## Write the LocalStack CLI completion code for bash to a file and source it from .bash_profile - localstack completion bash > ~/.localstack/completion.bash.inc - printf " - # LocalStack CLI bash completion - source '$HOME/.localstack/completion.bash.inc' - " >> $HOME/.bash_profile - source $HOME/.bash_profile - \b - # zsh - ## Set the LocalStack completion code for zsh to autoload on startup: - localstack completion zsh > "${fpath[1]}/_localstack" - \b - # fish - ## Set the LocalStack completion code for fish to autoload on startup: - localstack completion fish > ~/.config/fish/completions/localstack.fish - """ - - # lookup the completion, raise an error if the given completion is not found - import click.shell_completion - - comp_cls = click.shell_completion.get_completion_class(shell) - if comp_cls is None: - raise CLIError("Completion for given shell could not be found.") - - # Click's program name is the base path of sys.argv[0] - path = sys.argv[0] - prog_name = os.path.basename(path) - - # create the completion variable according to the docs - # https://click.palletsprojects.com/en/8.1.x/shell-completion/#enabling-completion - complete_var = f"_{prog_name}_COMPLETE".replace("-", "_").upper() - - # instantiate the completion class and print the completion source - comp = comp_cls(ctx.command, {}, prog_name, complete_var) - click.echo(comp.source()) - - -def print_version() -> None: - console.print(f"- [bold]LocalStack CLI:[/bold] [blue]{VERSION}[/blue]") - - -def print_profile() -> None: - if config.LOADED_PROFILES: - console.print(f"- [bold]Profile:[/bold] [blue]{', '.join(config.LOADED_PROFILES)}[/blue]") - - -def print_app() -> None: - console.print("- [bold]App:[/bold] https://app.localstack.cloud") - - -def print_banner() -> None: - print(BANNER) - - -def is_frozen_bundle() -> bool: - """ - :return: true if we are currently running in a frozen bundle / a pyinstaller binary. - """ - # check if we are in a PyInstaller binary - # https://pyinstaller.org/en/stable/runtime-information.html - return getattr(sys, "frozen", False) and hasattr(sys, "_MEIPASS") diff --git a/localstack-core/localstack/cli/lpm.py b/localstack-core/localstack/cli/lpm.py index 719051b8fe38e..5d90dbf7b0732 100644 --- a/localstack-core/localstack/cli/lpm.py +++ b/localstack-core/localstack/cli/lpm.py @@ -1,7 +1,6 @@ import itertools import logging from multiprocessing.pool import ThreadPool -from typing import Optional import click from rich.console import Console @@ -75,9 +74,9 @@ def _do_install_package(package: Package, version: str = None, target: InstallTa ) def install( package: list[str], - parallel: Optional[int] = 1, - version: Optional[str] = None, - target: Optional[str] = None, + parallel: int | None = 1, + version: str | None = None, + target: str | None = None, ): """Install one or more packages.""" try: diff --git a/localstack-core/localstack/cli/main.py b/localstack-core/localstack/cli/main.py deleted file mode 100644 index de1f04e38cac5..0000000000000 --- a/localstack-core/localstack/cli/main.py +++ /dev/null @@ -1,22 +0,0 @@ -import os - - -def main(): - # indicate to the environment we are starting from the CLI - os.environ["LOCALSTACK_CLI"] = "1" - - # config profiles are the first thing that need to be loaded (especially before localstack.config!) - from .profiles import set_and_remove_profile_from_sys_argv - - # WARNING: This function modifies sys.argv to remove the profile argument. - set_and_remove_profile_from_sys_argv() - - # initialize CLI plugins - from .localstack import create_with_plugins - - cli = create_with_plugins() - cli() - - -if __name__ == "__main__": - main() diff --git a/localstack-core/localstack/cli/plugin.py b/localstack-core/localstack/cli/plugin.py deleted file mode 100644 index f9af88474a6d5..0000000000000 --- a/localstack-core/localstack/cli/plugin.py +++ /dev/null @@ -1,39 +0,0 @@ -import abc -import logging -import os - -import click -from plux import Plugin, PluginManager - -LOG = logging.getLogger(__name__) - - -class LocalstackCli: - group: click.Group - - def __call__(self, *args, **kwargs): - self.group(*args, **kwargs) - - -class LocalstackCliPlugin(Plugin): - namespace = "localstack.plugins.cli" - - def load(self, cli) -> None: - self.attach(cli) - - @abc.abstractmethod - def attach(self, cli: LocalstackCli) -> None: - """ - Attach commands to the `localstack` CLI. - - :param cli: the cli object - """ - - -def load_cli_plugins(cli): - if os.environ.get("DEBUG_PLUGINS", "0").lower() in ("true", "1"): - # importing localstack.config is still quite expensive... - logging.basicConfig(level=logging.DEBUG) - - loader = PluginManager("localstack.plugins.cli", load_args=(cli,)) - loader.load_all() diff --git a/localstack-core/localstack/cli/plugins.py b/localstack-core/localstack/cli/plugins.py deleted file mode 100644 index ebd6e22485b52..0000000000000 --- a/localstack-core/localstack/cli/plugins.py +++ /dev/null @@ -1,134 +0,0 @@ -import os -import time - -import click -from plux import PluginManager -from plux.build.setuptools import find_plugins -from plux.core.entrypoint import spec_to_entry_point -from rich import print as rprint -from rich.console import Console -from rich.table import Table -from rich.tree import Tree - -from localstack.cli.exceptions import CLIError - -console = Console() - - -@click.group() -def cli(): - """ - The plugins CLI is a set of commands to help troubleshoot LocalStack's plugin mechanism. - """ - pass - - -@cli.command() -@click.option("--where", type=str, default=os.path.abspath(os.curdir)) -@click.option("--exclude", multiple=True, default=()) -@click.option("--include", multiple=True, default=("*",)) -@click.option("--output", type=str, default="tree") -def find(where, exclude, include, output): - """ - Find plugins by scanning the given path for PluginSpecs. - It starts from the current directory if --where is not specified. - This is what a setup.py method would run as a build step, i.e., discovering entry points. - """ - with console.status(f"Scanning path {where}"): - plugins = find_plugins(where, exclude, include) - - if output == "tree": - tree = Tree("Entrypoints") - for namespace, entry_points in plugins.items(): - node = tree.add(f"[bold]{namespace}") - - t = Table() - t.add_column("Name") - t.add_column("Location") - - for ep in entry_points: - key, value = ep.split("=") - t.add_row(key, value) - - node.add(t) - - rprint(tree) - elif output == "dict": - rprint(dict(plugins)) - else: - raise CLIError(f"unknown output format {output}") - - -@cli.command("list") -@click.option("--namespace", type=str, required=True) -def cmd_list(namespace): - """ - List all available plugins using a PluginManager from available endpoints. - """ - manager = PluginManager(namespace) - - t = Table() - t.add_column("Name") - t.add_column("Factory") - - for spec in manager.list_plugin_specs(): - ep = spec_to_entry_point(spec) - t.add_row(spec.name, ep.value) - - rprint(t) - - -@cli.command() -@click.option("--namespace", type=str, required=True) -@click.option("--name", type=str, required=True) -def load(namespace, name): - """ - Attempts to load a plugin using a PluginManager. - """ - manager = PluginManager(namespace) - - with console.status(f"Loading {namespace}:{name}"): - then = time.time() - plugin = manager.load(name) - took = time.time() - then - - rprint( - f":tada: successfully loaded [bold][green]{namespace}[/green][/bold]:[bold][cyan]{name}[/cyan][/bold] ({type(plugin)}" - ) - rprint(f":stopwatch: loading took {took:.4f} s") - - -@cli.command() -@click.option("--namespace", type=str) -def cache(namespace): - """ - Outputs the stevedore entrypoints cache from which plugins are loaded. - """ - from stevedore._cache import _c - - data = _c._get_data_for_path(None) - - tree = Tree("Entrypoints") - for group, entry_points in data.get("groups").items(): - if namespace and group != namespace: - continue - node = tree.add(f"[bold]{group}") - - t = Table() - t.add_column("Name") - t.add_column("Value") - - for key, value, _ in entry_points: - t.add_row(key, value) - - node.add(t) - - if namespace: - rprint(t) - return - - rprint(tree) - - -if __name__ == "__main__": - cli() diff --git a/localstack-core/localstack/cli/profiles.py b/localstack-core/localstack/cli/profiles.py deleted file mode 100644 index 5af5e089658a4..0000000000000 --- a/localstack-core/localstack/cli/profiles.py +++ /dev/null @@ -1,66 +0,0 @@ -import argparse -import os -import sys -from typing import Optional - -# important: this needs to be free of localstack imports - - -def set_and_remove_profile_from_sys_argv(): - """ - Performs the following steps: - - 1. Use argparse to parse the command line arguments for the --profile flag. - All occurrences are removed from the sys.argv list, and the value from - the last occurrence is used. This allows the user to specify a profile - at any point on the command line. - - 2. If a --profile flag is not found, check for the -p flag. The first - occurrence of the -p flag is used and it is not removed from sys.argv. - The reasoning for this is that at least one of the CLI subcommands has - a -p flag, and we want to keep it in sys.argv for that command to - pick up. An existing bug means that if a -p flag is used with a - subcommand, it could erroneously be used as the profile value as well. - This behaviour is undesired, but we must maintain back-compatibility of - allowing the profile to be specified using -p. - - 3. If a profile is found, the 'CONFIG_PROFILE' os variable is set - accordingly. This is later picked up by ``localstack.config``. - - WARNING: Any --profile options are REMOVED from sys.argv, so that they are - not passed to the localstack CLI. This allows the profile option - to be set at any point on the command line. - """ - parser = argparse.ArgumentParser(add_help=False) - parser.add_argument("--profile") - namespace, sys.argv = parser.parse_known_args(sys.argv) - profile = namespace.profile - - if not profile: - # if no profile is given, check for the -p argument - profile = parse_p_argument(sys.argv) - - if profile: - os.environ["CONFIG_PROFILE"] = profile.strip() - - -def parse_p_argument(args) -> Optional[str]: - """ - Lightweight arg parsing to find the first occurrence of ``-p ``, or ``-p=`` and return the value of - ```` from the given arguments. - - :param args: list of CLI arguments - :returns: the value of ``-p``. - """ - for i, current_arg in enumerate(args): - if current_arg.startswith("-p="): - # if using the "=" notation, we remove the "-p=" prefix to get the value - return current_arg[3:] - if current_arg == "-p": - # otherwise use the next arg in the args list as value - try: - return args[i + 1] - except IndexError: - return None - - return None diff --git a/localstack-core/localstack/config.py b/localstack-core/localstack/config.py index ddfca40f220f8..1139d80c35f33 100644 --- a/localstack-core/localstack/config.py +++ b/localstack-core/localstack/config.py @@ -10,7 +10,7 @@ import warnings from collections import defaultdict from collections.abc import Mapping -from typing import Any, Optional, TypeVar, Union +from typing import Any, TypeVar from localstack import constants from localstack.constants import ( @@ -19,6 +19,7 @@ DEFAULT_VOLUME_DIR, ENV_INTERNAL_TEST_COLLECT_METRIC, ENV_INTERNAL_TEST_RUN, + ENV_INTERNAL_TEST_STORE_METRICS_IN_LOCALSTACK, FALSE_STRINGS, LOCALHOST, LOCALHOST_IP, @@ -208,13 +209,13 @@ def __str__(self): return str(self.__dict__) -def eval_log_type(env_var_name: str) -> Union[str, bool]: +def eval_log_type(env_var_name: str) -> str | bool: """Get the log type from environment variable""" ls_log = os.environ.get(env_var_name, "").lower().strip() return ls_log if ls_log in LOG_LEVELS else False -def parse_boolean_env(env_var_name: str) -> Optional[bool]: +def parse_boolean_env(env_var_name: str) -> bool | None: """Parse the value of the given env variable and return True/False, or None if it is not a boolean value.""" value = os.environ.get(env_var_name, "").lower().strip() if value in TRUE_STRINGS: @@ -224,6 +225,11 @@ def parse_boolean_env(env_var_name: str) -> Optional[bool]: return None +def parse_comma_separated_list(env_var_name: str) -> list[str]: + """Parse a comma separated list from the given environment variable.""" + return os.environ.get(env_var_name, "").strip().split(",") + + def is_env_true(env_var_name: str) -> bool: """Whether the given environment variable has a truthy value.""" return os.environ.get(env_var_name, "").lower().strip() in TRUE_STRINGS @@ -489,6 +495,9 @@ def in_docker(): # Docker image to use when starting up containers for port checks PORTS_CHECK_DOCKER_IMAGE = os.environ.get("PORTS_CHECK_DOCKER_IMAGE", "").strip() +# global prefix to prepend to Docker image names (e.g., for using a custom registry mirror) +DOCKER_GLOBAL_IMAGE_PREFIX = os.environ.get("DOCKER_GLOBAL_IMAGE_PREFIX", "").strip() + def is_trace_logging_enabled(): if LS_LOG: @@ -649,7 +658,7 @@ class UniqueHostAndPortList(list[HostAndPort]): - Identical identical hosts and ports are de-duped """ - def __init__(self, iterable: Union[list[HostAndPort], None] = None): + def __init__(self, iterable: list[HostAndPort] | None = None): super().__init__(iterable or []) self._ensure_unique() @@ -857,12 +866,6 @@ def populate_edge_configuration( # get-function call. INTERNAL_RESOURCE_ACCOUNT = os.environ.get("INTERNAL_RESOURCE_ACCOUNT") or "949334387222" -# TODO: remove with 4.1.0 -# Determine which implementation to use for the event rule / event filtering engine used by multiple services: -# EventBridge, EventBridge Pipes, Lambda Event Source Mapping -# Options: python (default) | java (deprecated since 4.0.3) -EVENT_RULE_ENGINE = os.environ.get("EVENT_RULE_ENGINE", "python").strip() - # ----- # SERVICE-SPECIFIC CONFIGS BELOW # ----- @@ -1210,6 +1213,18 @@ def populate_edge_configuration( # EXPERIMENTAL CFN_IGNORE_UNSUPPORTED_RESOURCE_TYPES = is_env_not_false("CFN_IGNORE_UNSUPPORTED_RESOURCE_TYPES") +# Comma-separated list of resource type names that CloudFormation will ignore on stack creation +CFN_IGNORE_UNSUPPORTED_TYPE_CREATE = parse_comma_separated_list( + "CFN_IGNORE_UNSUPPORTED_TYPE_CREATE" +) +# Comma-separated list of resource type names that CloudFormation will ignore on stack update +CFN_IGNORE_UNSUPPORTED_TYPE_UPDATE = parse_comma_separated_list( + "CFN_IGNORE_UNSUPPORTED_TYPE_UPDATE" +) + +# Decrease the waiting time for resource deployment +CFN_NO_WAIT_ITERATIONS: str | int | None = os.environ.get("CFN_NO_WAIT_ITERATIONS") + # bind address of local DNS server DNS_ADDRESS = os.environ.get("DNS_ADDRESS") or "0.0.0.0" # port of the local DNS server @@ -1451,6 +1466,11 @@ def is_collect_metrics_mode() -> bool: return is_env_true(ENV_INTERNAL_TEST_COLLECT_METRIC) +def store_test_metrics_in_local_filesystem() -> bool: + """Returns True if test metrics should be stored in the local filesystem (instead of the system that runs pytest).""" + return is_env_true(ENV_INTERNAL_TEST_STORE_METRICS_IN_LOCALSTACK) + + def collect_config_items() -> list[tuple[str, Any]]: """Returns a list of key-value tuples of LocalStack configuration values.""" none = object() # sentinel object @@ -1503,10 +1523,10 @@ def get_protocol() -> str: def external_service_url( - host: Optional[str] = None, - port: Optional[int] = None, - protocol: Optional[str] = None, - subdomains: Optional[str] = None, + host: str | None = None, + port: int | None = None, + protocol: str | None = None, + subdomains: str | None = None, ) -> str: """Returns a service URL (e.g., SQS queue URL) to an external client (e.g., boto3) potentially running on another machine than LocalStack. The configurations LOCALSTACK_HOST and USE_SSL can customize these returned URLs. @@ -1523,10 +1543,10 @@ def external_service_url( def internal_service_url( - host: Optional[str] = None, - port: Optional[int] = None, - protocol: Optional[str] = None, - subdomains: Optional[str] = None, + host: str | None = None, + port: int | None = None, + protocol: str | None = None, + subdomains: str | None = None, ) -> str: """Returns a service URL for internal use within LocalStack (i.e., same host). The configuration USE_SSL can customize these returned URLs but LOCALSTACK_HOST has no effect. diff --git a/localstack-core/localstack/constants.py b/localstack-core/localstack/constants.py index 27e3ace83c083..a946c591f4fc6 100644 --- a/localstack-core/localstack/constants.py +++ b/localstack-core/localstack/constants.py @@ -80,6 +80,10 @@ # environment variable name to tag collect metrics during a test run ENV_INTERNAL_TEST_COLLECT_METRIC = "LOCALSTACK_INTERNAL_TEST_COLLECT_METRIC" +# environment variable name to indicate that metrics should be stored within the container +ENV_INTERNAL_TEST_STORE_METRICS_IN_LOCALSTACK = "LOCALSTACK_INTERNAL_TEST_METRICS_IN_LOCALSTACK" +ENV_INTERNAL_TEST_STORE_METRICS_PATH = "LOCALSTACK_INTERNAL_TEST_STORE_METRICS_PATH" + # environment variable that flags whether pro was activated. do not use it for security purposes! ENV_PRO_ACTIVATED = "PRO_ACTIVATED" @@ -113,6 +117,9 @@ # AWS region us-east-1 AWS_REGION_US_EAST_1 = "us-east-1" +# AWS region eu-west-1 +AWS_REGION_EU_WEST_1 = "eu-west-1" + # environment variable to override max pool connections try: MAX_POOL_CONNECTIONS = int(os.environ["MAX_POOL_CONNECTIONS"]) diff --git a/localstack-core/localstack/deprecations.py b/localstack-core/localstack/deprecations.py index b9713f06d23e5..282a6c8cf67ec 100644 --- a/localstack-core/localstack/deprecations.py +++ b/localstack-core/localstack/deprecations.py @@ -35,12 +35,6 @@ def is_affected(self) -> bool: # Please make sure this is in-sync with https://docs.localstack.cloud/references/configuration/ # DEPRECATIONS = [ - # Since 0.11.3 - HTTP / HTTPS multiplexing - EnvVarDeprecation( - "USE_SSL", - "0.11.3", - "Each endpoint now supports multiplexing HTTP/HTTPS traffic over the same port. Please remove this environment variable.", # noqa - ), # Since 0.12.8 - PORT_UI was removed EnvVarDeprecation( "PORT_WEB_UI", @@ -325,6 +319,12 @@ def is_affected(self) -> bool: "By default, LocalStack routes Step Functions traffic to its internal runtime. " "Use this variable only if you need to redirect traffic to a different local Step Functions runtime.", ), + EnvVarDeprecation( + "ACTIVATE_PRO", + "4.14.0", + "Starting in March 2026, LocalStack will require an auth token. " + "Go to this page for more infos: https://localstack.cloud/2026-updates", + ), ] diff --git a/localstack-core/localstack/dev/kubernetes/__main__.py b/localstack-core/localstack/dev/kubernetes/__main__.py index d8ecdcdda4bc3..a72a0dfe32604 100644 --- a/localstack-core/localstack/dev/kubernetes/__main__.py +++ b/localstack-core/localstack/dev/kubernetes/__main__.py @@ -1,5 +1,7 @@ import dataclasses import os +import shlex +import subprocess as sp from typing import Literal import click @@ -9,6 +11,7 @@ NODE_PORT_START = 30010 SERVICE_PORT_START = 4510 NUMBER_OF_SERVICE_PORTS = 50 +EDGE_SERVICE_DNS_PORT = 31053 @dataclasses.dataclass @@ -144,7 +147,12 @@ def generate_mount_points( return mount_points -def generate_k8s_cluster_config(mount_points: list[MountPoint], port: int = 4566): +def generate_k8s_cluster_config( + mount_points: list[MountPoint], + port: int = 4566, + expose_dns: bool = False, + dns_port: int = 53, +): volumes = [ { "volume": f"{mount_point.host_path}:{mount_point.node_path}", @@ -177,6 +185,16 @@ def generate_k8s_cluster_config(mount_points: list[MountPoint], port: int = 4566 }, ] + if expose_dns: + ports.append( + { + "nodeFilters": [ + "server:0", + ], + "port": f"{dns_port}:{EDGE_SERVICE_DNS_PORT}", + } + ) + config = { "apiVersion": "k3d.io/v1alpha5", "kind": "Simple", @@ -279,7 +297,10 @@ def generate_k8s_helm_overrides( "end": SERVICE_PORT_START + NUMBER_OF_SERVICE_PORTS, "nodePortStart": NODE_PORT_START, }, - "dnsService": True, + "dnsService": { + "enabled": True, + "nodePort": EDGE_SERVICE_DNS_PORT, + }, } overrides = { "debug": True, @@ -296,12 +317,11 @@ def generate_k8s_helm_overrides( return overrides -def write_file(content: dict, output_path: str, file_name: str): - path = os.path.join(output_path, file_name) - with open(path, "w") as f: +def write_file(content: dict, output_path: str): + with open(output_path, "w") as f: f.write(yaml.dump(content)) f.close() - print(f"Generated file at {path}") + print(f"Generated file at {output_path}") def print_file(content: dict, file_name: str): @@ -311,6 +331,22 @@ def print_file(content: dict, file_name: str): print("=====================================") +def generate_k3d_command(config_file_path: str) -> str: + return f"k3d cluster create --config {config_file_path}" + + +def generate_helm_command(overrides_file_path: str) -> str: + return f"helm upgrade --install localstack localstack/localstack -f {overrides_file_path}" + + +def execute_deployment(config_file_path: str, overrides_file_path: str): + """ + Use the k3d and helm commands to create a cluster and deploy LocalStack in one command + """ + sp.check_call(shlex.split(generate_k3d_command(config_file_path))) + sp.check_call(shlex.split(generate_helm_command(overrides_file_path))) + + @click.command("run") @click.option( "--pro", is_flag=True, default=None, help="Mount the localstack-pro code into the cluster." @@ -355,6 +391,25 @@ def print_file(content: dict, file_name: str): help="Port to expose from the kubernetes node", type=click.IntRange(0, 65535), ) +@click.option( + "--expose-dns", + is_flag=True, + default=False, + help="Expose DNS port from the kubernetes node.", +) +@click.option( + "--dns-port", + default=53, + help="DNS port to expose from the kubernetes node. It is applied only if --expose-dns is set.", + type=click.IntRange(0, 65535), +) +@click.option( + "--execute", + "-x", + is_flag=True, + default=False, + help="Execute deployment from generated config files. Implies -w/--write.", +) @click.argument("command", nargs=-1, required=False) def run( pro: bool = None, @@ -367,13 +422,18 @@ def run( command: str = None, env: list[str] = None, port: int = None, + expose_dns: bool = False, + dns_port: int = 53, + execute: bool = False, ): """ A tool for localstack developers to generate the kubernetes cluster configuration file and the overrides to mount the localstack code into the cluster. """ mount_points = generate_mount_points(pro, mount_moto, mount_entrypoints) - config = generate_k8s_cluster_config(mount_points, port=port) + config = generate_k8s_cluster_config( + mount_points, port=port, expose_dns=expose_dns, dns_port=dns_port + ) overrides = generate_k8s_helm_overrides(mount_points, pro=pro, env=env) @@ -381,25 +441,25 @@ def run( overrides_file = overrides_file or "overrides.yml" config_file = config_file or "configuration.yml" - if write: - write_file(config, output_dir, config_file) - write_file(overrides, output_dir, overrides_file) + overrides_file_path = os.path.join(output_dir, overrides_file) + config_file_path = os.path.join(output_dir, config_file) + + if write or execute: + write_file(config, config_file_path) + write_file(overrides, overrides_file_path) + if execute: + execute_deployment(config_file, overrides_file) else: print_file(config, config_file) print_file(overrides, overrides_file) - overrides_file_path = os.path.join(output_dir, overrides_file) - config_file_path = os.path.join(output_dir, config_file) - print("\nTo create a k3d cluster with the generated configuration, follow these steps:") print("1. Run the following command to create the cluster:") - print(f"\n k3d cluster create --config {config_file_path}\n") + print(f"\n {generate_k3d_command(config_file_path)}\n") print("2. Once the cluster is created, start LocalStack with the generated overrides:") print("\n helm repo add localstack https://localstack.github.io/helm-charts # (if required)") - print( - f"\n helm upgrade --install localstack localstack/localstack -f {overrides_file_path}\n" - ) + print(f"\n {generate_helm_command(overrides_file_path)}\n") def main(): diff --git a/localstack-core/localstack/dev/run/__main__.py b/localstack-core/localstack/dev/run/__main__.py index ae6ad89e04c8d..ffc6b4d65692f 100644 --- a/localstack-core/localstack/dev/run/__main__.py +++ b/localstack-core/localstack/dev/run/__main__.py @@ -3,10 +3,19 @@ from collections.abc import Iterable import click +from rich.console import Console from rich.rule import Rule from localstack import config -from localstack.cli import console +from localstack.dev.run.configurators import ( + ConfigEnvironmentConfigurator, + DependencyMountConfigurator, + EntryPointMountConfigurator, + ImageConfigurator, + PortConfigurator, + SourceVolumeMountConfigurator, +) +from localstack.dev.run.paths import HOST_PATH_MAPPINGS, HostPaths from localstack.runtime import hooks from localstack.utils.bootstrap import Container, ContainerConfigurators from localstack.utils.container_utils.container_client import ( @@ -19,15 +28,7 @@ from localstack.utils.run import run_interactive from localstack.utils.strings import short_uid -from .configurators import ( - ConfigEnvironmentConfigurator, - DependencyMountConfigurator, - EntryPointMountConfigurator, - ImageConfigurator, - PortConfigurator, - SourceVolumeMountConfigurator, -) -from .paths import HOST_PATH_MAPPINGS, HostPaths +console = Console() @click.command("run") @@ -68,6 +69,12 @@ default=True, help="Mount source files from localstack and localstack-pro. Use --local-packages for optional dependencies such as moto.", ) +@click.option( + "--live-reload/--no-live-reload", + is_flag=True, + default=False, + help="Watch mounted source directories for .py file changes and automatically restart the container runtime.", +) @click.option( "--mount-dependencies/--no-mount-dependencies", is_flag=True, @@ -130,6 +137,7 @@ def run( develop: bool = False, randomize: bool = False, mount_source: bool = True, + live_reload: bool = False, mount_dependencies: bool = False, mount_entrypoints: bool = False, mount_docker_socket: bool = True, @@ -179,6 +187,11 @@ def run( python -m localstack.dev.run --entrypoint /bin/bash -- echo "hello" + Use the --live-reload flag to restart LocalStack on code changes. Beware: this will remove any state + that you had in your LocalStack instance. Consider using PERSISTENCE to keep resources: + + python -m localstack.dev.run --live-reload + You can import and expose debugpy: python -m localstack.dev.run --develop @@ -339,10 +352,24 @@ def run( rule = Rule(f"Interactive session with {container_id[:12]} 💻") console.print(rule) + stop_live_reload_watcher = None try: + if live_reload and mount_source: + # Some install targets don't include the `watchdog` dependency, and some developers + # don't install LocalStack using the `Makefile`, so they find that they don't have + # the `watchdog` dependency. We lazy import these functions so that we don't trigger + # an import error for these developers. + from localstack.dev.run.watcher import collect_watch_directories, start_file_watcher + + if watch_dirs := collect_watch_directories(host_paths, pro, local_packages): + stop_live_reload_watcher = start_file_watcher(watch_dirs, docker, container_id) + cmd = [*docker._docker_cmd(), "start", "--interactive", "--attach", container_id] run_interactive(cmd) finally: + if stop_live_reload_watcher is not None: + stop_live_reload_watcher.set() + if container_config.remove: try: if docker.is_container_running(container_id): diff --git a/localstack-core/localstack/dev/run/configurators.py b/localstack-core/localstack/dev/run/configurators.py index a43982b04043c..fdb6d54d48f3f 100644 --- a/localstack-core/localstack/dev/run/configurators.py +++ b/localstack-core/localstack/dev/run/configurators.py @@ -187,12 +187,23 @@ def try_mount_to_site_packages(self, cfg: ContainerConfiguration, sources_path: class EntryPointMountConfigurator: """ - Mounts ``entry_points.txt`` files of localstack and dependencies into the venv in the container. + Mounts ``entry_points.txt`` files of localstack and dependencies into the venv in the container. + + For example, when starting the pro container, the entrypoints of localstack-pro on the host would be in + ``~/workspace/localstack-pro/localstack-pro-core/localstack_ext.egg-info/entry_points.txt`` + which needs to be mounted into the distribution info of the installed dependency within the container: + Mounts ``plux.ini`` files of localstack and localstack-pro into the venv in the container. + For other dependencies, we mount the ``entry_points.txt`` build artifacts. For example, when starting the pro container, the entrypoints of localstack-pro on the host would be in - ``~/workspace/localstack-pro/localstack-pro-core/localstack_ext.egg-info/entry_points.txt`` - which needs to be mounted into the distribution info of the installed dependency within the container: - ``/opt/code/localstack/.venv/.../site-packages/localstack_ext-2.1.0.dev0.dist-info/entry_points.txt``. + ``~/workspace/localstack-pro/localstack-pro-core/plux.ini`` which needs to be mounted into the distribution info + of the installed dependency within the container: + ``/opt/code/localstack/.venv/.../site-packages/localstack_ext-4.13.0.dev0.dist-info/entry_points.txt``. + + For a dependency using plugins, the entrypoints would be in the build artifact at + ``~/workspace//.egg-info/entry_points.txt`` + which also needs to be mounted into the distribution info of the installed dependency within the container: + ``/opt/code/localstack/.venv/.../site-packages/.dist-info/entry_points.txt``. """ entry_point_glob = ( @@ -236,12 +247,7 @@ def __call__(self, cfg: ContainerConfiguration): dep, ver = dep_path.split("-") if dep == "localstack_core": - host_path = ( - self.host_paths.localstack_project_dir - / "localstack-core" - / "localstack_core.egg-info" - / "entry_points.txt" - ) + host_path = self.host_paths.localstack_project_dir / "plux.ini" if host_path.is_file(): cfg.volumes.add( BindMount( @@ -250,13 +256,9 @@ def __call__(self, cfg: ContainerConfiguration): read_only=True, ) ) - continue elif dep == "localstack_ext": host_path = ( - self.host_paths.localstack_pro_project_dir - / "localstack-pro-core" - / "localstack_ext.egg-info" - / "entry_points.txt" + self.host_paths.localstack_pro_project_dir / "localstack-pro-core" / "plux.ini" ) if host_path.is_file(): cfg.volumes.add( @@ -266,12 +268,12 @@ def __call__(self, cfg: ContainerConfiguration): read_only=True, ) ) - continue - for host_path in self.host_paths.workspace_dir.glob( - f"*/{dep}.egg-info/entry_points.txt" - ): - cfg.volumes.add(BindMount(str(host_path), str(container_path), read_only=True)) - break + else: + for host_path in self.host_paths.workspace_dir.glob( + f"*/{dep}.egg-info/entry_points.txt" + ): + cfg.volumes.add(BindMount(str(host_path), str(container_path), read_only=True)) + break class DependencyMountConfigurator: diff --git a/localstack-core/localstack/dev/run/watcher.py b/localstack-core/localstack/dev/run/watcher.py new file mode 100644 index 0000000000000..63fa7b07ff7eb --- /dev/null +++ b/localstack-core/localstack/dev/run/watcher.py @@ -0,0 +1,131 @@ +"""File watcher that monitors source directories and signals container restart on changes.""" + +import os +import threading +import time +from pathlib import Path + +from rich.console import Console +from watchdog.events import FileSystemEvent, FileSystemEventHandler +from watchdog.observers import Observer + +from localstack.dev.run.paths import HOST_PATH_MAPPINGS, HostPaths +from localstack.utils.container_utils.container_client import ContainerClient +from localstack.utils.threads import TMP_THREADS, FuncThread + +DEBOUNCE_WINDOW = 0.5 + + +console = Console() + + +class ChangeHandler(FileSystemEventHandler): + """Handles file system events for .py files, debouncing and signalling the container.""" + + def __init__( + self, + directories: list[Path], + docker: ContainerClient, + container_id: str, + ): + super().__init__() + self._directories = directories + self._docker = docker + self._container_id = container_id + self._last_signal_time = 0.0 + self._lock = threading.Lock() + + def _relative_path(self, path: str) -> str: + for d in self._directories: + try: + return os.path.relpath(path, d.parent) + except ValueError: + pass + return path + + def on_any_event(self, event: FileSystemEvent): + if event.is_directory: + return + src = event.src_path + if not src.endswith(".py") or "__pycache__" in src: + return + + with self._lock: + now = time.monotonic() + if now - self._last_signal_time < DEBOUNCE_WINDOW: + return + self._last_signal_time = now + + console.print("Live reload: sending restart signal to container") + _signal_container_restart(self._docker, self._container_id) + + +def _signal_container_restart(docker: ContainerClient, container_id: str): + """Send SIGUSR1 to PID 1 inside the container to trigger supervisor restart.""" + try: + docker.exec_in_container(container_id, ["kill", "-USR1", "1"]) + except Exception as e: + console.print(f"Live reload: failed to signal container: {e}") + + +def start_file_watcher( + directories: list[Path], + docker: ContainerClient, + container_id: str, +) -> threading.Event: + """Start a watchdog observer that watches directories for .py changes and signals the container. + + Returns a stop_event that the caller can set to shut down the watcher. + """ + console.print( + f"Live reload: watching {len(directories)} " + f"director{'y' if len(directories) == 1 else 'ies'} for .py changes" + ) + for d in directories: + console.print(f" {d}") + + handler = ChangeHandler(directories, docker, container_id) + observer = Observer() + for d in directories: + observer.schedule(handler, str(d), recursive=True) + observer.daemon = True + observer.start() + + stop_event = threading.Event() + + def _shutdown_when_signalled(): + stop_event.wait() + observer.stop() + + shutdown_thread = FuncThread( + func=_shutdown_when_signalled, + name="live-reload-shutdown", + ) + shutdown_thread.start() + TMP_THREADS.append(shutdown_thread) + + return stop_event + + +def collect_watch_directories( + host_paths: HostPaths, pro: bool, chosen_packages: list[str] | None +) -> list[Path]: + """Collect host-side source directories that are bind-mounted into the container.""" + dirs: list[Path] = [] + + source = host_paths.aws_community_package_dir + if source.exists(): + dirs.append(source) + + if pro: + source = host_paths.aws_pro_package_dir + if source.exists(): + dirs.append(source) + + for package_name in chosen_packages or []: + extractor = HOST_PATH_MAPPINGS[package_name] + path = extractor(host_paths) + if path.exists(): + dirs.append(path) + + return dirs diff --git a/localstack-core/localstack/dns/plugins.py b/localstack-core/localstack/dns/plugins.py index 05566573cfec8..7353c0ecf3594 100644 --- a/localstack-core/localstack/dns/plugins.py +++ b/localstack-core/localstack/dns/plugins.py @@ -11,8 +11,12 @@ """Make sure the DNS server is shut down after the ON_AFTER_SERVICE_SHUTDOWN_HANDLERS, which in turn is after SERVICE_SHUTDOWN_PRIORITY. Currently this value needs to be less than -20""" +DNS_START_PRIORITY = 20 +"""Make sure the DNS server is started before the pro activation, to ensure proper DNS resolution for the activate call, +if the resolv.conf is set to localhost from outside the container""" -@hooks.on_infra_start(priority=10) + +@hooks.on_infra_start(priority=DNS_START_PRIORITY) def start_dns_server(): try: from localstack.dns import server diff --git a/localstack-core/localstack/dns/server.py b/localstack-core/localstack/dns/server.py index 78e43b2bfc7ef..9ab09bed763aa 100644 --- a/localstack-core/localstack/dns/server.py +++ b/localstack-core/localstack/dns/server.py @@ -34,7 +34,7 @@ DNSRecord, ) from dnslib.server import DNSHandler, DNSServer -from psutil._common import snicaddr +from psutil._ntuples import snicaddr import dns.flags import dns.message diff --git a/localstack-core/localstack/openapi.yaml b/localstack-core/localstack/openapi.yaml index b3656c3f6f1af..fce767a9bde22 100644 --- a/localstack-core/localstack/openapi.yaml +++ b/localstack-core/localstack/openapi.yaml @@ -81,10 +81,10 @@ components: START: type: boolean required: - - BOOT - - START - - READY - - SHUTDOWN + - BOOT + - START + - READY + - SHUTDOWN type: object scripts: items: @@ -97,14 +97,14 @@ components: state: type: string required: - - stage - - name - - state + - stage + - name + - state type: object type: array required: - - completed - - scripts + - completed + - scripts type: object InitScriptsStage: additionalProperties: false @@ -162,7 +162,7 @@ components: text_part: type: string required: - - text_part + - text_part type: object Destination: $ref: '#/components/schemas/SESDestination' @@ -183,10 +183,10 @@ components: Timestamp: type: string required: - - Id - - Region - - Timestamp - - Source + - Id + - Region + - Timestamp + - Source type: object SessionInfo: additionalProperties: false @@ -210,15 +210,15 @@ components: version: type: string required: - - version - - edition - - is_license_activated - - session_id - - machine_id - - system - - is_docker - - server_time_utc - - uptime + - version + - edition + - is_license_activated + - session_id + - machine_id + - system + - is_docker + - server_time_utc + - uptime type: object SnsSubscriptionTokenError: additionalProperties: false @@ -228,8 +228,8 @@ components: subscription_arn: type: string required: - - error - - subscription_arn + - error + - subscription_arn type: object SNSPlatformEndpointMessage: type: object @@ -456,7 +456,7 @@ paths: description: Number of expired items that were deleted type: integer required: - - ExpiredItems + - ExpiredItems type: object description: Operation was successful /_aws/events/rules/{rule_arn}/trigger: @@ -465,12 +465,12 @@ paths: operationId: trigger_event_bridge_rule tags: [aws] parameters: - - description: EventBridge rule ARN - in: path - name: rule_arn - required: true - schema: - type: string + - description: EventBridge rule ARN + in: path + name: rule_arn + required: true + schema: + type: string responses: '200': description: EventBridge rule was triggered @@ -492,16 +492,16 @@ paths: operationId: get_lambda_runtimes tags: [aws] parameters: - - in: query - name: filter - required: false - schema: - default: supported - enum: - - all - - deprecated - - supported - type: string + - in: query + name: filter + required: false + schema: + default: supported + enum: + - all + - deprecated + - supported + type: string responses: '200': content: @@ -514,7 +514,7 @@ paths: type: string type: array required: - - Runtimes + - Runtimes type: object description: Available Lambda runtimes /_aws/ses: @@ -523,7 +523,7 @@ paths: operationId: discard_ses_messages tags: [aws] parameters: - - $ref: '#/components/parameters/SesIdFilter' + - $ref: '#/components/parameters/SesIdFilter' responses: '204': description: Message was successfully discarded @@ -532,8 +532,8 @@ paths: operationId: get_ses_messages tags: [aws] parameters: - - $ref: '#/components/parameters/SesIdFilter' - - $ref: '#/components/parameters/SesEmailFilter' + - $ref: '#/components/parameters/SesIdFilter' + - $ref: '#/components/parameters/SesEmailFilter' responses: '200': content: @@ -546,7 +546,7 @@ paths: $ref: '#/components/schemas/SesSentEmail' type: array required: - - messages + - messages type: object description: List of sent messages /_aws/sns/platform-endpoint-messages: @@ -555,9 +555,9 @@ paths: operationId: discard_sns_endpoint_messages tags: [aws] parameters: - - $ref: '#/components/parameters/SnsAccountId' - - $ref: '#/components/parameters/SnsRegion' - - $ref: '#/components/parameters/SnsEndpointArn' + - $ref: '#/components/parameters/SnsAccountId' + - $ref: '#/components/parameters/SnsRegion' + - $ref: '#/components/parameters/SnsEndpointArn' responses: '204': description: Platform endpoint message was discarded @@ -566,9 +566,9 @@ paths: operationId: get_sns_endpoint_messages tags: [aws] parameters: - - $ref: '#/components/parameters/SnsAccountId' - - $ref: '#/components/parameters/SnsRegion' - - $ref: '#/components/parameters/SnsEndpointArn' + - $ref: '#/components/parameters/SnsAccountId' + - $ref: '#/components/parameters/SnsRegion' + - $ref: '#/components/parameters/SnsEndpointArn' responses: '200': content: @@ -582,9 +582,9 @@ paths: operationId: discard_sns_sms_messages tags: [aws] parameters: - - $ref: '#/components/parameters/SnsAccountId' - - $ref: '#/components/parameters/SnsRegion' - - $ref: '#/components/parameters/SnsPhoneNumber' + - $ref: '#/components/parameters/SnsAccountId' + - $ref: '#/components/parameters/SnsRegion' + - $ref: '#/components/parameters/SnsPhoneNumber' responses: '204': description: SMS message was discarded @@ -593,9 +593,9 @@ paths: operationId: get_sns_sms_messages tags: [aws] parameters: - - $ref: '#/components/parameters/SnsAccountId' - - $ref: '#/components/parameters/SnsRegion' - - $ref: '#/components/parameters/SnsPhoneNumber' + - $ref: '#/components/parameters/SnsAccountId' + - $ref: '#/components/parameters/SnsRegion' + - $ref: '#/components/parameters/SnsPhoneNumber' responses: '200': content: @@ -609,12 +609,12 @@ paths: operationId: get_sns_subscription_token tags: [aws] parameters: - - description: '`subscriptionArn` resource of subscription token' - in: path - name: subscription_arn - required: true - schema: - type: string + - description: '`subscriptionArn` resource of subscription token' + in: path + name: subscription_arn + required: true + schema: + type: string responses: '200': content: @@ -627,8 +627,8 @@ paths: subscription_token: type: string required: - - subscription_token - - subscription_arn + - subscription_token + - subscription_arn type: object description: Subscription token '400': @@ -649,12 +649,12 @@ paths: operationId: list_all_sqs_messages tags: [aws] parameters: - - description: SQS queue URL - in: query - name: QueueUrl - required: false - schema: - type: string + - description: SQS queue URL + in: query + name: QueueUrl + required: false + schema: + type: string responses: '200': content: @@ -686,10 +686,10 @@ paths: content: application/x-www-form-urlencoded: schema: - $ref: '#/components/schemas/ReceiveMessageRequest' + $ref: '#/components/schemas/ReceiveMessageRequest' application/json: schema: - $ref: '#/components/schemas/ReceiveMessageRequest' + $ref: '#/components/schemas/ReceiveMessageRequest' responses: '200': content: @@ -714,24 +714,24 @@ paths: operationId: list_sqs_messages tags: [aws] parameters: - - description: SQS queue region - in: path - name: region - required: true - schema: - type: string - - description: SQS queue account ID - in: path - name: account_id - required: true - schema: - type: string - - description: SQS queue name - in: path - name: queue_name - required: true - schema: - type: string + - description: SQS queue region + in: path + name: region + required: true + schema: + type: string + - description: SQS queue account ID + in: path + name: account_id + required: true + schema: + type: string + - description: SQS queue name + in: path + name: queue_name + required: true + schema: + type: string responses: '200': content: @@ -762,6 +762,8 @@ paths: schema: type: object description: Current LocalStack configuration + '404': + description: Not found post: description: Configuration option to update with new value operationId: update_config_option @@ -774,14 +776,14 @@ paths: properties: value: type: - - number - - string + - number + - string variable: pattern: ^[_a-zA-Z0-9]+$ type: string required: - - variable - - value + - variable + - value type: object required: true responses: @@ -793,19 +795,21 @@ paths: properties: value: type: - - number - - string + - number + - string variable: type: string required: - - variable - - value + - variable + - value type: object description: Configuration option is updated '400': content: application/json: {} description: Bad request + '404': + description: Not found /_localstack/diagnose: get: description: Get diagnostics report @@ -820,6 +824,8 @@ paths: properties: config: type: object + docker-dependent-image-hashes: + type: object docker-dependent-image-hosts: type: object docker-inspect: @@ -836,7 +842,7 @@ paths: docker: type: string required: - - docker + - docker type: object services: type: object @@ -851,7 +857,7 @@ paths: kernel: type: string required: - - kernel + - kernel type: object image-version: additionalProperties: false @@ -865,47 +871,47 @@ paths: tag: type: string required: - - id - - sha256 - - tag - - created + - id + - sha256 + - tag + - created type: object localstack-version: additionalProperties: false properties: build-date: type: - - string - - 'null' + - string + - 'null' build-git-hash: type: - - string - - 'null' + - string + - 'null' build-version: type: - - string - - 'null' + - string + - 'null' required: - - build-date - - build-git-hash - - build-version + - build-date + - build-git-hash + - build-version type: object required: - - image-version - - localstack-version - - host + - image-version + - localstack-version + - host type: object required: - - version - - info - - services - - config - - docker-inspect - - docker-dependent-image-hosts - - file-tree - - important-endpoints - - logs - - usage + - version + - info + - services + - config + - docker-inspect + - docker-dependent-image-hosts + - file-tree + - important-endpoints + - logs + - usage type: object description: Diagnostics report /_localstack/health: @@ -914,12 +920,12 @@ paths: operationId: get_features_and_services tags: [localstack] parameters: - - allowEmptyValue: true - in: query - name: reload - required: false - schema: - type: string + - allowEmptyValue: true + in: query + name: reload + required: false + schema: + type: string responses: '200': content: @@ -929,10 +935,10 @@ paths: properties: edition: enum: - - community - - pro - - enterprise - - unknown + - community + - pro + - enterprise + - unknown type: string features: type: object @@ -941,9 +947,9 @@ paths: version: type: string required: - - edition - - services - - version + - edition + - services + - version type: object description: Available LocalStack features and AWS services head: @@ -966,11 +972,11 @@ paths: properties: action: enum: - - restart - - kill + - restart + - kill type: string required: - - action + - action type: object description: Action to perform required: true @@ -1003,7 +1009,7 @@ paths: status: type: string required: - - status + - status type: object description: Data was saved /_localstack/info: @@ -1036,11 +1042,11 @@ paths: operationId: get_init_script_info_stage tags: [localstack] parameters: - - in: path - name: stage - required: true - schema: - type: string + - in: path + name: stage + required: true + schema: + type: string responses: '200': content: @@ -1048,6 +1054,12 @@ paths: schema: $ref: '#/components/schemas/InitScriptsStage' description: Information about init scripts in a specific stage + '404': + content: + text/plain: + schema: + type: string + description: Stage not found /_localstack/plugins: get: description: '' diff --git a/localstack-core/localstack/packages/api.py b/localstack-core/localstack/packages/api.py index 04d50b0012f87..88a9e4a54b63b 100644 --- a/localstack-core/localstack/packages/api.py +++ b/localstack-core/localstack/packages/api.py @@ -3,10 +3,11 @@ import logging import os from collections import defaultdict +from collections.abc import Callable from enum import Enum from inspect import getmodule -from threading import RLock -from typing import Any, Callable, Generic, Optional, ParamSpec, TypeVar +from threading import Lock, RLock +from typing import Any, Generic, ParamSpec, TypeVar from plux import Plugin, PluginManager, PluginSpec # type: ignore @@ -56,7 +57,7 @@ class PackageInstaller(abc.ABC): multiple versions). """ - def __init__(self, name: str, version: str, install_lock: Optional[RLock] = None): + def __init__(self, name: str, version: str, install_lock: Lock | None = None): """ :param name: technical package name, f.e. "opensearch" :param version: version of the package to install @@ -70,7 +71,7 @@ def __init__(self, name: str, version: str, install_lock: Optional[RLock] = None self.install_lock = install_lock or RLock() self._setup_for_target: dict[InstallTarget, bool] = defaultdict(lambda: False) - def install(self, target: Optional[InstallTarget] = None) -> None: + def install(self, target: InstallTarget | None = None) -> None: """ Performs the package installation. @@ -210,7 +211,7 @@ def get_installed_dir(self, version: str | None = None) -> str | None: """ return self.get_installer(version).get_installed_dir() - def install(self, version: str | None = None, target: Optional[InstallTarget] = None) -> None: + def install(self, version: str | None = None, target: InstallTarget | None = None) -> None: """ Installs the package in the given version in the preferred target location. :param version: version of the package to install. If None, the default version of the package will be used. @@ -274,7 +275,7 @@ def __init__(self, name: str, version: str, package_installer: list[PackageInsta assert len(package_installer) > 0 self.package_installer = package_installer - def install(self, target: Optional[InstallTarget] = None) -> None: + def install(self, target: InstallTarget | None = None) -> None: """ Installs the different packages this installer is composed of. @@ -356,7 +357,7 @@ def get_all_packages(self) -> list[tuple[str, str, Package[PackageInstaller]]]: ) def get_packages( - self, package_names: list[str], version: Optional[str] = None + self, package_names: list[str], version: str | None = None ) -> list[Package[PackageInstaller]]: # Plugin names are unique, but there could be multiple packages with the same name in different scopes plugin_specs_per_name = defaultdict(list) @@ -390,7 +391,7 @@ def get_packages( def package( name: str | None = None, scope: str = "community", - should_load: Optional[Callable[[], bool]] = None, + should_load: Callable[[], bool] | None = None, ) -> Callable[[Callable[[], Package[Any] | list[Package[Any]]]], PluginSpec]: """ Decorator for marking methods that create Package instances as a PackagePlugin. diff --git a/localstack-core/localstack/packages/core.py b/localstack-core/localstack/packages/core.py index fcc9ed180e19b..c969521f9872e 100644 --- a/localstack-core/localstack/packages/core.py +++ b/localstack-core/localstack/packages/core.py @@ -4,7 +4,7 @@ from abc import ABC from functools import lru_cache from sys import version_info -from typing import Any, Optional +from typing import Any import requests @@ -238,7 +238,7 @@ def __init__( self, package_name: str, version: str, - package_spec: Optional[str] = None, + package_spec: str | None = None, main_module: str = "main.js", ): """ diff --git a/localstack-core/localstack/packages/java.py b/localstack-core/localstack/packages/java.py index 83ed684e8d49a..eeb51fd2885d1 100644 --- a/localstack-core/localstack/packages/java.py +++ b/localstack-core/localstack/packages/java.py @@ -46,6 +46,11 @@ def get_java_lib_path(self) -> str | None: """ if java_home := self.get_java_home(): if is_mac_os(): + # location in JRE versions 12+, see https://bugs.openjdk.org/browse/JDK-8210931 + jli_path = os.path.join(java_home, "lib", "libjli.dylib") + if os.path.isfile(jli_path): + return jli_path + # location in JRE versions 11- return os.path.join(java_home, "lib", "jli", "libjli.dylib") return os.path.join(java_home, "lib", "server", "libjvm.so") return None diff --git a/localstack-core/localstack/runtime/analytics.py b/localstack-core/localstack/runtime/analytics.py index a4a18b95d6eaf..1afd0dab777e9 100644 --- a/localstack-core/localstack/runtime/analytics.py +++ b/localstack-core/localstack/runtime/analytics.py @@ -1,16 +1,19 @@ import logging import os -from localstack import config from localstack.runtime import hooks from localstack.utils.analytics import log LOG = logging.getLogger(__name__) +# Config options for which both usage and values are reported in analytics. +# Important: This list must only contain options whose values do not contain PII or sensitive data. TRACKED_ENV_VAR = [ "ACTIVATE_PRO", "ALLOW_NONSTANDARD_REGIONS", "BEDROCK_PREWARM", + "CFN_IGNORE_UNSUPPORTED_TYPE_CREATE", + "CFN_IGNORE_UNSUPPORTED_TYPE_UPDATE", "CFN_IGNORE_UNSUPPORTED_RESOURCE_TYPES", "CLOUDFRONT_LAMBDA_EDGE", "CONTAINER_RUNTIME", @@ -26,9 +29,12 @@ "DYNAMODB_IN_MEMORY", "DYNAMODB_REMOVE_EXPIRED_ITEMS", "EAGER_SERVICE_LOADING", + "EC2_DOCKER_INIT", "EC2_VM_MANAGER", "ECS_TASK_EXECUTOR", "EDGE_PORT", + "EKS_K8S_PROVIDER", + "EKS_PERSIST_CLUSTER_CONTENTS", "ENABLE_REPLICATOR", "ENFORCE_IAM", "ES_CUSTOM_BACKEND", # deprecated in 0.14.0, removed in 3.0.0 @@ -71,9 +77,15 @@ "USE_SSL", ] +# Config options for which only the usage is reported in analytics. +# Use this for options which may hold sensitive data or PII. PRESENCE_ENV_VAR = [ "DATA_DIR", "EDGE_FORWARD_URL", # Not functional; deprecated in 1.4.0, removed in 3.0.0 + "EC2_HYPERVISOR_URI", + "EC2_REFERENCE_DOMAIN", + "EC2_LIBVIRT_NETWORK", + "EC2_LIBVIRT_POOL", "GATEWAY_LISTEN", "HOSTNAME", "HOSTNAME_EXTERNAL", @@ -108,33 +120,8 @@ def _publish_config_as_analytics_event(): env_vars = {key: os.getenv(key) for key in env_vars} present_env_vars = {env_var: 1 for env_var in PRESENCE_ENV_VAR if os.getenv(env_var)} - log.event("config", env_vars=env_vars, set_vars=present_env_vars) - - -class LocalstackContainerInfo: - def get_image_variant(self) -> str: - for f in os.listdir("/usr/lib/localstack"): - if f.startswith(".") and f.endswith("-version"): - return f[1:-8] - return "unknown" - - def has_docker_socket(self) -> bool: - return os.path.exists("/run/docker.sock") - - def to_dict(self): - return { - "variant": self.get_image_variant(), - "has_docker_socket": self.has_docker_socket(), - } + # filter out irrelevant None values, making the payload significantly smaller. + env_vars = {k: v for k, v in env_vars.items() if v is not None} + present_env_vars = {k: v for k, v in present_env_vars.items() if v is not None} - -@hooks.on_infra_start() -def _publish_container_info(): - if not config.is_in_docker: - return - - try: - log.event("container_info", payload=LocalstackContainerInfo().to_dict()) - except Exception as e: - if config.DEBUG_ANALYTICS: - LOG.debug("error gathering container information: %s", e) + log.event("config", env_vars=env_vars, set_vars=present_env_vars) diff --git a/localstack-core/localstack/services/acm/provider.py b/localstack-core/localstack/services/acm/provider.py index 7425b88832e6b..97873fd2d1cb3 100644 --- a/localstack-core/localstack/services/acm/provider.py +++ b/localstack-core/localstack/services/acm/provider.py @@ -10,12 +10,23 @@ RequestCertificateResponse, ) from localstack.services import moto +from localstack.state import StateVisitor from localstack.utils.patch import patch # reduce the validation wait time from 60 (default) to 10 seconds moto_settings.ACM_VALIDATION_WAIT = min(10, moto_settings.ACM_VALIDATION_WAIT) +@patch(acm_models.AWSCertificateManagerBackend.list_certificates) +def list_certificates(list_certificates_orig, self, statuses, includes): + # Normalize keyTypes filter to match our describe() output format (hyphens) + if includes and "keyTypes" in includes: + includes["keyTypes"] = [ + kt.replace("RSA_", "RSA-").replace("EC_", "EC-") for kt in includes["keyTypes"] + ] + return list_certificates_orig(self, statuses, includes) + + @patch(acm_models.CertBundle.describe) def describe(describe_orig, self): # TODO fix! Terrible hack (for parity). Moto adds certain required fields only if status is PENDING_VALIDATION. @@ -70,8 +81,10 @@ def describe(describe_orig, self): cert[key] = value cert["Serial"] = str(cert.get("Serial") or "") - if cert.get("KeyAlgorithm") in ["RSA_1024", "RSA_2048"]: + if cert.get("KeyAlgorithm") in ["RSA_1024", "RSA_2048", "RSA_3072", "RSA_4096"]: cert["KeyAlgorithm"] = cert["KeyAlgorithm"].replace("RSA_", "RSA-") + if cert.get("KeyAlgorithm") in ["EC_prime256v1", "EC_secp384r1", "EC_secp521r1"]: + cert["KeyAlgorithm"] = cert["KeyAlgorithm"].replace("EC_", "EC-") # add subject alternative names if cert["DomainName"] not in sans: @@ -100,6 +113,9 @@ def describe(describe_orig, self): class AcmProvider(AcmApi): + def accept_state_visitor(self, visitor: StateVisitor): + visitor.visit(acm_models.acm_backends) + @handler("RequestCertificate", expand=False) def request_certificate( self, diff --git a/localstack-core/localstack/services/apigateway/helpers.py b/localstack-core/localstack/services/apigateway/helpers.py index 74b988753a7a9..75337e5f1807e 100644 --- a/localstack-core/localstack/services/apigateway/helpers.py +++ b/localstack-core/localstack/services/apigateway/helpers.py @@ -23,7 +23,7 @@ IntegrationType, Model, NotFoundException, - PutRestApiRequest, + PutMode, RequestValidator, ) from localstack.constants import ( @@ -39,8 +39,7 @@ apigateway_stores, ) from localstack.utils import common -from localstack.utils.json import parse_json_or_yaml -from localstack.utils.strings import short_uid, to_bytes, to_str +from localstack.utils.strings import short_uid, to_bytes from localstack.utils.urls import localstack_host LOG = logging.getLogger(__name__) @@ -456,6 +455,9 @@ def add_documentation_parts(rest_api_container, documentation): for doc_part in documentation.get("documentationParts", []): entity_id = short_uid()[:6] location = doc_part["location"] + properties = doc_part["properties"] + if not isinstance(properties, str): + properties = json.dumps(properties) rest_api_container.documentation_parts[entity_id] = DocumentationPart( id=entity_id, location=DocumentationPartLocation( @@ -467,16 +469,14 @@ def add_documentation_parts(rest_api_container, documentation): statusCode=location.get("statusCode"), name=location.get("name"), ), - properties=doc_part["properties"], + properties=properties, ) def import_api_from_openapi_spec( - rest_api: MotoRestAPI, context: RequestContext, request: PutRestApiRequest + rest_api: MotoRestAPI, context: RequestContext, open_api_spec: dict, mode: PutMode ) -> tuple[MotoRestAPI, list[str]]: """Import an API from an OpenAPI spec document""" - body = parse_json_or_yaml(to_str(request["body"].read())) - warnings = [] # TODO There is an issue with the botocore specs so the parameters doesn't get populated as it should @@ -484,15 +484,14 @@ def import_api_from_openapi_spec( # query_params = request.get("parameters") or {} query_params: dict = context.request.values.to_dict() - resolved_schema = resolve_references(copy.deepcopy(body), rest_api_id=rest_api.id) + resolved_schema = resolve_references(copy.deepcopy(open_api_spec), rest_api_id=rest_api.id) account_id = context.account_id region_name = context.region # TODO: - # 1. validate the "mode" property of the spec document, "merge" or "overwrite", and properly apply it + # 1. properly apply the mode (overwrite or merge) # for now, it only considers it for the binaryMediaTypes # 2. validate the document type, "swagger" or "openapi" - mode = request.get("mode", "merge") rest_api.version = ( str(version) if (version := resolved_schema.get("info", {}).get("version")) else None @@ -988,20 +987,20 @@ def is_variable_path(path_part: str) -> bool: return path_part.startswith("{") and path_part.endswith("}") -def get_domain_name_hash(domain_name: str) -> str: +def get_domain_name_hash(domain_name: str, region_name: str) -> str: """ Return a hash of the given domain name, which help construct regional domain names for APIs. TODO: use this in the future to dispatch API Gateway API invocations made to the regional domain name """ - return hashlib.shake_128(to_bytes(domain_name)).hexdigest(4) + return hashlib.shake_128(to_bytes(domain_name + region_name)).hexdigest(4) -def get_regional_domain_name(domain_name: str) -> str: +def get_regional_domain_name(domain_name: str, region_name: str) -> str: """ Return the regional domain name for the given domain name. In real AWS, this would look something like: "d-oplm2qchq0.execute-api.us-east-1.amazonaws.com" In LocalStack, we're returning this format: "d-.execute-api.localhost.localstack.cloud" """ - domain_name_hash = get_domain_name_hash(domain_name) + domain_name_hash = get_domain_name_hash(domain_name, region_name) host = localstack_host().host return f"d-{domain_name_hash}.execute-api.{host}" diff --git a/localstack-core/localstack/services/apigateway/legacy/provider.py b/localstack-core/localstack/services/apigateway/legacy/provider.py index 31b42e6e171fe..c946f0a7733d4 100644 --- a/localstack-core/localstack/services/apigateway/legacy/provider.py +++ b/localstack-core/localstack/services/apigateway/legacy/provider.py @@ -42,6 +42,7 @@ DomainName, DomainNames, DomainNameStatus, + EndpointAccessMode, EndpointConfiguration, EndpointType, ExportResponse, @@ -93,6 +94,7 @@ UsagePlans, VpcLink, VpcLinks, + VpcLinkStatus, ) from localstack.aws.connect import connect_to from localstack.aws.forwarder import create_aws_request_context @@ -117,7 +119,11 @@ from localstack.services.apigateway.legacy.helpers import multi_value_dict_for_list from localstack.services.apigateway.legacy.invocations import invoke_rest_api_from_request from localstack.services.apigateway.legacy.router_asf import ApigatewayRouter, to_invocation_context -from localstack.services.apigateway.models import ApiGatewayStore, RestApiContainer +from localstack.services.apigateway.models import ( + ApiGatewayStore, + RestApiContainer, + apigateway_stores, +) from localstack.services.apigateway.next_gen.execute_api.router import ( ApiGatewayRouter as ApiGatewayRouterNextGen, ) @@ -125,6 +131,7 @@ from localstack.services.edge import ROUTER from localstack.services.moto import call_moto, call_moto_with_request from localstack.services.plugins import ServiceLifecycleHook +from localstack.state import StateVisitor from localstack.utils.aws.arns import InvalidArnException, get_partition, parse_arn from localstack.utils.collections import ( DelSafeDict, @@ -191,6 +198,12 @@ def on_after_init(self): apply_patches() self.router.register_routes() + def accept_state_visitor(self, visitor: StateVisitor): + from moto.apigateway import apigateway_backends + + visitor.visit(apigateway_backends) + visitor.visit(apigateway_stores) + @handler("TestInvokeMethod", expand=False) def test_invoke_method( self, context: RequestContext, request: TestInvokeMethodRequest @@ -323,8 +336,18 @@ def create_api_key( tags: MapOfStringToString = None, **kwargs, ) -> ApiKey: + if name and len(name) > 1024: + raise BadRequestException("Invalid API Key name, can be at most 1024 characters.") + if value: + if len(value) > 128: + raise BadRequestException("API Key value exceeds maximum size of 128 characters") + elif len(value) < 20: + raise BadRequestException("API Key value should be at least 20 characters") + if description and len(description) > 125000: + raise BadRequestException("Invalid API Key description specified.") api_key = call_moto(context) - + if name == "": + api_key.pop("name", None) # transform array of stage keys [{'restApiId': '0iscapk09u', 'stageName': 'dev'}] into # array of strings ['0iscapk09u/dev'] stage_keys = api_key.get("stageKeys", []) @@ -466,11 +489,19 @@ def update_rest_api( @handler("PutRestApi", expand=False) def put_rest_api(self, context: RequestContext, request: PutRestApiRequest) -> RestApi: + body_data = request["body"].read() + try: + openapi_spec = parse_json_or_yaml(to_str(body_data)) + except Exception: + raise BadRequestException("Invalid OpenAPI input.") # TODO: take into account the mode: overwrite or merge # the default is now `merge`, but we are removing everything rest_api = get_moto_rest_api(context, request["restApiId"]) rest_api, warnings = import_api_from_openapi_spec( - rest_api, context=context, request=request + rest_api, + context=context, + open_api_spec=openapi_spec, + mode=request.get("mode") or PutMode.merge, ) rest_api.root_resource_id = get_moto_rest_api_root_resource(rest_api) @@ -493,20 +524,21 @@ def create_domain_name( self, context: RequestContext, domain_name: String, - certificate_name: String = None, - certificate_body: String = None, - certificate_private_key: String = None, - certificate_chain: String = None, - certificate_arn: String = None, - regional_certificate_name: String = None, - regional_certificate_arn: String = None, - endpoint_configuration: EndpointConfiguration = None, - tags: MapOfStringToString = None, - security_policy: SecurityPolicy = None, - mutual_tls_authentication: MutualTlsAuthenticationInput = None, - ownership_verification_certificate_arn: String = None, - policy: String = None, - routing_mode: RoutingMode = None, + certificate_name: String | None = None, + certificate_body: String | None = None, + certificate_private_key: String | None = None, + certificate_chain: String | None = None, + certificate_arn: String | None = None, + regional_certificate_name: String | None = None, + regional_certificate_arn: String | None = None, + endpoint_configuration: EndpointConfiguration | None = None, + tags: MapOfStringToString | None = None, + security_policy: SecurityPolicy | None = None, + endpoint_access_mode: EndpointAccessMode | None = None, + mutual_tls_authentication: MutualTlsAuthenticationInput | None = None, + ownership_verification_certificate_arn: String | None = None, + policy: String | None = None, + routing_mode: RoutingMode | None = None, **kwargs, ) -> DomainName: if not domain_name: @@ -530,7 +562,7 @@ def create_domain_name( domainName=domain_name, certificateName=certificate_name, certificateArn=certificate_arn, - regionalDomainName=get_regional_domain_name(domain_name), + regionalDomainName=get_regional_domain_name(domain_name, context.region), domainNameStatus=DomainNameStatus.AVAILABLE, regionalHostedZoneId=zone_id, regionalCertificateName=regional_certificate_name, @@ -1142,6 +1174,10 @@ def get_stages( self._patch_stage_response(stage) if not stage.get("description"): stage.pop("description", None) + if deployment_id: + response["item"] = [ + s for s in response["item"] if s.get("deploymentId") == deployment_id + ] return Stages(**response) @handler("UpdateStage") @@ -1502,7 +1538,10 @@ def import_documentation_parts( **kwargs, ) -> DocumentationPartIds: body_data = body.read() - openapi_spec = parse_json_or_yaml(to_str(body_data)) + try: + openapi_spec = parse_json_or_yaml(to_str(body_data)) + except Exception: + raise BadRequestException("Unable to build importer with provided input.") rest_api_container = get_rest_api_container(context, rest_api_id=rest_api_id) @@ -1516,6 +1555,7 @@ def import_documentation_parts( rest_api_container.documentation_parts.clear() for doc_part in documentation["documentationParts"]: entity_id = short_uid()[:6] + doc_part["properties"] = json.dumps(doc_part.get("properties", "")) rest_api_container.documentation_parts[entity_id] = DocumentationPart( id=entity_id, **doc_part ) @@ -1787,11 +1827,31 @@ def create_vpc_link( tags: MapOfStringToString = None, **kwargs, ) -> VpcLink: + # TODO add tag support + if not name: + raise BadRequestException("Name cannot be empty") + for arn in target_arns: + try: + parse_arn(arn) + except InvalidArnException: + raise BadRequestException(f"Invalid ARN. ARN is not well formed {arn}") + region_details = get_apigateway_store(context=context) link_id = short_uid() - entry = {"id": link_id, "status": "AVAILABLE"} + entry = { + "id": link_id, + "status": VpcLinkStatus.PENDING, + "name": name, + "description": description, + "targetArns": target_arns, + } region_details.vpc_links[link_id] = entry result = to_vpc_link_response_json(entry) + + # update the status and status message of the store object + entry["status"] = VpcLinkStatus.AVAILABLE + entry["statusMessage"] = "Your vpc link is ready for use" + return VpcLink(**result) def get_vpc_links( @@ -1811,7 +1871,7 @@ def get_vpc_link(self, context: RequestContext, vpc_link_id: String, **kwargs) - region_details = get_apigateway_store(context=context) vpc_link = region_details.vpc_links.get(vpc_link_id) if vpc_link is None: - raise NotFoundException(f'VPC link ID "{vpc_link_id}" not found') + raise NotFoundException("Invalid Vpc Link identifier specified") result = to_vpc_link_response_json(vpc_link) return VpcLink(**result) @@ -1825,7 +1885,7 @@ def update_vpc_link( region_details = get_apigateway_store(context=context) vpc_link = region_details.vpc_links.get(vpc_link_id) if vpc_link is None: - raise NotFoundException(f'VPC link ID "{vpc_link_id}" not found') + raise NotFoundException("Invalid Vpc Link identifier specified") result = apply_json_patch_safe(vpc_link, patch_operations) result = to_vpc_link_response_json(result) return VpcLink(**result) @@ -1834,7 +1894,7 @@ def delete_vpc_link(self, context: RequestContext, vpc_link_id: String, **kwargs region_details = get_apigateway_store(context=context) vpc_link = region_details.vpc_links.pop(vpc_link_id, None) if vpc_link is None: - raise NotFoundException(f'VPC link ID "{vpc_link_id}" not found for deletion') + raise NotFoundException("Invalid Vpc Link identifier specified") # request validators @@ -2002,7 +2062,11 @@ def import_rest_api( body_data = body.read() # create rest api - openapi_spec = parse_json_or_yaml(to_str(body_data)) + try: + openapi_spec = parse_json_or_yaml(to_str(body_data)) + except Exception: + raise BadRequestException("Invalid OpenAPI input.") + create_api_request = CreateRestApiRequest(name=openapi_spec.get("info").get("title")) create_api_context = create_custom_context( context, @@ -2043,17 +2107,39 @@ def get_integration( **kwargs, ) -> Integration: try: - response: Integration = call_moto(context) - except CommonServiceException as e: - # the Exception raised by moto does not have the right message not status code - if e.code == "NotFoundException": - raise NotFoundException("Invalid Integration identifier specified") - raise + moto_rest_api = get_moto_rest_api(context, rest_api_id) + except NotFoundException: + raise NotFoundException("Invalid Resource identifier specified") + + if not (moto_resource := moto_rest_api.resources.get(resource_id)): + raise NotFoundException("Invalid Resource identifier specified") + + if not (moto_method := moto_resource.resource_methods.get(http_method)): + raise NotFoundException("Invalid Method identifier specified") + + if not moto_method.method_integration: + raise NotFoundException("Invalid Integration identifier specified") + + response: Integration = call_moto(context) if integration_responses := response.get("integrationResponses"): for integration_response in integration_responses.values(): remove_empty_attributes_from_integration_response(integration_response) + if response.get("connectionType") == "VPC_LINK": + # FIXME: this is hacky to workaround moto not saving the VPC Link `connectionId` + # only do this internal check of Moto if the integration is of VPC_LINK type + moto_rest_api = get_moto_rest_api(context=context, rest_api_id=rest_api_id) + try: + method = moto_rest_api.resources[resource_id].resource_methods[http_method] + integration = method.method_integration + if connection_id := getattr(integration, "connection_id", None): + response["connectionId"] = connection_id + + except (AttributeError, KeyError): + # this error should have been caught by `call_moto` + pass + return response def put_integration( @@ -2108,6 +2194,7 @@ def put_integration( moto_request.setdefault("timeoutInMillis", 29000) if integration_type in (IntegrationType.HTTP, IntegrationType.HTTP_PROXY): moto_request.setdefault("connectionType", ConnectionType.INTERNET) + response = call_moto_with_request(context, moto_request) remove_empty_attributes_from_integration(integration=response) @@ -2115,6 +2202,13 @@ def put_integration( if integration_type == "MOCK": response.pop("uri", None) + # TODO: moto does not save the connection_id + elif moto_request.get("connectionType") == "VPC_LINK": + connection_id = moto_request.get("connectionId", "") + # attach the connection id to the moto object + method.method_integration.connection_id = connection_id + response["connectionId"] = connection_id + return response def update_integration( @@ -2136,6 +2230,7 @@ def update_integration( raise NotFoundException("Invalid Integration identifier specified") integration = method.method_integration + # TODO: validate the patch operations patch_api_gateway_entity(integration, patch_operations) # fix data types @@ -2144,8 +2239,12 @@ def update_integration( if skip_verification := (integration.tls_config or {}).get("insecureSkipVerification"): integration.tls_config["insecureSkipVerification"] = str_to_bool(skip_verification) - integration_dict: Integration = integration.to_json() - return integration_dict + response: Integration = integration.to_json() + + if connection_id := getattr(integration, "connection_id", None): + response["connectionId"] = connection_id + + return response def delete_integration( self, @@ -2393,6 +2492,10 @@ def get_api_keys( for api_key in api_keys: api_key.pop("value") + if limit is not None: + if limit < 1 or limit > 500: + limit = None + item_list = PaginatedList(api_keys) def token_generator(item): @@ -2417,6 +2520,14 @@ def update_api_key( patch_operations: ListOfPatchOperation = None, **kwargs, ) -> ApiKey: + for patch_op in patch_operations: + if patch_op["path"] not in ("/description", "/enabled", "/name", "/customerId"): + raise BadRequestException( + f"Invalid patch path '{patch_op['path']}' specified for op '{patch_op['op']}'. Must be one of: [/description, /enabled, /name, /customerId]" + ) + + if patch_op["path"] == "/description" and len(patch_op["value"]) > 125000: + raise BadRequestException("Invalid API Key description specified.") response: ApiKey = call_moto(context) if "value" in response: response.pop("value", None) diff --git a/localstack-core/localstack/services/apigateway/models.py b/localstack-core/localstack/services/apigateway/models.py index e287210f1a4f3..c5b04f4211e97 100644 --- a/localstack-core/localstack/services/apigateway/models.py +++ b/localstack-core/localstack/services/apigateway/models.py @@ -1,9 +1,10 @@ from typing import Any -from requests.structures import CaseInsensitiveDict - from localstack.aws.api.apigateway import ( + Account, Authorizer, + BasePathMapping, + ClientCertificate, DocumentationPart, DocumentationVersion, DomainName, @@ -13,6 +14,7 @@ RequestValidator, Resource, RestApi, + VpcLink, ) from localstack.services.stores import ( AccountRegionBundle, @@ -40,7 +42,7 @@ class RestApiContainer: # maps Model name -> Model models: dict[str, Model] # maps Model name -> resolved dict Model, so we don't need to load the JSON everytime - resolved_models: dict[str, dict] + resolved_models: dict[str, dict[str, Any]] # maps ResourceId of a Resource to its children ResourceIds resource_children: dict[str, list[str]] @@ -88,6 +90,10 @@ def from_rest_api_container( class RestApiDeployment: + account_id: str + region: str + rest_api: MergedRestApi + def __init__( self, account_id: str, @@ -101,20 +107,19 @@ def __init__( class ApiGatewayStore(BaseStore): # maps (API id) -> RestApiContainer - # TODO: remove CaseInsensitiveDict, and lower the value of the ID when getting it from the tags - rest_apis: dict[str, RestApiContainer] = LocalAttribute(default=CaseInsensitiveDict) + rest_apis: dict[str, RestApiContainer] = LocalAttribute(default=dict) # account details - _account: dict[str, Any] = LocalAttribute(default=dict) + _account: Account = LocalAttribute(default=dict) # maps (domain_name) -> [path_mappings] - base_path_mappings: dict[str, list[dict]] = LocalAttribute(default=dict) + base_path_mappings: dict[str, list[BasePathMapping]] = LocalAttribute(default=dict) # maps ID to VPC link details - vpc_links: dict[str, dict] = LocalAttribute(default=dict) + vpc_links: dict[str, VpcLink] = LocalAttribute(default=dict) # maps cert ID to client certificate details - client_certificates: dict[str, dict] = LocalAttribute(default=dict) + client_certificates: dict[str, ClientCertificate] = LocalAttribute(default=dict) # maps domain name to domain name model domain_names: dict[str, DomainName] = LocalAttribute(default=dict) @@ -137,7 +142,7 @@ def __init__(self): super().__init__() @property - def account(self): + def account(self) -> Account: if not self._account: self._account.update( { diff --git a/localstack-core/localstack/services/apigateway/next_gen/provider.py b/localstack-core/localstack/services/apigateway/next_gen/provider.py index ac1c0029fee67..9b87ea7cb8f15 100644 --- a/localstack-core/localstack/services/apigateway/next_gen/provider.py +++ b/localstack-core/localstack/services/apigateway/next_gen/provider.py @@ -149,10 +149,17 @@ def update_stage( if is_canary := patch_path.startswith("/canarySettings"): skip_moto_apply = True path_valid = is_canary_settings_update_patch_valid(op=patch_op, path=patch_path) - # it seems our JSON Patch utility does not handle replace properly if the value does not exists before + # it seems our JSON Patch utility does not handle replace properly if the value does not exist before # it seems to maybe be a Stage-only thing, so replacing it here if patch_op == "replace": patch_operation["op"] = "add" + elif patch_path.startswith("/accessLogSettings"): + validate_access_log_settings_update_patch_valid( + op=patch_op, path=patch_path, value=patch_operation.get("value") + ) + # for AccessLogSettings, Moto does support its patching, but does not support `add`, so we replace it + if patch_op == "add": + patch_operation["op"] = "replace" if patch_op == "copy": copy_from = patch_operation.get("from") @@ -479,6 +486,26 @@ def is_canary_settings_update_patch_valid(op: str, path: str) -> bool: return True +def validate_access_log_settings_update_patch_valid(op: str, path: str, value: str | None) -> None: + # See https://docs.aws.amazon.com/apigateway/latest/api/patch-operations.html#UpdateStage-Patch + # not everything is right on the table, for example no path supports `remove` accept the root path + # TODO: validate destinationArn is a valid ARN (does not have to validate it exists) + valid_paths = ["/accessLogSettings/destinationArn", "/accessLogSettings/format"] + if op == "remove": + if path != "/accessLogSettings": + stripped_path = path.removeprefix("/") + raise BadRequestException( + f"Cannot remove method setting {stripped_path} because there is no method setting for this method " + ) + elif op in ("add", "replace"): + if path not in valid_paths: + raise BadRequestException( + "Invalid accessLogSettings path. Must be one of : [/accessLogSettings/destinationArn, /accessLogSettings/format]" + ) + if not value: + raise BadRequestException("Access Log value must not be empty") + + def _get_gateway_response_or_default( response_type: GatewayResponseType, gateway_responses: dict[GatewayResponseType, GatewayResponse], diff --git a/localstack-core/localstack/services/apigateway/patches.py b/localstack-core/localstack/services/apigateway/patches.py index ca12f96284fff..6f9839f76d520 100644 --- a/localstack-core/localstack/services/apigateway/patches.py +++ b/localstack-core/localstack/services/apigateway/patches.py @@ -4,9 +4,8 @@ from moto.apigateway import models as apigateway_models from moto.apigateway.exceptions import ( + BadRequestException, DeploymentNotFoundException, - NoIntegrationDefined, - RestAPINotFound, StageStillActive, ) from moto.apigateway.responses import APIGatewayResponse @@ -113,14 +112,6 @@ def _get_default_method_settings(fn, self): ) return result - # patch integration error responses - @patch(apigateway_models.Resource.get_integration) - def apigateway_models_resource_get_integration(fn, self, method_type): - resource_method = self.resource_methods.get(method_type, {}) - if not resource_method.method_integration: - raise NoIntegrationDefined() - return resource_method.method_integration - @patch(apigateway_models.RestAPI.to_dict) def apigateway_models_rest_api_to_dict(fn, self): resp = fn(self) @@ -178,19 +169,19 @@ def create_rest_api(fn, self, *args, tags=None, **kwargs): """ tags = tags or {} result = fn(self, *args, tags=tags, **kwargs) - # TODO: lower the custom_id when getting it from the tags, as AWS is case insensitive + if custom_id := tags.get(TAG_KEY_CUSTOM_ID): self.apis.pop(result.id) result.id = custom_id self.apis[custom_id] = result - return result - @patch(apigateway_models.APIGatewayBackend.get_rest_api, pass_target=False) - def get_rest_api(self, function_id): - for key in self.apis.keys(): - if key.lower() == function_id.lower(): - return self.apis[key] - raise RestAPINotFound() + if not (result.id.islower() or result.id.isnumeric()): + self.apis.pop(result.id) + raise BadRequestException( + f"The RestApiId '{result.id}' cannot contain uppercase characters" + ) + + return result @patch(apigateway_models.RestAPI.delete_deployment, pass_target=False) def patch_delete_deployment(self, deployment_id: str) -> apigateway_models.Deployment: diff --git a/localstack-core/localstack/services/apigateway/resource_providers/aws_apigateway_basepathmapping.py b/localstack-core/localstack/services/apigateway/resource_providers/aws_apigateway_basepathmapping.py index 8b9378d53f7f0..4fa7006911c50 100644 --- a/localstack-core/localstack/services/apigateway/resource_providers/aws_apigateway_basepathmapping.py +++ b/localstack-core/localstack/services/apigateway/resource_providers/aws_apigateway_basepathmapping.py @@ -66,6 +66,7 @@ def create( } response = apigw.create_base_path_mapping(**params) model["RestApiId"] = response["restApiId"] + model["BasePath"] = response["basePath"] # TODO: validations return ProgressEvent( diff --git a/localstack-core/localstack/services/apigateway/resource_providers/aws_apigateway_stage.py b/localstack-core/localstack/services/apigateway/resource_providers/aws_apigateway_stage.py index 2c9fccbc051f4..df5f93623675e 100644 --- a/localstack-core/localstack/services/apigateway/resource_providers/aws_apigateway_stage.py +++ b/localstack-core/localstack/services/apigateway/resource_providers/aws_apigateway_stage.py @@ -102,7 +102,6 @@ def create( stage_variables = model.get("Variables") # we need to deep copy as several fields are nested dict and arrays params = keys_to_lower(copy.deepcopy(model)) - # TODO: add methodSettings # TODO: add custom CfN tags param_names = [ "restApiId", @@ -124,6 +123,23 @@ def create( result = apigw.create_stage(**params) model["StageName"] = result["stageName"] + # TODO: add methodSettings with the same principle + patch_operations = [] + if access_log_settings := model.get("AccessLogSetting"): + access_patch_ops = [ + {"op": "replace", "path": f"/accessLogSettings/{key}", "value": value} + for key, value in keys_to_lower(copy.deepcopy(access_log_settings)).items() + if value + ] + patch_operations.extend(access_patch_ops) + + if patch_operations: + apigw.update_stage( + restApiId=params["restApiId"], + stageName=stage_name, + patchOperations=patch_operations, + ) + return ProgressEvent( status=OperationStatus.SUCCESS, resource_model=model, diff --git a/localstack-core/localstack/services/cloudformation/analytics.py b/localstack-core/localstack/services/cloudformation/analytics.py index 80ec4d1960005..95bae2b357bf2 100644 --- a/localstack-core/localstack/services/cloudformation/analytics.py +++ b/localstack-core/localstack/services/cloudformation/analytics.py @@ -1,12 +1,17 @@ import enum +import traceback from typing import Self from localstack.aws.api.cloudformation import ChangeAction +from localstack.utils.analytics import log from localstack.utils.analytics.metrics import LabeledCounter COUNTER_NAMESPACE = "cloudformation" COUNTER_VERSION = 2 +FAILURE_ANALYTICS_NAMESPACE = "cfn_stack_deploy_failures" +FAILURE_ANALYTICS_VERSION = 1 + class ActionOptions(enum.StrEnum): """ @@ -65,3 +70,22 @@ def track_resource_operation( missing=missing, action=ActionOptions.from_action(action), ).increment() + + +def emit_stack_failure(reason: str, exception: Exception | None = None) -> None: + """ + Capture the stack failure reason in telemetry + """ + + payload = { + "reason": reason, + "version": FAILURE_ANALYTICS_VERSION, + } + if exception: + tb = "".join(traceback.format_exception(exception)) + payload["tb"] = tb + + log.event( + FAILURE_ANALYTICS_NAMESPACE, + payload, + ) diff --git a/localstack-core/localstack/services/cloudformation/cfn_utils.py b/localstack-core/localstack/services/cloudformation/cfn_utils.py index 9cac04969abbe..20a0399393d38 100644 --- a/localstack-core/localstack/services/cloudformation/cfn_utils.py +++ b/localstack-core/localstack/services/cloudformation/cfn_utils.py @@ -19,10 +19,8 @@ def do_rename(account_id, region_name, params, logical_resource_id, *args, **kwa def lambda_convert_types(func, types): - return ( - lambda account_id, region_name, params, logical_resource_id, *args, **kwargs: convert_types( - func(account_id, region_name, params, *args, **kwargs), types - ) + return lambda account_id, region_name, params, logical_resource_id, *args, **kwargs: ( + convert_types(func(account_id, region_name, params, *args, **kwargs), types) ) @@ -42,13 +40,8 @@ def recurse(o, path): return o func = func or (lambda account_id, region_name, x, logical_resource_id, *args, **kwargs: x) - return ( - lambda account_id, - region_name, - params, - logical_resource_id, - *args, - **kwargs: recurse_object( + return lambda account_id, region_name, params, logical_resource_id, *args, **kwargs: ( + recurse_object( func(account_id, region_name, params, logical_resource_id, *args, **kwargs), recurse ) ) diff --git a/localstack-core/localstack/services/cloudformation/deploy.html b/localstack-core/localstack/services/cloudformation/deploy.html deleted file mode 100644 index 47af619288057..0000000000000 --- a/localstack-core/localstack/services/cloudformation/deploy.html +++ /dev/null @@ -1,144 +0,0 @@ - - - - - LocalStack - CloudFormation Deployment - - - - - - - - -
- - - diff --git a/localstack-core/localstack/services/cloudformation/deploy_ui.py b/localstack-core/localstack/services/cloudformation/deploy_ui.py deleted file mode 100644 index deac95b408b1f..0000000000000 --- a/localstack-core/localstack/services/cloudformation/deploy_ui.py +++ /dev/null @@ -1,47 +0,0 @@ -import json -import logging -import os - -import requests -from rolo import Response - -from localstack import constants -from localstack.utils.files import load_file -from localstack.utils.json import parse_json_or_yaml - -LOG = logging.getLogger(__name__) - - -class CloudFormationUi: - def on_get(self, request): - from localstack.utils.aws.aws_stack import get_valid_regions - - deploy_html_file = os.path.join( - constants.MODULE_MAIN_PATH, "services", "cloudformation", "deploy.html" - ) - deploy_html = load_file(deploy_html_file) - req_params = request.values - params = { - "stackName": "stack1", - "templateBody": "{}", - "errorMessage": "''", - "regions": json.dumps(sorted(get_valid_regions())), - } - - download_url = req_params.get("templateURL") - if download_url: - try: - LOG.debug("Attempting to download CloudFormation template URL: %s", download_url) - template_body = requests.get(download_url).text - template_body = parse_json_or_yaml(template_body) - params["templateBody"] = json.dumps(template_body) - except Exception as e: - msg = f"Unable to download CloudFormation template URL: {e}" - LOG.info(msg) - params["errorMessage"] = json.dumps(msg.replace("\n", " - ")) - - # using simple string replacement here, for simplicity (could be replaced with, e.g., jinja) - for key, value in params.items(): - deploy_html = deploy_html.replace(f"<{key}>", value) - - return Response(deploy_html, mimetype="text/html") diff --git a/localstack-core/localstack/services/cloudformation/deployment_utils.py b/localstack-core/localstack/services/cloudformation/deployment_utils.py index 771b2ac6bf724..fd25ec5dffc33 100644 --- a/localstack-core/localstack/services/cloudformation/deployment_utils.py +++ b/localstack-core/localstack/services/cloudformation/deployment_utils.py @@ -89,26 +89,16 @@ def do_replace(account_id: str, region_name: str, params, logical_resource_id, * def lambda_keys_to_lower(key=None, skip_children_of: list[str] = None): - return ( - lambda account_id, - region_name, - params, - logical_resource_id, - *args, - **kwargs: common.keys_to_lower( + return lambda account_id, region_name, params, logical_resource_id, *args, **kwargs: ( + common.keys_to_lower( obj=(params.get(key) if key else params), skip_children_of=skip_children_of ) ) def merge_parameters(func1, func2): - return ( - lambda account_id, - region_name, - properties, - logical_resource_id, - *args, - **kwargs: common.merge_dicts( + return lambda account_id, region_name, properties, logical_resource_id, *args, **kwargs: ( + common.merge_dicts( func1(account_id, region_name, properties, logical_resource_id, *args, **kwargs), func2(account_id, region_name, properties, logical_resource_id, *args, **kwargs), ) @@ -159,13 +149,8 @@ def lambda_select_params(*selected): def select_parameters(*param_names): - return ( - lambda account_id, - region_name, - properties, - logical_resource_id, - *args, - **kwargs: select_attributes(properties, param_names) + return lambda account_id, region_name, properties, logical_resource_id, *args, **kwargs: ( + select_attributes(properties, param_names) ) diff --git a/localstack-core/localstack/services/cloudformation/engine/template_preparer.py b/localstack-core/localstack/services/cloudformation/engine/template_preparer.py index 8206a7d6a99fc..db1265164ea6c 100644 --- a/localstack-core/localstack/services/cloudformation/engine/template_preparer.py +++ b/localstack-core/localstack/services/cloudformation/engine/template_preparer.py @@ -6,6 +6,7 @@ apply_global_transformations, apply_intrinsic_transformations, ) +from localstack.services.cloudformation.engine.validations import ValidationError from localstack.utils.json import clone_safe LOG = logging.getLogger(__name__) @@ -17,9 +18,12 @@ def parse_template(template: str) -> dict: except Exception: try: return clone_safe(yaml_parser.parse_yaml(template)) - except Exception as e: - LOG.debug("Unable to parse CloudFormation template (%s): %s", e, template) + except ValidationError: + # The error is handled in the yaml parsing helper raise + except Exception: + # TODO: present the user with a better error message including error location + raise ValidationError("Template format error: YAML not well-formed.") def template_to_json(template: str) -> str: diff --git a/localstack-core/localstack/services/cloudformation/engine/v2/change_set_model.py b/localstack-core/localstack/services/cloudformation/engine/v2/change_set_model.py index 35467cc9ed5b5..ac7d2e11b47da 100644 --- a/localstack-core/localstack/services/cloudformation/engine/v2/change_set_model.py +++ b/localstack-core/localstack/services/cloudformation/engine/v2/change_set_model.py @@ -4,9 +4,7 @@ import enum from collections.abc import Generator from itertools import zip_longest -from typing import Any, Final, TypedDict, cast - -from typing_extensions import TypeVar +from typing import Any, Final, TypedDict, TypeVar, cast from localstack.aws.api.cloudformation import ChangeAction from localstack.services.cloudformation.resource_provider import ResourceProviderExecutor @@ -813,19 +811,24 @@ def _resolve_intrinsic_function_fn_find_in_map(self, arguments: ChangeSetEntity) if arguments.change_type != ChangeType.UNCHANGED: return arguments.change_type # TODO: validate arguments structure and type. - # TODO: add support for nested functions, here we assume the arguments are string literals. if not isinstance(arguments, NodeArray) or not arguments.array: raise RuntimeError() argument_mapping_name = arguments.array[0] - if not isinstance(argument_mapping_name, TerminalValue): - raise NotImplementedError() argument_top_level_key = arguments.array[1] - if not isinstance(argument_top_level_key, TerminalValue): - raise NotImplementedError() argument_second_level_key = arguments.array[2] - if not isinstance(argument_second_level_key, TerminalValue): - raise NotImplementedError() + + # If any argument is not a terminal value (e.g., it contains nested intrinsic functions + # like Ref, Fn::Sub, etc.), we cannot perform the static mapping lookup at this stage. + # Instead, return the parent change type based on all arguments' change states. + if any( + not isinstance(arg, TerminalValue) + for arg in [argument_mapping_name, argument_top_level_key, argument_second_level_key] + ): + return parent_change_type_of( + [argument_mapping_name, argument_top_level_key, argument_second_level_key] + ) + mapping_name = argument_mapping_name.value top_level_key = argument_top_level_key.value second_level_key = argument_second_level_key.value @@ -876,10 +879,10 @@ def _resolve_requires_replacement( property.replace("/properties/", "", 1) for property in create_only_properties ] for node_property in node_properties.properties: - if ( - node_property.change_type == ChangeType.MODIFIED - and node_property.name in create_only_properties - ): + if node_property.name not in create_only_properties: + continue + + if node_property.change_type != ChangeType.UNCHANGED: return True return False @@ -1043,26 +1046,20 @@ def _visit_type(self, scope: Scope, before_type: Any, after_type: Any) -> Termin def _visit_deletion_policy( self, scope: Scope, before_deletion_policy: Any, after_deletion_policy: Any - ) -> TerminalValue: + ) -> ChangeSetEntity: value = self._visit_value( scope=scope, before_value=before_deletion_policy, after_value=after_deletion_policy ) - if not isinstance(value, TerminalValue): - # TODO: decide where template schema validation should occur. - raise RuntimeError() return value def _visit_update_replace_policy( self, scope: Scope, before_update_replace_policy: Any, after_deletion_policy: Any - ) -> TerminalValue: + ) -> ChangeSetEntity: value = self._visit_value( scope=scope, before_value=before_update_replace_policy, after_value=after_deletion_policy, ) - if not isinstance(value, TerminalValue): - # TODO: decide where template schema validation should occur. - raise RuntimeError() return value def _visit_resource( @@ -1169,6 +1166,15 @@ def _visit_resource( fn_transform, ], ) + + # special case of where either the before or after state does not specify properties but + # the resource was in the previous template + if ( + terminal_value_type.change_type == ChangeType.UNCHANGED + and properties.change_type != ChangeType.UNCHANGED + ): + change_type = ChangeType.MODIFIED + requires_replacement = self._resolve_requires_replacement( node_properties=properties, resource_type=terminal_value_type ) diff --git a/localstack-core/localstack/services/cloudformation/engine/v2/change_set_model_describer.py b/localstack-core/localstack/services/cloudformation/engine/v2/change_set_model_describer.py index a689225d172a0..672cd619d395f 100644 --- a/localstack-core/localstack/services/cloudformation/engine/v2/change_set_model_describer.py +++ b/localstack-core/localstack/services/cloudformation/engine/v2/change_set_model_describer.py @@ -20,6 +20,7 @@ PreprocResource, ) from localstack.services.cloudformation.v2.entities import ChangeSet +from localstack.utils.numbers import is_number CHANGESET_KNOWN_AFTER_APPLY: Final[str] = "{{changeSet:KNOWN_AFTER_APPLY}}" @@ -96,6 +97,19 @@ def _resolve_attribute(self, arguments: str | list[str], select_before: bool) -> return value + def visit_node_intrinsic_function(self, node_intrinsic_function: NodeIntrinsicFunction): + """ + Intrinsic function results are always strings when referring to the describe output + """ + # TODO: what about other places? + # TODO: should this be put in the preproc? + delta = super().visit_node_intrinsic_function(node_intrinsic_function) + if is_number(delta.before): + delta.before = str(delta.before) + if is_number(delta.after): + delta.after = str(delta.after) + return delta + def visit_node_intrinsic_function_fn_join( self, node_intrinsic_function: NodeIntrinsicFunction ) -> PreprocEntityDelta: diff --git a/localstack-core/localstack/services/cloudformation/engine/v2/change_set_model_executor.py b/localstack-core/localstack/services/cloudformation/engine/v2/change_set_model_executor.py index dcc8be4508716..249a91db45182 100644 --- a/localstack-core/localstack/services/cloudformation/engine/v2/change_set_model_executor.py +++ b/localstack-core/localstack/services/cloudformation/engine/v2/change_set_model_executor.py @@ -16,7 +16,10 @@ StackStatus, ) from localstack.constants import INTERNAL_AWS_SECRET_ACCESS_KEY -from localstack.services.cloudformation.analytics import track_resource_operation +from localstack.services.cloudformation.analytics import ( + emit_stack_failure, + track_resource_operation, +) from localstack.services.cloudformation.deployment_utils import log_not_available_message from localstack.services.cloudformation.engine.v2.change_set_model import ( NodeDependsOn, @@ -28,10 +31,15 @@ _AWS_URL_SUFFIX, MOCKED_REFERENCE, ChangeSetModelPreproc, + DeletionPolicy, PreprocEntityDelta, PreprocOutput, PreprocProperties, PreprocResource, + UpdateReplacePolicy, +) +from localstack.services.cloudformation.engine.v2.unsupported_resource import ( + should_ignore_unsupported_resource_type, ) from localstack.services.cloudformation.resource_provider import ( Credentials, @@ -106,14 +114,15 @@ def execute(self) -> ChangeSetModelExecutorResult: except Exception as e: failure_message = str(e) + is_deletion = self._change_set.stack.status == StackStatus.DELETE_IN_PROGRESS if self._deferred_actions: - if failure_message: - # TODO: differentiate between update and create - self._change_set.stack.set_stack_status(StackStatus.ROLLBACK_IN_PROGRESS) - else: + if not is_deletion: # TODO: correct status + # TODO: differentiate between update and create self._change_set.stack.set_stack_status( - StackStatus.UPDATE_COMPLETE_CLEANUP_IN_PROGRESS + StackStatus.ROLLBACK_IN_PROGRESS + if failure_message + else StackStatus.UPDATE_COMPLETE_CLEANUP_IN_PROGRESS ) # perform all deferred actions such as deletions. These must happen in reverse from their @@ -123,7 +132,7 @@ def execute(self) -> ChangeSetModelExecutorResult: LOG.debug("executing deferred action: '%s'", deferred.name) deferred.action() - if failure_message: + if failure_message and not is_deletion: # TODO: differentiate between update and create self._change_set.stack.set_stack_status(StackStatus.ROLLBACK_COMPLETE) @@ -161,19 +170,25 @@ def _process_event( resource_type: str, special_action: str = None, reason: str = None, + custom_status: ResourceStatus | str | None = None, ): status_from_action = special_action or EventOperationFromAction[action.value] + + status: ResourceStatus if event_status == OperationStatus.SUCCESS: - status = f"{status_from_action}_COMPLETE" + status = ResourceStatus(f"{status_from_action}_COMPLETE") else: - status = f"{status_from_action}_{event_status.name}" + status = ResourceStatus(f"{status_from_action}_{event_status.name}") + + if custom_status: + status = ResourceStatus(custom_status) physical_resource_id = self._get_physical_id(logical_resource_id, False) self._change_set.stack.set_resource_status( logical_resource_id=logical_resource_id, physical_resource_id=physical_resource_id, resource_type=resource_type, - status=ResourceStatus(status), + status=status, resource_status_reason=reason, ) @@ -331,27 +346,37 @@ def _execute_resource_change( ) def cleanup(): - self._process_event( - action=ChangeAction.Remove, - logical_resource_id=name, - event_status=OperationStatus.IN_PROGRESS, - resource_type=before.resource_type, - ) - event = self._execute_resource_action( - action=ChangeAction.Remove, - logical_resource_id=name, - resource_type=before.resource_type, - before_properties=before_properties, - after_properties=None, - part_of_replacement=True, - ) - self._process_event( - action=ChangeAction.Remove, - logical_resource_id=name, - event_status=event.status, - resource_type=before.resource_type, - reason=event.message, - ) + # TODO: handle other update replace policy values + if after.update_replace_policy != UpdateReplacePolicy.Retain: + self._process_event( + action=ChangeAction.Remove, + logical_resource_id=name, + event_status=OperationStatus.IN_PROGRESS, + resource_type=before.resource_type, + ) + event = self._execute_resource_action( + action=ChangeAction.Remove, + logical_resource_id=name, + resource_type=before.resource_type, + before_properties=before_properties, + after_properties=None, + part_of_replacement=True, + ) + self._process_event( + action=ChangeAction.Remove, + logical_resource_id=name, + event_status=event.status, + resource_type=before.resource_type, + reason=event.message, + ) + else: + self._process_event( + action=ChangeAction.Remove, + logical_resource_id=name, + event_status=OperationStatus.SUCCESS, + resource_type=before.resource_type, + custom_status=ResourceStatus.DELETE_SKIPPED, + ) self._defer_action(f"cleanup-from-replacement-{name}", cleanup) else: @@ -415,26 +440,37 @@ def perform_deletion(): before_properties = self._merge_before_properties(name, before) def perform_deletion(): - self._process_event( - action=ChangeAction.Remove, - logical_resource_id=name, - resource_type=before.resource_type, - event_status=OperationStatus.IN_PROGRESS, - ) - event = self._execute_resource_action( - action=ChangeAction.Remove, - logical_resource_id=name, - resource_type=before.resource_type, - before_properties=before_properties, - after_properties=None, - ) - self._process_event( - action=ChangeAction.Remove, - logical_resource_id=name, - event_status=event.status, - resource_type=before.resource_type, - reason=event.message, - ) + # TODO: other deletion policies + if before.deletion_policy != DeletionPolicy.Retain: + self._process_event( + action=ChangeAction.Remove, + logical_resource_id=name, + resource_type=before.resource_type, + event_status=OperationStatus.IN_PROGRESS, + ) + event = self._execute_resource_action( + action=ChangeAction.Remove, + logical_resource_id=name, + resource_type=before.resource_type, + before_properties=before_properties, + after_properties=None, + ) + + self._process_event( + action=ChangeAction.Remove, + logical_resource_id=name, + event_status=event.status, + resource_type=before.resource_type, + reason=event.message, + ) + else: + self._process_event( + action=ChangeAction.Remove, + logical_resource_id=name, + event_status=OperationStatus.SUCCESS, + resource_type=before.resource_type, + custom_status=ResourceStatus.DELETE_SKIPPED, + ) self._defer_action(f"remove-{name}", perform_deletion) elif not is_nothing(after): @@ -510,8 +546,11 @@ def _execute_resource_action( OperationStatus.FAILED, resource_model={}, message=f"Resource provider operation failed: {reason}", + custom_context={"exception": e}, ) - elif config.CFN_IGNORE_UNSUPPORTED_RESOURCE_TYPES: + elif should_ignore_unsupported_resource_type( + resource_type=resource_type, change_set_type=self._change_set.change_set_type + ): log_not_available_message( resource_type, f'No resource provider found for "{resource_type}"', @@ -575,7 +614,6 @@ def _execute_resource_action( ) # TODO: do we actually need this line? resolved_resource.update(extra_resource_properties) - case OperationStatus.FAILED: reason = event.message LOG.warning( @@ -584,6 +622,10 @@ def _execute_resource_action( ) resolved_resource["ResourceStatus"] = ResourceStatus(f"{status_from_action}_FAILED") resolved_resource["ResourceStatusReason"] = reason + + exception = event.custom_context.get("exception") + emit_stack_failure(reason, exception=exception) + case other: raise NotImplementedError(f"Event status '{other}' not handled") diff --git a/localstack-core/localstack/services/cloudformation/engine/v2/change_set_model_preproc.py b/localstack-core/localstack/services/cloudformation/engine/v2/change_set_model_preproc.py index 8533c98394559..d82f9b4a84baa 100644 --- a/localstack-core/localstack/services/cloudformation/engine/v2/change_set_model_preproc.py +++ b/localstack-core/localstack/services/cloudformation/engine/v2/change_set_model_preproc.py @@ -4,7 +4,8 @@ import copy import re from collections.abc import Callable -from typing import Any, Final, Generic, TypeVar +from enum import StrEnum +from typing import Any, Final from botocore.exceptions import ClientError @@ -30,6 +31,7 @@ NodeProperties, NodeProperty, NodeResource, + NodeResources, NodeTemplate, Nothing, NothingType, @@ -49,6 +51,9 @@ extract_dynamic_reference, perform_dynamic_reference_lookup, ) +from localstack.services.cloudformation.engine.v2.unsupported_resource import ( + should_ignore_unsupported_resource_type, +) from localstack.services.cloudformation.engine.validations import ValidationError from localstack.services.cloudformation.stores import ( exports_map, @@ -56,6 +61,7 @@ from localstack.services.cloudformation.v2.entities import ChangeSet from localstack.services.cloudformation.v2.types import ResolvedResource from localstack.utils.aws.arns import get_partition +from localstack.utils.numbers import to_number from localstack.utils.objects import get_value_from_path from localstack.utils.run import to_str from localstack.utils.strings import to_bytes @@ -74,9 +80,6 @@ "AWS::NotificationARNs", } -TBefore = TypeVar("TBefore") -TAfter = TypeVar("TAfter") -_T = TypeVar("_T") REGEX_OUTPUT_APIGATEWAY = re.compile( rf"^(https?://.+\.execute-api\.)(?:[^-]+-){{2,3}}\d\.(amazonaws\.com|{_AWS_URL_SUFFIX})/?(.*)$" @@ -86,7 +89,7 @@ VALID_LOGICAL_RESOURCE_ID_RE = re.compile(r"^[A-Za-z0-9]+$") -class PreprocEntityDelta(Generic[TBefore, TAfter]): +class PreprocEntityDelta[TBefore, TAfter]: before: Maybe[TBefore] after: Maybe[TAfter] @@ -112,6 +115,19 @@ def __eq__(self, other): return self.properties == other.properties +class DeletionPolicy(StrEnum): + Retain = "Retain" + Delete = "Delete" + RetainExceptOnCreate = "RetainExceptOnCreate" + Snapshot = "Snapshot" + + +class UpdateReplacePolicy(StrEnum): + Delete = "Delete" + Retain = "Retain" + Snapshot = "Snapshot" + + class PreprocResource: logical_id: str physical_resource_id: str | None @@ -121,6 +137,9 @@ class PreprocResource: depends_on: list[str] | None requires_replacement: bool status: ResourceStatus | None + # TODO: typing + deletion_policy: DeletionPolicy | None + update_replace_policy: UpdateReplacePolicy | None def __init__( self, @@ -132,6 +151,8 @@ def __init__( depends_on: list[str] | None, requires_replacement: bool, status: ResourceStatus | None = None, + deletion_policy: str | None = None, + update_replace_policy: str | None = None, ): self.logical_id = logical_id self.physical_resource_id = physical_resource_id @@ -141,6 +162,8 @@ def __init__( self.depends_on = depends_on self.requires_replacement = requires_replacement self.status = status + self.deletion_policy = deletion_policy + self.update_replace_policy = update_replace_policy @staticmethod def _compare_conditions(c1: bool, c2: bool): @@ -225,6 +248,8 @@ def _save_runtime_cache(self) -> None: def process(self) -> None: self._setup_runtime_cache() node_template = self._change_set.update_model.node_template + node_conditions = self._change_set.update_model.node_template.conditions + self.visit(node_conditions) self.visit(node_template) self._save_runtime_cache() @@ -270,19 +295,23 @@ def _deployed_property_value_of( f"No deployed instances of resource '{resource_logical_id}' were found" ) properties = resolved_resource.get("Properties", {}) + resource_type = resolved_resource.get("Type") # TODO support structured properties, e.g. NestedStack.Outputs.OutputName property_value: Any | None = get_value_from_path(properties, property_name) if property_value: - if not isinstance(property_value, (str, list)): - # TODO: is this correct? If there is a bug in the logic here, it's probably - # better to know about it with a clear error message than to receive some form - # of message about trying to use a dictionary in place of a string + if not isinstance(property_value, (str, list, dict)): + # Str: Standard expected type. TODO validate bools and numbers + # List: Multiple resource types can return a list of values e.g. AWS::EC2::VPC. + # Dict: Custom resources in CloudFormation can return arbitrary data structures. raise RuntimeError( f"Accessing property '{property_name}' from '{resource_logical_id}' resulted in a non-string value nor list" ) return property_value - elif config.CFN_IGNORE_UNSUPPORTED_RESOURCE_TYPES: + elif resource_type and should_ignore_unsupported_resource_type( + resource_type=resource_type, + change_set_type=self._change_set.change_set_type, + ): return MOCKED_REFERENCE return property_value @@ -421,8 +450,8 @@ def _maybe_perform_static_replacements(self, delta: PreprocEntityDelta) -> Prepr def _maybe_perform_dynamic_replacements(self, delta: PreprocEntityDelta) -> PreprocEntityDelta: return self._maybe_perform_on_delta(delta, self._perform_dynamic_replacements) - def _maybe_perform_on_delta( - self, delta: PreprocEntityDelta | None, f: Callable[[_T], _T] + def _maybe_perform_on_delta[T]( + self, delta: PreprocEntityDelta | None, f: Callable[[T], T] ) -> PreprocEntityDelta | None: if isinstance(delta.before, str): delta.before = f(delta.before) @@ -430,7 +459,7 @@ def _maybe_perform_on_delta( delta.after = f(delta.after) return delta - def _perform_dynamic_replacements(self, value: _T) -> _T: + def _perform_dynamic_replacements[T](self, value: T) -> T: if not isinstance(value, str): return value @@ -565,8 +594,14 @@ def _resolve_attribute(self, arguments: str | list[str], select_before: bool) -> arguments_list = arguments.split(".") else: arguments_list = arguments + + if len(arguments_list) < 2: + raise ValidationError( + "Template error: every Fn::GetAtt object requires two non-empty parameters, the resource name and the resource attribute" + ) + logical_name_of_resource = arguments_list[0] - attribute_name = arguments_list[1] + attribute_name = ".".join(arguments_list[1:]) node_resource = self._get_node_resource_for( resource_name=logical_name_of_resource, @@ -587,6 +622,21 @@ def _resolve_attribute(self, arguments: str | list[str], select_before: bool) -> f"Template format error: Unresolved resource dependencies [{logical_name_of_resource}] in the Resources block of the template" ) + # Custom Resources can mutate their definition + # So the preproc should search first in the resource values and then check the template + if select_before: + value = self._before_deployed_property_value_of( + resource_logical_id=logical_name_of_resource, + property_name=attribute_name, + ) + else: + value = self._after_deployed_property_value_of( + resource_logical_id=logical_name_of_resource, + property_name=attribute_name, + ) + if value is not None: + return value + node_property: NodeProperty | None = self._get_node_property_for( property_name=attribute_name, node_resource=node_resource ) @@ -594,19 +644,7 @@ def _resolve_attribute(self, arguments: str | list[str], select_before: bool) -> # The property is statically defined in the template and its value can be computed. property_delta = self.visit(node_property) value = property_delta.before if select_before else property_delta.after - else: - # The property is not statically defined and must therefore be available in - # the properties deployed set. - if select_before: - value = self._before_deployed_property_value_of( - resource_logical_id=logical_name_of_resource, - property_name=attribute_name, - ) - else: - value = self._after_deployed_property_value_of( - resource_logical_id=logical_name_of_resource, - property_name=attribute_name, - ) + return value def visit_node_intrinsic_function_fn_get_att( @@ -635,6 +673,12 @@ def _compute_fn_equals(args: list[Any]) -> bool: return args[0] == args[1] arguments_delta = self.visit(node_intrinsic_function.arguments) + + if isinstance(arguments_delta.after, list) and len(arguments_delta.after) != 2: + raise ValidationError( + "Template error: every Fn::Equals object requires a list of 2 string parameters." + ) + delta = self._cached_apply( scope=node_intrinsic_function.scope, arguments_delta=arguments_delta, @@ -658,6 +702,13 @@ def visit_node_intrinsic_function_fn_if( node_condition = self._get_node_condition_if_exists( condition_name=condition_delta.before ) + if is_nothing(node_condition): + # TODO: I don't think this is a possible state since for us to be evaluating the before state, + # we must have successfully deployed the stack and as such this case was not reached before + raise ValidationError( + f"Template error: unresolved condition dependency {condition_delta.before} in Fn::If" + ) + condition_value = self.visit(node_condition).before if condition_value: arg_delta = self.visit(node_intrinsic_function.arguments.array[1]) @@ -669,6 +720,11 @@ def visit_node_intrinsic_function_fn_if( node_condition = self._get_node_condition_if_exists( condition_name=condition_delta.after ) + if is_nothing(node_condition): + raise ValidationError( + f"Template error: unresolved condition dependency {condition_delta.after} in Fn::If" + ) + condition_value = self.visit(node_condition).after if condition_value: arg_delta = self.visit(node_intrinsic_function.arguments.array[1]) @@ -911,6 +967,17 @@ def _compute_fn_split(args: list[Any]) -> Any: return split_string arguments_delta = self.visit(node_intrinsic_function.arguments) + + if not ( + is_nothing(arguments_delta.after) + or isinstance(arguments_delta.after, list) + and len(arguments_delta.after) == 2 + ): + raise ValidationError( + "Template error: every Fn::Split object requires two parameters, " + "(1) a string delimiter and (2) a string to be split or a function that returns a string to be split." + ) + delta = self._cached_apply( scope=node_intrinsic_function.scope, arguments_delta=arguments_delta, @@ -1027,8 +1094,13 @@ def visit_node_parameter(self, node_parameter: NodeParameter) -> PreprocEntityDe def _resolve_parameter_type(value: str, type_: str) -> Any: match type_: - case "List" | "CommaDelimitedList": + case s if re.match(r"List<[^>]+>", s): + return [item.strip() for item in value.split(",")] + case "CommaDelimitedList": return [item.strip() for item in value.split(",")] + case "Number": + # TODO: validate the parameter type at template parse time (or whatever is in parity with AWS) so we know this cannot fail + return to_number(value) return value if not is_nothing(after): @@ -1170,6 +1242,20 @@ def _resolve_resource_condition_reference(self, reference: TerminalValue) -> Pre after = after_delta.after return PreprocEntityDelta(before=before, after=after) + def visit_node_resources(self, node_resources: NodeResources): + """ + Skip resources where they conditionally evaluate to False + """ + for node_resource in node_resources.resources: + if not is_nothing(node_resource.condition_reference): + condition_delta = self._resolve_resource_condition_reference( + node_resource.condition_reference + ) + condition_after = condition_delta.after + if condition_after is False: + continue + self.visit(node_resource) + def visit_node_resource( self, node_resource: NodeResource ) -> PreprocEntityDelta[PreprocResource, PreprocResource]: @@ -1195,13 +1281,39 @@ def visit_node_resource( depends_on_after = depends_on_delta.after type_delta = self.visit(node_resource.type_) - properties_delta: PreprocEntityDelta[PreprocProperties, PreprocProperties] = self.visit( - node_resource.properties + + # Check conditions before visiting properties to avoid resolving references + # (e.g. GetAtt) to conditional resources that were never created. + should_process_before = change_type != ChangeType.CREATED and ( + is_nothing(condition_before) or condition_before ) + should_process_after = change_type != ChangeType.REMOVED and ( + is_nothing(condition_after) or condition_after + ) + + properties_delta: PreprocEntityDelta[PreprocProperties, PreprocProperties] + if should_process_before or should_process_after: + properties_delta = self.visit(node_resource.properties) + else: + properties_delta = PreprocEntityDelta(before=Nothing, after=Nothing) + + deletion_policy_before = Nothing + deletion_policy_after = Nothing + if not is_nothing(node_resource.deletion_policy): + deletion_policy_delta = self.visit(node_resource.deletion_policy) + deletion_policy_before = deletion_policy_delta.before + deletion_policy_after = deletion_policy_delta.after + + update_replace_policy_before = Nothing + update_replace_policy_after = Nothing + if not is_nothing(node_resource.update_replace_policy): + update_replace_policy_delta = self.visit(node_resource.update_replace_policy) + update_replace_policy_before = update_replace_policy_delta.before + update_replace_policy_after = update_replace_policy_delta.after before = Nothing after = Nothing - if change_type != ChangeType.CREATED and is_nothing(condition_before) or condition_before: + if should_process_before: logical_resource_id = node_resource.name before_physical_resource_id = self._before_resource_physical_id( resource_logical_id=logical_resource_id @@ -1214,8 +1326,10 @@ def visit_node_resource( properties=properties_delta.before, depends_on=depends_on_before, requires_replacement=False, + deletion_policy=deletion_policy_before, + update_replace_policy=update_replace_policy_before, ) - if change_type != ChangeType.REMOVED and is_nothing(condition_after) or condition_after: + if should_process_after: logical_resource_id = node_resource.name try: after_physical_resource_id = self._after_resource_physical_id( @@ -1231,6 +1345,8 @@ def visit_node_resource( properties=properties_delta.after, depends_on=depends_on_after, requires_replacement=node_resource.requires_replacement, + deletion_policy=deletion_policy_after, + update_replace_policy=update_replace_policy_after, ) return PreprocEntityDelta(before=before, after=after) @@ -1280,6 +1396,14 @@ def visit_node_outputs( before: list[PreprocOutput] = [] after: list[PreprocOutput] = [] for node_output in node_outputs.outputs: + if not is_nothing(node_output.condition_reference): + condition_delta = self._resolve_resource_condition_reference( + node_output.condition_reference + ) + condition_after = condition_delta.after + if condition_after is False: + continue + output_delta: PreprocEntityDelta[PreprocOutput, PreprocOutput] = self.visit(node_output) output_before = output_delta.before output_after = output_delta.after diff --git a/localstack-core/localstack/services/cloudformation/engine/v2/change_set_model_validator.py b/localstack-core/localstack/services/cloudformation/engine/v2/change_set_model_validator.py index dfc386f00a330..9d4ee68cd8fcb 100644 --- a/localstack-core/localstack/services/cloudformation/engine/v2/change_set_model_validator.py +++ b/localstack-core/localstack/services/cloudformation/engine/v2/change_set_model_validator.py @@ -17,6 +17,7 @@ PreprocEntityDelta, PreprocResource, ) +from localstack.services.cloudformation.engine.validations import ValidationError class ChangeSetModelValidator(ChangeSetModelPreproc): @@ -162,6 +163,10 @@ def visit_node_intrinsic_function_fn_select( return self.visit(node_intrinsic_function.arguments) def visit_node_resource(self, node_resource: NodeResource) -> PreprocEntityDelta: + if is_nothing(node_resource.type_.value): + raise ValidationError( + f"Template format error: [{node_resource.scope}] Every Resources object must contain a Type member." + ) try: if delta := super().visit_node_resource(node_resource): return delta diff --git a/localstack-core/localstack/services/cloudformation/engine/v2/change_set_model_visitor.py b/localstack-core/localstack/services/cloudformation/engine/v2/change_set_model_visitor.py index 882e8a8d58bc7..ace45f5001184 100644 --- a/localstack-core/localstack/services/cloudformation/engine/v2/change_set_model_visitor.py +++ b/localstack-core/localstack/services/cloudformation/engine/v2/change_set_model_visitor.py @@ -54,6 +54,7 @@ def visit_node_template(self, node_template: NodeTemplate): # entities (parameters, mappings, conditions, etc.). Then compute the output fields; computing # only the output fields would only result in the deployment logic of the referenced outputs # being evaluated, hence enforce the visiting of all the resources first. + self.visit(node_template.conditions) self.visit(node_template.resources) self.visit(node_template.outputs) diff --git a/localstack-core/localstack/services/cloudformation/engine/v2/change_set_resource_support_checker.py b/localstack-core/localstack/services/cloudformation/engine/v2/change_set_resource_support_checker.py new file mode 100644 index 0000000000000..f590996f05524 --- /dev/null +++ b/localstack-core/localstack/services/cloudformation/engine/v2/change_set_resource_support_checker.py @@ -0,0 +1,122 @@ +from localstack.aws.api.cloudformation import ChangeSetType +from localstack.services.cloudformation.engine.v2.change_set_model import NodeResource +from localstack.services.cloudformation.engine.v2.change_set_model_visitor import ( + ChangeSetModelVisitor, +) +from localstack.services.cloudformation.engine.v2.unsupported_resource import ( + should_ignore_unsupported_resource_type, +) +from localstack.services.cloudformation.resources import AWS_AVAILABLE_CFN_RESOURCES +from localstack.utils.catalog.catalog import ( + AwsServicesSupportStatus, + CatalogPlugin, + CfnResourceSupportStatus, +) +from localstack.utils.catalog.common import ( + AwsServicesSupportInLatest, + AwsServiceSupportAtRuntime, + CloudFormationResourcesSupportAtRuntime, + CloudFormationResourcesSupportInLatest, +) +from localstack.utils.catalog.plugins import get_aws_catalog + + +# TODO handle all available resource types +def _get_service_name(resource_type: str) -> str | None: + parts = resource_type.split("::") + if len(parts) == 1: + return None + + match parts: + case _ if "Cognito::IdentityPool" in resource_type: + return "cognito-identity" + case [*_, "Cognito", "UserPool"]: + return "cognito-idp" + case [*_, "Cognito", _]: + return "cognito-idp" + case [*_, "Elasticsearch", _]: + return "es" + case [*_, "OpenSearchService", _]: + return "opensearch" + case [*_, "KinesisFirehose", _]: + return "firehose" + case [*_, "ResourceGroups", _]: + return "resource-groups" + case [*_, "CertificateManager", _]: + return "acm" + case _ if "ElasticLoadBalancing::" in resource_type: + return "elb" + case _ if "ElasticLoadBalancingV2::" in resource_type: + return "elbv2" + case _ if "ApplicationAutoScaling::" in resource_type: + return "application-autoscaling" + case _ if "MSK::" in resource_type: + return "kafka" + case _ if "Timestream::" in resource_type: + return "timestream-write" + case [_, service, *_]: + return service.lower() + + +def _build_resource_failure_message( + resource_type: str, status: AwsServicesSupportStatus | CfnResourceSupportStatus +) -> str: + service_name = _get_service_name(resource_type) or "malformed" + template = "Sorry, the {resource} resource in the {service} service is not supported." + match status: + case CloudFormationResourcesSupportAtRuntime.NOT_IMPLEMENTED: + template = "Sorry, the {resource} resource (from the {service} service) is not supported by this version of LocalStack, but is available in the latest version." + case CloudFormationResourcesSupportInLatest.NOT_SUPPORTED: + template = "Sorry, the {resource} resource (from the {service} service) is not currently supported by LocalStack." + case AwsServiceSupportAtRuntime.AVAILABLE_WITH_LICENSE_UPGRADE: + template = "Sorry, the {service} service (for the {resource} resource) is not included within your LocalStack license, but is available in an upgraded license." + case AwsServiceSupportAtRuntime.NOT_IMPLEMENTED: + template = "The API for service {service} (for the {resource} resource) is either not included in your current license plan or has not yet been emulated by LocalStack." + case AwsServicesSupportInLatest.NOT_SUPPORTED: + template = "Sorry, the {service} (for the {resource} resource) service is not currently supported by LocalStack." + case AwsServicesSupportInLatest.SUPPORTED_WITH_LICENSE_UPGRADE: + template = "Sorry, the {service} service (for the {resource} resource) is not supported by this version of LocalStack, but is available in the latest version if you upgrade to the latest stable version." + return template.format( + resource=resource_type, + service=service_name, + ) + + +class ChangeSetResourceSupportChecker(ChangeSetModelVisitor): + change_set_type: ChangeSetType + catalog: CatalogPlugin + + TITLE_MESSAGE = "Unsupported resources detected:" + + def __init__(self, change_set_type: ChangeSetType): + self._resource_failure_messages: dict[str, str] = {} + self.change_set_type = change_set_type + self.catalog = get_aws_catalog() + + def visit_node_resource(self, node_resource: NodeResource): + resource_type = node_resource.type_.value + ignore_unsupported = should_ignore_unsupported_resource_type( + resource_type=resource_type, change_set_type=self.change_set_type + ) + + if resource_type not in self._resource_failure_messages and not ignore_unsupported: + if resource_type not in AWS_AVAILABLE_CFN_RESOURCES: + # Ignore non-AWS resources + pass + support_status = self._resource_support_status(resource_type) + if support_status == CloudFormationResourcesSupportAtRuntime.AVAILABLE: + pass + else: + failure_message = _build_resource_failure_message(resource_type, support_status) + self._resource_failure_messages[resource_type] = failure_message + super().visit_node_resource(node_resource) + + def _resource_support_status( + self, resource_type: str + ) -> AwsServicesSupportStatus | CfnResourceSupportStatus: + service_name = _get_service_name(resource_type) + return self.catalog.get_cloudformation_resource_status(resource_type, service_name, True) + + @property + def failure_messages(self) -> list[str]: + return list(self._resource_failure_messages.values()) diff --git a/localstack-core/localstack/services/cloudformation/engine/v2/unsupported_resource.py b/localstack-core/localstack/services/cloudformation/engine/v2/unsupported_resource.py new file mode 100644 index 0000000000000..5059f88e556d1 --- /dev/null +++ b/localstack-core/localstack/services/cloudformation/engine/v2/unsupported_resource.py @@ -0,0 +1,19 @@ +from __future__ import annotations + +from localstack import config +from localstack.aws.api.cloudformation import ChangeSetType + + +def should_ignore_unsupported_resource_type( + resource_type: str, change_set_type: ChangeSetType +) -> bool: + if config.CFN_IGNORE_UNSUPPORTED_RESOURCE_TYPES: + return True + + match change_set_type: + case ChangeSetType.CREATE: + return resource_type in config.CFN_IGNORE_UNSUPPORTED_TYPE_CREATE + case ChangeSetType.UPDATE | ChangeSetType.IMPORT: + return resource_type in config.CFN_IGNORE_UNSUPPORTED_TYPE_UPDATE + case _: + return False diff --git a/localstack-core/localstack/services/cloudformation/engine/yaml_parser.py b/localstack-core/localstack/services/cloudformation/engine/yaml_parser.py index c0b72ead58f8f..3d12004f42423 100644 --- a/localstack-core/localstack/services/cloudformation/engine/yaml_parser.py +++ b/localstack-core/localstack/services/cloudformation/engine/yaml_parser.py @@ -1,5 +1,7 @@ import yaml +from localstack.services.cloudformation.engine.validations import ValidationError + def construct_raw(_, node): return node.value @@ -60,5 +62,10 @@ def shorthand_constructor(loader: yaml.Loader, tag_suffix: str, node: yaml.Node) yaml.add_multi_constructor("!", shorthand_constructor, customloader) -def parse_yaml(input_data: str): - return yaml.load(input_data, customloader) +def parse_yaml(input_data: str) -> dict: + parsed = yaml.load(input_data, Loader=customloader) + + if not isinstance(parsed, dict): + raise ValidationError("Template format error: unsupported structure.") + + return parsed diff --git a/localstack-core/localstack/services/cloudformation/plugins.py b/localstack-core/localstack/services/cloudformation/plugins.py deleted file mode 100644 index 72ef0104aaeb2..0000000000000 --- a/localstack-core/localstack/services/cloudformation/plugins.py +++ /dev/null @@ -1,12 +0,0 @@ -from rolo import Resource - -from localstack.runtime import hooks - - -@hooks.on_infra_start() -def register_cloudformation_deploy_ui(): - from localstack.services.internal import get_internal_apis - - from .deploy_ui import CloudFormationUi - - get_internal_apis().add(Resource("/_localstack/cloudformation/deploy", CloudFormationUi())) diff --git a/localstack-core/localstack/services/cloudformation/provider.py b/localstack-core/localstack/services/cloudformation/provider.py index 473bde3fc66bd..8335084903fc1 100644 --- a/localstack-core/localstack/services/cloudformation/provider.py +++ b/localstack-core/localstack/services/cloudformation/provider.py @@ -5,6 +5,7 @@ from collections import defaultdict from copy import deepcopy +from localstack import config from localstack.aws.api import CommonServiceException, RequestContext, handler from localstack.aws.api.cloudformation import ( AlreadyExistsException, @@ -120,7 +121,9 @@ find_stack_by_id, get_cloudformation_store, ) +from localstack.services.plugins import ServiceLifecycleHook from localstack.state import StateVisitor +from localstack.utils.aws.arns import ARN_PARTITION_REGEX from localstack.utils.collections import ( remove_attributes, select_attributes, @@ -132,13 +135,13 @@ LOG = logging.getLogger(__name__) ARN_CHANGESET_REGEX = re.compile( - r"arn:(aws|aws-us-gov|aws-cn):cloudformation:[-a-zA-Z0-9]+:\d{12}:changeSet/[a-zA-Z][-a-zA-Z0-9]*/[-a-zA-Z0-9:/._+]+" + rf"{ARN_PARTITION_REGEX}:cloudformation:[-a-zA-Z0-9]+:\d{{12}}:changeSet/[a-zA-Z][-a-zA-Z0-9]*/[-a-zA-Z0-9:/._+]+" ) ARN_STACK_REGEX = re.compile( - r"arn:(aws|aws-us-gov|aws-cn):cloudformation:[-a-zA-Z0-9]+:\d{12}:stack/[a-zA-Z][-a-zA-Z0-9]*/[-a-zA-Z0-9:/._+]+" + rf"{ARN_PARTITION_REGEX}:cloudformation:[-a-zA-Z0-9]+:\d{{12}}:stack/[a-zA-Z][-a-zA-Z0-9]*/[-a-zA-Z0-9:/._+]+" ) ARN_STACK_SET_REGEX = re.compile( - r"arn:(aws|aws-us-gov|aws-cn):cloudformation:[-a-zA-Z0-9]+:\d{12}:stack-set/[a-zA-Z][-a-zA-Z0-9]*/[-a-zA-Z0-9:/._+]+" + rf"{ARN_PARTITION_REGEX}:cloudformation:[-a-zA-Z0-9]+:\d{{12}}:stack-set/[a-zA-Z][-a-zA-Z0-9]*/[-a-zA-Z0-9:/._+]+" ) @@ -177,7 +180,30 @@ def __init__(self, message=None): super().__init__("InternalFailure", status_code=500, message=message, sender_fault=False) -class CloudformationProvider(CloudformationApi): +class CloudformationProvider(CloudformationApi, ServiceLifecycleHook): + def on_before_start(self): + self._validate_config() + + def _validate_config(self): + no_wait_value: int = 5 + try: + no_wait_value = int(config.CFN_NO_WAIT_ITERATIONS or 5) + except (TypeError, ValueError): + LOG.warning( + "You have set CFN_NO_WAIT_ITERATIONS to an invalid value: '%s'. It must be an integer greater or equal to 0. Using the default of 5", + config.CFN_NO_WAIT_ITERATIONS, + ) + + if no_wait_value < 0: + LOG.warning( + "You have set CFN_NO_WAIT_ITERATIONS to an invalid value: '%s'. It must be an integer greater or equal to 0. Using the default of 5", + config.CFN_NO_WAIT_ITERATIONS, + ) + no_wait_value = 5 + + # Set the configuration back + config.CFN_NO_WAIT_ITERATIONS = no_wait_value + def _stack_status_is_active(self, stack_status: str) -> bool: return stack_status not in [StackStatus.DELETE_COMPLETE] @@ -952,8 +978,8 @@ def list_imports( def describe_stack_events( self, context: RequestContext, - stack_name: StackName = None, - next_token: NextToken = None, + stack_name: StackName, + next_token: NextToken | None = None, **kwargs, ) -> DescribeStackEventsOutput: if stack_name is None: diff --git a/localstack-core/localstack/services/cloudformation/provider_utils.py b/localstack-core/localstack/services/cloudformation/provider_utils.py index c87238a9ae86d..677f023af2796 100644 --- a/localstack-core/localstack/services/cloudformation/provider_utils.py +++ b/localstack-core/localstack/services/cloudformation/provider_utils.py @@ -275,8 +275,30 @@ def recursive_convert(obj): return recursive_convert(input_dict) +def resource_tags_to_remove_or_update( + prev_tags: list[dict], new_tags: list[dict] +) -> tuple[list[str], dict[str, str]]: + """ + When updating resources that have tags, we need to determine which tags to remove and which to add/update, + as these are typically done in separate API calls. The format of prev_tags and new_tags is expected to + be [{ "Key": tagName, "Value": tagValue }, ...]. The return value will be a tuple of (tags_to_remove, tags_to_update), + where: + - tags_to_remove is a list of tag keys that are present in prev_tags but not in new_tags. + - tags_to_update is a dict of tags to add or update, with the format: { tagName: tagValue, ... }. + """ + prev_tag_keys = [tag["Key"] for tag in prev_tags] + new_tag_keys = [tag["Key"] for tag in new_tags] + tags_to_remove = list(set(prev_tag_keys) - set(new_tag_keys)) + + # convert from list of dicts, to a single dict because that's what tag_queue APIs expect. + tags_to_update = {tag["Key"]: tag["Value"] for tag in new_tags} + return (tags_to_remove, tags_to_update) + + # LocalStack specific utilities def get_schema_path(file_path: Path) -> dict: - file_name_base = file_path.name.removesuffix(".py").removesuffix(".py.enc") + file_name_base = ( + file_path.name.removesuffix("_base.py").removesuffix(".py").removesuffix(".py.enc") + ) with Path(file_path).parent.joinpath(f"{file_name_base}.schema.json").open() as fd: return json.load(fd) diff --git a/localstack-core/localstack/services/cloudformation/resource_provider.py b/localstack-core/localstack/services/cloudformation/resource_provider.py index f38bbd88623d7..b84ed961bdd50 100644 --- a/localstack-core/localstack/services/cloudformation/resource_provider.py +++ b/localstack-core/localstack/services/cloudformation/resource_provider.py @@ -10,7 +10,7 @@ from enum import Enum, auto from logging import Logger from math import ceil -from typing import TYPE_CHECKING, Any, Generic, TypedDict, TypeVar +from typing import TYPE_CHECKING, Any, TypedDict, TypeVar import botocore from botocore.client import BaseClient @@ -65,7 +65,7 @@ class OperationStatus(Enum): @dataclass -class ProgressEvent(Generic[Properties]): +class ProgressEvent[Properties]: status: OperationStatus resource_model: Properties | None = None resource_models: list[Properties] | None = None @@ -165,7 +165,7 @@ def convert_payload( @dataclass -class ResourceRequest(Generic[Properties]): +class ResourceRequest[Properties]: _original_payload: Properties aws_client_factory: ServiceLevelClientFactory @@ -198,7 +198,7 @@ class CloudFormationResourceProviderPlugin(Plugin): namespace = "localstack.cloudformation.resource_providers" -class ResourceProvider(Generic[Properties]): +class ResourceProvider[Properties]: """ This provides a base class onto which service-specific resource providers are built. """ @@ -401,7 +401,7 @@ class NoResourceProvider(Exception): pass -def resolve_json_pointer(resource_props: Properties, primary_id_path: str) -> str: +def resolve_json_pointer[Properties](resource_props: Properties, primary_id_path: str) -> str: primary_id_path = primary_id_path.replace("/properties", "") parts = [p for p in primary_id_path.split("/") if p] @@ -436,11 +436,11 @@ def deploy_loop( resource: dict, raw_payload: ResourceProviderPayload, max_timeout: int = config.CFN_PER_RESOURCE_TIMEOUT, - sleep_time: float = 5, + sleep_time: float = 1, ) -> ProgressEvent[Properties]: payload = copy.deepcopy(raw_payload) - max_iterations = max(ceil(max_timeout / sleep_time), 2) + max_iterations = max(ceil(max_timeout / sleep_time), 10) for current_iteration in range(max_iterations): resource_type = get_resource_type({"Type": raw_payload["resourceType"]}) @@ -486,10 +486,11 @@ def deploy_loop( payload["requestData"]["resourceProperties"] = event.resource_model resource["Properties"] = event.resource_model - if current_iteration == 0: - time.sleep(0) + if current_iteration < config.CFN_NO_WAIT_ITERATIONS: + pass else: time.sleep(sleep_time) + case OperationStatus.PENDING: # come back to this resource in another iteration return event @@ -547,6 +548,7 @@ def execute_action( status=OperationStatus.FAILED, resource_model={}, message=f"Failed to delete resource with id {request.logical_resource_id} of type {request.resource_type}", + custom_context={"exception": e}, ) case "Remove": try: @@ -560,6 +562,7 @@ def execute_action( status=OperationStatus.FAILED, resource_model={}, message=f"Failed to delete resource with id {request.logical_resource_id} of type {request.resource_type}", + custom_context={"exception": e}, ) case _: raise NotImplementedError(change_type) # TODO: change error type diff --git a/localstack-core/localstack/services/cloudformation/resources.py b/localstack-core/localstack/services/cloudformation/resources.py index 5c338d20bb0ff..61e0c9c1753a9 100644 --- a/localstack-core/localstack/services/cloudformation/resources.py +++ b/localstack-core/localstack/services/cloudformation/resources.py @@ -92,6 +92,25 @@ "us-east-2", "us-west-2", ], + "AWS::APS::AnomalyDetector": [ + "ap-northeast-1", + "ap-northeast-2", + "ap-northeast-3", + "ap-south-1", + "ap-southeast-1", + "ap-southeast-2", + "ca-central-1", + "eu-central-1", + "eu-north-1", + "eu-west-1", + "eu-west-2", + "eu-west-3", + "sa-east-1", + "us-east-1", + "us-east-2", + "us-west-1", + "us-west-2", + ], "AWS::APS::ResourcePolicy": [ "ap-northeast-1", "ap-northeast-2", @@ -2061,6 +2080,25 @@ "us-west-1", "us-west-2", ], + "AWS::ApplicationSignals::GroupingConfiguration": [ + "ap-northeast-1", + "ap-northeast-2", + "ap-northeast-3", + "ap-south-1", + "ap-southeast-1", + "ap-southeast-2", + "ca-central-1", + "eu-central-1", + "eu-north-1", + "eu-west-1", + "eu-west-2", + "eu-west-3", + "sa-east-1", + "us-east-1", + "us-east-2", + "us-west-1", + "us-west-2", + ], "AWS::ApplicationSignals::ServiceLevelObjective": [ "ap-northeast-1", "ap-northeast-2", @@ -2082,14 +2120,21 @@ ], "AWS::Athena::CapacityReservation": [ "ap-northeast-1", + "ap-northeast-2", + "ap-northeast-3", "ap-south-1", "ap-southeast-1", "ap-southeast-2", + "ca-central-1", + "eu-central-1", "eu-north-1", "eu-west-1", + "eu-west-2", + "eu-west-3", "sa-east-1", "us-east-1", "us-east-2", + "us-west-1", "us-west-2", ], "AWS::Athena::DataCatalog": [ @@ -2316,21 +2361,29 @@ "us-west-2", ], "AWS::B2BI::Capability": [ + "eu-west-1", + "eu-west-3", "us-east-1", "us-east-2", "us-west-2", ], "AWS::B2BI::Partnership": [ + "eu-west-1", + "eu-west-3", "us-east-1", "us-east-2", "us-west-2", ], "AWS::B2BI::Profile": [ + "eu-west-1", + "eu-west-3", "us-east-1", "us-east-2", "us-west-2", ], "AWS::B2BI::Transformer": [ + "eu-west-1", + "eu-west-3", "us-east-1", "us-east-2", "us-west-2", @@ -2491,6 +2544,25 @@ "us-west-1", "us-west-2", ], + "AWS::Backup::TieringConfiguration": [ + "ap-northeast-1", + "ap-northeast-2", + "ap-northeast-3", + "ap-south-1", + "ap-southeast-1", + "ap-southeast-2", + "ca-central-1", + "eu-central-1", + "eu-north-1", + "eu-west-1", + "eu-west-2", + "eu-west-3", + "sa-east-1", + "us-east-1", + "us-east-2", + "us-west-1", + "us-west-2", + ], "AWS::BackupGateway::Hypervisor": [ "ap-northeast-1", "ap-northeast-2", @@ -2887,23 +2959,7 @@ "us-east-2", "us-west-2", ], - "AWS::Billing::BillingView": [ - "us-east-1", - "us-west-2", - ], - "AWS::BillingConductor::BillingGroup": [ - "us-east-1", - ], - "AWS::BillingConductor::CustomLineItem": [ - "us-east-1", - ], - "AWS::BillingConductor::PricingPlan": [ - "us-east-1", - ], - "AWS::BillingConductor::PricingRule": [ - "us-east-1", - ], - "AWS::Budgets::Budget": [ + "AWS::BedrockAgentCore::BrowserCustom": [ "ap-northeast-1", "ap-northeast-2", "ap-south-1", @@ -2911,36 +2967,28 @@ "ap-southeast-2", "ca-central-1", "eu-central-1", + "eu-north-1", "eu-west-1", "eu-west-2", "eu-west-3", - "sa-east-1", "us-east-1", "us-east-2", - "us-west-1", "us-west-2", ], - "AWS::Budgets::BudgetsAction": [ - "ap-northeast-1", + "AWS::BedrockAgentCore::BrowserProfile": [ "ap-northeast-2", "ap-south-1", - "ap-southeast-1", "ap-southeast-2", - "ca-central-1", "eu-central-1", - "eu-west-1", + "eu-north-1", "eu-west-2", "eu-west-3", - "sa-east-1", "us-east-1", - "us-east-2", - "us-west-1", "us-west-2", ], - "AWS::CE::AnomalyMonitor": [ + "AWS::BedrockAgentCore::CodeInterpreterCustom": [ "ap-northeast-1", "ap-northeast-2", - "ap-northeast-3", "ap-south-1", "ap-southeast-1", "ap-southeast-2", @@ -2950,16 +2998,19 @@ "eu-west-1", "eu-west-2", "eu-west-3", - "sa-east-1", "us-east-1", "us-east-2", - "us-west-1", "us-west-2", ], - "AWS::CE::AnomalySubscription": [ + "AWS::BedrockAgentCore::Evaluator": [ + "ap-southeast-2", + "eu-central-1", + "us-east-1", + "us-west-2", + ], + "AWS::BedrockAgentCore::Gateway": [ "ap-northeast-1", "ap-northeast-2", - "ap-northeast-3", "ap-south-1", "ap-southeast-1", "ap-southeast-2", @@ -2969,16 +3020,13 @@ "eu-west-1", "eu-west-2", "eu-west-3", - "sa-east-1", "us-east-1", "us-east-2", - "us-west-1", "us-west-2", ], - "AWS::CE::CostCategory": [ + "AWS::BedrockAgentCore::GatewayTarget": [ "ap-northeast-1", "ap-northeast-2", - "ap-northeast-3", "ap-south-1", "ap-southeast-1", "ap-southeast-2", @@ -2988,16 +3036,11 @@ "eu-west-1", "eu-west-2", "eu-west-3", - "sa-east-1", "us-east-1", "us-east-2", - "us-west-1", "us-west-2", ], - "AWS::CUR::ReportDefinition": [ - "us-east-1", - ], - "AWS::Cassandra::Keyspace": [ + "AWS::BedrockAgentCore::Memory": [ "ap-northeast-1", "ap-northeast-2", "ap-south-1", @@ -3012,10 +3055,15 @@ "sa-east-1", "us-east-1", "us-east-2", - "us-west-1", "us-west-2", ], - "AWS::Cassandra::Table": [ + "AWS::BedrockAgentCore::OnlineEvaluationConfig": [ + "ap-southeast-2", + "eu-central-1", + "us-east-1", + "us-west-2", + ], + "AWS::BedrockAgentCore::Runtime": [ "ap-northeast-1", "ap-northeast-2", "ap-south-1", @@ -3027,13 +3075,11 @@ "eu-west-1", "eu-west-2", "eu-west-3", - "sa-east-1", "us-east-1", "us-east-2", - "us-west-1", "us-west-2", ], - "AWS::Cassandra::Type": [ + "AWS::BedrockAgentCore::RuntimeEndpoint": [ "ap-northeast-1", "ap-northeast-2", "ap-south-1", @@ -3045,16 +3091,13 @@ "eu-west-1", "eu-west-2", "eu-west-3", - "sa-east-1", "us-east-1", "us-east-2", - "us-west-1", "us-west-2", ], - "AWS::CertificateManager::Account": [ + "AWS::BedrockAgentCore::WorkloadIdentity": [ "ap-northeast-1", "ap-northeast-2", - "ap-northeast-3", "ap-south-1", "ap-southeast-1", "ap-southeast-2", @@ -3064,41 +3107,45 @@ "eu-west-1", "eu-west-2", "eu-west-3", - "sa-east-1", "us-east-1", "us-east-2", - "us-west-1", "us-west-2", ], - "AWS::CertificateManager::Certificate": [ + "AWS::BedrockMantle::Project": [ "ap-northeast-1", - "ap-northeast-2", - "ap-northeast-3", "ap-south-1", - "ap-southeast-1", - "ap-southeast-2", - "ca-central-1", - "eu-central-1", "eu-north-1", "eu-west-1", "eu-west-2", - "eu-west-3", "sa-east-1", "us-east-1", "us-east-2", - "us-west-1", "us-west-2", ], - "AWS::Chatbot::CustomAction": [ + "AWS::Billing::BillingView": [ + "us-east-1", + "us-west-2", + ], + "AWS::BillingConductor::BillingGroup": [ + "us-east-1", + ], + "AWS::BillingConductor::CustomLineItem": [ + "us-east-1", + ], + "AWS::BillingConductor::PricingPlan": [ + "us-east-1", + ], + "AWS::BillingConductor::PricingRule": [ + "us-east-1", + ], + "AWS::Budgets::Budget": [ "ap-northeast-1", "ap-northeast-2", - "ap-northeast-3", "ap-south-1", "ap-southeast-1", "ap-southeast-2", "ca-central-1", "eu-central-1", - "eu-north-1", "eu-west-1", "eu-west-2", "eu-west-3", @@ -3108,16 +3155,14 @@ "us-west-1", "us-west-2", ], - "AWS::Chatbot::MicrosoftTeamsChannelConfiguration": [ + "AWS::Budgets::BudgetsAction": [ "ap-northeast-1", "ap-northeast-2", - "ap-northeast-3", "ap-south-1", "ap-southeast-1", "ap-southeast-2", "ca-central-1", "eu-central-1", - "eu-north-1", "eu-west-1", "eu-west-2", "eu-west-3", @@ -3127,7 +3172,7 @@ "us-west-1", "us-west-2", ], - "AWS::Chatbot::SlackChannelConfiguration": [ + "AWS::CE::AnomalyMonitor": [ "ap-northeast-1", "ap-northeast-2", "ap-northeast-3", @@ -3146,125 +3191,128 @@ "us-west-1", "us-west-2", ], - "AWS::CleanRooms::AnalysisTemplate": [ + "AWS::CE::AnomalySubscription": [ "ap-northeast-1", "ap-northeast-2", + "ap-northeast-3", + "ap-south-1", "ap-southeast-1", "ap-southeast-2", + "ca-central-1", "eu-central-1", "eu-north-1", "eu-west-1", "eu-west-2", + "eu-west-3", + "sa-east-1", "us-east-1", "us-east-2", + "us-west-1", "us-west-2", ], - "AWS::CleanRooms::Collaboration": [ + "AWS::CE::CostCategory": [ "ap-northeast-1", "ap-northeast-2", + "ap-northeast-3", + "ap-south-1", "ap-southeast-1", "ap-southeast-2", + "ca-central-1", "eu-central-1", "eu-north-1", "eu-west-1", "eu-west-2", + "eu-west-3", + "sa-east-1", "us-east-1", "us-east-2", + "us-west-1", "us-west-2", ], - "AWS::CleanRooms::ConfiguredTable": [ - "ap-northeast-1", - "ap-northeast-2", - "ap-southeast-1", - "ap-southeast-2", - "eu-central-1", - "eu-north-1", - "eu-west-1", - "eu-west-2", + "AWS::CUR::ReportDefinition": [ "us-east-1", - "us-east-2", - "us-west-2", ], - "AWS::CleanRooms::ConfiguredTableAssociation": [ + "AWS::Cases::CaseRule": [ "ap-northeast-1", "ap-northeast-2", + "ap-south-1", "ap-southeast-1", "ap-southeast-2", + "ca-central-1", "eu-central-1", - "eu-north-1", - "eu-west-1", "eu-west-2", "us-east-1", - "us-east-2", "us-west-2", ], - "AWS::CleanRooms::IdMappingTable": [ + "AWS::Cases::Domain": [ "ap-northeast-1", "ap-northeast-2", + "ap-south-1", "ap-southeast-1", "ap-southeast-2", + "ca-central-1", "eu-central-1", - "eu-west-1", "eu-west-2", "us-east-1", - "us-east-2", "us-west-2", ], - "AWS::CleanRooms::IdNamespaceAssociation": [ + "AWS::Cases::Field": [ "ap-northeast-1", "ap-northeast-2", + "ap-south-1", "ap-southeast-1", "ap-southeast-2", + "ca-central-1", "eu-central-1", - "eu-west-1", "eu-west-2", "us-east-1", - "us-east-2", "us-west-2", ], - "AWS::CleanRooms::Membership": [ + "AWS::Cases::Layout": [ "ap-northeast-1", "ap-northeast-2", + "ap-south-1", "ap-southeast-1", "ap-southeast-2", + "ca-central-1", "eu-central-1", - "eu-north-1", - "eu-west-1", "eu-west-2", "us-east-1", - "us-east-2", "us-west-2", ], - "AWS::CleanRooms::PrivacyBudgetTemplate": [ + "AWS::Cases::Template": [ "ap-northeast-1", "ap-northeast-2", + "ap-south-1", "ap-southeast-1", "ap-southeast-2", + "ca-central-1", "eu-central-1", - "eu-north-1", - "eu-west-1", "eu-west-2", "us-east-1", - "us-east-2", "us-west-2", ], - "AWS::CleanRoomsML::TrainingDataset": [ + "AWS::Cassandra::Keyspace": [ "ap-northeast-1", "ap-northeast-2", + "ap-south-1", "ap-southeast-1", "ap-southeast-2", + "ca-central-1", "eu-central-1", "eu-north-1", "eu-west-1", "eu-west-2", + "eu-west-3", + "sa-east-1", "us-east-1", "us-east-2", + "us-west-1", "us-west-2", ], - "AWS::Cloud9::EnvironmentEC2": [ + "AWS::Cassandra::Table": [ "ap-northeast-1", "ap-northeast-2", - "ap-northeast-3", "ap-south-1", "ap-southeast-1", "ap-southeast-2", @@ -3280,10 +3328,9 @@ "us-west-1", "us-west-2", ], - "AWS::CloudFormation::CustomResource": [ + "AWS::Cassandra::Type": [ "ap-northeast-1", "ap-northeast-2", - "ap-northeast-3", "ap-south-1", "ap-southeast-1", "ap-southeast-2", @@ -3299,7 +3346,7 @@ "us-west-1", "us-west-2", ], - "AWS::CloudFormation::GuardHook": [ + "AWS::CertificateManager::Account": [ "ap-northeast-1", "ap-northeast-2", "ap-northeast-3", @@ -3318,7 +3365,7 @@ "us-west-1", "us-west-2", ], - "AWS::CloudFormation::HookDefaultVersion": [ + "AWS::CertificateManager::Certificate": [ "ap-northeast-1", "ap-northeast-2", "ap-northeast-3", @@ -3337,7 +3384,7 @@ "us-west-1", "us-west-2", ], - "AWS::CloudFormation::HookTypeConfig": [ + "AWS::Chatbot::CustomAction": [ "ap-northeast-1", "ap-northeast-2", "ap-northeast-3", @@ -3356,7 +3403,7 @@ "us-west-1", "us-west-2", ], - "AWS::CloudFormation::HookVersion": [ + "AWS::Chatbot::MicrosoftTeamsChannelConfiguration": [ "ap-northeast-1", "ap-northeast-2", "ap-northeast-3", @@ -3375,7 +3422,7 @@ "us-west-1", "us-west-2", ], - "AWS::CloudFormation::LambdaHook": [ + "AWS::Chatbot::SlackChannelConfiguration": [ "ap-northeast-1", "ap-northeast-2", "ap-northeast-3", @@ -3394,20 +3441,268 @@ "us-west-1", "us-west-2", ], - "AWS::CloudFormation::Macro": [ + "AWS::CleanRooms::AnalysisTemplate": [ "ap-northeast-1", "ap-northeast-2", - "ap-northeast-3", - "ap-south-1", "ap-southeast-1", "ap-southeast-2", - "ca-central-1", "eu-central-1", "eu-north-1", "eu-west-1", "eu-west-2", - "eu-west-3", - "sa-east-1", + "us-east-1", + "us-east-2", + "us-west-2", + ], + "AWS::CleanRooms::Collaboration": [ + "ap-northeast-1", + "ap-northeast-2", + "ap-southeast-1", + "ap-southeast-2", + "eu-central-1", + "eu-north-1", + "eu-west-1", + "eu-west-2", + "us-east-1", + "us-east-2", + "us-west-2", + ], + "AWS::CleanRooms::ConfiguredTable": [ + "ap-northeast-1", + "ap-northeast-2", + "ap-southeast-1", + "ap-southeast-2", + "eu-central-1", + "eu-north-1", + "eu-west-1", + "eu-west-2", + "us-east-1", + "us-east-2", + "us-west-2", + ], + "AWS::CleanRooms::ConfiguredTableAssociation": [ + "ap-northeast-1", + "ap-northeast-2", + "ap-southeast-1", + "ap-southeast-2", + "eu-central-1", + "eu-north-1", + "eu-west-1", + "eu-west-2", + "us-east-1", + "us-east-2", + "us-west-2", + ], + "AWS::CleanRooms::IdMappingTable": [ + "ap-northeast-1", + "ap-northeast-2", + "ap-southeast-1", + "ap-southeast-2", + "eu-central-1", + "eu-west-1", + "eu-west-2", + "us-east-1", + "us-east-2", + "us-west-2", + ], + "AWS::CleanRooms::IdNamespaceAssociation": [ + "ap-northeast-1", + "ap-northeast-2", + "ap-southeast-1", + "ap-southeast-2", + "eu-central-1", + "eu-west-1", + "eu-west-2", + "us-east-1", + "us-east-2", + "us-west-2", + ], + "AWS::CleanRooms::Membership": [ + "ap-northeast-1", + "ap-northeast-2", + "ap-southeast-1", + "ap-southeast-2", + "eu-central-1", + "eu-north-1", + "eu-west-1", + "eu-west-2", + "us-east-1", + "us-east-2", + "us-west-2", + ], + "AWS::CleanRooms::PrivacyBudgetTemplate": [ + "ap-northeast-1", + "ap-northeast-2", + "ap-southeast-1", + "ap-southeast-2", + "eu-central-1", + "eu-north-1", + "eu-west-1", + "eu-west-2", + "us-east-1", + "us-east-2", + "us-west-2", + ], + "AWS::CleanRoomsML::TrainingDataset": [ + "ap-northeast-1", + "ap-northeast-2", + "ap-southeast-1", + "ap-southeast-2", + "eu-central-1", + "eu-north-1", + "eu-west-1", + "eu-west-2", + "us-east-1", + "us-east-2", + "us-west-2", + ], + "AWS::Cloud9::EnvironmentEC2": [ + "ap-northeast-1", + "ap-northeast-2", + "ap-northeast-3", + "ap-south-1", + "ap-southeast-1", + "ap-southeast-2", + "ca-central-1", + "eu-central-1", + "eu-north-1", + "eu-west-1", + "eu-west-2", + "eu-west-3", + "sa-east-1", + "us-east-1", + "us-east-2", + "us-west-1", + "us-west-2", + ], + "AWS::CloudFormation::CustomResource": [ + "ap-northeast-1", + "ap-northeast-2", + "ap-northeast-3", + "ap-south-1", + "ap-southeast-1", + "ap-southeast-2", + "ca-central-1", + "eu-central-1", + "eu-north-1", + "eu-west-1", + "eu-west-2", + "eu-west-3", + "sa-east-1", + "us-east-1", + "us-east-2", + "us-west-1", + "us-west-2", + ], + "AWS::CloudFormation::GuardHook": [ + "ap-northeast-1", + "ap-northeast-2", + "ap-northeast-3", + "ap-south-1", + "ap-southeast-1", + "ap-southeast-2", + "ca-central-1", + "eu-central-1", + "eu-north-1", + "eu-west-1", + "eu-west-2", + "eu-west-3", + "sa-east-1", + "us-east-1", + "us-east-2", + "us-west-1", + "us-west-2", + ], + "AWS::CloudFormation::HookDefaultVersion": [ + "ap-northeast-1", + "ap-northeast-2", + "ap-northeast-3", + "ap-south-1", + "ap-southeast-1", + "ap-southeast-2", + "ca-central-1", + "eu-central-1", + "eu-north-1", + "eu-west-1", + "eu-west-2", + "eu-west-3", + "sa-east-1", + "us-east-1", + "us-east-2", + "us-west-1", + "us-west-2", + ], + "AWS::CloudFormation::HookTypeConfig": [ + "ap-northeast-1", + "ap-northeast-2", + "ap-northeast-3", + "ap-south-1", + "ap-southeast-1", + "ap-southeast-2", + "ca-central-1", + "eu-central-1", + "eu-north-1", + "eu-west-1", + "eu-west-2", + "eu-west-3", + "sa-east-1", + "us-east-1", + "us-east-2", + "us-west-1", + "us-west-2", + ], + "AWS::CloudFormation::HookVersion": [ + "ap-northeast-1", + "ap-northeast-2", + "ap-northeast-3", + "ap-south-1", + "ap-southeast-1", + "ap-southeast-2", + "ca-central-1", + "eu-central-1", + "eu-north-1", + "eu-west-1", + "eu-west-2", + "eu-west-3", + "sa-east-1", + "us-east-1", + "us-east-2", + "us-west-1", + "us-west-2", + ], + "AWS::CloudFormation::LambdaHook": [ + "ap-northeast-1", + "ap-northeast-2", + "ap-northeast-3", + "ap-south-1", + "ap-southeast-1", + "ap-southeast-2", + "ca-central-1", + "eu-central-1", + "eu-north-1", + "eu-west-1", + "eu-west-2", + "eu-west-3", + "sa-east-1", + "us-east-1", + "us-east-2", + "us-west-1", + "us-west-2", + ], + "AWS::CloudFormation::Macro": [ + "ap-northeast-1", + "ap-northeast-2", + "ap-northeast-3", + "ap-south-1", + "ap-southeast-1", + "ap-southeast-2", + "ca-central-1", + "eu-central-1", + "eu-north-1", + "eu-west-1", + "eu-west-2", + "eu-west-3", + "sa-east-1", "us-east-1", "us-east-2", "us-west-1", @@ -3679,6 +3974,25 @@ "us-west-1", "us-west-2", ], + "AWS::CloudFront::ConnectionFunction": [ + "ap-northeast-1", + "ap-northeast-2", + "ap-northeast-3", + "ap-south-1", + "ap-southeast-1", + "ap-southeast-2", + "ca-central-1", + "eu-central-1", + "eu-north-1", + "eu-west-1", + "eu-west-2", + "eu-west-3", + "sa-east-1", + "us-east-1", + "us-east-2", + "us-west-1", + "us-west-2", + ], "AWS::CloudFront::ConnectionGroup": [ "ap-northeast-1", "ap-northeast-2", @@ -3945,7 +4259,45 @@ "us-west-1", "us-west-2", ], - "AWS::CloudFront::VpcOrigin": [ + "AWS::CloudFront::TrustStore": [ + "ap-northeast-1", + "ap-northeast-2", + "ap-northeast-3", + "ap-south-1", + "ap-southeast-1", + "ap-southeast-2", + "ca-central-1", + "eu-central-1", + "eu-north-1", + "eu-west-1", + "eu-west-2", + "eu-west-3", + "sa-east-1", + "us-east-1", + "us-east-2", + "us-west-1", + "us-west-2", + ], + "AWS::CloudFront::VpcOrigin": [ + "ap-northeast-1", + "ap-northeast-2", + "ap-northeast-3", + "ap-south-1", + "ap-southeast-1", + "ap-southeast-2", + "ca-central-1", + "eu-central-1", + "eu-north-1", + "eu-west-1", + "eu-west-2", + "eu-west-3", + "sa-east-1", + "us-east-1", + "us-east-2", + "us-west-1", + "us-west-2", + ], + "AWS::CloudTrail::Channel": [ "ap-northeast-1", "ap-northeast-2", "ap-northeast-3", @@ -3964,7 +4316,7 @@ "us-west-1", "us-west-2", ], - "AWS::CloudTrail::Channel": [ + "AWS::CloudTrail::Dashboard": [ "ap-northeast-1", "ap-northeast-2", "ap-northeast-3", @@ -3983,7 +4335,7 @@ "us-west-1", "us-west-2", ], - "AWS::CloudTrail::Dashboard": [ + "AWS::CloudTrail::EventDataStore": [ "ap-northeast-1", "ap-northeast-2", "ap-northeast-3", @@ -4002,7 +4354,7 @@ "us-west-1", "us-west-2", ], - "AWS::CloudTrail::EventDataStore": [ + "AWS::CloudTrail::ResourcePolicy": [ "ap-northeast-1", "ap-northeast-2", "ap-northeast-3", @@ -4021,7 +4373,7 @@ "us-west-1", "us-west-2", ], - "AWS::CloudTrail::ResourcePolicy": [ + "AWS::CloudTrail::Trail": [ "ap-northeast-1", "ap-northeast-2", "ap-northeast-3", @@ -4040,7 +4392,7 @@ "us-west-1", "us-west-2", ], - "AWS::CloudTrail::Trail": [ + "AWS::CloudWatch::Alarm": [ "ap-northeast-1", "ap-northeast-2", "ap-northeast-3", @@ -4059,7 +4411,7 @@ "us-west-1", "us-west-2", ], - "AWS::CloudWatch::Alarm": [ + "AWS::CloudWatch::AlarmMuteRule": [ "ap-northeast-1", "ap-northeast-2", "ap-northeast-3", @@ -4443,6 +4795,7 @@ "AWS::CodePipeline::Webhook": [ "ap-northeast-1", "ap-northeast-2", + "ap-northeast-3", "ap-south-1", "ap-southeast-1", "ap-southeast-2", @@ -4643,6 +4996,25 @@ "us-west-1", "us-west-2", ], + "AWS::Cognito::Terms": [ + "ap-northeast-1", + "ap-northeast-2", + "ap-northeast-3", + "ap-south-1", + "ap-southeast-1", + "ap-southeast-2", + "ca-central-1", + "eu-central-1", + "eu-north-1", + "eu-west-1", + "eu-west-2", + "eu-west-3", + "sa-east-1", + "us-east-1", + "us-east-2", + "us-west-1", + "us-west-2", + ], "AWS::Cognito::UserPool": [ "ap-northeast-1", "ap-northeast-2", @@ -4861,6 +5233,25 @@ "us-east-2", "us-west-2", ], + "AWS::ComputeOptimizer::AutomationRule": [ + "ap-northeast-1", + "ap-northeast-2", + "ap-northeast-3", + "ap-south-1", + "ap-southeast-1", + "ap-southeast-2", + "ca-central-1", + "eu-central-1", + "eu-north-1", + "eu-west-1", + "eu-west-2", + "eu-west-3", + "sa-east-1", + "us-east-1", + "us-east-2", + "us-west-1", + "us-west-2", + ], "AWS::Config::AggregationAuthorization": [ "ap-northeast-1", "ap-northeast-2", @@ -5103,6 +5494,16 @@ "us-east-1", "us-west-2", ], + "AWS::Connect::ContactFlowModuleAlias": [ + "ap-northeast-1", + "eu-central-1", + "us-west-2", + ], + "AWS::Connect::ContactFlowModuleVersion": [ + "ap-northeast-1", + "eu-central-1", + "us-west-2", + ], "AWS::Connect::ContactFlowVersion": [ "ca-central-1", "eu-central-1", @@ -5110,6 +5511,45 @@ "us-east-1", "us-west-2", ], + "AWS::Connect::DataTable": [ + "ap-northeast-1", + "ap-northeast-2", + "ap-northeast-3", + "ap-south-1", + "ap-southeast-1", + "ap-southeast-2", + "ca-central-1", + "eu-central-1", + "eu-west-2", + "us-east-1", + "us-west-2", + ], + "AWS::Connect::DataTableAttribute": [ + "ap-northeast-1", + "ap-northeast-2", + "ap-northeast-3", + "ap-south-1", + "ap-southeast-1", + "ap-southeast-2", + "ca-central-1", + "eu-central-1", + "eu-west-2", + "us-east-1", + "us-west-2", + ], + "AWS::Connect::DataTableRecord": [ + "ap-northeast-1", + "ap-northeast-2", + "ap-northeast-3", + "ap-south-1", + "ap-southeast-1", + "ap-southeast-2", + "ca-central-1", + "eu-central-1", + "eu-west-2", + "us-east-1", + "us-west-2", + ], "AWS::Connect::EmailAddress": [ "ap-northeast-1", "ap-northeast-2", @@ -5187,6 +5627,18 @@ "us-east-1", "us-west-2", ], + "AWS::Connect::Notification": [ + "ap-northeast-1", + "ap-northeast-2", + "ap-south-1", + "ap-southeast-1", + "ap-southeast-2", + "ca-central-1", + "eu-central-1", + "eu-west-2", + "us-east-1", + "us-west-2", + ], "AWS::Connect::PhoneNumber": [ "ap-northeast-1", "ap-northeast-2", @@ -5305,6 +5757,7 @@ "AWS::Connect::TaskTemplate": [ "ap-northeast-1", "ap-northeast-2", + "ap-northeast-3", "ap-south-1", "ap-southeast-1", "ap-southeast-2", @@ -5385,6 +5838,19 @@ "us-east-1", "us-west-2", ], + "AWS::Connect::Workspace": [ + "ap-northeast-1", + "ap-northeast-2", + "ap-northeast-3", + "ap-south-1", + "ap-southeast-1", + "ap-southeast-2", + "ca-central-1", + "eu-central-1", + "eu-west-2", + "us-east-1", + "us-west-2", + ], "AWS::ConnectCampaigns::Campaign": [ "ap-southeast-2", "ca-central-1", @@ -5815,6 +6281,8 @@ "ap-northeast-1", "ap-northeast-2", "ap-northeast-3", + "ap-southeast-2", + "ca-central-1", "eu-central-1", "eu-west-1", "eu-west-2", @@ -6329,6 +6797,23 @@ "us-east-2", "us-west-2", ], + "AWS::DataZone::FormType": [ + "ap-northeast-1", + "ap-northeast-2", + "ap-south-1", + "ap-southeast-1", + "ap-southeast-2", + "ca-central-1", + "eu-central-1", + "eu-north-1", + "eu-west-1", + "eu-west-2", + "eu-west-3", + "sa-east-1", + "us-east-1", + "us-east-2", + "us-west-2", + ], "AWS::DataZone::GroupProfile": [ "ap-northeast-1", "ap-northeast-2", @@ -6573,33 +7058,186 @@ "us-east-2", "us-west-2", ], - "AWS::Deadline::QueueLimitAssociation": [ + "AWS::Deadline::QueueLimitAssociation": [ + "ap-northeast-1", + "ap-northeast-2", + "ap-southeast-1", + "ap-southeast-2", + "eu-central-1", + "eu-west-1", + "eu-west-2", + "us-east-1", + "us-east-2", + "us-west-2", + ], + "AWS::Deadline::StorageProfile": [ + "ap-northeast-1", + "ap-northeast-2", + "ap-southeast-1", + "ap-southeast-2", + "eu-central-1", + "eu-west-1", + "eu-west-2", + "us-east-1", + "us-east-2", + "us-west-2", + ], + "AWS::Detective::Graph": [ + "ap-northeast-1", + "ap-northeast-2", + "ap-south-1", + "ap-southeast-1", + "ap-southeast-2", + "ca-central-1", + "eu-central-1", + "eu-north-1", + "eu-west-1", + "eu-west-2", + "eu-west-3", + "sa-east-1", + "us-east-1", + "us-east-2", + "us-west-1", + "us-west-2", + ], + "AWS::Detective::MemberInvitation": [ + "ap-northeast-1", + "ap-northeast-2", + "ap-south-1", + "ap-southeast-1", + "ap-southeast-2", + "ca-central-1", + "eu-central-1", + "eu-north-1", + "eu-west-1", + "eu-west-2", + "eu-west-3", + "sa-east-1", + "us-east-1", + "us-east-2", + "us-west-1", + "us-west-2", + ], + "AWS::Detective::OrganizationAdmin": [ + "ap-northeast-1", + "ap-northeast-2", + "ap-south-1", + "ap-southeast-1", + "ap-southeast-2", + "ca-central-1", + "eu-central-1", + "eu-north-1", + "eu-west-1", + "eu-west-2", + "eu-west-3", + "sa-east-1", + "us-east-1", + "us-east-2", + "us-west-1", + "us-west-2", + ], + "AWS::DevOpsAgent::AgentSpace": [ + "us-east-1", + ], + "AWS::DevOpsAgent::Association": [ + "us-east-1", + ], + "AWS::DevOpsAgent::Service": [ + "us-east-1", + ], + "AWS::DevOpsGuru::LogAnomalyDetectionIntegration": [ + "ap-northeast-1", + "ap-northeast-2", + "ap-south-1", + "ap-southeast-1", + "ap-southeast-2", + "ca-central-1", + "eu-central-1", + "eu-north-1", + "eu-west-1", + "eu-west-2", + "eu-west-3", + "sa-east-1", + "us-east-1", + "us-east-2", + "us-west-1", + "us-west-2", + ], + "AWS::DevOpsGuru::NotificationChannel": [ + "ap-northeast-1", + "ap-northeast-2", + "ap-south-1", + "ap-southeast-1", + "ap-southeast-2", + "ca-central-1", + "eu-central-1", + "eu-north-1", + "eu-west-1", + "eu-west-2", + "eu-west-3", + "sa-east-1", + "us-east-1", + "us-east-2", + "us-west-1", + "us-west-2", + ], + "AWS::DevOpsGuru::ResourceCollection": [ "ap-northeast-1", "ap-northeast-2", + "ap-south-1", "ap-southeast-1", "ap-southeast-2", + "ca-central-1", "eu-central-1", + "eu-north-1", "eu-west-1", "eu-west-2", + "eu-west-3", + "sa-east-1", "us-east-1", "us-east-2", + "us-west-1", "us-west-2", ], - "AWS::Deadline::StorageProfile": [ - "ap-northeast-1", + "AWS::DeviceFarm::DevicePool": [ + "us-west-2", + ], + "AWS::DeviceFarm::InstanceProfile": [ + "us-west-2", + ], + "AWS::DeviceFarm::NetworkProfile": [ + "us-west-2", + ], + "AWS::DeviceFarm::Project": [ + "us-west-2", + ], + "AWS::DeviceFarm::TestGridProject": [ + "us-west-2", + ], + "AWS::DeviceFarm::VPCEConfiguration": [ + "us-west-2", + ], + "AWS::DirectConnect::Connection": [ "ap-northeast-2", + "ap-northeast-3", + "ap-south-1", "ap-southeast-1", "ap-southeast-2", + "ca-central-1", "eu-central-1", + "eu-north-1", "eu-west-1", "eu-west-2", + "eu-west-3", + "sa-east-1", "us-east-1", "us-east-2", + "us-west-1", "us-west-2", ], - "AWS::Detective::Graph": [ - "ap-northeast-1", + "AWS::DirectConnect::DirectConnectGateway": [ "ap-northeast-2", + "ap-northeast-3", "ap-south-1", "ap-southeast-1", "ap-southeast-2", @@ -6615,9 +7253,9 @@ "us-west-1", "us-west-2", ], - "AWS::Detective::MemberInvitation": [ - "ap-northeast-1", + "AWS::DirectConnect::DirectConnectGatewayAssociation": [ "ap-northeast-2", + "ap-northeast-3", "ap-south-1", "ap-southeast-1", "ap-southeast-2", @@ -6633,9 +7271,9 @@ "us-west-1", "us-west-2", ], - "AWS::Detective::OrganizationAdmin": [ - "ap-northeast-1", + "AWS::DirectConnect::Lag": [ "ap-northeast-2", + "ap-northeast-3", "ap-south-1", "ap-southeast-1", "ap-southeast-2", @@ -6651,9 +7289,9 @@ "us-west-1", "us-west-2", ], - "AWS::DevOpsGuru::LogAnomalyDetectionIntegration": [ - "ap-northeast-1", + "AWS::DirectConnect::PrivateVirtualInterface": [ "ap-northeast-2", + "ap-northeast-3", "ap-south-1", "ap-southeast-1", "ap-southeast-2", @@ -6669,9 +7307,9 @@ "us-west-1", "us-west-2", ], - "AWS::DevOpsGuru::NotificationChannel": [ - "ap-northeast-1", + "AWS::DirectConnect::PublicVirtualInterface": [ "ap-northeast-2", + "ap-northeast-3", "ap-south-1", "ap-southeast-1", "ap-southeast-2", @@ -6687,9 +7325,9 @@ "us-west-1", "us-west-2", ], - "AWS::DevOpsGuru::ResourceCollection": [ - "ap-northeast-1", + "AWS::DirectConnect::TransitVirtualInterface": [ "ap-northeast-2", + "ap-northeast-3", "ap-south-1", "ap-southeast-1", "ap-southeast-2", @@ -6705,24 +7343,6 @@ "us-west-1", "us-west-2", ], - "AWS::DeviceFarm::DevicePool": [ - "us-west-2", - ], - "AWS::DeviceFarm::InstanceProfile": [ - "us-west-2", - ], - "AWS::DeviceFarm::NetworkProfile": [ - "us-west-2", - ], - "AWS::DeviceFarm::Project": [ - "us-west-2", - ], - "AWS::DeviceFarm::TestGridProject": [ - "us-west-2", - ], - "AWS::DeviceFarm::VPCEConfiguration": [ - "us-west-2", - ], "AWS::DirectoryService::MicrosoftAD": [ "ap-northeast-1", "ap-northeast-2", @@ -6841,6 +7461,23 @@ "us-east-2", "us-west-2", ], + "AWS::DocDB::GlobalCluster": [ + "ap-northeast-1", + "ap-northeast-2", + "ap-northeast-3", + "ap-south-1", + "ap-southeast-1", + "ap-southeast-2", + "ca-central-1", + "eu-central-1", + "eu-north-1", + "eu-west-1", + "eu-west-2", + "eu-west-3", + "us-east-1", + "us-east-2", + "us-west-2", + ], "AWS::DocDBElastic::Cluster": [ "ap-northeast-1", "ap-northeast-2", @@ -6895,6 +7532,25 @@ "us-west-1", "us-west-2", ], + "AWS::EC2::CapacityManagerDataExport": [ + "ap-northeast-1", + "ap-northeast-2", + "ap-northeast-3", + "ap-south-1", + "ap-southeast-1", + "ap-southeast-2", + "ca-central-1", + "eu-central-1", + "eu-north-1", + "eu-west-1", + "eu-west-2", + "eu-west-3", + "sa-east-1", + "us-east-1", + "us-east-2", + "us-west-1", + "us-west-2", + ], "AWS::EC2::CapacityReservation": [ "ap-northeast-1", "ap-northeast-2", @@ -7287,6 +7943,25 @@ "us-west-1", "us-west-2", ], + "AWS::EC2::IPAMPrefixListResolver": [ + "ap-northeast-1", + "ap-northeast-2", + "ap-northeast-3", + "ap-south-1", + "ap-southeast-1", + "ap-southeast-2", + "ca-central-1", + "eu-central-1", + "eu-north-1", + "eu-west-1", + "eu-west-2", + "eu-west-3", + "sa-east-1", + "us-east-1", + "us-east-2", + "us-west-1", + "us-west-2", + ], "AWS::EC2::IPAMResourceDiscovery": [ "ap-northeast-1", "ap-northeast-2", @@ -7534,6 +8209,44 @@ "us-west-1", "us-west-2", ], + "AWS::EC2::LocalGatewayVirtualInterface": [ + "ap-northeast-1", + "ap-northeast-2", + "ap-northeast-3", + "ap-south-1", + "ap-southeast-1", + "ap-southeast-2", + "ca-central-1", + "eu-central-1", + "eu-north-1", + "eu-west-1", + "eu-west-2", + "eu-west-3", + "sa-east-1", + "us-east-1", + "us-east-2", + "us-west-1", + "us-west-2", + ], + "AWS::EC2::LocalGatewayVirtualInterfaceGroup": [ + "ap-northeast-1", + "ap-northeast-2", + "ap-northeast-3", + "ap-south-1", + "ap-southeast-1", + "ap-southeast-2", + "ca-central-1", + "eu-central-1", + "eu-north-1", + "eu-west-1", + "eu-west-2", + "eu-west-3", + "sa-east-1", + "us-east-1", + "us-east-2", + "us-west-1", + "us-west-2", + ], "AWS::EC2::NatGateway": [ "ap-northeast-1", "ap-northeast-2", @@ -7802,13 +8515,18 @@ ], "AWS::EC2::RouteServer": [ "ap-northeast-1", + "ap-northeast-2", + "ap-northeast-3", + "ap-south-1", "ap-southeast-1", "ap-southeast-2", "ca-central-1", "eu-central-1", + "eu-north-1", "eu-west-1", "eu-west-2", "eu-west-3", + "sa-east-1", "us-east-1", "us-east-2", "us-west-1", @@ -7816,13 +8534,18 @@ ], "AWS::EC2::RouteServerAssociation": [ "ap-northeast-1", + "ap-northeast-2", + "ap-northeast-3", + "ap-south-1", "ap-southeast-1", "ap-southeast-2", "ca-central-1", "eu-central-1", + "eu-north-1", "eu-west-1", "eu-west-2", "eu-west-3", + "sa-east-1", "us-east-1", "us-east-2", "us-west-1", @@ -7830,13 +8553,18 @@ ], "AWS::EC2::RouteServerEndpoint": [ "ap-northeast-1", + "ap-northeast-2", + "ap-northeast-3", + "ap-south-1", "ap-southeast-1", "ap-southeast-2", "ca-central-1", "eu-central-1", + "eu-north-1", "eu-west-1", "eu-west-2", "eu-west-3", + "sa-east-1", "us-east-1", "us-east-2", "us-west-1", @@ -7844,13 +8572,18 @@ ], "AWS::EC2::RouteServerPeer": [ "ap-northeast-1", + "ap-northeast-2", + "ap-northeast-3", + "ap-south-1", "ap-southeast-1", "ap-southeast-2", "ca-central-1", "eu-central-1", + "eu-north-1", "eu-west-1", "eu-west-2", "eu-west-3", + "sa-east-1", "us-east-1", "us-east-2", "us-west-1", @@ -7858,13 +8591,18 @@ ], "AWS::EC2::RouteServerPropagation": [ "ap-northeast-1", + "ap-northeast-2", + "ap-northeast-3", + "ap-south-1", "ap-southeast-1", "ap-southeast-2", "ca-central-1", "eu-central-1", + "eu-north-1", "eu-west-1", "eu-west-2", "eu-west-3", + "sa-east-1", "us-east-1", "us-east-2", "us-west-1", @@ -8231,6 +8969,44 @@ "us-west-1", "us-west-2", ], + "AWS::EC2::TransitGatewayMeteringPolicy": [ + "ap-northeast-1", + "ap-northeast-2", + "ap-northeast-3", + "ap-south-1", + "ap-southeast-1", + "ap-southeast-2", + "ca-central-1", + "eu-central-1", + "eu-north-1", + "eu-west-1", + "eu-west-2", + "eu-west-3", + "sa-east-1", + "us-east-1", + "us-east-2", + "us-west-1", + "us-west-2", + ], + "AWS::EC2::TransitGatewayMeteringPolicyEntry": [ + "ap-northeast-1", + "ap-northeast-2", + "ap-northeast-3", + "ap-south-1", + "ap-southeast-1", + "ap-southeast-2", + "ca-central-1", + "eu-central-1", + "eu-north-1", + "eu-west-1", + "eu-west-2", + "eu-west-3", + "sa-east-1", + "us-east-1", + "us-east-2", + "us-west-1", + "us-west-2", + ], "AWS::EC2::TransitGatewayMulticastDomain": [ "ap-northeast-1", "ap-northeast-2", @@ -8516,6 +9292,24 @@ "us-west-1", "us-west-2", ], + "AWS::EC2::VPCEncryptionControl": [ + "ap-northeast-1", + "ap-northeast-3", + "ap-south-1", + "ap-southeast-1", + "ap-southeast-2", + "ca-central-1", + "eu-central-1", + "eu-north-1", + "eu-west-1", + "eu-west-2", + "eu-west-3", + "sa-east-1", + "us-east-1", + "us-east-2", + "us-west-1", + "us-west-2", + ], "AWS::EC2::VPCEndpoint": [ "ap-northeast-1", "ap-northeast-2", @@ -8535,7 +9329,26 @@ "us-west-1", "us-west-2", ], - "AWS::EC2::VPCEndpointConnectionNotification": [ + "AWS::EC2::VPCEndpointConnectionNotification": [ + "ap-northeast-1", + "ap-northeast-2", + "ap-northeast-3", + "ap-south-1", + "ap-southeast-1", + "ap-southeast-2", + "ca-central-1", + "eu-central-1", + "eu-north-1", + "eu-west-1", + "eu-west-2", + "eu-west-3", + "sa-east-1", + "us-east-1", + "us-east-2", + "us-west-1", + "us-west-2", + ], + "AWS::EC2::VPCEndpointService": [ "ap-northeast-1", "ap-northeast-2", "ap-northeast-3", @@ -8554,7 +9367,7 @@ "us-west-1", "us-west-2", ], - "AWS::EC2::VPCEndpointService": [ + "AWS::EC2::VPCEndpointServicePermissions": [ "ap-northeast-1", "ap-northeast-2", "ap-northeast-3", @@ -8573,7 +9386,7 @@ "us-west-1", "us-west-2", ], - "AWS::EC2::VPCEndpointServicePermissions": [ + "AWS::EC2::VPCGatewayAttachment": [ "ap-northeast-1", "ap-northeast-2", "ap-northeast-3", @@ -8592,7 +9405,7 @@ "us-west-1", "us-west-2", ], - "AWS::EC2::VPCGatewayAttachment": [ + "AWS::EC2::VPCPeeringConnection": [ "ap-northeast-1", "ap-northeast-2", "ap-northeast-3", @@ -8611,7 +9424,7 @@ "us-west-1", "us-west-2", ], - "AWS::EC2::VPCPeeringConnection": [ + "AWS::EC2::VPNConcentrator": [ "ap-northeast-1", "ap-northeast-2", "ap-northeast-3", @@ -8834,6 +9647,25 @@ "us-west-1", "us-west-2", ], + "AWS::ECR::PullTimeUpdateExclusion": [ + "ap-northeast-1", + "ap-northeast-2", + "ap-northeast-3", + "ap-south-1", + "ap-southeast-1", + "ap-southeast-2", + "ca-central-1", + "eu-central-1", + "eu-north-1", + "eu-west-1", + "eu-west-2", + "eu-west-3", + "sa-east-1", + "us-east-1", + "us-east-2", + "us-west-1", + "us-west-2", + ], "AWS::ECR::RegistryPolicy": [ "ap-northeast-1", "ap-northeast-2", @@ -8929,6 +9761,24 @@ "us-west-1", "us-west-2", ], + "AWS::ECR::SigningConfiguration": [ + "ap-northeast-1", + "ap-northeast-2", + "ap-south-1", + "ap-southeast-1", + "ap-southeast-2", + "ca-central-1", + "eu-central-1", + "eu-north-1", + "eu-west-1", + "eu-west-2", + "eu-west-3", + "sa-east-1", + "us-east-1", + "us-east-2", + "us-west-1", + "us-west-2", + ], "AWS::ECS::CapacityProvider": [ "ap-northeast-1", "ap-northeast-2", @@ -8986,6 +9836,25 @@ "us-west-1", "us-west-2", ], + "AWS::ECS::ExpressGatewayService": [ + "ap-northeast-1", + "ap-northeast-2", + "ap-northeast-3", + "ap-south-1", + "ap-southeast-1", + "ap-southeast-2", + "ca-central-1", + "eu-central-1", + "eu-north-1", + "eu-west-1", + "eu-west-2", + "eu-west-3", + "sa-east-1", + "us-east-1", + "us-east-2", + "us-west-1", + "us-west-2", + ], "AWS::ECS::PrimaryTaskSet": [ "ap-northeast-1", "ap-northeast-2", @@ -9157,6 +10026,25 @@ "us-west-1", "us-west-2", ], + "AWS::EKS::Capability": [ + "ap-northeast-1", + "ap-northeast-2", + "ap-northeast-3", + "ap-south-1", + "ap-southeast-1", + "ap-southeast-2", + "ca-central-1", + "eu-central-1", + "eu-north-1", + "eu-west-1", + "eu-west-2", + "eu-west-3", + "sa-east-1", + "us-east-1", + "us-east-2", + "us-west-1", + "us-west-2", + ], "AWS::EKS::Cluster": [ "ap-northeast-1", "ap-northeast-2", @@ -9388,6 +10276,43 @@ "AWS::EMR::WALWorkspace": [ "ap-northeast-1", "ap-northeast-2", + "ap-northeast-3", + "ap-south-1", + "ap-southeast-1", + "ap-southeast-2", + "ca-central-1", + "eu-central-1", + "eu-north-1", + "eu-west-1", + "eu-west-2", + "sa-east-1", + "us-east-1", + "us-east-2", + "us-west-1", + "us-west-2", + ], + "AWS::EMRContainers::Endpoint": [ + "ap-northeast-1", + "ap-northeast-2", + "ap-south-1", + "ap-southeast-1", + "ap-southeast-2", + "ca-central-1", + "eu-central-1", + "eu-north-1", + "eu-west-1", + "eu-west-2", + "eu-west-3", + "sa-east-1", + "us-east-1", + "us-east-2", + "us-west-1", + "us-west-2", + ], + "AWS::EMRContainers::SecurityConfiguration": [ + "ap-northeast-1", + "ap-northeast-2", + "ap-northeast-3", "ap-south-1", "ap-southeast-1", "ap-southeast-2", @@ -9396,9 +10321,11 @@ "eu-north-1", "eu-west-1", "eu-west-2", + "eu-west-3", "sa-east-1", "us-east-1", "us-east-2", + "us-west-1", "us-west-2", ], "AWS::EMRContainers::VirtualCluster": [ @@ -9441,10 +10368,18 @@ ], "AWS::EVS::Environment": [ "ap-northeast-1", + "ap-south-1", + "ap-southeast-1", + "ap-southeast-2", + "ca-central-1", "eu-central-1", "eu-west-1", + "eu-west-2", + "eu-west-3", + "sa-east-1", "us-east-1", "us-east-2", + "us-west-1", "us-west-2", ], "AWS::ElastiCache::CacheCluster": [ @@ -10216,6 +11151,7 @@ "AWS::FIS::ExperimentTemplate": [ "ap-northeast-1", "ap-northeast-2", + "ap-northeast-3", "ap-south-1", "ap-southeast-1", "ap-southeast-2", @@ -10234,6 +11170,7 @@ "AWS::FIS::TargetAccountConfiguration": [ "ap-northeast-1", "ap-northeast-2", + "ap-northeast-3", "ap-south-1", "ap-southeast-1", "ap-southeast-2", @@ -10346,13 +11283,21 @@ ], "AWS::FSx::S3AccessPointAttachment": [ "ap-northeast-1", + "ap-northeast-2", + "ap-northeast-3", + "ap-south-1", "ap-southeast-1", "ap-southeast-2", + "ca-central-1", "eu-central-1", "eu-north-1", "eu-west-1", + "eu-west-2", + "eu-west-3", + "sa-east-1", "us-east-1", "us-east-2", + "us-west-1", "us-west-2", ], "AWS::FSx::Snapshot": [ @@ -10914,6 +11859,55 @@ "us-west-1", "us-west-2", ], + "AWS::Glue::IdentityCenterConfiguration": [ + "ap-northeast-1", + "ap-northeast-2", + "ap-northeast-3", + "ap-south-1", + "ap-southeast-1", + "ap-southeast-2", + "ca-central-1", + "eu-central-1", + "eu-north-1", + "eu-west-1", + "eu-west-2", + "eu-west-3", + "sa-east-1", + "us-east-1", + "us-east-2", + "us-west-1", + "us-west-2", + ], + "AWS::Glue::Integration": [ + "ap-northeast-1", + "ap-northeast-2", + "ap-southeast-1", + "ap-southeast-2", + "ca-central-1", + "eu-central-1", + "eu-north-1", + "eu-west-1", + "eu-west-2", + "sa-east-1", + "us-east-1", + "us-east-2", + "us-west-2", + ], + "AWS::Glue::IntegrationResourceProperty": [ + "ap-northeast-1", + "ap-northeast-2", + "ap-southeast-1", + "ap-southeast-2", + "ca-central-1", + "eu-central-1", + "eu-north-1", + "eu-west-1", + "eu-west-2", + "sa-east-1", + "us-east-1", + "us-east-2", + "us-west-2", + ], "AWS::Glue::Job": [ "ap-northeast-1", "ap-northeast-2", @@ -11442,6 +12436,18 @@ "us-east-2", "us-west-2", ], + "AWS::GroundStation::DataflowEndpointGroupV2": [ + "ap-northeast-2", + "ap-southeast-1", + "ap-southeast-2", + "eu-central-1", + "eu-north-1", + "eu-west-1", + "sa-east-1", + "us-east-1", + "us-east-2", + "us-west-2", + ], "AWS::GroundStation::MissionProfile": [ "ap-northeast-2", "ap-southeast-1", @@ -11653,6 +12659,7 @@ "AWS::HealthLake::FHIRDatastore": [ "ap-south-1", "ap-southeast-2", + "ca-central-1", "eu-west-1", "eu-west-2", "us-east-1", @@ -12345,6 +13352,7 @@ "ap-southeast-1", "ap-southeast-2", "eu-central-1", + "eu-north-1", "eu-west-1", "eu-west-2", "us-east-1", @@ -12356,6 +13364,7 @@ "ap-southeast-1", "ap-southeast-2", "eu-central-1", + "eu-north-1", "eu-west-1", "eu-west-2", "us-east-1", @@ -13047,21 +14056,6 @@ "us-east-2", "us-west-2", ], - "AWS::IoTFleetHub::Application": [ - "ap-northeast-1", - "ap-northeast-2", - "ap-south-1", - "ap-southeast-1", - "ap-southeast-2", - "ca-central-1", - "eu-central-1", - "eu-north-1", - "eu-west-1", - "eu-west-2", - "us-east-1", - "us-east-2", - "us-west-2", - ], "AWS::IoTFleetWise::Campaign": [ "ap-south-1", "eu-central-1", @@ -13420,6 +14414,7 @@ "AWS::KafkaConnect::Connector": [ "ap-northeast-1", "ap-northeast-2", + "ap-northeast-3", "ap-south-1", "ap-southeast-1", "ap-southeast-2", @@ -13438,6 +14433,7 @@ "AWS::KafkaConnect::CustomPlugin": [ "ap-northeast-1", "ap-northeast-2", + "ap-northeast-3", "ap-south-1", "ap-southeast-1", "ap-southeast-2", @@ -13456,6 +14452,7 @@ "AWS::KafkaConnect::WorkerConfiguration": [ "ap-northeast-1", "ap-northeast-2", + "ap-northeast-3", "ap-south-1", "ap-southeast-1", "ap-southeast-2", @@ -13905,6 +14902,18 @@ "us-west-1", "us-west-2", ], + "AWS::Lambda::CapacityProvider": [ + "ap-northeast-1", + "ap-south-1", + "ap-southeast-1", + "ap-southeast-2", + "eu-central-1", + "eu-north-1", + "eu-west-1", + "us-east-1", + "us-east-2", + "us-west-2", + ], "AWS::Lambda::CodeSigningConfig": [ "ap-northeast-1", "ap-northeast-2", @@ -14145,7 +15154,43 @@ "us-east-1", "us-west-2", ], - "AWS::LicenseManager::Grant": [ + "AWS::LicenseManager::Grant": [ + "ap-northeast-1", + "ap-northeast-2", + "ap-south-1", + "ap-southeast-1", + "ap-southeast-2", + "ca-central-1", + "eu-central-1", + "eu-north-1", + "eu-west-1", + "eu-west-2", + "eu-west-3", + "sa-east-1", + "us-east-1", + "us-east-2", + "us-west-1", + "us-west-2", + ], + "AWS::LicenseManager::License": [ + "ap-northeast-1", + "ap-northeast-2", + "ap-south-1", + "ap-southeast-1", + "ap-southeast-2", + "ca-central-1", + "eu-central-1", + "eu-north-1", + "eu-west-1", + "eu-west-2", + "eu-west-3", + "sa-east-1", + "us-east-1", + "us-east-2", + "us-west-1", + "us-west-2", + ], + "AWS::Lightsail::Alarm": [ "ap-northeast-1", "ap-northeast-2", "ap-south-1", @@ -14157,13 +15202,11 @@ "eu-west-1", "eu-west-2", "eu-west-3", - "sa-east-1", "us-east-1", "us-east-2", - "us-west-1", "us-west-2", ], - "AWS::LicenseManager::License": [ + "AWS::Lightsail::Bucket": [ "ap-northeast-1", "ap-northeast-2", "ap-south-1", @@ -14175,13 +15218,11 @@ "eu-west-1", "eu-west-2", "eu-west-3", - "sa-east-1", "us-east-1", "us-east-2", - "us-west-1", "us-west-2", ], - "AWS::Lightsail::Alarm": [ + "AWS::Lightsail::Certificate": [ "ap-northeast-1", "ap-northeast-2", "ap-south-1", @@ -14197,7 +15238,7 @@ "us-east-2", "us-west-2", ], - "AWS::Lightsail::Bucket": [ + "AWS::Lightsail::Container": [ "ap-northeast-1", "ap-northeast-2", "ap-south-1", @@ -14213,7 +15254,7 @@ "us-east-2", "us-west-2", ], - "AWS::Lightsail::Certificate": [ + "AWS::Lightsail::Database": [ "ap-northeast-1", "ap-northeast-2", "ap-south-1", @@ -14229,7 +15270,7 @@ "us-east-2", "us-west-2", ], - "AWS::Lightsail::Container": [ + "AWS::Lightsail::DatabaseSnapshot": [ "ap-northeast-1", "ap-northeast-2", "ap-south-1", @@ -14245,7 +15286,7 @@ "us-east-2", "us-west-2", ], - "AWS::Lightsail::Database": [ + "AWS::Lightsail::Disk": [ "ap-northeast-1", "ap-northeast-2", "ap-south-1", @@ -14261,7 +15302,7 @@ "us-east-2", "us-west-2", ], - "AWS::Lightsail::Disk": [ + "AWS::Lightsail::DiskSnapshot": [ "ap-northeast-1", "ap-northeast-2", "ap-south-1", @@ -14696,7 +15737,7 @@ "us-west-1", "us-west-2", ], - "AWS::Logs::SubscriptionFilter": [ + "AWS::Logs::ScheduledQuery": [ "ap-northeast-1", "ap-northeast-2", "ap-northeast-3", @@ -14705,7 +15746,6 @@ "ap-southeast-2", "ca-central-1", "eu-central-1", - "eu-north-1", "eu-west-1", "eu-west-2", "eu-west-3", @@ -14715,7 +15755,7 @@ "us-west-1", "us-west-2", ], - "AWS::Logs::Transformer": [ + "AWS::Logs::SubscriptionFilter": [ "ap-northeast-1", "ap-northeast-2", "ap-northeast-3", @@ -14734,32 +15774,29 @@ "us-west-1", "us-west-2", ], - "AWS::LookoutEquipment::InferenceScheduler": [ - "ap-northeast-2", - "eu-west-1", - "us-east-1", - ], - "AWS::LookoutMetrics::Alert": [ + "AWS::Logs::Transformer": [ "ap-northeast-1", + "ap-northeast-2", + "ap-northeast-3", + "ap-south-1", "ap-southeast-1", "ap-southeast-2", + "ca-central-1", "eu-central-1", "eu-north-1", "eu-west-1", + "eu-west-2", + "eu-west-3", + "sa-east-1", "us-east-1", "us-east-2", + "us-west-1", "us-west-2", ], - "AWS::LookoutMetrics::AnomalyDetector": [ - "ap-northeast-1", - "ap-southeast-1", - "ap-southeast-2", - "eu-central-1", - "eu-north-1", + "AWS::LookoutEquipment::InferenceScheduler": [ + "ap-northeast-2", "eu-west-1", "us-east-1", - "us-east-2", - "us-west-2", ], "AWS::LookoutVision::Project": [ "ap-northeast-1", @@ -14912,6 +15949,7 @@ "AWS::MSK::Replicator": [ "ap-northeast-1", "ap-northeast-2", + "ap-northeast-3", "ap-south-1", "ap-southeast-1", "ap-southeast-2", @@ -14939,8 +15977,28 @@ "eu-west-1", "eu-west-2", "eu-west-3", + "sa-east-1", + "us-east-1", + "us-east-2", + "us-west-2", + ], + "AWS::MSK::Topic": [ + "ap-northeast-1", + "ap-northeast-2", + "ap-northeast-3", + "ap-south-1", + "ap-southeast-1", + "ap-southeast-2", + "ca-central-1", + "eu-central-1", + "eu-north-1", + "eu-west-1", + "eu-west-2", + "eu-west-3", + "sa-east-1", "us-east-1", "us-east-2", + "us-west-1", "us-west-2", ], "AWS::MSK::VpcConnection": [ @@ -14981,6 +16039,23 @@ "us-west-1", "us-west-2", ], + "AWS::MWAAServerless::Workflow": [ + "ap-northeast-1", + "ap-northeast-2", + "ap-south-1", + "ap-southeast-1", + "ap-southeast-2", + "ca-central-1", + "eu-central-1", + "eu-north-1", + "eu-west-1", + "eu-west-2", + "eu-west-3", + "sa-east-1", + "us-east-1", + "us-east-2", + "us-west-2", + ], "AWS::Macie::AllowList": [ "ap-northeast-1", "ap-northeast-2", @@ -15255,6 +16330,63 @@ "us-west-1", "us-west-2", ], + "AWS::MediaConnect::RouterInput": [ + "ap-northeast-1", + "ap-northeast-2", + "ap-northeast-3", + "ap-south-1", + "ap-southeast-1", + "ap-southeast-2", + "ca-central-1", + "eu-central-1", + "eu-north-1", + "eu-west-1", + "eu-west-2", + "eu-west-3", + "sa-east-1", + "us-east-1", + "us-east-2", + "us-west-1", + "us-west-2", + ], + "AWS::MediaConnect::RouterNetworkInterface": [ + "ap-northeast-1", + "ap-northeast-2", + "ap-northeast-3", + "ap-south-1", + "ap-southeast-1", + "ap-southeast-2", + "ca-central-1", + "eu-central-1", + "eu-north-1", + "eu-west-1", + "eu-west-2", + "eu-west-3", + "sa-east-1", + "us-east-1", + "us-east-2", + "us-west-1", + "us-west-2", + ], + "AWS::MediaConnect::RouterOutput": [ + "ap-northeast-1", + "ap-northeast-2", + "ap-northeast-3", + "ap-south-1", + "ap-southeast-1", + "ap-southeast-2", + "ca-central-1", + "eu-central-1", + "eu-north-1", + "eu-west-1", + "eu-west-2", + "eu-west-3", + "sa-east-1", + "us-east-1", + "us-east-2", + "us-west-1", + "us-west-2", + ], "AWS::MediaConvert::JobTemplate": [ "ap-northeast-1", "ap-northeast-2", @@ -16072,24 +17204,40 @@ ], "AWS::NeptuneGraph::Graph": [ "ap-northeast-1", + "ap-northeast-2", + "ap-northeast-3", "ap-south-1", "ap-southeast-1", + "ap-southeast-2", + "ca-central-1", "eu-central-1", + "eu-north-1", "eu-west-1", "eu-west-2", + "eu-west-3", + "sa-east-1", "us-east-1", "us-east-2", + "us-west-1", "us-west-2", ], "AWS::NeptuneGraph::PrivateGraphEndpoint": [ "ap-northeast-1", + "ap-northeast-2", + "ap-northeast-3", "ap-south-1", "ap-southeast-1", + "ap-southeast-2", + "ca-central-1", "eu-central-1", + "eu-north-1", "eu-west-1", "eu-west-2", + "eu-west-3", + "sa-east-1", "us-east-1", "us-east-2", + "us-west-1", "us-west-2", ], "AWS::NetworkFirewall::Firewall": [ @@ -16263,6 +17411,24 @@ "us-west-1", "us-west-2", ], + "AWS::NetworkManager::CoreNetworkPrefixListAssociation": [ + "ap-northeast-1", + "ap-northeast-2", + "ap-northeast-3", + "ap-south-1", + "ap-southeast-1", + "ap-southeast-2", + "ca-central-1", + "eu-central-1", + "eu-north-1", + "eu-west-1", + "eu-west-2", + "eu-west-3", + "us-east-1", + "us-east-2", + "us-west-1", + "us-west-2", + ], "AWS::NetworkManager::CustomerGatewayAssociation": [ "ap-northeast-1", "ap-northeast-2", @@ -16520,28 +17686,119 @@ "us-east-1", ], "AWS::ODB::CloudAutonomousVmCluster": [ + "ap-northeast-1", + "ap-southeast-2", + "ca-central-1", + "eu-central-1", + "eu-west-1", + "eu-west-2", "us-east-1", + "us-east-2", "us-west-2", ], "AWS::ODB::CloudExadataInfrastructure": [ + "ap-northeast-1", + "ap-southeast-2", + "ca-central-1", + "eu-central-1", + "eu-west-1", + "eu-west-2", "us-east-1", + "us-east-2", "us-west-2", ], "AWS::ODB::CloudVmCluster": [ + "ap-northeast-1", + "ap-southeast-2", + "ca-central-1", + "eu-central-1", + "eu-west-1", + "eu-west-2", "us-east-1", + "us-east-2", "us-west-2", ], "AWS::ODB::OdbNetwork": [ + "ap-northeast-1", + "ap-southeast-2", + "ca-central-1", + "eu-central-1", + "eu-west-1", + "eu-west-2", "us-east-1", + "us-east-2", "us-west-2", ], "AWS::ODB::OdbPeeringConnection": [ + "ap-northeast-1", + "ap-southeast-2", + "ca-central-1", + "eu-central-1", + "eu-west-1", + "eu-west-2", + "us-east-1", + "us-east-2", + "us-west-2", + ], + "AWS::OSIS::Pipeline": [ + "ap-northeast-1", + "ap-northeast-2", + "ap-south-1", + "ap-southeast-1", + "ap-southeast-2", + "ca-central-1", + "eu-central-1", + "eu-north-1", + "eu-west-1", + "eu-west-2", + "sa-east-1", + "us-east-1", + "us-east-2", + "us-west-1", + "us-west-2", + ], + "AWS::Oam::Link": [ + "ap-northeast-1", + "ap-northeast-2", + "ap-northeast-3", + "ap-south-1", + "ap-southeast-1", + "ap-southeast-2", + "ca-central-1", + "eu-central-1", + "eu-north-1", + "eu-west-1", + "eu-west-2", + "eu-west-3", + "sa-east-1", + "us-east-1", + "us-east-2", + "us-west-1", + "us-west-2", + ], + "AWS::Oam::Sink": [ + "ap-northeast-1", + "ap-northeast-2", + "ap-northeast-3", + "ap-south-1", + "ap-southeast-1", + "ap-southeast-2", + "ca-central-1", + "eu-central-1", + "eu-north-1", + "eu-west-1", + "eu-west-2", + "eu-west-3", + "sa-east-1", "us-east-1", + "us-east-2", + "us-west-1", "us-west-2", ], - "AWS::OSIS::Pipeline": [ + "AWS::ObservabilityAdmin::OrganizationCentralizationRule": [ "ap-northeast-1", "ap-northeast-2", + "ap-northeast-3", "ap-south-1", "ap-southeast-1", "ap-southeast-2", @@ -16550,13 +17807,14 @@ "eu-north-1", "eu-west-1", "eu-west-2", + "eu-west-3", "sa-east-1", "us-east-1", "us-east-2", "us-west-1", "us-west-2", ], - "AWS::Oam::Link": [ + "AWS::ObservabilityAdmin::OrganizationTelemetryRule": [ "ap-northeast-1", "ap-northeast-2", "ap-northeast-3", @@ -16575,7 +17833,7 @@ "us-west-1", "us-west-2", ], - "AWS::Oam::Sink": [ + "AWS::ObservabilityAdmin::S3TableIntegration": [ "ap-northeast-1", "ap-northeast-2", "ap-northeast-3", @@ -16594,7 +17852,7 @@ "us-west-1", "us-west-2", ], - "AWS::ObservabilityAdmin::OrganizationTelemetryRule": [ + "AWS::ObservabilityAdmin::TelemetryPipelines": [ "ap-northeast-1", "ap-northeast-2", "ap-northeast-3", @@ -16729,6 +17987,25 @@ "us-west-1", "us-west-2", ], + "AWS::OpenSearchServerless::CollectionGroup": [ + "ap-northeast-1", + "ap-northeast-2", + "ap-northeast-3", + "ap-south-1", + "ap-southeast-1", + "ap-southeast-2", + "ca-central-1", + "eu-central-1", + "eu-north-1", + "eu-west-1", + "eu-west-2", + "eu-west-3", + "sa-east-1", + "us-east-1", + "us-east-2", + "us-west-1", + "us-west-2", + ], "AWS::OpenSearchServerless::Index": [ "ap-northeast-1", "ap-northeast-2", @@ -17228,36 +18505,42 @@ ], "AWS::PCS::Cluster": [ "ap-northeast-1", + "ap-south-1", "ap-southeast-1", "ap-southeast-2", "eu-central-1", "eu-north-1", "eu-west-1", "eu-west-2", + "eu-west-3", "us-east-1", "us-east-2", "us-west-2", ], "AWS::PCS::ComputeNodeGroup": [ "ap-northeast-1", + "ap-south-1", "ap-southeast-1", "ap-southeast-2", "eu-central-1", "eu-north-1", "eu-west-1", "eu-west-2", + "eu-west-3", "us-east-1", "us-east-2", "us-west-2", ], "AWS::PCS::Queue": [ "ap-northeast-1", + "ap-south-1", "ap-southeast-1", "ap-southeast-2", "eu-central-1", "eu-north-1", "eu-west-1", "eu-west-2", + "eu-west-3", "us-east-1", "us-east-2", "us-west-2", @@ -17291,8 +18574,12 @@ "ap-northeast-3", "ap-south-1", "ap-southeast-1", + "ap-southeast-2", + "ca-central-1", "eu-central-1", "eu-west-1", + "eu-west-2", + "eu-west-3", "us-east-1", "us-east-2", "us-west-2", @@ -17302,8 +18589,12 @@ "ap-northeast-3", "ap-south-1", "ap-southeast-1", + "ap-southeast-2", + "ca-central-1", "eu-central-1", "eu-west-1", + "eu-west-2", + "eu-west-3", "us-east-1", "us-east-2", "us-west-2", @@ -17729,6 +19020,7 @@ "us-west-2", ], "AWS::QBusiness::Plugin": [ + "eu-west-1", "us-east-1", "us-west-2", ], @@ -17769,6 +19061,12 @@ "us-east-2", "us-west-2", ], + "AWS::QuickSight::ActionConnector": [ + "ap-southeast-2", + "eu-west-1", + "us-east-1", + "us-west-2", + ], "AWS::QuickSight::Analysis": [ "ap-northeast-1", "ap-northeast-2", @@ -18293,6 +19591,46 @@ "us-west-1", "us-west-2", ], + "AWS::RTBFabric::InboundExternalLink": [ + "ap-northeast-1", + "ap-southeast-1", + "eu-central-1", + "eu-west-1", + "us-east-1", + "us-west-2", + ], + "AWS::RTBFabric::Link": [ + "ap-northeast-1", + "ap-southeast-1", + "eu-central-1", + "eu-west-1", + "us-east-1", + "us-west-2", + ], + "AWS::RTBFabric::OutboundExternalLink": [ + "ap-northeast-1", + "ap-southeast-1", + "eu-central-1", + "eu-west-1", + "us-east-1", + "us-west-2", + ], + "AWS::RTBFabric::RequesterGateway": [ + "ap-northeast-1", + "ap-southeast-1", + "eu-central-1", + "eu-west-1", + "us-east-1", + "us-west-2", + ], + "AWS::RTBFabric::ResponderGateway": [ + "ap-northeast-1", + "ap-southeast-1", + "eu-central-1", + "eu-west-1", + "us-east-1", + "us-west-2", + ], "AWS::RUM::AppMonitor": [ "ap-northeast-1", "ap-northeast-2", @@ -18524,6 +19862,7 @@ "AWS::RedshiftServerless::Namespace": [ "ap-northeast-1", "ap-northeast-2", + "ap-northeast-3", "ap-south-1", "ap-southeast-1", "ap-southeast-2", @@ -18542,6 +19881,7 @@ "AWS::RedshiftServerless::Snapshot": [ "ap-northeast-1", "ap-northeast-2", + "ap-northeast-3", "ap-south-1", "ap-southeast-1", "ap-southeast-2", @@ -18560,6 +19900,7 @@ "AWS::RedshiftServerless::Workgroup": [ "ap-northeast-1", "ap-northeast-2", + "ap-northeast-3", "ap-south-1", "ap-southeast-1", "ap-southeast-2", @@ -19806,6 +21147,54 @@ "us-west-1", "us-west-2", ], + "AWS::S3Vectors::Index": [ + "ap-northeast-1", + "ap-northeast-2", + "ap-south-1", + "ap-southeast-1", + "ap-southeast-2", + "ca-central-1", + "eu-central-1", + "eu-north-1", + "eu-west-1", + "eu-west-2", + "eu-west-3", + "us-east-1", + "us-east-2", + "us-west-2", + ], + "AWS::S3Vectors::VectorBucket": [ + "ap-northeast-1", + "ap-northeast-2", + "ap-south-1", + "ap-southeast-1", + "ap-southeast-2", + "ca-central-1", + "eu-central-1", + "eu-north-1", + "eu-west-1", + "eu-west-2", + "eu-west-3", + "us-east-1", + "us-east-2", + "us-west-2", + ], + "AWS::S3Vectors::VectorBucketPolicy": [ + "ap-northeast-1", + "ap-northeast-2", + "ap-south-1", + "ap-southeast-1", + "ap-southeast-2", + "ca-central-1", + "eu-central-1", + "eu-north-1", + "eu-west-1", + "eu-west-2", + "eu-west-3", + "us-east-1", + "us-east-2", + "us-west-2", + ], "AWS::SDB::Domain": [ "ap-northeast-1", "ap-northeast-2", @@ -19882,6 +21271,25 @@ "us-west-1", "us-west-2", ], + "AWS::SES::CustomVerificationEmailTemplate": [ + "ap-northeast-1", + "ap-northeast-2", + "ap-northeast-3", + "ap-south-1", + "ap-southeast-1", + "ap-southeast-2", + "ca-central-1", + "eu-central-1", + "eu-north-1", + "eu-west-1", + "eu-west-2", + "eu-west-3", + "sa-east-1", + "us-east-1", + "us-east-2", + "us-west-1", + "us-west-2", + ], "AWS::SES::DedicatedIpPool": [ "ap-northeast-1", "ap-northeast-2", @@ -20072,6 +21480,25 @@ "us-west-1", "us-west-2", ], + "AWS::SES::MultiRegionEndpoint": [ + "ap-northeast-1", + "ap-northeast-2", + "ap-northeast-3", + "ap-south-1", + "ap-southeast-1", + "ap-southeast-2", + "ca-central-1", + "eu-central-1", + "eu-north-1", + "eu-west-1", + "eu-west-2", + "eu-west-3", + "sa-east-1", + "us-east-1", + "us-east-2", + "us-west-1", + "us-west-2", + ], "AWS::SES::ReceiptFilter": [ "ap-northeast-1", "ap-northeast-2", @@ -20148,6 +21575,25 @@ "us-west-1", "us-west-2", ], + "AWS::SES::Tenant": [ + "ap-northeast-1", + "ap-northeast-2", + "ap-northeast-3", + "ap-south-1", + "ap-southeast-1", + "ap-southeast-2", + "ca-central-1", + "eu-central-1", + "eu-north-1", + "eu-west-1", + "eu-west-2", + "eu-west-3", + "sa-east-1", + "us-east-1", + "us-east-2", + "us-west-1", + "us-west-2", + ], "AWS::SES::VdmAttributes": [ "ap-northeast-1", "ap-northeast-2", @@ -20748,6 +22194,24 @@ "us-west-1", "us-west-2", ], + "AWS::SSMQuickSetup::LifecycleAutomation": [ + "ap-northeast-1", + "ap-northeast-2", + "ap-south-1", + "ap-southeast-1", + "ap-southeast-2", + "ca-central-1", + "eu-central-1", + "eu-north-1", + "eu-west-1", + "eu-west-2", + "eu-west-3", + "sa-east-1", + "us-east-1", + "us-east-2", + "us-west-1", + "us-west-2", + ], "AWS::SSO::Application": [ "ap-northeast-1", "ap-northeast-2", @@ -20905,6 +22369,7 @@ "ap-south-1", "ap-southeast-1", "ap-southeast-2", + "ca-central-1", "eu-central-1", "eu-north-1", "eu-west-1", @@ -21668,6 +23133,25 @@ "us-west-1", "us-west-2", ], + "AWS::SecurityHub::ConnectorV2": [ + "ap-northeast-1", + "ap-northeast-2", + "ap-northeast-3", + "ap-south-1", + "ap-southeast-1", + "ap-southeast-2", + "ca-central-1", + "eu-central-1", + "eu-north-1", + "eu-west-1", + "eu-west-2", + "eu-west-3", + "sa-east-1", + "us-east-1", + "us-east-2", + "us-west-1", + "us-west-2", + ], "AWS::SecurityHub::DelegatedAdmin": [ "ap-northeast-1", "ap-northeast-2", @@ -22707,6 +24191,21 @@ "us-east-2", "us-west-2", ], + "AWS::Timestream::InfluxDBCluster": [ + "ap-northeast-1", + "ap-south-1", + "ap-southeast-1", + "ap-southeast-2", + "ca-central-1", + "eu-central-1", + "eu-north-1", + "eu-west-1", + "eu-west-2", + "eu-west-3", + "us-east-1", + "us-east-2", + "us-west-2", + ], "AWS::Timestream::InfluxDBInstance": [ "ap-northeast-1", "ap-south-1", @@ -23018,6 +24517,24 @@ "us-west-1", "us-west-2", ], + "AWS::VpcLattice::DomainVerification": [ + "ap-northeast-1", + "ap-northeast-2", + "ap-northeast-3", + "ap-south-1", + "ap-southeast-1", + "ap-southeast-2", + "eu-central-1", + "eu-north-1", + "eu-west-1", + "eu-west-2", + "eu-west-3", + "sa-east-1", + "us-east-1", + "us-east-2", + "us-west-1", + "us-west-2", + ], "AWS::VpcLattice::Listener": [ "ap-northeast-1", "ap-northeast-2", @@ -23855,6 +25372,7 @@ "eu-central-1", "eu-west-1", "eu-west-2", + "eu-west-3", "sa-east-1", "us-east-1", "us-west-2", diff --git a/localstack-core/localstack/services/cloudformation/scaffolding/CloudformationSchema.zip b/localstack-core/localstack/services/cloudformation/scaffolding/CloudformationSchema.zip deleted file mode 100644 index f9c8e2f6dbf4d..0000000000000 Binary files a/localstack-core/localstack/services/cloudformation/scaffolding/CloudformationSchema.zip and /dev/null differ diff --git a/localstack-core/localstack/services/cloudformation/scaffolding/__main__.py b/localstack-core/localstack/services/cloudformation/scaffolding/__main__.py index 2ea55f0493542..88888eaff9183 100644 --- a/localstack-core/localstack/services/cloudformation/scaffolding/__main__.py +++ b/localstack-core/localstack/services/cloudformation/scaffolding/__main__.py @@ -2,6 +2,8 @@ import json import os +import subprocess +import sys import zipfile from collections.abc import Generator from dataclasses import dataclass @@ -10,6 +12,7 @@ from pathlib import Path from typing import Any, Literal, TypedDict, TypeVar +import boto3 import click from jinja2 import Environment, FileSystemLoader from yaml import safe_dump @@ -140,14 +143,76 @@ def schema(self, resource_name: ResourceName) -> ResourceSchema: ) from e +class LiveSchemaProvider: + """ + Provides CloudFormation resource schemas by fetching them from the live AWS CloudFormation service, rather than + a local zip file. + """ + + def __init__(self, cfn_client): + self.cfn_client = cfn_client + + def available_schemas(self, pattern: str) -> list[str]: + """ + Return the names of available CloudFormation resource types. `pattern` should be something like + AWS::S3::Bucket or AWS::S3::*, depending on whether you want all resources for a service or a specific one. + The result is a list of matching resource type names (e.g. [AWS::S3::Bucket, AWS::S3::Object, ...]) + """ + + is_wildcard = pattern.endswith("*") + pattern = pattern[:-1] if is_wildcard else pattern + matching_names = [] + + params = { + "Visibility": "PUBLIC", + "Type": "RESOURCE", + "DeprecatedStatus": "LIVE", + "Filters": {"Category": "AWS_TYPES", "TypeNamePrefix": pattern}, + } + next_token: str | None = None + + # Note: pagination is necessary since list_types requires multiple calls even to get a single result. + while True: + if next_token: + params["NextToken"] = next_token + response = self.cfn_client.list_types(**params) + + # collect any matching type names (if wildcard, all; else exact match only) + matching_names.extend( + [ + type_summary["TypeName"] + for type_summary in response.get("TypeSummaries", []) + if (is_wildcard or type_summary["TypeName"] == pattern) + ] + ) + + next_token = response.get("NextToken") + if not next_token: + break + + return matching_names + + def schema(self, type_name: ResourceName) -> ResourceSchema: + """ + Given a CloudFormation ResourceName (representing something like "AWS::S3::Bucket"), return the resource + schema as dict. + """ + response = self.cfn_client.describe_type( + Type="RESOURCE", + TypeName=type_name.full_name, + ) + schema_str = response.get("Schema") + if not schema_str: + raise click.ClickException( + f"Could not fetch schema for CloudFormation resource type: {type_name}" + ) + return json.loads(schema_str) + + LOCALSTACK_ROOT_DIR = Path(__file__).parent.joinpath("../../../../..").resolve() LOCALSTACK_PRO_ROOT_DIR = LOCALSTACK_ROOT_DIR.joinpath("../localstack-pro").resolve() -TESTS_ROOT_DIR = LOCALSTACK_ROOT_DIR.joinpath( - "tests/aws/services/cloudformation/resource_providers" -) -TESTS_PRO_ROOT_DIR = LOCALSTACK_PRO_ROOT_DIR.joinpath( - "localstack-pro-core/tests/aws/services/cloudformation/resource_providers" -) +TESTS_ROOT_DIR = LOCALSTACK_ROOT_DIR.joinpath("tests/aws/services") +TESTS_PRO_ROOT_DIR = LOCALSTACK_PRO_ROOT_DIR.joinpath("localstack-pro-core/tests/aws/services") assert LOCALSTACK_ROOT_DIR.is_dir(), f"{LOCALSTACK_ROOT_DIR} does not exist" assert LOCALSTACK_PRO_ROOT_DIR.is_dir(), f"{LOCALSTACK_PRO_ROOT_DIR} does not exist" @@ -193,7 +258,7 @@ def template_path( output_path = ( tests_root_dir(pro) .joinpath( - f"{resource_name.python_compatible_service_name.lower()}/{resource_name.path_compatible_full_name()}/templates/{stub}" + f"{resource_name.python_compatible_service_name.lower()}/resource_providers/templates/{stub}" ) .resolve() ) @@ -202,7 +267,7 @@ def template_path( test_path = ( root_dir(pro) .joinpath( - f"tests/aws/cloudformation/resource_providers/{resource_name.python_compatible_service_name.lower()}/{resource_name.path_compatible_full_name()}" + f"tests/aws/{resource_name.python_compatible_service_name.lower()}/resource_providers/templates" ) .resolve() ) @@ -217,6 +282,7 @@ class FileType(Enum): # service code plugin = auto() provider = auto() + provider_base = auto() # test files integration_test = auto() @@ -262,6 +328,7 @@ def render( template_mapping = { FileType.plugin: "plugin_template.py.j2", FileType.provider: "provider_template.py.j2", + FileType.provider_base: "provider_base_template.py.j2", FileType.getatt_test: "test_getatt_template.py.j2", FileType.integration_test: "test_integration_template.py.j2", # FileType.cloudcontrol_test: "test_cloudcontrol_template.py.j2", @@ -276,7 +343,7 @@ def render( # e.g. .../resource_providers/aws_iam_role/test_X.py vs. .../resource_providers/iam/test_X.py # add extra parameters tests_output_path = root_dir(self.pro).joinpath( - f"tests/aws/cloudformation/resource_providers/{resource_name.python_compatible_service_name.lower()}/{resource_name.full_name.lower()}" + f"tests/aws/{resource_name.python_compatible_service_name.lower()}/resource_providers/templates" ) match file_type: case FileType.getatt_test: @@ -284,9 +351,11 @@ def render( kwargs["service"] = resource_name.service.lower() kwargs["resource"] = resource_name.resource.lower() kwargs["template_path"] = str( - template_path(resource_name, FileType.attribute_template, tests_output_path) + template_path( + resource_name, FileType.attribute_template, tests_output_path, pro=self.pro + ) ) - case FileType.provider: + case FileType.provider | FileType.provider_base: property_ir = generate_ir_for_type( [self.schema], resource_name.full_name, @@ -312,23 +381,34 @@ def render( kwargs["list_permissions"] = ( self.schema.get("handlers", {}).get("list", {}).get("permissions") ) + kwargs["service"] = resource_name.python_compatible_service_name.lower() + kwargs["lower_resource"] = resource_name.resource.lower() + kwargs["pro"] = self.pro case FileType.plugin: kwargs["service"] = resource_name.python_compatible_service_name.lower() kwargs["lower_resource"] = resource_name.resource.lower() kwargs["pro"] = self.pro case FileType.integration_test: kwargs["black_box_template_path"] = str( - template_path(resource_name, FileType.minimal_template, tests_output_path) + template_path( + resource_name, FileType.minimal_template, tests_output_path, pro=self.pro + ) ) kwargs["update_template_path"] = str( template_path( resource_name, FileType.update_without_replacement_template, tests_output_path, + pro=self.pro, ) ) kwargs["autogenerated_template_path"] = str( - template_path(resource_name, FileType.autogenerated_template, tests_output_path) + template_path( + resource_name, + FileType.autogenerated_template, + tests_output_path, + pro=self.pro, + ) ) # case FileType.cloudcontrol_test: case FileType.parity_test: @@ -340,7 +420,7 @@ def render( self.environment, template_mapping[file_type], **kwargs ) - def get_getatt_targets(self) -> Generator[str, None, None]: + def get_getatt_targets(self) -> Generator[str]: for name, defn in self.schema["properties"].items(): if "type" in defn and defn["type"] in ["string"]: yield name @@ -515,11 +595,20 @@ def __init__( "resource_providers", f"{self.resource_name.namespace.lower()}_{self.resource_name.service.lower()}_{self.resource_name.resource.lower()}.py", ), + FileType.provider_base: root_dir(self.pro).joinpath( + *base_path, + "services", + self.resource_name.python_compatible_service_name.lower(), + "resource_providers", + "generated", + f"{self.resource_name.namespace.lower()}_{self.resource_name.service.lower()}_{self.resource_name.resource.lower()}_base.py", + ), FileType.plugin: root_dir(self.pro).joinpath( *base_path, "services", self.resource_name.python_compatible_service_name.lower(), "resource_providers", + "generated", f"{self.resource_name.namespace.lower()}_{self.resource_name.service.lower()}_{self.resource_name.resource.lower()}_plugin.py", ), FileType.schema: root_dir(self.pro).joinpath( @@ -527,24 +616,29 @@ def __init__( "services", self.resource_name.python_compatible_service_name.lower(), "resource_providers", + "generated", f"aws_{self.resource_name.service.lower()}_{self.resource_name.resource.lower()}.schema.json", ), FileType.integration_test: tests_root_dir(self.pro).joinpath( self.resource_name.python_compatible_service_name.lower(), + "resource_providers", self.resource_name.path_compatible_full_name(), "test_basic.py", ), FileType.getatt_test: tests_root_dir(self.pro).joinpath( self.resource_name.python_compatible_service_name.lower(), + "resource_providers", self.resource_name.path_compatible_full_name(), "test_exploration.py", ), # FileType.cloudcontrol_test: tests_root_dir(self.pro).joinpath( # self.resource_name.python_compatible_service_name.lower(), + # "resource_providers", # f"test_aws_{self.resource_name.service.lower()}_{self.resource_name.resource.lower()}_cloudcontrol.py", # ), FileType.parity_test: tests_root_dir(self.pro).joinpath( self.resource_name.python_compatible_service_name.lower(), + "resource_providers", self.resource_name.path_compatible_full_name(), "test_parity.py", ), @@ -558,7 +652,9 @@ def __init__( FileType.autogenerated_template, ] for template_type in templates: - self.destination_files[template_type] = template_path(self.resource_name, template_type) + self.destination_files[template_type] = template_path( + self.resource_name, template_type, pro=self.pro + ) def write(self, file_type: FileType, contents: str): file_destination = self.destination_files[file_type] @@ -577,6 +673,10 @@ def write(self, file_type: FileType, contents: str): self.ensure_python_init_files(destination_path) self.write_text(contents, file_destination) self.console.print(f"Written provider to {file_destination}") + case FileType.provider_base: + self.ensure_python_init_files(destination_path) + self.write_text(contents, file_destination) + self.console.print(f"Written provider base to {file_destination}") case FileType.plugin: self.ensure_python_init_files(destination_path) self.write_text(contents, file_destination) @@ -628,13 +728,25 @@ def confirm_overwrite(self, destination_file: Path) -> bool: :return True if file should be (over-)written, False otherwise """ - return self.overwrite or click.confirm("Destination files already exist, overwrite?") + return self.overwrite or click.confirm( + f"Destination file {destination_file} already exists, overwrite?" + ) @staticmethod def write_text(contents: str, destination: Path): with destination.open("wt") as outfile: print(contents, file=outfile) + # for Python files, use ruff to clean up formatting errors introduced by scaffolding + if destination.suffix == ".py": + command = [sys.executable, "-m", "ruff", "format", destination] + try: + subprocess.run(command, check=True, capture_output=True, text=True) + except subprocess.CalledProcessError as e: + print( + f"Ruff fix command failed (exit code {e.returncode}):\n{e.stdout}\n{e.stderr}" + ) + @staticmethod def ensure_python_init_files(path: Path): """ @@ -698,6 +810,9 @@ def print(self): case FileType.provider: self.printer.print("\n[underline]Provider template[/underline]\n") self.printer.print(Syntax(self.contents, "python")) + case FileType.provider_base: + self.printer.print("\n[underline]Provider base template[/underline]\n") + self.printer.print(Syntax(self.contents, "python")) case FileType.plugin: self.printer.print("\n[underline]Plugin[/underline]\n") self.printer.print(Syntax(self.contents, "python")) @@ -763,21 +878,14 @@ def generate( console = Console() console.rule(title=resource_type) - schema_provider = SchemaProvider( - zipfile_path=Path(__file__).parent.joinpath("CloudformationSchema.zip") - ) + schema_provider = LiveSchemaProvider(boto3.client("cloudformation")) template_root = Path(__file__).parent.joinpath("templates") env = Environment( loader=FileSystemLoader(template_root), ) - parts = resource_type.rpartition("::") - if parts[-1] == "*": - # generate all resource types for that service - matching_resources = [x for x in schema_provider.schemas.keys() if x.startswith(parts[0])] - else: - matching_resources = [resource_type] + matching_resources = schema_provider.available_schemas(resource_type) for matching_resource in matching_resources: console.rule(title=matching_resource) @@ -814,7 +922,7 @@ def generate( ) console.print("\nWondering where to get started?") console.print( - "First run `make entrypoints` to make sure your resource provider plugin is actually registered." + "First run `make entrypoints` to update the plux.ini file with your new resource provider plugin." ) console.print( 'Then start off by finalizing the generated minimal ("basic") template and get it to deploy against AWS.' diff --git a/localstack-core/localstack/services/cloudformation/scaffolding/templates/plugin_template.py.j2 b/localstack-core/localstack/services/cloudformation/scaffolding/templates/plugin_template.py.j2 index 0a9a530cdfccc..6f5b7da7a5a16 100644 --- a/localstack-core/localstack/services/cloudformation/scaffolding/templates/plugin_template.py.j2 +++ b/localstack-core/localstack/services/cloudformation/scaffolding/templates/plugin_template.py.j2 @@ -1,3 +1,6 @@ +# +# AUTOGENERATED FILE - DO NOT EDIT +# from typing import Optional, Type from localstack.services.cloudformation.resource_provider import ResourceProvider diff --git a/localstack-core/localstack/services/cloudformation/scaffolding/templates/provider_base_template.py.j2 b/localstack-core/localstack/services/cloudformation/scaffolding/templates/provider_base_template.py.j2 new file mode 100644 index 0000000000000..f25cf665d6a35 --- /dev/null +++ b/localstack-core/localstack/services/cloudformation/scaffolding/templates/provider_base_template.py.j2 @@ -0,0 +1,139 @@ +# LocalStack Resource Provider Base Class Scaffolding {{ scaffolding_version }} +# +# AUTOGENERATED FILE - DO NOT EDIT +# + +from __future__ import annotations + +from abc import ABC, abstractmethod +from pathlib import Path +from typing import Optional, TypedDict + +import localstack.services.cloudformation.provider_utils as util +from localstack.services.cloudformation.resource_provider import ( + ProgressEvent, + ResourceProvider, + ResourceRequest, +) + +{{ provider_properties }} + +REPEATED_INVOCATION = "repeated_invocation" + +class {{ resource }}ProviderBase(ResourceProvider[{{ resource }}Properties], ABC): + + TYPE = "{{ name }}" # Autogenerated. Don't change + SCHEMA = util.get_schema_path(Path(__file__)) # Autogenerated. Don't change + + @abstractmethod + def create( + self, + request: ResourceRequest[{{ resource }}Properties], + ) -> ProgressEvent[{{ resource }}Properties]: + """ + Create a new resource. + + {% if primary_identifier -%} + Primary identifier fields: + {%- for property in primary_identifier %} + - {{ property }} + {%- endfor %} + {%- endif %} + + {% if required_properties -%} + Required properties: + {%- for property in required_properties %} + - {{ property }} + {%- endfor %} + {%- endif %} + + {% if create_only_properties -%} + Create-only properties: + {%- for property in create_only_properties %} + - {{ property }} + {%- endfor %} + {%- endif %} + + {% if read_only_properties -%} + Read-only properties: + {%- for property in read_only_properties %} + - {{ property }} + {%- endfor %} + {%- endif %} + + {% if create_permissions -%} + IAM permissions required: + {%- for permission in create_permissions %} + - {{ permission }} + {%- endfor -%} + {%- endif %} + + """ + raise NotImplementedError + + @abstractmethod + def read( + self, + request: ResourceRequest[{{ resource }}Properties], + ) -> ProgressEvent[{{ resource }}Properties]: + """ + Fetch resource information + + {% if read_permissions -%} + IAM permissions required: + {%- for permission in read_permissions %} + - {{ permission }} + {%- endfor %} + {%- endif %} + """ + raise NotImplementedError + + @abstractmethod + def delete( + self, + request: ResourceRequest[{{ resource }}Properties], + ) -> ProgressEvent[{{ resource }}Properties]: + """ + Delete a resource + + {% if delete_permissions -%} + IAM permissions required: + {%- for permission in delete_permissions %} + - {{ permission }} + {%- endfor %} + {%- endif %} + """ + raise NotImplementedError + + @abstractmethod + def update( + self, + request: ResourceRequest[{{ resource }}Properties], + ) -> ProgressEvent[{{ resource }}Properties]: + """ + Update a resource + + {% if update_permissions -%} + IAM permissions required: + {%- for permission in update_permissions %} + - {{ permission }} + {%- endfor %} + {%- endif %} + """ + raise NotImplementedError + + @abstractmethod + def list( + self, + request: ResourceRequest[{{ resource }}Properties], + ) -> ProgressEvent[{{ resource }}Properties]: + """ + List available resources of this type + {% if list_permissions -%} + IAM permissions required: + {%- for permission in list_permissions %} + - {{ permission }} + {%- endfor %} + {%- endif %} + """ + raise NotImplementedError diff --git a/localstack-core/localstack/services/cloudformation/scaffolding/templates/provider_template.py.j2 b/localstack-core/localstack/services/cloudformation/scaffolding/templates/provider_template.py.j2 index 3d52dbd6b7a83..81d81cec10eab 100644 --- a/localstack-core/localstack/services/cloudformation/scaffolding/templates/provider_template.py.j2 +++ b/localstack-core/localstack/services/cloudformation/scaffolding/templates/provider_template.py.j2 @@ -1,26 +1,22 @@ # LocalStack Resource Provider Scaffolding {{ scaffolding_version }} -from __future__ import annotations -from pathlib import Path -from typing import Optional, TypedDict - -import localstack.services.cloudformation.provider_utils as util from localstack.services.cloudformation.resource_provider import ( OperationStatus, ProgressEvent, - ResourceProvider, ResourceRequest, ) +{%- if pro %} +{%- set root_module = "localstack.pro.core" %} +{%- else %} +{%- set root_module = "localstack" %} +{%- endif %} +from {{ root_module }}.services.{{ service }}.resource_providers.generated.aws_{{ service }}_{{ lower_resource }}_base import ( + {{ resource }}ProviderBase, + {{ resource }}Properties, + REPEATED_INVOCATION +) -{{ provider_properties }} - - -REPEATED_INVOCATION = "repeated_invocation" - -class {{ resource }}Provider(ResourceProvider[{{ resource }}Properties]): - - TYPE = "{{ name }}" # Autogenerated. Don't change - SCHEMA = util.get_schema_path(Path(__file__)) # Autogenerated. Don't change +class {{ resource }}Provider({{ resource }}ProviderBase): def create( self, @@ -63,7 +59,6 @@ class {{ resource }}Provider(ResourceProvider[{{ resource }}Properties]): - {{ permission }} {%- endfor -%} {%- endif %} - """ model = request.desired_state @@ -136,3 +131,18 @@ class {{ resource }}Provider(ResourceProvider[{{ resource }}Properties]): {%- endif %} """ raise NotImplementedError + + def list( + self, + request: ResourceRequest[{{ resource }}Properties], + ) -> ProgressEvent[{{ resource }}Properties]: + """ + List available resources of this type + {% if list_permissions -%} + IAM permissions required: + {%- for permission in list_permissions %} + - {{ permission }} + {%- endfor %} + {%- endif %} + """ + raise NotImplementedError diff --git a/localstack-core/localstack/services/cloudformation/v2/provider.py b/localstack-core/localstack/services/cloudformation/v2/provider.py index d5e437b5d13ad..e3d4629cb55c6 100644 --- a/localstack-core/localstack/services/cloudformation/v2/provider.py +++ b/localstack-core/localstack/services/cloudformation/v2/provider.py @@ -103,6 +103,9 @@ from localstack.services.cloudformation.engine.v2.change_set_model_validator import ( ChangeSetModelValidator, ) +from localstack.services.cloudformation.engine.v2.change_set_resource_support_checker import ( + ChangeSetResourceSupportChecker, +) from localstack.services.cloudformation.engine.validations import ValidationError from localstack.services.cloudformation.provider import ( ARN_CHANGESET_REGEX, @@ -120,9 +123,10 @@ StackInstance, StackSet, ) -from localstack.services.cloudformation.v2.types import EngineParameter +from localstack.services.cloudformation.v2.types import EngineParameter, engine_parameter_value from localstack.services.plugins import ServiceLifecycleHook from localstack.utils.collections import select_attributes +from localstack.utils.numbers import is_number from localstack.utils.strings import short_uid from localstack.utils.threads import start_worker_thread @@ -134,15 +138,15 @@ def is_stack_arn(stack_name_or_id: str) -> bool: - return ARN_STACK_REGEX.match(stack_name_or_id) is not None + return stack_name_or_id and ARN_STACK_REGEX.match(stack_name_or_id) is not None def is_changeset_arn(change_set_name_or_id: str) -> bool: - return ARN_CHANGESET_REGEX.match(change_set_name_or_id) is not None + return change_set_name_or_id and ARN_CHANGESET_REGEX.match(change_set_name_or_id) is not None def is_stack_set_arn(stack_set_name_or_id: str) -> bool: - return ARN_STACK_SET_REGEX.match(stack_set_name_or_id) is not None + return stack_set_name_or_id and ARN_STACK_SET_REGEX.match(stack_set_name_or_id) is not None class StackNotFoundError(ValidationError): @@ -221,6 +225,12 @@ def find_stack_instance(stack_set: StackSet, account: str, region: str) -> Stack class CloudformationProviderV2(CloudformationProvider, ServiceLifecycleHook): def on_before_start(self): + # TODO: make sure to bring `_validate_config` from the base class when removing it + # as this ensures we have a valid CFN_NO_WAIT_ITERATIONS value + super().on_before_start() + self._log_create_issue_info() + + def _log_create_issue_info(self): base = "https://github.com/localstack/localstack/issues/new" query_args = { "template": "bug-report.yml", @@ -262,6 +272,12 @@ def _resolve_parameters( no_echo=parameter.get("NoEcho"), ) + # validate the type + if parameter["Type"] == "Number" and not is_number( + engine_parameter_value(resolved_parameter) + ): + raise ValidationError(f"Parameter '{name}' must be a number.") + # TODO: support other parameter types if match := SSM_PARAMETER_TYPE_RE.match(parameter["Type"]): inner_type = match.group("innertype") @@ -410,6 +426,40 @@ def _setup_change_set_model( update_model.node_template.change_type = ChangeType.MODIFIED change_set.processed_template = transformed_after_template + if not config.CFN_IGNORE_UNSUPPORTED_RESOURCE_TYPES: + support_visitor = ChangeSetResourceSupportChecker( + change_set_type=change_set.change_set_type + ) + support_visitor.visit(change_set.update_model.node_template) + failure_messages = support_visitor.failure_messages + if failure_messages: + reason_suffix = ", ".join(failure_messages) + status_reason = f"{ChangeSetResourceSupportChecker.TITLE_MESSAGE} {reason_suffix}" + + change_set.status_reason = status_reason + change_set.set_change_set_status(ChangeSetStatus.FAILED) + failure_transitions = { + ChangeSetType.CREATE: ( + StackStatus.ROLLBACK_IN_PROGRESS, + StackStatus.CREATE_FAILED, + ), + ChangeSetType.UPDATE: ( + StackStatus.UPDATE_ROLLBACK_IN_PROGRESS, + StackStatus.UPDATE_ROLLBACK_FAILED, + ), + ChangeSetType.IMPORT: ( + StackStatus.IMPORT_ROLLBACK_IN_PROGRESS, + StackStatus.IMPORT_ROLLBACK_FAILED, + ), + } + transitions = failure_transitions.get(change_set.change_set_type) + if transitions: + first_status, *remaining_statuses = transitions + change_set.stack.set_stack_status(first_status, status_reason) + for status in remaining_statuses: + change_set.stack.set_stack_status(status) + return + @handler("CreateChangeSet", expand=False) def create_change_set( self, context: RequestContext, request: CreateChangeSetInput @@ -490,6 +540,14 @@ def create_change_set( f"Stack [{stack_name}] already exists and cannot be created again with the changeSet [{change_set_name}]." ) + if change_set_type == ChangeSetType.UPDATE and ( + stack.status == StackStatus.DELETE_COMPLETE + or stack.status == StackStatus.DELETE_IN_PROGRESS + ): + raise ValidationError( + f"Stack:{stack.stack_id} is in {stack.status} state and can not be updated." + ) + before_parameters: dict[str, Parameter] | None = None match change_set_type: case ChangeSetType.UPDATE: @@ -617,6 +675,11 @@ def _run(*args): result = change_set_executor.execute() change_set.stack.resolved_parameters = change_set.resolved_parameters change_set.stack.resolved_resources = result.resources + change_set.stack.template = change_set.template + change_set.stack.processed_template = change_set.processed_template + change_set.stack.template_body = change_set.template_body + change_set.stack.description = change_set.template.get("Description") + if not result.failure_message: new_stack_status = StackStatus.UPDATE_COMPLETE if change_set.change_set_type == ChangeSetType.CREATE: @@ -631,13 +694,6 @@ def _run(*args): change_set.stack.resolved_exports[export_name] = output["OutputValue"] change_set.stack.change_set_id = change_set.change_set_id - - # if the deployment succeeded, update the stack's template representation to that - # which was just deployed - change_set.stack.template = change_set.template - change_set.stack.description = change_set.template.get("Description") - change_set.stack.processed_template = change_set.processed_template - change_set.stack.template_body = change_set.template_body else: LOG.error( "Execute change set failed: %s", @@ -1096,6 +1152,12 @@ def describe_stack_resource( try: resource = stack.resolved_resources[logical_resource_id] + if resource.get("ResourceStatus") not in [ + StackStatus.CREATE_COMPLETE, + StackStatus.UPDATE_COMPLETE, + StackStatus.ROLLBACK_COMPLETE, + ]: + raise KeyError except KeyError: raise ValidationError( f"Resource {logical_resource_id} does not exist for stack {stack_name}" @@ -1330,8 +1392,8 @@ def delete_stack_set( def describe_stack_events( self, context: RequestContext, - stack_name: StackName = None, - next_token: NextToken = None, + stack_name: StackName, + next_token: NextToken | None = None, **kwargs, ) -> DescribeStackEventsOutput: if not stack_name: @@ -1369,7 +1431,7 @@ def get_template( stack_name, message_override=f"Stack with id {stack_name} does not exist" ) else: - raise StackNotFoundError(stack_name) + raise ValidationError("StackName is required if ChangeSetName is not specified.") if template_stage == TemplateStage.Processed and "Transform" in stack.template_body: template_body = json.dumps(stack.processed_template) @@ -1421,6 +1483,11 @@ def get_template_summary( template = template_preparer.parse_template(template_body) id_summaries = defaultdict(list) + if "Resources" not in template: + raise ValidationError( + "Template format error: At least one Resources member must be defined." + ) + for resource_id, resource in template["Resources"].items(): res_type = resource["Type"] id_summaries[res_type].append(resource_id) @@ -1524,6 +1591,14 @@ def update_stack( raise RuntimeError("Multiple stacks matched, update matching logic") stack = active_stack_candidates[0] + if ( + stack.status == StackStatus.DELETE_COMPLETE + or stack.status == StackStatus.DELETE_IN_PROGRESS + ): + raise ValidationError( + f"Stack:{stack.stack_id} is in {stack.status} state and can not be updated." + ) + # TODO: proper status modeling before_parameters = stack.resolved_parameters # TODO: reconsider the way parameters are modelled in the update graph process. @@ -1671,6 +1746,7 @@ def _run(*args): stack.set_stack_status(StackStatus.DELETE_FAILED) start_worker_thread(_run) + return ExecuteChangeSetOutput() @handler("ListExports") def list_exports( diff --git a/localstack-core/localstack/services/cloudwatch/alarm_scheduler.py b/localstack-core/localstack/services/cloudwatch/alarm_scheduler.py index 9ae3b3c7ee79d..07018e4124f20 100644 --- a/localstack-core/localstack/services/cloudwatch/alarm_scheduler.py +++ b/localstack-core/localstack/services/cloudwatch/alarm_scheduler.py @@ -7,8 +7,9 @@ from localstack.aws.api.cloudwatch import MetricAlarm, MetricDataQuery, MetricStat, StateValue from localstack.aws.connect import connect_to +from localstack.runtime.shutdown import SHUTDOWN_HANDLERS from localstack.utils.aws import arns, aws_stack -from localstack.utils.scheduler import Scheduler +from localstack.utils.scheduler import ScheduledTask, Scheduler if TYPE_CHECKING: from mypy_boto3_cloudwatch import CloudWatchClient @@ -38,16 +39,26 @@ def __init__(self) -> None: """ super().__init__() self.scheduler = Scheduler() - self.thread = threading.Thread(target=self.scheduler.run, name="cloudwatch-scheduler") - self.thread.start() - self.scheduled_alarms = {} + self.scheduled_alarms: dict[str, ScheduledTask] = {} + self.thread: threading.Thread | None = None - def shutdown_scheduler(self) -> None: + def start(self) -> None: + if not (self.thread and self.thread.is_alive()): + LOG.debug("Starting CloudWatch scheduler") + self.thread = threading.Thread(target=self.scheduler.run, name="cloudwatch-scheduler") + self.thread.start() + SHUTDOWN_HANDLERS.register(self.shutdown) + + def shutdown(self) -> None: """ - Shutsdown the scheduler, must be called before application stops + Shutdown the scheduler, must be called before application stops """ + LOG.debug("Stopping CloudWatch scheduler") self.scheduler.close() - self.thread.join(10) + self.scheduled_alarms.clear() + SHUTDOWN_HANDLERS.unregister(self.shutdown) + if self.thread: + self.thread.join(10) def schedule_metric_alarm(self, alarm_arn: str) -> None: """(Re-)schedules the alarm, if the alarm is re-scheduled, the running alarm scheduler will be cancelled before @@ -233,15 +244,16 @@ def collect_metric_data(alarm_details: MetricAlarm, client: "CloudWatchClient") evaluation_periods = alarm_details["EvaluationPeriods"] period = alarm_details["Period"] - # From the docs: "Whenever an alarm evaluates whether to change state, CloudWatch attempts to retrieve a higher number of data - # points than the number specified as Evaluation Periods." + # From the docs: "Whenever an alarm evaluates whether to change state, CloudWatch attempts to retrieve a + # higher number of data points than the number specified as Evaluation Periods." # No other indication, try to calculate a reasonable value: magic_number = max(math.floor(evaluation_periods / 3), 2) collected_periods = evaluation_periods + magic_number - now = datetime.utcnow().replace(tzinfo=UTC) + now = datetime.now(tz=UTC) metric_query = generate_metric_query(alarm_details) + # Fetching the evaluation range: # get_metric_data needs to be run in a loop, so we also collect empty data points on the right position for i in range(0, collected_periods): start_time = now - timedelta(seconds=period) @@ -393,6 +405,7 @@ def calculate_alarm_state(alarm_arn: str) -> None: alarm_name, alarm_state, StateValue.OK, + # TODO: cannot find a snapshot with StateValue.OK and the Threshold crossed value, verify this case THRESHOLD_CROSSED, state_reason_data=state_reason_data, ) diff --git a/localstack-core/localstack/services/cloudwatch/models.py b/localstack-core/localstack/services/cloudwatch/models.py index 72e4e0ffc5313..247ea45903641 100644 --- a/localstack-core/localstack/services/cloudwatch/models.py +++ b/localstack-core/localstack/services/cloudwatch/models.py @@ -1,14 +1,19 @@ import datetime -from localstack.aws.api.cloudwatch import CompositeAlarm, DashboardBody, MetricAlarm, StateValue +from localstack.aws.api.cloudwatch import ( + AlarmHistoryItem, + CompositeAlarm, + DashboardBody, + MetricAlarm, + StateValue, +) from localstack.services.stores import ( AccountRegionBundle, BaseStore, - CrossRegionAttribute, LocalAttribute, ) from localstack.utils.aws import arns -from localstack.utils.tagging import TaggingService +from localstack.utils.tagging import Tags class LocalStackMetricAlarm: @@ -20,6 +25,8 @@ def __init__(self, account_id: str, region: str, alarm: MetricAlarm): self.account_id = account_id self.region = region self.alarm = alarm + # Tags are already stored as part of Tagging Service or RGTA plugin + self.alarm.pop("Tags", None) self.set_default_attributes() def set_default_attributes(self): @@ -48,6 +55,8 @@ def __init__(self, account_id: str, region: str, alarm: CompositeAlarm): self.account_id = account_id self.region = region self.alarm = alarm + # Tags are already stored as part of Tagging Service or RGTA plugin + self.alarm.pop("Tags", None) self.set_default_attributes() def set_default_attributes(self): @@ -72,6 +81,8 @@ class LocalStackDashboard: dashboard_name: str dashboard_arn: str dashboard_body: DashboardBody + last_modified: datetime.datetime + size: int def __init__( self, account_id: str, region: str, dashboard_name: str, dashboard_body: DashboardBody @@ -91,17 +102,16 @@ def __init__( class CloudWatchStore(BaseStore): - # maps resource ARN to tags - TAGS: TaggingService = CrossRegionAttribute(default=TaggingService) - # maps resource ARN to alarms alarms: dict[str, LocalStackAlarm] = LocalAttribute(default=dict) # Contains all the Alarm Histories. Per documentation, an alarm history is retained even if the alarm is deleted, # making it necessary to save this at store level - histories: list[dict] = LocalAttribute(default=list) + histories: list[AlarmHistoryItem] = LocalAttribute(default=list) dashboards: dict[str, LocalStackDashboard] = LocalAttribute(default=dict) + # Maps resource ARN to tags + tags: Tags = LocalAttribute(default=Tags) cloudwatch_stores = AccountRegionBundle("cloudwatch", CloudWatchStore) diff --git a/localstack-core/localstack/services/cloudwatch/provider.py b/localstack-core/localstack/services/cloudwatch/provider.py index 0f5d705a7b780..1c706369bfc40 100644 --- a/localstack-core/localstack/services/cloudwatch/provider.py +++ b/localstack-core/localstack/services/cloudwatch/provider.py @@ -35,6 +35,7 @@ from localstack.services.cloudwatch.alarm_scheduler import AlarmScheduler from localstack.services.edge import ROUTER from localstack.services.plugins import SERVICE_PLUGINS, ServiceLifecycleHook +from localstack.state import StateVisitor from localstack.utils.aws import arns from localstack.utils.aws.arns import extract_account_id_from_arn, lambda_function_name from localstack.utils.aws.request_context import ( @@ -304,23 +305,28 @@ class CloudwatchProvider(CloudwatchApi, ServiceLifecycleHook): def __init__(self): self.tags = TaggingService() - self.alarm_scheduler = None + self.alarm_scheduler = AlarmScheduler() + + def accept_state_visitor(self, visitor: StateVisitor): + visitor.visit(cloudwatch_backends) def on_after_init(self): ROUTER.add(PATH_GET_RAW_METRICS, self.get_raw_metrics) - self.start_alarm_scheduler() + + def on_before_start(self): + self.alarm_scheduler.start() def on_before_state_reset(self): - self.shutdown_alarm_scheduler() + self.alarm_scheduler.shutdown() def on_after_state_reset(self): - self.start_alarm_scheduler() + self.alarm_scheduler.start() def on_before_state_load(self): - self.shutdown_alarm_scheduler() + self.alarm_scheduler.shutdown() def on_after_state_load(self): - self.start_alarm_scheduler() + self.alarm_scheduler.start() def restart_alarms(*args): poll_condition(lambda: SERVICE_PLUGINS.is_running("cloudwatch")) @@ -329,17 +335,7 @@ def restart_alarms(*args): start_worker_thread(restart_alarms) def on_before_stop(self): - self.shutdown_alarm_scheduler() - - def start_alarm_scheduler(self): - if not self.alarm_scheduler: - LOG.debug("starting cloudwatch scheduler") - self.alarm_scheduler = AlarmScheduler() - - def shutdown_alarm_scheduler(self): - LOG.debug("stopping cloudwatch scheduler") - self.alarm_scheduler.shutdown_scheduler() - self.alarm_scheduler = None + self.alarm_scheduler.shutdown() def delete_alarms(self, context: RequestContext, alarm_names: AlarmNames, **kwargs) -> None: moto.call_moto(context) diff --git a/localstack-core/localstack/services/cloudwatch/provider_v2.py b/localstack-core/localstack/services/cloudwatch/provider_v2.py index 2a41252cefb37..8428e6eaf8b90 100644 --- a/localstack-core/localstack/services/cloudwatch/provider_v2.py +++ b/localstack-core/localstack/services/cloudwatch/provider_v2.py @@ -9,6 +9,7 @@ from localstack.aws.api.cloudwatch import ( AccountId, ActionPrefix, + AlarmHistoryItem, AlarmName, AlarmNamePrefix, AlarmNames, @@ -66,6 +67,7 @@ Statistic, Statistics, StrictEntityValidation, + Tag, TagKeyList, TagList, TagResourceOutput, @@ -147,9 +149,9 @@ class CloudwatchProvider(CloudwatchApi, ServiceLifecycleHook): """ def __init__(self): - self.alarm_scheduler: AlarmScheduler = None self.store = None self.cloudwatch_database = CloudwatchDatabase() + self.alarm_scheduler = AlarmScheduler() @staticmethod def get_store(account_id: str, region: str) -> CloudWatchStore: @@ -161,21 +163,23 @@ def accept_state_visitor(self, visitor: StateVisitor): def on_after_init(self): ROUTER.add(PATH_GET_RAW_METRICS, self.get_raw_metrics) - self.start_alarm_scheduler() + + def on_before_start(self): + self.alarm_scheduler.start() def on_before_state_reset(self): - self.shutdown_alarm_scheduler() + self.alarm_scheduler.shutdown() self.cloudwatch_database.clear_tables() def on_after_state_reset(self): self.cloudwatch_database = CloudwatchDatabase() - self.start_alarm_scheduler() + self.alarm_scheduler.start() def on_before_state_load(self): - self.shutdown_alarm_scheduler() + self.alarm_scheduler.shutdown() def on_after_state_load(self): - self.start_alarm_scheduler() + self.alarm_scheduler.start() def restart_alarms(*args): poll_condition(lambda: SERVICE_PLUGINS.is_running("cloudwatch")) @@ -184,17 +188,7 @@ def restart_alarms(*args): start_worker_thread(restart_alarms) def on_before_stop(self): - self.shutdown_alarm_scheduler() - - def start_alarm_scheduler(self): - if not self.alarm_scheduler: - LOG.debug("starting cloudwatch scheduler") - self.alarm_scheduler = AlarmScheduler() - - def shutdown_alarm_scheduler(self): - LOG.debug("stopping cloudwatch scheduler") - self.alarm_scheduler.shutdown_scheduler() - self.alarm_scheduler = None + self.alarm_scheduler.shutdown() def delete_alarms(self, context: RequestContext, alarm_names: AlarmNames, **kwargs) -> None: """ @@ -208,6 +202,7 @@ def delete_alarms(self, context: RequestContext, alarm_names: AlarmNames, **kwar self.alarm_scheduler.delete_scheduler_for_alarm(alarm_arn) store = self.get_store(context.account_id, context.region) store.alarms.pop(alarm_arn, None) + self._remove_all_resource_tags(alarm_arn, context.account_id, context.region) def put_metric_data( self, @@ -273,7 +268,7 @@ def get_metric_data( # Paginate timestamp_value_dicts = [ { - "Timestamp": timestamp, + "Timestamp": datetime.datetime.fromtimestamp(timestamp, tz=datetime.UTC), "Value": float(value), } for timestamp, value in zip(timestamps, values, strict=False) @@ -402,6 +397,32 @@ def get_raw_metrics(self, request: Request): """ return {"metrics": self.cloudwatch_database.get_all_metric_data() or []} + def _get_resource_tags( + self, resource_arn: AmazonResourceName, account_id: str, region: str + ) -> TagList: + store = self.get_store(account_id, region) + return [ + Tag(Key=key, Value=value) for key, value in store.tags.get_tags(resource_arn).items() + ] + + def _set_resource_tags( + self, resource_arn: AmazonResourceName, account_id: str, region: str, tags: TagList + ) -> None: + store = self.get_store(account_id, region) + store.tags.update_tags(resource_arn, {tag["Key"]: tag["Value"] for tag in tags}) + + def _remove_resource_tags( + self, resource_arn: AmazonResourceName, account_id: str, region: str, tag_keys: TagKeyList + ) -> None: + store = self.get_store(account_id, region) + store.tags.delete_tags(resource_arn, tag_keys) + + def _remove_all_resource_tags( + self, resource_arn: AmazonResourceName, account_id: str, region: str + ): + store = self.get_store(account_id, region) + store.tags.delete_all_tags(resource_arn) + @handler("PutMetricAlarm", expand=False) def put_metric_alarm(self, context: RequestContext, request: PutMetricAlarmInput) -> None: # missing will be the default, when not set (but it will not explicitly be set) @@ -453,6 +474,9 @@ def put_metric_alarm(self, context: RequestContext, request: PutMetricAlarmInput alarm_arn = metric_alarm.alarm["AlarmArn"] store.alarms[alarm_arn] = metric_alarm self.alarm_scheduler.schedule_metric_alarm(alarm_arn) + self._set_resource_tags( + alarm_arn, context.account_id, context.region, request.get("Tags", []) + ) @handler("PutCompositeAlarm", expand=False) def put_composite_alarm(self, context: RequestContext, request: PutCompositeAlarmInput) -> None: @@ -468,6 +492,9 @@ def put_composite_alarm(self, context: RequestContext, request: PutCompositeAlar alarm_arn = composite_alarm.alarm["AlarmArn"] store.alarms[alarm_arn] = composite_alarm + self._set_resource_tags( + alarm_arn, context.account_id, context.region, request.get("Tags", []) + ) def describe_alarms( self, @@ -535,9 +562,8 @@ def describe_alarms_for_metric( def list_tags_for_resource( self, context: RequestContext, resource_arn: AmazonResourceName, **kwargs ) -> ListTagsForResourceOutput: - store = self.get_store(context.account_id, context.region) - tags = store.TAGS.list_tags_for_resource(resource_arn) - return ListTagsForResourceOutput(Tags=tags.get("Tags", [])) + tags = self._get_resource_tags(resource_arn, context.account_id, context.region) + return ListTagsForResourceOutput(Tags=tags) def untag_resource( self, @@ -546,15 +572,13 @@ def untag_resource( tag_keys: TagKeyList, **kwargs, ) -> UntagResourceOutput: - store = self.get_store(context.account_id, context.region) - store.TAGS.untag_resource(resource_arn, tag_keys) + self._remove_resource_tags(resource_arn, context.account_id, context.region, tag_keys) return UntagResourceOutput() def tag_resource( self, context: RequestContext, resource_arn: AmazonResourceName, tags: TagList, **kwargs ) -> TagResourceOutput: - store = self.get_store(context.account_id, context.region) - store.TAGS.tag_resource(resource_arn, tags) + self._set_resource_tags(resource_arn, context.account_id, context.region, tags) return TagResourceOutput() def put_dashboard( @@ -655,7 +679,9 @@ def list_metrics( ] aliases_list = PaginatedList(metrics) page, nxt = aliases_list.get_page( - lambda metric: f"{metric.get('Namespace')}-{metric.get('MetricName')}-{metric.get('Dimensions')}", + lambda metric: ( + f"{metric.get('Namespace')}-{metric.get('MetricName')}-{metric.get('Dimensions')}" + ), next_token=next_token, page_size=LIST_METRICS_MAX_RESULTS, ) @@ -757,7 +783,7 @@ def _update_state( self, context: RequestContext, alarm: LocalStackAlarm, - state_value: str, + state_value: StateValue, state_reason: str, state_reason_data: dict = None, ): @@ -777,18 +803,17 @@ def _update_state( "stateReasonData": state_reason_data, }, } - store.histories.append( - { - "Timestamp": timestamp_millis(alarm.alarm["StateUpdatedTimestamp"]), - "HistoryItemType": HistoryItemType.StateUpdate, - "AlarmName": alarm.alarm["AlarmName"], - "HistoryData": json.dumps(history_data), - "HistorySummary": f"Alarm updated from {old_state} to {state_value}", - "AlarmType": "MetricAlarm" - if isinstance(alarm, LocalStackMetricAlarm) - else "CompositeAlarm", - } + alarm_history_item = AlarmHistoryItem( + Timestamp=alarm.alarm["StateUpdatedTimestamp"], + HistoryItemType=HistoryItemType.StateUpdate, + AlarmName=alarm.alarm["AlarmName"], + HistoryData=json.dumps(history_data), + HistorySummary=f"Alarm updated from {old_state} to {state_value}", + AlarmType="MetricAlarm" + if isinstance(alarm, LocalStackMetricAlarm) + else "CompositeAlarm", ) + store.histories.append(alarm_history_item) alarm.alarm["StateValue"] = state_value alarm.alarm["StateReason"] = state_reason if state_reason_data: @@ -834,15 +859,10 @@ def describe_alarm_history( if alarm_name: history = [h for h in history if h["AlarmName"] == alarm_name] - def _get_timestamp(input: dict): - if timestamp_string := input.get("Timestamp"): - return datetime.datetime.fromisoformat(timestamp_string) - return None - if start_date: - history = [h for h in history if (date := _get_timestamp(h)) and date >= start_date] + history = [h for h in history if (date := h.get("Timestamp")) and date >= start_date] if end_date: - history = [h for h in history if (date := _get_timestamp(h)) and date <= end_date] + history = [h for h in history if (date := h.get("Timestamp")) and date <= end_date] return DescribeAlarmHistoryOutput(AlarmHistoryItems=history) def _evaluate_composite_alarms(self, context: RequestContext, triggering_alarm): diff --git a/localstack-core/localstack/services/configservice/provider.py b/localstack-core/localstack/services/configservice/provider.py index 3087c6b23e270..b570dc05b5962 100644 --- a/localstack-core/localstack/services/configservice/provider.py +++ b/localstack-core/localstack/services/configservice/provider.py @@ -1,5 +1,9 @@ from localstack.aws.api.config import ConfigApi +from localstack.state import StateVisitor class ConfigProvider(ConfigApi): - pass + def accept_state_visitor(self, visitor: StateVisitor): + from moto.config.models import config_backends + + visitor.visit(config_backends) diff --git a/localstack-core/localstack/services/dynamodb/models.py b/localstack-core/localstack/services/dynamodb/models.py index cc6d7ee2e4939..46492f822dc50 100644 --- a/localstack-core/localstack/services/dynamodb/models.py +++ b/localstack-core/localstack/services/dynamodb/models.py @@ -3,10 +3,15 @@ from localstack.aws.api.dynamodb import ( AttributeMap, + BackupDetails, + ContinuousBackupsDescription, + GlobalTableDescription, Key, + KinesisDataStreamDestination, RegionName, ReplicaDescription, StreamViewType, + TableDescription, TableName, TimeToLiveSpecification, ) @@ -91,9 +96,20 @@ class TableRecords(TypedDict): RecordsMap = dict[TableName, TableRecords] +class TableProperties(TypedDict, total=False): + ContinuousBackupsDescription: ContinuousBackupsDescription + + +@dataclasses.dataclass +class Backup: + details: BackupDetails + backup_file: str + table_name: str + + class DynamoDBStore(BaseStore): # maps global table names to configurations (for the legacy v.2017 tables) - GLOBAL_TABLES: dict[str, dict] = CrossRegionAttribute(default=dict) + GLOBAL_TABLES: dict[str, GlobalTableDescription] = CrossRegionAttribute(default=dict) # Maps table name to the region they exist in on DDBLocal (for v.2019 global tables) TABLE_REGION: dict[TableName, RegionName] = CrossRegionAttribute(default=dict) @@ -104,19 +120,24 @@ class DynamoDBStore(BaseStore): ) # cache table taggings - maps table ARN to tags dict - TABLE_TAGS: dict[str, dict] = CrossRegionAttribute(default=dict) + TABLE_TAGS: dict[str, dict[str, str]] = CrossRegionAttribute(default=dict) # maps table names to cached table definitions - table_definitions: dict[str, dict] = LocalAttribute(default=dict) + table_definitions: dict[str, TableDescription] = LocalAttribute(default=dict) + + # map table name to streaming destinations + streaming_destinations: dict[str, list[KinesisDataStreamDestination]] = LocalAttribute( + default=dict + ) # maps table names to additional table properties that are not stored upstream (e.g., ReplicaUpdates) - table_properties: dict[str, dict] = LocalAttribute(default=dict) + table_properties: dict[str, TableProperties] = LocalAttribute(default=dict) # maps table names to TTL specifications ttl_specifications: dict[str, TimeToLiveSpecification] = LocalAttribute(default=dict) # maps backups - backups: dict[str, dict] = LocalAttribute(default=dict) + backups: dict[str, Backup] = LocalAttribute(default=dict) dynamodb_stores = AccountRegionBundle("dynamodb", DynamoDBStore) diff --git a/localstack-core/localstack/services/dynamodb/provider.py b/localstack-core/localstack/services/dynamodb/provider.py index a1492fc2b41d8..a5511a877c062 100644 --- a/localstack-core/localstack/services/dynamodb/provider.py +++ b/localstack-core/localstack/services/dynamodb/provider.py @@ -6,7 +6,6 @@ import re import threading import time -import traceback from collections import defaultdict from concurrent.futures import ThreadPoolExecutor from contextlib import contextmanager @@ -47,6 +46,8 @@ DeleteRequest, DeleteTableOutput, DescribeContinuousBackupsOutput, + DescribeContributorInsightsInput, + DescribeContributorInsightsOutput, DescribeGlobalTableOutput, DescribeKinesisStreamingDestinationOutput, DescribeTableOutput, @@ -62,6 +63,7 @@ GetItemOutput, GlobalTableAlreadyExistsException, GlobalTableNotFoundException, + KinesisDataStreamDestination, KinesisStreamingDestinationOutput, ListGlobalTablesOutput, ListTablesInputLimit, @@ -272,7 +274,12 @@ def forward_to_kinesis_stream( table_arn = arns.dynamodb_table_arn(table_name, account_id, region_name) records = table_records["records"] table_def = store.table_definitions.get(table_name) or {} - stream_arn = table_def["KinesisDataStreamDestinations"][-1]["StreamArn"] + destinations = store.streaming_destinations.get(table_name) + if not destinations: + LOG.debug("Table %s has no Kinesis streaming destinations enabled", table_name) + continue + + stream_arn = destinations[-1]["StreamArn"] for record in records: kinesis_record = dict( tableName=table_name, @@ -533,6 +540,7 @@ def __init__(self): self.server = self._new_dynamodb_server() self._expired_items_worker = ExpiredItemsWorker() self._router_rules = [] + # TODO: fix _event_forwarder to have lazy instantiation of the ThreadPoolExecutor self._event_forwarder = EventForwarder() def on_before_start(self): @@ -746,6 +754,9 @@ def create_table( if "NumberOfDecreasesToday" not in table_description["ProvisionedThroughput"]: table_description["ProvisionedThroughput"]["NumberOfDecreasesToday"] = 0 + if "WarmThroughput" in table_description: + table_description["WarmThroughput"]["Status"] = "UPDATING" + tags = table_definitions.pop("Tags", []) if tags: get_store(context.account_id, context.region).TABLE_TAGS[table_arn] = { @@ -763,6 +774,13 @@ def delete_table( ) -> DeleteTableOutput: global_table_region = self.get_global_table_region(context, table_name) + self.ensure_table_exists( + context.account_id, + global_table_region, + table_name, + error_message=f"Requested resource not found: Table: {table_name} not found", + ) + # Limitation note: On AWS, for a replicated table, if the source table is deleted, the replicated tables continue to exist. # This is not the case for LocalStack, where all replicated tables will also be removed if source is deleted. @@ -823,6 +841,9 @@ def describe_table( table_description["TableClassSummary"] = { "TableClass": table_definitions["TableClass"] } + if warm_throughput := table_definitions.get("WarmThroughput"): + table_description["WarmThroughput"] = warm_throughput.copy() + table_description["WarmThroughput"].setdefault("Status", "ACTIVE") if "GlobalSecondaryIndexes" in table_description: for gsi in table_description["GlobalSecondaryIndexes"]: @@ -835,6 +856,17 @@ def describe_table( # Terraform depends on this parity for update operations gsi["ProvisionedThroughput"] = default_values | gsi.get("ProvisionedThroughput", {}) + # Set defaults for warm throughput + if "WarmThroughput" not in table_description: + billing_mode = table_definitions.get("BillingMode") if table_definitions else None + table_description["WarmThroughput"] = { + "ReadUnitsPerSecond": 12000 if billing_mode == "PAY_PER_REQUEST" else 5, + "WriteUnitsPerSecond": 4000 if billing_mode == "PAY_PER_REQUEST" else 5, + } + table_description["WarmThroughput"]["Status"] = ( + table_description.get("TableStatus") or "ACTIVE" + ) + return DescribeTableOutput( Table=select_from_typed_dict(TableDescription, table_description) ) @@ -955,6 +987,22 @@ def list_tables( return response + # + # Contributor Insights + # + + @handler("DescribeContributorInsights", expand=False) + def describe_contributor_insights( + self, + context: RequestContext, + describe_contributor_insights_input: DescribeContributorInsightsInput, + ) -> DescribeContributorInsightsOutput: + return DescribeContributorInsightsOutput( + TableName=describe_contributor_insights_input["TableName"], + IndexName=describe_contributor_insights_input.get("IndexName"), + ContributorInsightsStatus="DISABLED", + ) + # # Item ops # @@ -1281,11 +1329,15 @@ def transact_write_items( for item in transact_items: item: TransactWriteItem - for key in ["Put", "Update", "Delete"]: + for key in ["Put", "Update", "Delete", "ConditionCheck"]: inner_item: Put | Delete | Update = item.get(key) if inner_item: - table_name = inner_item["TableName"] - # if we've seen the table already and it does not have streams, skip + # Extract the table name from the ARN; DynamoDB Local does not currently support + # full ARNs in this operation: https://github.com/awslabs/amazon-dynamodb-local-samples/issues/34 + inner_item["TableName"] = table_name = inner_item["TableName"].split(":table/")[ + -1 + ] + # if we've seen the table already exists and it does not have streams, skip if table_name in no_stream_tables: continue @@ -1311,6 +1363,10 @@ def transact_write_items( updated_items_to_fetch_for_table.append(inner_item) continue + # Normalize the request structure to ensure it matches the expected format for DynamoDB Local. + data = json.loads(context.request.data) + data["TransactItems"] = transact_items + context.request.data = to_bytes(json.dumps(data, cls=BytesEncoder)) if existing_items_to_fetch: existing_items = ItemFinder.find_existing_items( @@ -1361,6 +1417,17 @@ def transact_get_items( transact_items: TransactGetItemList, return_consumed_capacity: ReturnConsumedCapacity = None, ) -> TransactGetItemsOutput: + for transact_item in transact_items["TransactItems"]: + if item := transact_item.get("Get"): + # Extract the table name from the ARN; DynamoDB Local does not currently support + # full ARNs in this operation: https://github.com/awslabs/amazon-dynamodb-local-samples/issues/34 + item["TableName"] = item["TableName"].split(":table/")[-1] + + # Normalize the request structure to ensure it matches the expected format for DynamoDB Local. + data = json.loads(context.request.data) + data["TransactItems"] = transact_items["TransactItems"] + context.request.data = to_bytes(json.dumps(data, cls=BytesEncoder)) + return self.forward_request(context) @handler("ExecuteTransaction", expand=False) @@ -1603,34 +1670,32 @@ def enable_kinesis_streaming_destination( if not stream: raise ValidationException("User does not have a permission to use kinesis stream") - table_def = get_store(context.account_id, context.region).table_definitions.setdefault( - table_name, {} - ) - - dest_status = table_def.get("KinesisDataStreamDestinationStatus") - if dest_status not in ["DISABLED", "ENABLE_FAILED", None]: - raise ValidationException( - "Table is not in a valid state to enable Kinesis Streaming " - "Destination:EnableKinesisStreamingDestination must be DISABLED or ENABLE_FAILED " - "to perform ENABLE operation." - ) + store = get_store(context.account_id, context.region) + streaming_destinations = store.streaming_destinations.get(table_name) or [] - table_def.setdefault("KinesisDataStreamDestinations", []) + destinations = [d for d in streaming_destinations if d["StreamArn"] == stream_arn] + if destinations: + status = destinations[0].get("DestinationStatus", None) + if status not in ["DISABLED", "ENABLED_FAILED", None]: + raise ValidationException( + "Table is not in a valid state to enable Kinesis Streaming " + "Destination:EnableKinesisStreamingDestination must be DISABLED or ENABLE_FAILED " + "to perform ENABLE operation." + ) # remove the stream destination if already present - table_def["KinesisDataStreamDestinations"] = [ - t for t in table_def["KinesisDataStreamDestinations"] if t["StreamArn"] != stream_arn + store.streaming_destinations[table_name] = [ + _d for _d in streaming_destinations if _d["StreamArn"] != stream_arn ] # append the active stream destination at the end of the list - table_def["KinesisDataStreamDestinations"].append( - { - "DestinationStatus": DestinationStatus.ACTIVE, - "DestinationStatusDescription": "Stream is active", - "StreamArn": stream_arn, - "ApproximateCreationDateTimePrecision": ApproximateCreationDateTimePrecision.MILLISECOND, - } + store.streaming_destinations[table_name].append( + KinesisDataStreamDestination( + DestinationStatus=DestinationStatus.ACTIVE, + DestinationStatusDescription="Stream is active", + StreamArn=stream_arn, + ApproximateCreationDateTimePrecision=ApproximateCreationDateTimePrecision.MILLISECOND, + ) ) - table_def["KinesisDataStreamDestinationStatus"] = DestinationStatus.ACTIVE return KinesisStreamingDestinationOutput( DestinationStatus=DestinationStatus.ENABLING, StreamArn=stream_arn, @@ -1653,34 +1718,25 @@ def disable_kinesis_streaming_destination( error_message=f"Requested resource not found: Table: {table_name} not found", ) - # TODO: Must raise if invoked before KinesisStreamingDestination is ACTIVE - stream = self._event_forwarder.is_kinesis_stream_exists(stream_arn=stream_arn) if not stream: raise ValidationException( "User does not have a permission to use kinesis stream", ) - table_def = get_store(context.account_id, context.region).table_definitions.setdefault( - table_name, {} - ) - - stream_destinations = table_def.get("KinesisDataStreamDestinations") - if stream_destinations: - if table_def["KinesisDataStreamDestinationStatus"] == DestinationStatus.ACTIVE: - for dest in stream_destinations: - if ( - dest["StreamArn"] == stream_arn - and dest["DestinationStatus"] == DestinationStatus.ACTIVE - ): - dest["DestinationStatus"] = DestinationStatus.DISABLED - dest["DestinationStatusDescription"] = ("Stream is disabled",) - table_def["KinesisDataStreamDestinationStatus"] = DestinationStatus.DISABLED - return KinesisStreamingDestinationOutput( - DestinationStatus=DestinationStatus.DISABLING, - StreamArn=stream_arn, - TableName=table_name, - ) + store = get_store(context.account_id, context.region) + streaming_destinations = store.streaming_destinations.get(table_name) or [] + + # Get the right destination based on the arn + destinations = [d for d in streaming_destinations if d["StreamArn"] == stream_arn] + if destinations: + destinations[0]["DestinationStatus"] = DestinationStatus.DISABLED + destinations[0]["DestinationStatusDescription"] = "Stream is disabled" + return KinesisStreamingDestinationOutput( + DestinationStatus=DestinationStatus.DISABLING, + StreamArn=stream_arn, + TableName=table_name, + ) raise ValidationException( "Table is not in a valid state to disable Kinesis Streaming Destination:" "DisableKinesisStreamingDestination must be ACTIVE to perform DISABLE operation." @@ -1691,12 +1747,9 @@ def describe_kinesis_streaming_destination( ) -> DescribeKinesisStreamingDestinationOutput: self.ensure_table_exists(context.account_id, context.region, table_name) - table_def = ( - get_store(context.account_id, context.region).table_definitions.get(table_name) or {} - ) - - stream_destinations = table_def.get("KinesisDataStreamDestinations") or [] - stream_destinations = copy.deepcopy(stream_destinations) + store = get_store(context.account_id, context.region) + table_destinations = store.streaming_destinations.get(table_name) or [] + stream_destinations = copy.deepcopy(table_destinations) for destination in stream_destinations: destination.pop("ApproximateCreationDateTimePrecision", None) @@ -1737,23 +1790,21 @@ def update_kinesis_streaming_destination( ) store = get_store(context.account_id, context.region) + table_destinations = store.streaming_destinations.get(table_name) or [] - table_def = store.table_definitions.get(table_name) or {} - table_def.setdefault("KinesisDataStreamDestinations", []) - - table_id = table_def["TableId"] - - destination = None - for stream in table_def["KinesisDataStreamDestinations"]: - if stream["StreamArn"] == stream_arn: - destination = stream - - if destination is None: + # filter the right destination based on the stream ARN + destinations = [d for d in table_destinations if d["StreamArn"] == stream_arn] + if not destinations: raise ValidationException( "Table is not in a valid state to enable Kinesis Streaming Destination: " f"No streaming destination with streamArn: {stream_arn} found for table with tableName: {table_name}" ) + destination = destinations[0] + table_def = store.table_definitions.get(table_name) or {} + table_def.setdefault("KinesisDataStreamDestinations", []) + + table_id = store.table_definitions.get(table_name, {}).get("TableId") if ( existing_precision := destination["ApproximateCreationDateTimePrecision"] ) == update_kinesis_streaming_configuration["ApproximateCreationDateTimePrecision"]: @@ -1761,7 +1812,6 @@ def update_kinesis_streaming_destination( f"Invalid Request: Precision is already set to the desired value of {existing_precision} " f"for tableId: {table_id}, kdsArn: {stream_arn}" ) - destination["ApproximateCreationDateTimePrecision"] = time_precision return UpdateKinesisStreamingDestinationOutput( @@ -2255,19 +2305,20 @@ def get_table_stream_type( :return: a TableStreamViewType object if the table has streams enabled. If not, return None """ if not table_name_or_arn: - return + return None table_name = table_name_or_arn.split(":table/")[-1] is_kinesis = False stream_view_type = None - if table_definition := get_store(account_id, region_name).table_definitions.get(table_name): - if table_definition.get("KinesisDataStreamDestinationStatus") == "ACTIVE": + # To determine if stream to kinesis is enabled, we look for active kinesis destinations + destinations = get_store(account_id, region_name).streaming_destinations.get(table_name) or [] + for destination in destinations: + if destination["DestinationStatus"] == DestinationStatus.ACTIVE: is_kinesis = True table_arn = arns.dynamodb_table_arn(table_name, account_id=account_id, region_name=region_name) - if ( stream := dynamodbstreams_api.get_stream_for_table(account_id, region_name, table_arn) ) and stream["StreamStatus"] in (StreamStatus.ENABLING, StreamStatus.ENABLED): @@ -2275,6 +2326,7 @@ def get_table_stream_type( if is_kinesis or stream_view_type: return TableStreamType(stream_view_type, is_kinesis=is_kinesis) + return None def get_updated_records( @@ -2348,7 +2400,9 @@ def _add_record(item, comparison_set: ItemSet): return {table_name: TableRecords(records=result, table_stream_type=table_stream_type)} -def create_dynamodb_stream(account_id: str, region_name: str, data, latest_stream_label): +def create_dynamodb_stream( + account_id: str, region_name: str, data: CreateTableInput, latest_stream_label: str | None +) -> None: stream = data["StreamSpecification"] enabled = stream.get("StreamEnabled") @@ -2366,22 +2420,6 @@ def create_dynamodb_stream(account_id: str, region_name: str, data, latest_strea ) -def dynamodb_get_table_stream_specification(account_id: str, region_name: str, table_name: str): - try: - table_schema = SchemaExtractor.get_table_schema( - table_name, account_id=account_id, region_name=region_name - ) - return table_schema["Table"].get("StreamSpecification") - except Exception as e: - LOG.info( - "Unable to get stream specification for table %s: %s %s", - table_name, - e, - traceback.format_exc(), - ) - raise e - - def find_item_for_keys_values_in_batch( table_name: str, item_keys: dict, batch: BatchGetResponseMap ) -> AttributeMap | None: diff --git a/localstack-core/localstack/services/dynamodb/v2/provider.py b/localstack-core/localstack/services/dynamodb/v2/provider.py index b7f22b83b8a59..88e2c0b93cd4d 100644 --- a/localstack-core/localstack/services/dynamodb/v2/provider.py +++ b/localstack-core/localstack/services/dynamodb/v2/provider.py @@ -40,6 +40,8 @@ DeleteRequest, DeleteTableOutput, DescribeContinuousBackupsOutput, + DescribeContributorInsightsInput, + DescribeContributorInsightsOutput, DescribeGlobalTableOutput, DescribeKinesisStreamingDestinationOutput, DescribeTableOutput, @@ -51,10 +53,12 @@ ExecuteStatementOutput, ExecuteTransactionInput, ExecuteTransactionOutput, + Get, GetItemInput, GetItemOutput, GlobalTableAlreadyExistsException, GlobalTableNotFoundException, + KinesisDataStreamDestination, KinesisStreamingDestinationOutput, ListGlobalTablesOutput, ListTablesInputLimit, @@ -140,7 +144,7 @@ ) from localstack.utils.collections import select_attributes, select_from_typed_dict from localstack.utils.common import short_uid, to_bytes -from localstack.utils.json import canonical_json +from localstack.utils.json import BytesEncoder, canonical_json from localstack.utils.scheduler import Scheduler from localstack.utils.strings import long_uid, to_str from localstack.utils.threads import FuncThread, start_thread @@ -390,6 +394,7 @@ def on_before_stop(self): def accept_state_visitor(self, visitor: StateVisitor): visitor.visit(dynamodb_stores) + # FIXME: DDB v2 does not depend on dynamodbstreams_stores as DynamoDB Local holds all the state visitor.visit(dynamodbstreams_stores) visitor.visit(AssetDirectory(self.service, os.path.join(config.dirs.data, self.service))) @@ -558,6 +563,9 @@ def create_table( if "NumberOfDecreasesToday" not in table_description["ProvisionedThroughput"]: table_description["ProvisionedThroughput"]["NumberOfDecreasesToday"] = 0 + if "WarmThroughput" in table_description: + table_description["WarmThroughput"]["Status"] = "UPDATING" + tags = table_definitions.pop("Tags", []) if tags: get_store(context.account_id, context.region).TABLE_TAGS[table_arn] = { @@ -575,6 +583,13 @@ def delete_table( ) -> DeleteTableOutput: global_table_region = self.get_global_table_region(context, table_name) + self.ensure_table_exists( + context.account_id, + global_table_region, + table_name, + error_message=f"Requested resource not found: Table: {table_name} not found", + ) + # Limitation note: On AWS, for a replicated table, if the source table is deleted, the replicated tables continue to exist. # This is not the case for LocalStack, where all replicated tables will also be removed if source is deleted. @@ -634,6 +649,9 @@ def describe_table( table_description["TableClassSummary"] = { "TableClass": table_definitions["TableClass"] } + if warm_throughput := table_definitions.get("WarmThroughput"): + table_description["WarmThroughput"] = warm_throughput.copy() + table_description["WarmThroughput"].setdefault("Status", "ACTIVE") if "GlobalSecondaryIndexes" in table_description: for gsi in table_description["GlobalSecondaryIndexes"]: @@ -646,6 +664,17 @@ def describe_table( # Terraform depends on this parity for update operations gsi["ProvisionedThroughput"] = default_values | gsi.get("ProvisionedThroughput", {}) + # Set defaults for warm throughput + if "WarmThroughput" not in table_description: + billing_mode = table_definitions.get("BillingMode") if table_definitions else None + table_description["WarmThroughput"] = { + "ReadUnitsPerSecond": 12000 if billing_mode == "PAY_PER_REQUEST" else 5, + "WriteUnitsPerSecond": 4000 if billing_mode == "PAY_PER_REQUEST" else 5, + } + table_description["WarmThroughput"]["Status"] = ( + table_description.get("TableStatus") or "ACTIVE" + ) + return DescribeTableOutput( Table=select_from_typed_dict(TableDescription, table_description) ) @@ -757,6 +786,22 @@ def list_tables( return response + # + # Contributor Insights + # + + @handler("DescribeContributorInsights", expand=False) + def describe_contributor_insights( + self, + context: RequestContext, + describe_contributor_insights_input: DescribeContributorInsightsInput, + ) -> DescribeContributorInsightsOutput: + return DescribeContributorInsightsOutput( + TableName=describe_contributor_insights_input["TableName"], + IndexName=describe_contributor_insights_input.get("IndexName"), + ContributorInsightsStatus="DISABLED", + ) + # # Item ops # @@ -898,6 +943,21 @@ def transact_write_items( transact_write_items_input: TransactWriteItemsInput, ) -> TransactWriteItemsOutput: # TODO: add global table support + + transact_items = transact_write_items_input["TransactItems"] + for item in transact_items: + for key in ["Put", "Update", "Delete", "ConditionCheck"]: + inner_item = item.get(key) + if inner_item: + # Extract the table name from the ARN; DynamoDB Local does not currently support + # full ARNs in this operation: https://github.com/awslabs/amazon-dynamodb-local-samples/issues/34 + inner_item["TableName"] = inner_item["TableName"].split(":table/")[-1] + + # Normalize the request structure to ensure it matches the expected format for DynamoDB Local. + data = json.loads(context.request.data) + data["TransactItems"] = transact_items + context.request.data = to_bytes(json.dumps(data, cls=BytesEncoder)) + client_token: str | None = transact_write_items_input.get("ClientRequestToken") if client_token: @@ -914,6 +974,18 @@ def transact_get_items( transact_items: TransactGetItemList, return_consumed_capacity: ReturnConsumedCapacity = None, ) -> TransactGetItemsOutput: + for transact_item in transact_items["TransactItems"]: + item: Get = transact_item.get("Get") + if item: + # Extract the table name from the ARN; DynamoDB Local does not currently support + # full ARNs in this operation: https://github.com/awslabs/amazon-dynamodb-local-samples/issues/34 + item["TableName"] = item["TableName"].split(":table/")[-1] + + # Normalize the request structure to ensure it matches the expected format for DynamoDB Local. + data = json.loads(context.request.data) + data["TransactItems"] = transact_items["TransactItems"] + context.request.data = to_bytes(json.dumps(data, cls=BytesEncoder)) + return self.forward_request(context) @handler("ExecuteTransaction", expand=False) @@ -1125,34 +1197,32 @@ def enable_kinesis_streaming_destination( if not kinesis_stream_exists(stream_arn=stream_arn): raise ValidationException("User does not have a permission to use kinesis stream") - table_def = get_store(context.account_id, context.region).table_definitions.setdefault( - table_name, {} - ) - - dest_status = table_def.get("KinesisDataStreamDestinationStatus") - if dest_status not in ["DISABLED", "ENABLE_FAILED", None]: - raise ValidationException( - "Table is not in a valid state to enable Kinesis Streaming " - "Destination:EnableKinesisStreamingDestination must be DISABLED or ENABLE_FAILED " - "to perform ENABLE operation." - ) + store = get_store(context.account_id, context.region) + streaming_destinations = store.streaming_destinations.get(table_name) or [] - table_def.setdefault("KinesisDataStreamDestinations", []) + destinations = [d for d in streaming_destinations if d["StreamArn"] == stream_arn] + if destinations: + status = destinations[0].get("DestinationStatus", None) + if status not in ["DISABLED", "ENABLED_FAILED", None]: + raise ValidationException( + "Table is not in a valid state to enable Kinesis Streaming " + "Destination:EnableKinesisStreamingDestination must be DISABLED or ENABLE_FAILED " + "to perform ENABLE operation." + ) # remove the stream destination if already present - table_def["KinesisDataStreamDestinations"] = [ - t for t in table_def["KinesisDataStreamDestinations"] if t["StreamArn"] != stream_arn + store.streaming_destinations[table_name] = [ + _d for _d in streaming_destinations if _d["StreamArn"] != stream_arn ] # append the active stream destination at the end of the list - table_def["KinesisDataStreamDestinations"].append( - { - "DestinationStatus": DestinationStatus.ACTIVE, - "DestinationStatusDescription": "Stream is active", - "StreamArn": stream_arn, - "ApproximateCreationDateTimePrecision": ApproximateCreationDateTimePrecision.MILLISECOND, - } + store.streaming_destinations[table_name].append( + KinesisDataStreamDestination( + DestinationStatus=DestinationStatus.ACTIVE, + DestinationStatusDescription="Stream is active", + StreamArn=stream_arn, + ApproximateCreationDateTimePrecision=ApproximateCreationDateTimePrecision.MILLISECOND, + ) ) - table_def["KinesisDataStreamDestinationStatus"] = DestinationStatus.ACTIVE return KinesisStreamingDestinationOutput( DestinationStatus=DestinationStatus.ENABLING, StreamArn=stream_arn, @@ -1180,26 +1250,19 @@ def disable_kinesis_streaming_destination( "User does not have a permission to use kinesis stream", ) - table_def = get_store(context.account_id, context.region).table_definitions.setdefault( - table_name, {} - ) - - stream_destinations = table_def.get("KinesisDataStreamDestinations") - if stream_destinations: - if table_def["KinesisDataStreamDestinationStatus"] == DestinationStatus.ACTIVE: - for dest in stream_destinations: - if ( - dest["StreamArn"] == stream_arn - and dest["DestinationStatus"] == DestinationStatus.ACTIVE - ): - dest["DestinationStatus"] = DestinationStatus.DISABLED - dest["DestinationStatusDescription"] = ("Stream is disabled",) - table_def["KinesisDataStreamDestinationStatus"] = DestinationStatus.DISABLED - return KinesisStreamingDestinationOutput( - DestinationStatus=DestinationStatus.DISABLING, - StreamArn=stream_arn, - TableName=table_name, - ) + store = get_store(context.account_id, context.region) + streaming_destinations = store.streaming_destinations.get(table_name) or [] + + # Get the right destination based on the arn + destinations = [d for d in streaming_destinations if d["StreamArn"] == stream_arn] + if destinations: + destinations[0]["DestinationStatus"] = DestinationStatus.DISABLED + destinations[0]["DestinationStatusDescription"] = "Stream is disabled" + return KinesisStreamingDestinationOutput( + DestinationStatus=DestinationStatus.DISABLING, + StreamArn=stream_arn, + TableName=table_name, + ) raise ValidationException( "Table is not in a valid state to disable Kinesis Streaming Destination:" "DisableKinesisStreamingDestination must be ACTIVE to perform DISABLE operation." @@ -1210,12 +1273,9 @@ def describe_kinesis_streaming_destination( ) -> DescribeKinesisStreamingDestinationOutput: self.ensure_table_exists(context.account_id, context.region, table_name) - table_def = ( - get_store(context.account_id, context.region).table_definitions.get(table_name) or {} - ) - - stream_destinations = table_def.get("KinesisDataStreamDestinations") or [] - stream_destinations = copy.deepcopy(stream_destinations) + store = get_store(context.account_id, context.region) + table_destinations = store.streaming_destinations.get(table_name) or [] + stream_destinations = copy.deepcopy(table_destinations) for destination in stream_destinations: destination.pop("ApproximateCreationDateTimePrecision", None) @@ -1256,23 +1316,21 @@ def update_kinesis_streaming_destination( ) store = get_store(context.account_id, context.region) + table_destinations = store.streaming_destinations.get(table_name) or [] - table_def = store.table_definitions.get(table_name) or {} - table_def.setdefault("KinesisDataStreamDestinations", []) - - table_id = table_def["TableId"] - - destination = None - for stream in table_def["KinesisDataStreamDestinations"]: - if stream["StreamArn"] == stream_arn: - destination = stream - - if destination is None: + # filter the right destination based on the stream ARN + destinations = [d for d in table_destinations if d["StreamArn"] == stream_arn] + if not destinations: raise ValidationException( "Table is not in a valid state to enable Kinesis Streaming Destination: " f"No streaming destination with streamArn: {stream_arn} found for table with tableName: {table_name}" ) + destination = destinations[0] + table_def = store.table_definitions.get(table_name) or {} + table_def.setdefault("KinesisDataStreamDestinations", []) + + table_id = store.table_definitions.get(table_name, {}).get("TableId") if ( existing_precision := destination["ApproximateCreationDateTimePrecision"] ) == update_kinesis_streaming_configuration["ApproximateCreationDateTimePrecision"]: @@ -1280,7 +1338,6 @@ def update_kinesis_streaming_destination( f"Invalid Request: Precision is already set to the desired value of {existing_precision} " f"for tableId: {table_id}, kdsArn: {stream_arn}" ) - destination["ApproximateCreationDateTimePrecision"] = time_precision return UpdateKinesisStreamingDestinationOutput( @@ -1554,7 +1611,7 @@ def is_index_query_valid(account_id: str, region_name: str, query_data: dict) -> return True -def kinesis_stream_exists(stream_arn): +def kinesis_stream_exists(stream_arn: str) -> bool: account_id = extract_account_id_from_arn(stream_arn) region_name = extract_region_from_arn(stream_arn) diff --git a/localstack-core/localstack/services/dynamodbstreams/dynamodbstreams_api.py b/localstack-core/localstack/services/dynamodbstreams/dynamodbstreams_api.py index 45ae3f3bc472f..16c0451bacb4d 100644 --- a/localstack-core/localstack/services/dynamodbstreams/dynamodbstreams_api.py +++ b/localstack-core/localstack/services/dynamodbstreams/dynamodbstreams_api.py @@ -6,10 +6,19 @@ from localstack import config from localstack.aws.api import RequestContext -from localstack.aws.api.dynamodbstreams import StreamStatus, StreamViewType, TableName +from localstack.aws.api.dynamodbstreams import ( + StreamDescription, + StreamStatus, + StreamViewType, + TableName, +) from localstack.aws.connect import connect_to from localstack.services.dynamodb.v2.provider import DynamoDBProvider -from localstack.services.dynamodbstreams.models import DynamoDbStreamsStore, dynamodbstreams_stores +from localstack.services.dynamodbstreams.models import ( + DynamoDbStreamsStore, + StreamWrapper, + dynamodbstreams_stores, +) from localstack.utils.aws import arns, resources from localstack.utils.common import now_utc from localstack.utils.threads import FuncThread @@ -65,28 +74,32 @@ def add_dynamodb_stream( stream_name=stream_name, ) latest_stream_label = latest_stream_label or "latest" - stream = { - "StreamArn": arns.dynamodb_stream_arn( - table_name=table_name, - latest_stream_label=latest_stream_label, - account_id=account_id, - region_name=region_name, - ), - "TableName": table_name, - "StreamLabel": latest_stream_label, - "StreamStatus": StreamStatus.ENABLING, - "KeySchema": [], - "Shards": [], - "StreamViewType": view_type, - "shards_id_map": {}, - } - store.ddb_streams[table_name] = stream - - -def get_stream_for_table(account_id: str, region_name: str, table_arn: str) -> dict: + stream_arn = arns.dynamodb_stream_arn( + table_name=table_name, + latest_stream_label=latest_stream_label, + account_id=account_id, + region_name=region_name, + ) + stream = StreamDescription( + TableName=table_name, + StreamArn=stream_arn, + StreamLabel=latest_stream_label, + StreamStatus=StreamStatus.ENABLING, + KeySchema=[], + Shards=[], + StreamViewType=view_type, + ) + store.ddb_streams[table_name] = StreamWrapper(StreamDescription=stream) + + +def get_stream_for_table( + account_id: str, region_name: str, table_arn: str +) -> StreamDescription | None: store = get_dynamodbstreams_store(account_id, region_name) table_name = table_name_from_stream_arn(table_arn) - return store.ddb_streams.get(table_name) + if stream := store.ddb_streams.get(table_name): + return stream.StreamDescription + return None def _process_forwarded_records( @@ -206,11 +219,11 @@ def kinesis_shard_id(dynamodbstream_shard_id: str) -> str: return f"{shard_params[0]}-{shard_params[-1]}" -def get_shard_id(stream: dict, kinesis_shard_id: str) -> str: - ddb_stream_shard_id = stream.get("shards_id_map", {}).get(kinesis_shard_id) +def get_shard_id(stream: StreamWrapper, kinesis_shard_id: str) -> str: + ddb_stream_shard_id = stream.shards_id_map.get(kinesis_shard_id) if not ddb_stream_shard_id: ddb_stream_shard_id = shard_id(kinesis_shard_id) - stream["shards_id_map"][kinesis_shard_id] = ddb_stream_shard_id + stream.shards_id_map[kinesis_shard_id] = ddb_stream_shard_id return ddb_stream_shard_id diff --git a/localstack-core/localstack/services/dynamodbstreams/models.py b/localstack-core/localstack/services/dynamodbstreams/models.py index 858954f3f9772..811f09e9a6536 100644 --- a/localstack-core/localstack/services/dynamodbstreams/models.py +++ b/localstack-core/localstack/services/dynamodbstreams/models.py @@ -1,9 +1,19 @@ +import dataclasses + +from localstack.aws.api.dynamodbstreams import StreamDescription from localstack.services.stores import AccountRegionBundle, BaseStore, LocalAttribute +@dataclasses.dataclass +class StreamWrapper: + """Wrapper for the API stub and additional information about a store""" + + StreamDescription: StreamDescription + shards_id_map: dict[str, str] = dataclasses.field(default_factory=dict) + + class DynamoDbStreamsStore(BaseStore): - # maps table names to DynamoDB stream descriptions - ddb_streams: dict[str, dict] = LocalAttribute(default=dict) + ddb_streams: dict[str, StreamWrapper] = LocalAttribute(default=dict) dynamodbstreams_stores = AccountRegionBundle("dynamodbstreams", DynamoDbStreamsStore) diff --git a/localstack-core/localstack/services/dynamodbstreams/provider.py b/localstack-core/localstack/services/dynamodbstreams/provider.py index 2888b2b610cc0..7f5412a6cb0d0 100644 --- a/localstack-core/localstack/services/dynamodbstreams/provider.py +++ b/localstack-core/localstack/services/dynamodbstreams/provider.py @@ -20,7 +20,6 @@ ShardIteratorType, Stream, StreamArn, - StreamDescription, StreamStatus, TableName, ) @@ -37,6 +36,7 @@ table_name_from_stream_arn, ) from localstack.services.plugins import ServiceLifecycleHook +from localstack.state import StateVisitor from localstack.utils.collections import select_from_typed_dict LOG = logging.getLogger(__name__) @@ -57,6 +57,11 @@ class DynamoDBStreamsProvider(DynamodbstreamsApi, ServiceLifecycleHook): def __init__(self): self.shard_to_region = {} + def accept_state_visitor(self, visitor: StateVisitor): + from localstack.services.dynamodbstreams.models import dynamodbstreams_stores + + visitor.visit(dynamodbstreams_stores) + def describe_stream( self, context: RequestContext, @@ -71,20 +76,21 @@ def describe_stream( store = get_dynamodbstreams_store(context.account_id, og_region) kinesis = get_kinesis_client(account_id=context.account_id, region_name=og_region) for stream in store.ddb_streams.values(): + stream_description = stream.StreamDescription _stream_arn = stream_arn if context.region != og_region: _stream_arn = change_region_in_ddb_stream_arn(_stream_arn, og_region) - if stream["StreamArn"] == _stream_arn: + if stream_description["StreamArn"] == _stream_arn: # get stream details dynamodb = connect_to( aws_access_key_id=context.account_id, region_name=og_region ).dynamodb - table_name = table_name_from_stream_arn(stream["StreamArn"]) + table_name = table_name_from_stream_arn(stream_description["StreamArn"]) stream_name = get_kinesis_stream_name(table_name) stream_details = kinesis.describe_stream(StreamName=stream_name) table_details = dynamodb.describe_table(TableName=table_name) - stream["KeySchema"] = table_details["Table"]["KeySchema"] - stream["StreamStatus"] = STREAM_STATUS_MAP.get( + stream_description["KeySchema"] = table_details["Table"]["KeySchema"] + stream_description["StreamStatus"] = STREAM_STATUS_MAP.get( stream_details["StreamDescription"]["StreamStatus"] ) @@ -104,8 +110,7 @@ def describe_stream( # slicing the resulting shards after the exclusive_start_shard_id parameters stream_shards = stream_shards[start_index + 1 :] - stream["Shards"] = stream_shards - stream_description = select_from_typed_dict(StreamDescription, stream) + stream_description["Shards"] = stream_shards stream_description["StreamArn"] = _stream_arn return DescribeStreamOutput(StreamDescription=stream_description) @@ -184,7 +189,10 @@ def list_streams( ) -> ListStreamsOutput: og_region = get_original_region(context=context, table_name=table_name) store = get_dynamodbstreams_store(context.account_id, og_region) - result = [select_from_typed_dict(Stream, res) for res in store.ddb_streams.values()] + result = [ + select_from_typed_dict(Stream, _s.StreamDescription) + for _s in store.ddb_streams.values() + ] if table_name: result: list[Stream] = [res for res in result if res["TableName"] == table_name] # If this is a stream from a table replica, we need to change the region in the stream ARN, as LocalStack diff --git a/localstack-core/localstack/services/dynamodbstreams/v2/provider.py b/localstack-core/localstack/services/dynamodbstreams/v2/provider.py index a91fbc592a992..9c8bb6d02bd8a 100644 --- a/localstack-core/localstack/services/dynamodbstreams/v2/provider.py +++ b/localstack-core/localstack/services/dynamodbstreams/v2/provider.py @@ -18,6 +18,7 @@ from localstack.services.dynamodb.v2.provider import DynamoDBProvider, modify_context_region from localstack.services.dynamodbstreams.dynamodbstreams_api import get_original_region from localstack.services.plugins import ServiceLifecycleHook +from localstack.state import StateVisitor from localstack.utils.aws.arns import parse_arn LOG = logging.getLogger(__name__) @@ -32,6 +33,11 @@ def __init__(self): self.server = DynamodbServer.get() self.shard_to_region = {} + def accept_state_visitor(self, visitor: StateVisitor): + # DynamoDB Streams state is entirely dependent on DynamoDB Local state, and does not hold state itself + # the DynamoDB provider is responsible for the persistence of DDB Streams + pass + def on_after_init(self): # add response processor specific to ddblocal handlers.modify_service_response.append(self.service, modify_ddblocal_arns) diff --git a/localstack-core/localstack/services/ec2/models.py b/localstack-core/localstack/services/ec2/models.py index cf2bc854900da..bb64aa3fd3b22 100644 --- a/localstack-core/localstack/services/ec2/models.py +++ b/localstack-core/localstack/services/ec2/models.py @@ -1,27 +1,6 @@ from moto.ec2 import ec2_backends from moto.ec2.models import EC2Backend -from moto.ec2.models.subnets import Subnet def get_ec2_backend(account_id: str, region: str) -> EC2Backend: return ec2_backends[account_id][region] - - -# -# Pickle patches -# - - -def set_state(self, state): - state["_subnet_ip_generator"] = state["cidr"].hosts() - self.__dict__.update(state) - - -def get_state(self): - state = self.__dict__.copy() - state.pop("_subnet_ip_generator", None) - return state - - -Subnet.__setstate__ = set_state -Subnet.__getstate__ = get_state diff --git a/localstack-core/localstack/services/ec2/provider.py b/localstack-core/localstack/services/ec2/provider.py index 03a72e873b35f..2480058d5f089 100644 --- a/localstack-core/localstack/services/ec2/provider.py +++ b/localstack-core/localstack/services/ec2/provider.py @@ -94,6 +94,7 @@ from localstack.services.ec2.patches import apply_patches from localstack.services.moto import call_moto, call_moto_with_request from localstack.services.plugins import ServiceLifecycleHook +from localstack.state import StateVisitor from localstack.utils.patch import patch from localstack.utils.strings import first_char_to_upper, long_uid, short_uid @@ -107,6 +108,11 @@ class Ec2Provider(Ec2Api, ABC, ServiceLifecycleHook): def on_after_init(self): apply_patches() + def accept_state_visitor(self, visitor: StateVisitor): + from moto.ec2.models import ec2_backends + + visitor.visit(ec2_backends) + @handler("DescribeAvailabilityZones", expand=False) def describe_availability_zones( self, diff --git a/localstack-core/localstack/services/es/provider.py b/localstack-core/localstack/services/es/provider.py index 0551b956d8621..0490568228975 100644 --- a/localstack-core/localstack/services/es/provider.py +++ b/localstack-core/localstack/services/es/provider.py @@ -68,6 +68,7 @@ ) from localstack.aws.connect import connect_to from localstack.services.opensearch.packages import ELASTICSEARCH_DEFAULT_VERSION +from localstack.state import StateVisitor def _version_to_opensearch( @@ -208,6 +209,11 @@ def exception_mapper(): class EsProvider(EsApi): + def accept_state_visitor(self, visitor: StateVisitor): + # ES state entirely depends on `opensearch`, and delegates its entire state to it + # we do not need to manage state in ES + pass + def create_elasticsearch_domain( self, context: RequestContext, diff --git a/localstack-core/localstack/services/events/archive.py b/localstack-core/localstack/services/events/archive.py index 36d0db5394605..60cb7f6906eec 100644 --- a/localstack-core/localstack/services/events/archive.py +++ b/localstack-core/localstack/services/events/archive.py @@ -60,9 +60,9 @@ def create_archive_service( region: str, account_id: str, event_source_arn: Arn, - description: ArchiveDescription, - event_pattern: EventPattern, - retention_days: RetentionDays, + description: ArchiveDescription | None, + event_pattern: EventPattern | None, + retention_days: RetentionDays | None, ) -> Self: return cls( Archive( diff --git a/localstack-core/localstack/services/events/event_bus.py b/localstack-core/localstack/services/events/event_bus.py index 19a4657233b4c..4d86279387aa0 100644 --- a/localstack-core/localstack/services/events/event_bus.py +++ b/localstack-core/localstack/services/events/event_bus.py @@ -1,6 +1,6 @@ import json from datetime import UTC, datetime -from typing import Self +from typing import Any, Self from localstack.aws.api.events import ( Action, @@ -12,7 +12,7 @@ StatementId, TagList, ) -from localstack.services.events.models import EventBus, ResourcePolicy, RuleDict, Statement +from localstack.services.events.models import EventBus, ResourcePolicy, RuleDict from localstack.utils.aws.arns import get_partition @@ -111,21 +111,20 @@ def _parse_statement( principal: Principal, resource_arn: Arn, condition: Condition, - ) -> Statement: + ) -> dict[str, Any]: # TODO: cover via test # if condition and principal != "*": # raise ValueError("Condition can only be set when principal is '*'") if principal != "*": principal = {"AWS": f"arn:{get_partition(self.event_bus.region)}:iam::{principal}:root"} - statement = Statement( - Sid=statement_id, - Effect="Allow", - Principal=principal, - Action=action, - Resource=resource_arn, - Condition=condition, - ) - return statement + return { + "Sid": statement_id, + "Effect": "Allow", + "Principal": principal, + "Action": action, + "Resource": resource_arn, + "Condition": condition, + } EventBusServiceDict = dict[Arn, EventBusService] diff --git a/localstack-core/localstack/services/events/event_rule_engine.py b/localstack-core/localstack/services/events/event_rule_engine.py index a1af9a9cdb339..0014e933d76f6 100644 --- a/localstack-core/localstack/services/events/event_rule_engine.py +++ b/localstack-core/localstack/services/events/event_rule_engine.py @@ -59,14 +59,21 @@ def _evaluate_nested_event_pattern_on_dict(self, event_pattern, payload: dict) - for flat_pattern in flat_pattern_conditions ) - def _evaluate_condition(self, value, condition, field_exists: bool): + def _evaluate_condition(self, value: t.Any, condition: t.Any, field_exists: bool) -> bool: if not isinstance(condition, dict): return field_exists and value == condition + elif (must_exist := condition.get("exists")) is not None: # if must_exists is True then field_exists must be True # if must_exists is False then fields_exists must be False return must_exist == field_exists + elif (anything_but := condition.get("anything-but")) is not None: + if not field_exists: + # anything-but can handle None `value`, but it needs to differentiate between user-set `null` and + # missing value + return False + if isinstance(anything_but, dict): if (not_condition := anything_but.get("prefix")) is not None: predicate = self._evaluate_prefix @@ -95,6 +102,7 @@ def _evaluate_condition(self, value, condition, field_exists: bool): elif value is None: # the remaining conditions require the value to not be None return False + elif (prefix := condition.get("prefix")) is not None: if isinstance(prefix, dict): if (prefix_equal_ignore_case := prefix.get("equals-ignore-case")) is not None: @@ -104,7 +112,7 @@ def _evaluate_condition(self, value, condition, field_exists: bool): elif (suffix := condition.get("suffix")) is not None: if isinstance(suffix, dict): - if suffix_equal_ignore_case := suffix.get("equals-ignore-case"): + if (suffix_equal_ignore_case := suffix.get("equals-ignore-case")) is not None: return self._evaluate_suffix(suffix_equal_ignore_case.lower(), value.lower()) else: return self._evaluate_suffix(suffix, value) @@ -126,19 +134,19 @@ def _evaluate_condition(self, value, condition, field_exists: bool): return False @staticmethod - def _evaluate_prefix(condition: str | list, value: str) -> bool: - return value.startswith(condition) + def _evaluate_prefix(condition: str | list, value: t.Any) -> bool: + return isinstance(value, str) and value.startswith(condition) @staticmethod - def _evaluate_suffix(condition: str | list, value: str) -> bool: - return value.endswith(condition) + def _evaluate_suffix(condition: str | list, value: t.Any) -> bool: + return isinstance(value, str) and value.endswith(condition) @staticmethod - def _evaluate_equal_ignore_case(condition: str, value: str) -> bool: - return condition.lower() == value.lower() + def _evaluate_equal_ignore_case(condition: str, value: t.Any) -> bool: + return isinstance(value, str) and condition.lower() == value.lower() @staticmethod - def _evaluate_cidr(condition: str, value: str) -> bool: + def _evaluate_cidr(condition: str, value: t.Any) -> bool: try: ip = ipaddress.ip_address(value) return ip in ipaddress.ip_network(condition) @@ -146,8 +154,10 @@ def _evaluate_cidr(condition: str, value: str) -> bool: return False @staticmethod - def _evaluate_wildcard(condition: str, value: str) -> bool: - return bool(re.match(re.escape(condition).replace("\\*", ".+") + "$", value)) + def _evaluate_wildcard(condition: str, value: t.Any) -> bool: + return isinstance(value, str) and bool( + re.match(re.escape(condition).replace("\\*", ".+") + "$", value) + ) @staticmethod def _evaluate_numeric_condition(conditions: list, value: t.Any) -> bool: @@ -457,10 +467,18 @@ def _validate_rule(self, rule: t.Any, from_: str | None = None) -> None: return elif operator == "anything-but": - # anything-but can actually contain any kind of simple rule (str, number, and list) + # anything-but can actually contain any kind of simple rule (str, number, and list) except Null + if value is None: + raise InvalidEventPatternException( + f"{self.error_prefix}Value of anything-but must be an array or single string/number value." + ) if isinstance(value, list): for v in value: - self._validate_rule(v) + if v is None: + raise InvalidEventPatternException( + f"{self.error_prefix}Inside anything but list, start|null|boolean is not supported." + ) + self._validate_rule(v, from_="anything-but") return diff --git a/localstack-core/localstack/services/events/models.py b/localstack-core/localstack/services/events/models.py index 6d62e5f05045a..dfff8f2d34177 100644 --- a/localstack-core/localstack/services/events/models.py +++ b/localstack-core/localstack/services/events/models.py @@ -2,7 +2,7 @@ from dataclasses import dataclass, field from datetime import UTC, datetime from enum import Enum -from typing import Literal, TypeAlias, TypedDict +from typing import Any, TypedDict from localstack.aws.api import CommonServiceException from localstack.aws.api.events import ( @@ -27,7 +27,6 @@ EventPattern, EventResourceList, EventSourceName, - EventTime, HttpsEndpoint, ManagedBy, ReplayDescription, @@ -87,10 +86,10 @@ def __init__(self, reason=None, message=None) -> None: "detail-type": str | None, "source": EventSourceName | None, "account": str, - "time": EventTime, + "time": str, "region": str, "resources": EventResourceList | None, - "detail": dict[str, str | dict], + "detail": dict[str, Any], "replay-name": ReplayName | None, "event-bus-name": EventBusName, }, @@ -100,7 +99,7 @@ def __init__(self, reason=None, message=None) -> None: FormattedEventDict = dict[str, FormattedEvent] FormattedEventList = list[FormattedEvent] -TransformedEvent: TypeAlias = FormattedEvent | dict | str +type TransformedEvent = FormattedEvent | dict | str class ResourceType(Enum): @@ -108,24 +107,9 @@ class ResourceType(Enum): RULE = "rule" -class Condition(TypedDict): - Type: Literal["StringEquals"] - Key: Literal["aws:PrincipalOrgID"] - Value: str - - -class Statement(TypedDict): - Sid: str - Effect: str - Principal: str | dict[str, str] - Action: str - Resource: str - Condition: Condition - - class ResourcePolicy(TypedDict): Version: str - Statement: list[Statement] + Statement: list[dict[str, Any]] @dataclass @@ -191,13 +175,14 @@ class Archive: region: str account_id: str event_source_arn: Arn - description: ArchiveDescription = None - event_pattern: EventPattern = None - retention_days: RetentionDays = None - state: ArchiveState = ArchiveState.DISABLED - creation_time: Timestamp = None - size_bytes: int = 0 # TODO how to deal with updating this value? - events: FormattedEventDict = field(default_factory=dict) + description: ArchiveDescription | None = None + event_pattern: EventPattern | None = None + retention_days: RetentionDays | None = None + state: ArchiveState = field(init=False, default=ArchiveState.DISABLED) + creation_time: Timestamp = field(init=False, default_factory=lambda: datetime.now(UTC)) + events: FormattedEventDict = field(init=False, default_factory=dict) + # TODO how to deal with updating this value? + size_bytes: int = field(init=False, default=0) @property def arn(self) -> Arn: @@ -221,12 +206,10 @@ class EventBus: tags: TagList = field(default_factory=list) policy: ResourcePolicy | None = None rules: RuleDict = field(default_factory=dict) - creation_time: Timestamp = field(init=False) - last_modified_time: Timestamp = field(init=False) + creation_time: Timestamp = field(init=False, default_factory=lambda: datetime.now(UTC)) + last_modified_time: Timestamp = field(init=False, default_factory=lambda: datetime.now(UTC)) def __post_init__(self): - self.creation_time = datetime.now(UTC) - self.last_modified_time = datetime.now(UTC) if self.rules is None: self.rules = {} if self.tags is None: @@ -251,17 +234,13 @@ class Connection: secret_arn: Arn description: ConnectionDescription | None = None invocation_connectivity_parameters: ConnectivityResourceParameters | None = None - creation_time: Timestamp = field(init=False) - last_modified_time: Timestamp = field(init=False) - last_authorized_time: Timestamp = field(init=False) + creation_time: Timestamp = field(init=False, default_factory=lambda: datetime.now(UTC)) + last_modified_time: Timestamp = field(init=False, default_factory=lambda: datetime.now(UTC)) + last_authorized_time: Timestamp = field(init=False, default_factory=lambda: datetime.now(UTC)) tags: TagList = field(default_factory=list) id: str = str(uuid.uuid4()) def __post_init__(self): - timestamp_now = datetime.now(UTC) - self.creation_time = timestamp_now - self.last_modified_time = timestamp_now - self.last_authorized_time = timestamp_now if self.tags is None: self.tags = [] @@ -284,17 +263,13 @@ class ApiDestination: state: ApiDestinationState _invocation_rate_limit_per_second: ApiDestinationInvocationRateLimitPerSecond | None = None description: ApiDestinationDescription | None = None - creation_time: Timestamp = field(init=False) - last_modified_time: Timestamp = field(init=False) - last_authorized_time: Timestamp = field(init=False) + creation_time: Timestamp = field(init=False, default_factory=lambda: datetime.now(UTC)) + last_modified_time: Timestamp = field(init=False, default_factory=lambda: datetime.now(UTC)) + last_authorized_time: Timestamp = field(init=False, default_factory=lambda: datetime.now(UTC)) tags: TagList = field(default_factory=list) id: str = str(short_uid()) def __post_init__(self): - timestamp_now = datetime.now(UTC) - self.creation_time = timestamp_now - self.last_modified_time = timestamp_now - self.last_authorized_time = timestamp_now if self.tags is None: self.tags = [] diff --git a/localstack-core/localstack/services/events/provider.py b/localstack-core/localstack/services/events/provider.py index 2226a6ef41b44..de561563f9ae9 100644 --- a/localstack-core/localstack/services/events/provider.py +++ b/localstack-core/localstack/services/events/provider.py @@ -168,9 +168,11 @@ recursive_remove_none_values_from_dict, ) from localstack.services.plugins import ServiceLifecycleHook +from localstack.state import StateVisitor from localstack.utils.common import truncate from localstack.utils.event_matcher import matches_event from localstack.utils.strings import long_uid +from localstack.utils.threads import start_worker_thread from localstack.utils.time import TIMESTAMP_FORMAT_TZ, timestamp from localstack.utils.xray.trace_header import TraceHeader @@ -246,6 +248,9 @@ def __init__(self): self._connection_service_store: ConnectionServiceDict = {} self._api_destination_service_store: ApiDestinationServiceDict = {} + def accept_state_visitor(self, visitor: StateVisitor): + visitor.visit(events_stores) + def on_before_start(self): JobScheduler.start() @@ -1899,13 +1904,19 @@ def _process_entry( # Always add the successful EventId entry, even if target processing might fail processed_entries.append({"EventId": event_formatted["id"]}) + # Process rules asynchronously to match AWS behavior where put-events returns immediately if configured_rules := list(event_bus.rules.values()): - for rule in configured_rules: - if rule.schedule_expression: - # we do not want to execute Scheduled Rules on PutEvents - continue - - self._process_rules(rule, region, account_id, event_formatted, trace_header) + start_worker_thread( + self._process_rules_async, + params={ + "rules": configured_rules, + "region": region, + "account_id": account_id, + "event_formatted": event_formatted, + "trace_header": trace_header, + }, + name="events-process-rules", + ) else: LOG.info( json.dumps( @@ -1922,6 +1933,27 @@ def _proxy_capture_input_event( # only required for EventStudio to capture input event if no rule is configured pass + def _process_rules_async(self, params: dict) -> None: + """Process rules asynchronously in a background thread. + + TODO: Use a worker pool (similar to SNS) instead of spawning a new thread + for each request to improve performance and resource management. + """ + rules = params["rules"] + region = params["region"] + account_id = params["account_id"] + event_formatted = params["event_formatted"] + trace_header = params["trace_header"] + + for rule in rules: + if rule.schedule_expression: + # we do not want to execute Scheduled Rules on PutEvents + continue + + # TODO: Process each rule asynchronously instead of sequentially to further + # improve performance when multiple rules need to be evaluated. + self._process_rules(rule, region, account_id, event_formatted, trace_header) + def _process_rules( self, rule: Rule, @@ -1979,7 +2011,7 @@ def _process_rules( ) ) else: - LOG.info( + LOG.debug( json.dumps( { "InfoCode": "InternalInfoEvents at matches_rule", diff --git a/localstack-core/localstack/services/events/rule.py b/localstack-core/localstack/services/events/rule.py index 853005d8e3f2a..c43cbee079527 100644 --- a/localstack-core/localstack/services/events/rule.py +++ b/localstack-core/localstack/services/events/rule.py @@ -24,11 +24,11 @@ TARGET_ID_REGEX = re.compile(r"^[\.\-_A-Za-z0-9]+$") TARGET_ARN_REGEX = re.compile(r"arn:[\d\w:\-/]*") -CRON_REGEX = ( # borrowed from https://regex101.com/r/I80Eu0/1 - r"^(?:cron[(](?:(?:(?:[0-5]?[0-9])|[*])(?:(?:[-](?:(?:[0-5]?[0-9])|[*]))|(?:[/][0-9]+))?" - r"(?:[,](?:(?:[0-5]?[0-9])|[*])(?:(?:[-](?:(?:[0-5]?[0-9])|[*]))|(?:[/][0-9]+))?)*)[ ]+" - r"(?:(?:(?:[0-2]?[0-9])|[*])(?:(?:[-](?:(?:[0-2]?[0-9])|[*]))|(?:[/][0-9]+))?" - r"(?:[,](?:(?:[0-2]?[0-9])|[*])(?:(?:[-](?:(?:[0-2]?[0-9])|[*]))|(?:[/][0-9]+))?)*)[ ]+" +CRON_REGEX = ( # based on https://regex101.com/r/I80Eu0/1, fixed to allow range/step combined (e.g. 0-15/5) + r"^(?:cron[(](?:(?:(?:[0-5]?[0-9])|[*])(?:[-](?:(?:[0-5]?[0-9])|[*]))?(?:[/][0-9]+)?" # minutes + r"(?:[,](?:(?:[0-5]?[0-9])|[*])(?:[-](?:(?:[0-5]?[0-9])|[*]))?(?:[/][0-9]+)?)*)[ ]+" + r"(?:(?:(?:[0-2]?[0-9])|[*])(?:[-](?:(?:[0-2]?[0-9])|[*]))?(?:[/][0-9]+)?" # hours + r"(?:[,](?:(?:[0-2]?[0-9])|[*])(?:[-](?:(?:[0-2]?[0-9])|[*]))?(?:[/][0-9]+)?)*)[ ]+" r"(?:(?:[?][ ]+(?:(?:(?:[1]?[0-9])|(?:JAN|FEB|MAR|APR|MAY|JUN|JUL|AUG|SEP|OCT|NOV|DEC)|[*])" r"(?:(?:[-](?:(?:[1]?[0-9])|(?:JAN|FEB|MAR|APR|MAY|JUN|JUL|AUG|SEP|OCT|NOV|DEC)|[*])(?:[/][0-9]+)?)|" r"(?:[/][0-9]+))?(?:[,](?:(?:[1]?[0-9])|(?:JAN|FEB|MAR|APR|MAY|JUN|JUL|AUG|SEP|OCT|NOV|DEC)|[*])" diff --git a/localstack-core/localstack/services/events/target.py b/localstack-core/localstack/services/events/target.py index 6ab0c6a7a2aaf..70b2ad7d3428a 100644 --- a/localstack-core/localstack/services/events/target.py +++ b/localstack-core/localstack/services/events/target.py @@ -90,11 +90,20 @@ def get_template_replacements( return template_replacements -def replace_template_placeholders( - template: str, replacements: dict[str, Any], is_json_template: bool -) -> TransformedEvent: - """Replace placeholders defined by in the template with the values from the replacements dict. - Can handle single template string or template dict.""" +def replace_template_placeholders(template: str, replacements: dict[str, Any]) -> TransformedEvent: + """ + Replaces placeholders in an EventBridge-style InputTemplate string. + + :param template: The template string containing placeholders like ``<$.foo.bar>``. + :type template: str + :param replacements: A dictionary providing values to fill in. + :type replacements: dict + :returns: The transformed string with placeholders replaced by values from ``replacements``. + :rtype: str + """ + + ... + is_json_template = template.strip().startswith("{") def replace_placeholder(match): key = match.group(1) @@ -110,6 +119,8 @@ def replace_placeholder(match): if is_json_template: return json.dumps(value) return f"[{','.join(value)}]" + if isinstance(value, bool): + return json.dumps(value) if is_nested_in_string(template, match): return value if is_json_template: @@ -222,10 +233,7 @@ def transform_event_with_target_input_transformer( predefined_template_replacements = self._get_predefined_template_replacements(event) template_replacements.update(predefined_template_replacements) - is_json_template = input_template.strip().startswith("{") - populated_template = replace_template_placeholders( - input_template, template_replacements, is_json_template - ) + populated_template = replace_template_placeholders(input_template, template_replacements) return populated_template diff --git a/localstack-core/localstack/services/events/v1/provider.py b/localstack-core/localstack/services/events/v1/provider.py index 9c0352a1aa76b..15716399b47c1 100644 --- a/localstack-core/localstack/services/events/v1/provider.py +++ b/localstack-core/localstack/services/events/v1/provider.py @@ -45,6 +45,7 @@ from localstack.services.events.v1.models import EventsStore, events_stores from localstack.services.moto import call_moto from localstack.services.plugins import ServiceLifecycleHook +from localstack.state import StateVisitor from localstack.utils.aws.arns import event_bus_arn, parse_arn from localstack.utils.aws.client_types import ServicePrincipal from localstack.utils.aws.message_forwarding import send_event_to_target @@ -83,6 +84,14 @@ def on_before_start(self): def on_before_stop(self): JobScheduler.shutdown() + def accept_state_visitor(self, visitor: StateVisitor): + from moto.events.models import events_backends + + from localstack.services.events.v1.models import events_stores + + visitor.visit(events_backends) + visitor.visit(events_stores) + @route("/_aws/events/rules//trigger") def trigger_scheduled_rule(self, request: Request, rule_arn: str): """Developer endpoint to trigger a scheduled rule.""" diff --git a/localstack-core/localstack/services/firehose/models.py b/localstack-core/localstack/services/firehose/models.py index f4e1a665e3c65..77d05b8a607ac 100644 --- a/localstack-core/localstack/services/firehose/models.py +++ b/localstack-core/localstack/services/firehose/models.py @@ -2,18 +2,17 @@ from localstack.services.stores import ( AccountRegionBundle, BaseStore, - CrossRegionAttribute, LocalAttribute, ) -from localstack.utils.tagging import TaggingService +from localstack.utils.tagging import Tags class FirehoseStore(BaseStore): # maps delivery stream names to DeliveryStreamDescription delivery_streams: dict[str, DeliveryStreamDescription] = LocalAttribute(default=dict) - # static tagging service instance - TAGS = CrossRegionAttribute(default=TaggingService) + # resource tags + tags: Tags = LocalAttribute(default=Tags) firehose_stores = AccountRegionBundle("firehose", FirehoseStore) diff --git a/localstack-core/localstack/services/firehose/provider.py b/localstack-core/localstack/services/firehose/provider.py index 788300470d1f2..a38c8e447c9ce 100644 --- a/localstack-core/localstack/services/firehose/provider.py +++ b/localstack-core/localstack/services/firehose/provider.py @@ -52,7 +52,6 @@ ListDeliveryStreamsOutput, ListTagsForDeliveryStreamInputLimit, ListTagsForDeliveryStreamOutput, - ListTagsForDeliveryStreamOutputTagList, MSKSourceConfiguration, PutRecordBatchOutput, PutRecordBatchRequestEntryList, @@ -94,6 +93,7 @@ convert_source_config_to_desc, ) from localstack.services.firehose.models import FirehoseStore, firehose_stores +from localstack.state import StateVisitor from localstack.utils.aws.arns import ( extract_account_id_from_arn, extract_region_from_arn, @@ -117,6 +117,7 @@ from localstack.utils.kinesis import kinesis_connector from localstack.utils.kinesis.kinesis_connector import KinesisProcessorThread from localstack.utils.run import run_for_max_seconds +from localstack.utils.tagging import tag_list_to_map, tag_map_to_list LOG = logging.getLogger(__name__) @@ -251,8 +252,12 @@ class FirehoseProvider(FirehoseApi): def __init__(self) -> None: super().__init__() + # TODO: stop/restart the kinesis listeners when stopping the service / reset the state / restore the state self.kinesis_listeners = {} + def accept_state_visitor(self, visitor: StateVisitor): + visitor.visit(firehose_stores) + @staticmethod def get_store(account_id: str, region_name: str) -> FirehoseStore: return firehose_stores[account_id][region_name] @@ -403,7 +408,9 @@ def _startup(): run_for_max_seconds(25, _startup) - store.TAGS.tag_resource(delivery_stream_arn, tags) + if tags: + tag_map = tag_list_to_map(tags) + store.tags.update_tags(delivery_stream_arn, tag_map) store.delivery_streams[delivery_stream_name] = stream return CreateDeliveryStreamOutput(DeliveryStreamARN=stream["DeliveryStreamARN"]) @@ -431,6 +438,8 @@ def delete_delivery_stream( LOG.debug("Stopping kinesis listener for %s", delivery_stream_name) kinesis_process.stop() + store.tags.delete_all_tags(delivery_stream_arn) + return DeleteDeliveryStreamOutput() def describe_delivery_stream( @@ -503,7 +512,8 @@ def tag_delivery_stream( delivery_stream_description = _get_description_or_raise_not_found( context, delivery_stream_name ) - store.TAGS.tag_resource(delivery_stream_description["DeliveryStreamARN"], tags) + tag_map = tag_list_to_map(tags) + store.tags.update_tags(delivery_stream_description["DeliveryStreamARN"], tag_map) return ListTagsForDeliveryStreamOutput() def list_tags_for_delivery_stream( @@ -518,12 +528,8 @@ def list_tags_for_delivery_stream( delivery_stream_description = _get_description_or_raise_not_found( context, delivery_stream_name ) - # The tagging service returns a dictionary with the given root name - tags = store.TAGS.list_tags_for_resource( - arn=delivery_stream_description["DeliveryStreamARN"], root_name="root" - ) - # Extract the actual list of tags for the typed response - tag_list: ListTagsForDeliveryStreamOutputTagList = tags["root"] + tag_map = store.tags.get_tags(delivery_stream_description["DeliveryStreamARN"]) + tag_list = tag_map_to_list(tag_map) return ListTagsForDeliveryStreamOutput(Tags=tag_list, HasMoreTags=False) def untag_delivery_stream( @@ -537,10 +543,7 @@ def untag_delivery_stream( delivery_stream_description = _get_description_or_raise_not_found( context, delivery_stream_name ) - # The tagging service returns a dictionary with the given root name - store.TAGS.untag_resource( - arn=delivery_stream_description["DeliveryStreamARN"], tag_names=tag_keys - ) + store.tags.delete_tags(delivery_stream_description["DeliveryStreamARN"], tag_keys) return UntagDeliveryStreamOutput() def update_destination( diff --git a/localstack-core/localstack/services/iam/provider.py b/localstack-core/localstack/services/iam/provider.py index 9f90f37d3d7b7..e62b43f503894 100644 --- a/localstack-core/localstack/services/iam/provider.py +++ b/localstack-core/localstack/services/iam/provider.py @@ -20,10 +20,7 @@ from localstack.aws.api import CommonServiceException, RequestContext, handler from localstack.aws.api.iam import ( - ActionNameListType, - ActionNameType, AttachedPermissionsBoundary, - ContextEntryListType, CreateRoleRequest, CreateRoleResponse, CreateServiceLinkedRoleResponse, @@ -33,7 +30,6 @@ DeleteServiceLinkedRoleResponse, DeletionTaskIdType, DeletionTaskStatusType, - EvaluationResult, GetServiceLinkedRoleDeletionStatusResponse, GetUserResponse, IamApi, @@ -43,16 +39,12 @@ ListServiceSpecificCredentialsResponse, MalformedPolicyDocumentException, NoSuchEntityException, - PolicyEvaluationDecisionType, ResetServiceSpecificCredentialResponse, - ResourceHandlingOptionType, - ResourceNameListType, - ResourceNameType, Role, ServiceSpecificCredential, ServiceSpecificCredentialMetadata, SimulatePolicyResponse, - SimulationPolicyListType, + SimulatePrincipalPolicyRequest, User, allUsers, arnType, @@ -65,7 +57,6 @@ maxItemsType, pathPrefixType, pathType, - policyDocumentType, roleDescriptionType, roleNameType, serviceName, @@ -78,8 +69,13 @@ from localstack.aws.connect import connect_to from localstack.constants import INTERNAL_AWS_SECRET_ACCESS_KEY from localstack.services.iam.iam_patches import apply_iam_patches +from localstack.services.iam.resources.policy_simulator import ( + BasicIAMPolicySimulator, + IAMPolicySimulator, +) from localstack.services.iam.resources.service_linked_roles import SERVICE_LINKED_ROLES from localstack.services.moto import call_moto +from localstack.state import StateVisitor from localstack.utils.aws.request_context import extract_access_key_id_from_auth_header LOG = logging.getLogger(__name__) @@ -108,58 +104,15 @@ def get_iam_backend(context: RequestContext) -> IAMBackend: return iam_backends[context.account_id][context.partition] -def get_policies_from_principal(backend: IAMBackend, principal_arn: str) -> list[dict]: - policies = [] - if ":role" in principal_arn: - role_name = principal_arn.split("/")[-1] - - policies.append(backend.get_role(role_name=role_name).assume_role_policy_document) - - policy_names = backend.list_role_policies(role_name=role_name) - policies.extend( - [ - backend.get_role_policy(role_name=role_name, policy_name=policy_name)[1] - for policy_name in policy_names - ] - ) - - attached_policies, _ = backend.list_attached_role_policies(role_name=role_name) - policies.extend([policy.document for policy in attached_policies]) - - if ":group" in principal_arn: - print(principal_arn) - group_name = principal_arn.split("/")[-1] - policy_names = backend.list_group_policies(group_name=group_name) - policies.extend( - [ - backend.get_group_policy(group_name=group_name, policy_name=policy_name)[1] - for policy_name in policy_names - ] - ) - - attached_policies, _ = backend.list_attached_group_policies(group_name=group_name) - policies.extend([policy.document for policy in attached_policies]) - - if ":user" in principal_arn: - print(principal_arn) - user_name = principal_arn.split("/")[-1] - policy_names = backend.list_user_policies(user_name=user_name) - policies.extend( - [ - backend.get_user_policy(user_name=user_name, policy_name=policy_name)[1] - for policy_name in policy_names - ] - ) - - attached_policies, _ = backend.list_attached_user_policies(user_name=user_name) - policies.extend([policy.document for policy in attached_policies]) - - return policies - - class IamProvider(IamApi): + policy_simulator: IAMPolicySimulator + def __init__(self): apply_iam_patches() + self.policy_simulator = BasicIAMPolicySimulator() + + def accept_state_visitor(self, visitor: StateVisitor): + visitor.visit(iam_backends) @handler("CreateRole", expand=False) def create_role( @@ -181,68 +134,14 @@ def create_role( return result - @staticmethod - def build_evaluation_result( - action_name: ActionNameType, resource_name: ResourceNameType, policy_statements: list[dict] - ) -> EvaluationResult: - eval_res = EvaluationResult() - eval_res["EvalActionName"] = action_name - eval_res["EvalResourceName"] = resource_name - eval_res["EvalDecision"] = PolicyEvaluationDecisionType.explicitDeny - for statement in policy_statements: - # TODO Implement evaluation logic here - if ( - action_name in statement["Action"] - and resource_name in statement["Resource"] - and statement["Effect"] == "Allow" - ): - eval_res["EvalDecision"] = PolicyEvaluationDecisionType.allowed - eval_res["MatchedStatements"] = [] # TODO: add support for statement compilation. - return eval_res - + @handler("SimulatePrincipalPolicy", expand=False) def simulate_principal_policy( self, context: RequestContext, - policy_source_arn: arnType, - action_names: ActionNameListType, - policy_input_list: SimulationPolicyListType = None, - permissions_boundary_policy_input_list: SimulationPolicyListType = None, - resource_arns: ResourceNameListType = None, - resource_policy: policyDocumentType = None, - resource_owner: ResourceNameType = None, - caller_arn: ResourceNameType = None, - context_entries: ContextEntryListType = None, - resource_handling_option: ResourceHandlingOptionType = None, - max_items: maxItemsType = None, - marker: markerType = None, + request: SimulatePrincipalPolicyRequest, **kwargs, ) -> SimulatePolicyResponse: - backend = get_iam_backend(context) - - policies = get_policies_from_principal(backend, policy_source_arn) - - def _get_statements_from_policy_list(policies: list[str]): - statements = [] - for policy_str in policies: - policy_dict = json.loads(policy_str) - if isinstance(policy_dict["Statement"], list): - statements.extend(policy_dict["Statement"]) - else: - statements.append(policy_dict["Statement"]) - return statements - - policy_statements = _get_statements_from_policy_list(policies) - - evaluations = [ - self.build_evaluation_result(action_name, resource_arn, policy_statements) - for action_name in action_names - for resource_arn in resource_arns - ] - - response = SimulatePolicyResponse() - response["IsTruncated"] = False - response["EvaluationResults"] = evaluations - return response + return self.policy_simulator.simulate_principal_policy(context, request) def delete_policy(self, context: RequestContext, policy_arn: arnType, **kwargs) -> None: backend = get_iam_backend(context) diff --git a/localstack-core/localstack/services/iam/resource_providers/aws_iam_managedpolicy.py b/localstack-core/localstack/services/iam/resource_providers/aws_iam_managedpolicy.py index b85f0997e79ed..3bebb37a28191 100644 --- a/localstack-core/localstack/services/iam/resource_providers/aws_iam_managedpolicy.py +++ b/localstack-core/localstack/services/iam/resource_providers/aws_iam_managedpolicy.py @@ -61,7 +61,13 @@ def create( group_name = util.generate_default_name(request.stack_name, request.logical_resource_id) model["ManagedPolicyName"] = group_name - policy_doc = json.dumps(util.remove_none_values(model["PolicyDocument"])) + # PolicyDocument can be either a dict or a JSON string (e.g., from Fn::Sub) + policy_document = model["PolicyDocument"] + if isinstance(policy_document, str): + policy_doc = policy_document + else: + policy_doc = json.dumps(util.remove_none_values(policy_document)) + policy = iam_client.create_policy( PolicyName=model["ManagedPolicyName"], PolicyDocument=policy_doc ) diff --git a/localstack-core/localstack/services/iam/resource_providers/aws_iam_policy.py b/localstack-core/localstack/services/iam/resource_providers/aws_iam_policy.py index 9273bb31d9597..61a16551ec793 100644 --- a/localstack-core/localstack/services/iam/resource_providers/aws_iam_policy.py +++ b/localstack-core/localstack/services/iam/resource_providers/aws_iam_policy.py @@ -53,7 +53,13 @@ def create( model = request.desired_state iam_client = request.aws_client_factory.iam - policy_doc = json.dumps(util.remove_none_values(model["PolicyDocument"])) + # PolicyDocument can be either a dict or a JSON string (e.g., from Fn::Sub) + policy_document = model["PolicyDocument"] + if isinstance(policy_document, str): + policy_doc = policy_document + else: + policy_doc = json.dumps(util.remove_none_values(policy_document)) + policy_name = model["PolicyName"] if not any([model.get("Roles"), model.get("Users"), model.get("Groups")]): @@ -122,7 +128,14 @@ def update( iam_client = request.aws_client_factory.iam model = request.desired_state # FIXME: this wasn't properly implemented before as well, still needs to be rewritten - policy_doc = json.dumps(util.remove_none_values(model["PolicyDocument"])) + + # PolicyDocument can be either a dict or a JSON string (e.g., from Fn::Sub) + policy_document = model["PolicyDocument"] + if isinstance(policy_document, str): + policy_doc = policy_document + else: + policy_doc = json.dumps(util.remove_none_values(policy_document)) + policy_name = model["PolicyName"] for role in model.get("Roles", []): diff --git a/localstack-core/localstack/services/iam/resources/policy_simulator.py b/localstack-core/localstack/services/iam/resources/policy_simulator.py new file mode 100644 index 0000000000000..341ace67bc482 --- /dev/null +++ b/localstack-core/localstack/services/iam/resources/policy_simulator.py @@ -0,0 +1,133 @@ +import abc +import json + +from moto.iam import iam_backends +from moto.iam.models import IAMBackend + +from localstack.aws.api import RequestContext +from localstack.aws.api.iam import ( + ActionNameType, + EvaluationResult, + PolicyEvaluationDecisionType, + ResourceNameType, + SimulatePolicyResponse, + SimulatePrincipalPolicyRequest, +) + + +class IAMPolicySimulator(abc.ABC): + @abc.abstractmethod + def simulate_principal_policy( + self, context: RequestContext, request: SimulatePrincipalPolicyRequest + ) -> SimulatePolicyResponse: + """ + Simulate principal policy + :param request: SimulatePrincipalPolicyRequest + :param context: RequestContext + :return: SimulatePrincipalResponse + """ + pass + + +class BasicIAMPolicySimulator(IAMPolicySimulator): + def simulate_principal_policy( + self, + context: RequestContext, + request: SimulatePrincipalPolicyRequest, + ) -> SimulatePolicyResponse: + backend = self.get_iam_backend(context) + policies = self.get_policies_from_principal(backend, request.get("PolicySourceArn")) + + def _get_statements_from_policy_list(_policies: list[str]): + statements = [] + for policy_str in _policies: + policy_dict = json.loads(policy_str) + if isinstance(policy_dict["Statement"], list): + statements.extend(policy_dict["Statement"]) + else: + statements.append(policy_dict["Statement"]) + return statements + + policy_statements = _get_statements_from_policy_list(policies) + + evaluations = [ + self.build_evaluation_result(action_name, resource_arn, policy_statements) + for action_name in request.get("ActionNames") + for resource_arn in request.get("ResourceArns") + ] + + response = SimulatePolicyResponse() + response["IsTruncated"] = False + response["EvaluationResults"] = evaluations + + return response + + @staticmethod + def build_evaluation_result( + action_name: ActionNameType, resource_name: ResourceNameType, policy_statements: list[dict] + ) -> EvaluationResult: + eval_res = EvaluationResult() + eval_res["EvalActionName"] = action_name + eval_res["EvalResourceName"] = resource_name + eval_res["EvalDecision"] = PolicyEvaluationDecisionType.explicitDeny + for statement in policy_statements: + # TODO Implement evaluation logic here + if ( + action_name in statement["Action"] + and resource_name in statement["Resource"] + and statement["Effect"] == "Allow" + ): + eval_res["EvalDecision"] = PolicyEvaluationDecisionType.allowed + eval_res["MatchedStatements"] = [] # TODO: add support for statement compilation. + return eval_res + + @staticmethod + def get_iam_backend(context: RequestContext) -> IAMBackend: + return iam_backends[context.account_id][context.partition] + + @staticmethod + def get_policies_from_principal(backend: IAMBackend, principal_arn: str) -> list[dict]: + policies = [] + if ":role" in principal_arn: + role_name = principal_arn.split("/")[-1] + + policies.append(backend.get_role(role_name=role_name).assume_role_policy_document) + + policy_names = backend.list_role_policies(role_name=role_name) + policies.extend( + [ + backend.get_role_policy(role_name=role_name, policy_name=policy_name)[1] + for policy_name in policy_names + ] + ) + + attached_policies, _ = backend.list_attached_role_policies(role_name=role_name) + policies.extend([policy.document for policy in attached_policies]) + + if ":group" in principal_arn: + group_name = principal_arn.split("/")[-1] + policy_names = backend.list_group_policies(group_name=group_name) + policies.extend( + [ + backend.get_group_policy(group_name=group_name, policy_name=policy_name)[1] + for policy_name in policy_names + ] + ) + + attached_policies, _ = backend.list_attached_group_policies(group_name=group_name) + policies.extend([policy.document for policy in attached_policies]) + + if ":user" in principal_arn: + user_name = principal_arn.split("/")[-1] + policy_names = backend.list_user_policies(user_name=user_name) + policies.extend( + [ + backend.get_user_policy(user_name=user_name, policy_name=policy_name)[1] + for policy_name in policy_names + ] + ) + + attached_policies, _ = backend.list_attached_user_policies(user_name=user_name) + policies.extend([policy.document for policy in attached_policies]) + + return policies diff --git a/localstack-core/localstack/services/internal.py b/localstack-core/localstack/services/internal.py index 85c4de12ff351..a1b1333ce66e2 100644 --- a/localstack-core/localstack/services/internal.py +++ b/localstack-core/localstack/services/internal.py @@ -8,7 +8,6 @@ from datetime import datetime from plux import PluginManager -from werkzeug.exceptions import NotFound from localstack import config, constants from localstack.deprecations import deprecated_endpoint @@ -260,8 +259,8 @@ def on_get(self, request, stage: str): try: stage = Stage[stage.upper()] - except KeyError as e: - raise NotFound(f"no such stage {stage}") from e + except KeyError: + return Response(f"no such stage {stage}", 404) return { "completed": manager.stage_completed.get(stage), diff --git a/localstack-core/localstack/services/kinesis/packages.py b/localstack-core/localstack/services/kinesis/packages.py index 1d0615d3fc109..0f10c3d2415f5 100644 --- a/localstack-core/localstack/services/kinesis/packages.py +++ b/localstack-core/localstack/services/kinesis/packages.py @@ -7,7 +7,7 @@ from localstack.packages.core import GitHubReleaseInstaller, NodePackageInstaller from localstack.packages.java import JavaInstallerMixin, java_package -_KINESIS_MOCK_VERSION = os.environ.get("KINESIS_MOCK_VERSION") or "0.4.13" +_KINESIS_MOCK_VERSION = os.environ.get("KINESIS_MOCK_VERSION") or "0.5.2" class KinesisMockEngine(StrEnum): diff --git a/localstack-core/localstack/services/kinesis/provider.py b/localstack-core/localstack/services/kinesis/provider.py index 6c4f19f2f09da..09f8f335a6eb9 100644 --- a/localstack-core/localstack/services/kinesis/provider.py +++ b/localstack-core/localstack/services/kinesis/provider.py @@ -26,6 +26,7 @@ ShardId, StartingPosition, StreamARN, + StreamId, StreamName, SubscribeToShardEvent, SubscribeToShardEventStream, @@ -105,6 +106,7 @@ def put_resource_policy( context: RequestContext, resource_arn: ResourceARN, policy: Policy, + stream_id: StreamId | None = None, **kwargs, ) -> None: if not is_valid_kinesis_arn(resource_arn): @@ -125,6 +127,7 @@ def get_resource_policy( self, context: RequestContext, resource_arn: ResourceARN, + stream_id: StreamId | None = None, **kwargs, ) -> GetResourcePolicyOutput: if not is_valid_kinesis_arn(resource_arn): @@ -146,6 +149,7 @@ def delete_resource_policy( self, context: RequestContext, resource_arn: ResourceARN, + stream_id: StreamId | None = None, **kwargs, ) -> None: if not is_valid_kinesis_arn(resource_arn): @@ -164,6 +168,7 @@ def subscribe_to_shard( consumer_arn: ConsumerARN, shard_id: ShardId, starting_position: StartingPosition, + stream_id: StreamId | None = None, **kwargs, ) -> SubscribeToShardOutput: kinesis = connect_to( @@ -234,6 +239,7 @@ def put_record( explicit_hash_key: HashKey = None, sequence_number_for_ordering: SequenceNumber = None, stream_arn: StreamARN = None, + stream_id: StreamId | None = None, **kwargs, ) -> PutRecordOutput: # TODO: Ensure use of `stream_arn` works. Currently kinesis-mock only works with ctx request account ID and region @@ -251,6 +257,7 @@ def put_records( records: PutRecordsRequestEntryList, stream_name: StreamName = None, stream_arn: StreamARN = None, + stream_id: StreamId | None = None, **kwargs, ) -> PutRecordsOutput: # TODO: Ensure use of `stream_arn` works. Currently kinesis-mock only works with ctx request account ID and region diff --git a/localstack-core/localstack/services/kms/models.py b/localstack-core/localstack/services/kms/models.py index f28d2995edd7d..2f1334801433a 100644 --- a/localstack-core/localstack/services/kms/models.py +++ b/localstack-core/localstack/services/kms/models.py @@ -7,6 +7,7 @@ import random import re import struct +import typing import uuid from collections import namedtuple from dataclasses import dataclass @@ -20,7 +21,6 @@ from cryptography.hazmat.primitives.asymmetric.padding import PSS, PKCS1v15 from cryptography.hazmat.primitives.asymmetric.rsa import RSAPrivateKey from cryptography.hazmat.primitives.asymmetric.utils import Prehashed -from cryptography.hazmat.primitives.kdf.hkdf import HKDF from cryptography.hazmat.primitives.serialization import load_der_public_key from localstack.aws.api.kms import ( @@ -45,16 +45,15 @@ OriginType, ReplicateKeyRequest, SigningAlgorithmSpec, - TagList, UnsupportedOperationException, ) -from localstack.constants import TAG_KEY_CUSTOM_ID -from localstack.services.kms.exceptions import TagException, ValidationException -from localstack.services.kms.utils import is_valid_key_arn, validate_tag +from localstack.services.kms.exceptions import ValidationException +from localstack.services.kms.utils import is_valid_key_arn from localstack.services.stores import AccountRegionBundle, BaseStore, LocalAttribute from localstack.utils.aws.arns import get_partition, kms_alias_arn, kms_key_arn from localstack.utils.crypto import decrypt, encrypt from localstack.utils.strings import long_uid, to_bytes, to_str +from localstack.utils.tagging import Tags LOG = logging.getLogger(__name__) @@ -114,9 +113,6 @@ # list of key names that should be skipped when serializing the encryption context IGNORED_CONTEXT_KEYS = ["aws-crypto-public-key"] -# special tag name to allow specifying a custom key material for created keys -TAG_KEY_CUSTOM_KEY_MATERIAL = "_custom_key_material_" - def _serialize_ciphertext_blob(ciphertext: Ciphertext) -> bytes: header = struct.pack( @@ -172,7 +168,8 @@ class KmsCryptoKey: public_key: bytes | None private_key: bytes | None - key_material: bytes + key_material: bytes | None + pending_key_material: bytes | None key_spec: str @staticmethod @@ -217,6 +214,7 @@ def raise_validation(): def __init__(self, key_spec: str, key_material: bytes | None = None): self.private_key = None self.public_key = None + self.pending_key_material = None # Technically, key_material, being a symmetric encryption key, is only relevant for # key_spec == SYMMETRIC_DEFAULT. # But LocalStack uses symmetric encryption with this key_material even for other specs. Asymmetric keys are @@ -231,7 +229,10 @@ def __init__(self, key_spec: str, key_material: bytes | None = None): if key_spec.startswith("RSA"): key_size = RSA_CRYPTO_KEY_LENGTHS.get(key_spec) - key = rsa.generate_private_key(public_exponent=65537, key_size=key_size) + if key_material: + key = crypto_serialization.load_der_private_key(key_material, password=None) + else: + key = rsa.generate_private_key(public_exponent=65537, key_size=key_size) elif key_spec.startswith("ECC"): curve = ECC_CURVES.get(key_spec) if key_material: @@ -248,8 +249,9 @@ def __init__(self, key_spec: str, key_material: bytes | None = None): self._serialize_key(key) def load_key_material(self, material: bytes): - if self.key_spec in [ - KeySpec.SYMMETRIC_DEFAULT, + if self.key_spec == KeySpec.SYMMETRIC_DEFAULT: + self.pending_key_material = material + elif self.key_spec in [ KeySpec.HMAC_224, KeySpec.HMAC_256, KeySpec.HMAC_384, @@ -283,30 +285,25 @@ def key(self) -> RSAPrivateKey | EllipticCurvePrivateKey: class KmsKey: metadata: KeyMetadata crypto_key: KmsCryptoKey - tags: dict[str, str] policy: str is_key_rotation_enabled: bool rotation_period_in_days: int - next_rotation_date: datetime.datetime - previous_keys = [str] + next_rotation_date: datetime.datetime | None + previous_keys: list[bytes | None] + _internal_key_id: uuid.UUID def __init__( self, create_key_request: CreateKeyRequest = None, account_id: str = None, region: str = None, + custom_key_material: bytes | None = None, + custom_key_id: str | None = None, ): create_key_request = create_key_request or CreateKeyRequest() self.previous_keys = [] - # Please keep in mind that tags of a key could be present in the request, they are not a part of metadata. At - # least in the sense of DescribeKey not returning them with the rest of the metadata. Instead, tags are more - # like aliases: - # https://docs.aws.amazon.com/kms/latest/APIReference/API_DescribeKey.html - # "DescribeKey does not return the following information: ... Tags on the KMS key." - self.tags = {} - self.add_tags(create_key_request.get("Tags")) - # Same goes for the policy. It is in the request, but not in the metadata. + # Policy is in the request but not in the metadata. self.policy = create_key_request.get("Policy") or self._get_default_key_policy( account_id, region ) @@ -315,17 +312,30 @@ def __init__( # disable it." self.is_key_rotation_enabled = False - self._populate_metadata(create_key_request, account_id, region) - custom_key_material = None - if TAG_KEY_CUSTOM_KEY_MATERIAL in self.tags: - # check if the _custom_key_material_ tag is specified, to use a custom key material for this key - custom_key_material = base64.b64decode(self.tags[TAG_KEY_CUSTOM_KEY_MATERIAL]) - # remove the _custom_key_material_ tag from the tags to not readily expose the custom key material - del self.tags[TAG_KEY_CUSTOM_KEY_MATERIAL] + self._populate_metadata(create_key_request, account_id, region, custom_key_id=custom_key_id) self.crypto_key = KmsCryptoKey(self.metadata.get("KeySpec"), custom_key_material) + self._internal_key_id = uuid.uuid4() + + # The KMS implementation always provides a crypto key with key material which doesn't suit scenarios where a + # KMS Key may have no key material e.g. for external keys. Don't expose the CurrentKeyMaterialId in those cases. + if custom_key_material or ( + self.metadata["Origin"] == "AWS_KMS" + and self.metadata["KeySpec"] == KeySpec.SYMMETRIC_DEFAULT + ): + self.metadata["CurrentKeyMaterialId"] = self.generate_key_material_id( + self.crypto_key.key_material + ) + self.rotation_period_in_days = 365 self.next_rotation_date = None + def generate_key_material_id(self, key_material: bytes) -> str: + # The KeyMaterialId depends on the key material and the KeyId. Use an internal ID to prevent brute forcing + # the value of the key material from the public KeyId and KeyMaterialId. + # https://docs.aws.amazon.com/kms/latest/APIReference/API_ImportKeyMaterial.html + key_material_id_hex = uuid.uuid5(self._internal_key_id, key_material).hex + return str(key_material_id_hex) * 2 + def calculate_and_set_arn(self, account_id, region): self.metadata["Arn"] = kms_key_arn(self.metadata.get("KeyId"), account_id, region) @@ -420,17 +430,15 @@ def verify( def derive_shared_secret(self, public_key: bytes) -> bytes: key_spec = self.metadata.get("KeySpec") - match key_spec: - case KeySpec.ECC_NIST_P256 | KeySpec.ECC_SECG_P256K1: - algorithm = hashes.SHA256() - case KeySpec.ECC_NIST_P384: - algorithm = hashes.SHA384() - case KeySpec.ECC_NIST_P521: - algorithm = hashes.SHA512() - case _: - raise InvalidKeyUsageException( - f"{self.metadata['Arn']} key usage is {self.metadata['KeyUsage']} which is not valid for DeriveSharedSecret." - ) + if key_spec not in ( + KeySpec.ECC_NIST_P256, + KeySpec.ECC_SECG_P256K1, + KeySpec.ECC_NIST_P384, + KeySpec.ECC_NIST_P521, + ): + raise InvalidKeyUsageException( + f"{self.metadata['Arn']} key usage is {self.metadata['KeyUsage']} which is not valid for DeriveSharedSecret." + ) # Deserialize public key from DER encoded data to EllipticCurvePublicKey. try: @@ -438,14 +446,7 @@ def derive_shared_secret(self, public_key: bytes) -> bytes: except (UnsupportedAlgorithm, ValueError): raise ValidationException("") shared_secret = self.crypto_key.key.exchange(ec.ECDH(), pub_key) - # Perform shared secret derivation. - return HKDF( - algorithm=algorithm, - salt=None, - info=b"", - length=algorithm.digest_size, - backend=default_backend(), - ).derive(shared_secret) + return shared_secret # This method gets called when a key is replicated to another region. It's meant to populate the required metadata # fields in a new replica key. @@ -543,7 +544,11 @@ def _construct_sign_verify_padding( # # Data keys are symmetric, data key pairs are asymmetric. def _populate_metadata( - self, create_key_request: CreateKeyRequest, account_id: str, region: str + self, + create_key_request: CreateKeyRequest, + account_id: str, + region: str, + custom_key_id: str | None = None, ) -> None: self.metadata = KeyMetadata() # Metadata fields coming from a creation request @@ -580,9 +585,8 @@ def _populate_metadata( else KeyState.PendingImport ) - if TAG_KEY_CUSTOM_ID in self.tags: - # check if the _custom_id_ tag is specified, to set a user-defined KeyId for this key - self.metadata["KeyId"] = self.tags[TAG_KEY_CUSTOM_ID].strip() + if custom_key_id: + self.metadata["KeyId"] = custom_key_id elif self.metadata.get("MultiRegion"): # https://docs.aws.amazon.com/kms/latest/developerguide/multi-region-keys-overview.html # "Notice that multi-Region keys have a distinctive key ID that begins with mrk-. You can use the mrk- prefix to @@ -608,25 +612,6 @@ def _populate_metadata( ReplicaKeys=[], ) - def add_tags(self, tags: TagList) -> None: - # Just in case we get None from somewhere. - if not tags: - return - - unique_tag_keys = {tag["TagKey"] for tag in tags} - if len(unique_tag_keys) < len(tags): - raise TagException("Duplicate tag keys") - - if len(tags) > 50: - raise TagException("Too many tags") - - # Do not care if we overwrite an existing tag: - # https://docs.aws.amazon.com/kms/latest/APIReference/API_TagResource.html - # "To edit a tag, specify an existing tag key and a new tag value." - for i, tag in enumerate(tags, start=1): - validate_tag(i, tag) - self.tags[tag.get("TagKey")] = tag.get("TagValue") - def schedule_key_deletion(self, pending_window_in_days: int) -> None: self.metadata["Enabled"] = False # TODO For MultiRegion keys, the status of replicas get set to "PendingDeletion", while the primary key @@ -746,8 +731,16 @@ def rotate_key_on_demand(self): f"The on-demand rotations limit has been reached for the given keyId. " f"No more on-demand rotations can be performed for this key: {self.metadata['Arn']}" ) - self.previous_keys.append(self.crypto_key.key_material) - self.crypto_key = KmsCryptoKey(KeySpec.SYMMETRIC_DEFAULT) + current_key_material = self.crypto_key.key_material + pending_key_material = self.crypto_key.pending_key_material + + self.previous_keys.append(current_key_material) + + # If there is no pending material stored on the key, then key material will be generated. + self.crypto_key = KmsCryptoKey(KeySpec.SYMMETRIC_DEFAULT, pending_key_material) + self.metadata["CurrentKeyMaterialId"] = self.generate_key_material_id( + self.crypto_key.key_material + ) class KmsGrant: @@ -755,7 +748,7 @@ class KmsGrant: # keys. But, based on our understanding of AWS documentation for CreateGrant, ListGrants operations etc, # AWS has some set of fields for grants like it has for keys. So we are going to call them `metadata` here for # consistency. - metadata: dict + metadata: dict[str, typing.Any] # dumped to JSON for persistence serialization # Tokens are not a part of metadata, as their use is more limited and specific than for the rest of the # metadata: https://docs.aws.amazon.com/kms/latest/developerguide/grant-manage.html#using-grant-token # Tokens are used to refer to a grant in a short period right after the grant gets created. Normally it might @@ -800,18 +793,19 @@ def __init__(self, create_grant_request: CreateGrantRequest, account_id: str, re class KmsAlias: # Like with grants (see comment for KmsGrant), there is no mention of some specific object modeling metadata # for KMS aliases. But there is data that is some metadata, so we model it in a way similar to KeyMetadata for keys. - metadata: dict + metadata: dict[str, typing.Any] # dumped to JSON for persistence serialization def __init__( self, - create_alias_request: CreateAliasRequest = None, - account_id: str = None, - region: str = None, + create_alias_request: CreateAliasRequest | None = None, + account_id: str | None = None, + region: str | None = None, ): create_alias_request = create_alias_request or CreateAliasRequest() - self.metadata = {} - self.metadata["AliasName"] = create_alias_request.get("AliasName") - self.metadata["TargetKeyId"] = create_alias_request.get("TargetKeyId") + self.metadata = { + "AliasName": create_alias_request.get("AliasName"), + "TargetKeyId": create_alias_request.get("TargetKeyId"), + } self.update_date_of_last_update() self.metadata["CreationDate"] = self.metadata["LastUpdateDate"] self.metadata["AliasArn"] = kms_alias_arn(self.metadata["AliasName"], account_id, region) @@ -836,11 +830,9 @@ class KmsStore(BaseStore): # "Cross-account use: Yes. You can retire a grant on a KMS key in a different AWS account." # maps grant ids to grants + # TODO: KmsKey might hold the grant grants: dict[str, KmsGrant] = LocalAttribute(default=dict) - # maps from (grant names (used for idempotency), key id) to grant ids - grant_names: dict[tuple[str, str], str] = LocalAttribute(default=dict) - # maps grant tokens to grant ids grant_tokens: dict[str, str] = LocalAttribute(default=dict) @@ -850,5 +842,8 @@ class KmsStore(BaseStore): # maps import tokens to import data imports: dict[str, KeyImportState] = LocalAttribute(default=dict) + # maps key arn to tags + tags: Tags = LocalAttribute(default=Tags) + kms_stores = AccountRegionBundle("kms", KmsStore) diff --git a/localstack-core/localstack/services/kms/provider.py b/localstack-core/localstack/services/kms/provider.py index be5abc2728832..e3b8af6530b51 100644 --- a/localstack-core/localstack/services/kms/provider.py +++ b/localstack-core/localstack/services/kms/provider.py @@ -4,10 +4,13 @@ import logging import os +from cbor2 import loads as cbor2_loads from cryptography.exceptions import InvalidTag from cryptography.hazmat.backends import default_backend from cryptography.hazmat.primitives import hashes, keywrap from cryptography.hazmat.primitives.asymmetric import padding +from cryptography.hazmat.primitives.asymmetric.rsa import RSAPublicKey +from cryptography.hazmat.primitives.serialization import load_der_public_key from localstack.aws.api import CommonServiceException, RequestContext, handler from localstack.aws.api.kms import ( @@ -33,6 +36,7 @@ DisabledException, DisableKeyRequest, DisableKeyRotationRequest, + DryRunModifierList, EnableKeyRequest, EnableKeyRotationRequest, EncryptionAlgorithmSpec, @@ -103,6 +107,9 @@ ScheduleKeyDeletionResponse, SignRequest, SignResponse, + Tag, + TagKeyList, + TagList, TagResourceRequest, UnsupportedOperationException, UntagResourceRequest, @@ -130,14 +137,19 @@ ) from localstack.services.kms.utils import ( execute_dry_run_capable, + get_custom_key_id, + get_custom_key_material, is_valid_key_arn, parse_key_arn, validate_alias_name, + validate_and_filter_tags, ) from localstack.services.plugins import ServiceLifecycleHook +from localstack.state import StateVisitor from localstack.utils.aws.arns import get_partition, kms_alias_arn, parse_arn from localstack.utils.collections import PaginatedList from localstack.utils.common import select_attributes +from localstack.utils.crypto import pkcs7_envelope_encrypt from localstack.utils.strings import short_uid, to_bytes, to_str LOG = logging.getLogger(__name__) @@ -197,6 +209,9 @@ class KmsProvider(KmsApi, ServiceLifecycleHook): - VerifyMac """ + def accept_state_visitor(self, visitor: StateVisitor): + visitor.visit(kms_stores) + # # Helpers # @@ -217,7 +232,13 @@ def _create_kms_key( account_id: str, region_name: str, request: CreateKeyRequest = None ) -> KmsKey: store = kms_stores[account_id][region_name] - key = KmsKey(request, account_id, region_name) + key = KmsKey( + request, + account_id, + region_name, + get_custom_key_material(request), + get_custom_key_id(request), + ) key_id = key.metadata["KeyId"] store.keys[key_id] = key return key @@ -287,11 +308,9 @@ def _create_alias_if_reserved_and_not_exists( store = kms_stores[account_id][region_name] if alias_name not in RESERVED_ALIASES or alias_name in store.aliases: return - create_key_request = {} key_id = KmsProvider._create_kms_key( account_id, region_name, - create_key_request, ).metadata.get("KeyId") create_alias_request = CreateAliasRequest(AliasName=alias_name, TargetKeyId=key_id) KmsProvider._create_kms_alias(account_id, region_name, create_alias_request) @@ -381,6 +400,26 @@ def _parse_key_id(key_id_or_arn: str, context: RequestContext) -> tuple[str, str def _is_rsa_spec(key_spec: str) -> bool: return key_spec in [KeySpec.RSA_2048, KeySpec.RSA_3072, KeySpec.RSA_4096] + def _get_key_tags(self, account_id: str, region: str, resource_arn: str) -> TagList: + store = self._get_store(account_id, region) + return [ + Tag(TagKey=key, TagValue=value) + for key, value in store.tags.get_tags(resource_arn).items() + ] + + def _set_key_tags(self, account_id: str, region: str, resource_arn: str, tags: TagList) -> None: + validated_tags = validate_and_filter_tags(tags) + store = self._get_store(account_id, region) + store.tags.update_tags( + resource_arn, {tag["TagKey"]: tag["TagValue"] for tag in validated_tags} + ) + + def _remove_key_tags( + self, account_id: str, region: str, resource_arn: str, tag_keys: TagKeyList + ) -> None: + store = self._get_store(account_id, region) + store.tags.delete_tags(resource_arn, tag_keys) + # # Operation Handlers # @@ -391,7 +430,10 @@ def create_key( context: RequestContext, request: CreateKeyRequest = None, ) -> CreateKeyResponse: + tags = validate_and_filter_tags(request.get("Tags", [])) key = self._create_kms_key(context.account_id, context.region, request) + if tags: + self._set_key_tags(context.account_id, context.region, key.metadata["Arn"], tags) return CreateKeyResponse(KeyMetadata=key.metadata) @handler("ScheduleKeyDeletion", expand=False) @@ -518,7 +560,12 @@ def replicate_key( self.update_primary_key_with_replica_keys(primary_key, replica_key, replica_region) - return ReplicateKeyResponse(ReplicaKeyMetadata=replica_key.metadata) + # CurrentKeyMaterialId is not returned in the ReplicaKeyMetadata. May be due to not being evaluated until + # the key has been successfully replicated as it does not show up in DescribeKey immediately either. + replica_key_metadata_response = copy.deepcopy(replica_key.metadata) + replica_key_metadata_response.pop("CurrentKeyMaterialId", None) + + return ReplicateKeyResponse(ReplicaKeyMetadata=replica_key_metadata_response) @staticmethod # Adds new multi region replica key to the primary key's metadata. @@ -558,14 +605,21 @@ def create_grant( grant_name = request.get("Name") store = self._get_store(context.account_id, context.region) - if grant_name and (grant_name, key_id) in store.grant_names: - grant = store.grants[store.grant_names[(grant_name, key_id)]] - else: + + # Check for existing grant with the same name for idempotency + grant: KmsGrant | None = None + if grant_name: + for existing_grant in store.grants.values(): + if existing_grant.metadata.get("Name") != grant_name: + continue + if existing_grant.metadata.get("KeyId") == key_id: + grant = existing_grant + break + + if grant is None: grant = KmsGrant(request, context.account_id, context.region) grant_id = grant.metadata["GrantId"] store.grants[grant_id] = grant - if grant_name: - store.grant_names[(grant_name, key_id)] = grant_id store.grant_tokens[grant.token] = grant_id # At the moment we do not support multiple GrantTokens for grant creation request. Instead, we always use @@ -630,7 +684,6 @@ def _delete_grant(store: KmsStore, grant_id: str, key_id: str): raise ValidationError(f"Invalid KeyId={key_id} specified for grant {grant_id}") store.grant_tokens.pop(grant.token) - store.grant_names.pop((grant.metadata.get("Name"), key_id), None) store.grants.pop(grant_id) def revoke_grant( @@ -956,15 +1009,16 @@ def verify(self, context: RequestContext, request: VerifyRequest) -> VerifyRespo def re_encrypt( self, context: RequestContext, - ciphertext_blob: CiphertextType, destination_key_id: KeyIdType, - source_encryption_context: EncryptionContextType = None, - source_key_id: KeyIdType = None, - destination_encryption_context: EncryptionContextType = None, - source_encryption_algorithm: EncryptionAlgorithmSpec = None, - destination_encryption_algorithm: EncryptionAlgorithmSpec = None, - grant_tokens: GrantTokenList = None, - dry_run: NullableBooleanType = None, + ciphertext_blob: CiphertextType | None = None, + source_encryption_context: EncryptionContextType | None = None, + source_key_id: KeyIdType | None = None, + destination_encryption_context: EncryptionContextType | None = None, + source_encryption_algorithm: EncryptionAlgorithmSpec | None = None, + destination_encryption_algorithm: EncryptionAlgorithmSpec | None = None, + grant_tokens: GrantTokenList | None = None, + dry_run: NullableBooleanType | None = None, + dry_run_modifiers: DryRunModifierList | None = None, **kwargs, ) -> ReEncryptResponse: # TODO: when implementing, ensure cross-account support for source_key_id and destination_key_id @@ -1034,13 +1088,14 @@ def encrypt( def decrypt( self, context: RequestContext, - ciphertext_blob: CiphertextType, - encryption_context: EncryptionContextType = None, - grant_tokens: GrantTokenList = None, - key_id: KeyIdType = None, - encryption_algorithm: EncryptionAlgorithmSpec = None, - recipient: RecipientInfo = None, - dry_run: NullableBooleanType = None, + ciphertext_blob: CiphertextType | None = None, + encryption_context: EncryptionContextType | None = None, + grant_tokens: GrantTokenList | None = None, + key_id: KeyIdType | None = None, + encryption_algorithm: EncryptionAlgorithmSpec | None = None, + recipient: RecipientInfo | None = None, + dry_run: NullableBooleanType | None = None, + dry_run_modifiers: DryRunModifierList | None = None, **kwargs, ) -> DecryptResponse: # In AWS, key_id is only supplied for data encrypted with an asymmetrical algorithm. For symmetrical @@ -1075,6 +1130,25 @@ def decrypt( self._validate_key_for_encryption_decryption(context, key) self._validate_key_state_not_pending_import(key) + # Handle the recipient field. This is used by AWS Nitro to re-encrypt the plaintext to the key specified + # by the enclave. Proper support for this will take significant work to figure out how to model enforcing + # the attestation measurements; for now, if recipient is specified and has an attestation doc in it including + # a public key where it's expected to be, we encrypt to that public key. This at least allows users to use + # localstack as a drop-in replacement for AWS when testing without having to skip the secondary decryption + # when using localstack. + recipient_pubkey = None + if recipient: + attestation_document = recipient["AttestationDocument"] + # We do all of this in a try/catch and warn if it fails so that if users are currently passing a nonsense + # value we don't break it for them. In the future we could do a breaking change to require a valid attestation + # (or at least one that contains the public key). + try: + recipient_pubkey = self._extract_attestation_pubkey(attestation_document) + except Exception as e: + logging.warning( + "Unable to extract public key from non-empty attestation document: %s", e + ) + try: # TODO: Extend the implementation to handle additional encryption/decryption scenarios # beyond the current support for offline encryption and online decryption using RSA keys if key id exists in @@ -1088,20 +1162,27 @@ def decrypt( plaintext = key.decrypt(ciphertext, encryption_context) except InvalidTag: raise InvalidCiphertextException() + # For compatibility, we return EncryptionAlgorithm values expected from AWS. But LocalStack currently always # encrypts with symmetric encryption no matter the key settings. # # We return a key ARN instead of KeyId despite the name of the parameter, as this is what AWS does and states # in its docs. - # TODO add support for "recipient" # https://docs.aws.amazon.com/kms/latest/APIReference/API_Decrypt.html#API_Decrypt_RequestSyntax # TODO add support for "dry_run" - return DecryptResponse( + response = DecryptResponse( KeyId=key.metadata.get("Arn"), - Plaintext=plaintext, EncryptionAlgorithm=encryption_algorithm, ) + # Encrypt to the recipient pubkey if specified. Otherwise, return the actual plaintext + if recipient_pubkey: + response["CiphertextForRecipient"] = pkcs7_envelope_encrypt(plaintext, recipient_pubkey) + else: + response["Plaintext"] = plaintext + + return response + def get_parameters_for_import( self, context: RequestContext, @@ -1176,13 +1257,10 @@ def import_key_material( # TODO check if there was already a key imported for this kms key # if so, it has to be identical. We cannot change keys by reimporting after deletion/expiry key_material = self._decrypt_wrapped_key_material(import_state, encrypted_key_material) - - if expiration_model: - key_to_import_material_to.metadata["ExpirationModel"] = expiration_model - else: - key_to_import_material_to.metadata["ExpirationModel"] = ( - ExpirationModelType.KEY_MATERIAL_EXPIRES - ) + key_material_id = key_to_import_material_to.generate_key_material_id(key_material) + key_to_import_material_to.metadata["ExpirationModel"] = ( + expiration_model or ExpirationModelType.KEY_MATERIAL_EXPIRES + ) if ( key_to_import_material_to.metadata["ExpirationModel"] == ExpirationModelType.KEY_MATERIAL_EXPIRES @@ -1191,12 +1269,42 @@ def import_key_material( raise ValidationException( "A validTo date must be set if the ExpirationModel is KEY_MATERIAL_EXPIRES" ) + if existing_pending_material := key_to_import_material_to.crypto_key.pending_key_material: + pending_key_material_id = key_to_import_material_to.generate_key_material_id( + existing_pending_material + ) + raise KMSInvalidStateException( + f"New key material (id: {key_material_id}) cannot be imported into KMS key " + f"{key_to_import_material_to.metadata['Arn']}, because another key material " + f"(id: {pending_key_material_id}) is pending rotation." + ) + # TODO actually set validTo and make the key expire key_to_import_material_to.metadata["Enabled"] = True key_to_import_material_to.metadata["KeyState"] = KeyState.Enabled key_to_import_material_to.crypto_key.load_key_material(key_material) - return ImportKeyMaterialResponse() + # KeyMaterialId / CurrentKeyMaterialId is only exposed for symmetric encryption keys. + key_material_id_response = None + if key_to_import_material_to.metadata["KeySpec"] == KeySpec.SYMMETRIC_DEFAULT: + key_material_id_response = key_to_import_material_to.generate_key_material_id( + key_material + ) + + # If there is no CurrentKeyMaterialId, instantly promote the pending key material to the current. + if key_to_import_material_to.metadata.get("CurrentKeyMaterialId") is None: + key_to_import_material_to.metadata["CurrentKeyMaterialId"] = ( + key_material_id_response + ) + key_to_import_material_to.crypto_key.key_material = ( + key_to_import_material_to.crypto_key.pending_key_material + ) + key_to_import_material_to.crypto_key.pending_key_material = None + + return ImportKeyMaterialResponse( + KeyId=key_to_import_material_to.metadata["Arn"], + KeyMaterialId=key_material_id_response, + ) def delete_imported_key_material( self, @@ -1323,7 +1431,7 @@ def get_key_rotation_status( key = self._get_kms_key(account_id, region_name, key_id, any_key_state_allowed=True) response = GetKeyRotationStatusResponse( - KeyId=key_id, + KeyId=key.metadata["Arn"], KeyRotationEnabled=key.is_key_rotation_enabled, NextRotationDate=key.next_rotation_date, ) @@ -1395,14 +1503,16 @@ def list_resource_tags( context.account_id, context.region, request.get("KeyId"), any_key_state_allowed=True ) keys_list = PaginatedList( - [{"TagKey": tag_key, "TagValue": tag_value} for tag_key, tag_value in key.tags.items()] + self._get_key_tags(context.account_id, context.region, key.metadata["Arn"]) ) page, next_token = keys_list.get_page( lambda tag: tag.get("TagKey"), next_token=request.get("Marker"), page_size=request.get("Limit", 50), ) - kwargs = {"NextMarker": next_token, "Truncated": True} if next_token else {} + kwargs = ( + {"NextMarker": next_token, "Truncated": True} if next_token else {"Truncated": False} + ) return ListResourceTagsResponse(Tags=page, **kwargs) @handler("RotateKeyOnDemand", expand=False) @@ -1415,13 +1525,13 @@ def rotate_key_on_demand( if key.metadata["KeySpec"] != KeySpec.SYMMETRIC_DEFAULT: raise UnsupportedOperationException() - if key.metadata["Origin"] == OriginType.EXTERNAL: - raise NotImplementedError("Rotation of imported keys is not supported yet.") + self._validate_key_state_not_pending_import(key) + self._validate_external_key_has_pending_material(key) key.rotate_key_on_demand() return RotateKeyOnDemandResponse( - KeyId=key_id, + KeyId=key.metadata["Arn"], ) @handler("TagResource", expand=False) @@ -1433,7 +1543,8 @@ def tag_resource(self, context: RequestContext, request: TagResourceRequest) -> enabled_key_allowed=True, disabled_key_allowed=True, ) - key.add_tags(request.get("Tags")) + if tags := request["Tags"]: + self._set_key_tags(context.account_id, context.region, key.metadata["Arn"], tags) @handler("UntagResource", expand=False) def untag_resource(self, context: RequestContext, request: UntagResourceRequest) -> None: @@ -1444,11 +1555,9 @@ def untag_resource(self, context: RequestContext, request: UntagResourceRequest) enabled_key_allowed=True, disabled_key_allowed=True, ) - if not request.get("TagKeys"): - return - for tag_key in request.get("TagKeys"): - # AWS doesn't seem to mind removal of a non-existent tag, so we do not raise any exception. - key.tags.pop(tag_key, None) + self._remove_key_tags( + context.account_id, context.region, key.metadata["Arn"], request["TagKeys"] + ) def derive_shared_secret( self, @@ -1498,6 +1607,12 @@ def _validate_key_state_not_pending_import(self, key: KmsKey): if key.metadata["KeyState"] == KeyState.PendingImport: raise KMSInvalidStateException(f"{key.metadata['Arn']} is pending import.") + def _validate_external_key_has_pending_material(self, key: KmsKey): + if key.metadata["Origin"] == "EXTERNAL" and key.crypto_key.pending_key_material is None: + raise KMSInvalidStateException( + f"No available key material pending rotation for the key: {key.metadata['Arn']}." + ) + def _validate_key_for_encryption_decryption(self, context: RequestContext, key: KmsKey): key_usage = key.metadata["KeyUsage"] if key_usage != "ENCRYPT_DECRYPT": @@ -1559,6 +1674,15 @@ def _validate_grant_request(self, data: dict): f" constraint: [Member must satisfy enum value set: {VALID_OPERATIONS}]" ) + def _extract_attestation_pubkey(self, attestation_document: bytes) -> RSAPublicKey: + # The attestation document comes as a COSE (CBOR Object Signing and Encryption) object: the CBOR + # attestation is signed and then the attestation and signature are again CBOR-encoded. For now + # we don't bother validating the signature, though in the future we could. + cose_document = cbor2_loads(attestation_document) + attestation = cbor2_loads(cose_document[2]) + public_key_bytes = attestation["public_key"] + return load_der_public_key(public_key_bytes) + def _decrypt_wrapped_key_material( self, import_state: KeyImportState, diff --git a/localstack-core/localstack/services/kms/utils.py b/localstack-core/localstack/services/kms/utils.py index 550d9a31c23c7..e51c080a89b4a 100644 --- a/localstack-core/localstack/services/kms/utils.py +++ b/localstack-core/localstack/services/kms/utils.py @@ -1,16 +1,23 @@ +import base64 import re from collections.abc import Callable -from typing import TypeVar -from localstack.aws.api.kms import DryRunOperationException, Tag, TagException +from localstack.aws.api.kms import ( + CreateKeyRequest, + DryRunOperationException, + Tag, + TagException, + TagList, +) +from localstack.constants import TAG_KEY_CUSTOM_ID from localstack.services.kms.exceptions import ValidationException from localstack.utils.aws.arns import ARN_PARTITION_REGEX -T = TypeVar("T") - KMS_KEY_ARN_PATTERN = re.compile( rf"{ARN_PARTITION_REGEX}:kms:(?P[^:]+):(?P\d{{12}}):((?=key/)key/|(?=alias/))(?P[^:]+)$" ) +# special tag name to allow specifying a custom key material for created keys +TAG_KEY_CUSTOM_KEY_MATERIAL = "_custom_key_material_" def get_hash_algorithm(signing_algorithm: str) -> str: @@ -63,7 +70,63 @@ def validate_tag(tag_position: int, tag: Tag) -> None: raise TagException("Tags beginning with aws: are reserved") -def execute_dry_run_capable(func: Callable[..., T], dry_run: bool, *args, **kwargs) -> T: +def validate_and_filter_tags(tag_list: TagList) -> TagList: + """ + Validates tags and filters out LocalStack specific tags + + :param tag_list: The list of tags provided to apply to the KMS key. + :returns: Filtered and validated list of tags to apply to the KMS key. + """ + unique_tag_keys = {tag["TagKey"] for tag in tag_list} + if len(unique_tag_keys) < len(tag_list): + raise TagException("Duplicate tag keys") + if len(tag_list) > 50: + raise TagException("Too many tags") + + validated_tags = [] + for i, tag in enumerate(tag_list, start=1): + if tag["TagKey"] != TAG_KEY_CUSTOM_KEY_MATERIAL: + validate_tag(i, tag) + validated_tags.append(tag) + + return validated_tags + + +def get_custom_key_material(request: CreateKeyRequest | None) -> bytes | None: + """ + Retrieves custom material which is sent in a CreateKeyRequest via the Tags. + + :param request: The request for creating a KMS key. + :returns: Custom key material for the KMS key. + """ + if not request: + return None + + tags = request.get("Tags", []) + for tag in tags: + if tag["TagKey"] == TAG_KEY_CUSTOM_KEY_MATERIAL: + return base64.b64decode(tag["TagValue"]) + return None + + +def get_custom_key_id(request: CreateKeyRequest | None) -> bytes | None: + """ + Retrieves a custom Key ID for the KMS key which is sent in a CreateKeyRequest via the Tags. + + :param request: The request for creating a KMS key. + :returns: THe custom Key ID for the KMS key. + """ + if not request: + return None + + tags = request.get("Tags", []) + for tag in tags: + if tag["TagKey"] == TAG_KEY_CUSTOM_ID: + return tag["TagValue"] + return None + + +def execute_dry_run_capable[T](func: Callable[..., T], dry_run: bool, *args, **kwargs) -> T: """ Executes a function unless dry run mode is enabled. diff --git a/localstack-core/localstack/services/lambda_/analytics.py b/localstack-core/localstack/services/lambda_/analytics.py index ff4a1ae6f516c..df100137e87c7 100644 --- a/localstack-core/localstack/services/lambda_/analytics.py +++ b/localstack-core/localstack/services/lambda_/analytics.py @@ -14,9 +14,10 @@ "status", "runtime", "package_type", - # only for operation "invoke" - "invocation_type", + "invocation_type", # only for operation "invoke", otherwise "n/a" + "initialization_type", ], + schema_version=2, ) @@ -38,6 +39,15 @@ class FunctionStatus(StrEnum): invocation_error = "invocation_error" +class FunctionInitializationType(StrEnum): + # Maps to the Lambda environment variable AWS_LAMBDA_INITIALIZATION_TYPE + # Matches with lambda_models.InitializationType + on_demand = "on-demand" + lambda_managed_instances = "lambda-managed-instances" + # Only applies to the operation "invoke" because provisioned concurrency is not configured on "create" + provisioned_concurrency = "provisioned-concurrency" + + esm_counter = LabeledCounter(namespace=NAMESPACE, name="esm", labels=["source", "status"]) diff --git a/localstack-core/localstack/services/lambda_/api_utils.py b/localstack-core/localstack/services/lambda_/api_utils.py index 5fcb0e881f0d4..cfb507a7111c5 100644 --- a/localstack-core/localstack/services/lambda_/api_utils.py +++ b/localstack-core/localstack/services/lambda_/api_utils.py @@ -3,6 +3,8 @@ """ import datetime +import hashlib +import json import random import re import string @@ -62,13 +64,14 @@ r"^$|arn:(aws[a-zA-Z0-9-]*):([a-zA-Z0-9\-])+:([a-z]{2}(-gov)?-[a-z]+-\d{1})?:(\d{12})?:(.*)" ) +# TODO: what's the difference between AWS_FUNCTION_NAME_REGEX and FUNCTION_NAME_REGEX? Can we unify? AWS_FUNCTION_NAME_REGEX = re.compile( - "^(arn:(aws[a-zA-Z-]*)?:lambda:)?([a-z]{2}((-gov)|(-iso([a-z]?)))?-[a-z]+-\\d{1}:)?(\\d{12}:)?(function:)?([a-zA-Z0-9-_.]+)(:(\\$LATEST|[a-zA-Z0-9-_]+))?$" + "^(arn:(aws[a-zA-Z-]*)?:lambda:)?([a-z]{2}((-gov)|(-iso([a-z]?)))?-[a-z]+-\\d{1}:)?(\\d{12}:)?(function:)?([a-zA-Z0-9-_.]+)(:(\\$LATEST(\\.PUBLISHED)?|[a-zA-Z0-9-_]+))?$" ) # Pattern for extracting various attributes from a full or partial ARN or just a function name. FUNCTION_NAME_REGEX = re.compile( - r"(arn:(aws[a-zA-Z-]*):lambda:)?((?P[a-z]{2}(-gov)?-[a-z]+-\d{1}):)?(?:(?P\d{12}):)?(function:)?(?P[a-zA-Z0-9-_\.]+)(:(?P\$LATEST|[a-zA-Z0-9-_]+))?" + r"(arn:(aws[a-zA-Z-]*):lambda:)?((?P[a-z]{2}(-gov)?-[a-z]+-\d{1}):)?(?:(?P\d{12}):)?(function:)?(?P[a-zA-Z0-9-_\.]+)(:(?P\$LATEST(\.PUBLISHED)?|[a-zA-Z0-9-_]+))?" ) # also length 1-170 incl. # Pattern for a lambda function handler HANDLER_REGEX = re.compile(r"[^\s]+") @@ -86,9 +89,11 @@ SIGNING_PROFILE_VERSION_ARN_REGEX = re.compile( r"arn:(aws[a-zA-Z0-9-]*):([a-zA-Z0-9\-])+:([a-z]{2}(-gov)?-[a-z]+-\d{1})?:(\d{12})?:(.*)" ) -# Combined pattern for alias and version based on AWS error using "(|[a-zA-Z0-9$_-]+)" -QUALIFIER_REGEX = re.compile(r"(^[a-zA-Z0-9$_-]+$)") +# Combined pattern for alias and version based on AWS error using "\\$(LATEST(\\.PUBLISHED)?)|[a-zA-Z0-9-_$]+" +# This regex is based on the snapshotted validation message, just removing the double \\ before $LATEST +QUALIFIER_REGEX = re.compile(r"^\$(LATEST(\\.PUBLISHED)?)|[a-zA-Z0-9-_$]+$") # Pattern for a version qualifier +# TODO: do we need to consider $LATEST.PUBLISHED here? VERSION_REGEX = re.compile(r"^[0-9]+$") # Pattern for an alias qualifier # Rules: https://docs.aws.amazon.com/lambda/latest/dg/API_CreateAlias.html#SSS-CreateAlias-request-Name @@ -107,36 +112,42 @@ # An unordered list of all Lambda CPU architectures supported by LocalStack. ARCHITECTURES = [Architecture.arm64, Architecture.x86_64] -# ARN pattern returned in validation exception messages. -# Some excpetions from AWS return a '\.' in the function name regex -# pattern therefore we can sub this value in when appropriate. -ARN_NAME_PATTERN_VALIDATION_TEMPLATE = "(arn:(aws[a-zA-Z-]*)?:lambda:)?([a-z]{{2}}((-gov)|(-iso([a-z]?)))?-[a-z]+-\\d{{1}}:)?(\\d{{12}}:)?(function:)?([a-zA-Z0-9-_{0}]+)(:(\\$LATEST|[a-zA-Z0-9-_]+))?" +# ARN patterns returned in validation exception messages +ARN_NAME_PATTERN_GET = r"(arn:(aws[a-zA-Z-]*)?:lambda:)?((eusc-)?[a-z]{2}((-gov)|(-iso([a-z]?)))?-[a-z]+-\d{1}:)?(\d{12}:)?(function:)?([a-zA-Z0-9-_\.]+)(:(\$LATEST(\.PUBLISHED)?|[a-zA-Z0-9-_]+))?" +ARN_NAME_PATTERN_CREATE = r"(arn:(aws[a-zA-Z-]*)?:lambda:)?((eusc-)?[a-z]{2}((-gov)|(-iso([a-z]?)))?-[a-z]+-\d{1}:)?(\d{12}:)?(function:)?([a-zA-Z0-9-_]+)(:(\$LATEST|[a-zA-Z0-9-_]+))?" # AWS response when invalid ARNs are used in Tag operations. -TAGGABLE_RESOURCE_ARN_PATTERN = "arn:(aws[a-zA-Z-]*):lambda:[a-z]{2}((-gov)|(-iso([a-z]?)))?-[a-z]+-\\d{1}:\\d{12}:(function:[a-zA-Z0-9-_]+(:(\\$LATEST|[a-zA-Z0-9-_]+))?|layer:([a-zA-Z0-9-_]+)|code-signing-config:csc-[a-z0-9]{17}|event-source-mapping:[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12})" +TAGGABLE_RESOURCE_ARN_PATTERN = "arn:(aws[a-zA-Z-]*):lambda:(eusc-)?[a-z]{2}((-gov)|(-iso([a-z]?)))?-[a-z]+-\\d{1}:\\d{12}:(function:[a-zA-Z0-9-_]+(:(\\$LATEST|[a-zA-Z0-9-_]+))?|layer:([a-zA-Z0-9-_]+)|code-signing-config:csc-[a-z0-9]{17}|event-source-mapping:[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}|capacity-provider:[a-zA-Z0-9-_]+)" def validate_function_name(function_name_or_arn: str, operation_type: str): function_name, *_ = function_locators_from_arn(function_name_or_arn) - arn_name_pattern = ARN_NAME_PATTERN_VALIDATION_TEMPLATE.format("") + arn_name_pattern = ARN_NAME_PATTERN_CREATE max_length = 170 - match operation_type: - case "GetFunction" | "Invoke": - arn_name_pattern = ARN_NAME_PATTERN_VALIDATION_TEMPLATE.format(r"\.") - case "CreateFunction" if function_name == function_name_or_arn: # only a function name + if operation_type == "GetFunction" or operation_type == "Invoke": + arn_name_pattern = ARN_NAME_PATTERN_GET + elif operation_type == "CreateFunction": + # https://docs.aws.amazon.com/lambda/latest/api/API_CreateFunction.html#lambda-CreateFunction-request-FunctionName + if function_name == function_name_or_arn: # only a function name max_length = 64 - case "CreateFunction" | "DeleteFunction": + else: # full or partial ARN max_length = 140 + elif operation_type == "DeleteFunction": + max_length = 140 + arn_name_pattern = ARN_NAME_PATTERN_GET validations = [] - if len(function_name_or_arn) > max_length: - constraint = f"Member must have length less than or equal to {max_length}" + if not AWS_FUNCTION_NAME_REGEX.match(function_name_or_arn) or not function_name: + constraint = f"Member must satisfy regular expression pattern: {arn_name_pattern}" validation_msg = f"Value '{function_name_or_arn}' at 'functionName' failed to satisfy constraint: {constraint}" validations.append(validation_msg) + if not operation_type == "CreateFunction": + # Immediately raises rather than summarizing all validations, except for CreateFunction + return validations - if not AWS_FUNCTION_NAME_REGEX.match(function_name_or_arn) or not function_name: - constraint = f"Member must satisfy regular expression pattern: {arn_name_pattern}" + if len(function_name_or_arn) > max_length: + constraint = f"Member must have length less than or equal to {max_length}" validation_msg = f"Value '{function_name_or_arn}' at 'functionName' failed to satisfy constraint: {constraint}" validations.append(validation_msg) @@ -154,7 +165,7 @@ def validate_qualifier(qualifier: str): validations.append(validation_msg) if not QUALIFIER_REGEX.match(qualifier): - constraint = "Member must satisfy regular expression pattern: (|[a-zA-Z0-9$_-]+)" + constraint = "Member must satisfy regular expression pattern: \\$(LATEST(\\.PUBLISHED)?)|[a-zA-Z0-9-_$]+" validation_msg = ( f"Value '{qualifier}' at 'qualifier' failed to satisfy constraint: {constraint}" ) @@ -571,6 +582,12 @@ def map_config_out( optional_kwargs["CodeSize"] = 0 optional_kwargs["CodeSha256"] = version.config.image.code_sha256 + if version.config.capacity_provider_config: + optional_kwargs["CapacityProviderConfig"] = version.config.capacity_provider_config + data = json.dumps(version.config.capacity_provider_config, sort_keys=True).encode("utf-8") + config_sha_256 = hashlib.sha256(data).hexdigest() + optional_kwargs["ConfigSha256"] = config_sha_256 + # output for an alias qualifier is completely the same except for the returned ARN if alias_name: function_arn = f"{':'.join(version.id.qualified_arn().split(':')[:-1])}:{alias_name}" @@ -722,7 +739,9 @@ def validate_layer_runtimes_and_architectures( validations.append(validation_msg) if compatible_architectures and set(compatible_architectures).difference(ARCHITECTURES): - constraint = "[Member must satisfy enum value set: [x86_64, arm64]]" + constraint = ( + "[Member must satisfy enum value set: [x86_64, arm64], Member must not be null]" + ) validation_msg = f"Value '[{', '.join(list(compatible_architectures))}]' at 'compatibleArchitectures' failed to satisfy constraint: Member must satisfy constraint: {constraint}" validations.append(validation_msg) diff --git a/localstack-core/localstack/services/lambda_/event_source_mapping/pollers/stream_poller.py b/localstack-core/localstack/services/lambda_/event_source_mapping/pollers/stream_poller.py index fb1433519caa0..288e932c441d7 100644 --- a/localstack-core/localstack/services/lambda_/event_source_mapping/pollers/stream_poller.py +++ b/localstack-core/localstack/services/lambda_/event_source_mapping/pollers/stream_poller.py @@ -36,7 +36,7 @@ ) from localstack.utils.aws.arns import parse_arn, s3_bucket_name from localstack.utils.backoff import ExponentialBackoff -from localstack.utils.batch_policy import Batcher +from localstack.utils.batching import Batcher from localstack.utils.strings import long_uid LOG = logging.getLogger(__name__) diff --git a/localstack-core/localstack/services/lambda_/invocation/assignment.py b/localstack-core/localstack/services/lambda_/invocation/assignment.py index d72505c6447ba..9edd5f7dc2cc2 100644 --- a/localstack-core/localstack/services/lambda_/invocation/assignment.py +++ b/localstack-core/localstack/services/lambda_/invocation/assignment.py @@ -1,6 +1,8 @@ import contextlib import logging +import threading from collections import defaultdict +from collections.abc import Iterator from concurrent.futures import Future, ThreadPoolExecutor from localstack.services.lambda_.invocation.execution_environment import ( @@ -33,9 +35,16 @@ class AssignmentService(OtherServiceEndpoint): # Global pool for spawning and killing provisioned Lambda runtime environments provisioning_pool: ThreadPoolExecutor + # Semaphore limiting the number of on-demand containers starting simultaneously. + # Concurrent container starts are I/O-heavy (Docker API calls, copying runtime files) + # and can exhaust OS file descriptor limits on machines with low ulimits. + on_demand_start_semaphore: threading.Semaphore + def __init__(self): self.environments = defaultdict(dict) self.provisioning_pool = ThreadPoolExecutor(thread_name_prefix="lambda-provisioning-pool") + # TODO: make this value configurable; 16 is a conservative default + self.on_demand_start_semaphore = threading.Semaphore(16) @contextlib.contextmanager def get_environment( @@ -43,12 +52,14 @@ def get_environment( version_manager_id: str, function_version: FunctionVersion, provisioning_type: InitializationType, - ) -> contextlib.AbstractContextManager[ExecutionEnvironment]: - applicable_envs = ( + ) -> Iterator[ExecutionEnvironment]: + # Snapshot the values list before iterating to avoid skipped entries + # that can be caused by concurrent invocations + applicable_envs = [ env - for env in self.environments[version_manager_id].values() + for env in list(self.environments[version_manager_id].values()) if env.initialization_type == provisioning_type - ) + ] execution_environment = None for environment in applicable_envs: try: @@ -59,12 +70,15 @@ def get_environment( pass if execution_environment is None: - if provisioning_type == "provisioned-concurrency": + if provisioning_type == InitializationType.provisioned_concurrency: raise AssignmentException( "No provisioned concurrency environment available despite lease." ) - elif provisioning_type == "on-demand": - execution_environment = self.start_environment(version_manager_id, function_version) + elif provisioning_type == InitializationType.on_demand: + with self.on_demand_start_semaphore: + execution_environment = self.start_environment( + version_manager_id, function_version + ) self.environments[version_manager_id][execution_environment.id] = ( execution_environment ) @@ -81,16 +95,28 @@ def get_environment( LOG.error( "Failed invocation <%s>: %s", type(e), e, exc_info=LOG.isEnabledFor(logging.DEBUG) ) - self.stop_environment(execution_environment) + if execution_environment.initialization_type == InitializationType.on_demand: + self.stop_environment(execution_environment) + else: + # Try to restore to READY rather than stopping. + # Transient errors (e.g., OS-level connection failures) should not + # permanently remove healthy provisioned containers from the pool. + try: + execution_environment.release() + except InvalidStatusException: + self.stop_environment(execution_environment) raise e def start_environment( self, version_manager_id: str, function_version: FunctionVersion ) -> ExecutionEnvironment: LOG.debug("Starting new environment") + initialization_type = InitializationType.on_demand + if function_version.config.capacity_provider_config: + initialization_type = InitializationType.lambda_managed_instances execution_environment = ExecutionEnvironment( function_version=function_version, - initialization_type="on-demand", + initialization_type=initialization_type, on_timeout=self.on_timeout, version_manager_id=version_manager_id, ) @@ -138,20 +164,20 @@ def scale_provisioned_concurrency( current_provisioned_environments = [ e for e in self.environments[version_manager_id].values() - if e.initialization_type == "provisioned-concurrency" + if e.initialization_type == InitializationType.provisioned_concurrency ] # TODO: refine scaling loop to re-use existing environments instead of re-creating all # current_provisioned_environments_count = len(current_provisioned_environments) # diff = target_provisioned_environments - current_provisioned_environments_count - # TODO: handle case where no provisioned environment is available during scaling + # TODO: handle case where no provisioned environment is available during scaling. Does AWS serve on-demand? # Most simple scaling implementation for now: futures = [] # 1) Re-create new target for _ in range(target_provisioned_environments): execution_environment = ExecutionEnvironment( function_version=function_version, - initialization_type="provisioned-concurrency", + initialization_type=InitializationType.provisioned_concurrency, on_timeout=self.on_timeout, version_manager_id=version_manager_id, ) diff --git a/localstack-core/localstack/services/lambda_/invocation/counting_service.py b/localstack-core/localstack/services/lambda_/invocation/counting_service.py index 8887172c99e97..39226a0a08e5e 100644 --- a/localstack-core/localstack/services/lambda_/invocation/counting_service.py +++ b/localstack-core/localstack/services/lambda_/invocation/counting_service.py @@ -1,14 +1,16 @@ import contextlib import logging from collections import defaultdict +from collections.abc import Iterator from threading import RLock from localstack import config -from localstack.aws.api.lambda_ import TooManyRequestsException +from localstack.aws.api.lambda_ import ProvisionedConcurrencyStatusEnum, TooManyRequestsException from localstack.services.lambda_.invocation.lambda_models import ( Function, FunctionVersion, InitializationType, + ProvisionedConcurrencyState, ) from localstack.services.lambda_.invocation.models import lambda_stores @@ -66,12 +68,12 @@ class CountingService: """ # (account, region) => ConcurrencyTracker (unqualified arn) => concurrent executions - on_demand_concurrency_trackers: dict[(str, str), ConcurrencyTracker] + on_demand_concurrency_trackers: dict[tuple[str, str], ConcurrencyTracker] # Lock for safely initializing new on-demand concurrency trackers on_demand_init_lock: RLock # (account, region) => ConcurrencyTracker (qualified arn) => concurrent executions - provisioned_concurrency_trackers: dict[(str, str), ConcurrencyTracker] + provisioned_concurrency_trackers: dict[tuple[str, str], ConcurrencyTracker] # Lock for safely initializing new provisioned concurrency trackers provisioned_concurrency_init_lock: RLock @@ -83,8 +85,11 @@ def __init__(self): @contextlib.contextmanager def get_invocation_lease( - self, function: Function | None, function_version: FunctionVersion - ) -> InitializationType: + self, + function: Function | None, + function_version: FunctionVersion, + provisioned_state: ProvisionedConcurrencyState | None = None, + ) -> Iterator[InitializationType]: """An invocation lease reserves the right to schedule an invocation. The returned lease type can either be on-demand or provisioned. Scheduling preference: @@ -117,13 +122,6 @@ def get_invocation_lease( ConcurrencyTracker() ) - # TODO: check that we don't give a lease while updating provisioned concurrency - # Potential challenge if an update happens in between reserving the lease here and actually assigning - # * Increase provisioned: It could happen that we give a lease for provisioned-concurrency although - # brand new provisioned environments are not yet initialized. - # * Decrease provisioned: It could happen that we have running invocations that should still be counted - # against the limit but they are not because we already updated the concurrency config to fewer envs. - unqualified_function_arn = function_version.id.unqualified_arn() qualified_arn = function_version.id.qualified_arn() @@ -144,14 +142,24 @@ def get_invocation_lease( function.provisioned_concurrency_configs.get(alias.name) ) break - if provisioned_concurrency_config: + # Favor provisioned concurrency if configured and ready + # TODO: test updating provisioned concurrency? Does AWS serve on-demand during updates? + # Potential challenge if an update happens in between reserving the lease here and actually assigning + # * Increase provisioned: It could happen that we give a lease for provisioned-concurrency although + # brand new provisioned environments are not yet initialized. + # * Decrease provisioned: It could happen that we have running invocations that should still be counted + # against the limit but they are not because we already updated the concurrency config to fewer envs. + if ( + provisioned_concurrency_config + and provisioned_state.status == ProvisionedConcurrencyStatusEnum.READY + ): available_provisioned_concurrency = ( provisioned_concurrency_config.provisioned_concurrent_executions - provisioned_tracker.concurrent_executions[qualified_arn] ) if available_provisioned_concurrency > 0: provisioned_tracker.increment(qualified_arn) - lease_type = "provisioned-concurrency" + lease_type = InitializationType.provisioned_concurrency if not lease_type: with on_demand_tracker.lock: @@ -169,7 +177,7 @@ def get_invocation_lease( ) if available_reserved_concurrency > 0: on_demand_tracker.increment(unqualified_function_arn) - lease_type = "on-demand" + lease_type = InitializationType.on_demand else: extras = { "available_reserved_concurrency": available_reserved_concurrency, @@ -211,7 +219,7 @@ def get_invocation_lease( ) if available_unreserved_concurrency > 0: on_demand_tracker.increment(unqualified_function_arn) - lease_type = "on-demand" + lease_type = InitializationType.on_demand else: if available_unreserved_concurrency < 0: LOG.error( @@ -233,9 +241,9 @@ def get_invocation_lease( try: yield lease_type finally: - if lease_type == "provisioned-concurrency": + if lease_type == InitializationType.provisioned_concurrency: provisioned_tracker.atomic_decrement(qualified_arn) - elif lease_type == "on-demand": + elif lease_type == InitializationType.on_demand: on_demand_tracker.atomic_decrement(unqualified_function_arn) else: LOG.error( diff --git a/localstack-core/localstack/services/lambda_/invocation/docker_runtime_executor.py b/localstack-core/localstack/services/lambda_/invocation/docker_runtime_executor.py index dc427ca8f5c3c..719fa2ca90648 100644 --- a/localstack-core/localstack/services/lambda_/invocation/docker_runtime_executor.py +++ b/localstack-core/localstack/services/lambda_/invocation/docker_runtime_executor.py @@ -7,7 +7,6 @@ from collections import defaultdict from collections.abc import Callable from pathlib import Path -from typing import Literal from localstack import config from localstack.aws.api.lambda_ import Architecture, PackageType, Runtime @@ -54,15 +53,13 @@ RAPID_ENTRYPOINT = "/var/rapid/init" -InitializationType = Literal["on-demand", "provisioned-concurrency"] - LAMBDA_DOCKERFILE = """FROM {base_img} COPY init {rapid_entrypoint} COPY code/ /var/task """ -PULLED_IMAGES: set[(str, DockerPlatform)] = set() -PULL_LOCKS: dict[(str, DockerPlatform), threading.RLock] = defaultdict(threading.RLock) +PULLED_IMAGES: set[tuple[str, DockerPlatform]] = set() +PULL_LOCKS: dict[tuple[str, DockerPlatform], threading.RLock] = defaultdict(threading.RLock) HOT_RELOADING_ENV_VARIABLE = "LOCALSTACK_HOT_RELOADING_PATHS" diff --git a/localstack-core/localstack/services/lambda_/invocation/event_manager.py b/localstack-core/localstack/services/lambda_/invocation/event_manager.py index 4e1414db29c42..e68785d5bba15 100644 --- a/localstack-core/localstack/services/lambda_/invocation/event_manager.py +++ b/localstack-core/localstack/services/lambda_/invocation/event_manager.py @@ -13,6 +13,7 @@ from localstack import config from localstack.aws.api.lambda_ import InvocationType, TooManyRequestsException from localstack.services.lambda_.analytics import ( + FunctionInitializationType, FunctionOperation, FunctionStatus, function_counter, @@ -198,22 +199,22 @@ def stop(self): def handle_message(self, message: dict) -> None: failure_cause = None qualifier = self.version_manager.function_version.id.qualifier + function_config = self.version_manager.function_version.config event_invoke_config = self.version_manager.function.event_invoke_configs.get(qualifier) runtime = None status = None + # TODO: handle initialization_type provisioned-concurrency, which requires enriching invocation_result + initialization_type = ( + FunctionInitializationType.lambda_managed_instances + if function_config.capacity_provider_config + else FunctionInitializationType.on_demand + ) try: sqs_invocation = SQSInvocation.decode(message["Body"]) invocation = sqs_invocation.invocation try: invocation_result = self.version_manager.invoke(invocation=invocation) - function_config = self.version_manager.function_version.config - function_counter.labels( - operation=FunctionOperation.invoke, - runtime=function_config.runtime or "n/a", - status=FunctionStatus.success, - invocation_type=InvocationType.Event, - package_type=function_config.package_type, - ).increment() + status = FunctionStatus.success except Exception as e: # Reserved concurrency == 0 if self.version_manager.function.reserved_concurrent_executions == 0: @@ -223,6 +224,7 @@ def handle_message(self, message: dict) -> None: elif not has_enough_time_for_retry(sqs_invocation, event_invoke_config): failure_cause = "EventAgeExceeded" status = FunctionStatus.event_age_exceeded_error + if failure_cause: invocation_result = InvocationResult( is_error=True, request_id=invocation.request_id, payload=None, logs=None @@ -240,14 +242,14 @@ def handle_message(self, message: dict) -> None: sqs_client.delete_message( QueueUrl=self.event_queue_url, ReceiptHandle=message["ReceiptHandle"] ) - # status MUST be set before returning - package_type = self.version_manager.function_version.config.package_type + assert status, "status MUST be set before returning" function_counter.labels( operation=FunctionOperation.invoke, runtime=runtime or "n/a", status=status, invocation_type=InvocationType.Event, - package_type=package_type, + package_type=function_config.package_type, + initialization_type=initialization_type, ).increment() # Good summary blogpost: https://haithai91.medium.com/aws-lambdas-retry-behaviors-edff90e1cf1b @@ -257,6 +259,8 @@ def handle_message(self, message: dict) -> None: if event_invoke_config and event_invoke_config.maximum_retry_attempts is not None: max_retry_attempts = event_invoke_config.maximum_retry_attempts + assert invocation_result, "Invocation result MUST exist if we are not returning before" + # An invocation error either leads to a terminal failure or to a scheduled retry if invocation_result.is_error: # invocation error failure_cause = None diff --git a/localstack-core/localstack/services/lambda_/invocation/execution_environment.py b/localstack-core/localstack/services/lambda_/invocation/execution_environment.py index 3db4d308e234e..8279df83a75e5 100644 --- a/localstack-core/localstack/services/lambda_/invocation/execution_environment.py +++ b/localstack-core/localstack/services/lambda_/invocation/execution_environment.py @@ -8,6 +8,7 @@ from threading import RLock, Timer from localstack import config +from localstack.aws.api.lambda_ import LogFormat from localstack.aws.connect import connect_to from localstack.services.lambda_.invocation.lambda_models import ( Credentials, @@ -149,6 +150,22 @@ def get_environment_variables(self) -> dict[str, str]: # LOCALSTACK_USER conditionally added below } # Conditionally added environment variables + # Lambda advanced logging controls: + # https://aws.amazon.com/blogs/compute/introducing-advanced-logging-controls-for-aws-lambda-functions/ + logging_config = self.function_version.config.logging_config + if logging_config.get("LogFormat") == LogFormat.JSON: + env_vars["AWS_LAMBDA_LOG_FORMAT"] = logging_config["LogFormat"] + # TODO: test this (currently not implemented in LocalStack) + env_vars["AWS_LAMBDA_LOG_LEVEL"] = logging_config["ApplicationLogLevel"].capitalize() + # Lambda Managed Instances + if capacity_provider_config := self.function_version.config.capacity_provider_config: + # Disable dropping privileges for parity + # TODO: implement mixed permissions (maybe in RIE) + # env_vars["LOCALSTACK_USER"] = "root" + env_vars["AWS_LAMBDA_MAX_CONCURRENCY"] = capacity_provider_config[ + "LambdaManagedInstancesCapacityProviderConfig" + ]["PerExecutionEnvironmentMaxConcurrency"] + env_vars["TZ"] = ":/etc/localtime" if not config.LAMBDA_DISABLE_AWS_ENDPOINT_URL: env_vars["AWS_ENDPOINT_URL"] = ( f"http://{self.runtime_executor.get_endpoint_from_executor()}:{config.GATEWAY_LISTEN[0].port}" @@ -159,8 +176,6 @@ def get_environment_variables(self) -> dict[str, str]: # Will be overridden by the runtime itself unless it is a provided runtime if self.function_version.config.runtime: env_vars["AWS_EXECUTION_ENV"] = "AWS_Lambda_rapid" - if self.function_version.config.environment: - env_vars.update(self.function_version.config.environment) if config.LAMBDA_INIT_DEBUG: # Disable dropping privileges because it breaks debugging env_vars["LOCALSTACK_USER"] = "root" @@ -175,6 +190,10 @@ def get_environment_variables(self) -> dict[str, str]: env_vars["LOCALSTACK_MAX_PAYLOAD_SIZE"] = int( config.LAMBDA_LIMITS_MAX_FUNCTION_PAYLOAD_SIZE_BYTES ) + + # Let users overwrite any environment variable at last (if they want so) + if self.function_version.config.environment: + env_vars.update(self.function_version.config.environment) return env_vars # Lifecycle methods @@ -250,7 +269,7 @@ def release(self) -> None: ) self.status = RuntimeStatus.READY - if self.initialization_type == "on-demand": + if self.initialization_type == InitializationType.on_demand: self.keepalive_timer = Timer(config.LAMBDA_KEEPALIVE_MS / 1000, self.keepalive_passed) self.keepalive_timer.start() diff --git a/localstack-core/localstack/services/lambda_/invocation/lambda_models.py b/localstack-core/localstack/services/lambda_/invocation/lambda_models.py index c0e2f9057f18f..90c51d20d240b 100644 --- a/localstack-core/localstack/services/lambda_/invocation/lambda_models.py +++ b/localstack-core/localstack/services/lambda_/invocation/lambda_models.py @@ -11,8 +11,9 @@ import threading from abc import ABCMeta, abstractmethod from datetime import datetime +from enum import StrEnum from pathlib import Path -from typing import IO, Literal, TypedDict +from typing import IO, Any, TypedDict import boto3 from botocore.exceptions import ClientError @@ -22,12 +23,20 @@ from localstack.aws.api.lambda_ import ( AllowedPublishers, Architecture, + CapacityProviderArn, + CapacityProviderConfig, + CapacityProviderPermissionsConfig, + CapacityProviderScalingConfig, + CapacityProviderVpcConfig, CodeSigningPolicies, Cors, DestinationConfig, + FunctionScalingConfig, FunctionUrlAuthType, + InstanceRequirements, InvocationType, InvokeMode, + KMSKeyArn, LastUpdateStatus, LoggingConfig, PackageType, @@ -38,12 +47,14 @@ SnapStartResponse, State, StateReasonCode, + Timestamp, TracingMode, ) from localstack.aws.connect import connect_to from localstack.constants import AWS_REGION_US_EAST_1, INTERNAL_AWS_SECRET_ACCESS_KEY from localstack.services.lambda_.api_utils import qualified_lambda_arn, unqualified_lambda_arn from localstack.utils.archives import unzip +from localstack.utils.files import chmod_r from localstack.utils.strings import long_uid, short_uid LOG = logging.getLogger(__name__) @@ -70,7 +81,10 @@ class Invocation: user_agent: str | None = None -InitializationType = Literal["on-demand", "provisioned-concurrency"] +class InitializationType(StrEnum): + on_demand = "on-demand" + provisioned_concurrency = "provisioned-concurrency" + lambda_managed_instances = "lambda-managed-instances" class ArchiveCode(metaclass=ABCMeta): @@ -208,10 +222,20 @@ def prepare_for_execution(self) -> None: if target_path.exists(): return LOG.debug("Saving code %s to disk", self.id) - target_path.mkdir(parents=True, exist_ok=True) - with tempfile.NamedTemporaryFile() as file: - self._download_archive_to_file(file) - unzip(file.name, str(target_path)) + target_path.parent.mkdir(parents=True, exist_ok=True) + # Use a temp directory for atomic operation to prevent partial reads + # if the process crashes or is killed during unzip. + # Create temp dir in same parent to ensure same filesystem for atomic rename. + with tempfile.TemporaryDirectory(dir=target_path.parent) as temp_dir: + temp_path = Path(temp_dir) + + with tempfile.NamedTemporaryFile() as file: + self._download_archive_to_file(file) + unzip(file.name, str(temp_path)) + chmod_r(str(temp_path), 0o755) + + # Atomic move/rename + temp_path.rename(target_path) def destroy_cached(self) -> None: """ @@ -316,9 +340,9 @@ class FileSystemConfig: @dataclasses.dataclass(frozen=True) class ImageConfig: - working_directory: str - command: list[str] = dataclasses.field(default_factory=list) - entrypoint: list[str] = dataclasses.field(default_factory=list) + working_directory: str | None + command: list[str] | None = dataclasses.field(default_factory=list) + entrypoint: list[str] | None = dataclasses.field(default_factory=list) @dataclasses.dataclass @@ -331,7 +355,7 @@ class VpcConfig: @dataclasses.dataclass(frozen=True) class UpdateStatus: status: LastUpdateStatus | None - code: str | None = None # TODO: probably not a string + code: str | None = None reason: str | None = None @@ -350,11 +374,11 @@ class FunctionUrlConfig: function_arn: str # fully qualified ARN function_name: str # resolved name - cors: Cors url_id: str # Custom URL (via tag), or generated unique subdomain id e.g. pfn5bdb2dl5mzkbn6eb2oi3xfe0nthdn url: str # full URL (e.g. "https://pfn5bdb2dl5mzkbn6eb2oi3xfe0nthdn.lambda-url.eu-west-3.on.aws/") auth_type: FunctionUrlAuthType creation_time: str # time + cors: Cors | None last_modified_time: str | None = ( None # TODO: check if this is the creation time when initially creating ) @@ -421,7 +445,7 @@ class VersionAlias: class ResourcePolicy: Version: str Id: str - Statement: list[dict] + Statement: list[dict[str, Any]] @dataclasses.dataclass @@ -485,8 +509,8 @@ class CodeSigningConfig: arn: str allowed_publishers: AllowedPublishers - policies: CodeSigningPolicies last_modified: str + policies: CodeSigningPolicies | None = None description: str | None = None @@ -514,14 +538,15 @@ class LayerVersion: layer_arn: str version: int - code: ArchiveCode - license_info: str - compatible_runtimes: list[Runtime] - compatible_architectures: list[Architecture] + # we need to use Union types as inheritance is not supported by serialization framework + code: S3Code | HotReloadingCode | None + license_info: str | None + compatible_runtimes: list[Runtime] | None + compatible_architectures: list[Architecture] | None created: str # date description: str = "" - policy: LayerPolicy = None + policy: LayerPolicy | None = None @dataclasses.dataclass @@ -538,19 +563,20 @@ class VersionFunctionConfiguration: description: str role: str timeout: int - runtime: Runtime + runtime: Runtime | None memory_size: int - handler: str + handler: str | None package_type: PackageType - environment: dict[str, str] + environment: dict[str, str] | None architectures: list[Architecture] # internal revision is updated when runtime restart is necessary internal_revision: str ephemeral_storage: LambdaEphemeralStorage - snap_start: SnapStartResponse + snap_start: SnapStartResponse | None tracing_config_mode: TracingMode - code: ArchiveCode + # we need to use Union types as inheritance is not supported by serialization framework + code: S3Code | HotReloadingCode | None last_modified: str # ISO string state: VersionState @@ -568,6 +594,7 @@ class VersionFunctionConfiguration: vpc_config: VpcConfig | None = None logging_config: LoggingConfig = dataclasses.field(default_factory=dict) + capacity_provider_config: CapacityProviderConfig | None = None @dataclasses.dataclass(frozen=True) @@ -580,6 +607,34 @@ def qualified_arn(self) -> str: return self.id.qualified_arn() +class DesiredCapacityProviderState(StrEnum): + Running = "Running" + Stopped = "Stopped" + + +@dataclasses.dataclass +class CapacityProvider: + CapacityProviderArn: CapacityProviderArn + # State is determined dynamically based on DesiredState + VpcConfig: CapacityProviderVpcConfig + PermissionsConfig: CapacityProviderPermissionsConfig + InstanceRequirements: InstanceRequirements + CapacityProviderScalingConfig: CapacityProviderScalingConfig + LastModified: Timestamp + KmsKeyArn: KMSKeyArn | None = None + # Tracks whether the capacity provider should be running or stopped. + # Set to Stopped when deletion is initiated; used to skip restoration on state load. + DesiredState: DesiredCapacityProviderState = DesiredCapacityProviderState.Running + + +@dataclasses.dataclass +class FunctionScalingState: + """Tracks both applied and requested scaling configs for async updates.""" + + applied: FunctionScalingConfig = dataclasses.field(default_factory=dict) + requested: FunctionScalingConfig | None = None + + @dataclasses.dataclass class Function: function_name: str @@ -600,38 +655,17 @@ class Function: provisioned_concurrency_configs: dict[str, ProvisionedConcurrencyConfiguration] = ( dataclasses.field(default_factory=dict) ) + function_scaling_configs: dict[str, FunctionScalingState] = dataclasses.field( + default_factory=dict + ) lock: threading.RLock = dataclasses.field(default_factory=threading.RLock) next_version: int = 1 + instance_id: str = dataclasses.field(default_factory=short_uid, init=False) def latest(self) -> FunctionVersion: return self.versions["$LATEST"] - # HACK to model a volatile variable that should be ignored for persistence - def __post_init__(self): - # Identifier unique to this function and LocalStack instance. - # A LocalStack restart or persistence load should create a new instance id. - # Used for retaining invoke queues across version updates for $LATEST, but separate unrelated instances. - self.instance_id = short_uid() - - def __getstate__(self): - """Ignore certain volatile fields for pickling. - # https://docs.python.org/3/library/pickle.html#handling-stateful-objects - """ - # Copy the object's state from self.__dict__ which contains - # all our instance attributes. Always use the dict.copy() - # method to avoid modifying the original state. - state = self.__dict__.copy() - # Remove the volatile entries. - del state["instance_id"] - return state - - def __setstate__(self, state): - # Inject persistent state - self.__dict__.update(state) - # Create new instance id - self.__post_init__() - class ValidationException(CommonServiceException): def __init__(self, message: str): diff --git a/localstack-core/localstack/services/lambda_/invocation/lambda_service.py b/localstack-core/localstack/services/lambda_/invocation/lambda_service.py index 4722314fcc068..043171ab7fd0b 100644 --- a/localstack-core/localstack/services/lambda_/invocation/lambda_service.py +++ b/localstack-core/localstack/services/lambda_/invocation/lambda_service.py @@ -5,6 +5,7 @@ import logging import os.path import random +import time import uuid from concurrent.futures import Executor, Future, ThreadPoolExecutor from datetime import datetime @@ -19,6 +20,7 @@ InvalidRequestContentException, InvocationType, LastUpdateStatus, + NoPublishedVersionException, ResourceConflictException, ResourceNotFoundException, State, @@ -27,6 +29,7 @@ from localstack.constants import AWS_REGION_US_EAST_1 from localstack.services.lambda_ import hooks as lambda_hooks from localstack.services.lambda_.analytics import ( + FunctionInitializationType, FunctionOperation, FunctionStatus, function_counter, @@ -53,7 +56,7 @@ VersionAlias, VersionState, ) -from localstack.services.lambda_.invocation.models import lambda_stores +from localstack.services.lambda_.invocation.models import LambdaStore, lambda_stores from localstack.services.lambda_.invocation.version_manager import LambdaVersionManager from localstack.services.lambda_.lambda_utils import HINT_LOG from localstack.utils.archives import get_unzipped_size, is_zip_file @@ -190,6 +193,69 @@ def create_function_version(self, function_version: FunctionVersion) -> Future[N lambda_hooks.create_function_version.run(function_version.qualified_arn) return self.task_executor.submit(self._start_lambda_version, version_manager) + def publish_version_async(self, function_version: FunctionVersion): + self.task_executor.submit(self.publish_version, function_version) + + def delete_function_version_async( + self, function: Function, version: FunctionVersion, qualifier: str + ): + """ + Simulates async function cleanup after function deletion API is called + by introducing a small delay before actually removing the function from the store + to allow for getting the function details after deletion. + """ + + def _cleanup(): + time.sleep(0.5) + function.versions.pop(qualifier, None) + + new_state = VersionState(state=State.Deleting) + new_last_status = UpdateStatus(status=LastUpdateStatus.InProgress) + function.versions[version.id.qualifier] = dataclasses.replace( + version, + config=dataclasses.replace( + version.config, state=new_state, last_update=new_last_status + ), + ) + destroy_code_if_not_used(code=version.config.code, function=function) + + self.task_executor.submit(_cleanup) + + def delete_function_async(self, store: LambdaStore, function_name: str): + """ + Simulates async function version cleanup after function deletion API is called + by introducing a small delay before actually removing the function from the store + to allow for getting the function version details after deletion. + """ + + def _cleanup(): + time.sleep(0.5) + store.functions.pop(function_name) + + # set each version of the function to deleting state first, to allow for getting the function version details after deletion + function = store.functions.get(function_name) + if function: + for version in function.versions.values(): + new_state = VersionState(state=State.Deleting) + new_last_status = UpdateStatus(status=LastUpdateStatus.InProgress) + previous_revision_id = version.config.revision_id + + function.versions[version.id.qualifier] = dataclasses.replace( + version, + config=dataclasses.replace( + version.config, state=new_state, last_update=new_last_status + ), + ) + # Seems the revision id doesn't change when deleting a function right after it has been created (even though state has changed) + # reassign revision id to avoid dataclass replace removing it, since it's init=False + object.__setattr__( + function.versions[version.id.qualifier].config, + "revision_id", + previous_revision_id, + ) + + self.task_executor.submit(_cleanup) + def publish_version(self, function_version: FunctionVersion): """ Synchronously create a function version (manager) @@ -200,6 +266,14 @@ def publish_version(self, function_version: FunctionVersion): :param function_version: Function Version to create """ + # HACK: trying to match the AWS timing behavior of Lambda Managed Instances for the operation + # publish_version followed by get_function because transitioning LastUpdateStatus from InProgress to + # Successful happens too fast on LocalStack (thanks to caching in prepare_version). + # Without this hack, test_latest_published_update_config fails at get_function_response_postpublish + # and test_lifecycle_invoke is flaky, sometimes not triggering the ResourceConflictException + # Increasing this sleep too much (e.g., 10s) shouldn't cause any side effects apart from slow responsiveness + if function_version.config.capacity_provider_config: + time.sleep(0.1) with self.lambda_version_manager_lock: qualified_arn = function_version.id.qualified_arn() version_manager = self.lambda_starting_versions.get(qualified_arn) @@ -225,7 +299,7 @@ def publish_version(self, function_version: FunctionVersion): def invoke( self, function_name: str, - qualifier: str, + qualifier: str | None, region: str, account_id: str, invocation_type: InvocationType | None, @@ -258,13 +332,27 @@ def invoke( account=account_id, region=region, ) - qualifier = qualifier or "$LATEST" state = lambda_stores[account_id][region] function = state.functions.get(function_name) if function is None: + if not qualifier: + invoked_arn += ":$LATEST" raise ResourceNotFoundException(f"Function not found: {invoked_arn}", Type="User") + # A provided qualifier always takes precedence, but the default depends on whether $LATEST.PUBLISHED exists + version_latest_published = function.versions.get("$LATEST.PUBLISHED") + if version_latest_published: + qualifier = qualifier or "$LATEST.PUBLISHED" + invoked_arn = lambda_arn( + function_name=function_name, + qualifier=qualifier, + account=account_id, + region=region, + ) + else: + qualifier = qualifier or "$LATEST" + if qualifier_is_alias(qualifier): alias = function.aliases.get(qualifier) if not alias: @@ -282,8 +370,27 @@ def invoke( # Need the qualified arn to exactly get the target lambda qualified_arn = qualified_lambda_arn(function_name, version_qualifier, account_id, region) version = function.versions.get(version_qualifier) + if version is None: + raise ResourceNotFoundException(f"Function not found: {invoked_arn}", Type="User") runtime = version.config.runtime or "n/a" package_type = version.config.package_type + # Not considering provisioned concurrency for such early errors + initialization_type = ( + FunctionInitializationType.lambda_managed_instances + if version.config.capacity_provider_config + else FunctionInitializationType.on_demand + ) + if version.config.capacity_provider_config and qualifier == "$LATEST": + if function.versions.get("$LATEST.PUBLISHED"): + raise InvalidParameterValueException( + "Functions configured with capacity provider configuration can't be invoked with $LATEST qualifier. To invoke this function, specify a published version qualifier or $LATEST.PUBLISHED.", + Type="User", + ) + else: + raise NoPublishedVersionException( + "The function can't be invoked because no published version exists. For functions with capacity provider configuration, either publish a version to $LATEST.PUBLISHED, or specify a published version qualifier.", + Type="User", + ) try: version_manager = self.get_lambda_version_manager(qualified_arn) event_manager = self.get_lambda_event_manager(qualified_arn) @@ -315,6 +422,7 @@ def invoke( status=status, invocation_type=invocation_type, package_type=package_type, + initialization_type=initialization_type, ).increment() raise ResourceConflictException( f"The operation cannot be performed at this time. The function is currently in the following state: {state}" @@ -333,6 +441,7 @@ def invoke( status=FunctionStatus.invalid_payload_error, invocation_type=invocation_type, package_type=package_type, + initialization_type=initialization_type, ).increment() # MAYBE: improve parity of detailed exception message (quite cumbersome) raise InvalidRequestContentException( @@ -377,12 +486,14 @@ def invoke( if invocation_result.is_error else FunctionStatus.success ) + # TODO: handle initialization_type provisioned-concurrency, requires enriching invocation_result function_counter.labels( operation=FunctionOperation.invoke, runtime=runtime, status=status, invocation_type=invocation_type, package_type=package_type, + initialization_type=initialization_type, ).increment() return invocation_result @@ -393,7 +504,15 @@ def update_version(self, new_version: FunctionVersion) -> Future[None]: :param new_version: New version (with the same qualifier as an older one) """ - if new_version.qualified_arn not in self.lambda_running_versions: + if new_version.config.capacity_provider_config: + # simulate AWS behavior with a slight delay after update_function_configuration, + # so we can observe LastUpdateStatus transitioning to InProgress before it becomes Successful + time.sleep(0.5) + + if ( + new_version.qualified_arn not in self.lambda_running_versions + and not new_version.config.capacity_provider_config + ): raise ValueError( f"Version {new_version.qualified_arn} cannot be updated if an old one is not running" ) @@ -437,6 +556,11 @@ def update_version_state( elif new_state.state == State.Failed: update_status = UpdateStatus(status=LastUpdateStatus.Failed) self.task_executor.submit(new_version_manager.stop) + elif ( + new_state.state == State.ActiveNonInvocable + and function_version.config.capacity_provider_config + ): + update_status = UpdateStatus(status=LastUpdateStatus.Successful) else: # TODO what to do if state pending or inactive is supported? self.task_executor.submit(new_version_manager.stop) diff --git a/localstack-core/localstack/services/lambda_/invocation/models.py b/localstack-core/localstack/services/lambda_/invocation/models.py index bc0eef5e7ebf0..c10f97650ddc3 100644 --- a/localstack-core/localstack/services/lambda_/invocation/models.py +++ b/localstack-core/localstack/services/lambda_/invocation/models.py @@ -1,7 +1,12 @@ from localstack.aws.api.lambda_ import EventSourceMappingConfiguration -from localstack.services.lambda_.invocation.lambda_models import CodeSigningConfig, Function, Layer +from localstack.services.lambda_.invocation.lambda_models import ( + CapacityProvider, + CodeSigningConfig, + Function, + Layer, +) from localstack.services.stores import AccountRegionBundle, BaseStore, LocalAttribute -from localstack.utils.tagging import TaggingService +from localstack.utils.tagging import Tags class LambdaStore(BaseStore): @@ -17,8 +22,11 @@ class LambdaStore(BaseStore): # maps layer names to Layers layers: dict[str, Layer] = LocalAttribute(default=dict) + # maps capacity provider names to respective CapacityProvider + capacity_providers: dict[str, CapacityProvider] = LocalAttribute(default=dict) + # maps resource ARNs for EventSourceMappings and CodeSigningConfiguration to tags - TAGS = LocalAttribute(default=TaggingService) + tags: Tags = LocalAttribute(default=Tags) lambda_stores = AccountRegionBundle("lambda", LambdaStore) diff --git a/localstack-core/localstack/services/lambda_/invocation/version_manager.py b/localstack-core/localstack/services/lambda_/invocation/version_manager.py index 75fdfad3783d1..dec627bb8a27c 100644 --- a/localstack-core/localstack/services/lambda_/invocation/version_manager.py +++ b/localstack-core/localstack/services/lambda_/invocation/version_manager.py @@ -3,7 +3,7 @@ import threading import time from concurrent.futures import Future -from concurrent.futures._base import CancelledError +from concurrent.futures._base import ALL_COMPLETED, CancelledError from localstack import config from localstack.aws.api.lambda_ import ( @@ -79,10 +79,10 @@ def __init__( self.shutdown_event = threading.Event() # async state - self.provisioned_state = None + self.provisioned_state: ProvisionedConcurrencyState | None = None self.provisioned_state_lock = threading.RLock() # https://aws.amazon.com/blogs/compute/coming-soon-expansion-of-aws-lambda-states-to-all-functions/ - self.state = VersionState(state=State.Pending) + self.state: VersionState = VersionState(state=State.Pending) self.ldm_provisioner = None lambda_hooks.inject_ldm_provisioner.run(self) @@ -100,11 +100,26 @@ def start(self) -> VersionState: # code and reason not set for success scenario because only failed states provide this field: # https://docs.aws.amazon.com/lambda/latest/dg/API_GetFunctionConfiguration.html#SSS-GetFunctionConfiguration-response-LastUpdateStatusReasonCode - self.state = VersionState(state=State.Active) + new_state = State.Active + if ( + self.function_version.config.capacity_provider_config + and self.function_version.id.qualifier == "$LATEST" + ): + new_state = State.ActiveNonInvocable + # HACK: trying to match the AWS timing behavior of Lambda Managed Instances for the operation + # update_function_configuration followed by get_function because transitioning LastUpdateStatus from + # InProgress to Successful happens too fast on LocalStack (thanks to caching in prepare_version). + # Without this hack, test_latest_published_update_config fails at get_function_response_postupdate_latest + # TODO: this sleep has side-effects and we should be looking into alternatives + # Increasing this sleep too much (e.g., 3s) could cause the side effect that a created function is not + # ready for updates (i.e., rejected with a ResourceConflictException) and failing other tests + # time.sleep(0.1) + self.state = VersionState(state=new_state) LOG.debug( - "Changing Lambda %s (id %s) to active", + "Changing Lambda %s (id %s) to %s", self.function_arn, self.function_version.config.internal_revision, + new_state, ) except Exception as e: self.state = VersionState( @@ -113,7 +128,7 @@ def start(self) -> VersionState: reason=f"Error while creating lambda: {e}", ) LOG.debug( - "Changing Lambda %s (id %s) to failed. Reason: %s", + "Changing Lambda %s (id %s) to Failed. Reason: %s", self.function_arn, self.function_version.config.internal_revision, e, @@ -138,8 +153,6 @@ def update_provisioned_concurrency_config( TODO: implement update while in progress (see test_provisioned_concurrency test) TODO: loop until diff == 0 and retry to remove/add diff environments TODO: alias routing & allocated (i.e., the status while updating provisioned concurrency) - TODO: ProvisionedConcurrencyStatusEnum.FAILED - TODO: status reason :param provisioned_concurrent_executions: set to 0 to stop all provisioned environments """ @@ -160,16 +173,37 @@ def scale_environments(*args, **kwargs) -> None: futures = self.assignment_service.scale_provisioned_concurrency( self.id, self.function_version, provisioned_concurrent_executions ) + # Wait for all provisioning/de-provisioning tasks to finish using a timeout longer than max Lambda execution + concurrent.futures.wait(futures, timeout=20 * 60, return_when=ALL_COMPLETED) - concurrent.futures.wait(futures) + success_count = 0 + start_error = None + for i, future in enumerate(futures): + try: + future.result() + success_count += 1 + except Exception as e: + start_error = e with self.provisioned_state_lock: if provisioned_concurrent_executions == 0: self.provisioned_state = None else: - self.provisioned_state.available = provisioned_concurrent_executions - self.provisioned_state.allocated = provisioned_concurrent_executions - self.provisioned_state.status = ProvisionedConcurrencyStatusEnum.READY + # TODO: check whether available changes with active invokes while updating + self.provisioned_state.available = success_count + self.provisioned_state.allocated = success_count + if start_error or success_count < provisioned_concurrent_executions: + self.provisioned_state.status = ProvisionedConcurrencyStatusEnum.FAILED + self.provisioned_state.status_reason = "FUNCTION_ERROR_INIT_FAILURE" + LOG.warning( + "Failed to provision %d/%s environments for function %s. Error: %s", + provisioned_concurrent_executions - success_count, + provisioned_concurrent_executions, + self.function_arn, + start_error, + ) + else: + self.provisioned_state.status = ProvisionedConcurrencyStatusEnum.READY self.provisioning_thread = start_thread(scale_environments) return self.provisioning_thread.result_future @@ -240,7 +274,7 @@ def invoke(self, *, invocation: Invocation) -> InvocationResult: return invocation_result with self.counting_service.get_invocation_lease( - self.function, self.function_version + self.function, self.function_version, self.provisioned_state ) as provisioning_type: # TODO: potential race condition when changing provisioned concurrency after getting the lease but before # getting an environment diff --git a/localstack-core/localstack/services/lambda_/packages.py b/localstack-core/localstack/services/lambda_/packages.py index d580ace02153f..c0f1a6c0a83dc 100644 --- a/localstack-core/localstack/services/lambda_/packages.py +++ b/localstack-core/localstack/services/lambda_/packages.py @@ -12,7 +12,7 @@ """Customized LocalStack version of the AWS Lambda Runtime Interface Emulator (RIE). https://github.com/localstack/lambda-runtime-init/blob/localstack/README-LOCALSTACK.md """ -LAMBDA_RUNTIME_DEFAULT_VERSION = "v0.1.35-pre" +LAMBDA_RUNTIME_DEFAULT_VERSION = "v0.1.41-pre" LAMBDA_RUNTIME_VERSION = config.LAMBDA_INIT_RELEASE_VERSION or LAMBDA_RUNTIME_DEFAULT_VERSION LAMBDA_RUNTIME_INIT_URL = "https://github.com/localstack/lambda-runtime-init/releases/download/{version}/aws-lambda-rie-{arch}" @@ -66,7 +66,10 @@ def _install(self, target: InstallTarget) -> None: super()._install(target) install_location = self.get_executable_path() st = os.stat(install_location) - os.chmod(install_location, mode=st.st_mode | stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH) + os.chmod( + install_location, + mode=st.st_mode | stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH, + ) # TODO: replace usage in LocalStack tests with locally built Java jar and remove this unmaintained dependency. diff --git a/localstack-core/localstack/services/lambda_/provider.py b/localstack-core/localstack/services/lambda_/provider.py index ff86ec7e9faac..51d0d78393f1d 100644 --- a/localstack-core/localstack/services/lambda_/provider.py +++ b/localstack-core/localstack/services/lambda_/provider.py @@ -27,6 +27,7 @@ Arn, Blob, BlobStream, + CapacityProviderConfig, CodeSigningConfigArn, CodeSigningConfigNotFoundException, CodeSigningPolicies, @@ -39,8 +40,10 @@ CreateFunctionRequest, CreateFunctionUrlConfigResponse, DeleteCodeSigningConfigResponse, + DeleteFunctionResponse, Description, DestinationConfig, + DurableExecutionName, EventSourceMappingConfiguration, FunctionCodeLocation, FunctionConfiguration, @@ -48,6 +51,7 @@ FunctionName, FunctionUrlAuthType, FunctionUrlQualifier, + FunctionVersionLatestPublished, GetAccountSettingsResponse, GetCodeSigningConfigResponse, GetFunctionCodeSigningConfigResponse, @@ -65,6 +69,7 @@ InvokeAsyncResponse, InvokeMode, LambdaApi, + LambdaManagedInstancesCapacityProviderConfig, LastUpdateStatus, LayerName, LayerPermissionAllowedAction, @@ -99,6 +104,7 @@ MaxProvisionedConcurrencyConfigListItems, NamespacedFunctionName, NamespacedStatementId, + NumericLatestPublishedOrAliasQualifier, OnFailure, OnSuccess, OrganizationId, @@ -130,6 +136,7 @@ TaggableResource, TagKeyList, Tags, + TenantId, TracingMode, UnqualifiedFunctionName, UpdateCodeSigningConfigResponse, @@ -137,7 +144,7 @@ UpdateFunctionCodeRequest, UpdateFunctionConfigurationRequest, UpdateFunctionUrlConfigResponse, - Version, + VersionWithLatestPublished, ) from localstack.aws.api.lambda_ import FunctionVersion as FunctionVersionApi from localstack.aws.api.lambda_ import ServiceException as LambdaServiceException @@ -151,6 +158,7 @@ from localstack.services.lambda_ import api_utils from localstack.services.lambda_ import hooks as lambda_hooks from localstack.services.lambda_.analytics import ( + FunctionInitializationType, FunctionOperation, FunctionStatus, function_counter, @@ -179,6 +187,7 @@ from localstack.services.lambda_.invocation.lambda_models import ( AliasRoutingConfig, CodeSigningConfig, + DesiredCapacityProviderState, EventInvokeConfig, Function, FunctionResourcePolicy, @@ -209,6 +218,7 @@ store_lambda_archive, store_s3_bucket_archive, ) +from localstack.services.lambda_.invocation.models import CapacityProvider as CapacityProviderModel from localstack.services.lambda_.invocation.models import LambdaStore from localstack.services.lambda_.invocation.runtime_executor import get_runtime_executor from localstack.services.lambda_.lambda_utils import HINT_LOG @@ -224,6 +234,7 @@ DEPRECATED_RUNTIMES_UPGRADES, RUNTIMES_AGGREGATED, SNAP_START_SUPPORTED_RUNTIMES, + VALID_MANAGED_INSTANCE_RUNTIMES, VALID_RUNTIMES, ) from localstack.services.lambda_.urlrouter import FunctionUrlRouter @@ -231,6 +242,7 @@ from localstack.state import StateVisitor from localstack.utils.aws.arns import ( ArnData, + capacity_provider_arn, extract_resource_from_arn, extract_service_from_arn, get_partition, @@ -239,7 +251,7 @@ ) from localstack.utils.aws.client_types import ServicePrincipal from localstack.utils.bootstrap import is_api_enabled -from localstack.utils.collections import PaginatedList +from localstack.utils.collections import PaginatedList, merge_recursive from localstack.utils.event_matcher import validate_event_pattern from localstack.utils.strings import get_random_hex, short_uid, to_bytes, to_str from localstack.utils.sync import poll_condition @@ -247,6 +259,7 @@ LOG = logging.getLogger(__name__) +CAPACITY_PROVIDER_ARN_NAME = "arn:aws[a-zA-Z-]*:lambda:(eusc-)?[a-z]{2}((-gov)|(-iso([a-z]?)))?-[a-z]+-\\d{1}:\\d{12}:capacity-provider:[a-zA-Z0-9-_]+" LAMBDA_DEFAULT_TIMEOUT = 3 LAMBDA_DEFAULT_MEMORY_SIZE = 128 @@ -280,6 +293,9 @@ def accept_state_visitor(self, visitor: StateVisitor): visitor.visit(lambda_stores) def on_before_state_reset(self): + for esm_worker in self.esm_workers.values(): + esm_worker.stop_for_shutdown() + self.esm_workers = {} self.lambda_service.stop() def on_after_state_reset(self): @@ -295,20 +311,48 @@ def on_after_state_load(self): for account_id, account_bundle in lambda_stores.items(): for region_name, state in account_bundle.items(): for fn in state.functions.values(): + # HACK to model a volatile variable that should be ignored for persistence + # Identifier unique to this function and LocalStack instance. + # A LocalStack restart or persistence load should create a new instance id. + # Used for retaining invoke queues across version updates for $LATEST, but + # separate unrelated instances. + fn.instance_id = short_uid() + for fn_version in fn.versions.values(): - # restore the "Pending" state for every function version and start it try: - new_state = VersionState( - state=State.Pending, - code=StateReasonCode.Creating, - reason="The function is being created.", - ) - new_config = dataclasses.replace(fn_version.config, state=new_state) - new_version = dataclasses.replace(fn_version, config=new_config) - fn.versions[fn_version.id.qualifier] = new_version - self.lambda_service.create_function_version(fn_version).result( - timeout=5 + # Skip function versions that were being deleted + if fn_version.config.state.state == State.Deleting: + continue + + # Skip function versions whose capacity provider has been stopped + if fn_version.config.capacity_provider_config: + cp_arn = fn_version.config.capacity_provider_config[ + "LambdaManagedInstancesCapacityProviderConfig" + ]["CapacityProviderArn"] + cp_name = cp_arn.split(":")[-1] + cp = state.capacity_providers.get(cp_name) + if cp and cp.DesiredState == DesiredCapacityProviderState.Stopped: + continue + + # $LATEST is not invokable for Lambda functions with a capacity provider + # and has a different State (i.e., ActiveNonInvokable) + is_capacity_provider_latest = ( + fn_version.config.capacity_provider_config + and fn_version.id.qualifier == "$LATEST" ) + if not is_capacity_provider_latest: + # Restore the "Pending" state for the function version and start it + new_state = VersionState( + state=State.Pending, + code=StateReasonCode.Creating, + reason="The function is being created.", + ) + new_config = dataclasses.replace(fn_version.config, state=new_state) + new_version = dataclasses.replace(fn_version, config=new_config) + fn.versions[fn_version.id.qualifier] = new_version + self.lambda_service.create_function_version(fn_version).result( + timeout=5 + ) except Exception: LOG.warning( "Failed to restore function version %s", @@ -354,8 +398,10 @@ def on_after_state_load(self): # TODO: How do we know the event source is up? # A basic poll to see if the mapped Lambda function is active/failed if not poll_condition( - lambda: get_function_version_from_arn(function_arn).config.state.state - in [State.Active, State.Failed], + lambda: ( + get_function_version_from_arn(function_arn).config.state.state + in [State.Active, State.Failed] + ), timeout=10, ): LOG.warning( @@ -419,6 +465,23 @@ def _get_esm(uuid: str, account_id: str, region: str) -> EventSourceMappingConfi ) return esm + @staticmethod + def _get_capacity_provider( + capacity_provider_name: str, + account_id: str, + region: str, + error_msg_template: str = "Capacity provider not found: {}", + ) -> CapacityProviderModel: + state = lambda_stores[account_id][region] + cp = state.capacity_providers.get(capacity_provider_name) + if not cp: + arn = capacity_provider_arn(capacity_provider_name, account_id, region) + raise ResourceNotFoundException( + error_msg_template.format(arn), + Type="User", + ) + return cp + @staticmethod def _validate_qualifier_expression(qualifier: str) -> None: if error_messages := api_utils.validate_qualifier(qualifier): @@ -426,6 +489,13 @@ def _validate_qualifier_expression(qualifier: str) -> None: message=api_utils.construct_validation_exception_message(error_messages) ) + @staticmethod + def _validate_publish_to(publish_to: str): + if publish_to != FunctionVersionLatestPublished.LATEST_PUBLISHED: + raise ValidationException( + message=f"1 validation error detected: Value '{publish_to}' at 'publishTo' failed to satisfy constraint: Member must satisfy enum value set: [LATEST_PUBLISHED]" + ) + @staticmethod def _resolve_fn_qualifier(resolved_fn: Function, qualifier: str | None) -> tuple[str, str]: """Attempts to resolve a given qualifier and returns a qualifier that exists or @@ -489,7 +559,7 @@ def _build_vpc_config( subnet_id = subnet_ids[0] if not bool(SUBNET_ID_REGEX.match(subnet_id)): raise ValidationException( - f"1 validation error detected: Value '[{subnet_id}]' at 'vpcConfig.subnetIds' failed to satisfy constraint: Member must satisfy constraint: [Member must have length less than or equal to 1024, Member must have length greater than or equal to 0, Member must satisfy regular expression pattern: ^subnet-[0-9a-z]*$]" + f"1 validation error detected: Value '[{subnet_id}]' at 'vpcConfig.subnetIds' failed to satisfy constraint: Member must satisfy constraint: [Member must have length less than or equal to 1024, Member must have length greater than or equal to 0, Member must satisfy regular expression pattern: subnet-[0-9a-z]*]" ) return VpcConfig( @@ -506,6 +576,8 @@ def _create_version_model( description: str | None = None, revision_id: str | None = None, code_sha256: str | None = None, + publish_to: FunctionVersionLatestPublished | None = None, + is_active: bool = False, ) -> tuple[FunctionVersion, bool]: """ Release a new version to the model if all restrictions are met. @@ -568,38 +640,57 @@ def _create_version_model( ): return prev_version, False # TODO check if there was a change since last version - next_version = str(function.next_version) - function.next_version += 1 + if publish_to == FunctionVersionLatestPublished.LATEST_PUBLISHED: + qualifier = "$LATEST.PUBLISHED" + else: + qualifier = str(function.next_version) + function.next_version += 1 new_id = VersionIdentifier( function_name=function_name, - qualifier=next_version, + qualifier=qualifier, region=region, account=account_id, ) - apply_on = current_latest_version.config.snap_start["ApplyOn"] - optimization_status = SnapStartOptimizationStatus.Off - if apply_on == SnapStartApplyOn.PublishedVersions: - optimization_status = SnapStartOptimizationStatus.On - snap_start = SnapStartResponse( - ApplyOn=apply_on, - OptimizationStatus=optimization_status, + + if current_latest_version.config.capacity_provider_config: + # for lambda managed functions, snap start is not supported + snap_start = None + else: + apply_on = current_latest_version.config.snap_start["ApplyOn"] + optimization_status = SnapStartOptimizationStatus.Off + if apply_on == SnapStartApplyOn.PublishedVersions: + optimization_status = SnapStartOptimizationStatus.On + snap_start = SnapStartResponse( + ApplyOn=apply_on, + OptimizationStatus=optimization_status, + ) + + last_update = None + new_state = VersionState( + state=State.Pending, + code=StateReasonCode.Creating, + reason="The function is being created.", ) + if publish_to == FunctionVersionLatestPublished.LATEST_PUBLISHED: + last_update = UpdateStatus( + status=LastUpdateStatus.InProgress, + code="Updating", + reason="The function is being updated.", + ) + if is_active: + new_state = VersionState(state=State.Active) new_version = dataclasses.replace( current_latest_version, config=dataclasses.replace( current_latest_version.config, - last_update=None, # versions never have a last update status - state=VersionState( - state=State.Pending, - code=StateReasonCode.Creating, - reason="The function is being created.", - ), + last_update=last_update, + state=new_state, snap_start=snap_start, **changes, ), id=new_id, ) - function.versions[next_version] = new_version + function.versions[qualifier] = new_version return new_version, True def _publish_version_from_existing_version( @@ -610,6 +701,7 @@ def _publish_version_from_existing_version( description: str | None = None, revision_id: str | None = None, code_sha256: str | None = None, + publish_to: FunctionVersionLatestPublished | None = None, ) -> FunctionVersion: """ Publish version from an existing, already initialized LATEST @@ -622,6 +714,7 @@ def _publish_version_from_existing_version( :param code_sha256: code sha (check if current code matches) :return: new version """ + is_active = True if publish_to == FunctionVersionLatestPublished.LATEST_PUBLISHED else False new_version, changed = self._create_version_model( function_name=function_name, region=region, @@ -629,18 +722,34 @@ def _publish_version_from_existing_version( description=description, revision_id=revision_id, code_sha256=code_sha256, + publish_to=publish_to, + is_active=is_active, ) if not changed: return new_version - self.lambda_service.publish_version(new_version) + + if new_version.config.capacity_provider_config: + self.lambda_service.publish_version_async(new_version) + else: + self.lambda_service.publish_version(new_version) state = lambda_stores[account_id][region] function = state.functions.get(function_name) + + # Update revision id for $LATEST version # TODO: re-evaluate data model to prevent this dirty hack just for bumping the revision id latest_version = function.versions["$LATEST"] function.versions["$LATEST"] = dataclasses.replace( latest_version, config=dataclasses.replace(latest_version.config) ) - return function.versions.get(new_version.id.qualifier) + if new_version.config.capacity_provider_config: + # publish_version happens async for functions with a capacity provider. + # Therefore, we return the new_version with State=Pending or LastUpdateStatus=InProgress ($LATEST.PUBLISHED) + return new_version + else: + # Regular functions yield an Active state modified during `publish_version` (sync). + # Therefore, we need to get the updated version from the store. + updated_version = function.versions.get(new_version.id.qualifier) + return updated_version def _publish_version_with_changes( self, @@ -650,6 +759,8 @@ def _publish_version_with_changes( description: str | None = None, revision_id: str | None = None, code_sha256: str | None = None, + publish_to: FunctionVersionLatestPublished | None = None, + is_active: bool = False, ) -> FunctionVersion: """ Publish version together with a new latest version (publish on create / update) @@ -669,6 +780,8 @@ def _publish_version_with_changes( description=description, revision_id=revision_id, code_sha256=code_sha256, + publish_to=publish_to, + is_active=is_active, ) if not changed: return new_version @@ -720,7 +833,8 @@ def _validate_layers(self, new_layers: list[str], region: str, account_id: str): if layer_version_str is None: raise ValidationException( f"1 validation error detected: Value '[{layer_version_arn}]'" - + r" at 'layers' failed to satisfy constraint: Member must satisfy constraint: [Member must have length less than or equal to 140, Member must have length greater than or equal to 1, Member must satisfy regular expression pattern: (arn:[a-zA-Z0-9-]+:lambda:[a-z]{2}((-gov)|(-iso(b?)))?-[a-z]+-\d{1}:\d{12}:layer:[a-zA-Z0-9-_]+:[0-9]+)|(arn:[a-zA-Z0-9-]+:lambda:::awslayer:[a-zA-Z0-9-_]+), Member must not be null]", + + " at 'layers' failed to satisfy constraint: Member must satisfy constraint: [Member must have length less than or equal to 2048, Member must have length greater than or equal to 1, Member must satisfy regular expression pattern: " + + "(arn:(aws[a-zA-Z-]*)?:lambda:(eusc-)?[a-z]{2}((-gov)|(-iso([a-z]?)))?-[a-z]+-\\d{1}:\\d{12}:layer:[a-zA-Z0-9-_]+:[0-9]+)|(arn:[a-zA-Z0-9-]+:lambda:::awslayer:[a-zA-Z0-9-_]+), Member must not be null]", ) state = lambda_stores[layer_account_id][layer_region] @@ -783,6 +897,30 @@ def _validate_layers(self, new_layers: list[str], region: str, account_id: str): ) visited_layers[layer_arn] = layer_version_arn + def _validate_capacity_provider_config( + self, capacity_provider_config: CapacityProviderConfig, context: RequestContext + ): + if not capacity_provider_config.get("LambdaManagedInstancesCapacityProviderConfig"): + raise ValidationException( + "1 validation error detected: Value null at 'capacityProviderConfig.lambdaManagedInstancesCapacityProviderConfig' failed to satisfy constraint: Member must not be null" + ) + + capacity_provider_arn = capacity_provider_config.get( + "LambdaManagedInstancesCapacityProviderConfig", {} + ).get("CapacityProviderArn") + if not capacity_provider_arn: + raise ValidationException( + "1 validation error detected: Value null at 'capacityProviderConfig.lambdaManagedInstancesCapacityProviderConfig.capacityProviderArn' failed to satisfy constraint: Member must not be null" + ) + + if not re.match(CAPACITY_PROVIDER_ARN_NAME, capacity_provider_arn): + raise ValidationException( + f"1 validation error detected: Value '{capacity_provider_arn}' at 'capacityProviderConfig.lambdaManagedInstancesCapacityProviderConfig.capacityProviderArn' failed to satisfy constraint: Member must satisfy regular expression pattern: {CAPACITY_PROVIDER_ARN_NAME}" + ) + + capacity_provider_name = capacity_provider_arn.split(":")[-1] + self.get_capacity_provider(context, capacity_provider_name) + @staticmethod def map_layers(new_layers: list[str]) -> list[LayerVersion]: layers = [] @@ -837,7 +975,7 @@ def create_function( context_region = context.region context_account_id = context.account_id - zip_file = request.get("Code", {}).get("ZipFile") + zip_file = (request.get("Code") or {}).get("ZipFile") if zip_file and len(zip_file) > config.LAMBDA_LIMITS_CODE_SIZE_ZIPPED: raise RequestEntityTooLargeException( f"Zipped size must be smaller than {config.LAMBDA_LIMITS_CODE_SIZE_ZIPPED} bytes" @@ -898,6 +1036,8 @@ def create_function( ) if snap_start := request.get("SnapStart"): self._validate_snapstart(snap_start, runtime) + if publish_to := request.get("PublishTo"): + self._validate_publish_to(publish_to) state = lambda_stores[context_account_id][context_region] with self.create_fn_lock: @@ -919,7 +1059,7 @@ def create_function( # Potential implementation: provide (cached) sha256 hash of used Docker image RuntimeVersionArn=f"arn:{context.partition}:lambda:{context_region}::runtime:8eeff65f6809a3ce81507fe733fe09b835899b99481ba22fd75b5a7338290ec1" ) - request_code = request.get("Code") + request_code = request.get("Code") or {} if package_type == PackageType.Zip: # TODO verify if correct combination of code is set if zip_file := request_code.get("ZipFile"): @@ -941,14 +1081,16 @@ def create_function( account_id=context_account_id, ) else: - raise LambdaServiceException("Gotta have s3 bucket or zip file") + raise LambdaServiceException("A ZIP file or S3 bucket is required") elif package_type == PackageType.Image: image = request_code.get("ImageUri") if not image: - raise LambdaServiceException("Gotta have an image when package type is image") + raise LambdaServiceException( + "An image is required when the package type is set to 'image'" + ) image = create_image_code(image_uri=image) - image_config_req = request.get("ImageConfig", {}) + image_config_req = request.get("ImageConfig") or {} image_config = ImageConfig( command=image_config_req.get("Command"), entrypoint=image_config_req.get("EntryPoint"), @@ -956,6 +1098,27 @@ def create_function( ) # Runtime management controls are not available when providing a custom image runtime_version_config = None + + capacity_provider_config = None + memory_size = request.get("MemorySize", LAMBDA_DEFAULT_MEMORY_SIZE) + if "CapacityProviderConfig" in request: + capacity_provider_config = request["CapacityProviderConfig"] + self._validate_capacity_provider_config(capacity_provider_config, context) + self._validate_managed_instances_runtime(runtime) + + default_config = CapacityProviderConfig( + LambdaManagedInstancesCapacityProviderConfig=LambdaManagedInstancesCapacityProviderConfig( + ExecutionEnvironmentMemoryGiBPerVCpu=2.0, + PerExecutionEnvironmentMaxConcurrency=16, + ) + ) + capacity_provider_config = merge_recursive(default_config, capacity_provider_config) + memory_size = 2048 + if (request.get("LoggingConfig") or {}).get("LogFormat") == LogFormat.Text: + raise InvalidParameterValueException( + 'LogLevel is not supported when LogFormat is set to "Text". Remove LogLevel from your request or change the LogFormat to "JSON" and try again.', + Type="User", + ) if "LoggingConfig" in request: logging_config = request["LoggingConfig"] LOG.warning( @@ -979,11 +1142,25 @@ def create_function( | logging_config ) + elif capacity_provider_config: + logging_config = LoggingConfig( + LogFormat=LogFormat.JSON, + LogGroup=f"/aws/lambda/{function_name}", + ApplicationLogLevel="INFO", + SystemLogLevel="INFO", + ) else: logging_config = LoggingConfig( LogFormat=LogFormat.Text, LogGroup=f"/aws/lambda/{function_name}" ) - + snap_start = ( + None + if capacity_provider_config + else SnapStartResponse( + ApplyOn=request.get("SnapStart", {}).get("ApplyOn", SnapStartApplyOn.None_), + OptimizationStatus=SnapStartOptimizationStatus.Off, + ) + ) version = FunctionVersion( id=arn, config=VersionFunctionConfiguration( @@ -992,7 +1169,7 @@ def create_function( role=request["Role"], timeout=request.get("Timeout", LAMBDA_DEFAULT_TIMEOUT), runtime=request.get("Runtime"), - memory_size=request.get("MemorySize", LAMBDA_DEFAULT_MEMORY_SIZE), + memory_size=memory_size, handler=request.get("Handler"), package_type=package_type, environment=env_vars, @@ -1008,10 +1185,7 @@ def create_function( ephemeral_storage=LambdaEphemeralStorage( size=request.get("EphemeralStorage", {}).get("Size", 512) ), - snap_start=SnapStartResponse( - ApplyOn=request.get("SnapStart", {}).get("ApplyOn", SnapStartApplyOn.None_), - OptimizationStatus=SnapStartOptimizationStatus.Off, - ), + snap_start=snap_start, runtime_version_config=runtime_version_config, dead_letter_arn=request.get("DeadLetterConfig", {}).get("TargetArn"), vpc_config=self._build_vpc_config( @@ -1023,18 +1197,40 @@ def create_function( reason="The function is being created.", ), logging_config=logging_config, + # TODO: might need something like **optional_kwargs if None + # -> Test with regular GetFunction (i.e., without a capacity provider) + capacity_provider_config=capacity_provider_config, ), ) - fn.versions["$LATEST"] = version + version_post_response = None + if capacity_provider_config: + version_post_response = dataclasses.replace( + version, + config=dataclasses.replace( + version.config, + last_update=UpdateStatus(status=LastUpdateStatus.Successful), + state=VersionState(state=State.ActiveNonInvocable), + ), + ) + fn.versions["$LATEST"] = version_post_response or version state.functions[function_name] = fn + initialization_type = ( + FunctionInitializationType.lambda_managed_instances + if capacity_provider_config + else FunctionInitializationType.on_demand + ) function_counter.labels( operation=FunctionOperation.create, runtime=runtime or "n/a", status=FunctionStatus.success, invocation_type="n/a", package_type=package_type, + initialization_type=initialization_type, ) - self.lambda_service.create_function_version(version) + # TODO: consider potential other side effects of not having a function version for $LATEST + # Provisioning happens upon publishing for functions using a capacity provider + if not capacity_provider_config: + self.lambda_service.create_function_version(version) if tags := request.get("Tags"): # This will check whether the function exists. @@ -1042,16 +1238,21 @@ def create_function( if request.get("Publish"): version = self._publish_version_with_changes( - function_name=function_name, region=context_region, account_id=context_account_id + function_name=function_name, + region=context_region, + account_id=context_account_id, + publish_to=request.get("PublishTo"), ) if config.LAMBDA_SYNCHRONOUS_CREATE: # block via retrying until "terminal" condition reached before returning if not poll_condition( - lambda: get_function_version( - function_name, version.id.qualifier, version.id.account, version.id.region - ).config.state.state - in [State.Active, State.Failed], + lambda: ( + get_function_version( + function_name, version.id.qualifier, version.id.account, version.id.region + ).config.state.state + in [State.Active, State.ActiveNonInvocable, State.Failed] + ), timeout=10, ): LOG.warning( @@ -1082,6 +1283,12 @@ def _validate_runtime(self, package_type, runtime): Type="User", ) + def _validate_managed_instances_runtime(self, runtime): + if runtime not in VALID_MANAGED_INSTANCE_RUNTIMES: + raise InvalidParameterValueException( + f"Runtime Enum {runtime} does not support specified feature: Lambda Managed Instances" + ) + def _check_for_recomended_migration_target(self, deprecated_runtime): # AWS offers recommended runtime for migration for "newly" deprecated runtimes # in order to preserve parity with error messages we need the code bellow @@ -1242,6 +1449,30 @@ def update_function_configuration( if new_mode: replace_kwargs["tracing_config_mode"] = new_mode + if "CapacityProviderConfig" in request: + capacity_provider_config = request["CapacityProviderConfig"] + self._validate_capacity_provider_config(capacity_provider_config, context) + + if latest_version.config.capacity_provider_config and not request[ + "CapacityProviderConfig" + ].get("LambdaManagedInstancesCapacityProviderConfig"): + raise ValidationException( + "1 validation error detected: Value null at 'capacityProviderConfig.lambdaManagedInstancesCapacityProviderConfig' failed to satisfy constraint: Member must not be null" + ) + if not latest_version.config.capacity_provider_config: + raise InvalidParameterValueException( + "CapacityProviderConfig isn't supported for Lambda Default functions.", + Type="User", + ) + + default_config = CapacityProviderConfig( + LambdaManagedInstancesCapacityProviderConfig=LambdaManagedInstancesCapacityProviderConfig( + ExecutionEnvironmentMemoryGiBPerVCpu=2.0, + PerExecutionEnvironmentMaxConcurrency=16, + ) + ) + capacity_provider_config = merge_recursive(default_config, capacity_provider_config) + replace_kwargs["capacity_provider_config"] = capacity_provider_config new_latest_version = dataclasses.replace( latest_version, config=dataclasses.replace( @@ -1257,7 +1488,22 @@ def update_function_configuration( ), ) function.versions["$LATEST"] = new_latest_version # TODO: notify - self.lambda_service.update_version(new_version=new_latest_version) + + if function.latest().config.capacity_provider_config: + + def _update_version_with_logging(): + try: + self.lambda_service.update_version(new_latest_version) + except Exception: + LOG.error( + "Failed to update Lambda Managed Instances function version %s", + new_latest_version.id.qualified_arn(), + exc_info=LOG.isEnabledFor(logging.DEBUG), + ) + + self.lambda_service.task_executor.submit(_update_version_with_logging) + else: + self.lambda_service.update_version(new_version=new_latest_version) return api_utils.map_config_out(new_latest_version) @@ -1305,6 +1551,9 @@ def update_function_code( Type="User", ) + if publish_to := request.get("PublishTo"): + self._validate_publish_to(publish_to) + if zip_file := request.get("ZipFile"): code = store_lambda_archive( archive_file=zip_file, @@ -1327,7 +1576,7 @@ def update_function_code( code = None image = create_image_code(image_uri=image) else: - raise LambdaServiceException("Gotta have s3 bucket or zip file or image") + raise LambdaServiceException("A ZIP file, S3 bucket, or image is required") old_function_version = function.versions.get("$LATEST") replace_kwargs = {"code": code} if code else {"image": image} @@ -1365,7 +1614,11 @@ def update_function_code( self.lambda_service.update_version(new_version=function_version) if request.get("Publish"): function_version = self._publish_version_with_changes( - function_name=function_name, region=region, account_id=account_id + function_name=function_name, + region=region, + account_id=account_id, + publish_to=publish_to, + is_active=True, ) return api_utils.map_config_out( function_version, return_qualified_arn=bool(request.get("Publish")) @@ -1380,10 +1633,10 @@ def update_function_code( def delete_function( self, context: RequestContext, - function_name: FunctionName, - qualifier: Qualifier = None, + function_name: NamespacedFunctionName, + qualifier: NumericLatestPublishedOrAliasQualifier | None = None, **kwargs, - ) -> None: + ) -> DeleteFunctionResponse: account_id, region = api_utils.get_account_and_region(function_name, context) function_name, qualifier = api_utils.get_name_and_qualifier( function_name, qualifier, context @@ -1401,30 +1654,55 @@ def delete_function( "$LATEST version cannot be deleted without deleting the function.", Type="User" ) + unqualified_function_arn = api_utils.unqualified_lambda_arn( + function_name=function_name, region=region, account=account_id + ) if function_name not in store.functions: e = ResourceNotFoundException( - f"Function not found: {api_utils.unqualified_lambda_arn(function_name=function_name, region=region, account=account_id)}", + f"Function not found: {unqualified_function_arn}", Type="User", ) raise e function = store.functions.get(function_name) + function_has_capacity_provider = False if qualifier: # delete a version of the function - version = function.versions.pop(qualifier, None) + version = function.versions.get(qualifier, None) if version: + if version.config.capacity_provider_config: + function_has_capacity_provider = True + # async delete from store + self.lambda_service.delete_function_version_async(function, version, qualifier) + else: + function.versions.pop(qualifier, None) self.lambda_service.stop_version(version.id.qualified_arn()) destroy_code_if_not_used(code=version.config.code, function=function) else: # delete the whole function + self._remove_all_tags(unqualified_function_arn) # TODO: introduce locking for safe deletion: We could create a new version at the API layer before # the old version gets cleaned up in the internal lambda service. - function = store.functions.pop(function_name) + function = store.functions.get(function_name) + if function.latest().config.capacity_provider_config: + function_has_capacity_provider = True + # async delete version from store + self.lambda_service.delete_function_async(store, function_name) + for version in function.versions.values(): - self.lambda_service.stop_version(qualified_arn=version.id.qualified_arn()) + # Functions with a capacity provider do NOT have a version manager for $LATEST because only + # published versions are invokable. + if not function_has_capacity_provider or ( + function_has_capacity_provider and version.id.qualifier != "$LATEST" + ): + self.lambda_service.stop_version(qualified_arn=version.id.qualified_arn()) # we can safely destroy the code here if version.config.code: version.config.code.destroy() + if not function_has_capacity_provider: + store.functions.pop(function_name, None) + + return DeleteFunctionResponse(StatusCode=202 if function_has_capacity_provider else 204) def list_functions( self, @@ -1469,7 +1747,7 @@ def get_function( self, context: RequestContext, function_name: NamespacedFunctionName, - qualifier: Qualifier = None, + qualifier: NumericLatestPublishedOrAliasQualifier | None = None, **kwargs, ) -> GetFunctionResponse: account_id, region = api_utils.get_account_and_region(function_name, context) @@ -1540,7 +1818,7 @@ def get_function_configuration( self, context: RequestContext, function_name: NamespacedFunctionName, - qualifier: Qualifier = None, + qualifier: NumericLatestPublishedOrAliasQualifier | None = None, **kwargs, ) -> FunctionConfiguration: account_id, region = api_utils.get_account_and_region(function_name, context) @@ -1560,11 +1838,13 @@ def invoke( self, context: RequestContext, function_name: NamespacedFunctionName, - invocation_type: InvocationType = None, - log_type: LogType = None, - client_context: String = None, - payload: IO[Blob] = None, - qualifier: Qualifier = None, + invocation_type: InvocationType | None = None, + log_type: LogType | None = None, + client_context: String | None = None, + durable_execution_name: DurableExecutionName | None = None, + payload: IO[Blob] | None = None, + qualifier: NumericLatestPublishedOrAliasQualifier | None = None, + tenant_id: TenantId | None = None, **kwargs, ) -> InvocationResponse: account_id, region = api_utils.get_account_and_region(function_name, context) @@ -1634,13 +1914,16 @@ def publish_version( self, context: RequestContext, function_name: FunctionName, - code_sha256: String = None, - description: Description = None, - revision_id: String = None, + code_sha256: String | None = None, + description: Description | None = None, + revision_id: String | None = None, + publish_to: FunctionVersionLatestPublished | None = None, **kwargs, ) -> FunctionConfiguration: account_id, region = api_utils.get_account_and_region(function_name, context) function_name = api_utils.get_function_name(function_name, context) + if publish_to: + self._validate_publish_to(publish_to) new_version = self._publish_version_from_existing_version( function_name=function_name, description=description, @@ -1648,6 +1931,7 @@ def publish_version( region=region, revision_id=revision_id, code_sha256=code_sha256, + publish_to=publish_to, ) return api_utils.map_config_out(new_version, return_qualified_arn=True) @@ -1706,7 +1990,7 @@ def _create_routing_config_model( ) if not api_utils.qualifier_is_version(key): raise ValidationException( - f"1 validation error detected: Value '{{{key}={value}}}' at 'routingConfig.additionalVersionWeights' failed to satisfy constraint: Map keys must satisfy constraint: [Member must have length less than or equal to 1024, Member must have length greater than or equal to 1, Member must satisfy regular expression pattern: [0-9]+, Member must not be null]" + f"1 validation error detected: Value '{{{key}={value}}}' at 'routingConfig.additionalVersionWeights' failed to satisfy constraint: Map keys must satisfy constraint: [Member must have length less than or equal to 1024, Member must have length greater than or equal to 1, Member must satisfy regular expression pattern: [0-9]+]" ) # checking if the version in the config exists @@ -1723,7 +2007,7 @@ def create_alias( context: RequestContext, function_name: FunctionName, name: Alias, - function_version: Version, + function_version: VersionWithLatestPublished, description: Description = None, routing_config: AliasRoutingConfiguration = None, **kwargs, @@ -1774,7 +2058,7 @@ def list_aliases( self, context: RequestContext, function_name: FunctionName, - function_version: Version = None, + function_version: VersionWithLatestPublished = None, marker: String = None, max_items: MaxListItems = None, **kwargs, @@ -1842,7 +2126,7 @@ def update_alias( context: RequestContext, function_name: FunctionName, name: Alias, - function_version: Version = None, + function_version: VersionWithLatestPublished = None, description: Description = None, routing_config: AliasRoutingConfiguration = None, revision_id: String = None, @@ -2069,6 +2353,9 @@ def validate_event_source_mapping(self, context, request): raise Exception("unknown version") # TODO: cover via test elif qualifier == "$LATEST": pass + elif qualifier == "$LATEST.PUBLISHED": + if fn.versions.get(qualifier): + pass else: raise Exception("invalid functionname") # TODO: cover via test fn_arn = api_utils.qualified_lambda_arn(function_name, qualifier, account, region) @@ -2224,6 +2511,10 @@ def delete_event_source_mapping( raise ResourceNotFoundException( "The resource you requested does not exist.", Type="User" ) + # the full deletion of the ESM is happening asynchronously, but we delete the Tags instantly + # this behavior is similar to ``get_event_source_mapping`` which will raise right after deletion, but it is not + # always the case in AWS. Add more testing and align behavior with ``get_event_source_mapping``. + self._remove_all_tags(event_source_mapping["EventSourceMappingArn"]) esm_worker.delete() return {**esm, "State": EsmState.DELETING} @@ -2288,7 +2579,9 @@ def get_source_type_from_request(self, request: dict[str, Any]) -> str: @staticmethod def _validate_qualifier(qualifier: str) -> None: - if qualifier == "$LATEST" or (qualifier and api_utils.qualifier_is_version(qualifier)): + if qualifier in ["$LATEST", "$LATEST.PUBLISHED"] or ( + qualifier and api_utils.qualifier_is_version(qualifier) + ): raise ValidationException( f"1 validation error detected: Value '{qualifier}' at 'qualifier' failed to satisfy constraint: Member must satisfy regular expression pattern: ((?!^\\d+$)^[0-9a-zA-Z-_]+$)" ) @@ -2591,7 +2884,7 @@ def add_permission( if revision_id != fn_revision_id: raise PreconditionFailedException( "The Revision Id provided does not match the latest Revision Id. " - "Call the GetFunction/GetAlias API to retrieve the latest Revision Id", + "Call the GetPolicy API to retrieve the latest Revision Id", Type="User", ) @@ -2649,10 +2942,10 @@ def add_permission( def remove_permission( self, context: RequestContext, - function_name: FunctionName, + function_name: NamespacedFunctionName, statement_id: NamespacedStatementId, - qualifier: Qualifier = None, - revision_id: String = None, + qualifier: NumericLatestPublishedOrAliasQualifier | None = None, + revision_id: String | None = None, **kwargs, ) -> None: account_id, region = api_utils.get_account_and_region(function_name, context) @@ -2716,7 +3009,7 @@ def get_policy( self, context: RequestContext, function_name: NamespacedFunctionName, - qualifier: Qualifier = None, + qualifier: NumericLatestPublishedOrAliasQualifier | None = None, **kwargs, ) -> GetPolicyResponse: account_id, region = api_utils.get_account_and_region(function_name, context) @@ -2758,9 +3051,9 @@ def create_code_signing_config( self, context: RequestContext, allowed_publishers: AllowedPublishers, - description: Description = None, - code_signing_policies: CodeSigningPolicies = None, - tags: Tags = None, + description: Description | None = None, + code_signing_policies: CodeSigningPolicies | None = None, + tags: Tags | None = None, **kwargs, ) -> CreateCodeSigningConfigResponse: account = context.account_id @@ -2785,7 +3078,7 @@ def put_function_code_signing_config( self, context: RequestContext, code_signing_config_arn: CodeSigningConfigArn, - function_name: FunctionName, + function_name: NamespacedFunctionName, **kwargs, ) -> PutFunctionCodeSigningConfigResponse: account_id, region = api_utils.get_account_and_region(function_name, context) @@ -2852,7 +3145,7 @@ def get_code_signing_config( return GetCodeSigningConfigResponse(CodeSigningConfig=api_utils.map_csc(csc)) def get_function_code_signing_config( - self, context: RequestContext, function_name: FunctionName, **kwargs + self, context: RequestContext, function_name: NamespacedFunctionName, **kwargs ) -> GetFunctionCodeSigningConfigResponse: account_id, region = api_utils.get_account_and_region(function_name, context) state = lambda_stores[account_id][region] @@ -2870,7 +3163,7 @@ def get_function_code_signing_config( return GetFunctionCodeSigningConfigResponse() def delete_function_code_signing_config( - self, context: RequestContext, function_name: FunctionName, **kwargs + self, context: RequestContext, function_name: NamespacedFunctionName, **kwargs ) -> None: account_id, region = api_utils.get_account_and_region(function_name, context) state = lambda_stores[account_id][region] @@ -3280,7 +3573,8 @@ def _validate_destination_arn(destination_arn) -> bool: raise ValidationException( "1 validation error detected: Value '" + destination_arn - + r"' at 'destinationConfig.onFailure.destination' failed to satisfy constraint: Member must satisfy regular expression pattern: ^$|arn:(aws[a-zA-Z0-9-]*):([a-zA-Z0-9\-])+:([a-z]{2}((-gov)|(-iso(b?)))?-[a-z]+-\d{1})?:(\d{12})?:(.*)" + + "' at 'destinationConfig.onFailure.destination' failed to satisfy constraint: Member must satisfy regular expression pattern: " + + "$|kafka://([^.]([a-zA-Z0-9\\-_.]{0,248}))|arn:(aws[a-zA-Z0-9-]*):([a-zA-Z0-9\\-])+:((eusc-)?[a-z]{2}((-gov)|(-iso([a-z]?)))?-[a-z]+-\\d{1})?:(\\d{12})?:(.*)" ) match destination_arn.split(":")[2]: @@ -3330,7 +3624,7 @@ def put_function_event_invoke_config( self, context: RequestContext, function_name: FunctionName, - qualifier: Qualifier = None, + qualifier: NumericLatestPublishedOrAliasQualifier = None, maximum_retry_attempts: MaximumRetryAttempts = None, maximum_event_age_in_seconds: MaximumEventAgeInSeconds = None, destination_config: DestinationConfig = None, @@ -3412,7 +3706,7 @@ def get_function_event_invoke_config( self, context: RequestContext, function_name: FunctionName, - qualifier: Qualifier = None, + qualifier: NumericLatestPublishedOrAliasQualifier | None = None, **kwargs, ) -> FunctionEventInvokeConfig: account_id, region = api_utils.get_account_and_region(function_name, context) @@ -3489,7 +3783,7 @@ def delete_function_event_invoke_config( self, context: RequestContext, function_name: FunctionName, - qualifier: Qualifier = None, + qualifier: NumericLatestPublishedOrAliasQualifier | None = None, **kwargs, ) -> None: account_id, region = api_utils.get_account_and_region(function_name, context) @@ -3517,7 +3811,7 @@ def update_function_event_invoke_config( self, context: RequestContext, function_name: FunctionName, - qualifier: Qualifier = None, + qualifier: NumericLatestPublishedOrAliasQualifier = None, maximum_retry_attempts: MaximumRetryAttempts = None, maximum_event_age_in_seconds: MaximumEventAgeInSeconds = None, destination_config: DestinationConfig = None, @@ -3608,10 +3902,10 @@ def publish_layer_version( context: RequestContext, layer_name: LayerName, content: LayerVersionContentInput, - description: Description = None, - compatible_runtimes: CompatibleRuntimes = None, - license_info: LicenseInfo = None, - compatible_architectures: CompatibleArchitectures = None, + description: Description | None = None, + compatible_runtimes: CompatibleRuntimes | None = None, + license_info: LicenseInfo | None = None, + compatible_architectures: CompatibleArchitectures | None = None, **kwargs, ) -> PublishLayerVersionResponse: """ @@ -3728,7 +4022,7 @@ def get_layer_version_by_arn( if not layer_version: raise ValidationException( f"1 validation error detected: Value '{arn}' at 'arn' failed to satisfy constraint: Member must satisfy regular expression pattern: " - + "(arn:(aws[a-zA-Z-]*)?:lambda:[a-z]{2}((-gov)|(-iso([a-z]?)))?-[a-z]+-\\d{1}:\\d{12}:layer:[a-zA-Z0-9-_]+:[0-9]+)|(arn:[a-zA-Z0-9-]+:lambda:::awslayer:[a-zA-Z0-9-_]+)" + + "(arn:(aws[a-zA-Z-]*)?:lambda:(eusc-)?[a-z]{2}((-gov)|(-iso([a-z]?)))?-[a-z]+-\\d{1}:\\d{12}:layer:[a-zA-Z0-9-_]+:[0-9]+)|(arn:[a-zA-Z0-9-]+:lambda:::awslayer:[a-zA-Z0-9-_]+)" ) store = lambda_stores[account_id][region_name] @@ -3749,10 +4043,10 @@ def get_layer_version_by_arn( def list_layers( self, context: RequestContext, - compatible_runtime: Runtime = None, - marker: String = None, - max_items: MaxLayerListItems = None, - compatible_architecture: Architecture = None, + compatible_runtime: Runtime | None = None, + marker: String | None = None, + max_items: MaxLayerListItems | None = None, + compatible_architecture: Architecture | None = None, **kwargs, ) -> ListLayersResponse: validation_errors = [] @@ -3804,10 +4098,10 @@ def list_layer_versions( self, context: RequestContext, layer_name: LayerName, - compatible_runtime: Runtime = None, - marker: String = None, - max_items: MaxLayerListItems = None, - compatible_architecture: Architecture = None, + compatible_runtime: Runtime | None = None, + marker: String | None = None, + max_items: MaxLayerListItems | None = None, + compatible_architecture: Architecture | None = None, **kwargs, ) -> ListLayerVersionsResponse: validation_errors = api_utils.validate_layer_runtimes_and_architectures( @@ -4133,29 +4427,66 @@ def delete_function_concurrency( # ======================================= # =============== TAGS =============== # ======================================= - # only Function, Event Source Mapping, and Code Signing Config (not currently supported by LocalStack) ARNs an are available for tagging in AWS + # only Function, Event Source Mapping, and Code Signing Config (not currently supported by LocalStack) ARNs + # are available for tagging in AWS - def _get_tags(self, resource: TaggableResource) -> dict[str, str]: - state = self.fetch_lambda_store_for_tagging(resource) - lambda_adapted_tags = { - tag["Key"]: tag["Value"] - for tag in state.TAGS.list_tags_for_resource(resource).get("Tags") - } - return lambda_adapted_tags + @staticmethod + def _update_resource_tags( + resource_arn: str, account_id: str, region: str, tags: dict[str, str] + ) -> None: + lambda_stores[account_id][region].tags.update_tags(resource_arn, tags) + + @staticmethod + def _list_resource_tags(resource_arn: str, account_id: str, region: str) -> dict[str, str]: + return lambda_stores[account_id][region].tags.get_tags(resource_arn) - def _store_tags(self, resource: TaggableResource, tags: dict[str, str]): - state = self.fetch_lambda_store_for_tagging(resource) - if len(state.TAGS.tags.get(resource, {}) | tags) > LAMBDA_TAG_LIMIT_PER_RESOURCE: + @staticmethod + def _remove_resource_tags( + resource_arn: str, account_id: str, region: str, keys: TagKeyList + ) -> None: + lambda_stores[account_id][region].tags.delete_tags(resource_arn, keys) + + @staticmethod + def _remove_all_resource_tags(resource_arn: str, account_id: str, region: str) -> None: + lambda_stores[account_id][region].tags.delete_all_tags(resource_arn) + + def _get_tags(self, resource: TaggableResource) -> dict[str, str]: + account_id, region = self._get_account_id_and_region_for_taggable_resource(resource) + tags = self._list_resource_tags(resource_arn=resource, account_id=account_id, region=region) + return tags + + def _store_tags(self, resource: TaggableResource, tags: dict[str, str]) -> None: + account_id, region = self._get_account_id_and_region_for_taggable_resource(resource) + existing_tags = self._list_resource_tags( + resource_arn=resource, account_id=account_id, region=region + ) + if len({**existing_tags, **tags}) > LAMBDA_TAG_LIMIT_PER_RESOURCE: + # note: we cannot use | on `ImmutableDict` and regular `dict` raise InvalidParameterValueException( "Number of tags exceeds resource tag limit.", Type="User" ) + self._update_resource_tags( + resource_arn=resource, + account_id=account_id, + region=region, + tags=tags, + ) + + def _remove_tags(self, resource: TaggableResource, keys: TagKeyList) -> None: + account_id, region = self._get_account_id_and_region_for_taggable_resource(resource) + self._remove_resource_tags( + resource_arn=resource, account_id=account_id, region=region, keys=keys + ) - tag_svc_adapted_tags = [{"Key": key, "Value": value} for key, value in tags.items()] - state.TAGS.tag_resource(resource, tag_svc_adapted_tags) + def _remove_all_tags(self, resource: TaggableResource) -> None: + account_id, region = self._get_account_id_and_region_for_taggable_resource(resource) + self._remove_all_resource_tags(resource_arn=resource, account_id=account_id, region=region) - def fetch_lambda_store_for_tagging(self, resource: TaggableResource) -> LambdaStore: + def _get_account_id_and_region_for_taggable_resource( + self, resource: TaggableResource + ) -> tuple[str, str]: """ - Takes a resource ARN for a TaggableResource (Lambda Function, Event Source Mapping, or Code Signing Config) and returns a corresponding + Takes a resource ARN for a TaggableResource (Lambda Function, Event Source Mapping, Code Signing Config, or Capacity Provider) and returns a corresponding LambdaStore for its region and account. In addition, this function validates that the ARN is a valid TaggableResource type, and that the TaggableResource exists. @@ -4190,9 +4521,8 @@ def _raise_validation_exception(): _raise_validation_exception() resource_type, resource_identifier, *qualifier = parts - if resource_type not in {"event-source-mapping", "code-signing-config", "function"}: - _raise_validation_exception() + # Qualifier validation raises before checking for NotFound if qualifier: if resource_type == "function": raise InvalidParameterValueException( @@ -4201,18 +4531,21 @@ def _raise_validation_exception(): ) _raise_validation_exception() - match resource_type: - case "event-source-mapping": - self._get_esm(resource_identifier, account_id, region) - case "code-signing-config": - raise NotImplementedError("Resource tagging on CSC not yet implemented.") - case "function": - self._get_function( - function_name=resource_identifier, account_id=account_id, region=region - ) + if resource_type == "event-source-mapping": + self._get_esm(resource_identifier, account_id, region) + elif resource_type == "code-signing-config": + raise NotImplementedError("Resource tagging on CSC not yet implemented.") + elif resource_type == "function": + self._get_function( + function_name=resource_identifier, account_id=account_id, region=region + ) + elif resource_type == "capacity-provider": + self._get_capacity_provider(resource_identifier, account_id, region) + else: + _raise_validation_exception() # If no exceptions are raised, assume ARN and referenced resource is valid for tag operations - return lambda_stores[account_id][region] + return account_id, region def tag_resource( self, context: RequestContext, resource: TaggableResource, tags: Tags, **kwargs @@ -4249,8 +4582,7 @@ def untag_resource( "1 validation error detected: Value null at 'tagKeys' failed to satisfy constraint: Member must not be null" ) # should probably be generalized a bit - state = self.fetch_lambda_store_for_tagging(resource) - state.TAGS.untag_resource(resource, tag_keys) + self._remove_tags(resource, tag_keys) if (resource_id := extract_resource_from_arn(resource)) and resource_id.startswith( "function" diff --git a/localstack-core/localstack/services/lambda_/resource_providers/aws_lambda_function.py b/localstack-core/localstack/services/lambda_/resource_providers/aws_lambda_function.py index 21342d9d55a76..f25851ea25613 100644 --- a/localstack-core/localstack/services/lambda_/resource_providers/aws_lambda_function.py +++ b/localstack-core/localstack/services/lambda_/resource_providers/aws_lambda_function.py @@ -2,28 +2,42 @@ from __future__ import annotations import os -from pathlib import Path from typing import TypedDict import localstack.services.cloudformation.provider_utils as util from localstack.services.cloudformation.resource_provider import ( OperationStatus, ProgressEvent, - ResourceProvider, ResourceRequest, ) from localstack.services.lambda_.lambda_utils import get_handler_file_from_name +from localstack.services.lambda_.resource_providers.generated.aws_lambda_function_base import ( + LambdaFunctionProviderBase, +) from localstack.utils.archives import is_zip_file from localstack.utils.files import mkdir, new_tmp_dir, rm_rf, save_file from localstack.utils.strings import is_base64, to_bytes from localstack.utils.testutil import create_zip_file +class LambdaManagedInstancesCapacityProviderConfig(TypedDict): + CapacityProviderArn: str | None + PerExecutionEnvironmentMaxConcurrency: int | None + ExecutionEnvironmentMemoryGiBPerVCpu: float | None + + +class CapacityProviderConfig(TypedDict): + LambdaManagedInstancesCapacityProviderConfig: ( + LambdaManagedInstancesCapacityProviderConfig | None + ) + + class LambdaFunctionProperties(TypedDict): Code: Code | None Role: str | None Architectures: list[str] | None Arn: str | None + CapacityProviderConfig: CapacityProviderConfig | None CodeSigningConfigArn: str | None DeadLetterConfig: DeadLetterConfig | None Description: str | None @@ -297,16 +311,14 @@ def _transform_function_to_model(function): "Arn", "EphemeralStorage", "Architectures", + "CapacityProviderConfig", ] response_model = util.select_attributes(function, model_properties) response_model["Arn"] = function["FunctionArn"] return response_model -class LambdaFunctionProvider(ResourceProvider[LambdaFunctionProperties]): - TYPE = "AWS::Lambda::Function" # Autogenerated. Don't change - SCHEMA = util.get_schema_path(Path(__file__)) # Autogenerated. Don't change - +class LambdaFunctionProvider(LambdaFunctionProviderBase): def create( self, request: ResourceRequest[LambdaFunctionProperties], @@ -323,6 +335,8 @@ def create( Create-only properties: - /properties/FunctionName + - /properties/PackageType + - /properties/TenancyConfig Read-only properties: - /properties/Arn @@ -352,10 +366,10 @@ def create( - lambda:PutRuntimeManagementConfig - lambda:TagResource - lambda:GetPolicy - - lambda:AddPermission - - lambda:RemovePermission - - lambda:GetResourcePolicy - - lambda:PutResourcePolicy + - lambda:PutFunctionRecursionConfig + - lambda:GetFunctionRecursionConfig + - lambda:PutFunctionScalingConfig + - lambda:PassCapacityProvider """ model = request.desired_state @@ -387,6 +401,7 @@ def create( "TracingConfig", "VpcConfig", "LoggingConfig", + "CapacityProviderConfig", ], ) if "Timeout" in kwargs: @@ -408,11 +423,27 @@ def create( } kwargs["Code"] = _get_lambda_code_param(model) + + # For managed instance lambdas, we publish them immediately + if "CapacityProviderConfig" in kwargs: + kwargs["Publish"] = True + kwargs["PublishTo"] = "LATEST_PUBLISHED" + create_response = lambda_client.create_function(**kwargs) + # TODO: if version is in the schema, just put it in the model instead of the custom context + request.custom_context["Version"] = create_response["Version"] # $LATEST.PUBLISHED model["Arn"] = create_response["FunctionArn"] - get_fn_response = lambda_client.get_function(FunctionName=model["Arn"]) + if request.custom_context.get("Version") == "$LATEST.PUBLISHED": + # for managed instance lambdas, we need to wait until the version is published & active + get_fn_response = lambda_client.get_function( + FunctionName=model["FunctionName"], Qualifier=request.custom_context["Version"] + ) + else: + get_fn_response = lambda_client.get_function(FunctionName=model["Arn"]) + match get_fn_response["Configuration"]["State"]: + # TODO: explicitly handle new ActiveNonInvocable state? case "Pending": return ProgressEvent( status=OperationStatus.IN_PROGRESS, @@ -449,6 +480,9 @@ def read( IAM permissions required: - lambda:GetFunction - lambda:GetFunctionCodeSigningConfig + - lambda:GetFunctionRecursionConfig + - lambda:GetRuntimeManagementConfig + - lambda:GetFunctionScalingConfig """ function_name = request.desired_state["FunctionName"] lambda_client = request.aws_client_factory.lambda_ @@ -468,6 +502,7 @@ def delete( IAM permissions required: - lambda:DeleteFunction + - lambda:GetFunction - ec2:DescribeNetworkInterfaces """ try: @@ -489,7 +524,6 @@ def update( - lambda:DeleteFunctionConcurrency - lambda:GetFunction - lambda:PutFunctionConcurrency - - lambda:ListTags - lambda:TagResource - lambda:UntagResource - lambda:UpdateFunctionConfiguration @@ -510,12 +544,11 @@ def update( - lambda:DeleteFunctionCodeSigningConfig - lambda:GetCodeSigningConfig - lambda:GetFunctionCodeSigningConfig - - lambda:GetPolicy - - lambda:AddPermission - - lambda:RemovePermission - - lambda:GetResourcePolicy - - lambda:PutResourcePolicy - - lambda:DeleteResourcePolicy + - lambda:PutFunctionRecursionConfig + - lambda:GetFunctionRecursionConfig + - lambda:PutFunctionScalingConfig + - lambda:PublishVersion + - lambda:PassCapacityProvider """ client = request.aws_client_factory.lambda_ @@ -541,6 +574,7 @@ def update( "TracingConfig", "VpcConfig", "LoggingConfig", + "CapacityProviderConfig", ] update_config_props = util.select_attributes(request.desired_state, config_keys) function_name = request.previous_state["FunctionName"] @@ -578,6 +612,11 @@ def list( self, request: ResourceRequest[LambdaFunctionProperties], ) -> ProgressEvent[LambdaFunctionProperties]: + """ + List available resources of this type + IAM permissions required: + - lambda:ListFunctions + """ functions = request.aws_client_factory.lambda_.list_functions() return ProgressEvent( status=OperationStatus.SUCCESS, diff --git a/localstack-core/localstack/services/lambda_/resource_providers/aws_lambda_function.schema.json b/localstack-core/localstack/services/lambda_/resource_providers/aws_lambda_function.schema.json deleted file mode 100644 index b1d128047b150..0000000000000 --- a/localstack-core/localstack/services/lambda_/resource_providers/aws_lambda_function.schema.json +++ /dev/null @@ -1,566 +0,0 @@ -{ - "tagging": { - "taggable": true, - "tagOnCreate": true, - "tagUpdatable": true, - "tagProperty": "/properties/Tags", - "cloudFormationSystemTags": true - }, - "handlers": { - "read": { - "permissions": [ - "lambda:GetFunction", - "lambda:GetFunctionCodeSigningConfig" - ] - }, - "create": { - "permissions": [ - "lambda:CreateFunction", - "lambda:GetFunction", - "lambda:PutFunctionConcurrency", - "iam:PassRole", - "s3:GetObject", - "s3:GetObjectVersion", - "ec2:DescribeSecurityGroups", - "ec2:DescribeSubnets", - "ec2:DescribeVpcs", - "elasticfilesystem:DescribeMountTargets", - "kms:CreateGrant", - "kms:Decrypt", - "kms:Encrypt", - "kms:GenerateDataKey", - "lambda:GetCodeSigningConfig", - "lambda:GetFunctionCodeSigningConfig", - "lambda:GetLayerVersion", - "lambda:GetRuntimeManagementConfig", - "lambda:PutRuntimeManagementConfig", - "lambda:TagResource", - "lambda:GetPolicy", - "lambda:AddPermission", - "lambda:RemovePermission", - "lambda:GetResourcePolicy", - "lambda:PutResourcePolicy" - ] - }, - "update": { - "permissions": [ - "lambda:DeleteFunctionConcurrency", - "lambda:GetFunction", - "lambda:PutFunctionConcurrency", - "lambda:ListTags", - "lambda:TagResource", - "lambda:UntagResource", - "lambda:UpdateFunctionConfiguration", - "lambda:UpdateFunctionCode", - "iam:PassRole", - "s3:GetObject", - "s3:GetObjectVersion", - "ec2:DescribeSecurityGroups", - "ec2:DescribeSubnets", - "ec2:DescribeVpcs", - "elasticfilesystem:DescribeMountTargets", - "kms:CreateGrant", - "kms:Decrypt", - "kms:GenerateDataKey", - "lambda:GetRuntimeManagementConfig", - "lambda:PutRuntimeManagementConfig", - "lambda:PutFunctionCodeSigningConfig", - "lambda:DeleteFunctionCodeSigningConfig", - "lambda:GetCodeSigningConfig", - "lambda:GetFunctionCodeSigningConfig", - "lambda:GetPolicy", - "lambda:AddPermission", - "lambda:RemovePermission", - "lambda:GetResourcePolicy", - "lambda:PutResourcePolicy", - "lambda:DeleteResourcePolicy" - ] - }, - "list": { - "permissions": [ - "lambda:ListFunctions" - ] - }, - "delete": { - "permissions": [ - "lambda:DeleteFunction", - "ec2:DescribeNetworkInterfaces" - ] - } - }, - "typeName": "AWS::Lambda::Function", - "readOnlyProperties": [ - "/properties/SnapStartResponse", - "/properties/SnapStartResponse/ApplyOn", - "/properties/SnapStartResponse/OptimizationStatus", - "/properties/Arn" - ], - "description": "Resource Type definition for AWS::Lambda::Function in region", - "writeOnlyProperties": [ - "/properties/SnapStart", - "/properties/SnapStart/ApplyOn", - "/properties/Code", - "/properties/Code/ImageUri", - "/properties/Code/S3Bucket", - "/properties/Code/S3Key", - "/properties/Code/S3ObjectVersion", - "/properties/Code/ZipFile" - ], - "createOnlyProperties": [ - "/properties/FunctionName" - ], - "additionalProperties": false, - "primaryIdentifier": [ - "/properties/FunctionName" - ], - "definitions": { - "ImageConfig": { - "additionalProperties": false, - "type": "object", - "properties": { - "WorkingDirectory": { - "description": "WorkingDirectory.", - "type": "string" - }, - "Command": { - "maxItems": 1500, - "uniqueItems": true, - "description": "Command.", - "type": "array", - "items": { - "type": "string" - } - }, - "EntryPoint": { - "maxItems": 1500, - "uniqueItems": true, - "description": "EntryPoint.", - "type": "array", - "items": { - "type": "string" - } - } - } - }, - "TracingConfig": { - "description": "The function's AWS X-Ray tracing configuration. To sample and record incoming requests, set Mode to Active.", - "additionalProperties": false, - "type": "object", - "properties": { - "Mode": { - "description": "The tracing mode.", - "type": "string", - "enum": [ - "Active", - "PassThrough" - ] - } - } - }, - "VpcConfig": { - "description": "The VPC security groups and subnets that are attached to a Lambda function. When you connect a function to a VPC, Lambda creates an elastic network interface for each combination of security group and subnet in the function's VPC configuration. The function can only access resources and the internet through that VPC.", - "additionalProperties": false, - "type": "object", - "properties": { - "Ipv6AllowedForDualStack": { - "description": "A boolean indicating whether IPv6 protocols will be allowed for dual stack subnets", - "type": "boolean" - }, - "SecurityGroupIds": { - "maxItems": 5, - "uniqueItems": false, - "description": "A list of VPC security groups IDs.", - "type": "array", - "items": { - "type": "string" - } - }, - "SubnetIds": { - "maxItems": 16, - "uniqueItems": false, - "description": "A list of VPC subnet IDs.", - "type": "array", - "items": { - "type": "string" - } - } - } - }, - "DeadLetterConfig": { - "description": "The dead-letter queue for failed asynchronous invocations.", - "additionalProperties": false, - "type": "object", - "properties": { - "TargetArn": { - "pattern": "^(arn:(aws[a-zA-Z-]*)?:[a-z0-9-.]+:.*)|()$", - "description": "The Amazon Resource Name (ARN) of an Amazon SQS queue or Amazon SNS topic.", - "type": "string" - } - } - }, - "RuntimeManagementConfig": { - "additionalProperties": false, - "type": "object", - "properties": { - "UpdateRuntimeOn": { - "description": "Trigger for runtime update", - "type": "string", - "enum": [ - "Auto", - "FunctionUpdate", - "Manual" - ] - }, - "RuntimeVersionArn": { - "description": "Unique identifier for a runtime version arn", - "type": "string" - } - }, - "required": [ - "UpdateRuntimeOn" - ] - }, - "SnapStart": { - "description": "The function's SnapStart setting. When set to PublishedVersions, Lambda creates a snapshot of the execution environment when you publish a function version.", - "additionalProperties": false, - "type": "object", - "properties": { - "ApplyOn": { - "description": "Applying SnapStart setting on function resource type.", - "type": "string", - "enum": [ - "PublishedVersions", - "None" - ] - } - }, - "required": [ - "ApplyOn" - ] - }, - "SnapStartResponse": { - "description": "The function's SnapStart Response. When set to PublishedVersions, Lambda creates a snapshot of the execution environment when you publish a function version.", - "additionalProperties": false, - "type": "object", - "properties": { - "OptimizationStatus": { - "description": "Indicates whether SnapStart is activated for the specified function version.", - "type": "string", - "enum": [ - "On", - "Off" - ] - }, - "ApplyOn": { - "description": "Applying SnapStart setting on function resource type.", - "type": "string", - "enum": [ - "PublishedVersions", - "None" - ] - } - } - }, - "Code": { - "additionalProperties": false, - "type": "object", - "properties": { - "S3ObjectVersion": { - "minLength": 1, - "description": "For versioned objects, the version of the deployment package object to use.", - "type": "string", - "maxLength": 1024 - }, - "S3Bucket": { - "minLength": 3, - "pattern": "^[0-9A-Za-z\\.\\-_]*(?``. To use a different log group, enter an existing log group or enter a new log group name.", + "type": "string", + "maxLength": 512 + }, + "SystemLogLevel": { + "description": "Set this property to filter the system logs for your function that Lambda sends to CloudWatch. Lambda only sends system logs at the selected level of detail and lower, where ``DEBUG`` is the highest level and ``WARN`` is the lowest.", + "type": "string", + "enum": [ + "DEBUG", + "INFO", + "WARN" + ] + } + } + }, + "RecursiveLoop": { + "description": "The function recursion configuration.", + "type": "string", + "enum": [ + "Allow", + "Terminate" + ] + }, + "Environment": { + "description": "A function's environment variable settings. You can use environment variables to adjust your function's behavior without updating code. An environment variable is a pair of strings that are stored in a function's version-specific configuration.", + "additionalProperties": false, + "type": "object", + "properties": { + "Variables": { + "patternProperties": { + "[a-zA-Z][a-zA-Z0-9_]+": { + "type": "string" + } + }, + "description": "Environment variable key-value pairs. For more information, see [Using Lambda environment variables](https://docs.aws.amazon.com/lambda/latest/dg/configuration-envvars.html).\n If the value of the environment variable is a time or a duration, enclose the value in quotes.", + "additionalProperties": false, + "type": "object" + } + } + }, + "FileSystemConfig": { + "description": "Details about the connection between a Lambda function and an [Amazon EFS file system](https://docs.aws.amazon.com/lambda/latest/dg/configuration-filesystem.html).", + "additionalProperties": false, + "type": "object", + "properties": { + "Arn": { + "pattern": "^arn:aws[a-zA-Z-]*:elasticfilesystem:(eusc-)?[a-z]{2}((-gov)|(-iso([a-z]?)))?-[a-z]+-\\d{1}:\\d{12}:access-point/fsap-[a-f0-9]{17}$", + "description": "The Amazon Resource Name (ARN) of the Amazon EFS access point that provides access to the file system.", + "type": "string", + "maxLength": 200 + }, + "LocalMountPath": { + "pattern": "^/mnt/[a-zA-Z0-9-_.]+$", + "description": "The path where the function can access the file system, starting with ``/mnt/``.", + "type": "string", + "maxLength": 160 + } + }, + "required": [ + "Arn", + "LocalMountPath" + ] + }, + "Tag": { + "description": "A [tag](https://docs.aws.amazon.com/lambda/latest/dg/tagging.html) to apply to the function.", + "additionalProperties": false, + "type": "object", + "properties": { + "Value": { + "minLength": 0, + "description": "The value for this tag.", + "type": "string", + "maxLength": 256 + }, + "Key": { + "minLength": 1, + "description": "The key for this tag.", + "type": "string", + "maxLength": 128 + } + }, + "required": [ + "Key" + ] + }, + "EphemeralStorage": { + "description": "The size of the function's ``/tmp`` directory in MB. The default value is 512, but it can be any whole number between 512 and 10,240 MB.", + "additionalProperties": false, + "type": "object", + "properties": { + "Size": { + "description": "The size of the function's ``/tmp`` directory.", + "maximum": 10240, + "type": "integer", + "minimum": 512 + } + }, + "required": [ + "Size" + ] + }, + "TenancyConfig": { + "description": "", + "additionalProperties": false, + "type": "object", + "properties": { + "TenantIsolationMode": { + "description": "Determines how your Lambda function isolates execution environments between tenants.", + "type": "string", + "enum": [ + "PER_TENANT" + ] + } + }, + "required": [ + "TenantIsolationMode" + ] + } + }, + "properties": { + "FunctionScalingConfig": { + "description": "", + "$ref": "#/definitions/FunctionScalingConfig" + }, + "Description": { + "description": "A description of the function.", + "type": "string", + "maxLength": 256 + }, + "TracingConfig": { + "description": "Set ``Mode`` to ``Active`` to sample and trace a subset of incoming requests with [X-Ray](https://docs.aws.amazon.com/lambda/latest/dg/services-xray.html).", + "$ref": "#/definitions/TracingConfig" + }, + "VpcConfig": { + "description": "For network connectivity to AWS resources in a VPC, specify a list of security groups and subnets in the VPC. When you connect a function to a VPC, it can access resources and the internet only through that VPC. For more information, see [Configuring a Lambda function to access resources in a VPC](https://docs.aws.amazon.com/lambda/latest/dg/configuration-vpc.html).", + "$ref": "#/definitions/VpcConfig" + }, + "RuntimeManagementConfig": { + "description": "Sets the runtime management configuration for a function's version. For more information, see [Runtime updates](https://docs.aws.amazon.com/lambda/latest/dg/runtimes-update.html).", + "$ref": "#/definitions/RuntimeManagementConfig" + }, + "DurableConfig": { + "description": "", + "$ref": "#/definitions/DurableConfig" + }, + "ReservedConcurrentExecutions": { + "description": "The number of simultaneous executions to reserve for the function.", + "type": "integer", + "minimum": 0 + }, + "SnapStart": { + "description": "The function's [SnapStart](https://docs.aws.amazon.com/lambda/latest/dg/snapstart.html) setting.", + "$ref": "#/definitions/SnapStart" + }, + "FileSystemConfigs": { + "maxItems": 1, + "description": "Connection settings for an Amazon EFS file system. To connect a function to a file system, a mount target must be available in every Availability Zone that your function connects to. If your template contains an [AWS::EFS::MountTarget](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-efs-mounttarget.html) resource, you must also specify a ``DependsOn`` attribute to ensure that the mount target is created or updated before the function.\n For more information about using the ``DependsOn`` attribute, see [DependsOn Attribute](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-attribute-dependson.html).", + "type": "array", + "items": { + "$ref": "#/definitions/FileSystemConfig" + } + }, + "FunctionName": { + "minLength": 1, + "description": "The name of the Lambda function, up to 64 characters in length. If you don't specify a name, CFN generates one.\n If you specify a name, you cannot perform updates that require replacement of this resource. You can perform updates that require no or some interruption. If you must replace the resource, specify a new name.", + "type": "string" + }, + "Runtime": { + "description": "The identifier of the function's [runtime](https://docs.aws.amazon.com/lambda/latest/dg/lambda-runtimes.html). Runtime is required if the deployment package is a .zip file archive. Specifying a runtime results in an error if you're deploying a function using a container image.\n The following list includes deprecated runtimes. Lambda blocks creating new functions and updating existing functions shortly after each runtime is deprecated. For more information, see [Runtime use after deprecation](https://docs.aws.amazon.com/lambda/latest/dg/lambda-runtimes.html#runtime-deprecation-levels).\n For a list of all currently supported runtimes, see [Supported runtimes](https://docs.aws.amazon.com/lambda/latest/dg/lambda-runtimes.html#runtimes-supported).", + "type": "string" + }, + "KmsKeyArn": { + "pattern": "^(arn:(aws[a-zA-Z-]*)?:[a-z0-9-.]+:.*)|()$", + "description": "The ARN of the KMSlong (KMS) customer managed key that's used to encrypt the following resources:\n + The function's [environment variables](https://docs.aws.amazon.com/lambda/latest/dg/configuration-envvars.html#configuration-envvars-encryption).\n + The function's [Lambda SnapStart](https://docs.aws.amazon.com/lambda/latest/dg/snapstart-security.html) snapshots.\n + When used with ``SourceKMSKeyArn``, the unzipped version of the .zip deployment package that's used for function invocations. For more information, see [Specifying a customer managed key for Lambda](https://docs.aws.amazon.com/lambda/latest/dg/encrypt-zip-package.html#enable-zip-custom-encryption).\n + The optimized version of the container image that's used for function invocations. Note that this is not the same key that's used to protect your container image in the Amazon Elastic Container Registry (Amazon ECR). For more information, see [Function lifecycle](https://docs.aws.amazon.com/lambda/latest/dg/images-create.html#images-lifecycle).\n \n If you don't provide a customer managed key, Lambda uses an [owned key](https://docs.aws.amazon.com/kms/latest/developerguide/concepts.html#aws-owned-cmk) or an [](https://docs.aws.amazon.com/kms/latest/developerguide/concepts.html#aws-managed-cmk).", + "type": "string" + }, + "PublishToLatestPublished": { + "description": "", + "type": "boolean" + }, + "PackageType": { + "description": "The type of deployment package. Set to ``Image`` for container image and set ``Zip`` for .zip file archive.", + "type": "string", + "enum": [ + "Image", + "Zip" + ] + }, + "CodeSigningConfigArn": { + "pattern": "arn:(aws[a-zA-Z-]*)?:lambda:(eusc-)?[a-z]{2}((-gov)|(-iso([a-z]?)))?-[a-z]+-\\d{1}:\\d{12}:code-signing-config:csc-[a-z0-9]{17}", + "description": "To enable code signing for this function, specify the ARN of a code-signing configuration. A code-signing configuration includes a set of signing profiles, which define the trusted publishers for this function.", + "type": "string" + }, + "Layers": { + "uniqueItems": false, + "description": "A list of [function layers](https://docs.aws.amazon.com/lambda/latest/dg/configuration-layers.html) to add to the function's execution environment. Specify each layer by its ARN, including the version.", + "type": "array", + "items": { + "type": "string" + } + }, + "TenancyConfig": { + "description": "", + "$ref": "#/definitions/TenancyConfig" + }, + "Tags": { + "uniqueItems": true, + "description": "A list of [tags](https://docs.aws.amazon.com/lambda/latest/dg/tagging.html) to apply to the function.\n You must have the ``lambda:TagResource``, ``lambda:UntagResource``, and ``lambda:ListTags`` permissions for your [principal](https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_terms-and-concepts.html) to manage the CFN stack. If you don't have these permissions, there might be unexpected behavior with stack-level tags propagating to the resource during resource creation and update.", + "insertionOrder": false, + "type": "array", + "items": { + "$ref": "#/definitions/Tag" + } + }, + "ImageConfig": { + "description": "Configuration values that override the container image Dockerfile settings. For more information, see [Container image settings](https://docs.aws.amazon.com/lambda/latest/dg/images-create.html#images-parms).", + "$ref": "#/definitions/ImageConfig" + }, + "MemorySize": { + "description": "The amount of [memory available to the function](https://docs.aws.amazon.com/lambda/latest/dg/configuration-function-common.html#configuration-memory-console) at runtime. Increasing the function memory also increases its CPU allocation. The default value is 128 MB. The value can be any multiple of 1 MB. Note that new AWS accounts have reduced concurrency and memory quotas. AWS raises these quotas automatically based on your usage. You can also request a quota increase.", + "type": "integer" + }, + "DeadLetterConfig": { + "description": "A dead-letter queue configuration that specifies the queue or topic where Lambda sends asynchronous events when they fail processing. For more information, see [Dead-letter queues](https://docs.aws.amazon.com/lambda/latest/dg/invocation-async.html#invocation-dlq).", + "$ref": "#/definitions/DeadLetterConfig" + }, + "Timeout": { + "description": "The amount of time (in seconds) that Lambda allows a function to run before stopping it. The default is 3 seconds. The maximum allowed value is 900 seconds. For more information, see [Lambda execution environment](https://docs.aws.amazon.com/lambda/latest/dg/runtimes-context.html).", + "type": "integer", + "minimum": 1 + }, + "CapacityProviderConfig": { + "description": "", + "$ref": "#/definitions/CapacityProviderConfig" + }, + "Handler": { + "pattern": "^[^\\s]+$", + "description": "The name of the method within your code that Lambda calls to run your function. Handler is required if the deployment package is a .zip file archive. The format includes the file name. It can also include namespaces and other qualifiers, depending on the runtime. For more information, see [Lambda programming model](https://docs.aws.amazon.com/lambda/latest/dg/foundation-progmodel.html).", + "type": "string", + "maxLength": 128 + }, + "SnapStartResponse": { + "description": "", + "$ref": "#/definitions/SnapStartResponse" + }, + "Code": { + "description": "The code for the function. You can define your function code in multiple ways:\n + For .zip deployment packages, you can specify the S3 location of the .zip file in the ``S3Bucket``, ``S3Key``, and ``S3ObjectVersion`` properties.\n + For .zip deployment packages, you can alternatively define the function code inline in the ``ZipFile`` property. This method works only for Node.js and Python functions.\n + For container images, specify the URI of your container image in the ECR registry in the ``ImageUri`` property.", + "$ref": "#/definitions/Code" + }, + "Role": { + "pattern": "^arn:(aws[a-zA-Z-]*)?:iam::\\d{12}:role/?[a-zA-Z_0-9+=,.@\\-_/]+$", + "description": "The Amazon Resource Name (ARN) of the function's execution role.", + "type": "string" + }, + "LoggingConfig": { + "description": "The function's Amazon CloudWatch Logs configuration settings.", + "$ref": "#/definitions/LoggingConfig" + }, + "RecursiveLoop": { + "description": "The status of your function's recursive loop detection configuration.\n When this value is set to ``Allow``and Lambda detects your function being invoked as part of a recursive loop, it doesn't take any action.\n When this value is set to ``Terminate`` and Lambda detects your function being invoked as part of a recursive loop, it stops your function being invoked and notifies you.", + "$ref": "#/definitions/RecursiveLoop" + }, + "Environment": { + "description": "Environment variables that are accessible from function code during execution.", + "$ref": "#/definitions/Environment" + }, + "Arn": { + "description": "", + "type": "string" + }, + "EphemeralStorage": { + "description": "The size of the function's ``/tmp`` directory in MB. The default value is 512, but it can be any whole number between 512 and 10,240 MB.", + "$ref": "#/definitions/EphemeralStorage" + }, + "Architectures": { + "minItems": 1, + "maxItems": 1, + "uniqueItems": true, + "description": "The instruction set architecture that the function supports. Enter a string array with one of the valid values (arm64 or x86_64). The default value is ``x86_64``.", + "type": "array", + "items": { + "type": "string", + "enum": [ + "x86_64", + "arm64" + ] + } + } + } +} diff --git a/localstack-core/localstack/services/lambda_/resource_providers/generated/aws_lambda_function_base.py b/localstack-core/localstack/services/lambda_/resource_providers/generated/aws_lambda_function_base.py new file mode 100644 index 0000000000000..19c348048d3ec --- /dev/null +++ b/localstack-core/localstack/services/lambda_/resource_providers/generated/aws_lambda_function_base.py @@ -0,0 +1,294 @@ +# LocalStack Resource Provider Base Class Scaffolding v2 +# +# AUTOGENERATED FILE - DO NOT EDIT +# + +from __future__ import annotations + +from abc import ABC, abstractmethod +from pathlib import Path +from typing import TypedDict + +import localstack.services.cloudformation.provider_utils as util +from localstack.services.cloudformation.resource_provider import ( + ProgressEvent, + ResourceProvider, + ResourceRequest, +) + + +class LambdaFunctionProperties(TypedDict): + Code: Code | None + Role: str | None + Architectures: list[str] | None + Arn: str | None + CapacityProviderConfig: CapacityProviderConfig | None + CodeSigningConfigArn: str | None + DeadLetterConfig: DeadLetterConfig | None + Description: str | None + DurableConfig: DurableConfig | None + Environment: Environment | None + EphemeralStorage: EphemeralStorage | None + FileSystemConfigs: list[FileSystemConfig] | None + FunctionName: str | None + FunctionScalingConfig: FunctionScalingConfig | None + Handler: str | None + ImageConfig: ImageConfig | None + KmsKeyArn: str | None + Layers: list[str] | None + LoggingConfig: LoggingConfig | None + MemorySize: int | None + PackageType: str | None + PublishToLatestPublished: bool | None + RecursiveLoop: str | None + ReservedConcurrentExecutions: int | None + Runtime: str | None + RuntimeManagementConfig: RuntimeManagementConfig | None + SnapStart: SnapStart | None + SnapStartResponse: SnapStartResponse | None + Tags: list[Tag] | None + TenancyConfig: TenancyConfig | None + Timeout: int | None + TracingConfig: TracingConfig | None + VpcConfig: VpcConfig | None + + +class FunctionScalingConfig(TypedDict): + MaxExecutionEnvironments: int | None + MinExecutionEnvironments: int | None + + +class TracingConfig(TypedDict): + Mode: str | None + + +class VpcConfig(TypedDict): + Ipv6AllowedForDualStack: bool | None + SecurityGroupIds: list[str] | None + SubnetIds: list[str] | None + + +class RuntimeManagementConfig(TypedDict): + UpdateRuntimeOn: str | None + RuntimeVersionArn: str | None + + +class DurableConfig(TypedDict): + ExecutionTimeout: int | None + RetentionPeriodInDays: int | None + + +class SnapStart(TypedDict): + ApplyOn: str | None + + +class FileSystemConfig(TypedDict): + Arn: str | None + LocalMountPath: str | None + + +class TenancyConfig(TypedDict): + TenantIsolationMode: str | None + + +class Tag(TypedDict): + Key: str | None + Value: str | None + + +class ImageConfig(TypedDict): + Command: list[str] | None + EntryPoint: list[str] | None + WorkingDirectory: str | None + + +class DeadLetterConfig(TypedDict): + TargetArn: str | None + + +class LambdaManagedInstancesCapacityProviderConfig(TypedDict): + CapacityProviderArn: str | None + ExecutionEnvironmentMemoryGiBPerVCpu: float | None + PerExecutionEnvironmentMaxConcurrency: int | None + + +class CapacityProviderConfig(TypedDict): + LambdaManagedInstancesCapacityProviderConfig: ( + LambdaManagedInstancesCapacityProviderConfig | None + ) + + +class SnapStartResponse(TypedDict): + ApplyOn: str | None + OptimizationStatus: str | None + + +class Code(TypedDict): + ImageUri: str | None + S3Bucket: str | None + S3Key: str | None + S3ObjectVersion: str | None + SourceKMSKeyArn: str | None + ZipFile: str | None + + +class LoggingConfig(TypedDict): + ApplicationLogLevel: str | None + LogFormat: str | None + LogGroup: str | None + SystemLogLevel: str | None + + +class Environment(TypedDict): + Variables: dict | None + + +class EphemeralStorage(TypedDict): + Size: int | None + + +REPEATED_INVOCATION = "repeated_invocation" + + +class LambdaFunctionProviderBase(ResourceProvider[LambdaFunctionProperties], ABC): + TYPE = "AWS::Lambda::Function" # Autogenerated. Don't change + SCHEMA = util.get_schema_path(Path(__file__)) # Autogenerated. Don't change + + @abstractmethod + def create( + self, + request: ResourceRequest[LambdaFunctionProperties], + ) -> ProgressEvent[LambdaFunctionProperties]: + """ + Create a new resource. + + Primary identifier fields: + - /properties/FunctionName + + Required properties: + - Code + - Role + + Create-only properties: + - /properties/FunctionName + - /properties/PackageType + - /properties/TenancyConfig + + Read-only properties: + - /properties/SnapStartResponse + - /properties/SnapStartResponse/ApplyOn + - /properties/SnapStartResponse/OptimizationStatus + - /properties/Arn + + IAM permissions required: + - lambda:CreateFunction + - lambda:GetFunction + - lambda:PutFunctionConcurrency + - iam:PassRole + - s3:GetObject + - s3:GetObjectVersion + - ec2:DescribeSecurityGroups + - ec2:DescribeSubnets + - ec2:DescribeVpcs + - elasticfilesystem:DescribeMountTargets + - kms:CreateGrant + - kms:Decrypt + - kms:Encrypt + - kms:GenerateDataKey + - lambda:GetCodeSigningConfig + - lambda:GetFunctionCodeSigningConfig + - lambda:GetLayerVersion + - lambda:GetRuntimeManagementConfig + - lambda:PutRuntimeManagementConfig + - lambda:TagResource + - lambda:PutFunctionRecursionConfig + - lambda:GetFunctionRecursionConfig + - lambda:PutFunctionScalingConfig + - lambda:PassCapacityProvider + + """ + raise NotImplementedError + + @abstractmethod + def read( + self, + request: ResourceRequest[LambdaFunctionProperties], + ) -> ProgressEvent[LambdaFunctionProperties]: + """ + Fetch resource information + + IAM permissions required: + - lambda:GetFunction + - lambda:GetFunctionCodeSigningConfig + - lambda:GetFunctionRecursionConfig + - lambda:GetRuntimeManagementConfig + - lambda:GetFunctionScalingConfig + """ + raise NotImplementedError + + @abstractmethod + def delete( + self, + request: ResourceRequest[LambdaFunctionProperties], + ) -> ProgressEvent[LambdaFunctionProperties]: + """ + Delete a resource + + IAM permissions required: + - lambda:DeleteFunction + - lambda:GetFunction + - ec2:DescribeNetworkInterfaces + """ + raise NotImplementedError + + @abstractmethod + def update( + self, + request: ResourceRequest[LambdaFunctionProperties], + ) -> ProgressEvent[LambdaFunctionProperties]: + """ + Update a resource + + IAM permissions required: + - lambda:DeleteFunctionConcurrency + - lambda:GetFunction + - lambda:PutFunctionConcurrency + - lambda:TagResource + - lambda:UntagResource + - lambda:UpdateFunctionConfiguration + - lambda:UpdateFunctionCode + - iam:PassRole + - s3:GetObject + - s3:GetObjectVersion + - ec2:DescribeSecurityGroups + - ec2:DescribeSubnets + - ec2:DescribeVpcs + - elasticfilesystem:DescribeMountTargets + - kms:CreateGrant + - kms:Decrypt + - kms:GenerateDataKey + - lambda:GetRuntimeManagementConfig + - lambda:PutRuntimeManagementConfig + - lambda:PutFunctionCodeSigningConfig + - lambda:DeleteFunctionCodeSigningConfig + - lambda:GetCodeSigningConfig + - lambda:GetFunctionCodeSigningConfig + - lambda:PutFunctionRecursionConfig + - lambda:GetFunctionRecursionConfig + - lambda:PutFunctionScalingConfig + - lambda:PublishVersion + - lambda:PassCapacityProvider + """ + raise NotImplementedError + + @abstractmethod + def list( + self, + request: ResourceRequest[LambdaFunctionProperties], + ) -> ProgressEvent[LambdaFunctionProperties]: + """ + List available resources of this type + IAM permissions required: + - lambda:ListFunctions + """ + raise NotImplementedError diff --git a/localstack-core/localstack/services/lambda_/resource_providers/aws_lambda_function_plugin.py b/localstack-core/localstack/services/lambda_/resource_providers/generated/aws_lambda_function_plugin.py similarity index 100% rename from localstack-core/localstack/services/lambda_/resource_providers/aws_lambda_function_plugin.py rename to localstack-core/localstack/services/lambda_/resource_providers/generated/aws_lambda_function_plugin.py diff --git a/localstack-core/localstack/services/lambda_/resource_providers/lambda_alias.py b/localstack-core/localstack/services/lambda_/resource_providers/lambda_alias.py index 2130958dde803..8b92d78a45fda 100644 --- a/localstack-core/localstack/services/lambda_/resource_providers/lambda_alias.py +++ b/localstack-core/localstack/services/lambda_/resource_providers/lambda_alias.py @@ -116,7 +116,7 @@ def create( return ProgressEvent( status=OperationStatus.FAILED, resource_model=model, - message="", + message=result.get("StatusReason", "Unknown"), error_code="VersionStateFailure", # TODO: not parity tested ) diff --git a/localstack-core/localstack/services/lambda_/runtimes.py b/localstack-core/localstack/services/lambda_/runtimes.py index 3e666949dd008..7c5ba22131479 100644 --- a/localstack-core/localstack/services/lambda_/runtimes.py +++ b/localstack-core/localstack/services/lambda_/runtimes.py @@ -13,7 +13,7 @@ # 2. Add the new runtime to these variables below: # a) `IMAGE_MAPPING` # b) `RUNTIMES_AGGREGATED` -# c) `SNAP_START_SUPPORTED_RUNTIMES` if supported (currently only new Java runtimes) +# c) `SNAP_START_SUPPORTED_RUNTIMES` if supported # 3. Re-create snapshots for Lambda tests with the marker @markers.lambda_runtime_update # => Filter the tests using pytest -m lambda_runtime_update (i.e., additional arguments in PyCharm) # Depending on the runtime, `test_lambda_runtimes.py` might require further snapshot updates. @@ -23,10 +23,12 @@ # 5. Run the unit test to check the runtime setup: # tests.unit.services.lambda_.test_api_utils.TestApiUtils.test_check_runtime # 6. Review special tests including: -# a) [ext] tests.aws.services.lambda_.test_lambda_endpoint_injection +# a) [pro] tests.aws.services.lambda_.test_lambda_endpoint_injection # 7. Before merging, run the ext integration tests to cover transparent endpoint injection testing. # 8. Add the new runtime to the K8 image build: https://github.com/localstack/lambda-images -# 9. Inform the web team to update the resource browser (consider offering an endpoint in the future) +# 9. Check that the Resource Browser shows the new runtime or reach out to the web team. +# The internal endpoint /_aws/lambda/runtimes yields all supported runtimes +# 10. Inform #devrel to announce the new feature in social media # Mapping from a) AWS Lambda runtime identifier => b) official AWS image on Amazon ECR Public # a) AWS Lambda runtimes: https://docs.aws.amazon.com/lambda/latest/dg/lambda-runtimes.html @@ -34,12 +36,14 @@ # => Synchronize the order with the "Supported runtimes" under "AWS Lambda runtimes" (a) # => Add comments for deprecated runtimes using => => IMAGE_MAPPING: dict[Runtime, str] = { + Runtime.nodejs24_x: "nodejs:24", Runtime.nodejs22_x: "nodejs:22", Runtime.nodejs20_x: "nodejs:20", Runtime.nodejs18_x: "nodejs:18", Runtime.nodejs16_x: "nodejs:16", Runtime.nodejs14_x: "nodejs:14", # deprecated Dec 4, 2023 => Jan 9, 2024 => Feb 8, 2024 Runtime.nodejs12_x: "nodejs:12", # deprecated Mar 31, 2023 => Mar 31, 2023 => Apr 30, 2023 + Runtime.python3_14: "python:3.14", Runtime.python3_13: "python:3.13", Runtime.python3_12: "python:3.12", Runtime.python3_11: "python:3.11", @@ -47,11 +51,13 @@ Runtime.python3_9: "python:3.9", Runtime.python3_8: "python:3.8", Runtime.python3_7: "python:3.7", # deprecated Dec 4, 2023 => Jan 9, 2024 => Feb 8, 2024 + Runtime.java25: "java:25", Runtime.java21: "java:21", Runtime.java17: "java:17", Runtime.java11: "java:11", Runtime.java8_al2: "java:8.al2", Runtime.java8: "java:8", # deprecated Jan 8, 2024 => Feb 8, 2024 => Mar 12, 2024 + Runtime.dotnet10: "dotnet:10", Runtime.dotnet8: "dotnet:8", # dotnet7 (container only) Runtime.dotnet6: "dotnet:6", @@ -110,12 +116,14 @@ # => Remove deprecated runtimes from this testing list RUNTIMES_AGGREGATED = { "nodejs": [ + Runtime.nodejs24_x, Runtime.nodejs22_x, Runtime.nodejs20_x, Runtime.nodejs18_x, Runtime.nodejs16_x, ], "python": [ + Runtime.python3_14, Runtime.python3_13, Runtime.python3_12, Runtime.python3_11, @@ -124,6 +132,7 @@ Runtime.python3_8, ], "java": [ + Runtime.java25, Runtime.java21, Runtime.java17, Runtime.java11, @@ -137,6 +146,7 @@ "dotnet": [ Runtime.dotnet6, Runtime.dotnet8, + Runtime.dotnet10, ], "provided": [ Runtime.provided_al2023, @@ -155,12 +165,28 @@ Runtime.java11, Runtime.java17, Runtime.java21, + Runtime.java25, Runtime.python3_12, Runtime.python3_13, Runtime.dotnet8, + Runtime.dotnet10, ] # An ordered list of all Lambda runtimes considered valid by AWS. Matching snapshots in test_create_lambda_exceptions -VALID_RUNTIMES: str = "[nodejs20.x, provided.al2023, python3.12, python3.13, nodejs22.x, java17, nodejs16.x, dotnet8, python3.10, java11, python3.11, dotnet6, java21, nodejs18.x, provided.al2, ruby3.3, ruby3.4, java8.al2, ruby3.2, python3.8, python3.9]" +VALID_RUNTIMES: str = "[nodejs20.x, python3.14, provided.al2023, python3.12, python3.13, nodejs24.x, nodejs22.x, java25, python3.10, python3.11, java21, ruby3.3, ruby3.4, ruby3.2, python3.8, python3.9, java17, nodejs16.x, dotnet10, dotnet8, java11, dotnet6, nodejs18.x, provided.al2, java8.al2]" # An ordered list of all Lambda runtimes for layers considered valid by AWS. Matching snapshots in test_layer_exceptions -VALID_LAYER_RUNTIMES: str = "[ruby2.6, dotnetcore1.0, python3.7, nodejs8.10, nasa, ruby2.7, python2.7-greengrass, dotnetcore2.0, python3.8, java21, dotnet6, dotnetcore2.1, python3.9, java11, nodejs6.10, provided, dotnetcore3.1, dotnet8, java25, java17, nodejs, nodejs4.3, java8.al2, go1.x, dotnet10, nodejs20.x, go1.9, byol, nodejs10.x, provided.al2023, nodejs22.x, python3.10, java8, nodejs12.x, python3.11, nodejs24.x, nodejs8.x, python3.12, nodejs14.x, nodejs8.9, python3.13, python3.14, nodejs16.x, provided.al2, nodejs4.3-edge, nodejs18.x, ruby3.2, python3.4, ruby3.3, ruby3.4, ruby2.5, python3.6, python2.7]" +VALID_LAYER_RUNTIMES: str = "[ruby3.5, ruby2.6, dotnetcore1.0, python3.7, nodejs8.10, nasa, ruby2.7, python2.7-greengrass, dotnetcore2.0, python3.8, java21, dotnet6, dotnetcore2.1, python3.9, java11, nodejs6.10, provided, dotnetcore3.1, dotnet8, java25, java17, nodejs, nodejs4.3, java8.al2, go1.x, dotnet10, nodejs20.x, go1.9, byol, nodejs10.x, provided.al2023, nodejs22.x, python3.10, java8, nodejs12.x, python3.11, nodejs24.x, nodejs8.x, python3.12, nodejs14.x, nodejs8.9, nodejs26.x, python3.13, python3.14, nodejs16.x, python3.15, provided.al2, nodejs4.3-edge, nodejs18.x, ruby3.2, python3.4, ruby3.3, ruby3.4, ruby2.5, python3.6, python2.7]" +# An unordered list of runtimes supporting Lambda Managed Instances: https://docs.aws.amazon.com/lambda/latest/dg/lambda-managed-instances-runtimes.html#lambda-managed-instances-supported-runtimes + +VALID_MANAGED_INSTANCE_RUNTIMES = [ + Runtime.nodejs24_x, + Runtime.nodejs22_x, + Runtime.python3_14, + Runtime.python3_13, + Runtime.java25, + Runtime.java21, + Runtime.dotnet10, + Runtime.dotnet8, + # not officially listed, but can be invoked + Runtime.provided_al2023, +] diff --git a/localstack-core/localstack/services/logs/provider.py b/localstack-core/localstack/services/logs/provider.py index b77bc646a3dfd..15007079d9802 100644 --- a/localstack-core/localstack/services/logs/provider.py +++ b/localstack-core/localstack/services/logs/provider.py @@ -14,6 +14,7 @@ from localstack.aws.api import CommonServiceException, RequestContext, handler from localstack.aws.api.logs import ( AmazonResourceName, + DeletionProtectionEnabled, DescribeLogGroupsRequest, DescribeLogGroupsResponse, DescribeLogStreamsRequest, @@ -22,10 +23,13 @@ InputLogEvents, InvalidParameterException, KmsKeyId, + ListLogGroupsRequest, + ListLogGroupsResponse, ListTagsForResourceResponse, ListTagsLogGroupResponse, LogGroupClass, LogGroupName, + LogGroupSummary, LogsApi, LogStreamName, PutLogEventsResponse, @@ -40,10 +44,11 @@ from localstack.services.logs.models import get_moto_logs_backend, logs_stores from localstack.services.moto import call_moto from localstack.services.plugins import ServiceLifecycleHook +from localstack.state import StateVisitor from localstack.utils.aws import arns from localstack.utils.aws.client_types import ServicePrincipal from localstack.utils.bootstrap import is_api_enabled -from localstack.utils.common import is_number +from localstack.utils.numbers import is_number from localstack.utils.patch import patch LOG = logging.getLogger(__name__) @@ -54,14 +59,20 @@ def __init__(self): super().__init__() self.cw_client = connect_to().cloudwatch + def accept_state_visitor(self, visitor: StateVisitor): + from moto.logs.models import logs_backends + + visitor.visit(logs_backends) + visitor.visit(logs_stores) + def put_log_events( self, context: RequestContext, log_group_name: LogGroupName, log_stream_name: LogStreamName, log_events: InputLogEvents, - sequence_token: SequenceToken = None, - entity: Entity = None, + sequence_token: SequenceToken | None = None, + entity: Entity | None = None, **kwargs, ) -> PutLogEventsResponse: logs_backend = get_moto_logs_backend(context.account_id, context.region) @@ -97,33 +108,32 @@ def describe_log_groups( ) -> DescribeLogGroupsResponse: region_backend = get_moto_logs_backend(context.account_id, context.region) - prefix: str = request.get("logGroupNamePrefix", "") - pattern: str = request.get("logGroupNamePattern", "") + prefix: str | None = request.get("logGroupNamePrefix", "") + pattern: str | None = request.get("logGroupNamePattern", "") if pattern and prefix: raise InvalidParameterException( "LogGroup name prefix and LogGroup name pattern are mutually exclusive parameters." ) - copy_groups = copy.deepcopy(region_backend.groups) + moto_groups = copy.deepcopy(dict(region_backend.groups)).values() groups = [ - group.to_describe_dict() - for name, group in copy_groups.items() + {"logGroupClass": LogGroupClass.STANDARD} | group.to_describe_dict() + for group in sorted(moto_groups, key=lambda g: g.name) if not (prefix or pattern) - or (prefix and name.startswith(prefix)) - or (pattern and pattern in name) + or (prefix and group.name.startswith(prefix)) + or (pattern and pattern in group.name) ] - groups = sorted(groups, key=lambda x: x["logGroupName"]) return DescribeLogGroupsResponse(logGroups=groups) @handler("DescribeLogStreams", expand=False) def describe_log_streams( self, context: RequestContext, request: DescribeLogStreamsRequest ) -> DescribeLogStreamsResponse: - log_group_name: str = request.get("logGroupName") - log_group_identifier: str = request.get("logGroupIdentifier") + log_group_name: str | None = request.get("logGroupName") + log_group_identifier: str | None = request.get("logGroupIdentifier") if log_group_identifier and log_group_name: raise CommonServiceException( @@ -138,13 +148,30 @@ def describe_log_streams( return moto.call_moto_with_request(context, request_copy) + @handler("ListLogGroups", expand=False) + def list_log_groups( + self, context: RequestContext, request: ListLogGroupsRequest + ) -> ListLogGroupsResponse: + pattern: str | None = request.get("logGroupNamePattern") + region_backend: LogsBackend = get_moto_logs_backend(context.account_id, context.region) + moto_groups = copy.deepcopy(region_backend.groups).values() + groups = [ + LogGroupSummary( + logGroupName=group.name, logGroupArn=group.arn, logGroupClass=LogGroupClass.STANDARD + ) + for group in sorted(moto_groups, key=lambda g: g.name) + if not pattern or pattern in group.name + ] + return ListLogGroupsResponse(logGroups=groups) + def create_log_group( self, context: RequestContext, log_group_name: LogGroupName, - kms_key_id: KmsKeyId = None, - tags: Tags = None, - log_group_class: LogGroupClass = None, + kms_key_id: KmsKeyId | None = None, + tags: Tags | None = None, + log_group_class: LogGroupClass | None = None, + deletion_protection_enabled: DeletionProtectionEnabled | None = None, **kwargs, ) -> None: call_moto(context) @@ -442,10 +469,9 @@ def moto_to_describe_dict(target, self): # reported race condition in https://github.com/localstack/localstack/issues/8011 # making copy of "streams" dict here to avoid issues while summing up storedBytes copy_streams = copy.deepcopy(self.streams) - # parity tests shows that the arn ends with ":*" - arn = self.arn if self.arn.endswith(":*") else f"{self.arn}:*" log_group = { - "arn": arn, + "arn": f"{self.arn}:*", + "logGroupArn": self.arn, "creationTime": self.creation_time, "logGroupName": self.name, "metricFilterCount": 0, diff --git a/localstack-core/localstack/services/moto.py b/localstack-core/localstack/services/moto.py index ebc21b7684459..c2180066b06b6 100644 --- a/localstack-core/localstack/services/moto.py +++ b/localstack-core/localstack/services/moto.py @@ -5,12 +5,11 @@ import copy import sys from collections.abc import Callable -from contextlib import AbstractContextManager from functools import lru_cache import moto.backends as moto_backends from moto.core.base_backend import BackendDict -from moto.core.exceptions import RESTError, ServiceException +from moto.core.exceptions import RESTError from rolo.router import RegexConverter from werkzeug.exceptions import NotFound from werkzeug.routing import Map, Rule @@ -211,38 +210,3 @@ class _PartIsolatingRegexConverter(RegexConverter): def __init__(self, *args, **kwargs) -> None: super().__init__(*args, **kwargs) - - -class ServiceExceptionTranslator(AbstractContextManager): - """ - This reentrant context manager translates Moto exceptions into ASF service exceptions. This allows ASF to properly - serialise and generate the correct error response. - - This is useful when invoking Moto operations directly by importing the backend. For example: - - from moto.ses import ses_backends - - backend = ses_backend['000000000000']['us-east-1'] - - with ServiceExceptionTranslator(): - message = backend.send_raw_email(...) - - If `send_raw_email(...)` raises any `moto.core.exceptions.ServiceException`, this context manager will transparently - generate and raise a `localstack.aws.api.core.CommonServiceException`, maintaining the error code and message. - - This only works for Moto services that are integrated with its new core AWS response serialiser. - """ - - def __enter__(self): - pass - - def __exit__(self, exc_type, exc_val, exc_tb): - if exc_type is not None and issubclass(exc_type, ServiceException): - raise CommonServiceException( - code=exc_val.code, - message=exc_val.message, - ) - return False - - -translate_service_exception = ServiceExceptionTranslator() diff --git a/localstack-core/localstack/services/opensearch/models.py b/localstack-core/localstack/services/opensearch/models.py index 3141e4263cb4f..0cf6d2d769533 100644 --- a/localstack-core/localstack/services/opensearch/models.py +++ b/localstack-core/localstack/services/opensearch/models.py @@ -2,18 +2,15 @@ from localstack.services.stores import ( AccountRegionBundle, BaseStore, - CrossRegionAttribute, LocalAttribute, ) -from localstack.utils.tagging import TaggingService +from localstack.utils.tagging import Tags class OpenSearchStore(BaseStore): # storage for domain resources (access should be protected with the _domain_mutex) opensearch_domains: dict[str, DomainStatus] = LocalAttribute(default=dict) - - # static tagging service instance - TAGS = CrossRegionAttribute(default=TaggingService) + tags: Tags = LocalAttribute(default=Tags) opensearch_stores = AccountRegionBundle("opensearch", OpenSearchStore) diff --git a/localstack-core/localstack/services/opensearch/packages.py b/localstack-core/localstack/services/opensearch/packages.py index b5c266512ba43..9ef799a69b0a2 100644 --- a/localstack-core/localstack/services/opensearch/packages.py +++ b/localstack-core/localstack/services/opensearch/packages.py @@ -107,19 +107,31 @@ def _install(self, target: InstallTarget): # setup security based on the version self._setup_security(install_dir, parsed_version) + # Determine network configuration to use for plugin downloads + sys_props = { + **java_system_properties_proxy(), + **java_system_properties_ssl( + os.path.join(install_dir, "jdk", "bin", "keytool"), + {"JAVA_HOME": os.path.join(install_dir, "jdk")}, + ), + } + java_opts = system_properties_to_cli_args(sys_props) + + keystore_binary = os.path.join(install_dir, "bin", "opensearch-keystore") + if os.path.exists(keystore_binary): + # initialize and create the keystore. Concurrent starts of ES will all try to create it at the same + # time, and fail with a race condition. Creating once when installing solves the issue without + # the need to lock the starts + # Ultimately, each cluster should have its own `config` file and maybe not share the same one + output = run( + [keystore_binary, "create"], + env_vars={"OPENSEARCH_JAVA_OPTS": " ".join(java_opts)}, + ) + LOG.debug("Keystore init output: %s", output) + # install other default plugins for opensearch 1.1+ # https://forum.opensearch.org/t/ingest-attachment-cannot-be-installed/6494/12 if parsed_version >= "1.1.0": - # Determine network configuration to use for plugin downloads - sys_props = { - **java_system_properties_proxy(), - **java_system_properties_ssl( - os.path.join(install_dir, "jdk", "bin", "keytool"), - {"JAVA_HOME": os.path.join(install_dir, "jdk")}, - ), - } - java_opts = system_properties_to_cli_args(sys_props) - for plugin in OPENSEARCH_PLUGIN_LIST: plugin_binary = os.path.join(install_dir, "bin", "opensearch-plugin") plugin_dir = os.path.join(install_dir, "plugins", plugin) @@ -322,6 +334,18 @@ def try_install(): if not os.environ.get("IGNORE_ES_DOWNLOAD_ERRORS"): raise + keystore_binary = os.path.join(install_dir, "bin", "elasticsearch-keystore") + if os.path.exists(keystore_binary): + # initialize and create the keystore. Concurrent starts of ES will all try to create it at the same + # time, and fail with a race condition. Creating once when installing solves the issue without + # the need to lock the starts + # Ultimately, each cluster should have its own `config` file and maybe not share the same one + output = run( + [keystore_binary, "create"], + env_vars={"ES_JAVA_OPTS": " ".join(java_opts)}, + ) + LOG.debug("Keystore init output: %s", output) + # delete some plugins to free up space for plugin in ELASTICSEARCH_DELETE_MODULES: module_dir = os.path.join(install_dir, "modules", plugin) @@ -341,16 +365,6 @@ def try_install(): if jvm_options != jvm_options_replaced: save_file(jvm_options_file, jvm_options_replaced) - # patch JVM options file - replace hardcoded heap size settings - jvm_options_file = os.path.join(install_dir, "config", "jvm.options") - if os.path.exists(jvm_options_file): - jvm_options = load_file(jvm_options_file) - jvm_options_replaced = re.sub( - r"(^-Xm[sx][a-zA-Z0-9.]+$)", r"# \1", jvm_options, flags=re.MULTILINE - ) - if jvm_options != jvm_options_replaced: - save_file(jvm_options_file, jvm_options_replaced) - def _get_install_marker_path(self, install_dir: str) -> str: return os.path.join(install_dir, "bin", "elasticsearch") diff --git a/localstack-core/localstack/services/opensearch/provider.py b/localstack-core/localstack/services/opensearch/provider.py index 0818e1700c20f..da870bfe6586f 100644 --- a/localstack-core/localstack/services/opensearch/provider.py +++ b/localstack-core/localstack/services/opensearch/provider.py @@ -116,6 +116,11 @@ CustomEndpointEnabled=False, ) +DEFAULT_AUTOTUNE_OPTIONS = AutoTuneOptionsOutput( + State=AutoTuneState.ENABLED, + UseOffPeakWindow=False, +) + def cluster_manager() -> ClusterManager: global __CLUSTER_MANAGER @@ -203,6 +208,13 @@ def _status_to_config(status: DomainStatus) -> DomainConfig: cluster_cfg = status.get("ClusterConfig") or {} default_cfg = DEFAULT_OPENSEARCH_CLUSTER_CONFIG config_status = get_domain_config_status() + autotune_options = status.get("AutoTuneOptions") or DEFAULT_AUTOTUNE_OPTIONS + autotune_state = autotune_options.get("State") or AutoTuneState.ENABLED + desired_state = ( + AutoTuneDesiredState.ENABLED + if autotune_state == AutoTuneState.ENABLED + else AutoTuneDesiredState.DISABLED + ) return DomainConfig( AccessPolicies=AccessPoliciesStatus( Options=status.get("AccessPolicies", ""), @@ -275,15 +287,16 @@ def _status_to_config(status: DomainStatus) -> DomainConfig: ), AutoTuneOptions=AutoTuneOptionsStatus( Options=AutoTuneOptions( - DesiredState=AutoTuneDesiredState.ENABLED, + DesiredState=desired_state, RollbackOnDisable=RollbackOnDisable.NO_ROLLBACK, MaintenanceSchedules=[], + UseOffPeakWindow=autotune_options.get("UseOffPeakWindow", False), ), Status=AutoTuneStatus( CreationDate=config_status.get("CreationDate"), UpdateDate=config_status.get("UpdateDate"), UpdateVersion=config_status.get("UpdateVersion"), - State=AutoTuneState.ENABLED, + State=autotune_state, PendingDeletion=config_status.get("PendingDeletion"), ), ), @@ -315,6 +328,22 @@ def get_domain_status( stored_status.update(request) default_cfg.update(request.get("ClusterConfig", {})) + autotune_options = stored_status.get("AutoTuneOptions") or deepcopy(DEFAULT_AUTOTUNE_OPTIONS) + if request and (request_options := request.get("AutoTuneOptions")): + desired_state = request_options.get("DesiredState") or AutoTuneDesiredState.ENABLED + state = ( + AutoTuneState.ENABLED + if desired_state == AutoTuneDesiredState.ENABLED + else AutoTuneState.DISABLED + ) + autotune_options = AutoTuneOptionsOutput( + State=state, + UseOffPeakWindow=request_options.get( + "UseOffPeakWindow", autotune_options.get("UseOffPeakWindow", False) + ), + ) + stored_status["AutoTuneOptions"] = autotune_options + domain_processing_status = stored_status.get("DomainProcessingStatus", None) processing = stored_status.get("Processing", True) if deleted: @@ -377,7 +406,10 @@ def get_domain_status( AdvancedSecurityOptions=AdvancedSecurityOptions( Enabled=False, InternalUserDatabaseEnabled=False ), - AutoTuneOptions=AutoTuneOptionsOutput(State=AutoTuneState.ENABLE_IN_PROGRESS), + AutoTuneOptions=AutoTuneOptionsOutput( + State=stored_status.get("AutoTuneOptions", {}).get("State"), + UseOffPeakWindow=autotune_options.get("UseOffPeakWindow", False), + ), ) return new_status @@ -485,6 +517,22 @@ def _stop_clusters(self): for domain_name in store.opensearch_domains.keys(): cluster_manager().remove(DomainKey(domain_name, region, account_id).arn) + def _add_tags(self, context: RequestContext, arn: ARN, tag_list: TagList) -> None: + self.get_store(context.account_id, context.region).tags.update_tags( + arn, {tag["Key"]: tag["Value"] for tag in tag_list} + ) + + def _remove_tags(self, context: RequestContext, arn: ARN, tag_keys: StringList) -> None: + self.get_store(context.account_id, context.region).tags.delete_tags(arn, tag_keys) + + def _remove_all_tags(self, context: RequestContext, arn: ARN) -> None: + self.get_store(context.account_id, context.region).tags.delete_all_tags(arn) + + def _list_tags(self, context: RequestContext, arn: ARN) -> TagList: + store = self.get_store(context.account_id, context.region) + tags = store.tags.get_tags(arn) + return [{"Key": key, "Value": value} for key, value in tags.items()] + @handler("CreateDomain", expand=False) def create_domain( self, context: RequestContext, request: CreateDomainRequest @@ -526,7 +574,8 @@ def create_domain( ) # set the tags - self.add_tags(context, domain_key.arn, request.get("TagList")) + if tags := request.get("TagList", []): + self._add_tags(context, domain_key.arn, tags) # get the (updated) status status = get_domain_status(domain_key) @@ -548,6 +597,7 @@ def delete_domain( status = get_domain_status(domain_key, deleted=True) _remove_cluster(domain_key) + self._remove_all_tags(context, domain_key.arn) return DeleteDomainResponse(DomainStatus=status) @@ -582,6 +632,24 @@ def update_domain_config( if domain_status is None: raise ResourceNotFoundException(f"Domain not found: {domain_key.domain_name}") + if payload.get("AutoTuneOptions"): + auto_request = payload.pop("AutoTuneOptions") + desired_state = auto_request.get("DesiredState") or AutoTuneDesiredState.ENABLED + + state = ( + AutoTuneState.ENABLED + if desired_state == AutoTuneDesiredState.ENABLED + else AutoTuneState.DISABLED + ) + + current_autotune = domain_status.get("AutoTuneOptions", {}) + domain_status["AutoTuneOptions"] = AutoTuneOptionsOutput( + State=state, + UseOffPeakWindow=auto_request.get( + "UseOffPeakWindow", current_autotune.get("UseOffPeakWindow", False) + ), + ) + status_update: dict = _update_domain_config_request_to_status(payload) domain_status.update(status_update) @@ -674,20 +742,15 @@ def describe_domain_config( def add_tags(self, context: RequestContext, arn: ARN, tag_list: TagList, **kwargs) -> None: _ensure_domain_exists(arn) - self.get_store(context.account_id, context.region).TAGS.tag_resource(arn, tag_list) + self._add_tags(context, arn, tag_list) def list_tags(self, context: RequestContext, arn: ARN, **kwargs) -> ListTagsResponse: _ensure_domain_exists(arn) - - # The tagging service returns a dictionary with the given root name - store = self.get_store(context.account_id, context.region) - tags = store.TAGS.list_tags_for_resource(arn=arn, root_name="root") - # Extract the actual list of tags for the typed response - tag_list: TagList = tags["root"] + tag_list = self._list_tags(context, arn) return ListTagsResponse(TagList=tag_list) def remove_tags( self, context: RequestContext, arn: ARN, tag_keys: StringList, **kwargs ) -> None: _ensure_domain_exists(arn) - self.get_store(context.account_id, context.region).TAGS.untag_resource(arn, tag_keys) + self._remove_tags(context, arn, tag_keys) diff --git a/localstack-core/localstack/services/providers.py b/localstack-core/localstack/services/providers.py index 0e18b8ddbb281..ef1d9a55c5435 100644 --- a/localstack-core/localstack/services/providers.py +++ b/localstack-core/localstack/services/providers.py @@ -311,17 +311,8 @@ def ses(): @aws_provider() def sns(): - from localstack.services.moto import MotoFallbackDispatcher from localstack.services.sns.provider import SnsProvider - provider = SnsProvider() - return Service.for_provider(provider, dispatch_table_factory=MotoFallbackDispatcher) - - -@aws_provider(api="sns", name="v2") -def sns_v2(): - from localstack.services.sns.v2.provider import SnsProvider - provider = SnsProvider() return Service.for_provider(provider) diff --git a/localstack-core/localstack/services/resource_groups/provider.py b/localstack-core/localstack/services/resource_groups/provider.py index 647dbadbae1e3..f98ce1fd1e796 100644 --- a/localstack-core/localstack/services/resource_groups/provider.py +++ b/localstack-core/localstack/services/resource_groups/provider.py @@ -1,5 +1,9 @@ from localstack.aws.api.resource_groups import ResourceGroupsApi +from localstack.state import StateVisitor class ResourceGroupsProvider(ResourceGroupsApi): - pass + def accept_state_visitor(self, visitor: StateVisitor): + from moto.resourcegroups.models import resourcegroups_backends + + visitor.visit(resourcegroups_backends) diff --git a/localstack-core/localstack/services/resourcegroupstaggingapi/provider.py b/localstack-core/localstack/services/resourcegroupstaggingapi/provider.py index a9535da68eaae..ea7629b5304e1 100644 --- a/localstack-core/localstack/services/resourcegroupstaggingapi/provider.py +++ b/localstack-core/localstack/services/resourcegroupstaggingapi/provider.py @@ -1,7 +1,12 @@ from abc import ABC from localstack.aws.api.resourcegroupstaggingapi import ResourcegroupstaggingapiApi +from localstack.state import StateVisitor class ResourcegroupstaggingapiProvider(ResourcegroupstaggingapiApi, ABC): - pass + def accept_state_visitor(self, visitor: StateVisitor): + # currently, Moto resourcegroupstaggingapi stores all tags into the other services backend, so their backend + # does not hold any state and is not worth saving. It only holds direct references to other services + # It only holds pagination tokens that are not worth keeping + pass diff --git a/localstack-core/localstack/services/route53/models.py b/localstack-core/localstack/services/route53/models.py index 3d96a9c223100..32173d6aee236 100644 --- a/localstack-core/localstack/services/route53/models.py +++ b/localstack-core/localstack/services/route53/models.py @@ -1,10 +1,12 @@ from localstack.aws.api.route53 import DelegationSet from localstack.services.stores import AccountRegionBundle, BaseStore, LocalAttribute +from localstack.utils.tagging import Tags class Route53Store(BaseStore): # maps delegation set ID to reusable delegation set details reusable_delegation_sets: dict[str, DelegationSet] = LocalAttribute(default=dict) + tags: Tags = LocalAttribute(default=Tags) -route53_stores = AccountRegionBundle("route53", Route53Store) +route53_stores = AccountRegionBundle("route53", Route53Store, validate=False) diff --git a/localstack-core/localstack/services/route53/provider.py b/localstack-core/localstack/services/route53/provider.py index 58078805f9f1f..ad07970af4731 100644 --- a/localstack-core/localstack/services/route53/provider.py +++ b/localstack-core/localstack/services/route53/provider.py @@ -11,6 +11,7 @@ ChangeStatus, CreateHostedZoneResponse, DeleteHealthCheckResponse, + DeleteHostedZoneResponse, DNSName, GetChangeResponse, GetHealthCheckResponse, @@ -26,9 +27,22 @@ from localstack.aws.connect import connect_to from localstack.services.moto import call_moto from localstack.services.plugins import ServiceLifecycleHook +from localstack.services.route53.models import route53_stores +from localstack.state import StateVisitor class Route53Provider(Route53Api, ServiceLifecycleHook): + def accept_state_visitor(self, visitor: StateVisitor): + + visitor.visit(route53_backends) + visitor.visit(route53_stores) + + # No tag deletion logic to handle in Community. Overwritten in Pro implementation. + def remove_resource_tags( + self, context: RequestContext, resource_type: str, resource_id: str + ) -> None: + return + def create_hosted_zone( self, context: RequestContext, @@ -107,6 +121,13 @@ def get_health_check( ) ) + def delete_hosted_zone( + self, context: RequestContext, id: ResourceId, **kwargs + ) -> DeleteHostedZoneResponse: + response = call_moto(context) + self.remove_resource_tags(context=context, resource_type="hostedzone", resource_id=id) + return response + def delete_health_check( self, context: RequestContext, health_check_id: HealthCheckId, **kwargs ) -> DeleteHealthCheckResponse: @@ -119,4 +140,8 @@ def delete_health_check( ) route53_backends[context.account_id][context.partition].delete_health_check(health_check_id) - return {} + self.remove_resource_tags( + context=context, resource_type="healthcheck", resource_id=health_check_id + ) + + return DeleteHealthCheckResponse() diff --git a/localstack-core/localstack/services/route53/resource_providers/aws_route53_recordset.py b/localstack-core/localstack/services/route53/resource_providers/aws_route53_recordset.py index e2497adfe09c1..1a985f9f4cde3 100644 --- a/localstack-core/localstack/services/route53/resource_providers/aws_route53_recordset.py +++ b/localstack-core/localstack/services/route53/resource_providers/aws_route53_recordset.py @@ -6,6 +6,7 @@ if TYPE_CHECKING: from mypy_boto3_route53 import Route53Client + from mypy_boto3_route53.type_defs import ResourceRecordSetTypeDef import localstack.services.cloudformation.provider_utils as util from localstack.services.cloudformation.resource_provider import ( @@ -91,33 +92,7 @@ def create( hosted_zone_id = self.get_hosted_zone_id_from_name(hosted_zone_name, route53) model["HostedZoneId"] = hosted_zone_id - attr_names = [ - "Name", - "Type", - "SetIdentifier", - "Weight", - "Region", - "GeoLocation", - "Failover", - "MultiValueAnswer", - "TTL", - "ResourceRecords", - "AliasTarget", - "HealthCheckId", - ] - attrs = util.select_attributes(model, attr_names) - - if "AliasTarget" in attrs: - # https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-route53-recordset-aliastarget.html - if "EvaluateTargetHealth" not in attrs["AliasTarget"]: - attrs["AliasTarget"]["EvaluateTargetHealth"] = False - else: - # TODO: CNAME & SOA only allow 1 record type. should we check that here? - attrs["ResourceRecords"] = [{"Value": record} for record in attrs["ResourceRecords"]] - - if "TTL" in attrs: - if isinstance(attrs["TTL"], str): - attrs["TTL"] = int(attrs["TTL"]) + attrs = self._get_resource_record_set_from_model(model) route53.change_resource_record_sets( HostedZoneId=model["HostedZoneId"], @@ -171,27 +146,15 @@ def delete( """ model = request.previous_state route53 = request.aws_client_factory.route53 - rrset_kwargs = { - "Name": model["Name"], - "Type": model["Type"], - } - - if "AliasTarget" in model: - rrset_kwargs["AliasTarget"] = model["AliasTarget"] - if "ResourceRecords" in model: - rrset_kwargs["ResourceRecords"] = [ - {"Value": record} for record in model["ResourceRecords"] - ] - if "TTL" in model: - rrset_kwargs["TTL"] = int(model["TTL"]) + resource_record_set = self._get_resource_record_set_from_model(model) route53.change_resource_record_sets( HostedZoneId=model["HostedZoneId"], ChangeBatch={ "Changes": [ { "Action": "DELETE", - "ResourceRecordSet": rrset_kwargs, + "ResourceRecordSet": resource_record_set, }, ] }, @@ -210,4 +173,72 @@ def update( """ - raise NotImplementedError + model = request.desired_state + prev_model = request.previous_state + + assert request.previous_state is not None + + route53 = request.aws_client_factory.route53 + changes = [] + + if model.get("SetIdentifier") != prev_model.get("SetIdentifier"): + prev_rrset = self._get_resource_record_set_from_model(prev_model) + changes.append( + { + "Action": "DELETE", + "ResourceRecordSet": prev_rrset, + } + ) + + updated_rrset = self._get_resource_record_set_from_model(model) + changes.append( + { + "Action": "UPSERT", + "ResourceRecordSet": updated_rrset, + } + ) + + route53.change_resource_record_sets( + HostedZoneId=model["HostedZoneId"], + ChangeBatch={"Changes": changes}, + ) + model["Id"] = model["Name"] + + return ProgressEvent( + status=OperationStatus.SUCCESS, + resource_model=model, + ) + + @staticmethod + def _get_resource_record_set_from_model( + model: Route53RecordSetProperties, + ) -> ResourceRecordSetTypeDef: + attr_names = [ + "Name", + "Type", + "SetIdentifier", + "Weight", + "Region", + "GeoLocation", + "Failover", + "MultiValueAnswer", + "TTL", + "ResourceRecords", + "AliasTarget", + "HealthCheckId", + ] + attrs = util.select_attributes(model, attr_names) + + if "AliasTarget" in attrs: + # https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-route53-recordset-aliastarget.html + if "EvaluateTargetHealth" not in attrs["AliasTarget"]: + attrs["AliasTarget"]["EvaluateTargetHealth"] = False + else: + # TODO: CNAME & SOA only allow 1 record type. should we check that here? + attrs["ResourceRecords"] = [{"Value": record} for record in attrs["ResourceRecords"]] + + if "TTL" in attrs: + if isinstance(attrs["TTL"], str): + attrs["TTL"] = int(attrs["TTL"]) + + return attrs diff --git a/localstack-core/localstack/services/route53resolver/provider.py b/localstack-core/localstack/services/route53resolver/provider.py index 7df4ade11cb25..d7cda705e2afb 100644 --- a/localstack-core/localstack/services/route53resolver/provider.py +++ b/localstack-core/localstack/services/route53resolver/provider.py @@ -76,11 +76,13 @@ ResolverQueryLogConfigStatus, ResourceId, ResourceNotFoundException, + RniEnhancedMetricsEnabled, Route53ResolverApi, SecurityGroupIds, SortByKey, SortOrder, TagList, + TargetNameServerMetricsEnabled, UpdateFirewallConfigResponse, UpdateFirewallDomainsResponse, UpdateFirewallRuleGroupAssociationResponse, @@ -100,6 +102,7 @@ validate_mutation_protection, validate_priority, ) +from localstack.state import StateVisitor from localstack.utils.aws import arns from localstack.utils.aws.arns import extract_account_id_from_arn, extract_region_from_arn from localstack.utils.collections import select_from_typed_dict @@ -107,6 +110,10 @@ class Route53ResolverProvider(Route53ResolverApi): + def accept_state_visitor(self, visitor: StateVisitor): + visitor.visit(route53resolver_backends) + visitor.visit(route53resolver_stores) + @staticmethod def get_store(account_id: str, region: str) -> Route53ResolverStore: return route53resolver_stores[account_id][region] @@ -596,12 +603,14 @@ def create_resolver_endpoint( security_group_ids: SecurityGroupIds, direction: ResolverEndpointDirection, ip_addresses: IpAddressesRequest, - name: Name = None, - outpost_arn: OutpostArn = None, - preferred_instance_type: OutpostInstanceType = None, - tags: TagList = None, - resolver_endpoint_type: ResolverEndpointType = None, - protocols: ProtocolList = None, + name: Name | None = None, + outpost_arn: OutpostArn | None = None, + preferred_instance_type: OutpostInstanceType | None = None, + tags: TagList | None = None, + resolver_endpoint_type: ResolverEndpointType | None = None, + protocols: ProtocolList | None = None, + rni_enhanced_metrics_enabled: RniEnhancedMetricsEnabled | None = None, + target_name_server_metrics_enabled: TargetNameServerMetricsEnabled | None = None, **kwargs, ) -> CreateResolverEndpointResponse: create_resolver_endpoint_resp = call_moto(context) diff --git a/localstack-core/localstack/services/s3/constants.py b/localstack-core/localstack/services/s3/constants.py index 510494d048d47..f5e73f0647adc 100644 --- a/localstack-core/localstack/services/s3/constants.py +++ b/localstack-core/localstack/services/s3/constants.py @@ -1,4 +1,5 @@ from localstack.aws.api.s3 import ( + BucketLocationConstraint, ChecksumAlgorithm, Grantee, Permission, @@ -10,8 +11,6 @@ ) from localstack.aws.api.s3 import Type as GranteeType -S3_VIRTUAL_HOST_FORWARDED_HEADER = "x-s3-vhost-forwarded-for" - S3_UPLOAD_PART_MIN_SIZE = 5242880 """ This is minimum size allowed by S3 when uploading more than one part for a Multipart Upload, except for the last part @@ -21,6 +20,11 @@ DEFAULT_PRE_SIGNED_ACCESS_KEY_ID = "test" DEFAULT_PRE_SIGNED_SECRET_ACCESS_KEY = "test" +S3_HOST_ID = "9Gjjt1m+cjU4OPvX9O9/8RuvnG41MRb/18Oux2o5H5MY7ISNTlXN+Dz9IG62/ILVxhAGI0qyPfg=" +""" +S3 is returning a Host Id as part of its exceptions +""" + AUTHENTICATED_USERS_ACL_GROUP = "http://acs.amazonaws.com/groups/global/AuthenticatedUsers" ALL_USERS_ACL_GROUP = "http://acs.amazonaws.com/groups/global/AllUsers" LOG_DELIVERY_ACL_GROUP = "http://acs.amazonaws.com/groups/s3/LogDelivery" @@ -63,6 +67,10 @@ ChecksumAlgorithm.CRC64NVME, ] +BUCKET_LOCATION_CONSTRAINTS = [constraint.value for constraint in BucketLocationConstraint] + +EU_WEST_1_LOCATION_CONSTRAINTS = [BucketLocationConstraint.EU, BucketLocationConstraint.eu_west_1] + # response header overrides the client may request ALLOWED_HEADER_OVERRIDES = { "ResponseContentType": "ContentType", diff --git a/localstack-core/localstack/services/s3/cors.py b/localstack-core/localstack/services/s3/cors.py index 13fb4a55ac662..3d7a11f348a9b 100644 --- a/localstack-core/localstack/services/s3/cors.py +++ b/localstack-core/localstack/services/s3/cors.py @@ -21,13 +21,13 @@ from localstack.aws.spec import get_service_catalog from localstack.config import S3_VIRTUAL_HOSTNAME from localstack.http import Request, Response +from localstack.services.s3.constants import S3_HOST_ID from localstack.services.s3.utils import S3_VIRTUAL_HOSTNAME_REGEX # TODO: add more logging statements LOG = logging.getLogger(__name__) _s3_virtual_host_regex = re.compile(S3_VIRTUAL_HOSTNAME_REGEX) -FAKE_HOST_ID = "9Gjjt1m+cjU4OPvX9O9/8RuvnG41MRb/18Oux2o5H5MY7ISNTlXN+Dz9IG62/ILVxhAGI0qyPfg=" # TODO: refactor those to expose the needed methods maybe in another way that both can import add_default_headers = CorsResponseEnricher.add_cors_headers @@ -135,7 +135,7 @@ def stop_options_chain(): if is_options_request: context.operation = self._get_op_from_request(request) raise BadRequest( - "Insufficient information. Origin request header needed.", HostId=FAKE_HOST_ID + "Insufficient information. Origin request header needed.", HostId=S3_HOST_ID ) else: # If the header is missing, Amazon S3 doesn't treat the request as a cross-origin request, @@ -167,7 +167,7 @@ def stop_options_chain(): context.operation = self._get_op_from_request(request) raise AccessForbidden( message, - HostId=FAKE_HOST_ID, + HostId=S3_HOST_ID, Method=request.headers.get("Access-Control-Request-Method", "OPTIONS"), ResourceType="BUCKET", ) @@ -182,7 +182,7 @@ def stop_options_chain(): context.operation = self._get_op_from_request(request) raise AccessForbidden( "CORSResponse: This CORS request is not allowed. This is usually because the evalution of Origin, request method / Access-Control-Request-Method or Access-Control-Request-Headers are not whitelisted by the resource's CORS spec.", - HostId=FAKE_HOST_ID, + HostId=S3_HOST_ID, Method=request.headers.get("Access-Control-Request-Method"), ResourceType="OBJECT", ) diff --git a/localstack-core/localstack/services/s3/exceptions.py b/localstack-core/localstack/services/s3/exceptions.py index 382631de91a50..7497469b719ff 100644 --- a/localstack-core/localstack/services/s3/exceptions.py +++ b/localstack-core/localstack/services/s3/exceptions.py @@ -51,3 +51,12 @@ def __init__(self, message=None) -> None: class TooManyConfigurations(CommonServiceException): def __init__(self, message=None) -> None: super().__init__("TooManyConfigurations", status_code=400, message=message) + + +class IllegalLocationConstraintException(CommonServiceException): + def __init__(self, location_constraint: str): + super().__init__( + "IllegalLocationConstraintException", + status_code=400, + message=f"The {location_constraint} location constraint is incompatible for the region specific endpoint this request was sent to.", + ) diff --git a/localstack-core/localstack/services/s3/headers.py b/localstack-core/localstack/services/s3/headers.py new file mode 100644 index 0000000000000..71e95c462f98e --- /dev/null +++ b/localstack-core/localstack/services/s3/headers.py @@ -0,0 +1,103 @@ +# Code inspired by the standard library ``email.quoprimime.header_encode``, but the safe characters set is different +# in AWS, so we need to override it +import unicodedata +from base64 import b64encode +from email.errors import HeaderParseError +from email.header import decode_header as _decode_header + +from localstack.utils.strings import to_str + +# Build a mapping of octets to the expansion of that octet. Since we're only +# going to have 256 of these things, this isn't terribly inefficient +# space-wise. Initialize the map with the full expansion, and then override +# the safe bytes with the more compact form. +_QUOPRI_HEADER_MAP = [f"={c:02X}" for c in range(256)] + +_SAFE_HEADERS_CHARS = b"!\"#$%&'()*+,-./0123456789:;<>@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^`abcdefghijklmnopqrstuvwxyz{|}~\t" +_NO_ENCODING_CHARS = _SAFE_HEADERS_CHARS + b" _=?" + +# For AWS, it seems it uses the std lib "safe body" bytes list which need no encoding. +for c in _SAFE_HEADERS_CHARS: + _QUOPRI_HEADER_MAP[c] = chr(c) + +# Headers have one other special encoding; spaces become underscores. +_QUOPRI_HEADER_MAP[ord(" ")] = "_" + + +def encode_header_rfc2047(header: str | None) -> str | None: + if header is None: + return None + + header_bytes = header.encode("utf-8") + # When all chars are "safe chars" plus " " and "_", AWS returns it as is. + # But if " " and "_" are presented in an encoded header, it will encode them as well + if all(c in _NO_ENCODING_CHARS for c in header_bytes): + return header + + if "�" in header or any(unicodedata.category(c).startswith("C") for c in header): + # if there are any character which cannot be printed (not a symbol, but will be escaped with \xNN), we need to + # base64 encode the header + # See https://www.unicode.org/reports/tr44/tr44-34.html#General_Category_Values + encoder = encoder_header_rfc2047_base64 + else: + encoder = encode_header_rfc2047_quote_printable + + return encoder(header_bytes) + + +def encode_header_rfc2047_quote_printable(header_bytes: bytes) -> str: + """ + Encode the header value in an RFC 2047 Quote-printable format. By default, Python would encode it in Base64, but + AWS encodes it in the QP (a format similar to Quoted-printable, but used for emails). + This is the same as the standard library ``email.quoprimime.header_encode``, used by ``email.header.Header`` and + ``email.charset.Charset``, but the list of safe characters that do not need to be encoded is different and not + overridable. + + See: + - https://www.rfc-editor.org/rfc/rfc2047.html + - https://docs.aws.amazon.com/AmazonS3/latest/userguide/UsingMetadata.html#UserMetadata + :param header_bytes: header byte value, UTF-8-encoded + :return: encoded header value in RFC 2047 Quoted-printable format + """ + # we use our own safe character map here + encoded = header_bytes.decode("latin1").translate(_QUOPRI_HEADER_MAP) + return f"=?UTF-8?Q?{encoded}?=" + + +def encoder_header_rfc2047_base64(header_bytes: bytes) -> str: + encoded = b64encode(header_bytes).decode("ascii") + return f"=?UTF-8?B?{encoded}?=" + + +def decode_header_rfc2047(header: str) -> str: + try: + header_parts = _decode_header(header) + return "".join(to_str(part, charset) for part, charset in header_parts) + except HeaderParseError: + if header.lower().startswith("=?utf-8?b?"): + # if the header is badly B64 encoded, AWS will return random data, which we cannot make sense of. + # we can use the Unicode replacement character instead to indicate an error + # we return as many replacement chars as there are b64 chars + replacement_header = "\ufffd" * (len(header) - 13) + return replacement_header + return header + + +def replace_non_iso_8859_1_characters(header: str, repl: str = " ") -> str: + """ + Sanitize the header value to not contain any character which cannot be encoded to latin-1, to be compatible with + webservers. + :param header: header value, UTF-8 encoded + :param repl: replacement value for latin-1 incompatible char, empty space by default in AWS + :return: sanitized header value which can be encoded as latin-1 + """ + sanitized_header = header + while True: + try: + sanitized_header.encode("iso-8859-1", errors="strict") + break + except UnicodeEncodeError as exc: + bad_char = sanitized_header[exc.start : exc.end] + sanitized_header = sanitized_header.replace(bad_char, repl) + + return sanitized_header diff --git a/localstack-core/localstack/services/s3/models.py b/localstack-core/localstack/services/s3/models.py index ba5f0c97429e8..a612468431e61 100644 --- a/localstack-core/localstack/services/s3/models.py +++ b/localstack-core/localstack/services/s3/models.py @@ -16,6 +16,7 @@ BadDigest, BucketAccelerateStatus, BucketKeyEnabled, + BucketLocationConstraint, BucketName, BucketRegion, BucketVersioningStatus, @@ -76,7 +77,12 @@ S3_UPLOAD_PART_MIN_SIZE, ) from localstack.services.s3.exceptions import InvalidRequest -from localstack.services.s3.utils import CombinedCrcHash, get_s3_checksum, rfc_1123_datetime +from localstack.services.s3.headers import replace_non_iso_8859_1_characters +from localstack.services.s3.utils import ( + CombinedCrcHash, + get_s3_checksum, + rfc_1123_datetime, +) from localstack.services.stores import ( AccountRegionBundle, BaseStore, @@ -85,7 +91,7 @@ LocalAttribute, ) from localstack.utils.aws import arns -from localstack.utils.tagging import TaggingService +from localstack.utils.tagging import Tags LOG = logging.getLogger(__name__) @@ -96,11 +102,12 @@ class InternalObjectPart(Part): _position: int -# note: not really a need to use a dataclass here, as it has a lot of fields, but only a few are set at creation class S3Bucket: name: BucketName bucket_account_id: AccountId bucket_region: BucketRegion + bucket_arn: str + location_constraint: BucketLocationConstraint | Literal[""] creation_date: datetime multiparts: dict[MultipartUploadId, "S3Multipart"] objects: Union["KeyStore", "VersionedKeyStore"] @@ -118,13 +125,13 @@ class S3Bucket: public_access_block: PublicAccessBlockConfiguration | None accelerate_status: BucketAccelerateStatus | None object_lock_enabled: bool - object_ownership: ObjectOwnership + object_ownership: ObjectOwnership | None # can be set to None manually in S3 intelligent_tiering_configurations: dict[IntelligentTieringId, IntelligentTieringConfiguration] analytics_configurations: dict[AnalyticsId, AnalyticsConfiguration] inventory_configurations: dict[InventoryId, InventoryConfiguration] metric_configurations: dict[MetricsId, MetricsConfiguration] object_lock_default_retention: DefaultRetention | None - replication: ReplicationConfiguration + replication: ReplicationConfiguration | None owner: Owner # set all buckets parameters here @@ -137,10 +144,13 @@ def __init__( acl: AccessControlPolicy = None, object_ownership: ObjectOwnership = None, object_lock_enabled_for_bucket: bool = None, + location_constraint: BucketLocationConstraint | Literal[""] = "", ): self.name = name self.bucket_account_id = account_id self.bucket_region = bucket_region + self.bucket_arn = arns.s3_bucket_arn(self.name, region=bucket_region) + self.location_constraint = location_constraint # If ObjectLock is enabled, it forces the bucket to be versioned as well self.versioning_status = None if not object_lock_enabled_for_bucket else "Enabled" self.objects = KeyStore() if not object_lock_enabled_for_bucket else VersionedKeyStore() @@ -168,7 +178,6 @@ def __init__( self.acl = acl # see https://docs.aws.amazon.com/AmazonS3/latest/API/API_Owner.html self.owner = owner - self.bucket_arn = arns.s3_bucket_arn(self.name, region=bucket_region) def get_object( self, @@ -257,7 +266,6 @@ def get_object( class S3Object: key: ObjectKey version_id: ObjectVersionId | None - bucket: BucketName owner: Owner | None size: Size | None etag: ETag | None @@ -271,16 +279,18 @@ class S3Object: kms_key_id: SSEKMSKeyId | None # inherit bucket bucket_key_enabled: bool | None # inherit bucket sse_key_hash: SSECustomerKeyMD5 | None - checksum_algorithm: ChecksumAlgorithm - checksum_value: str - checksum_type: ChecksumType + # ``checksum_algorithm`` can only be None when SSE-C is set and while creating a Multipart. + # TODO: remove `| None` when SSE-C is removed from AWS S3 + checksum_algorithm: ChecksumAlgorithm | None + checksum_value: str | None + checksum_type: ChecksumType | None lock_mode: ObjectLockMode | ObjectLockRetentionMode | None lock_legal_status: ObjectLockLegalHoldStatus | None lock_until: datetime | None website_redirect_location: WebsiteRedirectLocation | None acl: AccessControlPolicy | None is_current: bool - parts: dict[int, InternalObjectPart] | None + parts: dict[str, InternalObjectPart] restore: Restore | None internal_last_modified: int @@ -310,9 +320,7 @@ def __init__( owner: Owner | None = None, ): self.key = key - self.user_metadata = ( - {k.lower(): v for k, v in user_metadata.items()} if user_metadata else {} - ) + self.user_metadata = user_metadata or {} self.system_metadata = system_metadata or {} self.version_id = version_id self.storage_class = storage_class or StorageClass.STANDARD @@ -340,6 +348,7 @@ def __init__( self.internal_last_modified = 0 def get_system_metadata_fields(self) -> dict: + # TODO: change when updating the schema -> make it a property headers = { "LastModified": self.last_modified_rfc1123, "ContentLength": str(self.size), @@ -349,7 +358,7 @@ def get_system_metadata_fields(self) -> dict: headers["Expires"] = self.expires_rfc1123 for metadata_key, metadata_value in self.system_metadata.items(): - headers[metadata_key] = metadata_value + headers[metadata_key] = replace_non_iso_8859_1_characters(metadata_value) if self.storage_class != StorageClass.STANDARD: headers["StorageClass"] = self.storage_class @@ -384,7 +393,6 @@ def is_locked(self, bypass_governance: bool = False) -> bool: return False -# TODO: could use dataclass, validate after models are set class S3DeleteMarker: key: ObjectKey version_id: str @@ -403,7 +411,6 @@ def is_locked(*args, **kwargs) -> bool: return False -# TODO: could use dataclass, validate after models are set class S3Part: part_number: PartNumber etag: ETag | None @@ -433,14 +440,16 @@ def quoted_etag(self) -> str: class S3Multipart: - parts: dict[PartNumber, S3Part] + id: MultipartUploadId + parts: dict[str, S3Part] object: S3Object - upload_id: MultipartUploadId checksum_value: str | None checksum_type: ChecksumType | None - checksum_algorithm: ChecksumAlgorithm + checksum_algorithm: ChecksumAlgorithm | None initiated: datetime - precondition: bool + precondition: bool | None + initiator: Owner | None + tagging: dict[str, str] | None def __init__( self, @@ -512,9 +521,9 @@ def complete_multipart( checksum_hash = CombinedCrcHash(self.checksum_algorithm) pos = 0 - parts_map: dict[int, InternalObjectPart] = {} + parts_map: dict[str, InternalObjectPart] = {} for index, part in enumerate(parts): - part_number = part["PartNumber"] + part_number = str(part["PartNumber"]) part_etag = part["ETag"].strip('"') s3_part = self.parts.get(part_number) @@ -624,6 +633,8 @@ class KeyStore: retrieve the object from that key. """ + _store: dict[ObjectKey, S3Object | S3DeleteMarker] + def __init__(self): self._store = {} @@ -656,6 +667,8 @@ class VersionedKeyStore: See: https://docs.aws.amazon.com/AmazonS3/latest/userguide/versioning-workflows.html """ + _store: dict[ObjectKey, dict[ObjectVersionId, S3Object | S3DeleteMarker]] + def __init__(self): self._store = defaultdict(dict) @@ -750,9 +763,7 @@ class S3Store(BaseStore): buckets: dict[BucketName, S3Bucket] = CrossRegionAttribute(default=dict) global_bucket_map: dict[BucketName, AccountId] = CrossAccountAttribute(default=dict) aws_managed_kms_key_id: SSEKMSKeyId = LocalAttribute(default=str) - - # static tagging service instance - TAGS: TaggingService = CrossAccountAttribute(default=TaggingService) + tags: Tags = LocalAttribute(default=Tags) class BucketCorsIndex: diff --git a/localstack-core/localstack/services/s3/notifications.py b/localstack-core/localstack/services/s3/notifications.py index 6b708426d6ef3..a0035398fc35c 100644 --- a/localstack-core/localstack/services/s3/notifications.py +++ b/localstack-core/localstack/services/s3/notifications.py @@ -105,7 +105,7 @@ class S3EventNotificationContext: key_storage_class: StorageClass | None @classmethod - def from_request_context_native( + def from_request_context( cls, request_context: RequestContext, s3_bucket: S3Bucket, diff --git a/localstack-core/localstack/services/s3/presigned_url.py b/localstack-core/localstack/services/s3/presigned_url.py index 3cb675d492a44..b782391bc5721 100644 --- a/localstack-core/localstack/services/s3/presigned_url.py +++ b/localstack-core/localstack/services/s3/presigned_url.py @@ -20,7 +20,7 @@ from botocore.utils import percent_encode_sequence from werkzeug.datastructures import Headers, ImmutableMultiDict -from localstack import config +from localstack import config, constants from localstack.aws.accounts import get_account_id_from_access_key_id from localstack.aws.api import CommonServiceException, RequestContext from localstack.aws.api.s3 import ( @@ -35,24 +35,25 @@ from localstack.aws.chain import HandlerChain from localstack.aws.protocol.op_router import RestServiceOperationRouter from localstack.aws.spec import get_service_catalog +from localstack.constants import AWS_REGION_US_EAST_1 from localstack.http import Request, Response from localstack.http.request import get_raw_path from localstack.services.s3.constants import ( DEFAULT_PRE_SIGNED_ACCESS_KEY_ID, DEFAULT_PRE_SIGNED_SECRET_ACCESS_KEY, + S3_HOST_ID, SIGNATURE_V2_PARAMS, SIGNATURE_V4_PARAMS, ) from localstack.services.s3.utils import ( - S3_VIRTUAL_HOST_FORWARDED_HEADER, capitalize_header_name_from_snake_case, extract_bucket_name_and_key_from_headers_and_path, - forwarded_from_virtual_host_addressed_request, is_bucket_name_valid, is_presigned_url_request, uses_host_addressing, ) from localstack.utils.aws.arns import get_partition +from localstack.utils.aws.request_context import mock_aws_request_headers from localstack.utils.strings import to_bytes LOG = logging.getLogger(__name__) @@ -85,8 +86,6 @@ "x-amz-content-sha256", ] -FAKE_HOST_ID = "9Gjjt1m+cjU4OPvX9O9/8RuvnG41MRb/18Oux2o5H5MY7ISNTlXN+Dz9IG62/ILVxhAGI0qyPfg=" - HOST_COMBINATION_REGEX = r"^(.*)(:[\d]{0,6})" PORT_REPLACEMENT = [":80", ":443", f":{config.GATEWAY_LISTEN[0].port}", ""] @@ -156,7 +155,7 @@ def create_signature_does_not_match_sig_v2( "The request signature we calculated does not match the signature you provided. Check your key and signing method." ) ex.AWSAccessKeyId = access_key_id - ex.HostId = FAKE_HOST_ID + ex.HostId = S3_HOST_ID ex.SignatureProvided = request_signature ex.StringToSign = string_to_sign ex.StringToSignBytes = to_bytes(string_to_sign).hex(sep=" ", bytes_per_sep=2).upper() @@ -194,8 +193,8 @@ def __call__(self, _: HandlerChain, context: RequestContext, __: Response): return try: if not is_presigned_url_request(context): - # validate headers, as some can raise ValueError in Moto - _validate_headers_for_moto(context.request.headers) + # validate headers + _validate_streaming_headers(context.request.headers) return # will raise exceptions if the url is not valid, except if S3_SKIP_SIGNATURE_VALIDATION is True # will still try to validate it and log if there's an error @@ -209,7 +208,7 @@ def __call__(self, _: HandlerChain, context: RequestContext, __: Response): elif is_valid_sig_v4(query_arg_set): validate_presigned_url_s3v4(context) - _validate_headers_for_moto(context.request.headers) + _validate_streaming_headers(context.request.headers) LOG.debug("Valid presign url.") # TODO: set the Authorization with the data from the pre-signed query string @@ -248,7 +247,10 @@ def get_credentials_from_parameters(parameters: dict, region: str) -> PreSignedC # fallback to the hardcoded value access_key_id = DEFAULT_PRE_SIGNED_ACCESS_KEY_ID - if not (secret_access_key := get_secret_access_key_from_access_key_id(access_key_id, region)): + if access_key_id in (constants.INTERNAL_AWS_ACCESS_KEY_ID, config.INTERNAL_RESOURCE_ACCOUNT): + secret_access_key = constants.INTERNAL_AWS_SECRET_ACCESS_KEY + + elif not (secret_access_key := get_secret_access_key_from_access_key_id(access_key_id, region)): # if we could not retrieve the secret access key, it means the access key was not registered in LocalStack, # fallback to hardcoded necessary secret access key secret_access_key = DEFAULT_PRE_SIGNED_SECRET_ACCESS_KEY @@ -299,7 +301,7 @@ def is_valid_sig_v2(query_args: set) -> bool: LOG.info("Presign signature calculation failed") raise AccessDenied( "Query-string authentication requires the Signature, Expires and AWSAccessKeyId parameters", - HostId=FAKE_HOST_ID, + HostId=S3_HOST_ID, ) return True @@ -317,7 +319,7 @@ def is_valid_sig_v4(query_args: set) -> bool: LOG.info("Presign signature calculation failed") raise AuthorizationQueryParametersError( "Query-string authentication version 4 requires the X-Amz-Algorithm, X-Amz-Credential, X-Amz-Signature, X-Amz-Date, X-Amz-SignedHeaders, and X-Amz-Expires parameters.", - HostId=FAKE_HOST_ID, + HostId=S3_HOST_ID, ) return True @@ -351,7 +353,7 @@ def validate_presigned_url_s3(context: RequestContext) -> None: ) else: raise AccessDenied( - "Request has expired", HostId=FAKE_HOST_ID, Expires=expires, ServerTime=time.time() + "Request has expired", HostId=S3_HOST_ID, Expires=expires, ServerTime=time.time() ) auth_signer = HmacV1QueryAuthValidation(credentials=signing_credentials, expires=expires) @@ -377,6 +379,14 @@ def validate_presigned_url_s3(context: RequestContext) -> None: ) raise ex + # we need to add a new Authorization header to the request so that the request has the right account id + if not headers.get("Authorization"): + headers["Authorization"] = mock_aws_request_headers( + "s3", + aws_access_key_id=credentials.access_key_id, + region_name=AWS_REGION_US_EAST_1, + )["Authorization"] + add_headers_to_original_request(context, headers) @@ -450,7 +460,7 @@ def validate_presigned_url_s3v4(context: RequestContext) -> None: else: raise AccessDenied( "There were headers present in the request which were not signed", - HostId=FAKE_HOST_ID, + HostId=S3_HOST_ID, HeadersNotSigned=", ".join(sigv4_context.missing_signed_headers), ) @@ -482,7 +492,7 @@ def validate_presigned_url_s3v4(context: RequestContext) -> None: else: raise AccessDenied( "Request has expired", - HostId=FAKE_HOST_ID, + HostId=S3_HOST_ID, Expires=expiration_time.timestamp(), ServerTime=time.time(), X_Amz_Expires=x_amz_expires, @@ -568,34 +578,21 @@ def __init__(self, context: RequestContext): self._query_parameters ) - if forwarded_from_virtual_host_addressed_request(self._headers): - # FIXME: maybe move this so it happens earlier in the chain when using virtual host? - if not is_bucket_name_valid(self._bucket): - raise InvalidBucketName(BucketName=self._bucket) - netloc = self._headers.get(S3_VIRTUAL_HOST_FORWARDED_HEADER) - self.host = netloc - self._original_host = netloc - self.signed_headers["host"] = netloc - # the request comes from the Virtual Host router, we need to remove the bucket from the path + netloc = urlparse.urlparse(self.request.url).netloc + self.host = netloc + self._original_host = netloc + if (host_addressed := uses_host_addressing(self._headers)) and not is_bucket_name_valid( + self._bucket + ): + raise InvalidBucketName(BucketName=self._bucket) + + if not host_addressed and not self.request.path.startswith(f"/{self._bucket}"): + # if in path style, check that the path starts with the bucket + # our path has been sanitized, we should use the un-sanitized one splitted_path = self.request.path.split("/", maxsplit=2) - self.path = f"/{splitted_path[-1]}" - + self.path = f"/{self._bucket}/{splitted_path[-1]}" else: - netloc = urlparse.urlparse(self.request.url).netloc - self.host = netloc - self._original_host = netloc - if (host_addressed := uses_host_addressing(self._headers)) and not is_bucket_name_valid( - self._bucket - ): - raise InvalidBucketName(BucketName=self._bucket) - - if not host_addressed and not self.request.path.startswith(f"/{self._bucket}"): - # if in path style, check that the path starts with the bucket - # our path has been sanitized, we should use the un-sanitized one - splitted_path = self.request.path.split("/", maxsplit=2) - self.path = f"/{self._bucket}/{splitted_path[-1]}" - else: - self.path = self.request.path + self.path = self.request.path # we need to URL encode the path, as the key needs to be urlencoded for the signature to match self.path = urlparse.quote(self.path) @@ -714,7 +711,7 @@ def _get_region_from_x_amz_credential(credential: str) -> str: if not (split_creds := credential.split("/")) or len(split_creds) != 5: raise AuthorizationQueryParametersError( 'Error parsing the X-Amz-Credential parameter; the Credential is mal-formed; expecting "/YYYYMMDD/REGION/SERVICE/aws4_request".', - HostId=FAKE_HOST_ID, + HostId=S3_HOST_ID, ) return split_creds[2] @@ -737,16 +734,13 @@ def add_headers_to_original_request(context: RequestContext, headers: Mapping[st context.request.headers.add(header, value) -def _validate_headers_for_moto(headers: Headers) -> None: +def _validate_streaming_headers(headers: Headers) -> None: """ - The headers can contain values that do not have the right type, and it will throw Exception when passed to Moto + The headers can contain values that do not have the right type, and should be validated. Validate them before it get passed :param headers: request headers """ if headers.get("x-amz-content-sha256", None) == "STREAMING-AWS4-HMAC-SHA256-PAYLOAD": - # this is sign that this is a SigV4 request, with payload encoded - # we do not support payload encoding yet - # moto parses it to an int, it would raise a 500 content_length = headers.get("x-amz-decoded-content-length") if not content_length: raise SignatureDoesNotMatch('"X-Amz-Decoded-Content-Length" header is missing') @@ -775,7 +769,7 @@ def validate_post_policy( "Bucket POST must contain a field named 'key'. If it is specified, please check the order of the fields.", ArgumentName="key", ArgumentValue="", - HostId=FAKE_HOST_ID, + HostId=S3_HOST_ID, ) form_dict = {k.lower(): v for k, v in request_form.items()} @@ -791,7 +785,7 @@ def validate_post_policy( if not is_v2 and not is_v4: ex: AccessDenied = AccessDenied("Access Denied") - ex.HostId = FAKE_HOST_ID + ex.HostId = S3_HOST_ID raise ex try: @@ -810,7 +804,7 @@ def validate_post_policy( if expiration := policy_decoded.get("expiration"): if is_expired(_parse_policy_expiration_date(expiration)): ex: AccessDenied = AccessDenied("Invalid according to Policy: Policy expired.") - ex.HostId = FAKE_HOST_ID + ex.HostId = S3_HOST_ID raise ex # TODO: validate the signature @@ -832,7 +826,7 @@ def validate_post_policy( str_condition = str(condition).replace("'", '"') raise AccessDenied( f"Invalid according to Policy: Policy Condition failed: {str_condition}", - HostId=FAKE_HOST_ID, + HostId=S3_HOST_ID, ) @@ -885,7 +879,7 @@ def _verify_condition(condition: list | dict, form: dict, additional_policy_meta "Your proposed upload exceeds the maximum allowed size", ProposedSize=size, MaxSizeAllowed=end, - HostId=FAKE_HOST_ID, + HostId=S3_HOST_ID, ) else: return True @@ -934,7 +928,7 @@ def _is_match_with_signature_fields( f"Bucket POST must contain a field named '{argument_name}'. If it is specified, please check the order of the fields.", ArgumentName=argument_name, ArgumentValue="", - HostId=FAKE_HOST_ID, + HostId=S3_HOST_ID, ) return True diff --git a/localstack-core/localstack/services/s3/provider.py b/localstack-core/localstack/services/s3/provider.py index 78dcd3b02a2c3..2413fa5a33e10 100644 --- a/localstack-core/localstack/services/s3/provider.py +++ b/localstack-core/localstack/services/s3/provider.py @@ -1,4 +1,5 @@ import base64 +import contextlib import copy import datetime import json @@ -8,6 +9,7 @@ from inspect import signature from io import BytesIO from operator import itemgetter +from threading import RLock from typing import IO from urllib import parse as urlparse from zoneinfo import ZoneInfo @@ -23,6 +25,7 @@ AccountId, AnalyticsConfiguration, AnalyticsId, + AuthorizationHeaderMalformed, BadDigest, Body, Bucket, @@ -30,6 +33,7 @@ BucketAlreadyOwnedByYou, BucketCannedACL, BucketLifecycleConfiguration, + BucketLocationConstraint, BucketLoggingStatus, BucketName, BucketNotEmpty, @@ -114,7 +118,6 @@ InvalidArgument, InvalidBucketName, InvalidDigest, - InvalidLocationConstraint, InvalidObjectState, InvalidPartNumber, InvalidPartOrder, @@ -208,6 +211,7 @@ SSECustomerKeyMD5, StartAfter, StorageClass, + Tag, Tagging, Token, TransitionDefaultMinimumObjectSize, @@ -226,7 +230,7 @@ preprocess_request, serve_custom_service_request_handlers, ) -from localstack.constants import AWS_REGION_US_EAST_1 +from localstack.constants import AWS_REGION_EU_WEST_1, AWS_REGION_US_EAST_1 from localstack.services.edge import ROUTER from localstack.services.plugins import ServiceLifecycleHook from localstack.services.s3.codec import AwsChunkedDecoder @@ -235,6 +239,7 @@ ARCHIVES_STORAGE_CLASSES, CHECKSUM_ALGORITHMS, DEFAULT_BUCKET_ENCRYPTION, + S3_HOST_ID, ) from localstack.services.s3.cors import S3CorsHandler, s3_cors_request_handler from localstack.services.s3.exceptions import ( @@ -271,9 +276,14 @@ base_64_content_md5_to_etag, create_redirect_for_post_request, create_s3_kms_managed_key_for_region, + decode_continuation_token, + decode_user_metadata, + encode_continuation_token, + encode_user_metadata, etag_to_base_64_content_md5, extract_bucket_key_version_id_from_copy_source, generate_safe_version_id, + get_bucket_location_xml, get_canned_acl, get_class_attrs_from_spec_class, get_failed_precondition_copy_source, @@ -288,6 +298,8 @@ get_s3_checksum_algorithm_from_trailing_headers, get_system_metadata_from_request, get_unique_key_id, + get_url_encoded_object_location, + header_name_from_capitalized_param, is_bucket_name_valid, is_version_older_than_other, parse_copy_source_range_header, @@ -300,6 +312,7 @@ validate_dict_fields, validate_failed_precondition, validate_kms_key_id, + validate_location_constraint, validate_tag_set, ) from localstack.services.s3.validation import ( @@ -310,6 +323,7 @@ validate_canned_acl, validate_checksum_value, validate_cors_configuration, + validate_encoding_type, validate_inventory_configuration, validate_lifecycle_configuration, validate_object_key, @@ -319,6 +333,7 @@ from localstack.services.s3.website_hosting import register_website_hosting_routes from localstack.state import AssetDirectory, StateVisitor from localstack.utils.aws.arns import s3_bucket_name +from localstack.utils.aws.aws_stack import get_valid_regions_for_service from localstack.utils.collections import select_from_typed_dict from localstack.utils.strings import short_uid, to_bytes, to_str @@ -338,6 +353,8 @@ def __init__(self, storage_backend: S3ObjectStore = None) -> None: self._storage_backend = storage_backend or EphemeralS3ObjectStore(DEFAULT_S3_TMP_DIR) self._notification_dispatcher = NotificationDispatcher() self._cors_handler = S3CorsHandler(BucketCorsIndex()) + # TODO: add lock for keys for PutObject, only way to support precondition writes for versioned buckets + self._preconditions_locks = defaultdict(lambda: defaultdict(RLock)) # runtime cache of Lifecycle Expiration headers, as they need to be calculated everytime we fetch an object # in case the rules have changed @@ -382,7 +399,7 @@ def _notify( """ if s3_bucket.notification_configuration: if not s3_notif_ctx: - s3_notif_ctx = S3EventNotificationContext.from_request_context_native( + s3_notif_ctx = S3EventNotificationContext.from_request_context( context, s3_bucket=s3_bucket, s3_object=s3_object, @@ -445,19 +462,20 @@ def _get_cross_account_bucket( f"The value of the expected bucket owner parameter must be an AWS Account ID... [{expected_bucket_owner}]", ) - store = self.get_store(context.account_id, context.region) - if not (s3_bucket := store.buckets.get(bucket_name)): - if not (account_id := store.global_bucket_map.get(bucket_name)): + request_store = self.get_store(context.account_id, context.region) + if not (s3_bucket := request_store.buckets.get(bucket_name)): + if not (bucket_account_id := request_store.global_bucket_map.get(bucket_name)): raise NoSuchBucket("The specified bucket does not exist", BucketName=bucket_name) - store = self.get_store(account_id, context.region) - if not (s3_bucket := store.buckets.get(bucket_name)): + bucket_account_store = self.get_store(bucket_account_id, context.region) + if not (s3_bucket := bucket_account_store.buckets.get(bucket_name)): raise NoSuchBucket("The specified bucket does not exist", BucketName=bucket_name) if expected_bucket_owner and s3_bucket.bucket_account_id != expected_bucket_owner: raise AccessDenied("Access Denied") - return store, s3_bucket + regional_bucket_store = self.get_store(s3_bucket.bucket_account_id, s3_bucket.bucket_region) + return regional_bucket_store, s3_bucket @staticmethod def get_store(account_id: str, region_name: str) -> S3Store: @@ -470,39 +488,35 @@ def create_bucket( context: RequestContext, request: CreateBucketRequest, ) -> CreateBucketOutput: + if context.region == "aws-global": + # TODO: extend this logic to probably all the provider, and maybe all services. S3 is the most impacted + # right now so this will help users to properly set a region in their config + # See the `TestS3.test_create_bucket_aws_global` test + raise AuthorizationHeaderMalformed( + f"The authorization header is malformed; the region 'aws-global' is wrong; expecting '{AWS_REGION_US_EAST_1}'", + HostId=S3_HOST_ID, + Region=AWS_REGION_US_EAST_1, + ) + bucket_name = request["Bucket"] if not is_bucket_name_valid(bucket_name): raise InvalidBucketName("The specified bucket is not valid.", BucketName=bucket_name) - # the XML parser returns an empty dict if the body contains the following: - # - # but it also returns an empty dict if the body is fully empty. We need to differentiate the 2 cases by checking - # if the body is empty or not - if context.request.data and ( - (create_bucket_configuration := request.get("CreateBucketConfiguration")) is not None - ): - if not (bucket_region := create_bucket_configuration.get("LocationConstraint")): - raise MalformedXML() - - if context.region == AWS_REGION_US_EAST_1: - if bucket_region == "us-east-1": - raise InvalidLocationConstraint( - "The specified location-constraint is not valid", - LocationConstraint=bucket_region, - ) - elif context.region != bucket_region: - raise CommonServiceException( - code="IllegalLocationConstraintException", - message=f"The {bucket_region} location constraint is incompatible for the region specific endpoint this request was sent to.", - ) - else: + create_bucket_configuration = request.get("CreateBucketConfiguration") or {} + + bucket_tags = create_bucket_configuration.get("Tags", []) + if bucket_tags: + validate_tag_set(bucket_tags, type_set="create-bucket") + + location_constraint = create_bucket_configuration.get("LocationConstraint", "") + validate_location_constraint(context.region, location_constraint) + + bucket_region = location_constraint + if not location_constraint: bucket_region = AWS_REGION_US_EAST_1 - if context.region != bucket_region: - raise CommonServiceException( - code="IllegalLocationConstraintException", - message="The unspecified location constraint is incompatible for the region specific endpoint this request was sent to.", - ) + if location_constraint == BucketLocationConstraint.EU: + bucket_region = AWS_REGION_EU_WEST_1 store = self.get_store(context.account_id, bucket_region) @@ -511,15 +525,20 @@ def create_bucket( if existing_bucket_owner != context.account_id: raise BucketAlreadyExists() - # if the existing bucket has the same owner, the behaviour will depend on the region - if bucket_region != "us-east-1": + # if the existing bucket has the same owner, the behaviour will depend on the region and if the request has + # tags + if bucket_region != AWS_REGION_US_EAST_1 or bucket_tags: raise BucketAlreadyOwnedByYou( "Your previous request to create the named bucket succeeded and you already own it.", BucketName=bucket_name, ) else: + existing_bucket = store.buckets[bucket_name] # CreateBucket is idempotent in us-east-1 - return CreateBucketOutput(Location=f"/{bucket_name}") + return CreateBucketOutput( + Location=f"/{bucket_name}", + BucketArn=existing_bucket.bucket_arn, + ) if ( object_ownership := request.get("ObjectOwnership") @@ -531,6 +550,7 @@ def create_bucket( # see https://docs.aws.amazon.com/AmazonS3/latest/API/API_Owner.html owner = get_owner_for_account_id(context.account_id) acl = get_access_control_policy_for_new_resource_request(request, owner=owner) + s3_bucket = S3Bucket( name=bucket_name, account_id=context.account_id, @@ -538,11 +558,16 @@ def create_bucket( owner=owner, acl=acl, object_ownership=request.get("ObjectOwnership"), - object_lock_enabled_for_bucket=request.get("ObjectLockEnabledForBucket"), + object_lock_enabled_for_bucket=request.get("ObjectLockEnabledForBucket") or False, + location_constraint=location_constraint, ) store.buckets[bucket_name] = s3_bucket store.global_bucket_map[bucket_name] = s3_bucket.bucket_account_id + if bucket_tags: + store.tags.update_tags( + s3_bucket.bucket_arn, {tag["Key"]: tag["Value"] for tag in bucket_tags} + ) self._cors_handler.invalidate_cache() self._storage_backend.create_bucket(bucket_name) @@ -552,7 +577,7 @@ def create_bucket( if bucket_region == "us-east-1" else get_full_default_bucket_location(bucket_name) ) - response = CreateBucketOutput(Location=location) + response = CreateBucketOutput(Location=location, BucketArn=s3_bucket.bucket_arn) return response def delete_bucket( @@ -578,8 +603,10 @@ def delete_bucket( store.global_bucket_map.pop(bucket) self._cors_handler.invalidate_cache() self._expiration_cache.pop(bucket, None) + self._preconditions_locks.pop(bucket, None) # clean up the storage backend self._storage_backend.delete_bucket(bucket) + store.tags.delete_all_tags(s3_bucket.bucket_arn) def list_buckets( self, @@ -590,6 +617,13 @@ def list_buckets( bucket_region: BucketRegion = None, **kwargs, ) -> ListBucketsOutput: + if bucket_region and not config.ALLOW_NONSTANDARD_REGIONS: + if bucket_region not in get_valid_regions_for_service(self.service): + raise InvalidArgument( + f"Argument value {bucket_region} is not a valid AWS Region", + ArgumentName="bucket-region", + ) + owner = get_owner_for_account_id(context.account_id) store = self.get_store(context.account_id, context.region) @@ -622,6 +656,7 @@ def list_buckets( Name=bucket.name, CreationDate=bucket.creation_date, BucketRegion=bucket.bucket_region, + BucketArn=bucket.bucket_arn, ) buckets.append(output_bucket) count += 1 @@ -637,6 +672,16 @@ def head_bucket( expected_bucket_owner: AccountId = None, **kwargs, ) -> HeadBucketOutput: + if context.region == "aws-global": + # TODO: extend this logic to probably all the provider, and maybe all services. S3 is the most impacted + # right now so this will help users to properly set a region in their config + # See the `TestS3.test_create_bucket_aws_global` test + raise AuthorizationHeaderMalformed( + f"The authorization header is malformed; the region 'aws-global' is wrong; expecting '{AWS_REGION_US_EAST_1}'", + HostId=S3_HOST_ID, + Region=AWS_REGION_US_EAST_1, + ) + store = self.get_store(context.account_id, context.region) if not (s3_bucket := store.buckets.get(bucket)): if not (account_id := store.global_bucket_map.get(bucket)): @@ -650,7 +695,9 @@ def head_bucket( # TODO: this call is also used to check if the user has access/authorization for the bucket # it can return 403 - return HeadBucketOutput(BucketRegion=s3_bucket.bucket_region) + return HeadBucketOutput( + BucketRegion=s3_bucket.bucket_region, BucketArn=s3_bucket.bucket_arn + ) def get_bucket_location( self, @@ -671,17 +718,10 @@ def get_bucket_location( """ store, s3_bucket = self._get_cross_account_bucket(context, bucket) - location_constraint = ( - '\n' - '{{location}}' + return GetBucketLocationOutput( + LocationConstraint=get_bucket_location_xml(s3_bucket.location_constraint) ) - location = s3_bucket.bucket_region if s3_bucket.bucket_region != "us-east-1" else "" - location_constraint = location_constraint.replace("{{location}}", location) - - response = GetBucketLocationOutput(LocationConstraint=location_constraint) - return response - @handler("PutObject", expand=False) def put_object( self, @@ -727,7 +767,15 @@ def put_object( if not system_metadata.get("ContentType"): system_metadata["ContentType"] = "binary/octet-stream" + user_metadata = decode_user_metadata(request.get("Metadata")) + version_id = generate_version_id(s3_bucket.versioning_status) + if version_id != "null": + # if we are in a versioned bucket, we need to lock around the full key (all the versions) + # because object versions have locks per version + precondition_lock = self._preconditions_locks[bucket_name][key] + else: + precondition_lock = contextlib.nullcontext() etag_content_md5 = "" if content_md5 := request.get("ContentMD5"): @@ -771,7 +819,7 @@ def put_object( version_id=version_id, storage_class=storage_class, expires=request.get("Expires"), - user_metadata=request.get("Metadata"), + user_metadata=user_metadata, system_metadata=system_metadata, checksum_algorithm=checksum_algorithm, checksum_value=checksum_value, @@ -810,7 +858,10 @@ def put_object( if encodings: s3_object.system_metadata["ContentEncoding"] = ",".join(encodings) - with self._storage_backend.open(bucket_name, s3_object, mode="w") as s3_stored_object: + with ( + precondition_lock, + self._storage_backend.open(bucket_name, s3_object, mode="w") as s3_stored_object, + ): # as we are inside the lock here, if multiple concurrent requests happen for the same object, it's the first # one to finish to succeed, and subsequent will raise exceptions. Once the first write finishes, we're # opening the lock and other requests can check this condition @@ -855,9 +906,9 @@ def put_object( # in case we are overriding an object, delete the tags entry key_id = get_unique_key_id(bucket_name, key, version_id) - store.TAGS.tags.pop(key_id, None) + store.tags.delete_all_tags(key_id) if tagging: - store.TAGS.tags[key_id] = tagging + store.tags.update_tags(key_id, tagging) # RequestCharged: Optional[RequestCharged] # TODO response = PutObjectOutput( @@ -868,14 +919,14 @@ def put_object( if s3_object.checksum_algorithm: response[f"Checksum{s3_object.checksum_algorithm}"] = s3_object.checksum_value - response["ChecksumType"] = getattr(s3_object, "checksum_type", ChecksumType.FULL_OBJECT) + response["ChecksumType"] = s3_object.checksum_type if s3_bucket.lifecycle_rules: if expiration_header := self._get_expiration_header( s3_bucket.lifecycle_rules, bucket_name, s3_object, - store.TAGS.tags.get(key_id, {}), + store.tags.get_tags(key_id), ): # TODO: we either apply the lifecycle to existing objects when we set the new rules, or we need to # apply them everytime we get/head an object @@ -921,15 +972,13 @@ def get_object( validate_kms_key_id(kms_key=s3_object.kms_key_id, bucket=s3_bucket) sse_c_key_md5 = request.get("SSECustomerKeyMD5") - # we're using getattr access because when restoring, the field might not exist - # TODO: cleanup at next major release - if sse_key_hash := getattr(s3_object, "sse_key_hash", None): - if sse_key_hash and not sse_c_key_md5: + if s3_object.sse_key_hash: + if s3_object.sse_key_hash and not sse_c_key_md5: raise InvalidRequest( "The object was stored using a form of Server Side Encryption. " "The correct parameters must be provided to retrieve the object." ) - elif sse_key_hash != sse_c_key_md5: + elif s3_object.sse_key_hash != sse_c_key_md5: raise AccessDenied( "Requests specifying Server Side Encryption with Customer provided keys must provide the correct secret key." ) @@ -973,7 +1022,7 @@ def get_object( **s3_object.get_system_metadata_fields(), ) if s3_object.user_metadata: - response["Metadata"] = s3_object.user_metadata + response["Metadata"] = encode_user_metadata(s3_object.user_metadata) if s3_object.parts and request.get("PartNumber"): response["PartsCount"] = len(s3_object.parts) @@ -992,7 +1041,7 @@ def get_object( if checksum_algorithm := s3_object.checksum_algorithm: if (request.get("ChecksumMode") or "").upper() == "ENABLED": checksum_value = s3_object.checksum_value - checksum_type = getattr(s3_object, "checksum_type", ChecksumType.FULL_OBJECT) + checksum_type = s3_object.checksum_type if range_data: s3_stored_object.seek(range_data.begin) @@ -1004,7 +1053,7 @@ def get_object( response["StatusCode"] = 206 if checksum_value: if s3_object.parts and part_number and checksum_type == ChecksumType.COMPOSITE: - part_data = s3_object.parts[part_number] + part_data = s3_object.parts[str(part_number)] checksum_key = f"Checksum{checksum_algorithm.upper()}" response[checksum_key] = part_data.get(checksum_key) response["ChecksumType"] = ChecksumType.COMPOSITE @@ -1022,11 +1071,10 @@ def get_object( add_encryption_to_response(response, s3_object=s3_object) - if object_tags := store.TAGS.tags.get( - get_unique_key_id(bucket_name, object_key, version_id) - ): - response["TagCount"] = len(object_tags) + object_tags = store.tags.get_tags(get_unique_key_id(bucket_name, object_key, version_id)) + if tag_count := len(object_tags): + response["TagCount"] = tag_count if s3_object.is_current and s3_bucket.lifecycle_rules: if expiration_header := self._get_expiration_header( s3_bucket.lifecycle_rules, @@ -1055,6 +1103,17 @@ def get_object( for request_param, response_param in ALLOWED_HEADER_OVERRIDES.items(): if request_param_value := request.get(request_param): + if isinstance(request_param_value, str): + try: + request_param_value.encode("latin-1") + except UnicodeEncodeError: + raise InvalidArgument( + "Header value cannot be represented using ISO-8859-1.", + ArgumentName=header_name_from_capitalized_param(request_param), + ArgumentValue=request_param_value, + HostId=S3_HOST_ID, + ) + response[response_param] = request_param_value return response @@ -1101,14 +1160,14 @@ def head_object( **s3_object.get_system_metadata_fields(), ) if s3_object.user_metadata: - response["Metadata"] = s3_object.user_metadata + response["Metadata"] = encode_user_metadata(s3_object.user_metadata) checksum_value = None checksum_type = None if checksum_algorithm := s3_object.checksum_algorithm: if (request.get("ChecksumMode") or "").upper() == "ENABLED": checksum_value = s3_object.checksum_value - checksum_type = getattr(s3_object, "checksum_type", ChecksumType.FULL_OBJECT) + checksum_type = s3_object.checksum_type if s3_object.parts and request.get("PartNumber"): response["PartsCount"] = len(s3_object.parts) @@ -1138,7 +1197,7 @@ def head_object( response["StatusCode"] = 206 if checksum_value: if s3_object.parts and part_number and checksum_type == ChecksumType.COMPOSITE: - part_data = s3_object.parts[part_number] + part_data = s3_object.parts[str(part_number)] checksum_key = f"Checksum{checksum_algorithm.upper()}" response[checksum_key] = part_data.get(checksum_key) response["ChecksumType"] = ChecksumType.COMPOSITE @@ -1153,12 +1212,14 @@ def head_object( response["ChecksumType"] = checksum_type add_encryption_to_response(response, s3_object=s3_object) + object_tags = store.tags.get_tags( + get_unique_key_id(bucket_name, object_key, s3_object.version_id) + ) + if tag_count := len(object_tags): + response["TagCount"] = tag_count # if you specify the VersionId, AWS won't return the Expiration header, even if that's the current version if not version_id and s3_bucket.lifecycle_rules: - object_tags = store.TAGS.tags.get( - get_unique_key_id(bucket_name, object_key, s3_object.version_id) - ) if expiration_header := self._get_expiration_header( s3_bucket.lifecycle_rules, bucket_name, @@ -1241,7 +1302,7 @@ def delete_object( if found_object: self._storage_backend.remove(bucket, found_object) self._notify(context, s3_bucket=s3_bucket, s3_object=found_object) - store.TAGS.tags.pop(get_unique_key_id(bucket, key, version_id), None) + store.tags.delete_all_tags(get_unique_key_id(bucket, key, version_id)) return DeleteObjectOutput() @@ -1249,7 +1310,7 @@ def delete_object( delete_marker_id = generate_version_id(s3_bucket.versioning_status) delete_marker = S3DeleteMarker(key=key, version_id=delete_marker_id) s3_bucket.objects.set(key, delete_marker) - s3_notif_ctx = S3EventNotificationContext.from_request_context_native( + s3_notif_ctx = S3EventNotificationContext.from_request_context( context, s3_bucket=s3_bucket, s3_object=delete_marker, @@ -1279,9 +1340,13 @@ def delete_object( response["DeleteMarker"] = True else: self._storage_backend.remove(bucket, s3_object) - store.TAGS.tags.pop(get_unique_key_id(bucket, key, version_id), None) + store.tags.delete_all_tags(get_unique_key_id(bucket, key, version_id)) self._notify(context, s3_bucket=s3_bucket, s3_object=s3_object) + if key not in s3_bucket.objects: + # we clean up keys that do not have any object versions in them anymore + self._preconditions_locks[bucket].pop(key, None) + return response def delete_objects( @@ -1315,6 +1380,7 @@ def delete_objects( errors = [] to_remove = [] + versioned_keys = set() for to_delete_object in objects: object_key = to_delete_object.get("Key") version_id = to_delete_object.get("VersionId") @@ -1334,7 +1400,7 @@ def delete_objects( if found_object: to_remove.append(found_object) self._notify(context, s3_bucket=s3_bucket, s3_object=found_object) - store.TAGS.tags.pop(get_unique_key_id(bucket, object_key, version_id), None) + store.tags.delete_all_tags(get_unique_key_id(bucket, object_key, version_id)) # small hack to not create a fake object for nothing elif s3_bucket.notification_configuration: # DeleteObjects is a bit weird, even if the object didn't exist, S3 will trigger a notification @@ -1352,7 +1418,7 @@ def delete_objects( delete_marker_id = generate_version_id(s3_bucket.versioning_status) delete_marker = S3DeleteMarker(key=object_key, version_id=delete_marker_id) s3_bucket.objects.set(object_key, delete_marker) - s3_notif_ctx = S3EventNotificationContext.from_request_context_native( + s3_notif_ctx = S3EventNotificationContext.from_request_context( context, s3_bucket=s3_bucket, s3_object=delete_marker, @@ -1395,6 +1461,8 @@ def delete_objects( continue s3_bucket.objects.pop(object_key=object_key, version_id=version_id) + versioned_keys.add(object_key) + if not quiet: deleted_object = DeletedObject( Key=object_key, @@ -1410,7 +1478,12 @@ def delete_objects( to_remove.append(found_object) self._notify(context, s3_bucket=s3_bucket, s3_object=found_object) - store.TAGS.tags.pop(get_unique_key_id(bucket, object_key, version_id), None) + store.tags.delete_all_tags(get_unique_key_id(bucket, object_key, version_id)) + + for versioned_key in versioned_keys: + # we clean up keys that do not have any object versions in them anymore + if versioned_key not in s3_bucket.objects: + self._preconditions_locks[bucket].pop(versioned_key, None) # TODO: request charged self._storage_backend.remove(bucket, to_remove) @@ -1432,6 +1505,25 @@ def copy_object( # request_payer: RequestPayer = None, # TODO: dest_bucket = request["Bucket"] dest_key = request["Key"] + + if_match = request.get("IfMatch") + if_none_match = request.get("IfNoneMatch") + + if if_none_match and if_match: + raise NotImplementedException( + "A header you provided implies functionality that is not implemented", + Header="If-Match,If-None-Match", + additionalMessage="Multiple conditional request headers present in the request", + ) + + elif (if_none_match and if_none_match != "*") or (if_match and if_match == "*"): + header_name = "If-None-Match" if if_none_match else "If-Match" + raise NotImplementedException( + "A header you provided implies functionality that is not implemented", + Header=header_name, + additionalMessage=f"We don't accept the provided value of {header_name} header for this API", + ) + validate_object_key(dest_key) store, dest_s3_bucket = self._get_cross_account_bucket(context, dest_bucket) @@ -1525,7 +1617,7 @@ def copy_object( tagging = parse_tagging_header(tagging) if metadata_directive == "REPLACE": - user_metadata = request.get("Metadata") + user_metadata = decode_user_metadata(request.get("Metadata")) system_metadata = get_system_metadata_from_request(request) if not system_metadata.get("ContentType"): system_metadata["ContentType"] = "binary/octet-stream" @@ -1534,6 +1626,12 @@ def copy_object( system_metadata = src_s3_object.system_metadata dest_version_id = generate_version_id(dest_s3_bucket.versioning_status) + if dest_version_id != "null": + # if we are in a versioned bucket, we need to lock around the full key (all the versions) + # because object versions have locks per version + precondition_lock = self._preconditions_locks[dest_bucket][dest_key] + else: + precondition_lock = contextlib.nullcontext() encryption_parameters = get_encryption_parameters_from_request_and_bucket( request, @@ -1573,12 +1671,25 @@ def copy_object( owner=dest_s3_bucket.owner, ) - with self._storage_backend.copy( - src_bucket=src_bucket, - src_object=src_s3_object, - dest_bucket=dest_bucket, - dest_object=s3_object, - ) as s3_stored_object: + with ( + precondition_lock, + self._storage_backend.copy( + src_bucket=src_bucket, + src_object=src_s3_object, + dest_bucket=dest_bucket, + dest_object=s3_object, + ) as s3_stored_object, + ): + # Check destination write preconditions inside the lock to prevent race conditions. + if if_none_match and object_exists_for_precondition_write(dest_s3_bucket, dest_key): + raise PreconditionFailed( + "At least one of the pre-conditions you specified did not hold", + Condition="If-None-Match", + ) + + elif if_match: + verify_object_equality_precondition_write(dest_s3_bucket, dest_key, if_match) + s3_object.checksum_value = s3_stored_object.checksum or src_s3_object.checksum_value s3_object.etag = s3_stored_object.etag or src_s3_object.etag @@ -1587,11 +1698,13 @@ def copy_object( dest_key_id = get_unique_key_id(dest_bucket, dest_key, dest_version_id) if (request.get("TaggingDirective")) == "REPLACE": - store.TAGS.tags[dest_key_id] = tagging or {} + store.tags.delete_all_tags(dest_key_id) + store.tags.update_tags(dest_key_id, tagging or {}) else: src_key_id = get_unique_key_id(src_bucket, src_key, src_s3_object.version_id) - src_tags = store.TAGS.tags.get(src_key_id, {}) - store.TAGS.tags[dest_key_id] = copy.copy(src_tags) + src_tags = store.tags.get_tags(src_key_id) + store.tags.delete_all_tags(dest_key_id) + store.tags.update_tags(dest_key_id, src_tags) copy_object_result = CopyObjectResult( ETag=s3_object.quoted_etag, @@ -1601,6 +1714,7 @@ def copy_object( copy_object_result[f"Checksum{s3_object.checksum_algorithm.upper()}"] = ( s3_object.checksum_value ) + copy_object_result["ChecksumType"] = s3_object.checksum_type response = CopyObjectOutput( CopyObjectResult=copy_object_result, @@ -1644,6 +1758,7 @@ def list_objects( **kwargs, ) -> ListObjectsOutput: store, s3_bucket = self._get_cross_account_bucket(context, bucket) + validate_encoding_type(encoding_type) common_prefixes = set() count = 0 @@ -1652,7 +1767,7 @@ def list_objects( max_keys = max_keys or 1000 prefix = prefix or "" delimiter = delimiter or "" - if encoding_type: + if encoding_type == EncodingType.url: prefix = urlparse.quote(prefix) delimiter = urlparse.quote(delimiter) @@ -1699,9 +1814,7 @@ def list_objects( if s3_object.checksum_algorithm: object_data["ChecksumAlgorithm"] = [s3_object.checksum_algorithm] - object_data["ChecksumType"] = getattr( - s3_object, "checksum_type", ChecksumType.FULL_OBJECT - ) + object_data["ChecksumType"] = s3_object.checksum_type s3_objects.append(object_data) @@ -1763,6 +1876,7 @@ def list_objects_v2( "The continuation token provided is incorrect", ArgumentName="continuation-token", ) + validate_encoding_type(encoding_type) common_prefixes = set() count = 0 @@ -1771,14 +1885,14 @@ def list_objects_v2( max_keys = max_keys or 1000 prefix = prefix or "" delimiter = delimiter or "" - if encoding_type: + start_after = start_after or "" + decoded_continuation_token = decode_continuation_token(continuation_token) + + if encoding_type == EncodingType.url: prefix = urlparse.quote(prefix) delimiter = urlparse.quote(delimiter) - decoded_continuation_token = ( - to_str(base64.urlsafe_b64decode(continuation_token.encode())) - if continuation_token - else None - ) + start_after = urlparse.quote(start_after) + decoded_continuation_token = urlparse.quote(decoded_continuation_token) s3_objects: list[Object] = [] @@ -1814,7 +1928,7 @@ def list_objects_v2( # After skipping all entries, verify we're not over the MaxKeys before adding a new entry if count >= max_keys: is_truncated = True - next_continuation_token = to_str(base64.urlsafe_b64encode(s3_object.key.encode())) + next_continuation_token = encode_continuation_token(s3_object.key) break # if we found a new CommonPrefix, add it to the CommonPrefixes @@ -1836,9 +1950,7 @@ def list_objects_v2( if s3_object.checksum_algorithm: object_data["ChecksumAlgorithm"] = [s3_object.checksum_algorithm] - object_data["ChecksumType"] = getattr( - s3_object, "checksum_type", ChecksumType.FULL_OBJECT - ) + object_data["ChecksumType"] = s3_object.checksum_type s3_objects.append(object_data) @@ -1897,6 +2009,7 @@ def list_object_versions( ArgumentName="version-id-marker", ArgumentValue=version_id_marker, ) + validate_encoding_type(encoding_type) store, s3_bucket = self._get_cross_account_bucket(context, bucket) common_prefixes = set() @@ -1907,7 +2020,7 @@ def list_object_versions( max_keys = max_keys or 1000 prefix = prefix or "" delimiter = delimiter or "" - if encoding_type: + if encoding_type == EncodingType.url: prefix = urlparse.quote(prefix) delimiter = urlparse.quote(delimiter) version_key_marker_found = False @@ -1988,9 +2101,7 @@ def list_object_versions( if version.checksum_algorithm: object_version["ChecksumAlgorithm"] = [version.checksum_algorithm] - object_version["ChecksumType"] = getattr( - version, "checksum_type", ChecksumType.FULL_OBJECT - ) + object_version["ChecksumType"] = version.checksum_type object_versions.append(object_version) @@ -2067,7 +2178,7 @@ def get_object_attributes( object_attrs = request.get("ObjectAttributes", []) response = GetObjectAttributesOutput() - object_checksum_type = getattr(s3_object, "checksum_type", ChecksumType.FULL_OBJECT) + object_checksum_type = s3_object.checksum_type if "ETag" in object_attrs: response["ETag"] = s3_object.etag if "StorageClass" in object_attrs: @@ -2103,18 +2214,11 @@ def get_object_attributes( max_parts = request.get("MaxParts") or 1000 parts = [] - all_parts = sorted(s3_object.parts.items()) + all_parts = sorted( + (int(part_number), part) for part_number, part in s3_object.parts.items() + ) last_part_number, last_part = all_parts[-1] - # TODO: remove this backward compatibility hack needed for state created with <= 4.5 - # the parts would only be a tuple and would not store the proper state for 4.5 and earlier, so we need - # to return early - if isinstance(last_part, tuple): - response["ObjectParts"] = GetObjectAttributesParts( - TotalPartsCount=len(s3_object.parts) - ) - return response - for part_number, part in all_parts: if part_number <= part_number_marker: continue @@ -2180,7 +2284,7 @@ def restore_object( # TODO: add a way to transition from ongoing-request=true to false? for now it is instant s3_object.restore = f'ongoing-request="false", expiry-date="{restore_expiration_date}"' - s3_notif_ctx_initiated = S3EventNotificationContext.from_request_context_native( + s3_notif_ctx_initiated = S3EventNotificationContext.from_request_context( context, s3_bucket=s3_bucket, s3_object=s3_object, @@ -2228,10 +2332,12 @@ def create_multipart_upload( if not system_metadata.get("ContentType"): system_metadata["ContentType"] = "binary/octet-stream" + user_metadata = decode_user_metadata(request.get("Metadata")) + checksum_algorithm = request.get("ChecksumAlgorithm") if checksum_algorithm and checksum_algorithm not in CHECKSUM_ALGORITHMS: raise InvalidRequest( - "Checksum algorithm provided is unsupported. Please try again with any of the valid types: [CRC32, CRC32C, SHA1, SHA256]" + "Checksum algorithm provided is unsupported. Please try again with any of the valid types: [CRC32, CRC32C, CRC64NVME, SHA1, SHA256]" ) if not (checksum_type := request.get("ChecksumType")) and checksum_algorithm: @@ -2276,12 +2382,16 @@ def create_multipart_upload( acl = get_access_control_policy_for_new_resource_request(request, owner=s3_bucket.owner) - # validate encryption values + initiator = get_owner_for_account_id(context.account_id) + # This is weird, but for all other operations, AWS does not return a DisplayName anymore except for the + # `initiator` field in Multipart related operation. We will probably remove this soon once AWS changes that + initiator["DisplayName"] = "webfile" + s3_multipart = S3Multipart( key=key, storage_class=storage_class, expires=request.get("Expires"), - user_metadata=request.get("Metadata"), + user_metadata=user_metadata, system_metadata=system_metadata, checksum_algorithm=checksum_algorithm, checksum_type=checksum_type, @@ -2295,7 +2405,7 @@ def create_multipart_upload( website_redirect_location=request.get("WebsiteRedirectLocation"), expiration=None, # TODO, from lifecycle, or should it be updated with config? acl=acl, - initiator=get_owner_for_account_id(context.account_id), + initiator=initiator, tagging=tagging, owner=s3_bucket.owner, precondition=object_exists_for_precondition_write(s3_bucket, key), @@ -2460,7 +2570,7 @@ def upload_part( CalculatedDigest=calculated_md5, ) - s3_multipart.parts[part_number] = s3_part + s3_multipart.parts[str(part_number)] = s3_part response = UploadPartOutput( ETag=s3_part.quoted_etag, @@ -2561,7 +2671,7 @@ def upload_part_copy( stored_multipart = self._storage_backend.get_multipart(dest_bucket, s3_multipart) stored_multipart.copy_from_object(s3_part, src_bucket, src_s3_object, range_data) - s3_multipart.parts[part_number] = s3_part + s3_multipart.parts[str(part_number)] = s3_part # TODO: return those fields # RequestCharged: Optional[RequestCharged] @@ -2627,6 +2737,7 @@ def complete_multipart_upload( ) elif if_none_match: + # TODO: improve concurrency mechanism for `if_none_match` and `if_match` if if_none_match != "*": raise NotImplementedException( "A header you provided implies functionality that is not implemented", @@ -2671,7 +2782,7 @@ def complete_multipart_upload( ) mpu_checksum_algorithm = s3_multipart.checksum_algorithm - mpu_checksum_type = getattr(s3_multipart, "checksum_type", None) + mpu_checksum_type = s3_multipart.checksum_type if checksum_type and checksum_type != mpu_checksum_type: raise InvalidRequest( @@ -2722,7 +2833,7 @@ def complete_multipart_upload( stored_multipart = self._storage_backend.get_multipart(bucket, s3_multipart) stored_multipart.complete_multipart( - [s3_multipart.parts.get(part_number) for part_number in parts_numbers] + [s3_multipart.parts.get(str(part_number)) for part_number in parts_numbers] ) if not s3_multipart.checksum_algorithm and s3_multipart.object.checksum_algorithm: with self._storage_backend.open( @@ -2740,9 +2851,9 @@ def complete_multipart_upload( s3_bucket.multiparts.pop(s3_multipart.id, None) key_id = get_unique_key_id(bucket, key, version_id) - store.TAGS.tags.pop(key_id, None) + store.tags.delete_all_tags(key_id) if s3_multipart.tagging: - store.TAGS.tags[key_id] = s3_multipart.tagging + store.tags.update_tags(key_id, s3_multipart.tagging) # RequestCharged: Optional[RequestCharged] TODO @@ -2750,7 +2861,7 @@ def complete_multipart_upload( Bucket=bucket, Key=key, ETag=s3_object.quoted_etag, - Location=f"{get_full_default_bucket_location(bucket)}{key}", + Location=get_url_encoded_object_location(bucket, key), ) if s3_object.version_id: @@ -2833,7 +2944,9 @@ def list_parts( max_parts = max_parts or 1000 parts = [] - all_parts = sorted(s3_multipart.parts.items()) + all_parts = sorted( + (int(part_number), part) for part_number, part in s3_multipart.parts.items() + ) last_part_number = all_parts[-1][0] if all_parts else None for part_number, part in all_parts: if part_number <= part_number_marker: @@ -2859,7 +2972,7 @@ def list_parts( Key=key, UploadId=upload_id, Initiator=s3_multipart.initiator, - Owner=s3_multipart.initiator, + Owner=s3_multipart.object.owner, StorageClass=s3_multipart.object.storage_class, IsTruncated=is_truncated, MaxParts=max_parts, @@ -2875,7 +2988,7 @@ def list_parts( response["PartNumberMarker"] = part_number_marker if s3_multipart.checksum_algorithm: response["ChecksumAlgorithm"] = s3_multipart.object.checksum_algorithm - response["ChecksumType"] = getattr(s3_multipart, "checksum_type", None) + response["ChecksumType"] = s3_multipart.checksum_type # AbortDate: Optional[AbortDate] TODO: lifecycle # AbortRuleId: Optional[AbortRuleId] TODO: lifecycle @@ -2898,6 +3011,7 @@ def list_multipart_uploads( **kwargs, ) -> ListMultipartUploadsOutput: store, s3_bucket = self._get_cross_account_bucket(context, bucket) + validate_encoding_type(encoding_type) common_prefixes = set() count = 0 @@ -2905,7 +3019,7 @@ def list_multipart_uploads( max_uploads = max_uploads or 1000 prefix = prefix or "" delimiter = delimiter or "" - if encoding_type: + if encoding_type == EncodingType.url: prefix = urlparse.quote(prefix) delimiter = urlparse.quote(delimiter) upload_id_marker_found = False @@ -2974,12 +3088,12 @@ def list_multipart_uploads( Key=multipart.object.key, Initiated=multipart.initiated, StorageClass=multipart.object.storage_class, - Owner=multipart.initiator, # TODO: check the difference + Owner=multipart.object.owner, Initiator=multipart.initiator, ) if multipart.checksum_algorithm: multipart_upload["ChecksumAlgorithm"] = multipart.checksum_algorithm - multipart_upload["ChecksumType"] = getattr(multipart, "checksum_type", None) + multipart_upload["ChecksumType"] = multipart.checksum_type uploads.append(multipart_upload) @@ -3175,8 +3289,8 @@ def put_bucket_tagging( validate_tag_set(tag_set, type_set="bucket") # remove the previous tags before setting the new ones, it overwrites the whole TagSet - store.TAGS.tags.pop(s3_bucket.bucket_arn, None) - store.TAGS.tag_resource(s3_bucket.bucket_arn, tags=tag_set) + store.tags.delete_all_tags(s3_bucket.bucket_arn) + store.tags.update_tags(s3_bucket.bucket_arn, {tag["Key"]: tag["Value"] for tag in tag_set}) def get_bucket_tagging( self, @@ -3186,7 +3300,8 @@ def get_bucket_tagging( **kwargs, ) -> GetBucketTaggingOutput: store, s3_bucket = self._get_cross_account_bucket(context, bucket) - tag_set = store.TAGS.list_tags_for_resource(s3_bucket.bucket_arn, root_name="Tags")["Tags"] + tags = store.tags.get_tags(s3_bucket.bucket_arn) + tag_set = [{"Key": key, "Value": value} for key, value in dict(tags).items()] if not tag_set: raise NoSuchTagSet( "The TagSet does not exist", @@ -3204,7 +3319,10 @@ def delete_bucket_tagging( ) -> None: store, s3_bucket = self._get_cross_account_bucket(context, bucket) - store.TAGS.tags.pop(s3_bucket.bucket_arn, None) + # This operation doesn't remove the tags from the store like deleting a resource does + # it just sets them as empty. + store.tags.delete_all_tags(s3_bucket.bucket_arn) + store.tags.update_tags(s3_bucket.bucket_arn, {}) def put_object_tagging( self, @@ -3231,8 +3349,8 @@ def put_object_tagging( key_id = get_unique_key_id(bucket, key, s3_object.version_id) # remove the previous tags before setting the new ones, it overwrites the whole TagSet - store.TAGS.tags.pop(key_id, None) - store.TAGS.tag_resource(key_id, tags=tag_set) + store.tags.delete_all_tags(key_id) + store.tags.update_tags(key_id, {tag["Key"]: tag["Value"] for tag in tag_set}) response = PutObjectTaggingOutput() if s3_object.version_id: response["VersionId"] = s3_object.version_id @@ -3252,7 +3370,6 @@ def get_object_tagging( **kwargs, ) -> GetObjectTaggingOutput: store, s3_bucket = self._get_cross_account_bucket(context, bucket) - try: s3_object = s3_bucket.get_object(key=key, version_id=version_id) except NoSuchKey as e: @@ -3276,10 +3393,10 @@ def get_object_tagging( e.Key = f"{bucket}/{key}" raise e - tag_set = store.TAGS.list_tags_for_resource( - get_unique_key_id(bucket, key, s3_object.version_id) - )["Tags"] - response = GetObjectTaggingOutput(TagSet=tag_set) + object_tags = store.tags.get_tags(get_unique_key_id(bucket, key, s3_object.version_id)) + response = GetObjectTaggingOutput( + TagSet=[Tag(Key=key, Value=value) for key, value in object_tags.items()] + ) if s3_object.version_id: response["VersionId"] = s3_object.version_id @@ -3298,7 +3415,7 @@ def delete_object_tagging( s3_object = s3_bucket.get_object(key=key, version_id=version_id, http_method="DELETE") - store.TAGS.tags.pop(get_unique_key_id(bucket, key, s3_object.version_id), None) + store.tags.delete_all_tags(get_unique_key_id(bucket, key, s3_object.version_id)) response = DeleteObjectTaggingOutput() if s3_object.version_id: response["VersionId"] = s3_object.version_id @@ -3368,12 +3485,7 @@ def get_bucket_lifecycle_configuration( return GetBucketLifecycleConfigurationOutput( Rules=s3_bucket.lifecycle_rules, - # TODO: remove for next major version, safe access to new attribute - TransitionDefaultMinimumObjectSize=getattr( - s3_bucket, - "transition_default_minimum_object_size", - TransitionDefaultMinimumObjectSize.all_storage_classes_128K, - ), + TransitionDefaultMinimumObjectSize=s3_bucket.transition_default_minimum_object_size, ) def put_bucket_lifecycle_configuration( @@ -4414,7 +4526,8 @@ def post_object( system_metadata = {} for system_metadata_field in post_system_settable_headers: if field_value := form.get(system_metadata_field): - system_metadata[system_metadata_field.replace("-", "")] = field_value + system_key = system_metadata_field.replace("-", "") + system_metadata[system_key] = field_value if not system_metadata.get("ContentType"): system_metadata["ContentType"] = "binary/octet-stream" @@ -4491,9 +4604,9 @@ def post_object( # in case we are overriding an object, delete the tags entry key_id = get_unique_key_id(bucket, object_key, version_id) - store.TAGS.tags.pop(key_id, None) + store.tags.delete_all_tags(key_id) if tagging: - store.TAGS.tags[key_id] = tagging + store.tags.update_tags(key_id, tagging) response = PostResponse() # hacky way to set the etag in the headers as well: two locations for one value @@ -4520,7 +4633,8 @@ def post_object( response["StatusCode"] = 204 response["LocationHeader"] = response.get( - "LocationHeader", f"{get_full_default_bucket_location(bucket)}{object_key}" + "LocationHeader", + get_url_encoded_object_location(bucket, object_key), ) if s3_bucket.versioning_status == "Enabled": @@ -4535,7 +4649,7 @@ def post_object( s3_bucket.lifecycle_rules, bucket, s3_object, - store.TAGS.tags.get(key_id, {}), + store.tags.get_tags(key_id), ): # TODO: we either apply the lifecycle to existing objects when we set the new rules, or we need to # apply them everytime we get/head an object @@ -4805,7 +4919,7 @@ def get_part_range(s3_object: S3Object, part_number: PartNumber) -> ObjectRange: content_length=s3_object.size, content_range=f"bytes 0-{s3_object.size - 1}/{s3_object.size}", ) - elif not (part_data := s3_object.parts.get(part_number)): + elif not (part_data := s3_object.parts.get(str(part_number))): raise InvalidPartNumber( "The requested partnumber is not satisfiable", PartNumberRequested=part_number, diff --git a/localstack-core/localstack/services/s3/storage/core.py b/localstack-core/localstack/services/s3/storage/core.py index b6962275c3e33..7559c0090543c 100644 --- a/localstack-core/localstack/services/s3/storage/core.py +++ b/localstack-core/localstack/services/s3/storage/core.py @@ -3,7 +3,7 @@ from io import RawIOBase from typing import IO, Literal -from localstack.aws.api.s3 import BucketName, PartNumber +from localstack.aws.api.s3 import BucketName, PartNumber, Parts from localstack.services.s3.models import S3Multipart, S3Object, S3Part from localstack.services.s3.utils import ObjectRange @@ -158,7 +158,7 @@ def remove_part(self, s3_part: S3Part): pass @abc.abstractmethod - def complete_multipart(self, parts: list[PartNumber]) -> None: + def complete_multipart(self, parts: list[Parts]) -> None: pass @abc.abstractmethod diff --git a/localstack-core/localstack/services/s3/utils.py b/localstack-core/localstack/services/s3/utils.py index 54da792a0a753..7114afd748837 100644 --- a/localstack-core/localstack/services/s3/utils.py +++ b/localstack-core/localstack/services/s3/utils.py @@ -7,6 +7,7 @@ import re import time import zlib +from collections.abc import Mapping from enum import StrEnum from secrets import token_bytes from typing import Any, Literal, NamedTuple, Protocol @@ -33,6 +34,7 @@ Grantee, HeadObjectRequest, InvalidArgument, + InvalidLocationConstraint, InvalidRange, InvalidTag, LifecycleExpiration, @@ -56,19 +58,26 @@ from localstack.aws.api.s3 import Type as GranteeType from localstack.aws.chain import HandlerChain from localstack.aws.connect import connect_to +from localstack.constants import AWS_REGION_EU_WEST_1, AWS_REGION_US_EAST_1 from localstack.http import Response from localstack.services.s3 import checksums from localstack.services.s3.constants import ( ALL_USERS_ACL_GRANTEE, AUTHENTICATED_USERS_ACL_GRANTEE, + BUCKET_LOCATION_CONSTRAINTS, CHECKSUM_ALGORITHMS, + EU_WEST_1_LOCATION_CONSTRAINTS, LOG_DELIVERY_ACL_GRANTEE, - S3_VIRTUAL_HOST_FORWARDED_HEADER, SIGNATURE_V2_PARAMS, SIGNATURE_V4_PARAMS, SYSTEM_METADATA_SETTABLE_HEADERS, ) -from localstack.services.s3.exceptions import InvalidRequest, MalformedXML +from localstack.services.s3.exceptions import ( + IllegalLocationConstraintException, + InvalidRequest, + MalformedXML, +) +from localstack.services.s3.headers import decode_header_rfc2047, encode_header_rfc2047 from localstack.utils.aws import arns from localstack.utils.aws.arns import parse_arn from localstack.utils.objects import singleton_factory @@ -137,7 +146,6 @@ def get_owner_for_account_id(account_id: str): :return: the Owner object containing the DisplayName and owner ID """ return Owner( - DisplayName="webfile", # only in certain regions, see above ID="75aa57f09aa0c8caeab4f8c24e99d10f8e7faeebf76c078efc7c6caea54ba06a", ) @@ -421,6 +429,7 @@ def get_failed_upload_part_copy_source_preconditions( if_none_match = request.get("CopySourceIfNoneMatch") if_unmodified_since = request.get("CopySourceIfUnmodifiedSince") if_modified_since = request.get("CopySourceIfModifiedSince") + last_modified = second_resolution_datetime(last_modified) if if_match: if if_match.strip('"') != etag.strip('"'): @@ -431,15 +440,15 @@ def get_failed_upload_part_copy_source_preconditions( if if_unmodified_since: return None - if if_unmodified_since and if_unmodified_since < last_modified: + if if_unmodified_since and second_resolution_datetime(if_unmodified_since) < last_modified: return "x-amz-copy-source-If-Unmodified-Since" if if_none_match and if_none_match.strip('"') == etag.strip('"'): return "x-amz-copy-source-If-None-Match" - if if_modified_since and last_modified < if_modified_since < datetime.datetime.now( - tz=_gmt_zone_info - ): + if if_modified_since and last_modified <= second_resolution_datetime( + if_modified_since + ) < datetime.datetime.now(tz=_gmt_zone_info): return "x-amz-copy-source-If-Modified-Since" @@ -453,6 +462,10 @@ def get_full_default_bucket_location(bucket_name: BucketName) -> str: return f"{config.get_protocol()}://{bucket_name}.s3.{host_definition.host_and_port()}/" +def get_url_encoded_object_location(bucket_name: BucketName, object_key: str) -> str: + return f"{get_full_default_bucket_location(bucket_name)}{urlparser.quote(object_key)}" + + def etag_to_base_64_content_md5(etag: ETag) -> str: """ Convert an ETag, representing a MD5 hexdigest (might be quoted), to its base64 encoded representation @@ -522,7 +535,7 @@ def is_valid_canonical_id(canonical_id: str) -> bool: return False -def uses_host_addressing(headers: dict[str, str]) -> str | None: +def uses_host_addressing(headers: Mapping[str, str]) -> str | None: """ Determines if the request is targeting S3 with virtual host addressing :param headers: the request headers @@ -551,13 +564,18 @@ def get_system_metadata_from_request(request: dict) -> Metadata: return metadata -def forwarded_from_virtual_host_addressed_request(headers: dict[str, str]) -> bool: - """ - Determines if the request was forwarded from a v-host addressing style into a path one - """ - # we can assume that the host header we are receiving here is actually the header we originally received - # from the client (because the edge service is forwarding the request in memory) - return S3_VIRTUAL_HOST_FORWARDED_HEADER in headers +def encode_user_metadata(metadata: Metadata) -> Metadata: + """Encode the user metadata in the RFC 2047 format if necessary so that it can be returned in HTTP headers""" + return {k: encode_header_rfc2047(v) for k, v in metadata.items()} + + +def decode_user_metadata(metadata: Metadata | None) -> Metadata: + """Decode the user metadata if provided in the RFC2047 format, or leave as is if not. AWS also lowercase the + metadata key""" + if not metadata: + return {} + + return {k.lower(): decode_header_rfc2047(v) for k, v in metadata.items()} def extract_bucket_name_and_key_from_headers_and_path( @@ -618,6 +636,10 @@ def capitalize_header_name_from_snake_case(header_name: str) -> str: return "-".join([part.capitalize() for part in header_name.split("-")]) +def header_name_from_capitalized_param(param_name: str) -> str: + return "-".join(re.findall("[A-Z][^A-Z]*", param_name)).lower() + + def get_kms_key_arn(kms_key: str, account_id: str, bucket_region: str) -> str | None: """ In S3, the KMS key can be passed as a KeyId or a KeyArn. This method allows to always get the KeyArn from either. @@ -710,6 +732,10 @@ def str_to_rfc_1123_datetime(value: str) -> datetime.datetime: return datetime.datetime.strptime(value, RFC1123).replace(tzinfo=_gmt_zone_info) +def second_resolution_datetime(src: datetime.datetime) -> datetime.datetime: + return src.replace(microsecond=0) + + def add_expiration_days_to_datetime(user_datatime: datetime.datetime, exp_days: int) -> str: """ This adds expiration days to a datetime, rounding to the next day at midnight UTC. @@ -845,13 +871,20 @@ def parse_tagging_header(tagging_header: TaggingHeader) -> dict: ) -def validate_tag_set(tag_set: TagSet, type_set: Literal["bucket", "object"] = "bucket"): +def validate_tag_set( + tag_set: TagSet, type_set: Literal["bucket", "object", "create-bucket"] = "bucket" +): keys = set() for tag in tag_set: if set(tag) != {"Key", "Value"}: raise MalformedXML() key = tag["Key"] + value = tag["Value"] + + if key is None or value is None: + raise MalformedXML() + if key in keys: raise InvalidTag( "Cannot provide multiple Tags with the same key", @@ -861,11 +894,15 @@ def validate_tag_set(tag_set: TagSet, type_set: Literal["bucket", "object"] = "b if key.startswith("aws:"): if type_set == "bucket": message = "System tags cannot be added/updated by requester" - else: + elif type_set == "object": message = "Your TagKey cannot be prefixed with aws:" + else: + message = 'User-defined tag keys can\'t start with "aws:". This prefix is reserved for system tags. Remove "aws:" from your tag keys and try again.' raise InvalidTag( message, - TagKey=key, + # weirdly, AWS does not return the `TagKey` field here, but it does if the TagKey does not match the + # regex in the next step + TagKey=key if type_set != "create-bucket" else None, ) if not TAG_REGEX.match(key): @@ -873,14 +910,35 @@ def validate_tag_set(tag_set: TagSet, type_set: Literal["bucket", "object"] = "b "The TagKey you have provided is invalid", TagKey=key, ) - elif not TAG_REGEX.match(tag["Value"]): + elif not TAG_REGEX.match(value): raise InvalidTag( - "The TagValue you have provided is invalid", TagKey=key, TagValue=tag["Value"] + "The TagValue you have provided is invalid", TagKey=key, TagValue=value ) keys.add(key) +def validate_location_constraint(context_region: str, location_constraint: str) -> None: + if location_constraint: + if context_region == AWS_REGION_US_EAST_1: + if ( + not config.ALLOW_NONSTANDARD_REGIONS + and location_constraint not in BUCKET_LOCATION_CONSTRAINTS + ): + raise InvalidLocationConstraint( + "The specified location-constraint is not valid", + LocationConstraint=location_constraint, + ) + elif context_region == AWS_REGION_EU_WEST_1: + if location_constraint not in EU_WEST_1_LOCATION_CONSTRAINTS: + raise IllegalLocationConstraintException(location_constraint) + elif context_region != location_constraint: + raise IllegalLocationConstraintException(location_constraint) + else: + if context_region != AWS_REGION_US_EAST_1: + raise IllegalLocationConstraintException("unspecified") + + def get_unique_key_id( bucket: BucketName, object_key: ObjectKey, version_id: ObjectVersionId ) -> str: @@ -917,6 +975,7 @@ def get_failed_precondition_copy_source( :param etag: source object ETag :return str: the failed precondition to raise """ + last_modified = second_resolution_datetime(last_modified) if (cs_if_match := request.get("CopySourceIfMatch")) and etag.strip('"') != cs_if_match.strip( '"' ): @@ -924,7 +983,7 @@ def get_failed_precondition_copy_source( elif ( cs_if_unmodified_since := request.get("CopySourceIfUnmodifiedSince") - ) and last_modified > cs_if_unmodified_since: + ) and last_modified > second_resolution_datetime(cs_if_unmodified_since): return "x-amz-copy-source-If-Unmodified-Since" elif (cs_if_none_match := request.get("CopySourceIfNoneMatch")) and etag.strip( @@ -934,7 +993,9 @@ def get_failed_precondition_copy_source( elif ( cs_if_modified_since := request.get("CopySourceIfModifiedSince") - ) and last_modified < cs_if_modified_since < datetime.datetime.now(tz=_gmt_zone_info): + ) and last_modified <= second_resolution_datetime(cs_if_modified_since) < datetime.datetime.now( + tz=_gmt_zone_info + ): return "x-amz-copy-source-If-Modified-Since" @@ -952,13 +1013,13 @@ def validate_failed_precondition( """ precondition_failed = None # last_modified needs to be rounded to a second so that strict equality can be enforced from a RFC1123 header - last_modified = last_modified.replace(microsecond=0) + last_modified = second_resolution_datetime(last_modified) if (if_match := request.get("IfMatch")) and etag != if_match.strip('"'): precondition_failed = "If-Match" elif ( if_unmodified_since := request.get("IfUnmodifiedSince") - ) and last_modified > if_unmodified_since: + ) and last_modified > second_resolution_datetime(if_unmodified_since): precondition_failed = "If-Unmodified-Since" if precondition_failed: @@ -969,7 +1030,9 @@ def validate_failed_precondition( if ((if_none_match := request.get("IfNoneMatch")) and etag == if_none_match.strip('"')) or ( (if_modified_since := request.get("IfModifiedSince")) - and last_modified <= if_modified_since < datetime.datetime.now(tz=_gmt_zone_info) + and last_modified + <= second_resolution_datetime(if_modified_since) + < datetime.datetime.now(tz=_gmt_zone_info) ): raise CommonServiceException( message="Not Modified", @@ -1093,3 +1156,39 @@ def is_version_older_than_other(version_id: str, other: str): See `generate_safe_version_id` """ return base64.b64decode(version_id, altchars=b"._") < base64.b64decode(other, altchars=b"._") + + +def get_bucket_location_xml(location_constraint: str) -> str: + """ + Returns the formatted XML for the GetBucketLocation operation. + + :param location_constraint: The location constraint to return in the XML. It can be an empty string when + it's not specified in the bucket configuration. + :return: The XML response. + """ + + return ( + '\n' + '" if not location_constraint else f">{location_constraint}") + ) + + +def encode_continuation_token(value: str) -> str: + """ + :param value: a string value to be encoded + :return: a base64 encoded S3 ContinuationMarker + """ + return base64.b64encode(value.encode(), altchars=b"._").decode("ascii") + + +def decode_continuation_token(value: str | None) -> str: + """ + Pendant to ``encode_continuation_token``, will decode the value back to its original form + :param value: a ContinuationMarker value + :return: a string from the base64 decoded value + """ + if value is None: + return "" + + return base64.b64decode(value, altchars=b"._").decode("ascii") diff --git a/localstack-core/localstack/services/s3/validation.py b/localstack-core/localstack/services/s3/validation.py index 509300fc447a5..ee012c899f3fc 100644 --- a/localstack-core/localstack/services/s3/validation.py +++ b/localstack-core/localstack/services/s3/validation.py @@ -15,6 +15,7 @@ BucketName, ChecksumAlgorithm, CORSConfiguration, + EncodingType, Grant, Grantee, Grants, @@ -467,13 +468,11 @@ def validate_sse_c( raise InvalidArgument( "Requests specifying Server Side Encryption with Customer provided keys must provide a valid encryption algorithm.", ArgumentName="x-amz-server-side-encryption", - ArgumentValue="null", ) elif not encryption_key and algorithm: raise InvalidArgument( "Requests specifying Server Side Encryption with Customer provided keys must provide an appropriate secret key.", ArgumentName="x-amz-server-side-encryption", - ArgumentValue="null", ) if algorithm != "AES256": @@ -488,7 +487,6 @@ def validate_sse_c( raise InvalidArgument( "The secret key was invalid for the specified algorithm.", ArgumentName="x-amz-server-side-encryption", - ArgumentValue="null", ) sse_customer_key_md5 = base64.b64encode(hashlib.md5(sse_customer_key).digest()).decode("utf-8") @@ -497,7 +495,6 @@ def validate_sse_c( "The calculated MD5 hash of the key did not match the hash that was provided.", # weirdly, the argument name is wrong, it should be `x-amz-server-side-encryption-customer-key-MD5` ArgumentName="x-amz-server-side-encryption", - ArgumentValue="null", ) @@ -520,3 +517,12 @@ def validate_checksum_value(checksum_value: str, checksum_algorithm: ChecksumAlg valid_length = 0 return len(checksum) == valid_length + + +def validate_encoding_type(encoding_type: EncodingType): + if encoding_type is not None and not encoding_type == EncodingType.url: + raise InvalidArgument( + "Invalid Encoding Method specified in Request", + ArgumentName="encoding-type", + ArgumentValue=encoding_type, + ) diff --git a/localstack-core/localstack/services/s3control/exceptions.py b/localstack-core/localstack/services/s3control/exceptions.py new file mode 100644 index 0000000000000..98d7ae36e109d --- /dev/null +++ b/localstack-core/localstack/services/s3control/exceptions.py @@ -0,0 +1,6 @@ +from localstack.aws.api import CommonServiceException + + +class NoSuchResource(CommonServiceException): + def __init__(self, message=None): + super().__init__("NoSuchResource", status_code=404, message=message) diff --git a/localstack-core/localstack/services/s3control/provider.py b/localstack-core/localstack/services/s3control/provider.py index f4057b0adc0bc..3cca0f9477c02 100644 --- a/localstack-core/localstack/services/s3control/provider.py +++ b/localstack-core/localstack/services/s3control/provider.py @@ -1,5 +1,74 @@ -from localstack.aws.api.s3control import S3ControlApi +from localstack.aws.api import RequestContext +from localstack.aws.api.s3control import ( + AccountId, + ListTagsForResourceResult, + S3ControlApi, + S3ResourceArn, + Tag, + TagKeyList, + TagList, + TagResourceResult, + UntagResourceResult, +) +from localstack.services.s3.models import S3Store, s3_stores +from localstack.services.s3control.validation import validate_arn_for_tagging, validate_tags +from localstack.state import StateVisitor class S3ControlProvider(S3ControlApi): - pass + def accept_state_visitor(self, visitor: StateVisitor): + from moto.s3control.models import s3control_backends + + visitor.visit(s3control_backends) + + """ + S3Control is a management interface for S3, and can access some of its internals with no public API + This requires us to access the s3 stores directly + """ + + @staticmethod + def get_s3_store(account_id: str, region: str) -> S3Store: + return s3_stores[account_id][region] + + def tag_resource( + self, + context: RequestContext, + account_id: AccountId, + resource_arn: S3ResourceArn, + tags: TagList, + **kwargs, + ) -> TagResourceResult: + # Currently S3Control only supports tagging buckets + validate_arn_for_tagging(resource_arn, context.partition, account_id, context.region) + validate_tags(tags) + + store = self.get_s3_store(account_id, context.region) + store.tags.update_tags(resource_arn, {tag["Key"]: tag["Value"] for tag in tags}) + return TagResourceResult() + + def untag_resource( + self, + context: RequestContext, + account_id: AccountId, + resource_arn: S3ResourceArn, + tag_keys: TagKeyList, + **kwargs, + ) -> UntagResourceResult: + # Currently S3Control only supports tagging buckets + validate_arn_for_tagging(resource_arn, context.partition, account_id, context.region) + + store = self.get_s3_store(account_id, context.region) + store.tags.delete_tags(resource_arn, tag_keys) + return TagResourceResult() + + def list_tags_for_resource( + self, context: RequestContext, account_id: AccountId, resource_arn: S3ResourceArn, **kwargs + ) -> ListTagsForResourceResult: + # Currently S3Control only supports tagging buckets + validate_arn_for_tagging(resource_arn, context.partition, account_id, context.region) + + store = self.get_s3_store(account_id, context.region) + tags = store.tags.get_tags(resource_arn) + return ListTagsForResourceResult( + Tags=[Tag(Key=key, Value=value) for key, value in tags.items()] + ) diff --git a/localstack-core/localstack/services/s3control/validation.py b/localstack-core/localstack/services/s3control/validation.py new file mode 100644 index 0000000000000..9f99ffcc17718 --- /dev/null +++ b/localstack-core/localstack/services/s3control/validation.py @@ -0,0 +1,80 @@ +from localstack.aws.api.s3 import InvalidTag +from localstack.aws.api.s3control import Tag, TagList +from localstack.aws.forwarder import NotImplementedAvoidFallbackError +from localstack.services.s3.exceptions import MalformedXML +from localstack.services.s3.models import s3_stores +from localstack.services.s3.utils import TAG_REGEX +from localstack.services.s3control.exceptions import NoSuchResource + + +def validate_arn_for_tagging( + resource_arn: str, partition: str, account_id: str, region: str +) -> None: + """ + Validates the resource ARN for the resource being tagged. + + :param resource_arn: The ARN of the resource being tagged. + :param partition: The partition the request is originating from. + :param account_id: The account ID of the target resource. + :param region: The region the request is originating from. + :return: None + """ + + s3_prefix = f"arn:{partition}:s3:::" + if not resource_arn.startswith(s3_prefix): + # Moto does not support Tagging operations for S3 Control, so we should not forward those operations back + # to it + raise NotImplementedAvoidFallbackError( + "LocalStack only support Bucket tagging operations for S3Control" + ) + + store = s3_stores[account_id][region] + bucket_name = resource_arn.removeprefix(s3_prefix) + if bucket_name not in store.global_bucket_map: + raise NoSuchResource("The specified resource doesn't exist.") + + +def validate_tags(tags: TagList): + """ + Validate the tags provided. This is the same function as S3, but with different error messages + :param tags: a TagList object + :raises MalformedXML if the object does not conform to the schema + :raises InvalidTag if the tag key or value are outside the set of validations defined by S3 and S3Control + :return: None + """ + keys = set() + for tag in tags: + tag: Tag + if set(tag) != {"Key", "Value"}: + raise MalformedXML() + + key = tag["Key"] + value = tag["Value"] + + if key is None or value is None: + raise MalformedXML() + + if key in keys: + raise InvalidTag( + "There are duplicate tag keys in your request. Remove the duplicate tag keys and try again.", + TagKey=key, + ) + + if key.startswith("aws:"): + raise InvalidTag( + 'User-defined tag keys can\'t start with "aws:". This prefix is reserved for system tags. Remove "aws:" from your tag keys and try again.', + ) + + if not TAG_REGEX.match(key): + raise InvalidTag( + "This request contains a tag key or value that isn't valid. Valid characters include the following: [a-zA-Z+-=._:/]. Tag keys can contain up to 128 characters. Tag values can contain up to 256 characters.", + TagKey=key, + ) + elif not TAG_REGEX.match(value): + raise InvalidTag( + "This request contains a tag key or value that isn't valid. Valid characters include the following: [a-zA-Z+-=._:/]. Tag keys can contain up to 128 characters. Tag values can contain up to 256 characters.", + TagKey=key, + TagValue=value, + ) + + keys.add(key) diff --git a/localstack-core/localstack/services/scheduler/provider.py b/localstack-core/localstack/services/scheduler/provider.py index 63177c01fda30..3ba12874d8727 100644 --- a/localstack-core/localstack/services/scheduler/provider.py +++ b/localstack-core/localstack/services/scheduler/provider.py @@ -1,11 +1,12 @@ import logging import re -from moto.scheduler.models import EventBridgeSchedulerBackend +from moto.scheduler.models import EventBridgeSchedulerBackend, scheduler_backends from localstack.aws.api.scheduler import SchedulerApi, ValidationException from localstack.services.events.rule import RULE_SCHEDULE_CRON_REGEX, RULE_SCHEDULE_RATE_REGEX from localstack.services.plugins import ServiceLifecycleHook +from localstack.state import StateVisitor from localstack.utils.patch import patch LOG = logging.getLogger(__name__) @@ -17,7 +18,8 @@ class SchedulerProvider(SchedulerApi, ServiceLifecycleHook): - pass + def accept_state_visitor(self, visitor: StateVisitor): + visitor.visit(scheduler_backends) def _validate_schedule_expression(schedule_expression: str) -> None: diff --git a/localstack-core/localstack/services/secretsmanager/provider.py b/localstack-core/localstack/services/secretsmanager/provider.py index e57a0d6b3d8f6..e48dd53066a64 100644 --- a/localstack-core/localstack/services/secretsmanager/provider.py +++ b/localstack-core/localstack/services/secretsmanager/provider.py @@ -65,6 +65,7 @@ ) from localstack.aws.connect import connect_to from localstack.services.moto import call_moto +from localstack.state import StateVisitor from localstack.utils.aws import arns from localstack.utils.patch import patch from localstack.utils.time import today_no_time @@ -105,6 +106,9 @@ def __init__(self): super().__init__() apply_patches() + def accept_state_visitor(self, visitor: StateVisitor): + visitor.visit(secretsmanager_backends) + @staticmethod def get_moto_backend_for_resource( name_or_arn: str, context: RequestContext @@ -315,7 +319,8 @@ def put_secret_value( secret_binary = request.get("SecretBinary") if not secret_binary and not secret_string: raise InvalidRequestException("You must provide either SecretString or SecretBinary.") - + if secret_binary: + secret_binary = base64.b64encode(secret_binary) version_stages = request.get("VersionStages", ["AWSCURRENT"]) if not isinstance(version_stages, list): version_stages = [version_stages] @@ -398,6 +403,8 @@ def update_secret( secret_id = request["SecretId"] secret_string = request.get("SecretString") secret_binary = request.get("SecretBinary") + if secret_binary: + secret_binary = base64.b64encode(secret_binary) description = request.get("Description") kms_key_id = request.get("KmsKeyId") client_req_token = request.get("ClientRequestToken") @@ -610,6 +617,32 @@ def backend_update_secret( return json.dumps(resp) +@patch(SecretsManagerBackend.tag_resource) +def backend_tag_resource(fn, self, secret_id, tags): + if secret_id not in self.secrets: + raise SecretNotFoundException() + + if self.secrets[secret_id].is_deleted(): + raise InvalidRequestException( + "You can't perform this operation on the secret because it was marked for deletion." + ) + + return fn(self, secret_id, tags) + + +@patch(SecretsManagerBackend.untag_resource) +def backend_untag_resource(fn, self, secret_id, tag_keys): + if secret_id not in self.secrets: + raise SecretNotFoundException() + + if self.secrets[secret_id].is_deleted(): + raise InvalidRequestException( + "You can't perform this operation on the secret because it was marked for deletion." + ) + + return fn(self, secret_id, tag_keys) + + @patch(SecretsManagerResponse.update_secret, pass_target=False) def response_update_secret(self): secret_id = self._get_param("SecretId") diff --git a/localstack-core/localstack/services/ses/provider.py b/localstack-core/localstack/services/ses/provider.py index daa133ddec32a..4a15773b91e8f 100644 --- a/localstack-core/localstack/services/ses/provider.py +++ b/localstack-core/localstack/services/ses/provider.py @@ -8,7 +8,6 @@ from typing import TYPE_CHECKING, Any from botocore.exceptions import ClientError -from moto.core.parsers import XFormedDict from moto.ses import ses_backends from moto.ses.models import SESBackend @@ -60,9 +59,10 @@ from localstack.aws.connect import connect_to from localstack.constants import INTERNAL_AWS_SECRET_ACCESS_KEY from localstack.http import Resource, Response -from localstack.services.moto import call_moto, translate_service_exception +from localstack.services.moto import call_moto from localstack.services.plugins import ServiceLifecycleHook from localstack.services.ses.models import EmailType, SentEmail, SentEmailBody +from localstack.state import StateVisitor from localstack.utils.aws import arns from localstack.utils.files import mkdir from localstack.utils.strings import long_uid, to_str @@ -178,6 +178,9 @@ def register_ses_api_resource(): class SesProvider(SesApi, ServiceLifecycleHook): + def accept_state_visitor(self, visitor: StateVisitor): + visitor.visit(ses_backends) + # # Lifecycle Hooks # @@ -486,8 +489,7 @@ def send_raw_email( destinations = destinations or [] backend = get_ses_backend(context) - with translate_service_exception: - message = backend.send_raw_email(source, destinations, raw_data) + message = backend.send_raw_email(source, destinations, raw_data) if event_destinations := backend.config_set_event_destination.get(configuration_set_name): payload = EventDestinationPayload( @@ -559,7 +561,7 @@ def set_identity_headers_in_notifications_enabled( ) backend = get_ses_backend(context) - if identity not in backend.addresses: + if identity not in backend.email_identities: raise MessageRejected(f"Identity {identity} is not verified or does not exist.") # Store the setting in the backend @@ -689,7 +691,7 @@ def _client_for_topic(topic_arn: str) -> "SNSClient": def notify_event_destinations( context: RequestContext, # FIXME: Moto stores the Event Destinations as a single value when it should be a list - event_destinations: XFormedDict, + event_destinations: EventDestination | list[EventDestination], payload: EventDestinationPayload, email_type: EmailType, ): @@ -699,14 +701,14 @@ def notify_event_destinations( event_destinations = [event_destinations] for event_destination in event_destinations: - if not event_destination["enabled"]: + if not event_destination["Enabled"]: continue - sns_destination_arn = event_destination.get("sns_destination", {}).get("topic_arn") + sns_destination_arn = event_destination.get("SNSDestination", {}).get("TopicARN") if not sns_destination_arn: continue - matching_event_types = event_destination.get("matching_event_types") or [] + matching_event_types = event_destination.get("MatchingEventTypes") or [] if EventType.send in matching_event_types: emitter.emit_send_event( payload, sns_destination_arn, emit_source_arn=email_type != EmailType.TEMPLATED diff --git a/localstack-core/localstack/services/sns/constants.py b/localstack-core/localstack/services/sns/constants.py index 04b5f05293818..2ef391b1ebb0a 100644 --- a/localstack-core/localstack/services/sns/constants.py +++ b/localstack-core/localstack/services/sns/constants.py @@ -1,5 +1,8 @@ import re from string import ascii_letters, digits +from typing import get_args + +from localstack.services.sns.models import SnsApplicationPlatforms SNS_PROTOCOLS = [ "http", @@ -13,7 +16,7 @@ "firehose", ] -VALID_SUBSCRIPTION_ATTR_NAME = [ +VALID_SUBSCRIPTION_ATTR_NAME: list[str] = [ "DeliveryPolicy", "FilterPolicy", "FilterPolicyScope", @@ -22,9 +25,24 @@ "SubscriptionRoleArn", ] + +VALID_POLICY_ACTIONS = [ + "GetTopicAttributes", + "SetTopicAttributes", + "AddPermission", + "RemovePermission", + "DeleteTopic", + "Subscribe", + "ListSubscriptionsByTopic", + "Publish", + "Receive", +] + MSG_ATTR_NAME_REGEX = re.compile(r"^(?!\.)(?!.*\.$)(?!.*\.\.)[a-zA-Z0-9_\-.]+$") ATTR_TYPE_REGEX = re.compile(r"^(String|Number|Binary)\..+$") VALID_MSG_ATTR_NAME_CHARS = set(ascii_letters + digits + "." + "-" + "_") +E164_REGEX = re.compile(r"^\+?[1-9]\d{1,14}$") +BATCH_ENTRY_ID_REGEX = re.compile(r"^[a-zA-Z0-9_-]+$") GCM_URL = "https://fcm.googleapis.com/fcm/send" @@ -33,9 +51,14 @@ PLATFORM_ENDPOINT_MSGS_ENDPOINT = "/_aws/sns/platform-endpoint-messages" SMS_MSGS_ENDPOINT = "/_aws/sns/sms-messages" SUBSCRIPTION_TOKENS_ENDPOINT = "/_aws/sns/subscription-tokens" +SMS_PHONE_NUMBER_OPT_OUT_ENDPOINT = "/_aws/sns/phone-opt-outs" # we add hex chars to respect the format of AWS with certificate ID, hardcoded for now # we could parametrize the certificate ID in the future SNS_CERT_ENDPOINT = "/_aws/sns/SimpleNotificationService-6c6f63616c737461636b69736e696365.pem" DUMMY_SUBSCRIPTION_PRINCIPAL = "arn:{partition}:iam::{account_id}:user/DummySNSPrincipal" + +VALID_APPLICATION_PLATFORMS = list(get_args(SnsApplicationPlatforms)) + +MAXIMUM_MESSAGE_LENGTH = 262144 diff --git a/localstack-core/localstack/services/sns/models.py b/localstack-core/localstack/services/sns/models.py index bbbc923e74421..ebb7b7a0f9627 100644 --- a/localstack-core/localstack/services/sns/models.py +++ b/localstack-core/localstack/services/sns/models.py @@ -2,18 +2,36 @@ import time from dataclasses import dataclass, field from enum import StrEnum -from typing import Literal, TypedDict +from typing import Any, Literal, TypedDict from localstack.aws.api.sns import ( + Endpoint, MessageAttributeMap, + PhoneNumber, + PlatformApplication, PublishBatchRequestEntry, + TopicAttributesMap, subscriptionARN, topicARN, ) -from localstack.services.stores import AccountRegionBundle, BaseStore, LocalAttribute -from localstack.utils.aws.arns import parse_arn +from localstack.services.stores import ( + AccountRegionBundle, + BaseStore, + CrossRegionAttribute, + LocalAttribute, +) from localstack.utils.objects import singleton_factory from localstack.utils.strings import long_uid +from localstack.utils.tagging import Tags + + +class Topic(TypedDict, total=True): + arn: str + name: str + attributes: TopicAttributesMap + data_protection_policy: str | None + subscriptions: list[str] + SnsProtocols = Literal[ "http", "https", "email", "email-json", "sms", "sqs", "application", "lambda", "firehose" @@ -23,39 +41,47 @@ "APNS", "APNS_SANDBOX", "ADM", "FCM", "Baidu", "GCM", "MPNS", "WNS" ] + +class EndpointAttributeNames(StrEnum): + CUSTOM_USER_DATA = "CustomUserData" + Token = "Token" + ENABLED = "Enabled" + + +SMS_ATTRIBUTE_NAMES = [ + "DeliveryStatusIAMRole", + "DeliveryStatusSuccessSamplingRate", + "DefaultSenderID", + "DefaultSMSType", + "UsageReportS3Bucket", +] +SMS_TYPES = ["Promotional", "Transactional"] +SMS_DEFAULT_SENDER_REGEX = r"^(?=[A-Za-z0-9]{1,11}$)(?=.*[A-Za-z])[A-Za-z0-9]+$" SnsMessageProtocols = Literal[SnsProtocols, SnsApplicationPlatforms] -def create_default_sns_topic_policy(topic_arn: str) -> dict: +class SnsSubscription(TypedDict, total=False): """ - Creates the default SNS topic policy for the given topic ARN. - - :param topic_arn: The topic arn - :return: A policy document + In SNS, Subscription can be represented with only TopicArn, Endpoint, Protocol, SubscriptionArn and Owner, for + example in ListSubscriptions. However, when getting a subscription with GetSubscriptionAttributes, it will return + the Subscription object merged with its own attributes. + This represents this merged object, for internal use and in GetSubscriptionAttributes + https://docs.aws.amazon.com/cli/latest/reference/sns/get-subscription-attributes.html """ - return { - "Version": "2008-10-17", - "Id": "__default_policy_ID", - "Statement": [ - { - "Sid": "__default_statement_ID", - "Effect": "Allow", - "Principal": {"AWS": "*"}, - "Action": [ - "SNS:GetTopicAttributes", - "SNS:SetTopicAttributes", - "SNS:AddPermission", - "SNS:RemovePermission", - "SNS:DeleteTopic", - "SNS:Subscribe", - "SNS:ListSubscriptionsByTopic", - "SNS:Publish", - ], - "Resource": topic_arn, - "Condition": {"StringEquals": {"AWS:SourceOwner": parse_arn(topic_arn)["account"]}}, - } - ], - } + + TopicArn: topicARN + Endpoint: str + Protocol: SnsProtocols + SubscriptionArn: subscriptionARN + PendingConfirmation: Literal["true", "false"] + Owner: str | None + SubscriptionPrincipal: str | None + FilterPolicy: str | None + FilterPolicyScope: Literal["MessageAttributes", "MessageBody"] + RawMessageDelivery: Literal["true", "false"] + ConfirmationWasAuthenticated: Literal["true", "false"] + SubscriptionRoleArn: str | None + DeliveryPolicy: str | None @singleton_factory @@ -126,60 +152,52 @@ def from_batch_entry(cls, entry: PublishBatchRequestEntry, is_fifo=False) -> "Sn ) -class SnsSubscription(TypedDict, total=False): - """ - In SNS, Subscription can be represented with only TopicArn, Endpoint, Protocol, SubscriptionArn and Owner, for - example in ListSubscriptions. However, when getting a subscription with GetSubscriptionAttributes, it will return - the Subscription object merged with its own attributes. - This represents this merged object, for internal use and in GetSubscriptionAttributes - https://docs.aws.amazon.com/cli/latest/reference/sns/get-subscription-attributes.html - """ +@dataclass +class PlatformEndpoint: + platform_application_arn: str + platform_endpoint: Endpoint - TopicArn: topicARN - Endpoint: str - Protocol: SnsProtocols - SubscriptionArn: subscriptionARN - PendingConfirmation: Literal["true", "false"] - Owner: str | None - SubscriptionPrincipal: str | None - FilterPolicy: str | None - FilterPolicyScope: Literal["MessageAttributes", "MessageBody"] - RawMessageDelivery: Literal["true", "false"] - ConfirmationWasAuthenticated: Literal["true", "false"] - SubscriptionRoleArn: str | None - DeliveryPolicy: str | None + +@dataclass +class PlatformApplicationDetails: + platform_application: PlatformApplication + # maps all Endpoints of the PlatformApplication, from their Token to their ARN + platform_endpoints: dict[str, str] class SnsStore(BaseStore): - # maps topic ARN to subscriptions ARN - topic_subscriptions: dict[str, list[str]] = LocalAttribute(default=dict) + # maps topic ARN to Topic + topics: dict[str, Topic] = LocalAttribute(default=dict) # maps subscription ARN to SnsSubscription subscriptions: dict[str, SnsSubscription] = LocalAttribute(default=dict) + # filter policy are stored as JSON string in subscriptions, store the decoded result Dict + subscription_filter_policy: dict[subscriptionARN, dict[str, Any] | None] = LocalAttribute( + default=dict + ) + # maps confirmation token to subscription ARN subscription_tokens: dict[str, str] = LocalAttribute(default=dict) - # maps topic ARN to list of tags - sns_tags: dict[str, list[dict]] = LocalAttribute(default=dict) + # maps platform application arns to platform applications + platform_applications: dict[str, PlatformApplicationDetails] = LocalAttribute(default=dict) + + # maps endpoint arns to platform endpoints + platform_endpoints: dict[str, PlatformEndpoint] = LocalAttribute(default=dict) # cache of topic ARN to platform endpoint messages (used primarily for testing) - platform_endpoint_messages: dict[str, list[dict]] = LocalAttribute(default=dict) + platform_endpoint_messages: dict[str, list[dict[str, Any]]] = LocalAttribute(default=dict) + + # topic/subscription independent default values for sending sms messages + sms_attributes: dict[str, str] = LocalAttribute(default=dict) # list of sent SMS messages - sms_messages: list[dict] = LocalAttribute(default=list) + sms_messages: list[dict[str, Any]] = LocalAttribute(default=list) - # filter policy are stored as JSON string in subscriptions, store the decoded result Dict - subscription_filter_policy: dict[subscriptionARN, dict] = LocalAttribute(default=dict) - - def get_topic_subscriptions(self, topic_arn: str) -> list[SnsSubscription]: - topic_subscriptions = self.topic_subscriptions.get(topic_arn, []) - subscriptions = [ - subscription - for subscription_arn in topic_subscriptions - if (subscription := self.subscriptions.get(subscription_arn)) - ] - return subscriptions + tags: Tags = CrossRegionAttribute(default=Tags) + + PHONE_NUMBERS_OPTED_OUT: set[PhoneNumber] = CrossRegionAttribute(default=set) sns_stores = AccountRegionBundle("sns", SnsStore) diff --git a/localstack-core/localstack/services/sns/provider.py b/localstack-core/localstack/services/sns/provider.py index 71e1ffdda3c4f..fb906be0bb817 100644 --- a/localstack-core/localstack/services/sns/provider.py +++ b/localstack-core/localstack/services/sns/provider.py @@ -1,45 +1,60 @@ -import base64 import contextlib import copy import functools import json import logging -from uuid import uuid4 +import re from botocore.utils import InvalidArnException -from moto.core.utils import camelcase_to_pascal, underscores_to_camelcase -from moto.sns import sns_backends -from moto.sns.models import MAXIMUM_MESSAGE_LENGTH, SNSBackend, Topic -from moto.sns.utils import is_e164 +from rolo import Request, Router, route from localstack.aws.api import CommonServiceException, RequestContext from localstack.aws.api.sns import ( + ActionsList, AmazonResourceName, BatchEntryIdsNotDistinctException, + CheckIfPhoneNumberIsOptedOutResponse, ConfirmSubscriptionResponse, CreateEndpointResponse, CreatePlatformApplicationResponse, CreateTopicResponse, + DelegatesList, + Endpoint, EndpointDisabledException, + GetDataProtectionPolicyResponse, + GetEndpointAttributesResponse, + GetPlatformApplicationAttributesResponse, + GetSMSAttributesResponse, GetSubscriptionAttributesResponse, GetTopicAttributesResponse, + InvalidBatchEntryIdException, InvalidParameterException, InvalidParameterValueException, + ListEndpointsByPlatformApplicationResponse, + ListPhoneNumbersOptedOutResponse, + ListPlatformApplicationsResponse, + ListString, ListSubscriptionsByTopicResponse, ListSubscriptionsResponse, ListTagsForResourceResponse, + ListTopicsResponse, MapStringToString, MessageAttributeMap, NotFoundException, + OptInPhoneNumberResponse, + PhoneNumber, + PlatformApplication, PublishBatchRequestEntryList, PublishBatchResponse, PublishBatchResultEntry, PublishResponse, + SetSMSAttributesResponse, SnsApi, String, SubscribeResponse, Subscription, SubscriptionAttributesMap, + Tag, TagKeyList, TagList, TagResourceResponse, @@ -49,26 +64,55 @@ attributeName, attributeValue, authenticateOnUnsubscribe, - boolean, + endpoint, + label, + message, messageStructure, nextToken, + protocol, + string, + subject, subscriptionARN, topicARN, topicName, ) from localstack.constants import AWS_REGION_US_EAST_1, DEFAULT_AWS_ACCOUNT_ID -from localstack.http import Request, Response, Router, route +from localstack.http import Response from localstack.services.edge import ROUTER -from localstack.services.moto import call_moto from localstack.services.plugins import ServiceLifecycleHook -from localstack.services.sns import constants as sns_constants +from localstack.services.sns.analytics import internal_api_calls from localstack.services.sns.certificate import SNS_SERVER_CERT +from localstack.services.sns.constants import ( + ATTR_TYPE_REGEX, + BATCH_ENTRY_ID_REGEX, + DUMMY_SUBSCRIPTION_PRINCIPAL, + E164_REGEX, + MAXIMUM_MESSAGE_LENGTH, + MSG_ATTR_NAME_REGEX, + PLATFORM_ENDPOINT_MSGS_ENDPOINT, + SMS_MSGS_ENDPOINT, + SMS_PHONE_NUMBER_OPT_OUT_ENDPOINT, + SNS_CERT_ENDPOINT, + SNS_PROTOCOLS, + SUBSCRIPTION_TOKENS_ENDPOINT, + VALID_APPLICATION_PLATFORMS, + VALID_MSG_ATTR_NAME_CHARS, + VALID_POLICY_ACTIONS, + VALID_SUBSCRIPTION_ATTR_NAME, +) from localstack.services.sns.filter import FilterPolicyValidator from localstack.services.sns.models import ( + SMS_ATTRIBUTE_NAMES, + SMS_DEFAULT_SENDER_REGEX, + SMS_TYPES, + EndpointAttributeNames, + PlatformApplicationDetails, + PlatformEndpoint, SnsMessage, SnsMessageType, SnsStore, SnsSubscription, + Topic, sns_stores, ) from localstack.services.sns.publisher import ( @@ -76,48 +120,47 @@ SnsBatchPublishContext, SnsPublishContext, ) +from localstack.services.sns.utils import ( + create_default_topic_policy, + create_platform_endpoint_arn, + create_subscription_arn, + encode_subscription_token_with_region, + get_next_page_token_from_arn, + get_region_from_subscription_token, + get_topic_subscriptions, + is_valid_e164_number, + parse_and_validate_platform_application_arn, + parse_and_validate_topic_arn, + validate_subscription_attribute, +) +from localstack.state import StateVisitor from localstack.utils.aws.arns import ( - ArnData, extract_account_id_from_arn, extract_region_from_arn, get_partition, parse_arn, + sns_platform_application_arn, + sns_topic_arn, ) from localstack.utils.collections import PaginatedList, select_from_typed_dict -from localstack.utils.strings import short_uid, to_bytes, to_str - -from .analytics import internal_api_calls +from localstack.utils.strings import to_bytes # set up logger LOG = logging.getLogger(__name__) +SNS_TOPIC_NAME_PATTERN_FIFO = r"^[a-zA-Z0-9_-]{1,256}\.fifo$" +SNS_TOPIC_NAME_PATTERN = r"^[a-zA-Z0-9_-]{1,256}$" -class SnsProvider(SnsApi, ServiceLifecycleHook): - """ - Provider class for AWS Simple Notification Service. - - AWS supports following operations in a cross-account setup: - - GetTopicAttributes - - SetTopicAttributes - - AddPermission - - RemovePermission - - Publish - - Subscribe - - ListSubscriptionByTopic - - DeleteTopic - """ - - @route(sns_constants.SNS_CERT_ENDPOINT, methods=["GET"]) - def get_signature_cert_pem_file(self, request: Request): - # see http://sns-public-resources.s3.amazonaws.com/SNS_Message_Signing_Release_Note_Jan_25_2011.pdf - # see https://docs.aws.amazon.com/sns/latest/dg/sns-verify-signature-of-message.html - return Response(self._signature_cert_pem, 200) +class SnsProvider(SnsApi, ServiceLifecycleHook): def __init__(self) -> None: super().__init__() self._publisher = PublishDispatcher() self._signature_cert_pem: str = SNS_SERVER_CERT + def accept_state_visitor(self, visitor: StateVisitor): + visitor.visit(sns_stores) + def on_before_stop(self): self._publisher.shutdown() @@ -127,295 +170,321 @@ def on_after_init(self): # add the route to serve the certificate used to validate message signatures ROUTER.add(self.get_signature_cert_pem_file) - @staticmethod - def get_store(account_id: str, region_name: str) -> SnsStore: - return sns_stores[account_id][region_name] + @route(SNS_CERT_ENDPOINT, methods=["GET"]) + def get_signature_cert_pem_file(self, request: Request): + # see http://sns-public-resources.s3.amazonaws.com/SNS_Message_Signing_Release_Note_Jan_25_2011.pdf + # see https://docs.aws.amazon.com/sns/latest/dg/sns-verify-signature-of-message.html + return Response(self._signature_cert_pem, 200) - @staticmethod - def get_moto_backend(account_id: str, region_name: str) -> SNSBackend: - return sns_backends[account_id][region_name] + # Tag Utils - @staticmethod - def _get_topic(arn: str, context: RequestContext) -> Topic: + def _check_matching_tags( + self, context: RequestContext, topic_arn: str, tags: TagList | None + ) -> bool: """ - :param arn: the Topic ARN - :param context: the RequestContext of the request - :param multiregion: if the request can fetch the topic across regions or not (ex. Publish cannot publish to a - topic in a different region than the request) - :return: the Moto model Topic + Checks if a topic to be created doesn't already exist with different tags + :param context: The context of the original request + :param topic_arn: Arn of the topic + :param tags: Tags to be checked + :return: False if there is a mismatch in tags, True otherwise """ - arn_data = parse_and_validate_topic_arn(arn) - if context.region != arn_data["region"]: - raise InvalidParameterException("Invalid parameter: TopicArn") - - try: - return sns_backends[arn_data["account"]][context.region].topics[arn] - except KeyError: - raise NotFoundException("Topic does not exist") + store = self.get_store(context.account_id, context.region) + existing_tags = self._list_resource_tags(context, resource_arn=topic_arn) + # if this is none there is nothing to check + if topic_arn in store.topics: + if tags is None: + tags = [] + for tag in tags: + # this means topic already created with empty tags and when we try to create it + # again with other tag value then it should fail according to aws documentation. + if existing_tags is not None and tag not in existing_tags: + return False + return True + + def _list_resource_tags(self, context: RequestContext, resource_arn: str) -> TagList: + store = self.get_store(context.account_id, context.region) + tags = store.tags.get_tags(resource_arn) + return [Tag(Key=key, Value=value) for key, value in tags.items()] - def get_topic_attributes( - self, context: RequestContext, topic_arn: topicARN, **kwargs - ) -> GetTopicAttributesResponse: - # get the Topic from moto manually first, because Moto does not handle well the case where the ARN is malformed - # (raises ValueError: not enough values to unpack (expected 6, got 1)) - moto_topic_model = self._get_topic(topic_arn, context) - moto_response: GetTopicAttributesResponse = call_moto(context) - # TODO: fix some attributes by moto, see snapshot - # DeliveryPolicy - # EffectiveDeliveryPolicy - # Policy.Statement..Action -> SNS:Receive is added by moto but not returned in AWS - # TODO: very hacky way to get the attributes we need instead of a moto patch - # see the attributes we need: https://docs.aws.amazon.com/sns/latest/dg/sns-topic-attributes.html - # would need more work to have the proper format out of moto, maybe extract the model to our store - attributes = moto_response["Attributes"] - for attr in vars(moto_topic_model): - if "_feedback" in attr: - key = camelcase_to_pascal(underscores_to_camelcase(attr)) - attributes[key] = getattr(moto_topic_model, attr) - elif attr == "signature_version": - attributes["SignatureVersion"] = moto_topic_model.signature_version - elif attr == "archive_policy": - attributes["ArchivePolicy"] = moto_topic_model.archive_policy - - return moto_response + def _tag_resource(self, context: RequestContext, resource_arn: str, tags: TagList) -> None: + store = self.get_store(context.account_id, context.region) + store.tags.update_tags(resource_arn, {tag["Key"]: tag["Value"] for tag in tags}) - def set_topic_attributes( - self, - context: RequestContext, - topic_arn: topicARN, - attribute_name: attributeName, - attribute_value: attributeValue | None = None, - **kwargs, + def _untag_resource( + self, context: RequestContext, resource_arn: str, tag_keys: TagKeyList ) -> None: - # validate the topic first - self._get_topic(topic_arn, context) - call_moto(context) + store = self.get_store(context.account_id, context.region) + store.tags.delete_tags(resource_arn, tag_keys) - def publish_batch( + def _remove_resource_tags(self, context: RequestContext, resource_arn: str) -> None: + store = self.get_store(context.account_id, context.region) + store.tags.delete_all_tags(resource_arn) + + ## Topic Operations + + def create_topic( self, context: RequestContext, - topic_arn: topicARN, - publish_batch_request_entries: PublishBatchRequestEntryList, + name: topicName, + attributes: TopicAttributesMap | None = None, + tags: TagList | None = None, + data_protection_policy: attributeValue | None = None, **kwargs, - ) -> PublishBatchResponse: - if len(publish_batch_request_entries) > 10: - raise TooManyEntriesInBatchRequestException( - "The batch request contains more entries than permissible." - ) - - parsed_arn = parse_and_validate_topic_arn(topic_arn) - store = self.get_store(account_id=parsed_arn["account"], region_name=context.region) - moto_topic = self._get_topic(topic_arn, context) - - ids = [entry["Id"] for entry in publish_batch_request_entries] - if len(set(ids)) != len(publish_batch_request_entries): - raise BatchEntryIdsNotDistinctException( - "Two or more batch entries in the request have the same Id." - ) - - response: PublishBatchResponse = {"Successful": [], "Failed": []} + ) -> CreateTopicResponse: + store = self.get_store(context.account_id, context.region) + topic_arn = sns_topic_arn( + topic_name=name, region_name=context.region, account_id=context.account_id + ) + attributes = dict(attributes) if attributes else {} + if attributes.get("FifoTopic") and attributes["FifoTopic"].lower() == "true": + pattern = SNS_TOPIC_NAME_PATTERN_FIFO + else: + # AWS does not seem to save explicit settings of fifo = false + attributes.pop("FifoTopic", None) + pattern = SNS_TOPIC_NAME_PATTERN + + if not re.match(pattern, name): + raise InvalidParameterException("Invalid parameter: Topic Name") + + if existing_topic := store.topics.get(topic_arn): + existing_attrs = existing_topic["attributes"] + # TODO: validate attribute names + for k, v in attributes.items(): + # special case for FifoTopic + if k == "FifoTopic" and v == "false" and "FifoTopic" not in existing_attrs: + continue + + if not existing_attrs.get(k) or not existing_attrs.get(k) == v: + raise InvalidParameterException( + "Invalid parameter: Attributes Reason: Topic already exists with different attributes" + ) + tag_resource_success = self._check_matching_tags(context, topic_arn, tags) + if not tag_resource_success: + raise InvalidParameterException( + "Invalid parameter: Tags Reason: Topic already exists with different tags" + ) + return CreateTopicResponse(TopicArn=topic_arn) - # TODO: write AWS validated tests with FilterPolicy and batching - # TODO: find a scenario where we can fail to send a message synchronously to be able to report it - # right now, it seems that AWS fails the whole publish if something is wrong in the format of 1 message + attributes["EffectiveDeliveryPolicy"] = _create_default_effective_delivery_policy() - total_batch_size = 0 - message_contexts = [] - for entry_index, entry in enumerate(publish_batch_request_entries, start=1): - message_payload = entry.get("Message") - message_attributes = entry.get("MessageAttributes", {}) - if message_attributes: - # if a message contains non-valid message attributes - # will fail for the first non-valid message encountered, and raise ParameterValueInvalid - validate_message_attributes(message_attributes, position=entry_index) + topic = _create_topic( + name=name, + attributes=attributes, + data_protection_policy=data_protection_policy, + context=context, + ) + if tags: + self._tag_resource(context, resource_arn=topic_arn, tags=tags) - total_batch_size += get_total_publish_size(message_payload, message_attributes) + store.topics[topic_arn] = topic - # TODO: WRITE AWS VALIDATED - if entry.get("MessageStructure") == "json": - try: - message = json.loads(message_payload) - # Keys in the JSON object that correspond to supported transport protocols must have - # simple JSON string values. - # Non-string values will cause the key to be ignored. - message = { - key: field for key, field in message.items() if isinstance(field, str) - } - if "default" not in message: - raise InvalidParameterException( - "Invalid parameter: Message Structure - No default entry in JSON message body" - ) - entry["Message"] = message # noqa - except json.JSONDecodeError: - raise InvalidParameterException( - "Invalid parameter: Message Structure - JSON message body failed to parse" - ) + return CreateTopicResponse(TopicArn=topic_arn) - if is_fifo := (".fifo" in topic_arn): - if not all("MessageGroupId" in entry for entry in publish_batch_request_entries): - raise InvalidParameterException( - "Invalid parameter: The MessageGroupId parameter is required for FIFO topics" - ) - if moto_topic.content_based_deduplication == "false": - if not all( - "MessageDeduplicationId" in entry for entry in publish_batch_request_entries - ): - raise InvalidParameterException( - "Invalid parameter: The topic should either have ContentBasedDeduplication enabled or MessageDeduplicationId provided explicitly", - ) + def get_topic_attributes( + self, context: RequestContext, topic_arn: topicARN, **kwargs + ) -> GetTopicAttributesResponse: + topic: Topic = self._get_topic(arn=topic_arn, context=context) + if topic: + attributes = topic["attributes"] + return GetTopicAttributesResponse(Attributes=attributes) + else: + raise NotFoundException("Topic does not exist") - msg_ctx = SnsMessage.from_batch_entry(entry, is_fifo=is_fifo) - message_contexts.append(msg_ctx) - success = PublishBatchResultEntry( - Id=entry["Id"], - MessageId=msg_ctx.message_id, - ) - if is_fifo: - success["SequenceNumber"] = msg_ctx.sequencer_number - response["Successful"].append(success) + def delete_topic(self, context: RequestContext, topic_arn: topicARN, **kwargs) -> None: + # This also deletes all subscriptions for the topic. In AWS, this is not immediately the case; + # the subs still exist for a certain period of time (~48h), detached, after which they are garbage collected + arn_data = parse_and_validate_topic_arn(topic_arn) + if context.region != arn_data["region"]: + raise InvalidParameterException("Invalid parameter: TopicArn") - if total_batch_size > MAXIMUM_MESSAGE_LENGTH: - raise CommonServiceException( - code="BatchRequestTooLong", - message="The length of all the messages put together is more than the limit.", - sender_fault=True, - ) + store = self.get_store(context.account_id, context.region) + self._remove_resource_tags(context, topic_arn) + store.topics.pop(topic_arn, None) - publish_ctx = SnsBatchPublishContext( - messages=message_contexts, - store=store, - request_headers=context.request.headers, - topic_attributes=vars(moto_topic), + def list_topics( + self, context: RequestContext, next_token: nextToken | None = None, **kwargs + ) -> ListTopicsResponse: + store = self.get_store(context.account_id, context.region) + topics = [{"TopicArn": t["arn"]} for t in list(store.topics.values())] + topics = PaginatedList(topics) + page, nxt = topics.get_page( + token_generator=lambda x: get_next_page_token_from_arn(x["TopicArn"]), + next_token=next_token, + page_size=100, ) - self._publisher.publish_batch_to_topic(publish_ctx, topic_arn) + topics = {"Topics": page, "NextToken": nxt} + return ListTopicsResponse(**topics) - return response - - def set_subscription_attributes( + def set_topic_attributes( self, context: RequestContext, - subscription_arn: subscriptionARN, + topic_arn: topicARN, attribute_name: attributeName, - attribute_value: attributeValue = None, + attribute_value: attributeValue | None = None, **kwargs, ) -> None: - store = self.get_store(account_id=context.account_id, region_name=context.region) - sub = store.subscriptions.get(subscription_arn) - if not sub: - raise NotFoundException("Subscription does not exist") - - validate_subscription_attribute( - attribute_name=attribute_name, - attribute_value=attribute_value, - topic_arn=sub["TopicArn"], - endpoint=sub["Endpoint"], - ) - if attribute_name == "RawMessageDelivery": - attribute_value = attribute_value.lower() - - elif attribute_name == "FilterPolicy": - filter_policy = json.loads(attribute_value) if attribute_value else None - if filter_policy: - validator = FilterPolicyValidator( - scope=sub.get("FilterPolicyScope", "MessageAttributes"), - is_subscribe_call=False, - ) - validator.validate_filter_policy(filter_policy) - - store.subscription_filter_policy[subscription_arn] = filter_policy + topic: Topic = self._get_topic(arn=topic_arn, context=context) + if attribute_name == "FifoTopic": + raise InvalidParameterException("Invalid parameter: AttributeName") + topic["attributes"][attribute_name] = attribute_value - sub[attribute_name] = attribute_value + ## Subscribe operations - def confirm_subscription( + def subscribe( self, context: RequestContext, topic_arn: topicARN, - token: String, - authenticate_on_unsubscribe: authenticateOnUnsubscribe = None, + protocol: protocol, + endpoint: endpoint | None = None, + attributes: SubscriptionAttributesMap | None = None, + return_subscription_arn: bool | None = None, **kwargs, - ) -> ConfirmSubscriptionResponse: - # TODO: validate format on the token (seems to be 288 hex chars) - # this request can come from any http client, it might not be signed (we would need to implement - # `authenticate_on_unsubscribe` to force a signing client to do this request. - # so, the region and account_id might not be in the request. Use the ones from the topic_arn - try: - parsed_arn = parse_arn(topic_arn) - except InvalidArnException: - raise InvalidParameterException("Invalid parameter: Topic") + ) -> SubscribeResponse: + parsed_topic_arn = parse_and_validate_topic_arn(topic_arn) + if context.region != parsed_topic_arn["region"]: + raise InvalidParameterException("Invalid parameter: TopicArn") - store = self.get_store(account_id=parsed_arn["account"], region_name=parsed_arn["region"]) + store = self.get_store(account_id=parsed_topic_arn["account"], region=context.region) - # it seems SNS is able to know what the region of the topic should be, even though a wrong topic is accepted - if parsed_arn["region"] != get_region_from_subscription_token(token): - raise InvalidParameterException("Invalid parameter: Topic") + topic = self._get_topic(arn=topic_arn, context=context) + topic_subscriptions = topic["subscriptions"] + if not endpoint: + # TODO: check AWS behaviour (because endpoint is optional) + raise NotFoundException("Endpoint not specified in subscription") + if protocol not in SNS_PROTOCOLS: + raise InvalidParameterException( + f"Invalid parameter: Amazon SNS does not support this protocol string: {protocol}" + ) + elif protocol in ["http", "https"] and not endpoint.startswith(f"{protocol}://"): + raise InvalidParameterException( + "Invalid parameter: Endpoint must match the specified protocol" + ) + elif protocol == "sms" and not is_valid_e164_number(endpoint): + raise InvalidParameterException(f"Invalid SMS endpoint: {endpoint}") - subscription_arn = store.subscription_tokens.get(token) - if not subscription_arn: - raise InvalidParameterException("Invalid parameter: Token") + elif protocol == "sqs": + try: + parse_arn(endpoint) + except InvalidArnException: + raise InvalidParameterException("Invalid parameter: SQS endpoint ARN") - subscription = store.subscriptions.get(subscription_arn) - if not subscription: - # subscription could have been deleted in the meantime - raise InvalidParameterException("Invalid parameter: Token") + elif protocol == "application": + # TODO: Validate exact behaviour + try: + parse_arn(endpoint) + except InvalidArnException: + raise InvalidParameterException("Invalid parameter: ApplicationEndpoint ARN") - # ConfirmSubscription is idempotent - if subscription.get("PendingConfirmation") == "false": - return ConfirmSubscriptionResponse(SubscriptionArn=subscription_arn) + if ".fifo" in endpoint and ".fifo" not in topic_arn: + # TODO: move to sqs protocol block if possible + raise InvalidParameterException( + "Invalid parameter: Invalid parameter: Endpoint Reason: FIFO SQS Queues can not be subscribed to standard SNS topics" + ) - subscription["PendingConfirmation"] = "false" - subscription["ConfirmationWasAuthenticated"] = "true" + sub_attributes = copy.deepcopy(attributes) if attributes else None + if sub_attributes: + for attr_name, attr_value in sub_attributes.items(): + validate_subscription_attribute( + attribute_name=attr_name, + attribute_value=attr_value, + topic_arn=topic_arn, + endpoint=endpoint, + is_subscribe_call=True, + ) + if raw_msg_delivery := sub_attributes.get("RawMessageDelivery"): + sub_attributes["RawMessageDelivery"] = raw_msg_delivery.lower() - return ConfirmSubscriptionResponse(SubscriptionArn=subscription_arn) + # An endpoint may only be subscribed to a topic once. Subsequent + # subscribe calls do nothing (subscribe is idempotent), except if its attributes are different. + for existing_topic_subscription in topic_subscriptions: + sub = store.subscriptions.get(existing_topic_subscription, {}) + if sub.get("Endpoint") == endpoint: + if sub_attributes: + # validate the subscription attributes aren't different + for attr in VALID_SUBSCRIPTION_ATTR_NAME: + # if a new attribute is present and different from an existent one, raise + if (new_attr := sub_attributes.get(attr)) and sub.get(attr) != new_attr: + raise InvalidParameterException( + "Invalid parameter: Attributes Reason: Subscription already exists with different attributes" + ) - def untag_resource( - self, - context: RequestContext, - resource_arn: AmazonResourceName, - tag_keys: TagKeyList, - **kwargs, - ) -> UntagResourceResponse: - call_moto(context) - # TODO: probably get the account_id and region from the `resource_arn` - store = self.get_store(context.account_id, context.region) - existing_tags = store.sns_tags.setdefault(resource_arn, []) - store.sns_tags[resource_arn] = [t for t in existing_tags if t["Key"] not in tag_keys] - return UntagResourceResponse() + return SubscribeResponse(SubscriptionArn=sub["SubscriptionArn"]) + principal = DUMMY_SUBSCRIPTION_PRINCIPAL.format( + partition=get_partition(context.region), account_id=context.account_id + ) + subscription_arn = create_subscription_arn(topic_arn) + subscription = SnsSubscription( + # http://docs.aws.amazon.com/cli/latest/reference/sns/get-subscription-attributes.html + TopicArn=topic_arn, + Endpoint=endpoint, + Protocol=protocol, + SubscriptionArn=subscription_arn, + PendingConfirmation="true", + Owner=context.account_id, + RawMessageDelivery="false", # default value, will be overridden if set + FilterPolicyScope="MessageAttributes", # default value, will be overridden if set + SubscriptionPrincipal=principal, # dummy value, could be fetched with a call to STS? + ) + if sub_attributes: + subscription.update(sub_attributes) + if "FilterPolicy" in sub_attributes: + filter_policy = ( + json.loads(sub_attributes["FilterPolicy"]) + if sub_attributes["FilterPolicy"] + else None + ) + if filter_policy: + validator = FilterPolicyValidator( + scope=subscription.get("FilterPolicyScope", "MessageAttributes"), + is_subscribe_call=True, + ) + validator.validate_filter_policy(filter_policy) - def list_tags_for_resource( - self, context: RequestContext, resource_arn: AmazonResourceName, **kwargs - ) -> ListTagsForResourceResponse: - # TODO: probably get the account_id and region from the `resource_arn` - store = self.get_store(context.account_id, context.region) - tags = store.sns_tags.setdefault(resource_arn, []) - return ListTagsForResourceResponse(Tags=tags) + store.subscription_filter_policy[subscription_arn] = filter_policy - def create_platform_application( - self, - context: RequestContext, - name: String, - platform: String, - attributes: MapStringToString, - **kwargs, - ) -> CreatePlatformApplicationResponse: - # TODO: validate platform - # see https://docs.aws.amazon.com/cli/latest/reference/sns/create-platform-application.html - # list of possible values: ADM, Baidu, APNS, APNS_SANDBOX, GCM, MPNS, WNS - # each platform has a specific way to handle credentials - # this can also be used for dispatching message to the right platform - return call_moto(context) + store.subscriptions[subscription_arn] = subscription + + topic_subscriptions.append(subscription_arn) + + # store the token and subscription arn + # TODO: the token is a 288 hex char string + subscription_token = encode_subscription_token_with_region(region=context.region) + store.subscription_tokens[subscription_token] = subscription_arn + + response_subscription_arn = subscription_arn + # Send out confirmation message for HTTP(S), fix for https://github.com/localstack/localstack/issues/881 + if protocol in ["http", "https"]: + message_ctx = SnsMessage( + type=SnsMessageType.SubscriptionConfirmation, + token=subscription_token, + message=f"You have chosen to subscribe to the topic {topic_arn}.\nTo confirm the subscription, visit the SubscribeURL included in this message.", + ) + publish_ctx = SnsPublishContext( + message=message_ctx, + store=store, + request_headers=context.request.headers, + topic_attributes=topic["attributes"], + ) + self._publisher.publish_to_topic_subscriber( + ctx=publish_ctx, + topic_arn=topic_arn, + subscription_arn=subscription_arn, + ) + if not return_subscription_arn: + response_subscription_arn = "pending confirmation" + + elif protocol not in ["email", "email-json"]: + # Only HTTP(S) and email subscriptions are not auto validated + # Except if the endpoint and the topic are not in the same AWS account, then you'd need to manually confirm + # the subscription with the token + # TODO: revisit for multi-account + # TODO: test with AWS for email & email-json confirmation message + # we need to add the following check: + # if parsed_topic_arn["account"] == endpoint account (depending on the type, SQS, lambda, parse the arn) + subscription["PendingConfirmation"] = "false" + subscription["ConfirmationWasAuthenticated"] = "true" - def create_platform_endpoint( - self, - context: RequestContext, - platform_application_arn: String, - token: String, - custom_user_data: String = None, - attributes: MapStringToString = None, - **kwargs, - ) -> CreateEndpointResponse: - # TODO: support mobile app events - # see https://docs.aws.amazon.com/sns/latest/dg/application-event-notifications.html - return call_moto(context) + return SubscribeResponse(SubscriptionArn=response_subscription_arn) def unsubscribe( self, context: RequestContext, subscription_arn: subscriptionARN, **kwargs @@ -436,12 +505,12 @@ def unsubscribe( account_id = parsed_arn["account"] region_name = parsed_arn["region"] - store = self.get_store(account_id=account_id, region_name=region_name) + store = self.get_store(account_id=account_id, region=region_name) if count == 6 and subscription_arn not in store.subscriptions: raise InvalidParameterException("Invalid parameter: SubscriptionId") - moto_sns_backend = self.get_moto_backend(account_id, region_name) - moto_sns_backend.unsubscribe(subscription_arn) + # TODO: here was a moto_backend.unsubscribe call, check correct functionality and remove this comment + # before switching to v2 for production # pop the subscription at the end, to avoid race condition by iterating over the topic subscriptions subscription = store.subscriptions.get(subscription_arn) @@ -461,12 +530,12 @@ def unsubscribe( token=subscription_token, message=f"You have chosen to deactivate subscription {subscription_arn}.\nTo cancel this operation and restore the subscription, visit the SubscribeURL included in this message.", ) - moto_topic = moto_sns_backend.topics.get(subscription["TopicArn"]) publish_ctx = SnsPublishContext( message=message_ctx, store=store, request_headers=context.request.headers, - topic_attributes=vars(moto_topic), + # TODO: add the topic attributes once we ported them from moto to LocalStack + # topic_attributes=vars(moto_topic), ) self._publisher.publish_to_topic_subscriber( publish_ctx, @@ -474,15 +543,15 @@ def unsubscribe( subscription_arn=subscription_arn, ) - with contextlib.suppress(ValueError): - store.topic_subscriptions[subscription["TopicArn"]].remove(subscription_arn) + with contextlib.suppress(KeyError): + store.topics[subscription["TopicArn"]]["subscriptions"].remove(subscription_arn) store.subscription_filter_policy.pop(subscription_arn, None) store.subscriptions.pop(subscription_arn, None) def get_subscription_attributes( self, context: RequestContext, subscription_arn: subscriptionARN, **kwargs ) -> GetSubscriptionAttributesResponse: - store = self.get_store(account_id=context.account_id, region_name=context.region) + store = self.get_store(account_id=context.account_id, region=context.region) sub = store.subscriptions.get(subscription_arn) if not sub: raise NotFoundException("Subscription does not exist") @@ -496,13 +565,93 @@ def get_subscription_attributes( attributes = {k: v for k, v in sub.items() if k not in removed_attrs} return GetSubscriptionAttributesResponse(Attributes=attributes) + def set_subscription_attributes( + self, + context: RequestContext, + subscription_arn: subscriptionARN, + attribute_name: attributeName, + attribute_value: attributeValue = None, + **kwargs, + ) -> None: + store = self.get_store(account_id=context.account_id, region=context.region) + sub = store.subscriptions.get(subscription_arn) + if not sub: + raise NotFoundException("Subscription does not exist") + + validate_subscription_attribute( + attribute_name=attribute_name, + attribute_value=attribute_value, + topic_arn=sub["TopicArn"], + endpoint=sub["Endpoint"], + ) + if attribute_name == "RawMessageDelivery": + attribute_value = attribute_value.lower() + + elif attribute_name == "FilterPolicy": + filter_policy = json.loads(attribute_value) if attribute_value else None + if filter_policy: + validator = FilterPolicyValidator( + scope=sub.get("FilterPolicyScope", "MessageAttributes"), + is_subscribe_call=False, + ) + validator.validate_filter_policy(filter_policy) + + store.subscription_filter_policy[subscription_arn] = filter_policy + + sub[attribute_name] = attribute_value + + def confirm_subscription( + self, + context: RequestContext, + topic_arn: topicARN, + token: String, + authenticate_on_unsubscribe: authenticateOnUnsubscribe = None, + **kwargs, + ) -> ConfirmSubscriptionResponse: + # TODO: validate format on the token (seems to be 288 hex chars) + # this request can come from any http client, it might not be signed (we would need to implement + # `authenticate_on_unsubscribe` to force a signing client to do this request. + # so, the region and account_id might not be in the request. Use the ones from the topic_arn + try: + parsed_arn = parse_arn(topic_arn) + except InvalidArnException: + raise InvalidParameterException("Invalid parameter: Topic") + + store = self.get_store(account_id=parsed_arn["account"], region=parsed_arn["region"]) + + # it seems SNS is able to know what the region of the topic should be, even though a wrong topic is accepted + if parsed_arn["region"] != get_region_from_subscription_token(token): + raise InvalidParameterException("Invalid parameter: Topic") + + subscription_arn = store.subscription_tokens.get(token) + if not subscription_arn: + raise InvalidParameterException("Invalid parameter: Token") + + subscription = store.subscriptions.get(subscription_arn) + if not subscription: + # subscription could have been deleted in the meantime + raise InvalidParameterException("Invalid parameter: Token") + + # ConfirmSubscription is idempotent + if subscription.get("PendingConfirmation") == "false": + return ConfirmSubscriptionResponse(SubscriptionArn=subscription_arn) + + subscription["PendingConfirmation"] = "false" + subscription["ConfirmationWasAuthenticated"] = "true" + + return ConfirmSubscriptionResponse(SubscriptionArn=subscription_arn) + def list_subscriptions( self, context: RequestContext, next_token: nextToken = None, **kwargs ) -> ListSubscriptionsResponse: store = self.get_store(context.account_id, context.region) - subscriptions = [ - select_from_typed_dict(Subscription, sub) for sub in list(store.subscriptions.values()) - ] + subscriptions = [] + for s in list(store.subscriptions.values()): + sub = select_from_typed_dict(Subscription, s) + if s["PendingConfirmation"] == "true": + sub["SubscriptionArn"] = "PendingConfirmation" + subscriptions.append(sub) + paginated_subscriptions = PaginatedList(subscriptions) page, next_token = paginated_subscriptions.get_page( token_generator=lambda x: get_next_page_token_from_arn(x["SubscriptionArn"]), @@ -518,11 +667,10 @@ def list_subscriptions( def list_subscriptions_by_topic( self, context: RequestContext, topic_arn: topicARN, next_token: nextToken = None, **kwargs ) -> ListSubscriptionsByTopicResponse: - self._get_topic(topic_arn, context) + self._get_topic(topic_arn, context) # for validation purposes only parsed_topic_arn = parse_and_validate_topic_arn(topic_arn) store = self.get_store(parsed_topic_arn["account"], parsed_topic_arn["region"]) - sns_subscriptions = store.get_topic_subscriptions(topic_arn) - subscriptions = [select_from_typed_dict(Subscription, sub) for sub in sns_subscriptions] + subscriptions = get_topic_subscriptions(store, topic_arn) paginated_subscriptions = PaginatedList(subscriptions) page, next_token = paginated_subscriptions.get_page( @@ -536,18 +684,22 @@ def list_subscriptions_by_topic( response["NextToken"] = next_token return response + # + # Publish + # + def publish( self, context: RequestContext, - message: String, - topic_arn: topicARN = None, - target_arn: String = None, - phone_number: String = None, - subject: String = None, - message_structure: messageStructure = None, - message_attributes: MessageAttributeMap = None, - message_deduplication_id: String = None, - message_group_id: String = None, + message: message, + topic_arn: topicARN | None = None, + target_arn: String | None = None, + phone_number: PhoneNumber | None = None, + subject: subject | None = None, + message_structure: messageStructure | None = None, + message_attributes: MessageAttributeMap | None = None, + message_deduplication_id: String | None = None, + message_group_id: String | None = None, **kwargs, ) -> PublishResponse: if subject == "": @@ -557,29 +709,29 @@ def publish( # TODO: check for topic + target + phone number at the same time? # TODO: more validation on phone, it might be opted out? - if phone_number and not is_e164(phone_number): + if phone_number and not is_valid_e164_number(phone_number): raise InvalidParameterException( f"Invalid parameter: PhoneNumber Reason: {phone_number} is not valid to publish to" ) if message_attributes: - validate_message_attributes(message_attributes) + _validate_message_attributes(message_attributes) - if get_total_publish_size(message, message_attributes) > MAXIMUM_MESSAGE_LENGTH: + if _get_total_publish_size(message, message_attributes) > MAXIMUM_MESSAGE_LENGTH: raise InvalidParameterException("Invalid parameter: Message too long") # for compatibility reasons, AWS allows users to use either TargetArn or TopicArn for publishing to a topic # use any of them for topic validation topic_or_target_arn = topic_arn or target_arn - topic_model = None + topic = None if is_fifo := (topic_or_target_arn and ".fifo" in topic_or_target_arn): if not message_group_id: raise InvalidParameterException( "Invalid parameter: The MessageGroupId parameter is required for FIFO topics", ) - topic_model = self._get_topic(topic_or_target_arn, context) - if topic_model.content_based_deduplication == "false": + topic = self._get_topic(topic_or_target_arn, context) + if topic["attributes"]["ContentBasedDeduplication"] == "false": if not message_deduplication_id: raise InvalidParameterException( "Invalid parameter: The topic should either have ContentBasedDeduplication enabled or MessageDeduplicationId provided explicitly", @@ -612,20 +764,24 @@ def publish( if not phone_number: # use the account to get the store from the TopicArn (you can only publish in the same region as the topic) parsed_arn = parse_and_validate_topic_arn(topic_or_target_arn) - store = self.get_store(account_id=parsed_arn["account"], region_name=context.region) - moto_sns_backend = self.get_moto_backend(parsed_arn["account"], context.region) + store = self.get_store(account_id=parsed_arn["account"], region=context.region) if is_endpoint_publish: - if not (platform_endpoint := moto_sns_backend.platform_endpoints.get(target_arn)): + if not (platform_endpoint := store.platform_endpoints.get(target_arn)): raise InvalidParameterException( "Invalid parameter: TargetArn Reason: No endpoint found for the target arn specified" ) - elif not platform_endpoint.enabled: + elif ( + not platform_endpoint.platform_endpoint["Attributes"] + .get("Enabled", "false") + .lower() + == "true" + ): raise EndpointDisabledException("Endpoint is disabled") else: - topic_model = self._get_topic(topic_or_target_arn, context) + topic = self._get_topic(topic_or_target_arn, context) else: # use the store from the request context - store = self.get_store(account_id=context.account_id, region_name=context.region) + store = self.get_store(account_id=context.account_id, region=context.region) message_ctx = SnsMessage( type=SnsMessageType.Notification, @@ -651,7 +807,7 @@ def publish( # beware if the subscription is FIFO, the order might not be guaranteed. # 2 quick call to this method in succession might not be executed in order in the executor? # TODO: test how this behaves in a FIFO context with a lot of threads. - publish_ctx.topic_attributes |= vars(topic_model) + publish_ctx.topic_attributes |= topic["attributes"] self._publisher.publish_to_topic(publish_ctx, topic_or_target_arn) if is_fifo: @@ -661,300 +817,583 @@ def publish( return PublishResponse(MessageId=message_ctx.message_id) - def subscribe( + def publish_batch( self, context: RequestContext, topic_arn: topicARN, - protocol: String, - endpoint: String = None, - attributes: SubscriptionAttributesMap = None, - return_subscription_arn: boolean = None, + publish_batch_request_entries: PublishBatchRequestEntryList, **kwargs, - ) -> SubscribeResponse: - # TODO: check validation ordering - parsed_topic_arn = parse_and_validate_topic_arn(topic_arn) - if context.region != parsed_topic_arn["region"]: - raise InvalidParameterException("Invalid parameter: TopicArn") + ) -> PublishBatchResponse: + if len(publish_batch_request_entries) > 10: + raise TooManyEntriesInBatchRequestException( + "The batch request contains more entries than permissible." + ) - store = self.get_store(account_id=parsed_topic_arn["account"], region_name=context.region) + parsed_arn = parse_and_validate_topic_arn(topic_arn) + store = self.get_store(account_id=parsed_arn["account"], region=context.region) + topic = self._get_topic(topic_arn, context) + ids = [entry["Id"] for entry in publish_batch_request_entries] + if len(set(ids)) != len(publish_batch_request_entries): + raise BatchEntryIdsNotDistinctException( + "Two or more batch entries in the request have the same Id." + ) - if topic_arn not in store.topic_subscriptions: - raise NotFoundException("Topic does not exist") + # Validate each entry ID + for entry_id in ids: + if len(entry_id) > 80: + raise InvalidBatchEntryIdException( + f"The Id of a batch entry in the batch request is too long: {entry_id}" + ) + if not BATCH_ENTRY_ID_REGEX.match(entry_id): + raise InvalidBatchEntryIdException( + f"The Id of a batch entry in the batch request contains an impermissible character: {entry_id}" + ) - if not endpoint: - # TODO: check AWS behaviour (because endpoint is optional) - raise NotFoundException("Endpoint not specified in subscription") - if protocol not in sns_constants.SNS_PROTOCOLS: - raise InvalidParameterException( - f"Invalid parameter: Amazon SNS does not support this protocol string: {protocol}" + response: PublishBatchResponse = {"Successful": [], "Failed": []} + + # TODO: write AWS validated tests with FilterPolicy and batching + # TODO: find a scenario where we can fail to send a message synchronously to be able to report it + # right now, it seems that AWS fails the whole publish if something is wrong in the format of 1 message + + total_batch_size = 0 + message_contexts = [] + for entry_index, entry in enumerate(publish_batch_request_entries, start=1): + message_payload = entry.get("Message") + message_attributes = entry.get("MessageAttributes", {}) + if message_attributes: + # if a message contains non-valid message attributes, it + # will fail for the first non-valid message encountered, and raise ParameterValueInvalid + _validate_message_attributes(message_attributes, position=entry_index) + + total_batch_size += _get_total_publish_size(message_payload, message_attributes) + + # TODO: WRITE AWS VALIDATED + if entry.get("MessageStructure") == "json": + try: + message = json.loads(message_payload) + # Keys in the JSON object that correspond to supported transport protocols must have + # simple JSON string values. + # Non-string values will cause the key to be ignored. + message = { + key: field for key, field in message.items() if isinstance(field, str) + } + if "default" not in message: + raise InvalidParameterException( + "Invalid parameter: Message Structure - No default entry in JSON message body" + ) + entry["Message"] = message # noqa + except json.JSONDecodeError: + raise InvalidParameterException( + "Invalid parameter: Message Structure - JSON message body failed to parse" + ) + + if is_fifo := (topic_arn.endswith(".fifo")): + if not all("MessageGroupId" in entry for entry in publish_batch_request_entries): + raise InvalidParameterException( + "Invalid parameter: The MessageGroupId parameter is required for FIFO topics" + ) + if topic["attributes"]["ContentBasedDeduplication"] == "false": + if not all( + "MessageDeduplicationId" in entry for entry in publish_batch_request_entries + ): + raise InvalidParameterException( + "Invalid parameter: The topic should either have ContentBasedDeduplication enabled or MessageDeduplicationId provided explicitly", + ) + + msg_ctx = SnsMessage.from_batch_entry(entry, is_fifo=is_fifo) + message_contexts.append(msg_ctx) + success = PublishBatchResultEntry( + Id=entry["Id"], + MessageId=msg_ctx.message_id, ) - elif protocol in ["http", "https"] and not endpoint.startswith(f"{protocol}://"): - raise InvalidParameterException( - "Invalid parameter: Endpoint must match the specified protocol" + if is_fifo: + success["SequenceNumber"] = msg_ctx.sequencer_number + response["Successful"].append(success) + + if total_batch_size > MAXIMUM_MESSAGE_LENGTH: + raise CommonServiceException( + code="BatchRequestTooLong", + message="The length of all the messages put together is more than the limit.", + sender_fault=True, ) - elif protocol == "sms" and not is_e164(endpoint): - raise InvalidParameterException(f"Invalid SMS endpoint: {endpoint}") - elif protocol == "sqs": - try: - parse_arn(endpoint) - except InvalidArnException: - raise InvalidParameterException("Invalid parameter: SQS endpoint ARN") + publish_ctx = SnsBatchPublishContext( + messages=message_contexts, + store=store, + request_headers=context.request.headers, + topic_attributes=topic["attributes"], + ) + self._publisher.publish_batch_to_topic(publish_ctx, topic_arn) - elif protocol == "application": - # TODO: this is taken from moto, validate it - moto_backend = self.get_moto_backend( - account_id=parsed_topic_arn["account"], region_name=context.region - ) - if endpoint not in moto_backend.platform_endpoints: - raise NotFoundException("Endpoint does not exist") + return response - if ".fifo" in endpoint and ".fifo" not in topic_arn: + # + # PlatformApplications + # + def create_platform_application( + self, + context: RequestContext, + name: String, + platform: String, + attributes: MapStringToString, + **kwargs, + ) -> CreatePlatformApplicationResponse: + _validate_platform_application_name(name) + if platform not in VALID_APPLICATION_PLATFORMS: raise InvalidParameterException( - "Invalid parameter: Invalid parameter: Endpoint Reason: FIFO SQS Queues can not be subscribed to standard SNS topics" + f"Invalid parameter: Platform Reason: {platform} is not supported" ) - sub_attributes = copy.deepcopy(attributes) if attributes else None - if sub_attributes: - for attr_name, attr_value in sub_attributes.items(): - validate_subscription_attribute( - attribute_name=attr_name, - attribute_value=attr_value, - topic_arn=topic_arn, - endpoint=endpoint, - is_subscribe_call=True, - ) - if raw_msg_delivery := sub_attributes.get("RawMessageDelivery"): - sub_attributes["RawMessageDelivery"] = raw_msg_delivery.lower() + _validate_platform_application_attributes(attributes) - # An endpoint may only be subscribed to a topic once. Subsequent - # subscribe calls do nothing (subscribe is idempotent), except if its attributes are different. - for existing_topic_subscription in store.topic_subscriptions.get(topic_arn, []): - sub = store.subscriptions.get(existing_topic_subscription, {}) - if sub.get("Endpoint") == endpoint: - if sub_attributes: - # validate the subscription attributes aren't different - for attr in sns_constants.VALID_SUBSCRIPTION_ATTR_NAME: - # if a new attribute is present and different from an existent one, raise - if (new_attr := sub_attributes.get(attr)) and sub.get(attr) != new_attr: - raise InvalidParameterException( - "Invalid parameter: Attributes Reason: Subscription already exists with different attributes" - ) + # attribute validation specific to create_platform_application + if "PlatformCredential" in attributes and "PlatformPrincipal" not in attributes: + raise InvalidParameterException( + "Invalid parameter: Attributes Reason: PlatformCredential attribute provided without PlatformPrincipal" + ) - return SubscribeResponse(SubscriptionArn=sub["SubscriptionArn"]) + elif "PlatformPrincipal" in attributes and "PlatformCredential" not in attributes: + raise InvalidParameterException( + "Invalid parameter: Attributes Reason: PlatformPrincipal attribute provided without PlatformCredential" + ) - principal = sns_constants.DUMMY_SUBSCRIPTION_PRINCIPAL.format( - partition=get_partition(context.region), account_id=context.account_id + store = self.get_store(context.account_id, context.region) + # We are not validating the access data here like AWS does (against ADM and the like) + attributes.pop("PlatformPrincipal") + attributes.pop("PlatformCredential") + _attributes = {"Enabled": "true"} + _attributes.update(attributes) + application_arn = sns_platform_application_arn( + platform_application_name=name, + platform=platform, + account_id=context.account_id, + region_name=context.region, ) - subscription_arn = create_subscription_arn(topic_arn) - subscription = SnsSubscription( - # http://docs.aws.amazon.com/cli/latest/reference/sns/get-subscription-attributes.html - TopicArn=topic_arn, - Endpoint=endpoint, - Protocol=protocol, - SubscriptionArn=subscription_arn, - PendingConfirmation="true", - Owner=context.account_id, - RawMessageDelivery="false", # default value, will be overridden if set - FilterPolicyScope="MessageAttributes", # default value, will be overridden if set - SubscriptionPrincipal=principal, # dummy value, could be fetched with a call to STS? + platform_application_details = PlatformApplicationDetails( + platform_application=PlatformApplication( + PlatformApplicationArn=application_arn, + Attributes=_attributes, + ), + platform_endpoints={}, ) - if sub_attributes: - subscription.update(sub_attributes) - if "FilterPolicy" in sub_attributes: - filter_policy = ( - json.loads(sub_attributes["FilterPolicy"]) - if sub_attributes["FilterPolicy"] - else None - ) - if filter_policy: - validator = FilterPolicyValidator( - scope=subscription.get("FilterPolicyScope", "MessageAttributes"), - is_subscribe_call=True, - ) - validator.validate_filter_policy(filter_policy) + store.platform_applications[application_arn] = platform_application_details - store.subscription_filter_policy[subscription_arn] = filter_policy + return platform_application_details.platform_application - store.subscriptions[subscription_arn] = subscription + def delete_platform_application( + self, context: RequestContext, platform_application_arn: String, **kwargs + ) -> None: + store = self.get_store(context.account_id, context.region) + store.platform_applications.pop(platform_application_arn, None) + # TODO: if the platform had endpoints, should we remove them from the store? There is no way to list + # endpoints without an application, so this is impossible to check the state of AWS here - topic_subscriptions = store.topic_subscriptions.setdefault(topic_arn, []) - topic_subscriptions.append(subscription_arn) + def list_platform_applications( + self, context: RequestContext, next_token: String | None = None, **kwargs + ) -> ListPlatformApplicationsResponse: + store = self.get_store(context.account_id, context.region) + platform_applications = store.platform_applications.values() + paginated_applications = PaginatedList(platform_applications) + page, token = paginated_applications.get_page( + token_generator=lambda x: get_next_page_token_from_arn(x["PlatformApplicationArn"]), + page_size=100, + next_token=next_token, + ) - # store the token and subscription arn - # TODO: the token is a 288 hex char string - subscription_token = encode_subscription_token_with_region(region=context.region) - store.subscription_tokens[subscription_token] = subscription_arn + response = ListPlatformApplicationsResponse( + PlatformApplications=[platform_app.platform_application for platform_app in page] + ) + if token: + response["NextToken"] = token + return response - response_subscription_arn = subscription_arn - # Send out confirmation message for HTTP(S), fix for https://github.com/localstack/localstack/issues/881 - if protocol in ["http", "https"]: - message_ctx = SnsMessage( - type=SnsMessageType.SubscriptionConfirmation, - token=subscription_token, - message=f"You have chosen to subscribe to the topic {topic_arn}.\nTo confirm the subscription, visit the SubscribeURL included in this message.", - ) - publish_ctx = SnsPublishContext( - message=message_ctx, - store=store, - request_headers=context.request.headers, - topic_attributes=vars(self._get_topic(topic_arn, context)), - ) - self._publisher.publish_to_topic_subscriber( - ctx=publish_ctx, - topic_arn=topic_arn, - subscription_arn=subscription_arn, - ) - if not return_subscription_arn: - response_subscription_arn = "pending confirmation" + def get_platform_application_attributes( + self, context: RequestContext, platform_application_arn: String, **kwargs + ) -> GetPlatformApplicationAttributesResponse: + platform_application = self._get_platform_application(platform_application_arn, context) + attributes = platform_application["Attributes"] + return GetPlatformApplicationAttributesResponse(Attributes=attributes) - elif protocol not in ["email", "email-json"]: - # Only HTTP(S) and email subscriptions are not auto validated - # Except if the endpoint and the topic are not in the same AWS account, then you'd need to manually confirm - # the subscription with the token - # TODO: revisit for multi-account - # TODO: test with AWS for email & email-json confirmation message - # we need to add the following check: - # if parsed_topic_arn["account"] == endpoint account (depending on the type, SQS, lambda, parse the arn) - subscription["PendingConfirmation"] = "false" - subscription["ConfirmationWasAuthenticated"] = "true" + def set_platform_application_attributes( + self, + context: RequestContext, + platform_application_arn: String, + attributes: MapStringToString, + **kwargs, + ) -> None: + parse_and_validate_platform_application_arn(platform_application_arn) + _validate_platform_application_attributes(attributes) - return SubscribeResponse(SubscriptionArn=response_subscription_arn) + platform_application = self._get_platform_application(platform_application_arn, context) + platform_application["Attributes"].update(attributes) - def tag_resource( - self, context: RequestContext, resource_arn: AmazonResourceName, tags: TagList, **kwargs - ) -> TagResourceResponse: - # each tag key must be unique - # https://docs.aws.amazon.com/general/latest/gr/aws_tagging.html#tag-best-practices - unique_tag_keys = {tag["Key"] for tag in tags} - if len(unique_tag_keys) < len(tags): - raise InvalidParameterException("Invalid parameter: Duplicated keys are not allowed.") + # + # Platform Endpoints + # - call_moto(context) + def create_platform_endpoint( + self, + context: RequestContext, + platform_application_arn: String, + token: String, + custom_user_data: String | None = None, + attributes: MapStringToString | None = None, + **kwargs, + ) -> CreateEndpointResponse: store = self.get_store(context.account_id, context.region) - existing_tags = store.sns_tags.get(resource_arn, []) - - def existing_tag_index(_item): - for idx, tag in enumerate(existing_tags): - if _item["Key"] == tag["Key"]: - return idx - return None - - for item in tags: - existing_index = existing_tag_index(item) - if existing_index is None: - existing_tags.append(item) + application = store.platform_applications.get(platform_application_arn) + if not application: + raise NotFoundException("PlatformApplication does not exist") + endpoint_arn = application.platform_endpoints.get(token, {}) + attributes = attributes or {} + _validate_endpoint_attributes(attributes, allow_empty=True) + # CustomUserData can be specified both in attributes and as parameter. Attributes take precedence + if custom_user_data: + attributes.setdefault(EndpointAttributeNames.CUSTOM_USER_DATA, custom_user_data) + _attributes = {"Enabled": "true", "Token": token, **attributes} + if endpoint_arn and ( + platform_endpoint_details := store.platform_endpoints.get(endpoint_arn) + ): + # endpoint for that application with that particular token already exists + if not platform_endpoint_details.platform_endpoint["Attributes"] == _attributes: + raise InvalidParameterException( + f"Invalid parameter: Token Reason: Endpoint {endpoint_arn} already exists with the same Token, but different attributes." + ) else: - existing_tags[existing_index] = item + return CreateEndpointResponse(EndpointArn=endpoint_arn) + + endpoint_arn = create_platform_endpoint_arn(platform_application_arn) + platform_endpoint = PlatformEndpoint( + platform_application_arn=endpoint_arn, + platform_endpoint=Endpoint( + Attributes=_attributes, + EndpointArn=endpoint_arn, + ), + ) + store.platform_endpoints[endpoint_arn] = platform_endpoint + application.platform_endpoints[token] = endpoint_arn - store.sns_tags[resource_arn] = existing_tags - return TagResourceResponse() + return CreateEndpointResponse(EndpointArn=endpoint_arn) - def delete_topic(self, context: RequestContext, topic_arn: topicARN, **kwargs) -> None: - parsed_arn = parse_and_validate_topic_arn(topic_arn) - if context.region != parsed_arn["region"]: - raise InvalidParameterException("Invalid parameter: TopicArn") + def delete_endpoint(self, context: RequestContext, endpoint_arn: String, **kwargs) -> None: + store = self.get_store(context.account_id, context.region) + platform_endpoint_details = store.platform_endpoints.pop(endpoint_arn, None) + if platform_endpoint_details: + platform_application = store.platform_applications.get( + platform_endpoint_details.platform_application_arn + ) + if platform_application: + platform_endpoint = platform_endpoint_details.platform_endpoint + platform_application.platform_endpoints.pop( + platform_endpoint["Attributes"]["Token"], None + ) + + def list_endpoints_by_platform_application( + self, + context: RequestContext, + platform_application_arn: String, + next_token: String | None = None, + **kwargs, + ) -> ListEndpointsByPlatformApplicationResponse: + store = self.get_store(context.account_id, context.region) + platform_application = store.platform_applications.get(platform_application_arn) + if not platform_application: + raise NotFoundException("PlatformApplication does not exist") + endpoint_arns = platform_application.platform_endpoints.values() + paginated_endpoint_arns = PaginatedList(endpoint_arns) + page, token = paginated_endpoint_arns.get_page( + token_generator=lambda x: get_next_page_token_from_arn(x), + page_size=100, + next_token=next_token, + ) - call_moto(context) - store = self.get_store(account_id=parsed_arn["account"], region_name=context.region) - topic_subscriptions = store.topic_subscriptions.pop(topic_arn, []) - for topic_sub in topic_subscriptions: - store.subscriptions.pop(topic_sub, None) + response = ListEndpointsByPlatformApplicationResponse( + Endpoints=[ + store.platform_endpoints[endpoint_arn].platform_endpoint + for endpoint_arn in page + if endpoint_arn in store.platform_endpoints + ] + ) + if token: + response["NextToken"] = token + return response - store.sns_tags.pop(topic_arn, None) + def get_endpoint_attributes( + self, context: RequestContext, endpoint_arn: String, **kwargs + ) -> GetEndpointAttributesResponse: + store = self.get_store(context.account_id, context.region) + platform_endpoint_details = store.platform_endpoints.get(endpoint_arn) + if not platform_endpoint_details: + raise NotFoundException("Endpoint does not exist") + attributes = platform_endpoint_details.platform_endpoint["Attributes"] + return GetEndpointAttributesResponse(Attributes=attributes) + + def set_endpoint_attributes( + self, context: RequestContext, endpoint_arn: String, attributes: MapStringToString, **kwargs + ) -> None: + store = self.get_store(context.account_id, context.region) + platform_endpoint_details = store.platform_endpoints.get(endpoint_arn) + if not platform_endpoint_details: + raise NotFoundException("Endpoint does not exist") + _validate_endpoint_attributes(attributes) + attributes = attributes or {} + platform_endpoint_details.platform_endpoint["Attributes"].update(attributes) + + # + # Sms operations + # + + def set_sms_attributes( + self, context: RequestContext, attributes: MapStringToString, **kwargs + ) -> SetSMSAttributesResponse: + store = self.get_store(context.account_id, context.region) + _validate_sms_attributes(attributes) + _set_sms_attribute_default(store) + store.sms_attributes.update(attributes or {}) + return SetSMSAttributesResponse() + + def get_sms_attributes( + self, context: RequestContext, attributes: ListString | None = None, **kwargs + ) -> GetSMSAttributesResponse: + store = self.get_store(context.account_id, context.region) + _set_sms_attribute_default(store) + store_attributes = store.sms_attributes + return_attributes = {} + for k, v in store_attributes.items(): + if not attributes or k in attributes: + return_attributes[k] = store_attributes[k] + + return GetSMSAttributesResponse(attributes=return_attributes) + + # + # Phone number operations + # + + def check_if_phone_number_is_opted_out( + self, context: RequestContext, phone_number: PhoneNumber, **kwargs + ) -> CheckIfPhoneNumberIsOptedOutResponse: + store = sns_stores[context.account_id][context.region] + return CheckIfPhoneNumberIsOptedOutResponse( + isOptedOut=phone_number in store.PHONE_NUMBERS_OPTED_OUT + ) - def create_topic( + def list_phone_numbers_opted_out( + self, context: RequestContext, next_token: string | None = None, **kwargs + ) -> ListPhoneNumbersOptedOutResponse: + store = self.get_store(context.account_id, context.region) + numbers_opted_out = PaginatedList(store.PHONE_NUMBERS_OPTED_OUT) + page, nxt = numbers_opted_out.get_page( + token_generator=lambda x: x, + next_token=next_token, + page_size=100, + ) + phone_numbers = {"phoneNumbers": page, "nextToken": nxt} + return ListPhoneNumbersOptedOutResponse(**phone_numbers) + + def opt_in_phone_number( + self, context: RequestContext, phone_number: PhoneNumber, **kwargs + ) -> OptInPhoneNumberResponse: + _validate_phone_number(phone_number) + store = self.get_store(context.account_id, context.region) + if phone_number in store.PHONE_NUMBERS_OPTED_OUT: + store.PHONE_NUMBERS_OPTED_OUT.remove(phone_number) + return OptInPhoneNumberResponse() + + # + # Permission operations + # + + def add_permission( self, context: RequestContext, - name: topicName, - attributes: TopicAttributesMap = None, - tags: TagList = None, - data_protection_policy: attributeValue = None, + topic_arn: topicARN, + label: label, + aws_account_id: DelegatesList, + action_name: ActionsList, **kwargs, - ) -> CreateTopicResponse: - moto_response = call_moto(context) - store = self.get_store(account_id=context.account_id, region_name=context.region) - topic_arn = moto_response["TopicArn"] - tag_resource_success = extract_tags(topic_arn, tags, True, store) - if not tag_resource_success: + ) -> None: + topic: Topic = self._get_topic(topic_arn, context) + policy = json.loads(topic["attributes"]["Policy"]) + statement = next( + (statement for statement in policy["Statement"] if statement["Sid"] == label), + None, + ) + + if statement: + raise InvalidParameterException("Invalid parameter: Statement already exists") + + if any(action not in VALID_POLICY_ACTIONS for action in action_name): raise InvalidParameterException( - "Invalid parameter: Tags Reason: Topic already exists with different tags" + "Invalid parameter: Policy statement action out of service scope!" ) - if tags: - self.tag_resource(context=context, resource_arn=topic_arn, tags=tags) - store.topic_subscriptions.setdefault(topic_arn, []) - return CreateTopicResponse(TopicArn=topic_arn) + principals = [ + f"arn:{get_partition(context.region)}:iam::{account_id}:root" + for account_id in aws_account_id + ] + actions = [f"SNS:{action}" for action in action_name] + + statement = { + "Sid": label, + "Effect": "Allow", + "Principal": {"AWS": principals[0] if len(principals) == 1 else principals}, + "Action": actions[0] if len(actions) == 1 else actions, + "Resource": topic_arn, + } -def is_raw_message_delivery(susbcriber): - return susbcriber.get("RawMessageDelivery") in ("true", True, "True") + policy["Statement"].append(statement) + topic["attributes"]["Policy"] = json.dumps(policy) + def remove_permission( + self, context: RequestContext, topic_arn: topicARN, label: label, **kwargs + ) -> None: + topic = self._get_topic(topic_arn, context) + policy = json.loads(topic["attributes"]["Policy"]) + statements = policy["Statement"] + statements = [statement for statement in statements if statement["Sid"] != label] + policy["Statement"] = statements + topic["attributes"]["Policy"] = json.dumps(policy) + + # + # Data Protection Policy operations + # + + def get_data_protection_policy( + self, context: RequestContext, resource_arn: topicARN, **kwargs + ) -> GetDataProtectionPolicyResponse: + topic = self._get_topic(resource_arn, context) + return GetDataProtectionPolicyResponse( + DataProtectionPolicy=topic.get("data_protection_policy") + ) -def validate_subscription_attribute( - attribute_name: str, - attribute_value: str, - topic_arn: str, - endpoint: str, - is_subscribe_call: bool = False, -) -> None: - """ - Validate the subscription attribute to be set. See: - https://docs.aws.amazon.com/sns/latest/api/API_SetSubscriptionAttributes.html - :param attribute_name: the subscription attribute name, must be in VALID_SUBSCRIPTION_ATTR_NAME - :param attribute_value: the subscription attribute value - :param topic_arn: the topic_arn of the subscription, needed to know if it is FIFO - :param endpoint: the subscription endpoint (like an SQS queue ARN) - :param is_subscribe_call: the error message is different if called from Subscribe or SetSubscriptionAttributes - :raises InvalidParameterException - :return: - """ - error_prefix = ( - "Invalid parameter: Attributes Reason: " if is_subscribe_call else "Invalid parameter: " - ) - if attribute_name not in sns_constants.VALID_SUBSCRIPTION_ATTR_NAME: - raise InvalidParameterException(f"{error_prefix}AttributeName") + def put_data_protection_policy( + self, + context: RequestContext, + resource_arn: topicARN, + data_protection_policy: attributeValue, + **kwargs, + ) -> None: + topic = self._get_topic(resource_arn, context) + topic["data_protection_policy"] = data_protection_policy - if attribute_name == "FilterPolicy": - try: - json.loads(attribute_value or "{}") - except json.JSONDecodeError: - raise InvalidParameterException(f"{error_prefix}FilterPolicy: failed to parse JSON.") - elif attribute_name == "FilterPolicyScope": - if attribute_value not in ("MessageAttributes", "MessageBody"): - raise InvalidParameterException( - f"{error_prefix}FilterPolicyScope: Invalid value [{attribute_value}]. " - f"Please use either MessageBody or MessageAttributes" - ) - elif attribute_name == "RawMessageDelivery": - # TODO: only for SQS and https(s) subs, + firehose - if attribute_value.lower() not in ("true", "false"): - raise InvalidParameterException( - f"{error_prefix}RawMessageDelivery: Invalid value [{attribute_value}]. " - f"Must be true or false." - ) + def list_tags_for_resource( + self, context: RequestContext, resource_arn: AmazonResourceName, **kwargs + ) -> ListTagsForResourceResponse: + tags = self._list_resource_tags(context, resource_arn) + return ListTagsForResourceResponse(Tags=tags) + + def tag_resource( + self, context: RequestContext, resource_arn: AmazonResourceName, tags: TagList, **kwargs + ) -> TagResourceResponse: + unique_tag_keys = {tag["Key"] for tag in tags} + if len(unique_tag_keys) < len(tags): + raise InvalidParameterException("Invalid parameter: Duplicated keys are not allowed.") + self._tag_resource(context, resource_arn, tags) + return TagResourceResponse() + + def untag_resource( + self, + context: RequestContext, + resource_arn: AmazonResourceName, + tag_keys: TagKeyList, + **kwargs, + ) -> UntagResourceResponse: + self._untag_resource(context, resource_arn, tag_keys) + return UntagResourceResponse() + + @staticmethod + def get_store(account_id: str, region: str) -> SnsStore: + return sns_stores[account_id][region] - elif attribute_name == "RedrivePolicy": + @staticmethod + def _get_topic(arn: str, context: RequestContext, multi_region: bool = False) -> Topic: + """ + :param arn: the Topic ARN + :param context: the RequestContext of the request + :return: the model Topic + """ + arn_data = parse_and_validate_topic_arn(arn) + if not multi_region and context.region != arn_data["region"]: + raise InvalidParameterException("Invalid parameter: TopicArn") try: - dlq_target_arn = json.loads(attribute_value).get("deadLetterTargetArn", "") - except json.JSONDecodeError: - raise InvalidParameterException(f"{error_prefix}RedrivePolicy: failed to parse JSON.") + store = SnsProvider.get_store(arn_data["account"], arn_data["region"]) + return store.topics[arn] + except KeyError: + raise NotFoundException("Topic does not exist") + + @staticmethod + def _get_platform_application( + platform_application_arn: str, context: RequestContext + ) -> PlatformApplication: + parse_and_validate_platform_application_arn(platform_application_arn) try: - parsed_arn = parse_arn(dlq_target_arn) - except InvalidArnException: - raise InvalidParameterException( - f"{error_prefix}RedrivePolicy: deadLetterTargetArn is an invalid arn" - ) + store = SnsProvider.get_store(context.account_id, context.region) + return store.platform_applications[platform_application_arn].platform_application + except KeyError: + raise NotFoundException("PlatformApplication does not exist") - if topic_arn.endswith(".fifo"): - if endpoint.endswith(".fifo") and ( - not parsed_arn["resource"].endswith(".fifo") or "sqs" not in parsed_arn["service"] - ): - raise InvalidParameterException( - f"{error_prefix}RedrivePolicy: must use a FIFO queue as DLQ for a FIFO Subscription to a FIFO Topic." - ) + +def _create_topic( + name: str, attributes: dict, data_protection_policy: str, context: RequestContext +) -> Topic: + topic_arn = sns_topic_arn( + topic_name=name, region_name=context.region, account_id=context.account_id + ) + topic: Topic = { + "name": name, + "arn": topic_arn, + "attributes": {}, + "subscriptions": [], + "data_protection_policy": data_protection_policy, + } + attrs = _default_attributes(topic, context) + attrs.update(attributes or {}) + topic["attributes"] = attrs + + return topic + + +def _default_attributes(topic: Topic, context: RequestContext) -> TopicAttributesMap: + default_attributes = { + "DisplayName": "", + "Owner": context.account_id, + "Policy": create_default_topic_policy(topic["arn"]), + "SubscriptionsConfirmed": "0", + "SubscriptionsDeleted": "0", + "SubscriptionsPending": "0", + "TopicArn": topic["arn"], + } + if topic["name"].endswith(".fifo"): + default_attributes.update( + { + "ContentBasedDeduplication": "false", + "FifoTopic": "false", + } + ) + return default_attributes + + +def _create_default_effective_delivery_policy(): + return json.dumps( + { + "http": { + "defaultHealthyRetryPolicy": { + "minDelayTarget": 20, + "maxDelayTarget": 20, + "numRetries": 3, + "numMaxDelayRetries": 0, + "numNoDelayRetries": 0, + "numMinDelayRetries": 0, + "backoffFunction": "linear", + }, + "disableSubscriptionOverrides": False, + "defaultRequestPolicy": {"headerContentType": "text/plain; charset=UTF-8"}, + } + } + ) -def validate_message_attributes( +def _validate_message_attributes( message_attributes: MessageAttributeMap, position: int | None = None ) -> None: """ @@ -971,7 +1410,7 @@ def validate_message_attributes( raise InvalidParameterValueException( "Length of message attribute name must be less than 256 bytes." ) - validate_message_attribute_name(attr_name) + _validate_message_attribute_name(attr_name) # `DataType` is a required field for MessageAttributeValue if (data_type := attr.get("DataType")) is None: if position: @@ -989,7 +1428,7 @@ def validate_message_attributes( "String", "Number", "Binary", - ) and not sns_constants.ATTR_TYPE_REGEX.match(data_type): + ) and not ATTR_TYPE_REGEX.match(data_type): raise InvalidParameterValueException( f"The message attribute '{attr_name}' has an invalid message attribute type, the set of supported type prefixes is Binary, Number, and String." ) @@ -1010,14 +1449,14 @@ def validate_message_attributes( ) -def validate_message_attribute_name(name: str) -> None: +def _validate_message_attribute_name(name: str) -> None: """ Validate the message attribute name with the specification of AWS. The message attribute name can contain the following characters: A-Z, a-z, 0-9, underscore(_), hyphen(-), and period (.). The name must not start or end with a period, and it should not have successive periods. :param name: message attribute name :raises InvalidParameterValueException: if the name does not conform to the spec """ - if not sns_constants.MSG_ATTR_NAME_REGEX.match(name): + if not MSG_ATTR_NAME_REGEX.match(name): # find the proper exception if name[0] == ".": raise InvalidParameterValueException( @@ -1029,7 +1468,7 @@ def validate_message_attribute_name(name: str) -> None: ) for idx, char in enumerate(name): - if char not in sns_constants.VALID_MSG_ATTR_NAME_CHARS: + if char not in VALID_MSG_ATTR_NAME_CHARS: # change prefix from 0x to #x, without capitalizing the x hex_char = "#x" + hex(ord(char)).upper()[2:] raise InvalidParameterValueException( @@ -1042,72 +1481,72 @@ def validate_message_attribute_name(name: str) -> None: ) -def extract_tags( - topic_arn: str, tags: TagList, is_create_topic_request: bool, store: SnsStore -) -> bool: - existing_tags = list(store.sns_tags.get(topic_arn, [])) - # if this is none there is nothing to check - if topic_arn in store.topic_subscriptions: - if tags is None: - tags = [] - for tag in tags: - # this means topic already created with empty tags and when we try to create it - # again with other tag value then it should fail according to aws documentation. - if is_create_topic_request and existing_tags is not None and tag not in existing_tags: - return False - return True - - -def parse_and_validate_topic_arn(topic_arn: str | None) -> ArnData: - topic_arn = topic_arn or "" - try: - return parse_arn(topic_arn) - except InvalidArnException: - count = len(topic_arn.split(":")) - raise InvalidParameterException( - f"Invalid parameter: TopicArn Reason: An ARN must have at least 6 elements, not {count}" - ) +def _validate_platform_application_name(name: str) -> None: + reason = "" + if not name: + reason = "cannot be empty" + elif not re.match(r"^.{0,256}$", name): + reason = "must be at most 256 characters long" + elif not re.match(r"^[A-Za-z0-9._-]+$", name): + reason = "must contain only characters 'a'-'z', 'A'-'Z', '0'-'9', '_', '-', and '.'" + if reason: + LOG.debug("SNS Platform Application Name rejected due to reason: %s", reason) + raise InvalidParameterException(f"Invalid parameter: {name} Reason: {reason}") -def create_subscription_arn(topic_arn: str) -> str: - # This is the format of a Subscription ARN - # arn:aws:sns:us-west-2:123456789012:my-topic:8a21d249-4329-4871-acc6-7be709c6ea7f - return f"{topic_arn}:{uuid4()}" +def _validate_platform_application_attributes(attributes: dict) -> None: + _check_empty_attributes(attributes) -def encode_subscription_token_with_region(region: str) -> str: - """ - Create a 64 characters Subscription Token with the region encoded - :param region: - :return: a subscription token with the region encoded - """ - return ((region.encode() + b"/").hex() + short_uid() * 8)[:64] +def _check_empty_attributes(attributes: dict) -> None: + if not attributes: + raise CommonServiceException( + code="ValidationError", + message="1 validation error detected: Value null at 'attributes' failed to satisfy constraint: Member must not be null", + sender_fault=True, + ) -def get_region_from_subscription_token(token: str) -> str: - """ - Try to decode and return the region from a subscription token - :param token: - :return: the region if able to decode it - :raises: InvalidParameterException if the token is invalid - """ - try: - region = token.split("2f", maxsplit=1)[0] - return bytes.fromhex(region).decode("utf-8") - except (IndexError, ValueError, TypeError, UnicodeDecodeError): - raise InvalidParameterException("Invalid parameter: Token") + +def _validate_endpoint_attributes(attributes: dict, allow_empty: bool = False) -> None: + if not allow_empty: + _check_empty_attributes(attributes) + for key in attributes: + if key not in EndpointAttributeNames: + raise InvalidParameterException( + f"Invalid parameter: Attributes Reason: Invalid attribute name: {key}" + ) + if len(attributes.get(EndpointAttributeNames.CUSTOM_USER_DATA, "")) > 2048: + raise InvalidParameterException( + "Invalid parameter: Attributes Reason: Invalid value for attribute: CustomUserData: must be at most 2048 bytes long in UTF-8 encoding" + ) -def get_next_page_token_from_arn(resource_arn: str) -> str: - return to_str(base64.b64encode(to_bytes(resource_arn))) +def _validate_sms_attributes(attributes: dict) -> None: + for k, v in attributes.items(): + if k not in SMS_ATTRIBUTE_NAMES: + raise InvalidParameterException(f"{k} is not a valid attribute") + default_send_id = attributes.get("DefaultSendID") + if default_send_id and not re.match(SMS_DEFAULT_SENDER_REGEX, default_send_id): + raise InvalidParameterException("DefaultSendID is not a valid attribute") + sms_type = attributes.get("DefaultSMSType") + if sms_type and sms_type not in SMS_TYPES: + raise InvalidParameterException("DefaultSMSType is invalid") -def _get_byte_size(payload: str | bytes) -> int: - # Calculate the real length of the byte object if the object is a string - return len(to_bytes(payload)) +def _set_sms_attribute_default(store: SnsStore) -> None: + # TODO: don't call this on every sms attribute crud api call + store.sms_attributes.setdefault("MonthlySpendLimit", "1") + +def _validate_phone_number(phone_number: str): + if not re.match(E164_REGEX, phone_number): + raise InvalidParameterException( + "Invalid parameter: PhoneNumber Reason: input incorrectly formatted" + ) -def get_total_publish_size( + +def _get_total_publish_size( message_body: str, message_attributes: MessageAttributeMap | None ) -> int: size = _get_byte_size(message_body) @@ -1125,32 +1564,18 @@ def get_total_publish_size( return size -def register_sns_api_resource(router: Router): +def _get_byte_size(payload: str | bytes) -> int: + # Calculate the real length of the byte object if the object is a string + return len(to_bytes(payload)) + + +def _register_sns_api_resource(router: Router): """Register the retrospection endpoints as internal LocalStack endpoints.""" router.add(SNSServicePlatformEndpointMessagesApiResource()) router.add(SNSServiceSMSMessagesApiResource()) router.add(SNSServiceSubscriptionTokenApiResource()) -def _format_messages(sent_messages: list[dict[str, str]], validated_keys: list[str]): - """ - This method format the messages to be more readable and undo the format change that was needed for Moto - Should be removed once we refactor SNS. - """ - formatted_messages = [] - for sent_message in sent_messages: - msg = { - key: json.dumps(value) - if key == "Message" and sent_message.get("MessageStructure") == "json" - else value - for key, value in sent_message.items() - if key in validated_keys - } - formatted_messages.append(msg) - - return formatted_messages - - class SNSInternalResource: resource_type: str """Base class with helper to properly track usage of internal endpoints""" @@ -1193,7 +1618,7 @@ class SNSServicePlatformEndpointMessagesApiResource(SNSInternalResource): "MessageId", ] - @route(sns_constants.PLATFORM_ENDPOINT_MSGS_ENDPOINT, methods=["GET"]) + @route(PLATFORM_ENDPOINT_MSGS_ENDPOINT, methods=["GET"]) @count_usage def on_get(self, request: Request): filter_endpoint_arn = request.args.get("endpointArn") @@ -1225,7 +1650,7 @@ def on_get(self, request: Request): "region": region, } - @route(sns_constants.PLATFORM_ENDPOINT_MSGS_ENDPOINT, methods=["DELETE"]) + @route(PLATFORM_ENDPOINT_MSGS_ENDPOINT, methods=["DELETE"]) @count_usage def on_delete(self, request: Request) -> Response: filter_endpoint_arn = request.args.get("endpointArn") @@ -1248,6 +1673,33 @@ def on_delete(self, request: Request) -> Response: return Response("", status=204) +def register_sns_api_resource(router: Router): + """Register the retrospection endpoints as internal LocalStack endpoints.""" + router.add(SNSServicePlatformEndpointMessagesApiResource()) + router.add(SNSServiceSMSMessagesApiResource()) + router.add(SNSServiceSubscriptionTokenApiResource()) + router.add(SNSServiceSMSPhoneOptOutResource()) + + +def _format_messages(sent_messages: list[dict[str, str]], validated_keys: list[str]): + """ + This method format the messages to be more readable and undo the format change that was needed for Moto + Should be removed once we refactor SNS. + """ + formatted_messages = [] + for sent_message in sent_messages: + msg = { + key: json.dumps(value) + if key == "Message" and sent_message.get("MessageStructure") == "json" + else value + for key, value in sent_message.items() + if key in validated_keys + } + formatted_messages.append(msg) + + return formatted_messages + + class SNSServiceSMSMessagesApiResource(SNSInternalResource): resource_type = "sms-message" """Provides a REST API for retrospective access to SMS messages sent via SNS. @@ -1271,7 +1723,7 @@ class SNSServiceSMSMessagesApiResource(SNSInternalResource): "Subject", ] - @route(sns_constants.SMS_MSGS_ENDPOINT, methods=["GET"]) + @route(SMS_MSGS_ENDPOINT, methods=["GET"]) @count_usage def on_get(self, request: Request): account_id = request.args.get("accountId", DEFAULT_AWS_ACCOUNT_ID) @@ -1298,7 +1750,7 @@ def on_get(self, request: Request): "region": region, } - @route(sns_constants.SMS_MSGS_ENDPOINT, methods=["DELETE"]) + @route(SMS_MSGS_ENDPOINT, methods=["DELETE"]) @count_usage def on_delete(self, request: Request) -> Response: account_id = request.args.get("accountId", DEFAULT_AWS_ACCOUNT_ID) @@ -1327,7 +1779,7 @@ class SNSServiceSubscriptionTokenApiResource(SNSInternalResource): - GET `subscription_arn`: `subscriptionArn`resource in SNS for which you want the SubscriptionToken """ - @route(f"{sns_constants.SUBSCRIPTION_TOKENS_ENDPOINT}/", methods=["GET"]) + @route(f"{SUBSCRIPTION_TOKENS_ENDPOINT}/", methods=["GET"]) @count_usage def on_get(self, _request: Request, subscription_arn: str): try: @@ -1359,3 +1811,27 @@ def on_get(self, _request: Request, subscription_arn: str): } ) return response + + +class SNSServiceSMSPhoneOptOutResource(SNSInternalResource): + resource_type = "phone-number-opt-out" + """Provides a REST API for adding phone numbers to the opt out list for testing purposes. + In AWS this seems to be handled by pin-point, which is scheduled for deprecation. + + This is registered as a LocalStack internal HTTP resource. + + This endpoint accepts: + - POST data `phoneNumber`: phone number to be opted out in SNS + - POST data `accountId`: account ID + """ + + @route(SMS_PHONE_NUMBER_OPT_OUT_ENDPOINT, methods=["POST"]) + @count_usage + def on_post(self, request: Request): + data = json.loads(request.data) or {} + account_id = data.get("accountId", DEFAULT_AWS_ACCOUNT_ID) + region = AWS_REGION_US_EAST_1 # opt-out list is account-wide + opt_out_phone_number = data.get("phoneNumber") + store: SnsStore = sns_stores[account_id][region] + if opt_out_phone_number: + store.PHONE_NUMBERS_OPTED_OUT.add(opt_out_phone_number) diff --git a/localstack-core/localstack/services/sns/publisher.py b/localstack-core/localstack/services/sns/publisher.py index 107dd013586f4..f3589df6fc20d 100644 --- a/localstack-core/localstack/services/sns/publisher.py +++ b/localstack-core/localstack/services/sns/publisher.py @@ -16,7 +16,7 @@ from localstack import config from localstack.aws.api.lambda_ import InvocationType -from localstack.aws.api.sns import MessageAttributeMap +from localstack.aws.api.sns import MessageAttributeMap, TopicAttributesMap from localstack.aws.connect import connect_to from localstack.config import external_service_url from localstack.services.sns import constants as sns_constants @@ -30,6 +30,7 @@ SnsStore, SnsSubscription, ) +from localstack.services.sns.utils import get_topic_subscriptions, snake_to_pascal_case from localstack.utils.aws.arns import ( PARTITION_NAMES, extract_account_id_from_arn, @@ -110,7 +111,7 @@ def prepare_message( self, message_context: SnsMessage, subscriber: SnsSubscription, - topic_attributes: dict[str, str] = None, + topic_attributes: TopicAttributesMap = None, ) -> str: """ Returns the message formatted in the base SNS message format. The base SNS message format is shared amongst @@ -232,7 +233,7 @@ def prepare_message( self, message_context: SnsMessage, subscriber: SnsSubscription, - topic_attributes: dict[str, str] = None, + topic_attributes: TopicAttributesMap = None, ) -> str: """ You can see Lambda SNS Event format here: https://docs.aws.amazon.com/lambda/latest/dg/with-sns.html @@ -254,9 +255,11 @@ def prepare_message( "UnsubscribeUrl": unsubscribe_url, "MessageAttributes": message_attributes, } - + # TODO: remove v1 "signature_version" access once v1 is retired signature_version = ( - topic_attributes.get("signature_version", "1") if topic_attributes else "1" + topic_attributes.get("signature_version", topic_attributes.get("SignatureVersion", "1")) + if topic_attributes + else "1" ) canonical_string = compute_canonical_string(event_payload, message_context.type) signature = get_message_signature(canonical_string, signature_version=signature_version) @@ -558,7 +561,10 @@ def _get_content_type(subscriber: SnsSubscription, topic_attributes: dict) -> st ): return sub_content_type - if json_topic_delivery_policy := topic_attributes.get("delivery_policy"): + # TODO: remove lower case access once legacy v1 provider is removed + if json_topic_delivery_policy := topic_attributes.get( + "delivery_policy", topic_attributes.get("DeliveryPolicy") + ): topic_delivery_policy = json.loads(json_topic_delivery_policy) if not ( topic_content_type := topic_delivery_policy.get(subscriber["Protocol"].lower()) @@ -615,7 +621,7 @@ def prepare_message( self, message_context: SnsMessage, subscriber: SnsSubscription, - topic_attributes: dict[str, str] = None, + topic_attributes: TopicAttributesMap = None, ) -> str: return message_context.message_content(subscriber["Protocol"]) @@ -658,8 +664,8 @@ def prepare_message( self, message_context: SnsMessage, subscriber: SnsSubscription, - topic_attributes: dict[str, str] = None, - ) -> dict[str, str]: + topic_attributes: TopicAttributesMap = None, + ) -> dict[str, str | MessageAttributeMap | None]: endpoint_arn = subscriber["Endpoint"] platform_type = get_platform_type_from_endpoint_arn(endpoint_arn) return { @@ -719,8 +725,8 @@ def prepare_message( self, message_context: SnsMessage, subscriber: SnsSubscription, - topic_attributes: dict[str, str] = None, - ) -> dict: + topic_attributes: TopicAttributesMap = None, + ) -> dict[str, str | MessageAttributeMap | None]: return { "PhoneNumber": subscriber["Endpoint"], "TopicArn": subscriber["TopicArn"], @@ -872,7 +878,7 @@ def get_application_platform_arn_from_endpoint_arn(endpoint_arn: str) -> str: parsed_arn = parse_arn(endpoint_arn) _, platform_type, app_name, _ = parsed_arn["resource"].split("/") - base_arn = f"arn:aws:sns:{parsed_arn['region']}:{parsed_arn['account']}" + base_arn = f"arn:{parsed_arn['partition']}:sns:{parsed_arn['region']}:{parsed_arn['account']}" return f"{base_arn}:app/{platform_type}/{app_name}" @@ -1009,7 +1015,10 @@ def create_sns_message_body( # FIFO topics do not add the signature in the message if not subscriber.get("TopicArn", "").endswith(".fifo"): signature_version = ( - topic_attributes.get("signature_version", "1") if topic_attributes else "1" + # we allow for both casings, depending on v1 or v2 provider + topic_attributes.get("signature_version", topic_attributes.get("SignatureVersion", "1")) + if topic_attributes + else "1" ) canonical_string = compute_canonical_string(data, message_type) signature = get_message_signature(canonical_string, signature_version=signature_version) @@ -1086,7 +1095,6 @@ def store_delivery_log( # SMS is a special case: https://docs.aws.amazon.com/sns/latest/dg/sms_stats_cloudwatch.html # seems like you need to configure on the Console, leave it on by default now in LocalStack protocol = subscriber.get("Protocol") - if protocol != "sms": if protocol not in available_delivery_logs_services or not topic_attributes: # this service does not have DeliveryLogs feature, return @@ -1101,7 +1109,11 @@ def store_delivery_log( # TODO: on purpose not using walrus operator to show that we get the RoleArn here for CloudWatch role_arn = topic_attributes.get(topic_attribute) if not role_arn: - return + # TODO: remove snake case access once v1 is completely obsolete + topic_attribute = snake_to_pascal_case(topic_attribute) + role_arn = topic_attributes.get(topic_attribute) + if not role_arn: + return if not is_api_enabled("logs"): LOG.warning( @@ -1234,7 +1246,7 @@ def _should_publish( ) def publish_to_topic(self, ctx: SnsPublishContext, topic_arn: str) -> None: - subscriptions = ctx.store.get_topic_subscriptions(topic_arn) + subscriptions = get_topic_subscriptions(ctx.store, topic_arn) for subscriber in subscriptions: if self._should_publish(ctx.store.subscription_filter_policy, ctx.message, subscriber): notifier = self.topic_notifiers[subscriber["Protocol"]] @@ -1249,7 +1261,7 @@ def publish_to_topic(self, ctx: SnsPublishContext, topic_arn: str) -> None: self._submit_notification(notifier, ctx, subscriber) def publish_batch_to_topic(self, ctx: SnsBatchPublishContext, topic_arn: str) -> None: - subscriptions = ctx.store.get_topic_subscriptions(topic_arn) + subscriptions = get_topic_subscriptions(ctx.store, topic_arn) for subscriber in subscriptions: protocol = subscriber["Protocol"] notifier = self.batch_topic_notifiers.get(protocol) diff --git a/localstack-core/localstack/services/sns/resource_providers/aws_sns_topicpolicy.py b/localstack-core/localstack/services/sns/resource_providers/aws_sns_topicpolicy.py index a9f88c2765538..bbe17c09466a4 100644 --- a/localstack-core/localstack/services/sns/resource_providers/aws_sns_topicpolicy.py +++ b/localstack-core/localstack/services/sns/resource_providers/aws_sns_topicpolicy.py @@ -14,7 +14,7 @@ ResourceProvider, ResourceRequest, ) -from localstack.services.sns.models import create_default_sns_topic_policy +from localstack.services.sns.provider import create_default_topic_policy class SNSTopicPolicyProperties(TypedDict): @@ -99,7 +99,7 @@ def delete( sns.set_topic_attributes( TopicArn=topic_arn, AttributeName="Policy", - AttributeValue=json.dumps(create_default_sns_topic_policy(topic_arn)), + AttributeValue=create_default_topic_policy(topic_arn), ) except ClientError as err: diff --git a/localstack-core/localstack/services/sns/utils.py b/localstack-core/localstack/services/sns/utils.py new file mode 100644 index 0000000000000..cfad0431b5b2f --- /dev/null +++ b/localstack-core/localstack/services/sns/utils.py @@ -0,0 +1,184 @@ +import base64 +import json +from uuid import uuid4 + +from botocore.utils import InvalidArnException + +from localstack.aws.api.sns import InvalidParameterException +from localstack.services.sns.constants import E164_REGEX, VALID_SUBSCRIPTION_ATTR_NAME +from localstack.services.sns.models import SnsStore, SnsSubscription +from localstack.utils.aws.arns import ArnData, parse_arn +from localstack.utils.strings import short_uid, to_bytes, to_str + + +def parse_and_validate_topic_arn(topic_arn: str | None) -> ArnData: + return _parse_and_validate_arn(topic_arn, "Topic") + + +def parse_and_validate_platform_application_arn(platform_application_arn: str | None) -> ArnData: + return _parse_and_validate_arn(platform_application_arn, "PlatformApplication") + + +def _parse_and_validate_arn(arn: str | None, resource_type: str) -> ArnData: + arn = arn or "" + try: + return parse_arn(arn) + except InvalidArnException: + count = len(arn.split(":")) + raise InvalidParameterException( + f"Invalid parameter: {resource_type}Arn Reason: An ARN must have at least 6 elements, not {count}" + ) + + +def is_valid_e164_number(number: str) -> bool: + return E164_REGEX.match(number) is not None + + +def snake_to_pascal_case(snake_case_string: str) -> str: + return "".join(word.capitalize() for word in snake_case_string.split("_")) + + +def validate_subscription_attribute( + attribute_name: str, + attribute_value: str, + topic_arn: str, + endpoint: str, + is_subscribe_call: bool = False, +) -> None: + """ + Validate the subscription attribute to be set. See: + https://docs.aws.amazon.com/sns/latest/api/API_SetSubscriptionAttributes.html + :param attribute_name: the subscription attribute name, must be in VALID_SUBSCRIPTION_ATTR_NAME + :param attribute_value: the subscription attribute value + :param topic_arn: the topic_arn of the subscription, needed to know if it is FIFO + :param endpoint: the subscription endpoint (like an SQS queue ARN) + :param is_subscribe_call: the error message is different if called from Subscribe or SetSubscriptionAttributes + :raises InvalidParameterException + :return: + """ + error_prefix = ( + "Invalid parameter: Attributes Reason: " if is_subscribe_call else "Invalid parameter: " + ) + if attribute_name not in VALID_SUBSCRIPTION_ATTR_NAME: + raise InvalidParameterException(f"{error_prefix}AttributeName") + + if attribute_name == "FilterPolicy": + try: + json.loads(attribute_value or "{}") + except json.JSONDecodeError: + raise InvalidParameterException(f"{error_prefix}FilterPolicy: failed to parse JSON.") + elif attribute_name == "FilterPolicyScope": + if attribute_value not in ("MessageAttributes", "MessageBody"): + raise InvalidParameterException( + f"{error_prefix}FilterPolicyScope: Invalid value [{attribute_value}]. " + f"Please use either MessageBody or MessageAttributes" + ) + elif attribute_name == "RawMessageDelivery": + # TODO: only for SQS and https(s) subs, + firehose + if attribute_value.lower() not in ("true", "false"): + raise InvalidParameterException( + f"{error_prefix}RawMessageDelivery: Invalid value [{attribute_value}]. " + f"Must be true or false." + ) + + elif attribute_name == "RedrivePolicy": + try: + dlq_target_arn = json.loads(attribute_value).get("deadLetterTargetArn", "") + except json.JSONDecodeError: + raise InvalidParameterException(f"{error_prefix}RedrivePolicy: failed to parse JSON.") + try: + parsed_arn = parse_arn(dlq_target_arn) + except InvalidArnException: + raise InvalidParameterException( + f"{error_prefix}RedrivePolicy: deadLetterTargetArn is an invalid arn" + ) + + if topic_arn.endswith(".fifo"): + if endpoint.endswith(".fifo") and ( + not parsed_arn["resource"].endswith(".fifo") or "sqs" not in parsed_arn["service"] + ): + raise InvalidParameterException( + f"{error_prefix}RedrivePolicy: must use a FIFO queue as DLQ for a FIFO Subscription to a FIFO Topic." + ) + + +def create_subscription_arn(topic_arn: str) -> str: + # This is the format of a Subscription ARN + # arn:aws:sns:us-west-2:123456789012:my-topic:8a21d249-4329-4871-acc6-7be709c6ea7f + return f"{topic_arn}:{uuid4()}" + + +def create_platform_endpoint_arn( + platform_application_arn: str, +) -> str: + # This is the format of an Endpoint Arn + # arn:aws:sns:us-west-2:1234567890:endpoint/GCM/MyApplication/12345678-abcd-9012-efgh-345678901234 + return f"{platform_application_arn.replace('app', 'endpoint', 1)}/{uuid4()}" + + +def encode_subscription_token_with_region(region: str) -> str: + """ + Create a 64 characters Subscription Token with the region encoded + :param region: + :return: a subscription token with the region encoded + """ + return ((region.encode() + b"/").hex() + short_uid() * 8)[:64] + + +def get_next_page_token_from_arn(resource_arn: str) -> str: + return to_str(base64.b64encode(to_bytes(resource_arn))) + + +def get_region_from_subscription_token(token: str) -> str: + """ + Try to decode and return the region from a subscription token + :param token: + :return: the region if able to decode it + :raises: InvalidParameterException if the token is invalid + """ + try: + region = token.split("2f", maxsplit=1)[0] + return bytes.fromhex(region).decode("utf-8") + except (IndexError, ValueError, TypeError, UnicodeDecodeError): + raise InvalidParameterException("Invalid parameter: Token") + + +def get_topic_subscriptions(store: SnsStore, topic_arn: str) -> list[SnsSubscription]: + # TODO: delete this once the legacy v1 implementation has been removed + if hasattr(store, "topic_subscriptions"): + sub_arns = store.topic_subscriptions.get(topic_arn, []) + else: + sub_arns: list[str] = store.topics[topic_arn].get("subscriptions", []) + + subscriptions = [store.subscriptions[k] for k in sub_arns if k in store.subscriptions] + return subscriptions + + +def create_default_topic_policy(topic_arn: str) -> str: + return json.dumps( + { + "Version": "2008-10-17", + "Id": "__default_policy_ID", + "Statement": [ + { + "Effect": "Allow", + "Sid": "__default_statement_ID", + "Principal": {"AWS": "*"}, + "Action": [ + "SNS:GetTopicAttributes", + "SNS:SetTopicAttributes", + "SNS:AddPermission", + "SNS:RemovePermission", + "SNS:DeleteTopic", + "SNS:Subscribe", + "SNS:ListSubscriptionsByTopic", + "SNS:Publish", + ], + "Resource": topic_arn, + "Condition": { + "StringEquals": {"AWS:SourceOwner": parse_arn(topic_arn)["account"]} + }, + } + ], + } + ) diff --git a/localstack-core/localstack/services/sns/v2/provider.py b/localstack-core/localstack/services/sns/v2/provider.py deleted file mode 100644 index 1278c0ecf1be5..0000000000000 --- a/localstack-core/localstack/services/sns/v2/provider.py +++ /dev/null @@ -1,9 +0,0 @@ -import logging - -from localstack.aws.api.sns import SnsApi - -# set up logger -LOG = logging.getLogger(__name__) - - -class SnsProvider(SnsApi): ... diff --git a/localstack-core/localstack/services/sqs/constants.py b/localstack-core/localstack/services/sqs/constants.py index 83662a9262e79..40664d122b601 100644 --- a/localstack-core/localstack/services/sqs/constants.py +++ b/localstack-core/localstack/services/sqs/constants.py @@ -19,6 +19,13 @@ # the default maximum message size in SQS DEFAULT_MAXIMUM_MESSAGE_SIZE = 1048576 +DYNAMIC_ATTRIBUTES = [ + # these attributes are not set once, but calculated dynamically, therefore we do not to store them + # internally with the other attributes, and only include them in the necessary responses. + QueueAttributeName.ApproximateNumberOfMessages, + QueueAttributeName.ApproximateNumberOfMessagesDelayed, + QueueAttributeName.ApproximateNumberOfMessagesNotVisible, +] INTERNAL_QUEUE_ATTRIBUTES = [ # these attributes cannot be changed by set_queue_attributes and should # therefore be ignored when comparing queue attributes for create_queue @@ -31,6 +38,12 @@ QueueAttributeName.QueueArn, ] +# +# If these attributes are set to their default values, they are effectively +# deleted from the queue attributes and not returned in future calls to get_queue_attributes() +# +DELETE_IF_DEFAULT = {"KmsMasterKeyId": "", "KmsDataKeyReusePeriodSeconds": "300"} + INVALID_STANDARD_QUEUE_ATTRIBUTES = [ QueueAttributeName.FifoQueue, QueueAttributeName.ContentBasedDeduplication, diff --git a/localstack-core/localstack/services/sqs/models.py b/localstack-core/localstack/services/sqs/models.py index 15c2bafb1e2b8..4f0de6365dea3 100644 --- a/localstack-core/localstack/services/sqs/models.py +++ b/localstack-core/localstack/services/sqs/models.py @@ -24,6 +24,7 @@ TagMap, ) from localstack.services.sqs import constants as sqs_constants +from localstack.services.sqs.constants import DYNAMIC_ATTRIBUTES from localstack.services.sqs.exceptions import ( InvalidAttributeValue, InvalidParameterValueException, @@ -44,6 +45,7 @@ from localstack.services.stores import AccountRegionBundle, BaseStore, LocalAttribute from localstack.utils.aws.arns import get_partition from localstack.utils.strings import long_uid +from localstack.utils.tagging import Tags from localstack.utils.time import now from localstack.utils.urls import localstack_host @@ -55,7 +57,7 @@ class SqsMessage: message: Message created: float - visibility_timeout: int + visibility_timeout: int | None receive_count: int delay_seconds: int | None receipt_handles: set[str] @@ -64,9 +66,7 @@ class SqsMessage: visibility_deadline: float | None deleted: bool priority: float - message_deduplication_id: str - message_group_id: str - sequence_number: str + sequence_number: str | None def __init__( self, @@ -84,6 +84,7 @@ def __init__( self.delay_seconds = None self.last_received = None self.first_received = None + self.visibility_timeout = None self.visibility_deadline = None self.deleted = False self.priority = priority @@ -269,28 +270,36 @@ class MessageMoveTask: # configurable fields source_arn: str """The arn of the DLQ the messages are currently in.""" - destination_arn: str | None = None + destination_arn: str | None """If the DestinationArn is not specified, the original source arn will be used as target.""" - max_number_of_messages_per_second: int | None = None + max_number_of_messages_per_second: int | None # dynamic fields task_id: str - status: str = MessageMoveTaskStatus.CREATED - started_timestamp: datetime | None = None - approximate_number_of_messages_moved: int | None = None - approximate_number_of_messages_to_move: int | None = None - failure_reason: str | None = None + status: str + started_timestamp: datetime | None + approximate_number_of_messages_moved: int | None + approximate_number_of_messages_to_move: int | None + failure_reason: str | None cancel_event: threading.Event def __init__( - self, source_arn: str, destination_arn: str, max_number_of_messages_per_second: int = None + self, + source_arn: str, + destination_arn: str, + max_number_of_messages_per_second: int | None = None, ): self.task_id = long_uid() self.source_arn = source_arn self.destination_arn = destination_arn self.max_number_of_messages_per_second = max_number_of_messages_per_second self.cancel_event = threading.Event() + self.status = MessageMoveTaskStatus.CREATED + self.started_timestamp = None + self.approximate_number_of_messages_moved = None + self.approximate_number_of_messages_to_move = None + self.failure_reason = None def mark_started(self): self.started_timestamp = datetime.utcnow() @@ -314,8 +323,10 @@ class SqsQueue: purge_timestamp: float | None delayed: set[SqsMessage] - inflight: set[SqsMessage] + # Simulating an ordered set in python. Only the keys are used and of interest. + inflight: dict[SqsMessage, None] receipts: dict[str, SqsMessage] + mutex: threading.RLock def __init__(self, name: str, region: str, account_id: str, attributes=None, tags=None) -> None: self.name = name @@ -326,7 +337,7 @@ def __init__(self, name: str, region: str, account_id: str, attributes=None, tag self.tags = tags or {} self.delayed = set() - self.inflight = set() + self.inflight = {} self.receipts = {} self.attributes = self.default_attributes() @@ -345,15 +356,6 @@ def shutdown(self): def default_attributes(self) -> QueueAttributeMap: return { - QueueAttributeName.ApproximateNumberOfMessages: lambda: str( - self.approx_number_of_messages - ), - QueueAttributeName.ApproximateNumberOfMessagesNotVisible: lambda: str( - self.approx_number_of_messages_not_visible - ), - QueueAttributeName.ApproximateNumberOfMessagesDelayed: lambda: str( - self.approx_number_of_messages_delayed - ), QueueAttributeName.CreatedTimestamp: str(now()), QueueAttributeName.DelaySeconds: "0", QueueAttributeName.LastModifiedTimestamp: str(now()), @@ -472,15 +474,15 @@ def maximum_message_size(self) -> int: return int(self.attributes[QueueAttributeName.MaximumMessageSize]) @property - def approx_number_of_messages(self) -> int: + def approximate_number_of_messages(self) -> int: raise NotImplementedError @property - def approx_number_of_messages_not_visible(self) -> int: + def approximate_number_of_messages_not_visible(self) -> int: return len(self.inflight) @property - def approx_number_of_messages_delayed(self) -> int: + def approximate_number_of_messages_delayed(self) -> int: return len(self.delayed) def validate_receipt_handle(self, receipt_handle: str): @@ -513,7 +515,7 @@ def update_visibility_timeout(self, receipt_handle: str, visibility_timeout: int ) # Terminating the visibility timeout for a message # https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/sqs-visibility-timeout.html#terminating-message-visibility-timeout - self.inflight.remove(standard_message) + del self.inflight[standard_message] self._put_message(standard_message) def remove(self, receipt_handle: str): @@ -606,9 +608,17 @@ def requeue_inflight_messages(self): standard_message, self.arn, ) - self.inflight.remove(standard_message) + del self.inflight[standard_message] self._put_message(standard_message) + def add_inflight_message(self, message: SqsMessage): + """ + We are simulating an ordered set with a dict. When a value is added, it is added as key to the dict, which + is all we need. Hence all "values" in this ordered set are None + :param message: The message to put in flight + """ + self.inflight[message] = None + def enqueue_delayed_messages(self): if not self.delayed: return @@ -715,7 +725,7 @@ def get_queue_attributes(self, attribute_names: AttributeNameList = None) -> dic return {} if QueueAttributeName.All in attribute_names: - attribute_names = self.attributes.keys() + attribute_names = list(self.attributes.keys()) + DYNAMIC_ATTRIBUTES result: dict[QueueAttributeName, str] = {} @@ -725,13 +735,18 @@ def get_queue_attributes(self, attribute_names: AttributeNameList = None) -> dic except AttributeError: raise InvalidAttributeName(f"Unknown Attribute {attr}.") - value = self.attributes.get(attr) - if callable(value): - func = value - value = func() - if value is not None: - result[attr] = value - elif value == "False" or value == "True": + # The approximate_* attributes are calculated on the spot when accessed. + # We have a @property for each of those which calculates the value. + match attr: + case QueueAttributeName.ApproximateNumberOfMessages: + value = str(self.approximate_number_of_messages) + case QueueAttributeName.ApproximateNumberOfMessagesDelayed: + value = str(self.approximate_number_of_messages_delayed) + case QueueAttributeName.ApproximateNumberOfMessagesNotVisible: + value = str(self.approximate_number_of_messages_not_visible) + case _: + value = self.attributes.get(attr) + if value == "False" or value == "True": result[attr] = value.lower() elif value is not None: result[attr] = value @@ -779,7 +794,6 @@ def _pre_delete_checks(self, standard_message: SqsMessage, receipt_handle: str) class StandardQueue(SqsQueue): visible: InterruptiblePriorityQueue[SqsMessage] - inflight: set[SqsMessage] def __init__(self, name: str, region: str, account_id: str, attributes=None, tags=None) -> None: super().__init__(name, region, account_id, attributes, tags) @@ -791,7 +805,7 @@ def clear(self): self.visible.queue.clear() @property - def approx_number_of_messages(self): + def approximate_number_of_messages(self): return self.visible.qsize() def shutdown(self): @@ -923,13 +937,13 @@ def receive( if message.visibility_timeout == 0: self.visible.put_nowait(message) else: - self.inflight.add(message) + self.add_inflight_message(message) return result def _on_remove_message(self, message: SqsMessage): try: - self.inflight.remove(message) + del self.inflight[message] except KeyError: # this likely means the message was removed with an expired receipt handle unfortunately this # means we need to scan the queue for the element and remove it from there, and then re-heapify @@ -1017,7 +1031,7 @@ def __init__(self, name: str, region: str, account_id: str, attributes=None, tag self.deduplication_scope = self.attributes[QueueAttributeName.DeduplicationScope] @property - def approx_number_of_messages(self): + def approximate_number_of_messages(self): n = 0 for message_group in self.message_groups.values(): n += len(message_group.messages) @@ -1053,8 +1067,7 @@ def update_delay_seconds(self, value: int): message.delay_seconds = value def _pre_delete_checks(self, message: SqsMessage, receipt_handle: str) -> None: - _, _, _, last_received = extract_receipt_handle_info(receipt_handle) - if time.time() - float(last_received) > message.visibility_timeout: + if message.is_visible: raise InvalidParameterValueException( f"Value {receipt_handle} for parameter ReceiptHandle is invalid. Reason: The receipt handle has expired." ) @@ -1150,6 +1163,26 @@ def _put_message(self, message: SqsMessage): elif previously_empty: self.message_group_queue.put_nowait(message_group) + def requeue_inflight_messages(self): + if not self.inflight: + return + + with self.mutex: + messages = list(self.inflight) + for standard_message in messages: + # in fifo, an invisible message blocks potentially visible messages afterwards + # this can happen for example if multiple message of the same group are received at once, then one + # message of this batch has its visibility timeout extended + if not standard_message.is_visible: + return + LOG.debug( + "re-queueing inflight messages %s into queue %s", + standard_message, + self.arn, + ) + del self.inflight[standard_message] + self._put_message(standard_message) + def remove_expired_messages(self): with self.mutex: retention_period = self.message_retention_period @@ -1279,8 +1312,7 @@ def receive( if message.visibility_timeout == 0: self._put_message(message) else: - self.inflight.add(message) - + self.add_inflight_message(message) return result def _on_remove_message(self, message: SqsMessage): @@ -1289,7 +1321,7 @@ def _on_remove_message(self, message: SqsMessage): with self.mutex: try: - self.inflight.remove(message) + del self.inflight[message] except KeyError: # in FIFO queues, this should not happen, as expired receipt handles cannot be used to # delete a message. @@ -1351,13 +1383,15 @@ def clear(self): class SqsStore(BaseStore): - queues: dict[str, SqsQueue] = LocalAttribute(default=dict) + queues: dict[str, FifoQueue | StandardQueue] = LocalAttribute(default=dict) deleted: dict[str, float] = LocalAttribute(default=dict) move_tasks: dict[str, MessageMoveTask] = LocalAttribute(default=dict) """Maps task IDs to their ``MoveMessageTask`` object. Task IDs can be found by decoding a task handle.""" + tags: Tags = LocalAttribute(default=Tags) + def expire_deleted(self): for k in list(self.deleted.keys()): if self.deleted[k] <= (time.time() - sqs_constants.RECENTLY_DELETED_TIMEOUT): diff --git a/localstack-core/localstack/services/sqs/provider.py b/localstack-core/localstack/services/sqs/provider.py index 49e177682a75a..0058e6828a267 100644 --- a/localstack-core/localstack/services/sqs/provider.py +++ b/localstack-core/localstack/services/sqs/provider.py @@ -101,6 +101,7 @@ parse_queue_url, ) from localstack.services.stores import AccountRegionBundle +from localstack.state import StateVisitor from localstack.utils.aws.arns import parse_arn from localstack.utils.bootstrap import is_api_enabled from localstack.utils.cloudwatch.cloudwatch_util import ( @@ -320,21 +321,21 @@ def publish_approximate_cloudwatch_metrics(self): SqsMetricBatchData( QueueName=queue.name, MetricName="ApproximateNumberOfMessagesVisible", - Value=queue.approx_number_of_messages, + Value=queue.approximate_number_of_messages, ) ) batch_data.append( SqsMetricBatchData( QueueName=queue.name, MetricName="ApproximateNumberOfMessagesNotVisible", - Value=queue.approx_number_of_messages_not_visible, + Value=queue.approximate_number_of_messages_not_visible, ) ) batch_data.append( SqsMetricBatchData( QueueName=queue.name, MetricName="ApproximateNumberOfMessagesDelayed", - Value=queue.approx_number_of_messages_delayed, + Value=queue.approximate_number_of_messages_delayed, ) ) @@ -464,7 +465,7 @@ def submit(self, move_task: MessageMoveTask): try: source_queue = self._get_queue_by_arn(move_task.source_arn) move_task.approximate_number_of_messages_to_move = ( - source_queue.approx_number_of_messages + source_queue.approximate_number_of_messages ) move_task.approximate_number_of_messages_moved = 0 move_task.mark_started() @@ -659,6 +660,9 @@ def __init__(self) -> None: self._router_rules = [] self._init_cloudwatch_metrics_reporting() + def accept_state_visitor(self, visitor: StateVisitor): + visitor.visit(sqs_stores) + @staticmethod def get_store(account_id: str, region: str) -> SqsStore: return sqs_stores[account_id][region] @@ -808,6 +812,8 @@ def create_queue( queue = StandardQueue( queue_name, context.region, context.account_id, attributes, tags ) + if tags: + self._tag_queue(queue, tags) LOG.debug("creating queue key=%s attributes=%s tags=%s", queue_name, attributes, tags) @@ -934,6 +940,7 @@ def delete_queue(self, context: RequestContext, queue_url: String, **kwargs) -> store.queues[queue.name].shutdown() del store.queues[queue.name] store.deleted[queue.name] = time.time() + self._remove_all_queue_tags(queue) def get_queue_attributes( self, @@ -1126,7 +1133,7 @@ def receive_message( num = override elif num == -1: # backdoor to get all messages - num = queue.approx_number_of_messages + num = queue.approximate_number_of_messages elif ( num < 1 or num > MAX_NUMBER_OF_MESSAGES ) and not SQS_DISABLE_MAX_NUMBER_OF_MESSAGE_LIMIT: @@ -1269,7 +1276,11 @@ def set_queue_attributes( for k, v in attributes.items(): if k in sqs_constants.INTERNAL_QUEUE_ATTRIBUTES: raise InvalidAttributeName(f"Unknown Attribute {k}.") - queue.attributes[k] = v + if k in sqs_constants.DELETE_IF_DEFAULT and v == sqs_constants.DELETE_IF_DEFAULT[k]: + if k in queue.attributes: + del queue.attributes[k] + else: + queue.attributes[k] = v # Special cases if queue.attributes.get(QueueAttributeName.Policy) == "": @@ -1477,28 +1488,24 @@ def cancel_message_move_task( ) def tag_queue(self, context: RequestContext, queue_url: String, tags: TagMap, **kwargs) -> None: - queue = self._resolve_queue(context, queue_url=queue_url) - if not tags: return - for k, v in tags.items(): - queue.tags[k] = v + queue = self._resolve_queue(context, queue_url=queue_url) + self._tag_queue(queue, tags) def list_queue_tags( self, context: RequestContext, queue_url: String, **kwargs ) -> ListQueueTagsResult: queue = self._resolve_queue(context, queue_url=queue_url) - return ListQueueTagsResult(Tags=(queue.tags if queue.tags else None)) + tags = self._get_queue_tags(queue) + return ListQueueTagsResult(Tags=tags if tags else None) def untag_queue( self, context: RequestContext, queue_url: String, tag_keys: TagKeyList, **kwargs ) -> None: queue = self._resolve_queue(context, queue_url=queue_url) - - for k in tag_keys: - if k in queue.tags: - del queue.tags[k] + self._untag_queue(queue, tag_keys) def add_permission( self, @@ -1636,6 +1643,22 @@ def _stop_cloudwatch_metrics_reporting(self): self._cloudwatch_publish_worker.stop() self._cloudwatch_dispatcher.shutdown() + def _get_queue_tags(self, queue: SqsQueue) -> TagMap: + store = self.get_store(queue.account_id, queue.region) + return store.tags.get_tags(queue.arn) + + def _tag_queue(self, queue: SqsQueue, tags: TagMap) -> None: + store = self.get_store(queue.account_id, queue.region) + store.tags.update_tags(queue.arn, tags) + + def _untag_queue(self, queue: SqsQueue, tag_keys: TagKeyList) -> None: + store = self.get_store(queue.account_id, queue.region) + store.tags.delete_tags(queue.arn, tag_keys) + + def _remove_all_queue_tags(self, queue: SqsQueue) -> None: + store = self.get_store(queue.account_id, queue.region) + store.tags.delete_all_tags(queue.arn) + def resolve_queue_location( context: RequestContext, queue_name: str | None = None, queue_url: str | None = None diff --git a/localstack-core/localstack/services/sqs/queue.py b/localstack-core/localstack/services/sqs/queue.py index dc3b5e8d88f70..ea250191c083b 100644 --- a/localstack-core/localstack/services/sqs/queue.py +++ b/localstack-core/localstack/services/sqs/queue.py @@ -2,15 +2,15 @@ from queue import Empty, PriorityQueue, Queue -class InterruptibleQueue(Queue): +class InterruptibleQueue[T](Queue): # is_shutdown is used to check whether we have triggered a shutdown of the Queue is_shutdown: bool - def __init__(self, maxsize=0): + def __init__(self, maxsize: int = 0): super().__init__(maxsize) self.is_shutdown = False - def get(self, block=True, timeout=None): + def get(self, block: bool = True, timeout: float | None = None) -> T: with self.not_empty: if self.is_shutdown: raise Empty @@ -35,7 +35,7 @@ def get(self, block=True, timeout=None): self.not_full.notify() return item - def shutdown(self): + def shutdown(self) -> None: """ `shutdown` signals to stop all current and future `Queue.get` calls from executing. @@ -46,5 +46,5 @@ def shutdown(self): self.not_empty.notify_all() -class InterruptiblePriorityQueue(PriorityQueue, InterruptibleQueue): +class InterruptiblePriorityQueue[T](PriorityQueue[T], InterruptibleQueue[T]): pass diff --git a/localstack-core/localstack/services/sqs/resource_providers/aws_sqs_queue.py b/localstack-core/localstack/services/sqs/resource_providers/aws_sqs_queue.py index 861449ed53bc5..bf3914c278e76 100644 --- a/localstack-core/localstack/services/sqs/resource_providers/aws_sqs_queue.py +++ b/localstack-core/localstack/services/sqs/resource_providers/aws_sqs_queue.py @@ -2,45 +2,17 @@ from __future__ import annotations import json -from pathlib import Path -from typing import TypedDict import localstack.services.cloudformation.provider_utils as util from localstack.services.cloudformation.resource_provider import ( OperationStatus, ProgressEvent, - ResourceProvider, ResourceRequest, ) - - -class SQSQueueProperties(TypedDict): - Arn: str | None - ContentBasedDeduplication: bool | None - DeduplicationScope: str | None - DelaySeconds: int | None - FifoQueue: bool | None - FifoThroughputLimit: str | None - KmsDataKeyReusePeriodSeconds: int | None - KmsMasterKeyId: str | None - MaximumMessageSize: int | None - MessageRetentionPeriod: int | None - QueueName: str | None - QueueUrl: str | None - ReceiveMessageWaitTimeSeconds: int | None - RedriveAllowPolicy: dict | str | None - RedrivePolicy: dict | str | None - SqsManagedSseEnabled: bool | None - Tags: list[Tag] | None - VisibilityTimeout: int | None - - -class Tag(TypedDict): - Key: str | None - Value: str | None - - -REPEATED_INVOCATION = "repeated_invocation" +from localstack.services.sqs.resource_providers.generated.aws_sqs_queue_base import ( + SQSQueueProperties, + SQSQueueProviderBase, +) _queue_attribute_list = [ "ContentBasedDeduplication", @@ -60,9 +32,35 @@ class Tag(TypedDict): ] -class SQSQueueProvider(ResourceProvider[SQSQueueProperties]): - TYPE = "AWS::SQS::Queue" # Autogenerated. Don't change - SCHEMA = util.get_schema_path(Path(__file__)) # Autogenerated. Don't change +class SQSQueueProvider(SQSQueueProviderBase): + # Values used when a property is removed from a template and needs to be set to its default. + # If AWS changes their defaults in the future, our parity tests should break. + DEFAULT_ATTRIBUTE_VALUES = { + "ReceiveMessageWaitTimeSeconds": "0", + "DelaySeconds": "0", + "KmsMasterKeyId": "", + "RedrivePolicy": "", + "MessageRetentionPeriod": "345600", + "MaximumMessageSize": "262144", # Note: CloudFormation sets this to 256KB on update, but 1MB on create + "VisibilityTimeout": "30", + "KmsDataKeyReusePeriodSeconds": "300", + # Note that "SqsManagedSseEnabled" is deliberately omitted from this list, since AWS + # doesn't seem to reset it to a default. + } + + # Similar for FIFO, but only applied when FifoQueue is true (these can't be set otherwise) + DEFAULT_FIFO_ATTRIBUTE_VALUES = { + "ContentBasedDeduplication": "false", + "DeduplicationScope": "messageGroup", + "FifoThroughputLimit": "perMessageGroupId", + } + + # Private method for creating a unique queue name, if none is specified. + def _autogenerated_queue_name(self, request: ResourceRequest[SQSQueueProperties]) -> str: + queue_name = util.generate_default_name(request.stack_name, request.logical_resource_id) + if self._is_true_property(request.desired_state.get("FifoQueue")): + queue_name = f"{queue_name[:-5]}.fifo" + return queue_name def create( self, @@ -74,8 +72,6 @@ def create( Primary identifier fields: - /properties/QueueUrl - - Create-only properties: - /properties/FifoQueue - /properties/QueueName @@ -92,26 +88,13 @@ def create( - sqs:TagQueue """ - # TODO: validations + # TODO: validations - what validations are needed? model = request.desired_state sqs = request.aws_client_factory.sqs - if model.get("FifoQueue", False): - model["FifoQueue"] = model["FifoQueue"] - - queue_name = model.get("QueueName") - if not queue_name: - # TODO: verify patterns here - if model.get("FifoQueue"): - queue_name = util.generate_default_name( - request.stack_name, request.logical_resource_id - )[:-5] - queue_name = f"{queue_name}.fifo" - else: - queue_name = util.generate_default_name( - request.stack_name, request.logical_resource_id - ) - model["QueueName"] = queue_name + # if no QueueName is specified, automatically generate one + if not model.get("QueueName"): + model["QueueName"] = self._autogenerated_queue_name(request) attributes = self._compile_sqs_queue_attributes(model) result = request.aws_client_factory.sqs.create_queue( @@ -184,38 +167,30 @@ def update( """ sqs = request.aws_client_factory.sqs model = request.desired_state + prev_model = request.previous_state assert request.previous_state is not None - should_replace = ( - request.desired_state.get("QueueName", request.previous_state["QueueName"]) - != request.previous_state["QueueName"] - ) or ( - request.desired_state.get("FifoQueue", request.previous_state.get("FifoQueue")) - != request.previous_state.get("FifoQueue") + queue_url = prev_model["QueueUrl"] + self._populate_missing_attributes_with_defaults(model) + sqs.set_queue_attributes( + QueueUrl=queue_url, Attributes=self._compile_sqs_queue_attributes(model) ) - if not should_replace: - return ProgressEvent(OperationStatus.SUCCESS, resource_model=request.previous_state) - - # TODO: copied from the create handler, extract? - if model.get("FifoQueue"): - queue_name = util.generate_default_name( - request.stack_name, request.logical_resource_id - )[:-5] - queue_name = f"{queue_name}.fifo" - else: - queue_name = util.generate_default_name(request.stack_name, request.logical_resource_id) - - # replacement (TODO: find out if we should handle this in the provider or outside of it) - # delete old queue - sqs.delete_queue(QueueUrl=request.previous_state["QueueUrl"]) - # create new queue (TODO: re-use create logic to make this more robust, e.g. for - # auto-generated queue names) - model["QueueUrl"] = sqs.create_queue(QueueName=queue_name)["QueueUrl"] - model["Arn"] = sqs.get_queue_attributes( - QueueUrl=model["QueueUrl"], AttributeNames=["QueueArn"] - )["Attributes"]["QueueArn"] + (tags_to_remove, tags_to_add_or_update) = util.resource_tags_to_remove_or_update( + prev_model.get("Tags", []), model.get("Tags", []) + ) + sqs.untag_queue(QueueUrl=queue_url, TagKeys=tags_to_remove) + sqs.tag_queue(QueueUrl=queue_url, Tags=tags_to_add_or_update) + + model["QueueUrl"] = queue_url + model["Arn"] = request.previous_state["Arn"] + + # For QueueName and FifoQueue, always use the value from the previous model. These fields + # are create-only, so they cannot be changed via an update (even though they might be omitted) + model["QueueName"] = prev_model.get("QueueName") + model["FifoQueue"] = prev_model.get("FifoQueue", False) + return ProgressEvent(OperationStatus.SUCCESS, resource_model=model) def _compile_sqs_queue_attributes(self, properties: SQSQueueProperties) -> dict[str, str]: @@ -250,6 +225,30 @@ def _compile_sqs_queue_attributes(self, properties: SQSQueueProperties) -> dict[ return result + def _populate_missing_attributes_with_defaults(self, properties: SQSQueueProperties) -> None: + """ + For any attribute that is missing from the desired state, populate it with the default value. + This is the only way to remove an attribute from an existing SQS queue's configuration. + :param properties: the properties passed from cloudformation + """ + for k, v in self.DEFAULT_ATTRIBUTE_VALUES.items(): + properties.setdefault(k, v) + + if self._is_true_property(properties.get("FifoQueue")): + for k, v in self.DEFAULT_FIFO_ATTRIBUTE_VALUES.items(): + properties.setdefault(k, v) + + def _is_true_property(self, property_value: str | None) -> bool: + """ + Detect whether a 'true' value is passed in a property. If it's None (property was omitted) or False, or any + type of string (e.g. a typo such as "Fasle"), then it's not a true value. This extra check is needed because + the CloudFormation engine doesn't fully validate booleans properties before passing them to the resource provider. + """ + return ( + property_value == True # noqa: E712 + or (isinstance(property_value, str) and property_value.lower() == "true") + ) + def list( self, request: ResourceRequest[SQSQueueProperties], diff --git a/localstack-core/localstack/services/sqs/resource_providers/aws_sqs_queueinlinepolicy.py b/localstack-core/localstack/services/sqs/resource_providers/aws_sqs_queueinlinepolicy.py new file mode 100644 index 0000000000000..3ef15877a8da1 --- /dev/null +++ b/localstack-core/localstack/services/sqs/resource_providers/aws_sqs_queueinlinepolicy.py @@ -0,0 +1,76 @@ +# LocalStack Resource Provider Scaffolding v2 +import json + +from localstack.services.cloudformation.resource_provider import ( + OperationStatus, + ProgressEvent, + ResourceRequest, +) +from localstack.services.sqs.resource_providers.generated.aws_sqs_queueinlinepolicy_base import ( + SQSQueueInlinePolicyProperties, + SQSQueueInlinePolicyProviderBase, +) + + +class SQSQueueInlinePolicyProvider(SQSQueueInlinePolicyProviderBase): + def create( + self, + request: ResourceRequest[SQSQueueInlinePolicyProperties], + ) -> ProgressEvent[SQSQueueInlinePolicyProperties]: + model = request.desired_state + sqs = request.aws_client_factory.sqs + + queue = model.get("Queue") + policy = model.get("PolicyDocument") + sqs.set_queue_attributes(QueueUrl=queue, Attributes={"Policy": json.dumps(policy)}) + + return ProgressEvent( + status=OperationStatus.SUCCESS, + resource_model=model, + custom_context=request.custom_context, + ) + + def read( + self, + request: ResourceRequest[SQSQueueInlinePolicyProperties], + ) -> ProgressEvent[SQSQueueInlinePolicyProperties]: + raise NotImplementedError + + def delete( + self, + request: ResourceRequest[SQSQueueInlinePolicyProperties], + ) -> ProgressEvent[SQSQueueInlinePolicyProperties]: + model = request.desired_state + sqs = request.aws_client_factory.sqs + + queue = model.get("Queue") + sqs.set_queue_attributes(QueueUrl=queue, Attributes={"Policy": ""}) + + return ProgressEvent(status=OperationStatus.SUCCESS, resource_model={}) + + def update( + self, + request: ResourceRequest[SQSQueueInlinePolicyProperties], + ) -> ProgressEvent[SQSQueueInlinePolicyProperties]: + model = request.desired_state + sqs = request.aws_client_factory.sqs + + queue = model.get("Queue") + policy = model.get("PolicyDocument") + sqs.set_queue_attributes(QueueUrl=queue, Attributes={"Policy": json.dumps(policy)}) + + return ProgressEvent( + status=OperationStatus.SUCCESS, + resource_model=model, + custom_context=request.custom_context, + ) + + def list( + self, + request: ResourceRequest[SQSQueueInlinePolicyProperties], + ) -> ProgressEvent[SQSQueueInlinePolicyProperties]: + """ + List available resources of this type + + """ + raise NotImplementedError diff --git a/localstack-core/localstack/services/sqs/resource_providers/aws_sqs_queuepolicy.py b/localstack-core/localstack/services/sqs/resource_providers/aws_sqs_queuepolicy.py index 4c29b3e000fb2..397eb6719e9a3 100644 --- a/localstack-core/localstack/services/sqs/resource_providers/aws_sqs_queuepolicy.py +++ b/localstack-core/localstack/services/sqs/resource_providers/aws_sqs_queuepolicy.py @@ -1,49 +1,25 @@ # LocalStack Resource Provider Scaffolding v2 -from __future__ import annotations - import json -from pathlib import Path -from typing import TypedDict import localstack.services.cloudformation.provider_utils as util from localstack.services.cloudformation.resource_provider import ( OperationStatus, ProgressEvent, - ResourceProvider, ResourceRequest, ) +from localstack.services.sqs.resource_providers.generated.aws_sqs_queuepolicy_base import ( + SQSQueuePolicyProperties, + SQSQueuePolicyProviderBase, +) -class SQSQueuePolicyProperties(TypedDict): - PolicyDocument: dict | None - Queues: list[str] | None - Id: str | None - - -REPEATED_INVOCATION = "repeated_invocation" - - -class SQSQueuePolicyProvider(ResourceProvider[SQSQueuePolicyProperties]): - TYPE = "AWS::SQS::QueuePolicy" # Autogenerated. Don't change - SCHEMA = util.get_schema_path(Path(__file__)) # Autogenerated. Don't change - +class SQSQueuePolicyProvider(SQSQueuePolicyProviderBase): def create( self, request: ResourceRequest[SQSQueuePolicyProperties], ) -> ProgressEvent[SQSQueuePolicyProperties]: """ Create a new resource. - - Primary identifier fields: - - /properties/Id - - Required properties: - - PolicyDocument - - Queues - - Read-only properties: - - /properties/Id - """ model = request.desired_state sqs = request.aws_client_factory.sqs @@ -100,13 +76,31 @@ def update( """ model = request.desired_state sqs = request.aws_client_factory.sqs - for queue in model.get("Queues", []): + + # handle new/updated queues + desired_queues = model.get("Queues", []) + for queue in desired_queues: policy = json.dumps(model["PolicyDocument"]) sqs.set_queue_attributes(QueueUrl=queue, Attributes={"Policy": policy}) + # handle queues no longer in the desired state + previous_queues = request.previous_state.get("Queues", []) + outdated_queues = set(previous_queues) - set(desired_queues) + for queue in outdated_queues: + sqs.set_queue_attributes(QueueUrl=queue, Attributes={"Policy": ""}) + model["Id"] = request.previous_state["Id"] return ProgressEvent( status=OperationStatus.SUCCESS, resource_model=model, ) + + def list( + self, + request: ResourceRequest[SQSQueuePolicyProperties], + ) -> ProgressEvent[SQSQueuePolicyProperties]: + """ + List available resources of this type + """ + raise NotImplementedError diff --git a/localstack-core/localstack/services/sqs/resource_providers/aws_sqs_queuepolicy.schema.json b/localstack-core/localstack/services/sqs/resource_providers/aws_sqs_queuepolicy.schema.json deleted file mode 100644 index 654910643709d..0000000000000 --- a/localstack-core/localstack/services/sqs/resource_providers/aws_sqs_queuepolicy.schema.json +++ /dev/null @@ -1,30 +0,0 @@ -{ - "typeName": "AWS::SQS::QueuePolicy", - "description": "Resource Type definition for AWS::SQS::QueuePolicy", - "additionalProperties": false, - "properties": { - "Id": { - "type": "string" - }, - "PolicyDocument": { - "type": "object" - }, - "Queues": { - "type": "array", - "uniqueItems": false, - "items": { - "type": "string" - } - } - }, - "required": [ - "PolicyDocument", - "Queues" - ], - "primaryIdentifier": [ - "/properties/Id" - ], - "readOnlyProperties": [ - "/properties/Id" - ] -} diff --git a/tests/aws/services/stepfunctions/mocked_service_integrations/__init__.py b/localstack-core/localstack/services/sqs/resource_providers/generated/__init__.py similarity index 100% rename from tests/aws/services/stepfunctions/mocked_service_integrations/__init__.py rename to localstack-core/localstack/services/sqs/resource_providers/generated/__init__.py diff --git a/localstack-core/localstack/services/sqs/resource_providers/aws_sqs_queue.schema.json b/localstack-core/localstack/services/sqs/resource_providers/generated/aws_sqs_queue.schema.json similarity index 97% rename from localstack-core/localstack/services/sqs/resource_providers/aws_sqs_queue.schema.json rename to localstack-core/localstack/services/sqs/resource_providers/generated/aws_sqs_queue.schema.json index 0756d0bfb2b07..e5d96f59901bb 100644 --- a/localstack-core/localstack/services/sqs/resource_providers/aws_sqs_queue.schema.json +++ b/localstack-core/localstack/services/sqs/resource_providers/generated/aws_sqs_queue.schema.json @@ -123,8 +123,13 @@ "taggable": true, "tagOnCreate": true, "tagUpdatable": true, - "cloudFormationSystemTags": true, - "tagProperty": "/properties/Tags" + "cloudFormationSystemTags": false, + "tagProperty": "/properties/Tags", + "permissions": [ + "sqs:TagQueue", + "sqs:UntagQueue", + "sqs:ListQueueTags" + ] }, "handlers": { "create": { diff --git a/localstack-core/localstack/services/sqs/resource_providers/generated/aws_sqs_queue_base.py b/localstack-core/localstack/services/sqs/resource_providers/generated/aws_sqs_queue_base.py new file mode 100644 index 0000000000000..289d1679531ce --- /dev/null +++ b/localstack-core/localstack/services/sqs/resource_providers/generated/aws_sqs_queue_base.py @@ -0,0 +1,139 @@ +# LocalStack Resource Provider Base Class Scaffolding v2 +# +# AUTOGENERATED FILE - DO NOT EDIT +# + +from __future__ import annotations + +from abc import ABC, abstractmethod +from pathlib import Path +from typing import TypedDict + +import localstack.services.cloudformation.provider_utils as util +from localstack.services.cloudformation.resource_provider import ( + ProgressEvent, + ResourceProvider, + ResourceRequest, +) + + +class SQSQueueProperties(TypedDict): + Arn: str | None + ContentBasedDeduplication: bool | None + DeduplicationScope: str | None + DelaySeconds: int | None + FifoQueue: bool | None + FifoThroughputLimit: str | None + KmsDataKeyReusePeriodSeconds: int | None + KmsMasterKeyId: str | None + MaximumMessageSize: int | None + MessageRetentionPeriod: int | None + QueueName: str | None + QueueUrl: str | None + ReceiveMessageWaitTimeSeconds: int | None + RedriveAllowPolicy: dict | str | None + RedrivePolicy: dict | str | None + SqsManagedSseEnabled: bool | None + Tags: list[Tag] | None + VisibilityTimeout: int | None + + +class Tag(TypedDict): + Key: str | None + Value: str | None + + +REPEATED_INVOCATION = "repeated_invocation" + + +class SQSQueueProviderBase(ResourceProvider[SQSQueueProperties], ABC): + TYPE = "AWS::SQS::Queue" # Autogenerated. Don't change + SCHEMA = util.get_schema_path(Path(__file__)) # Autogenerated. Don't change + + @abstractmethod + def create( + self, + request: ResourceRequest[SQSQueueProperties], + ) -> ProgressEvent[SQSQueueProperties]: + """ + Create a new resource. + + Primary identifier fields: + - /properties/QueueUrl + + + + Create-only properties: + - /properties/FifoQueue + - /properties/QueueName + + Read-only properties: + - /properties/QueueUrl + - /properties/Arn + + IAM permissions required: + - sqs:CreateQueue + - sqs:GetQueueUrl + - sqs:GetQueueAttributes + - sqs:ListQueueTags + - sqs:TagQueue + + """ + raise NotImplementedError + + @abstractmethod + def read( + self, + request: ResourceRequest[SQSQueueProperties], + ) -> ProgressEvent[SQSQueueProperties]: + """ + Fetch resource information + + IAM permissions required: + - sqs:GetQueueAttributes + - sqs:ListQueueTags + """ + raise NotImplementedError + + @abstractmethod + def delete( + self, + request: ResourceRequest[SQSQueueProperties], + ) -> ProgressEvent[SQSQueueProperties]: + """ + Delete a resource + + IAM permissions required: + - sqs:DeleteQueue + - sqs:GetQueueAttributes + """ + raise NotImplementedError + + @abstractmethod + def update( + self, + request: ResourceRequest[SQSQueueProperties], + ) -> ProgressEvent[SQSQueueProperties]: + """ + Update a resource + + IAM permissions required: + - sqs:SetQueueAttributes + - sqs:GetQueueAttributes + - sqs:ListQueueTags + - sqs:TagQueue + - sqs:UntagQueue + """ + raise NotImplementedError + + @abstractmethod + def list( + self, + request: ResourceRequest[SQSQueueProperties], + ) -> ProgressEvent[SQSQueueProperties]: + """ + List available resources of this type + IAM permissions required: + - sqs:ListQueues + """ + raise NotImplementedError diff --git a/localstack-core/localstack/services/sqs/resource_providers/aws_sqs_queue_plugin.py b/localstack-core/localstack/services/sqs/resource_providers/generated/aws_sqs_queue_plugin.py similarity index 92% rename from localstack-core/localstack/services/sqs/resource_providers/aws_sqs_queue_plugin.py rename to localstack-core/localstack/services/sqs/resource_providers/generated/aws_sqs_queue_plugin.py index e71ec95f4f0b5..0da1d17979fdb 100644 --- a/localstack-core/localstack/services/sqs/resource_providers/aws_sqs_queue_plugin.py +++ b/localstack-core/localstack/services/sqs/resource_providers/generated/aws_sqs_queue_plugin.py @@ -1,3 +1,7 @@ +# +# AUTOGENERATED FILE - DO NOT EDIT +# + from localstack.services.cloudformation.resource_provider import ( CloudFormationResourceProviderPlugin, ResourceProvider, diff --git a/localstack-core/localstack/services/sqs/resource_providers/generated/aws_sqs_queueinlinepolicy.schema.json b/localstack-core/localstack/services/sqs/resource_providers/generated/aws_sqs_queueinlinepolicy.schema.json new file mode 100644 index 0000000000000..6093c0943f49f --- /dev/null +++ b/localstack-core/localstack/services/sqs/resource_providers/generated/aws_sqs_queueinlinepolicy.schema.json @@ -0,0 +1,60 @@ +{ + "typeName": "AWS::SQS::QueueInlinePolicy", + "description": "Schema for SQS QueueInlinePolicy", + "sourceUrl": "https://github.com/aws-cloudformation/aws-cloudformation-resource-providers-sqs.git", + "properties": { + "PolicyDocument": { + "description": "A policy document that contains permissions to add to the specified SQS queue", + "type": "object" + }, + "Queue": { + "description": "The URL of the SQS queue.", + "type": "string" + } + }, + "additionalProperties": false, + "tagging": { + "taggable": false, + "tagOnCreate": false, + "tagUpdatable": false, + "cloudFormationSystemTags": false + }, + "required": [ + "PolicyDocument", + "Queue" + ], + "primaryIdentifier": [ + "/properties/Queue" + ], + "createOnlyProperties": [ + "/properties/Queue" + ], + "handlers": { + "create": { + "permissions": [ + "sqs:SetQueueAttributes", + "sqs:GetQueueAttributes", + "sqs:GetQueueUrl" + ] + }, + "read": { + "permissions": [ + "sqs:GetQueueAttributes", + "sqs:GetQueueUrl" + ] + }, + "delete": { + "permissions": [ + "sqs:SetQueueAttributes", + "sqs:GetQueueAttributes" + ] + }, + "update": { + "permissions": [ + "sqs:SetQueueAttributes", + "sqs:GetQueueAttributes", + "sqs:GetQueueUrl" + ] + } + } +} diff --git a/localstack-core/localstack/services/sqs/resource_providers/generated/aws_sqs_queueinlinepolicy_base.py b/localstack-core/localstack/services/sqs/resource_providers/generated/aws_sqs_queueinlinepolicy_base.py new file mode 100644 index 0000000000000..f336f341ae1cc --- /dev/null +++ b/localstack-core/localstack/services/sqs/resource_providers/generated/aws_sqs_queueinlinepolicy_base.py @@ -0,0 +1,112 @@ +# LocalStack Resource Provider Base Class Scaffolding v2 +# +# AUTOGENERATED FILE - DO NOT EDIT +# + +from __future__ import annotations + +from abc import ABC, abstractmethod +from pathlib import Path +from typing import TypedDict + +import localstack.services.cloudformation.provider_utils as util +from localstack.services.cloudformation.resource_provider import ( + ProgressEvent, + ResourceProvider, + ResourceRequest, +) + + +class SQSQueueInlinePolicyProperties(TypedDict): + PolicyDocument: dict | None + Queue: str | None + + +REPEATED_INVOCATION = "repeated_invocation" + + +class SQSQueueInlinePolicyProviderBase(ResourceProvider[SQSQueueInlinePolicyProperties], ABC): + TYPE = "AWS::SQS::QueueInlinePolicy" # Autogenerated. Don't change + SCHEMA = util.get_schema_path(Path(__file__)) # Autogenerated. Don't change + + @abstractmethod + def create( + self, + request: ResourceRequest[SQSQueueInlinePolicyProperties], + ) -> ProgressEvent[SQSQueueInlinePolicyProperties]: + """ + Create a new resource. + + Primary identifier fields: + - /properties/Queue + + Required properties: + - PolicyDocument + - Queue + + Create-only properties: + - /properties/Queue + + + + IAM permissions required: + - sqs:SetQueueAttributes + - sqs:GetQueueAttributes + - sqs:GetQueueUrl + + """ + raise NotImplementedError + + @abstractmethod + def read( + self, + request: ResourceRequest[SQSQueueInlinePolicyProperties], + ) -> ProgressEvent[SQSQueueInlinePolicyProperties]: + """ + Fetch resource information + + IAM permissions required: + - sqs:GetQueueAttributes + - sqs:GetQueueUrl + """ + raise NotImplementedError + + @abstractmethod + def delete( + self, + request: ResourceRequest[SQSQueueInlinePolicyProperties], + ) -> ProgressEvent[SQSQueueInlinePolicyProperties]: + """ + Delete a resource + + IAM permissions required: + - sqs:SetQueueAttributes + - sqs:GetQueueAttributes + """ + raise NotImplementedError + + @abstractmethod + def update( + self, + request: ResourceRequest[SQSQueueInlinePolicyProperties], + ) -> ProgressEvent[SQSQueueInlinePolicyProperties]: + """ + Update a resource + + IAM permissions required: + - sqs:SetQueueAttributes + - sqs:GetQueueAttributes + - sqs:GetQueueUrl + """ + raise NotImplementedError + + @abstractmethod + def list( + self, + request: ResourceRequest[SQSQueueInlinePolicyProperties], + ) -> ProgressEvent[SQSQueueInlinePolicyProperties]: + """ + List available resources of this type + + """ + raise NotImplementedError diff --git a/localstack-core/localstack/services/sqs/resource_providers/generated/aws_sqs_queueinlinepolicy_plugin.py b/localstack-core/localstack/services/sqs/resource_providers/generated/aws_sqs_queueinlinepolicy_plugin.py new file mode 100644 index 0000000000000..bcc7af85d1916 --- /dev/null +++ b/localstack-core/localstack/services/sqs/resource_providers/generated/aws_sqs_queueinlinepolicy_plugin.py @@ -0,0 +1,22 @@ +# +# AUTOGENERATED FILE - DO NOT EDIT +# + +from localstack.services.cloudformation.resource_provider import ( + CloudFormationResourceProviderPlugin, + ResourceProvider, +) + + +class SQSQueueInlinePolicyProviderPlugin(CloudFormationResourceProviderPlugin): + name = "AWS::SQS::QueueInlinePolicy" + + def __init__(self): + self.factory: type[ResourceProvider] | None = None + + def load(self): + from localstack.services.sqs.resource_providers.aws_sqs_queueinlinepolicy import ( + SQSQueueInlinePolicyProvider, + ) + + self.factory = SQSQueueInlinePolicyProvider diff --git a/localstack-core/localstack/services/sqs/resource_providers/generated/aws_sqs_queuepolicy.schema.json b/localstack-core/localstack/services/sqs/resource_providers/generated/aws_sqs_queuepolicy.schema.json new file mode 100644 index 0000000000000..5924a0637eef7 --- /dev/null +++ b/localstack-core/localstack/services/sqs/resource_providers/generated/aws_sqs_queuepolicy.schema.json @@ -0,0 +1,61 @@ +{ + "typeName": "AWS::SQS::QueuePolicy", + "description": "Resource Type definition for AWS::SQS::QueuePolicy", + "sourceUrl": "https://github.com/aws-cloudformation/aws-cloudformation-resource-providers-sqs.git", + "additionalProperties": false, + "properties": { + "Id": { + "type": "string", + "description": "The provider-assigned unique ID for this managed resource." + }, + "PolicyDocument": { + "type": [ + "object", + "string" + ], + "description": "A policy document that contains the permissions for the specified Amazon SQS queues. For more information about Amazon SQS policies, see Creating Custom Policies Using the Access Policy Language in the Amazon Simple Queue Service Developer Guide." + }, + "Queues": { + "type": "array", + "description": "The URLs of the queues to which you want to add the policy. You can use the Ref function to specify an AWS::SQS::Queue resource.", + "uniqueItems": false, + "insertionOrder": false, + "items": { + "type": "string" + } + } + }, + "required": [ + "PolicyDocument", + "Queues" + ], + "primaryIdentifier": [ + "/properties/Id" + ], + "readOnlyProperties": [ + "/properties/Id" + ], + "tagging": { + "taggable": false, + "tagOnCreate": false, + "tagUpdatable": false, + "cloudFormationSystemTags": false + }, + "handlers": { + "create": { + "permissions": [ + "sqs:SetQueueAttributes" + ] + }, + "update": { + "permissions": [ + "sqs:SetQueueAttributes" + ] + }, + "delete": { + "permissions": [ + "sqs:SetQueueAttributes" + ] + } + } +} diff --git a/localstack-core/localstack/services/sqs/resource_providers/generated/aws_sqs_queuepolicy_base.py b/localstack-core/localstack/services/sqs/resource_providers/generated/aws_sqs_queuepolicy_base.py new file mode 100644 index 0000000000000..c057ce766d17d --- /dev/null +++ b/localstack-core/localstack/services/sqs/resource_providers/generated/aws_sqs_queuepolicy_base.py @@ -0,0 +1,106 @@ +# LocalStack Resource Provider Base Class Scaffolding v2 +# +# AUTOGENERATED FILE - DO NOT EDIT +# + +from __future__ import annotations + +from abc import ABC, abstractmethod +from pathlib import Path +from typing import TypedDict + +import localstack.services.cloudformation.provider_utils as util +from localstack.services.cloudformation.resource_provider import ( + ProgressEvent, + ResourceProvider, + ResourceRequest, +) + + +class SQSQueuePolicyProperties(TypedDict): + PolicyDocument: dict | str | None + Queues: list[str] | None + Id: str | None + + +REPEATED_INVOCATION = "repeated_invocation" + + +class SQSQueuePolicyProviderBase(ResourceProvider[SQSQueuePolicyProperties], ABC): + TYPE = "AWS::SQS::QueuePolicy" # Autogenerated. Don't change + SCHEMA = util.get_schema_path(Path(__file__)) # Autogenerated. Don't change + + @abstractmethod + def create( + self, + request: ResourceRequest[SQSQueuePolicyProperties], + ) -> ProgressEvent[SQSQueuePolicyProperties]: + """ + Create a new resource. + + Primary identifier fields: + - /properties/Id + + Required properties: + - PolicyDocument + - Queues + + + + Read-only properties: + - /properties/Id + + IAM permissions required: + - sqs:SetQueueAttributes + + """ + raise NotImplementedError + + @abstractmethod + def read( + self, + request: ResourceRequest[SQSQueuePolicyProperties], + ) -> ProgressEvent[SQSQueuePolicyProperties]: + """ + Fetch resource information + + + """ + raise NotImplementedError + + @abstractmethod + def delete( + self, + request: ResourceRequest[SQSQueuePolicyProperties], + ) -> ProgressEvent[SQSQueuePolicyProperties]: + """ + Delete a resource + + IAM permissions required: + - sqs:SetQueueAttributes + """ + raise NotImplementedError + + @abstractmethod + def update( + self, + request: ResourceRequest[SQSQueuePolicyProperties], + ) -> ProgressEvent[SQSQueuePolicyProperties]: + """ + Update a resource + + IAM permissions required: + - sqs:SetQueueAttributes + """ + raise NotImplementedError + + @abstractmethod + def list( + self, + request: ResourceRequest[SQSQueuePolicyProperties], + ) -> ProgressEvent[SQSQueuePolicyProperties]: + """ + List available resources of this type + + """ + raise NotImplementedError diff --git a/localstack-core/localstack/services/sqs/resource_providers/aws_sqs_queuepolicy_plugin.py b/localstack-core/localstack/services/sqs/resource_providers/generated/aws_sqs_queuepolicy_plugin.py similarity index 92% rename from localstack-core/localstack/services/sqs/resource_providers/aws_sqs_queuepolicy_plugin.py rename to localstack-core/localstack/services/sqs/resource_providers/generated/aws_sqs_queuepolicy_plugin.py index 8f656bea99512..1b05883131c65 100644 --- a/localstack-core/localstack/services/sqs/resource_providers/aws_sqs_queuepolicy_plugin.py +++ b/localstack-core/localstack/services/sqs/resource_providers/generated/aws_sqs_queuepolicy_plugin.py @@ -1,3 +1,7 @@ +# +# AUTOGENERATED FILE - DO NOT EDIT +# + from localstack.services.cloudformation.resource_provider import ( CloudFormationResourceProviderPlugin, ResourceProvider, diff --git a/localstack-core/localstack/services/ssm/provider.py b/localstack-core/localstack/services/ssm/provider.py index 8e2b91371eac8..6c1d0c7d1a2fa 100644 --- a/localstack-core/localstack/services/ssm/provider.py +++ b/localstack-core/localstack/services/ssm/provider.py @@ -78,6 +78,7 @@ ) from localstack.aws.connect import connect_to from localstack.services.moto import call_moto, call_moto_with_request +from localstack.state import StateVisitor from localstack.utils.aws.arns import extract_resource_from_arn, is_arn from localstack.utils.bootstrap import is_api_enabled from localstack.utils.collections import remove_attributes @@ -105,6 +106,11 @@ def __init__(self): # TODO: check if _normalize_name(..) calls are still required here class SsmProvider(SsmApi, ABC): + def accept_state_visitor(self, visitor: StateVisitor): + from moto.ssm.models import ssm_backends + + visitor.visit(ssm_backends) + def get_parameters( self, context: RequestContext, diff --git a/localstack-core/localstack/services/stepfunctions/asl/component/common/path/result_path.py b/localstack-core/localstack/services/stepfunctions/asl/component/common/path/result_path.py index 67224ed145652..f08fdf1637fd1 100644 --- a/localstack-core/localstack/services/stepfunctions/asl/component/common/path/result_path.py +++ b/localstack-core/localstack/services/stepfunctions/asl/component/common/path/result_path.py @@ -18,7 +18,7 @@ def __init__(self, result_path_src: str | None): def _eval_body(self, env: Environment) -> None: state_input = env.states.get_input() - # Discard task output if there is one, and set the output ot be the state's input. + # Discard task output if there is one, and set the output to be the state's input. if self.result_path_src is None: env.stack.clear() env.stack.append(state_input) diff --git a/localstack-core/localstack/services/stepfunctions/asl/component/state/state.py b/localstack-core/localstack/services/stepfunctions/asl/component/state/state.py index fe28c07e41e44..3c63a235aef63 100644 --- a/localstack-core/localstack/services/stepfunctions/asl/component/state/state.py +++ b/localstack-core/localstack/services/stepfunctions/asl/component/state/state.py @@ -134,7 +134,7 @@ def _set_next(self, env: Environment) -> None: else: LOG.error("Could not handle ContinueWith type of '%s'.", type(self.continue_with)) - def _is_language_query_jsonpath(self) -> bool: + def is_jsonpath_query_language(self) -> bool: return self.query_language.query_language_mode == QueryLanguageMode.JSONPath def _get_state_entered_event_details(self, env: Environment) -> StateEnteredEventDetails: diff --git a/localstack-core/localstack/services/stepfunctions/asl/component/state/state_choice/state_choice.py b/localstack-core/localstack/services/stepfunctions/asl/component/state/state_choice/state_choice.py index a0e84ef6f170b..2f4bd50b26eac 100644 --- a/localstack-core/localstack/services/stepfunctions/asl/component/state/state_choice/state_choice.py +++ b/localstack-core/localstack/services/stepfunctions/asl/component/state/state_choice/state_choice.py @@ -66,7 +66,7 @@ def _eval_state_output(self, env: Environment) -> None: self.output.eval(env=env) # Handle legacy output sequences if in JsonPath mode. - if self._is_language_query_jsonpath(): + if self.is_jsonpath_query_language(): if self.output_path: self.output_path.eval(env=env) else: diff --git a/localstack-core/localstack/services/stepfunctions/asl/component/state/state_execution/execute_state.py b/localstack-core/localstack/services/stepfunctions/asl/component/state/state_execution/execute_state.py index ac1a441fd2c33..ee8025370db6d 100644 --- a/localstack-core/localstack/services/stepfunctions/asl/component/state/state_execution/execute_state.py +++ b/localstack-core/localstack/services/stepfunctions/asl/component/state/state_execution/execute_state.py @@ -200,7 +200,7 @@ def _exec_and_notify(): execution_output = execution_outputs.pop() env.stack.append(execution_output) - if not self._is_language_query_jsonpath(): + if not self.is_jsonpath_query_language(): env.states.set_result(execution_output) if self.assign_decl: @@ -251,7 +251,6 @@ def _eval_state(self, env: Environment) -> None: ) error_output = self._construct_error_output_value(failure_event=failure_event) env.states.set_error_output(error_output) - env.states.set_result(error_output) if self.retry: retry_outcome: RetryOutcome = self._handle_retry( diff --git a/localstack-core/localstack/services/stepfunctions/asl/component/state/state_execution/state_map/state_map.py b/localstack-core/localstack/services/stepfunctions/asl/component/state/state_execution/state_map/state_map.py index a49beeac19c1a..80a0bbbbbff8d 100644 --- a/localstack-core/localstack/services/stepfunctions/asl/component/state/state_execution/state_map/state_map.py +++ b/localstack-core/localstack/services/stepfunctions/asl/component/state/state_execution/state_map/state_map.py @@ -122,7 +122,7 @@ def __init__(self): def from_state_props(self, state_props: StateProps) -> None: super().from_state_props(state_props) - if self._is_language_query_jsonpath(): + if self.is_jsonpath_query_language(): self.items = None self.items_path = state_props.get(ItemsPath) or ItemsPath( string_sampler=StringJsonPath(JSONPATH_ROOT_PATH) @@ -311,7 +311,6 @@ def _eval_state(self, env: Environment) -> None: failure_event: FailureEvent = self._from_error(env=env, ex=ex) error_output = self._construct_error_output_value(failure_event=failure_event) env.states.set_error_output(error_output) - env.states.set_result(error_output) if self.retry: retry_outcome: RetryOutcome = self._handle_retry( diff --git a/localstack-core/localstack/services/stepfunctions/asl/component/state/state_execution/state_task/lambda_eval_utils.py b/localstack-core/localstack/services/stepfunctions/asl/component/state/state_execution/state_task/lambda_eval_utils.py index 4f331a11ace76..f88dc1d950276 100644 --- a/localstack-core/localstack/services/stepfunctions/asl/component/state/state_execution/state_task/lambda_eval_utils.py +++ b/localstack-core/localstack/services/stepfunctions/asl/component/state/state_execution/state_task/lambda_eval_utils.py @@ -6,13 +6,13 @@ from localstack.services.stepfunctions.asl.component.state.state_execution.state_task.credentials import ( StateCredentials, ) -from localstack.services.stepfunctions.asl.component.state.state_execution.state_task.mock_eval_utils import ( - eval_mocked_response, +from localstack.services.stepfunctions.asl.component.state.state_execution.state_task.local_mock_eval_utils import ( + eval_local_mocked_response, ) from localstack.services.stepfunctions.asl.eval.environment import Environment from localstack.services.stepfunctions.asl.utils.boto_client import boto_client_for from localstack.services.stepfunctions.asl.utils.encoding import to_json_str -from localstack.services.stepfunctions.mocking.mock_config import MockedResponse +from localstack.services.stepfunctions.local_mocking.mock_config import LocalMockedResponse from localstack.utils.collections import select_from_typed_dict from localstack.utils.strings import to_bytes @@ -42,9 +42,9 @@ def _from_payload(payload_streaming_body: IO[bytes]) -> Any | str: return decoded_data -def _mocked_invoke_lambda_function(env: Environment) -> InvocationResponse: - mocked_response: MockedResponse = env.get_current_mocked_response() - eval_mocked_response(env=env, mocked_response=mocked_response) +def _local_mocked_invoke_lambda_function(env: Environment) -> InvocationResponse: + mocked_response: LocalMockedResponse = env.get_current_local_mocked_response() + eval_local_mocked_response(env=env, mocked_response=mocked_response) invocation_resp: InvocationResponse = env.stack.pop() return invocation_resp @@ -68,8 +68,8 @@ def _invoke_lambda_function( def execute_lambda_function_integration( env: Environment, parameters: dict, region: str, state_credentials: StateCredentials ) -> None: - if env.is_mocked_mode(): - invocation_response: InvocationResponse = _mocked_invoke_lambda_function(env=env) + if env.is_local_mocked_mode(): + invocation_response: InvocationResponse = _local_mocked_invoke_lambda_function(env=env) else: invocation_response: InvocationResponse = _invoke_lambda_function( parameters=parameters, region=region, state_credentials=state_credentials diff --git a/localstack-core/localstack/services/stepfunctions/asl/component/state/state_execution/state_task/mock_eval_utils.py b/localstack-core/localstack/services/stepfunctions/asl/component/state/state_execution/state_task/local_mock_eval_utils.py similarity index 69% rename from localstack-core/localstack/services/stepfunctions/asl/component/state/state_execution/state_task/mock_eval_utils.py rename to localstack-core/localstack/services/stepfunctions/asl/component/state/state_execution/state_task/local_mock_eval_utils.py index aa8a9c423f433..2ed6e2287e7a2 100644 --- a/localstack-core/localstack/services/stepfunctions/asl/component/state/state_execution/state_task/mock_eval_utils.py +++ b/localstack-core/localstack/services/stepfunctions/asl/component/state/state_execution/state_task/local_mock_eval_utils.py @@ -10,14 +10,16 @@ ) from localstack.services.stepfunctions.asl.eval.environment import Environment from localstack.services.stepfunctions.asl.eval.event.event_detail import EventDetails -from localstack.services.stepfunctions.mocking.mock_config import ( - MockedResponse, - MockedResponseReturn, - MockedResponseThrow, +from localstack.services.stepfunctions.local_mocking.mock_config import ( + LocalMockedResponse, + LocalMockedResponseReturn, + LocalMockedResponseThrow, ) -def _eval_mocked_response_throw(env: Environment, mocked_response: MockedResponseThrow) -> None: +def _eval_mocked_response_throw( + env: Environment, mocked_response: LocalMockedResponseThrow +) -> None: task_failed_event_details = TaskFailedEventDetails( error=mocked_response.error, cause=mocked_response.cause ) @@ -31,15 +33,17 @@ def _eval_mocked_response_throw(env: Environment, mocked_response: MockedRespons raise FailureEventException(failure_event=failure_event) -def _eval_mocked_response_return(env: Environment, mocked_response: MockedResponseReturn) -> None: +def _eval_mocked_response_return( + env: Environment, mocked_response: LocalMockedResponseReturn +) -> None: payload_copy = copy.deepcopy(mocked_response.payload) env.stack.append(payload_copy) -def eval_mocked_response(env: Environment, mocked_response: MockedResponse) -> None: - if isinstance(mocked_response, MockedResponseReturn): +def eval_local_mocked_response(env: Environment, mocked_response: LocalMockedResponse) -> None: + if isinstance(mocked_response, LocalMockedResponseReturn): _eval_mocked_response_return(env=env, mocked_response=mocked_response) - elif isinstance(mocked_response, MockedResponseThrow): + elif isinstance(mocked_response, LocalMockedResponseThrow): _eval_mocked_response_throw(env=env, mocked_response=mocked_response) else: raise RuntimeError(f"Invalid MockedResponse type '{type(mocked_response)}'") diff --git a/localstack-core/localstack/services/stepfunctions/asl/component/state/state_execution/state_task/service/state_task_service.py b/localstack-core/localstack/services/stepfunctions/asl/component/state/state_execution/state_task/service/state_task_service.py index 1812657450f2e..1768833567680 100644 --- a/localstack-core/localstack/services/stepfunctions/asl/component/state/state_execution/state_task/service/state_task_service.py +++ b/localstack-core/localstack/services/stepfunctions/asl/component/state/state_execution/state_task/service/state_task_service.py @@ -33,8 +33,8 @@ from localstack.services.stepfunctions.asl.component.state.state_execution.state_task.credentials import ( StateCredentials, ) -from localstack.services.stepfunctions.asl.component.state.state_execution.state_task.mock_eval_utils import ( - eval_mocked_response, +from localstack.services.stepfunctions.asl.component.state.state_execution.state_task.local_mock_eval_utils import ( + eval_local_mocked_response, ) from localstack.services.stepfunctions.asl.component.state.state_execution.state_task.service.resource import ( ResourceRuntimePart, @@ -47,7 +47,7 @@ from localstack.services.stepfunctions.asl.eval.environment import Environment from localstack.services.stepfunctions.asl.eval.event.event_detail import EventDetails from localstack.services.stepfunctions.asl.utils.encoding import to_json_str -from localstack.services.stepfunctions.mocking.mock_config import MockedResponse +from localstack.services.stepfunctions.local_mocking.mock_config import LocalMockedResponse from localstack.services.stepfunctions.quotas import is_within_size_quota from localstack.utils.strings import camel_to_snake_case, snake_to_camel_case, to_bytes, to_str @@ -356,9 +356,9 @@ def _eval_execution(self, env: Environment) -> None: normalised_parameters = copy.deepcopy(raw_parameters) self._normalise_parameters(normalised_parameters) - if env.is_mocked_mode(): - mocked_response: MockedResponse = env.get_current_mocked_response() - eval_mocked_response(env=env, mocked_response=mocked_response) + if env.is_local_mocked_mode(): + mocked_response: LocalMockedResponse = env.get_current_local_mocked_response() + eval_local_mocked_response(env=env, mocked_response=mocked_response) else: self._eval_service_task( env=env, diff --git a/localstack-core/localstack/services/stepfunctions/asl/component/state/state_execution/state_task/service/state_task_service_callback.py b/localstack-core/localstack/services/stepfunctions/asl/component/state/state_execution/state_task/service/state_task_service_callback.py index 3d219e77bed0b..bec4b68e9c838 100644 --- a/localstack-core/localstack/services/stepfunctions/asl/component/state/state_execution/state_task/service/state_task_service_callback.py +++ b/localstack-core/localstack/services/stepfunctions/asl/component/state/state_execution/state_task/service/state_task_service_callback.py @@ -217,7 +217,8 @@ def _eval_integration_pattern( # finished, ensure all waiting # threads on this endpoint (or task) will stop. This is in an effort to # release resources sooner than when these would eventually synchronise with the updated environment # state of this task. - callback_endpoint.interrupt_all() + if callback_endpoint: + callback_endpoint.interrupt_all() # Handle Callback outcome types. if isinstance(outcome, CallbackOutcomeTimedOut): @@ -346,7 +347,7 @@ def _after_eval_execution( ) ), ) - if not env.is_mocked_mode(): + if not env.is_local_mocked_mode() and not env.is_test_state_mocked_mode(): self._eval_integration_pattern( env=env, resource_runtime_part=resource_runtime_part, diff --git a/localstack-core/localstack/services/stepfunctions/asl/component/state/state_fail/state_fail.py b/localstack-core/localstack/services/stepfunctions/asl/component/state/state_fail/state_fail.py index c351ac4155585..607434657cec5 100644 --- a/localstack-core/localstack/services/stepfunctions/asl/component/state/state_fail/state_fail.py +++ b/localstack-core/localstack/services/stepfunctions/asl/component/state/state_fail/state_fail.py @@ -7,6 +7,9 @@ FailureEventException, ) from localstack.services.stepfunctions.asl.component.state.state import CommonStateField +from localstack.services.stepfunctions.asl.component.state.state_continue_with import ( + ContinueWithEnd, +) from localstack.services.stepfunctions.asl.component.state.state_fail.cause_decl import CauseDecl from localstack.services.stepfunctions.asl.component.state.state_fail.error_decl import ErrorDecl from localstack.services.stepfunctions.asl.component.state.state_props import StateProps @@ -27,6 +30,7 @@ def from_state_props(self, state_props: StateProps) -> None: super().from_state_props(state_props) self.cause = state_props.get(CauseDecl) self.error = state_props.get(ErrorDecl) + self.continue_with = ContinueWithEnd() def _eval_state(self, env: Environment) -> None: task_failed_event_details = TaskFailedEventDetails() diff --git a/localstack-core/localstack/services/stepfunctions/asl/component/state/state_pass/state_pass.py b/localstack-core/localstack/services/stepfunctions/asl/component/state/state_pass/state_pass.py index 7a5b4a8e227fc..9a522df47157d 100644 --- a/localstack-core/localstack/services/stepfunctions/asl/component/state/state_pass/state_pass.py +++ b/localstack-core/localstack/services/stepfunctions/asl/component/state/state_pass/state_pass.py @@ -46,7 +46,7 @@ def _eval_state(self, env: Environment) -> None: if self.result: self.result.eval(env=env) - if not self._is_language_query_jsonpath(): + if not self.is_jsonpath_query_language(): output_value = env.stack[-1] env.states.set_result(output_value) diff --git a/localstack-core/localstack/services/stepfunctions/asl/component/test_state/state/base_mock.py b/localstack-core/localstack/services/stepfunctions/asl/component/test_state/state/base_mock.py new file mode 100644 index 0000000000000..8541431af54d3 --- /dev/null +++ b/localstack-core/localstack/services/stepfunctions/asl/component/test_state/state/base_mock.py @@ -0,0 +1,115 @@ +import abc +import copy + +from localstack.services.stepfunctions.asl.component.eval_component import EvalComponent +from localstack.services.stepfunctions.asl.component.state.state import CommonStateField +from localstack.services.stepfunctions.asl.component.state.state_continue_with import ( + ContinueWithNext, +) +from localstack.services.stepfunctions.asl.eval.test_state.environment import TestStateEnvironment +from localstack.services.stepfunctions.asl.utils.encoding import to_json_str +from localstack.services.stepfunctions.backend.test_state.test_state_mock import ( + TestStateResponseReturn, + TestStateResponseThrow, + eval_mocked_response_throw, +) + + +class MockedBaseState[T: CommonStateField](abc.ABC): + is_single_state: bool + _wrapped: T + + def __init__(self, wrapped: T): + super().__init__() + self._wrapped = wrapped + self.apply_patches() + + def apply_patches(self): + self._apply_patches() + + original_eval_body = self._wrapped._eval_body + self._wrapped._eval_body = self.wrap_with_post_return( + original_eval_body, self.stop_execution + ) + + @abc.abstractmethod + def _apply_patches(self): ... + + @classmethod + def wrap(cls, state: T, is_single_state: bool = False) -> T: + cls.is_single_state = is_single_state + cls._wrapped = state + return cls(state)._wrapped + + def __getattr__(self, attr: str): + return getattr(self._wrapped, attr) + + @classmethod + def before_mock(self, env: TestStateEnvironment): + return + + @classmethod + def do_mock(self, env: TestStateEnvironment): + mocked_response = env.mock.get_next_result() + if not mocked_response: + return + + if isinstance(mocked_response, TestStateResponseThrow): + eval_mocked_response_throw(env, mocked_response) + return + + if isinstance(mocked_response, TestStateResponseReturn): + result_copy = copy.deepcopy(mocked_response.payload) + env.stack.append(result_copy) + + @classmethod + def after_mock(self, env: TestStateEnvironment): + return + + @classmethod + def wrap_with_mock(cls, original_method): + def wrapper(env: TestStateEnvironment, *args, **kwargs): + if not env.mock.is_mocked(): + original_method(env, *args, **kwargs) + return + + cls.before_mock(env) + try: + cls.do_mock(env) + finally: + cls.after_mock(env) + + return wrapper + + @staticmethod + def wrap_with_post_return(method, post_return_fn): + def wrapper(env: TestStateEnvironment, *args, **kwargs): + try: + method(env, *args, **kwargs) + finally: + post_return_fn(env) + + return wrapper + + @staticmethod + def _eval_with_inspect(component: EvalComponent, key: str): + if not component: + return + + eval_body_fn = component._eval_body + + def _update(env: TestStateEnvironment, *args, **kwargs): + # if inspectionData already populated, don't execute again + if key in env.inspection_data: + return + + eval_body_fn(env, *args, **kwargs) + result = env.stack[-1] + env.inspection_data[key] = to_json_str(result) + + component._eval_body = MockedBaseState.wrap_with_post_return(eval_body_fn, _update) + + def stop_execution(self, env: TestStateEnvironment): + if isinstance(self._wrapped.continue_with, ContinueWithNext): + if next_state := self._wrapped.continue_with.next_state: + env.set_choice_selected(next_state.name) diff --git a/localstack-core/localstack/services/stepfunctions/asl/component/test_state/state/common.py b/localstack-core/localstack/services/stepfunctions/asl/component/test_state/state/common.py new file mode 100644 index 0000000000000..d56b009d7bee4 --- /dev/null +++ b/localstack-core/localstack/services/stepfunctions/asl/component/test_state/state/common.py @@ -0,0 +1,89 @@ +from localstack.services.stepfunctions.asl.component.state.state import CommonStateField +from localstack.services.stepfunctions.asl.component.state.state_choice.state_choice import ( + StateChoice, +) +from localstack.services.stepfunctions.asl.component.state.state_continue_with import ( + ContinueWithEnd, +) +from localstack.services.stepfunctions.asl.component.state.state_fail.state_fail import StateFail +from localstack.services.stepfunctions.asl.component.state.state_pass.state_pass import StatePass +from localstack.services.stepfunctions.asl.component.state.state_succeed.state_succeed import ( + StateSucceed, +) +from localstack.services.stepfunctions.asl.component.test_state.state.base_mock import ( + MockedBaseState, +) +from localstack.services.stepfunctions.asl.eval.test_state.environment import TestStateEnvironment + + +class MockedCommonState(MockedBaseState[CommonStateField]): + def add_inspection_data(self, env: TestStateEnvironment): + state = self._wrapped + + if state.is_jsonpath_query_language(): + self._add_jsonpath_inspection_data(env) + + def _add_jsonpath_inspection_data(self, env: TestStateEnvironment): + + state = self._wrapped + + if not isinstance(state, StatePass): + if not self.is_single_state: + return + + if "afterInputPath" not in env.inspection_data: + env.inspection_data["afterInputPath"] = env.states.get_input() + return + + # If not a terminal state, only populate inspection data from pre-processor. + if not isinstance(self._wrapped.continue_with, ContinueWithEnd): + return + + if state.result: + # TODO: investigate interactions between these inspectionData field types. + # i.e parity tests shows that if "Result" is defined, 'afterInputPath' and 'afterParameters' + # cannot be present in the inspection data. + env.inspection_data.pop("afterInputPath", None) + env.inspection_data.pop("afterParameters", None) + + if "afterResultSelector" not in env.inspection_data: + env.inspection_data["afterResultSelector"] = state.result.result_obj + + if "afterResultPath" not in env.inspection_data: + env.inspection_data["afterResultPath"] = env.inspection_data.get( + "afterResultSelector", env.states.get_input() + ) + return + + if "afterInputPath" not in env.inspection_data: + env.inspection_data["afterInputPath"] = env.states.get_input() + + if "afterParameters" not in env.inspection_data: + env.inspection_data["afterParameters"] = env.inspection_data.get( + "afterInputPath", env.states.get_input() + ) + + if "afterResultSelector" not in env.inspection_data: + env.inspection_data["afterResultSelector"] = env.inspection_data["afterParameters"] + + if "afterResultPath" not in env.inspection_data: + env.inspection_data["afterResultPath"] = env.inspection_data.get( + "afterResultSelector", env.states.get_input() + ) + + def _apply_patches(self): + if not isinstance(self._wrapped, (StatePass, StateFail, StateChoice, StateSucceed)): + raise ValueError("Needs to be a Pass, Fail, Choice, or Succeed state.") + + original_eval_body = self.wrap_with_mock(self._wrapped._eval_body) + + def mock_eval_execution(env: TestStateEnvironment): + original_eval_body(env) + env.set_choice_selected(env.next_state_name) + + mock_eval_execution = self.wrap_with_post_return( + method=mock_eval_execution, + post_return_fn=self.add_inspection_data, + ) + + self._wrapped._eval_body = mock_eval_execution diff --git a/localstack-core/localstack/services/stepfunctions/asl/component/test_state/state/execution.py b/localstack-core/localstack/services/stepfunctions/asl/component/test_state/state/execution.py new file mode 100644 index 0000000000000..831f07b481f3d --- /dev/null +++ b/localstack-core/localstack/services/stepfunctions/asl/component/test_state/state/execution.py @@ -0,0 +1,139 @@ +from collections.abc import Callable +from functools import partial + +from localstack.services.stepfunctions.asl.component.common.catch.catcher_outcome import ( + CatcherOutcomeCaught, +) +from localstack.services.stepfunctions.asl.component.common.error_name.failure_event import ( + FailureEvent, +) +from localstack.services.stepfunctions.asl.component.common.query_language import ( + QueryLanguageMode, +) +from localstack.services.stepfunctions.asl.component.common.retry.retrier_decl import RetrierDecl +from localstack.services.stepfunctions.asl.component.common.retry.retrier_outcome import ( + RetrierOutcome, +) +from localstack.services.stepfunctions.asl.component.common.retry.retry_outcome import RetryOutcome +from localstack.services.stepfunctions.asl.component.state.state_execution.execute_state import ( + ExecutionState, +) +from localstack.services.stepfunctions.asl.component.test_state.state.base_mock import ( + MockedBaseState, +) +from localstack.services.stepfunctions.asl.eval.test_state.environment import TestStateEnvironment +from localstack.services.stepfunctions.asl.utils.encoding import to_json_str + + +class MockedStateExecution(MockedBaseState[ExecutionState]): + def add_inspection_data(self, env: TestStateEnvironment): + if self._wrapped.query_language.query_language_mode == QueryLanguageMode.JSONPath: + if "afterResultSelector" not in env.inspection_data: + # HACK: A DistributedItemProcessorEvalInput is added to the stack and never popped off + # during an error case. So we need to check the inspected value is correct before + # adding it to our inspectionData. + if isinstance(env.stack[-1], (dict, str, int, float, list)): + env.inspection_data["afterResultSelector"] = to_json_str(env.stack[-1]) + + if catch := self._wrapped.catch: + for ind, catcher in enumerate(catch.catchers): + original_fn = catcher._eval_body + catcher._eval_body = self.with_catch_state_id(original_fn, ind) + + if retry := self._wrapped.retry: + for ind, retrier in enumerate(retry.retriers): + original_fn = retrier._eval_body + retrier._eval_body = self.with_retry_state_id(retrier, ind) + + def _apply_patches(self): + if not isinstance(self._wrapped, ExecutionState): + raise ValueError("Can only apply MockedStateExecution patches to an ExecutionState") + state = self._wrapped + + if state.query_language.query_language_mode == QueryLanguageMode.JSONPath: + self._eval_with_inspect(self._wrapped.input_path, "afterInputPath") + self._eval_with_inspect(self._wrapped.result_path, "afterResultPath") + + self._eval_with_inspect(self._wrapped.result_selector, "afterResultSelector") + original_eval_execution = self._wrapped._eval_execution + + if self._wrapped.catch: + original_fn = self._wrapped._handle_catch + self._wrapped._handle_catch = partial(self._handle_catch, original_fn) + + if self._wrapped.retry: + original_fn = self._wrapped._handle_retry + self._wrapped._handle_retry = partial(self._handle_retry, original_fn) + + self._wrapped._eval_execution = self.wrap_with_post_return( + method=original_eval_execution, + post_return_fn=self.add_inspection_data, + ) + + @staticmethod + def with_catch_state_id( + original_eval_body: Callable[[TestStateEnvironment], None], state_id: int + ) -> Callable[[TestStateEnvironment], None]: + def _wrapped(env: TestStateEnvironment): + original_eval_body(env) + + if isinstance(env.stack[-1], CatcherOutcomeCaught): + if not (error_details := env.inspection_data.get("errorDetails")): + error_details = env.inspection_data["errorDetails"] = {} + + error_details["catchIndex"] = state_id + + return _wrapped + + @staticmethod + def with_retry_state_id( + retrier: RetrierDecl, state_id: int + ) -> Callable[[TestStateEnvironment], None]: + original_retrier_eval_body = retrier._eval_body + + def _wrapped(env: TestStateEnvironment): + if (retry_count := env.mock._state_configuration.get("retrierRetryCount", 0)) > 0: + retrier.max_attempts._store_attempt_number(env, retry_count - 1) + + original_retrier_eval_body(env) + + if not (error_details := env.inspection_data.get("errorDetails")): + error_details = env.inspection_data["errorDetails"] = {} + + error_details["retryIndex"] = state_id + if env.stack[-1] == RetrierOutcome.Executed: + # TODO(gregfurman): Ideally, retryBackoffIntervalSeconds should be written to inspectionData + # within the retrier.backoff_rate decleration (perhaps at _access_next_multiplier). + rate = retrier.backoff_rate.rate + interval = retrier.interval_seconds.seconds + error_details["retryBackoffIntervalSeconds"] = int(interval * (rate**retry_count)) + + return _wrapped + + @staticmethod + def _handle_catch( + original_handle_catch: Callable[[TestStateEnvironment, FailureEvent], None], + env: TestStateEnvironment, + failure_event: FailureEvent, + ) -> None: + original_handle_catch(env, failure_event) + + spec: dict[str, str] = ExecutionState._construct_error_output_value(failure_event) + error, cause = spec.get("Error"), spec.get("Cause") + + env.set_caught_error(env.next_state_name, error, cause) + + @staticmethod + def _handle_retry( + original_handle_retry: Callable[[TestStateEnvironment, FailureEvent], RetryOutcome], + env: TestStateEnvironment, + failure_event: FailureEvent, + ) -> RetryOutcome: + res = original_handle_retry(env, failure_event) + + spec: dict[str, str] = ExecutionState._construct_error_output_value(failure_event) + error, cause = spec.get("Error"), spec.get("Cause") + + if res == RetryOutcome.CanRetry: + env.set_retriable_error(error, cause) + return res diff --git a/localstack-core/localstack/services/stepfunctions/asl/component/test_state/state/map.py b/localstack-core/localstack/services/stepfunctions/asl/component/test_state/state/map.py new file mode 100644 index 0000000000000..9c76e934cc336 --- /dev/null +++ b/localstack-core/localstack/services/stepfunctions/asl/component/test_state/state/map.py @@ -0,0 +1,74 @@ +from localstack.services.stepfunctions.asl.component.common.error_name.states_error_name_type import ( + StatesErrorNameType, +) +from localstack.services.stepfunctions.asl.component.state.state_execution.state_map.state_map import ( + StateMap, +) +from localstack.services.stepfunctions.asl.component.test_state.state.base_mock import ( + MockedBaseState, +) +from localstack.services.stepfunctions.asl.component.test_state.state.execution import ( + MockedStateExecution, +) +from localstack.services.stepfunctions.asl.eval.test_state.environment import TestStateEnvironment +from localstack.services.stepfunctions.backend.test_state.test_state_mock import ( + TestStateResponseThrow, +) + + +class MockedStateMap(MockedBaseState[StateMap]): + def add_inspection_data(self, env: TestStateEnvironment): + if tolerated_failure_percentage := env.inspection_data.get("toleratedFailurePercentage"): + env.inspection_data["toleratedFailurePercentage"] = float(tolerated_failure_percentage) + + if tolerated_failure_count := env.inspection_data.get("toleratedFailureCount"): + env.inspection_data["toleratedFailureCount"] = int(tolerated_failure_count) + + @classmethod + def before_mock(cls, env: TestStateEnvironment): + if not env.mock or not env.mock._state_configuration: + return + + if not cls._wrapped.catch and not cls._wrapped.retry: + return + + if failure_count := env.mock._state_configuration.get("mapIterationFailureCount"): + max_failure_count = ( + cls._wrapped.tolerated_failure_count_decl._eval_tolerated_failure_count(env) + ) + if failure_count > max_failure_count: + error_response = TestStateResponseThrow( + error=StatesErrorNameType.StatesExceedToleratedFailureThreshold.to_name(), + cause="The specified tolerated failure threshold was exceeded", + ) + env.mock.add_result(error_response) + return + + def _apply_patches(self): + self._wrapped = MockedStateExecution.wrap(self._wrapped) + + if self._wrapped.is_jsonpath_query_language(): + self._eval_with_inspect(self._wrapped.items_path, "afterInputPath") + self._eval_with_inspect(self._wrapped.item_selector, "afterItemsSelector") + + original_eval_max_concurrency = self._wrapped.max_concurrency_decl._eval_max_concurrency + original_iteration_component_eval_body = self._wrapped.iteration_component._eval_body + original_eval_execution = self._wrapped._eval_execution + + # HACK(gregfurman): Ideally we should be using the "$$.Map.Item.Index" to access each item of the + # mocked result list. This is turning out to be quite complicated, so instead just patch the + # StateMap's max concurrency decleration to always eval to '1' -- making the map run in serial. + def mock_max_concurrency(env: TestStateEnvironment) -> int: + # always set concurrency to 1 but inspection data is accurate to original + env.inspection_data["maxConcurrency"] = original_eval_max_concurrency(env) + return 1 + + self._wrapped._eval_execution = self.wrap_with_post_return( + method=original_eval_execution, + post_return_fn=self.add_inspection_data, + ) + + self._wrapped.max_concurrency_decl._eval_max_concurrency = mock_max_concurrency + self._wrapped.iteration_component._eval_body = self.wrap_with_mock( + original_iteration_component_eval_body + ) diff --git a/localstack-core/localstack/services/stepfunctions/asl/component/test_state/state/parallel.py b/localstack-core/localstack/services/stepfunctions/asl/component/test_state/state/parallel.py new file mode 100644 index 0000000000000..caefc6e7fff96 --- /dev/null +++ b/localstack-core/localstack/services/stepfunctions/asl/component/test_state/state/parallel.py @@ -0,0 +1,33 @@ +from localstack.services.stepfunctions.asl.component.state.state_execution.state_parallel.state_parallel import ( + StateParallel, +) +from localstack.services.stepfunctions.asl.component.test_state.state.base_mock import ( + MockedBaseState, +) +from localstack.services.stepfunctions.asl.component.test_state.state.execution import ( + MockedStateExecution, +) +from localstack.services.stepfunctions.asl.eval.test_state.environment import TestStateEnvironment + + +class MockedStateParallel(MockedBaseState[StateParallel]): + def _apply_patches(self): + self._wrapped = MockedStateExecution.wrap(self._wrapped) + + original_branches_eval_body = self._wrapped.branches._eval_body + original_eval_execution = self._wrapped._eval_execution + + self._wrapped._eval_execution = self.wrap_with_post_return( + method=original_eval_execution, + post_return_fn=self.add_inspection_data, + ) + + self._wrapped.branches._eval_body = self.wrap_with_mock(original_branches_eval_body) + + def add_inspection_data(self, env: TestStateEnvironment): + if self._wrapped.is_jsonpath_query_language(): + # AWS does not include afterInputPath in inspection data for Parallel states. + env.inspection_data.pop("afterInputPath", None) + else: + # AWS does not include afterArguments in inspection data for Parallel states. + env.inspection_data.pop("afterArguments", None) diff --git a/localstack-core/localstack/services/stepfunctions/asl/component/test_state/state/task.py b/localstack-core/localstack/services/stepfunctions/asl/component/test_state/state/task.py new file mode 100644 index 0000000000000..6cfbb147fa8ac --- /dev/null +++ b/localstack-core/localstack/services/stepfunctions/asl/component/test_state/state/task.py @@ -0,0 +1,44 @@ +from localstack.services.stepfunctions.asl.component.common.query_language import ( + QueryLanguageMode, +) +from localstack.services.stepfunctions.asl.component.state.state_execution.state_task.service.state_task_service import ( + StateTaskService, +) +from localstack.services.stepfunctions.asl.component.state.state_execution.state_task.state_task import ( + StateTask, +) +from localstack.services.stepfunctions.asl.component.test_state.state.base_mock import ( + MockedBaseState, +) +from localstack.services.stepfunctions.asl.component.test_state.state.execution import ( + MockedStateExecution, +) +from localstack.services.stepfunctions.asl.eval.test_state.environment import TestStateEnvironment +from localstack.services.stepfunctions.asl.utils.encoding import to_json_str + + +class MockedStateTask(MockedBaseState[StateTask]): + def add_inspection_data(self, env: TestStateEnvironment): + if self._wrapped.query_language.query_language_mode == QueryLanguageMode.JSONPath: + if "afterParameters" not in env.inspection_data: + env.inspection_data["afterParameters"] = to_json_str(env.states.get_input()) + + def _apply_patches(self): + self._wrapped = MockedStateExecution.wrap(self._wrapped) + + if self._wrapped.query_language.query_language_mode == QueryLanguageMode.JSONPath: + self._eval_with_inspect(self._wrapped.parargs, "afterParameters") + + if isinstance(self._wrapped, StateTaskService): + self._wrapped._eval_service_task = self.wrap_with_mock(self._wrapped._eval_service_task) + + original_eval_execution = self._wrapped._eval_execution + + def mock_eval_execution(env: TestStateEnvironment, *args, **kwargs): + original_eval_execution(env, *args, **kwargs) + result = to_json_str(env.stack[-1]) + env.inspection_data["result"] = result + + self._wrapped._eval_execution = self.wrap_with_post_return( + mock_eval_execution, self.add_inspection_data + ) diff --git a/localstack-core/localstack/services/stepfunctions/asl/eval/environment.py b/localstack-core/localstack/services/stepfunctions/asl/eval/environment.py index b62dacbc055cf..b4f997422b978 100644 --- a/localstack-core/localstack/services/stepfunctions/asl/eval/environment.py +++ b/localstack-core/localstack/services/stepfunctions/asl/eval/environment.py @@ -3,7 +3,7 @@ import copy import logging import threading -from typing import Any, Final, Optional +from typing import Any, Final, Optional, Self from localstack.aws.api.stepfunctions import ( Arn, @@ -34,7 +34,10 @@ from localstack.services.stepfunctions.asl.eval.states import ContextObjectData, States from localstack.services.stepfunctions.asl.eval.variable_store import VariableStore from localstack.services.stepfunctions.backend.activity import Activity -from localstack.services.stepfunctions.mocking.mock_config import MockedResponse, MockTestCase +from localstack.services.stepfunctions.local_mocking.mock_config import ( + LocalMockedResponse, + LocalMockTestCase, +) LOG = logging.getLogger(__name__) @@ -52,7 +55,10 @@ class Environment: callback_pool_manager: CallbackPoolManager map_run_record_pool_manager: MapRunRecordPoolManager activity_store: Final[dict[Arn, Activity]] - mock_test_case: MockTestCase | None = None + local_mock_test_case: LocalMockTestCase | None = None + next_local_mock_invocation_number: dict[ + str, int + ] # Tracks invocation count per state for mock cycling _frames: Final[list[Environment]] _is_frame: bool = False @@ -71,7 +77,7 @@ def __init__( cloud_watch_logging_session: CloudWatchLoggingSession | None, activity_store: dict[Arn, Activity], variable_store: VariableStore | None = None, - mock_test_case: MockTestCase | None = None, + local_mock_test_case: LocalMockTestCase | None = None, ): super().__init__() self._state_mutex = threading.RLock() @@ -89,7 +95,8 @@ def __init__( self.activity_store = activity_store - self.mock_test_case = mock_test_case + self.local_mock_test_case = local_mock_test_case + self.next_local_mock_invocation_number = {} self._frames = [] self._is_frame = False @@ -101,9 +108,9 @@ def __init__( @classmethod def as_frame_of( - cls, env: Environment, event_history_frame_cache: EventHistoryContext | None = None - ) -> Environment: - return Environment.as_inner_frame_of( + cls, env: Self, event_history_frame_cache: EventHistoryContext | None = None + ) -> Self: + return cls.as_inner_frame_of( env=env, variable_store=env.variable_store, event_history_frame_cache=event_history_frame_cache, @@ -112,10 +119,10 @@ def as_frame_of( @classmethod def as_inner_frame_of( cls, - env: Environment, + env: Self, variable_store: VariableStore, event_history_frame_cache: EventHistoryContext | None = None, - ) -> Environment: + ) -> Self: # Construct the frame's context object data. context = ContextObjectData( Execution=env.states.context_object.context_object_data["Execution"], @@ -138,8 +145,11 @@ def as_inner_frame_of( cloud_watch_logging_session=env.cloud_watch_logging_session, activity_store=env.activity_store, variable_store=variable_store, - mock_test_case=env.mock_test_case, ) + frame.local_mock_test_case = env.local_mock_test_case + frame.next_local_mock_invocation_number = ( + env.next_local_mock_invocation_number + ) # Share counter with parent frame._is_frame = True frame.event_manager = env.event_manager if "State" in env.states.context_object.context_object_data: @@ -267,32 +277,41 @@ def is_frame(self) -> bool: def is_standard_workflow(self) -> bool: return self.execution_type == StateMachineType.STANDARD - def is_mocked_mode(self) -> bool: + def is_test_state_mocked_mode(self) -> bool: + return False + + def is_local_mocked_mode(self) -> bool: """ - Returns True if the state machine is running in mock mode and the current - state has a defined mock configuration in the target environment or frame; - otherwise, returns False. + Returns True if: + - the state machine is running in Step Functions Local mode + - the current state has a defined Local mock configuration in the target environment or frame + + Otherwise, returns False. """ return ( - self.mock_test_case is not None - and self.next_state_name in self.mock_test_case.state_mocked_responses + self.local_mock_test_case is not None + and self.next_state_name in self.local_mock_test_case.state_mocked_responses ) - def get_current_mocked_response(self) -> MockedResponse: - if not self.is_mocked_mode(): + def get_current_local_mocked_response(self) -> LocalMockedResponse: + if not self.is_local_mocked_mode(): raise RuntimeError( "Cannot retrieve mocked response: execution is not operating in mocked mode" ) state_name = self.next_state_name - state_mocked_responses: Optional = self.mock_test_case.state_mocked_responses.get( + state_mocked_responses: Optional = self.local_mock_test_case.state_mocked_responses.get( state_name ) if state_mocked_responses is None: - raise RuntimeError(f"No mocked response definition for state '{state_name}'") - retry_count = self.states.context_object.context_object_data["State"]["RetryCount"] - if len(state_mocked_responses.mocked_responses) <= retry_count: + raise RuntimeError(f"No Local mocked response definition for state '{state_name}'") + + # Get and increment the invocation counter for this state + invocation_number = self.next_local_mock_invocation_number.get(state_name, 0) + self.next_local_mock_invocation_number[state_name] = invocation_number + 1 + + if len(state_mocked_responses.mocked_responses) <= invocation_number: raise RuntimeError( - f"No mocked response definition for state '{state_name}' " - f"and retry number '{retry_count}'" + f"No Local mocked response definition for state '{state_name}' " + f"and invocation number '{invocation_number}'" ) - return state_mocked_responses.mocked_responses[retry_count] + return state_mocked_responses.mocked_responses[invocation_number] diff --git a/localstack-core/localstack/services/stepfunctions/asl/eval/states.py b/localstack-core/localstack/services/stepfunctions/asl/eval/states.py index 813fd292b0786..85aa0711fc1ec 100644 --- a/localstack-core/localstack/services/stepfunctions/asl/eval/states.py +++ b/localstack-core/localstack/services/stepfunctions/asl/eval/states.py @@ -82,7 +82,7 @@ class States: context_object: Final[ContextObject] def __init__(self, context: ContextObjectData): - input_value = context["Execution"]["Input"] + input_value = context.get("Execution", {}).get("Input", {}) self._states_data = StatesData(input=input_value, context=context) self.context_object = ContextObject(context_object=context) diff --git a/localstack-core/localstack/services/stepfunctions/asl/eval/test_state/environment.py b/localstack-core/localstack/services/stepfunctions/asl/eval/test_state/environment.py index 510fa534f1447..bb65c15fb7bde 100644 --- a/localstack-core/localstack/services/stepfunctions/asl/eval/test_state/environment.py +++ b/localstack-core/localstack/services/stepfunctions/asl/eval/test_state/environment.py @@ -1,5 +1,7 @@ from __future__ import annotations +from typing import Self + from localstack.aws.api.stepfunctions import Arn, InspectionData, StateMachineType from localstack.services.stepfunctions.asl.eval.environment import Environment from localstack.services.stepfunctions.asl.eval.evaluation_details import AWSExecutionDetails @@ -14,14 +16,19 @@ ) from localstack.services.stepfunctions.asl.eval.states import ContextObjectData from localstack.services.stepfunctions.asl.eval.test_state.program_state import ( + ProgramCaughtError, ProgramChoiceSelected, + ProgramRetriable, ) from localstack.services.stepfunctions.asl.eval.variable_store import VariableStore +from localstack.services.stepfunctions.asl.utils.encoding import to_json_str from localstack.services.stepfunctions.backend.activity import Activity +from localstack.services.stepfunctions.backend.test_state.test_state_mock import TestStateMock class TestStateEnvironment(Environment): inspection_data: InspectionData + mock: TestStateMock def __init__( self, @@ -31,6 +38,8 @@ def __init__( event_history_context: EventHistoryContext, activity_store: dict[Arn, Activity], cloud_watch_logging_session: CloudWatchLoggingSession | None = None, + variable_store: VariableStore | None = None, + mock: TestStateMock | None = None, ): super().__init__( aws_execution_details=aws_execution_details, @@ -39,30 +48,46 @@ def __init__( event_history_context=event_history_context, cloud_watch_logging_session=cloud_watch_logging_session, activity_store=activity_store, + variable_store=variable_store, ) self.inspection_data = InspectionData() + variables = variable_store.to_dict() + if variables: + self.inspection_data["variables"] = to_json_str(variables) + self.mock = mock + + def is_test_state_mocked_mode(self) -> bool: + return self.mock.is_mocked() + @classmethod def as_frame_of( cls, - env: TestStateEnvironment, + env: Self, event_history_frame_cache: EventHistoryContext | None = None, - ) -> Environment: - frame = super().as_frame_of(env=env, event_history_frame_cache=event_history_frame_cache) - frame.inspection_data = env.inspection_data - return frame + ) -> Self: + if (mocked_context := env.mock.get_context()) is not None: + env.states.context_object.context_object_data = mocked_context + return cls.as_inner_frame_of( + env=env, + variable_store=env.variable_store, + event_history_frame_cache=event_history_frame_cache, + ) + + @classmethod def as_inner_frame_of( cls, - env: TestStateEnvironment, + env: Self, variable_store: VariableStore, event_history_frame_cache: EventHistoryContext | None = None, - ) -> Environment: + ) -> Self: frame = super().as_inner_frame_of( env=env, event_history_frame_cache=event_history_frame_cache, variable_store=variable_store, ) frame.inspection_data = env.inspection_data + frame.mock = env.mock return frame def set_choice_selected(self, next_state_name: str) -> None: @@ -71,5 +96,24 @@ def set_choice_selected(self, next_state_name: str) -> None: self._program_state = ProgramChoiceSelected(next_state_name=next_state_name) self.program_state_event.set() self.program_state_event.clear() - else: - raise RuntimeError("Cannot set choice selected for non running ProgramState.") + + def set_caught_error(self, next_state_name: str, error: str, cause: str) -> None: + with self._state_mutex: + if isinstance(self._program_state, ProgramRunning): + self._program_state = ProgramCaughtError( + next_state_name=next_state_name, + error=error, + cause=cause, + ) + self.program_state_event.set() + self.program_state_event.clear() + + def set_retriable_error(self, error: str, cause: str) -> None: + with self._state_mutex: + if isinstance(self._program_state, ProgramRunning): + self._program_state = ProgramRetriable( + error=error, + cause=cause, + ) + self.program_state_event.set() + self.program_state_event.clear() diff --git a/localstack-core/localstack/services/stepfunctions/asl/eval/test_state/program_state.py b/localstack-core/localstack/services/stepfunctions/asl/eval/test_state/program_state.py index d9576ceda285b..a7755633d3198 100644 --- a/localstack-core/localstack/services/stepfunctions/asl/eval/test_state/program_state.py +++ b/localstack-core/localstack/services/stepfunctions/asl/eval/test_state/program_state.py @@ -9,3 +9,25 @@ class ProgramChoiceSelected(ProgramState): def __init__(self, next_state_name: str): super().__init__() self.next_state_name = next_state_name + + +class ProgramCaughtError(ProgramState): + next_state_name: Final[str] + error: Final[str] + cause: Final[str] + + def __init__(self, next_state_name: str, error: str, cause: str): + super().__init__() + self.next_state_name = next_state_name + self.error = error + self.cause = cause + + +class ProgramRetriable(ProgramState): + error: Final[str] + cause: Final[str] + + def __init__(self, error: str, cause: str): + super().__init__() + self.error = error + self.cause = cause diff --git a/localstack-core/localstack/services/stepfunctions/asl/eval/variable_store.py b/localstack-core/localstack/services/stepfunctions/asl/eval/variable_store.py index ff2f0957e825f..a17d557e990f7 100644 --- a/localstack-core/localstack/services/stepfunctions/asl/eval/variable_store.py +++ b/localstack-core/localstack/services/stepfunctions/asl/eval/variable_store.py @@ -54,13 +54,17 @@ class VariableStore: _outer_variable_declaration_cache: VariableDeclarations | None _variable_declarations_cache: VariableDeclarations | None - def __init__(self): + def __init__(self, variables: dict | None = None): self._outer_scope = {} self._inner_scope = {} self._declaration_tracing = set() self._outer_variable_declaration_cache = None self._variable_declarations_cache = None + if variables: + for key, value in variables.items(): + self.set(key, value) + @classmethod def as_inner_scope_of(cls, outer_variable_store: VariableStore) -> VariableStore: inner_variable_store = cls() @@ -85,6 +89,14 @@ def get_assigned_variables(self) -> dict[str, str]: assigned_variables[traced_declaration_identifier] = traced_declaration_value_json_str return assigned_variables + def to_dict(self) -> dict[str, str]: + assigned_variables: dict[str, str] = {} + for traced_declaration_identifier in self._declaration_tracing: + assigned_variables[traced_declaration_identifier] = self.get( + traced_declaration_identifier + ) + return assigned_variables + def get(self, variable_identifier: VariableIdentifier) -> VariableValue: if variable_identifier in self._inner_scope: return self._inner_scope[variable_identifier] diff --git a/localstack-core/localstack/services/stepfunctions/asl/jsonata/jsonata.py b/localstack-core/localstack/services/stepfunctions/asl/jsonata/jsonata.py index 9fa3b91c8c9ab..fe327bd829127 100644 --- a/localstack-core/localstack/services/stepfunctions/asl/jsonata/jsonata.py +++ b/localstack-core/localstack/services/stepfunctions/asl/jsonata/jsonata.py @@ -7,7 +7,7 @@ from typing import Any, Final import jpype -import jpype.imports +import jpype.imports # noqa # Required for JVM Java class imports from localstack.services.stepfunctions.asl.utils.encoding import to_json_str from localstack.services.stepfunctions.packages import jpype_jsonata_package @@ -33,8 +33,11 @@ # allowing escapes r"(?:\"(?:\\.|[^\"\\])*\"|\'(?:\\.|[^\'\\])*\')" r"|" - # 3) Capturing branch for $$, $identifier[.prop…], or lone $ - r"(\$\$|\$[A-Za-z0-9_$]+(?:\.[A-Za-z0-9_][A-Za-z0-9_$]*)*|\$)" + # 3) Capturing branch for $identifier[.prop…] + # Requires at least one identifier character after $, so bare $ (the + # JSONata context variable used in filter predicates like [$ = 1]) is + # never captured. $$ is captured but filtered out downstream. + r"(\$[A-Za-z0-9_$]+(?:\.[A-Za-z0-9_][A-Za-z0-9_$]*)*)" ) _ILLEGAL_VARIABLE_REFERENCES: Final[set[str]] = {"$", "$$"} diff --git a/localstack-core/localstack/services/stepfunctions/asl/parse/preprocessor.py b/localstack-core/localstack/services/stepfunctions/asl/parse/preprocessor.py index cb25e4989a4a0..94aaa897b5fa7 100644 --- a/localstack-core/localstack/services/stepfunctions/asl/parse/preprocessor.py +++ b/localstack-core/localstack/services/stepfunctions/asl/parse/preprocessor.py @@ -7,13 +7,17 @@ from localstack.services.stepfunctions.asl.antlr.runtime.ASLLexer import ASLLexer from localstack.services.stepfunctions.asl.antlr.runtime.ASLParser import ASLParser -from localstack.services.stepfunctions.asl.antlr.runtime.ASLParserVisitor import ASLParserVisitor +from localstack.services.stepfunctions.asl.antlr.runtime.ASLParserVisitor import ( + ASLParserVisitor, +) from localstack.services.stepfunctions.asl.antlt4utils.antlr4utils import ( from_string_literal, is_production, is_terminal, ) -from localstack.services.stepfunctions.asl.component.common.assign.assign_decl import AssignDecl +from localstack.services.stepfunctions.asl.component.common.assign.assign_decl import ( + AssignDecl, +) from localstack.services.stepfunctions.asl.component.common.assign.assign_decl_binding import ( AssignDeclBinding, ) @@ -36,9 +40,15 @@ AssignTemplateValueTerminalLit, AssignTemplateValueTerminalStringJSONata, ) -from localstack.services.stepfunctions.asl.component.common.catch.catch_decl import CatchDecl -from localstack.services.stepfunctions.asl.component.common.catch.catcher_decl import CatcherDecl -from localstack.services.stepfunctions.asl.component.common.catch.catcher_props import CatcherProps +from localstack.services.stepfunctions.asl.component.common.catch.catch_decl import ( + CatchDecl, +) +from localstack.services.stepfunctions.asl.component.common.catch.catcher_decl import ( + CatcherDecl, +) +from localstack.services.stepfunctions.asl.component.common.catch.catcher_props import ( + CatcherProps, +) from localstack.services.stepfunctions.asl.component.common.comment import Comment from localstack.services.stepfunctions.asl.component.common.error_name.custom_error_name import ( CustomErrorName, @@ -46,7 +56,9 @@ from localstack.services.stepfunctions.asl.component.common.error_name.error_equals_decl import ( ErrorEqualsDecl, ) -from localstack.services.stepfunctions.asl.component.common.error_name.error_name import ErrorName +from localstack.services.stepfunctions.asl.component.common.error_name.error_name import ( + ErrorName, +) from localstack.services.stepfunctions.asl.component.common.error_name.states_error_name import ( StatesErrorName, ) @@ -79,10 +91,18 @@ Parameters, Parargs, ) -from localstack.services.stepfunctions.asl.component.common.path.input_path import InputPath -from localstack.services.stepfunctions.asl.component.common.path.items_path import ItemsPath -from localstack.services.stepfunctions.asl.component.common.path.output_path import OutputPath -from localstack.services.stepfunctions.asl.component.common.path.result_path import ResultPath +from localstack.services.stepfunctions.asl.component.common.path.input_path import ( + InputPath, +) +from localstack.services.stepfunctions.asl.component.common.path.items_path import ( + ItemsPath, +) +from localstack.services.stepfunctions.asl.component.common.path.output_path import ( + OutputPath, +) +from localstack.services.stepfunctions.asl.component.common.path.result_path import ( + ResultPath, +) from localstack.services.stepfunctions.asl.component.common.payload.payloadvalue.payload_value import ( PayloadValue, ) @@ -116,7 +136,9 @@ QueryLanguage, QueryLanguageMode, ) -from localstack.services.stepfunctions.asl.component.common.result_selector import ResultSelector +from localstack.services.stepfunctions.asl.component.common.result_selector import ( + ResultSelector, +) from localstack.services.stepfunctions.asl.component.common.retry.backoff_rate_decl import ( BackoffRateDecl, ) @@ -133,9 +155,15 @@ from localstack.services.stepfunctions.asl.component.common.retry.max_delay_seconds_decl import ( MaxDelaySecondsDecl, ) -from localstack.services.stepfunctions.asl.component.common.retry.retrier_decl import RetrierDecl -from localstack.services.stepfunctions.asl.component.common.retry.retrier_props import RetrierProps -from localstack.services.stepfunctions.asl.component.common.retry.retry_decl import RetryDecl +from localstack.services.stepfunctions.asl.component.common.retry.retrier_decl import ( + RetrierDecl, +) +from localstack.services.stepfunctions.asl.component.common.retry.retrier_props import ( + RetrierProps, +) +from localstack.services.stepfunctions.asl.component.common.retry.retry_decl import ( + RetryDecl, +) from localstack.services.stepfunctions.asl.component.common.string.string_expression import ( StringContextPath, StringExpression, @@ -291,15 +319,23 @@ Error, ErrorPath, ) -from localstack.services.stepfunctions.asl.component.state.state_fail.state_fail import StateFail -from localstack.services.stepfunctions.asl.component.state.state_pass.result import Result -from localstack.services.stepfunctions.asl.component.state.state_pass.state_pass import StatePass +from localstack.services.stepfunctions.asl.component.state.state_fail.state_fail import ( + StateFail, +) +from localstack.services.stepfunctions.asl.component.state.state_pass.result import ( + Result, +) +from localstack.services.stepfunctions.asl.component.state.state_pass.state_pass import ( + StatePass, +) from localstack.services.stepfunctions.asl.component.state.state_props import StateProps from localstack.services.stepfunctions.asl.component.state.state_succeed.state_succeed import ( StateSucceed, ) from localstack.services.stepfunctions.asl.component.state.state_type import StateType -from localstack.services.stepfunctions.asl.component.state.state_wait.state_wait import StateWait +from localstack.services.stepfunctions.asl.component.state.state_wait.state_wait import ( + StateWait, +) from localstack.services.stepfunctions.asl.component.state.state_wait.wait_function.seconds import ( Seconds, SecondsJSONata, @@ -311,18 +347,24 @@ Timestamp, TimestampPath, ) -from localstack.services.stepfunctions.asl.parse.intrinsic.intrinsic_parser import IntrinsicParser +from localstack.services.stepfunctions.asl.parse.intrinsic.intrinsic_parser import ( + IntrinsicParser, +) from localstack.services.stepfunctions.asl.parse.typed_props import TypedProps LOG = logging.getLogger(__name__) class Preprocessor(ASLParserVisitor): - _query_language_per_scope: list[QueryLanguage] = [] + def __init__(self): + self._query_language_per_scope: list[QueryLanguage] = [] def _get_current_query_language(self) -> QueryLanguage: return self._query_language_per_scope[-1] + def _get_top_level_query_language(self) -> QueryLanguage: + return self._query_language_per_scope[0] + def _open_query_language_scope(self, parse_tree: ParseTree) -> None: production = is_production(parse_tree) if production is None: @@ -347,11 +389,11 @@ def _open_query_language_scope(self, parse_tree: ParseTree) -> None: query_language = QueryLanguage() # Otherwise, check for logical conflicts and add the latest or inherited value to as the next scope. else: - current_query_language = self._get_current_query_language() + top_query_language = self._get_top_level_query_language() if query_language is None: - query_language = current_query_language + query_language = top_query_language if ( - current_query_language.query_language_mode == QueryLanguageMode.JSONata + top_query_language.query_language_mode == QueryLanguageMode.JSONata and query_language.query_language_mode == QueryLanguageMode.JSONPath ): raise ValueError( @@ -1507,5 +1549,6 @@ def visitString_intrinsic_function( intrinsic_function_derivation = ctx.STRINGINTRINSICFUNC().getText()[1:-1] function, _ = IntrinsicParser.parse(intrinsic_function_derivation) return StringIntrinsicFunction( - intrinsic_function_derivation=intrinsic_function_derivation, function=function + intrinsic_function_derivation=intrinsic_function_derivation, + function=function, ) diff --git a/localstack-core/localstack/services/stepfunctions/asl/parse/test_state/asl_parser.py b/localstack-core/localstack/services/stepfunctions/asl/parse/test_state/asl_parser.py index d4c4b8b3ef582..3616984ea08fa 100644 --- a/localstack-core/localstack/services/stepfunctions/asl/parse/test_state/asl_parser.py +++ b/localstack-core/localstack/services/stepfunctions/asl/parse/test_state/asl_parser.py @@ -15,7 +15,9 @@ class TestStateAmazonStateLanguageParser(AmazonStateLanguageParser): @staticmethod - def parse(definition: str) -> tuple[EvalComponent, ParserRuleContext]: + def parse( + definition: str, state_name: str | None = None + ) -> tuple[EvalComponent, ParserRuleContext]: # Attempt to build the AST and look out for syntax errors. syntax_error_listener = SyntaxErrorListener() @@ -25,15 +27,14 @@ def parse(definition: str) -> tuple[EvalComponent, ParserRuleContext]: parser = ASLParser(stream) parser.removeErrorListeners() parser.addErrorListener(syntax_error_listener) - # Unlike the main Program parser, TestState parsing occurs at a state declaration level. - tree = parser.state_decl_body() + tree = parser.state_machine() if state_name else parser.state_decl_body() errors = syntax_error_listener.errors if errors: raise ASLParserException(errors=errors) # Attempt to preprocess the AST into evaluation components. preprocessor = TestStatePreprocessor() - test_state_program = preprocessor.visit(tree) + test_state_program = preprocessor.to_test_state_program(tree, state_name) return test_state_program, tree diff --git a/localstack-core/localstack/services/stepfunctions/asl/parse/test_state/preprocessor.py b/localstack-core/localstack/services/stepfunctions/asl/parse/test_state/preprocessor.py index 0565f74a67a55..8b8e99b6319d5 100644 --- a/localstack-core/localstack/services/stepfunctions/asl/parse/test_state/preprocessor.py +++ b/localstack-core/localstack/services/stepfunctions/asl/parse/test_state/preprocessor.py @@ -1,9 +1,19 @@ import enum from typing import Final +from antlr4.tree.Tree import ParseTree + from localstack.services.stepfunctions.asl.antlr.runtime.ASLParser import ASLParser -from localstack.services.stepfunctions.asl.component.common.parargs import Parameters +from localstack.services.stepfunctions.asl.antlt4utils.antlr4utils import ( + is_production, +) +from localstack.services.stepfunctions.asl.component.common.parargs import ( + ArgumentsJSONataTemplateValueObject, + ArgumentsStringJSONata, + Parameters, +) from localstack.services.stepfunctions.asl.component.common.path.input_path import InputPath +from localstack.services.stepfunctions.asl.component.common.path.items_path import ItemsPath from localstack.services.stepfunctions.asl.component.common.path.result_path import ResultPath from localstack.services.stepfunctions.asl.component.common.query_language import QueryLanguage from localstack.services.stepfunctions.asl.component.common.result_selector import ResultSelector @@ -11,13 +21,49 @@ from localstack.services.stepfunctions.asl.component.state.state_choice.state_choice import ( StateChoice, ) -from localstack.services.stepfunctions.asl.component.state.state_execution.execute_state import ( - ExecutionState, +from localstack.services.stepfunctions.asl.component.state.state_execution.state_map.max_concurrency import ( + MaxConcurrency, + MaxConcurrencyJSONata, + MaxConcurrencyPath, +) +from localstack.services.stepfunctions.asl.component.state.state_execution.state_map.state_map import ( + StateMap, ) +from localstack.services.stepfunctions.asl.component.state.state_execution.state_map.tolerated_failure import ( + ToleratedFailureCountInt, + ToleratedFailureCountPath, + ToleratedFailureCountStringJSONata, + ToleratedFailurePercentage, + ToleratedFailurePercentagePath, + ToleratedFailurePercentageStringJSONata, +) +from localstack.services.stepfunctions.asl.component.state.state_execution.state_parallel.state_parallel import ( + StateParallel, +) +from localstack.services.stepfunctions.asl.component.state.state_execution.state_task.state_task import ( + StateTask, +) +from localstack.services.stepfunctions.asl.component.state.state_fail.state_fail import StateFail from localstack.services.stepfunctions.asl.component.state.state_pass.result import Result +from localstack.services.stepfunctions.asl.component.state.state_pass.state_pass import StatePass +from localstack.services.stepfunctions.asl.component.state.state_succeed.state_succeed import ( + StateSucceed, +) from localstack.services.stepfunctions.asl.component.test_state.program.test_state_program import ( TestStateProgram, ) +from localstack.services.stepfunctions.asl.component.test_state.state.common import ( + MockedCommonState, +) +from localstack.services.stepfunctions.asl.component.test_state.state.map import ( + MockedStateMap, +) +from localstack.services.stepfunctions.asl.component.test_state.state.parallel import ( + MockedStateParallel, +) +from localstack.services.stepfunctions.asl.component.test_state.state.task import ( + MockedStateTask, +) from localstack.services.stepfunctions.asl.component.test_state.state.test_state_state_props import ( TestStateStateProps, ) @@ -30,63 +76,103 @@ class InspectionDataKey(enum.Enum): INPUT = "input" AFTER_INPUT_PATH = "afterInputPath" AFTER_PARAMETERS = "afterParameters" + AFTER_ARGUMENTS = "afterArguments" RESULT = "result" AFTER_RESULT_SELECTOR = "afterResultSelector" AFTER_RESULT_PATH = "afterResultPath" + AFTER_ITEMS_PATH = "afterItemsPath" REQUEST = "request" RESPONSE = "response" - -def _decorated_updated_choice_inspection_data(method): - def wrapper(env: TestStateEnvironment, *args, **kwargs): - method(env, *args, **kwargs) - env.set_choice_selected(env.next_state_name) - - return wrapper + MAX_CONCURRENCY = "maxConcurrency" + TOLERATED_FAILURE_COUNT = "toleratedFailureCount" + TOLERATED_FAILURE_PERCENTAGE = "toleratedFailurePercentage" def _decorated_updates_inspection_data(method, inspection_data_key: InspectionDataKey): def wrapper(env: TestStateEnvironment, *args, **kwargs): method(env, *args, **kwargs) - result = to_json_str(env.stack[-1]) + result = env.stack[-1] + if not isinstance(result, (int, float)): + result = to_json_str(result) # We know that the enum value used here corresponds to a supported inspection data field by design. env.inspection_data[inspection_data_key.value] = result # noqa return wrapper -def _decorate_state_field(state_field: CommonStateField) -> None: - if isinstance(state_field, ExecutionState): - state_field._eval_execution = _decorated_updates_inspection_data( - # As part of the decoration process, we intentionally access this protected member - # to facilitate the decorator's functionality. - method=state_field._eval_execution, # noqa - inspection_data_key=InspectionDataKey.RESULT, - ) - elif isinstance(state_field, StateChoice): - state_field._eval_body = _decorated_updated_choice_inspection_data( - # As part of the decoration process, we intentionally access this protected member - # to facilitate the decorator's functionality. - method=state_field._eval_body # noqa - ) +def _decorate_state_field(state_field: CommonStateField, is_single_state: bool = False) -> None: + if isinstance(state_field, StateMap): + MockedStateMap.wrap(state_field, is_single_state) + elif isinstance(state_field, StateParallel): + MockedStateParallel.wrap(state_field, is_single_state) + elif isinstance(state_field, StateTask): + MockedStateTask.wrap(state_field, is_single_state) + elif isinstance(state_field, (StateChoice, StatePass, StateFail, StateSucceed)): + MockedCommonState.wrap(state_field, is_single_state) + + +def find_state(state_name: str, states: dict[str, CommonStateField]) -> CommonStateField | None: + if state_name in states: + return states[state_name] + + for state in states.values(): + if isinstance(state, StateMap): + found_state = find_state(state_name, state.iteration_component._states.states) + if found_state: + return found_state + elif isinstance(state, StateParallel): + for program in state.branches.programs: + found_state = find_state(state_name, program.states.states) + if found_state: + return found_state class TestStatePreprocessor(Preprocessor): - STATE_NAME: Final[str] = "TestState" + STATE_NAME: Final[str] = "StateName" + _state_name_stack: list[str] = [] + + def to_test_state_program( + self, tree: ParseTree, state_name: str | None = None + ) -> TestStateProgram: + if is_production(tree, ASLParser.RULE_state_machine): + # full definition passed in + program = self.visitState_machine(ctx=tree) + state_field = find_state(state_name, program.states.states) + _decorate_state_field(state_field, False) + return TestStateProgram(state_field) - def visitState_decl_body(self, ctx: ASLParser.State_decl_bodyContext) -> TestStateProgram: + if is_production(tree, ASLParser.RULE_state_decl_body): + # single state case + state_props = self.visitState_decl_body(ctx=tree) + state_field = self._common_state_field_of(state_props=state_props) + _decorate_state_field(state_field, True) + return TestStateProgram(state_field) + + return super().visit(tree) + + def visitState_decl(self, ctx: ASLParser.State_declContext) -> CommonStateField: + # if we are parsing a full state machine, we need to record the state_name prior to stepping + # into the state body definition. + state_name = self._inner_string_of(parser_rule_context=ctx.string_literal()) + self._state_name_stack.append(state_name) + state_props: TestStateStateProps = self.visit(ctx.state_decl_body()) + state_field = self._common_state_field_of(state_props=state_props) + return state_field + + def visitState_decl_body(self, ctx: ASLParser.State_decl_bodyContext) -> TestStateStateProps: self._open_query_language_scope(ctx) state_props = TestStateStateProps() - state_props.name = self.STATE_NAME + state_props.name = ( + self._state_name_stack.pop(-1) if self._state_name_stack else self.STATE_NAME + ) for child in ctx.children: cmp = self.visit(child) state_props.add(cmp) - state_field = self._common_state_field_of(state_props=state_props) if state_props.get(QueryLanguage) is None: state_props.add(self._get_current_query_language()) - _decorate_state_field(state_field) self._close_query_language_scope() - return TestStateProgram(state_field) + return state_props def visitInput_path_decl(self, ctx: ASLParser.Input_path_declContext) -> InputPath: input_path: InputPath = super().visitInput_path_decl(ctx=ctx) @@ -129,3 +215,121 @@ def visitResult_decl(self, ctx: ASLParser.Result_declContext) -> Result: inspection_data_key=InspectionDataKey.RESULT, # noqa ) return result + + def visitMax_concurrency_int(self, ctx: ASLParser.Max_concurrency_intContext) -> MaxConcurrency: + max_concurrency: MaxConcurrency = super().visitMax_concurrency_int(ctx) + max_concurrency._eval_body = _decorated_updates_inspection_data( + method=max_concurrency._eval_body, + inspection_data_key=InspectionDataKey.MAX_CONCURRENCY, # noqa + ) + return max_concurrency + + def visitMax_concurrency_jsonata( + self, ctx: ASLParser.Max_concurrency_jsonataContext + ) -> MaxConcurrencyJSONata: + max_concurrency_jsonata: MaxConcurrencyJSONata = super().visitMax_concurrency_jsonata(ctx) + max_concurrency_jsonata._eval_body = _decorated_updates_inspection_data( + method=max_concurrency_jsonata._eval_body, + inspection_data_key=InspectionDataKey.MAX_CONCURRENCY, # noqa + ) + return max_concurrency_jsonata + + def visitMax_concurrency_path( + self, ctx: ASLParser.Max_concurrency_declContext + ) -> MaxConcurrencyPath: + max_concurrency_path: MaxConcurrencyPath = super().visitMax_concurrency_path(ctx) + max_concurrency_path._eval_body = _decorated_updates_inspection_data( + method=max_concurrency_path._eval_body, + inspection_data_key=InspectionDataKey.MAX_CONCURRENCY, # noqa + ) + return max_concurrency_path + + def visitTolerated_failure_count_int(self, ctx) -> ToleratedFailureCountInt: + tolerated_failure_count: ToleratedFailureCountInt = ( + super().visitTolerated_failure_count_int(ctx) + ) + tolerated_failure_count._eval_body = _decorated_updates_inspection_data( + method=tolerated_failure_count._eval_body, + inspection_data_key=InspectionDataKey.TOLERATED_FAILURE_COUNT, + ) + return tolerated_failure_count + + def visitTolerated_failure_count_path(self, ctx) -> ToleratedFailureCountPath: + tolerated_failure_count_path: ToleratedFailureCountPath = ( + super().visitTolerated_failure_count_path(ctx) + ) + tolerated_failure_count_path._eval_body = _decorated_updates_inspection_data( + method=tolerated_failure_count_path._eval_body, + inspection_data_key=InspectionDataKey.TOLERATED_FAILURE_COUNT, + ) + return tolerated_failure_count_path + + def visitTolerated_failure_count_string_jsonata( + self, ctx + ) -> ToleratedFailureCountStringJSONata: + tolerated_failure_count_jsonata: ToleratedFailureCountStringJSONata = ( + super().visitTolerated_failure_count_string_jsonata(ctx) + ) + tolerated_failure_count_jsonata._eval_body = _decorated_updates_inspection_data( + method=tolerated_failure_count_jsonata._eval_body, + inspection_data_key=InspectionDataKey.TOLERATED_FAILURE_COUNT, + ) + return tolerated_failure_count_jsonata + + def visitTolerated_failure_percentage_number(self, ctx) -> ToleratedFailurePercentage: + tolerated_failure_percentage: ToleratedFailurePercentage = ( + super().visitTolerated_failure_percentage_number(ctx) + ) + tolerated_failure_percentage._eval_body = _decorated_updates_inspection_data( + method=tolerated_failure_percentage._eval_body, + inspection_data_key=InspectionDataKey.TOLERATED_FAILURE_PERCENTAGE, + ) + return tolerated_failure_percentage + + def visitTolerated_failure_percentage_path(self, ctx) -> ToleratedFailurePercentagePath: + tolerated_failure_percentage_path: ToleratedFailurePercentagePath = ( + super().visitTolerated_failure_percentage_path(ctx) + ) + tolerated_failure_percentage_path._eval_body = _decorated_updates_inspection_data( + method=tolerated_failure_percentage_path._eval_body, + inspection_data_key=InspectionDataKey.TOLERATED_FAILURE_PERCENTAGE, + ) + return tolerated_failure_percentage_path + + def visitTolerated_failure_percentage_string_jsonata( + self, ctx + ) -> ToleratedFailurePercentageStringJSONata: + tolerated_failure_percentage_jsonata: ToleratedFailurePercentageStringJSONata = ( + super().visitTolerated_failure_percentage_string_jsonata(ctx) + ) + tolerated_failure_percentage_jsonata._eval_body = _decorated_updates_inspection_data( + method=tolerated_failure_percentage_jsonata._eval_body, + inspection_data_key=InspectionDataKey.TOLERATED_FAILURE_PERCENTAGE, + ) + return tolerated_failure_percentage_jsonata + + def visitItems_path_decl(self, ctx) -> ItemsPath: + items_path: ItemsPath = super().visitItems_path_decl(ctx) + items_path._eval_body = _decorated_updates_inspection_data( + method=items_path._eval_body, + inspection_data_key=InspectionDataKey.AFTER_ITEMS_PATH, + ) + return items_path + + def visitArguments_string_jsonata(self, ctx): + arguments: ArgumentsStringJSONata = super().visitArguments_string_jsonata(ctx) + arguments._eval_body = _decorated_updates_inspection_data( + method=arguments._eval_body, + inspection_data_key=InspectionDataKey.AFTER_ARGUMENTS, + ) + return arguments + + def visitArguments_jsonata_template_value_object(self, ctx): + arguments: ArgumentsJSONataTemplateValueObject = ( + super().visitArguments_jsonata_template_value_object(ctx) + ) + arguments._eval_body = _decorated_updates_inspection_data( + method=arguments._eval_body, + inspection_data_key=InspectionDataKey.AFTER_ARGUMENTS, + ) + return arguments diff --git a/localstack-core/localstack/services/stepfunctions/asl/static_analyser/test_state/test_state_analyser.py b/localstack-core/localstack/services/stepfunctions/asl/static_analyser/test_state/test_state_analyser.py index 79cb80196b54d..37a107dbf3a37 100644 --- a/localstack-core/localstack/services/stepfunctions/asl/static_analyser/test_state/test_state_analyser.py +++ b/localstack-core/localstack/services/stepfunctions/asl/static_analyser/test_state/test_state_analyser.py @@ -1,12 +1,51 @@ -from typing import Final +import json +from typing import Any, Final +# Botocore shape classes to drive validation +from botocore.model import ( + ListShape, + MapShape, + Shape, + StringShape, + StructureShape, +) + +from localstack.aws.api.stepfunctions import ( + Definition, + InvalidDefinition, + MockInput, + MockResponseValidationMode, + StateName, + TestStateConfiguration, + TestStateInput, + ValidationException, +) from localstack.services.stepfunctions.asl.antlr.runtime.ASLParser import ASLParser -from localstack.services.stepfunctions.asl.component.state.state_execution.state_task.service.resource import ( - ActivityResource, - Resource, - ServiceResource, +from localstack.services.stepfunctions.asl.component.state.state import CommonStateField +from localstack.services.stepfunctions.asl.component.state.state_execution.state_map.state_map import ( + StateMap, +) +from localstack.services.stepfunctions.asl.component.state.state_execution.state_parallel.state_parallel import ( + StateParallel, +) +from localstack.services.stepfunctions.asl.component.state.state_execution.state_task.service.state_task_service import ( + StateTaskService, +) +from localstack.services.stepfunctions.asl.component.state.state_execution.state_task.service.state_task_service_api_gateway import ( + StateTaskServiceApiGateway, +) +from localstack.services.stepfunctions.asl.component.state.state_execution.state_task.state_task import ( + StateTask, +) +from localstack.services.stepfunctions.asl.component.state.state_fail.state_fail import StateFail +from localstack.services.stepfunctions.asl.component.state.state_pass.state_pass import StatePass +from localstack.services.stepfunctions.asl.component.state.state_succeed.state_succeed import ( + StateSucceed, ) from localstack.services.stepfunctions.asl.component.state.state_type import StateType +from localstack.services.stepfunctions.asl.component.test_state.program.test_state_program import ( + TestStateProgram, +) from localstack.services.stepfunctions.asl.parse.test_state.asl_parser import ( TestStateAmazonStateLanguageParser, ) @@ -14,6 +53,11 @@ class TestStateStaticAnalyser(StaticAnalyser): + state_name: StateName | None + + def __init__(self, state_name: StateName | None = None): + self.state_name = state_name + _SUPPORTED_STATE_TYPES: Final[set[StateType]] = { StateType.Task, StateType.Pass, @@ -21,10 +65,260 @@ class TestStateStaticAnalyser(StaticAnalyser): StateType.Choice, StateType.Succeed, StateType.Fail, + StateType.Map, + StateType.Parallel, } - def analyse(self, definition) -> None: - _, parser_rule_context = TestStateAmazonStateLanguageParser.parse(definition) + @staticmethod + def is_state_in_definition(definition: Definition, state_name: StateName) -> bool: + test_program, _ = TestStateAmazonStateLanguageParser.parse(definition, state_name) + if not isinstance(test_program, TestStateProgram): + raise ValueError("expected parsed EvalComponent to be of type TestStateProgram") + + return test_program.test_state is not None + + @staticmethod + def validate_role_arn_required( + mock_input: MockInput, definition: Definition, state_name: StateName + ) -> None: + test_program, _ = TestStateAmazonStateLanguageParser.parse(definition, state_name) + test_state = test_program.test_state + if isinstance(test_state, StateTask) and mock_input is None: + raise ValidationException("RoleArn must be specified when testing a Task state") + + @staticmethod + def validate_state_configuration( + state_configuration: TestStateConfiguration | None, mock_input: MockInput + ): + if state_configuration is None: + return + + if "mapIterationFailureCount" not in state_configuration: + return + + if not mock_input: + raise ValidationException( + "TestState does not support MapIterationFailureCount when a mock is not specified." + ) + + mock_result_raw = mock_input.get("result") + if not mock_result_raw: + return + + mock_result = json.loads(mock_result_raw) + map_iteration_failure_count = state_configuration["mapIterationFailureCount"] + if isinstance(mock_result, list) and map_iteration_failure_count > len(mock_result): + raise ValidationException( + "Map iteration failure count must be less than or equal to the number of Map iterations" + ) + + @staticmethod + def validate_mock(test_state_input: TestStateInput) -> None: + test_program, _ = TestStateAmazonStateLanguageParser.parse( + test_state_input.get("definition"), test_state_input.get("stateName") + ) + test_state = test_program.test_state + mock_input = test_state_input.get("mock") + + TestStateStaticAnalyser.validate_test_state_allows_mocking( + mock_input=mock_input, test_state=test_state + ) + + if mock_input is None: + return + + if test_state_input.get("revealSecrets"): + raise ValidationException( + "TestState does not support RevealSecrets when a mock is specified." + ) + + if {"result", "errorOutput"} <= mock_input.keys(): + raise ValidationException( + "A test mock should have only one of the following fields: [result, errorOutput]." + ) + + mock_result_raw = mock_input.get("result") + if mock_result_raw is None: + return + try: + mock_result = json.loads(mock_result_raw) + except json.JSONDecodeError: + raise ValidationException("Mocked result must be valid JSON") + + if isinstance(test_state, StateMap): + TestStateStaticAnalyser.validate_mock_result_matches_map_definition( + mock_result=mock_result, test_state=test_state + ) + + if isinstance(test_state, StateParallel): + TestStateStaticAnalyser.validate_mock_result_matches_parallel_definition( + mock_result=mock_result, test_state=test_state + ) + + if isinstance(test_state, StateTaskService): + field_validation_mode = mock_input.get( + "fieldValidationMode", MockResponseValidationMode.STRICT + ) + TestStateStaticAnalyser.validate_mock_result_matches_api_shape( + mock_result=mock_result, + field_validation_mode=field_validation_mode, + test_state=test_state, + ) + + @staticmethod + def validate_test_state_allows_mocking( + mock_input: MockInput, test_state: CommonStateField + ) -> None: + if mock_input is None and isinstance(test_state, (StateMap, StateParallel)): + # This is a literal message when a Map or Parallel state is not accompanied by a mock in a test state request. + # The message is the same for both cases and is not parametrised anyhow. + raise InvalidDefinition( + "TestState API does not support Map or Parallel states. Supported state types include: [Task, Wait, Pass, Succeed, Fail, Choice]" + ) + + if mock_input is not None and isinstance(test_state, (StatePass, StateFail, StateSucceed)): + raise ValidationException( + f"State type '{test_state.state_type.name}' is not supported when a mock is specified" + ) + + @staticmethod + def validate_mock_result_matches_map_definition(mock_result: Any, test_state: StateMap): + if test_state.result_writer is not None and not isinstance(mock_result, dict): + raise ValidationException("Mocked result must be a JSON object.") + + if test_state.result_writer is None and not isinstance(mock_result, list): + raise ValidationException("Mocked result must be an array.") + + @staticmethod + def validate_mock_result_matches_parallel_definition( + mock_result: Any, test_state: StateParallel + ): + if not isinstance(mock_result, list): + raise ValidationException("Mocked result must be an array.") + + if len(mock_result) != len(test_state.branches.programs): + raise ValidationException( + "Mocked result must contain the same number of items as number of Parallel branches." + ) + + @staticmethod + def validate_mock_result_matches_api_shape( + mock_result: Any, + field_validation_mode: MockResponseValidationMode, + test_state: StateTaskService, + ): + # apigateway:invoke: has no equivalent in the AWS SDK service integration. + # Hence, the validation against botocore doesn't apply. + # See the note in https://docs.aws.amazon.com/step-functions/latest/dg/connect-api-gateway.html + # TODO do custom validation for apigateway:invoke: + if isinstance(test_state, StateTaskServiceApiGateway): + return + + if field_validation_mode == MockResponseValidationMode.NONE: + return + + boto_service_name = test_state._get_boto_service_name() + service_action_name = test_state._get_boto_service_action() + output_shape = test_state._get_boto_operation_model( + boto_service_name=boto_service_name, service_action_name=service_action_name + ).output_shape + + # If the operation has no output, there's nothing to validate + if output_shape is None: + return + + def _raise_type_error(expected_type: str, field_name: str) -> None: + raise ValidationException( + f"Mock result schema validation error: Field '{field_name}' must be {expected_type}" + ) + + def _validate_value(value: Any, shape: Shape, field_name: str | None = None) -> None: + # Document type accepts any JSON value + if shape.type_name == "document": + return + + if isinstance(shape, StructureShape): + if not isinstance(value, dict): + # this is a defensive check, the mock result is loaded from JSON before, so should always be a dict + raise ValidationException( + f"Mock result must be a valid JSON object, but got '{type(value)}' instead" + ) + # Build a mapping from SFN-normalised member keys -> botocore member shapes + members = shape.members + sfn_key_to_member_shape: dict[str, Shape] = { + StateTaskService._to_sfn_cased(member_key): member_shape + for member_key, member_shape in members.items() + } + if field_validation_mode == MockResponseValidationMode.STRICT: + # Ensure required members are present, using SFN-normalised keys + for required_key in shape.required_members: + sfn_required_key = StateTaskService._to_sfn_cased(required_key) + if sfn_required_key not in value: + raise ValidationException( + f"Mock result schema validation error: Required field '{sfn_required_key}' is missing" + ) + # Validate present fields (match SFN-normalised keys to member shapes) + for mock_field_name, mock_field_value in value.items(): + member_shape = sfn_key_to_member_shape.get(mock_field_name) + if member_shape is None: + # Fields that are present in mock but are not in the API spec should not raise validation errors - forward compatibility + continue + _validate_value(mock_field_value, member_shape, mock_field_name) + return + + if isinstance(shape, ListShape): + if not isinstance(value, list): + _raise_type_error("an array", field_name) + member_shape = shape.member + for list_item in value: + _validate_value(list_item, member_shape, field_name) + return + + if isinstance(shape, MapShape): + if not isinstance(value, dict): + _raise_type_error("an object", field_name) + value_shape = shape.value + for _, map_item_value in value.items(): + _validate_value(map_item_value, value_shape, field_name) + return + + # Primitive shapes and others + type_name = shape.type_name + match type_name: + case "string" | "timestamp": + if not isinstance(value, str): + _raise_type_error("a string", field_name) + # Validate enum if present + if isinstance(shape, StringShape): + enum = getattr(shape, "enum", None) + if enum and value not in enum: + raise ValidationException( + f"Mock result schema validation error: Field '{field_name}' is not an expected value" + ) + + case "integer" | "long": + if not isinstance(value, int) or isinstance(value, bool): + _raise_type_error("a number", field_name) + + case "float" | "double": + if not (isinstance(value, (int, float)) or isinstance(value, bool)): + _raise_type_error("a number", field_name) + + case "boolean": + if not isinstance(value, bool): + _raise_type_error("a boolean", field_name) + + case "blob": + if not (isinstance(value, (str, bytes))): + _raise_type_error("a string", field_name) + + # Perform validation against the output shape + _validate_value(mock_result, output_shape) + + def analyse(self, definition: str) -> None: + _, parser_rule_context = TestStateAmazonStateLanguageParser.parse( + definition, self.state_name + ) self.visit(parser_rule_context) def visitState_type(self, ctx: ASLParser.State_typeContext) -> None: @@ -32,18 +326,3 @@ def visitState_type(self, ctx: ASLParser.State_typeContext) -> None: state_type = StateType(state_type_value) if state_type not in self._SUPPORTED_STATE_TYPES: raise ValueError(f"Unsupported state type for TestState runs '{state_type}'.") - - def visitResource_decl(self, ctx: ASLParser.Resource_declContext) -> None: - resource_str: str = ctx.string_literal().getText()[1:-1] - resource = Resource.from_resource_arn(resource_str) - - if isinstance(resource, ActivityResource): - raise ValueError( - f"ActivityResources are not supported for TestState runs {resource_str}." - ) - - if isinstance(resource, ServiceResource): - if resource.condition is not None: - raise ValueError( - f"Service integration patterns are not supported for TestState runs {resource_str}." - ) diff --git a/localstack-core/localstack/services/stepfunctions/backend/execution.py b/localstack-core/localstack/services/stepfunctions/backend/execution.py index 2798bf7d479ee..5440afa0a8ea9 100644 --- a/localstack-core/localstack/services/stepfunctions/backend/execution.py +++ b/localstack-core/localstack/services/stepfunctions/backend/execution.py @@ -1,9 +1,8 @@ from __future__ import annotations import datetime -import json import logging -from typing import Final +from typing import Any, Final from localstack.aws.api.events import PutEventsRequestEntry from localstack.aws.api.stepfunctions import ( @@ -59,7 +58,7 @@ StateMachineInstance, StateMachineVersion, ) -from localstack.services.stepfunctions.mocking.mock_config import MockTestCase +from localstack.services.stepfunctions.local_mocking.mock_config import LocalMockTestCase LOG = logging.getLogger(__name__) @@ -108,10 +107,10 @@ class Execution: state_machine_version_arn: Final[Arn | None] state_machine_alias_arn: Final[Arn | None] - mock_test_case: Final[MockTestCase | None] + local_mock_test_case: Final[LocalMockTestCase | None] start_date: Final[Timestamp] - input_data: Final[json | None] + input_data: Final[dict[str, Any] | None] input_details: Final[CloudWatchEventsExecutionDataDetails | None] trace_header: Final[TraceHeader | None] _cloud_watch_logging_session: Final[CloudWatchLoggingSession | None] @@ -119,7 +118,7 @@ class Execution: exec_status: ExecutionStatus | None stop_date: Timestamp | None - output: json | None + output: dict[str, Any] | None output_details: CloudWatchEventsExecutionDataDetails | None error: SensitiveError | None @@ -141,10 +140,10 @@ def __init__( start_date: Timestamp, cloud_watch_logging_session: CloudWatchLoggingSession | None, activity_store: dict[Arn, Activity], - input_data: json | None = None, + input_data: dict[str, Any] | None = None, trace_header: TraceHeader | None = None, state_machine_alias_arn: Arn | None = None, - mock_test_case: MockTestCase | None = None, + local_mock_test_case: LocalMockTestCase | None = None, ): self.name = name self.sm_type = sm_type @@ -173,7 +172,7 @@ def __init__( self.error = None self.cause = None self._activity_store = activity_store - self.mock_test_case = mock_test_case + self.local_mock_test_case = local_mock_test_case def _get_events_client(self): return connect_to(aws_access_key_id=self.account_id, region_name=self.region_name).events @@ -304,7 +303,7 @@ def _get_start_execution_worker(self) -> ExecutionWorker: exec_comm=self._get_start_execution_worker_comm(), cloud_watch_logging_session=self._cloud_watch_logging_session, activity_store=self._activity_store, - mock_test_case=self.mock_test_case, + local_mock_test_case=self.local_mock_test_case, ) def start(self) -> None: @@ -391,7 +390,7 @@ def _get_start_execution_worker(self) -> SyncExecutionWorker: exec_comm=self._get_start_execution_worker_comm(), cloud_watch_logging_session=self._cloud_watch_logging_session, activity_store=self._activity_store, - mock_test_case=self.mock_test_case, + local_mock_test_case=self.local_mock_test_case, ) def _get_start_execution_worker_comm(self) -> BaseExecutionWorkerCommunication: diff --git a/localstack-core/localstack/services/stepfunctions/backend/execution_worker.py b/localstack-core/localstack/services/stepfunctions/backend/execution_worker.py index c3f382c883a71..24413272d2262 100644 --- a/localstack-core/localstack/services/stepfunctions/backend/execution_worker.py +++ b/localstack-core/localstack/services/stepfunctions/backend/execution_worker.py @@ -29,7 +29,7 @@ from localstack.services.stepfunctions.backend.execution_worker_comm import ( ExecutionWorkerCommunication, ) -from localstack.services.stepfunctions.mocking.mock_config import MockTestCase +from localstack.services.stepfunctions.local_mocking.mock_config import LocalMockTestCase from localstack.utils.common import TMP_THREADS @@ -37,7 +37,7 @@ class ExecutionWorker: _evaluation_details: Final[EvaluationDetails] _execution_communication: Final[ExecutionWorkerCommunication] _cloud_watch_logging_session: Final[CloudWatchLoggingSession | None] - _mock_test_case: Final[MockTestCase | None] + _local_mock_test_case: Final[LocalMockTestCase | None] _activity_store: dict[Arn, Activity] env: Environment | None @@ -48,12 +48,12 @@ def __init__( exec_comm: ExecutionWorkerCommunication, cloud_watch_logging_session: CloudWatchLoggingSession | None, activity_store: dict[Arn, Activity], - mock_test_case: MockTestCase | None = None, + local_mock_test_case: LocalMockTestCase | None = None, ): self._evaluation_details = evaluation_details self._execution_communication = exec_comm self._cloud_watch_logging_session = cloud_watch_logging_session - self._mock_test_case = mock_test_case + self._local_mock_test_case = local_mock_test_case self._activity_store = activity_store self.env = None @@ -82,7 +82,7 @@ def _get_evaluation_environment(self) -> Environment: event_history_context=EventHistoryContext.of_program_start(), cloud_watch_logging_session=self._cloud_watch_logging_session, activity_store=self._activity_store, - mock_test_case=self._mock_test_case, + local_mock_test_case=self._local_mock_test_case, ) def _execution_logic(self): diff --git a/localstack-core/localstack/services/stepfunctions/backend/store.py b/localstack-core/localstack/services/stepfunctions/backend/models.py similarity index 100% rename from localstack-core/localstack/services/stepfunctions/backend/store.py rename to localstack-core/localstack/services/stepfunctions/backend/models.py diff --git a/localstack-core/localstack/services/stepfunctions/backend/test_state/execution.py b/localstack-core/localstack/services/stepfunctions/backend/test_state/execution.py index 92fcb8546c0d6..7631ec5f1e7d9 100644 --- a/localstack-core/localstack/services/stepfunctions/backend/test_state/execution.py +++ b/localstack-core/localstack/services/stepfunctions/backend/test_state/execution.py @@ -12,14 +12,18 @@ TestStateOutput, Timestamp, ) -from localstack.services.stepfunctions.asl.eval.evaluation_details import EvaluationDetails +from localstack.services.stepfunctions.asl.eval.evaluation_details import ( + EvaluationDetails, +) from localstack.services.stepfunctions.asl.eval.program_state import ( ProgramEnded, ProgramError, ProgramState, ) from localstack.services.stepfunctions.asl.eval.test_state.program_state import ( + ProgramCaughtError, ProgramChoiceSelected, + ProgramRetriable, ) from localstack.services.stepfunctions.asl.utils.encoding import to_json_str from localstack.services.stepfunctions.backend.activity import Activity @@ -31,6 +35,7 @@ from localstack.services.stepfunctions.backend.test_state.execution_worker import ( TestStateExecutionWorker, ) +from localstack.services.stepfunctions.backend.test_state.test_state_mock import TestStateMock LOG = logging.getLogger(__name__) @@ -38,6 +43,9 @@ class TestStateExecution(Execution): exec_worker: TestStateExecutionWorker | None next_state: str | None + state_name: str | None + mock: TestStateMock | None + variables: dict | None class TestCaseExecutionWorkerCommunication(BaseExecutionWorkerCommunication): _execution: TestStateExecution @@ -48,6 +56,16 @@ def terminated(self) -> None: self.execution.exec_status = ExecutionStatus.SUCCEEDED self.execution.output = self.execution.exec_worker.env.states.get_input() self.execution.next_state = exit_program_state.next_state_name + elif isinstance(exit_program_state, ProgramCaughtError): + self.execution.exec_status = ExecutionStatus.SUCCEEDED + self.execution.error = exit_program_state.error + self.execution.cause = exit_program_state.cause + self.execution.output = self.execution.exec_worker.env.states.get_input() + self.execution.next_state = exit_program_state.next_state_name + elif isinstance(exit_program_state, ProgramRetriable): + self.execution.exec_status = ExecutionStatus.SUCCEEDED + self.execution.error = exit_program_state.error + self.execution.cause = exit_program_state.cause else: self._reflect_execution_status() @@ -61,7 +79,10 @@ def __init__( state_machine: StateMachineInstance, start_date: Timestamp, activity_store: dict[Arn, Activity], + state_name: str | None = None, input_data: dict | None = None, + mock: TestStateMock | None = None, + variables: dict | None = None, ): super().__init__( name=name, @@ -79,6 +100,9 @@ def __init__( ) self._execution_terminated_event = threading.Event() self.next_state = None + self.state_name = state_name + self.mock = mock + self.variables = variables def _get_start_execution_worker_comm(self) -> BaseExecutionWorkerCommunication: return self.TestCaseExecutionWorkerCommunication(self) @@ -93,6 +117,9 @@ def _get_start_execution_worker(self) -> TestStateExecutionWorker: exec_comm=self._get_start_execution_worker_comm(), cloud_watch_logging_session=self._cloud_watch_logging_session, activity_store=self._activity_store, + state_name=self.state_name, + mock=self.mock, + variables=self.variables, ) def publish_execution_status_change_event(self): @@ -117,6 +144,21 @@ def to_test_state_output(self, inspection_level: InspectionLevel) -> TestStateOu test_state_output = TestStateOutput( status=TestExecutionStatus.SUCCEEDED, nextState=self.next_state, output=output_str ) + elif isinstance(exit_program_state, ProgramCaughtError): + output_str = to_json_str(self.output) + test_state_output = TestStateOutput( + status=TestExecutionStatus.CAUGHT_ERROR, + nextState=self.next_state, + output=output_str, + error=exit_program_state.error, + cause=exit_program_state.cause, + ) + elif isinstance(exit_program_state, ProgramRetriable): + test_state_output = TestStateOutput( + status=TestExecutionStatus.RETRIABLE, + error=exit_program_state.error, + cause=exit_program_state.cause, + ) else: # TODO: handle other statuses LOG.warning( diff --git a/localstack-core/localstack/services/stepfunctions/backend/test_state/execution_worker.py b/localstack-core/localstack/services/stepfunctions/backend/test_state/execution_worker.py index 5caae15dc3780..32de04fef6b65 100644 --- a/localstack-core/localstack/services/stepfunctions/backend/test_state/execution_worker.py +++ b/localstack-core/localstack/services/stepfunctions/backend/test_state/execution_worker.py @@ -1,26 +1,61 @@ +from localstack.aws.api.stepfunctions import Arn, StateName from localstack.services.stepfunctions.asl.component.eval_component import EvalComponent from localstack.services.stepfunctions.asl.eval.environment import Environment +from localstack.services.stepfunctions.asl.eval.evaluation_details import EvaluationDetails from localstack.services.stepfunctions.asl.eval.event.event_manager import ( EventHistoryContext, ) +from localstack.services.stepfunctions.asl.eval.event.logging import ( + CloudWatchLoggingSession, +) from localstack.services.stepfunctions.asl.eval.states import ( ContextObjectData, ExecutionData, StateMachineData, ) from localstack.services.stepfunctions.asl.eval.test_state.environment import TestStateEnvironment +from localstack.services.stepfunctions.asl.eval.variable_store import VariableStore from localstack.services.stepfunctions.asl.parse.test_state.asl_parser import ( TestStateAmazonStateLanguageParser, ) +from localstack.services.stepfunctions.backend.activity import Activity from localstack.services.stepfunctions.backend.execution_worker import SyncExecutionWorker +from localstack.services.stepfunctions.backend.execution_worker_comm import ( + ExecutionWorkerCommunication, +) +from localstack.services.stepfunctions.backend.test_state.test_state_mock import TestStateMock class TestStateExecutionWorker(SyncExecutionWorker): env: TestStateEnvironment | None + state_name: str | None = None + mock: TestStateMock | None + variables: dict | None + + def __init__( + self, + evaluation_details: EvaluationDetails, + exec_comm: ExecutionWorkerCommunication, + cloud_watch_logging_session: CloudWatchLoggingSession | None, + activity_store: dict[Arn, Activity], + state_name: StateName | None = None, + mock: TestStateMock | None = None, + variables: dict | None = None, + ): + super().__init__( + evaluation_details, + exec_comm, + cloud_watch_logging_session, + activity_store, + local_mock_test_case=None, # local mock is only applicable to SFN Local, but not for TestState + ) + self.state_name = state_name + self.mock = mock + self.variables = variables def _get_evaluation_entrypoint(self) -> EvalComponent: return TestStateAmazonStateLanguageParser.parse( - self._evaluation_details.state_machine_details.definition + self._evaluation_details.state_machine_details.definition, self.state_name )[0] def _get_evaluation_environment(self) -> Environment: @@ -43,4 +78,6 @@ def _get_evaluation_environment(self) -> Environment: event_history_context=EventHistoryContext.of_program_start(), cloud_watch_logging_session=self._cloud_watch_logging_session, activity_store=self._activity_store, + variable_store=VariableStore(self.variables), + mock=self.mock, ) diff --git a/localstack-core/localstack/services/stepfunctions/backend/test_state/test_state_mock.py b/localstack-core/localstack/services/stepfunctions/backend/test_state/test_state_mock.py new file mode 100644 index 0000000000000..c4822fddc65a6 --- /dev/null +++ b/localstack-core/localstack/services/stepfunctions/backend/test_state/test_state_mock.py @@ -0,0 +1,127 @@ +import copy +import json +from typing import Final + +from pydantic import ( + ValidationError, +) + +from localstack.aws.api.stepfunctions import ( + HistoryEventType, + MockInput, + TaskFailedEventDetails, + TestStateConfiguration, +) +from localstack.services.stepfunctions.asl.component.common.error_name.error_name import ErrorName +from localstack.services.stepfunctions.asl.component.common.error_name.failure_event import ( + FailureEvent, + FailureEventException, +) +from localstack.services.stepfunctions.asl.component.state.state_type import StateType +from localstack.services.stepfunctions.asl.eval.environment import Environment +from localstack.services.stepfunctions.asl.eval.event.event_detail import EventDetails +from localstack.services.stepfunctions.asl.eval.states import ( + ContextObjectData, +) +from localstack.services.stepfunctions.test_state.mock_config import ( + TestStateContextObjectValidator, + TestStateMockedResponse, + TestStateResponseReturn, + TestStateResponseThrow, +) + + +def eval_mocked_response_throw(env: Environment, mocked_response: TestStateResponseThrow) -> None: + task_failed_event_details = TaskFailedEventDetails( + error=mocked_response.error, cause=mocked_response.cause + ) + error_name = ErrorName(mocked_response.error) + failure_event = FailureEvent( + env=env, + error_name=error_name, + event_type=HistoryEventType.TaskFailed, # TODO(gregfurman): Should this be state specific? + event_details=EventDetails(taskFailedEventDetails=task_failed_event_details), + ) + raise FailureEventException(failure_event=failure_event) + + +class TestStateMock: + _mock_input: MockInput | None + _state_configuration: TestStateConfiguration | None + _result_stack: Final[list[TestStateMockedResponse]] + _context: Final[ContextObjectData | None] + + def __init__( + self, + mock_input: MockInput | None, + state_configuration: TestStateConfiguration | None, + context: str | None, + ): + self._mock_input = mock_input + self._state_configuration = state_configuration + self._result_stack = [] + self._context = None + + if not mock_input: + return + + self._context = None if context is None else self.parse_context(context) + + if mock_result_raw := mock_input.get("result"): + mock = json.loads(mock_result_raw) + self._result_stack.append(TestStateResponseReturn(mock)) + return + + if mock_error_output := mock_input.get("errorOutput"): + mock = copy.deepcopy(mock_error_output) + self._result_stack.append(TestStateResponseThrow(**mock)) + return + + def is_mocked(self): + if self._mock_input or self._state_configuration: + return True + + return False + + def add_result(self, result: TestStateMockedResponse): + mock = copy.deepcopy(result) + self._result_stack.append(mock) + + def get_next_result(self) -> TestStateMockedResponse: + if not self._result_stack: + return None + return self._result_stack.pop() + + def get_context(self) -> ContextObjectData | None: + if self._context is not None: + return copy.deepcopy(self._context) + return None + + @staticmethod + def parse_context(context: str, state_type: StateType = None) -> ContextObjectData: + """Parse and validate context JSON string.""" + try: + validation_result = TestStateContextObjectValidator.model_validate_json(context) + return validation_result.model_dump(exclude_unset=True, exclude_none=True) + except ValidationError as e: + error = e.errors()[0] + path_str = ".".join(str(x) for x in error["loc"]) + + match error: + case {"type": "extra_forbidden", "loc": ("Map",)}: + raise ValueError("'Map' field is not supported when mocking a Context object") + + case {"type": "extra_forbidden", "loc": (*_, forbidden_key)}: + raise ValueError(f"Field '{forbidden_key}' is not allowed") + + case {"type": t} if t in ("string_type", "int_type", "dict_type", "model_type"): + expected_map = { + "string_type": "string", + "int_type": "integer", + "dict_type": "object", + "model_type": "object", + } + expected = expected_map.get(t, "valid type") + raise ValueError(f"{path_str} must be a {expected}") + case _: + raise ValueError(f"{error['msg']}") diff --git a/localstack-core/localstack/services/stepfunctions/local_mocking/__init__.py b/localstack-core/localstack/services/stepfunctions/local_mocking/__init__.py new file mode 100644 index 0000000000000..168f86b9bc63a --- /dev/null +++ b/localstack-core/localstack/services/stepfunctions/local_mocking/__init__.py @@ -0,0 +1,9 @@ +""" +local_mocking +------------- + +The implementation of the Step Functions Local Mocking + +Note that Step Functions Local is different from TestState API mocks. +TestState API mocking works differently and is implemented separately. +""" diff --git a/localstack-core/localstack/services/stepfunctions/mocking/mock_config.py b/localstack-core/localstack/services/stepfunctions/local_mocking/mock_config.py similarity index 88% rename from localstack-core/localstack/services/stepfunctions/mocking/mock_config.py rename to localstack-core/localstack/services/stepfunctions/local_mocking/mock_config.py index 10213d2b45f56..62cedf0480c9d 100644 --- a/localstack-core/localstack/services/stepfunctions/mocking/mock_config.py +++ b/localstack-core/localstack/services/stepfunctions/local_mocking/mock_config.py @@ -1,7 +1,7 @@ import abc from typing import Any, Final -from localstack.services.stepfunctions.mocking.mock_config_file import ( +from localstack.services.stepfunctions.local_mocking.mock_config_file import ( RawMockConfig, RawResponseModel, RawTestCase, @@ -9,7 +9,7 @@ ) -class MockedResponse(abc.ABC): +class LocalMockedResponse(abc.ABC): range_start: Final[int] range_end: Final[int] @@ -28,7 +28,7 @@ def __init__(self, range_start: int, range_end: int): self.range_end = range_end -class MockedResponseReturn(MockedResponse): +class LocalMockedResponseReturn(LocalMockedResponse): payload: Final[Any] def __init__(self, range_start: int, range_end: int, payload: Any): @@ -36,7 +36,7 @@ def __init__(self, range_start: int, range_end: int, payload: Any): self.payload = payload -class MockedResponseThrow(MockedResponse): +class LocalMockedResponseThrow(LocalMockedResponse): error: Final[str] cause: Final[str] @@ -49,10 +49,13 @@ def __init__(self, range_start: int, range_end: int, error: str, cause: str): class StateMockedResponses: state_name: Final[str] mocked_response_name: Final[str] - mocked_responses: Final[list[MockedResponse]] + mocked_responses: Final[list[LocalMockedResponse]] def __init__( - self, state_name: str, mocked_response_name: str, mocked_responses: list[MockedResponse] + self, + state_name: str, + mocked_response_name: str, + mocked_responses: list[LocalMockedResponse], ): self.state_name = state_name self.mocked_response_name = mocked_response_name @@ -74,7 +77,7 @@ def __init__( last_range_end = mocked_response.range_end -class MockTestCase: +class LocalMockTestCase: state_machine_name: Final[str] test_case_name: Final[str] state_mocked_responses: Final[dict[str, StateMockedResponses]] @@ -127,13 +130,15 @@ def _parse_mocked_response_range(string_definition: str) -> tuple[int, int]: def _mocked_response_from_raw( raw_response_model_range: str, raw_response_model: RawResponseModel -) -> MockedResponse: +) -> LocalMockedResponse: range_start, range_end = _parse_mocked_response_range(raw_response_model_range) if raw_response_model.Return: payload = raw_response_model.Return.model_dump() - return MockedResponseReturn(range_start=range_start, range_end=range_end, payload=payload) + return LocalMockedResponseReturn( + range_start=range_start, range_end=range_end, payload=payload + ) throw_definition = raw_response_model.Throw - return MockedResponseThrow( + return LocalMockedResponseThrow( range_start=range_start, range_end=range_end, error=throw_definition.Error, @@ -143,7 +148,7 @@ def _mocked_response_from_raw( def _mocked_responses_from_raw( mocked_response_name: str, raw_mock_config: RawMockConfig -) -> list[MockedResponse]: +) -> list[LocalMockedResponse]: raw_response_models: dict[str, RawResponseModel] | None = raw_mock_config.MockedResponses.get( mocked_response_name ) @@ -151,9 +156,9 @@ def _mocked_responses_from_raw( raise RuntimeError( f"No definitions for mocked response '{mocked_response_name}' in the mock configuration file." ) - mocked_responses: list[MockedResponse] = [] + mocked_responses: list[LocalMockedResponse] = [] for raw_response_model_range, raw_response_model in raw_response_models.items(): - mocked_response: MockedResponse = _mocked_response_from_raw( + mocked_response: LocalMockedResponse = _mocked_response_from_raw( raw_response_model_range=raw_response_model_range, raw_response_model=raw_response_model ) mocked_responses.append(mocked_response) @@ -175,7 +180,7 @@ def _state_mocked_responses_from_raw( def _mock_test_case_from_raw( state_machine_name: str, test_case_name: str, raw_mock_config: RawMockConfig -) -> MockTestCase: +) -> LocalMockTestCase: state_machine = raw_mock_config.StateMachines.get(state_machine_name) if not state_machine: raise RuntimeError( @@ -195,18 +200,20 @@ def _mock_test_case_from_raw( raw_mock_config=raw_mock_config, ) state_mocked_responses_list.append(state_mocked_responses) - return MockTestCase( + return LocalMockTestCase( state_machine_name=state_machine_name, test_case_name=test_case_name, state_mocked_responses_list=state_mocked_responses_list, ) -def load_mock_test_case_for(state_machine_name: str, test_case_name: str) -> MockTestCase | None: +def load_local_mock_test_case_for( + state_machine_name: str, test_case_name: str +) -> LocalMockTestCase | None: raw_mock_config: RawMockConfig | None = _load_sfn_raw_mock_config() if raw_mock_config is None: return None - mock_test_case: MockTestCase = _mock_test_case_from_raw( + mock_test_case: LocalMockTestCase = _mock_test_case_from_raw( state_machine_name=state_machine_name, test_case_name=test_case_name, raw_mock_config=raw_mock_config, diff --git a/localstack-core/localstack/services/stepfunctions/mocking/mock_config_file.py b/localstack-core/localstack/services/stepfunctions/local_mocking/mock_config_file.py similarity index 100% rename from localstack-core/localstack/services/stepfunctions/mocking/mock_config_file.py rename to localstack-core/localstack/services/stepfunctions/local_mocking/mock_config_file.py diff --git a/localstack-core/localstack/services/stepfunctions/provider.py b/localstack-core/localstack/services/stepfunctions/provider.py index 19e3e68e07603..08d0459fd26bd 100644 --- a/localstack-core/localstack/services/stepfunctions/provider.py +++ b/localstack-core/localstack/services/stepfunctions/provider.py @@ -63,7 +63,6 @@ Publish, PublishStateMachineVersionOutput, ResourceNotFound, - RevealSecrets, ReverseOrder, RevisionId, RoutingConfigurationList, @@ -89,6 +88,7 @@ TaskDoesNotExist, TaskTimedOut, TaskToken, + TestStateInput, TestStateOutput, ToleratedFailureCount, ToleratedFailurePercentage, @@ -140,19 +140,20 @@ from localstack.services.stepfunctions.backend.activity import Activity, ActivityTask from localstack.services.stepfunctions.backend.alias import Alias from localstack.services.stepfunctions.backend.execution import Execution, SyncExecution +from localstack.services.stepfunctions.backend.models import SFNStore, sfn_stores from localstack.services.stepfunctions.backend.state_machine import ( StateMachineInstance, StateMachineRevision, StateMachineVersion, TestStateMachine, ) -from localstack.services.stepfunctions.backend.store import SFNStore, sfn_stores from localstack.services.stepfunctions.backend.test_state.execution import ( TestStateExecution, ) -from localstack.services.stepfunctions.mocking.mock_config import ( - MockTestCase, - load_mock_test_case_for, +from localstack.services.stepfunctions.backend.test_state.test_state_mock import TestStateMock +from localstack.services.stepfunctions.local_mocking.mock_config import ( + LocalMockTestCase, + load_local_mock_test_case_for, ) from localstack.services.stepfunctions.stepfunctions_utils import ( assert_pagination_parameters_valid, @@ -160,6 +161,7 @@ normalise_max_results, ) from localstack.state import StateVisitor +from localstack.utils.aws import arns from localstack.utils.aws.arns import ( ARN_PARTITION_REGEX, stepfunctions_activity_arn, @@ -772,14 +774,16 @@ def _get_state_machine_arn(state_machine_arn: str) -> str: return state_machine_arn.split("#")[0] @staticmethod - def _get_mock_test_case(state_machine_arn: str, state_machine_name: str) -> MockTestCase | None: + def _get_local_mock_test_case( + state_machine_arn: str, state_machine_name: str + ) -> LocalMockTestCase | None: """Extract and load a mock test case from a state machine ARN if present.""" parts = state_machine_arn.split("#") if len(parts) != 2: return None mock_test_case_name = parts[1] - mock_test_case = load_mock_test_case_for( + mock_test_case = load_local_mock_test_case_for( state_machine_name=state_machine_name, test_case_name=mock_test_case_name ) if mock_test_case is None: @@ -856,7 +860,9 @@ def start_execution( configuration=state_machine_clone.cloud_watch_logging_configuration, ) - mock_test_case = self._get_mock_test_case(state_machine_arn, state_machine_clone.name) + local_mock_test_case = self._get_local_mock_test_case( + state_machine_arn, state_machine_clone.name + ) execution = Execution( name=exec_name, @@ -872,7 +878,7 @@ def start_execution( input_data=input_data, trace_header=trace_header, activity_store=self.get_store(context).activities, - mock_test_case=mock_test_case, + local_mock_test_case=local_mock_test_case, ) store.executions[exec_arn] = execution @@ -932,7 +938,9 @@ def start_sync_execution( configuration=state_machine_clone.cloud_watch_logging_configuration, ) - mock_test_case = self._get_mock_test_case(state_machine_arn, state_machine_clone.name) + local_mock_test_case = self._get_local_mock_test_case( + state_machine_arn, state_machine_clone.name + ) execution = SyncExecution( name=exec_name, @@ -947,7 +955,7 @@ def start_sync_execution( input_data=input_data, trace_header=trace_header, activity_store=self.get_store(context).activities, - mock_test_case=mock_test_case, + local_mock_test_case=local_mock_test_case, ) self.get_store(context).executions[exec_arn] = execution @@ -1483,35 +1491,85 @@ def update_map_run( raise ResourceNotFound() def test_state( - self, - context: RequestContext, - definition: Definition, - role_arn: Arn = None, - input: SensitiveData = None, - inspection_level: InspectionLevel = None, - reveal_secrets: RevealSecrets = None, - variables: SensitiveData = None, - **kwargs, + self, context: RequestContext, request: TestStateInput, **kwargs ) -> TestStateOutput: + state_name = request.get("stateName") + definition = request["definition"] + StepFunctionsProvider._validate_definition( - definition=definition, static_analysers=[TestStateStaticAnalyser()] + definition=definition, + static_analysers=[TestStateStaticAnalyser(state_name)], ) + # if StateName is present, we need to ensure the state being referenced exists in full definition. + if state_name and not TestStateStaticAnalyser.is_state_in_definition( + definition=definition, state_name=state_name + ): + raise ValidationException("State not found in definition") + + mock_input = request.get("mock") + state_configuration = request.get("stateConfiguration") + + TestStateStaticAnalyser.validate_state_configuration(state_configuration, mock_input) + TestStateStaticAnalyser.validate_mock(test_state_input=request) + + if state_context := request.get("context"): + # TODO: Add validation ensuring only present if 'mock' is specified + # An error occurred (ValidationException) when calling the TestState operation: State type 'Pass' is not supported when a mock is specified + pass + + try: + state_mock = TestStateMock( + mock_input=mock_input, + state_configuration=state_configuration, + context=state_context, + ) + except ValueError as e: + LOG.error(e) + raise ValidationException(f"Invalid Context object provided: {e}") + name: Name | None = f"TestState-{short_uid()}" arn = stepfunctions_state_machine_arn( name=name, account_id=context.account_id, region_name=context.region ) + role_arn = request.get("roleArn") + if role_arn is None: + TestStateStaticAnalyser.validate_role_arn_required( + mock_input=mock_input, definition=definition, state_name=state_name + ) + # HACK: Added dummy role ARN because it is a required field in Execution. + # To allow optional roleArn for the test state but preserve the mandatory one for regular executions + # we likely need to remove inheritance TestStateExecution(Execution) in favor of composition. + # TestState execution starts to have too many simplifications compared to a regular execution + # which renders the inheritance mechanism harmful. + # TODO make role_arn optional in TestStateExecution + role_arn = arns.iam_role_arn( + role_name=f"RoleFor-{name}", + account_id=context.account_id, + region_name=context.region, + ) + state_machine = TestStateMachine( name=name, arn=arn, role_arn=role_arn, - definition=definition, + definition=request["definition"], ) - exec_arn = stepfunctions_standard_execution_arn(state_machine.arn, name) - input_json = json.loads(input) + # HACK(gregfurman): The ARN that gets generated has a duplicate 'name' field in the + # resource ARN. Just replace this duplication and extract the execution ID. + exec_arn = stepfunctions_express_execution_arn(state_machine.arn, name) + exec_arn = exec_arn.replace(f":{name}:{name}:", f":{name}:", 1) + _, exec_name = exec_arn.rsplit(":", 1) + + if input_json := request.get("input", {}): + input_json = json.loads(input_json) + + if variables_json := request.get("variables"): + variables_json = json.loads(variables_json) + execution = TestStateExecution( - name=name, + name=exec_name, role_arn=role_arn, exec_arn=exec_arn, account_id=context.account_id, @@ -1519,12 +1577,15 @@ def test_state( state_machine=state_machine, start_date=datetime.datetime.now(tz=datetime.UTC), input_data=input_json, + state_name=state_name, activity_store=self.get_store(context).activities, + mock=state_mock, + variables=variables_json, ) execution.start() test_state_output = execution.to_test_state_output( - inspection_level=inspection_level or InspectionLevel.INFO + inspection_level=request.get("inspectionLevel", InspectionLevel.INFO) ) return test_state_output diff --git a/localstack-core/localstack/services/stepfunctions/test_state/mock_config.py b/localstack-core/localstack/services/stepfunctions/test_state/mock_config.py new file mode 100644 index 0000000000000..6731a44cf78fc --- /dev/null +++ b/localstack-core/localstack/services/stepfunctions/test_state/mock_config.py @@ -0,0 +1,47 @@ +import abc +from typing import Any, Final + +from pydantic import BaseModel, ConfigDict, StrictInt, StrictStr, create_model + +from localstack.services.stepfunctions.asl.eval.states import ( + ExecutionData, + StateData, + StateMachineData, + TaskData, +) + + +class TestStateMockedResponse(abc.ABC): + pass + + +class TestStateResponseReturn(TestStateMockedResponse): + payload: Final[Any] + + def __init__(self, payload: Any): + self.payload = payload + + +class TestStateResponseThrow(TestStateMockedResponse): + error: Final[str] + cause: Final[str] + + def __init__(self, error: str, cause: str): + self.error = error + self.cause = cause + + +def _to_strict_model(name: str, source: type): + type_map = {str: StrictStr, int: StrictInt} + fields = {k: (type_map.get(v, v) | None, None) for k, v in source.__annotations__.items()} + return create_model(name, __config__=ConfigDict(extra="forbid"), **fields) + + +TestStateContextObjectValidator: Final[type[BaseModel]] = create_model( + "ContextValidator", + __config__=ConfigDict(extra="forbid"), + Execution=(_to_strict_model("Execution", ExecutionData) | None, None), + State=(_to_strict_model("State", StateData) | None, None), + StateMachine=(_to_strict_model("StateMachine", StateMachineData) | None, None), + Task=(_to_strict_model("Task", TaskData) | None, None), +) diff --git a/localstack-core/localstack/services/stores.py b/localstack-core/localstack/services/stores.py index 8558746eec0c6..ad9a566b83205 100644 --- a/localstack-core/localstack/services/stores.py +++ b/localstack-core/localstack/services/stores.py @@ -32,7 +32,7 @@ class SqsStore(BaseStore): import re from collections.abc import Callable, Iterator from threading import RLock -from typing import Any, Generic, TypeVar +from typing import Any, TypeVar from localstack import config from localstack.utils.aws.aws_stack import get_valid_regions_for_service @@ -190,7 +190,7 @@ def __repr__(self): # -class RegionBundle(dict, Generic[BaseStoreType]): +class RegionBundle[BaseStoreType](dict): """ Encapsulation for stores across all regions for a specific AWS account ID. """ @@ -281,7 +281,7 @@ def reset(self, _reset_universal: bool = False): self.clear() -class AccountRegionBundle(dict, Generic[BaseStoreType]): +class AccountRegionBundle[BaseStoreType](dict): """ Encapsulation for all stores for all AWS account IDs. """ diff --git a/localstack-core/localstack/services/sts/models.py b/localstack-core/localstack/services/sts/models.py index de28b1e723647..ded792fd5665e 100644 --- a/localstack-core/localstack/services/sts/models.py +++ b/localstack-core/localstack/services/sts/models.py @@ -1,4 +1,4 @@ -from typing import TypedDict +from typing import Any, TypedDict from localstack.aws.api.sts import Tag from localstack.services.stores import AccountRegionBundle, BaseStore, CrossRegionAttribute @@ -10,7 +10,7 @@ class SessionConfig(TypedDict): # list of lowercase transitive tag keys transitive_tags: list[str] # other stored context variables - iam_context: dict[str, str | list[str]] + iam_context: dict[str, Any] class STSStore(BaseStore): diff --git a/localstack-core/localstack/services/sts/provider.py b/localstack-core/localstack/services/sts/provider.py index a4b76117a89e9..f2f56ad6eb950 100644 --- a/localstack-core/localstack/services/sts/provider.py +++ b/localstack-core/localstack/services/sts/provider.py @@ -23,6 +23,7 @@ from localstack.services.moto import call_moto from localstack.services.plugins import ServiceLifecycleHook from localstack.services.sts.models import SessionConfig, sts_stores +from localstack.state import StateVisitor from localstack.utils.aws.arns import extract_account_id_from_arn from localstack.utils.aws.request_context import extract_access_key_id_from_auth_header @@ -50,6 +51,12 @@ class StsProvider(StsApi, ServiceLifecycleHook): def __init__(self): apply_iam_patches() + def accept_state_visitor(self, visitor: StateVisitor): + from moto.sts.models import sts_backends + + visitor.visit(sts_backends) + visitor.visit(sts_stores) + def get_caller_identity(self, context: RequestContext, **kwargs) -> GetCallerIdentityResponse: response = call_moto(context) if "user/moto" in response["Arn"] and "sts" in response["Arn"]: diff --git a/localstack-core/localstack/services/support/provider.py b/localstack-core/localstack/services/support/provider.py index 5a31be07baf6d..6d136ef975280 100644 --- a/localstack-core/localstack/services/support/provider.py +++ b/localstack-core/localstack/services/support/provider.py @@ -1,7 +1,11 @@ from abc import ABC from localstack.aws.api.support import SupportApi +from localstack.state import StateVisitor class SupportProvider(SupportApi, ABC): - pass + def accept_state_visitor(self, visitor: StateVisitor): + from moto.support.models import support_backends + + visitor.visit(support_backends) diff --git a/localstack-core/localstack/services/swf/provider.py b/localstack-core/localstack/services/swf/provider.py index b21f71dfaa915..94bec537b377b 100644 --- a/localstack-core/localstack/services/swf/provider.py +++ b/localstack-core/localstack/services/swf/provider.py @@ -1,7 +1,11 @@ from abc import ABC from localstack.aws.api.swf import SwfApi +from localstack.state import StateVisitor class SWFProvider(SwfApi, ABC): - pass + def accept_state_visitor(self, visitor: StateVisitor): + from moto.swf.models import swf_backends + + visitor.visit(swf_backends) diff --git a/localstack-core/localstack/services/transcribe/provider.py b/localstack-core/localstack/services/transcribe/provider.py index 8870f43e83a01..9a70031bf732b 100644 --- a/localstack-core/localstack/services/transcribe/provider.py +++ b/localstack-core/localstack/services/transcribe/provider.py @@ -38,6 +38,7 @@ ) from localstack.services.transcribe.models import TranscribeStore, transcribe_stores from localstack.services.transcribe.packages import vosk_package +from localstack.state import StateVisitor from localstack.utils.files import new_tmp_file from localstack.utils.http import download from localstack.utils.run import run @@ -101,6 +102,12 @@ class TranscribeProvider(TranscribeApi): + def accept_state_visitor(self, visitor: StateVisitor) -> None: + from moto.transcribe.models import transcribe_backends + + visitor.visit(transcribe_backends) + visitor.visit(transcribe_stores) + def get_transcription_job( self, context: RequestContext, transcription_job_name: TranscriptionJobName, **kwargs: Any ) -> GetTranscriptionJobResponse: @@ -312,7 +319,7 @@ def _run_transcription_job(self, args: tuple[TranscribeStore, str]) -> None: job["MediaFormat"] = SUPPORTED_FORMAT_NAMES[format] duration = ffprobe_output["format"]["duration"] - if float(duration) >= MAX_AUDIO_DURATION_SECONDS: + if float(duration) > MAX_AUDIO_DURATION_SECONDS: failure_reason = "Invalid file size: file size too large. Maximum audio duration is 4.000000 hours.Check the length of the file and try your request again." raise RuntimeError() diff --git a/localstack-core/localstack/state/pickle.py b/localstack-core/localstack/state/pickle.py index 7ee892ebc4a7a..04b40a49df330 100644 --- a/localstack-core/localstack/state/pickle.py +++ b/localstack-core/localstack/state/pickle.py @@ -30,15 +30,13 @@ def _recreate(obj_type, obj_queue): import inspect from collections.abc import Callable -from typing import Any, BinaryIO, Generic, TypeVar +from typing import Any, BinaryIO import dill from dill._dill import MetaCatchingDict from .core import Decoder, Encoder -_T = TypeVar("_T") - PythonPickler = Any """Type placeholder for pickle._Pickler (which has for instance the save_reduce method)""" @@ -268,7 +266,7 @@ def get_default_decoder() -> Decoder: return get_default_decoder() -class ObjectStateReducer(Generic[_T]): +class ObjectStateReducer[T]: """ A generalization of the following pattern:: @@ -301,7 +299,7 @@ def restore(state: dict): state["this_one_doesnt_serialize"] = restore(state["this_one_serialized"]) """ - cls: _T + cls: T @classmethod def create(cls): @@ -313,7 +311,7 @@ def register(self, subclasses=False): """ add_dispatch_entry(self.cls, self._pickle, subclasses=subclasses) - def _pickle(self, pickler, obj: _T): + def _pickle(self, pickler, obj: T): state = self.get_state(obj) self.prepare(obj, state) return pickler.save_reduce(self._unpickle, (state,), obj=obj) @@ -324,7 +322,7 @@ def _unpickle(self, state: dict) -> dict: self.set_state(obj, state) return obj - def get_state(self, obj: _T) -> Any: + def get_state(self, obj: T) -> Any: """ Return the objects state. Can be overwritten by subclasses to return custom state. @@ -333,7 +331,7 @@ def get_state(self, obj: _T) -> Any: """ return obj.__dict__.copy() - def set_state(self, obj: _T, state: Any): + def set_state(self, obj: T, state: Any): """ Set the state of the object. Can be overwritten by subclasses to set custom state. @@ -342,7 +340,7 @@ def set_state(self, obj: _T, state: Any): """ obj.__dict__.update(state) - def prepare(self, obj: _T, state: Any): + def prepare(self, obj: T, state: Any): """ Can be overwritten by subclasses to prepare the object state for pickling. @@ -351,7 +349,7 @@ def prepare(self, obj: _T, state: Any): """ pass - def restore(self, obj: _T, state: Any): + def restore(self, obj: T, state: Any): """ Can be overwritten by subclasses to modify the object state to restore any previously removed attributes. diff --git a/localstack-core/localstack/testing/aws/cloudformation_utils.py b/localstack-core/localstack/testing/aws/cloudformation_utils.py index 0ef513dec8456..33dd9634b78d2 100644 --- a/localstack-core/localstack/testing/aws/cloudformation_utils.py +++ b/localstack-core/localstack/testing/aws/cloudformation_utils.py @@ -29,7 +29,7 @@ def load_template_file(file_path: str | os.PathLike, *, path_ctx: str | os.PathL elif not file_path_obj.is_absolute(): raise ValueError("Provided path must be absolute if no path_ctx is provided") - return load_file(file_path_obj.absolute()) + return load_file(file_path_obj.absolute(), strict=True) # TODO: TBH this utility really doesn't add anything, probably better to just remove it diff --git a/localstack-core/localstack/testing/aws/lambda_utils.py b/localstack-core/localstack/testing/aws/lambda_utils.py index 929ba0fed1fa5..c020cfdbec0a0 100644 --- a/localstack-core/localstack/testing/aws/lambda_utils.py +++ b/localstack-core/localstack/testing/aws/lambda_utils.py @@ -6,20 +6,22 @@ import zipfile from collections.abc import Mapping, Sequence from pathlib import Path -from typing import TYPE_CHECKING, Literal, Optional, overload +from typing import TYPE_CHECKING, Optional, overload from localstack import config +from localstack.services.lambda_.invocation.lambda_models import InitializationType from localstack.services.lambda_.runtimes import RUNTIMES_AGGREGATED from localstack.utils.files import load_file from localstack.utils.platform import Arch, get_arch from localstack.utils.strings import short_uid -from localstack.utils.sync import ShortCircuitWaitException, retry +from localstack.utils.sync import ShortCircuitWaitException, retry, wait_until from localstack.utils.testutil import get_lambda_log_events if TYPE_CHECKING: from mypy_boto3_lambda import LambdaClient from mypy_boto3_lambda.literals import ArchitectureType, PackageTypeType, RuntimeType from mypy_boto3_lambda.type_defs import ( + CapacityProviderConfigTypeDef, DeadLetterConfigTypeDef, EnvironmentTypeDef, EphemeralStorageTypeDef, @@ -199,6 +201,7 @@ def create_function( CodeSigningConfigArn: str | None = None, Architectures: Sequence["ArchitectureType"] | None = None, EphemeralStorage: Optional["EphemeralStorageTypeDef"] = None, + CapacityProviderConfig: Optional["CapacityProviderConfigTypeDef"] = None, ) -> "FunctionConfigurationResponseMetadataTypeDef": ... def create_function(self, **kwargs): @@ -215,9 +218,24 @@ def _create_function(): # localstack should normally not require the retries and will just continue here result = retry(_create_function, retries=3, sleep=4) self.function_names.append(result["FunctionArn"]) - self.lambda_client.get_waiter("function_active_v2").wait( - FunctionName=kwargs.get("FunctionName") - ) + + def _is_not_pending(): + # Using custom wait condition instead of the 'function_active_v2' waiter which expects 'Active' state, + # which is not true for lambda managed instances, whose state becomes in ActiveNonInvokable + try: + result = ( + self.lambda_client.get_function(FunctionName=kwargs.get("FunctionName"))[ + "Configuration" + ]["State"] + != "Pending" + ) + LOG.debug("lambda state result: result=%s", result) + return result + except Exception as e: + LOG.error(e) + raise + + wait_until(_is_not_pending) return result @@ -259,9 +277,23 @@ def _concurrency_update_done(): return _concurrency_update_done -def get_invoke_init_type( - client, function_name, qualifier -) -> Literal["on-demand", "provisioned-concurrency"]: +def concurrency_update_failed(client, function_name, qualifier): + """wait fn for ProvisionedConcurrencyConfig 'Status'""" + + def _concurrency_update_failed(): + status = client.get_provisioned_concurrency_config( + FunctionName=function_name, Qualifier=qualifier + )["Status"] + if status == "READY": + # We are expecting a failure and short-circuit upon success + raise ShortCircuitWaitException(f"Concurrency update succeeded: {status=}") + else: + return status == "FAILED" + + return _concurrency_update_failed + + +def get_invoke_init_type(client, function_name, qualifier) -> InitializationType: """check the environment in the lambda for AWS_LAMBDA_INITIALIZATION_TYPE indicating ondemand/provisioned""" invoke_result = client.invoke(FunctionName=function_name, Qualifier=qualifier) return json.load(invoke_result["Payload"]) diff --git a/localstack-core/localstack/testing/aws/util.py b/localstack-core/localstack/testing/aws/util.py index f0f00a31a5045..a270a016368b5 100644 --- a/localstack-core/localstack/testing/aws/util.py +++ b/localstack-core/localstack/testing/aws/util.py @@ -1,7 +1,6 @@ import functools import os from collections.abc import Callable -from typing import TypeVar import boto3 import botocore @@ -29,6 +28,7 @@ SECONDARY_TEST_AWS_SECRET_ACCESS_KEY, SECONDARY_TEST_AWS_SESSION_TOKEN, TEST_AWS_ACCESS_KEY_ID, + TEST_AWS_ENDPOINT_URL, TEST_AWS_REGION_NAME, TEST_AWS_SECRET_ACCESS_KEY, ) @@ -173,10 +173,7 @@ def event_handler(request: AWSPreparedRequest, **_): return wrapper_method -T = TypeVar("T", bound=BaseClient) - - -def RequestContextClient(client: T) -> T: +def RequestContextClient[T: BaseClient](client: T) -> T: return _RequestContextClient(client) # noqa @@ -240,7 +237,7 @@ def base_aws_client_factory(session: boto3.Session) -> ClientFactory: # Prevent this fixture from using the region configured in system config config = config.merge(botocore.config.Config(region_name=TEST_AWS_REGION_NAME)) - return ExternalClientFactory(session=session, config=config) + return ExternalClientFactory(session=session, config=config, endpoint=TEST_AWS_ENDPOINT_URL) def base_testing_aws_client(client_factory: ClientFactory) -> ServiceLevelClientFactory: diff --git a/localstack-core/localstack/testing/config.py b/localstack-core/localstack/testing/config.py index f6191e9faa977..8f4b8377e952e 100644 --- a/localstack-core/localstack/testing/config.py +++ b/localstack-core/localstack/testing/config.py @@ -1,5 +1,6 @@ import os +from localstack.config import is_env_true from localstack.constants import DEFAULT_AWS_ACCOUNT_ID # Credentials used in the test suite @@ -9,6 +10,7 @@ TEST_AWS_ACCESS_KEY_ID = os.getenv("TEST_AWS_ACCESS_KEY_ID") or "test" TEST_AWS_SECRET_ACCESS_KEY = os.getenv("TEST_AWS_SECRET_ACCESS_KEY") or "test" TEST_AWS_REGION_NAME = os.getenv("TEST_AWS_REGION_NAME") or "us-east-1" +TEST_AWS_ENDPOINT_URL = os.getenv("TEST_AWS_ENDPOINT_URL") # Secondary test AWS profile - only used for testing against AWS SECONDARY_TEST_AWS_PROFILE = os.getenv("SECONDARY_TEST_AWS_PROFILE") @@ -18,3 +20,6 @@ SECONDARY_TEST_AWS_SECRET_ACCESS_KEY = os.getenv("SECONDARY_TEST_AWS_SECRET_ACCESS_KEY") or "test2" SECONDARY_TEST_AWS_SESSION_TOKEN = os.getenv("SECONDARY_TEST_AWS_SESSION_TOKEN") SECONDARY_TEST_AWS_REGION_NAME = os.getenv("SECONDARY_TEST_AWS_REGION_NAME") or "ap-southeast-1" + +TEST_SKIP_LOCALSTACK_START = is_env_true("TEST_SKIP_LOCALSTACK_START") +TEST_FORCE_LOCALSTACK_START = is_env_true("TEST_FORCE_LOCALSTACK_START") diff --git a/localstack-core/localstack/testing/pytest/cloudformation/fixtures.py b/localstack-core/localstack/testing/pytest/cloudformation/fixtures.py index 137766d430f5b..7ed590e23f42b 100644 --- a/localstack-core/localstack/testing/pytest/cloudformation/fixtures.py +++ b/localstack-core/localstack/testing/pytest/cloudformation/fixtures.py @@ -1,7 +1,7 @@ import json from collections import defaultdict -from collections.abc import Generator -from typing import Callable, Optional, TypedDict +from collections.abc import Callable, Generator +from typing import TypedDict import pytest from botocore.exceptions import WaiterError @@ -13,7 +13,7 @@ class NormalizedEvent(TypedDict): - PhysicalResourceId: Optional[str] + PhysicalResourceId: str | None LogicalResourceId: str ResourceType: str ResourceStatus: str diff --git a/localstack-core/localstack/testing/pytest/container.py b/localstack-core/localstack/testing/pytest/container.py index aebb452c5d3d1..a962eb3a89ccc 100644 --- a/localstack-core/localstack/testing/pytest/container.py +++ b/localstack-core/localstack/testing/pytest/container.py @@ -2,8 +2,7 @@ import os import shlex import threading -from collections.abc import Generator -from typing import Callable, Optional +from collections.abc import Callable, Generator import pytest @@ -24,7 +23,7 @@ LOG = logging.getLogger(__name__) ENV_TEST_CONTAINER_MOUNT_SOURCES = "TEST_CONTAINER_MOUNT_SOURCES" -"""Environment variable used to indicate that we should mount LocalStack source files into the container.""" +"""Environment variable used to indicate that we should mount LocalStack source files into the container.""" ENV_TEST_CONTAINER_MOUNT_DEPENDENCIES = "TEST_CONTAINER_MOUNT_DEPENDENCIES" """Environment variable used to indicate that we should mount dependencies into the container.""" @@ -38,8 +37,8 @@ def __call__( self, # convenience properties pro: bool = False, - publish: Optional[list[int]] = None, - configurators: Optional[list[ContainerConfigurator]] = None, + publish: list[int] | None = None, + configurators: list[ContainerConfigurator] | None = None, # ContainerConfig properties **kwargs, ) -> Container: @@ -172,7 +171,7 @@ def container_factory() -> Generator[ContainerFactory, None, None]: @pytest.fixture(scope="session") def wait_for_localstack_ready(): - def _wait_for(container: RunningContainer, timeout: Optional[float] = None): + def _wait_for(container: RunningContainer, timeout: float | None = None): container.wait_until_ready(timeout) poll_condition( diff --git a/localstack-core/localstack/testing/pytest/fixtures.py b/localstack-core/localstack/testing/pytest/fixtures.py index 0c54995ea3223..afe2c8345937e 100644 --- a/localstack-core/localstack/testing/pytest/fixtures.py +++ b/localstack-core/localstack/testing/pytest/fixtures.py @@ -6,7 +6,9 @@ import re import textwrap import time -from typing import TYPE_CHECKING, Any, Callable, Optional, Unpack +from collections.abc import Callable +from typing import TYPE_CHECKING, Any, Unpack +from unittest.mock import MagicMock import botocore.auth import botocore.config @@ -32,7 +34,7 @@ LocalAttribute, ) from localstack.testing.aws.cloudformation_utils import load_template_file, render_template -from localstack.testing.aws.util import get_lambda_logs, is_aws_cloud +from localstack.testing.aws.util import get_lambda_logs, is_aws_cloud, wait_for_user from localstack.testing.config import ( SECONDARY_TEST_AWS_ACCOUNT_ID, SECONDARY_TEST_AWS_REGION_NAME, @@ -357,8 +359,8 @@ def factory(**kwargs): def sqs_receive_messages_delete(aws_client): def factory( queue_url: str, - expected_messages: Optional[int] = None, - wait_time: Optional[int] = 5, + expected_messages: int | None = None, + wait_time: int | None = 5, ): response = aws_client.sqs.receive_message( QueueUrl=queue_url, @@ -706,7 +708,7 @@ def factory(**kwargs): def transcribe_create_job(s3_bucket, aws_client): job_names = [] - def _create_job(audio_file: str, params: Optional[dict[str, Any]] = None) -> str: + def _create_job(audio_file: str, params: dict[str, Any] | None = None) -> str: s3_key = "test-clip.wav" if not params: @@ -1085,18 +1087,18 @@ def deploy_cfn_template( def _deploy( *, - is_update: Optional[bool] = False, - stack_name: Optional[str] = None, - change_set_name: Optional[str] = None, - template: Optional[str] = None, - template_path: Optional[str | os.PathLike] = None, - template_mapping: Optional[dict[str, Any]] = None, - parameters: Optional[dict[str, str]] = None, - role_arn: Optional[str] = None, - max_wait: Optional[int] = None, - delay_between_polls: Optional[int] = 2, - custom_aws_client: Optional[ServiceLevelClientFactory] = None, - raw_parameters: Optional[list[Parameter]] = None, + is_update: bool | None = False, + stack_name: str | None = None, + change_set_name: str | None = None, + template: str | None = None, + template_path: str | os.PathLike | None = None, + template_mapping: dict[str, Any] | None = None, + parameters: dict[str, str] | None = None, + role_arn: str | None = None, + max_wait: int | None = None, + delay_between_polls: int | None = 2, + custom_aws_client: ServiceLevelClientFactory | None = None, + raw_parameters: list[Parameter] | None = None, ) -> DeployResult: if is_update: assert stack_name @@ -1262,7 +1264,7 @@ def _inner(): @pytest.fixture def is_change_set_finished(aws_client): - def _is_change_set_finished(change_set_id: str, stack_name: Optional[str] = None): + def _is_change_set_finished(change_set_id: str, stack_name: str | None = None): def _inner(): kwargs = {"ChangeSetName": change_set_id} if stack_name: @@ -1425,6 +1427,34 @@ def _create_function(): LOG.debug("Unable to delete log group %s in cleanup", log_group_name) +@pytest.fixture +def lambda_is_function_deleted(aws_client): + """Example usage: + wait_until(lambda_is_function_deleted(function_name)) + wait_until(lambda_is_function_deleted(function_name, Qualifier="my-alias")) + + function_name can be a function name, function ARN, or partial function ARN. + """ + return _lambda_is_function_deleted(aws_client.lambda_) + + +def _lambda_is_function_deleted(lambda_client): + def _is_function_deleted( + function_name: str, + **kwargs, + ) -> Callable[[], bool]: + def _inner() -> bool: + try: + lambda_client.get_function(FunctionName=function_name, **kwargs) + return False + except lambda_client.exceptions.ResourceNotFoundException: + return True + + return _inner + + return _is_function_deleted + + @pytest.fixture def create_echo_http_server(aws_client, create_lambda_function): from localstack.aws.api.lambda_ import Runtime @@ -1518,8 +1548,10 @@ def _create_event_source_mapping(*args, **kwargs): for uuid in uuids: try: aws_client.lambda_.delete_event_source_mapping(UUID=uuid) - except Exception: - LOG.debug("Unable to delete event source mapping %s in cleanup", uuid) + except aws_client.lambda_.exceptions.ResourceNotFoundException: + pass + except Exception as ex: + LOG.debug("Unable to delete event source mapping %s in cleanup: %s", uuid, ex) @pytest.fixture @@ -1993,7 +2025,7 @@ def setup_sender_email_address(ses_verify_identity): email address and verify them. """ - def inner(sender_email_address: Optional[str] = None) -> str: + def inner(sender_email_address: str | None = None) -> str: if is_aws_cloud(): if sender_email_address is None: raise ValueError( @@ -2104,8 +2136,28 @@ def cleanups(): for cleanup_callback in cleanup_fns[::-1]: try: cleanup_callback() + except ClientError as e: + http_code = e.response["ResponseMetadata"]["HTTPStatusCode"] + # Covers non-standardized error codes such as NotFoundException, NoSuchEntity (IAM), NoSuchBucket (S3), etc + if http_code == 404: + LOG.warning( + "Failed to execute cleanup because a resource was not found. " + "This cleanup might be unnecessary. %s", + str(e), + exc_info=e, + ) + else: + LOG.warning( + "Failed to execute cleanup due to ClientError: %s", + str(e), + exc_info=e, + ) except Exception as e: - LOG.warning("Failed to execute cleanup", exc_info=e) + LOG.warning( + "Failed to execute cleanup due to unexpected error: %s", + str(e), + exc_info=e, + ) @pytest.fixture(scope="session") @@ -2252,7 +2304,7 @@ def assert_host_customisation(monkeypatch): def asserter( url: str, *, - custom_host: Optional[str] = None, + custom_host: str | None = None, ): if custom_host is not None: assert custom_host in url, f"Could not find `{custom_host}` in `{url}`" @@ -2365,13 +2417,15 @@ def _create_role_with_policy( @pytest.fixture -def create_user_with_policy(create_policy_generated_document, create_user, aws_client): - def _create_user_with_policy(effect, actions, resource=None): +def create_user_with_policy(create_policy_generated_document, create_user, aws_client, region_name): + def _create_user_with_policy(effect, actions, resource=None, user_name=None): policy_arn = create_policy_generated_document(effect, actions, resource=resource) - username = f"user-{short_uid()}" + username = user_name or f"user-{short_uid()}" create_user(UserName=username) aws_client.iam.attach_user_policy(UserName=username, PolicyArn=policy_arn) keys = aws_client.iam.create_access_key(UserName=username)["AccessKey"] + + wait_for_user(keys=keys, region_name=region_name) return username, keys return _create_user_with_policy @@ -2435,7 +2489,10 @@ def factory(**kwargs): yield factory for zone_id in zone_ids[::-1]: - aws_client.route53.delete_hosted_zone(Id=zone_id) + try: + aws_client.route53.delete_hosted_zone(Id=zone_id) + except ClientError as e: + LOG.debug("failed to delete hosted zone %s: %s", zone_id, e) @pytest.fixture @@ -2754,3 +2811,50 @@ def _delete_log_group(): call_safe(_delete_log_group) yield _clean_up + + +@pytest.fixture +def aws_catalog_mock(monkeypatch): + def _mock_catalog(path): + catalog = MagicMock() + monkeypatch.setattr(path, lambda: catalog) + return catalog + + return _mock_catalog + + +@pytest.fixture +def logs_log_group(aws_client): + """Create a log group for testing and clean up afterwards.""" + + log_group_names = [] + + def _create_log_group(): + log_group_name = f"test-log-group-{short_uid()}" + aws_client.logs.create_log_group(logGroupName=log_group_name) + log_group_names.append(log_group_name) + return log_group_name + + yield _create_log_group() + + for group_name in log_group_names: + aws_client.logs.delete_log_group(logGroupName=group_name) + + +@pytest.fixture +def logs_log_stream(logs_log_group, aws_client): + """Create a log stream for testing and clean up afterwards.""" + log_stream_names = [] + + def _create_log_stream(): + log_stream_name = f"test-log-stream-{short_uid()}" + aws_client.logs.create_log_stream( + logGroupName=logs_log_group, logStreamName=log_stream_name + ) + log_stream_names.append(log_stream_name) + return log_stream_name + + yield _create_log_stream() + + for stream_name in log_stream_names: + aws_client.logs.delete_log_stream(logStreamName=stream_name, logGroupName=logs_log_group) diff --git a/localstack-core/localstack/testing/pytest/in_memory_localstack.py b/localstack-core/localstack/testing/pytest/in_memory_localstack.py index f9ad069bbc901..534a8805cc65d 100644 --- a/localstack-core/localstack/testing/pytest/in_memory_localstack.py +++ b/localstack-core/localstack/testing/pytest/in_memory_localstack.py @@ -21,8 +21,8 @@ def pytest_configure(config): from _pytest.config.argparsing import Parser from _pytest.main import Session +import localstack.testing.config as test_config from localstack import config as localstack_config -from localstack.config import is_env_true from localstack.constants import ENV_INTERNAL_TEST_RUN LOG = logging.getLogger(__name__) @@ -53,18 +53,16 @@ def pytest_runtestloop(session: Session): from localstack.testing.aws.util import is_aws_cloud - if is_env_true("TEST_SKIP_LOCALSTACK_START"): + if test_config.TEST_SKIP_LOCALSTACK_START: LOG.info("TEST_SKIP_LOCALSTACK_START is set, not starting localstack") return if is_aws_cloud(): - if not is_env_true("TEST_FORCE_LOCALSTACK_START"): + if not test_config.TEST_FORCE_LOCALSTACK_START: LOG.info("Test running against aws, not starting localstack") return LOG.info("TEST_FORCE_LOCALSTACK_START is set, a Localstack instance will be created.") - from localstack.utils.common import safe_requests - if is_aws_cloud(): localstack_config.DEFAULT_DELAY = 5 localstack_config.DEFAULT_MAX_ATTEMPTS = 60 @@ -73,8 +71,6 @@ def pytest_runtestloop(session: Session): os.environ[ENV_INTERNAL_TEST_RUN] = "1" localstack_config.INCLUDE_STACK_TRACES_IN_HTTP_RESPONSE = True - safe_requests.verify_ssl = False - from localstack.runtime import current _started.set() diff --git a/localstack-core/localstack/testing/pytest/marking.py b/localstack-core/localstack/testing/pytest/marking.py index f677d64e0f249..f7479d510f9bd 100644 --- a/localstack-core/localstack/testing/pytest/marking.py +++ b/localstack-core/localstack/testing/pytest/marking.py @@ -3,7 +3,8 @@ """ import os -from typing import TYPE_CHECKING, Callable, Optional +from collections.abc import Callable +from typing import TYPE_CHECKING import pytest from _pytest.config import PytestPluginManager @@ -36,13 +37,13 @@ class SkipSnapshotVerifyMarker: def __call__( self, *, - paths: "Optional[list[str]]" = None, - condition: "Optional[Callable[[...], bool]]" = None, + paths: "list[str] | None" = None, + condition: "Callable[[...], bool] | None" = None, ): ... class MultiRuntimeMarker: - def __call__(self, *, scenario: str, runtimes: Optional[list[str]] = None): ... + def __call__(self, *, scenario: str, runtimes: list[str] | None = None): ... class SnapshotMarkers: @@ -75,8 +76,8 @@ class Markers: """The test requires docker or a compatible container engine - will not work on kubernetes""" lambda_runtime_update = pytest.mark.lambda_runtime_update """Tests to execute when updating snapshots for a new Lambda runtime""" - k8s_always_run = pytest.mark.k8s_always_run - """This tests will always run against k8s environment""" + skip_k8s = pytest.mark.skip_k8s + """This test will be skipped in k8s environment""" # pytest plugin @@ -228,7 +229,3 @@ def pytest_configure(config): "markers", "requires_in_process: mark the test as requiring the test to run inside the same process as LocalStack - will not work if tests are run against a running LS container.", ) - config.addinivalue_line( - "markers", - "k8s_always_run: mark the test to always run in k8s environment. This allows us to run tests that would otherwise be skipped, such as localstack_only tests.", - ) diff --git a/localstack-core/localstack/testing/pytest/stepfunctions/utils.py b/localstack-core/localstack/testing/pytest/stepfunctions/utils.py index 19f954e51fb54..78d257b230f09 100644 --- a/localstack-core/localstack/testing/pytest/stepfunctions/utils.py +++ b/localstack-core/localstack/testing/pytest/stepfunctions/utils.py @@ -1,6 +1,7 @@ import json import logging -from typing import Callable, Final, Optional +from collections.abc import Callable +from typing import Final from botocore.exceptions import ClientError from jsonpath_ng.ext import parse @@ -98,10 +99,12 @@ def await_state_machine_alias_is_deleted( stepfunctions_client, state_machine_arn: Arn, state_machine_alias_arn: Arn ): success = poll_condition( - condition=lambda: not _is_state_machine_alias_listed( - stepfunctions_client=stepfunctions_client, - state_machine_arn=state_machine_arn, - state_machine_alias_arn=state_machine_alias_arn, + condition=lambda: ( + not _is_state_machine_alias_listed( + stepfunctions_client=stepfunctions_client, + state_machine_arn=state_machine_arn, + state_machine_alias_arn=state_machine_alias_arn, + ) ), timeout=_DELETION_TIMEOUT_SECS, interval=_get_sampling_interval_seconds(), @@ -154,8 +157,10 @@ def await_state_machine_version_not_listed( stepfunctions_client, state_machine_arn: str, state_machine_version_arn: str ): success = poll_condition( - condition=lambda: not _is_state_machine_version_listed( - stepfunctions_client, state_machine_arn, state_machine_version_arn + condition=lambda: ( + not _is_state_machine_version_listed( + stepfunctions_client, state_machine_arn, state_machine_version_arn + ) ), timeout=_DELETION_TIMEOUT_SECS, interval=_get_sampling_interval_seconds(), @@ -402,8 +407,8 @@ def create_state_machine_with_iam_role( create_state_machine, snapshot, definition: Definition, - logging_configuration: Optional[LoggingConfiguration] = None, - state_machine_name: Optional[str] = None, + logging_configuration: LoggingConfiguration | None = None, + state_machine_name: str | None = None, state_machine_type: StateMachineType = StateMachineType.STANDARD, ): snf_role_arn = create_state_machine_iam_role(target_aws_client=target_aws_client) @@ -567,6 +572,7 @@ def launch_and_record_logs( sfn_snapshot.match("logged_execution_events", logged_execution_events) +# TODO refactor to have fewer positional arguments. Consider converting to a fixture. def create_and_record_execution( target_aws_client, create_state_machine_iam_role, diff --git a/localstack-core/localstack/testing/pytest/util.py b/localstack-core/localstack/testing/pytest/util.py index 28e88a8dbef24..9785e5e2b13f3 100644 --- a/localstack-core/localstack/testing/pytest/util.py +++ b/localstack-core/localstack/testing/pytest/util.py @@ -1,7 +1,7 @@ import os import pwd +from collections.abc import Callable from multiprocessing import Process, ProcessError -from typing import Callable def run_as_os_user(target: Callable, uid: str | int, gid: str | int = None): diff --git a/localstack-core/localstack/testing/pytest/validation_tracking.py b/localstack-core/localstack/testing/pytest/validation_tracking.py index 9c3531a31781a..8cb3b75ba0314 100644 --- a/localstack-core/localstack/testing/pytest/validation_tracking.py +++ b/localstack-core/localstack/testing/pytest/validation_tracking.py @@ -9,7 +9,6 @@ import json import os from pathlib import Path -from typing import Optional import pytest from pluggy import Result @@ -28,7 +27,7 @@ """ -def find_validation_data_for_item(item: pytest.Item) -> Optional[dict]: +def find_validation_data_for_item(item: pytest.Item) -> dict | None: base_path = os.path.join(item.fspath.dirname, item.fspath.purebasename) snapshot_path = f"{base_path}.validation.json" diff --git a/localstack-core/localstack/testing/snapshots/transformer_utility.py b/localstack-core/localstack/testing/snapshots/transformer_utility.py index d79cddd4ce5a5..ef2fdd13e6034 100644 --- a/localstack-core/localstack/testing/snapshots/transformer_utility.py +++ b/localstack-core/localstack/testing/snapshots/transformer_utility.py @@ -566,6 +566,8 @@ def kms_api(): """ return [ TransformerUtility.key_value("KeyId"), + TransformerUtility.key_value("KeyMaterialId"), + TransformerUtility.key_value("CurrentKeyMaterialId"), TransformerUtility.jsonpath( jsonpath="$..Signature", value_replacement="", @@ -789,6 +791,11 @@ def stepfunctions_api(): "x-amzn-RequestId", replace_reference=False, ), + JsonpathTransformer( + "$..x-amzn-requestid", + "x-amzn-requestid", + replace_reference=False, + ), KeyValueBasedTransformer(_transform_stepfunctions_cause_details, "json-input"), ] @@ -918,16 +925,18 @@ def _change_set_id_transformer(key: str, val: str) -> str: ), RegexTransformer(PATTERN_ISO8601, "date"), KeyValueBasedTransformer( - lambda k, v: (v if isinstance(v, datetime) else None), "datetime", replace_reference=False + lambda k, v: v if isinstance(v, datetime) else None, "datetime", replace_reference=False ), KeyValueBasedTransformer( - lambda k, v: str(v) - if ( - re.compile(r"^.*timestamp.*$", flags=re.IGNORECASE).match(k) - or k in ("creationTime", "ingestionTime") - ) - and not PATTERN_ISO8601.match(str(v)) - else None, + lambda k, v: ( + str(v) + if ( + re.compile(r"^.*timestamp.*$", flags=re.IGNORECASE).match(k) + or k in ("creationTime", "ingestionTime") + ) + and not PATTERN_ISO8601.match(str(v)) + else None + ), "timestamp", replace_reference=False, ), diff --git a/localstack-core/localstack/testing/testselection/matching.py b/localstack-core/localstack/testing/testselection/matching.py index 55fd25b09d844..6c6d2ab5a360d 100644 --- a/localstack-core/localstack/testing/testselection/matching.py +++ b/localstack-core/localstack/testing/testselection/matching.py @@ -84,10 +84,8 @@ def ignore(self): return lambda t: [SENTINEL_NO_TEST] if self.matching_func(t) else [] def service_tests(self, services: list[str]): - return ( - lambda t: [get_test_dir_for_service(svc) for svc in services] - if self.matching_func(t) - else [] + return lambda t: ( + [get_test_dir_for_service(svc) for svc in services] if self.matching_func(t) else [] ) def passthrough(self): @@ -181,7 +179,6 @@ def check_rule_has_matches(rule: MatchingRule, files: Iterable[str]) -> bool: ).passthrough(), # changes in a test file should always at least test that file # CI Matchers.glob(".github/**").full_suite(), - Matchers.glob(".circleci/**").full_suite(), # dependencies / project setup Matchers.glob("requirements*.txt").full_suite(), Matchers.glob("setup.cfg").full_suite(), diff --git a/localstack-core/localstack/utils/analytics/events.py b/localstack-core/localstack/utils/analytics/events.py index 5c81385b81865..ada536431f35a 100644 --- a/localstack-core/localstack/utils/analytics/events.py +++ b/localstack-core/localstack/utils/analytics/events.py @@ -1,8 +1,8 @@ import abc import dataclasses -from typing import Any, Union +from typing import Any -EventPayload = Union[dict[str, Any], Any] # FIXME: better typing +EventPayload = dict[str, Any] | Any # FIXME: better typing @dataclasses.dataclass diff --git a/localstack-core/localstack/utils/analytics/metadata.py b/localstack-core/localstack/utils/analytics/metadata.py index e5ddec72c73cd..32ef9b81145de 100644 --- a/localstack-core/localstack/utils/analytics/metadata.py +++ b/localstack-core/localstack/utils/analytics/metadata.py @@ -2,7 +2,6 @@ import logging import os import platform -from typing import Optional from localstack import config from localstack.constants import VERSION @@ -57,7 +56,7 @@ def read_client_metadata() -> ClientMetadata: session_id=get_session_id(), machine_id=get_machine_id(), api_key=get_api_key_or_auth_token() or "", # api key should not be None - system=get_system(), + system=get_system_information_summary(), version=get_version_string(), is_ci=os.getenv("CI") is not None, is_docker=config.is_in_docker, @@ -201,7 +200,7 @@ def _generate_machine_id() -> str: return f"gen_{long_uid()[:12]}" -def get_api_key_or_auth_token() -> Optional[str]: +def get_api_key_or_auth_token() -> str | None: # TODO: this is duplicated code from ext, but should probably migrate that to localstack auth_token = os.environ.get("LOCALSTACK_AUTH_TOKEN", "").strip("'\" ") if auth_token: @@ -216,6 +215,7 @@ def get_api_key_or_auth_token() -> Optional[str]: @singleton_factory def get_system() -> str: + # TODO: candidate for removal try: # try to get the system from the docker socket from localstack.utils.docker_utils import DOCKER_CLIENT @@ -232,6 +232,69 @@ def get_system() -> str: return platform.system().lower() +@singleton_factory +def get_system_information_summary() -> str: + """ + Returns a string that contains three comma-separated values: The operating system, kernel version, + and architecture. We either use the docker socket to resolve the information, if that is not available + we fall back ``platform.uname()``. If we're in docker and we don't have the docker socket available, + we add ``(Container)`` to the operating system type to indicate that we don't have any additional + information. + + Some examples: + + If the Docker socket is available: + - Docker Desktop,5.15.90.1-microsoft-standard-WSL2,x86_64 + - Linux Mint 21.1,5.19.0-32-generic,x86_64 + + If the Docker socket is not available, and we're on the host: + - Windows,10,AMD64 + - Linux,5.19.0-32-generic,x86_64 + + If the Docker socket is not available, and we're in the container: + - Linux(Container),5.19.0-32-generic,x86_64 + + :return: A string representing the system's information + """ + try: + # try to get the system from the docker socket + from localstack.utils.docker_utils import DOCKER_CLIENT + + system = DOCKER_CLIENT.get_system_info() + + return ",".join( + [ + system["OperatingSystem"], + system["KernelVersion"], + system["Architecture"], + ] + ) + except Exception: + if config.DEBUG_ANALYTICS: + LOG.exception( + "Unable to get system information from docker socket, falling back to platform.uname()" + ) + + uname = platform.uname() + + if config.is_in_docker: + return ",".join( + [ + f"{uname.system}(Container)", + uname.release, + uname.machine, + ] + ) + + return ",".join( + [ + uname.system, + uname.release, + uname.machine, + ] + ) + + @hooks.prepare_host() def prepare_host_machine_id(): # lazy-init machine ID into cache on the host, which can then be used in the container diff --git a/localstack-core/localstack/utils/analytics/metrics/counter.py b/localstack-core/localstack/utils/analytics/metrics/counter.py index 04f4d87acd482..acf25db4d2615 100644 --- a/localstack-core/localstack/utils/analytics/metrics/counter.py +++ b/localstack-core/localstack/utils/analytics/metrics/counter.py @@ -1,7 +1,7 @@ import threading from collections import defaultdict from dataclasses import dataclass -from typing import Any, Optional, Union +from typing import Any from localstack import config @@ -38,7 +38,7 @@ class LabeledCounterPayload: value: int type: str schema_version: int - labels: dict[str, Union[str, float]] + labels: dict[str, str | float] def as_dict(self) -> dict[str, Any]: payload_dict = { @@ -140,10 +140,8 @@ class LabeledCounter(Metric): _type: str _labels: list[str] - _label_values: tuple[Optional[Union[str, float]], ...] - _counters_by_label_values: defaultdict[ - tuple[Optional[Union[str, float]], ...], ThreadSafeCounter - ] + _label_values: tuple[str | float | None, ...] + _counters_by_label_values: defaultdict[tuple[str | float | None, ...], ThreadSafeCounter] def __init__(self, namespace: str, name: str, labels: list[str], schema_version: int = 1): super().__init__(namespace=namespace, name=name, schema_version=schema_version) @@ -162,7 +160,7 @@ def __init__(self, namespace: str, name: str, labels: list[str], schema_version: self._counters_by_label_values = defaultdict(ThreadSafeCounter) MetricRegistry().register(self) - def labels(self, **kwargs: Union[str, float, None]) -> ThreadSafeCounter: + def labels(self, **kwargs: str | float | None) -> ThreadSafeCounter: """ Create a scoped counter instance with specific label values. @@ -198,7 +196,7 @@ def collect(self) -> list[LabeledCounterPayload]: ) # Create labels dictionary - labels_dict = dict(zip(self._labels, label_values)) + labels_dict = dict(zip(self._labels, label_values, strict=False)) payload.append( LabeledCounterPayload( diff --git a/localstack-core/localstack/utils/analytics/publisher.py b/localstack-core/localstack/utils/analytics/publisher.py index 083e53d77ad98..7a3b1354b3d04 100644 --- a/localstack-core/localstack/utils/analytics/publisher.py +++ b/localstack-core/localstack/utils/analytics/publisher.py @@ -2,12 +2,10 @@ import atexit import logging import threading -import time -from queue import Full, Queue -from typing import Optional from localstack import config -from localstack.utils.threads import start_thread, start_worker_thread +from localstack.utils.batching import AsyncBatcher +from localstack.utils.threads import FuncThread, start_thread, start_worker_thread from .client import AnalyticsClient from .events import Event, EventHandler @@ -52,139 +50,36 @@ def publish(self, events: list[Event]): print(event.asdict()) -class PublisherBuffer(EventHandler): - """ - A PublisherBuffer is an EventHandler that collects events into a buffer until a flush condition is - met, and then flushes the buffer to a Publisher. The condition is either a given buffer size or - a time interval, whatever occurs first. The buffer is also flushed when the recorder is stopped - via `close()`. Internally it uses a simple event-loop mechanism to multiplex commands on a - single thread. - """ - - flush_size: int - flush_interval: float - - _cmd_flush = "__FLUSH__" - _cmd_stop = "__STOP__" - - # FIXME: figure out good default values - def __init__( - self, publisher: Publisher, flush_size: int = 20, flush_interval: float = 10, maxsize=0 - ): - self._publisher = publisher - self._queue = Queue(maxsize=maxsize) - self._command_queue = Queue() - - self.flush_size = flush_size - self.flush_interval = flush_interval - - self._last_flush = time.time() - self._stopping = threading.Event() - self._stopped = threading.Event() - - def handle(self, event: Event): - self._queue.put_nowait(event) - self.checked_flush() - - def close(self): - if self._stopping.is_set(): - return - - self._stopping.set() - self._command_queue.put(self._cmd_stop) +class GlobalAnalyticsBus(EventHandler): + _batcher: AsyncBatcher[Event] + _client: AnalyticsClient + _worker_thread: FuncThread | None - def close_sync(self, timeout: Optional[float] = None): - self.close() - return self._stopped.wait(timeout) - - def flush(self): - self._command_queue.put(self._cmd_flush) - self._last_flush = time.time() - - def checked_flush(self): - """ - Runs flush only if a flush condition is met. - """ - if config.DEBUG_ANALYTICS: - LOG.debug( - "analytics queue size: %d, command queue size: %d, time since last flush: %.1fs", - self._queue.qsize(), - self._command_queue.qsize(), - time.time() - self._last_flush, - ) - - if self._queue.qsize() >= self.flush_size: - self.flush() - return - if time.time() - self._last_flush >= self.flush_interval: - self.flush() - return - - def _run_flush_schedule(self, *_): - while True: - if self._stopping.wait(self.flush_interval): - return - self.checked_flush() - - def run(self, *_): - flush_scheduler = start_thread(self._run_flush_schedule, name="analytics-publishbuffer") - - try: - while True: - command = self._command_queue.get() - - if command is self._cmd_flush or command is self._cmd_stop: - try: - self._do_flush() - except Exception: - if config.DEBUG_ANALYTICS: - LOG.exception("error while flushing events") - - if command is self._cmd_stop: - return - finally: - self._stopped.set() - flush_scheduler.stop() - self._publisher.close() - if config.DEBUG_ANALYTICS: - LOG.debug("Exit analytics publisher") - - def _do_flush(self): - queue = self._queue - events = [] - - for _ in range(queue.qsize()): - event = queue.get_nowait() - events.append(event) - - if config.DEBUG_ANALYTICS: - LOG.debug("collected %d events to publish", len(events)) - - self._publisher.publish(events) - - -class GlobalAnalyticsBus(PublisherBuffer): - def __init__( - self, client: AnalyticsClient = None, flush_size=20, flush_interval=10, max_buffer_size=1000 - ) -> None: + def __init__(self, client: AnalyticsClient = None, flush_size=20, flush_interval=10) -> None: self._client = client or AnalyticsClient() self._publisher = AnalyticsClientPublisher(self._client) - - super().__init__( - self._publisher, - flush_size=flush_size, - flush_interval=flush_interval, - maxsize=max_buffer_size, + self._batcher = AsyncBatcher( + self._handle_batch, + max_batch_size=flush_size, + max_flush_interval=flush_interval, ) self._started = False - self._startup_complete = False self._startup_mutex = threading.Lock() - self._buffer_thread = None + self._worker_thread = None self.force_tracking = False # allow class to ignore all other tracking config self.tracking_disabled = False # disables tracking if global config would otherwise track + def _handle_batch(self, batch: list[Event]): + """Method that satisfies the BatchHandler[Event] protocol and is passed to AsyncBatcher.""" + try: + self._publisher.publish(batch) + except Exception: + # currently we're just dropping events if something goes wrong during publishing + if config.DEBUG_ANALYTICS: + LOG.exception("error while publishing analytics events") + @property def is_tracking_disabled(self): if self.force_tracking: @@ -201,44 +96,20 @@ def is_tracking_disabled(self): return False - def _do_flush(self): - if self.tracking_disabled: - # flushing although tracking has been disabled most likely means that _do_start_retry - # has failed, tracking is now disabled, and the system tries to flush the queued - # events. we use this opportunity to shut down the tracker and clear the queue, since - # no tracking should happen from this point on. - if config.DEBUG_ANALYTICS: - LOG.debug("attempting to flush while tracking is disabled, shutting down tracker") - self.close_sync(timeout=10) - self._queue.queue.clear() - return - - super()._do_flush() - - def flush(self): - if not self._startup_complete: - # don't flush until _do_start_retry has completed (command queue would fill up) - return - - super().flush() - def handle(self, event: Event): """ Publish an event to the global analytics event publisher. """ if self.is_tracking_disabled: if config.DEBUG_ANALYTICS: - LOG.debug("skipping event %s", event) + LOG.debug("tracking disabled, skipping event %s", event) return if not self._started: + # we make sure the batching worker is started self._start() - try: - super().handle(event) - except Full: - if config.DEBUG_ANALYTICS: - LOG.warning("event queue is full, dropping event %s", event) + self._batcher.add(event) def _start(self): with self._startup_mutex: @@ -268,12 +139,22 @@ def _do_start_retry(self, *_): if config.DEBUG_ANALYTICS: LOG.exception("error while registering session. disabling tracking") return - finally: - self._startup_complete = True - start_thread(self.run, name="global-analytics-bus") + self._worker_thread = start_thread(self._run, name="global-analytics-bus") + # given the "Global" nature of this class, we register a global atexit hook to make sure all events are flushed + # when localstack shuts down. def _do_close(): self.close_sync(timeout=2) atexit.register(_do_close) + + def _run(self, *_): + # main control loop, simply runs the batcher + self._batcher.run() + + def close_sync(self, timeout=None): + self._batcher.close() + + if self._worker_thread: + self._worker_thread.join(timeout=timeout) diff --git a/localstack-core/localstack/utils/analytics/service_providers.py b/localstack-core/localstack/utils/analytics/service_providers.py deleted file mode 100644 index cb242a73f04db..0000000000000 --- a/localstack-core/localstack/utils/analytics/service_providers.py +++ /dev/null @@ -1,19 +0,0 @@ -from localstack.runtime import hooks - - -@hooks.on_runtime_ready() -def publish_provider_assignment(): - """ - Publishes the service provider assignment to the analytics service. - """ - - from localstack.config import SERVICE_PROVIDER_CONFIG - from localstack.services.plugins import SERVICE_PLUGINS - from localstack.utils.analytics import log - - provider_assignment = { - service: f"localstack.aws.provider/{service}:{SERVICE_PROVIDER_CONFIG[service]}" - for service in SERVICE_PLUGINS.list_available() - } - - log.event("ls_service_provider_assignment", provider_assignment) diff --git a/localstack-core/localstack/utils/analytics/service_request_aggregator.py b/localstack-core/localstack/utils/analytics/service_request_aggregator.py index 2b0bdd590db2f..42ba4700c7794 100644 --- a/localstack-core/localstack/utils/analytics/service_request_aggregator.py +++ b/localstack-core/localstack/utils/analytics/service_request_aggregator.py @@ -2,7 +2,7 @@ import logging import threading from collections import Counter -from typing import NamedTuple, Optional +from typing import NamedTuple from localstack import config from localstack.runtime.shutdown import SHUTDOWN_HANDLERS @@ -11,7 +11,7 @@ LOG = logging.getLogger(__name__) -DEFAULT_FLUSH_INTERVAL_SECS = 15 +DEFAULT_FLUSH_INTERVAL_SECS = 60 EVENT_NAME = "aws_request_agg" OPTIONAL_FIELDS = ["err_type"] @@ -20,7 +20,7 @@ class ServiceRequestInfo(NamedTuple): service: str operation: str status_code: int - err_type: Optional[str] = None + err_type: str | None = None class ServiceRequestAggregator: @@ -34,7 +34,7 @@ def __init__(self, flush_interval: float = DEFAULT_FLUSH_INTERVAL_SECS): self._flush_interval = flush_interval self._flush_scheduler = Scheduler() self._mutex = threading.RLock() - self._period_start_time = datetime.datetime.utcnow() + self._period_start_time = datetime.datetime.now(datetime.UTC) self._is_started = False self._is_shutdown = False @@ -101,12 +101,14 @@ def _flush(self): self._emit_payload(analytics_payload) self.counter.clear() finally: - self._period_start_time = datetime.datetime.utcnow() + self._period_start_time = datetime.datetime.now(datetime.UTC) def _create_analytics_payload(self): return { - "period_start_time": self._period_start_time.isoformat() + "Z", - "period_end_time": datetime.datetime.utcnow().isoformat() + "Z", + "period_start_time": self._period_start_time.isoformat().replace("+00:00", "Z"), + "period_end_time": datetime.datetime.now(datetime.UTC) + .isoformat() + .replace("+00:00", "Z"), "api_calls": self._aggregate_api_calls(self.counter), } diff --git a/localstack-core/localstack/utils/archives.py b/localstack-core/localstack/utils/archives.py index 7503bbe8a8667..08328938e776a 100644 --- a/localstack-core/localstack/utils/archives.py +++ b/localstack-core/localstack/utils/archives.py @@ -8,7 +8,7 @@ import time import zipfile from subprocess import Popen -from typing import IO, Literal, Optional, Union +from typing import IO, Literal from localstack.constants import MAVEN_REPO_URL from localstack.utils.files import load_file, mkdir, new_tmp_file, rm_rf, save_file @@ -22,7 +22,7 @@ LOG = logging.getLogger(__name__) -StrPath = Union[str, os.PathLike] +StrPath = str | os.PathLike def is_zip_file(content): @@ -30,13 +30,13 @@ def is_zip_file(content): return zipfile.is_zipfile(stream) -def get_unzipped_size(zip_file: Union[str, IO[bytes]]): +def get_unzipped_size(zip_file: str | IO[bytes]): """Returns the size of the unzipped file.""" with zipfile.ZipFile(zip_file, "r") as zip_ref: return sum(f.file_size for f in zip_ref.infolist()) -def unzip(path: str, target_dir: str, overwrite: bool = True) -> Optional[Union[str, Popen]]: +def unzip(path: str, target_dir: str, overwrite: bool = True) -> str | Popen | None: from localstack.utils.platform import is_debian use_native_cmd = is_debian() or is_command_available("unzip") @@ -99,7 +99,7 @@ def create_zip_file_python( base_dir: StrPath, zip_file: StrPath, mode: Literal["r", "w", "x", "a"] = "w", - content_root: Optional[str] = None, + content_root: str | None = None, ): with zipfile.ZipFile(zip_file, mode) as zip_file: for root, dirs, files in os.walk(base_dir): @@ -122,7 +122,7 @@ def add_file_to_jar(class_file, class_url, target_jar, base_dir=None): def update_jar_manifest( - jar_file_name: str, parent_dir: str, search: Union[str, re.Pattern], replace: str + jar_file_name: str, parent_dir: str, search: str | re.Pattern, replace: str ): manifest_file_path = "META-INF/MANIFEST.MF" jar_path = os.path.join(parent_dir, jar_file_name) @@ -174,10 +174,10 @@ def upgrade_jar_file(base_dir: str, file_glob: str, maven_asset: str): def download_and_extract( archive_url: str, target_dir: str, - retries: Optional[int] = 0, - sleep: Optional[int] = 3, - tmp_archive: Optional[str] = None, - checksum_url: Optional[str] = None, + retries: int | None = 0, + sleep: int | None = 3, + tmp_archive: str | None = None, + checksum_url: str | None = None, ) -> None: """ Download and extract an archive to a target directory with optional checksum verification. @@ -250,7 +250,7 @@ def download_and_extract_with_retry( archive_url, tmp_archive, target_dir, - checksum_url: Optional[str] = None, + checksum_url: str | None = None, ): try: download_and_extract( diff --git a/localstack-core/localstack/utils/aws/arns.py b/localstack-core/localstack/utils/aws/arns.py index ababbd4834b32..01ada4a2f0d60 100644 --- a/localstack-core/localstack/utils/aws/arns.py +++ b/localstack-core/localstack/utils/aws/arns.py @@ -1,7 +1,7 @@ import logging import re from functools import cache -from typing import Optional, TypedDict +from typing import TypedDict from botocore.utils import ArnParser, InvalidArnException @@ -22,12 +22,13 @@ "us-gov-": "aws-us-gov", "us-iso-": "aws-iso", "us-isob-": "aws-iso-b", + "eusc-": "aws-eusc", } PARTITION_NAMES = list(REGION_PREFIX_TO_PARTITION.values()) + [DEFAULT_PARTITION] ARN_PARTITION_REGEX = r"^arn:(" + "|".join(sorted(PARTITION_NAMES)) + ")" -def get_partition(region: Optional[str]) -> str: +def get_partition(region: str | None) -> str: if not region: return DEFAULT_PARTITION if region in PARTITION_NAMES: @@ -65,28 +66,28 @@ def parse_arn(arn: str) -> ArnData: return _arn_parser.parse_arn(arn) -def extract_account_id_from_arn(arn: str) -> Optional[str]: +def extract_account_id_from_arn(arn: str) -> str | None: try: return parse_arn(arn).get("account") except InvalidArnException: return None -def extract_region_from_arn(arn: str) -> Optional[str]: +def extract_region_from_arn(arn: str) -> str | None: try: return parse_arn(arn).get("region") except InvalidArnException: return None -def extract_service_from_arn(arn: str) -> Optional[str]: +def extract_service_from_arn(arn: str) -> str | None: try: return parse_arn(arn).get("service") except InvalidArnException: return None -def extract_resource_from_arn(arn: str) -> Optional[str]: +def extract_resource_from_arn(arn: str) -> str | None: try: return parse_arn(arn).get("resource") except InvalidArnException: @@ -98,8 +99,10 @@ def extract_resource_from_arn(arn: str) -> Optional[str]: # -def _resource_arn(name: str, pattern: str, account_id: str, region_name: str) -> str: - if ":" in name: +def _resource_arn( + name: str, pattern: str, account_id: str, region_name: str, allow_colons=False +) -> str: + if ":" in name and not allow_colons: return name if len(pattern.split("%s")) == 4: return pattern % (get_partition(region_name), account_id, name) @@ -282,10 +285,17 @@ def lambda_event_source_mapping_arn(uuid: str, account_id: str, region_name: str return _resource_arn(uuid, pattern, account_id=account_id, region_name=region_name) +def capacity_provider_arn(capacity_provider_name: str, account_id: str, region_name: str) -> str: + pattern = "arn:%s:lambda:%s:%s:capacity-provider:%s" + return _resource_arn( + capacity_provider_name, pattern, account_id=account_id, region_name=region_name + ) + + def lambda_function_or_layer_arn( type: str, entity_name: str, - version: Optional[str], + version: str | None, account_id: str, region_name: str, ) -> str: @@ -474,6 +484,12 @@ def sns_topic_arn(topic_name: str, account_id: str, region_name: str) -> str: return f"arn:{get_partition(region_name)}:sns:{region_name}:{account_id}:{topic_name}" +def sns_platform_application_arn( + platform_application_name: str, platform: str, account_id: str, region_name: str +) -> str: + return f"arn:{get_partition(region_name)}:sns:{region_name}:{account_id}:app/{platform}/{platform_application_name}" + + # # ECR # diff --git a/localstack-core/localstack/utils/aws/aws_responses.py b/localstack-core/localstack/utils/aws/aws_responses.py index d7bd236019b38..1c1de72e686a2 100644 --- a/localstack-core/localstack/utils/aws/aws_responses.py +++ b/localstack-core/localstack/utils/aws/aws_responses.py @@ -3,7 +3,7 @@ import json import re from binascii import crc32 -from typing import Any, Optional, Union +from typing import Any from urllib.parse import parse_qs import xmltodict @@ -36,10 +36,10 @@ def requests_error_response_json(message, code=500, error_type="InternalFailure" def requests_error_response_xml( message: str, - code: Optional[int] = 400, - code_string: Optional[str] = "InvalidParameter", - service: Optional[str] = None, - xmlns: Optional[str] = None, + code: int | None = 400, + code_string: str | None = "InvalidParameter", + service: str | None = None, + xmlns: str | None = None, ): response = RequestsResponse() xmlns = xmlns or f"http://{service}.amazonaws.com/doc/2010-03-31/" @@ -100,7 +100,7 @@ def requests_error_response_xml_signature_calculation( def requests_error_response( req_headers: dict, - message: Union[str, bytes], + message: str | bytes, code: int = 500, error_type: str = "InternalFailure", service: str = None, @@ -201,7 +201,7 @@ def parse_query_string(url_or_qs: str, multi_values=False) -> dict[str, str]: return result -def calculate_crc32(content: Union[str, bytes]) -> int: +def calculate_crc32(content: str | bytes) -> int: return crc32(to_bytes(content)) & 0xFFFFFFFF diff --git a/localstack-core/localstack/utils/aws/aws_stack.py b/localstack-core/localstack/utils/aws/aws_stack.py index 2d105f11269b3..f03bbeb268a05 100644 --- a/localstack-core/localstack/utils/aws/aws_stack.py +++ b/localstack-core/localstack/utils/aws/aws_stack.py @@ -2,7 +2,6 @@ import re import socket from functools import lru_cache -from typing import Union import boto3 @@ -36,8 +35,11 @@ def get_valid_regions(): def get_valid_regions_for_service(service_name): session = boto3.Session() regions = list(session.get_available_regions(service_name)) - regions.extend(session.get_available_regions("cloudwatch", partition_name="aws-us-gov")) - regions.extend(session.get_available_regions("cloudwatch", partition_name="aws-cn")) + for partition in session.get_available_partitions(): + # handle default partition separately for now. + # We use cloudwatch as service here to avoid missing botocore updates preventing service access for non-default partitions + if partition != "aws": + regions.extend(session.get_available_regions("cloudwatch", partition_name=partition)) return regions @@ -46,7 +48,7 @@ def get_boto3_region() -> str: return boto3.session.Session().region_name -def get_local_service_url(service_name_or_port: Union[str, int]) -> str: +def get_local_service_url(service_name_or_port: str | int) -> str: """Return the local service URL for the given service name or port.""" # TODO(srw): we don't need to differentiate on service name any more, so remove the argument if isinstance(service_name_or_port, int): @@ -68,7 +70,7 @@ def get_s3_hostname(): def fix_account_id_in_arns( - response, replacement: str, colon_delimiter: str = ":", existing: Union[str, list[str]] = None + response, replacement: str, colon_delimiter: str = ":", existing: str | list[str] = None ): """Fix the account ID in the ARNs returned in the given Flask response or string""" from moto.core import DEFAULT_ACCOUNT_ID diff --git a/localstack-core/localstack/utils/aws/client_types.py b/localstack-core/localstack/utils/aws/client_types.py index 9a27171a209e4..15e64576a3d80 100644 --- a/localstack-core/localstack/utils/aws/client_types.py +++ b/localstack-core/localstack/utils/aws/client_types.py @@ -61,11 +61,9 @@ from mypy_boto3_identitystore import IdentityStoreClient from mypy_boto3_iot import IoTClient from mypy_boto3_iot_data import IoTDataPlaneClient - from mypy_boto3_iotanalytics import IoTAnalyticsClient from mypy_boto3_iotwireless import IoTWirelessClient from mypy_boto3_kafka import KafkaClient from mypy_boto3_kinesis import KinesisClient - from mypy_boto3_kinesisanalytics import KinesisAnalyticsClient from mypy_boto3_kinesisanalyticsv2 import KinesisAnalyticsV2Client from mypy_boto3_kms import KMSClient from mypy_boto3_lakeformation import LakeFormationClient @@ -73,7 +71,6 @@ from mypy_boto3_logs import CloudWatchLogsClient from mypy_boto3_managedblockchain import ManagedBlockchainClient from mypy_boto3_mediaconvert import MediaConvertClient - from mypy_boto3_mediastore import MediaStoreClient from mypy_boto3_mq import MQClient from mypy_boto3_mwaa import MWAAClient from mypy_boto3_neptune import NeptuneClient @@ -82,8 +79,6 @@ from mypy_boto3_pi import PIClient from mypy_boto3_pinpoint import PinpointClient from mypy_boto3_pipes import EventBridgePipesClient - from mypy_boto3_qldb import QLDBClient - from mypy_boto3_qldb_session import QLDBSessionClient from mypy_boto3_rds import RDSClient from mypy_boto3_rds_data import RDSDataServiceClient from mypy_boto3_redshift import RedshiftClient @@ -187,13 +182,9 @@ class TypedServiceClientFactory(abc.ABC): identitystore: Union["IdentityStoreClient", "MetadataRequestInjector[IdentityStoreClient]"] iot: Union["IoTClient", "MetadataRequestInjector[IoTClient]"] iot_data: Union["IoTDataPlaneClient", "MetadataRequestInjector[IoTDataPlaneClient]"] - iotanalytics: Union["IoTAnalyticsClient", "MetadataRequestInjector[IoTAnalyticsClient]"] iotwireless: Union["IoTWirelessClient", "MetadataRequestInjector[IoTWirelessClient]"] kafka: Union["KafkaClient", "MetadataRequestInjector[KafkaClient]"] kinesis: Union["KinesisClient", "MetadataRequestInjector[KinesisClient]"] - kinesisanalytics: Union[ - "KinesisAnalyticsClient", "MetadataRequestInjector[KinesisAnalyticsClient]" - ] kinesisanalyticsv2: Union[ "KinesisAnalyticsV2Client", "MetadataRequestInjector[KinesisAnalyticsV2Client]" ] @@ -205,7 +196,6 @@ class TypedServiceClientFactory(abc.ABC): "ManagedBlockchainClient", "MetadataRequestInjector[ManagedBlockchainClient]" ] mediaconvert: Union["MediaConvertClient", "MetadataRequestInjector[MediaConvertClient]"] - mediastore: Union["MediaStoreClient", "MetadataRequestInjector[MediaStoreClient]"] mq: Union["MQClient", "MetadataRequestInjector[MQClient]"] mwaa: Union["MWAAClient", "MetadataRequestInjector[MWAAClient]"] neptune: Union["NeptuneClient", "MetadataRequestInjector[NeptuneClient]"] @@ -214,8 +204,6 @@ class TypedServiceClientFactory(abc.ABC): pi: Union["PIClient", "MetadataRequestInjector[PIClient]"] pinpoint: Union["PinpointClient", "MetadataRequestInjector[PinpointClient]"] pipes: Union["EventBridgePipesClient", "MetadataRequestInjector[EventBridgePipesClient]"] - qldb: Union["QLDBClient", "MetadataRequestInjector[QLDBClient]"] - qldb_session: Union["QLDBSessionClient", "MetadataRequestInjector[QLDBSessionClient]"] rds: Union["RDSClient", "MetadataRequestInjector[RDSClient]"] rds_data: Union["RDSDataServiceClient", "MetadataRequestInjector[RDSDataServiceClient]"] redshift: Union["RedshiftClient", "MetadataRequestInjector[RedshiftClient]"] @@ -285,6 +273,8 @@ class ServicePrincipal(str): appsync = "appsync" cloudformation = "cloudformation" dms = "dms" + ecs = "ecs" + ecs_tasks = "ecs-tasks" edgelambda = "edgelambda" elasticloadbalancing = "elasticloadbalancing" events = "events" diff --git a/localstack-core/localstack/utils/aws/message_forwarding.py b/localstack-core/localstack/utils/aws/message_forwarding.py index d4ca0d0df445c..32ca4e4eefc17 100644 --- a/localstack-core/localstack/utils/aws/message_forwarding.py +++ b/localstack-core/localstack/utils/aws/message_forwarding.py @@ -3,7 +3,6 @@ import logging import re import uuid -from typing import Optional from moto.events.models import events_backends @@ -214,7 +213,7 @@ def list_of_parameters_to_object(items): return {item.get("Key"): item.get("Value") for item in items} -def send_event_to_api_destination(target_arn, event, http_parameters: Optional[dict] = None): +def send_event_to_api_destination(target_arn, event, http_parameters: dict | None = None): """Send an event to an EventBridge API destination See https://docs.aws.amazon.com/eventbridge/latest/userguide/eb-api-destinations.html""" diff --git a/localstack-core/localstack/utils/aws/request_context.py b/localstack-core/localstack/utils/aws/request_context.py index 10a4c38b337d6..23a56c9bb76ab 100644 --- a/localstack-core/localstack/utils/aws/request_context.py +++ b/localstack-core/localstack/utils/aws/request_context.py @@ -4,7 +4,6 @@ import logging import re -from typing import Optional from rolo import Request as RoloRequest @@ -30,7 +29,7 @@ def get_account_id_from_request(request: RoloRequest) -> str: return get_account_id_from_access_key_id(access_key_id) -def extract_region_from_auth_header(headers) -> Optional[str]: +def extract_region_from_auth_header(headers) -> str | None: auth = headers.get("Authorization") or "" region = re.sub(r".*Credential=[^/]+/[^/]+/([^/]+)/.*", r"\1", auth) if region == auth: @@ -38,12 +37,12 @@ def extract_region_from_auth_header(headers) -> Optional[str]: return region -def extract_account_id_from_auth_header(headers) -> Optional[str]: +def extract_account_id_from_auth_header(headers) -> str | None: if access_key_id := extract_access_key_id_from_auth_header(headers): return get_account_id_from_access_key_id(access_key_id) -def extract_access_key_id_from_auth_header(headers: dict[str, str]) -> Optional[str]: +def extract_access_key_id_from_auth_header(headers: dict[str, str]) -> str | None: auth = headers.get("Authorization") or "" if auth.startswith("AWS4-"): @@ -67,7 +66,7 @@ def extract_region_from_headers(headers) -> str: return extract_region_from_auth_header(headers) or AWS_REGION_US_EAST_1 -def extract_service_name_from_auth_header(headers: dict) -> Optional[str]: +def extract_service_name_from_auth_header(headers: dict) -> str | None: try: auth_header = headers.get("authorization", "") credential_scope = auth_header.split(",")[0].split()[1] diff --git a/localstack-core/localstack/utils/batch_policy.py b/localstack-core/localstack/utils/batch_policy.py deleted file mode 100644 index 1c7f4fa18dfde..0000000000000 --- a/localstack-core/localstack/utils/batch_policy.py +++ /dev/null @@ -1,124 +0,0 @@ -import copy -import time -from typing import Generic, Optional, TypeVar, overload - -from pydantic import Field -from pydantic.dataclasses import dataclass - -T = TypeVar("T") - -# alias to signify whether a batch policy has been triggered -BatchPolicyTriggered = bool - - -# TODO: Add batching on bytes as well. -@dataclass -class Batcher(Generic[T]): - """ - A utility for collecting items into batches and flushing them when one or more batch policy conditions are met. - - The batch policy can be created to trigger on: - - max_count: Maximum number of items added - - max_window: Maximum time window (in seconds) - - If no limits are specified, the batcher is always in triggered state. - - Example usage: - - import time - - # Triggers when 2 (or more) items are added - batcher = Batcher(max_count=2) - assert batcher.add(["item1", "item2", "item3"]) - assert batcher.flush() == ["item1", "item2", "item3"] - - # Triggers partially when 2 (or more) items are added - batcher = Batcher(max_count=2) - assert batcher.add(["item1", "item2", "item3"]) - assert batcher.flush(partial=True) == ["item1", "item2"] - assert batcher.add("item4") - assert batcher.flush(partial=True) == ["item3", "item4"] - - # Trigger 2 seconds after the first add - batcher = Batcher(max_window=2.0) - assert not batcher.add(["item1", "item2", "item3"]) - time.sleep(2.1) - assert not batcher.add(["item4"]) - assert batcher.flush() == ["item1", "item2", "item3", "item4"] - """ - - max_count: Optional[int] = Field(default=None, description="Maximum number of items", ge=0) - max_window: Optional[float] = Field( - default=None, description="Maximum time window in seconds", ge=0 - ) - - _triggered: bool = Field(default=False, init=False) - _last_batch_time: float = Field(default_factory=time.monotonic, init=False) - _batch: list[T] = Field(default_factory=list, init=False) - - @property - def period(self) -> float: - return time.monotonic() - self._last_batch_time - - def _check_batch_policy(self) -> bool: - """Check if any batch policy conditions are met""" - if self.max_count is not None and len(self._batch) >= self.max_count: - self._triggered = True - elif self.max_window is not None and self.period >= self.max_window: - self._triggered = True - elif not self.max_count and not self.max_window: - # always return true - self._triggered = True - - return self._triggered - - @overload - def add(self, item: T, *, deep_copy: bool = False) -> BatchPolicyTriggered: ... - - @overload - def add(self, items: list[T], *, deep_copy: bool = False) -> BatchPolicyTriggered: ... - - def add(self, item_or_items: T | list[T], *, deep_copy: bool = False) -> BatchPolicyTriggered: - """ - Add an item or list of items to the collected batch. - - Returns: - BatchPolicyTriggered: True if the batch policy was triggered during addition, False otherwise. - """ - if deep_copy: - item_or_items = copy.deepcopy(item_or_items) - - if isinstance(item_or_items, list): - self._batch.extend(item_or_items) - else: - self._batch.append(item_or_items) - - # Check if the last addition triggered the batch policy - return self.is_triggered() - - def flush(self, *, partial=False) -> list[T]: - result = [] - if not partial or not self.max_count: - result = self._batch.copy() - self._batch.clear() - else: - batch_size = min(self.max_count, len(self._batch)) - result = self._batch[:batch_size].copy() - self._batch = self._batch[batch_size:] - - self._last_batch_time = time.monotonic() - self._triggered = False - self._check_batch_policy() - - return result - - def duration_until_next_batch(self) -> float: - if not self.max_window: - return -1 - return max(self.max_window - self.period, -1) - - def get_current_size(self) -> int: - return len(self._batch) - - def is_triggered(self): - return self._triggered or self._check_batch_policy() diff --git a/localstack-core/localstack/utils/batching.py b/localstack-core/localstack/utils/batching.py new file mode 100644 index 0000000000000..500e00e719da8 --- /dev/null +++ b/localstack-core/localstack/utils/batching.py @@ -0,0 +1,258 @@ +import copy +import logging +import threading +import time +from typing import Generic, Protocol, TypeVar, overload + +LOG = logging.getLogger(__name__) + +T = TypeVar("T") + +# alias to signify whether a batch policy has been triggered +BatchPolicyTriggered = bool + + +# TODO: Add batching on bytes as well. +class Batcher(Generic[T]): + """ + A utility for collecting items into batches and flushing them when one or more batch policy conditions are met. + + The batch policy can be created to trigger on: + - max_count: Maximum number of items added + - max_window: Maximum time window (in seconds) + + If no limits are specified, the batcher is always in triggered state. + + Example usage: + + import time + + # Triggers when 2 (or more) items are added + batcher = Batcher(max_count=2) + assert batcher.add(["item1", "item2", "item3"]) + assert batcher.flush() == ["item1", "item2", "item3"] + + # Triggers partially when 2 (or more) items are added + batcher = Batcher(max_count=2) + assert batcher.add(["item1", "item2", "item3"]) + assert batcher.flush(partial=True) == ["item1", "item2"] + assert batcher.add("item4") + assert batcher.flush(partial=True) == ["item3", "item4"] + + # Trigger 2 seconds after the first add + batcher = Batcher(max_window=2.0) + assert not batcher.add(["item1", "item2", "item3"]) + time.sleep(2.1) + assert not batcher.add(["item4"]) + assert batcher.flush() == ["item1", "item2", "item3", "item4"] + """ + + max_count: int | None + """ + Maximum number of items, must be None or positive. + """ + + max_window: float | None + """ + Maximum time window in seconds, must be None or positive. + """ + + _triggered: bool + _last_batch_time: float + _batch: list[T] + + def __init__(self, max_count: int | None = None, max_window: float | None = None): + """ + Initialize a new Batcher instance. + + :param max_count: Maximum number of items that be None or positive. + :param max_window: Maximum time window in seconds that must be None or positive. + """ + self.max_count = max_count + self.max_window = max_window + + self._triggered = False + self._last_batch_time = time.monotonic() + self._batch = [] + + @property + def period(self) -> float: + return time.monotonic() - self._last_batch_time + + def _check_batch_policy(self) -> bool: + """Check if any batch policy conditions are met""" + if self.max_count is not None and len(self._batch) >= self.max_count: + self._triggered = True + elif self.max_window is not None and self.period >= self.max_window: + self._triggered = True + elif not self.max_count and not self.max_window: + # always return true + self._triggered = True + + return self._triggered + + @overload + def add(self, item: T, *, deep_copy: bool = False) -> BatchPolicyTriggered: ... + + @overload + def add(self, items: list[T], *, deep_copy: bool = False) -> BatchPolicyTriggered: ... + + def add(self, item_or_items: T | list[T], *, deep_copy: bool = False) -> BatchPolicyTriggered: + """ + Add an item or list of items to the collected batch. + + Returns: + BatchPolicyTriggered: True if the batch policy was triggered during addition, False otherwise. + """ + if deep_copy: + item_or_items = copy.deepcopy(item_or_items) + + if isinstance(item_or_items, list): + self._batch.extend(item_or_items) + else: + self._batch.append(item_or_items) + + # Check if the last addition triggered the batch policy + return self.is_triggered() + + def flush(self, *, partial=False) -> list[T]: + result = [] + if not partial or not self.max_count: + result = self._batch.copy() + self._batch.clear() + else: + batch_size = min(self.max_count, len(self._batch)) + result = self._batch[:batch_size].copy() + self._batch = self._batch[batch_size:] + + self._last_batch_time = time.monotonic() + self._triggered = False + self._check_batch_policy() + + return result + + def duration_until_next_batch(self) -> float: + if not self.max_window: + return -1 + return max(self.max_window - self.period, -1) + + def get_current_size(self) -> int: + return len(self._batch) + + def is_triggered(self): + return self._triggered or self._check_batch_policy() + + +class BatchHandler(Protocol[T]): + """ + A BatchHandler is a callable that processes a list of items handed down by the AsyncBatcher. + """ + + def __call__(self, batch: list[T]) -> None: ... + + +class AsyncBatcher(Generic[T]): + """ + Class for managing asynchronous batching of items. + + This class allows for efficient buffering and processing of items in batches by + periodically flushing the buffer to a given handler, or by automatically flushing + when the maximum batch size is reached. It is designed to be used in asynchronous + scenarios where the caller does not execute the flushing IO call itself, like with ``Batcher``. + + :ivar max_flush_interval: Maximum time interval in seconds between + automatic flushes, regardless of the batch size. + :ivar max_batch_size: Maximum number of items in a batch. When reached, + the batch is flushed automatically. + :ivar handler: Callable handler that processes each flushed batch. The handler must + be provided during initialization and must accept a list of items as input. + """ + + max_flush_interval: float + max_batch_size: int + handler: BatchHandler[T] + + _buffer: list[T] + _flush_lock: threading.Condition + _closed: bool + + def __init__( + self, + handler: BatchHandler[T], + max_flush_interval: float = 10, + max_batch_size: int = 20, + ): + self.handler = handler + self.max_flush_interval = max_flush_interval + self.max_batch_size = max_batch_size + + self._buffer = [] + self._flush_lock = threading.Condition() + self._closed = False + + def add(self, item: T): + """ + Adds an item to the buffer. + + :param item: the item to add + """ + with self._flush_lock: + if self._closed: + raise ValueError("Batcher is stopped, can no longer add items") + + self._buffer.append(item) + + if len(self._buffer) >= self.max_batch_size: + self._flush_lock.notify_all() + + @property + def current_batch_size(self) -> int: + """ + Returns the current number of items in the buffer waiting to be flushed. + """ + return len(self._buffer) + + def run(self): + """ + Runs the event loop that flushes the buffer to the handler based on the configured rules, and blocks until + ``close()`` is called. This method is meant to be run in a separate thread. + """ + while not self._closed: + with self._flush_lock: + # wait returns once either the condition is notified (in which case wait returns True, indicating that + # something has triggered a flush manually), or the timeout expires (in which case wait returns False) + self._flush_lock.wait(self.max_flush_interval) + + # if _flush_condition was notified because close() was called, we should still make sure we flush the + # last batch + + # perform the flush, if there are any items in the buffer + if not self._buffer: + continue + + batch = self._buffer.copy() + self._buffer.clear() + + # we can call the processor outside the lock so we can continue adding items into the next batch without + # waiting on the processor to return. + try: + self.handler(batch) + except Exception as e: + LOG.error( + "Unhandled exception while processing a batch: %s", + e, + exc_info=LOG.isEnabledFor(logging.DEBUG), + ) + + # this marks that the main control loop is done + return + + def close(self): + """ + Triggers a close of the batcher, which will cause one last flush, and then end the main event loop. + """ + with self._flush_lock: + if self._closed: + return + self._closed = True + self._flush_lock.notify_all() diff --git a/localstack-core/localstack/utils/bootstrap.py b/localstack-core/localstack/utils/bootstrap.py index 8e8280069f0f4..7bb8aa915d703 100644 --- a/localstack-core/localstack/utils/bootstrap.py +++ b/localstack-core/localstack/utils/bootstrap.py @@ -9,9 +9,11 @@ import signal import threading import time -from collections.abc import Iterable +from collections.abc import Callable, Iterable from functools import wraps -from typing import Any, Callable, Optional, Union +from typing import Any + +from rich.console import Console from localstack import config, constants from localstack.config import ( @@ -34,8 +36,8 @@ NoSuchImage, NoSuchNetwork, PortMappings, - VolumeDirMount, VolumeMappings, + VolumeMappingSpecification, ) from localstack.utils.container_utils.docker_cmd_client import CmdDockerClient from localstack.utils.docker_utils import DOCKER_CLIENT @@ -48,6 +50,7 @@ from localstack.utils.sync import poll_condition LOG = logging.getLogger(__name__) +console = Console() # Mandatory dependencies of services on other services # - maps from API names to list of other API names that they _explicitly_ depend on: : @@ -175,7 +178,7 @@ def get_docker_image_details(image_name: str = None) -> dict[str, str]: return result -def get_image_environment_variable(env_name: str) -> Optional[str]: +def get_image_environment_variable(env_name: str) -> str | None: image_name = get_docker_image_to_start() image_info = DOCKER_CLIENT.inspect_image(image_name) image_envs = image_info["Config"]["Env"] @@ -365,8 +368,6 @@ def validate_localstack_config(name: str): # (use exceptions to communicate errors, and return list of warnings) from subprocess import CalledProcessError - from localstack.cli import console - dirname = os.getcwd() compose_file_name = name if os.path.isabs(name) else os.path.join(dirname, name) warns = [] @@ -444,7 +445,7 @@ def port_exposed(port): return False -def get_docker_image_to_start(): +def get_docker_image_to_start() -> str: image_name = os.environ.get("IMAGE_NAME") if not image_name: image_name = constants.DOCKER_IMAGE_NAME @@ -544,7 +545,7 @@ def default_gateway_port(cfg: ContainerConfiguration): @staticmethod def gateway_listen( - port: Union[int, Iterable[int], HostAndPort, Iterable[HostAndPort]], + port: int | Iterable[int] | HostAndPort | Iterable[HostAndPort], ): """ Uses the given ports to configure GATEWAY_LISTEN. For instance, ``gateway_listen([4566, 443])`` would @@ -666,7 +667,7 @@ def _cfg(cfg: ContainerConfiguration): return _cfg @staticmethod - def volume(volume: BindMount | VolumeDirMount): + def volume(volume: VolumeMappingSpecification): def _cfg(cfg: ContainerConfiguration): cfg.volumes.add(volume) @@ -1000,7 +1001,7 @@ def shutdown(self, timeout: int = 10, remove: bool = True): return raise - def inspect(self) -> dict[str, Union[dict, str]]: + def inspect(self) -> dict[str, dict | str]: return self.container_client.inspect_container(container_name_or_id=self.id) def attach(self): @@ -1028,7 +1029,7 @@ def __init__(self, container: Container, callback: Callable[[str], None] = print self.callback = callback self._closed = threading.Event() - self._stream: Optional[CancellableStream] = None + self._stream: CancellableStream | None = None def _can_start_streaming(self): if self._closed.is_set(): @@ -1338,7 +1339,7 @@ def start_infra_in_docker_detached(console, cli_params: dict[str, Any] = None): console.log("detaching") -def wait_container_is_ready(timeout: Optional[float] = None): +def wait_container_is_ready(timeout: float | None = None): """Blocks until the localstack main container is running and the ready marker has been printed.""" container_name = config.MAIN_CONTAINER_NAME started = time.time() diff --git a/localstack-core/localstack/utils/catalog/catalog.py b/localstack-core/localstack/utils/catalog/catalog.py index ca5e7e8bcbf1e..a0a536fd36cff 100644 --- a/localstack-core/localstack/utils/catalog/catalog.py +++ b/localstack-core/localstack/utils/catalog/catalog.py @@ -1,11 +1,9 @@ import logging from abc import abstractmethod +from typing import TypeAlias from plux import Plugin -from localstack.services.cloudformation.resource_provider import ( - plugin_manager as cfn_plugin_manager, -) from localstack.utils.catalog.catalog_loader import RemoteCatalogLoader from localstack.utils.catalog.common import ( AwsServiceOperationsSupportInLatest, @@ -21,12 +19,13 @@ ProviderName = str CfnResourceName = str CfnResourceMethodName = str -AwsServicesSupportStatus = ( +AwsServicesSupportStatus: TypeAlias = ( AwsServiceSupportAtRuntime | AwsServicesSupportInLatest | AwsServiceOperationsSupportInLatest ) -CfnResourceSupportStatus = ( +CfnResourceSupportStatus: TypeAlias = ( CloudFormationResourcesSupportInLatest | CloudFormationResourcesSupportAtRuntime ) +CfnResourceCatalog = dict[LocalstackEmulatorType, dict[CfnResourceName, set[CfnResourceMethodName]]] LOG = logging.getLogger(__name__) @@ -35,18 +34,27 @@ class CatalogPlugin(Plugin): namespace = "localstack.utils.catalog" @staticmethod - def get_cfn_resources_catalog(cloudformation_resources: dict): + def _get_cfn_resources_catalog(cloudformation_resources: dict) -> CfnResourceCatalog: cfn_resources_catalog = {} for emulator_type, resources in cloudformation_resources.items(): + cfn_resources_catalog[emulator_type] = {} for resource_name, resource in resources.items(): - cfn_resources_catalog[emulator_type] = {resource_name: set(resource.methods)} + cfn_resources_catalog[emulator_type][resource_name] = set(resource.methods) return cfn_resources_catalog @staticmethod - def get_aws_services_at_runtime(): + def _get_services_at_runtime() -> set[ServiceName]: from localstack.services.plugins import SERVICE_PLUGINS - return SERVICE_PLUGINS.list_available() + return set(SERVICE_PLUGINS.list_available()) + + @staticmethod + def _get_cfn_resources_available_at_runtime() -> set[CfnResourceName]: + from localstack.services.cloudformation.resource_provider import ( + plugin_manager as cfn_plugin_manager, + ) + + return set(cfn_plugin_manager.list_names()) @abstractmethod def get_aws_service_status( @@ -56,7 +64,7 @@ def get_aws_service_status( @abstractmethod def get_cloudformation_resource_status( - self, resource_name: str, service_name: str + self, resource_name: str, service_name: str, is_pro_resource: bool = False ) -> CfnResourceSupportStatus | AwsServicesSupportInLatest | None: pass @@ -70,7 +78,7 @@ def get_aws_service_status( return None def get_cloudformation_resource_status( - self, resource_name: str, service_name: str + self, resource_name: str, service_name: str, is_pro_resource: bool = False ) -> CfnResourceSupportStatus | AwsServicesSupportInLatest | None: return None @@ -80,9 +88,7 @@ class AwsCatalogRemoteStatePlugin(CatalogPlugin): current_emulator_type: LocalstackEmulatorType = LocalstackEmulatorType.COMMUNITY services_in_latest: dict[ServiceName, dict[LocalstackEmulatorType, ServiceOperations]] = {} services_at_runtime: set[ServiceName] = set() - cfn_resources_in_latest: dict[ - LocalstackEmulatorType, dict[CfnResourceName, set[CfnResourceMethodName]] - ] = {} + cfn_resources_in_latest: CfnResourceCatalog = {} cfn_resources_at_runtime: set[CfnResourceName] = set() def __init__(self, remote_catalog_loader: RemoteCatalogLoader | None = None) -> None: @@ -94,11 +100,11 @@ def __init__(self, remote_catalog_loader: RemoteCatalogLoader | None = None) -> service_provider.operations ) - self.cfn_resources_in_latest = self.get_cfn_resources_catalog( + self.cfn_resources_in_latest = self._get_cfn_resources_catalog( remote_catalog.cloudformation_resources ) - self.cfn_resources_at_runtime = set(cfn_plugin_manager.list_names()) - self.services_at_runtime = self.get_aws_services_at_runtime() + self.cfn_resources_at_runtime = self._get_cfn_resources_available_at_runtime() + self.services_at_runtime = self._get_services_at_runtime() def get_aws_service_status( self, service_name: str, operation_name: str | None = None @@ -121,7 +127,7 @@ def get_aws_service_status( return AwsServiceOperationsSupportInLatest.NOT_SUPPORTED def get_cloudformation_resource_status( - self, resource_name: str, service_name: str + self, resource_name: str, service_name: str, is_pro_resource: bool = False ) -> CfnResourceSupportStatus | AwsServicesSupportInLatest | None: if resource_name in self.cfn_resources_at_runtime: return CloudFormationResourcesSupportAtRuntime.AVAILABLE diff --git a/localstack-core/localstack/utils/catalog/catalog_loader.py b/localstack-core/localstack/utils/catalog/catalog_loader.py index 885e2d9978a79..2c2e84628abca 100644 --- a/localstack-core/localstack/utils/catalog/catalog_loader.py +++ b/localstack-core/localstack/utils/catalog/catalog_loader.py @@ -1,11 +1,119 @@ import json +import logging +from json import JSONDecodeError +from pathlib import Path +import requests +from pydantic import BaseModel + +from localstack import config, constants from localstack.utils.catalog.common import AwsRemoteCatalog +from localstack.utils.http import get_proxies +from localstack.utils.json import FileMappedDocument + +LOG = logging.getLogger(__name__) + +AWS_CATALOG_FILE_NAME = "aws_catalog.json" + -LICENSE_CATALOG_PATH = "" +class RemoteCatalogVersionResponse(BaseModel): + emulator_type: str + version: str + + +class AwsCatalogLoaderException(Exception): + def __init__(self, msg: str, *args): + super().__init__(msg, *args) class RemoteCatalogLoader: + supported_schema_version = "v1" + api_endpoint_catalog = f"{constants.API_ENDPOINT}/license/catalog" + catalog_file_path = Path(config.dirs.cache) / AWS_CATALOG_FILE_NAME + def get_remote_catalog(self) -> AwsRemoteCatalog: - with open(LICENSE_CATALOG_PATH) as f: - return AwsRemoteCatalog(**json.load(f)) + catalog_doc = FileMappedDocument(self.catalog_file_path) + cached_catalog = AwsRemoteCatalog(**catalog_doc) if catalog_doc else None + if cached_catalog: + cached_catalog_version = cached_catalog.localstack.version + if not self._should_update_cached_catalog(cached_catalog_version): + return cached_catalog + catalog = self._get_catalog_from_platform() + self._save_catalog_to_cache(catalog_doc, catalog) + return catalog + + def _get_latest_localstack_version(self) -> str: + try: + proxies = get_proxies() + response = requests.get( + f"{self.api_endpoint_catalog}/aws/version", + verify=not config.is_env_true("SSL_NO_VERIFY"), + proxies=proxies, + ) + if response.ok: + return RemoteCatalogVersionResponse.model_validate(response.content).version + self._raise_server_error(response) + except requests.exceptions.RequestException as e: + raise AwsCatalogLoaderException( + f"An unexpected network error occurred when trying to fetch latest localstack version: {e}" + ) from e + + def _should_update_cached_catalog(self, current_catalog_version: str) -> bool: + try: + latest_version = self._get_latest_localstack_version() + return latest_version != current_catalog_version + except Exception as e: + LOG.warning( + "Failed to retrieve the latest catalog version, cached catalog update skipped: %s", + e, + ) + return False + + def _save_catalog_to_cache(self, catalog_doc: FileMappedDocument, catalog: AwsRemoteCatalog): + catalog_doc.clear() + catalog_doc.update(catalog.model_dump()) + catalog_doc.save() + + def _get_catalog_from_platform(self) -> AwsRemoteCatalog: + try: + proxies = get_proxies() + response = requests.post( + self.api_endpoint_catalog, + verify=not config.is_env_true("SSL_NO_VERIFY"), + proxies=proxies, + ) + + if response.ok: + return self._parse_catalog(response.content) + self._raise_server_error(response) + except requests.exceptions.RequestException as e: + raise AwsCatalogLoaderException( + f"An unexpected network error occurred when trying to fetch remote catalog: {e}" + ) from e + + def _parse_catalog(self, document: bytes) -> AwsRemoteCatalog | None: + try: + catalog_json = json.loads(document) + except JSONDecodeError as e: + raise AwsCatalogLoaderException(f"Could not de-serialize json catalog: {e}") from e + remote_catalog = AwsRemoteCatalog.model_validate(catalog_json) + if remote_catalog.schema_version != self.supported_schema_version: + raise AwsCatalogLoaderException( + f"Unsupported schema version: '{remote_catalog.schema_version}'. Only '{self.supported_schema_version}' is supported" + ) + return remote_catalog + + def _raise_server_error(self, response: requests.Response): + try: + server_error = response.json() + if error_message := server_error.get("message"): + raise AwsCatalogLoaderException( + f"Unexpected AWS catalog server error: {response.text}" + ) + raise AwsCatalogLoaderException( + f"A server error occurred while calling remote catalog API (HTTP {response.status_code}): {error_message}" + ) + except Exception: + raise AwsCatalogLoaderException( + f"An unexpected server error occurred while calling remote catalog API (HTTP {response.status_code}): {response.text}" + ) diff --git a/localstack-core/localstack/utils/catalog/common.py b/localstack-core/localstack/utils/catalog/common.py index df4d129b37d77..809310cb0b8ca 100644 --- a/localstack-core/localstack/utils/catalog/common.py +++ b/localstack-core/localstack/utils/catalog/common.py @@ -55,3 +55,4 @@ class CloudFormationResourcesSupportInLatest(StrEnum): class CloudFormationResourcesSupportAtRuntime(StrEnum): AVAILABLE = "AVAILABLE" + NOT_IMPLEMENTED = "NOT_IMPLEMENTED" diff --git a/localstack-core/localstack/utils/cloudwatch/cloudwatch_util.py b/localstack-core/localstack/utils/cloudwatch/cloudwatch_util.py index 4df924d441ba6..58adfe8a9bf1e 100644 --- a/localstack-core/localstack/utils/cloudwatch/cloudwatch_util.py +++ b/localstack-core/localstack/utils/cloudwatch/cloudwatch_util.py @@ -2,7 +2,7 @@ import time from datetime import datetime, timezone from itertools import islice -from typing import Optional, TypedDict +from typing import TypedDict from werkzeug import Response as WerkzeugResponse @@ -20,8 +20,8 @@ class SqsMetricBatchData(TypedDict, total=False): MetricName: str QueueName: str - Value: Optional[int] - Unit: Optional[str] + Value: int | None + Unit: str | None def dimension_lambda(kwargs): @@ -30,7 +30,7 @@ def dimension_lambda(kwargs): def publish_lambda_metric( - metric, value, kwargs, account_id: Optional[str] = None, region_name: Optional[str] = None + metric, value, kwargs, account_id: str | None = None, region_name: str | None = None ): # publish metric only if CloudWatch service is available if not is_api_enabled("cloudwatch"): @@ -155,7 +155,7 @@ def store_cloudwatch_logs( log_stream_name, log_output, start_time=None, - auto_create_group: Optional[bool] = True, + auto_create_group: bool | None = True, ): if not is_api_enabled("logs"): return diff --git a/localstack-core/localstack/utils/collections.py b/localstack-core/localstack/utils/collections.py index e129be52727ef..52b202d3e2463 100644 --- a/localstack-core/localstack/utils/collections.py +++ b/localstack-core/localstack/utils/collections.py @@ -5,10 +5,9 @@ import logging import re -from collections.abc import Iterable, Iterator, Mapping, Sized +from collections.abc import Callable, Generator, Iterable, Iterator, Mapping, Sized from typing import ( Any, - Callable, Optional, TypedDict, TypeVar, @@ -16,6 +15,7 @@ cast, get_args, get_origin, + overload, ) import cachetools @@ -25,6 +25,9 @@ # default regex to match an item in a comma-separated list string DEFAULT_REGEX_LIST_ITEM = r"[\w-]+" +_E = TypeVar("_E") +"""TypeVar var used internally for container type parameters.""" + class AccessTrackingDict(dict): """ @@ -102,21 +105,18 @@ def __hash__(self): return hash(canonical_json(self._dict)) -_ListType = TypeVar("_ListType") - - -class PaginatedList(list[_ListType]): +class PaginatedList(list[_E]): """List which can be paginated and filtered. For usage in AWS APIs with paginated responses""" DEFAULT_PAGE_SIZE = 50 def get_page( self, - token_generator: Callable[[_ListType], str], + token_generator: Callable[[_E], str], next_token: str = None, page_size: int = None, - filter_function: Callable[[_ListType], bool] = None, - ) -> tuple[list[_ListType], Optional[str]]: + filter_function: Callable[[_E], bool] = None, + ) -> tuple[list[_E], str | None]: if filter_function is not None: result_list = list(filter(filter_function, self)) else: @@ -148,7 +148,7 @@ def get_page( class CustomExpiryTTLCache(cachetools.TTLCache): """TTLCache that allows to set custom expiry times for individual keys.""" - def set_expiry(self, key: Any, ttl: Union[float, int]) -> float: + def set_expiry(self, key: Any, ttl: float | int) -> float: """Set the expiry of the given key in a TTLCache to ( + )""" with self.timer as time: # note: need to access the internal dunder API here @@ -315,7 +315,15 @@ def is_list_or_tuple(obj) -> bool: return isinstance(obj, (list, tuple)) -def ensure_list(obj: Any, wrap_none=False) -> Optional[list]: +@overload +def ensure_list(obj: None) -> None: ... + + +@overload +def ensure_list(obj: Any) -> list[Any]: ... + + +def ensure_list(obj: Any, wrap_none: bool = False) -> list[Any] | None: """Wrap the given object in a list, or return the object itself if it already is a list.""" if obj is None and not wrap_none: return obj @@ -414,7 +422,7 @@ def contained(item): return True -def is_none_or_empty(obj: Union[Optional[str], Optional[list]]) -> bool: +def is_none_or_empty(obj: str | None | list | None) -> bool: return ( obj is None or (isinstance(obj, str) and obj.strip() == "") @@ -475,7 +483,7 @@ def convert_to_typed_dict(typed_dict: type[T], obj: dict, strict: bool = False) return result -def dict_multi_values(elements: Union[list, dict]) -> dict[str, list[Any]]: +def dict_multi_values(elements: list | dict) -> dict[str, list[Any]]: """ Return a dictionary with the original keys from the list of dictionary and the values are the list of values of the original dictionary. @@ -516,7 +524,7 @@ def split_list_by( return truthy, falsy -def is_comma_delimited_list(string: str, item_regex: Optional[str] = None) -> bool: +def is_comma_delimited_list(string: str, item_regex: str | None = None) -> bool: """ Checks if the given string is a comma-delimited list of items. The optional `item_regex` parameter specifies the regex pattern for each item in the list. @@ -529,9 +537,6 @@ def is_comma_delimited_list(string: str, item_regex: Optional[str] = None) -> bo return True -_E = TypeVar("_E") - - def optional_list(condition: bool, items: Iterable[_E]) -> list[_E]: """ Given an iterable, either create a list out of the entire iterable (if `condition` is `True`), or return the empty list. @@ -541,3 +546,18 @@ def optional_list(condition: bool, items: Iterable[_E]) -> list[_E]: [] """ return list(filter(lambda _: condition, items)) + + +def iter_chunks(items: list[_E], chunk_size: int) -> Generator[list[_E], None, None]: + """ + Split a list into smaller chunks of a specified size and iterate over them. + + It is implemented as a generator and yields each chunk as needed, making it memory-efficient for large lists. + + :param items: A list of elements to be divided into chunks. + :param chunk_size: The maximum number of elements that a single chunk can contain. + :return: A generator that yields chunks (sublists) of the original list. Each chunk contains up to `chunk_size` + elements. + """ + for i in range(0, len(items), chunk_size): + yield items[i : i + chunk_size] diff --git a/localstack-core/localstack/utils/config_listener.py b/localstack-core/localstack/utils/config_listener.py index c410c2e667240..f6b1f15cc047f 100644 --- a/localstack-core/localstack/utils/config_listener.py +++ b/localstack-core/localstack/utils/config_listener.py @@ -1,7 +1,7 @@ import json import logging import re -from typing import Callable +from collections.abc import Callable from requests.models import Response diff --git a/localstack-core/localstack/utils/container_networking.py b/localstack-core/localstack/utils/container_networking.py index 1a734576fa035..aaf8ba5286a71 100644 --- a/localstack-core/localstack/utils/container_networking.py +++ b/localstack-core/localstack/utils/container_networking.py @@ -2,7 +2,6 @@ import os import re from functools import lru_cache -from typing import Optional from localstack import config, constants from localstack.utils.container_utils.container_client import ContainerException @@ -13,7 +12,7 @@ @lru_cache -def get_main_container_network() -> Optional[str]: +def get_main_container_network() -> str | None: """ Gets the main network of the LocalStack container (if we run in one, bridge otherwise) If there are multiple networks connected to the LocalStack container, we choose the first as "main" network @@ -50,7 +49,7 @@ def get_main_container_network() -> Optional[str]: @lru_cache -def get_endpoint_for_network(network: Optional[str] = None) -> str: +def get_endpoint_for_network(network: str | None = None) -> str: """ Get the LocalStack endpoint (= IP address) on the given network. If a network is given, it will return the IP address/hostname of LocalStack on that network diff --git a/localstack-core/localstack/utils/container_utils/container_client.py b/localstack-core/localstack/utils/container_utils/container_client.py index 0551d78af5431..e15efa2e87044 100644 --- a/localstack-core/localstack/utils/container_utils/container_client.py +++ b/localstack-core/localstack/utils/container_utils/container_client.py @@ -5,21 +5,18 @@ import os import re import shlex -import sys import tarfile import tempfile from abc import ABCMeta, abstractmethod +from collections.abc import Callable from enum import Enum, unique from pathlib import Path from typing import ( - Callable, Literal, NamedTuple, - Optional, Protocol, + TypeAlias, TypedDict, - Union, - get_args, ) import dotenv @@ -37,6 +34,27 @@ WELL_KNOWN_IMAGE_REPO_PREFIXES = ("localhost/", "docker.io/library/") +def get_registry_from_image_name(image_name: str) -> str: + parts = image_name.split("/", maxsplit=1) + + if prefix := config.DOCKER_GLOBAL_IMAGE_PREFIX: + return prefix + + if len(parts) == 1: + # If no slash is present at all, it's an image name + return "docker.io" + + potential_registry = parts[0] + + registry_indicators = (".", ":", "localhost") + if any(indicator in potential_registry for indicator in registry_indicators): + # This indicates a registry domain or a local registry + return potential_registry + + # No explicit registry, assume Docker Hub + return "docker.io" + + @unique class DockerContainerStatus(Enum): DOWN = -1 @@ -57,7 +75,7 @@ class DockerContainerStats(TypedDict): MemUsage: tuple[int, int] NetIO: tuple[int, int] PIDs: int - SDKStats: Optional[dict] + SDKStats: dict | None class ContainerException(Exception): @@ -128,6 +146,7 @@ def close(self): raise NotImplementedError +# TODO: Migrate to StrEnum once the CLI does not need to support Python 3.10 (EOL Oct'26) anymore class DockerPlatform(str): """Platform in the format ``os[/arch[/variant]]``""" @@ -143,7 +162,7 @@ class Ulimit: name: str soft_limit: int - hard_limit: Optional[int] = None + hard_limit: int | None = None def __repr__(self): """Format: =[:]""" @@ -154,19 +173,11 @@ def __repr__(self): # defines the type for port mappings (source->target port range) -PortRange = Union[list, HashableList] +PortRange = list | HashableList # defines the protocol for a port range ("tcp" or "udp") PortProtocol = str -def isinstance_union(obj, class_or_tuple): - # that's some dirty hack - if sys.version_info < (3, 10): - return isinstance(obj, get_args(PortRange)) - else: - return isinstance(obj, class_or_tuple) - - class PortMappings: """Maps source to target port ranges for Docker port mappings.""" @@ -181,14 +192,14 @@ def __init__(self, bind_host: str = None): def add( self, - port: Union[int, PortRange], - mapped: Union[int, PortRange] = None, + port: int | PortRange, + mapped: int | PortRange = None, protocol: PortProtocol = "tcp", ): mapped = mapped or port - if isinstance_union(port, PortRange): + if isinstance(port, PortRange): for i in range(port[1] - port[0] + 1): - if isinstance_union(mapped, PortRange): + if isinstance(mapped, PortRange): self.add(port[0] + i, mapped[0] + i, protocol) else: self.add(port[0] + i, mapped, protocol) @@ -266,7 +277,7 @@ def entry(k, v): return [item for k, v in self.mappings.items() for item in entry(k, v)] - def to_dict(self) -> dict[str, Union[tuple[str, Union[int, list[int]]], int]]: + def to_dict(self) -> dict[str, tuple[str, int | list[int]] | int]: bind_address = self.bind_host or "" def bind_port(bind_address, host_port): @@ -369,7 +380,13 @@ def __repr__(self): @dataclasses.dataclass -class BindMount: +class Mount: + def to_str(self) -> str: + return str(self) + + +@dataclasses.dataclass +class BindMount(Mount): """Represents a --volume argument run/create command. When using VolumeBind to bind-mount a file or directory that does not yet exist on the Docker host, -v creates the endpoint for you. It is always created as a directory. """ @@ -414,7 +431,7 @@ def parse(cls, param: str) -> "BindMount": @dataclasses.dataclass -class VolumeDirMount: +class VolumeDirMount(Mount): volume_path: str """ Absolute path inside /var/lib/localstack to mount into the container @@ -451,28 +468,25 @@ def to_docker_sdk_parameters(self) -> tuple[str, dict[str, str]]: } +VolumeMappingSpecification: TypeAlias = SimpleVolumeBind | Mount + + class VolumeMappings: - mappings: list[Union[SimpleVolumeBind, BindMount]] + mappings: list[VolumeMappingSpecification] - def __init__(self, mappings: list[Union[SimpleVolumeBind, BindMount, VolumeDirMount]] = None): + def __init__( + self, + mappings: list[VolumeMappingSpecification] = None, + ): self.mappings = mappings if mappings is not None else [] - def add(self, mapping: Union[SimpleVolumeBind, BindMount, VolumeDirMount]): + def add(self, mapping: VolumeMappingSpecification): self.append(mapping) - def append( - self, - mapping: Union[ - SimpleVolumeBind, - BindMount, - VolumeDirMount, - ], - ): + def append(self, mapping: VolumeMappingSpecification): self.mappings.append(mapping) - def find_target_mapping( - self, container_dir: str - ) -> Optional[Union[SimpleVolumeBind, BindMount, VolumeDirMount]]: + def find_target_mapping(self, container_dir: str) -> VolumeMappingSpecification | None: """ Looks through the volumes and returns the one where the container dir matches ``container_dir``. Returns None if there is no volume mapping to the given container directory. @@ -511,8 +525,8 @@ class VolumeInfo(NamedTuple): mode: str rw: bool propagation: str - name: Optional[str] = None - driver: Optional[str] = None + name: str | None = None + driver: str | None = None @dataclasses.dataclass @@ -524,13 +538,13 @@ class LogConfig: @dataclasses.dataclass class ContainerConfiguration: image_name: str - name: Optional[str] = None + name: str | None = None volumes: VolumeMappings = dataclasses.field(default_factory=VolumeMappings) ports: PortMappings = dataclasses.field(default_factory=PortMappings) exposed_ports: list[str] = dataclasses.field(default_factory=list) - entrypoint: Optional[Union[list[str], str]] = None - additional_flags: Optional[str] = None - command: Optional[list[str]] = None + entrypoint: list[str] | str | None = None + additional_flags: str | None = None + command: list[str] | None = None env_vars: dict[str, str] = dataclasses.field(default_factory=dict) privileged: bool = False @@ -539,19 +553,22 @@ class ContainerConfiguration: tty: bool = False detach: bool = False - stdin: Optional[str] = None - user: Optional[str] = None - cap_add: Optional[list[str]] = None - cap_drop: Optional[list[str]] = None - security_opt: Optional[list[str]] = None - network: Optional[str] = None - dns: Optional[str] = None - workdir: Optional[str] = None - platform: Optional[str] = None - ulimits: Optional[list[Ulimit]] = None - labels: Optional[dict[str, str]] = None - init: Optional[bool] = None - log_config: Optional[LogConfig] = None + stdin: str | None = None + user: str | None = None + cap_add: list[str] | None = None + cap_drop: list[str] | None = None + security_opt: list[str] | None = None + network: str | None = None + dns: str | None = None + workdir: str | None = None + platform: str | None = None + ulimits: list[Ulimit] | None = None + labels: dict[str, str] | None = None + init: bool | None = None + log_config: LogConfig | None = None + cpu_shares: int | None = None + mem_limit: int | str | None = None + auth_config: dict[str, str] | None = None class ContainerConfigurator(Protocol): @@ -574,17 +591,17 @@ class DockerRunFlags: create: https://docs.docker.com/engine/reference/commandline/create/ """ - env_vars: Optional[dict[str, str]] - extra_hosts: Optional[dict[str, str]] - labels: Optional[dict[str, str]] - volumes: Optional[list[SimpleVolumeBind]] - network: Optional[str] - platform: Optional[DockerPlatform] - privileged: Optional[bool] - ports: Optional[PortMappings] - ulimits: Optional[list[Ulimit]] - user: Optional[str] - dns: Optional[list[str]] + env_vars: dict[str, str] | None + extra_hosts: dict[str, str] | None + labels: dict[str, str] | None + volumes: list[SimpleVolumeBind] | None + network: str | None + platform: DockerPlatform | None + privileged: bool | None + ports: PortMappings | None + ulimits: list[Ulimit] | None + user: str | None + dns: list[str] | None class RegistryResolverStrategy(Protocol): @@ -706,7 +723,7 @@ def remove_image(self, image: str, force: bool = True) -> None: """ @abstractmethod - def list_containers(self, filter: Union[list[str], str, None] = None, all=True) -> list[dict]: + def list_containers(self, filter: list[str] | str | None = None, all=True) -> list[dict]: """List all containers matching the given filters :return: A list of dicts with keys id, image, name, labels, status @@ -729,7 +746,7 @@ def create_file_in_container( container_name, file_contents: bytes, container_path: str, - chmod_mode: Optional[int] = None, + chmod_mode: int | None = None, ) -> None: """ Create a file in container with the provided content. Provide the 'chmod_mode' argument if you want the file to have specific permissions. @@ -761,18 +778,25 @@ def copy_from_container( def pull_image( self, docker_image: str, - platform: Optional[DockerPlatform] = None, - log_handler: Optional[Callable[[str], None]] = None, + platform: DockerPlatform | None = None, + log_handler: Callable[[str], None] | None = None, + auth_config: dict[str, str] | None = None, ) -> None: """ Pulls an image with a given name from a Docker registry :log_handler: Optional parameter that can be used to process the logs. Logs will be streamed if possible, but this is not guaranteed. + :auth_config: Optional authentication configuration for private registries. Dict with keys: username, password, registry """ @abstractmethod - def push_image(self, docker_image: str) -> None: - """Pushes an image with a given name to a Docker registry""" + def push_image(self, docker_image: str, auth_config: dict[str, str] | None = None) -> None: + """ + Pushes an image with a given name to a Docker registry + + :param docker_image: Image name and tag to push + :param auth_config: Optional authentication configuration for private registries. Dict with keys: username, password, registry + """ @abstractmethod def build_image( @@ -780,7 +804,7 @@ def build_image( dockerfile_path: str, image_name: str, context_path: str = None, - platform: Optional[DockerPlatform] = None, + platform: DockerPlatform | None = None, ) -> str: """Builds an image from the given Dockerfile @@ -824,7 +848,7 @@ def stream_container_logs(self, container_name_or_id: str) -> CancellableStream: """Returns a blocking generator you can iterate over to retrieve log output as it happens.""" @abstractmethod - def inspect_container(self, container_name_or_id: str) -> dict[str, Union[dict, str]]: + def inspect_container(self, container_name_or_id: str) -> dict[str, dict | str]: """Get detailed attributes of a container. :return: Dict containing docker attributes as returned by the daemon @@ -845,7 +869,7 @@ def inspect_container_volumes(self, container_name_or_id) -> list[VolumeInfo]: @abstractmethod def inspect_image( self, image_name: str, pull: bool = True, strip_wellknown_repo_prefixes: bool = True - ) -> dict[str, Union[dict, list, str]]: + ) -> dict[str, dict | list | str]: """Get detailed attributes of an image. :param image_name: Image name to inspect @@ -871,7 +895,7 @@ def delete_network(self, network_name: str) -> None: """ @abstractmethod - def inspect_network(self, network_name: str) -> dict[str, Union[dict, str]]: + def inspect_network(self, network_name: str) -> dict[str, dict | str]: """Get detailed attributes of an network. :return: Dict containing docker attributes as returned by the daemon @@ -882,7 +906,7 @@ def connect_container_to_network( self, network_name: str, container_name_or_id: str, - aliases: Optional[list] = None, + aliases: list | None = None, link_local_ips: list[str] = None, ) -> None: """ @@ -987,6 +1011,9 @@ def create_container_from_config(self, container_config: ContainerConfiguration) ulimits=container_config.ulimits, init=container_config.init, log_config=container_config.log_config, + cpu_shares=container_config.cpu_shares, + mem_limit=container_config.mem_limit, + auth_config=container_config.auth_config, ) @abstractmethod @@ -994,31 +1021,34 @@ def create_container( self, image_name: str, *, - name: Optional[str] = None, - entrypoint: Optional[Union[list[str], str]] = None, + name: str | None = None, + entrypoint: list[str] | str | None = None, remove: bool = False, interactive: bool = False, tty: bool = False, detach: bool = False, - command: Optional[Union[list[str], str]] = None, - volumes: Optional[Union[VolumeMappings, list[SimpleVolumeBind]]] = None, - ports: Optional[PortMappings] = None, - exposed_ports: Optional[list[str]] = None, - env_vars: Optional[dict[str, str]] = None, - user: Optional[str] = None, - cap_add: Optional[list[str]] = None, - cap_drop: Optional[list[str]] = None, - security_opt: Optional[list[str]] = None, - network: Optional[str] = None, - dns: Optional[Union[str, list[str]]] = None, - additional_flags: Optional[str] = None, - workdir: Optional[str] = None, - privileged: Optional[bool] = None, - labels: Optional[dict[str, str]] = None, - platform: Optional[DockerPlatform] = None, - ulimits: Optional[list[Ulimit]] = None, - init: Optional[bool] = None, - log_config: Optional[LogConfig] = None, + command: list[str] | str | None = None, + volumes: VolumeMappings | list[SimpleVolumeBind] | None = None, + ports: PortMappings | None = None, + exposed_ports: list[str] | None = None, + env_vars: dict[str, str] | None = None, + user: str | None = None, + cap_add: list[str] | None = None, + cap_drop: list[str] | None = None, + security_opt: list[str] | None = None, + network: str | None = None, + dns: str | list[str] | None = None, + additional_flags: str | None = None, + workdir: str | None = None, + privileged: bool | None = None, + labels: dict[str, str] | None = None, + platform: DockerPlatform | None = None, + ulimits: list[Ulimit] | None = None, + init: bool | None = None, + log_config: LogConfig | None = None, + cpu_shares: int | None = None, + mem_limit: int | str | None = None, + auth_config: dict[str, str] | None = None, ) -> str: """Creates a container with the given image @@ -1031,31 +1061,34 @@ def run_container( image_name: str, stdin: bytes = None, *, - name: Optional[str] = None, - entrypoint: Optional[str] = None, + name: str | None = None, + entrypoint: str | None = None, remove: bool = False, interactive: bool = False, tty: bool = False, detach: bool = False, - command: Optional[Union[list[str], str]] = None, - volumes: Optional[Union[VolumeMappings, list[SimpleVolumeBind]]] = None, - ports: Optional[PortMappings] = None, - exposed_ports: Optional[list[str]] = None, - env_vars: Optional[dict[str, str]] = None, - user: Optional[str] = None, - cap_add: Optional[list[str]] = None, - cap_drop: Optional[list[str]] = None, - security_opt: Optional[list[str]] = None, - network: Optional[str] = None, - dns: Optional[str] = None, - additional_flags: Optional[str] = None, - workdir: Optional[str] = None, - labels: Optional[dict[str, str]] = None, - platform: Optional[DockerPlatform] = None, - privileged: Optional[bool] = None, - ulimits: Optional[list[Ulimit]] = None, - init: Optional[bool] = None, - log_config: Optional[LogConfig] = None, + command: list[str] | str | None = None, + volumes: VolumeMappings | list[SimpleVolumeBind] | None = None, + ports: PortMappings | None = None, + exposed_ports: list[str] | None = None, + env_vars: dict[str, str] | None = None, + user: str | None = None, + cap_add: list[str] | None = None, + cap_drop: list[str] | None = None, + security_opt: list[str] | None = None, + network: str | None = None, + dns: str | None = None, + additional_flags: str | None = None, + workdir: str | None = None, + labels: dict[str, str] | None = None, + platform: DockerPlatform | None = None, + privileged: bool | None = None, + ulimits: list[Ulimit] | None = None, + init: bool | None = None, + log_config: LogConfig | None = None, + cpu_shares: int | None = None, + mem_limit: int | str | None = None, + auth_config: dict[str, str] | None = None, ) -> tuple[bytes, bytes]: """Creates and runs a given docker container @@ -1094,19 +1127,22 @@ def run_container_from_config( ulimits=container_config.ulimits, init=container_config.init, log_config=container_config.log_config, + cpu_shares=container_config.cpu_shares, + mem_limit=container_config.mem_limit, + auth_config=container_config.auth_config, ) @abstractmethod def exec_in_container( self, container_name_or_id: str, - command: Union[list[str], str], + command: list[str] | str, interactive: bool = False, detach: bool = False, - env_vars: Optional[dict[str, Optional[str]]] = None, - stdin: Optional[bytes] = None, - user: Optional[str] = None, - workdir: Optional[str] = None, + env_vars: dict[str, str | None] | None = None, + stdin: bytes | None = None, + user: str | None = None, + workdir: str | None = None, ) -> tuple[bytes, bytes]: """Execute a given command in a container @@ -1120,7 +1156,7 @@ def start_container( stdin: bytes = None, interactive: bool = False, attach: bool = False, - flags: Optional[str] = None, + flags: str | None = None, ) -> tuple[bytes, bytes]: """Start a given, already created container @@ -1134,7 +1170,7 @@ def attach_to_container(self, container_name_or_id: str): """ @abstractmethod - def login(self, username: str, password: str, registry: Optional[str] = None) -> None: + def login(self, username: str, password: str, registry: str | None = None) -> None: """ Login into an OCI registry @@ -1153,13 +1189,13 @@ class Util: MAX_ENV_ARGS_LENGTH = 20000 @staticmethod - def format_env_vars(key: str, value: Optional[str]): + def format_env_vars(key: str, value: str | None): if value is None: return key return f"{key}={value}" @classmethod - def create_env_vars_file_flag(cls, env_vars: dict) -> tuple[list[str], Optional[str]]: + def create_env_vars_file_flag(cls, env_vars: dict) -> tuple[list[str], str | None]: if not env_vars: return [], None result = [] @@ -1292,16 +1328,16 @@ def _read_docker_cli_env_file(env_file: str) -> dict[str, str]: @staticmethod def parse_additional_flags( additional_flags: str, - env_vars: Optional[dict[str, str]] = None, - labels: Optional[dict[str, str]] = None, - volumes: Optional[list[SimpleVolumeBind]] = None, - network: Optional[str] = None, - platform: Optional[DockerPlatform] = None, - ports: Optional[PortMappings] = None, - privileged: Optional[bool] = None, - user: Optional[str] = None, - ulimits: Optional[list[Ulimit]] = None, - dns: Optional[Union[str, list[str]]] = None, + env_vars: dict[str, str] | None = None, + labels: dict[str, str] | None = None, + volumes: list[SimpleVolumeBind] | None = None, + network: str | None = None, + platform: DockerPlatform | None = None, + ports: PortMappings | None = None, + privileged: bool | None = None, + user: str | None = None, + ulimits: list[Ulimit] | None = None, + dns: str | list[str] | None = None, ) -> DockerRunFlags: """Parses additional CLI-formatted Docker flags, which could overwrite provided defaults. :param additional_flags: String which contains the flag definitions inspired by the Docker CLI reference: @@ -1522,11 +1558,12 @@ def parse_additional_flags( @staticmethod def convert_mount_list_to_dict( - volumes: Union[list[SimpleVolumeBind], VolumeMappings], + volumes: list[SimpleVolumeBind] | VolumeMappings, ) -> dict[str, dict[str, str]]: """Converts a List of (host_path, container_path) tuples to a Dict suitable as volume argument for docker sdk""" - def _map_to_dict(paths: SimpleVolumeBind | BindMount | VolumeDirMount): + def _map_to_dict(paths: VolumeMappingSpecification): + # TODO: move this logic to the `Mount` base class if isinstance(paths, (BindMount, VolumeDirMount)): return paths.to_docker_sdk_parameters() else: diff --git a/localstack-core/localstack/utils/container_utils/docker_cmd_client.py b/localstack-core/localstack/utils/container_utils/docker_cmd_client.py index 90f53e97a97e2..9066b2987a646 100644 --- a/localstack-core/localstack/utils/container_utils/docker_cmd_client.py +++ b/localstack-core/localstack/utils/container_utils/docker_cmd_client.py @@ -6,13 +6,12 @@ import re import shlex import subprocess -from typing import Callable, Optional, Union +from collections.abc import Callable from localstack import config from localstack.utils.collections import ensure_list from localstack.utils.container_utils.container_client import ( AccessDenied, - BindMount, CancellableStream, ContainerClient, ContainerException, @@ -21,16 +20,17 @@ DockerNotAvailable, DockerPlatform, LogConfig, + Mount, NoSuchContainer, NoSuchImage, NoSuchNetwork, NoSuchObject, PortMappings, RegistryConnectionError, - SimpleVolumeBind, Ulimit, Util, - VolumeDirMount, + VolumeMappingSpecification, + get_registry_from_image_name, ) from localstack.utils.run import run from localstack.utils.strings import first_char_to_upper, to_str @@ -96,7 +96,7 @@ class CmdDockerClient(ContainerClient): different response payloads or error messages returned by the `docker` vs `podman` commands. """ - default_run_outfile: Optional[str] = None + default_run_outfile: str | None = None def _docker_cmd(self) -> list[str]: """ @@ -289,7 +289,7 @@ def remove_container( f"Docker process returned with errorcode {e.returncode}", e.stdout, e.stderr ) from e - def list_containers(self, filter: Union[list[str], str, None] = None, all=True) -> list[dict]: + def list_containers(self, filter: list[str] | str | None = None, all=True) -> list[dict]: filter = [filter] if isinstance(filter, str) else filter cmd = self._docker_cmd() cmd.append("ps") @@ -365,9 +365,11 @@ def copy_from_container( def pull_image( self, docker_image: str, - platform: Optional[DockerPlatform] = None, - log_handler: Optional[Callable[[str], None]] = None, + platform: DockerPlatform | None = None, + log_handler: Callable[[str], None] | None = None, + auth_config: dict[str, str] | None = None, ) -> None: + self._login_if_needed(auth_config, docker_image) cmd = self._docker_cmd() docker_image = self.registry_resolver_strategy.resolve(docker_image) cmd += ["pull", docker_image] @@ -391,7 +393,8 @@ def pull_image( f"Docker process returned with errorcode {e.returncode}", e.stdout, e.stderr ) from e - def push_image(self, docker_image: str) -> None: + def push_image(self, docker_image: str, auth_config: dict[str, str] | None = None) -> None: + self._login_if_needed(auth_config, docker_image) cmd = self._docker_cmd() cmd += ["push", docker_image] LOG.debug("Pushing image with cmd: %s", cmd) @@ -404,10 +407,18 @@ def push_image(self, docker_image: str) -> None: raise AccessDenied(docker_image) if "access token has insufficient scopes" in to_str(e.stdout): raise AccessDenied(docker_image) + if "authorization failed: no basic auth credentials" in to_str(e.stdout): + raise AccessDenied(docker_image) + if "failed to authorize: failed to fetch oauth token" in to_str(e.stdout): + raise AccessDenied(docker_image) + if "insufficient_scope: authorization failed" in to_str(e.stdout): + raise AccessDenied(docker_image) if "does not exist" in to_str(e.stdout): raise NoSuchImage(docker_image) if "connection refused" in to_str(e.stdout): raise RegistryConnectionError(e.stdout) + if "failed to do request:" in to_str(e.stdout): + raise RegistryConnectionError(e.stdout) # note: error message 'image not known' raised by Podman client if "image not known" in to_str(e.stdout): raise NoSuchImage(docker_image) @@ -420,7 +431,7 @@ def build_image( dockerfile_path: str, image_name: str, context_path: str = None, - platform: Optional[DockerPlatform] = None, + platform: DockerPlatform | None = None, ): cmd = self._docker_cmd() dockerfile_path = Util.resolve_dockerfile_path(dockerfile_path) @@ -497,7 +508,7 @@ def stream_container_logs(self, container_name_or_id: str) -> CancellableStream: return CancellableProcessStream(process) - def _inspect_object(self, object_name_or_id: str) -> dict[str, Union[dict, list, str]]: + def _inspect_object(self, object_name_or_id: str) -> dict[str, dict | list | str]: cmd = self._docker_cmd() cmd += ["inspect", "--format", "{{json .}}", object_name_or_id] try: @@ -524,7 +535,7 @@ def _inspect_object(self, object_name_or_id: str) -> dict[str, Union[dict, list, ) return object_data - def inspect_container(self, container_name_or_id: str) -> dict[str, Union[dict, str]]: + def inspect_container(self, container_name_or_id: str) -> dict[str, dict | str]: try: return self._inspect_object(container_name_or_id) except NoSuchObject as e: @@ -535,7 +546,7 @@ def inspect_image( image_name: str, pull: bool = True, strip_wellknown_repo_prefixes: bool = True, - ) -> dict[str, Union[dict, list, str]]: + ) -> dict[str, dict | list | str]: image_name = self.registry_resolver_strategy.resolve(image_name) try: result = self._inspect_object(image_name) @@ -577,7 +588,7 @@ def delete_network(self, network_name: str) -> None: f"Docker process returned with errorcode {e.returncode}", e.stdout, e.stderr ) from e - def inspect_network(self, network_name: str) -> dict[str, Union[dict, str]]: + def inspect_network(self, network_name: str) -> dict[str, dict | str]: try: return self._inspect_object(network_name) except NoSuchObject as e: @@ -587,7 +598,7 @@ def connect_container_to_network( self, network_name: str, container_name_or_id: str, - aliases: Optional[list] = None, + aliases: list | None = None, link_local_ips: list[str] = None, ) -> None: LOG.debug( @@ -652,7 +663,7 @@ def get_container_ip(self, container_name_or_id: str) -> str: f"Docker process returned with errorcode {e.returncode}", e.stdout, e.stderr ) from e - def login(self, username: str, password: str, registry: Optional[str] = None) -> None: + def login(self, username: str, password: str, registry: str | None = None) -> None: cmd = self._docker_cmd() # TODO specify password via stdin cmd += ["login", "-u", username, "-p", password] @@ -675,6 +686,9 @@ def has_docker(self) -> bool: return False def create_container(self, image_name: str, **kwargs) -> str: + # Extract auth_config if provided + auth_config = kwargs.pop("auth_config", None) + self._login_if_needed(auth_config, image_name) image_name = self.registry_resolver_strategy.resolve(image_name) cmd, env_file = self._build_run_create_cmd("create", image_name, **kwargs) LOG.debug("Create container with cmd: %s", cmd) @@ -694,6 +708,8 @@ def create_container(self, image_name: str, **kwargs) -> str: Util.rm_env_vars_file(env_file) def run_container(self, image_name: str, stdin=None, **kwargs) -> tuple[bytes, bytes]: + auth_config = kwargs.pop("auth_config", None) + self._login_if_needed(auth_config, image_name) image_name = self.registry_resolver_strategy.resolve(image_name) cmd, env_file = self._build_run_create_cmd("run", image_name, **kwargs) LOG.debug("Run container with cmd: %s", cmd) @@ -709,13 +725,13 @@ def run_container(self, image_name: str, stdin=None, **kwargs) -> tuple[bytes, b def exec_in_container( self, container_name_or_id: str, - command: Union[list[str], str], + command: list[str] | str, interactive=False, detach=False, - env_vars: Optional[dict[str, Optional[str]]] = None, - stdin: Optional[bytes] = None, - user: Optional[str] = None, - workdir: Optional[str] = None, + env_vars: dict[str, str | None] | None = None, + stdin: bytes | None = None, + user: str | None = None, + workdir: str | None = None, ) -> tuple[bytes, bytes]: env_file = None cmd = self._docker_cmd() @@ -745,7 +761,7 @@ def start_container( stdin=None, interactive: bool = False, attach: bool = False, - flags: Optional[str] = None, + flags: str | None = None, ) -> tuple[bytes, bytes]: cmd = self._docker_cmd() + ["start"] if flags: @@ -803,31 +819,33 @@ def _build_run_create_cmd( action: str, image_name: str, *, - name: Optional[str] = None, - entrypoint: Optional[Union[list[str], str]] = None, + name: str | None = None, + entrypoint: list[str] | str | None = None, remove: bool = False, interactive: bool = False, tty: bool = False, detach: bool = False, - command: Optional[Union[list[str], str]] = None, - volumes: Optional[list[SimpleVolumeBind]] = None, - ports: Optional[PortMappings] = None, - exposed_ports: Optional[list[str]] = None, - env_vars: Optional[dict[str, str]] = None, - user: Optional[str] = None, - cap_add: Optional[list[str]] = None, - cap_drop: Optional[list[str]] = None, - security_opt: Optional[list[str]] = None, - network: Optional[str] = None, - dns: Optional[Union[str, list[str]]] = None, - additional_flags: Optional[str] = None, - workdir: Optional[str] = None, - privileged: Optional[bool] = None, - labels: Optional[dict[str, str]] = None, - platform: Optional[DockerPlatform] = None, - ulimits: Optional[list[Ulimit]] = None, - init: Optional[bool] = None, - log_config: Optional[LogConfig] = None, + command: list[str] | str | None = None, + volumes: list[VolumeMappingSpecification] | None = None, + ports: PortMappings | None = None, + exposed_ports: list[str] | None = None, + env_vars: dict[str, str] | None = None, + user: str | None = None, + cap_add: list[str] | None = None, + cap_drop: list[str] | None = None, + security_opt: list[str] | None = None, + network: str | None = None, + dns: str | list[str] | None = None, + additional_flags: str | None = None, + workdir: str | None = None, + privileged: bool | None = None, + labels: dict[str, str] | None = None, + platform: DockerPlatform | None = None, + ulimits: list[Ulimit] | None = None, + init: bool | None = None, + log_config: LogConfig | None = None, + cpu_shares: int | None = None, + mem_limit: int | str | None = None, ) -> tuple[list[str], str]: env_file = None cmd = self._docker_cmd() + [action] @@ -891,6 +909,10 @@ def _build_run_create_cmd( cmd += ["--log-driver", log_config.type] for key, value in log_config.config.items(): cmd += ["--log-opt", f"{key}={value}"] + if cpu_shares: + cmd += ["--cpu-shares", str(cpu_shares)] + if mem_limit: + cmd += ["--memory", str(mem_limit)] if additional_flags: cmd += shlex.split(additional_flags) @@ -900,7 +922,7 @@ def _build_run_create_cmd( return cmd, env_file @staticmethod - def _map_to_volume_param(volume: Union[SimpleVolumeBind, BindMount, VolumeDirMount]) -> str: + def _map_to_volume_param(volume: VolumeMappingSpecification) -> str: """ Maps the mount volume, to a parameter for the -v docker cli argument. @@ -911,7 +933,8 @@ def _map_to_volume_param(volume: Union[SimpleVolumeBind, BindMount, VolumeDirMou :param volume: Either a SimpleVolumeBind, in essence a tuple (host_dir, container_dir), or a VolumeBind object :return: String which is passable as parameter to the docker cli -v option """ - if isinstance(volume, (BindMount, VolumeDirMount)): + # TODO: move this logic to the VolumeMappingSpecification type + if isinstance(volume, Mount): return volume.to_str() else: return f"{volume[0]}:{volume[1]}" @@ -928,7 +951,7 @@ def _check_and_raise_no_such_container_error( ) def _check_output_and_raise_no_such_container_error( - self, container_name_or_id: str, output: str, error: Optional[str] = None + self, container_name_or_id: str, output: str, error: str | None = None ): """ Check the given client invocation output and raise a `NoSuchContainer` exception if it @@ -938,7 +961,7 @@ def _check_output_and_raise_no_such_container_error( if any(msg.lower() in output.lower() for msg in possible_not_found_messages): raise NoSuchContainer(container_name_or_id, stdout=output, stderr=error) - def _transform_container_labels(self, labels: Union[str, dict[str, str]]) -> dict[str, str]: + def _transform_container_labels(self, labels: str | dict[str, str]) -> dict[str, str]: """ Transforms the container labels returned by the docker command from the key-value pair format to a dict :param labels: Input string, comma separated key value pairs. Example: key1=value1,key2=value2 @@ -950,3 +973,17 @@ def _transform_container_labels(self, labels: Union[str, dict[str, str]]) -> dic labels = labels.split(",") labels = [label.partition("=") for label in labels] return {label[0]: label[2] for label in labels} + + def _login_if_needed(self, auth_config: dict[str, str] | None, image_name) -> None: + if auth_config: + LOG.warning( + "Using global docker login for authentication in docker_cmd_client. " + "This may lead to unexpected behaviors with concurrent requests to different registries. " + "Consider stop using LEGACY_DOCKER_CLIENT for thread-safe authentication." + ) + registry = get_registry_from_image_name(image_name) + self.login( + username=auth_config.get("username", ""), + password=auth_config.get("password", ""), + registry=registry, + ) diff --git a/localstack-core/localstack/utils/container_utils/docker_sdk_client.py b/localstack-core/localstack/utils/container_utils/docker_sdk_client.py index 45098e185f6bd..469bb8d400746 100644 --- a/localstack-core/localstack/utils/container_utils/docker_sdk_client.py +++ b/localstack-core/localstack/utils/container_utils/docker_sdk_client.py @@ -6,9 +6,10 @@ import re import socket import threading +from collections.abc import Callable from functools import cache from time import sleep -from typing import Callable, Optional, Union, cast +from typing import cast from urllib.parse import quote import docker @@ -56,9 +57,9 @@ class SdkDockerClient(ContainerClient): is doing some of the heavy lifting for us to support both target platforms. """ - docker_client: Optional[DockerClient] + docker_client: DockerClient | None - def __init__(self): + def __init__(self) -> None: try: self.docker_client = self._create_client() logging.getLogger("urllib3").setLevel(logging.INFO) @@ -280,7 +281,7 @@ def remove_container( except APIError as e: raise ContainerException() from e - def list_containers(self, filter: Union[list[str], str, None] = None, all=True) -> list[dict]: + def list_containers(self, filter: list[str] | str | None = None, all=True) -> list[dict]: if filter: filter = [filter] if isinstance(filter, str) else filter filter = dict([f.split("=", 1) for f in filter]) @@ -339,14 +340,17 @@ def copy_from_container( def pull_image( self, docker_image: str, - platform: Optional[DockerPlatform] = None, - log_handler: Optional[Callable[[str], None]] = None, + platform: DockerPlatform | None = None, + log_handler: Callable[[str], None] | None = None, + auth_config: dict[str, str] | None = None, ) -> None: LOG.debug("Pulling Docker image: %s", docker_image) # some path in the docker image string indicates a custom repository docker_image = self.registry_resolver_strategy.resolve(docker_image) - kwargs: dict[str, Union[str, bool]] = {"platform": platform} + kwargs: dict[str, str | bool | dict[str, str]] = {"platform": platform} + if auth_config: + kwargs["auth_config"] = auth_config try: if log_handler: # Use a lower-level API, as the 'stream' argument is not available in the higher-level `pull`-API @@ -361,10 +365,13 @@ def pull_image( except APIError as e: raise ContainerException() from e - def push_image(self, docker_image: str) -> None: + def push_image(self, docker_image: str, auth_config: dict[str, str] | None = None) -> None: LOG.debug("Pushing Docker image: %s", docker_image) + kwargs: dict[str, dict[str, str]] = {} + if auth_config: + kwargs["auth_config"] = auth_config try: - result = self.client().images.push(docker_image) + result = self.client().images.push(docker_image, **kwargs) # some SDK clients (e.g., 5.0.0) seem to return an error string, instead of raising if isinstance(result, (str, bytes)) and '"errorDetail"' in to_str(result): if "image does not exist locally" in to_str(result): @@ -375,8 +382,20 @@ def push_image(self, docker_image: str) -> None: raise AccessDenied(docker_image) if "access token has insufficient scopes" in to_str(result): raise AccessDenied(docker_image) + if "authorization failed: no basic auth credentials" in to_str(result): + raise AccessDenied(docker_image) + if "401 Unauthorized" in to_str(result): + raise AccessDenied(docker_image) + if "no basic auth credentials" in to_str(result): + raise AccessDenied(docker_image) + if "unauthorized: authentication required" in to_str(result): + raise AccessDenied(docker_image) + if "insufficient_scope: authorization failed" in to_str(result): + raise AccessDenied(docker_image) if "connection refused" in to_str(result): raise RegistryConnectionError(result) + if "failed to do request:" in to_str(result): + raise RegistryConnectionError(result) raise ContainerException(result) except ImageNotFound: raise NoSuchImage(docker_image) @@ -391,7 +410,7 @@ def build_image( dockerfile_path: str, image_name: str, context_path: str = None, - platform: Optional[DockerPlatform] = None, + platform: DockerPlatform | None = None, ): try: dockerfile_path = Util.resolve_dockerfile_path(dockerfile_path) @@ -468,7 +487,7 @@ def stream_container_logs(self, container_name_or_id: str) -> CancellableStream: except APIError as e: raise ContainerException() from e - def inspect_container(self, container_name_or_id: str) -> dict[str, Union[dict, str]]: + def inspect_container(self, container_name_or_id: str) -> dict[str, dict | str]: try: return self.client().containers.get(container_name_or_id).attrs except NotFound: @@ -481,7 +500,7 @@ def inspect_image( image_name: str, pull: bool = True, strip_wellknown_repo_prefixes: bool = True, - ) -> dict[str, Union[dict, list, str]]: + ) -> dict[str, dict | list | str]: image_name = self.registry_resolver_strategy.resolve(image_name) try: result = self.client().images.get(image_name).attrs @@ -515,7 +534,7 @@ def delete_network(self, network_name: str) -> None: except APIError as e: raise ContainerException() from e - def inspect_network(self, network_name: str) -> dict[str, Union[dict, str]]: + def inspect_network(self, network_name: str) -> dict[str, dict | str]: try: return self.client().networks.get(network_name).attrs except NotFound: @@ -527,7 +546,7 @@ def connect_container_to_network( self, network_name: str, container_name_or_id: str, - aliases: Optional[list] = None, + aliases: list | None = None, link_local_ips: list[str] = None, ) -> None: LOG.debug( @@ -621,7 +640,7 @@ def start_container( stdin=None, interactive: bool = False, attach: bool = False, - flags: Optional[str] = None, + flags: str | None = None, ) -> tuple[bytes, bytes]: LOG.debug("Starting container %s", container_name_or_id) try: @@ -670,7 +689,7 @@ def wait_for_result(*_): sock.sendall(to_bytes(stdin)) sock.shutdown(socket.SHUT_WR) stdout, stderr = self._read_from_sock(sock, False) - except socket.timeout: + except TimeoutError: LOG.debug( "Socket timeout when talking to the I/O streams of Docker container '%s'", container_name_or_id, @@ -703,31 +722,34 @@ def create_container( self, image_name: str, *, - name: Optional[str] = None, - entrypoint: Optional[Union[list[str], str]] = None, + name: str | None = None, + entrypoint: list[str] | str | None = None, remove: bool = False, interactive: bool = False, tty: bool = False, detach: bool = False, - command: Optional[Union[list[str], str]] = None, - volumes: Optional[list[SimpleVolumeBind]] = None, - ports: Optional[PortMappings] = None, - exposed_ports: Optional[list[str]] = None, - env_vars: Optional[dict[str, str]] = None, - user: Optional[str] = None, - cap_add: Optional[list[str]] = None, - cap_drop: Optional[list[str]] = None, - security_opt: Optional[list[str]] = None, - network: Optional[str] = None, - dns: Optional[Union[str, list[str]]] = None, - additional_flags: Optional[str] = None, - workdir: Optional[str] = None, - privileged: Optional[bool] = None, - labels: Optional[dict[str, str]] = None, - platform: Optional[DockerPlatform] = None, - ulimits: Optional[list[Ulimit]] = None, - init: Optional[bool] = None, - log_config: Optional[LogConfig] = None, + command: list[str] | str | None = None, + volumes: list[SimpleVolumeBind] | None = None, + ports: PortMappings | None = None, + exposed_ports: list[str] | None = None, + env_vars: dict[str, str] | None = None, + user: str | None = None, + cap_add: list[str] | None = None, + cap_drop: list[str] | None = None, + security_opt: list[str] | None = None, + network: str | None = None, + dns: str | list[str] | None = None, + additional_flags: str | None = None, + workdir: str | None = None, + privileged: bool | None = None, + labels: dict[str, str] | None = None, + platform: DockerPlatform | None = None, + ulimits: list[Ulimit] | None = None, + init: bool | None = None, + log_config: LogConfig | None = None, + cpu_shares: int | None = None, + mem_limit: int | str | None = None, + auth_config: dict[str, str] | None = None, ) -> str: LOG.debug("Creating container with attributes: %s", locals()) extra_hosts = None @@ -792,6 +814,10 @@ def create_container( ) for ulimit in ulimits ] + if cpu_shares: + kwargs["cpu_shares"] = cpu_shares + if mem_limit: + kwargs["mem_limit"] = mem_limit mounts = None if volumes: mounts = Util.convert_mount_list_to_dict(volumes) @@ -821,7 +847,7 @@ def create_container(): container = create_container() except ImageNotFound: LOG.debug("Image not found. Pulling image %s", image_name) - self.pull_image(image_name, platform) + self.pull_image(image_name, platform, auth_config=auth_config) container = create_container() return container.id except ImageNotFound: @@ -834,31 +860,34 @@ def run_container( image_name: str, stdin=None, *, - name: Optional[str] = None, - entrypoint: Optional[str] = None, + name: str | None = None, + entrypoint: str | None = None, remove: bool = False, interactive: bool = False, tty: bool = False, detach: bool = False, - command: Optional[Union[list[str], str]] = None, - volumes: Optional[list[SimpleVolumeBind]] = None, - ports: Optional[PortMappings] = None, - exposed_ports: Optional[list[str]] = None, - env_vars: Optional[dict[str, str]] = None, - user: Optional[str] = None, - cap_add: Optional[list[str]] = None, - cap_drop: Optional[list[str]] = None, - security_opt: Optional[list[str]] = None, - network: Optional[str] = None, - dns: Optional[str] = None, - additional_flags: Optional[str] = None, - workdir: Optional[str] = None, - labels: Optional[dict[str, str]] = None, - platform: Optional[DockerPlatform] = None, - privileged: Optional[bool] = None, - ulimits: Optional[list[Ulimit]] = None, - init: Optional[bool] = None, - log_config: Optional[LogConfig] = None, + command: list[str] | str | None = None, + volumes: list[SimpleVolumeBind] | None = None, + ports: PortMappings | None = None, + exposed_ports: list[str] | None = None, + env_vars: dict[str, str] | None = None, + user: str | None = None, + cap_add: list[str] | None = None, + cap_drop: list[str] | None = None, + security_opt: list[str] | None = None, + network: str | None = None, + dns: str | None = None, + additional_flags: str | None = None, + workdir: str | None = None, + labels: dict[str, str] | None = None, + platform: DockerPlatform | None = None, + privileged: bool | None = None, + ulimits: list[Ulimit] | None = None, + init: bool | None = None, + log_config: LogConfig | None = None, + cpu_shares: int | None = None, + mem_limit: int | str | None = None, + auth_config: dict[str, str] | None = None, ) -> tuple[bytes, bytes]: LOG.debug("Running container with image: %s", image_name) container = None @@ -890,6 +919,9 @@ def run_container( labels=labels, ulimits=ulimits, log_config=log_config, + cpu_shares=cpu_shares, + mem_limit=mem_limit, + auth_config=auth_config, ) result = self.start_container( container_name_or_id=container, @@ -905,13 +937,13 @@ def run_container( def exec_in_container( self, container_name_or_id: str, - command: Union[list[str], str], + command: list[str] | str, interactive=False, detach=False, - env_vars: Optional[dict[str, Optional[str]]] = None, - stdin: Optional[bytes] = None, - user: Optional[str] = None, - workdir: Optional[str] = None, + env_vars: dict[str, str | None] | None = None, + stdin: bytes | None = None, + user: str | None = None, + workdir: str | None = None, ) -> tuple[bytes, bytes]: LOG.debug("Executing command in container %s: %s", container_name_or_id, command) try: @@ -938,7 +970,7 @@ def exec_in_container( sock.shutdown(socket.SHUT_WR) stdout, stderr = self._read_from_sock(sock, tty) return stdout, stderr - except socket.timeout: + except TimeoutError: pass else: if detach: @@ -959,7 +991,7 @@ def exec_in_container( except APIError as e: raise ContainerException() from e - def login(self, username: str, password: str, registry: Optional[str] = None) -> None: + def login(self, username: str, password: str, registry: str | None = None) -> None: LOG.debug("Docker login for %s", username) try: self.client().login(username, password=password, registry=registry, reauth=True) diff --git a/localstack-core/localstack/utils/coverage_docs.py b/localstack-core/localstack/utils/coverage_docs.py deleted file mode 100644 index fde4628a32f67..0000000000000 --- a/localstack-core/localstack/utils/coverage_docs.py +++ /dev/null @@ -1,20 +0,0 @@ -_COVERAGE_LINK_BASE = "https://docs.localstack.cloud/references/coverage" - - -def get_coverage_link_for_service(service_name: str, action_name: str) -> str: - from localstack.services.plugins import SERVICE_PLUGINS - - available_services = SERVICE_PLUGINS.list_available() - - if service_name not in available_services: - return ( - f"The API for service '{service_name}' is either not included in your current license plan " - "or has not yet been emulated by LocalStack. " - f"Please refer to {_COVERAGE_LINK_BASE} for more details." - ) - else: - return ( - f"The API action '{action_name}' for service '{service_name}' is either not available in " - "your current license plan or has not yet been emulated by LocalStack. " - f"Please refer to {_COVERAGE_LINK_BASE}/coverage_{service_name} for more information." - ) diff --git a/localstack-core/localstack/utils/crypto.py b/localstack-core/localstack/utils/crypto.py index dc9f50947c905..70de3cec0da2b 100644 --- a/localstack-core/localstack/utils/crypto.py +++ b/localstack-core/localstack/utils/crypto.py @@ -4,7 +4,13 @@ import re import threading +from asn1crypto import algos, cms, core +from asn1crypto import x509 as asn1_x509 from cryptography.hazmat.backends import default_backend +from cryptography.hazmat.primitives import hashes +from cryptography.hazmat.primitives import padding as sym_padding +from cryptography.hazmat.primitives.asymmetric import padding +from cryptography.hazmat.primitives.asymmetric.rsa import RSAPublicKey from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes from .files import TMP_FILES, file_exists_not_empty, load_file, new_tmp_file, save_file @@ -26,6 +32,11 @@ PEM_KEY_START_REGEX = r"-----BEGIN(.*)PRIVATE KEY-----" PEM_KEY_END_REGEX = r"-----END(.*)PRIVATE KEY-----" +OID_AES256_CBC = "2.16.840.1.101.3.4.1.42" +OID_MGF1 = "1.2.840.113549.1.1.8" +OID_RSAES_OAEP = "1.2.840.113549.1.1.7" +OID_SHA256 = "2.16.840.1.101.3.4.2.1" + @synchronized(lock=SSL_CERT_LOCK) def generate_ssl_cert( @@ -183,3 +194,101 @@ def decrypt( decrypted = decryptor.update(encrypted) + decryptor.finalize() decrypted = unpad(decrypted) return decrypted + + +def pkcs7_envelope_encrypt(plaintext: bytes, recipient_pubkey: RSAPublicKey) -> bytes: + """ + Create a PKCS7 wrapper of some plaintext decryptable by recipient_pubkey. Uses RSA-OAEP with SHA-256 + to encrypt the AES-256-CBC content key. Hazmat's PKCS7EnvelopeBuilder doesn't support RSA-OAEP with SHA-256, + so we need to build the pieces manually and then put them together in an envelope with asn1crypto. + """ + + # Encrypt the plaintext with an AES session key, then encrypt the session key to the recipient_pubkey + session_key = os.urandom(32) + iv = os.urandom(16) + encrypted_session_key = recipient_pubkey.encrypt( + session_key, + padding.OAEP( + mgf=padding.MGF1(algorithm=hashes.SHA256()), algorithm=hashes.SHA256(), label=None + ), + ) + cipher = Cipher(algorithms.AES(session_key), modes.CBC(iv), backend=default_backend()) + encryptor = cipher.encryptor() + padder = sym_padding.PKCS7(algorithms.AES.block_size).padder() + padded_plaintext = padder.update(plaintext) + padder.finalize() + encrypted_content = encryptor.update(padded_plaintext) + encryptor.finalize() + + # Now put together the envelope. + # Add the recipient with their copy of the session key + recipient_identifier = cms.RecipientIdentifier( + name="issuer_and_serial_number", + value=cms.IssuerAndSerialNumber( + { + "issuer": asn1_x509.Name.build({"common_name": "recipient"}), + "serial_number": 1, + } + ), + ) + key_enc_algorithm = cms.KeyEncryptionAlgorithm( + { + "algorithm": OID_RSAES_OAEP, + "parameters": algos.RSAESOAEPParams( + { + "hash_algorithm": algos.DigestAlgorithm( + { + "algorithm": OID_SHA256, + } + ), + "mask_gen_algorithm": algos.MaskGenAlgorithm( + { + "algorithm": OID_MGF1, + "parameters": algos.DigestAlgorithm( + { + "algorithm": OID_SHA256, + } + ), + } + ), + } + ), + } + ) + recipient_info = cms.KeyTransRecipientInfo( + { + "version": "v0", + "rid": recipient_identifier, + "key_encryption_algorithm": key_enc_algorithm, + "encrypted_key": encrypted_session_key, + } + ) + + # Add the encrypted content + content_enc_algorithm = cms.EncryptionAlgorithm( + { + "algorithm": OID_AES256_CBC, + "parameters": core.OctetString(iv), + } + ) + encrypted_content_info = cms.EncryptedContentInfo( + { + "content_type": "data", + "content_encryption_algorithm": content_enc_algorithm, + "encrypted_content": encrypted_content, + } + ) + enveloped_data = cms.EnvelopedData( + { + "version": "v0", + "recipient_infos": [recipient_info], + "encrypted_content_info": encrypted_content_info, + } + ) + + # Finally add a wrapper and return its bytes + content_info = cms.ContentInfo( + { + "content_type": "enveloped_data", + "content": enveloped_data, + } + ) + return content_info.dump() diff --git a/localstack-core/localstack/utils/diagnose.py b/localstack-core/localstack/utils/diagnose.py index de4aa912d7916..c3c1bfc837ff4 100644 --- a/localstack-core/localstack/utils/diagnose.py +++ b/localstack-core/localstack/utils/diagnose.py @@ -3,7 +3,6 @@ import inspect import os import socket -from typing import Optional, Union from localstack import config from localstack.constants import DEFAULT_VOLUME_DIR @@ -77,14 +76,14 @@ def get_localstack_config() -> dict: return result -def inspect_main_container() -> Union[str, dict]: +def inspect_main_container() -> str | dict: try: return DOCKER_CLIENT.inspect_container(get_main_container_name()) except Exception as e: return f"inspect failed: {e}" -def get_localstack_version() -> dict[str, Optional[str]]: +def get_localstack_version() -> dict[str, str | None]: return { "build-date": os.environ.get("LOCALSTACK_BUILD_DATE"), "build-git-hash": os.environ.get("LOCALSTACK_BUILD_GIT_HASH"), diff --git a/localstack-core/localstack/utils/docker_utils.py b/localstack-core/localstack/utils/docker_utils.py index a6c8beb3e6772..8d73c2839c031 100644 --- a/localstack-core/localstack/utils/docker_utils.py +++ b/localstack-core/localstack/utils/docker_utils.py @@ -2,7 +2,6 @@ import logging import platform import random -from typing import Optional, Union from localstack import config from localstack.constants import DEFAULT_VOLUME_DIR, DOCKER_IMAGE_NAME @@ -80,7 +79,7 @@ def inspect_current_container_mounts() -> list[VolumeInfo]: @functools.lru_cache -def get_default_volume_dir_mount() -> Optional[VolumeInfo]: +def get_default_volume_dir_mount() -> VolumeInfo | None: """ Returns the volume information of LocalStack's DEFAULT_VOLUME_DIR (/var/lib/localstack), if mounted, else it returns None. If we're not currently in docker a VauleError is raised. in a container, a ValueError is @@ -95,7 +94,7 @@ def get_default_volume_dir_mount() -> Optional[VolumeInfo]: return None -def get_host_path_for_path_in_docker(path): +def get_host_path_for_path_in_docker(path: str) -> str: """ Returns the calculated host location for a given subpath of DEFAULT_VOLUME_DIR inside the localstack container. The path **has** to be a subdirectory of DEFAULT_VOLUME_DIR (the dir itself *will not* work). @@ -133,8 +132,8 @@ def get_host_path_for_path_in_docker(path): def container_ports_can_be_bound( - ports: Union[IntOrPort, list[IntOrPort]], - address: Optional[str] = None, + ports: IntOrPort | list[IntOrPort], + address: str | None = None, ) -> bool: """Determine whether a given list of ports can be bound by Docker containers @@ -142,8 +141,7 @@ def container_ports_can_be_bound( :return: True iff all ports can be bound """ port_mappings = PortMappings(bind_host=address or "") - ports = ensure_list(ports) - for port in ports: + for port in ensure_list(ports): port = Port.wrap(port) port_mappings.add(port.port, port.port, protocol=port.protocol) try: @@ -190,7 +188,7 @@ def is_port_available_for_containers(port: IntOrPort) -> bool: return not is_container_port_reserved(port) and container_ports_can_be_bound(port) -def reserve_container_port(port: IntOrPort, duration: int = None): +def reserve_container_port(port: IntOrPort, duration: int | None = None) -> None: """Reserve the given container port for a short period of time""" reserved_docker_ports.reserve_port(port, duration=duration) @@ -202,10 +200,10 @@ def is_container_port_reserved(port: IntOrPort) -> bool: def reserve_available_container_port( - duration: int = None, - port_start: int = None, - port_end: int = None, - protocol: str = None, + duration: int | None = None, + port_start: int | None = None, + port_end: int | None = None, + protocol: str | None = None, ) -> int: """ Determine a free port within the given port range that can be bound by a Docker container, and reserve @@ -221,7 +219,7 @@ def reserve_available_container_port( protocol = protocol or "tcp" - def _random_port(): + def _random_port() -> Port: port = None while not port or reserved_docker_ports.is_port_reserved(port): port_number = random.randint( @@ -264,7 +262,7 @@ def _get_ports_check_docker_image() -> str: try: # inspect the running container to determine the image container = DOCKER_CLIENT.inspect_container(get_current_container_id()) - return container["Config"]["Image"] + return container["Config"]["Image"] # type: ignore[index] except Exception: # fall back to using the default Docker image return DOCKER_IMAGE_NAME diff --git a/localstack-core/localstack/utils/files.py b/localstack-core/localstack/utils/files.py index 1a75583c46f1c..d510de503886f 100644 --- a/localstack-core/localstack/utils/files.py +++ b/localstack-core/localstack/utils/files.py @@ -1,24 +1,36 @@ import configparser -import inspect import logging import os import shutil import stat import tempfile from pathlib import Path +from typing import Any, AnyStr, Literal, overload LOG = logging.getLogger(__name__) -TMP_FILES = [] +TMP_FILES: list[str] = [] -def parse_config_file(file_or_str: str, single_section: bool = True) -> dict: +@overload +def parse_config_file(file_or_str: str, single_section: Literal[True]) -> dict[str, str]: ... + + +@overload +def parse_config_file( + file_or_str: str, single_section: Literal[False] +) -> dict[str, dict[str, str]]: ... + + +def parse_config_file( + file_or_str: str, single_section: bool = True +) -> dict[str, str] | dict[str, dict[str, str]]: """Parse the given properties config file/string and return a dict of section->key->value. If the config contains a single section, and 'single_section' is True, returns""" config = configparser.RawConfigParser() if os.path.exists(file_or_str): - file_or_str = load_file(file_or_str) + file_or_str = load_file(file_or_str) # type: ignore[assignment] try: config.read_string(file_or_str) @@ -30,7 +42,7 @@ def parse_config_file(file_or_str: str, single_section: bool = True) -> dict: result = {sec: dict(config.items(sec)) for sec in sections} if len(sections) == 1 and single_section: - result = result[sections[0]] + return result[sections[0]] return result @@ -64,13 +76,18 @@ def cache_dir() -> Path: return get_user_cache_dir() / "localstack" -def save_file(file, content, append=False, permissions=None): +def save_file( + file: str | os.PathLike[AnyStr], + content: str | bytes, + append: bool = False, + permissions: int | None = None, +) -> None: mode = "a" if append else "w+" if not isinstance(content, str): mode = mode + "b" - def _opener(path, flags): - return os.open(path, flags, permissions) + def _opener(path: str, flags: int) -> int: + return os.open(path, flags, permissions) # type: ignore[arg-type] # make sure that the parent dir exists mkdir(os.path.dirname(file)) @@ -80,9 +97,53 @@ def _opener(path, flags): f.flush() -def load_file(file_path: str, default=None, mode=None): +@overload +def load_file( + file_path: str | os.PathLike[AnyStr], + default: None = None, + mode: None = None, + strict: bool = False, +) -> str | None: ... + + +@overload +def load_file( + file_path: str | os.PathLike[AnyStr], + default: str, + mode: None = None, + strict: bool = False, +) -> str | None: ... + + +@overload +def load_file( + file_path: str | os.PathLike[AnyStr], + default: bytes, + mode: Literal["rb"], + strict: bool = False, +) -> bytes | None: ... + + +def load_file( + file_path: str | os.PathLike[AnyStr], + default: str | bytes | None = None, + mode: str | None = None, + strict: bool = False, +) -> str | bytes | None: + """ + Return file contents + + :param file_path: path of the file + :param default: if strict=False then return this value if the file does not exist + :param mode: mode to open the file with (e.g. `r`, `rw`) + :param strict: raise an error if the file path is not a file + :return: the file contents + """ if not os.path.isfile(file_path): - return default + if strict: + raise FileNotFoundError(file_path) + else: + return default if not mode: mode = "r" with open(file_path, mode) as f: @@ -90,7 +151,11 @@ def load_file(file_path: str, default=None, mode=None): return result -def get_or_create_file(file_path, content=None, permissions=None): +def get_or_create_file( + file_path: os.PathLike[AnyStr], + content: str | bytes | None = None, + permissions: int | None = None, +) -> str | bytes | None: if os.path.exists(file_path): return load_file(file_path) content = "{}" if content is None else content @@ -99,9 +164,10 @@ def get_or_create_file(file_path, content=None, permissions=None): return content except Exception: pass + return None -def replace_in_file(search, replace, file_path): +def replace_in_file(search: str, replace: str, file_path: os.PathLike[AnyStr]) -> None: """Replace all occurrences of `search` with `replace` in the given file (overwrites in place!)""" content = load_file(file_path) or "" content_new = content.replace(search, replace) @@ -109,7 +175,7 @@ def replace_in_file(search, replace, file_path): save_file(file_path, content_new) -def mkdir(folder: str): +def mkdir(folder: str | bytes | os.PathLike[AnyStr]) -> None: if not os.path.exists(folder): os.makedirs(folder, exist_ok=True) @@ -125,7 +191,7 @@ def is_empty_dir(directory: str, ignore_hidden: bool = False) -> bool: return not bool(entries) -def ensure_readable(file_path: str, default_perms: int = None): +def ensure_readable(file_path: str, default_perms: int | None = None) -> None: if default_perms is None: default_perms = 0o644 try: @@ -136,7 +202,7 @@ def ensure_readable(file_path: str, default_perms: int = None): os.chmod(file_path, default_perms) -def chown_r(path: str, user: str): +def chown_r(path: str, user: str) -> None: """Recursive chown on the given file/directory path.""" # keep these imports here for Windows compatibility import grp @@ -152,7 +218,7 @@ def chown_r(path: str, user: str): os.chown(os.path.join(root, filename), uid, gid) -def chmod_r(path: str, mode: int): +def chmod_r(path: str, mode: int) -> None: """ Recursive chmod :param path: path to file or directory @@ -168,7 +234,7 @@ def chmod_r(path: str, mode: int): idempotent_chmod(os.path.join(root, filename), mode) -def idempotent_chmod(path: str, mode: int): +def idempotent_chmod(path: str, mode: int) -> None: """ Perform idempotent chmod on the given file path (non-recursively). The function attempts to call `os.chmod`, and will catch and only re-raise exceptions (e.g., PermissionError) if the file does not have the given mode already. @@ -189,7 +255,7 @@ def idempotent_chmod(path: str, mode: int): raise -def rm_rf(path: str): +def rm_rf(path: str) -> None: """ Recursively removes a file or directory """ @@ -201,7 +267,7 @@ def rm_rf(path: str): # Running the native command can be an order of magnitude faster in Alpine on Travis-CI if is_debian(): try: - return run(f'rm -rf "{path}"') + return run(f'rm -rf "{path}"') # type: ignore[return-value] except Exception: pass # Make sure all files are writeable and dirs executable to remove @@ -217,13 +283,15 @@ def rm_rf(path: str): shutil.rmtree(path) -def cp_r(src: str, dst: str, rm_dest_on_conflict=False, ignore_copystat_errors=False, **kwargs): +def cp_r( + src: str, dst: str, rm_dest_on_conflict: bool = False, ignore_copystat_errors: bool = False +) -> None | str: """Recursively copies file/directory""" # attention: this patch is not threadsafe copystat_orig = shutil.copystat if ignore_copystat_errors: - def _copystat(*args, **kwargs): + def _copystat(*args: Any, **kwargs: Any) -> None: try: return copystat_orig(*args, **kwargs) except Exception: @@ -235,21 +303,19 @@ def _copystat(*args, **kwargs): if os.path.isdir(dst): dst = os.path.join(dst, os.path.basename(src)) return shutil.copyfile(src, dst) - if "dirs_exist_ok" in inspect.getfullargspec(shutil.copytree).args: - kwargs["dirs_exist_ok"] = True try: - return shutil.copytree(src, dst, **kwargs) + return shutil.copytree(src, dst, dirs_exist_ok=True) except FileExistsError: if rm_dest_on_conflict: rm_rf(dst) - return shutil.copytree(src, dst, **kwargs) + return shutil.copytree(src, dst, dirs_exist_ok=True) raise except Exception as e: - def _info(_path): + def _info(_path: str) -> str: return f"{_path} (file={os.path.isfile(_path)}, symlink={os.path.islink(_path)})" - LOG.debug("Error copying files from %s to %s: %s", _info(src), _info(dst), e) + LOG.debug("Error copying files from %s to %s", _info(src), _info(dst), e) raise finally: shutil.copystat = copystat_orig @@ -276,10 +342,10 @@ def disk_usage(path: str) -> int: def file_exists_not_empty(path: str) -> bool: """Return whether the given file or directory exists and is non-empty (i.e., >0 bytes content)""" - return path and disk_usage(path) > 0 + return bool(path) and disk_usage(path) > 0 -def cleanup_tmp_files(): +def cleanup_tmp_files() -> None: for tmp in TMP_FILES: try: rm_rf(tmp) @@ -288,7 +354,7 @@ def cleanup_tmp_files(): del TMP_FILES[:] -def new_tmp_file(suffix: str = None, dir: str = None) -> str: +def new_tmp_file(suffix: str | None = None, dir: str | None = None) -> str: """Return a path to a new temporary file.""" tmp_file, tmp_path = tempfile.mkstemp(suffix=suffix, dir=dir) os.close(tmp_file) @@ -296,8 +362,15 @@ def new_tmp_file(suffix: str = None, dir: str = None) -> str: return tmp_path -def new_tmp_dir(dir: str = None): - folder = new_tmp_file(dir=dir) - rm_rf(folder) - mkdir(folder) +def new_tmp_dir(dir: str | None = None, mode: int = 0o777) -> str: + """ + Create a new temporary directory with the specified permissions. The directory is added to the tracked temporary + files. + :param dir: parent directory for the temporary directory to be created. Systems's default otherwise. + :param mode: file permission for the directory (default: 0o777) + :return: the absolute path of the created directory + """ + folder = tempfile.mkdtemp(dir=dir) + TMP_FILES.append(folder) + idempotent_chmod(folder, mode=mode) return folder diff --git a/localstack-core/localstack/utils/functions.py b/localstack-core/localstack/utils/functions.py index ffdc1aec99d40..b3829306c1521 100644 --- a/localstack-core/localstack/utils/functions.py +++ b/localstack-core/localstack/utils/functions.py @@ -3,7 +3,8 @@ import functools import inspect import logging -from typing import Any, Callable, Optional +from collections.abc import Callable +from typing import Any LOG = logging.getLogger(__name__) @@ -20,7 +21,7 @@ def run_safe(_python_lambda, *args, _default=None, **kwargs): def call_safe( func: Callable, args: tuple = None, kwargs: dict = None, exception_message: str = None -) -> Optional[Any]: +) -> Any | None: """ Call the given function with the given arguments, and if it fails, log the given exception_message. If logging.DEBUG is set for the logger, then we also log the traceback. diff --git a/localstack-core/localstack/utils/http.py b/localstack-core/localstack/utils/http.py index 330a559194d47..d52d2b53e2762 100644 --- a/localstack-core/localstack/utils/http.py +++ b/localstack-core/localstack/utils/http.py @@ -2,7 +2,6 @@ import math import os import re -from typing import Optional, Union from urllib.parse import parse_qs, parse_qsl, urlencode, urlparse, urlunparse import requests @@ -54,7 +53,7 @@ def create_chunked_data(data, chunk_size: int = 80): return ret -def canonicalize_headers(headers: Union[dict, CaseInsensitiveDict]) -> dict: +def canonicalize_headers(headers: dict | CaseInsensitiveDict) -> dict: if not headers: return headers @@ -103,7 +102,7 @@ def add_query_params_to_url(uri: str, query_params: dict) -> str: def make_http_request( - url: str, data: Union[bytes, str] = None, headers: dict[str, str] = None, method: str = "GET" + url: str, data: bytes | str = None, headers: dict[str, str] = None, method: str = "GET" ) -> Response: return requests.request( url=url, method=method, headers=headers, data=data, auth=NetrcBypassAuth(), verify=False @@ -179,7 +178,7 @@ def download( path: str, verify_ssl: bool = True, timeout: float = None, - request_headers: Optional[dict] = None, + request_headers: dict | None = None, quiet: bool = False, ) -> None: """Downloads file at url to the given path. Raises TimeoutError if the optional timeout (in secs) is reached. @@ -291,7 +290,7 @@ def download_github_artifact(url: str, target_file: str, timeout: int = None): Optionally allows to define a timeout in seconds.""" def do_download( - download_url: str, request_headers: Optional[dict] = None, print_error: bool = False + download_url: str, request_headers: dict | None = None, print_error: bool = False ): try: download(download_url, target_file, timeout=timeout, request_headers=request_headers) diff --git a/localstack-core/localstack/utils/json.py b/localstack-core/localstack/utils/json.py index ab0bcab6364d9..53db4577d2519 100644 --- a/localstack-core/localstack/utils/json.py +++ b/localstack-core/localstack/utils/json.py @@ -5,7 +5,7 @@ import os from datetime import date, datetime from json import JSONDecodeError -from typing import Any, Union +from typing import Any from localstack.config import HostAndPort @@ -63,9 +63,9 @@ class FileMappedDocument(dict): concurrent writes, run load(). To save and overwrite the current document on disk, run save(). """ - path: Union[str, os.PathLike] + path: str | os.PathLike - def __init__(self, path: Union[str, os.PathLike], mode=0o664): + def __init__(self, path: str | os.PathLike, mode=0o664): super().__init__() self.path = path self.mode = mode @@ -169,10 +169,24 @@ def extract_jsonpath(value, path): return result -def assign_to_path(target, path: str, value, delimiter: str = "."): +def assign_to_path(target: dict, path: str, value: any, delimiter: str = ".") -> dict: + """Assign the given value to a dict. If the path doesn't exist in the target dict, it will be created. + The delimiter can be used to provide a path with a different delimiter. + + Examples: + - assign_to_path({}, "a", "b") => {"a": "b"} + - assign_to_path({}, "a.b.c", "d") => {"a": {"b": {"c": "d"}}} + - assign_to_path({}, "a.b/c", "d", delimiter="/") => {"a.b": {"c": "d"}} + + """ parts = path.strip(delimiter).split(delimiter) + + if len(parts) == 1: + target[parts[0]] = value + return target + path_to_parent = delimiter.join(parts[:-1]) - parent = extract_from_jsonpointer_path(target, path_to_parent, auto_create=True) + parent = extract_from_jsonpointer_path(target, path_to_parent, delimiter, auto_create=True) if not isinstance(parent, dict): LOG.debug( 'Unable to find parent (type %s) for path "%s" in object: %s', diff --git a/localstack-core/localstack/utils/kinesis/kinesis_connector.py b/localstack-core/localstack/utils/kinesis/kinesis_connector.py index f68e79a379638..cc12bf75e1716 100644 --- a/localstack-core/localstack/utils/kinesis/kinesis_connector.py +++ b/localstack-core/localstack/utils/kinesis/kinesis_connector.py @@ -6,7 +6,8 @@ import socket import tempfile import threading -from typing import Any, Callable +from collections.abc import Callable +from typing import Any from amazon_kclpy import kcl from amazon_kclpy.v2 import processor diff --git a/localstack-core/localstack/utils/net.py b/localstack-core/localstack/utils/net.py index fd55d9d5ec9c0..255b01c8b22bf 100644 --- a/localstack-core/localstack/utils/net.py +++ b/localstack-core/localstack/utils/net.py @@ -5,7 +5,7 @@ import threading from collections.abc import MutableMapping from contextlib import closing -from typing import Any, NamedTuple, Optional, Union +from typing import Any, NamedTuple from urllib.parse import urlparse import dns.resolver @@ -50,14 +50,14 @@ def wrap(cls, port: "IntOrPort") -> "Port": # simple helper type to encapsulate int/Port argument types -IntOrPort = Union[int, Port] +IntOrPort = int | Port def is_port_open( - port_or_url: Union[int, str], + port_or_url: int | str, http_path: str = None, expect_success: bool = True, - protocols: Optional[Union[str, list[str]]] = None, + protocols: str | list[str] | None = None, quiet: bool = True, ): from localstack.utils.http import safe_requests @@ -275,7 +275,7 @@ def _is_port_range_free(_range: PortRange): raise PortNotAvailableException("reached max_attempts when trying to find port range") -def resolve_hostname(hostname: str) -> Optional[str]: +def resolve_hostname(hostname: str) -> str | None: """Resolve the given hostname and return its IP address, or None if it cannot be resolved.""" try: return socket.gethostbyname(hostname) @@ -362,7 +362,7 @@ def as_range(self) -> range: """ return range(self.start, self.end + 1) - def reserve_port(self, port: Optional[IntOrPort] = None, duration: Optional[int] = None) -> int: + def reserve_port(self, port: IntOrPort | None = None, duration: int | None = None) -> int: """ Reserves the given port (if it is still free). If the given port is None, it reserves a free port from the configured port range for external services. If a port is given, it has to be within the configured diff --git a/localstack-core/localstack/utils/no_exit_argument_parser.py b/localstack-core/localstack/utils/no_exit_argument_parser.py index 6455a59b12800..0b71c1185e037 100644 --- a/localstack-core/localstack/utils/no_exit_argument_parser.py +++ b/localstack-core/localstack/utils/no_exit_argument_parser.py @@ -1,6 +1,6 @@ import argparse import logging -from typing import NoReturn, Optional +from typing import NoReturn LOG = logging.getLogger(__name__) @@ -12,7 +12,7 @@ class NoExitArgumentParser(argparse.ArgumentParser): * ArgumentParser subclassing example: https://stackoverflow.com/a/59072378/6875981 """ - def exit(self, status: int = ..., message: Optional[str] = ...) -> NoReturn: + def exit(self, status: int = ..., message: str | None = ...) -> NoReturn: LOG.warning("Error in argument parser but preventing exit: %s", message) def error(self, message: str) -> NoReturn: diff --git a/localstack-core/localstack/utils/numbers.py b/localstack-core/localstack/utils/numbers.py index 19f5dbab42014..d5a9f0f6fe5d7 100644 --- a/localstack-core/localstack/utils/numbers.py +++ b/localstack-core/localstack/utils/numbers.py @@ -1,4 +1,4 @@ -from typing import Any, Union +from typing import Any def format_number(number: float, decimals: int = 2): @@ -11,6 +11,13 @@ def format_number(number: float, decimals: int = 2): def is_number(s: Any) -> bool: + # booleans inherit from int + # + # >>> a.__class__.__mro__ + # (, , ) + if s is False or s is True: + return False + try: float(s) # for int, long and float return True @@ -18,7 +25,7 @@ def is_number(s: Any) -> bool: return False -def to_number(s: Any) -> Union[int, float]: +def to_number(s: Any) -> int | float: """Cast the string representation of the given object to a number (int or float), or raise ValueError.""" try: return int(str(s)) diff --git a/localstack-core/localstack/utils/objects.py b/localstack-core/localstack/utils/objects.py index 14e747fee72e0..98d307139c082 100644 --- a/localstack-core/localstack/utils/objects.py +++ b/localstack-core/localstack/utils/objects.py @@ -1,12 +1,13 @@ import functools import re import threading -from typing import Any, Callable, Generic, Optional, TypeVar, Union +from collections.abc import Callable +from typing import Any, Generic, TypeVar from .collections import ensure_list from .strings import first_char_to_lower, first_char_to_upper -ComplexType = Union[list, dict, object] +ComplexType = list | dict | object _T = TypeVar("_T") @@ -16,7 +17,7 @@ class Value(Generic[_T]): Simple value container. """ - value: Optional[_T] + value: _T | None def __init__(self, value: _T = None) -> None: self.value = value @@ -30,7 +31,7 @@ def set(self, value: _T): def is_set(self) -> bool: return self.value is not None - def get(self) -> Optional[_T]: + def get(self) -> _T | None: return self.value def __bool__(self): @@ -136,7 +137,7 @@ def fully_qualified_class_name(klass: type) -> str: return f"{klass.__module__}.{klass.__name__}" -def not_none_or(value: Optional[Any], alternative: Any) -> Any: +def not_none_or(value: Any | None, alternative: Any) -> Any: """Return 'value' if it is not None, or 'alternative' otherwise.""" return value if value is not None else alternative diff --git a/localstack-core/localstack/utils/patch.py b/localstack-core/localstack/utils/patch.py index d137b4ac81e2b..c250860cfef9e 100644 --- a/localstack-core/localstack/utils/patch.py +++ b/localstack-core/localstack/utils/patch.py @@ -1,7 +1,8 @@ import functools import inspect import types -from typing import Any, Callable +from collections.abc import Callable +from typing import Any def get_defining_object(method): diff --git a/localstack-core/localstack/utils/run.py b/localstack-core/localstack/utils/run.py index 1d220696020f4..60dafef182df7 100644 --- a/localstack-core/localstack/utils/run.py +++ b/localstack-core/localstack/utils/run.py @@ -7,9 +7,10 @@ import sys import threading import time +from collections.abc import Callable from functools import lru_cache from queue import Queue -from typing import Any, AnyStr, Callable, Optional, Union +from typing import Any, AnyStr from localstack import config @@ -23,19 +24,19 @@ def run( - cmd: Union[str, list[str]], + cmd: str | list[str], print_error=True, asynchronous=False, stdin=False, stderr=subprocess.STDOUT, outfile=None, - env_vars: Optional[dict[AnyStr, AnyStr]] = None, + env_vars: dict[AnyStr, AnyStr] | None = None, inherit_cwd=False, inherit_env=True, tty=False, shell=True, cwd: str = None, -) -> Union[str, subprocess.Popen]: +) -> str | subprocess.Popen: LOG.debug("Executing command: %s", cmd) env_dict = os.environ.copy() if inherit_env else {} if env_vars: @@ -169,7 +170,7 @@ def is_command_available(cmd: str) -> bool: return False -def kill_process_tree(parent_pid): +def kill_process_tree(parent_pid: int) -> None: # Note: Do NOT import "psutil" at the root scope import psutil @@ -202,7 +203,7 @@ def get_os_user() -> str: return run("whoami").strip() -def to_str(obj: Union[str, bytes], errors="strict"): +def to_str(obj: str | bytes, errors="strict"): return obj.decode(config.DEFAULT_ENCODING, errors) if isinstance(obj, bytes) else obj @@ -211,9 +212,9 @@ class ShellCommandThread(FuncThread): def __init__( self, - cmd: Union[str, list[str]], + cmd: str | list[str], params: Any = None, - outfile: Union[str, int] = None, + outfile: str | int = None, env_vars: dict[str, str] = None, stdin: bool = False, auto_restart: bool = False, @@ -223,8 +224,8 @@ def __init__( log_listener: Callable = None, stop_listener: Callable = None, strip_color: bool = False, - name: Optional[str] = None, - cwd: Optional[str] = None, + name: str | None = None, + cwd: str | None = None, ): params = params if params is not None else {} env_vars = env_vars if env_vars is not None else {} diff --git a/localstack-core/localstack/utils/scheduler.py b/localstack-core/localstack/utils/scheduler.py index b23f42d8f93c6..640a834a332fa 100644 --- a/localstack-core/localstack/utils/scheduler.py +++ b/localstack-core/localstack/utils/scheduler.py @@ -1,9 +1,9 @@ import queue import threading import time -from collections.abc import Mapping +from collections.abc import Callable, Mapping from concurrent.futures import Executor -from typing import Any, Callable, Optional, Union +from typing import Any class ScheduledTask: @@ -14,12 +14,12 @@ class ScheduledTask: def __init__( self, task: Callable, - period: Optional[float] = None, + period: float | None = None, fixed_rate: bool = True, - start: Optional[float] = None, + start: float | None = None, on_error: Callable[[Exception], None] = None, - args: Optional[Union[tuple, list]] = None, - kwargs: Optional[Mapping[str, Any]] = None, + args: tuple | list | None = None, + kwargs: Mapping[str, Any] | None = None, ) -> None: super().__init__() self.task = task @@ -76,7 +76,7 @@ class Scheduler: POISON = (-1, "__POISON__") - def __init__(self, executor: Optional[Executor] = None) -> None: + def __init__(self, executor: Executor | None = None) -> None: """ Creates a new Scheduler. If an executor is passed, then that executor will be used to run the scheduled tasks asynchronously, otherwise they will be executed synchronously inside the event loop. Running tasks @@ -94,12 +94,12 @@ def __init__(self, executor: Optional[Executor] = None) -> None: def schedule( self, func: Callable, - period: Optional[float] = None, + period: float | None = None, fixed_rate: bool = True, - start: Optional[float] = None, + start: float | None = None, on_error: Callable[[Exception], None] = None, - args: Optional[Union[tuple, list[Any]]] = None, - kwargs: Optional[Mapping[str, Any]] = None, + args: tuple | list[Any] | None = None, + kwargs: Mapping[str, Any] | None = None, ) -> ScheduledTask: """ Schedules a given task (function call). diff --git a/localstack-core/localstack/utils/server/tcp_proxy.py b/localstack-core/localstack/utils/server/tcp_proxy.py index 943120307a056..0327db2856d6e 100644 --- a/localstack-core/localstack/utils/server/tcp_proxy.py +++ b/localstack-core/localstack/utils/server/tcp_proxy.py @@ -1,8 +1,8 @@ import logging import select import socket +from collections.abc import Callable from concurrent.futures import ThreadPoolExecutor -from typing import Callable from localstack.utils.serving import Server @@ -93,7 +93,7 @@ def do_run(self): try: src_socket, _ = self._server_socket.accept() self._thread_pool.submit(self._handle_request, src_socket) - except socket.timeout: + except TimeoutError: pass except OSError as e: # avoid creating an error message if OSError is thrown due to socket closing diff --git a/localstack-core/localstack/utils/serving.py b/localstack-core/localstack/utils/serving.py index e85498cc12021..81848ab2512a2 100644 --- a/localstack-core/localstack/utils/serving.py +++ b/localstack-core/localstack/utils/serving.py @@ -1,7 +1,6 @@ import abc import logging import threading -from typing import Optional from localstack.utils.net import is_port_open from localstack.utils.sync import poll_condition @@ -21,7 +20,7 @@ class Server(abc.ABC): def __init__(self, port: int, host: str = "localhost") -> None: super().__init__() - self._thread: Optional[FuncThread] = None + self._thread: FuncThread | None = None self._lifecycle_lock = threading.RLock() self._stopped = threading.Event() @@ -46,7 +45,7 @@ def protocol(self): def url(self): return f"{self.protocol}://{self.host}:{self.port}" - def get_error(self) -> Optional[Exception]: + def get_error(self) -> Exception | None: """ If the thread running the server returned with an Exception, then this function will return that exception. """ diff --git a/localstack-core/localstack/utils/strings.py b/localstack-core/localstack/utils/strings.py index bd63f593fc43a..f3385cb08debd 100644 --- a/localstack-core/localstack/utils/strings.py +++ b/localstack-core/localstack/utils/strings.py @@ -7,10 +7,13 @@ import string import uuid import zlib -from typing import Union +from typing import TYPE_CHECKING, Any from localstack.config import DEFAULT_ENCODING +if TYPE_CHECKING: + from localstack.utils.objects import ComplexType + _unprintables = ( range(0x00, 0x09), range(0x0A, 0x0A), @@ -28,13 +31,13 @@ ) -def to_str(obj: Union[str, bytes], encoding: str = DEFAULT_ENCODING, errors="strict") -> str: +def to_str(obj: str | bytes, encoding: str = DEFAULT_ENCODING, errors: str = "strict") -> str: """If ``obj`` is an instance of ``binary_type``, return ``obj.decode(encoding, errors)``, otherwise return ``obj``""" return obj.decode(encoding, errors) if isinstance(obj, bytes) else obj -def to_bytes(obj: Union[str, bytes], encoding: str = DEFAULT_ENCODING, errors="strict") -> bytes: +def to_bytes(obj: str | bytes, encoding: str = DEFAULT_ENCODING, errors: str = "strict") -> bytes: """If ``obj`` is an instance of ``text_type``, return ``obj.encode(encoding, errors)``, otherwise return ``obj``""" return obj.encode(encoding, errors) if isinstance(obj, str) else obj @@ -45,7 +48,7 @@ def truncate(data: str, max_length: int = 100) -> str: return (f"{data[:max_length]}...") if len(data) > max_length else data -def is_string(s, include_unicode=True, exclude_binary=False): +def is_string(s: Any, include_unicode: bool = True, exclude_binary: bool = False) -> bool: if isinstance(s, bytes) and exclude_binary: return False if isinstance(s, str): @@ -55,13 +58,13 @@ def is_string(s, include_unicode=True, exclude_binary=False): return False -def is_string_or_bytes(s): +def is_string_or_bytes(s: Any) -> bool: return is_string(s) or isinstance(s, str) or isinstance(s, bytes) -def is_base64(s): +def is_base64(s: Any) -> bool: regex = r"^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$" - return is_string(s) and re.match(regex, s) + return is_string(s) and re.match(regex, s) is not None _re_camel_to_snake_case = re.compile("((?<=[a-z0-9])[A-Z]|(?!^)[A-Z](?=[a-z]))") @@ -86,22 +89,21 @@ def canonicalize_bool_to_str(val: bool) -> str: return "true" if str(val).lower() == "true" else "false" -def convert_to_printable_chars(value: Union[list, dict, str]) -> str: +def convert_to_printable_chars(value: "str | ComplexType") -> "ComplexType": """Removes all unprintable characters from the given string.""" from localstack.utils.objects import recurse_object - if isinstance(value, (dict, list)): + if isinstance(value, str): + return REGEX_UNPRINTABLE_CHARS.sub("", value) + else: - def _convert(obj, **kwargs): + def _convert(obj: Any, **kwargs: Any) -> "ComplexType": if isinstance(obj, str): return convert_to_printable_chars(obj) return obj return recurse_object(value, _convert) - result = REGEX_UNPRINTABLE_CHARS.sub("", value) - return result - def first_char_to_lower(s: str) -> str: return s and f"{s[0].lower()}{s[1:]}" @@ -111,7 +113,7 @@ def first_char_to_upper(s: str) -> str: return s and f"{s[0].upper()}{s[1:]}" -def str_to_bool(value): +def str_to_bool(value: Any) -> Any: """Return the boolean value of the given string, or the verbatim value if it is not a string""" if isinstance(value, str): true_strings = ["true", "True"] @@ -119,12 +121,12 @@ def str_to_bool(value): return value -def str_insert(string, index, content): +def str_insert(string: str, index: int, content: str) -> str: """Insert a substring into an existing string at a certain index.""" return f"{string[:index]}{content}{string[index:]}" -def str_remove(string, index, end_index=None): +def str_remove(string: str, index: int, end_index: int | None = None) -> str: """Remove a substring from an existing string at a certain from-to index range.""" end_index = end_index or (index + 1) return f"{string[:index]}{string[end_index:]}" @@ -148,19 +150,19 @@ def long_uid() -> str: return str(uuid.uuid4()) -def md5(string: Union[str, bytes]) -> str: +def md5(string: str | bytes) -> str: m = hashlib.md5() m.update(to_bytes(string)) return m.hexdigest() -def checksum_crc32(string: Union[str, bytes]) -> str: +def checksum_crc32(string: str | bytes) -> str: bytes = to_bytes(string) checksum = zlib.crc32(bytes) return base64.b64encode(checksum.to_bytes(4, "big")).decode() -def checksum_crc32c(string: Union[str, bytes]): +def checksum_crc32c(string: str | bytes) -> str: # import botocore locally here to avoid a dependency of the CLI to botocore from botocore.httpchecksum import CrtCrc32cChecksum @@ -169,7 +171,7 @@ def checksum_crc32c(string: Union[str, bytes]): return base64.b64encode(checksum.digest()).decode() -def checksum_crc64nvme(string: Union[str, bytes]): +def checksum_crc64nvme(string: str | bytes) -> str: # import botocore locally here to avoid a dependency of the CLI to botocore from botocore.httpchecksum import CrtCrc64NvmeChecksum @@ -178,12 +180,12 @@ def checksum_crc64nvme(string: Union[str, bytes]): return base64.b64encode(checksum.digest()).decode() -def hash_sha1(string: Union[str, bytes]) -> str: +def hash_sha1(string: str | bytes) -> str: digest = hashlib.sha1(to_bytes(string)).digest() return base64.b64encode(digest).decode() -def hash_sha256(string: Union[str, bytes]) -> str: +def hash_sha256(string: str | bytes) -> str: digest = hashlib.sha256(to_bytes(string)).digest() return base64.b64encode(digest).decode() @@ -192,7 +194,7 @@ def base64_to_hex(b64_string: str) -> bytes: return binascii.hexlify(base64.b64decode(b64_string)) -def base64_decode(data: Union[str, bytes]) -> bytes: +def base64_decode(data: str | bytes) -> bytes: """Decode base64 data - with optional padding, and able to handle urlsafe encoding (containing -/_).""" data = to_str(data) missing_padding = len(data) % 4 @@ -224,7 +226,9 @@ def prepend_with_slash(input: str) -> str: return input -def key_value_pairs_to_dict(pairs: str, delimiter: str = ",", separator: str = "=") -> dict: +def key_value_pairs_to_dict( + pairs: str, delimiter: str = ",", separator: str = "=" +) -> dict[str, str]: """ Converts a string of key-value pairs to a dictionary. diff --git a/localstack-core/localstack/utils/sync.py b/localstack-core/localstack/utils/sync.py index e5beea032d150..de025f7a07aaf 100644 --- a/localstack-core/localstack/utils/sync.py +++ b/localstack-core/localstack/utils/sync.py @@ -4,7 +4,8 @@ import threading import time from collections import defaultdict -from typing import Callable, Literal, TypeVar +from collections.abc import Callable +from typing import Literal, TypeVar class ShortCircuitWaitException(Exception): @@ -140,3 +141,127 @@ def __len__(self): def __str__(self): with self._lock: return super().__str__() + + +class Once: + """ + An object that will perform an action exactly once. + Inspired by Golang's [sync.Once](https://pkg.go.dev/sync#Once) operation. + + + ### Example 1 + + Multiple threads using `Once::do` to ensure only 1 line is printed. + + ```python + import threading + import time + import random + + greet_once = Once() + def greet(): + print("This should happen only once.") + + greet_threads = [] + for _ in range(10): + t = threading.Thread(target=lambda: greet_once.do(greet)) + greet_threads.append(t) + t.start() + + for t in greet_threads: + t.join() + ``` + + + ### Example 2 + + Ensuring idemponent calling to prevent exceptions on multiple calls. + + ```python + import os + + class Service: + close_once: sync.Once + + def start(self): + with open("my-service.txt) as f: + myfile.write("Started service") + + def close(self): + # Ensure we only ever delete the file once on close + self.close_once.do(lambda: os.remove("my-service.txt")) + + ``` + + + """ + + _is_done: bool = False + _mu: threading.Lock = threading.Lock() + + def do(self, fn: Callable[[], None]): + """ + `do` calls the function `fn()` if-and-only-if `do` has never been called before. + + This ensures idempotent and thread-safe execution. + + If the function raises an exception, `do` considers `fn` as done, where subsequent calls are still no-ops. + """ + if self._is_done: + return + + with self._mu: + if not self._is_done: + try: + fn() + finally: + self._is_done = True + + +def once_func(fn: Callable[..., T]) -> Callable[..., T | None]: + """ + Wraps and returns a function that can only ever execute once. + + The first call to the returned function will permanently set the result. + If the wrapped function raises an exception, this will be re-raised on each subsequent call. + + This function can be used either as a decorator or called directly. + + Direct usage: + ```python + delete_file = once_func(os.remove) + + delete_file("myfile.txt") # deletes the file + delete_file("myfile.txt") # does nothing + ``` + + As a decorator: + ```python + @once_func + def delete_file(): + os.remove("myfile.txt") + + delete_file() # deletes the file + delete_file() # does nothing + ``` + """ + once = Once() + + result, exception = None, None + + def _do(*args, **kwargs): + nonlocal result, exception + try: + result = fn(*args, **kwargs) + except Exception as e: + exception = e + raise + + @functools.wraps(fn) + def wrapper(*args, **kwargs): + once.do(lambda: _do(*args, **kwargs)) + if exception is not None: + raise exception + return result + + return wrapper diff --git a/localstack-core/localstack/utils/tagging.py b/localstack-core/localstack/utils/tagging.py index 6e42c96346c47..2a7e9fd499b87 100644 --- a/localstack-core/localstack/utils/tagging.py +++ b/localstack-core/localstack/utils/tagging.py @@ -1,6 +1,8 @@ -from typing import Optional +from dataclasses import dataclass, field +from warnings import deprecated +@deprecated("`TaggingService` is deprecated. Please use the `RGTAPlugin`/`Tags` system.") class TaggingService: key_field: str value_field: str @@ -17,7 +19,7 @@ def __init__(self, key_field: str = "Key", value_field: str = "Value"): self.tags = {} - def list_tags_for_resource(self, arn: str, root_name: Optional[str] = None): + def list_tags_for_resource(self, arn: str, root_name: str | None = None): root_name = root_name or "Tags" result = [] @@ -45,3 +47,150 @@ def del_resource(self, arn: str): def __delitem__(self, arn: str): self.del_resource(arn) + + +ResourceARN = str +TagKey = str +TagValue = str +TagMap = dict[TagKey, TagValue] + + +@dataclass +class Tags: + """ + This dataclass provides utilities for performing resource tagging. Tags for resources are stored on + the service provider's store within this `Tags` dataclass with ResourceARN mapped against a dictionary + containing tags in the form TagKey:TagValue to remain agnostic to the service's tag format. + + The `Tags` dataclass supports updating / creating tags, deleting tags, and removing the + resource from the tag dictionary (_tags). It's important that when a resource is deleted to remove this + resource ARN from the store using the `delete_all_tags` method:: + + store = get_store(account_id, region) + store.TAGS.delete_all_tags(my_resource_arn) + + Do not use the `Tags` dataclass to determine the existence of a resource. For this, use ``connect_to`` or + direct Moto Backend introspection. It's important that resources do not exist within _tags unless they + currently have tags or have had tags in the past and the resource exists. The resource ARN should not exist within + _tags if the resource has been deleted. + + This distinction is important to maintain parity with the Resource Groups Tagging API (RGTA) which will tap into + supported service's `Tags` dataclass within its store. + """ + + _tags: dict[ResourceARN, TagMap] = field(default_factory=dict) + + def update_tags(self, arn: ResourceARN, tags: TagMap) -> None: + """ + Updates the tags of the specified resource. + + :param arn: The ARN of the resource to tag. + :param tags: A mapping of tag keys to tag values or an array of tag objects. + :return: None + """ + stored_tags = self._tags.setdefault(arn, {}) + + for k, v in tags.items(): + stored_tags[k] = v + + def get_tags(self, arn: ResourceARN) -> TagMap: + """ + Retrieves the tags for a specified resource. + + The tags are returned as a flat map of tag key/value pairs, e.g.:: + { + "Environment": "Production", + "Owner": "LocalStack", + } + + :param arn: The ARN of the resource you want to retrieve tags for. + :return: A dictionary copy of tag keys to tag values for the resource. + """ + if arn not in self._tags: + return {} + return self._tags[arn].copy() + + def delete_tags(self, arn: ResourceARN, keys: list[TagKey]) -> None: + """ + Deletes the tag on the resource specified by the provided tag keys. + + :param arn: The ARN of the resource to remove tags for. + :param keys: An array of tag keys to remove from the resource. + :return: None + """ + if tags := self._tags.get(arn): + for key in keys: + tags.pop(key, None) + + def delete_all_tags(self, arn: ResourceARN) -> None: + """ + Removes all the tags for a resource and removes it from the internal tagging store. + To be used once a resource is deleted or when you wish to remove all a resources tags. + + :param arn: The ARN of the resource to remove from the store. + :return: None + """ + self._tags.pop(arn, None) + + def get_resource_tag_map(self) -> dict[ResourceARN, TagMap]: + """ + Retrieves the entire mapping between Resource ARNs and their tags. + + This should not be used to retrieve tags for a single resource and should instead use the + `Tags.get_tags(resource_arn)`. It should only be used in scenarios where visibility into the + entire internal tag store is required such as with the Resource Groups Tagging API (RGTA). + + :return: A mapping between Resource ARN and tags. + """ + + return self._tags.copy() + + +# Tagging operations for various services return tags in one of two formats: +# +# - Tag list: A list of dicts, each dict containing the fields 'Key' and 'Value' and appropriate tag key value pairs. +# Some services, like CodePipeline, use the fields 'key' and 'value':: +# +# [ +# { +# "Key": "Environment", +# "Value": "Production", +# }, +# { +# "Key": "Owner", +# "Value": "LocalStack", +# } +# ] +# +# - Tag map: a direct mapping of tag keys to tag values.:: +# +# { +# "Environment": "Production", +# "Owner": "LocalStack", +# } + + +def tag_list_to_map( + tag_list: list[dict[str, str]], key_field: str = "Key", value_field: str = "Value" +) -> dict[str, str]: + """ + Convert a tag list to a tag map:: + + >> tag_list_to_map([{"Key": "temperature", "Value": "warm"}]) + {"temperature": "warm"} + + """ + return {tag[key_field]: tag[value_field] for tag in tag_list} + + +def tag_map_to_list( + tag_map: dict[str, str], key_field: str = "Key", value_field: str = "Value" +) -> list[dict[str, str]]: + """ + Convert a tag map to a tag list:: + + >> tag_map_to_list({"temperature": "warm"}) + [{"Key": "temperature", "Value": "warm"}] + + """ + return [{key_field: key, value_field: value} for key, value in tag_map.items()] diff --git a/localstack-core/localstack/utils/testutil.py b/localstack-core/localstack/utils/testutil.py index db8ca34c1c292..cc5f62c17eee0 100644 --- a/localstack-core/localstack/utils/testutil.py +++ b/localstack-core/localstack/utils/testutil.py @@ -7,7 +7,8 @@ import shutil import tempfile import time -from typing import Any, Callable, Optional +from collections.abc import Callable +from typing import Any from localstack.aws.api.lambda_ import Runtime from localstack.aws.connect import connect_externally_to, connect_to @@ -20,7 +21,7 @@ try: from typing import Literal except ImportError: - from typing_extensions import Literal + from typing import Literal import boto3 import requests @@ -548,7 +549,7 @@ def list_all_log_events(log_group_name: str, logs_client=None) -> list[dict]: def get_lambda_log_events( function_name, delay_time=DEFAULT_GET_LOG_EVENTS_DELAY, - regex_filter: Optional[str] = None, + regex_filter: str | None = None, log_group=None, logs_client=None, ): @@ -596,7 +597,7 @@ def list_all_resources( page_function: Callable[[dict], Any], last_token_attr_name: str, list_attr_name: str, - next_token_attr_name: Optional[str] = None, + next_token_attr_name: str | None = None, ) -> list: """ List all available resources by loading all available pages using `page_function`. diff --git a/localstack-core/localstack/utils/threads.py b/localstack-core/localstack/utils/threads.py index 403a872546a03..4123302d69643 100644 --- a/localstack-core/localstack/utils/threads.py +++ b/localstack-core/localstack/utils/threads.py @@ -1,17 +1,21 @@ import concurrent.futures -import inspect import logging +import subprocess import threading import traceback +from collections.abc import Callable from concurrent.futures import Future from multiprocessing.dummy import Pool -from typing import Callable, Optional +from typing import Any, ParamSpec, TypeVar + +P = ParamSpec("P") +T = TypeVar("T") LOG = logging.getLogger(__name__) # arrays for temporary threads and resources -TMP_THREADS = [] -TMP_PROCESSES = [] +TMP_THREADS: list["FuncThread"] = [] +TMP_PROCESSES: list[subprocess.Popen[Any]] = [] counter_lock = threading.Lock() counter = 0 @@ -22,12 +26,12 @@ class FuncThread(threading.Thread): def __init__( self, - func, - params=None, - quiet=False, - on_stop: Callable[["FuncThread"], None] = None, - name: Optional[str] = None, - daemon=True, + func: "Callable[P, T]", + params: Any = None, + quiet: bool = False, + on_stop: Callable[["FuncThread"], None] | None = None, + name: str | None = None, + daemon: bool = True, ): global counter global counter_lock @@ -46,17 +50,14 @@ def __init__( self.params = params self.func = func self.quiet = quiet - self.result_future = Future() + self.result_future: Future[T | Exception | None] = Future() self._stop_event = threading.Event() self.on_stop = on_stop - def run(self): - result = None + def run(self) -> None: + result: Any = None try: - kwargs = {} - argspec = inspect.getfullargspec(self.func) - if argspec.varkw or "_thread" in (argspec.args or []) + (argspec.kwonlyargs or []): - kwargs["_thread"] = self + kwargs = {} # type: ignore[var-annotated] result = self.func(self.params, **kwargs) except Exception as e: self.result_future.set_exception(e) @@ -78,7 +79,7 @@ def run(self): LOG.debug(e) @property - def running(self): + def running(self) -> bool: return not self._stop_event.is_set() def stop(self, quiet: bool = False) -> None: @@ -91,27 +92,33 @@ def stop(self, quiet: bool = False) -> None: LOG.warning("error while calling on_stop callback: %s", e) -def start_thread(method, *args, **kwargs) -> FuncThread: # TODO: find all usages and add names... +def start_thread( + method: "Callable[P, T]", + params: Any = None, + quiet: bool = False, + on_stop: Callable[["FuncThread"], None] | None = None, + _shutdown_hook: bool = True, + name: str | None = None, +) -> FuncThread: """Start the given method in a background thread, and add the thread to the TMP_THREADS shutdown hook""" - _shutdown_hook = kwargs.pop("_shutdown_hook", True) - if not kwargs.get("name"): - LOG.debug( - "start_thread called without providing a custom name" - ) # technically we should add a new level here for *internal* warnings - kwargs.setdefault("name", method.__name__) - thread = FuncThread(method, *args, **kwargs) + if not name: + # technically we should add a new level here for *internal* warnings + LOG.debug("start_thread called without providing a custom name") + name = name or method.__name__ + thread = FuncThread(method, params=params, quiet=quiet, name=name, on_stop=on_stop) thread.start() if _shutdown_hook: TMP_THREADS.append(thread) return thread -def start_worker_thread(method, *args, **kwargs): - kwargs.setdefault("name", "start_worker_thread") - return start_thread(method, *args, _shutdown_hook=False, **kwargs) +def start_worker_thread( + method: "Callable[P, T]", params: Any = None, name: str | None = None +) -> FuncThread: + return start_thread(method, params, _shutdown_hook=False, name=name or "start_worker_thread") -def cleanup_threads_and_processes(quiet=True): +def cleanup_threads_and_processes(quiet: bool = True) -> None: from localstack.utils.run import kill_process_tree for thread in TMP_THREADS: @@ -153,7 +160,7 @@ def cleanup_threads_and_processes(quiet=True): TMP_PROCESSES.clear() -def parallelize(func: Callable, arr: list, size: int = None): +def parallelize(func: Callable, arr: list, size: int = None): # type: ignore if not size: size = len(arr) if size <= 0: diff --git a/localstack-core/localstack/utils/time.py b/localstack-core/localstack/utils/time.py index ce0d7f402770d..66c93dc8e4b1d 100644 --- a/localstack-core/localstack/utils/time.py +++ b/localstack-core/localstack/utils/time.py @@ -1,6 +1,5 @@ import time from datetime import date, datetime, timezone, tzinfo -from typing import Optional from zoneinfo import ZoneInfo TIMESTAMP_FORMAT = "%Y-%m-%dT%H:%M:%S" @@ -64,7 +63,7 @@ def parse_timestamp(ts_str: str) -> datetime: raise Exception(f"Unable to parse timestamp string with any known formats: {ts_str}") -def now(millis: bool = False, tz: Optional[tzinfo] = None) -> int: +def now(millis: bool = False, tz: tzinfo | None = None) -> int: return mktime(datetime.now(tz=tz), millis=millis) diff --git a/localstack-core/localstack/utils/urls.py b/localstack-core/localstack/utils/urls.py index 97b92af754996..a6f4dd6e9f76a 100644 --- a/localstack-core/localstack/utils/urls.py +++ b/localstack-core/localstack/utils/urls.py @@ -1,5 +1,3 @@ -from typing import Optional - from localstack import config from localstack.config import HostAndPort @@ -12,7 +10,7 @@ def hostname_from_url(url: str) -> str: return url.split("://")[-1].split("/")[0].split(":")[0] -def localstack_host(custom_port: Optional[int] = None) -> HostAndPort: +def localstack_host(custom_port: int | None = None) -> HostAndPort: """ Determine the host and port to return to the user based on: - the user's configuration (e.g environment variable overrides) diff --git a/localstack-core/mypy.ini b/localstack-core/mypy.ini index 5fdadc333f36c..30e0bd8e0b7b8 100644 --- a/localstack-core/mypy.ini +++ b/localstack-core/mypy.ini @@ -1,7 +1,7 @@ [mypy] explicit_package_bases = true mypy_path=localstack-core -files=localstack/aws/api/core.py,localstack/packages,localstack/services/transcribe,localstack/services/kinesis/packages.py +files=localstack/aws/api/core.py,localstack/utils/files.py,localstack/utils/docker_utils.py,localstack/utils/threads.py,localstack/utils/strings.py,localstack/packages,localstack/services/transcribe,localstack/services/kinesis/packages.py ignore_missing_imports = False follow_imports = silent ignore_errors = False diff --git a/plux.ini b/plux.ini new file mode 100644 index 0000000000000..6ef5ac38199b4 --- /dev/null +++ b/plux.ini @@ -0,0 +1,224 @@ +[localstack.aws.provider] +acm:default = localstack.services.providers:acm +apigateway:default = localstack.services.providers:apigateway +apigateway:legacy = localstack.services.providers:apigateway_legacy +apigateway:next_gen = localstack.services.providers:apigateway_next_gen +cloudformation:default = localstack.services.providers:cloudformation_v2 +cloudformation:engine-legacy = localstack.services.providers:cloudformation +cloudwatch:default = localstack.services.providers:cloudwatch +cloudwatch:v1 = localstack.services.providers:cloudwatch_v1 +cloudwatch:v2 = localstack.services.providers:cloudwatch_v2 +config:default = localstack.services.providers:awsconfig +dynamodb:default = localstack.services.providers:dynamodb +dynamodb:v2 = localstack.services.providers:dynamodb_v2 +dynamodbstreams:default = localstack.services.providers:dynamodbstreams +dynamodbstreams:v2 = localstack.services.providers:dynamodbstreams_v2 +ec2:default = localstack.services.providers:ec2 +es:default = localstack.services.providers:es +events:default = localstack.services.providers:events +events:legacy = localstack.services.providers:events_legacy +events:v1 = localstack.services.providers:events_v1 +events:v2 = localstack.services.providers:events_v2 +firehose:default = localstack.services.providers:firehose +iam:default = localstack.services.providers:iam +kinesis:default = localstack.services.providers:kinesis +kms:default = localstack.services.providers:kms +lambda:asf = localstack.services.providers:lambda_asf +lambda:default = localstack.services.providers:lambda_ +lambda:v2 = localstack.services.providers:lambda_v2 +logs:default = localstack.services.providers:logs +opensearch:default = localstack.services.providers:opensearch +redshift:default = localstack.services.providers:redshift +resource-groups:default = localstack.services.providers:resource_groups +resourcegroupstaggingapi:default = localstack.services.providers:resourcegroupstaggingapi +route53:default = localstack.services.providers:route53 +route53resolver:default = localstack.services.providers:route53resolver +s3:default = localstack.services.providers:s3 +s3control:default = localstack.services.providers:s3control +scheduler:default = localstack.services.providers:scheduler +secretsmanager:default = localstack.services.providers:secretsmanager +ses:default = localstack.services.providers:ses +sns:default = localstack.services.providers:sns +sqs:default = localstack.services.providers:sqs +ssm:default = localstack.services.providers:ssm +stepfunctions:default = localstack.services.providers:stepfunctions +stepfunctions:v2 = localstack.services.providers:stepfunctions_v2 +sts:default = localstack.services.providers:sts +support:default = localstack.services.providers:support +swf:default = localstack.services.providers:swf +transcribe:default = localstack.services.providers:transcribe + +[localstack.cloudformation.resource_providers] +aws::apigateway::account = localstack.services.apigateway.resource_providers.aws_apigateway_account_plugin:ApiGatewayAccountProviderPlugin +aws::apigateway::apikey = localstack.services.apigateway.resource_providers.aws_apigateway_apikey_plugin:ApiGatewayApiKeyProviderPlugin +aws::apigateway::basepathmapping = localstack.services.apigateway.resource_providers.aws_apigateway_basepathmapping_plugin:ApiGatewayBasePathMappingProviderPlugin +aws::apigateway::deployment = localstack.services.apigateway.resource_providers.aws_apigateway_deployment_plugin:ApiGatewayDeploymentProviderPlugin +aws::apigateway::domainname = localstack.services.apigateway.resource_providers.aws_apigateway_domainname_plugin:ApiGatewayDomainNameProviderPlugin +aws::apigateway::gatewayresponse = localstack.services.apigateway.resource_providers.aws_apigateway_gatewayresponse_plugin:ApiGatewayGatewayResponseProviderPlugin +aws::apigateway::method = localstack.services.apigateway.resource_providers.aws_apigateway_method_plugin:ApiGatewayMethodProviderPlugin +aws::apigateway::model = localstack.services.apigateway.resource_providers.aws_apigateway_model_plugin:ApiGatewayModelProviderPlugin +aws::apigateway::requestvalidator = localstack.services.apigateway.resource_providers.aws_apigateway_requestvalidator_plugin:ApiGatewayRequestValidatorProviderPlugin +aws::apigateway::resource = localstack.services.apigateway.resource_providers.aws_apigateway_resource_plugin:ApiGatewayResourceProviderPlugin +aws::apigateway::restapi = localstack.services.apigateway.resource_providers.aws_apigateway_restapi_plugin:ApiGatewayRestApiProviderPlugin +aws::apigateway::stage = localstack.services.apigateway.resource_providers.aws_apigateway_stage_plugin:ApiGatewayStageProviderPlugin +aws::apigateway::usageplan = localstack.services.apigateway.resource_providers.aws_apigateway_usageplan_plugin:ApiGatewayUsagePlanProviderPlugin +aws::apigateway::usageplankey = localstack.services.apigateway.resource_providers.aws_apigateway_usageplankey_plugin:ApiGatewayUsagePlanKeyProviderPlugin +aws::cdk::metadata = localstack.services.cdk.resource_providers.cdk_metadata_plugin:LambdaAliasProviderPlugin +aws::certificatemanager::certificate = localstack.services.certificatemanager.resource_providers.aws_certificatemanager_certificate_plugin:CertificateManagerCertificateProviderPlugin +aws::cloudformation::macro = localstack.services.cloudformation.resource_providers.aws_cloudformation_macro_plugin:CloudFormationMacroProviderPlugin +aws::cloudformation::stack = localstack.services.cloudformation.resource_providers.aws_cloudformation_stack_plugin:CloudFormationStackProviderPlugin +aws::cloudformation::waitcondition = localstack.services.cloudformation.resource_providers.aws_cloudformation_waitcondition_plugin:CloudFormationWaitConditionProviderPlugin +aws::cloudformation::waitconditionhandle = localstack.services.cloudformation.resource_providers.aws_cloudformation_waitconditionhandle_plugin:CloudFormationWaitConditionHandleProviderPlugin +aws::cloudwatch::alarm = localstack.services.cloudwatch.resource_providers.aws_cloudwatch_alarm_plugin:CloudWatchAlarmProviderPlugin +aws::cloudwatch::compositealarm = localstack.services.cloudwatch.resource_providers.aws_cloudwatch_compositealarm_plugin:CloudWatchCompositeAlarmProviderPlugin +aws::dynamodb::globaltable = localstack.services.dynamodb.resource_providers.aws_dynamodb_globaltable_plugin:DynamoDBGlobalTableProviderPlugin +aws::dynamodb::table = localstack.services.dynamodb.resource_providers.aws_dynamodb_table_plugin:DynamoDBTableProviderPlugin +aws::ec2::dhcpoptions = localstack.services.ec2.resource_providers.aws_ec2_dhcpoptions_plugin:EC2DHCPOptionsProviderPlugin +aws::ec2::instance = localstack.services.ec2.resource_providers.aws_ec2_instance_plugin:EC2InstanceProviderPlugin +aws::ec2::internetgateway = localstack.services.ec2.resource_providers.aws_ec2_internetgateway_plugin:EC2InternetGatewayProviderPlugin +aws::ec2::keypair = localstack.services.ec2.resource_providers.aws_ec2_keypair_plugin:EC2KeyPairProviderPlugin +aws::ec2::natgateway = localstack.services.ec2.resource_providers.aws_ec2_natgateway_plugin:EC2NatGatewayProviderPlugin +aws::ec2::networkacl = localstack.services.ec2.resource_providers.aws_ec2_networkacl_plugin:EC2NetworkAclProviderPlugin +aws::ec2::prefixlist = localstack.services.ec2.resource_providers.aws_ec2_prefixlist_plugin:EC2PrefixListProviderPlugin +aws::ec2::route = localstack.services.ec2.resource_providers.aws_ec2_route_plugin:EC2RouteProviderPlugin +aws::ec2::routetable = localstack.services.ec2.resource_providers.aws_ec2_routetable_plugin:EC2RouteTableProviderPlugin +aws::ec2::securitygroup = localstack.services.ec2.resource_providers.aws_ec2_securitygroup_plugin:EC2SecurityGroupProviderPlugin +aws::ec2::subnet = localstack.services.ec2.resource_providers.aws_ec2_subnet_plugin:EC2SubnetProviderPlugin +aws::ec2::subnetroutetableassociation = localstack.services.ec2.resource_providers.aws_ec2_subnetroutetableassociation_plugin:EC2SubnetRouteTableAssociationProviderPlugin +aws::ec2::transitgateway = localstack.services.ec2.resource_providers.aws_ec2_transitgateway_plugin:EC2TransitGatewayProviderPlugin +aws::ec2::transitgatewayattachment = localstack.services.ec2.resource_providers.aws_ec2_transitgatewayattachment_plugin:EC2TransitGatewayAttachmentProviderPlugin +aws::ec2::vpc = localstack.services.ec2.resource_providers.aws_ec2_vpc_plugin:EC2VPCProviderPlugin +aws::ec2::vpcendpoint = localstack.services.ec2.resource_providers.aws_ec2_vpcendpoint_plugin:EC2VPCEndpointProviderPlugin +aws::ec2::vpcgatewayattachment = localstack.services.ec2.resource_providers.aws_ec2_vpcgatewayattachment_plugin:EC2VPCGatewayAttachmentProviderPlugin +aws::ecr::repository = localstack.services.ecr.resource_providers.aws_ecr_repository_plugin:ECRRepositoryProviderPlugin +aws::elasticsearch::domain = localstack.services.opensearch.resource_providers.aws_elasticsearch_domain_plugin:ElasticsearchDomainProviderPlugin +aws::events::apidestination = localstack.services.events.resource_providers.aws_events_apidestination_plugin:EventsApiDestinationProviderPlugin +aws::events::connection = localstack.services.events.resource_providers.aws_events_connection_plugin:EventsConnectionProviderPlugin +aws::events::eventbus = localstack.services.events.resource_providers.aws_events_eventbus_plugin:EventsEventBusProviderPlugin +aws::events::eventbuspolicy = localstack.services.events.resource_providers.aws_events_eventbuspolicy_plugin:EventsEventBusPolicyProviderPlugin +aws::events::rule = localstack.services.events.resource_providers.aws_events_rule_plugin:EventsRuleProviderPlugin +aws::iam::accesskey = localstack.services.iam.resource_providers.aws_iam_accesskey_plugin:IAMAccessKeyProviderPlugin +aws::iam::group = localstack.services.iam.resource_providers.aws_iam_group_plugin:IAMGroupProviderPlugin +aws::iam::instanceprofile = localstack.services.iam.resource_providers.aws_iam_instanceprofile_plugin:IAMInstanceProfileProviderPlugin +aws::iam::managedpolicy = localstack.services.iam.resource_providers.aws_iam_managedpolicy_plugin:IAMManagedPolicyProviderPlugin +aws::iam::policy = localstack.services.iam.resource_providers.aws_iam_policy_plugin:IAMPolicyProviderPlugin +aws::iam::role = localstack.services.iam.resource_providers.aws_iam_role_plugin:IAMRoleProviderPlugin +aws::iam::servercertificate = localstack.services.iam.resource_providers.aws_iam_servercertificate_plugin:IAMServerCertificateProviderPlugin +aws::iam::servicelinkedrole = localstack.services.iam.resource_providers.aws_iam_servicelinkedrole_plugin:IAMServiceLinkedRoleProviderPlugin +aws::iam::user = localstack.services.iam.resource_providers.aws_iam_user_plugin:IAMUserProviderPlugin +aws::kms::alias = localstack.services.kms.resource_providers.aws_kms_alias_plugin:KMSAliasProviderPlugin +aws::kms::key = localstack.services.kms.resource_providers.aws_kms_key_plugin:KMSKeyProviderPlugin +aws::kinesis::stream = localstack.services.kinesis.resource_providers.aws_kinesis_stream_plugin:KinesisStreamProviderPlugin +aws::kinesis::streamconsumer = localstack.services.kinesis.resource_providers.aws_kinesis_streamconsumer_plugin:KinesisStreamConsumerProviderPlugin +aws::kinesisfirehose::deliverystream = localstack.services.kinesisfirehose.resource_providers.aws_kinesisfirehose_deliverystream_plugin:KinesisFirehoseDeliveryStreamProviderPlugin +aws::lambda::alias = localstack.services.lambda_.resource_providers.lambda_alias_plugin:LambdaAliasProviderPlugin +aws::lambda::codesigningconfig = localstack.services.lambda_.resource_providers.aws_lambda_codesigningconfig_plugin:LambdaCodeSigningConfigProviderPlugin +aws::lambda::eventinvokeconfig = localstack.services.lambda_.resource_providers.aws_lambda_eventinvokeconfig_plugin:LambdaEventInvokeConfigProviderPlugin +aws::lambda::eventsourcemapping = localstack.services.lambda_.resource_providers.aws_lambda_eventsourcemapping_plugin:LambdaEventSourceMappingProviderPlugin +aws::lambda::function = localstack.services.lambda_.resource_providers.generated.aws_lambda_function_plugin:LambdaFunctionProviderPlugin +aws::lambda::layerversion = localstack.services.lambda_.resource_providers.aws_lambda_layerversion_plugin:LambdaLayerVersionProviderPlugin +aws::lambda::layerversionpermission = localstack.services.lambda_.resource_providers.aws_lambda_layerversionpermission_plugin:LambdaLayerVersionPermissionProviderPlugin +aws::lambda::permission = localstack.services.lambda_.resource_providers.aws_lambda_permission_plugin:LambdaPermissionProviderPlugin +aws::lambda::url = localstack.services.lambda_.resource_providers.aws_lambda_url_plugin:LambdaUrlProviderPlugin +aws::lambda::version = localstack.services.lambda_.resource_providers.aws_lambda_version_plugin:LambdaVersionProviderPlugin +aws::logs::loggroup = localstack.services.logs.resource_providers.aws_logs_loggroup_plugin:LogsLogGroupProviderPlugin +aws::logs::logstream = localstack.services.logs.resource_providers.aws_logs_logstream_plugin:LogsLogStreamProviderPlugin +aws::logs::subscriptionfilter = localstack.services.logs.resource_providers.aws_logs_subscriptionfilter_plugin:LogsSubscriptionFilterProviderPlugin +aws::opensearchservice::domain = localstack.services.opensearch.resource_providers.aws_opensearchservice_domain_plugin:OpenSearchServiceDomainProviderPlugin +aws::redshift::cluster = localstack.services.redshift.resource_providers.aws_redshift_cluster_plugin:RedshiftClusterProviderPlugin +aws::resourcegroups::group = localstack.services.resource_groups.resource_providers.aws_resourcegroups_group_plugin:ResourceGroupsGroupProviderPlugin +aws::route53::healthcheck = localstack.services.route53.resource_providers.aws_route53_healthcheck_plugin:Route53HealthCheckProviderPlugin +aws::route53::recordset = localstack.services.route53.resource_providers.aws_route53_recordset_plugin:Route53RecordSetProviderPlugin +aws::s3::bucket = localstack.services.s3.resource_providers.aws_s3_bucket_plugin:S3BucketProviderPlugin +aws::s3::bucketpolicy = localstack.services.s3.resource_providers.aws_s3_bucketpolicy_plugin:S3BucketPolicyProviderPlugin +aws::ses::emailidentity = localstack.services.ses.resource_providers.aws_ses_emailidentity_plugin:SESEmailIdentityProviderPlugin +aws::sns::subscription = localstack.services.sns.resource_providers.aws_sns_subscription_plugin:SNSSubscriptionProviderPlugin +aws::sns::topic = localstack.services.sns.resource_providers.aws_sns_topic_plugin:SNSTopicProviderPlugin +aws::sns::topicpolicy = localstack.services.sns.resource_providers.aws_sns_topicpolicy_plugin:SNSTopicPolicyProviderPlugin +aws::sqs::queue = localstack.services.sqs.resource_providers.generated.aws_sqs_queue_plugin:SQSQueueProviderPlugin +aws::sqs::queueinlinepolicy = localstack.services.sqs.resource_providers.generated.aws_sqs_queueinlinepolicy_plugin:SQSQueueInlinePolicyProviderPlugin +aws::sqs::queuepolicy = localstack.services.sqs.resource_providers.generated.aws_sqs_queuepolicy_plugin:SQSQueuePolicyProviderPlugin +aws::ssm::maintenancewindow = localstack.services.ssm.resource_providers.aws_ssm_maintenancewindow_plugin:SSMMaintenanceWindowProviderPlugin +aws::ssm::maintenancewindowtarget = localstack.services.ssm.resource_providers.aws_ssm_maintenancewindowtarget_plugin:SSMMaintenanceWindowTargetProviderPlugin +aws::ssm::maintenancewindowtask = localstack.services.ssm.resource_providers.aws_ssm_maintenancewindowtask_plugin:SSMMaintenanceWindowTaskProviderPlugin +aws::ssm::parameter = localstack.services.ssm.resource_providers.aws_ssm_parameter_plugin:SSMParameterProviderPlugin +aws::ssm::patchbaseline = localstack.services.ssm.resource_providers.aws_ssm_patchbaseline_plugin:SSMPatchBaselineProviderPlugin +aws::scheduler::schedule = localstack.services.scheduler.resource_providers.aws_scheduler_schedule_plugin:SchedulerScheduleProviderPlugin +aws::scheduler::schedulegroup = localstack.services.scheduler.resource_providers.aws_scheduler_schedulegroup_plugin:SchedulerScheduleGroupProviderPlugin +aws::secretsmanager::resourcepolicy = localstack.services.secretsmanager.resource_providers.aws_secretsmanager_resourcepolicy_plugin:SecretsManagerResourcePolicyProviderPlugin +aws::secretsmanager::rotationschedule = localstack.services.secretsmanager.resource_providers.aws_secretsmanager_rotationschedule_plugin:SecretsManagerRotationScheduleProviderPlugin +aws::secretsmanager::secret = localstack.services.secretsmanager.resource_providers.aws_secretsmanager_secret_plugin:SecretsManagerSecretProviderPlugin +aws::secretsmanager::secrettargetattachment = localstack.services.secretsmanager.resource_providers.aws_secretsmanager_secrettargetattachment_plugin:SecretsManagerSecretTargetAttachmentProviderPlugin +aws::stepfunctions::activity = localstack.services.stepfunctions.resource_providers.aws_stepfunctions_activity_plugin:StepFunctionsActivityProviderPlugin +aws::stepfunctions::statemachine = localstack.services.stepfunctions.resource_providers.aws_stepfunctions_statemachine_plugin:StepFunctionsStateMachineProviderPlugin + +[localstack.hooks.configure_localstack_container] +_mount_machine_file = localstack.utils.analytics.metadata:_mount_machine_file + +[localstack.hooks.on_infra_ready] +_run_init_scripts_on_ready = localstack.runtime.init:_run_init_scripts_on_ready + +[localstack.hooks.on_infra_shutdown] +_run_init_scripts_on_shutdown = localstack.runtime.init:_run_init_scripts_on_shutdown +publish_metrics = localstack.utils.analytics.metrics.publisher:publish_metrics +remove_custom_endpoints = localstack.services.lambda_.plugins:remove_custom_endpoints +run_on_after_service_shutdown_handlers = localstack.runtime.shutdown:run_on_after_service_shutdown_handlers +run_shutdown_handlers = localstack.runtime.shutdown:run_shutdown_handlers +shutdown_services = localstack.runtime.shutdown:shutdown_services +stop_server = localstack.dns.plugins:stop_server + +[localstack.hooks.on_infra_start] +_patch_botocore_endpoint_in_memory = localstack.aws.client:_patch_botocore_endpoint_in_memory +_patch_botocore_json_parser = localstack.aws.client:_patch_botocore_json_parser +_patch_cbor2 = localstack.aws.client:_patch_cbor2 +_publish_config_as_analytics_event = localstack.runtime.analytics:_publish_config_as_analytics_event +_run_init_scripts_on_start = localstack.runtime.init:_run_init_scripts_on_start +apply_aws_runtime_patches = localstack.aws.patches:apply_aws_runtime_patches +apply_runtime_patches = localstack.runtime.patches:apply_runtime_patches +conditionally_enable_debugger = localstack.dev.debugger.plugins:conditionally_enable_debugger +delete_cached_certificate = localstack.plugins:delete_cached_certificate +deprecation_warnings = localstack.plugins:deprecation_warnings +eager_load_services = localstack.services.plugins:eager_load_services +init_response_mutation_handler = localstack.aws.handlers.response:init_response_mutation_handler +register_custom_endpoints = localstack.services.lambda_.plugins:register_custom_endpoints +register_swagger_endpoints = localstack.http.resources.swagger.plugins:register_swagger_endpoints +setup_dns_configuration_on_host = localstack.dns.plugins:setup_dns_configuration_on_host +start_dns_server = localstack.dns.plugins:start_dns_server +validate_configuration = localstack.services.lambda_.plugins:validate_configuration + +[localstack.hooks.prepare_host] +prepare_host_machine_id = localstack.utils.analytics.metadata:prepare_host_machine_id + +[localstack.init.runner] +py = localstack.runtime.init:PythonScriptRunner +sh = localstack.runtime.init:ShellScriptRunner + +[localstack.lambda.runtime_executor] +docker = localstack.services.lambda_.invocation.plugins:DockerRuntimeExecutorPlugin + +[localstack.openapi.spec] +localstack = localstack.plugins:CoreOASPlugin + +[localstack.packages] +dynamodb-local/community = localstack.services.dynamodb.plugins:dynamodb_local_package +elasticsearch/community = localstack.services.es.plugins:elasticsearch_package +ffmpeg/community = localstack.packages.plugins:ffmpeg_package +java/community = localstack.packages.plugins:java_package +jpype-jsonata/community = localstack.services.stepfunctions.plugins:jpype_jsonata_package +kinesis-mock/community = localstack.services.kinesis.plugins:kinesismock_package +lambda-java-libs/community = localstack.services.lambda_.plugins:lambda_java_libs +lambda-runtime/community = localstack.services.lambda_.plugins:lambda_runtime_package +opensearch/community = localstack.services.opensearch.plugins:opensearch_package +vosk/community = localstack.services.transcribe.plugins:vosk_package + +[localstack.runtime.components] +aws = localstack.aws.components:AwsComponents + +[localstack.runtime.server] +hypercorn = localstack.runtime.server.plugins:HypercornRuntimeServerPlugin +twisted = localstack.runtime.server.plugins:TwistedRuntimeServerPlugin + +[localstack.utils.catalog] +aws-catalog-remote-state = localstack.utils.catalog.catalog:AwsCatalogRemoteStatePlugin +aws-catalog-runtime-only = localstack.utils.catalog.catalog:AwsCatalogRuntimePlugin + diff --git a/pyproject.toml b/pyproject.toml index 400e439bde8df..878992c301468 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ # LocalStack project configuration [build-system] -requires = ['setuptools>=64', 'wheel', 'plux>=1.12', "setuptools_scm>=8.1"] +requires = ['setuptools>=64', 'wheel', 'setuptools_scm>=8.1'] build-backend = "setuptools.build_meta" [project] @@ -10,25 +10,23 @@ authors = [ ] description = "The core library and runtime of LocalStack" license = "Apache-2.0" -requires-python = ">=3.9" +requires-python = ">=3.10" dependencies = [ - "build", - "click>=7.1", + "asn1crypto>=1.5.1", + "click>=8.2.0", "cachetools>=5.0", "cryptography", - "dill==0.3.6", "dnslib>=0.9.10", "dnspython>=1.16.0", - "plux>=1.10", + "plux>=1.14.0", "psutil>=5.4.8", "python-dotenv>=0.19.1", "pyyaml>=5.1", "rich>=12.3.0", "requests>=2.20.0", "semver>=2.10", - "tailer>=0.4.1", ] -dynamic = ["version"] +dynamic = ["version", "entry-points"] classifiers = [ "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.13", @@ -53,50 +51,58 @@ Issues = "https://github.com/localstack/localstack/issues" # minimal required to actually run localstack on the host for services natively implemented in python base-runtime = [ # pinned / updated by ASF update action - "boto3==1.40.40", + "boto3==1.42.59", # pinned / updated by ASF update action - "botocore==1.40.40", + "botocore==1.42.59", + # transitive dependency of botocore, added to avoid specific version "awscrt>=0.13.14,!=0.27.1", "cbor2>=5.5.0", + "dill==0.3.6", "dnspython>=1.16.0", "docker>=6.1.1", "jsonpatch>=1.24", + "jsonpointer>=3.0.0", + "jsonschema>=4.25.1", "hypercorn>=0.14.4", - "localstack-twisted>=23.0", + "localstack-twisted>=25.0", "openapi-core>=0.19.2", + "pydantic>=2.11.9", "pyopenssl>=23.0.0", + "python-dateutil>=2.9.0", "readerwriterlock>=1.0.7", "requests-aws4auth>=1.0", # explicitly set urllib3 to force its usage / ensure compatibility "urllib3>=2.0.7", "Werkzeug>=3.1.3", "xmltodict>=0.13.0", - "rolo>=0.7", + "rolo>=0.8.1", ] # required to actually run localstack on the host runtime = [ "localstack-core[base-runtime]", # pinned / updated by ASF update action - "awscli==1.42.40", + "awscli==1.44.49", "airspeed-ext>=0.6.3", - # version that has a built wheel - "kclpy-ext>=3.0.0", # antlr4-python3-runtime: exact pin because antlr4 runtime is tightly coupled to the generated parser code "antlr4-python3-runtime==4.13.2", "apispec>=5.1.1", - "aws-sam-translator>=1.15.1", + # pinning it to a higher version than what moto-ext requires + "aws-sam-translator>=1.105.0", "crontab>=0.22.6", "cryptography>=41.0.5", + "jinja2>=3.1.6", # allow Python programs full access to Java class libraries. Used for stepfunctions jsonata support "jpype1>=1.6.0", - "json5>=0.9.11", - "jsonpath-ng>=1.6.1", + "jsonpath-ng==1.7.0", "jsonpath-rw>=1.4.0", - "moto-ext[all]>=5.1.12.post22", + # version that has a built wheel + "kclpy-ext>=3.0.0", + "moto-ext[all]>=5.1.22", "opensearch-py>=2.4.1", "pymongo>=4.2.0", "pyopenssl>=23.0.0", + "responses>=0.25.8", ] # for running tests and coverage analysis @@ -104,8 +110,8 @@ test = [ # runtime dependencies are required for running the tests "localstack-core[runtime]", "coverage[toml]>=5.5", - "deepdiff>=6.4.1", "httpx[http2]>=0.25", + "json5>=0.12.1", "pluggy>=1.3.0", "pytest>=7.4.2", "pytest-split>=0.8.0", @@ -122,6 +128,7 @@ dev = [ # test dependencies are required for developing localstack "localstack-core[test]", "coveralls>=3.3.1", + "deptry>=0.13.0", "Cython", "networkx>=2.8.4", "openapi-spec-validator>=0.7.1", @@ -131,6 +138,7 @@ dev = [ "ruff>=0.3.3", "rstr>=3.2.0", "mypy", + "watchdog>=6", ] # not strictly necessary for development, but provides type hint support for a better developer experience @@ -138,7 +146,7 @@ typehint = [ # typehint is an optional extension of the dev dependencies "localstack-core[dev]", # pinned / updated by ASF update action - "boto3-stubs[acm,acm-pca,amplify,apigateway,apigatewayv2,appconfig,appconfigdata,application-autoscaling,appsync,athena,autoscaling,backup,batch,ce,cloudcontrol,cloudformation,cloudfront,cloudtrail,cloudwatch,codebuild,codecommit,codeconnections,codedeploy,codepipeline,codestar-connections,cognito-identity,cognito-idp,dms,docdb,dynamodb,dynamodbstreams,ec2,ecr,ecs,efs,eks,elasticache,elasticbeanstalk,elbv2,emr,emr-serverless,es,events,firehose,fis,glacier,glue,iam,identitystore,iot,iot-data,iotanalytics,iotwireless,kafka,kinesis,kinesisanalytics,kinesisanalyticsv2,kms,lakeformation,lambda,logs,managedblockchain,mediaconvert,mediastore,mq,mwaa,neptune,opensearch,organizations,pi,pipes,pinpoint,qldb,qldb-session,rds,rds-data,redshift,redshift-data,resource-groups,resourcegroupstaggingapi,route53,route53resolver,s3,s3control,sagemaker,sagemaker-runtime,secretsmanager,serverlessrepo,servicediscovery,ses,sesv2,sns,sqs,ssm,sso-admin,stepfunctions,sts,timestream-query,timestream-write,transcribe,verifiedpermissions,wafv2,xray]", + "boto3-stubs[acm,acm-pca,amplify,apigateway,apigatewayv2,appconfig,appconfigdata,application-autoscaling,appsync,athena,autoscaling,backup,batch,ce,cloudcontrol,cloudformation,cloudfront,cloudtrail,cloudwatch,codebuild,codecommit,codeconnections,codedeploy,codepipeline,codestar-connections,cognito-identity,cognito-idp,dms,docdb,dynamodb,dynamodbstreams,ec2,ecr,ecs,efs,eks,elasticache,elasticbeanstalk,elbv2,emr,emr-serverless,es,events,firehose,fis,glacier,glue,iam,identitystore,iot,iot-data,iotwireless,kafka,kinesis,kinesisanalyticsv2,kms,lakeformation,lambda,logs,managedblockchain,mediaconvert,mq,mwaa,neptune,opensearch,organizations,pi,pipes,pinpoint,rds,rds-data,redshift,redshift-data,resource-groups,resourcegroupstaggingapi,route53,route53resolver,s3,s3control,sagemaker,sagemaker-runtime,secretsmanager,serverlessrepo,servicediscovery,ses,sesv2,sns,sqs,ssm,sso-admin,stepfunctions,sts,timestream-query,timestream-write,transcribe,verifiedpermissions,wafv2,xray]", ] [tool.setuptools] @@ -146,14 +154,13 @@ include-package-data = false # TODO using this is discouraged by setuptools, `project.scripts` should be used instead # However, `project.scripts` does not support non-python scripts. script-files = [ - "bin/localstack", - "bin/localstack.bat", "bin/localstack-supervisor", ] package-dir = { "" = "localstack-core" } [tool.setuptools.dynamic] readme = { file = ["README.md"], content-type = "text/markdown" } +entry-points = { file = ["plux.ini"] } [tool.setuptools.packages.find] where = ["localstack-core/"] @@ -168,7 +175,7 @@ exclude = ["tests*"] "localstack" = [ "aws/**/*.json", "services/**/*.html", - "services/**/resource_providers/*.schema.json", + "services/**/resource_providers/**/*.schema.json", "utils/kinesis/java/cloud/localstack/*.*", "openapi.yaml", "http/resources/swagger/templates/index.html" @@ -176,7 +183,7 @@ exclude = ["tests*"] [tool.ruff] # Generate code compatible with version defined in .python-version -target-version = "py311" +target-version = "py313" line-length = 100 src = ["localstack-core", "tests"] exclude = [ @@ -195,12 +202,41 @@ exclude = [ [tool.ruff.per-file-target-version] # Only allow minimum version for code used in the CLI -"localstack-core/localstack/cli/**" = "py39" -"localstack-core/localstack/packages/**" = "py39" -"localstack-core/localstack/config.py" = "py39" -"localstack-core/localstack/constants.py" = "py39" -"localstack-core/localstack/utils/**" = "py39" # imported by CLI tests -"localstack-core/localstack/testing/pytest/**" = "py39" # imported by CLI tests +"localstack-core/localstack/cli/**" = "py310" +"localstack-core/localstack/packages/**" = "py310" +"localstack-core/localstack/config.py" = "py310" +"localstack-core/localstack/constants.py" = "py310" +"localstack-core/localstack/utils/**" = "py310" # imported by CLI tests +"localstack-core/localstack/testing/pytest/**" = "py310" # imported by CLI tests +"localstack-core/localstack/aws/connect.py" = "py310" # imported by CLI tests + +[tool.deptry] +known_first_party = [ + "vosk", # managed by localstack package manager + "debugpy", # managed by localstack package manager +] +extend_exclude = [ + "scripts/**", # dependencies not handled by pyproject.toml + "localstack-core/localstack/testing/**", # utilities for testing + "localstack-core/localstack/aws/mocking.py", # not used at runtime + "localstack-core/localstack/aws/scaffold.py", # not used at runtime + "localstack-core/localstack/dev/**", # internal dev tooling + "localstack-core/localstack/services/stepfunctions/asl/antlr/runtime/**" # generated code +] +pep621_dev_dependency_groups = ["dev", "typehint", "test"] + +[tool.deptry.package_module_name_map] +"localstack-core" = ["localstack"] + +[tool.deptry.per_rule_ignores] +DEP001 = [ + "com", # This appears in jpype code and imports actual java packages like com.fasterxml.jackson.databind + "stevedore", # used for CLI plugin debugging - TODO move this debugging CLI into plux +] +DEP002 = [ + "awscli", # necessary for python init scripts - TODO deprecate python init scripts and remove this + "awscrt", # defined to ignore a specific version - TODO evaluate and clean up +] [tool.ruff.lint] ignore = [ @@ -219,15 +255,14 @@ ignore = [ ] select = ["B", "C", "E", "F", "I", "W", "T", "B9", "G", "UP"] extend-safe-fixes = [ - "UP006", # unsafe-fix for py39 - "UP035", # unsafe-fix for py39 + "UP006", # unsafe-fix for py39 + "UP035", # unsafe-fix for py39 ] # The rules below fill fix the code in a way that leaves multiple unused imports. # Since F401 (removing unused imports) is currently an unsafe fix, these imports cannot be automatically removed. # Therefore, we temporarily disable the rules below for __init__ files. [tool.ruff.lint.per-file-ignores] -"localstack-core/localstack/**/__init__.py" = ["UP006", "UP007", "UP035", "UP045"] "tests/aws/services/lambda_/functions/**" = ["UP"] # lambda tests parametrize the runtime [tool.ruff.lint.pyupgrade] @@ -270,3 +305,6 @@ log_cli_date_format = "%Y-%m-%dT%H:%M:%S" # adding localstack-core itself here because it is referenced in the pyproject.toml for stacking the extras # pip, setuptools, and distribute are pip-tools defaults which need to be set again here unsafe-package = ["localstack-core", "pip", "setuptools", "distribute"] # packages that should not be pinned + +[tool.plux] +entrypoint_build_mode = "manual" diff --git a/requirements-base-runtime.txt b/requirements-base-runtime.txt index a38115222821d..f89ff9902f151 100644 --- a/requirements-base-runtime.txt +++ b/requirements-base-runtime.txt @@ -2,39 +2,41 @@ # This file is autogenerated by pip-compile with Python 3.13 # by the following command: # -# pip-compile --cert=None --client-cert=None --extra=base-runtime --index-url=None --output-file=requirements-base-runtime.txt --pip-args=None --strip-extras --unsafe-package=distribute --unsafe-package=localstack-core --unsafe-package=pip --unsafe-package=setuptools pyproject.toml +# pip-compile --extra=base-runtime --output-file=requirements-base-runtime.txt --strip-extras --unsafe-package=distribute --unsafe-package=localstack-core --unsafe-package=pip --unsafe-package=setuptools pyproject.toml # -attrs==25.3.0 +annotated-types==0.7.0 + # via pydantic +asn1crypto==1.5.1 + # via localstack-core (pyproject.toml) +attrs==25.4.0 # via # jsonschema # localstack-twisted # referencing -awscrt==0.28.1 +awscrt==0.31.2 # via localstack-core (pyproject.toml) -boto3==1.40.40 +boto3==1.42.59 # via localstack-core (pyproject.toml) -botocore==1.40.40 +botocore==1.42.59 # via # boto3 # localstack-core (pyproject.toml) # s3transfer -build==1.3.0 - # via localstack-core (pyproject.toml) -cachetools==6.2.0 +cachetools==7.0.2 # via localstack-core (pyproject.toml) -cbor2==5.7.0 +cbor2==5.8.0 # via localstack-core (pyproject.toml) -certifi==2025.8.3 +certifi==2026.2.25 # via requests cffi==2.0.0 # via cryptography -charset-normalizer==3.4.3 +charset-normalizer==3.4.4 # via requests -click==8.3.0 +click==8.3.1 # via localstack-core (pyproject.toml) constantly==23.10.4 # via localstack-twisted -cryptography==46.0.1 +cryptography==46.0.5 # via # localstack-core (pyproject.toml) # pyopenssl @@ -56,31 +58,34 @@ h2==4.3.0 # localstack-twisted hpack==4.1.0 # via h2 -hypercorn==0.17.3 +hypercorn==0.18.0 # via localstack-core (pyproject.toml) hyperframe==6.1.0 # via h2 hyperlink==21.0.0 # via localstack-twisted -idna==3.10 +idna==3.11 # via # hyperlink # localstack-twisted # requests -incremental==24.7.2 +incremental==24.11.0 # via localstack-twisted isodate==0.7.2 # via openapi-core -jmespath==1.0.1 +jmespath==1.1.0 # via # boto3 # botocore jsonpatch==1.33 # via localstack-core (pyproject.toml) jsonpointer==3.0.0 - # via jsonpatch -jsonschema==4.25.1 # via + # jsonpatch + # localstack-core (pyproject.toml) +jsonschema==4.26.0 + # via + # localstack-core (pyproject.toml) # openapi-core # openapi-schema-validator # openapi-spec-validator @@ -94,7 +99,7 @@ jsonschema-specifications==2025.9.1 # openapi-schema-validator lazy-object-proxy==1.12.0 # via openapi-spec-validator -localstack-twisted==24.3.0 +localstack-twisted==25.5.0 # via localstack-core (pyproject.toml) markdown-it-py==4.0.0 # via rich @@ -104,7 +109,7 @@ mdurl==0.1.2 # via markdown-it-py more-itertools==10.8.0 # via openapi-core -openapi-core==0.19.4 +openapi-core==0.22.0 # via localstack-core (pyproject.toml) openapi-schema-validator==0.6.3 # via @@ -112,33 +117,35 @@ openapi-schema-validator==0.6.3 # openapi-spec-validator openapi-spec-validator==0.7.2 # via openapi-core -packaging==25.0 - # via build -parse==1.20.2 - # via openapi-core +packaging==26.0 + # via incremental pathable==0.4.4 # via jsonschema-path -plux==1.13.0 +plux==1.14.0 # via localstack-core (pyproject.toml) priority==1.3.0 # via # hypercorn # localstack-twisted -psutil==7.1.0 +psutil==7.2.2 # via localstack-core (pyproject.toml) -pycparser==2.23 +pycparser==3.0 # via cffi +pydantic==2.12.5 + # via localstack-core (pyproject.toml) +pydantic-core==2.41.5 + # via pydantic pygments==2.19.2 # via rich pyopenssl==25.3.0 # via # localstack-core (pyproject.toml) # localstack-twisted -pyproject-hooks==1.2.0 - # via build python-dateutil==2.9.0.post0 - # via botocore -python-dotenv==1.1.1 + # via + # botocore + # localstack-core (pyproject.toml) +python-dotenv==1.2.2 # via localstack-core (pyproject.toml) pyyaml==6.0.3 # via @@ -162,15 +169,15 @@ requests-aws4auth==1.3.1 # via localstack-core (pyproject.toml) rfc3339-validator==0.1.4 # via openapi-schema-validator -rich==14.1.0 +rich==14.3.3 # via localstack-core (pyproject.toml) -rolo==0.7.6 +rolo==0.8.1 # via localstack-core (pyproject.toml) -rpds-py==0.27.1 +rpds-py==0.30.0 # via # jsonschema # referencing -s3transfer==0.14.0 +s3transfer==0.16.0 # via boto3 semver==3.0.4 # via localstack-core (pyproject.toml) @@ -178,29 +185,30 @@ six==1.17.0 # via # python-dateutil # rfc3339-validator -tailer==0.4.1 - # via localstack-core (pyproject.toml) typing-extensions==4.15.0 # via # localstack-twisted + # openapi-core + # pydantic + # pydantic-core # readerwriterlock -urllib3==2.5.0 + # typing-inspection +typing-inspection==0.4.2 + # via pydantic +urllib3==2.6.3 # via # botocore # docker # localstack-core (pyproject.toml) # requests -werkzeug==3.1.3 +werkzeug==3.1.6 # via # localstack-core (pyproject.toml) # openapi-core # rolo -wsproto==1.2.0 +wsproto==1.3.2 # via hypercorn -xmltodict==1.0.2 +xmltodict==1.0.4 # via localstack-core (pyproject.toml) -zope-interface==8.0.1 +zope-interface==8.2 # via localstack-twisted - -# The following packages are considered to be unsafe in a requirements file: -# setuptools diff --git a/requirements-basic.txt b/requirements-basic.txt index bb3f799d08277..06adc17bab3ca 100644 --- a/requirements-basic.txt +++ b/requirements-basic.txt @@ -2,57 +2,49 @@ # This file is autogenerated by pip-compile with Python 3.13 # by the following command: # -# pip-compile --cert=None --client-cert=None --index-url=None --output-file=requirements-basic.txt --pip-args=None --strip-extras --unsafe-package=distribute --unsafe-package=localstack-core --unsafe-package=pip --unsafe-package=setuptools pyproject.toml +# pip-compile --output-file=requirements-basic.txt --strip-extras --unsafe-package=distribute --unsafe-package=localstack-core --unsafe-package=pip --unsafe-package=setuptools pyproject.toml # -build==1.3.0 +asn1crypto==1.5.1 # via localstack-core (pyproject.toml) -cachetools==6.2.0 +cachetools==7.0.2 # via localstack-core (pyproject.toml) -certifi==2025.8.3 +certifi==2026.2.25 # via requests cffi==2.0.0 # via cryptography -charset-normalizer==3.4.3 +charset-normalizer==3.4.4 # via requests -click==8.3.0 +click==8.3.1 # via localstack-core (pyproject.toml) -cryptography==46.0.1 - # via localstack-core (pyproject.toml) -dill==0.3.6 +cryptography==46.0.5 # via localstack-core (pyproject.toml) dnslib==0.9.26 # via localstack-core (pyproject.toml) dnspython==2.8.0 # via localstack-core (pyproject.toml) -idna==3.10 +idna==3.11 # via requests markdown-it-py==4.0.0 # via rich mdurl==0.1.2 # via markdown-it-py -packaging==25.0 - # via build -plux==1.13.0 +plux==1.14.0 # via localstack-core (pyproject.toml) -psutil==7.1.0 +psutil==7.2.2 # via localstack-core (pyproject.toml) -pycparser==2.23 +pycparser==3.0 # via cffi pygments==2.19.2 # via rich -pyproject-hooks==1.2.0 - # via build -python-dotenv==1.1.1 +python-dotenv==1.2.2 # via localstack-core (pyproject.toml) pyyaml==6.0.3 # via localstack-core (pyproject.toml) requests==2.32.5 # via localstack-core (pyproject.toml) -rich==14.1.0 +rich==14.3.3 # via localstack-core (pyproject.toml) semver==3.0.4 # via localstack-core (pyproject.toml) -tailer==0.4.1 - # via localstack-core (pyproject.toml) -urllib3==2.5.0 +urllib3==2.6.3 # via requests diff --git a/requirements-dev.txt b/requirements-dev.txt index 51847db0fbec4..542e17131d269 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -2,54 +2,61 @@ # This file is autogenerated by pip-compile with Python 3.13 # by the following command: # -# pip-compile --cert=None --client-cert=None --extra=dev --index-url=None --output-file=requirements-dev.txt --pip-args=None --strip-extras --unsafe-package=distribute --unsafe-package=localstack-core --unsafe-package=pip --unsafe-package=setuptools pyproject.toml +# pip-compile --extra=dev --output-file=requirements-dev.txt --strip-extras --unsafe-package=distribute --unsafe-package=localstack-core --unsafe-package=pip --unsafe-package=setuptools pyproject.toml # airspeed-ext==0.6.9 # via localstack-core +annotated-doc==0.0.4 + # via typer annotated-types==0.7.0 # via pydantic antlr4-python3-runtime==4.13.2 # via # localstack-core # moto-ext -anyio==4.11.0 +anyio==4.12.1 # via httpx -apispec==6.8.4 +apispec==6.9.0 # via localstack-core argparse==1.4.0 # via kclpy-ext -attrs==25.3.0 +asn1crypto==1.5.1 + # via + # localstack-core + # localstack-core (pyproject.toml) +attrs==25.4.0 # via # cattrs # jsii # jsonschema # localstack-twisted # referencing -aws-cdk-asset-awscli-v1==2.2.242 +aws-cdk-asset-awscli-v1==2.2.263 # via aws-cdk-lib -aws-cdk-asset-node-proxy-agent-v6==2.1.0 +aws-cdk-asset-node-proxy-agent-v6==2.1.1 # via aws-cdk-lib -aws-cdk-cloud-assembly-schema==48.11.0 +aws-cdk-cloud-assembly-schema==52.2.0 # via aws-cdk-lib -aws-cdk-lib==2.218.0 +aws-cdk-lib==2.241.0 # via localstack-core -aws-sam-translator==1.100.0 +aws-sam-translator==1.107.0 # via # cfn-lint # localstack-core -aws-xray-sdk==2.14.0 + # moto-ext +aws-xray-sdk==2.15.0 # via moto-ext -awscli==1.42.40 +awscli==1.44.49 # via localstack-core -awscrt==0.28.1 +awscrt==0.31.2 # via localstack-core -boto3==1.40.40 +boto3==1.42.59 # via # aws-sam-translator # kclpy-ext # localstack-core # moto-ext -botocore==1.40.40 +botocore==1.42.59 # via # aws-xray-sdk # awscli @@ -57,20 +64,16 @@ botocore==1.40.40 # localstack-core # moto-ext # s3transfer -build==1.3.0 - # via - # localstack-core - # localstack-core (pyproject.toml) -cachetools==6.2.0 +cachetools==7.0.2 # via # airspeed-ext # localstack-core # localstack-core (pyproject.toml) -cattrs==25.2.0 +cattrs==25.3.0 # via jsii -cbor2==5.7.0 +cbor2==5.8.0 # via localstack-core -certifi==2025.8.3 +certifi==2026.2.25 # via # httpcore # httpx @@ -78,49 +81,49 @@ certifi==2025.8.3 # requests cffi==2.0.0 # via cryptography -cfgv==3.4.0 +cfgv==3.5.0 # via pre-commit -cfn-lint==1.40.0 +cfn-lint==1.46.0 # via moto-ext -charset-normalizer==3.4.3 +charset-normalizer==3.4.4 # via requests -click==8.3.0 +click==8.3.1 # via + # deptry # localstack-core # localstack-core (pyproject.toml) + # typer colorama==0.4.6 # via awscli constantly==23.10.4 # via localstack-twisted -constructs==10.4.2 +constructs==10.5.1 # via aws-cdk-lib -coverage==6.5.0 +coverage==7.13.4 # via # coveralls # localstack-core -coveralls==3.3.1 +coveralls==4.1.0 # via localstack-core (pyproject.toml) crontab==1.0.5 # via localstack-core -cryptography==46.0.1 +cryptography==46.0.5 # via # joserfc # localstack-core # localstack-core (pyproject.toml) # moto-ext # pyopenssl -cython==3.1.4 +cython==3.2.4 # via localstack-core (pyproject.toml) decorator==5.2.1 # via jsonpath-rw deepdiff==8.6.1 - # via - # localstack-core - # localstack-snapshot + # via localstack-snapshot +deptry==0.24.0 + # via localstack-core (pyproject.toml) dill==0.3.6 - # via - # localstack-core - # localstack-core (pyproject.toml) + # via localstack-core distlib==0.4.0 # via virtualenv dnslib==0.9.26 @@ -136,16 +139,18 @@ docker==7.1.0 # via # localstack-core # moto-ext -docopt==0.6.2 - # via coveralls docutils==0.19 # via awscli events==0.5 # via opensearch-py -filelock==3.19.1 - # via virtualenv -graphql-core==3.2.6 +filelock==3.25.0 + # via + # python-discovery + # virtualenv +graphql-core==3.2.7 # via moto-ext +grpcio==1.78.0 + # via opensearch-protobufs h11==0.16.0 # via # httpcore @@ -162,15 +167,15 @@ httpcore==1.0.9 # via httpx httpx==0.28.1 # via localstack-core -hypercorn==0.17.3 +hypercorn==0.18.0 # via localstack-core hyperframe==6.1.0 # via h2 hyperlink==21.0.0 # via localstack-twisted -identify==2.6.14 +identify==2.6.17 # via pre-commit -idna==3.10 +idna==3.11 # via # anyio # httpx @@ -179,30 +184,32 @@ idna==3.10 # requests importlib-resources==6.5.2 # via jsii -incremental==24.7.2 +incremental==24.11.0 # via localstack-twisted -iniconfig==2.1.0 +iniconfig==2.3.0 # via pytest isodate==0.7.2 # via openapi-core jinja2==3.1.6 - # via moto-ext -jmespath==1.0.1 + # via + # localstack-core + # moto-ext +jmespath==1.1.0 # via # boto3 # botocore -joserfc==1.3.4 +joserfc==1.6.3 # via moto-ext jpype1==1.6.0 # via localstack-core -jsii==1.115.0 +jsii==1.127.0 # via # aws-cdk-asset-awscli-v1 # aws-cdk-asset-node-proxy-agent-v6 # aws-cdk-cloud-assembly-schema # aws-cdk-lib # constructs -json5==0.12.1 +json5==0.13.0 # via localstack-core jsonpatch==1.33 # via @@ -216,10 +223,13 @@ jsonpath-ng==1.7.0 jsonpath-rw==1.4.0 # via localstack-core jsonpointer==3.0.0 - # via jsonpatch -jsonschema==4.25.1 + # via + # jsonpatch + # localstack-core +jsonschema==4.26.0 # via # aws-sam-translator + # localstack-core # moto-ext # openapi-core # openapi-schema-validator @@ -236,9 +246,11 @@ kclpy-ext==3.0.5 # via localstack-core lazy-object-proxy==1.12.0 # via openapi-spec-validator -localstack-snapshot==0.3.0 +librt==0.8.1 + # via mypy +localstack-snapshot==0.3.3 # via localstack-core -localstack-twisted==24.3.0 +localstack-twisted==25.5.0 # via localstack-core markdown-it-py==4.0.0 # via rich @@ -250,23 +262,23 @@ mdurl==0.1.2 # via markdown-it-py more-itertools==10.8.0 # via openapi-core -moto-ext==5.1.13.post18 +moto-ext==5.1.25 # via localstack-core mpmath==1.3.0 # via sympy -multipart==1.3.0 +multipart==1.3.1 # via moto-ext -mypy==1.18.2 +mypy==1.19.1 # via localstack-core (pyproject.toml) mypy-extensions==1.1.0 # via mypy -networkx==3.5 +networkx==3.6.1 # via # cfn-lint # localstack-core (pyproject.toml) -nodeenv==1.9.1 +nodeenv==1.10.0 # via pre-commit -openapi-core==0.19.4 +openapi-core==0.22.0 # via localstack-core openapi-schema-validator==0.6.3 # via @@ -277,34 +289,38 @@ openapi-spec-validator==0.7.2 # localstack-core (pyproject.toml) # moto-ext # openapi-core -opensearch-py==3.0.0 +opensearch-protobufs==0.19.0 + # via opensearch-py +opensearch-py==3.1.0 # via localstack-core orderly-set==5.5.0 # via deepdiff -packaging==25.0 +packaging==26.0 # via # apispec - # build + # deptry + # incremental # jpype1 # pytest # pytest-rerunfailures + # requirements-parser pandoc==2.4 # via localstack-core (pyproject.toml) -parse==1.20.2 - # via openapi-core pathable==0.4.4 # via jsonschema-path -pathspec==0.12.1 +pathspec==1.0.4 # via mypy -platformdirs==4.4.0 - # via virtualenv +platformdirs==4.9.2 + # via + # python-discovery + # virtualenv pluggy==1.6.0 # via # localstack-core # pytest -plumbum==1.9.0 +plumbum==1.10.0 # via pandoc -plux==1.13.0 +plux==1.14.0 # via # localstack-core # localstack-core (pyproject.toml) @@ -313,13 +329,15 @@ ply==3.11 # jsonpath-ng # jsonpath-rw # pandoc -pre-commit==4.3.0 +pre-commit==4.5.1 # via localstack-core (pyproject.toml) priority==1.3.0 # via # hypercorn # localstack-twisted -psutil==7.1.0 +protobuf==7.34.0 + # via opensearch-protobufs +psutil==7.2.2 # via # localstack-core # localstack-core (pyproject.toml) @@ -331,43 +349,44 @@ publication==0.0.3 # aws-cdk-lib # constructs # jsii -py-partiql-parser==0.6.1 +py-partiql-parser==0.6.3 # via moto-ext -pyasn1==0.6.1 +pyasn1==0.6.2 # via rsa -pycparser==2.23 +pycparser==3.0 # via cffi -pydantic==2.11.9 - # via aws-sam-translator -pydantic-core==2.33.2 +pydantic==2.12.5 + # via + # aws-sam-translator + # localstack-core + # openapi-spec-validator +pydantic-core==2.41.5 # via pydantic pygments==2.19.2 # via # pytest # rich -pymongo==4.15.1 +pymongo==4.16.0 # via localstack-core pyopenssl==25.3.0 # via # localstack-core # localstack-twisted -pypandoc==1.15 +pypandoc==1.16.2 # via localstack-core (pyproject.toml) -pyparsing==3.2.5 +pyparsing==3.3.2 # via moto-ext -pyproject-hooks==1.2.0 - # via build -pytest==8.4.2 +pytest==9.0.2 # via # localstack-core # pytest-rerunfailures # pytest-split # pytest-tinybird -pytest-httpserver==1.1.3 +pytest-httpserver==1.1.5 # via localstack-core -pytest-rerunfailures==16.0.1 +pytest-rerunfailures==16.1 # via localstack-core -pytest-split==0.10.0 +pytest-split==0.11.0 # via localstack-core pytest-tinybird==0.5.0 # via localstack-core @@ -375,9 +394,12 @@ python-dateutil==2.9.0.post0 # via # botocore # jsii + # localstack-core # moto-ext # opensearch-py -python-dotenv==1.1.1 +python-discovery==1.1.0 + # via virtualenv +python-dotenv==1.2.2 # via # localstack-core # localstack-core (pyproject.toml) @@ -398,7 +420,7 @@ referencing==0.36.2 # jsonschema # jsonschema-path # jsonschema-specifications -regex==2025.9.18 +regex==2026.2.28 # via cfn-lint requests==2.32.5 # via @@ -415,17 +437,22 @@ requests==2.32.5 # rolo requests-aws4auth==1.3.1 # via localstack-core -responses==0.25.8 - # via moto-ext +requirements-parser==0.13.0 + # via deptry +responses==0.26.0 + # via + # localstack-core + # moto-ext rfc3339-validator==0.1.4 # via openapi-schema-validator -rich==14.1.0 +rich==14.3.3 # via # localstack-core # localstack-core (pyproject.toml) -rolo==0.7.6 + # typer +rolo==0.8.1 # via localstack-core -rpds-py==0.27.1 +rpds-py==0.30.0 # via # jsonschema # referencing @@ -433,9 +460,9 @@ rsa==4.7.2 # via awscli rstr==3.2.2 # via localstack-core (pyproject.toml) -ruff==0.13.2 +ruff==0.15.4 # via localstack-core (pyproject.toml) -s3transfer==0.14.0 +s3transfer==0.16.0 # via # awscli # boto3 @@ -443,20 +470,16 @@ semver==3.0.4 # via # localstack-core # localstack-core (pyproject.toml) +shellingham==1.5.4 + # via typer six==1.17.0 # via # airspeed-ext # jsonpath-rw # python-dateutil # rfc3339-validator -sniffio==1.3.1 - # via anyio sympy==1.14.0 # via cfn-lint -tailer==0.4.1 - # via - # localstack-core - # localstack-core (pyproject.toml) typeguard==2.13.3 # via # aws-cdk-asset-awscli-v1 @@ -465,21 +488,25 @@ typeguard==2.13.3 # aws-cdk-lib # constructs # jsii +typer==0.24.1 + # via coveralls typing-extensions==4.15.0 # via # aws-sam-translator # cattrs # cfn-lint + # grpcio # jsii # localstack-twisted # mypy + # openapi-core # pydantic # pydantic-core # readerwriterlock # typing-inspection -typing-inspection==0.4.1 +typing-inspection==0.4.2 # via pydantic -urllib3==2.5.0 +urllib3==2.6.3 # via # botocore # docker @@ -487,26 +514,28 @@ urllib3==2.5.0 # opensearch-py # requests # responses -virtualenv==20.34.0 +virtualenv==21.1.0 # via pre-commit -websocket-client==1.8.0 +watchdog==6.0.0 + # via localstack-core (pyproject.toml) +websocket-client==1.9.0 # via localstack-core -werkzeug==3.1.3 +werkzeug==3.1.6 # via # localstack-core # moto-ext # openapi-core # pytest-httpserver # rolo -wrapt==1.17.3 +wrapt==2.1.1 # via aws-xray-sdk -wsproto==1.2.0 +wsproto==1.3.2 # via hypercorn -xmltodict==1.0.2 +xmltodict==1.0.4 # via # localstack-core # moto-ext -zope-interface==8.0.1 +zope-interface==8.2 # via localstack-twisted # The following packages are considered to be unsafe in a requirements file: diff --git a/requirements-runtime.txt b/requirements-runtime.txt index af8460d90a512..55d85a384d0cc 100644 --- a/requirements-runtime.txt +++ b/requirements-runtime.txt @@ -2,7 +2,7 @@ # This file is autogenerated by pip-compile with Python 3.13 # by the following command: # -# pip-compile --cert=None --client-cert=None --extra=runtime --index-url=None --output-file=requirements-runtime.txt --pip-args=None --strip-extras --unsafe-package=distribute --unsafe-package=localstack-core --unsafe-package=pip --unsafe-package=setuptools pyproject.toml +# pip-compile --extra=runtime --output-file=requirements-runtime.txt --strip-extras --unsafe-package=distribute --unsafe-package=localstack-core --unsafe-package=pip --unsafe-package=setuptools pyproject.toml # airspeed-ext==0.6.9 # via localstack-core (pyproject.toml) @@ -12,32 +12,37 @@ antlr4-python3-runtime==4.13.2 # via # localstack-core (pyproject.toml) # moto-ext -apispec==6.8.4 +apispec==6.9.0 # via localstack-core (pyproject.toml) argparse==1.4.0 # via kclpy-ext -attrs==25.3.0 +asn1crypto==1.5.1 + # via + # localstack-core + # localstack-core (pyproject.toml) +attrs==25.4.0 # via # jsonschema # localstack-twisted # referencing -aws-sam-translator==1.100.0 +aws-sam-translator==1.107.0 # via # cfn-lint # localstack-core (pyproject.toml) -aws-xray-sdk==2.14.0 + # moto-ext +aws-xray-sdk==2.15.0 # via moto-ext -awscli==1.42.40 +awscli==1.44.49 # via localstack-core (pyproject.toml) -awscrt==0.28.1 +awscrt==0.31.2 # via localstack-core -boto3==1.40.40 +boto3==1.42.59 # via # aws-sam-translator # kclpy-ext # localstack-core # moto-ext -botocore==1.40.40 +botocore==1.42.59 # via # aws-xray-sdk # awscli @@ -45,28 +50,24 @@ botocore==1.40.40 # localstack-core # moto-ext # s3transfer -build==1.3.0 - # via - # localstack-core - # localstack-core (pyproject.toml) -cachetools==6.2.0 +cachetools==7.0.2 # via # airspeed-ext # localstack-core # localstack-core (pyproject.toml) -cbor2==5.7.0 +cbor2==5.8.0 # via localstack-core -certifi==2025.8.3 +certifi==2026.2.25 # via # opensearch-py # requests cffi==2.0.0 # via cryptography -cfn-lint==1.40.0 +cfn-lint==1.46.0 # via moto-ext -charset-normalizer==3.4.3 +charset-normalizer==3.4.4 # via requests -click==8.3.0 +click==8.3.1 # via # localstack-core # localstack-core (pyproject.toml) @@ -76,7 +77,7 @@ constantly==23.10.4 # via localstack-twisted crontab==1.0.5 # via localstack-core (pyproject.toml) -cryptography==46.0.1 +cryptography==46.0.5 # via # joserfc # localstack-core @@ -86,9 +87,7 @@ cryptography==46.0.1 decorator==5.2.1 # via jsonpath-rw dill==0.3.6 - # via - # localstack-core - # localstack-core (pyproject.toml) + # via localstack-core dnslib==0.9.26 # via # localstack-core @@ -106,8 +105,10 @@ docutils==0.19 # via awscli events==0.5 # via opensearch-py -graphql-core==3.2.6 +graphql-core==3.2.7 # via moto-ext +grpcio==1.78.0 + # via opensearch-protobufs h11==0.16.0 # via # hypercorn @@ -118,33 +119,33 @@ h2==4.3.0 # localstack-twisted hpack==4.1.0 # via h2 -hypercorn==0.17.3 +hypercorn==0.18.0 # via localstack-core hyperframe==6.1.0 # via h2 hyperlink==21.0.0 # via localstack-twisted -idna==3.10 +idna==3.11 # via # hyperlink # localstack-twisted # requests -incremental==24.7.2 +incremental==24.11.0 # via localstack-twisted isodate==0.7.2 # via openapi-core jinja2==3.1.6 - # via moto-ext -jmespath==1.0.1 + # via + # localstack-core (pyproject.toml) + # moto-ext +jmespath==1.1.0 # via # boto3 # botocore -joserfc==1.3.4 +joserfc==1.6.3 # via moto-ext jpype1==1.6.0 # via localstack-core (pyproject.toml) -json5==0.12.1 - # via localstack-core (pyproject.toml) jsonpatch==1.33 # via # cfn-lint @@ -156,10 +157,13 @@ jsonpath-ng==1.7.0 jsonpath-rw==1.4.0 # via localstack-core (pyproject.toml) jsonpointer==3.0.0 - # via jsonpatch -jsonschema==4.25.1 + # via + # jsonpatch + # localstack-core +jsonschema==4.26.0 # via # aws-sam-translator + # localstack-core # moto-ext # openapi-core # openapi-schema-validator @@ -176,7 +180,7 @@ kclpy-ext==3.0.5 # via localstack-core (pyproject.toml) lazy-object-proxy==1.12.0 # via openapi-spec-validator -localstack-twisted==24.3.0 +localstack-twisted==25.5.0 # via localstack-core markdown-it-py==4.0.0 # via rich @@ -188,15 +192,15 @@ mdurl==0.1.2 # via markdown-it-py more-itertools==10.8.0 # via openapi-core -moto-ext==5.1.13.post18 +moto-ext==5.1.25 # via localstack-core (pyproject.toml) mpmath==1.3.0 # via sympy -multipart==1.3.0 +multipart==1.3.1 # via moto-ext -networkx==3.5 +networkx==3.6.1 # via cfn-lint -openapi-core==0.19.4 +openapi-core==0.22.0 # via localstack-core openapi-schema-validator==0.6.3 # via @@ -206,18 +210,18 @@ openapi-spec-validator==0.7.2 # via # moto-ext # openapi-core -opensearch-py==3.0.0 +opensearch-protobufs==0.19.0 + # via opensearch-py +opensearch-py==3.1.0 # via localstack-core (pyproject.toml) -packaging==25.0 +packaging==26.0 # via # apispec - # build + # incremental # jpype1 -parse==1.20.2 - # via openapi-core pathable==0.4.4 # via jsonschema-path -plux==1.13.0 +plux==1.14.0 # via # localstack-core # localstack-core (pyproject.toml) @@ -229,39 +233,42 @@ priority==1.3.0 # via # hypercorn # localstack-twisted -psutil==7.1.0 +protobuf==7.34.0 + # via opensearch-protobufs +psutil==7.2.2 # via # localstack-core # localstack-core (pyproject.toml) -py-partiql-parser==0.6.1 +py-partiql-parser==0.6.3 # via moto-ext -pyasn1==0.6.1 +pyasn1==0.6.2 # via rsa -pycparser==2.23 +pycparser==3.0 # via cffi -pydantic==2.11.9 - # via aws-sam-translator -pydantic-core==2.33.2 +pydantic==2.12.5 + # via + # aws-sam-translator + # localstack-core +pydantic-core==2.41.5 # via pydantic pygments==2.19.2 # via rich -pymongo==4.15.1 +pymongo==4.16.0 # via localstack-core (pyproject.toml) pyopenssl==25.3.0 # via # localstack-core # localstack-core (pyproject.toml) # localstack-twisted -pyparsing==3.2.5 +pyparsing==3.3.2 # via moto-ext -pyproject-hooks==1.2.0 - # via build python-dateutil==2.9.0.post0 # via # botocore + # localstack-core # moto-ext # opensearch-py -python-dotenv==1.1.1 +python-dotenv==1.2.2 # via # localstack-core # localstack-core (pyproject.toml) @@ -281,7 +288,7 @@ referencing==0.36.2 # jsonschema # jsonschema-path # jsonschema-specifications -regex==2025.9.18 +regex==2026.2.28 # via cfn-lint requests==2.32.5 # via @@ -296,23 +303,25 @@ requests==2.32.5 # rolo requests-aws4auth==1.3.1 # via localstack-core -responses==0.25.8 - # via moto-ext +responses==0.26.0 + # via + # localstack-core (pyproject.toml) + # moto-ext rfc3339-validator==0.1.4 # via openapi-schema-validator -rich==14.1.0 +rich==14.3.3 # via # localstack-core # localstack-core (pyproject.toml) -rolo==0.7.6 +rolo==0.8.1 # via localstack-core -rpds-py==0.27.1 +rpds-py==0.30.0 # via # jsonschema # referencing rsa==4.7.2 # via awscli -s3transfer==0.14.0 +s3transfer==0.16.0 # via # awscli # boto3 @@ -328,22 +337,20 @@ six==1.17.0 # rfc3339-validator sympy==1.14.0 # via cfn-lint -tailer==0.4.1 - # via - # localstack-core - # localstack-core (pyproject.toml) typing-extensions==4.15.0 # via # aws-sam-translator # cfn-lint + # grpcio # localstack-twisted + # openapi-core # pydantic # pydantic-core # readerwriterlock # typing-inspection -typing-inspection==0.4.1 +typing-inspection==0.4.2 # via pydantic -urllib3==2.5.0 +urllib3==2.6.3 # via # botocore # docker @@ -351,21 +358,21 @@ urllib3==2.5.0 # opensearch-py # requests # responses -werkzeug==3.1.3 +werkzeug==3.1.6 # via # localstack-core # moto-ext # openapi-core # rolo -wrapt==1.17.3 +wrapt==2.1.1 # via aws-xray-sdk -wsproto==1.2.0 +wsproto==1.3.2 # via hypercorn -xmltodict==1.0.2 +xmltodict==1.0.4 # via # localstack-core # moto-ext -zope-interface==8.0.1 +zope-interface==8.2 # via localstack-twisted # The following packages are considered to be unsafe in a requirements file: diff --git a/requirements-test.txt b/requirements-test.txt index 0cb48f0be4181..25d17b3e1118b 100644 --- a/requirements-test.txt +++ b/requirements-test.txt @@ -2,7 +2,7 @@ # This file is autogenerated by pip-compile with Python 3.13 # by the following command: # -# pip-compile --cert=None --client-cert=None --extra=test --index-url=None --output-file=requirements-test.txt --pip-args=None --strip-extras --unsafe-package=distribute --unsafe-package=localstack-core --unsafe-package=pip --unsafe-package=setuptools pyproject.toml +# pip-compile --extra=test --output-file=requirements-test.txt --strip-extras --unsafe-package=distribute --unsafe-package=localstack-core --unsafe-package=pip --unsafe-package=setuptools pyproject.toml # airspeed-ext==0.6.9 # via localstack-core @@ -12,44 +12,49 @@ antlr4-python3-runtime==4.13.2 # via # localstack-core # moto-ext -anyio==4.11.0 +anyio==4.12.1 # via httpx -apispec==6.8.4 +apispec==6.9.0 # via localstack-core argparse==1.4.0 # via kclpy-ext -attrs==25.3.0 +asn1crypto==1.5.1 + # via + # localstack-core + # localstack-core (pyproject.toml) +attrs==25.4.0 # via # cattrs # jsii # jsonschema # localstack-twisted # referencing -aws-cdk-asset-awscli-v1==2.2.242 +aws-cdk-asset-awscli-v1==2.2.263 # via aws-cdk-lib -aws-cdk-asset-node-proxy-agent-v6==2.1.0 +aws-cdk-asset-node-proxy-agent-v6==2.1.1 # via aws-cdk-lib -aws-cdk-cloud-assembly-schema==48.11.0 +aws-cdk-cloud-assembly-schema==52.2.0 # via aws-cdk-lib -aws-cdk-lib==2.218.0 +aws-cdk-lib==2.241.0 # via localstack-core (pyproject.toml) -aws-sam-translator==1.100.0 +aws-sam-translator==1.107.0 # via # cfn-lint # localstack-core -aws-xray-sdk==2.14.0 + # moto-ext +aws-xray-sdk==2.15.0 # via moto-ext -awscli==1.42.40 +awscli==1.44.49 # via localstack-core -awscrt==0.28.1 +awscrt==0.31.2 # via localstack-core -boto3==1.40.40 +boto3==1.42.59 # via # aws-sam-translator # kclpy-ext # localstack-core # moto-ext -botocore==1.40.40 +botocore==1.42.59 # via # aws-xray-sdk # awscli @@ -57,20 +62,16 @@ botocore==1.40.40 # localstack-core # moto-ext # s3transfer -build==1.3.0 - # via - # localstack-core - # localstack-core (pyproject.toml) -cachetools==6.2.0 +cachetools==7.0.2 # via # airspeed-ext # localstack-core # localstack-core (pyproject.toml) -cattrs==25.2.0 +cattrs==25.3.0 # via jsii -cbor2==5.7.0 +cbor2==5.8.0 # via localstack-core -certifi==2025.8.3 +certifi==2026.2.25 # via # httpcore # httpx @@ -78,11 +79,11 @@ certifi==2025.8.3 # requests cffi==2.0.0 # via cryptography -cfn-lint==1.40.0 +cfn-lint==1.46.0 # via moto-ext -charset-normalizer==3.4.3 +charset-normalizer==3.4.4 # via requests -click==8.3.0 +click==8.3.1 # via # localstack-core # localstack-core (pyproject.toml) @@ -90,13 +91,13 @@ colorama==0.4.6 # via awscli constantly==23.10.4 # via localstack-twisted -constructs==10.4.2 +constructs==10.5.1 # via aws-cdk-lib -coverage==7.10.7 +coverage==7.13.4 # via localstack-core (pyproject.toml) crontab==1.0.5 # via localstack-core -cryptography==46.0.1 +cryptography==46.0.5 # via # joserfc # localstack-core @@ -106,13 +107,9 @@ cryptography==46.0.1 decorator==5.2.1 # via jsonpath-rw deepdiff==8.6.1 - # via - # localstack-core (pyproject.toml) - # localstack-snapshot + # via localstack-snapshot dill==0.3.6 - # via - # localstack-core - # localstack-core (pyproject.toml) + # via localstack-core dnslib==0.9.26 # via # localstack-core @@ -130,8 +127,10 @@ docutils==0.19 # via awscli events==0.5 # via opensearch-py -graphql-core==3.2.6 +graphql-core==3.2.7 # via moto-ext +grpcio==1.78.0 + # via opensearch-protobufs h11==0.16.0 # via # httpcore @@ -148,13 +147,13 @@ httpcore==1.0.9 # via httpx httpx==0.28.1 # via localstack-core (pyproject.toml) -hypercorn==0.17.3 +hypercorn==0.18.0 # via localstack-core hyperframe==6.1.0 # via h2 hyperlink==21.0.0 # via localstack-twisted -idna==3.10 +idna==3.11 # via # anyio # httpx @@ -163,31 +162,33 @@ idna==3.10 # requests importlib-resources==6.5.2 # via jsii -incremental==24.7.2 +incremental==24.11.0 # via localstack-twisted -iniconfig==2.1.0 +iniconfig==2.3.0 # via pytest isodate==0.7.2 # via openapi-core jinja2==3.1.6 - # via moto-ext -jmespath==1.0.1 + # via + # localstack-core + # moto-ext +jmespath==1.1.0 # via # boto3 # botocore -joserfc==1.3.4 +joserfc==1.6.3 # via moto-ext jpype1==1.6.0 # via localstack-core -jsii==1.115.0 +jsii==1.127.0 # via # aws-cdk-asset-awscli-v1 # aws-cdk-asset-node-proxy-agent-v6 # aws-cdk-cloud-assembly-schema # aws-cdk-lib # constructs -json5==0.12.1 - # via localstack-core +json5==0.13.0 + # via localstack-core (pyproject.toml) jsonpatch==1.33 # via # cfn-lint @@ -200,10 +201,13 @@ jsonpath-ng==1.7.0 jsonpath-rw==1.4.0 # via localstack-core jsonpointer==3.0.0 - # via jsonpatch -jsonschema==4.25.1 + # via + # jsonpatch + # localstack-core +jsonschema==4.26.0 # via # aws-sam-translator + # localstack-core # moto-ext # openapi-core # openapi-schema-validator @@ -220,9 +224,9 @@ kclpy-ext==3.0.5 # via localstack-core lazy-object-proxy==1.12.0 # via openapi-spec-validator -localstack-snapshot==0.3.0 +localstack-snapshot==0.3.3 # via localstack-core (pyproject.toml) -localstack-twisted==24.3.0 +localstack-twisted==25.5.0 # via localstack-core markdown-it-py==4.0.0 # via rich @@ -234,15 +238,15 @@ mdurl==0.1.2 # via markdown-it-py more-itertools==10.8.0 # via openapi-core -moto-ext==5.1.13.post18 +moto-ext==5.1.25 # via localstack-core mpmath==1.3.0 # via sympy -multipart==1.3.0 +multipart==1.3.1 # via moto-ext -networkx==3.5 +networkx==3.6.1 # via cfn-lint -openapi-core==0.19.4 +openapi-core==0.22.0 # via localstack-core openapi-schema-validator==0.6.3 # via @@ -252,26 +256,26 @@ openapi-spec-validator==0.7.2 # via # moto-ext # openapi-core -opensearch-py==3.0.0 +opensearch-protobufs==0.19.0 + # via opensearch-py +opensearch-py==3.1.0 # via localstack-core orderly-set==5.5.0 # via deepdiff -packaging==25.0 +packaging==26.0 # via # apispec - # build + # incremental # jpype1 # pytest # pytest-rerunfailures -parse==1.20.2 - # via openapi-core pathable==0.4.4 # via jsonschema-path pluggy==1.6.0 # via # localstack-core (pyproject.toml) # pytest -plux==1.13.0 +plux==1.14.0 # via # localstack-core # localstack-core (pyproject.toml) @@ -283,7 +287,9 @@ priority==1.3.0 # via # hypercorn # localstack-twisted -psutil==7.1.0 +protobuf==7.34.0 + # via opensearch-protobufs +psutil==7.2.2 # via # localstack-core # localstack-core (pyproject.toml) @@ -295,41 +301,41 @@ publication==0.0.3 # aws-cdk-lib # constructs # jsii -py-partiql-parser==0.6.1 +py-partiql-parser==0.6.3 # via moto-ext -pyasn1==0.6.1 +pyasn1==0.6.2 # via rsa -pycparser==2.23 +pycparser==3.0 # via cffi -pydantic==2.11.9 - # via aws-sam-translator -pydantic-core==2.33.2 +pydantic==2.12.5 + # via + # aws-sam-translator + # localstack-core +pydantic-core==2.41.5 # via pydantic pygments==2.19.2 # via # pytest # rich -pymongo==4.15.1 +pymongo==4.16.0 # via localstack-core pyopenssl==25.3.0 # via # localstack-core # localstack-twisted -pyparsing==3.2.5 +pyparsing==3.3.2 # via moto-ext -pyproject-hooks==1.2.0 - # via build -pytest==8.4.2 +pytest==9.0.2 # via # localstack-core (pyproject.toml) # pytest-rerunfailures # pytest-split # pytest-tinybird -pytest-httpserver==1.1.3 +pytest-httpserver==1.1.5 # via localstack-core (pyproject.toml) -pytest-rerunfailures==16.0.1 +pytest-rerunfailures==16.1 # via localstack-core (pyproject.toml) -pytest-split==0.10.0 +pytest-split==0.11.0 # via localstack-core (pyproject.toml) pytest-tinybird==0.5.0 # via localstack-core (pyproject.toml) @@ -337,9 +343,10 @@ python-dateutil==2.9.0.post0 # via # botocore # jsii + # localstack-core # moto-ext # opensearch-py -python-dotenv==1.1.1 +python-dotenv==1.2.2 # via # localstack-core # localstack-core (pyproject.toml) @@ -359,7 +366,7 @@ referencing==0.36.2 # jsonschema # jsonschema-path # jsonschema-specifications -regex==2025.9.18 +regex==2026.2.28 # via cfn-lint requests==2.32.5 # via @@ -375,23 +382,25 @@ requests==2.32.5 # rolo requests-aws4auth==1.3.1 # via localstack-core -responses==0.25.8 - # via moto-ext +responses==0.26.0 + # via + # localstack-core + # moto-ext rfc3339-validator==0.1.4 # via openapi-schema-validator -rich==14.1.0 +rich==14.3.3 # via # localstack-core # localstack-core (pyproject.toml) -rolo==0.7.6 +rolo==0.8.1 # via localstack-core -rpds-py==0.27.1 +rpds-py==0.30.0 # via # jsonschema # referencing rsa==4.7.2 # via awscli -s3transfer==0.14.0 +s3transfer==0.16.0 # via # awscli # boto3 @@ -405,14 +414,8 @@ six==1.17.0 # jsonpath-rw # python-dateutil # rfc3339-validator -sniffio==1.3.1 - # via anyio sympy==1.14.0 # via cfn-lint -tailer==0.4.1 - # via - # localstack-core - # localstack-core (pyproject.toml) typeguard==2.13.3 # via # aws-cdk-asset-awscli-v1 @@ -426,15 +429,17 @@ typing-extensions==4.15.0 # aws-sam-translator # cattrs # cfn-lint + # grpcio # jsii # localstack-twisted + # openapi-core # pydantic # pydantic-core # readerwriterlock # typing-inspection -typing-inspection==0.4.1 +typing-inspection==0.4.2 # via pydantic -urllib3==2.5.0 +urllib3==2.6.3 # via # botocore # docker @@ -442,24 +447,24 @@ urllib3==2.5.0 # opensearch-py # requests # responses -websocket-client==1.8.0 +websocket-client==1.9.0 # via localstack-core (pyproject.toml) -werkzeug==3.1.3 +werkzeug==3.1.6 # via # localstack-core # moto-ext # openapi-core # pytest-httpserver # rolo -wrapt==1.17.3 +wrapt==2.1.1 # via aws-xray-sdk -wsproto==1.2.0 +wsproto==1.3.2 # via hypercorn -xmltodict==1.0.2 +xmltodict==1.0.4 # via # localstack-core # moto-ext -zope-interface==8.0.1 +zope-interface==8.2 # via localstack-twisted # The following packages are considered to be unsafe in a requirements file: diff --git a/requirements-typehint.txt b/requirements-typehint.txt index 8e525795fbc39..59571e7a6ca8a 100644 --- a/requirements-typehint.txt +++ b/requirements-typehint.txt @@ -2,56 +2,63 @@ # This file is autogenerated by pip-compile with Python 3.13 # by the following command: # -# pip-compile --cert=None --client-cert=None --extra=typehint --index-url=None --output-file=requirements-typehint.txt --pip-args=None --strip-extras --unsafe-package=distribute --unsafe-package=localstack-core --unsafe-package=pip --unsafe-package=setuptools pyproject.toml +# pip-compile --extra=typehint --output-file=requirements-typehint.txt --strip-extras --unsafe-package=distribute --unsafe-package=localstack-core --unsafe-package=pip --unsafe-package=setuptools pyproject.toml # airspeed-ext==0.6.9 # via localstack-core +annotated-doc==0.0.4 + # via typer annotated-types==0.7.0 # via pydantic antlr4-python3-runtime==4.13.2 # via # localstack-core # moto-ext -anyio==4.11.0 +anyio==4.12.1 # via httpx -apispec==6.8.4 +apispec==6.9.0 # via localstack-core argparse==1.4.0 # via kclpy-ext -attrs==25.3.0 +asn1crypto==1.5.1 + # via + # localstack-core + # localstack-core (pyproject.toml) +attrs==25.4.0 # via # cattrs # jsii # jsonschema # localstack-twisted # referencing -aws-cdk-asset-awscli-v1==2.2.242 +aws-cdk-asset-awscli-v1==2.2.263 # via aws-cdk-lib -aws-cdk-asset-node-proxy-agent-v6==2.1.0 +aws-cdk-asset-node-proxy-agent-v6==2.1.1 # via aws-cdk-lib -aws-cdk-cloud-assembly-schema==48.11.0 +aws-cdk-cloud-assembly-schema==52.2.0 # via aws-cdk-lib -aws-cdk-lib==2.218.0 +aws-cdk-lib==2.241.0 # via localstack-core -aws-sam-translator==1.100.0 +aws-sam-translator==1.107.0 # via # cfn-lint # localstack-core -aws-xray-sdk==2.14.0 + # moto-ext +aws-xray-sdk==2.15.0 # via moto-ext -awscli==1.42.40 +awscli==1.44.49 # via localstack-core -awscrt==0.28.1 +awscrt==0.31.2 # via localstack-core -boto3==1.40.40 +boto3==1.42.59 # via # aws-sam-translator # kclpy-ext # localstack-core # moto-ext -boto3-stubs==1.40.41 +boto3-stubs==1.42.59 # via localstack-core (pyproject.toml) -botocore==1.40.40 +botocore==1.42.59 # via # aws-xray-sdk # awscli @@ -59,22 +66,18 @@ botocore==1.40.40 # localstack-core # moto-ext # s3transfer -botocore-stubs==1.40.33 +botocore-stubs==1.42.41 # via boto3-stubs -build==1.3.0 - # via - # localstack-core - # localstack-core (pyproject.toml) -cachetools==6.2.0 +cachetools==7.0.2 # via # airspeed-ext # localstack-core # localstack-core (pyproject.toml) -cattrs==25.2.0 +cattrs==25.3.0 # via jsii -cbor2==5.7.0 +cbor2==5.8.0 # via localstack-core -certifi==2025.8.3 +certifi==2026.2.25 # via # httpcore # httpx @@ -82,49 +85,49 @@ certifi==2025.8.3 # requests cffi==2.0.0 # via cryptography -cfgv==3.4.0 +cfgv==3.5.0 # via pre-commit -cfn-lint==1.40.0 +cfn-lint==1.46.0 # via moto-ext -charset-normalizer==3.4.3 +charset-normalizer==3.4.4 # via requests -click==8.3.0 +click==8.3.1 # via + # deptry # localstack-core # localstack-core (pyproject.toml) + # typer colorama==0.4.6 # via awscli constantly==23.10.4 # via localstack-twisted -constructs==10.4.2 +constructs==10.5.1 # via aws-cdk-lib -coverage==6.5.0 +coverage==7.13.4 # via # coveralls # localstack-core -coveralls==3.3.1 +coveralls==4.1.0 # via localstack-core crontab==1.0.5 # via localstack-core -cryptography==46.0.1 +cryptography==46.0.5 # via # joserfc # localstack-core # localstack-core (pyproject.toml) # moto-ext # pyopenssl -cython==3.1.4 +cython==3.2.4 # via localstack-core decorator==5.2.1 # via jsonpath-rw deepdiff==8.6.1 - # via - # localstack-core - # localstack-snapshot + # via localstack-snapshot +deptry==0.24.0 + # via localstack-core dill==0.3.6 - # via - # localstack-core - # localstack-core (pyproject.toml) + # via localstack-core distlib==0.4.0 # via virtualenv dnslib==0.9.26 @@ -140,16 +143,18 @@ docker==7.1.0 # via # localstack-core # moto-ext -docopt==0.6.2 - # via coveralls docutils==0.19 # via awscli events==0.5 # via opensearch-py -filelock==3.19.1 - # via virtualenv -graphql-core==3.2.6 +filelock==3.25.0 + # via + # python-discovery + # virtualenv +graphql-core==3.2.7 # via moto-ext +grpcio==1.78.0 + # via opensearch-protobufs h11==0.16.0 # via # httpcore @@ -166,15 +171,15 @@ httpcore==1.0.9 # via httpx httpx==0.28.1 # via localstack-core -hypercorn==0.17.3 +hypercorn==0.18.0 # via localstack-core hyperframe==6.1.0 # via h2 hyperlink==21.0.0 # via localstack-twisted -identify==2.6.14 +identify==2.6.17 # via pre-commit -idna==3.10 +idna==3.11 # via # anyio # httpx @@ -183,30 +188,32 @@ idna==3.10 # requests importlib-resources==6.5.2 # via jsii -incremental==24.7.2 +incremental==24.11.0 # via localstack-twisted -iniconfig==2.1.0 +iniconfig==2.3.0 # via pytest isodate==0.7.2 # via openapi-core jinja2==3.1.6 - # via moto-ext -jmespath==1.0.1 + # via + # localstack-core + # moto-ext +jmespath==1.1.0 # via # boto3 # botocore -joserfc==1.3.4 +joserfc==1.6.3 # via moto-ext jpype1==1.6.0 # via localstack-core -jsii==1.115.0 +jsii==1.127.0 # via # aws-cdk-asset-awscli-v1 # aws-cdk-asset-node-proxy-agent-v6 # aws-cdk-cloud-assembly-schema # aws-cdk-lib # constructs -json5==0.12.1 +json5==0.13.0 # via localstack-core jsonpatch==1.33 # via @@ -220,10 +227,13 @@ jsonpath-ng==1.7.0 jsonpath-rw==1.4.0 # via localstack-core jsonpointer==3.0.0 - # via jsonpatch -jsonschema==4.25.1 + # via + # jsonpatch + # localstack-core +jsonschema==4.26.0 # via # aws-sam-translator + # localstack-core # moto-ext # openapi-core # openapi-schema-validator @@ -240,9 +250,11 @@ kclpy-ext==3.0.5 # via localstack-core lazy-object-proxy==1.12.0 # via openapi-spec-validator -localstack-snapshot==0.3.0 +librt==0.8.1 + # via mypy +localstack-snapshot==0.3.3 # via localstack-core -localstack-twisted==24.3.0 +localstack-twisted==25.5.0 # via localstack-core markdown-it-py==4.0.0 # via rich @@ -254,229 +266,219 @@ mdurl==0.1.2 # via markdown-it-py more-itertools==10.8.0 # via openapi-core -moto-ext==5.1.13.post18 +moto-ext==5.1.25 # via localstack-core mpmath==1.3.0 # via sympy -multipart==1.3.0 +multipart==1.3.1 # via moto-ext -mypy==1.18.2 +mypy==1.19.1 # via localstack-core -mypy-boto3-acm==1.40.0 +mypy-boto3-acm==1.42.3 # via boto3-stubs -mypy-boto3-acm-pca==1.40.1 +mypy-boto3-acm-pca==1.42.3 # via boto3-stubs -mypy-boto3-amplify==1.40.0 +mypy-boto3-amplify==1.42.3 # via boto3-stubs -mypy-boto3-apigateway==1.40.0 +mypy-boto3-apigateway==1.42.3 # via boto3-stubs -mypy-boto3-apigatewayv2==1.40.0 +mypy-boto3-apigatewayv2==1.42.3 # via boto3-stubs -mypy-boto3-appconfig==1.40.0 +mypy-boto3-appconfig==1.42.3 # via boto3-stubs -mypy-boto3-appconfigdata==1.40.0 +mypy-boto3-appconfigdata==1.42.3 # via boto3-stubs -mypy-boto3-application-autoscaling==1.40.0 +mypy-boto3-application-autoscaling==1.42.3 # via boto3-stubs -mypy-boto3-appsync==1.40.0 +mypy-boto3-appsync==1.42.6 # via boto3-stubs -mypy-boto3-athena==1.40.0 +mypy-boto3-athena==1.42.43 # via boto3-stubs -mypy-boto3-autoscaling==1.40.27 +mypy-boto3-autoscaling==1.42.33 # via boto3-stubs -mypy-boto3-backup==1.40.0 +mypy-boto3-backup==1.42.3 # via boto3-stubs -mypy-boto3-batch==1.40.36 +mypy-boto3-batch==1.42.59 # via boto3-stubs -mypy-boto3-ce==1.40.40 +mypy-boto3-ce==1.42.28 # via boto3-stubs -mypy-boto3-cloudcontrol==1.40.0 +mypy-boto3-cloudcontrol==1.42.3 # via boto3-stubs -mypy-boto3-cloudformation==1.40.24 +mypy-boto3-cloudformation==1.42.3 # via boto3-stubs -mypy-boto3-cloudfront==1.40.23 +mypy-boto3-cloudfront==1.42.40 # via boto3-stubs -mypy-boto3-cloudtrail==1.40.0 +mypy-boto3-cloudtrail==1.42.3 # via boto3-stubs -mypy-boto3-cloudwatch==1.40.38 +mypy-boto3-cloudwatch==1.42.56 # via boto3-stubs -mypy-boto3-codebuild==1.40.8 +mypy-boto3-codebuild==1.42.3 # via boto3-stubs -mypy-boto3-codecommit==1.40.18 +mypy-boto3-codecommit==1.42.3 # via boto3-stubs -mypy-boto3-codeconnections==1.40.2 +mypy-boto3-codeconnections==1.42.3 # via boto3-stubs -mypy-boto3-codedeploy==1.40.20 +mypy-boto3-codedeploy==1.42.3 # via boto3-stubs -mypy-boto3-codepipeline==1.40.0 +mypy-boto3-codepipeline==1.42.3 # via boto3-stubs -mypy-boto3-codestar-connections==1.40.18 +mypy-boto3-codestar-connections==1.42.3 # via boto3-stubs -mypy-boto3-cognito-identity==1.40.15 +mypy-boto3-cognito-identity==1.42.3 # via boto3-stubs -mypy-boto3-cognito-idp==1.40.14 +mypy-boto3-cognito-idp==1.42.59 # via boto3-stubs -mypy-boto3-dms==1.40.0 +mypy-boto3-dms==1.42.3 # via boto3-stubs -mypy-boto3-docdb==1.40.16 +mypy-boto3-docdb==1.42.3 # via boto3-stubs -mypy-boto3-dynamodb==1.40.20 +mypy-boto3-dynamodb==1.42.55 # via boto3-stubs -mypy-boto3-dynamodbstreams==1.40.40 +mypy-boto3-dynamodbstreams==1.42.3 # via boto3-stubs -mypy-boto3-ec2==1.40.40 +mypy-boto3-ec2==1.42.58 # via boto3-stubs -mypy-boto3-ecr==1.40.0 +mypy-boto3-ecr==1.42.57 # via boto3-stubs -mypy-boto3-ecs==1.40.29 +mypy-boto3-ecs==1.42.58 # via boto3-stubs -mypy-boto3-efs==1.40.0 +mypy-boto3-efs==1.42.3 # via boto3-stubs -mypy-boto3-eks==1.40.36 +mypy-boto3-eks==1.42.47 # via boto3-stubs -mypy-boto3-elasticache==1.40.19 +mypy-boto3-elasticache==1.42.3 # via boto3-stubs -mypy-boto3-elasticbeanstalk==1.40.15 +mypy-boto3-elasticbeanstalk==1.42.3 # via boto3-stubs -mypy-boto3-elbv2==1.40.0 +mypy-boto3-elbv2==1.42.3 # via boto3-stubs -mypy-boto3-emr==1.40.0 +mypy-boto3-emr==1.42.3 # via boto3-stubs -mypy-boto3-emr-serverless==1.40.0 +mypy-boto3-emr-serverless==1.42.23 # via boto3-stubs -mypy-boto3-es==1.40.15 +mypy-boto3-es==1.42.56 # via boto3-stubs -mypy-boto3-events==1.40.0 +mypy-boto3-events==1.42.3 # via boto3-stubs -mypy-boto3-firehose==1.40.0 +mypy-boto3-firehose==1.42.3 # via boto3-stubs -mypy-boto3-fis==1.40.20 +mypy-boto3-fis==1.42.3 # via boto3-stubs -mypy-boto3-glacier==1.40.18 +mypy-boto3-glacier==1.42.30 # via boto3-stubs -mypy-boto3-glue==1.40.39 +mypy-boto3-glue==1.42.43 # via boto3-stubs -mypy-boto3-iam==1.40.0 +mypy-boto3-iam==1.42.4 # via boto3-stubs -mypy-boto3-identitystore==1.40.18 +mypy-boto3-identitystore==1.42.20 # via boto3-stubs -mypy-boto3-iot==1.40.0 +mypy-boto3-iot==1.42.14 # via boto3-stubs -mypy-boto3-iot-data==1.40.6 +mypy-boto3-iot-data==1.42.3 # via boto3-stubs -mypy-boto3-iotanalytics==1.40.16 +mypy-boto3-iotwireless==1.42.3 # via boto3-stubs -mypy-boto3-iotwireless==1.40.0 +mypy-boto3-kafka==1.42.50 # via boto3-stubs -mypy-boto3-kafka==1.40.18 +mypy-boto3-kinesis==1.42.41 # via boto3-stubs -mypy-boto3-kinesis==1.40.0 +mypy-boto3-kinesisanalyticsv2==1.42.3 # via boto3-stubs -mypy-boto3-kinesisanalytics==1.40.17 +mypy-boto3-kms==1.42.50 # via boto3-stubs -mypy-boto3-kinesisanalyticsv2==1.40.14 +mypy-boto3-lakeformation==1.42.45 # via boto3-stubs -mypy-boto3-kms==1.40.38 +mypy-boto3-lambda==1.42.37 # via boto3-stubs -mypy-boto3-lakeformation==1.40.19 +mypy-boto3-logs==1.42.10 # via boto3-stubs -mypy-boto3-lambda==1.40.7 +mypy-boto3-managedblockchain==1.42.3 # via boto3-stubs -mypy-boto3-logs==1.40.32 +mypy-boto3-mediaconvert==1.42.37 # via boto3-stubs -mypy-boto3-managedblockchain==1.40.15 +mypy-boto3-mq==1.42.3 # via boto3-stubs -mypy-boto3-mediaconvert==1.40.17 +mypy-boto3-mwaa==1.42.3 # via boto3-stubs -mypy-boto3-mediastore==1.40.17 +mypy-boto3-neptune==1.42.57 # via boto3-stubs -mypy-boto3-mq==1.40.23 +mypy-boto3-opensearch==1.42.56 # via boto3-stubs -mypy-boto3-mwaa==1.40.0 +mypy-boto3-organizations==1.42.41 # via boto3-stubs -mypy-boto3-neptune==1.40.38 +mypy-boto3-pi==1.42.3 # via boto3-stubs -mypy-boto3-opensearch==1.40.0 +mypy-boto3-pinpoint==1.42.3 # via boto3-stubs -mypy-boto3-organizations==1.40.27 +mypy-boto3-pipes==1.42.3 # via boto3-stubs -mypy-boto3-pi==1.40.19 +mypy-boto3-rds==1.42.51 # via boto3-stubs -mypy-boto3-pinpoint==1.40.18 +mypy-boto3-rds-data==1.42.3 # via boto3-stubs -mypy-boto3-pipes==1.40.0 +mypy-boto3-redshift==1.42.42 # via boto3-stubs -mypy-boto3-qldb==1.40.16 +mypy-boto3-redshift-data==1.42.3 # via boto3-stubs -mypy-boto3-qldb-session==1.40.19 +mypy-boto3-resource-groups==1.42.3 # via boto3-stubs -mypy-boto3-rds==1.40.29 +mypy-boto3-resourcegroupstaggingapi==1.42.3 # via boto3-stubs -mypy-boto3-rds-data==1.40.0 +mypy-boto3-route53==1.42.6 # via boto3-stubs -mypy-boto3-redshift==1.40.40 +mypy-boto3-route53resolver==1.42.10 # via boto3-stubs -mypy-boto3-redshift-data==1.40.0 +mypy-boto3-s3==1.42.37 # via boto3-stubs -mypy-boto3-resource-groups==1.40.15 +mypy-boto3-s3control==1.42.37 # via boto3-stubs -mypy-boto3-resourcegroupstaggingapi==1.40.17 +mypy-boto3-sagemaker==1.42.49 # via boto3-stubs -mypy-boto3-route53==1.40.23 +mypy-boto3-sagemaker-runtime==1.42.54 # via boto3-stubs -mypy-boto3-route53resolver==1.40.0 +mypy-boto3-secretsmanager==1.42.8 # via boto3-stubs -mypy-boto3-s3==1.40.26 +mypy-boto3-serverlessrepo==1.42.3 # via boto3-stubs -mypy-boto3-s3control==1.40.31 +mypy-boto3-servicediscovery==1.42.3 # via boto3-stubs -mypy-boto3-sagemaker==1.40.27 +mypy-boto3-ses==1.42.3 # via boto3-stubs -mypy-boto3-sagemaker-runtime==1.40.17 +mypy-boto3-sesv2==1.42.13 # via boto3-stubs -mypy-boto3-secretsmanager==1.40.0 +mypy-boto3-sns==1.42.3 # via boto3-stubs -mypy-boto3-serverlessrepo==1.40.17 +mypy-boto3-sqs==1.42.3 # via boto3-stubs -mypy-boto3-servicediscovery==1.40.10 +mypy-boto3-ssm==1.42.54 # via boto3-stubs -mypy-boto3-ses==1.40.20 +mypy-boto3-sso-admin==1.42.41 # via boto3-stubs -mypy-boto3-sesv2==1.40.0 +mypy-boto3-stepfunctions==1.42.3 # via boto3-stubs -mypy-boto3-sns==1.40.1 +mypy-boto3-sts==1.42.3 # via boto3-stubs -mypy-boto3-sqs==1.40.35 +mypy-boto3-timestream-query==1.42.3 # via boto3-stubs -mypy-boto3-ssm==1.40.37 +mypy-boto3-timestream-write==1.42.3 # via boto3-stubs -mypy-boto3-sso-admin==1.40.37 +mypy-boto3-transcribe==1.42.25 # via boto3-stubs -mypy-boto3-stepfunctions==1.40.0 +mypy-boto3-verifiedpermissions==1.42.33 # via boto3-stubs -mypy-boto3-sts==1.40.0 +mypy-boto3-wafv2==1.42.57 # via boto3-stubs -mypy-boto3-timestream-query==1.40.20 - # via boto3-stubs -mypy-boto3-timestream-write==1.40.19 - # via boto3-stubs -mypy-boto3-transcribe==1.40.8 - # via boto3-stubs -mypy-boto3-verifiedpermissions==1.40.24 - # via boto3-stubs -mypy-boto3-wafv2==1.40.16 - # via boto3-stubs -mypy-boto3-xray==1.40.21 +mypy-boto3-xray==1.42.3 # via boto3-stubs mypy-extensions==1.1.0 # via mypy -networkx==3.5 +networkx==3.6.1 # via # cfn-lint # localstack-core -nodeenv==1.9.1 +nodeenv==1.10.0 # via pre-commit -openapi-core==0.19.4 +openapi-core==0.22.0 # via localstack-core openapi-schema-validator==0.6.3 # via @@ -487,34 +489,38 @@ openapi-spec-validator==0.7.2 # localstack-core # moto-ext # openapi-core -opensearch-py==3.0.0 +opensearch-protobufs==0.19.0 + # via opensearch-py +opensearch-py==3.1.0 # via localstack-core orderly-set==5.5.0 # via deepdiff -packaging==25.0 +packaging==26.0 # via # apispec - # build + # deptry + # incremental # jpype1 # pytest # pytest-rerunfailures + # requirements-parser pandoc==2.4 # via localstack-core -parse==1.20.2 - # via openapi-core pathable==0.4.4 # via jsonschema-path -pathspec==0.12.1 +pathspec==1.0.4 # via mypy -platformdirs==4.4.0 - # via virtualenv +platformdirs==4.9.2 + # via + # python-discovery + # virtualenv pluggy==1.6.0 # via # localstack-core # pytest -plumbum==1.9.0 +plumbum==1.10.0 # via pandoc -plux==1.13.0 +plux==1.14.0 # via # localstack-core # localstack-core (pyproject.toml) @@ -523,13 +529,15 @@ ply==3.11 # jsonpath-ng # jsonpath-rw # pandoc -pre-commit==4.3.0 +pre-commit==4.5.1 # via localstack-core priority==1.3.0 # via # hypercorn # localstack-twisted -psutil==7.1.0 +protobuf==7.34.0 + # via opensearch-protobufs +psutil==7.2.2 # via # localstack-core # localstack-core (pyproject.toml) @@ -541,43 +549,44 @@ publication==0.0.3 # aws-cdk-lib # constructs # jsii -py-partiql-parser==0.6.1 +py-partiql-parser==0.6.3 # via moto-ext -pyasn1==0.6.1 +pyasn1==0.6.2 # via rsa -pycparser==2.23 +pycparser==3.0 # via cffi -pydantic==2.11.9 - # via aws-sam-translator -pydantic-core==2.33.2 +pydantic==2.12.5 + # via + # aws-sam-translator + # localstack-core + # openapi-spec-validator +pydantic-core==2.41.5 # via pydantic pygments==2.19.2 # via # pytest # rich -pymongo==4.15.1 +pymongo==4.16.0 # via localstack-core pyopenssl==25.3.0 # via # localstack-core # localstack-twisted -pypandoc==1.15 +pypandoc==1.16.2 # via localstack-core -pyparsing==3.2.5 +pyparsing==3.3.2 # via moto-ext -pyproject-hooks==1.2.0 - # via build -pytest==8.4.2 +pytest==9.0.2 # via # localstack-core # pytest-rerunfailures # pytest-split # pytest-tinybird -pytest-httpserver==1.1.3 +pytest-httpserver==1.1.5 # via localstack-core -pytest-rerunfailures==16.0.1 +pytest-rerunfailures==16.1 # via localstack-core -pytest-split==0.10.0 +pytest-split==0.11.0 # via localstack-core pytest-tinybird==0.5.0 # via localstack-core @@ -585,9 +594,12 @@ python-dateutil==2.9.0.post0 # via # botocore # jsii + # localstack-core # moto-ext # opensearch-py -python-dotenv==1.1.1 +python-discovery==1.1.0 + # via virtualenv +python-dotenv==1.2.2 # via # localstack-core # localstack-core (pyproject.toml) @@ -608,7 +620,7 @@ referencing==0.36.2 # jsonschema # jsonschema-path # jsonschema-specifications -regex==2025.9.18 +regex==2026.2.28 # via cfn-lint requests==2.32.5 # via @@ -625,17 +637,22 @@ requests==2.32.5 # rolo requests-aws4auth==1.3.1 # via localstack-core -responses==0.25.8 - # via moto-ext +requirements-parser==0.13.0 + # via deptry +responses==0.26.0 + # via + # localstack-core + # moto-ext rfc3339-validator==0.1.4 # via openapi-schema-validator -rich==14.1.0 +rich==14.3.3 # via # localstack-core # localstack-core (pyproject.toml) -rolo==0.7.6 + # typer +rolo==0.8.1 # via localstack-core -rpds-py==0.27.1 +rpds-py==0.30.0 # via # jsonschema # referencing @@ -643,9 +660,9 @@ rsa==4.7.2 # via awscli rstr==3.2.2 # via localstack-core -ruff==0.13.2 +ruff==0.15.4 # via localstack-core -s3transfer==0.14.0 +s3transfer==0.16.0 # via # awscli # boto3 @@ -653,20 +670,16 @@ semver==3.0.4 # via # localstack-core # localstack-core (pyproject.toml) +shellingham==1.5.4 + # via typer six==1.17.0 # via # airspeed-ext # jsonpath-rw # python-dateutil # rfc3339-validator -sniffio==1.3.1 - # via anyio sympy==1.14.0 # via cfn-lint -tailer==0.4.1 - # via - # localstack-core - # localstack-core (pyproject.toml) typeguard==2.13.3 # via # aws-cdk-asset-awscli-v1 @@ -675,25 +688,29 @@ typeguard==2.13.3 # aws-cdk-lib # constructs # jsii -types-awscrt==0.27.6 +typer==0.24.1 + # via coveralls +types-awscrt==0.31.2 # via botocore-stubs -types-s3transfer==0.13.1 +types-s3transfer==0.16.0 # via boto3-stubs typing-extensions==4.15.0 # via # aws-sam-translator # cattrs # cfn-lint + # grpcio # jsii # localstack-twisted # mypy + # openapi-core # pydantic # pydantic-core # readerwriterlock # typing-inspection -typing-inspection==0.4.1 +typing-inspection==0.4.2 # via pydantic -urllib3==2.5.0 +urllib3==2.6.3 # via # botocore # docker @@ -701,26 +718,28 @@ urllib3==2.5.0 # opensearch-py # requests # responses -virtualenv==20.34.0 +virtualenv==21.1.0 # via pre-commit -websocket-client==1.8.0 +watchdog==6.0.0 + # via localstack-core +websocket-client==1.9.0 # via localstack-core -werkzeug==3.1.3 +werkzeug==3.1.6 # via # localstack-core # moto-ext # openapi-core # pytest-httpserver # rolo -wrapt==1.17.3 +wrapt==2.1.1 # via aws-xray-sdk -wsproto==1.2.0 +wsproto==1.3.2 # via hypercorn -xmltodict==1.0.2 +xmltodict==1.0.4 # via # localstack-core # moto-ext -zope-interface==8.0.1 +zope-interface==8.2 # via localstack-twisted # The following packages are considered to be unsafe in a requirements file: diff --git a/scripts/metrics_coverage/diff_metrics_coverage.py b/scripts/metrics_coverage/diff_metrics_coverage.py index 1036dfa5283b6..0ab708b298958 100644 --- a/scripts/metrics_coverage/diff_metrics_coverage.py +++ b/scripts/metrics_coverage/diff_metrics_coverage.py @@ -213,7 +213,7 @@ def create_readable_report( if additional_test_details: fd.write("

Additional Test Coverage

\n") fd.write( - "
Note: this is probalby wrong usage of the script. It includes operations that have been covered with the acceptance tests only" + "
Note: this is probably wrong usage of the script. It includes operations that have been covered with the acceptance tests only" ) fd.write(f"

{additional_test_details}

\n") fd.write("") diff --git a/scripts/update_cfn_resources.py b/scripts/update_cfn_resources.py index ff318384fd682..55d5322a99239 100644 --- a/scripts/update_cfn_resources.py +++ b/scripts/update_cfn_resources.py @@ -16,7 +16,6 @@ """ import argparse -import logging import sys from collections.abc import Iterable from pathlib import Path @@ -24,8 +23,6 @@ import boto3 from botocore.exceptions import ClientError -LOG = logging.getLogger(__name__) - REPO_ROOT = Path(__file__).resolve().parents[1] DEFAULT_RESOURCE_FILE = ( REPO_ROOT / "localstack-core" / "localstack" / "services" / "cloudformation" / "resources.py" @@ -60,7 +57,7 @@ def collect_region_resource_types( params["NextToken"] = token response = client.list_types(**params) except ClientError as exc: - LOG.warning("Skipping region %s due to error while listing types: %s", region, exc) + print(f"Skipping region {region} due to error while listing types: {exc}") succeeded = False break @@ -162,19 +159,22 @@ def main() -> int: try: session = boto3.session.Session(**session_kwargs) except Exception as exc: - LOG.error("Failed to create boto3 session: %s", exc) + print(f"Failed to create boto3 session: {exc}") return 1 regions = get_regions(session, args.regions) if not regions: - LOG.error("Could not determine any regions to scan.") + print("Could not determine any regions to scan.") return 1 + print(f"Scanning CloudFormation resource types in {len(regions)} regions") resources, successful_regions = collect_all_resource_types(session, regions) if not resources: - LOG.error("No CloudFormation resources were discovered.") + print("No CloudFormation resources were discovered.") return 1 + print(f"Collected {len(resources)} resources across {len(successful_regions)} regions:") + print("Updating resource file...") content = render_resource_file(resources, successful_regions) if args.dry_run: diff --git a/tests/aws/conftest.py b/tests/aws/conftest.py index 94a19b8a2dd65..b6727d15b976a 100644 --- a/tests/aws/conftest.py +++ b/tests/aws/conftest.py @@ -7,6 +7,7 @@ from localstack import config as localstack_config from localstack import constants +from localstack.testing import config as test_config from localstack.testing.snapshots.transformer_utility import ( SNAPSHOT_BASIC_TRANSFORMER, SNAPSHOT_BASIC_TRANSFORMER_NEW, @@ -26,6 +27,26 @@ def pytest_configure(config: Config): def pytest_runtestloop(session): + """ + This pytest plugin allows us to pre-install external dependencies that are usually lazy-loaded by the services. + This helps us surface download issues earlier. + This is not needed if we are running the test against an external instance, as it installs the dependencies on the + runner running the tests. + """ + if not session.items: + return + + if session.config.option.collectonly: + return + + if test_config.TEST_SKIP_LOCALSTACK_START: + return + + from localstack.testing.aws.util import is_aws_cloud + + if is_aws_cloud() and not test_config.TEST_FORCE_LOCALSTACK_START: + return + # second pytest lifecycle hook (before test runner starts) test_init_functions = set() @@ -56,12 +77,6 @@ def pytest_runtestloop(session): test_init_functions.add(transcribe_install_async) - if not session.items: - return - - if session.config.option.collectonly: - return - for fn in test_init_functions: fn() @@ -143,3 +158,19 @@ def snapshot(request, _snapshot_session: SnapshotSession, account_id, region_nam _snapshot_session.add_transformer(SNAPSHOT_BASIC_TRANSFORMER_NEW, priority=2) return _snapshot_session + + +@pytest.hookimpl() +def pytest_addhooks(pluginmanager): + try: + # This is only relevant when running Community Tests against Pro pipeline + from localstack.pro.core.testing.pytest.store import StoreSerializationCheckerPlugin + + from localstack.testing.aws.util import is_aws_cloud + + if not test_config.TEST_SKIP_LOCALSTACK_START and not is_aws_cloud(): + # this directly accesses LocalStack state in memory, so it is not worth running in tests against external + # instances + pluginmanager.register(StoreSerializationCheckerPlugin(with_pickle=False)) + except ImportError: + pass diff --git a/tests/aws/scenario/bookstore/test_bookstore.py b/tests/aws/scenario/bookstore/test_bookstore.py index e707c91f509fa..f22da4da2e745 100644 --- a/tests/aws/scenario/bookstore/test_bookstore.py +++ b/tests/aws/scenario/bookstore/test_bookstore.py @@ -220,10 +220,12 @@ def _sort_hits(snapshot_content: dict, *args) -> dict: snapshot.add_transformer(GenericTransformer(_sort_hits)) snapshot.add_transformer( KeyValueBasedTransformer( - lambda k, v: v - if k in ("took", "max_score", "_score") - and (isinstance(v, float) or isinstance(v, int)) - else None, + lambda k, v: ( + v + if k in ("took", "max_score", "_score") + and (isinstance(v, float) or isinstance(v, int)) + else None + ), replacement="", replace_reference=False, ) diff --git a/tests/aws/scenario/loan_broker/test_loan_broker.py b/tests/aws/scenario/loan_broker/test_loan_broker.py index 4eb105c440398..f356437d06e8a 100644 --- a/tests/aws/scenario/loan_broker/test_loan_broker.py +++ b/tests/aws/scenario/loan_broker/test_loan_broker.py @@ -82,10 +82,8 @@ def infrastructure(self, aws_client, infrastructure_setup): @markers.aws.validated @markers.snapshot.skip_snapshot_verify( paths=[ - "$..Table.DeletionProtectionEnabled", "$..Table.ProvisionedThroughput.LastDecreaseDateTime", "$..Table.ProvisionedThroughput.LastIncreaseDateTime", - "$..Table.Replicas", ] ) def test_prefill_dynamodb_table(self, aws_client, infrastructure, snapshot): @@ -166,7 +164,13 @@ def test_prefill_dynamodb_table(self, aws_client, infrastructure, snapshot): ) @markers.aws.validated @markers.snapshot.skip_snapshot_verify( - paths=["$..traceHeader", "$..cause"] + paths=[ + "$..traceHeader", + "$..cause", + "$..redriveCount", + "$..redriveStatus", + "$..redriveStatusReason", + ] ) # TODO add missing properties def test_stepfunctions_input_recipient_list( self, aws_client, infrastructure, step_function_input, expected_result, snapshot diff --git a/tests/aws/scenario/loan_broker/test_loan_broker.snapshot.json b/tests/aws/scenario/loan_broker/test_loan_broker.snapshot.json index ad5837f072b94..9f244762e2228 100644 --- a/tests/aws/scenario/loan_broker/test_loan_broker.snapshot.json +++ b/tests/aws/scenario/loan_broker/test_loan_broker.snapshot.json @@ -1,6 +1,6 @@ { "tests/aws/scenario/loan_broker/test_loan_broker.py::TestLoanBrokerScenario::test_stepfunctions_input_recipient_list[step_function_input0-SUCCEEDED]": { - "recorded-date": "02-08-2023, 11:58:05", + "recorded-date": "13-10-2025, 18:55:01", "recorded-content": { "describe-execution-finished": { "executionArn": "", @@ -52,6 +52,9 @@ "outputDetails": { "included": true }, + "redriveCount": 0, + "redriveStatus": "NOT_REDRIVABLE", + "redriveStatusReason": "Execution is SUCCEEDED and cannot be redriven", "startDate": "datetime", "stateMachineArn": "", "status": "SUCCEEDED", @@ -65,7 +68,7 @@ } }, "tests/aws/scenario/loan_broker/test_loan_broker.py::TestLoanBrokerScenario::test_stepfunctions_input_recipient_list[step_function_input1-SUCCEEDED]": { - "recorded-date": "02-08-2023, 11:58:07", + "recorded-date": "13-10-2025, 18:55:03", "recorded-content": { "describe-execution-finished": { "executionArn": "", @@ -108,6 +111,9 @@ "outputDetails": { "included": true }, + "redriveCount": 0, + "redriveStatus": "NOT_REDRIVABLE", + "redriveStatusReason": "Execution is SUCCEEDED and cannot be redriven", "startDate": "datetime", "stateMachineArn": "", "status": "SUCCEEDED", @@ -121,7 +127,7 @@ } }, "tests/aws/scenario/loan_broker/test_loan_broker.py::TestLoanBrokerScenario::test_stepfunctions_input_recipient_list[step_function_input2-FAILED]": { - "recorded-date": "02-08-2023, 11:58:10", + "recorded-date": "13-10-2025, 18:55:04", "recorded-content": { "describe-execution-finished": { "cause": "An error occurred while executing the state 'Get Credit Score from credit bureau' (entered at the event id #2). The JSONPath '$.Payload.body.score' specified for the field 'Score.$' could not be found in the input ''", @@ -136,6 +142,8 @@ "included": true }, "name": "", + "redriveCount": 0, + "redriveStatus": "REDRIVABLE", "startDate": "datetime", "stateMachineArn": "", "status": "FAILED", @@ -149,7 +157,7 @@ } }, "tests/aws/scenario/loan_broker/test_loan_broker.py::TestLoanBrokerScenario::test_stepfunctions_input_recipient_list[step_function_input3-FAILED]": { - "recorded-date": "02-08-2023, 11:58:10", + "recorded-date": "13-10-2025, 18:55:05", "recorded-content": { "describe-execution-finished": { "cause": "An error occurred while executing the state 'Get Credit Score from credit bureau' (entered at the event id #2). The JSONPath '$.SSN' specified for the field 'SSN.$' could not be found in the input ''", @@ -162,6 +170,8 @@ "included": true }, "name": "", + "redriveCount": 0, + "redriveStatus": "REDRIVABLE", "startDate": "datetime", "stateMachineArn": "", "status": "FAILED", @@ -175,7 +185,7 @@ } }, "tests/aws/scenario/loan_broker/test_loan_broker.py::TestLoanBrokerScenario::test_stepfunctions_input_recipient_list[step_function_input4-FAILED]": { - "recorded-date": "02-08-2023, 11:58:13", + "recorded-date": "13-10-2025, 18:55:07", "recorded-content": { "describe-execution-finished": { "cause": "An error occurred while executing the state 'Get all bank quotes' (entered at the event id #12). The JSONPath '$.Amount' specified for the field 'Amount.$' could not be found in the input ''", @@ -188,6 +198,8 @@ "included": true }, "name": "", + "redriveCount": 0, + "redriveStatus": "REDRIVABLE", "startDate": "datetime", "stateMachineArn": "", "status": "FAILED", @@ -201,7 +213,7 @@ } }, "tests/aws/scenario/loan_broker/test_loan_broker.py::TestLoanBrokerScenario::test_prefill_dynamodb_table": { - "recorded-date": "24-08-2023, 16:33:21", + "recorded-date": "13-10-2025, 18:54:57", "recorded-content": { "describe_table": { "Table": { @@ -233,7 +245,12 @@ "TableId": "", "TableName": "LoanBrokerBanksTable", "TableSizeBytes": 0, - "TableStatus": "ACTIVE" + "TableStatus": "ACTIVE", + "WarmThroughput": { + "ReadUnitsPerSecond": 12000, + "Status": "ACTIVE", + "WriteUnitsPerSecond": 4000 + } }, "ResponseMetadata": { "HTTPHeaders": {}, diff --git a/tests/aws/scenario/loan_broker/test_loan_broker.validation.json b/tests/aws/scenario/loan_broker/test_loan_broker.validation.json index 21a07e5f891df..3b0ba70982865 100644 --- a/tests/aws/scenario/loan_broker/test_loan_broker.validation.json +++ b/tests/aws/scenario/loan_broker/test_loan_broker.validation.json @@ -1,20 +1,56 @@ { "tests/aws/scenario/loan_broker/test_loan_broker.py::TestLoanBrokerScenario::test_prefill_dynamodb_table": { - "last_validated_date": "2023-08-24T14:33:21+00:00" + "last_validated_date": "2025-10-13T18:54:57+00:00", + "durations_in_seconds": { + "setup": 64.27, + "call": 1.44, + "teardown": 0.0, + "total": 65.71 + } }, "tests/aws/scenario/loan_broker/test_loan_broker.py::TestLoanBrokerScenario::test_stepfunctions_input_recipient_list[step_function_input0-SUCCEEDED]": { - "last_validated_date": "2023-08-02T09:58:05+00:00" + "last_validated_date": "2025-10-13T18:55:01+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 3.37, + "teardown": 0.0, + "total": 3.37 + } }, "tests/aws/scenario/loan_broker/test_loan_broker.py::TestLoanBrokerScenario::test_stepfunctions_input_recipient_list[step_function_input1-SUCCEEDED]": { - "last_validated_date": "2023-08-02T09:58:07+00:00" + "last_validated_date": "2025-10-13T18:55:03+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 1.85, + "teardown": 0.0, + "total": 1.85 + } }, "tests/aws/scenario/loan_broker/test_loan_broker.py::TestLoanBrokerScenario::test_stepfunctions_input_recipient_list[step_function_input2-FAILED]": { - "last_validated_date": "2023-08-02T09:58:10+00:00" + "last_validated_date": "2025-10-13T18:55:04+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 1.74, + "teardown": 0.0, + "total": 1.74 + } }, "tests/aws/scenario/loan_broker/test_loan_broker.py::TestLoanBrokerScenario::test_stepfunctions_input_recipient_list[step_function_input3-FAILED]": { - "last_validated_date": "2023-08-02T09:58:10+00:00" + "last_validated_date": "2025-10-13T18:55:05+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.61, + "teardown": 0.0, + "total": 0.61 + } }, "tests/aws/scenario/loan_broker/test_loan_broker.py::TestLoanBrokerScenario::test_stepfunctions_input_recipient_list[step_function_input4-FAILED]": { - "last_validated_date": "2023-08-02T09:58:13+00:00" + "last_validated_date": "2025-10-13T18:56:43+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 1.85, + "teardown": 96.39, + "total": 98.24 + } } } diff --git a/tests/aws/scenario/note_taking/test_note_taking.py b/tests/aws/scenario/note_taking/test_note_taking.py index 492e3c1aa0946..96a2778a619bc 100644 --- a/tests/aws/scenario/note_taking/test_note_taking.py +++ b/tests/aws/scenario/note_taking/test_note_taking.py @@ -162,11 +162,8 @@ def _create_lambdas(): paths=[ "$..Tags", "$..get_resources.items", # TODO apigateway.get-resources - "$..Table.DeletionProtectionEnabled", "$..Table.ProvisionedThroughput.LastDecreaseDateTime", "$..Table.ProvisionedThroughput.LastIncreaseDateTime", - "$..Table.Replicas", - "$..Table.WarmThroughput", ] ) def test_validate_infra_setup(self, aws_client, infrastructure, snapshot): diff --git a/tests/aws/services/acm/test_acm.py b/tests/aws/services/acm/test_acm.py index 616d6c46108ee..e3e25e096f65e 100644 --- a/tests/aws/services/acm/test_acm.py +++ b/tests/aws/services/acm/test_acm.py @@ -1,4 +1,5 @@ import pytest +from botocore.exceptions import ClientError from localstack_snapshot.snapshots.transformer import SortingTransformer from moto import settings as moto_settings @@ -6,7 +7,7 @@ from localstack.testing.pytest import markers from localstack.utils.crypto import generate_ssl_cert from localstack.utils.strings import short_uid -from localstack.utils.sync import retry +from localstack.utils.sync import retry, wait_until class TestACM: @@ -27,7 +28,7 @@ class TestACM: ] ) def test_import_certificate(self, tmp_path, aws_client, cleanups, snapshot): - with pytest.raises(Exception) as exc_info: + with pytest.raises(ClientError) as exc_info: aws_client.acm.import_certificate(Certificate=b"CERT123", PrivateKey=b"KEY123") assert exc_info.value.response["Error"]["Code"] == "ValidationException" @@ -72,9 +73,19 @@ def test_domain_validation(self, acm_request_certificate, aws_client, snapshot): snapshot.add_transformer(snapshot.transform.key_value("SignatureAlgorithm")) certificate_arn = acm_request_certificate()["CertificateArn"] + + # we are manually waiting for some fields to be returned, as they are missing soon after creating the cert + def _cert_has_required_fields() -> bool: + _resp = aws_client.acm.describe_certificate(CertificateArn=certificate_arn) + return "DomainName" in _resp["Certificate"] + + if is_aws_cloud(): + wait_until(_cert_has_required_fields, wait=2, max_retries=20) + result = aws_client.acm.describe_certificate(CertificateArn=certificate_arn) snapshot.match("describe-certificate", result) + @markers.requires_in_process @markers.aws.needs_fixing def test_boto_wait_for_certificate_validation( self, acm_request_certificate, aws_client, monkeypatch @@ -84,8 +95,17 @@ def test_boto_wait_for_certificate_validation( waiter = aws_client.acm.get_waiter("certificate_validated") waiter.wait(CertificateArn=certificate_arn, WaiterConfig={"Delay": 0.5, "MaxAttempts": 3}) - @markers.aws.validated - @markers.snapshot.skip_snapshot_verify(paths=["$..Certificate.SignatureAlgorithm"]) + @markers.aws.manual_setup_required + # this test requires manual input to our DNS provider + @markers.snapshot.skip_snapshot_verify( + paths=[ + "$..Certificate.SignatureAlgorithm", + # those should also be returned by AWS, but regenerating the snapshots needs manual input + # skipped for now, validated by other tests + "$..Certificate.Options.Export", + "$..Exported", + ] + ) def test_certificate_for_subdomain_wildcard( self, acm_request_certificate, aws_client, snapshot, monkeypatch ): @@ -123,7 +143,7 @@ def _get_cert_with_records(): if is_aws_cloud(): # Wait until DNS entry has been added (needs to be done manually!) # Note: When running parity tests against AWS, we need to add the CNAME record to our DNS - # server (currently with gandi.net), to enable validation of the certificate. + # server (currently with Route53), to enable validation of the certificate. prompt = ( f"Please add the following CNAME entry to the LocalStack DNS server, then hit [ENTER] once " f"the certificate has been validated in AWS: {dns_options['Name']} = {dns_options['Value']}" @@ -161,6 +181,7 @@ def _get_cert_issued(): "$..ResourceRecord", "$..SignatureAlgorithm", "$..Serial", + "$..ExportOption", ] ) def test_create_certificate_for_multiple_alternative_domains( @@ -206,3 +227,106 @@ def _certificate_ready(): cert_description["DomainValidationOptions"], key=lambda x: x["DomainName"] ) snapshot.match("describe-cert", cert_description) + + @markers.aws.validated + @markers.snapshot.skip_snapshot_verify( + paths=[ + "$..CreatedAt", + "$..Exported", + "$..ExportOption", + "$..ExtendedKeyUsages", + "$..KeyUsages", + ] + ) + def test_list_certificates_with_key_types_filter_imported_certificate( + self, tmp_path, aws_client, cleanups, snapshot + ): + _, cert_file, key_file = generate_ssl_cert(target_file=str(tmp_path / "cert")) + with open(key_file, "rb") as infile: + private_key_bytes = infile.read() + with open(cert_file, "rb") as infile: + certificate_bytes = infile.read() + + import_response = aws_client.acm.import_certificate( + Certificate=certificate_bytes, PrivateKey=private_key_bytes + ) + cert_arn = import_response["CertificateArn"] + cleanups.append(lambda: aws_client.acm.delete_certificate(CertificateArn=cert_arn)) + + cert_id = cert_arn.split("certificate/")[-1] + snapshot.add_transformer(snapshot.transform.regex(cert_id, "")) + + def _certificate_ready(): + response = aws_client.acm.describe_certificate(CertificateArn=cert_arn) + # expecting FAILED on aws due to not requesting a valid certificate + # expecting ISSUED as default response from moto + if response["Certificate"]["Status"] not in ["FAILED", "ISSUED"]: + raise Exception("Certificate not yet ready") + + retry(_certificate_ready, sleep=1, retries=30) + + def _list_response(): + response = aws_client.acm.list_certificates( + Includes={ + "keyTypes": [ + "RSA_1024", + "RSA_2048", + "RSA_3072", + "RSA_4096", + "EC_prime256v1", + "EC_secp384r1", + "EC_secp521r1", + ] + } + ) + + cert = next( + filter( + lambda c: c["CertificateArn"] == cert_arn, response["CertificateSummaryList"] + ) + ) + snapshot.match("list-certificates-with-key-types", cert) + + retry(_list_response, sleep=1, retries=30) + + @markers.aws.validated + @markers.snapshot.skip_snapshot_verify( + paths=[ + "$..CertificateSummaryList..DomainName", + "$..CertificateSummaryList..SubjectAlternativeNameSummaries", + ] + ) + def test_list_certificates_with_key_types_filter_requested_certificate( + self, acm_request_certificate, aws_client, snapshot + ): + create_response = acm_request_certificate() + cert_arn = create_response["CertificateArn"] + + cert_id = cert_arn.split("certificate/")[-1] + snapshot.add_transformer(snapshot.transform.regex(cert_id, "")) + + def _certificate_ready(): + response = aws_client.acm.describe_certificate(CertificateArn=cert_arn) + assert response["Certificate"]["Status"] in ["PENDING_VALIDATION", "ISSUED", "FAILED"] + return response + + retry(_certificate_ready, sleep=1, retries=30) + + list_response = aws_client.acm.list_certificates( + Includes={ + "keyTypes": [ + "RSA_1024", + "RSA_2048", + "RSA_3072", + "RSA_4096", + "EC_prime256v1", + "EC_secp384r1", + "EC_secp521r1", + ] + } + ) + + cert_arns = [cert["CertificateArn"] for cert in list_response["CertificateSummaryList"]] + assert cert_arn in cert_arns + + snapshot.match("list-certificates-with-key-types", list_response) diff --git a/tests/aws/services/acm/test_acm.snapshot.json b/tests/aws/services/acm/test_acm.snapshot.json index 7b68ad84f0ef6..64465322c4417 100644 --- a/tests/aws/services/acm/test_acm.snapshot.json +++ b/tests/aws/services/acm/test_acm.snapshot.json @@ -139,19 +139,21 @@ } }, "tests/aws/services/acm/test_acm.py::TestACM::test_create_certificate_for_multiple_alternative_domains": { - "recorded-date": "09-01-2024, 14:58:14", + "recorded-date": "14-10-2025, 09:18:38", "recorded-content": { "list-cert-summary-list": { "CertificateArn": "arn::acm::111111111111:certificate/", "CreatedAt": "datetime", "DomainName": "test.example.com", + "ExportOption": "DISABLED", + "Exported": false, "ExtendedKeyUsages": [], "HasAdditionalSubjectAlternativeNames": false, "InUse": false, "KeyAlgorithm": "RSA-2048", "KeyUsages": [], "RenewalEligibility": "INELIGIBLE", - "Status": "FAILED", + "Status": "PENDING_VALIDATION", "SubjectAlternativeNameSummaries": [ "*.test.example.com", "another.domain.com", @@ -201,7 +203,8 @@ "KeyAlgorithm": "RSA-2048", "KeyUsages": [], "Options": { - "CertificateTransparencyLoggingPreference": "ENABLED" + "CertificateTransparencyLoggingPreference": "ENABLED", + "Export": "DISABLED" }, "RenewalEligibility": "INELIGIBLE", "SignatureAlgorithm": "SHA256WITHRSA", @@ -218,7 +221,7 @@ } }, "tests/aws/services/acm/test_acm.py::TestACM::test_import_certificate": { - "recorded-date": "22-02-2024, 17:41:15", + "recorded-date": "14-10-2025, 09:17:56", "recorded-content": { "import-certificate-response": { "CertificateArn": "arn::acm::111111111111:certificate/", @@ -270,7 +273,8 @@ "NotAfter": "datetime", "NotBefore": "datetime", "Options": { - "CertificateTransparencyLoggingPreference": "DISABLED" + "CertificateTransparencyLoggingPreference": "DISABLED", + "Export": "DISABLED" }, "RenewalEligibility": "INELIGIBLE", "Serial": "03:e9", @@ -293,7 +297,7 @@ } }, "tests/aws/services/acm/test_acm.py::TestACM::test_domain_validation": { - "recorded-date": "12-04-2024, 15:36:37", + "recorded-date": "14-10-2025, 09:31:48", "recorded-content": { "describe-certificate": { "Certificate": { @@ -315,7 +319,8 @@ "KeyAlgorithm": "RSA-2048", "KeyUsages": [], "Options": { - "CertificateTransparencyLoggingPreference": "ENABLED" + "CertificateTransparencyLoggingPreference": "ENABLED", + "Export": "DISABLED" }, "RenewalEligibility": "INELIGIBLE", "SignatureAlgorithm": "", @@ -332,5 +337,69 @@ } } } + }, + "tests/aws/services/acm/test_acm.py::TestACM::test_list_certificates_with_key_types_filter_imported_certificate": { + "recorded-date": "09-12-2025, 12:36:59", + "recorded-content": { + "list-certificates-with-key-types": { + "CertificateArn": "arn::acm::111111111111:certificate/", + "CreatedAt": "datetime", + "DomainName": "localhost", + "ExportOption": "DISABLED", + "ExtendedKeyUsages": [ + "TLS_WEB_SERVER_AUTHENTICATION" + ], + "HasAdditionalSubjectAlternativeNames": false, + "ImportedAt": "datetime", + "InUse": false, + "KeyAlgorithm": "RSA-2048", + "KeyUsages": [ + "DIGITAL_SIGNATURE", + "NON_REPUDIATION", + "KEY_ENCIPHERMENT" + ], + "NotAfter": "datetime", + "NotBefore": "datetime", + "RenewalEligibility": "INELIGIBLE", + "Status": "ISSUED", + "SubjectAlternativeNameSummaries": [ + "localhost", + "test.localhost.atlassian.io", + "localhost.localstack.cloud", + "localhost.localstack.cloudIP:127.0.0.1" + ], + "Type": "IMPORTED" + } + } + }, + "tests/aws/services/acm/test_acm.py::TestACM::test_list_certificates_with_key_types_filter_requested_certificate": { + "recorded-date": "03-12-2025, 04:02:40", + "recorded-content": { + "list-certificates-with-key-types": { + "CertificateSummaryList": [ + { + "CertificateArn": "arn::acm::111111111111:certificate/", + "CreatedAt": "datetime", + "DomainName": "test-domain-2b60e4d1.localhost.localstack.cloud", + "Exported": false, + "ExtendedKeyUsages": [], + "HasAdditionalSubjectAlternativeNames": false, + "InUse": false, + "KeyAlgorithm": "RSA-2048", + "KeyUsages": [], + "RenewalEligibility": "INELIGIBLE", + "Status": "PENDING_VALIDATION", + "SubjectAlternativeNameSummaries": [ + "test-domain-2b60e4d1.localhost.localstack.cloud" + ], + "Type": "AMAZON_ISSUED" + } + ], + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } } } diff --git a/tests/aws/services/acm/test_acm.validation.json b/tests/aws/services/acm/test_acm.validation.json index 8201f405c3e71..032ea2a286ae4 100644 --- a/tests/aws/services/acm/test_acm.validation.json +++ b/tests/aws/services/acm/test_acm.validation.json @@ -3,12 +3,39 @@ "last_validated_date": "2023-04-18T17:01:27+00:00" }, "tests/aws/services/acm/test_acm.py::TestACM::test_create_certificate_for_multiple_alternative_domains": { - "last_validated_date": "2024-01-09T14:58:14+00:00" + "last_validated_date": "2025-10-14T09:18:39+00:00", + "durations_in_seconds": { + "setup": 0.45, + "call": 5.97, + "teardown": 0.19, + "total": 6.61 + } }, "tests/aws/services/acm/test_acm.py::TestACM::test_domain_validation": { - "last_validated_date": "2024-04-12T15:36:37+00:00" + "last_validated_date": "2025-10-14T09:31:48+00:00", + "durations_in_seconds": { + "setup": 0.46, + "call": 2.94, + "teardown": 0.21, + "total": 3.61 + } }, "tests/aws/services/acm/test_acm.py::TestACM::test_import_certificate": { - "last_validated_date": "2024-02-22T17:41:15+00:00" + "last_validated_date": "2025-10-14T09:17:56+00:00", + "durations_in_seconds": { + "setup": 0.48, + "call": 1.25, + "teardown": 0.25, + "total": 1.98 + } + }, + "tests/aws/services/acm/test_acm.py::TestACM::test_list_certificates_with_key_types_filter_imported_certificate": { + "last_validated_date": "2025-12-09T12:42:45+00:00", + "durations_in_seconds": { + "setup": 0.57, + "call": 2.11, + "teardown": 0.23, + "total": 2.91 + } } } diff --git a/tests/aws/services/apigateway/conftest.py b/tests/aws/services/apigateway/conftest.py index 1063d7b75f372..c541e426e8389 100644 --- a/tests/aws/services/apigateway/conftest.py +++ b/tests/aws/services/apigateway/conftest.py @@ -1,4 +1,5 @@ from itertools import count +from typing import TYPE_CHECKING import pytest from botocore.config import Config @@ -19,6 +20,9 @@ ) from tests.aws.services.lambda_.test_lambda import TEST_LAMBDA_PYTHON_ECHO_STATUS_CODE +if TYPE_CHECKING: + from mypy_boto3_ec2.type_defs import VpcTypeDef + # default name used for created REST API stages DEFAULT_STAGE_NAME = "dev" @@ -297,3 +301,12 @@ def transform_response(response: dict) -> dict: return response return transform_response + + +@pytest.fixture +def default_vpc(aws_client) -> "VpcTypeDef": + vpcs = aws_client.ec2.describe_vpcs() + for vpc in vpcs["Vpcs"]: + if vpc.get("IsDefault"): + return vpc + raise Exception("Default VPC not found") diff --git a/tests/aws/services/apigateway/test_apigateway_api.py b/tests/aws/services/apigateway/test_apigateway_api.py index 3a7887df4080e..19fb4a1d33b81 100644 --- a/tests/aws/services/apigateway/test_apigateway_api.py +++ b/tests/aws/services/apigateway/test_apigateway_api.py @@ -3,6 +3,7 @@ import os.path import time from operator import itemgetter +from typing import TYPE_CHECKING, Unpack import pytest from botocore.config import Config @@ -10,6 +11,7 @@ from localstack_snapshot.snapshots.transformer import SortingTransformer from localstack.aws.api.apigateway import PutMode +from localstack.aws.connect import ServiceLevelClientFactory from localstack.testing.aws.util import is_aws_cloud from localstack.testing.pytest import markers from localstack.utils.files import load_file @@ -24,6 +26,10 @@ ) from tests.aws.services.apigateway.conftest import is_next_gen_api +if TYPE_CHECKING: + from mypy_boto3_apigateway.type_defs import CreateVpcLinkRequestTypeDef, VpcLinkResponseTypeDef + + LOG = logging.getLogger(__name__) THIS_DIR = os.path.dirname(os.path.abspath(__file__)) @@ -98,6 +104,28 @@ def _factory(*args, **kwargs): delete_rest_api_retry(apigateway_client, rest_api_id) +@pytest.fixture +def apigw_create_vpc_link(aws_client): + vpc_links: list[tuple[ServiceLevelClientFactory, str]] = [] + + def _create_vpc_link( + client: ServiceLevelClientFactory | None = None, + **kwargs: Unpack["CreateVpcLinkRequestTypeDef"], + ) -> "VpcLinkResponseTypeDef": + client = client or aws_client + vpc_link = client.apigateway.create_vpc_link(**kwargs) + vpc_links.append((client, vpc_link["id"])) + return vpc_link + + yield _create_vpc_link + + for _client, vpc_link_id in vpc_links: + try: + _client.apigateway.delete_vpc_link(vpcLinkId=vpc_link_id) + except ClientError as e: + LOG.error("Error deleting VPC link: %s", e) + + class TestApiGatewayApiRestApi: @markers.aws.validated def test_list_and_delete_apis(self, apigw_create_rest_api, snapshot, aws_client): @@ -2248,6 +2276,13 @@ def test_invalid_delete_documentation_part(self, apigw_create_rest_api, snapshot snapshot.match("delete_already_deleted_documentation_part", e.value.response) @markers.aws.validated + @markers.snapshot.skip_snapshot_verify( + paths=[ + # FIXME: AWS returns the `path` field for RESPONSE and METHOD + "$.get-documentations-parts-after-import.items[1].location.path", + "$.get-documentations-parts-after-import.items[3].location.path", + ] + ) def test_import_documentation_parts(self, aws_client, import_apigw, snapshot): # snapshot array "ids" snapshot.add_transformer(snapshot.transform.jsonpath("$..ids[*]", "id")) @@ -2258,7 +2293,9 @@ def test_import_documentation_parts(self, aws_client, import_apigw, snapshot): # get documentation parts to make sure import worked response = aws_client.apigateway.get_documentation_parts(restApiId=rest_api_id) - snapshot.match("create-import-documentations_parts", response["items"]) + snapshot.match("get-documentations-parts-after-api-imports", response) + # manually assert that the type is of string because snapshot auto-decodes JSON + assert isinstance(response["items"][0]["properties"], str) # delete documentation parts for doc_part_item in response["items"]: @@ -2280,6 +2317,39 @@ def test_import_documentation_parts(self, aws_client, import_apigw, snapshot): ) snapshot.match("import-documentation-parts", response) + # get documentation parts to make sure import worked + response = aws_client.apigateway.get_documentation_parts(restApiId=rest_api_id) + snapshot.match("get-documentations-parts-after-import", response) + assert isinstance(response["items"][0]["properties"], str) + + @markers.aws.validated + def test_import_documentation_parts_bad_file(self, aws_client, apigw_create_rest_api, snapshot): + rest_api_id = apigw_create_rest_api( + name=f"test-api-{short_uid()}", + description="APIGW test import documentation", + )["id"] + + bad_yaml_string = """test: + value: + - "value ... \"escaped\": $var, \"dt\": $(var +"%a")}\" + """ + + with pytest.raises(ClientError) as e: + aws_client.apigateway.import_documentation_parts( + restApiId=rest_api_id, + mode=PutMode.overwrite, + body=bad_yaml_string, + ) + snapshot.match("import-documentation-parts-bad-yaml-file", e.value.response) + + with pytest.raises(ClientError) as e: + aws_client.apigateway.import_documentation_parts( + restApiId=rest_api_id, + mode=PutMode.overwrite, + body="{'key:value}", + ) + snapshot.match("import-documentation-parts-bad-json-file", e.value.response) + class TestApiGatewayGatewayResponse: @markers.aws.validated @@ -2624,6 +2694,135 @@ def test_update_gateway_response( ) +class TestApiGatewayVpcLink: + @markers.aws.validated + @markers.snapshot.skip_snapshot_verify(paths=["$.update_vpc_link.tags", "$.get_vpc_link.tags"]) + def test_vpc_link_lifecycle( + self, + aws_client, + snapshot, + cleanups, + default_vpc, + region_name, + apigw_create_vpc_link, + account_id, + ): + snapshot.add_transformer(snapshot.transform.key_value("nlb-arn")) + + retries = 240 if is_aws_cloud() else 3 + sleep = 3 if is_aws_cloud() else 1 + + if is_aws_cloud(): + vpc_id = default_vpc["VpcId"] + subnets = aws_client.ec2.describe_subnets( + Filters=[{"Name": "vpc-id", "Values": [vpc_id]}] + )["Subnets"] + # require at least 2 subnets for the NLB + assert len(subnets) >= 2 + nlb = aws_client.elbv2.create_load_balancer( + Name=f"nlb-{short_uid()}", + Type="network", + Subnets=[subnets[0]["SubnetId"], subnets[1]["SubnetId"]], + )["LoadBalancers"][0] + nlb_arn = nlb["LoadBalancerArn"] + cleanups.append(lambda: aws_client.elbv2.delete_load_balancer(LoadBalancerArn=nlb_arn)) + waiter = aws_client.elbv2.get_waiter("load_balancer_available") + waiter.wait( + LoadBalancerArns=[nlb_arn], WaiterConfig={"Delay": sleep, "MaxAttempts": retries} + ) + else: + # ElbV2 is not available in community, so we just use a dummy arn + nlb_arn = f"arn:aws:elasticloadbalancing:{region_name}:{account_id}:loadbalancer/net/my-load-balancer/50dc6c495c0c9188" + + snapshot.match("nlb-arn", nlb_arn) + + # create vpc link + vpc_link_name = f"test-vpc-link-{short_uid()}" + create_vpc_link_response = apigw_create_vpc_link(name=vpc_link_name, targetArns=[nlb_arn]) + snapshot.match("create_vpc_link", create_vpc_link_response) + vpc_link_id = create_vpc_link_response["id"] + + # get vpc link + # AWS needs some time to make the VPC link available + def _wait_for_vpc_link_available(): + get_vpc_link_response = aws_client.apigateway.get_vpc_link(vpcLinkId=vpc_link_id) + assert get_vpc_link_response["status"] == "AVAILABLE" + return get_vpc_link_response + + vpc_link_response = retry(_wait_for_vpc_link_available, retries=retries, sleep=sleep) + snapshot.match("get_vpc_link", vpc_link_response) + + # get vpc links + get_vpc_links_response = aws_client.apigateway.get_vpc_links() + # for the snapshot to be stable, we need to filter for the VPC link we created + get_vpc_links_response["items"] = [ + item for item in get_vpc_links_response["items"] if item["id"] == vpc_link_id + ] + snapshot.match("get_vpc_links", get_vpc_links_response) + + # update vpc link + patch_operations = [ + {"op": "replace", "path": "/name", "value": f"{vpc_link_name}-updated"}, + ] + update_vpc_link_response = aws_client.apigateway.update_vpc_link( + vpcLinkId=vpc_link_id, patchOperations=patch_operations + ) + snapshot.match("update_vpc_link", update_vpc_link_response) + + delete_response = aws_client.apigateway.delete_vpc_link(vpcLinkId=vpc_link_id) + snapshot.match("delete_vpc_link", delete_response) + + def _wait_for_deleted(): + try: + vpc_link = aws_client.apigateway.get_vpc_link(vpcLinkId=vpc_link_id) + # this assertion shouldn't happen, but this will ensure failure if the vpc link is still being deleted + assert vpc_link["status"] == "DELETED" + except aws_client.apigateway.exceptions.NotFoundException: + pass + + # waiting for delete, as it takes a long time and would prevent NLB deletion + retry(_wait_for_deleted, retries=retries, sleep=sleep) + + @markers.aws.validated + def test_create_vpc_link_invalid_parameters(self, aws_client, snapshot): + with pytest.raises(ClientError) as e: + aws_client.apigateway.create_vpc_link( + name=f"test-vpc-link-{short_uid()}", + targetArns=["invalid-arn"], + ) + snapshot.match("create_vpc_link_invalid_target_arn", e.value.response) + + with pytest.raises(ClientError) as e: + aws_client.apigateway.create_vpc_link( + name="", + targetArns=[], + ) + snapshot.match("create_vpc_link_empty_name", e.value.response) + + @markers.aws.validated + def test_get_vpc_link_invalid_id(self, aws_client, snapshot): + with pytest.raises(ClientError) as e: + aws_client.apigateway.get_vpc_link(vpcLinkId="invalid-id") + snapshot.match("get_vpc_link_invalid_id", e.value.response) + + @markers.aws.validated + def test_delete_vpc_link_invalid_id(self, aws_client, snapshot): + with pytest.raises(ClientError) as e: + aws_client.apigateway.delete_vpc_link(vpcLinkId="invalid-id") + snapshot.match("delete_vpc_link_invalid_id", e.value.response) + + @markers.aws.validated + def test_update_vpc_link_invalid_id(self, aws_client, snapshot): + patch_operations = [ + {"op": "replace", "path": "/name", "value": "new-name"}, + ] + with pytest.raises(ClientError) as e: + aws_client.apigateway.update_vpc_link( + vpcLinkId="invalid-id", patchOperations=patch_operations + ) + snapshot.match("update_vpc_link_invalid_id", e.value.response) + + class TestApigatewayTestInvoke: @markers.aws.validated def test_invoke_test_method( @@ -3074,6 +3273,63 @@ def test_put_integration_response_validation( snapshot.match("put-integration-response-wrong-resource", e.value.response) + @markers.aws.validated + def test_put_integration_response_templates( + self, aws_client, apigw_create_rest_api, aws_client_factory, snapshot + ): + apigw_client = aws_client_factory(config=Config(parameter_validation=False)).apigateway + response = apigw_create_rest_api( + name=f"test-api-{short_uid()}", description="testing PutIntegrationResponse method exc" + ) + api_id = response["id"] + root_id = response["rootResourceId"] + + aws_client.apigateway.put_method( + restApiId=api_id, + resourceId=root_id, + httpMethod="POST", + authorizationType="NONE", + ) + + aws_client.apigateway.put_integration( + restApiId=api_id, + resourceId=root_id, + httpMethod="POST", + integrationHttpMethod="GET", + type="MOCK", + requestTemplates={"application/json": '{"statusCode": 200}'}, + ) + + response = apigw_client.put_integration_response( + restApiId=api_id, + resourceId=root_id, + httpMethod="POST", + statusCode="200", + selectionPattern="", + responseTemplates={"application/json": None}, + ) + + snapshot.match("put-integration-response-template-none", response) + + response = apigw_client.put_integration_response( + restApiId=api_id, + resourceId=root_id, + httpMethod="POST", + statusCode="200", + selectionPattern="", + responseTemplates={"application/json": ""}, + ) + snapshot.match("put-integration-response-template-empty", response) + + response = apigw_client.put_integration_response( + restApiId=api_id, + resourceId=root_id, + httpMethod="POST", + statusCode="200", + selectionPattern="", + ) + snapshot.match("put-integration-no-response-template", response) + @markers.aws.validated @pytest.mark.skipif( condition=not is_aws_cloud(), reason="Validation behavior not yet implemented" @@ -3137,6 +3393,109 @@ def test_put_integration_request_parameter_bool_type( ) snapshot.match("put-integration-request-param-bool-value", e.value.response) + @markers.aws.validated + def test_create_integration_with_vpc_link( + self, create_rest_apigw, aws_client, snapshot, region_name + ): + """ + We cannot properly validate the CRUD logic of creating VPC Link, as they require an ELB Network Load Balancer + which are not implemented yet. But we can use stage variables to delay the evaluation of the real connection id + """ + snapshot.add_transformer(snapshot.transform.key_value("cacheNamespace")) + rest_api_id, _, root_resource_id = create_rest_apigw(name="test vpc link") + + aws_client.apigateway.put_method( + restApiId=rest_api_id, + resourceId=root_resource_id, + httpMethod="GET", + authorizationType="NONE", + ) + + # see example here: + # https://docs.aws.amazon.com/apigateway/latest/developerguide/set-up-api-with-vpclink-cli.html + put_integration = aws_client.apigateway.put_integration( + restApiId=rest_api_id, + resourceId=root_resource_id, + httpMethod="GET", + type="HTTP_PROXY", + uri=f"http://my-vpclink-test-nlb-1234567890abcdef.{region_name}.amazonaws.com", + integrationHttpMethod="GET", + connectionType="VPC_LINK", + connectionId="${stageVariables.vpcLinkId}", + ) + snapshot.match("put-integration-vpc-link", put_integration) + + get_integration = aws_client.apigateway.get_integration( + restApiId=rest_api_id, + resourceId=root_resource_id, + httpMethod="GET", + ) + snapshot.match("get-integration-vpc-link", get_integration) + + update_integration = aws_client.apigateway.update_integration( + restApiId=rest_api_id, + resourceId=root_resource_id, + httpMethod="GET", + patchOperations=[ + { + "op": "replace", + "path": "/connectionId", + "value": "${stageVariables.vpcLinkIdBeta}", + } + ], + ) + snapshot.match("update-integration-vpc-link", update_integration) + + get_integration_update = aws_client.apigateway.get_integration( + restApiId=rest_api_id, + resourceId=root_resource_id, + httpMethod="GET", + ) + snapshot.match("get-integration-update-vpc-link", get_integration_update) + + @markers.aws.validated + def test_get_integration_non_existent( + self, aws_client, apigw_create_rest_api, aws_client_factory, snapshot + ): + apigw_client = aws_client_factory(config=Config(parameter_validation=False)).apigateway + response = apigw_create_rest_api( + name=f"test-api-{short_uid()}", + description="APIGW test PutIntegration Types", + ) + api_id = response["id"] + root_resource_id = response["rootResourceId"] + + with pytest.raises(ClientError) as e: + apigw_client.get_integration( + restApiId=short_uid(), resourceId=root_resource_id, httpMethod="GET" + ) + snapshot.match("get-integration-no-api", e.value.response) + + with pytest.raises(ClientError) as e: + apigw_client.get_integration(restApiId=api_id, resourceId=short_uid(), httpMethod="GET") + snapshot.match("get-integration-no-resource", e.value.response) + + with pytest.raises(ClientError) as e: + apigw_client.get_integration( + restApiId=api_id, resourceId=root_resource_id, httpMethod="GET" + ) + snapshot.match("get-integration-no-method", e.value.response) + + aws_client.apigateway.put_method( + restApiId=api_id, + resourceId=root_resource_id, + httpMethod="GET", + authorizationType="NONE", + ) + + with pytest.raises(ClientError) as e: + apigw_client.get_integration( + restApiId=api_id, resourceId=root_resource_id, httpMethod="GET" + ) + snapshot.match("get-integration-no-integration", e.value.response) + + +class TestApigatewayIntegrationResponse: @markers.aws.validated def test_integration_response_wrong_api(self, aws_client, apigw_create_rest_api, snapshot): with pytest.raises(ClientError) as e: @@ -3503,6 +3862,8 @@ def test_delete_integration_response_errors( ) snapshot.match("bad-method", e.value.response) + +class TestApigatewayMethodResponse: @markers.aws.validated def test_update_method_wrong_param_names(self, aws_client, apigw_create_rest_api, snapshot): snapshot.add_transformer(snapshot.transform.key_value("cacheNamespace")) @@ -4098,3 +4459,278 @@ def test_lifecycle_method_response(self, aws_client, apigw_create_rest_api, snap statusCode="200", ) snapshot.match("delete-method-response", delete_response) + + +class TestApiGatewayStage: + @pytest.fixture + def create_api_for_deployment(self, apigw_create_rest_api, aws_client): + def _create() -> str: + # Create REST API with a MOCK method (required for deployment) + response = apigw_create_rest_api(name=f"test-stages-{short_uid()}") + api_id = response["id"] + root_id = response["rootResourceId"] + + aws_client.apigateway.put_method( + restApiId=api_id, + resourceId=root_id, + httpMethod="GET", + authorizationType="NONE", + ) + aws_client.apigateway.put_integration( + restApiId=api_id, + resourceId=root_id, + httpMethod="GET", + type="MOCK", + requestTemplates={"application/json": '{"statusCode": 200}'}, + ) + return api_id + + return _create + + @pytest.fixture + def logs_create_log_group(self, aws_client): + log_group_names = [] + + def _create_log_group(name: str = None) -> str: + if not name: + name = f"test-log-group-{short_uid()}" + + aws_client.logs.create_log_group(logGroupName=name) + log_group_names.append(name) + describe_result = aws_client.logs.describe_log_groups(logGroupNamePrefix=name) + return describe_result["logGroups"][0]["arn"] + + yield _create_log_group + + for _name in log_group_names: + try: + aws_client.logs.delete_log_group(logGroupName=_name) + except Exception as e: + LOG.debug("error cleaning up log group %s: %s", _name, e) + + @markers.aws.validated + def test_get_stages_filters_by_deployment_id( + self, create_api_for_deployment, aws_client, snapshot + ): + """ + Regression test for https://github.com/localstack/localstack/issues/13667 + Verifies that get_stages filters results by deploymentId when provided. + """ + snapshot.add_transformer(snapshot.transform.key_value("deploymentId")) + + # Create REST API with a MOCK method (required for deployment) + api_id = create_api_for_deployment() + + # Create two deployments with different stages + deploy1 = aws_client.apigateway.create_deployment(restApiId=api_id, stageName="stage1") + if is_aws_cloud(): + time.sleep(1) + deploy2 = aws_client.apigateway.create_deployment(restApiId=api_id, stageName="stage2") + + # get_stages without deploymentId returns all stages + all_stages = aws_client.apigateway.get_stages(restApiId=api_id) + snapshot.match("all-stages", all_stages) + assert len(all_stages["item"]) == 2 + + # get_stages with deploymentId should return only the matching stage + stages_deploy1 = aws_client.apigateway.get_stages( + restApiId=api_id, deploymentId=deploy1["id"] + ) + snapshot.match("stages-deploy1", stages_deploy1) + assert len(stages_deploy1["item"]) == 1 + assert stages_deploy1["item"][0]["stageName"] == "stage1" + + stages_deploy2 = aws_client.apigateway.get_stages( + restApiId=api_id, deploymentId=deploy2["id"] + ) + snapshot.match("stages-deploy2", stages_deploy2) + assert len(stages_deploy2["item"]) == 1 + assert stages_deploy2["item"][0]["stageName"] == "stage2" + + @markers.aws.validated + def test_stage_access_log_settings( + self, create_api_for_deployment, aws_client, logs_create_log_group, snapshot + ): + # see https://docs.aws.amazon.com/apigateway/latest/api/patch-operations.html#UpdateStage-Patch + # for list of possible operations + api_id = create_api_for_deployment() + log_group_arn = logs_create_log_group() + # AWS appends ":*" to the ARN which API Gateway doesn't allow + log_group_arn = log_group_arn.removesuffix(":*") + snapshot.add_transformer(snapshot.transform.regex(log_group_arn, "")) + + create_deployment = aws_client.apigateway.create_deployment(restApiId=api_id) + snapshot.match("create-deployment", create_deployment) + deployment_id = create_deployment["id"] + + stage_name = "dev" + create_stage = aws_client.apigateway.create_stage( + restApiId=api_id, + stageName=stage_name, + deploymentId=deployment_id, + description="dev stage", + ) + snapshot.match("create-stage", create_stage) + + update_stage = aws_client.apigateway.update_stage( + restApiId=api_id, + stageName=stage_name, + patchOperations=[ + { + "op": "add", + "path": "/accessLogSettings/destinationArn", + "value": log_group_arn, + }, + ], + ) + snapshot.match("update-stage-access-log-dest-add", update_stage) + + update_stage = aws_client.apigateway.update_stage( + restApiId=api_id, + stageName=stage_name, + patchOperations=[ + { + "op": "replace", + "path": "/accessLogSettings/destinationArn", + "value": log_group_arn + "a", + }, + ], + ) + snapshot.match("update-stage-access-log-dest-replace", update_stage) + + # $context.extendedRequestId $context.identity.sourceIp + update_stage = aws_client.apigateway.update_stage( + restApiId=api_id, + stageName=stage_name, + patchOperations=[ + { + "op": "add", + "path": "/accessLogSettings/format", + "value": "$context.requestId $context.identity.sourceIp", + }, + ], + ) + snapshot.match("update-stage-access-log-format-add", update_stage) + + update_stage = aws_client.apigateway.update_stage( + restApiId=api_id, + stageName=stage_name, + patchOperations=[ + { + "op": "remove", + "path": "/accessLogSettings", + }, + ], + ) + snapshot.match("update-stage-access-log-remove-all", update_stage) + + @markers.aws.validated + def test_stage_access_log_settings_validation( + self, create_api_for_deployment, aws_client, logs_create_log_group, snapshot + ): + # see https://docs.aws.amazon.com/apigateway/latest/api/patch-operations.html#UpdateStage-Patch + # for list of possible operations + api_id = create_api_for_deployment() + log_group_arn = logs_create_log_group() + # AWS appends ":*" to the ARN which API Gateway doesn't allow + log_group_arn = log_group_arn.removesuffix(":*") + snapshot.add_transformer(snapshot.transform.regex(log_group_arn, "")) + + create_deployment = aws_client.apigateway.create_deployment(restApiId=api_id) + snapshot.match("create-deployment", create_deployment) + deployment_id = create_deployment["id"] + + stage_name = "dev" + create_stage = aws_client.apigateway.create_stage( + restApiId=api_id, + stageName=stage_name, + deploymentId=deployment_id, + description="dev stage", + ) + snapshot.match("create-stage", create_stage) + + for op in ("add", "remove", "replace"): + with pytest.raises(ClientError) as e: + aws_client.apigateway.update_stage( + restApiId=api_id, + stageName=stage_name, + patchOperations=[ + { + "op": op, + "path": "/accessLogSettings/randomValue", + "value": "updated", + }, + ], + ) + snapshot.match(f"invalid-path-{op}", e.value.response) + + for op in ("add", "remove", "replace"): + with pytest.raises(ClientError) as e: + aws_client.apigateway.update_stage( + restApiId=api_id, + stageName=stage_name, + patchOperations=[ + { + "op": op, + "path": "/accessLogSettings/*", + "value": "updated", + }, + ], + ) + snapshot.match(f"star-and-{op}", e.value.response) + + for op in ("add", "replace"): + with pytest.raises(ClientError) as e: + aws_client.apigateway.update_stage( + restApiId=api_id, + stageName=stage_name, + patchOperations=[ + { + "op": op, + "path": "/accessLogSettings", + "value": "test", + }, + ], + ) + snapshot.match(f"root-and-{op}", e.value.response) + + update_stage = aws_client.apigateway.update_stage( + restApiId=api_id, + stageName=stage_name, + patchOperations=[ + { + "op": "add", + "path": "/accessLogSettings/destinationArn", + "value": log_group_arn, + }, + ], + ) + snapshot.match("update-stage-access-log-dest-add", update_stage) + + for path in ("destinationArn", "format"): + with pytest.raises(ClientError) as e: + aws_client.apigateway.update_stage( + restApiId=api_id, + stageName=stage_name, + patchOperations=[ + { + "op": "replace", + "path": f"/accessLogSettings/{path}", + "value": "", + }, + ], + ) + snapshot.match(f"update-stage-access-log-{path}-empty", e.value.response) + + with pytest.raises(ClientError) as e: + aws_client.apigateway.update_stage( + restApiId=api_id, + stageName=stage_name, + patchOperations=[ + { + "op": "remove", + "path": "/accessLogSettings/destinationArn", + }, + ], + ) + snapshot.match("update-stage-access-log-dest-remove", e.value.response) diff --git a/tests/aws/services/apigateway/test_apigateway_api.snapshot.json b/tests/aws/services/apigateway/test_apigateway_api.snapshot.json index 84b358853287f..85ccf98e4816d 100644 --- a/tests/aws/services/apigateway/test_apigateway_api.snapshot.json +++ b/tests/aws/services/apigateway/test_apigateway_api.snapshot.json @@ -3344,56 +3344,62 @@ } }, "tests/aws/services/apigateway/test_apigateway_api.py::TestApiGatewayApiDocumentationPart::test_import_documentation_parts": { - "recorded-date": "15-04-2024, 20:57:15", + "recorded-date": "09-02-2026, 18:59:24", "recorded-content": { - "create-import-documentations_parts": [ - { - "id": "", - "location": { - "type": "API" - }, - "properties": { - "description": "API description", - "info": { - "description": "API info description 4", - "version": "API info version 3" + "get-documentations-parts-after-api-imports": { + "items": [ + { + "id": "", + "location": { + "type": "API" + }, + "properties": { + "description": "API description", + "info": { + "description": "API info description 4", + "version": "API info version 3" + } } - } - }, - { - "id": "", - "location": { - "type": "METHOD", - "path": "/", - "method": "GET" }, - "properties": { - "description": "Method description." - } - }, - { - "id": "", - "location": { - "type": "MODEL", - "name": "" + { + "id": "", + "location": { + "method": "GET", + "path": "/", + "type": "METHOD" + }, + "properties": { + "description": "Method description." + } }, - "properties": { - "title": " Schema" - } - }, - { - "id": "", - "location": { - "type": "RESPONSE", - "path": "/", - "method": "GET", - "statusCode": "200" + { + "id": "", + "location": { + "name": "", + "type": "MODEL" + }, + "properties": { + "title": " Schema" + } }, - "properties": { - "description": "200 response" + { + "id": "", + "location": { + "method": "GET", + "path": "/", + "statusCode": "200", + "type": "RESPONSE" + }, + "properties": { + "description": "200 response" + } } + ], + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 } - ], + }, "import-documentation-parts": { "ids": [ "", @@ -3405,6 +3411,60 @@ "HTTPHeaders": {}, "HTTPStatusCode": 200 } + }, + "get-documentations-parts-after-import": { + "items": [ + { + "id": "", + "location": { + "type": "API" + }, + "properties": { + "description": "API description", + "info": { + "description": "API info description 4", + "version": "API info version 3" + } + } + }, + { + "id": "", + "location": { + "method": "GET", + "path": "/", + "type": "METHOD" + }, + "properties": { + "description": "Method description." + } + }, + { + "id": "", + "location": { + "name": "", + "type": "MODEL" + }, + "properties": { + "title": " Schema" + } + }, + { + "id": "", + "location": { + "method": "GET", + "path": "/", + "statusCode": "200", + "type": "RESPONSE" + }, + "properties": { + "description": "200 response" + } + } + ], + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } } } }, @@ -3833,7 +3893,7 @@ } } }, - "tests/aws/services/apigateway/test_apigateway_api.py::TestApigatewayIntegration::test_lifecycle_integration_response": { + "tests/aws/services/apigateway/test_apigateway_api.py::TestApigatewayIntegrationResponse::test_lifecycle_integration_response": { "recorded-date": "11-06-2025, 09:12:54", "recorded-content": { "put-integration-response": { @@ -3918,7 +3978,7 @@ } } }, - "tests/aws/services/apigateway/test_apigateway_api.py::TestApigatewayIntegration::test_integration_response_wrong_api": { + "tests/aws/services/apigateway/test_apigateway_api.py::TestApigatewayIntegrationResponse::test_integration_response_wrong_api": { "recorded-date": "18-06-2025, 12:28:55", "recorded-content": { "put-integration-response-wrong-api": { @@ -3945,7 +4005,7 @@ } } }, - "tests/aws/services/apigateway/test_apigateway_api.py::TestApigatewayIntegration::test_integration_response_wrong_resource": { + "tests/aws/services/apigateway/test_apigateway_api.py::TestApigatewayIntegrationResponse::test_integration_response_wrong_resource": { "recorded-date": "18-06-2025, 12:28:25", "recorded-content": { "put-integration-response-wrong-resource": { @@ -3972,7 +4032,7 @@ } } }, - "tests/aws/services/apigateway/test_apigateway_api.py::TestApigatewayIntegration::test_integration_response_wrong_method": { + "tests/aws/services/apigateway/test_apigateway_api.py::TestApigatewayIntegrationResponse::test_integration_response_wrong_method": { "recorded-date": "18-06-2025, 11:47:00", "recorded-content": { "put-integration-response-wrong-method": { @@ -3999,7 +4059,7 @@ } } }, - "tests/aws/services/apigateway/test_apigateway_api.py::TestApigatewayIntegration::test_integration_response_invalid_statuscode": { + "tests/aws/services/apigateway/test_apigateway_api.py::TestApigatewayIntegrationResponse::test_integration_response_invalid_statuscode": { "recorded-date": "18-06-2025, 11:51:51", "recorded-content": { "put-integration-response-invalid-statusCode": { @@ -4024,7 +4084,7 @@ } } }, - "tests/aws/services/apigateway/test_apigateway_api.py::TestApigatewayIntegration::test_integration_response_invalid_responsetemplates": { + "tests/aws/services/apigateway/test_apigateway_api.py::TestApigatewayIntegrationResponse::test_integration_response_invalid_responsetemplates": { "recorded-date": "18-06-2025, 13:03:29", "recorded-content": { "put-integration-response-invalid-responseTemplates-1": { @@ -4050,7 +4110,7 @@ } } }, - "tests/aws/services/apigateway/test_apigateway_api.py::TestApigatewayIntegration::test_integration_response_invalid_integration": { + "tests/aws/services/apigateway/test_apigateway_api.py::TestApigatewayIntegrationResponse::test_integration_response_invalid_integration": { "recorded-date": "26-06-2025, 11:21:05", "recorded-content": { "get-integration-response-without-integration": { @@ -4066,7 +4126,7 @@ } } }, - "tests/aws/services/apigateway/test_apigateway_api.py::TestApigatewayIntegration::test_integration_response_wrong_status_code": { + "tests/aws/services/apigateway/test_apigateway_api.py::TestApigatewayIntegrationResponse::test_integration_response_wrong_status_code": { "recorded-date": "26-06-2025, 11:21:43", "recorded-content": { "get-integration-response-wrong-status-code": { @@ -4082,7 +4142,7 @@ } } }, - "tests/aws/services/apigateway/test_apigateway_api.py::TestApigatewayIntegration::test_lifecycle_method_response": { + "tests/aws/services/apigateway/test_apigateway_api.py::TestApigatewayMethodResponse::test_lifecycle_method_response": { "recorded-date": "01-07-2025, 15:48:02", "recorded-content": { "put-method-response": { @@ -4169,7 +4229,7 @@ } } }, - "tests/aws/services/apigateway/test_apigateway_api.py::TestApigatewayIntegration::test_update_method_response": { + "tests/aws/services/apigateway/test_apigateway_api.py::TestApigatewayMethodResponse::test_update_method_response": { "recorded-date": "30-06-2025, 12:42:31", "recorded-content": { "remove-update-method-response": { @@ -4194,7 +4254,7 @@ } } }, - "tests/aws/services/apigateway/test_apigateway_api.py::TestApigatewayIntegration::test_update_method_response_wrong_operations": { + "tests/aws/services/apigateway/test_apigateway_api.py::TestApigatewayMethodResponse::test_update_method_response_wrong_operations": { "recorded-date": "30-06-2025, 13:54:57", "recorded-content": { "update-method-response-wrong-operation-1": { @@ -4249,7 +4309,7 @@ } } }, - "tests/aws/services/apigateway/test_apigateway_api.py::TestApigatewayIntegration::test_update_method_response_negative_tests": { + "tests/aws/services/apigateway/test_apigateway_api.py::TestApigatewayMethodResponse::test_update_method_response_negative_tests": { "recorded-date": "30-06-2025, 15:24:43", "recorded-content": { "update-method-response-wrong-statuscode": { @@ -4307,7 +4367,7 @@ } } }, - "tests/aws/services/apigateway/test_apigateway_api.py::TestApigatewayIntegration::test_update_method_lack_response_parameters_and_models": { + "tests/aws/services/apigateway/test_apigateway_api.py::TestApigatewayMethodResponse::test_update_method_lack_response_parameters_and_models": { "recorded-date": "01-07-2025, 15:48:38", "recorded-content": { "update-method-response-operation-without-response-parameters": { @@ -4345,7 +4405,7 @@ } } }, - "tests/aws/services/apigateway/test_apigateway_api.py::TestApigatewayIntegration::test_update_method_wrong_param_names": { + "tests/aws/services/apigateway/test_apigateway_api.py::TestApigatewayMethodResponse::test_update_method_wrong_param_names": { "recorded-date": "01-07-2025, 15:49:16", "recorded-content": { "update-method-response-operation-with-wrong-param-name-1": { @@ -4775,7 +4835,7 @@ } } }, - "tests/aws/services/apigateway/test_apigateway_api.py::TestApigatewayIntegration::test_delete_integration_response_errors": { + "tests/aws/services/apigateway/test_apigateway_api.py::TestApigatewayIntegrationResponse::test_delete_integration_response_errors": { "recorded-date": "21-08-2025, 17:53:19", "recorded-content": { "put-integration-response": { @@ -4908,5 +4968,659 @@ } } } + }, + "tests/aws/services/apigateway/test_apigateway_api.py::TestApigatewayIntegration::test_create_integration_with_vpc_link": { + "recorded-date": "08-10-2025, 09:05:56", + "recorded-content": { + "put-integration-vpc-link": { + "cacheKeyParameters": [], + "cacheNamespace": "", + "connectionId": "${stageVariables.vpcLinkId}", + "connectionType": "VPC_LINK", + "httpMethod": "GET", + "passthroughBehavior": "WHEN_NO_MATCH", + "timeoutInMillis": 29000, + "type": "HTTP_PROXY", + "uri": "http://my-vpclink-test-nlb-1234567890abcdef..amazonaws.com", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 201 + } + }, + "get-integration-vpc-link": { + "cacheKeyParameters": [], + "cacheNamespace": "", + "connectionId": "${stageVariables.vpcLinkId}", + "connectionType": "VPC_LINK", + "httpMethod": "GET", + "passthroughBehavior": "WHEN_NO_MATCH", + "timeoutInMillis": 29000, + "type": "HTTP_PROXY", + "uri": "http://my-vpclink-test-nlb-1234567890abcdef..amazonaws.com", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "update-integration-vpc-link": { + "cacheKeyParameters": [], + "cacheNamespace": "", + "connectionId": "${stageVariables.vpcLinkIdBeta}", + "connectionType": "VPC_LINK", + "httpMethod": "GET", + "passthroughBehavior": "WHEN_NO_MATCH", + "timeoutInMillis": 29000, + "type": "HTTP_PROXY", + "uri": "http://my-vpclink-test-nlb-1234567890abcdef..amazonaws.com", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "get-integration-update-vpc-link": { + "cacheKeyParameters": [], + "cacheNamespace": "", + "connectionId": "${stageVariables.vpcLinkIdBeta}", + "connectionType": "VPC_LINK", + "httpMethod": "GET", + "passthroughBehavior": "WHEN_NO_MATCH", + "timeoutInMillis": 29000, + "type": "HTTP_PROXY", + "uri": "http://my-vpclink-test-nlb-1234567890abcdef..amazonaws.com", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/apigateway/test_apigateway_api.py::TestApigatewayIntegration::test_get_integration_non_existent": { + "recorded-date": "18-11-2025, 17:03:33", + "recorded-content": { + "get-integration-no-api": { + "Error": { + "Code": "NotFoundException", + "Message": "Invalid Resource identifier specified" + }, + "message": "Invalid Resource identifier specified", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 404 + } + }, + "get-integration-no-resource": { + "Error": { + "Code": "NotFoundException", + "Message": "Invalid Resource identifier specified" + }, + "message": "Invalid Resource identifier specified", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 404 + } + }, + "get-integration-no-method": { + "Error": { + "Code": "NotFoundException", + "Message": "Invalid Method identifier specified" + }, + "message": "Invalid Method identifier specified", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 404 + } + }, + "get-integration-no-integration": { + "Error": { + "Code": "NotFoundException", + "Message": "Invalid Integration identifier specified" + }, + "message": "Invalid Integration identifier specified", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 404 + } + } + } + }, + "tests/aws/services/apigateway/test_apigateway_api.py::TestApiGatewayApiDocumentationPart::test_import_documentation_parts_bad_file": { + "recorded-date": "18-11-2025, 17:21:35", + "recorded-content": { + "import-documentation-parts-bad-yaml-file": { + "Error": { + "Code": "BadRequestException", + "Message": "Unable to build importer with provided input." + }, + "message": "Unable to build importer with provided input.", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + }, + "import-documentation-parts-bad-json-file": { + "Error": { + "Code": "BadRequestException", + "Message": "Unable to build importer with provided input." + }, + "message": "Unable to build importer with provided input.", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + } + } + }, + "tests/aws/services/apigateway/test_apigateway_api.py::TestApiGatewayVpcLink::test_vpc_link_lifecycle": { + "recorded-date": "15-12-2025, 08:04:55", + "recorded-content": { + "nlb-arn": "", + "create_vpc_link": { + "id": "", + "name": "", + "status": "PENDING", + "targetArns": [ + "" + ], + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 202 + } + }, + "get_vpc_link": { + "id": "", + "name": "", + "status": "AVAILABLE", + "statusMessage": "Your vpc link is ready for use", + "tags": {}, + "targetArns": [ + "" + ], + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "get_vpc_links": { + "items": [ + { + "id": "", + "name": "", + "status": "AVAILABLE", + "statusMessage": "Your vpc link is ready for use", + "targetArns": [ + "" + ] + } + ], + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "update_vpc_link": { + "id": "", + "name": "-updated", + "status": "AVAILABLE", + "statusMessage": "Your vpc link is ready for use", + "tags": {}, + "targetArns": [ + "" + ], + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "delete_vpc_link": { + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 202 + } + } + } + }, + "tests/aws/services/apigateway/test_apigateway_api.py::TestApiGatewayVpcLink::test_create_vpc_link_invalid_parameters": { + "recorded-date": "15-12-2025, 04:55:32", + "recorded-content": { + "create_vpc_link_invalid_target_arn": { + "Error": { + "Code": "BadRequestException", + "Message": "Invalid ARN. ARN is not well formed invalid-arn" + }, + "message": "Invalid ARN. ARN is not well formed invalid-arn", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + }, + "create_vpc_link_empty_name": { + "Error": { + "Code": "BadRequestException", + "Message": "Name cannot be empty" + }, + "message": "Name cannot be empty", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + } + } + }, + "tests/aws/services/apigateway/test_apigateway_api.py::TestApiGatewayVpcLink::test_get_vpc_link_invalid_id": { + "recorded-date": "15-12-2025, 04:55:32", + "recorded-content": { + "get_vpc_link_invalid_id": { + "Error": { + "Code": "NotFoundException", + "Message": "Invalid Vpc Link identifier specified" + }, + "message": "Invalid Vpc Link identifier specified", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 404 + } + } + } + }, + "tests/aws/services/apigateway/test_apigateway_api.py::TestApiGatewayVpcLink::test_delete_vpc_link_invalid_id": { + "recorded-date": "15-12-2025, 04:55:32", + "recorded-content": { + "delete_vpc_link_invalid_id": { + "Error": { + "Code": "NotFoundException", + "Message": "Invalid Vpc Link identifier specified" + }, + "message": "Invalid Vpc Link identifier specified", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 404 + } + } + } + }, + "tests/aws/services/apigateway/test_apigateway_api.py::TestApiGatewayVpcLink::test_update_vpc_link_invalid_id": { + "recorded-date": "15-12-2025, 04:55:32", + "recorded-content": { + "update_vpc_link_invalid_id": { + "Error": { + "Code": "NotFoundException", + "Message": "Invalid Vpc Link identifier specified" + }, + "message": "Invalid Vpc Link identifier specified", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 404 + } + } + } + }, + "tests/aws/services/apigateway/test_apigateway_api.py::TestApiGatewayStage::test_get_stages_filters_by_deployment_id": { + "recorded-date": "25-02-2026, 23:40:35", + "recorded-content": { + "all-stages": { + "item": [ + { + "cacheClusterEnabled": false, + "cacheClusterStatus": "NOT_AVAILABLE", + "createdDate": "datetime", + "deploymentId": "", + "lastUpdatedDate": "datetime", + "methodSettings": {}, + "stageName": "stage1", + "tracingEnabled": false + }, + { + "cacheClusterEnabled": false, + "cacheClusterStatus": "NOT_AVAILABLE", + "createdDate": "datetime", + "deploymentId": "", + "lastUpdatedDate": "datetime", + "methodSettings": {}, + "stageName": "stage2", + "tracingEnabled": false + } + ], + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "stages-deploy1": { + "item": [ + { + "cacheClusterEnabled": false, + "cacheClusterStatus": "NOT_AVAILABLE", + "createdDate": "datetime", + "deploymentId": "", + "lastUpdatedDate": "datetime", + "methodSettings": {}, + "stageName": "stage1", + "tracingEnabled": false + } + ], + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "stages-deploy2": { + "item": [ + { + "cacheClusterEnabled": false, + "cacheClusterStatus": "NOT_AVAILABLE", + "createdDate": "datetime", + "deploymentId": "", + "lastUpdatedDate": "datetime", + "methodSettings": {}, + "stageName": "stage2", + "tracingEnabled": false + } + ], + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/apigateway/test_apigateway_api.py::TestApigatewayIntegration::test_put_integration_response_templates": { + "recorded-date": "12-02-2026, 16:25:03", + "recorded-content": { + "put-integration-response-template-none": { + "responseTemplates": { + "application/json": null + }, + "selectionPattern": "", + "statusCode": "200", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 201 + } + }, + "put-integration-response-template-empty": { + "responseTemplates": { + "application/json": null + }, + "selectionPattern": "", + "statusCode": "200", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 201 + } + }, + "put-integration-no-response-template": { + "selectionPattern": "", + "statusCode": "200", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 201 + } + } + } + }, + "tests/aws/services/apigateway/test_apigateway_api.py::TestApiGatewayStage::test_stage_access_log_settings": { + "recorded-date": "25-02-2026, 23:08:31", + "recorded-content": { + "create-deployment": { + "createdDate": "datetime", + "id": "", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 201 + } + }, + "create-stage": { + "cacheClusterEnabled": false, + "cacheClusterStatus": "NOT_AVAILABLE", + "createdDate": "datetime", + "deploymentId": "", + "description": "dev stage", + "lastUpdatedDate": "datetime", + "methodSettings": {}, + "stageName": "dev", + "tracingEnabled": false, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 201 + } + }, + "update-stage-access-log-dest-add": { + "accessLogSettings": { + "destinationArn": "" + }, + "cacheClusterEnabled": false, + "cacheClusterStatus": "NOT_AVAILABLE", + "createdDate": "datetime", + "deploymentId": "", + "description": "dev stage", + "lastUpdatedDate": "datetime", + "methodSettings": {}, + "stageName": "dev", + "tracingEnabled": false, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "update-stage-access-log-dest-replace": { + "accessLogSettings": { + "destinationArn": "a" + }, + "cacheClusterEnabled": false, + "cacheClusterStatus": "NOT_AVAILABLE", + "createdDate": "datetime", + "deploymentId": "", + "description": "dev stage", + "lastUpdatedDate": "datetime", + "methodSettings": {}, + "stageName": "dev", + "tracingEnabled": false, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "update-stage-access-log-format-add": { + "accessLogSettings": { + "destinationArn": "a", + "format": "$context.requestId $context.identity.sourceIp" + }, + "cacheClusterEnabled": false, + "cacheClusterStatus": "NOT_AVAILABLE", + "createdDate": "datetime", + "deploymentId": "", + "description": "dev stage", + "lastUpdatedDate": "datetime", + "methodSettings": {}, + "stageName": "dev", + "tracingEnabled": false, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "update-stage-access-log-remove-all": { + "cacheClusterEnabled": false, + "cacheClusterStatus": "NOT_AVAILABLE", + "createdDate": "datetime", + "deploymentId": "", + "description": "dev stage", + "lastUpdatedDate": "datetime", + "methodSettings": {}, + "stageName": "dev", + "tracingEnabled": false, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/apigateway/test_apigateway_api.py::TestApiGatewayStage::test_stage_access_log_settings_validation": { + "recorded-date": "25-02-2026, 23:16:02", + "recorded-content": { + "create-deployment": { + "createdDate": "datetime", + "id": "", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 201 + } + }, + "create-stage": { + "cacheClusterEnabled": false, + "cacheClusterStatus": "NOT_AVAILABLE", + "createdDate": "datetime", + "deploymentId": "", + "description": "dev stage", + "lastUpdatedDate": "datetime", + "methodSettings": {}, + "stageName": "dev", + "tracingEnabled": false, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 201 + } + }, + "invalid-path-add": { + "Error": { + "Code": "BadRequestException", + "Message": "Invalid accessLogSettings path. Must be one of : [/accessLogSettings/destinationArn, /accessLogSettings/format]" + }, + "message": "Invalid accessLogSettings path. Must be one of : [/accessLogSettings/destinationArn, /accessLogSettings/format]", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + }, + "invalid-path-remove": { + "Error": { + "Code": "BadRequestException", + "Message": "Cannot remove method setting accessLogSettings/randomValue because there is no method setting for this method " + }, + "message": "Cannot remove method setting accessLogSettings/randomValue because there is no method setting for this method ", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + }, + "invalid-path-replace": { + "Error": { + "Code": "BadRequestException", + "Message": "Invalid accessLogSettings path. Must be one of : [/accessLogSettings/destinationArn, /accessLogSettings/format]" + }, + "message": "Invalid accessLogSettings path. Must be one of : [/accessLogSettings/destinationArn, /accessLogSettings/format]", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + }, + "star-and-add": { + "Error": { + "Code": "BadRequestException", + "Message": "Invalid accessLogSettings path. Must be one of : [/accessLogSettings/destinationArn, /accessLogSettings/format]" + }, + "message": "Invalid accessLogSettings path. Must be one of : [/accessLogSettings/destinationArn, /accessLogSettings/format]", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + }, + "star-and-remove": { + "Error": { + "Code": "BadRequestException", + "Message": "Cannot remove method setting accessLogSettings/* because there is no method setting for this method " + }, + "message": "Cannot remove method setting accessLogSettings/* because there is no method setting for this method ", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + }, + "star-and-replace": { + "Error": { + "Code": "BadRequestException", + "Message": "Invalid accessLogSettings path. Must be one of : [/accessLogSettings/destinationArn, /accessLogSettings/format]" + }, + "message": "Invalid accessLogSettings path. Must be one of : [/accessLogSettings/destinationArn, /accessLogSettings/format]", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + }, + "root-and-add": { + "Error": { + "Code": "BadRequestException", + "Message": "Invalid accessLogSettings path. Must be one of : [/accessLogSettings/destinationArn, /accessLogSettings/format]" + }, + "message": "Invalid accessLogSettings path. Must be one of : [/accessLogSettings/destinationArn, /accessLogSettings/format]", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + }, + "root-and-replace": { + "Error": { + "Code": "BadRequestException", + "Message": "Invalid accessLogSettings path. Must be one of : [/accessLogSettings/destinationArn, /accessLogSettings/format]" + }, + "message": "Invalid accessLogSettings path. Must be one of : [/accessLogSettings/destinationArn, /accessLogSettings/format]", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + }, + "update-stage-access-log-dest-add": { + "accessLogSettings": { + "destinationArn": "" + }, + "cacheClusterEnabled": false, + "cacheClusterStatus": "NOT_AVAILABLE", + "createdDate": "datetime", + "deploymentId": "", + "description": "dev stage", + "lastUpdatedDate": "datetime", + "methodSettings": {}, + "stageName": "dev", + "tracingEnabled": false, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "update-stage-access-log-destinationArn-empty": { + "Error": { + "Code": "BadRequestException", + "Message": "Access Log value must not be empty" + }, + "message": "Access Log value must not be empty", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + }, + "update-stage-access-log-format-empty": { + "Error": { + "Code": "BadRequestException", + "Message": "Access Log value must not be empty" + }, + "message": "Access Log value must not be empty", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + }, + "update-stage-access-log-dest-remove": { + "Error": { + "Code": "BadRequestException", + "Message": "Cannot remove method setting accessLogSettings/destinationArn because there is no method setting for this method " + }, + "message": "Cannot remove method setting accessLogSettings/destinationArn because there is no method setting for this method ", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + } + } } } diff --git a/tests/aws/services/apigateway/test_apigateway_api.validation.json b/tests/aws/services/apigateway/test_apigateway_api.validation.json index a21557799c53f..ad5d0abfc83e5 100644 --- a/tests/aws/services/apigateway/test_apigateway_api.validation.json +++ b/tests/aws/services/apigateway/test_apigateway_api.validation.json @@ -9,7 +9,22 @@ "last_validated_date": "2024-04-15T20:52:34+00:00" }, "tests/aws/services/apigateway/test_apigateway_api.py::TestApiGatewayApiDocumentationPart::test_import_documentation_parts": { - "last_validated_date": "2024-04-15T20:56:45+00:00" + "last_validated_date": "2026-02-09T18:59:24+00:00", + "durations_in_seconds": { + "setup": 0.92, + "call": 2.22, + "teardown": 0.3, + "total": 3.44 + } + }, + "tests/aws/services/apigateway/test_apigateway_api.py::TestApiGatewayApiDocumentationPart::test_import_documentation_parts_bad_file": { + "last_validated_date": "2025-11-18T17:21:35+00:00", + "durations_in_seconds": { + "setup": 0.83, + "call": 1.14, + "teardown": 0.34, + "total": 2.31 + } }, "tests/aws/services/apigateway/test_apigateway_api.py::TestApiGatewayApiDocumentationPart::test_invalid_create_documentation_part_operations": { "last_validated_date": "2024-04-15T20:53:48+00:00" @@ -245,7 +260,112 @@ "tests/aws/services/apigateway/test_apigateway_api.py::TestApiGatewayGatewayResponse::test_update_gateway_response": { "last_validated_date": "2024-04-15T20:47:11+00:00" }, - "tests/aws/services/apigateway/test_apigateway_api.py::TestApigatewayIntegration::test_delete_integration_response_errors": { + "tests/aws/services/apigateway/test_apigateway_api.py::TestApiGatewayStage::test_get_stages_filters_by_deployment_id": { + "last_validated_date": "2026-02-25T23:40:35+00:00", + "durations_in_seconds": { + "setup": 0.91, + "call": 13.16, + "teardown": 0.45, + "total": 14.52 + } + }, + "tests/aws/services/apigateway/test_apigateway_api.py::TestApiGatewayStage::test_stage_access_log_settings": { + "last_validated_date": "2026-02-25T23:08:31+00:00", + "durations_in_seconds": { + "setup": 0.88, + "call": 3.57, + "teardown": 0.62, + "total": 5.07 + } + }, + "tests/aws/services/apigateway/test_apigateway_api.py::TestApiGatewayStage::test_stage_access_log_settings_validation": { + "last_validated_date": "2026-02-25T23:16:02+00:00", + "durations_in_seconds": { + "setup": 0.92, + "call": 3.99, + "teardown": 0.49, + "total": 5.4 + } + }, + "tests/aws/services/apigateway/test_apigateway_api.py::TestApiGatewayVpcLink::test_create_vpc_link_invalid_parameters": { + "last_validated_date": "2025-12-15T04:55:32+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.21, + "teardown": 0.0, + "total": 0.21 + } + }, + "tests/aws/services/apigateway/test_apigateway_api.py::TestApiGatewayVpcLink::test_delete_vpc_link_invalid_id": { + "last_validated_date": "2025-12-15T04:55:32+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.1, + "teardown": 0.0, + "total": 0.1 + } + }, + "tests/aws/services/apigateway/test_apigateway_api.py::TestApiGatewayVpcLink::test_get_vpc_link_invalid_id": { + "last_validated_date": "2025-12-15T04:55:32+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.1, + "teardown": 0.0, + "total": 0.1 + } + }, + "tests/aws/services/apigateway/test_apigateway_api.py::TestApiGatewayVpcLink::test_update_vpc_link_invalid_id": { + "last_validated_date": "2025-12-15T04:55:32+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.1, + "teardown": 0.02, + "total": 0.12 + } + }, + "tests/aws/services/apigateway/test_apigateway_api.py::TestApiGatewayVpcLink::test_vpc_link_lifecycle": { + "last_validated_date": "2025-12-15T08:04:55+00:00", + "durations_in_seconds": { + "setup": 1.52, + "call": 548.36, + "teardown": 0.56, + "total": 550.44 + } + }, + "tests/aws/services/apigateway/test_apigateway_api.py::TestApigatewayIntegration::test_create_integration_with_vpc_link": { + "last_validated_date": "2025-10-08T09:05:56+00:00", + "durations_in_seconds": { + "setup": 0.84, + "call": 1.59, + "teardown": 0.63, + "total": 3.06 + } + }, + "tests/aws/services/apigateway/test_apigateway_api.py::TestApigatewayIntegration::test_get_integration_non_existent": { + "last_validated_date": "2025-11-18T17:03:33+00:00", + "durations_in_seconds": { + "setup": 0.83, + "call": 1.6, + "teardown": 0.38, + "total": 2.81 + } + }, + "tests/aws/services/apigateway/test_apigateway_api.py::TestApigatewayIntegration::test_put_integration_request_parameter_bool_type": { + "last_validated_date": "2024-12-12T10:46:41+00:00" + }, + "tests/aws/services/apigateway/test_apigateway_api.py::TestApigatewayIntegration::test_put_integration_response_templates": { + "last_validated_date": "2026-02-12T16:25:03+00:00", + "durations_in_seconds": { + "setup": 0.9, + "call": 1.65, + "teardown": 0.29, + "total": 2.84 + } + }, + "tests/aws/services/apigateway/test_apigateway_api.py::TestApigatewayIntegration::test_put_integration_wrong_type": { + "last_validated_date": "2024-04-15T20:48:47+00:00" + }, + "tests/aws/services/apigateway/test_apigateway_api.py::TestApigatewayIntegrationResponse::test_delete_integration_response_errors": { "last_validated_date": "2025-08-21T17:53:19+00:00", "durations_in_seconds": { "setup": 0.84, @@ -254,7 +374,7 @@ "total": 3.31 } }, - "tests/aws/services/apigateway/test_apigateway_api.py::TestApigatewayIntegration::test_integration_response_invalid_integration": { + "tests/aws/services/apigateway/test_apigateway_api.py::TestApigatewayIntegrationResponse::test_integration_response_invalid_integration": { "last_validated_date": "2025-06-26T11:21:05+00:00", "durations_in_seconds": { "setup": 1.63, @@ -263,7 +383,7 @@ "total": 3.2 } }, - "tests/aws/services/apigateway/test_apigateway_api.py::TestApigatewayIntegration::test_integration_response_invalid_responsetemplates": { + "tests/aws/services/apigateway/test_apigateway_api.py::TestApigatewayIntegrationResponse::test_integration_response_invalid_responsetemplates": { "last_validated_date": "2025-06-18T13:03:29+00:00", "durations_in_seconds": { "setup": 1.43, @@ -272,7 +392,7 @@ "total": 3.8 } }, - "tests/aws/services/apigateway/test_apigateway_api.py::TestApigatewayIntegration::test_integration_response_invalid_statuscode": { + "tests/aws/services/apigateway/test_apigateway_api.py::TestApigatewayIntegrationResponse::test_integration_response_invalid_statuscode": { "last_validated_date": "2025-06-18T11:51:51+00:00", "durations_in_seconds": { "setup": 1.61, @@ -281,7 +401,7 @@ "total": 3.33 } }, - "tests/aws/services/apigateway/test_apigateway_api.py::TestApigatewayIntegration::test_integration_response_wrong_api": { + "tests/aws/services/apigateway/test_apigateway_api.py::TestApigatewayIntegrationResponse::test_integration_response_wrong_api": { "last_validated_date": "2025-06-18T12:28:55+00:00", "durations_in_seconds": { "setup": 1.08, @@ -290,7 +410,7 @@ "total": 1.4 } }, - "tests/aws/services/apigateway/test_apigateway_api.py::TestApigatewayIntegration::test_integration_response_wrong_method": { + "tests/aws/services/apigateway/test_apigateway_api.py::TestApigatewayIntegrationResponse::test_integration_response_wrong_method": { "last_validated_date": "2025-06-18T11:47:00+00:00", "durations_in_seconds": { "setup": 1.42, @@ -299,7 +419,7 @@ "total": 2.96 } }, - "tests/aws/services/apigateway/test_apigateway_api.py::TestApigatewayIntegration::test_integration_response_wrong_resource": { + "tests/aws/services/apigateway/test_apigateway_api.py::TestApigatewayIntegrationResponse::test_integration_response_wrong_resource": { "last_validated_date": "2025-06-18T12:28:25+00:00", "durations_in_seconds": { "setup": 1.35, @@ -308,7 +428,7 @@ "total": 2.98 } }, - "tests/aws/services/apigateway/test_apigateway_api.py::TestApigatewayIntegration::test_integration_response_wrong_status_code": { + "tests/aws/services/apigateway/test_apigateway_api.py::TestApigatewayIntegrationResponse::test_integration_response_wrong_status_code": { "last_validated_date": "2025-06-26T11:21:43+00:00", "durations_in_seconds": { "setup": 1.58, @@ -317,7 +437,7 @@ "total": 3.4 } }, - "tests/aws/services/apigateway/test_apigateway_api.py::TestApigatewayIntegration::test_lifecycle_integration_response": { + "tests/aws/services/apigateway/test_apigateway_api.py::TestApigatewayIntegrationResponse::test_lifecycle_integration_response": { "last_validated_date": "2025-06-11T09:12:54+00:00", "durations_in_seconds": { "setup": 1.49, @@ -326,7 +446,10 @@ "total": 4.21 } }, - "tests/aws/services/apigateway/test_apigateway_api.py::TestApigatewayIntegration::test_lifecycle_method_response": { + "tests/aws/services/apigateway/test_apigateway_api.py::TestApigatewayIntegrationResponse::test_put_integration_response_validation": { + "last_validated_date": "2025-03-03T14:27:24+00:00" + }, + "tests/aws/services/apigateway/test_apigateway_api.py::TestApigatewayMethodResponse::test_lifecycle_method_response": { "last_validated_date": "2025-07-01T15:48:02+00:00", "durations_in_seconds": { "setup": 1.38, @@ -335,16 +458,7 @@ "total": 4.55 } }, - "tests/aws/services/apigateway/test_apigateway_api.py::TestApigatewayIntegration::test_put_integration_request_parameter_bool_type": { - "last_validated_date": "2024-12-12T10:46:41+00:00" - }, - "tests/aws/services/apigateway/test_apigateway_api.py::TestApigatewayIntegration::test_put_integration_response_validation": { - "last_validated_date": "2025-03-03T14:27:24+00:00" - }, - "tests/aws/services/apigateway/test_apigateway_api.py::TestApigatewayIntegration::test_put_integration_wrong_type": { - "last_validated_date": "2024-04-15T20:48:47+00:00" - }, - "tests/aws/services/apigateway/test_apigateway_api.py::TestApigatewayIntegration::test_update_method_lack_response_parameters_and_models": { + "tests/aws/services/apigateway/test_apigateway_api.py::TestApigatewayMethodResponse::test_update_method_lack_response_parameters_and_models": { "last_validated_date": "2025-07-01T15:48:38+00:00", "durations_in_seconds": { "setup": 1.4, @@ -353,7 +467,7 @@ "total": 3.77 } }, - "tests/aws/services/apigateway/test_apigateway_api.py::TestApigatewayIntegration::test_update_method_response": { + "tests/aws/services/apigateway/test_apigateway_api.py::TestApigatewayMethodResponse::test_update_method_response": { "last_validated_date": "2025-06-30T12:42:31+00:00", "durations_in_seconds": { "setup": 1.26, @@ -362,7 +476,7 @@ "total": 3.24 } }, - "tests/aws/services/apigateway/test_apigateway_api.py::TestApigatewayIntegration::test_update_method_response_negative_tests": { + "tests/aws/services/apigateway/test_apigateway_api.py::TestApigatewayMethodResponse::test_update_method_response_negative_tests": { "last_validated_date": "2025-06-30T15:24:43+00:00", "durations_in_seconds": { "setup": 1.53, @@ -371,7 +485,7 @@ "total": 4.41 } }, - "tests/aws/services/apigateway/test_apigateway_api.py::TestApigatewayIntegration::test_update_method_response_wrong_operations": { + "tests/aws/services/apigateway/test_apigateway_api.py::TestApigatewayMethodResponse::test_update_method_response_wrong_operations": { "last_validated_date": "2025-06-30T13:54:57+00:00", "durations_in_seconds": { "setup": 1.36, @@ -380,7 +494,7 @@ "total": 4.13 } }, - "tests/aws/services/apigateway/test_apigateway_api.py::TestApigatewayIntegration::test_update_method_wrong_param_names": { + "tests/aws/services/apigateway/test_apigateway_api.py::TestApigatewayMethodResponse::test_update_method_wrong_param_names": { "last_validated_date": "2025-07-01T15:49:16+00:00", "durations_in_seconds": { "setup": 1.44, diff --git a/tests/aws/services/apigateway/test_apigateway_basic.py b/tests/aws/services/apigateway/test_apigateway_basic.py index 5fc8bc1de3173..2512c51b7f68b 100644 --- a/tests/aws/services/apigateway/test_apigateway_basic.py +++ b/tests/aws/services/apigateway/test_apigateway_basic.py @@ -142,7 +142,7 @@ def test_create_rest_api_with_custom_id(self, create_rest_apigw, url_function, a if not is_next_gen_api() and url_function == localstack_path_based_url: pytest.skip("This URL type is not supported in the legacy implementation") apigw_name = f"gw-{short_uid()}" - test_id = "testId123" + test_id = "test-id123" api_id, name, _ = create_rest_apigw(name=apigw_name, tags={TAG_KEY_CUSTOM_ID: test_id}) assert test_id == api_id assert apigw_name == name @@ -160,6 +160,20 @@ def test_create_rest_api_with_custom_id(self, create_rest_apigw, url_function, a assert response.ok assert response._content == b'{"echo": "foobar", "response": "mocked"}' + @markers.aws.only_localstack + # This is not a possible feature on aws. + def test_create_rest_api_with_invalid_custom_id(self, create_rest_apigw, aws_client): + apigw_name = f"gw-{short_uid()}" + test_id = "testId123" + with pytest.raises(ClientError) as exc: + create_rest_apigw(name=apigw_name, tags={TAG_KEY_CUSTOM_ID: test_id}) + + assert exc.value.response["Error"]["Code"] == "BadRequestException" + assert ( + exc.value.response["Error"]["Message"] + == f"The RestApiId '{test_id}' cannot contain uppercase characters" + ) + @markers.aws.validated def test_update_rest_api_deployment(self, create_rest_apigw, aws_client, snapshot): snapshot.add_transformer(snapshot.transform.key_value("id")) @@ -301,6 +315,7 @@ def test_api_gateway_lambda_integration_aws_type( @pytest.mark.parametrize("disable_custom_cors", [True, False]) @pytest.mark.parametrize("origin", ["http://allowed", "http://denied"]) @markers.aws.only_localstack + @markers.requires_in_process def test_invoke_endpoint_cors_headers( self, url_type, disable_custom_cors, origin, monkeypatch, aws_client ): @@ -1504,10 +1519,11 @@ class TestTagging: def test_tag_api(self, create_rest_apigw, aws_client, account_id, region_name): api_name = f"api-{short_uid()}" tags = {"foo": "bar"} + custom_id = "c0stiom1d" # add resource tags - api_id, _, _ = create_rest_apigw(name=api_name, tags={TAG_KEY_CUSTOM_ID: "c0stIOm1d"}) - assert api_id == "c0stIOm1d" + api_id, _, _ = create_rest_apigw(name=api_name, tags={TAG_KEY_CUSTOM_ID: custom_id}) + assert api_id == custom_id api_arn = arns.apigateway_restapi_arn(api_id, account_id, region_name) aws_client.apigateway.tag_resource(resourceArn=api_arn, tags=tags) diff --git a/tests/aws/services/apigateway/test_apigateway_custom_ids.py b/tests/aws/services/apigateway/test_apigateway_custom_ids.py index 0accdcfdfd103..1df103348b91b 100644 --- a/tests/aws/services/apigateway/test_apigateway_custom_ids.py +++ b/tests/aws/services/apigateway/test_apigateway_custom_ids.py @@ -1,3 +1,5 @@ +import pytest +from botocore.exceptions import ClientError from moto.apigateway.utils import ( ApigwApiKeyIdentifier, ApigwResourceIdentifier, @@ -7,7 +9,7 @@ from localstack.testing.pytest import markers from localstack.utils.strings import long_uid, short_uid -API_ID = "ApiId" +API_ID = "api-id" ROOT_RESOURCE_ID = "RootId" PET_1_RESOURCE_ID = "Pet1Id" PET_2_RESOURCE_ID = "Pet2Id" @@ -16,6 +18,7 @@ # Custom ids can't be set on aws. @markers.aws.only_localstack +@markers.requires_in_process def test_apigateway_custom_ids( aws_client, set_resource_custom_id, create_rest_apigw, account_id, region_name, cleanups ): @@ -59,3 +62,23 @@ def test_apigateway_custom_ids( assert pet_resource_1["id"] == PET_1_RESOURCE_ID assert pet_resource_2["id"] == PET_2_RESOURCE_ID assert api_key["id"] == API_KEY_ID + + +@markers.aws.only_localstack +@markers.requires_in_process +def test_apigateway_invalid_rest_api_custom_id( + aws_client, set_resource_custom_id, create_rest_apigw, account_id, region_name, cleanups +): + rest_api_name = f"apigw-{short_uid()}" + bad_api_id = "UpperCaseApi" + + set_resource_custom_id( + ApigwRestApiIdentifier(account_id, region_name, rest_api_name), bad_api_id + ) + with pytest.raises(ClientError) as exc: + create_rest_apigw(name=rest_api_name) + assert exc.value.response["Error"]["Code"] == "BadRequestException" + assert ( + exc.value.response["Error"]["Message"] + == f"The RestApiId '{bad_api_id}' cannot contain uppercase characters" + ) diff --git a/tests/aws/services/apigateway/test_apigateway_extended.py b/tests/aws/services/apigateway/test_apigateway_extended.py index c95965db241c1..555bcb882f2da 100644 --- a/tests/aws/services/apigateway/test_apigateway_extended.py +++ b/tests/aws/services/apigateway/test_apigateway_extended.py @@ -46,8 +46,6 @@ def _create(**kwargs): @markers.snapshot.skip_snapshot_verify( paths=[ "$..body.host", - # TODO: not returned by LS - "$..endpointConfiguration.ipAddressType", ] ) def test_export_swagger_openapi(aws_client, snapshot, import_apigw, import_file, region_name): @@ -91,8 +89,6 @@ def test_export_swagger_openapi(aws_client, snapshot, import_apigw, import_file, @markers.snapshot.skip_snapshot_verify( paths=[ "$..body.servers..url", - # TODO: not returned by LS - "$..endpointConfiguration.ipAddressType", ] ) def test_export_oas30_openapi(aws_client, snapshot, import_apigw, region_name, import_file): @@ -272,7 +268,7 @@ def test_get_usage_plan_api_keys(self, aws_client, apigw_create_api_key, snapsho snapshot.match("create-api-key", create_api_key) create_api_key_2 = apigw_create_api_key(name=api_key_name_2) - snapshot.match("create-api-key-2", create_api_key) + snapshot.match("create-api-key-2", create_api_key_2) get_api_keys_after_create = aws_client.apigateway.get_api_keys() snapshot.match("get-api-keys-after-create-1", get_api_keys_after_create) @@ -332,3 +328,141 @@ def test_get_usage_plan_api_keys(self, aws_client, apigw_create_api_key, snapsho get_up_keys_bad_d = aws_client.apigateway.get_usage_plan_keys(usagePlanId="bad-id") snapshot.match("get-up-keys-bad-usage-plan", get_up_keys_bad_d) + + @markers.aws.validated + def test_negative_get_usage_plan_api_keys( + self, aws_client, apigw_create_api_key, snapshot, cleanup_api_keys, cleanups + ): + snapshot.add_transformers_list( + [ + snapshot.transform.key_value("id"), + snapshot.transform.key_value("value"), + snapshot.transform.key_value("name"), + ] + ) + + get_keys = aws_client.apigateway.get_api_keys(limit=-1) + snapshot.match("get-api-keys-invalid-limit", get_keys) + + create_api_key = apigw_create_api_key(name="key-enabled-false", enabled=False) + assert not create_api_key["enabled"] + snapshot.match("create-api-key", create_api_key) + + update_resp = aws_client.apigateway.update_api_key( + apiKey=create_api_key["id"], + patchOperations=[{"op": "replace", "path": "/name", "value": "new-name"}], + ) + snapshot.match("update-api-key-name", update_resp) + + @markers.aws.validated + def test_create_api_key_with_invalid_name( + self, aws_client, snapshot, cleanup_api_keys, cleanups + ): + snapshot.add_transformers_list( + [ + snapshot.transform.key_value("id"), + snapshot.transform.key_value("value"), + ] + ) + long_name = "a" * 1025 + with pytest.raises(ClientError) as e: + aws_client.apigateway.create_api_key(name=long_name) + snapshot.match("create-api-key-name-too-long", e.value.response) + + create_empty_name = aws_client.apigateway.create_api_key(name="") + snapshot.match("create-api-key-empty-name", create_empty_name) + + create_no_name = aws_client.apigateway.create_api_key() + snapshot.match("create-api-key-no-name", create_no_name) + + @markers.aws.validated + def test_create_api_key_with_invalid_value( + self, aws_client, snapshot, cleanup_api_keys, cleanups + ): + snapshot.add_transformers_list([snapshot.transform.key_value("id")]) + shot_value = "short" + with pytest.raises(ClientError) as e: + aws_client.apigateway.create_api_key(value=shot_value) + snapshot.match("create-api-key-short-value", e.value.response) + + long_value = "a" * 129 + with pytest.raises(ClientError) as e: + aws_client.apigateway.create_api_key(value=long_value) + snapshot.match("create-api-key-invalid-value-too-long", e.value.response) + + snapshot.add_transformers_list( + [ + snapshot.transform.key_value("id"), + snapshot.transform.key_value("value"), + ] + ) + empty_value = aws_client.apigateway.create_api_key(value="") + snapshot.add_transformers_list([snapshot.transform.key_value("id")]) + snapshot.match("create-api-key-empty-value", empty_value) + + @markers.aws.validated + def test_update_api_key_invalid_description_length( + self, aws_client, snapshot, apigw_create_api_key, cleanup_api_keys, cleanups + ): + long_description = "a" * 125001 + with pytest.raises(ClientError) as e: + apigw_create_api_key(description=long_description) + snapshot.match("create-api-key-description-too-long", e.value.response) + + api_key = apigw_create_api_key() + api_key_id = api_key["id"] + + long_description = "a" * 125001 + with pytest.raises(ClientError) as e: + aws_client.apigateway.update_api_key( + apiKey=api_key_id, + patchOperations=[ + {"op": "replace", "path": "/description", "value": long_description} + ], + ) + snapshot.match("update-api-key-description-too-long", e.value.response) + + @markers.aws.validated + def test_update_api_key_invalid_enabled_type( + self, aws_client, snapshot, apigw_create_api_key, cleanup_api_keys, cleanups + ): + snapshot.add_transformers_list([snapshot.transform.key_value("id")]) + api_key = apigw_create_api_key() + api_key_id = api_key["id"] + + invalid_enabled_type = aws_client.apigateway.update_api_key( + apiKey=api_key_id, + patchOperations=[{"op": "replace", "path": "/enabled", "value": "not-a-boolean"}], + ) + snapshot.match("update-api-key-invalid-enabled-type", invalid_enabled_type) + + @markers.aws.validated + def test_update_api_key_immutable_field( + self, aws_client, snapshot, apigw_create_api_key, cleanup_api_keys, cleanups + ): + api_key = apigw_create_api_key() + api_key_id = api_key["id"] + + with pytest.raises(ClientError) as e: + aws_client.apigateway.update_api_key( + apiKey=api_key_id, + patchOperations=[{"op": "replace", "path": "/id", "value": "new-id"}], + ) + snapshot.match("update-api-key-immutable-field", e.value.response) + + @markers.aws.validated + def test_create_usage_plan_with_throttle( + self, aws_client, snapshot, cleanup_api_keys, cleanups + ): + snapshot.add_transformer( + [ + snapshot.transform.key_value("id"), + snapshot.transform.key_value("name"), + ] + ) + + invalid_burst_limit = aws_client.apigateway.create_usage_plan( + name=f"invalid-throttle-burst-gt-rate-{short_uid()}", + throttle={"rateLimit": 10, "burstLimit": 20}, + ) + snapshot.match("create-usage-plan-burst-gt-rate", invalid_burst_limit) diff --git a/tests/aws/services/apigateway/test_apigateway_extended.snapshot.json b/tests/aws/services/apigateway/test_apigateway_extended.snapshot.json index 76db5eff4a01b..f22d6adb87600 100644 --- a/tests/aws/services/apigateway/test_apigateway_extended.snapshot.json +++ b/tests/aws/services/apigateway/test_apigateway_extended.snapshot.json @@ -1847,7 +1847,7 @@ } }, "tests/aws/services/apigateway/test_apigateway_extended.py::TestApigatewayApiKeysCrud::test_get_usage_plan_api_keys": { - "recorded-date": "10-10-2024, 18:54:42", + "recorded-date": "26-09-2025, 16:23:51", "recorded-content": { "get-api-keys": { "items": [], @@ -1872,11 +1872,11 @@ "create-api-key-2": { "createdDate": "datetime", "enabled": false, - "id": "", + "id": "", "lastUpdatedDate": "datetime", - "name": "", + "name": "", "stageKeys": [], - "value": "", + "value": "", "ResponseMetadata": { "HTTPHeaders": {}, "HTTPStatusCode": 201 @@ -2025,5 +2025,200 @@ } } } + }, + "tests/aws/services/apigateway/test_apigateway_extended.py::TestApigatewayApiKeysCrud::test_negative_get_usage_plan_api_keys": { + "recorded-date": "16-07-2025, 15:26:48", + "recorded-content": { + "get-api-keys-invalid-limit": { + "items": [], + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "create-api-key": { + "createdDate": "datetime", + "enabled": false, + "id": "", + "lastUpdatedDate": "datetime", + "name": "", + "stageKeys": [], + "value": "", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 201 + } + }, + "update-api-key-name": { + "createdDate": "datetime", + "enabled": false, + "id": "", + "lastUpdatedDate": "datetime", + "name": "", + "stageKeys": [], + "tags": {}, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/apigateway/test_apigateway_extended.py::TestApigatewayApiKeysCrud::test_create_api_key_with_invalid_name": { + "recorded-date": "17-07-2025, 13:16:59", + "recorded-content": { + "create-api-key-name-too-long": { + "Error": { + "Code": "BadRequestException", + "Message": "Invalid API Key name, can be at most 1024 characters." + }, + "message": "Invalid API Key name, can be at most 1024 characters.", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + }, + "create-api-key-empty-name": { + "createdDate": "datetime", + "enabled": false, + "id": "", + "lastUpdatedDate": "datetime", + "stageKeys": [], + "value": "", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 201 + } + }, + "create-api-key-no-name": { + "createdDate": "datetime", + "enabled": false, + "id": "", + "lastUpdatedDate": "datetime", + "stageKeys": [], + "value": "", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 201 + } + } + } + }, + "tests/aws/services/apigateway/test_apigateway_extended.py::TestApigatewayApiKeysCrud::test_create_api_key_with_invalid_value": { + "recorded-date": "17-07-2025, 13:59:45", + "recorded-content": { + "create-api-key-short-value": { + "Error": { + "Code": "BadRequestException", + "Message": "API Key value should be at least 20 characters" + }, + "message": "API Key value should be at least 20 characters", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + }, + "create-api-key-invalid-value-too-long": { + "Error": { + "Code": "BadRequestException", + "Message": "API Key value exceeds maximum size of 128 characters" + }, + "message": "API Key value exceeds maximum size of 128 characters", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + }, + "create-api-key-empty-value": { + "createdDate": "datetime", + "enabled": false, + "id": "", + "lastUpdatedDate": "datetime", + "stageKeys": [], + "value": "", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 201 + } + } + } + }, + "tests/aws/services/apigateway/test_apigateway_extended.py::TestApigatewayApiKeysCrud::test_update_api_key_invalid_description_length": { + "recorded-date": "17-07-2025, 15:02:27", + "recorded-content": { + "create-api-key-description-too-long": { + "Error": { + "Code": "BadRequestException", + "Message": "Invalid API Key description specified." + }, + "message": "Invalid API Key description specified.", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + }, + "update-api-key-description-too-long": { + "Error": { + "Code": "BadRequestException", + "Message": "Invalid API Key description specified." + }, + "message": "Invalid API Key description specified.", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + } + } + }, + "tests/aws/services/apigateway/test_apigateway_extended.py::TestApigatewayApiKeysCrud::test_update_api_key_invalid_enabled_type": { + "recorded-date": "17-07-2025, 15:33:05", + "recorded-content": { + "update-api-key-invalid-enabled-type": { + "createdDate": "datetime", + "enabled": false, + "id": "", + "lastUpdatedDate": "datetime", + "stageKeys": [], + "tags": {}, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/apigateway/test_apigateway_extended.py::TestApigatewayApiKeysCrud::test_update_api_key_immutable_field": { + "recorded-date": "18-07-2025, 14:31:57", + "recorded-content": { + "update-api-key-immutable-field": { + "Error": { + "Code": "BadRequestException", + "Message": "Invalid patch path '/id' specified for op 'replace'. Must be one of: [/description, /enabled, /name, /customerId]" + }, + "message": "Invalid patch path '/id' specified for op 'replace'. Must be one of: [/description, /enabled, /name, /customerId]", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + } + } + }, + "tests/aws/services/apigateway/test_apigateway_extended.py::TestApigatewayApiKeysCrud::test_create_usage_plan_with_throttle": { + "recorded-date": "26-09-2025, 15:15:33", + "recorded-content": { + "create-usage-plan-burst-gt-rate": { + "apiStages": [], + "id": "", + "name": "", + "throttle": { + "burstLimit": 20, + "rateLimit": 10.0 + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 201 + } + } + } } } diff --git a/tests/aws/services/apigateway/test_apigateway_extended.validation.json b/tests/aws/services/apigateway/test_apigateway_extended.validation.json index 1486731f72d07..8c1979af0efb9 100644 --- a/tests/aws/services/apigateway/test_apigateway_extended.validation.json +++ b/tests/aws/services/apigateway/test_apigateway_extended.validation.json @@ -1,9 +1,78 @@ { + "tests/aws/services/apigateway/test_apigateway_extended.py::TestApigatewayApiKeysCrud::test_create_api_key_with_invalid_name": { + "last_validated_date": "2025-09-26T15:36:15+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.43, + "teardown": 0.0, + "total": 0.43 + } + }, + "tests/aws/services/apigateway/test_apigateway_extended.py::TestApigatewayApiKeysCrud::test_create_api_key_with_invalid_value": { + "last_validated_date": "2025-09-26T15:36:16+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.39, + "teardown": 0.0, + "total": 0.39 + } + }, + "tests/aws/services/apigateway/test_apigateway_extended.py::TestApigatewayApiKeysCrud::test_create_usage_plan_with_throttle": { + "last_validated_date": "2025-09-26T15:36:19+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.41, + "teardown": 0.0, + "total": 0.41 + } + }, "tests/aws/services/apigateway/test_apigateway_extended.py::TestApigatewayApiKeysCrud::test_get_api_keys": { "last_validated_date": "2024-10-10T18:53:36+00:00" }, "tests/aws/services/apigateway/test_apigateway_extended.py::TestApigatewayApiKeysCrud::test_get_usage_plan_api_keys": { - "last_validated_date": "2024-10-10T18:54:41+00:00" + "last_validated_date": "2025-09-26T16:25:01+00:00", + "durations_in_seconds": { + "setup": 0.88, + "call": 4.05, + "teardown": 0.59, + "total": 5.52 + } + }, + "tests/aws/services/apigateway/test_apigateway_extended.py::TestApigatewayApiKeysCrud::test_negative_get_usage_plan_api_keys": { + "last_validated_date": "2025-09-26T15:36:15+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.51, + "teardown": 0.24, + "total": 0.75 + } + }, + "tests/aws/services/apigateway/test_apigateway_extended.py::TestApigatewayApiKeysCrud::test_update_api_key_immutable_field": { + "last_validated_date": "2025-09-26T15:36:18+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.29, + "teardown": 0.32, + "total": 0.61 + } + }, + "tests/aws/services/apigateway/test_apigateway_extended.py::TestApigatewayApiKeysCrud::test_update_api_key_invalid_description_length": { + "last_validated_date": "2025-09-26T15:36:17+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.66, + "teardown": 0.29, + "total": 0.95 + } + }, + "tests/aws/services/apigateway/test_apigateway_extended.py::TestApigatewayApiKeysCrud::test_update_api_key_invalid_enabled_type": { + "last_validated_date": "2025-09-26T15:36:18+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.55, + "teardown": 0.31, + "total": 0.86 + } }, "tests/aws/services/apigateway/test_apigateway_extended.py::test_export_oas30_openapi[TEST_IMPORT_PETSTORE_SWAGGER]": { "last_validated_date": "2025-05-06T18:34:11+00:00" diff --git a/tests/aws/services/apigateway/test_apigateway_http.py b/tests/aws/services/apigateway/test_apigateway_http.py index 5d81a181e82bd..6d946469db042 100644 --- a/tests/aws/services/apigateway/test_apigateway_http.py +++ b/tests/aws/services/apigateway/test_apigateway_http.py @@ -245,6 +245,8 @@ def invoke_api(url: str, method: str) -> dict: "$..headers.x-amzn-remapped-x-amzn-requestid", # TODO AWS doesn't seems to add Server to lambda invocation for lambda url "$..headers.x-amzn-remapped-server", + # The value of Accept-Encoding can change when the zstandard package is present + "$..content.headers.accept-encoding", ] ) @pytest.mark.skipif( diff --git a/tests/aws/services/apigateway/test_apigateway_import.py b/tests/aws/services/apigateway/test_apigateway_import.py index 3b3a9f83d6c12..668989ee64d64 100644 --- a/tests/aws/services/apigateway/test_apigateway_import.py +++ b/tests/aws/services/apigateway/test_apigateway_import.py @@ -964,3 +964,28 @@ def test_put_rest_api_mode_binary_media_types( if is_aws_cloud(): # waiting before cleaning up to avoid TooManyRequests, as we create multiple REST APIs time.sleep(15) + + @markers.aws.validated + def test_import_api_bad_file(self, aws_client, import_apigw, apigw_create_rest_api, snapshot): + bad_yaml_string = """test: + value: + - "value ... \"escaped\": $var, \"dt\": $(var +"%a")}\" + """ + + bad_json_string = "{'key:value}" + + with pytest.raises(ClientError) as e: + import_apigw(body=bad_yaml_string) + snapshot.match("import-api-bad-yaml-file", e.value.response) + + with pytest.raises(ClientError) as e: + import_apigw(body=bad_json_string) + snapshot.match("import-api-bad-json-file", e.value.response) + + with pytest.raises(ClientError) as e: + aws_client.apigateway.put_rest_api(restApiId=short_uid(), body=bad_yaml_string) + snapshot.match("put-rest-api-bad-yaml-file", e.value.response) + + with pytest.raises(ClientError) as e: + aws_client.apigateway.put_rest_api(restApiId=short_uid(), body=bad_json_string) + snapshot.match("put-rest-api-bad-json-file", e.value.response) diff --git a/tests/aws/services/apigateway/test_apigateway_import.snapshot.json b/tests/aws/services/apigateway/test_apigateway_import.snapshot.json index 4fe5b2643b022..fe6ded88a898f 100644 --- a/tests/aws/services/apigateway/test_apigateway_import.snapshot.json +++ b/tests/aws/services/apigateway/test_apigateway_import.snapshot.json @@ -5474,5 +5474,54 @@ } } } + }, + "tests/aws/services/apigateway/test_apigateway_import.py::TestApiGatewayImportRestApi::test_import_api_bad_file": { + "recorded-date": "18-11-2025, 17:29:30", + "recorded-content": { + "import-api-bad-yaml-file": { + "Error": { + "Code": "BadRequestException", + "Message": "Invalid OpenAPI input." + }, + "message": "Invalid OpenAPI input.", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + }, + "import-api-bad-json-file": { + "Error": { + "Code": "BadRequestException", + "Message": "Invalid OpenAPI input." + }, + "message": "Invalid OpenAPI input.", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + }, + "put-rest-api-bad-yaml-file": { + "Error": { + "Code": "BadRequestException", + "Message": "Invalid OpenAPI input." + }, + "message": "Invalid OpenAPI input.", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + }, + "put-rest-api-bad-json-file": { + "Error": { + "Code": "BadRequestException", + "Message": "Invalid OpenAPI input." + }, + "message": "Invalid OpenAPI input.", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + } + } } } diff --git a/tests/aws/services/apigateway/test_apigateway_import.validation.json b/tests/aws/services/apigateway/test_apigateway_import.validation.json index 15d0d347311eb..d61573549bde6 100644 --- a/tests/aws/services/apigateway/test_apigateway_import.validation.json +++ b/tests/aws/services/apigateway/test_apigateway_import.validation.json @@ -17,6 +17,15 @@ "total": 22.98 } }, + "tests/aws/services/apigateway/test_apigateway_import.py::TestApiGatewayImportRestApi::test_import_api_bad_file": { + "last_validated_date": "2025-11-18T17:29:30+00:00", + "durations_in_seconds": { + "setup": 0.51, + "call": 0.97, + "teardown": 0.01, + "total": 1.49 + } + }, "tests/aws/services/apigateway/test_apigateway_import.py::TestApiGatewayImportRestApi::test_import_rest_api": { "last_validated_date": "2025-07-02T16:22:33+00:00", "durations_in_seconds": { diff --git a/tests/aws/services/apigateway/test_apigateway_integrations.py b/tests/aws/services/apigateway/test_apigateway_integrations.py index 40ea1a556f53e..34cd6d15fac8a 100644 --- a/tests/aws/services/apigateway/test_apigateway_integrations.py +++ b/tests/aws/services/apigateway/test_apigateway_integrations.py @@ -887,15 +887,6 @@ def invoke_api(url) -> requests.Response: ) -@pytest.fixture -def default_vpc(aws_client): - vpcs = aws_client.ec2.describe_vpcs() - for vpc in vpcs["Vpcs"]: - if vpc.get("IsDefault"): - return vpc - raise Exception("Default VPC not found") - - @pytest.fixture def create_vpc_endpoint(default_vpc, aws_client): endpoints = [] diff --git a/tests/aws/services/apigateway/test_apigateway_lambda.py b/tests/aws/services/apigateway/test_apigateway_lambda.py index 8aa53aaca9890..0cdd0defe1c6b 100644 --- a/tests/aws/services/apigateway/test_apigateway_lambda.py +++ b/tests/aws/services/apigateway/test_apigateway_lambda.py @@ -59,7 +59,14 @@ def handler(event, context, *args): @markers.aws.validated -@markers.snapshot.skip_snapshot_verify(paths=CLOUDFRONT_SKIP_HEADERS) +@markers.snapshot.skip_snapshot_verify( + paths=CLOUDFRONT_SKIP_HEADERS + + [ + # The value of Accept-Encoding can change when the zstandard package is present + "$..headers.Accept-Encoding", + "$..multiValueHeaders.Accept-Encoding", + ] +) @markers.snapshot.skip_snapshot_verify( condition=lambda: not is_next_gen_api(), paths=[ @@ -1244,7 +1251,14 @@ def _invoke_url(url): @markers.aws.validated -@markers.snapshot.skip_snapshot_verify(paths=CLOUDFRONT_SKIP_HEADERS) +@markers.snapshot.skip_snapshot_verify( + paths=CLOUDFRONT_SKIP_HEADERS + + [ + # The value of Accept-Encoding can change when the zstandard package is present + "$..content.headers.Accept-Encoding", + "$..content.multiValueHeaders.Accept-Encoding", + ] +) @markers.snapshot.skip_snapshot_verify( condition=lambda: not is_next_gen_api(), paths=[ diff --git a/tests/aws/services/cloudformation/api/test_changesets.py b/tests/aws/services/cloudformation/api/test_changesets.py index 1888fbd7b8eff..086efdfbf8bff 100644 --- a/tests/aws/services/cloudformation/api/test_changesets.py +++ b/tests/aws/services/cloudformation/api/test_changesets.py @@ -1487,3 +1487,40 @@ def test_update_change_set_with_aws_novalue_repro(aws_client, cleanups): {"ParameterKey": "FallbackBucketName", "ParameterValue": fallback_bucket}, ], ) + + +@markers.aws.validated +@skip_if_legacy_engine +def test_changeset_for_deleted_stack(aws_client, deploy_cfn_template, snapshot): + parameter_resource_body = { + "Type": "AWS::SSM::Parameter", + "Properties": {"Type": "String", "Value": "Test"}, + } + template = json.dumps( + {"Resources": {f"Parameter{i}": parameter_resource_body for i in range(5)}} + ) + + stack = deploy_cfn_template(template=template) + aws_client.cloudformation.delete_stack(StackName=stack.stack_id) + + with pytest.raises(ClientError) as in_progress_ex: + aws_client.cloudformation.create_change_set( + StackName=stack.stack_id, + ChangeSetName="test", + TemplateBody=template, + ChangeSetType="UPDATE", + ) + + aws_client.cloudformation.get_waiter("stack_delete_complete").wait(StackName=stack.stack_id) + + with pytest.raises(ClientError) as complete_ex: + aws_client.cloudformation.create_change_set( + StackName=stack.stack_id, + ChangeSetName="test", + TemplateBody=template, + ChangeSetType="UPDATE", + ) + + snapshot.add_transformer(snapshot.transform.regex(stack.stack_id, "")) + snapshot.match("ErrorForInProgress", in_progress_ex.value.response) + snapshot.match("ErrorForComplete", complete_ex.value.response) diff --git a/tests/aws/services/cloudformation/api/test_changesets.snapshot.json b/tests/aws/services/cloudformation/api/test_changesets.snapshot.json index 29bcbbac23a46..4affa37115e01 100644 --- a/tests/aws/services/cloudformation/api/test_changesets.snapshot.json +++ b/tests/aws/services/cloudformation/api/test_changesets.snapshot.json @@ -655,5 +655,59 @@ } } } + }, + "tests/aws/services/cloudformation/api/test_changesets.py::test_create_changeset_for_deleted_stack": { + "recorded-date": "10-10-2025, 18:02:05", + "recorded-content": { + "ErrorForCreate": { + "Error": { + "Code": "ValidationError", + "Message": "Stack [] already exists and cannot be created again with the changeSet [test].", + "Type": "Sender" + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + }, + "ErrorForUpdate": { + "Error": { + "Code": "ValidationError", + "Message": "Stack: is in DELETE_COMPLETE state and can not be updated.", + "Type": "Sender" + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + } + } + }, + "tests/aws/services/cloudformation/api/test_changesets.py::test_changeset_for_deleted_stack": { + "recorded-date": "10-10-2025, 18:49:37", + "recorded-content": { + "ErrorForInProgress": { + "Error": { + "Code": "ValidationError", + "Message": "Stack: is in DELETE_IN_PROGRESS state and can not be updated.", + "Type": "Sender" + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + }, + "ErrorForComplete": { + "Error": { + "Code": "ValidationError", + "Message": "Stack: is in DELETE_COMPLETE state and can not be updated.", + "Type": "Sender" + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + } + } } } diff --git a/tests/aws/services/cloudformation/api/test_changesets.validation.json b/tests/aws/services/cloudformation/api/test_changesets.validation.json index d6e9bd354872b..a20a8cb87d8d9 100644 --- a/tests/aws/services/cloudformation/api/test_changesets.validation.json +++ b/tests/aws/services/cloudformation/api/test_changesets.validation.json @@ -47,6 +47,15 @@ "tests/aws/services/cloudformation/api/test_changesets.py::TestUpdates::test_simple_update_two_resources": { "last_validated_date": "2025-04-02T10:05:26+00:00" }, + "tests/aws/services/cloudformation/api/test_changesets.py::test_changeset_for_deleted_stack": { + "last_validated_date": "2025-10-10T19:59:52+00:00", + "durations_in_seconds": { + "setup": 0.25, + "call": 15.15, + "teardown": 0.12, + "total": 15.52 + } + }, "tests/aws/services/cloudformation/api/test_changesets.py::test_create_and_then_update_refreshes_template_metadata": { "last_validated_date": "2025-08-20T22:17:01+00:00", "durations_in_seconds": { @@ -77,6 +86,15 @@ "tests/aws/services/cloudformation/api/test_changesets.py::test_create_change_set_update_without_parameters": { "last_validated_date": "2022-05-31T07:32:02+00:00" }, + "tests/aws/services/cloudformation/api/test_changesets.py::test_create_changeset_for_deleted_stack": { + "last_validated_date": "2025-10-10T18:02:05+00:00", + "durations_in_seconds": { + "setup": 0.27, + "call": 16.63, + "teardown": 0.13, + "total": 17.03 + } + }, "tests/aws/services/cloudformation/api/test_changesets.py::test_create_changeset_with_stack_id": { "last_validated_date": "2023-11-28T06:48:23+00:00" }, diff --git a/tests/aws/services/cloudformation/api/test_resources.py b/tests/aws/services/cloudformation/api/test_resources.py index 49f858ad5cc85..2d26ae9aa42e0 100644 --- a/tests/aws/services/cloudformation/api/test_resources.py +++ b/tests/aws/services/cloudformation/api/test_resources.py @@ -6,6 +6,8 @@ from tests.aws.services.cloudformation.conftest import skip_if_legacy_engine from localstack.testing.pytest import markers +from localstack.testing.pytest.fixtures import StackDeployError +from localstack.utils.strings import short_uid @skip_if_legacy_engine() @@ -53,3 +55,64 @@ def test_invalid_logical_resource_id(deploy_cfn_template, snapshot): deploy_cfn_template(template=json.dumps(template)) snapshot.match("error", err.value) + + +@markers.aws.validated +@markers.snapshot.skip_snapshot_verify(paths=["$..StackResourceDetail.Metadata"]) +@skip_if_legacy_engine +def test_describe_deleted_resource_on_update(aws_client, snapshot, deploy_cfn_template): + template = { + "Resources": { + "Parameter": { + "Type": "AWS::SSM::Parameter", + "Properties": {"Type": "String", "Value": "Test"}, + } + } + } + + stack = deploy_cfn_template(template=json.dumps(template)) + + # Update the template to remove the previous resource and create a new one + template["Resources"]["Parameter2"] = template["Resources"].pop("Parameter") + deploy_cfn_template(template=json.dumps(template), is_update=True, stack_name=stack.stack_name) + + with pytest.raises(ClientError) as err: + aws_client.cloudformation.describe_stack_resource( + StackName=stack.stack_name, LogicalResourceId="Parameter" + ) + + parameter2 = aws_client.cloudformation.describe_stack_resource( + StackName=stack.stack_name, LogicalResourceId="Parameter2" + ) + + snapshot.add_transformer(snapshot.transform.key_value("PhysicalResourceId")) + snapshot.add_transformer(snapshot.transform.key_value("StackId")) + snapshot.add_transformer(snapshot.transform.key_value("StackName")) + + snapshot.match("error", err.value.response) + snapshot.match("parameter", parameter2) + + +@markers.aws.validated +@skip_if_legacy_engine +def test_describe_failed_resource(aws_client, snapshot, deploy_cfn_template): + template = { + "Resources": { + "Parameter": { + "Type": "AWS::SSM::Parameter", + "Properties": {"Type": "Invalid", "Value": "Test"}, + } + } + } + + stack_name = f"test-stack-{short_uid()}" + with pytest.raises(StackDeployError): + deploy_cfn_template(template=json.dumps(template), stack_name=stack_name) + + with pytest.raises(ClientError) as err: + aws_client.cloudformation.describe_stack_resource( + StackName=stack_name, LogicalResourceId="Parameter" + ) + + snapshot.add_transformer(snapshot.transform.regex(stack_name, "")) + snapshot.match("error", err.value.response) diff --git a/tests/aws/services/cloudformation/api/test_resources.snapshot.json b/tests/aws/services/cloudformation/api/test_resources.snapshot.json index 7bf7bc35886b5..353882f467bb9 100644 --- a/tests/aws/services/cloudformation/api/test_resources.snapshot.json +++ b/tests/aws/services/cloudformation/api/test_resources.snapshot.json @@ -16,5 +16,56 @@ "recorded-content": { "error": "An error occurred (ValidationError) when calling the CreateChangeSet operation: Template format error: Resource name my-bad-resource-id is non alphanumeric." } + }, + "tests/aws/services/cloudformation/api/test_resources.py::test_describe_deleted_resource_on_update": { + "recorded-date": "16-10-2025, 15:06:04", + "recorded-content": { + "error": { + "Error": { + "Code": "ValidationError", + "Message": "Resource Parameter does not exist for stack ", + "Type": "Sender" + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + }, + "parameter": { + "StackResourceDetail": { + "DriftInformation": { + "StackResourceDriftStatus": "NOT_CHECKED" + }, + "LastUpdatedTimestamp": "timestamp", + "LogicalResourceId": "Parameter2", + "Metadata": {}, + "PhysicalResourceId": "", + "ResourceStatus": "CREATE_COMPLETE", + "ResourceType": "AWS::SSM::Parameter", + "StackId": "", + "StackName": "" + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/cloudformation/api/test_resources.py::test_describe_failed_resource": { + "recorded-date": "16-10-2025, 15:02:53", + "recorded-content": { + "error": { + "Error": { + "Code": "ValidationError", + "Message": "Resource Parameter does not exist for stack ", + "Type": "Sender" + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + } + } } } diff --git a/tests/aws/services/cloudformation/api/test_resources.validation.json b/tests/aws/services/cloudformation/api/test_resources.validation.json index 4bd2c1ca3dd99..2f011bfb176ef 100644 --- a/tests/aws/services/cloudformation/api/test_resources.validation.json +++ b/tests/aws/services/cloudformation/api/test_resources.validation.json @@ -1,4 +1,22 @@ { + "tests/aws/services/cloudformation/api/test_resources.py::test_describe_deleted_resource_on_update": { + "last_validated_date": "2025-10-16T15:08:41+00:00", + "durations_in_seconds": { + "setup": 0.28, + "call": 22.95, + "teardown": 4.6, + "total": 27.83 + } + }, + "tests/aws/services/cloudformation/api/test_resources.py::test_describe_failed_resource": { + "last_validated_date": "2025-10-16T15:02:53+00:00", + "durations_in_seconds": { + "setup": 0.29, + "call": 8.61, + "teardown": 0.0, + "total": 8.9 + } + }, "tests/aws/services/cloudformation/v2/ported_from_v1/api/test_resources.py::test_describe_non_existent_resource": { "last_validated_date": "2025-07-25T22:01:40+00:00", "durations_in_seconds": { diff --git a/tests/aws/services/cloudformation/api/test_stacks.py b/tests/aws/services/cloudformation/api/test_stacks.py index dc70b77aafca9..bb39d16db8414 100644 --- a/tests/aws/services/cloudformation/api/test_stacks.py +++ b/tests/aws/services/cloudformation/api/test_stacks.py @@ -183,6 +183,18 @@ def test_stack_name_creation(self, deploy_cfn_template, snapshot, aws_client): snapshot.match("stack_response", e.value.response) + @markers.aws.validated + def test_create_stack_url_as_template(self, snapshot, aws_client): + snapshot.add_transformer(snapshot.transform.cloudformation_api()) + + stack_name = f"stack-{short_uid()}" + + template_url = "https://raw.githubusercontent.com/aws-cloudformation/aws-cloudformation-templates/refs/heads/main/EC2/InstanceWithCfnInit.yaml" + + with pytest.raises(ClientError) as e: + aws_client.cloudformation.create_stack(StackName=stack_name, TemplateBody=template_url) + snapshot.match("stack_create_ec2", e.value) + @markers.aws.validated @pytest.mark.parametrize("fileformat", ["yaml", "json"]) def test_get_template_using_create_stack(self, snapshot, fileformat, aws_client): @@ -328,6 +340,7 @@ def test_update_stack_with_same_template_withoutchange_transformation( ) @markers.aws.validated + @skip_if_legacy_engine() def test_update_stack_actual_update(self, deploy_cfn_template, aws_client): template = load_file( os.path.join(os.path.dirname(__file__), "../../../templates/sqs_queue_update.yml") @@ -462,6 +475,7 @@ def _assert_stack_process_finished(): ] assert len(updated_resources) == length_expected + @markers.requires_in_process @markers.aws.only_localstack def test_create_stack_with_custom_id( self, aws_client, cleanups, account_id, region_name, set_resource_custom_id @@ -690,8 +704,6 @@ def test_events_resource_types(deploy_cfn_template, snapshot, aws_client): @markers.aws.validated def test_list_parameter_type(aws_client, deploy_cfn_template, cleanups): - stack_name = f"test-stack-{short_uid()}" - cleanups.append(lambda: aws_client.cloudformation.delete_stack(StackName=stack_name)) stack = deploy_cfn_template( template_path=os.path.join( os.path.dirname(__file__), "../../../templates/cfn_parameter_list_type.yaml" @@ -704,6 +716,35 @@ def test_list_parameter_type(aws_client, deploy_cfn_template, cleanups): assert stack.outputs["ParamValue"] == "foo|bar" +@markers.aws.validated +def test_subnet_id_parameter_type(aws_client, deploy_cfn_template, cleanups, snapshot): + vpc_id = aws_client.ec2.create_vpc(CidrBlock="10.0.0.0/16")["Vpc"]["VpcId"] + cleanups.append(lambda: aws_client.ec2.delete_vpc(VpcId=vpc_id)) + aws_client.ec2.get_waiter("vpc_available").wait(VpcIds=[vpc_id]) + subnet_id_1 = aws_client.ec2.create_subnet(VpcId=vpc_id, CidrBlock="10.0.0.0/24")["Subnet"][ + "SubnetId" + ] + cleanups.append(lambda: aws_client.ec2.delete_subnet(SubnetId=subnet_id_1)) + subnet_id_2 = aws_client.ec2.create_subnet(VpcId=vpc_id, CidrBlock="10.0.1.0/24")["Subnet"][ + "SubnetId" + ] + cleanups.append(lambda: aws_client.ec2.delete_subnet(SubnetId=subnet_id_2)) + + subnets_list = ",".join([subnet_id_1, subnet_id_2]) + stack = deploy_cfn_template( + template_path=os.path.join( + os.path.dirname(__file__), "../../../templates/cfn_parameter_list_subnet_id_type.yaml" + ), + parameters={ + "ParamsList": subnets_list, + }, + ) + + snapshot.add_transformer(snapshot.transform.regex(subnet_id_1, "subnet-id-1")) + snapshot.add_transformer(snapshot.transform.regex(subnet_id_2, "subnet-id-2")) + snapshot.match("outputs", stack.outputs) + + @markers.aws.validated @pytest.mark.skipif(condition=not is_aws_cloud(), reason="rollback not implemented") def test_blocked_stack_deletion(aws_client, cleanups, snapshot): @@ -865,9 +906,8 @@ def test_name_conflicts(aws_client, snapshot, cleanups): @markers.aws.validated def test_describe_stack_events_errors(aws_client, snapshot): - with pytest.raises(aws_client.cloudformation.exceptions.ClientError) as e: + with pytest.raises(botocore.exceptions.ParamValidationError) as e: aws_client.cloudformation.describe_stack_events() - snapshot.match("describe_stack_events_no_stack_name", e.value.response) with pytest.raises(aws_client.cloudformation.exceptions.ClientError) as e: aws_client.cloudformation.describe_stack_events(StackName="does-not-exist") snapshot.match("describe_stack_events_stack_not_found", e.value.response) diff --git a/tests/aws/services/cloudformation/api/test_stacks.snapshot.json b/tests/aws/services/cloudformation/api/test_stacks.snapshot.json index fde3beada5d45..de702011a9e58 100644 --- a/tests/aws/services/cloudformation/api/test_stacks.snapshot.json +++ b/tests/aws/services/cloudformation/api/test_stacks.snapshot.json @@ -986,17 +986,6 @@ "tests/aws/services/cloudformation/api/test_stacks.py::test_describe_stack_events_errors": { "recorded-date": "26-03-2024, 17:54:41", "recorded-content": { - "describe_stack_events_no_stack_name": { - "Error": { - "Code": "ValidationError", - "Message": "1 validation error detected: Value null at 'stackName' failed to satisfy constraint: Member must not be null", - "Type": "Sender" - }, - "ResponseMetadata": { - "HTTPHeaders": {}, - "HTTPStatusCode": 400 - } - }, "describe_stack_events_stack_not_found": { "Error": { "Code": "ValidationError", @@ -4347,5 +4336,19 @@ ] } } + }, + "tests/aws/services/cloudformation/api/test_stacks.py::TestStacksApi::test_create_stack_url_as_template": { + "recorded-date": "23-10-2025, 19:25:10", + "recorded-content": { + "stack_create_ec2": "An error occurred (ValidationError) when calling the CreateStack operation: Template format error: unsupported structure." + } + }, + "tests/aws/services/cloudformation/api/test_stacks.py::test_subnet_id_parameter_type": { + "recorded-date": "08-12-2025, 15:18:37", + "recorded-content": { + "outputs": { + "ParamValue": "subnet-id-1|subnet-id-2" + } + } } } diff --git a/tests/aws/services/cloudformation/api/test_stacks.validation.json b/tests/aws/services/cloudformation/api/test_stacks.validation.json index 9dd42d7bd0ce4..fb734e04fbccd 100644 --- a/tests/aws/services/cloudformation/api/test_stacks.validation.json +++ b/tests/aws/services/cloudformation/api/test_stacks.validation.json @@ -1,4 +1,13 @@ { + "tests/aws/services/cloudformation/api/test_stacks.py::TestStacksApi::test_create_stack_url_as_template": { + "last_validated_date": "2025-10-23T19:25:10+00:00", + "durations_in_seconds": { + "setup": 0.82, + "call": 0.82, + "teardown": 0.02, + "total": 1.66 + } + }, "tests/aws/services/cloudformation/api/test_stacks.py::TestStacksApi::test_failure_options_for_stack_update[False-2]": { "last_validated_date": "2024-06-25T17:21:51+00:00" }, @@ -206,6 +215,15 @@ "tests/aws/services/cloudformation/api/test_stacks.py::test_stack_resource_not_found": { "last_validated_date": "2025-01-29T09:08:15+00:00" }, + "tests/aws/services/cloudformation/api/test_stacks.py::test_subnet_id_parameter_type": { + "last_validated_date": "2025-12-08T15:18:43+00:00", + "durations_in_seconds": { + "setup": 0.45, + "call": 13.02, + "teardown": 6.25, + "total": 19.72 + } + }, "tests/aws/services/cloudformation/api/test_stacks.py::test_update_termination_protection": { "last_validated_date": "2023-01-04T15:23:22+00:00" }, diff --git a/tests/aws/services/cloudformation/api/test_templates.py b/tests/aws/services/cloudformation/api/test_templates.py index e478ef54a3c4c..95a817fb3418f 100644 --- a/tests/aws/services/cloudformation/api/test_templates.py +++ b/tests/aws/services/cloudformation/api/test_templates.py @@ -8,6 +8,7 @@ from tests.aws.services.cloudformation.conftest import skip_if_legacy_engine from localstack.testing.pytest import markers +from localstack.testing.pytest.fixtures import StackDeployError from localstack.utils.common import load_file from localstack.utils.strings import short_uid, to_bytes @@ -68,6 +69,42 @@ def test_get_template_summary_non_executed_change_set(aws_client, snapshot, clea snapshot.match("error", exc_info.value.response) +@markers.aws.validated +@skip_if_legacy_engine() +def test_get_template_summary_no_resources(aws_client, snapshot): + with pytest.raises(ClientError) as exc_info: + aws_client.cloudformation.get_template_summary(TemplateBody="{}") + snapshot.match("error", exc_info.value.response) + + +@markers.aws.validated +@markers.snapshot.skip_snapshot_verify( + paths=["$..ResourceIdentifierSummaries..ResourceIdentifiers"] +) +@skip_if_legacy_engine() +def test_get_template_summary_failed_stack(deploy_cfn_template, aws_client, snapshot): + snapshot.add_transformer(snapshot.transform.cloudformation_api()) + + template = { + "Resources": { + "MyParameter": { + "Type": "AWS::SSM::Parameter", + "Properties": { + "Type": "String", + # Note: missing Value parameter so the resource provider should fail + }, + }, + }, + } + + stack_name = f"stack-{short_uid()}" + with pytest.raises(StackDeployError): + deploy_cfn_template(template=json.dumps(template), stack_name=stack_name) + + summary = aws_client.cloudformation.get_template_summary(StackName=stack_name) + snapshot.match("template-summary", summary) + + @markers.aws.validated @pytest.mark.parametrize("url_style", ["s3_url", "http_path", "http_host", "http_invalid"]) def test_create_stack_from_s3_template_url( @@ -154,6 +191,14 @@ def test_validate_invalid_json_template_should_fail(aws_client, snapshot): snapshot.match("validate-invalid-json", ctx.value.response) +@skip_if_legacy_engine() +@markers.aws.validated +def test_get_template_no_arguments(aws_client, snapshot): + with pytest.raises(ClientError) as exc_info: + aws_client.cloudformation.get_template() + snapshot.match("stack-error", exc_info.value.response) + + @markers.aws.validated def test_get_template_missing_resources_stack(aws_client, snapshot): with pytest.raises(ClientError) as exc_info: @@ -179,3 +224,29 @@ def test_get_template_missing_resources_change_set_id(aws_client, snapshot): with pytest.raises(ClientError) as exc_info: aws_client.cloudformation.get_template(ChangeSetName=change_set_id) snapshot.match("change-set-error", exc_info.value.response) + + +@markers.aws.validated +def test_create_stack_invalid_yaml_template_should_fail(aws_client, snapshot): + snapshot.add_transformer(snapshot.transform.cloudformation_api()) + # add transformer to ignore the error location + # TODO: add this information back in to improve the UX + snapshot.add_transformer(snapshot.transform.regex(r"\s+\([^)]+\)", "")) + + stack_name = f"stack-{short_uid()}" + invalid_yaml = textwrap.dedent( + """\ + Resources: + MyBucket: + Type: AWS::S3::Bucket + Properties: + BucketName: test + VersioningConfiguration: + Status: Enabled + """ + ) + + with pytest.raises(ClientError) as ctx: + aws_client.cloudformation.create_stack(StackName=stack_name, TemplateBody=invalid_yaml) + + snapshot.match("create-invalid-yaml", ctx.value.response) diff --git a/tests/aws/services/cloudformation/api/test_templates.snapshot.json b/tests/aws/services/cloudformation/api/test_templates.snapshot.json index 307f2faf91ee4..2934d32161ac0 100644 --- a/tests/aws/services/cloudformation/api/test_templates.snapshot.json +++ b/tests/aws/services/cloudformation/api/test_templates.snapshot.json @@ -200,5 +200,80 @@ } } } + }, + "tests/aws/services/cloudformation/api/test_templates.py::test_get_template_summary_no_resources": { + "recorded-date": "07-10-2025, 22:28:52", + "recorded-content": { + "error": { + "Error": { + "Code": "ValidationError", + "Message": "Template format error: At least one Resources member must be defined.", + "Type": "Sender" + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + } + } + }, + "tests/aws/services/cloudformation/api/test_templates.py::test_get_template_summary_failed_stack": { + "recorded-date": "07-10-2025, 22:44:53", + "recorded-content": { + "template-summary": { + "Parameters": [], + "ResourceIdentifierSummaries": [ + { + "LogicalResourceIds": [ + "MyParameter" + ], + "ResourceIdentifiers": [ + "Name" + ], + "ResourceType": "AWS::SSM::Parameter" + } + ], + "ResourceTypes": [ + "AWS::SSM::Parameter" + ], + "Version": "2010-09-09", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/cloudformation/api/test_templates.py::test_get_template_no_arguments": { + "recorded-date": "13-11-2025, 16:48:31", + "recorded-content": { + "stack-error": { + "Error": { + "Code": "ValidationError", + "Message": "StackName is required if ChangeSetName is not specified.", + "Type": "Sender" + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + } + } + }, + "tests/aws/services/cloudformation/api/test_templates.py::test_create_stack_invalid_yaml_template_should_fail": { + "recorded-date": "13-11-2025, 11:36:51", + "recorded-content": { + "create-invalid-yaml": { + "Error": { + "Code": "ValidationError", + "Message": "Template format error: YAML not well-formed.", + "Type": "Sender" + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + } + } } } diff --git a/tests/aws/services/cloudformation/api/test_templates.validation.json b/tests/aws/services/cloudformation/api/test_templates.validation.json index af86ad38d2f4b..abfd75080a124 100644 --- a/tests/aws/services/cloudformation/api/test_templates.validation.json +++ b/tests/aws/services/cloudformation/api/test_templates.validation.json @@ -11,6 +11,15 @@ "tests/aws/services/cloudformation/api/test_templates.py::test_create_stack_from_s3_template_url[s3_url]": { "last_validated_date": "2023-10-10T22:03:44+00:00" }, + "tests/aws/services/cloudformation/api/test_templates.py::test_create_stack_invalid_yaml_template_should_fail": { + "last_validated_date": "2025-11-13T11:36:51+00:00", + "durations_in_seconds": { + "setup": 1.06, + "call": 0.3, + "teardown": 0.0, + "total": 1.36 + } + }, "tests/aws/services/cloudformation/api/test_templates.py::test_get_template_missing_resources": { "last_validated_date": "2025-09-12T16:08:17+00:00", "durations_in_seconds": { @@ -47,9 +56,36 @@ "total": 1.19 } }, + "tests/aws/services/cloudformation/api/test_templates.py::test_get_template_no_arguments": { + "last_validated_date": "2025-11-13T16:48:31+00:00", + "durations_in_seconds": { + "setup": 1.54, + "call": 0.19, + "teardown": 0.0, + "total": 1.73 + } + }, "tests/aws/services/cloudformation/api/test_templates.py::test_get_template_summary": { "last_validated_date": "2023-05-24T13:05:00+00:00" }, + "tests/aws/services/cloudformation/api/test_templates.py::test_get_template_summary_failed_stack": { + "last_validated_date": "2025-10-07T22:44:53+00:00", + "durations_in_seconds": { + "setup": 1.0, + "call": 134.39, + "teardown": 0.0, + "total": 135.39 + } + }, + "tests/aws/services/cloudformation/api/test_templates.py::test_get_template_summary_no_resources": { + "last_validated_date": "2025-10-07T22:28:52+00:00", + "durations_in_seconds": { + "setup": 1.58, + "call": 0.22, + "teardown": 0.0, + "total": 1.8 + } + }, "tests/aws/services/cloudformation/api/test_templates.py::test_get_template_summary_non_executed_change_set": { "last_validated_date": "2025-09-10T23:25:47+00:00", "durations_in_seconds": { diff --git a/tests/aws/services/cloudformation/api/test_update_stack.py b/tests/aws/services/cloudformation/api/test_update_stack.py index 286e8dbff2586..a1b9a918cf427 100644 --- a/tests/aws/services/cloudformation/api/test_update_stack.py +++ b/tests/aws/services/cloudformation/api/test_update_stack.py @@ -5,6 +5,7 @@ import botocore.errorfactory import botocore.exceptions import pytest +from tests.aws.services.cloudformation.conftest import skip_if_legacy_engine from localstack.testing.pytest import markers from localstack.utils.files import load_file @@ -459,3 +460,32 @@ def test_diff_after_update(deploy_cfn_template, aws_client, snapshot): describe_stack_response = aws_client.cloudformation.describe_stacks(StackName=stack.stack_name) assert describe_stack_response["Stacks"][0]["StackStatus"] == "UPDATE_COMPLETE" + + +@markers.aws.validated +@skip_if_legacy_engine +def test_update_deleted_stack(aws_client, deploy_cfn_template, snapshot): + template = json.dumps( + { + "Resources": { + "Parameter": { + "Type": "AWS::SSM::Parameter", + "Properties": {"Type": "String", "Value": "Test"}, + } + } + } + ) + + stack = deploy_cfn_template(template=template) + stack.destroy() + + with pytest.raises(botocore.exceptions.ClientError) as ex: + aws_client.cloudformation.create_change_set( + StackName=stack.stack_id, + ChangeSetName="test", + TemplateBody=template, + ChangeSetType="UPDATE", + ) + + snapshot.add_transformer(snapshot.transform.regex(stack.stack_id, "")) + snapshot.match("Error", ex.value.response) diff --git a/tests/aws/services/cloudformation/api/test_update_stack.snapshot.json b/tests/aws/services/cloudformation/api/test_update_stack.snapshot.json index d8c3556c151d9..9462ff023e36f 100644 --- a/tests/aws/services/cloudformation/api/test_update_stack.snapshot.json +++ b/tests/aws/services/cloudformation/api/test_update_stack.snapshot.json @@ -186,5 +186,21 @@ } } } + }, + "tests/aws/services/cloudformation/api/test_update_stack.py::test_update_deleted_stack": { + "recorded-date": "10-10-2025, 21:42:05", + "recorded-content": { + "Error": { + "Error": { + "Code": "ValidationError", + "Message": "Stack: is in DELETE_COMPLETE state and can not be updated.", + "Type": "Sender" + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + } + } } } diff --git a/tests/aws/services/cloudformation/api/test_update_stack.validation.json b/tests/aws/services/cloudformation/api/test_update_stack.validation.json index c52a3e2f276c0..831f96299a8d6 100644 --- a/tests/aws/services/cloudformation/api/test_update_stack.validation.json +++ b/tests/aws/services/cloudformation/api/test_update_stack.validation.json @@ -8,6 +8,15 @@ "tests/aws/services/cloudformation/api/test_update_stack.py::test_no_template_error": { "last_validated_date": "2022-11-21T07:57:45+00:00" }, + "tests/aws/services/cloudformation/api/test_update_stack.py::test_update_deleted_stack": { + "last_validated_date": "2025-10-10T21:42:05+00:00", + "durations_in_seconds": { + "setup": 0.25, + "call": 18.99, + "teardown": 0.12, + "total": 19.36 + } + }, "tests/aws/services/cloudformation/api/test_update_stack.py::test_update_with_invalid_rollback_configuration_errors": { "last_validated_date": "2022-11-21T14:36:32+00:00" }, diff --git a/tests/aws/services/cloudformation/conftest.py b/tests/aws/services/cloudformation/conftest.py index 2f467d089504d..289bf3508bcc8 100644 --- a/tests/aws/services/cloudformation/conftest.py +++ b/tests/aws/services/cloudformation/conftest.py @@ -1,6 +1,5 @@ import re from collections.abc import Iterable -from typing import TypeVar import pytest @@ -18,8 +17,5 @@ def skip_if_legacy_engine(reason: str | None = None): ) -_T = TypeVar("_T") - - -def skipped_v2_items(*items: Iterable[_T]) -> list[_T]: +def skipped_v2_items[T](*items: Iterable[T]) -> list[T]: return optional_list(is_v2_engine(), items) diff --git a/tests/aws/services/cloudformation/engine/test_conditions.py b/tests/aws/services/cloudformation/engine/test_conditions.py index 229f5ca86d776..57235adf7ec0c 100644 --- a/tests/aws/services/cloudformation/engine/test_conditions.py +++ b/tests/aws/services/cloudformation/engine/test_conditions.py @@ -1,6 +1,9 @@ +import json import os.path import pytest +from botocore.exceptions import ClientError +from localstack_snapshot.snapshots.transformer import SortingTransformer from tests.aws.services.cloudformation.conftest import skip_if_legacy_engine from localstack.services.cloudformation.v2.utils import is_v2_engine @@ -153,7 +156,7 @@ def test_dependent_get_att(self, aws_client, snapshot): snapshot.match("dependent_ref_exc", e.value.response) @markers.aws.validated - @pytest.mark.skipif(condition=not is_aws_cloud(), reason="not supported yet") + @skip_if_legacy_engine() def test_dependent_ref_intrinsic_fn_condition(self, aws_client, deploy_cfn_template): """ Checks behavior of un-refable resources @@ -515,3 +518,89 @@ def test_update_conditions(self, deploy_cfn_template, aws_client): assert aws_client.s3.head_bucket(Bucket=bucket_1) with pytest.raises(aws_client.s3.exceptions.ClientError): aws_client.s3.head_bucket(Bucket=bucket_2) + + @markers.aws.validated + @pytest.mark.parametrize("should_deploy", ["yes", "no"]) + @skip_if_legacy_engine() + def test_references_to_disabled_resources( + self, deploy_cfn_template, aws_client, should_deploy, snapshot + ): + snapshot.add_transformer( + SortingTransformer("StackResources", lambda e: e["LogicalResourceId"]) + ) + snapshot.add_transformer(SortingTransformer("Parameters", lambda e: e["ParameterKey"])) + snapshot.add_transformer(snapshot.transform.key_value("PhysicalResourceId")) + snapshot.add_transformer(snapshot.transform.cloudformation_api()) + + parameter_value = short_uid() + snapshot.add_transformer(snapshot.transform.regex(parameter_value, "")) + + stack = deploy_cfn_template( + template_path=os.path.join( + os.path.dirname(__file__), "../../../templates/references_to_conditions.yml" + ), + parameters={ + "Toggle": should_deploy, + "ParameterValue": parameter_value, + }, + ) + + describe_stack_res = aws_client.cloudformation.describe_stacks(StackName=stack.stack_id) + snapshot.match("stack-description", describe_stack_res) + + describe_resources = aws_client.cloudformation.describe_stack_resources( + StackName=stack.stack_id + ) + snapshot.match("resources-description", describe_resources) + + @markers.aws.validated + @skip_if_legacy_engine() + def test_conditional_resource_referencing_conditional( + self, deploy_cfn_template, aws_client, snapshot + ): + """ + Test that a template with a conditional resource referencing another conditional + resource via !GetAtt is accepted and deploys correctly when conditions are false. + """ + snapshot.add_transformer( + SortingTransformer("StackResources", lambda e: e["LogicalResourceId"]) + ) + snapshot.add_transformer(snapshot.transform.key_value("PhysicalResourceId")) + snapshot.add_transformer(snapshot.transform.cloudformation_api()) + + stack = deploy_cfn_template( + template_path=os.path.join( + os.path.dirname(__file__), + "../../../templates/conditions/conditional-resource-getatt-delete.yaml", + ), + parameters={"EnableQueue": "false"}, + ) + + resources = aws_client.cloudformation.describe_stack_resources(StackName=stack.stack_id) + snapshot.match("resources-description", resources) + + +class TestValidateConditions: + @markers.aws.validated + @skip_if_legacy_engine + def test_validate_equals_args_len(self, aws_client, snapshot): + template = { + "Conditions": {"ShouldDeploy": {"Fn::Equals": ["a"]}}, + "Resources": { + "Topic1": { + "Type": "AWS::SNS::Topic", + }, + }, + } + + stack_name = f"stack-{short_uid()}" + change_set_name = f"ch-{short_uid()}" + with pytest.raises(ClientError) as ex: + aws_client.cloudformation.create_change_set( + StackName=stack_name, + ChangeSetName=change_set_name, + ChangeSetType="CREATE", + TemplateBody=json.dumps(template), + ) + + snapshot.match("error", ex.value.response) diff --git a/tests/aws/services/cloudformation/engine/test_conditions.snapshot.json b/tests/aws/services/cloudformation/engine/test_conditions.snapshot.json index 3ae8686edd44d..a2558b6d066dd 100644 --- a/tests/aws/services/cloudformation/engine/test_conditions.snapshot.json +++ b/tests/aws/services/cloudformation/engine/test_conditions.snapshot.json @@ -775,5 +775,204 @@ } } } + }, + "tests/aws/services/cloudformation/engine/test_conditions.py::TestCloudFormationConditions::test_references_to_disabled_resources[yes]": { + "recorded-date": "07-10-2025, 21:21:23", + "recorded-content": { + "stack-description": { + "Stacks": [ + { + "Capabilities": [ + "CAPABILITY_AUTO_EXPAND", + "CAPABILITY_IAM", + "CAPABILITY_NAMED_IAM" + ], + "ChangeSetId": "arn::cloudformation::111111111111:changeSet/", + "CreationTime": "datetime", + "DisableRollback": false, + "DriftInformation": { + "StackDriftStatus": "NOT_CHECKED" + }, + "EnableTerminationProtection": false, + "LastUpdatedTime": "datetime", + "NotificationARNs": [], + "Outputs": [ + { + "OutputKey": "ConditionalParameterValue", + "OutputValue": "" + } + ], + "Parameters": [ + { + "ParameterKey": "ParameterValue", + "ParameterValue": "" + }, + { + "ParameterKey": "Toggle", + "ParameterValue": "yes" + } + ], + "RollbackConfiguration": {}, + "StackId": "arn::cloudformation::111111111111:stack//", + "StackName": "", + "StackStatus": "CREATE_COMPLETE", + "Tags": [] + } + ], + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "resources-description": { + "StackResources": [ + { + "DriftInformation": { + "StackResourceDriftStatus": "NOT_CHECKED" + }, + "LogicalResourceId": "AnotherResource", + "PhysicalResourceId": "", + "ResourceStatus": "CREATE_COMPLETE", + "ResourceType": "AWS::SSM::Parameter", + "StackId": "arn::cloudformation::111111111111:stack//", + "StackName": "", + "Timestamp": "timestamp" + }, + { + "DriftInformation": { + "StackResourceDriftStatus": "NOT_CHECKED" + }, + "LogicalResourceId": "BaseParameter", + "PhysicalResourceId": "", + "ResourceStatus": "CREATE_COMPLETE", + "ResourceType": "AWS::SSM::Parameter", + "StackId": "arn::cloudformation::111111111111:stack//", + "StackName": "", + "Timestamp": "timestamp" + }, + { + "DriftInformation": { + "StackResourceDriftStatus": "NOT_CHECKED" + }, + "LogicalResourceId": "ConditionalParameter", + "PhysicalResourceId": "", + "ResourceStatus": "CREATE_COMPLETE", + "ResourceType": "AWS::SSM::Parameter", + "StackId": "arn::cloudformation::111111111111:stack//", + "StackName": "", + "Timestamp": "timestamp" + } + ], + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/cloudformation/engine/test_conditions.py::TestCloudFormationConditions::test_references_to_disabled_resources[no]": { + "recorded-date": "07-10-2025, 21:21:37", + "recorded-content": { + "stack-description": { + "Stacks": [ + { + "Capabilities": [ + "CAPABILITY_AUTO_EXPAND", + "CAPABILITY_IAM", + "CAPABILITY_NAMED_IAM" + ], + "ChangeSetId": "arn::cloudformation::111111111111:changeSet/", + "CreationTime": "datetime", + "DisableRollback": false, + "DriftInformation": { + "StackDriftStatus": "NOT_CHECKED" + }, + "EnableTerminationProtection": false, + "LastUpdatedTime": "datetime", + "NotificationARNs": [], + "Parameters": [ + { + "ParameterKey": "ParameterValue", + "ParameterValue": "" + }, + { + "ParameterKey": "Toggle", + "ParameterValue": "no" + } + ], + "RollbackConfiguration": {}, + "StackId": "arn::cloudformation::111111111111:stack//", + "StackName": "", + "StackStatus": "CREATE_COMPLETE", + "Tags": [] + } + ], + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "resources-description": { + "StackResources": [ + { + "DriftInformation": { + "StackResourceDriftStatus": "NOT_CHECKED" + }, + "LogicalResourceId": "BaseParameter", + "PhysicalResourceId": "", + "ResourceStatus": "CREATE_COMPLETE", + "ResourceType": "AWS::SSM::Parameter", + "StackId": "arn::cloudformation::111111111111:stack//", + "StackName": "", + "Timestamp": "timestamp" + } + ], + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/cloudformation/engine/test_conditions.py::TestValidateConditions::test_validate_equals_args_len": { + "recorded-date": "08-10-2025, 18:18:14", + "recorded-content": { + "error": { + "Error": { + "Code": "ValidationError", + "Message": "Template error: every Fn::Equals object requires a list of 2 string parameters.", + "Type": "Sender" + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + } + } + }, + "tests/aws/services/cloudformation/engine/test_conditions.py::TestCloudFormationConditions::test_conditional_resource_referencing_conditional": { + "recorded-date": "04-02-2026, 01:53:15", + "recorded-content": { + "resources-description": { + "StackResources": [ + { + "DriftInformation": { + "StackResourceDriftStatus": "NOT_CHECKED" + }, + "LogicalResourceId": "MyTable", + "PhysicalResourceId": "", + "ResourceStatus": "CREATE_COMPLETE", + "ResourceType": "AWS::DynamoDB::Table", + "StackId": "arn::cloudformation::111111111111:stack//", + "StackName": "", + "Timestamp": "timestamp" + } + ], + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } } } diff --git a/tests/aws/services/cloudformation/engine/test_conditions.validation.json b/tests/aws/services/cloudformation/engine/test_conditions.validation.json index 33145a6055c7e..b628813cd9f79 100644 --- a/tests/aws/services/cloudformation/engine/test_conditions.validation.json +++ b/tests/aws/services/cloudformation/engine/test_conditions.validation.json @@ -1,4 +1,13 @@ { + "tests/aws/services/cloudformation/engine/test_conditions.py::TestCloudFormationConditions::test_conditional_resource_referencing_conditional": { + "last_validated_date": "2026-02-04T01:53:29+00:00", + "durations_in_seconds": { + "setup": 0.7, + "call": 23.45, + "teardown": 14.46, + "total": 38.61 + } + }, "tests/aws/services/cloudformation/engine/test_conditions.py::TestCloudFormationConditions::test_dependent_get_att": { "last_validated_date": "2025-09-30T19:25:10+00:00", "durations_in_seconds": { @@ -32,7 +41,34 @@ "tests/aws/services/cloudformation/engine/test_conditions.py::TestCloudFormationConditions::test_output_reference_to_skipped_resource": { "last_validated_date": "2023-06-26T22:43:18+00:00" }, + "tests/aws/services/cloudformation/engine/test_conditions.py::TestCloudFormationConditions::test_references_to_disabled_resources[no]": { + "last_validated_date": "2025-10-07T21:21:41+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 7.01, + "teardown": 4.39, + "total": 11.4 + } + }, + "tests/aws/services/cloudformation/engine/test_conditions.py::TestCloudFormationConditions::test_references_to_disabled_resources[yes]": { + "last_validated_date": "2025-10-07T21:21:30+00:00", + "durations_in_seconds": { + "setup": 0.89, + "call": 10.41, + "teardown": 6.43, + "total": 17.73 + } + }, "tests/aws/services/cloudformation/engine/test_conditions.py::TestCloudFormationConditions::test_update_conditions": { "last_validated_date": "2024-06-18T19:43:43+00:00" + }, + "tests/aws/services/cloudformation/engine/test_conditions.py::TestValidateConditions::test_validate_equals_args_len": { + "last_validated_date": "2025-10-08T18:18:14+00:00", + "durations_in_seconds": { + "setup": 0.25, + "call": 0.36, + "teardown": 0.0, + "total": 0.61 + } } } diff --git a/tests/aws/services/cloudformation/engine/test_deletion_policy.py b/tests/aws/services/cloudformation/engine/test_deletion_policy.py new file mode 100644 index 0000000000000..e539fcb653097 --- /dev/null +++ b/tests/aws/services/cloudformation/engine/test_deletion_policy.py @@ -0,0 +1,85 @@ +import os + +import pytest +from botocore.exceptions import ClientError +from tests.aws.services.cloudformation.conftest import skip_if_legacy_engine + +from localstack.testing.pytest import markers +from localstack.utils.strings import short_uid + + +@markers.snapshot.skip_snapshot_verify( + paths=[ + # our message is different. The AWS message does not seem to include the parameter + # name but ours does + "$..message", + ] +) +@markers.aws.validated +def test_deletion_policy_with_deletion(aws_client, deploy_cfn_template, snapshot): + template_path = os.path.join( + os.path.dirname(__file__), + "../../../templates/deletion_policy.yaml", + ) + parameter_value = short_uid() + stack = deploy_cfn_template( + template_path=template_path, + parameters={ + "EnvType": "dev", + "ParameterValue": parameter_value, + }, + ) + + parameter_name = stack.outputs["ParameterName"] + value = aws_client.ssm.get_parameter(Name=parameter_name)["Parameter"]["Value"] + assert value == parameter_value + + stack.destroy() + + with pytest.raises(ClientError) as exc_info: + aws_client.ssm.get_parameter(Name=parameter_name) + + snapshot.match("error", {"message": str(exc_info.value)}) + + +@markers.aws.validated +@markers.snapshot.skip_snapshot_verify( + paths=[ + "$..PhysicalResourceId", + ] +) +@skip_if_legacy_engine() +def test_deletion_policy_with_retain( + aws_client, deploy_cfn_template, capture_per_resource_events, snapshot, cleanups +): + snapshot.add_transformer(snapshot.transform.cloudformation_api()) + template_path = os.path.join( + os.path.dirname(__file__), + "../../../templates/deletion_policy.yaml", + ) + parameter_value = short_uid() + stack = deploy_cfn_template( + template_path=template_path, + parameters={ + "EnvType": "prod", + "ParameterValue": parameter_value, + }, + ) + + snapshot.add_transformer(snapshot.transform.regex(stack.stack_name, "")) + + parameter_name = stack.outputs["ParameterName"] + + # make sure we clean up the parameter + cleanups.append(lambda: aws_client.ssm.delete_parameter(Name=parameter_name)) + + value = aws_client.ssm.get_parameter(Name=parameter_name)["Parameter"]["Value"] + assert value == parameter_value + + stack.destroy() + + value = aws_client.ssm.get_parameter(Name=parameter_name)["Parameter"]["Value"] + assert value == parameter_value + + events = capture_per_resource_events(stack.stack_id) + snapshot.match("per-resource-events", events) diff --git a/tests/aws/services/cloudformation/engine/test_deletion_policy.snapshot.json b/tests/aws/services/cloudformation/engine/test_deletion_policy.snapshot.json new file mode 100644 index 0000000000000..0b62aa8baa838 --- /dev/null +++ b/tests/aws/services/cloudformation/engine/test_deletion_policy.snapshot.json @@ -0,0 +1,77 @@ +{ + "tests/aws/services/cloudformation/engine/test_deletion_policy.py::test_deletion_policy_with_deletion": { + "recorded-date": "23-01-2026, 12:03:31", + "recorded-content": { + "error": { + "message": "An error occurred (ParameterNotFound) when calling the GetParameter operation: " + } + } + }, + "tests/aws/services/cloudformation/engine/test_deletion_policy.py::test_deletion_policy_with_retain": { + "recorded-date": "23-01-2026, 12:03:43", + "recorded-content": { + "per-resource-events": { + "MyParameter": [ + { + "LogicalResourceId": "MyParameter", + "PhysicalResourceId": "CFN-MyParameter-EZmrlQrQjjTv", + "ResourceStatus": "CREATE_IN_PROGRESS", + "ResourceType": "AWS::SSM::Parameter", + "Timestamp": "timestamp" + }, + { + "LogicalResourceId": "MyParameter", + "PhysicalResourceId": "CFN-MyParameter-EZmrlQrQjjTv", + "ResourceStatus": "CREATE_COMPLETE", + "ResourceType": "AWS::SSM::Parameter", + "Timestamp": "timestamp" + }, + { + "LogicalResourceId": "MyParameter", + "PhysicalResourceId": "CFN-MyParameter-EZmrlQrQjjTv", + "ResourceStatus": "DELETE_SKIPPED", + "ResourceType": "AWS::SSM::Parameter", + "Timestamp": "timestamp" + } + ], + "Stack": [ + { + "LogicalResourceId": "", + "PhysicalResourceId": "arn::cloudformation::111111111111:stack//", + "ResourceStatus": "REVIEW_IN_PROGRESS", + "ResourceType": "AWS::CloudFormation::Stack", + "Timestamp": "timestamp" + }, + { + "LogicalResourceId": "", + "PhysicalResourceId": "arn::cloudformation::111111111111:stack//", + "ResourceStatus": "CREATE_IN_PROGRESS", + "ResourceType": "AWS::CloudFormation::Stack", + "Timestamp": "timestamp" + }, + { + "LogicalResourceId": "", + "PhysicalResourceId": "arn::cloudformation::111111111111:stack//", + "ResourceStatus": "CREATE_COMPLETE", + "ResourceType": "AWS::CloudFormation::Stack", + "Timestamp": "timestamp" + }, + { + "LogicalResourceId": "", + "PhysicalResourceId": "arn::cloudformation::111111111111:stack//", + "ResourceStatus": "DELETE_IN_PROGRESS", + "ResourceType": "AWS::CloudFormation::Stack", + "Timestamp": "timestamp" + }, + { + "LogicalResourceId": "", + "PhysicalResourceId": "arn::cloudformation::111111111111:stack//", + "ResourceStatus": "DELETE_COMPLETE", + "ResourceType": "AWS::CloudFormation::Stack", + "Timestamp": "timestamp" + } + ] + } + } + } +} diff --git a/tests/aws/services/cloudformation/engine/test_deletion_policy.validation.json b/tests/aws/services/cloudformation/engine/test_deletion_policy.validation.json new file mode 100644 index 0000000000000..c33f7eb27d770 --- /dev/null +++ b/tests/aws/services/cloudformation/engine/test_deletion_policy.validation.json @@ -0,0 +1,20 @@ +{ + "tests/aws/services/cloudformation/engine/test_deletion_policy.py::test_deletion_policy_with_deletion": { + "last_validated_date": "2026-01-23T12:03:31+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 12.38, + "teardown": 0.08, + "total": 12.46 + } + }, + "tests/aws/services/cloudformation/engine/test_deletion_policy.py::test_deletion_policy_with_retain": { + "last_validated_date": "2026-01-23T12:03:43+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 12.35, + "teardown": 0.18, + "total": 12.53 + } + } +} diff --git a/tests/aws/services/cloudformation/engine/test_mappings.py b/tests/aws/services/cloudformation/engine/test_mappings.py index 26052e60e3f0a..f1b8c443a0509 100644 --- a/tests/aws/services/cloudformation/engine/test_mappings.py +++ b/tests/aws/services/cloudformation/engine/test_mappings.py @@ -43,7 +43,7 @@ def test_simple_mapping_working(self, aws_client, deploy_cfn_template): ] @markers.aws.validated - @pytest.mark.skip(reason="not implemented") + @skip_if_legacy_engine() def test_mapping_with_nonexisting_key(self, aws_client, cleanups, snapshot): """ Tries to deploy a resource with a dependency on a mapping key diff --git a/tests/aws/services/cloudformation/engine/test_replacement.py b/tests/aws/services/cloudformation/engine/test_replacement.py new file mode 100644 index 0000000000000..28e3c30e61fb4 --- /dev/null +++ b/tests/aws/services/cloudformation/engine/test_replacement.py @@ -0,0 +1,70 @@ +import json + +from tests.aws.services.cloudformation.conftest import skip_if_legacy_engine + +from localstack.testing.pytest import markers +from localstack.utils.strings import short_uid + + +@skip_if_legacy_engine() +@markers.aws.validated +@markers.snapshot.skip_snapshot_verify(paths=["$..PhysicalResourceId"]) +def test_requires_replacement( + deploy_cfn_template, + capture_per_resource_events, + snapshot, +): + snapshot.add_transformer(snapshot.transform.cloudformation_api()) + + t1 = { + "Resources": { + "MyQueue": { + "Type": "AWS::SQS::Queue", + }, + }, + "Outputs": { + "QueueName": { + "Value": {"Fn::GetAtt": ["MyQueue", "QueueName"]}, + }, + }, + } + t2 = { + "Parameters": { + "QueueName": { + "Type": "String", + }, + }, + "Resources": { + "MyQueue": { + "Type": "AWS::SQS::Queue", + "Properties": { + "QueueName": {"Ref": "QueueName"}, + }, + }, + }, + "Outputs": { + "QueueName": { + "Value": {"Fn::GetAtt": ["MyQueue", "QueueName"]}, + }, + }, + } + + deploy_result = deploy_cfn_template(template=json.dumps(t1)) + given_queue_name = deploy_result.outputs["QueueName"] + snapshot.add_transformer(snapshot.transform.regex(given_queue_name, "")) + + new_queue_name = f"queue-{short_uid()}" + deploy_result_2 = deploy_cfn_template( + template=json.dumps(t2), + is_update=True, + stack_name=deploy_result.stack_id, + parameters={"QueueName": new_queue_name}, + ) + + assert deploy_result_2.outputs["QueueName"] == new_queue_name + assert given_queue_name != new_queue_name + + per_resource_events = capture_per_resource_events( + deploy_result.stack_id, + ) + snapshot.match("queue-events", per_resource_events["MyQueue"]) diff --git a/tests/aws/services/cloudformation/engine/test_replacement.snapshot.json b/tests/aws/services/cloudformation/engine/test_replacement.snapshot.json new file mode 100644 index 0000000000000..b55fe6284c2d1 --- /dev/null +++ b/tests/aws/services/cloudformation/engine/test_replacement.snapshot.json @@ -0,0 +1,51 @@ +{ + "tests/aws/services/cloudformation/engine/test_replacement.py::test_requires_replacement": { + "recorded-date": "14-01-2026, 14:00:11", + "recorded-content": { + "queue-events": [ + { + "PhysicalResourceId": "https://sqs..amazonaws.com/111111111111/", + "LogicalResourceId": "MyQueue", + "ResourceType": "AWS::SQS::Queue", + "ResourceStatus": "CREATE_IN_PROGRESS", + "Timestamp": "timestamp" + }, + { + "PhysicalResourceId": "https://sqs..amazonaws.com/111111111111/", + "LogicalResourceId": "MyQueue", + "ResourceType": "AWS::SQS::Queue", + "ResourceStatus": "CREATE_COMPLETE", + "Timestamp": "timestamp" + }, + { + "PhysicalResourceId": "https://sqs..amazonaws.com/111111111111/queue-47128d25", + "LogicalResourceId": "MyQueue", + "ResourceType": "AWS::SQS::Queue", + "ResourceStatus": "UPDATE_IN_PROGRESS", + "Timestamp": "timestamp" + }, + { + "PhysicalResourceId": "https://sqs..amazonaws.com/111111111111/queue-47128d25", + "LogicalResourceId": "MyQueue", + "ResourceType": "AWS::SQS::Queue", + "ResourceStatus": "UPDATE_COMPLETE", + "Timestamp": "timestamp" + }, + { + "PhysicalResourceId": "https://sqs..amazonaws.com/111111111111/", + "LogicalResourceId": "MyQueue", + "ResourceType": "AWS::SQS::Queue", + "ResourceStatus": "DELETE_IN_PROGRESS", + "Timestamp": "timestamp" + }, + { + "PhysicalResourceId": "https://sqs..amazonaws.com/111111111111/", + "LogicalResourceId": "MyQueue", + "ResourceType": "AWS::SQS::Queue", + "ResourceStatus": "DELETE_COMPLETE", + "Timestamp": "timestamp" + } + ] + } + } +} diff --git a/tests/aws/services/cloudformation/engine/test_replacement.validation.json b/tests/aws/services/cloudformation/engine/test_replacement.validation.json new file mode 100644 index 0000000000000..d570c031c7acb --- /dev/null +++ b/tests/aws/services/cloudformation/engine/test_replacement.validation.json @@ -0,0 +1,11 @@ +{ + "tests/aws/services/cloudformation/engine/test_replacement.py::test_requires_replacement": { + "last_validated_date": "2026-01-14T14:00:47+00:00", + "durations_in_seconds": { + "setup": 0.81, + "call": 111.56, + "teardown": 35.27, + "total": 147.64 + } + } +} diff --git a/tests/aws/services/cloudformation/engine/test_update_policy.py b/tests/aws/services/cloudformation/engine/test_update_policy.py new file mode 100644 index 0000000000000..cfb5f9f7bee9a --- /dev/null +++ b/tests/aws/services/cloudformation/engine/test_update_policy.py @@ -0,0 +1,119 @@ +import os + +import pytest +from botocore.exceptions import ClientError +from tests.aws.services.cloudformation.conftest import skip_if_legacy_engine + +from localstack.testing.pytest import markers +from localstack.utils.strings import short_uid + + +@markers.snapshot.skip_snapshot_verify( + paths=[ + # our message is different. The AWS message does not seem to include the parameter + # name but ours does + "$..message", + ] +) +@markers.aws.validated +@skip_if_legacy_engine() +def test_update_replace_policy_deletion(deploy_cfn_template, aws_client, snapshot): + template_path = os.path.join( + os.path.dirname(__file__), + "../../../templates/update_retain_policy.yaml", + ) + parameter_value = short_uid() + parameter_name = f"param-{short_uid()}" + stack = deploy_cfn_template( + template_path=template_path, + parameters={ + "ParameterValue": parameter_value, + "ParameterName": parameter_name, + "PolicyType": "Delete", + }, + ) + assert ( + aws_client.ssm.get_parameter(Name=parameter_name)["Parameter"]["Value"] == parameter_value + ) + + # force deletion by changing the resource name + new_parameter_name = f"param-{short_uid()}" + deploy_cfn_template( + template_path=template_path, + parameters={ + "ParameterValue": parameter_value, + "ParameterName": new_parameter_name, + "PolicyType": "Delete", + }, + stack_name=stack.stack_id, + is_update=True, + ) + assert ( + aws_client.ssm.get_parameter(Name=new_parameter_name)["Parameter"]["Value"] + == parameter_value + ) + + # check the previous parameter was deleted + with pytest.raises(ClientError) as exc_info: + aws_client.ssm.get_parameter(Name=parameter_name) + + snapshot.match("error", {"message": str(exc_info.value)}) + + +@markers.aws.validated +@markers.snapshot.skip_snapshot_verify( + paths=[ + "$..PhysicalResourceId", + ] +) +@skip_if_legacy_engine() +def test_update_replace_policy_retain( + deploy_cfn_template, aws_client, snapshot, capture_per_resource_events, cleanups +): + snapshot.add_transformer(snapshot.transform.cloudformation_api()) + template_path = os.path.join( + os.path.dirname(__file__), + "../../../templates/update_retain_policy.yaml", + ) + parameter_value = short_uid() + parameter_name = f"param-{short_uid()}" + # make sure we clean up the parameter when the test finishes + cleanups.append(lambda: aws_client.ssm.delete_parameter(Name=parameter_name)) + + stack = deploy_cfn_template( + template_path=template_path, + parameters={ + "ParameterValue": parameter_value, + "ParameterName": parameter_name, + "PolicyType": "Retain", + }, + ) + snapshot.add_transformer(snapshot.transform.regex(stack.stack_name, "")) + assert ( + aws_client.ssm.get_parameter(Name=parameter_name)["Parameter"]["Value"] == parameter_value + ) + + # force deletion by changing the resource name + new_parameter_name = f"param-{short_uid()}" + deploy_cfn_template( + template_path=template_path, + parameters={ + "ParameterValue": parameter_value, + "ParameterName": new_parameter_name, + "PolicyType": "Retain", + }, + stack_name=stack.stack_id, + is_update=True, + ) + assert ( + aws_client.ssm.get_parameter(Name=new_parameter_name)["Parameter"]["Value"] + == parameter_value + ) + + # check the previous parameter was not deleted + assert ( + aws_client.ssm.get_parameter(Name=parameter_name)["Parameter"]["Value"] == parameter_value + ) + + events = capture_per_resource_events(stack.stack_id) + snapshot.match("per-resource-events", events) diff --git a/tests/aws/services/cloudformation/engine/test_update_policy.snapshot.json b/tests/aws/services/cloudformation/engine/test_update_policy.snapshot.json new file mode 100644 index 0000000000000..d9c8fcb671d22 --- /dev/null +++ b/tests/aws/services/cloudformation/engine/test_update_policy.snapshot.json @@ -0,0 +1,91 @@ +{ + "tests/aws/services/cloudformation/engine/test_update_policy.py::test_update_replace_policy_deletion": { + "recorded-date": "23-01-2026, 12:02:50", + "recorded-content": { + "error": { + "message": "An error occurred (ParameterNotFound) when calling the GetParameter operation: " + } + } + }, + "tests/aws/services/cloudformation/engine/test_update_policy.py::test_update_replace_policy_retain": { + "recorded-date": "23-01-2026, 12:03:14", + "recorded-content": { + "per-resource-events": { + "MyParameter": [ + { + "LogicalResourceId": "MyParameter", + "PhysicalResourceId": "param-fe430ac7", + "ResourceStatus": "CREATE_IN_PROGRESS", + "ResourceType": "AWS::SSM::Parameter", + "Timestamp": "timestamp" + }, + { + "LogicalResourceId": "MyParameter", + "PhysicalResourceId": "param-fe430ac7", + "ResourceStatus": "CREATE_COMPLETE", + "ResourceType": "AWS::SSM::Parameter", + "Timestamp": "timestamp" + }, + { + "LogicalResourceId": "MyParameter", + "PhysicalResourceId": "param-14aa098c", + "ResourceStatus": "UPDATE_IN_PROGRESS", + "ResourceType": "AWS::SSM::Parameter", + "Timestamp": "timestamp" + }, + { + "LogicalResourceId": "MyParameter", + "PhysicalResourceId": "param-14aa098c", + "ResourceStatus": "UPDATE_COMPLETE", + "ResourceType": "AWS::SSM::Parameter", + "Timestamp": "timestamp" + }, + { + "LogicalResourceId": "MyParameter", + "PhysicalResourceId": "param-fe430ac7", + "ResourceStatus": "DELETE_SKIPPED", + "ResourceType": "AWS::SSM::Parameter", + "Timestamp": "timestamp" + } + ], + "Stack": [ + { + "LogicalResourceId": "", + "PhysicalResourceId": "arn::cloudformation::111111111111:stack//", + "ResourceStatus": "REVIEW_IN_PROGRESS", + "ResourceType": "AWS::CloudFormation::Stack", + "Timestamp": "timestamp" + }, + { + "LogicalResourceId": "", + "PhysicalResourceId": "arn::cloudformation::111111111111:stack//", + "ResourceStatus": "CREATE_IN_PROGRESS", + "ResourceType": "AWS::CloudFormation::Stack", + "Timestamp": "timestamp" + }, + { + "LogicalResourceId": "", + "PhysicalResourceId": "arn::cloudformation::111111111111:stack//", + "ResourceStatus": "CREATE_COMPLETE", + "ResourceType": "AWS::CloudFormation::Stack", + "Timestamp": "timestamp" + }, + { + "LogicalResourceId": "", + "PhysicalResourceId": "arn::cloudformation::111111111111:stack//", + "ResourceStatus": "UPDATE_IN_PROGRESS", + "ResourceType": "AWS::CloudFormation::Stack", + "Timestamp": "timestamp" + }, + { + "LogicalResourceId": "", + "PhysicalResourceId": "arn::cloudformation::111111111111:stack//", + "ResourceStatus": "UPDATE_COMPLETE", + "ResourceType": "AWS::CloudFormation::Stack", + "Timestamp": "timestamp" + } + ] + } + } + } +} diff --git a/tests/aws/services/cloudformation/engine/test_update_policy.validation.json b/tests/aws/services/cloudformation/engine/test_update_policy.validation.json new file mode 100644 index 0000000000000..cfbc5a9895a35 --- /dev/null +++ b/tests/aws/services/cloudformation/engine/test_update_policy.validation.json @@ -0,0 +1,20 @@ +{ + "tests/aws/services/cloudformation/engine/test_update_policy.py::test_update_replace_policy_deletion": { + "last_validated_date": "2026-01-23T12:02:55+00:00", + "durations_in_seconds": { + "setup": 0.73, + "call": 23.55, + "teardown": 4.43, + "total": 28.71 + } + }, + "tests/aws/services/cloudformation/engine/test_update_policy.py::test_update_replace_policy_retain": { + "last_validated_date": "2026-01-23T12:03:18+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 19.21, + "teardown": 4.51, + "total": 23.72 + } + } +} diff --git a/tests/aws/services/cloudformation/resource_providers/iam/aws_iam_user/test_basic_user.validation.json b/tests/aws/services/cloudformation/resource_providers/iam/aws_iam_user/test_basic_user.validation.json deleted file mode 100644 index cd0a9d6da97bd..0000000000000 --- a/tests/aws/services/cloudformation/resource_providers/iam/aws_iam_user/test_basic_user.validation.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "tests/aws/services/cloudformation/resource_providers/iam/aws_iam_user/test_basic_user.py::TestBasicCRD::test_autogenerated_values": { - "last_validated_date": "2023-06-28T20:54:57+00:00" - }, - "tests/aws/services/cloudformation/resource_providers/iam/aws_iam_user/test_basic_user.py::TestBasicCRD::test_black_box": { - "last_validated_date": "2023-06-28T20:01:50+00:00" - }, - "tests/aws/services/cloudformation/resource_providers/iam/aws_iam_user/test_basic_user.py::TestBasicCRD::test_getatt": { - "last_validated_date": "2023-07-05T12:15:12+00:00" - }, - "tests/aws/services/cloudformation/resource_providers/iam/aws_iam_user/test_basic_user.py::TestUpdates::test_update_without_replacement": { - "last_validated_date": "2023-06-28T20:31:43+00:00" - } -} diff --git a/tests/aws/services/cloudformation/resource_providers/iam/aws_iam_user/test_parity.validation.json b/tests/aws/services/cloudformation/resource_providers/iam/aws_iam_user/test_parity.validation.json deleted file mode 100644 index a0b1ff9f59556..0000000000000 --- a/tests/aws/services/cloudformation/resource_providers/iam/aws_iam_user/test_parity.validation.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "tests/aws/services/cloudformation/resource_providers/iam/aws_iam_user/test_parity.py::TestParity::test_create_with_full_properties": { - "last_validated_date": "2023-06-29T11:59:27+00:00" - } -} diff --git a/tests/aws/services/cloudformation/resource_providers/iam/test_iam.validation.json b/tests/aws/services/cloudformation/resource_providers/iam/test_iam.validation.json deleted file mode 100644 index 3f4b3cd0f9538..0000000000000 --- a/tests/aws/services/cloudformation/resource_providers/iam/test_iam.validation.json +++ /dev/null @@ -1,29 +0,0 @@ -{ - "tests/aws/services/cloudformation/resource_providers/iam/test_iam.py::test_cfn_handle_iam_role_resource_no_role_name": { - "last_validated_date": "2024-06-18T20:29:57+00:00" - }, - "tests/aws/services/cloudformation/resource_providers/iam/test_iam.py::test_iam_user_access_key": { - "last_validated_date": "2023-07-11T06:23:54+00:00" - }, - "tests/aws/services/cloudformation/resource_providers/iam/test_iam.py::test_iam_username_defaultname": { - "last_validated_date": "2022-05-31T09:29:45+00:00" - }, - "tests/aws/services/cloudformation/resource_providers/iam/test_iam.py::test_managed_policy_with_empty_resource": { - "last_validated_date": "2025-08-01T09:44:24+00:00", - "durations_in_seconds": { - "setup": 1.31, - "call": 41.85, - "teardown": 16.77, - "total": 59.93 - } - }, - "tests/aws/services/cloudformation/resource_providers/iam/test_iam.py::test_server_certificate": { - "last_validated_date": "2024-03-13T20:20:07+00:00" - }, - "tests/aws/services/cloudformation/resource_providers/iam/test_iam.py::test_update_inline_policy": { - "last_validated_date": "2023-04-05T09:55:22+00:00" - }, - "tests/aws/services/cloudformation/resource_providers/iam/test_iam.py::test_updating_stack_with_iam_role": { - "last_validated_date": "2024-06-18T21:02:59+00:00" - } -} diff --git a/tests/aws/services/cloudformation/resources/test_apigateway.py b/tests/aws/services/cloudformation/resources/test_apigateway.py index a79fe5a524851..0291585eed4f5 100644 --- a/tests/aws/services/cloudformation/resources/test_apigateway.py +++ b/tests/aws/services/cloudformation/resources/test_apigateway.py @@ -111,6 +111,7 @@ def test_cfn_apigateway_aws_integration(deploy_cfn_template, aws_client): assert mappings[0] == "(none)" +@markers.requires_in_process # uses pytest httpserver @markers.aws.validated @markers.snapshot.skip_snapshot_verify( paths=[ @@ -729,6 +730,58 @@ def test_serverless_like_deployment_with_update( get_fn_2 = aws_client.lambda_.get_function(FunctionName="test-service-local-api") assert get_fn_2["Configuration"]["Handler"] == "index.handler2" + @markers.aws.validated + def test_serverless_like_deployment_stage_survives_update( + self, deploy_cfn_template, aws_client, snapshot + ): + """ + Regression test for https://github.com/localstack/localstack/issues/13667 + When the Serverless Framework redeploys, it generates a new deployment logical ID each time. + CloudFormation sees this as Add(new) + Remove(old). The old deployment's delete handler + was incorrectly deleting stages that now belong to the new deployment, causing all + subsequent API requests (including CORS OPTIONS) to return 404. + + Uses MOCK integrations (no Lambda dependency) to isolate the CF deployment replacement bug. + """ + snapshot.add_transformer(snapshot.transform.key_value("deploymentId")) + + template_path = os.path.join( + os.path.dirname(__file__), "../../../templates/apigateway-mock-cors-deployment.json" + ) + + # 1. Create stack with first deployment logical ID + stack = deploy_cfn_template( + template_path=template_path, + template_mapping={"deployment_logical_id": "Deploy1000000001", "response_msg": "v1"}, + ) + api_id = stack.outputs["ApiId"] + + # Verify stage and deployment exist after initial creation + stages_after_create = aws_client.apigateway.get_stages(restApiId=api_id) + snapshot.match("stages-after-create", stages_after_create) + assert len(stages_after_create["item"]) == 1 + assert stages_after_create["item"][0]["stageName"] == "local" + + # 2. Update stack with a NEW deployment logical ID (simulates Serverless Framework redeploy) + # CF will Add Deploy2000000002, then Remove Deploy1000000001 + deploy_cfn_template( + is_update=True, + stack_name=stack.stack_name, + template_path=template_path, + template_mapping={"deployment_logical_id": "Deploy2000000002", "response_msg": "v2"}, + ) + + # KEY ASSERTIONS: stage must survive the deployment replacement + stages_after_update = aws_client.apigateway.get_stages(restApiId=api_id) + snapshot.match("stages-after-update", stages_after_update) + assert len(stages_after_update["item"]) == 1, ( + "Stage 'local' was deleted during deployment replacement — this is the bug in #13667" + ) + assert stages_after_update["item"][0]["stageName"] == "local" + + deployments_after_update = aws_client.apigateway.get_deployments(restApiId=api_id) + snapshot.match("deployments-after-update", deployments_after_update) + @markers.snapshot.skip_snapshot_verify(paths=["$..tags"]) @markers.aws.validated @@ -755,3 +808,62 @@ def test_apigateway_deployment_canary_settings(deploy_cfn_template, snapshot, aw deployments = aws_client.apigateway.get_deployments(restApiId=api_id) snapshot.match("get-deployments", deployments) + + +@markers.snapshot.skip_snapshot_verify(paths=["$..tags"]) +@markers.aws.validated +def test_apigateway_stage_with_access_log_settings(deploy_cfn_template, snapshot, aws_client): + snapshot.add_transformers_list( + [ + snapshot.transform.key_value("deploymentId"), + snapshot.transform.key_value("destinationArn"), + snapshot.transform.key_value("aws:cloudformation:stack-name"), + snapshot.transform.resource_name(), + SortingTransformer("items", itemgetter("description")), + ] + ) + + api_name = f"api-{short_uid()}" + stack = deploy_cfn_template( + template_path=os.path.join( + os.path.dirname(__file__), + "../../../templates/apigateway_stage_access_log_settings.yaml", + ), + parameters={"RestApiName": api_name}, + ) + api_id = stack.outputs["RestApiId"] + stage = aws_client.apigateway.get_stages(restApiId=api_id) + snapshot.match("get-stages", stage) + + +class TestApiGatewayBasePathMapping: + @markers.aws.only_localstack + def test_delete_base_path_mapping_missing_base_path( + self, + deploy_cfn_template, + aws_client_factory, + aws_client, + ): + """ + Ensure correct deletion of the AWS::ApiGateway::BasePathMapping resource. + + Note: this test is `only_localstack` because it requires a valid ACM certificate + which is difficult to do wtih our sandbox accounts + """ + # Certificates must always be created in us-east-1 + acm_client = aws_client_factory(region_name="us-east-1").acm + domain_name = f"api-{short_uid()}.localhost.localstack.cloud" + cert_arn = acm_client.request_certificate(DomainName=domain_name)["CertificateArn"] + + template_path = os.path.join( + os.path.dirname(__file__), "../../../templates/apigateway_basepath_mapping.yaml" + ) + + stack = deploy_cfn_template( + template_path=template_path, + parameters={ + "CertificateArn": cert_arn, + "DomainName": domain_name, + }, + ) + stack.destroy() diff --git a/tests/aws/services/cloudformation/resources/test_apigateway.snapshot.json b/tests/aws/services/cloudformation/resources/test_apigateway.snapshot.json index e142016552658..a8781d753ab26 100644 --- a/tests/aws/services/cloudformation/resources/test_apigateway.snapshot.json +++ b/tests/aws/services/cloudformation/resources/test_apigateway.snapshot.json @@ -791,5 +791,91 @@ } } } + }, + "tests/aws/services/cloudformation/resources/test_apigateway.py::TestServerlessApigwLambda::test_serverless_like_deployment_stage_survives_update": { + "recorded-date": "12-02-2026, 18:32:14", + "recorded-content": { + "stages-after-create": { + "item": [ + { + "cacheClusterEnabled": false, + "cacheClusterStatus": "NOT_AVAILABLE", + "createdDate": "datetime", + "deploymentId": "", + "lastUpdatedDate": "datetime", + "methodSettings": {}, + "stageName": "local", + "tracingEnabled": false + } + ], + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "stages-after-update": { + "item": [ + { + "cacheClusterEnabled": false, + "cacheClusterStatus": "NOT_AVAILABLE", + "createdDate": "datetime", + "deploymentId": "", + "lastUpdatedDate": "datetime", + "methodSettings": {}, + "stageName": "local", + "tracingEnabled": false + } + ], + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "deployments-after-update": { + "items": [ + { + "createdDate": "datetime", + "id": "" + } + ], + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/cloudformation/resources/test_apigateway.py::test_apigateway_stage_with_access_log_settings": { + "recorded-date": "25-02-2026, 23:35:55", + "recorded-content": { + "get-stages": { + "item": [ + { + "accessLogSettings": { + "destinationArn": "", + "format": "$context.extendedRequestId $context.identity.sourceIp $context.identity.caller $context.identity.user [$context.requestTime] \"$context.httpMethod $context.resourcePath $context.protocol\" $context.status $context.responseLength $context.requestId" + }, + "cacheClusterEnabled": false, + "cacheClusterStatus": "NOT_AVAILABLE", + "createdDate": "datetime", + "deploymentId": "", + "description": "test stage description", + "lastUpdatedDate": "datetime", + "methodSettings": {}, + "stageName": "test", + "tags": { + "aws:cloudformation:logical-id": "TestStage", + "aws:cloudformation:stack-id": "arn::cloudformation::111111111111:stack//", + "aws:cloudformation:stack-name": "" + }, + "tracingEnabled": false + } + ], + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } } } diff --git a/tests/aws/services/cloudformation/resources/test_apigateway.validation.json b/tests/aws/services/cloudformation/resources/test_apigateway.validation.json index 4008e85bfca4c..349ec2083c2de 100644 --- a/tests/aws/services/cloudformation/resources/test_apigateway.validation.json +++ b/tests/aws/services/cloudformation/resources/test_apigateway.validation.json @@ -1,4 +1,13 @@ { + "tests/aws/services/cloudformation/resources/test_apigateway.py::TestServerlessApigwLambda::test_serverless_like_deployment_stage_survives_update": { + "last_validated_date": "2026-02-12T18:32:21+00:00", + "durations_in_seconds": { + "setup": 0.49, + "call": 32.79, + "teardown": 7.04, + "total": 40.32 + } + }, "tests/aws/services/cloudformation/resources/test_apigateway.py::TestServerlessApigwLambda::test_serverless_like_deployment_with_update": { "last_validated_date": "2024-02-19T08:55:12+00:00" }, @@ -20,6 +29,15 @@ "total": 34.05 } }, + "tests/aws/services/cloudformation/resources/test_apigateway.py::test_apigateway_stage_with_access_log_settings": { + "last_validated_date": "2026-02-25T23:36:04+00:00", + "durations_in_seconds": { + "setup": 0.48, + "call": 24.72, + "teardown": 9.14, + "total": 34.34 + } + }, "tests/aws/services/cloudformation/resources/test_apigateway.py::test_cfn_apigateway_rest_api": { "last_validated_date": "2025-05-05T14:50:14+00:00" }, diff --git a/tests/aws/services/cloudformation/resources/test_dynamodb.py b/tests/aws/services/cloudformation/resources/test_dynamodb.py index ffa1302bc14ca..62d35f8212f99 100644 --- a/tests/aws/services/cloudformation/resources/test_dynamodb.py +++ b/tests/aws/services/cloudformation/resources/test_dynamodb.py @@ -4,6 +4,7 @@ import pytest from aws_cdk import aws_dynamodb as dynamodb from aws_cdk.aws_dynamodb import BillingMode +from botocore.exceptions import ClientError from localstack.testing.pytest import markers from localstack.utils.aws.arns import get_partition @@ -67,8 +68,6 @@ def test_globalindex_read_write_provisioned_throughput_dynamodb_table( paths=[ "$..Table.ProvisionedThroughput.LastDecreaseDateTime", "$..Table.ProvisionedThroughput.LastIncreaseDateTime", - "$..Table.Replicas", - "$..Table.DeletionProtectionEnabled", ] ) def test_default_name_for_table(deploy_cfn_template, snapshot, aws_client): @@ -92,8 +91,6 @@ def test_default_name_for_table(deploy_cfn_template, snapshot, aws_client): paths=[ "$..Table.ProvisionedThroughput.LastDecreaseDateTime", "$..Table.ProvisionedThroughput.LastIncreaseDateTime", - "$..Table.Replicas", - "$..Table.DeletionProtectionEnabled", ] ) @pytest.mark.parametrize("billing_mode", ["PROVISIONED", "PAY_PER_REQUEST"]) @@ -117,7 +114,6 @@ def test_billing_mode_as_conditional(deploy_cfn_template, snapshot, aws_client, @markers.aws.validated @markers.snapshot.skip_snapshot_verify( paths=[ - "$..Table.DeletionProtectionEnabled", "$..Table.ProvisionedThroughput.LastDecreaseDateTime", "$..Table.ProvisionedThroughput.LastIncreaseDateTime", "$..Table.Replicas", @@ -136,7 +132,7 @@ def test_global_table(deploy_cfn_template, snapshot, aws_client): stack.destroy() - with pytest.raises(Exception) as ex: + with pytest.raises(ClientError) as ex: aws_client.dynamodb.describe_table(TableName=stack.outputs["TableName"]) error_code = ex.value.response["Error"]["Code"] diff --git a/tests/aws/services/cloudformation/resources/test_dynamodb.snapshot.json b/tests/aws/services/cloudformation/resources/test_dynamodb.snapshot.json index 3f6efc6628fb0..bff7a5948b1b5 100644 --- a/tests/aws/services/cloudformation/resources/test_dynamodb.snapshot.json +++ b/tests/aws/services/cloudformation/resources/test_dynamodb.snapshot.json @@ -1,6 +1,6 @@ { "tests/aws/services/cloudformation/resources/test_dynamodb.py::test_default_name_for_table": { - "recorded-date": "28-08-2023, 12:34:19", + "recorded-date": "13-10-2025, 18:57:55", "recorded-content": { "table_description": { "Table": { @@ -28,7 +28,12 @@ "TableId": "", "TableName": "", "TableSizeBytes": 0, - "TableStatus": "ACTIVE" + "TableStatus": "ACTIVE", + "WarmThroughput": { + "ReadUnitsPerSecond": 5, + "Status": "ACTIVE", + "WriteUnitsPerSecond": 5 + } }, "ResponseMetadata": { "HTTPHeaders": {}, @@ -54,7 +59,7 @@ } }, "tests/aws/services/cloudformation/resources/test_dynamodb.py::test_billing_mode_as_conditional[PROVISIONED]": { - "recorded-date": "28-08-2023, 12:34:41", + "recorded-date": "13-10-2025, 18:59:26", "recorded-content": { "table_description": { "Table": { @@ -88,7 +93,12 @@ "TableId": "", "TableName": "", "TableSizeBytes": 0, - "TableStatus": "ACTIVE" + "TableStatus": "ACTIVE", + "WarmThroughput": { + "ReadUnitsPerSecond": 5, + "Status": "ACTIVE", + "WriteUnitsPerSecond": 5 + } }, "ResponseMetadata": { "HTTPHeaders": {}, @@ -98,7 +108,7 @@ } }, "tests/aws/services/cloudformation/resources/test_dynamodb.py::test_billing_mode_as_conditional[PAY_PER_REQUEST]": { - "recorded-date": "28-08-2023, 12:35:02", + "recorded-date": "13-10-2025, 19:00:03", "recorded-content": { "table_description": { "Table": { @@ -136,7 +146,12 @@ "TableId": "", "TableName": "", "TableSizeBytes": 0, - "TableStatus": "ACTIVE" + "TableStatus": "ACTIVE", + "WarmThroughput": { + "ReadUnitsPerSecond": 12000, + "Status": "ACTIVE", + "WriteUnitsPerSecond": 4000 + } }, "ResponseMetadata": { "HTTPHeaders": {}, @@ -146,7 +161,7 @@ } }, "tests/aws/services/cloudformation/resources/test_dynamodb.py::test_global_table": { - "recorded-date": "01-12-2023, 12:54:13", + "recorded-date": "13-10-2025, 19:01:29", "recorded-content": { "table_description": { "Table": { @@ -178,7 +193,12 @@ "TableId": "", "TableName": "", "TableSizeBytes": 0, - "TableStatus": "ACTIVE" + "TableStatus": "ACTIVE", + "WarmThroughput": { + "ReadUnitsPerSecond": 12000, + "Status": "ACTIVE", + "WriteUnitsPerSecond": 4000 + } }, "ResponseMetadata": { "HTTPHeaders": {}, diff --git a/tests/aws/services/cloudformation/resources/test_dynamodb.validation.json b/tests/aws/services/cloudformation/resources/test_dynamodb.validation.json index fc40777d4d842..c2e3b5520fc7c 100644 --- a/tests/aws/services/cloudformation/resources/test_dynamodb.validation.json +++ b/tests/aws/services/cloudformation/resources/test_dynamodb.validation.json @@ -1,15 +1,39 @@ { "tests/aws/services/cloudformation/resources/test_dynamodb.py::test_billing_mode_as_conditional[PAY_PER_REQUEST]": { - "last_validated_date": "2023-08-28T10:35:02+00:00" + "last_validated_date": "2025-10-13T19:00:19+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 21.82, + "teardown": 15.38, + "total": 37.2 + } }, "tests/aws/services/cloudformation/resources/test_dynamodb.py::test_billing_mode_as_conditional[PROVISIONED]": { - "last_validated_date": "2023-08-28T10:34:41+00:00" + "last_validated_date": "2025-10-13T18:59:41+00:00", + "durations_in_seconds": { + "setup": 0.47, + "call": 22.58, + "teardown": 15.38, + "total": 38.43 + } }, "tests/aws/services/cloudformation/resources/test_dynamodb.py::test_default_name_for_table": { - "last_validated_date": "2023-08-28T10:34:19+00:00" + "last_validated_date": "2025-10-13T18:58:11+00:00", + "durations_in_seconds": { + "setup": 0.48, + "call": 22.98, + "teardown": 15.44, + "total": 38.9 + } }, "tests/aws/services/cloudformation/resources/test_dynamodb.py::test_global_table": { - "last_validated_date": "2023-12-01T11:54:13+00:00" + "last_validated_date": "2025-10-13T19:01:29+00:00", + "durations_in_seconds": { + "setup": 0.47, + "call": 38.13, + "teardown": 0.24, + "total": 38.84 + } }, "tests/aws/services/cloudformation/resources/test_dynamodb.py::test_global_table_with_ttl_and_sse": { "last_validated_date": "2024-03-12T15:44:36+00:00" diff --git a/tests/aws/services/cloudformation/resources/test_events.py b/tests/aws/services/cloudformation/resources/test_events.py index e8eb95e232c1f..035c20cfafc73 100644 --- a/tests/aws/services/cloudformation/resources/test_events.py +++ b/tests/aws/services/cloudformation/resources/test_events.py @@ -141,8 +141,9 @@ def test_event_rule_to_logs(deploy_cfn_template, aws_client): assert len(resp["Entries"]) == 1 wait_until( - lambda: len(aws_client.logs.describe_log_streams(logGroupName=log_group_name)["logStreams"]) - > 0, + lambda: ( + len(aws_client.logs.describe_log_streams(logGroupName=log_group_name)["logStreams"]) > 0 + ), 1.0, 5, "linear", diff --git a/tests/aws/services/cloudformation/resources/test_lambda.py b/tests/aws/services/cloudformation/resources/test_lambda.py index 3367ad065f467..02dd57e8fb371 100644 --- a/tests/aws/services/cloudformation/resources/test_lambda.py +++ b/tests/aws/services/cloudformation/resources/test_lambda.py @@ -549,6 +549,7 @@ def test_lambda_cfn_run_with_empty_string_replacement_deny_list( ) +@markers.requires_in_process @markers.aws.only_localstack(reason="This is functionality specific to Localstack") def test_lambda_cfn_run_with_non_empty_string_replacement_deny_list( deploy_cfn_template, aws_client, get_function_envars, monkeypatch @@ -981,7 +982,6 @@ def _send_events(): # dynamodb describe_table "$..Table.ProvisionedThroughput.LastDecreaseDateTime", "$..Table.ProvisionedThroughput.LastIncreaseDateTime", - "$..Table.Replicas", # stream result "$..StreamDescription.CreationRequestDateTime", ] diff --git a/tests/aws/services/cloudformation/resources/test_lambda.snapshot.json b/tests/aws/services/cloudformation/resources/test_lambda.snapshot.json index c997af736bf37..b104b74f4924d 100644 --- a/tests/aws/services/cloudformation/resources/test_lambda.snapshot.json +++ b/tests/aws/services/cloudformation/resources/test_lambda.snapshot.json @@ -860,7 +860,7 @@ } }, "tests/aws/services/cloudformation/resources/test_lambda.py::TestCfnLambdaIntegrations::test_cfn_lambda_dynamodb_source": { - "recorded-date": "12-10-2024, 10:46:17", + "recorded-date": "13-10-2025, 21:45:29", "recorded-content": { "stack_resources": { "StackResources": [ @@ -1069,7 +1069,12 @@ "TableId": "", "TableName": "", "TableSizeBytes": 0, - "TableStatus": "ACTIVE" + "TableStatus": "ACTIVE", + "WarmThroughput": { + "ReadUnitsPerSecond": 5, + "Status": "ACTIVE", + "WriteUnitsPerSecond": 5 + } }, "ResponseMetadata": { "HTTPHeaders": {}, diff --git a/tests/aws/services/cloudformation/resources/test_lambda.validation.json b/tests/aws/services/cloudformation/resources/test_lambda.validation.json index c38f2474516d6..2bab5abcf3c0e 100644 --- a/tests/aws/services/cloudformation/resources/test_lambda.validation.json +++ b/tests/aws/services/cloudformation/resources/test_lambda.validation.json @@ -3,7 +3,13 @@ "last_validated_date": "2024-12-10T16:48:04+00:00" }, "tests/aws/services/cloudformation/resources/test_lambda.py::TestCfnLambdaIntegrations::test_cfn_lambda_dynamodb_source": { - "last_validated_date": "2024-10-12T10:46:17+00:00" + "last_validated_date": "2025-10-13T21:45:29+00:00", + "durations_in_seconds": { + "setup": 0.5, + "call": 142.89, + "teardown": 0.24, + "total": 143.63 + } }, "tests/aws/services/cloudformation/resources/test_lambda.py::TestCfnLambdaIntegrations::test_cfn_lambda_kinesis_source": { "last_validated_date": "2024-10-12T10:52:28+00:00" diff --git a/tests/aws/services/cloudformation/resources/test_logs.py b/tests/aws/services/cloudformation/resources/test_logs.py index 6813283c5b505..69a0298b7b92c 100644 --- a/tests/aws/services/cloudformation/resources/test_logs.py +++ b/tests/aws/services/cloudformation/resources/test_logs.py @@ -1,6 +1,11 @@ import os.path +import pytest +from tests.aws.services.cloudformation.conftest import skip_if_legacy_engine + from localstack.testing.pytest import markers +from localstack.testing.pytest.fixtures import StackDeployError +from localstack.utils.strings import short_uid @markers.aws.validated @@ -47,3 +52,26 @@ def test_cfn_handle_log_group_resource(deploy_cfn_template, aws_client, snapshot stack.destroy() response = aws_client.logs.describe_log_groups(logGroupNamePrefix=log_group_prefix) assert len(response["logGroups"]) == 0 + + +@markers.aws.validated +@skip_if_legacy_engine() +def test_handle_existing_log_group(deploy_cfn_template, aws_client, snapshot, cleanups): + snapshot.add_transformer(snapshot.transform.cloudformation_api()) + snapshot.add_transformer(snapshot.transform.key_value("ParameterValue")) + + log_group_name = f"logs-{short_uid()}" + + # create the log group + aws_client.logs.create_log_group(logGroupName=log_group_name) + cleanups.append(lambda: aws_client.logs.delete_log_group(logGroupName=log_group_name)) + + with pytest.raises(StackDeployError) as exc_info: + deploy_cfn_template( + template_path=os.path.join( + os.path.dirname(__file__), "../../../templates/logs_group.yml" + ), + parameters={"LogGroupName": log_group_name}, + ) + + snapshot.match("failed-stack-describe", exc_info.value.describe_result) diff --git a/tests/aws/services/cloudformation/resources/test_logs.snapshot.json b/tests/aws/services/cloudformation/resources/test_logs.snapshot.json index 8ad8af97a9ca5..eb3c9d98ae554 100644 --- a/tests/aws/services/cloudformation/resources/test_logs.snapshot.json +++ b/tests/aws/services/cloudformation/resources/test_logs.snapshot.json @@ -38,5 +38,37 @@ } } } + }, + "tests/aws/services/cloudformation/resources/test_logs.py::test_handle_existing_log_group": { + "recorded-date": "06-10-2025, 16:24:57", + "recorded-content": { + "failed-stack-describe": { + "Capabilities": [ + "CAPABILITY_AUTO_EXPAND", + "CAPABILITY_IAM", + "CAPABILITY_NAMED_IAM" + ], + "CreationTime": "datetime", + "DeletionTime": "datetime", + "DisableRollback": false, + "DriftInformation": { + "StackDriftStatus": "NOT_CHECKED" + }, + "EnableTerminationProtection": false, + "LastUpdatedTime": "datetime", + "NotificationARNs": [], + "Parameters": [ + { + "ParameterKey": "LogGroupName", + "ParameterValue": "" + } + ], + "RollbackConfiguration": {}, + "StackId": "arn::cloudformation::111111111111:stack//", + "StackName": "", + "StackStatus": "ROLLBACK_COMPLETE", + "Tags": [] + } + } } } diff --git a/tests/aws/services/cloudformation/resources/test_logs.validation.json b/tests/aws/services/cloudformation/resources/test_logs.validation.json index fce835093de2a..a4ffe25914229 100644 --- a/tests/aws/services/cloudformation/resources/test_logs.validation.json +++ b/tests/aws/services/cloudformation/resources/test_logs.validation.json @@ -2,6 +2,15 @@ "tests/aws/services/cloudformation/resources/test_logs.py::test_cfn_handle_log_group_resource": { "last_validated_date": "2024-06-20T16:15:47+00:00" }, + "tests/aws/services/cloudformation/resources/test_logs.py::test_handle_existing_log_group": { + "last_validated_date": "2025-10-06T16:24:57+00:00", + "durations_in_seconds": { + "setup": 0.81, + "call": 10.58, + "teardown": 0.22, + "total": 11.61 + } + }, "tests/aws/services/cloudformation/resources/test_logs.py::test_logstream": { "last_validated_date": "2022-07-29T11:22:53+00:00" } diff --git a/tests/aws/services/cloudformation/resources/test_route53.py b/tests/aws/services/cloudformation/resources/test_route53.py deleted file mode 100644 index 5b5ff47e6ea04..0000000000000 --- a/tests/aws/services/cloudformation/resources/test_route53.py +++ /dev/null @@ -1,66 +0,0 @@ -import os - -from localstack.testing.pytest import markers - - -@markers.aws.validated -def test_create_record_set_via_id(route53_hosted_zone, deploy_cfn_template): - create_zone_response = route53_hosted_zone() - hosted_zone_id = create_zone_response["HostedZone"]["Id"] - route53_name = create_zone_response["HostedZone"]["Name"] - parameters = {"HostedZoneId": hosted_zone_id, "Name": route53_name} - deploy_cfn_template( - template_path=os.path.join( - os.path.dirname(__file__), "../../../templates/route53_hostedzoneid_template.yaml" - ), - parameters=parameters, - max_wait=300, - ) - - -@markers.aws.validated -def test_create_record_set_via_name(deploy_cfn_template, route53_hosted_zone): - create_zone_response = route53_hosted_zone() - route53_name = create_zone_response["HostedZone"]["Name"] - parameters = {"HostedZoneName": route53_name, "Name": route53_name} - deploy_cfn_template( - template_path=os.path.join( - os.path.dirname(__file__), "../../../templates/route53_hostedzonename_template.yaml" - ), - parameters=parameters, - ) - - -@markers.aws.validated -def test_create_record_set_without_resource_record(deploy_cfn_template, route53_hosted_zone): - create_zone_response = route53_hosted_zone() - hosted_zone_id = create_zone_response["HostedZone"]["Id"] - route53_name = create_zone_response["HostedZone"]["Name"] - parameters = {"HostedZoneId": hosted_zone_id, "Name": route53_name} - deploy_cfn_template( - template_path=os.path.join( - os.path.dirname(__file__), - "../../../templates/route53_recordset_without_resource_records.yaml", - ), - parameters=parameters, - ) - - -@markers.aws.validated -@markers.snapshot.skip_snapshot_verify( - paths=["$..HealthCheckConfig.EnableSNI", "$..HealthCheckVersion"] -) -def test_create_health_check(deploy_cfn_template, aws_client, snapshot): - stack = deploy_cfn_template( - template_path=os.path.join( - os.path.dirname(__file__), - "../../../templates/route53_healthcheck.yml", - ), - ) - health_check_id = stack.outputs["HealthCheckId"] - print(health_check_id) - health_check = aws_client.route53.get_health_check(HealthCheckId=health_check_id) - - snapshot.add_transformer(snapshot.transform.key_value("Id", "id")) - snapshot.add_transformer(snapshot.transform.key_value("CallerReference", "caller-reference")) - snapshot.match("HealthCheck", health_check["HealthCheck"]) diff --git a/tests/aws/services/cloudformation/resources/test_route53.validation.json b/tests/aws/services/cloudformation/resources/test_route53.validation.json deleted file mode 100644 index 8b56e5dacfa51..0000000000000 --- a/tests/aws/services/cloudformation/resources/test_route53.validation.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "tests/aws/services/cloudformation/resources/test_route53.py::test_create_health_check": { - "last_validated_date": "2023-09-22T11:50:49+00:00" - } -} diff --git a/tests/aws/services/cloudformation/resources/test_sns.validation.json b/tests/aws/services/cloudformation/resources/test_sns.validation.json index 8686e44ea3fd8..a44447db4d4c2 100644 --- a/tests/aws/services/cloudformation/resources/test_sns.validation.json +++ b/tests/aws/services/cloudformation/resources/test_sns.validation.json @@ -24,12 +24,12 @@ } }, "tests/aws/services/cloudformation/resources/test_sns.py::test_sns_topic_policy_resets_to_default": { - "last_validated_date": "2025-07-04T00:04:32+00:00", + "last_validated_date": "2026-02-04T13:55:33+00:00", "durations_in_seconds": { - "setup": 1.08, - "call": 22.27, - "teardown": 0.09, - "total": 23.44 + "setup": 2.07, + "call": 33.8, + "teardown": 0.31, + "total": 36.18 } }, "tests/aws/services/cloudformation/resources/test_sns.py::test_sns_topic_update_attributes": { diff --git a/tests/aws/services/cloudformation/resources/test_sqs.py b/tests/aws/services/cloudformation/resources/test_sqs.py deleted file mode 100644 index d054c3f82a55d..0000000000000 --- a/tests/aws/services/cloudformation/resources/test_sqs.py +++ /dev/null @@ -1,143 +0,0 @@ -import os - -import pytest -from botocore.exceptions import ClientError - -from localstack.testing.pytest import markers -from localstack.utils.strings import short_uid -from localstack.utils.sync import wait_until - - -@markers.aws.validated -def test_sqs_queue_policy(deploy_cfn_template, aws_client, snapshot): - result = deploy_cfn_template( - template_path=os.path.join( - os.path.dirname(__file__), "../../../templates/sqs_with_queuepolicy.yaml" - ) - ) - queue_url = result.outputs["QueueUrlOutput"] - resp = aws_client.sqs.get_queue_attributes(QueueUrl=queue_url, AttributeNames=["Policy"]) - snapshot.match("policy", resp) - snapshot.add_transformer(snapshot.transform.key_value("Resource")) - - -@markers.aws.validated -def test_sqs_fifo_queue_generates_valid_name(deploy_cfn_template): - result = deploy_cfn_template( - template_path=os.path.join( - os.path.dirname(__file__), "../../../templates/sqs_fifo_autogenerate_name.yaml" - ), - parameters={"IsFifo": "true"}, - max_wait=240, - ) - assert ".fifo" in result.outputs["FooQueueName"] - - -@markers.aws.validated -def test_sqs_non_fifo_queue_generates_valid_name(deploy_cfn_template): - result = deploy_cfn_template( - template_path=os.path.join( - os.path.dirname(__file__), "../../../templates/sqs_fifo_autogenerate_name.yaml" - ), - parameters={"IsFifo": "false"}, - max_wait=240, - ) - assert ".fifo" not in result.outputs["FooQueueName"] - - -@markers.aws.validated -def test_cfn_handle_sqs_resource(deploy_cfn_template, aws_client, snapshot): - queue_name = f"queue-{short_uid()}" - - stack = deploy_cfn_template( - template_path=os.path.join( - os.path.dirname(__file__), "../../../templates/sqs_fifo_queue.yml" - ), - parameters={"QueueName": queue_name}, - ) - - rs = aws_client.sqs.get_queue_attributes( - QueueUrl=stack.outputs["QueueURL"], AttributeNames=["All"] - ) - snapshot.match("queue", rs) - snapshot.add_transformer(snapshot.transform.regex(queue_name, "")) - - # clean up - stack.destroy() - - with pytest.raises(ClientError) as ctx: - aws_client.sqs.get_queue_url(QueueName=f"{queue_name}.fifo") - snapshot.match("error", ctx.value.response) - - -@markers.aws.validated -def test_update_queue_no_change(deploy_cfn_template, aws_client, snapshot): - bucket_name = f"bucket-{short_uid()}" - - stack = deploy_cfn_template( - template_path=os.path.join( - os.path.dirname(__file__), "../../../templates/sqs_queue_update_no_change.yml" - ), - parameters={ - "AddBucket": "false", - "BucketName": bucket_name, - }, - ) - queue_url = stack.outputs["QueueUrl"] - queue_arn = stack.outputs["QueueArn"] - snapshot.add_transformer(snapshot.transform.regex(queue_url, "")) - snapshot.add_transformer(snapshot.transform.regex(queue_arn, "")) - - snapshot.match("outputs-1", stack.outputs) - - # deploy a second time with no change to the SQS queue - updated_stack = deploy_cfn_template( - template_path=os.path.join( - os.path.dirname(__file__), "../../../templates/sqs_queue_update_no_change.yml" - ), - is_update=True, - stack_name=stack.stack_name, - parameters={ - "AddBucket": "true", - "BucketName": bucket_name, - }, - ) - snapshot.match("outputs-2", updated_stack.outputs) - - -@markers.aws.validated -def test_update_sqs_queuepolicy(deploy_cfn_template, aws_client, snapshot): - stack = deploy_cfn_template( - template_path=os.path.join( - os.path.dirname(__file__), "../../../templates/sqs_with_queuepolicy.yaml" - ) - ) - - policy = aws_client.sqs.get_queue_attributes( - QueueUrl=stack.outputs["QueueUrlOutput"], AttributeNames=["Policy"] - ) - snapshot.match("policy1", policy["Attributes"]["Policy"]) - - updated_stack = deploy_cfn_template( - template_path=os.path.join( - os.path.dirname(__file__), "../../../templates/sqs_with_queuepolicy_updated.yaml" - ), - is_update=True, - stack_name=stack.stack_name, - ) - - def check_policy_updated(): - policy_updated = aws_client.sqs.get_queue_attributes( - QueueUrl=updated_stack.outputs["QueueUrlOutput"], AttributeNames=["Policy"] - ) - assert policy_updated["Attributes"]["Policy"] != policy["Attributes"]["Policy"] - return policy_updated - - wait_until(check_policy_updated) - - policy = aws_client.sqs.get_queue_attributes( - QueueUrl=updated_stack.outputs["QueueUrlOutput"], AttributeNames=["Policy"] - ) - - snapshot.match("policy2", policy["Attributes"]["Policy"]) - snapshot.add_transformer(snapshot.transform.cloudformation_api()) diff --git a/tests/aws/services/cloudformation/resources/test_sqs.snapshot.json b/tests/aws/services/cloudformation/resources/test_sqs.snapshot.json deleted file mode 100644 index 9f26c7054cc7c..0000000000000 --- a/tests/aws/services/cloudformation/resources/test_sqs.snapshot.json +++ /dev/null @@ -1,119 +0,0 @@ -{ - "tests/aws/services/cloudformation/resources/test_sqs.py::test_update_queue_no_change": { - "recorded-date": "08-12-2023, 21:11:26", - "recorded-content": { - "outputs-1": { - "QueueArn": "", - "QueueUrl": "" - }, - "outputs-2": { - "QueueArn": "", - "QueueUrl": "" - } - } - }, - "tests/aws/services/cloudformation/resources/test_sqs.py::test_update_sqs_queuepolicy": { - "recorded-date": "27-03-2024, 20:30:24", - "recorded-content": { - "policy1": { - "Version": "2012-10-17", - "Statement": [ - { - "Effect": "Allow", - "Principal": "*", - "Action": [ - "sqs:SendMessage", - "sqs:GetQueueAttributes", - "sqs:GetQueueUrl" - ], - "Resource": "arn::sqs::111111111111:" - } - ] - }, - "policy2": { - "Version": "2012-10-17", - "Statement": [ - { - "Effect": "Deny", - "Principal": "*", - "Action": [ - "sqs:SendMessage", - "sqs:GetQueueAttributes", - "sqs:GetQueueUrl" - ], - "Resource": "arn::sqs::111111111111:" - } - ] - } - } - }, - "tests/aws/services/cloudformation/resources/test_sqs.py::test_sqs_queue_policy": { - "recorded-date": "03-07-2024, 19:49:04", - "recorded-content": { - "policy": { - "Attributes": { - "Policy": { - "Version": "2012-10-17", - "Statement": [ - { - "Effect": "Allow", - "Principal": "*", - "Action": [ - "sqs:SendMessage", - "sqs:GetQueueAttributes", - "sqs:GetQueueUrl" - ], - "Resource": "" - } - ] - } - }, - "ResponseMetadata": { - "HTTPHeaders": {}, - "HTTPStatusCode": 200 - } - } - } - }, - "tests/aws/services/cloudformation/resources/test_sqs.py::test_cfn_handle_sqs_resource": { - "recorded-date": "27-08-2025, 09:37:44", - "recorded-content": { - "queue": { - "Attributes": { - "ApproximateNumberOfMessages": "0", - "ApproximateNumberOfMessagesDelayed": "0", - "ApproximateNumberOfMessagesNotVisible": "0", - "ContentBasedDeduplication": "false", - "CreatedTimestamp": "timestamp", - "DeduplicationScope": "queue", - "DelaySeconds": "0", - "FifoQueue": "true", - "FifoThroughputLimit": "perQueue", - "LastModifiedTimestamp": "timestamp", - "MaximumMessageSize": "1048576", - "MessageRetentionPeriod": "345600", - "QueueArn": "arn::sqs::111111111111:.fifo", - "ReceiveMessageWaitTimeSeconds": "0", - "SqsManagedSseEnabled": "true", - "VisibilityTimeout": "30" - }, - "ResponseMetadata": { - "HTTPHeaders": {}, - "HTTPStatusCode": 200 - } - }, - "error": { - "Error": { - "Code": "AWS.SimpleQueueService.NonExistentQueue", - "Message": "The specified queue does not exist.", - "QueryErrorCode": "QueueDoesNotExist", - "Type": "Sender" - }, - "ResponseMetadata": { - "HTTPHeaders": {}, - "HTTPStatusCode": 400 - } - } - } - } -} diff --git a/tests/aws/services/cloudformation/resources/test_sqs.validation.json b/tests/aws/services/cloudformation/resources/test_sqs.validation.json deleted file mode 100644 index 1b9bdb2d7d36b..0000000000000 --- a/tests/aws/services/cloudformation/resources/test_sqs.validation.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "tests/aws/services/cloudformation/resources/test_sqs.py::test_cfn_handle_sqs_resource": { - "last_validated_date": "2025-08-27T09:37:44+00:00", - "durations_in_seconds": { - "setup": 0.82, - "call": 74.96, - "teardown": 0.11, - "total": 75.89 - } - }, - "tests/aws/services/cloudformation/resources/test_sqs.py::test_sqs_fifo_queue_generates_valid_name": { - "last_validated_date": "2024-05-15T02:01:00+00:00" - }, - "tests/aws/services/cloudformation/resources/test_sqs.py::test_sqs_non_fifo_queue_generates_valid_name": { - "last_validated_date": "2024-05-15T01:59:34+00:00" - }, - "tests/aws/services/cloudformation/resources/test_sqs.py::test_sqs_queue_policy": { - "last_validated_date": "2024-07-03T19:49:04+00:00" - }, - "tests/aws/services/cloudformation/resources/test_sqs.py::test_update_queue_no_change": { - "last_validated_date": "2023-12-08T20:11:26+00:00" - }, - "tests/aws/services/cloudformation/resources/test_sqs.py::test_update_sqs_queuepolicy": { - "last_validated_date": "2024-03-27T20:30:23+00:00" - } -} diff --git a/tests/aws/services/cloudformation/test_change_set_conditions.py b/tests/aws/services/cloudformation/test_change_set_conditions.py index d99a8025912c5..b9ca722b71a9f 100644 --- a/tests/aws/services/cloudformation/test_change_set_conditions.py +++ b/tests/aws/services/cloudformation/test_change_set_conditions.py @@ -1,8 +1,12 @@ +import json + +import pytest +from botocore.exceptions import ClientError from localstack_snapshot.snapshots.transformer import RegexTransformer from tests.aws.services.cloudformation.conftest import skip_if_legacy_engine from localstack.testing.pytest import markers -from localstack.utils.strings import long_uid +from localstack.utils.strings import long_uid, short_uid @skip_if_legacy_engine() @@ -166,3 +170,33 @@ def test_condition_add_new_positive_condition_to_existent_resource( }, } capture_update_process(snapshot, template_1, template_2) + + @markers.aws.validated + def test_missing_condition(self, snapshot, aws_client): + template = { + "Resources": { + "MyVpc": { + "Type": "AWS::EC2::VPC", + "Properties": { + "CidrBlock": "10.0.0.0/24", + "Tags": [ + { + "Fn::If": ["MissingCondition", "AWS::NoValue", "AWS::NoValue"], + }, + ], + }, + }, + } + } + + cs_name = f"cs-{short_uid()}" + stack_name = f"stack-{short_uid()}" + with pytest.raises(ClientError) as exc_info: + aws_client.cloudformation.create_change_set( + StackName=stack_name, + ChangeSetName=cs_name, + ChangeSetType="CREATE", + TemplateBody=json.dumps(template), + ) + + snapshot.match("error", exc_info.value.response) diff --git a/tests/aws/services/cloudformation/test_change_set_conditions.snapshot.json b/tests/aws/services/cloudformation/test_change_set_conditions.snapshot.json index b479512b031d5..b637e191e5dcb 100644 --- a/tests/aws/services/cloudformation/test_change_set_conditions.snapshot.json +++ b/tests/aws/services/cloudformation/test_change_set_conditions.snapshot.json @@ -1532,5 +1532,21 @@ "Tags": [] } } + }, + "tests/aws/services/cloudformation/test_change_set_conditions.py::TestChangeSetConditions::test_missing_condition": { + "recorded-date": "08-10-2025, 15:58:18", + "recorded-content": { + "error": { + "Error": { + "Code": "ValidationError", + "Message": "Template error: unresolved condition dependency MissingCondition in Fn::If", + "Type": "Sender" + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + } + } } } diff --git a/tests/aws/services/cloudformation/test_change_set_conditions.validation.json b/tests/aws/services/cloudformation/test_change_set_conditions.validation.json index ebc592903e0bb..546d39602228d 100644 --- a/tests/aws/services/cloudformation/test_change_set_conditions.validation.json +++ b/tests/aws/services/cloudformation/test_change_set_conditions.validation.json @@ -10,5 +10,14 @@ }, "tests/aws/services/cloudformation/test_change_set_conditions.py::TestChangeSetConditions::test_condition_update_removes_resource": { "last_validated_date": "2025-04-15T13:51:50+00:00" + }, + "tests/aws/services/cloudformation/test_change_set_conditions.py::TestChangeSetConditions::test_missing_condition": { + "last_validated_date": "2025-10-08T15:58:18+00:00", + "durations_in_seconds": { + "setup": 0.96, + "call": 0.3, + "teardown": 0.0, + "total": 1.26 + } } } diff --git a/tests/aws/services/cloudformation/test_change_set_fn_get_attr.py b/tests/aws/services/cloudformation/test_change_set_fn_get_attr.py index 24f9725a5be77..381c26031011c 100644 --- a/tests/aws/services/cloudformation/test_change_set_fn_get_attr.py +++ b/tests/aws/services/cloudformation/test_change_set_fn_get_attr.py @@ -1,9 +1,12 @@ +import os + import pytest +from botocore.exceptions import ClientError from localstack_snapshot.snapshots.transformer import RegexTransformer from tests.aws.services.cloudformation.conftest import skip_if_legacy_engine from localstack.testing.pytest import markers -from localstack.utils.strings import long_uid +from localstack.utils.strings import long_uid, short_uid @skip_if_legacy_engine() @@ -308,3 +311,30 @@ def test_immutable_property_update_causes_resource_replacement( } } capture_update_process(snapshot, template_1, template_2) + + @markers.aws.validated + @pytest.mark.parametrize("template_name", ["getatt_validation.yml", "getatt_validation2.yml"]) + def test_invalid_structure(self, snapshot, deploy_cfn_template, aws_client, template_name): + cs_name = f"cs-{short_uid()}" + stack_name = f"stack-{short_uid()}" + + with open( + os.path.join(os.path.dirname(__file__), f"../../templates/{template_name}") + ) as infile: + template_body = infile.read() + + with pytest.raises(ClientError) as exc_info: + aws_client.cloudformation.create_change_set( + StackName=stack_name, + ChangeSetName=cs_name, + ChangeSetType="CREATE", + TemplateBody=template_body, + Parameters=[ + { + "ParameterKey": "MyParameterValue", + "ParameterValue": "BadResourceName", + }, + ], + ) + + snapshot.match("error", exc_info.value.response) diff --git a/tests/aws/services/cloudformation/test_change_set_fn_get_attr.snapshot.json b/tests/aws/services/cloudformation/test_change_set_fn_get_attr.snapshot.json index 8cdfbcbee1fe8..628748f38c8b6 100644 --- a/tests/aws/services/cloudformation/test_change_set_fn_get_attr.snapshot.json +++ b/tests/aws/services/cloudformation/test_change_set_fn_get_attr.snapshot.json @@ -3016,5 +3016,37 @@ "Tags": [] } } + }, + "tests/aws/services/cloudformation/test_change_set_fn_get_attr.py::TestChangeSetFnGetAttr::test_invalid_structure[getatt_validation.yml]": { + "recorded-date": "08-10-2025, 12:13:08", + "recorded-content": { + "error": { + "Error": { + "Code": "ValidationError", + "Message": "Template error: every Fn::GetAtt object requires two non-empty parameters, the resource name and the resource attribute", + "Type": "Sender" + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + } + } + }, + "tests/aws/services/cloudformation/test_change_set_fn_get_attr.py::TestChangeSetFnGetAttr::test_invalid_structure[getatt_validation2.yml]": { + "recorded-date": "08-10-2025, 12:13:08", + "recorded-content": { + "error": { + "Error": { + "Code": "ValidationError", + "Message": "Template error: every Fn::GetAtt object requires two non-empty parameters, the resource name and the resource attribute", + "Type": "Sender" + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + } + } } } diff --git a/tests/aws/services/cloudformation/test_change_set_fn_get_attr.validation.json b/tests/aws/services/cloudformation/test_change_set_fn_get_attr.validation.json index 2bd651509bd74..03b7ac8e94f84 100644 --- a/tests/aws/services/cloudformation/test_change_set_fn_get_attr.validation.json +++ b/tests/aws/services/cloudformation/test_change_set_fn_get_attr.validation.json @@ -11,6 +11,24 @@ "tests/aws/services/cloudformation/test_change_set_fn_get_attr.py::TestChangeSetFnGetAttr::test_immutable_property_update_causes_resource_replacement": { "last_validated_date": "2025-04-08T12:17:00+00:00" }, + "tests/aws/services/cloudformation/test_change_set_fn_get_attr.py::TestChangeSetFnGetAttr::test_invalid_structure[getatt_validation.yml]": { + "last_validated_date": "2025-10-08T12:13:08+00:00", + "durations_in_seconds": { + "setup": 0.96, + "call": 0.31, + "teardown": 0.0, + "total": 1.27 + } + }, + "tests/aws/services/cloudformation/test_change_set_fn_get_attr.py::TestChangeSetFnGetAttr::test_invalid_structure[getatt_validation2.yml]": { + "last_validated_date": "2025-10-08T12:13:08+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.15, + "teardown": 0.0, + "total": 0.15 + } + }, "tests/aws/services/cloudformation/test_change_set_fn_get_attr.py::TestChangeSetFnGetAttr::test_resource_addition": { "last_validated_date": "2025-04-08T12:33:53+00:00" }, diff --git a/tests/aws/services/cloudformation/test_change_set_fn_split.py b/tests/aws/services/cloudformation/test_change_set_fn_split.py index 01b2869a38001..33f25c4ecfcff 100644 --- a/tests/aws/services/cloudformation/test_change_set_fn_split.py +++ b/tests/aws/services/cloudformation/test_change_set_fn_split.py @@ -1,8 +1,12 @@ +import json + +import pytest +from botocore.exceptions import ClientError from localstack_snapshot.snapshots.transformer import RegexTransformer from tests.aws.services.cloudformation.conftest import skip_if_legacy_engine from localstack.testing.pytest import markers -from localstack.utils.strings import long_uid +from localstack.utils.strings import long_uid, short_uid @skip_if_legacy_engine() @@ -236,3 +240,30 @@ def test_fn_split_with_get_att( } capture_update_process(snapshot, template_1, template_2) + + +class TestSplitValidations: + @markers.aws.validated + @skip_if_legacy_engine + def test_validate_split_arguments_len(self, aws_client, snapshot): + template = { + "Resources": { + "Parameter": { + "Type": "AWS::SSM::Parameter", + "Properties": { + "Type": "String", + "Value": {"Fn::Split": {"Ref": "AWS::Region"}}, + }, + } + } + } + + with pytest.raises(ClientError) as ex: + aws_client.cloudformation.create_change_set( + StackName=f"st-{short_uid()}", + ChangeSetName=f"ch-{short_uid()}", + ChangeSetType="CREATE", + TemplateBody=json.dumps(template), + ) + + snapshot.match("validation", ex.value.response) diff --git a/tests/aws/services/cloudformation/test_change_set_fn_split.snapshot.json b/tests/aws/services/cloudformation/test_change_set_fn_split.snapshot.json index fa687acb00f0c..555cb616241c7 100644 --- a/tests/aws/services/cloudformation/test_change_set_fn_split.snapshot.json +++ b/tests/aws/services/cloudformation/test_change_set_fn_split.snapshot.json @@ -2451,5 +2451,21 @@ "Tags": [] } } + }, + "tests/aws/services/cloudformation/test_change_set_fn_split.py::TestSplitValidations::test_validate_split_arguments_len": { + "recorded-date": "08-10-2025, 20:08:15", + "recorded-content": { + "validation": { + "Error": { + "Code": "ValidationError", + "Message": "Template error: every Fn::Split object requires two parameters, (1) a string delimiter and (2) a string to be split or a function that returns a string to be split.", + "Type": "Sender" + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + } + } } } diff --git a/tests/aws/services/cloudformation/test_change_set_fn_split.validation.json b/tests/aws/services/cloudformation/test_change_set_fn_split.validation.json index 3ecf3eeb393eb..a3e830ca7477b 100644 --- a/tests/aws/services/cloudformation/test_change_set_fn_split.validation.json +++ b/tests/aws/services/cloudformation/test_change_set_fn_split.validation.json @@ -16,5 +16,14 @@ }, "tests/aws/services/cloudformation/test_change_set_fn_split.py::TestChangeSetFnSplit::test_fn_split_with_ref_as_string_source": { "last_validated_date": "2025-06-02T11:23:28+00:00" + }, + "tests/aws/services/cloudformation/test_change_set_fn_split.py::TestSplitValidations::test_validate_split_arguments_len": { + "last_validated_date": "2025-10-08T20:08:15+00:00", + "durations_in_seconds": { + "setup": 0.23, + "call": 0.38, + "teardown": 0.0, + "total": 0.61 + } } } diff --git a/tests/aws/services/cloudformation/test_change_set_mappings.py b/tests/aws/services/cloudformation/test_change_set_mappings.py index c48430ab96c13..28556771c83db 100644 --- a/tests/aws/services/cloudformation/test_change_set_mappings.py +++ b/tests/aws/services/cloudformation/test_change_set_mappings.py @@ -296,3 +296,179 @@ def test_mapping_key_deletion_with_resource_remap( }, } capture_update_process(snapshot, template_1, template_2) + + @markers.snapshot.skip_snapshot_verify(paths=["$..LastOperations"]) + @markers.aws.validated + def test_fn_find_in_map_with_nested_ref( + self, + snapshot, + capture_update_process, + ): + name1 = f"topic-name-1-{long_uid()}" + snapshot.add_transformer(RegexTransformer(name1, "topic-name-1")) + + # Template mimicking the CloudFront/Route53 pattern from the bug report + # This is the common CDK pattern for alias target hosted zone IDs + template_1 = { + "Mappings": { + "AWSCloudFrontPartitionHostedZoneIdMap": { + "aws": {"zoneId": "Z2FDTNDATAQYW2"}, + "aws-cn": {"zoneId": "Z3RFFRIM2A3IF5"}, + } + }, + "Resources": { + "Topic1": { + "Type": "AWS::SNS::Topic", + "Properties": { + "TopicName": name1, + # Using nested Ref - the problematic pattern + "DisplayName": { + "Fn::FindInMap": [ + "AWSCloudFrontPartitionHostedZoneIdMap", + {"Ref": "AWS::Partition"}, # Nested Ref + "zoneId", + ] + }, + }, + } + }, + } + + # Change the TopicName to create an actual update + # The key is that the FindInMap with nested Ref is processed without error + template_2 = { + "Mappings": { + "AWSCloudFrontPartitionHostedZoneIdMap": { + "aws": {"zoneId": "Z2FDTNDATAQYW2"}, + "aws-cn": {"zoneId": "Z3RFFRIM2A3IF5"}, + } + }, + "Resources": { + "Topic1": { + "Type": "AWS::SNS::Topic", + "Properties": { + "TopicName": f"{name1}-updated", # Changed to trigger update + "DisplayName": { + "Fn::FindInMap": [ + "AWSCloudFrontPartitionHostedZoneIdMap", + {"Ref": "AWS::Partition"}, # Still has nested Ref + "zoneId", + ] + }, + }, + } + }, + } + + # Before the fix, this would raise NotImplementedError when processing the changeset + # After the fix, it successfully processes the changeset and detects the change + capture_update_process(snapshot, template_1, template_2) + + @markers.snapshot.skip_snapshot_verify(paths=["$..LastOperations"]) + @markers.aws.validated + def test_fn_find_in_map_with_nested_ref_change_mapping( + self, + snapshot, + capture_update_process, + region_name, + secondary_region_name, + ): + name1 = f"topic-name-1-{long_uid()}" + snapshot.add_transformer(RegexTransformer(name1, "topic-name-1")) + + template_1 = { + "Mappings": { + "RegionMap": { + region_name: {"value": "value-1"}, + secondary_region_name: {"value": "value-2"}, + } + }, + "Resources": { + "Topic1": { + "Type": "AWS::SNS::Topic", + "Properties": { + "TopicName": name1, + "DisplayName": { + "Fn::FindInMap": [ + "RegionMap", + {"Ref": "AWS::Region"}, # Nested Ref + "value", + ] + }, + }, + } + }, + } + + # Change the mapping values + template_2 = { + "Mappings": { + "RegionMap": { + region_name: {"value": "value-3"}, # changed + secondary_region_name: {"value": "value-4"}, # changed + } + }, + "Resources": { + "Topic1": { + "Type": "AWS::SNS::Topic", + "Properties": { + "TopicName": name1, + "DisplayName": { + "Fn::FindInMap": [ + "RegionMap", + {"Ref": "AWS::Region"}, + "value", + ] + }, + }, + } + }, + } + + # Should detect the mapping change and mark resource as modified + capture_update_process(snapshot, template_1, template_2) + + @markers.snapshot.skip_snapshot_verify(paths=["$..LastOperations"]) + @markers.aws.validated + def test_fn_find_in_map_with_multiple_nested_functions( + self, + snapshot, + capture_update_process, + ): + name1 = f"topic-name-1-{long_uid()}" + snapshot.add_transformer(RegexTransformer(name1, "topic-name-1")) + + template = { + "Parameters": { + "Environment": { + "Type": "String", + } + }, + "Mappings": { + "ComplexMap": { + "prod": {"aws": "prod-aws-value"}, + "dev": {"aws": "dev-aws-value"}, + } + }, + "Resources": { + "Topic1": { + "Type": "AWS::SNS::Topic", + "Properties": { + "TopicName": name1, + "DisplayName": { + "Fn::FindInMap": [ + "ComplexMap", + {"Ref": "Environment"}, # Nested Ref to parameter + {"Ref": "AWS::Partition"}, # Another nested Ref + ] + }, + }, + } + }, + } + + # Change the parameter value to trigger an update + # The nested Refs in FindInMap should still work without error + capture_update_process( + snapshot, template, template, p1={"Environment": "prod"}, p2={"Environment": "dev"} + ) diff --git a/tests/aws/services/cloudformation/test_change_set_mappings.snapshot.json b/tests/aws/services/cloudformation/test_change_set_mappings.snapshot.json index a194134d1dd56..db8e9f5b38182 100644 --- a/tests/aws/services/cloudformation/test_change_set_mappings.snapshot.json +++ b/tests/aws/services/cloudformation/test_change_set_mappings.snapshot.json @@ -2424,5 +2424,1263 @@ "Tags": [] } } + }, + "tests/aws/services/cloudformation/test_change_set_mappings.py::TestChangeSetMappings::test_fn_find_in_map_with_nested_ref": { + "recorded-date": "02-02-2026, 11:35:11", + "recorded-content": { + "create-change-set-1": { + "Id": "arn::cloudformation::111111111111:changeSet/", + "StackId": "arn::cloudformation::111111111111:stack//", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "describe-change-set-1-prop-values": { + "Capabilities": [ + "CAPABILITY_IAM", + "CAPABILITY_NAMED_IAM", + "CAPABILITY_AUTO_EXPAND" + ], + "ChangeSetId": "arn::cloudformation::111111111111:changeSet/", + "ChangeSetName": "", + "Changes": [ + { + "ResourceChange": { + "Action": "Add", + "AfterContext": { + "Properties": { + "DisplayName": "Z2FDTNDATAQYW2", + "TopicName": "topic-name-1" + } + }, + "Details": [], + "LogicalResourceId": "Topic1", + "ResourceType": "AWS::SNS::Topic", + "Scope": [] + }, + "Type": "Resource" + } + ], + "CreationTime": "datetime", + "ExecutionStatus": "AVAILABLE", + "IncludeNestedStacks": false, + "NotificationARNs": [], + "RollbackConfiguration": {}, + "StackId": "arn::cloudformation::111111111111:stack//", + "StackName": "", + "Status": "CREATE_COMPLETE", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "describe-change-set-1": { + "Capabilities": [ + "CAPABILITY_IAM", + "CAPABILITY_NAMED_IAM", + "CAPABILITY_AUTO_EXPAND" + ], + "ChangeSetId": "arn::cloudformation::111111111111:changeSet/", + "ChangeSetName": "", + "Changes": [ + { + "ResourceChange": { + "Action": "Add", + "Details": [], + "LogicalResourceId": "Topic1", + "ResourceType": "AWS::SNS::Topic", + "Scope": [] + }, + "Type": "Resource" + } + ], + "CreationTime": "datetime", + "ExecutionStatus": "AVAILABLE", + "IncludeNestedStacks": false, + "NotificationARNs": [], + "RollbackConfiguration": {}, + "StackId": "arn::cloudformation::111111111111:stack//", + "StackName": "", + "Status": "CREATE_COMPLETE", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "execute-change-set-1": { + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "post-create-1-describe": { + "Capabilities": [ + "CAPABILITY_IAM", + "CAPABILITY_NAMED_IAM", + "CAPABILITY_AUTO_EXPAND" + ], + "ChangeSetId": "arn::cloudformation::111111111111:changeSet/", + "CreationTime": "datetime", + "DisableRollback": false, + "DriftInformation": { + "StackDriftStatus": "NOT_CHECKED" + }, + "EnableTerminationProtection": false, + "LastOperations": [ + { + "OperationId": "", + "OperationType": "CREATE_STACK" + } + ], + "LastUpdatedTime": "datetime", + "NotificationARNs": [], + "RollbackConfiguration": {}, + "StackId": "arn::cloudformation::111111111111:stack//", + "StackName": "", + "StackStatus": "CREATE_COMPLETE", + "Tags": [] + }, + "create-change-set-2": { + "Id": "arn::cloudformation::111111111111:changeSet/", + "StackId": "arn::cloudformation::111111111111:stack//", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "describe-change-set-2-prop-values": { + "Capabilities": [ + "CAPABILITY_IAM", + "CAPABILITY_NAMED_IAM", + "CAPABILITY_AUTO_EXPAND" + ], + "ChangeSetId": "arn::cloudformation::111111111111:changeSet/", + "ChangeSetName": "", + "Changes": [ + { + "ResourceChange": { + "Action": "Modify", + "AfterContext": { + "Properties": { + "DisplayName": "Z2FDTNDATAQYW2", + "TopicName": "topic-name-1-updated" + } + }, + "BeforeContext": { + "Properties": { + "DisplayName": "Z2FDTNDATAQYW2", + "TopicName": "topic-name-1" + } + }, + "Details": [ + { + "ChangeSource": "DirectModification", + "Evaluation": "Static", + "Target": { + "AfterValue": "topic-name-1-updated", + "Attribute": "Properties", + "AttributeChangeType": "Modify", + "BeforeValue": "topic-name-1", + "Name": "TopicName", + "Path": "/Properties/TopicName", + "RequiresRecreation": "Always" + } + } + ], + "LogicalResourceId": "Topic1", + "PhysicalResourceId": "arn::sns::111111111111:topic-name-1", + "PolicyAction": "ReplaceAndDelete", + "Replacement": "True", + "ResourceType": "AWS::SNS::Topic", + "Scope": [ + "Properties" + ] + }, + "Type": "Resource" + } + ], + "CreationTime": "datetime", + "ExecutionStatus": "AVAILABLE", + "IncludeNestedStacks": false, + "NotificationARNs": [], + "RollbackConfiguration": {}, + "StackId": "arn::cloudformation::111111111111:stack//", + "StackName": "", + "Status": "CREATE_COMPLETE", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "describe-change-set-2": { + "Capabilities": [ + "CAPABILITY_IAM", + "CAPABILITY_NAMED_IAM", + "CAPABILITY_AUTO_EXPAND" + ], + "ChangeSetId": "arn::cloudformation::111111111111:changeSet/", + "ChangeSetName": "", + "Changes": [ + { + "ResourceChange": { + "Action": "Modify", + "Details": [ + { + "ChangeSource": "DirectModification", + "Evaluation": "Static", + "Target": { + "Attribute": "Properties", + "Name": "TopicName", + "RequiresRecreation": "Always" + } + } + ], + "LogicalResourceId": "Topic1", + "PhysicalResourceId": "arn::sns::111111111111:topic-name-1", + "PolicyAction": "ReplaceAndDelete", + "Replacement": "True", + "ResourceType": "AWS::SNS::Topic", + "Scope": [ + "Properties" + ] + }, + "Type": "Resource" + } + ], + "CreationTime": "datetime", + "ExecutionStatus": "AVAILABLE", + "IncludeNestedStacks": false, + "NotificationARNs": [], + "RollbackConfiguration": {}, + "StackId": "arn::cloudformation::111111111111:stack//", + "StackName": "", + "Status": "CREATE_COMPLETE", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "execute-change-set-2": { + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "post-create-2-describe": { + "Capabilities": [ + "CAPABILITY_IAM", + "CAPABILITY_NAMED_IAM", + "CAPABILITY_AUTO_EXPAND" + ], + "ChangeSetId": "arn::cloudformation::111111111111:changeSet/", + "CreationTime": "datetime", + "DisableRollback": false, + "DriftInformation": { + "StackDriftStatus": "NOT_CHECKED" + }, + "EnableTerminationProtection": false, + "LastOperations": [ + { + "OperationId": "", + "OperationType": "UPDATE_STACK" + } + ], + "LastUpdatedTime": "datetime", + "NotificationARNs": [], + "RollbackConfiguration": {}, + "StackId": "arn::cloudformation::111111111111:stack//", + "StackName": "", + "StackStatus": "UPDATE_COMPLETE", + "Tags": [] + }, + "delete-describe": { + "Capabilities": [ + "CAPABILITY_IAM", + "CAPABILITY_NAMED_IAM", + "CAPABILITY_AUTO_EXPAND" + ], + "CreationTime": "datetime", + "DeletionTime": "datetime", + "DisableRollback": false, + "DriftInformation": { + "StackDriftStatus": "NOT_CHECKED" + }, + "LastOperations": [ + { + "OperationId": "", + "OperationType": "DELETE_STACK" + } + ], + "LastUpdatedTime": "datetime", + "NotificationARNs": [], + "RollbackConfiguration": {}, + "StackId": "arn::cloudformation::111111111111:stack//", + "StackName": "", + "StackStatus": "DELETE_COMPLETE", + "Tags": [] + }, + "per-resource-events": { + "Stack": [ + { + "LogicalResourceId": "", + "PhysicalResourceId": "arn::cloudformation::111111111111:stack//", + "ResourceStatus": "REVIEW_IN_PROGRESS", + "ResourceType": "AWS::CloudFormation::Stack", + "Timestamp": "timestamp" + }, + { + "LogicalResourceId": "", + "PhysicalResourceId": "arn::cloudformation::111111111111:stack//", + "ResourceStatus": "CREATE_IN_PROGRESS", + "ResourceType": "AWS::CloudFormation::Stack", + "Timestamp": "timestamp" + }, + { + "LogicalResourceId": "", + "PhysicalResourceId": "arn::cloudformation::111111111111:stack//", + "ResourceStatus": "CREATE_COMPLETE", + "ResourceType": "AWS::CloudFormation::Stack", + "Timestamp": "timestamp" + }, + { + "LogicalResourceId": "", + "PhysicalResourceId": "arn::cloudformation::111111111111:stack//", + "ResourceStatus": "UPDATE_IN_PROGRESS", + "ResourceType": "AWS::CloudFormation::Stack", + "Timestamp": "timestamp" + }, + { + "LogicalResourceId": "", + "PhysicalResourceId": "arn::cloudformation::111111111111:stack//", + "ResourceStatus": "UPDATE_COMPLETE", + "ResourceType": "AWS::CloudFormation::Stack", + "Timestamp": "timestamp" + }, + { + "LogicalResourceId": "", + "PhysicalResourceId": "arn::cloudformation::111111111111:stack//", + "ResourceStatus": "DELETE_IN_PROGRESS", + "ResourceType": "AWS::CloudFormation::Stack", + "Timestamp": "timestamp" + }, + { + "LogicalResourceId": "", + "PhysicalResourceId": "arn::cloudformation::111111111111:stack//", + "ResourceStatus": "DELETE_COMPLETE", + "ResourceType": "AWS::CloudFormation::Stack", + "Timestamp": "timestamp" + } + ], + "Topic1": [ + { + "LogicalResourceId": "Topic1", + "PhysicalResourceId": "arn::sns::111111111111:topic-name-1", + "ResourceStatus": "CREATE_IN_PROGRESS", + "ResourceType": "AWS::SNS::Topic", + "Timestamp": "timestamp" + }, + { + "LogicalResourceId": "Topic1", + "PhysicalResourceId": "arn::sns::111111111111:topic-name-1", + "ResourceStatus": "CREATE_COMPLETE", + "ResourceType": "AWS::SNS::Topic", + "Timestamp": "timestamp" + }, + { + "LogicalResourceId": "Topic1", + "PhysicalResourceId": "arn::sns::111111111111:topic-name-1-updated", + "ResourceStatus": "UPDATE_IN_PROGRESS", + "ResourceType": "AWS::SNS::Topic", + "Timestamp": "timestamp" + }, + { + "LogicalResourceId": "Topic1", + "PhysicalResourceId": "arn::sns::111111111111:topic-name-1-updated", + "ResourceStatus": "UPDATE_COMPLETE", + "ResourceType": "AWS::SNS::Topic", + "Timestamp": "timestamp" + }, + { + "LogicalResourceId": "Topic1", + "PhysicalResourceId": "arn::sns::111111111111:topic-name-1", + "ResourceStatus": "DELETE_IN_PROGRESS", + "ResourceType": "AWS::SNS::Topic", + "Timestamp": "timestamp" + }, + { + "LogicalResourceId": "Topic1", + "PhysicalResourceId": "arn::sns::111111111111:topic-name-1", + "ResourceStatus": "DELETE_COMPLETE", + "ResourceType": "AWS::SNS::Topic", + "Timestamp": "timestamp" + }, + { + "LogicalResourceId": "Topic1", + "PhysicalResourceId": "arn::sns::111111111111:topic-name-1-updated", + "ResourceStatus": "DELETE_IN_PROGRESS", + "ResourceType": "AWS::SNS::Topic", + "Timestamp": "timestamp" + }, + { + "LogicalResourceId": "Topic1", + "PhysicalResourceId": "arn::sns::111111111111:topic-name-1-updated", + "ResourceStatus": "DELETE_COMPLETE", + "ResourceType": "AWS::SNS::Topic", + "Timestamp": "timestamp" + } + ] + } + } + }, + "tests/aws/services/cloudformation/test_change_set_mappings.py::TestChangeSetMappings::test_fn_find_in_map_with_nested_ref_change_mapping": { + "recorded-date": "04-02-2026, 11:54:54", + "recorded-content": { + "create-change-set-1": { + "Id": "arn::cloudformation::111111111111:changeSet/", + "StackId": "arn::cloudformation::111111111111:stack//", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "describe-change-set-1-prop-values": { + "Capabilities": [ + "CAPABILITY_IAM", + "CAPABILITY_NAMED_IAM", + "CAPABILITY_AUTO_EXPAND" + ], + "ChangeSetId": "arn::cloudformation::111111111111:changeSet/", + "ChangeSetName": "", + "Changes": [ + { + "ResourceChange": { + "Action": "Add", + "AfterContext": { + "Properties": { + "DisplayName": "value-1", + "TopicName": "topic-name-1" + } + }, + "Details": [], + "LogicalResourceId": "Topic1", + "ResourceType": "AWS::SNS::Topic", + "Scope": [] + }, + "Type": "Resource" + } + ], + "CreationTime": "datetime", + "ExecutionStatus": "AVAILABLE", + "IncludeNestedStacks": false, + "NotificationARNs": [], + "RollbackConfiguration": {}, + "StackId": "arn::cloudformation::111111111111:stack//", + "StackName": "", + "Status": "CREATE_COMPLETE", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "describe-change-set-1": { + "Capabilities": [ + "CAPABILITY_IAM", + "CAPABILITY_NAMED_IAM", + "CAPABILITY_AUTO_EXPAND" + ], + "ChangeSetId": "arn::cloudformation::111111111111:changeSet/", + "ChangeSetName": "", + "Changes": [ + { + "ResourceChange": { + "Action": "Add", + "Details": [], + "LogicalResourceId": "Topic1", + "ResourceType": "AWS::SNS::Topic", + "Scope": [] + }, + "Type": "Resource" + } + ], + "CreationTime": "datetime", + "ExecutionStatus": "AVAILABLE", + "IncludeNestedStacks": false, + "NotificationARNs": [], + "RollbackConfiguration": {}, + "StackId": "arn::cloudformation::111111111111:stack//", + "StackName": "", + "Status": "CREATE_COMPLETE", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "execute-change-set-1": { + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "post-create-1-describe": { + "Capabilities": [ + "CAPABILITY_IAM", + "CAPABILITY_NAMED_IAM", + "CAPABILITY_AUTO_EXPAND" + ], + "ChangeSetId": "arn::cloudformation::111111111111:changeSet/", + "CreationTime": "datetime", + "DisableRollback": false, + "DriftInformation": { + "StackDriftStatus": "NOT_CHECKED" + }, + "EnableTerminationProtection": false, + "LastOperations": [ + { + "OperationId": "", + "OperationType": "CREATE_STACK" + } + ], + "LastUpdatedTime": "datetime", + "NotificationARNs": [], + "RollbackConfiguration": {}, + "StackId": "arn::cloudformation::111111111111:stack//", + "StackName": "", + "StackStatus": "CREATE_COMPLETE", + "Tags": [] + }, + "create-change-set-2": { + "Id": "arn::cloudformation::111111111111:changeSet/", + "StackId": "arn::cloudformation::111111111111:stack//", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "describe-change-set-2-prop-values": { + "Capabilities": [ + "CAPABILITY_IAM", + "CAPABILITY_NAMED_IAM", + "CAPABILITY_AUTO_EXPAND" + ], + "ChangeSetId": "arn::cloudformation::111111111111:changeSet/", + "ChangeSetName": "", + "Changes": [ + { + "ResourceChange": { + "Action": "Modify", + "AfterContext": { + "Properties": { + "DisplayName": "value-3", + "TopicName": "topic-name-1" + } + }, + "BeforeContext": { + "Properties": { + "DisplayName": "value-1", + "TopicName": "topic-name-1" + } + }, + "Details": [ + { + "ChangeSource": "DirectModification", + "Evaluation": "Static", + "Target": { + "AfterValue": "value-3", + "Attribute": "Properties", + "AttributeChangeType": "Modify", + "BeforeValue": "value-1", + "Name": "DisplayName", + "Path": "/Properties/DisplayName", + "RequiresRecreation": "Never" + } + } + ], + "LogicalResourceId": "Topic1", + "PhysicalResourceId": "arn::sns::111111111111:topic-name-1", + "Replacement": "False", + "ResourceType": "AWS::SNS::Topic", + "Scope": [ + "Properties" + ] + }, + "Type": "Resource" + } + ], + "CreationTime": "datetime", + "ExecutionStatus": "AVAILABLE", + "IncludeNestedStacks": false, + "NotificationARNs": [], + "RollbackConfiguration": {}, + "StackId": "arn::cloudformation::111111111111:stack//", + "StackName": "", + "Status": "CREATE_COMPLETE", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "describe-change-set-2": { + "Capabilities": [ + "CAPABILITY_IAM", + "CAPABILITY_NAMED_IAM", + "CAPABILITY_AUTO_EXPAND" + ], + "ChangeSetId": "arn::cloudformation::111111111111:changeSet/", + "ChangeSetName": "", + "Changes": [ + { + "ResourceChange": { + "Action": "Modify", + "Details": [ + { + "ChangeSource": "DirectModification", + "Evaluation": "Static", + "Target": { + "Attribute": "Properties", + "Name": "DisplayName", + "RequiresRecreation": "Never" + } + } + ], + "LogicalResourceId": "Topic1", + "PhysicalResourceId": "arn::sns::111111111111:topic-name-1", + "Replacement": "False", + "ResourceType": "AWS::SNS::Topic", + "Scope": [ + "Properties" + ] + }, + "Type": "Resource" + } + ], + "CreationTime": "datetime", + "ExecutionStatus": "AVAILABLE", + "IncludeNestedStacks": false, + "NotificationARNs": [], + "RollbackConfiguration": {}, + "StackId": "arn::cloudformation::111111111111:stack//", + "StackName": "", + "Status": "CREATE_COMPLETE", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "execute-change-set-2": { + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "post-create-2-describe": { + "Capabilities": [ + "CAPABILITY_IAM", + "CAPABILITY_NAMED_IAM", + "CAPABILITY_AUTO_EXPAND" + ], + "ChangeSetId": "arn::cloudformation::111111111111:changeSet/", + "CreationTime": "datetime", + "DisableRollback": false, + "DriftInformation": { + "StackDriftStatus": "NOT_CHECKED" + }, + "EnableTerminationProtection": false, + "LastOperations": [ + { + "OperationId": "", + "OperationType": "UPDATE_STACK" + } + ], + "LastUpdatedTime": "datetime", + "NotificationARNs": [], + "RollbackConfiguration": {}, + "StackId": "arn::cloudformation::111111111111:stack//", + "StackName": "", + "StackStatus": "UPDATE_COMPLETE", + "Tags": [] + }, + "delete-describe": { + "Capabilities": [ + "CAPABILITY_IAM", + "CAPABILITY_NAMED_IAM", + "CAPABILITY_AUTO_EXPAND" + ], + "CreationTime": "datetime", + "DeletionTime": "datetime", + "DisableRollback": false, + "DriftInformation": { + "StackDriftStatus": "NOT_CHECKED" + }, + "LastOperations": [ + { + "OperationId": "", + "OperationType": "DELETE_STACK" + } + ], + "LastUpdatedTime": "datetime", + "NotificationARNs": [], + "RollbackConfiguration": {}, + "StackId": "arn::cloudformation::111111111111:stack//", + "StackName": "", + "StackStatus": "DELETE_COMPLETE", + "Tags": [] + }, + "per-resource-events": { + "Stack": [ + { + "LogicalResourceId": "", + "PhysicalResourceId": "arn::cloudformation::111111111111:stack//", + "ResourceStatus": "REVIEW_IN_PROGRESS", + "ResourceType": "AWS::CloudFormation::Stack", + "Timestamp": "timestamp" + }, + { + "LogicalResourceId": "", + "PhysicalResourceId": "arn::cloudformation::111111111111:stack//", + "ResourceStatus": "CREATE_IN_PROGRESS", + "ResourceType": "AWS::CloudFormation::Stack", + "Timestamp": "timestamp" + }, + { + "LogicalResourceId": "", + "PhysicalResourceId": "arn::cloudformation::111111111111:stack//", + "ResourceStatus": "CREATE_COMPLETE", + "ResourceType": "AWS::CloudFormation::Stack", + "Timestamp": "timestamp" + }, + { + "LogicalResourceId": "", + "PhysicalResourceId": "arn::cloudformation::111111111111:stack//", + "ResourceStatus": "UPDATE_IN_PROGRESS", + "ResourceType": "AWS::CloudFormation::Stack", + "Timestamp": "timestamp" + }, + { + "LogicalResourceId": "", + "PhysicalResourceId": "arn::cloudformation::111111111111:stack//", + "ResourceStatus": "UPDATE_COMPLETE", + "ResourceType": "AWS::CloudFormation::Stack", + "Timestamp": "timestamp" + }, + { + "LogicalResourceId": "", + "PhysicalResourceId": "arn::cloudformation::111111111111:stack//", + "ResourceStatus": "DELETE_IN_PROGRESS", + "ResourceType": "AWS::CloudFormation::Stack", + "Timestamp": "timestamp" + }, + { + "LogicalResourceId": "", + "PhysicalResourceId": "arn::cloudformation::111111111111:stack//", + "ResourceStatus": "DELETE_COMPLETE", + "ResourceType": "AWS::CloudFormation::Stack", + "Timestamp": "timestamp" + } + ], + "Topic1": [ + { + "LogicalResourceId": "Topic1", + "PhysicalResourceId": "arn::sns::111111111111:topic-name-1", + "ResourceStatus": "CREATE_IN_PROGRESS", + "ResourceType": "AWS::SNS::Topic", + "Timestamp": "timestamp" + }, + { + "LogicalResourceId": "Topic1", + "PhysicalResourceId": "arn::sns::111111111111:topic-name-1", + "ResourceStatus": "CREATE_COMPLETE", + "ResourceType": "AWS::SNS::Topic", + "Timestamp": "timestamp" + }, + { + "LogicalResourceId": "Topic1", + "PhysicalResourceId": "arn::sns::111111111111:topic-name-1", + "ResourceStatus": "UPDATE_IN_PROGRESS", + "ResourceType": "AWS::SNS::Topic", + "Timestamp": "timestamp" + }, + { + "LogicalResourceId": "Topic1", + "PhysicalResourceId": "arn::sns::111111111111:topic-name-1", + "ResourceStatus": "UPDATE_COMPLETE", + "ResourceType": "AWS::SNS::Topic", + "Timestamp": "timestamp" + }, + { + "LogicalResourceId": "Topic1", + "PhysicalResourceId": "arn::sns::111111111111:topic-name-1", + "ResourceStatus": "DELETE_IN_PROGRESS", + "ResourceType": "AWS::SNS::Topic", + "Timestamp": "timestamp" + }, + { + "LogicalResourceId": "Topic1", + "PhysicalResourceId": "arn::sns::111111111111:topic-name-1", + "ResourceStatus": "DELETE_COMPLETE", + "ResourceType": "AWS::SNS::Topic", + "Timestamp": "timestamp" + } + ] + } + } + }, + "tests/aws/services/cloudformation/test_change_set_mappings.py::TestChangeSetMappings::test_fn_find_in_map_with_multiple_nested_functions": { + "recorded-date": "03-02-2026, 09:11:57", + "recorded-content": { + "create-change-set-1": { + "Id": "arn::cloudformation::111111111111:changeSet/", + "StackId": "arn::cloudformation::111111111111:stack//", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "describe-change-set-1-prop-values": { + "Capabilities": [ + "CAPABILITY_IAM", + "CAPABILITY_NAMED_IAM", + "CAPABILITY_AUTO_EXPAND" + ], + "ChangeSetId": "arn::cloudformation::111111111111:changeSet/", + "ChangeSetName": "", + "Changes": [ + { + "ResourceChange": { + "Action": "Add", + "AfterContext": { + "Properties": { + "DisplayName": "prod-aws-value", + "TopicName": "topic-name-1" + } + }, + "Details": [], + "LogicalResourceId": "Topic1", + "ResourceType": "AWS::SNS::Topic", + "Scope": [] + }, + "Type": "Resource" + } + ], + "CreationTime": "datetime", + "ExecutionStatus": "AVAILABLE", + "IncludeNestedStacks": false, + "NotificationARNs": [], + "Parameters": [ + { + "ParameterKey": "Environment", + "ParameterValue": "prod" + } + ], + "RollbackConfiguration": {}, + "StackId": "arn::cloudformation::111111111111:stack//", + "StackName": "", + "Status": "CREATE_COMPLETE", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "describe-change-set-1": { + "Capabilities": [ + "CAPABILITY_IAM", + "CAPABILITY_NAMED_IAM", + "CAPABILITY_AUTO_EXPAND" + ], + "ChangeSetId": "arn::cloudformation::111111111111:changeSet/", + "ChangeSetName": "", + "Changes": [ + { + "ResourceChange": { + "Action": "Add", + "Details": [], + "LogicalResourceId": "Topic1", + "ResourceType": "AWS::SNS::Topic", + "Scope": [] + }, + "Type": "Resource" + } + ], + "CreationTime": "datetime", + "ExecutionStatus": "AVAILABLE", + "IncludeNestedStacks": false, + "NotificationARNs": [], + "Parameters": [ + { + "ParameterKey": "Environment", + "ParameterValue": "prod" + } + ], + "RollbackConfiguration": {}, + "StackId": "arn::cloudformation::111111111111:stack//", + "StackName": "", + "Status": "CREATE_COMPLETE", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "execute-change-set-1": { + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "post-create-1-describe": { + "Capabilities": [ + "CAPABILITY_IAM", + "CAPABILITY_NAMED_IAM", + "CAPABILITY_AUTO_EXPAND" + ], + "ChangeSetId": "arn::cloudformation::111111111111:changeSet/", + "CreationTime": "datetime", + "DisableRollback": false, + "DriftInformation": { + "StackDriftStatus": "NOT_CHECKED" + }, + "EnableTerminationProtection": false, + "LastOperations": [ + { + "OperationId": "", + "OperationType": "CREATE_STACK" + } + ], + "LastUpdatedTime": "datetime", + "NotificationARNs": [], + "Parameters": [ + { + "ParameterKey": "Environment", + "ParameterValue": "prod" + } + ], + "RollbackConfiguration": {}, + "StackId": "arn::cloudformation::111111111111:stack//", + "StackName": "", + "StackStatus": "CREATE_COMPLETE", + "Tags": [] + }, + "create-change-set-2": { + "Id": "arn::cloudformation::111111111111:changeSet/", + "StackId": "arn::cloudformation::111111111111:stack//", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "describe-change-set-2-prop-values": { + "Capabilities": [ + "CAPABILITY_IAM", + "CAPABILITY_NAMED_IAM", + "CAPABILITY_AUTO_EXPAND" + ], + "ChangeSetId": "arn::cloudformation::111111111111:changeSet/", + "ChangeSetName": "", + "Changes": [ + { + "ResourceChange": { + "Action": "Modify", + "AfterContext": { + "Properties": { + "DisplayName": "dev-aws-value", + "TopicName": "topic-name-1" + } + }, + "BeforeContext": { + "Properties": { + "DisplayName": "prod-aws-value", + "TopicName": "topic-name-1" + } + }, + "Details": [ + { + "CausingEntity": "Environment", + "ChangeSource": "ParameterReference", + "Evaluation": "Static", + "Target": { + "AfterValue": "dev-aws-value", + "Attribute": "Properties", + "AttributeChangeType": "Modify", + "BeforeValue": "prod-aws-value", + "Name": "DisplayName", + "Path": "/Properties/DisplayName", + "RequiresRecreation": "Never" + } + }, + { + "ChangeSource": "DirectModification", + "Evaluation": "Dynamic", + "Target": { + "AfterValue": "dev-aws-value", + "Attribute": "Properties", + "AttributeChangeType": "Modify", + "BeforeValue": "prod-aws-value", + "Name": "DisplayName", + "Path": "/Properties/DisplayName", + "RequiresRecreation": "Never" + } + } + ], + "LogicalResourceId": "Topic1", + "PhysicalResourceId": "arn::sns::111111111111:topic-name-1", + "Replacement": "False", + "ResourceType": "AWS::SNS::Topic", + "Scope": [ + "Properties" + ] + }, + "Type": "Resource" + } + ], + "CreationTime": "datetime", + "ExecutionStatus": "AVAILABLE", + "IncludeNestedStacks": false, + "NotificationARNs": [], + "Parameters": [ + { + "ParameterKey": "Environment", + "ParameterValue": "dev" + } + ], + "RollbackConfiguration": {}, + "StackId": "arn::cloudformation::111111111111:stack//", + "StackName": "", + "Status": "CREATE_COMPLETE", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "describe-change-set-2": { + "Capabilities": [ + "CAPABILITY_IAM", + "CAPABILITY_NAMED_IAM", + "CAPABILITY_AUTO_EXPAND" + ], + "ChangeSetId": "arn::cloudformation::111111111111:changeSet/", + "ChangeSetName": "", + "Changes": [ + { + "ResourceChange": { + "Action": "Modify", + "Details": [ + { + "ChangeSource": "DirectModification", + "Evaluation": "Dynamic", + "Target": { + "Attribute": "Properties", + "Name": "DisplayName", + "RequiresRecreation": "Never" + } + }, + { + "CausingEntity": "Environment", + "ChangeSource": "ParameterReference", + "Evaluation": "Static", + "Target": { + "Attribute": "Properties", + "Name": "DisplayName", + "RequiresRecreation": "Never" + } + } + ], + "LogicalResourceId": "Topic1", + "PhysicalResourceId": "arn::sns::111111111111:topic-name-1", + "Replacement": "False", + "ResourceType": "AWS::SNS::Topic", + "Scope": [ + "Properties" + ] + }, + "Type": "Resource" + } + ], + "CreationTime": "datetime", + "ExecutionStatus": "AVAILABLE", + "IncludeNestedStacks": false, + "NotificationARNs": [], + "Parameters": [ + { + "ParameterKey": "Environment", + "ParameterValue": "dev" + } + ], + "RollbackConfiguration": {}, + "StackId": "arn::cloudformation::111111111111:stack//", + "StackName": "", + "Status": "CREATE_COMPLETE", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "execute-change-set-2": { + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "post-create-2-describe": { + "Capabilities": [ + "CAPABILITY_IAM", + "CAPABILITY_NAMED_IAM", + "CAPABILITY_AUTO_EXPAND" + ], + "ChangeSetId": "arn::cloudformation::111111111111:changeSet/", + "CreationTime": "datetime", + "DisableRollback": false, + "DriftInformation": { + "StackDriftStatus": "NOT_CHECKED" + }, + "EnableTerminationProtection": false, + "LastOperations": [ + { + "OperationId": "", + "OperationType": "UPDATE_STACK" + } + ], + "LastUpdatedTime": "datetime", + "NotificationARNs": [], + "Parameters": [ + { + "ParameterKey": "Environment", + "ParameterValue": "dev" + } + ], + "RollbackConfiguration": {}, + "StackId": "arn::cloudformation::111111111111:stack//", + "StackName": "", + "StackStatus": "UPDATE_COMPLETE", + "Tags": [] + }, + "delete-describe": { + "Capabilities": [ + "CAPABILITY_IAM", + "CAPABILITY_NAMED_IAM", + "CAPABILITY_AUTO_EXPAND" + ], + "CreationTime": "datetime", + "DeletionTime": "datetime", + "DisableRollback": false, + "DriftInformation": { + "StackDriftStatus": "NOT_CHECKED" + }, + "LastOperations": [ + { + "OperationId": "", + "OperationType": "DELETE_STACK" + } + ], + "LastUpdatedTime": "datetime", + "NotificationARNs": [], + "Parameters": [ + { + "ParameterKey": "Environment", + "ParameterValue": "dev" + } + ], + "RollbackConfiguration": {}, + "StackId": "arn::cloudformation::111111111111:stack//", + "StackName": "", + "StackStatus": "DELETE_COMPLETE", + "Tags": [] + }, + "per-resource-events": { + "Stack": [ + { + "LogicalResourceId": "", + "PhysicalResourceId": "arn::cloudformation::111111111111:stack//", + "ResourceStatus": "REVIEW_IN_PROGRESS", + "ResourceType": "AWS::CloudFormation::Stack", + "Timestamp": "timestamp" + }, + { + "LogicalResourceId": "", + "PhysicalResourceId": "arn::cloudformation::111111111111:stack//", + "ResourceStatus": "CREATE_IN_PROGRESS", + "ResourceType": "AWS::CloudFormation::Stack", + "Timestamp": "timestamp" + }, + { + "LogicalResourceId": "", + "PhysicalResourceId": "arn::cloudformation::111111111111:stack//", + "ResourceStatus": "CREATE_COMPLETE", + "ResourceType": "AWS::CloudFormation::Stack", + "Timestamp": "timestamp" + }, + { + "LogicalResourceId": "", + "PhysicalResourceId": "arn::cloudformation::111111111111:stack//", + "ResourceStatus": "UPDATE_IN_PROGRESS", + "ResourceType": "AWS::CloudFormation::Stack", + "Timestamp": "timestamp" + }, + { + "LogicalResourceId": "", + "PhysicalResourceId": "arn::cloudformation::111111111111:stack//", + "ResourceStatus": "UPDATE_COMPLETE", + "ResourceType": "AWS::CloudFormation::Stack", + "Timestamp": "timestamp" + }, + { + "LogicalResourceId": "", + "PhysicalResourceId": "arn::cloudformation::111111111111:stack//", + "ResourceStatus": "DELETE_IN_PROGRESS", + "ResourceType": "AWS::CloudFormation::Stack", + "Timestamp": "timestamp" + }, + { + "LogicalResourceId": "", + "PhysicalResourceId": "arn::cloudformation::111111111111:stack//", + "ResourceStatus": "DELETE_COMPLETE", + "ResourceType": "AWS::CloudFormation::Stack", + "Timestamp": "timestamp" + } + ], + "Topic1": [ + { + "LogicalResourceId": "Topic1", + "PhysicalResourceId": "arn::sns::111111111111:topic-name-1", + "ResourceStatus": "CREATE_IN_PROGRESS", + "ResourceType": "AWS::SNS::Topic", + "Timestamp": "timestamp" + }, + { + "LogicalResourceId": "Topic1", + "PhysicalResourceId": "arn::sns::111111111111:topic-name-1", + "ResourceStatus": "CREATE_COMPLETE", + "ResourceType": "AWS::SNS::Topic", + "Timestamp": "timestamp" + }, + { + "LogicalResourceId": "Topic1", + "PhysicalResourceId": "arn::sns::111111111111:topic-name-1", + "ResourceStatus": "UPDATE_IN_PROGRESS", + "ResourceType": "AWS::SNS::Topic", + "Timestamp": "timestamp" + }, + { + "LogicalResourceId": "Topic1", + "PhysicalResourceId": "arn::sns::111111111111:topic-name-1", + "ResourceStatus": "UPDATE_COMPLETE", + "ResourceType": "AWS::SNS::Topic", + "Timestamp": "timestamp" + }, + { + "LogicalResourceId": "Topic1", + "PhysicalResourceId": "arn::sns::111111111111:topic-name-1", + "ResourceStatus": "DELETE_IN_PROGRESS", + "ResourceType": "AWS::SNS::Topic", + "Timestamp": "timestamp" + }, + { + "LogicalResourceId": "Topic1", + "PhysicalResourceId": "arn::sns::111111111111:topic-name-1", + "ResourceStatus": "DELETE_COMPLETE", + "ResourceType": "AWS::SNS::Topic", + "Timestamp": "timestamp" + } + ] + } + } } } diff --git a/tests/aws/services/cloudformation/test_change_set_mappings.validation.json b/tests/aws/services/cloudformation/test_change_set_mappings.validation.json index db9c5158538e7..6a8f667c41974 100644 --- a/tests/aws/services/cloudformation/test_change_set_mappings.validation.json +++ b/tests/aws/services/cloudformation/test_change_set_mappings.validation.json @@ -1,4 +1,31 @@ { + "tests/aws/services/cloudformation/test_change_set_mappings.py::TestChangeSetMappings::test_fn_find_in_map_with_multiple_nested_functions": { + "last_validated_date": "2026-02-03T09:11:57+00:00", + "durations_in_seconds": { + "setup": 0.65, + "call": 92.72, + "teardown": 0.33, + "total": 93.7 + } + }, + "tests/aws/services/cloudformation/test_change_set_mappings.py::TestChangeSetMappings::test_fn_find_in_map_with_nested_ref": { + "last_validated_date": "2026-02-02T11:35:11+00:00", + "durations_in_seconds": { + "setup": 0.59, + "call": 119.51, + "teardown": 0.31, + "total": 120.41 + } + }, + "tests/aws/services/cloudformation/test_change_set_mappings.py::TestChangeSetMappings::test_fn_find_in_map_with_nested_ref_change_mapping": { + "last_validated_date": "2026-02-04T11:54:54+00:00", + "durations_in_seconds": { + "setup": 0.61, + "call": 91.81, + "teardown": 0.32, + "total": 92.74 + } + }, "tests/aws/services/cloudformation/test_change_set_mappings.py::TestChangeSetMappings::test_mapping_addition_with_resource": { "last_validated_date": "2025-04-15T13:05:52+00:00" }, diff --git a/tests/aws/services/cloudformation/test_change_set_parameters.py b/tests/aws/services/cloudformation/test_change_set_parameters.py index ac73648b20e16..e2c0c43fe14f3 100644 --- a/tests/aws/services/cloudformation/test_change_set_parameters.py +++ b/tests/aws/services/cloudformation/test_change_set_parameters.py @@ -1,8 +1,13 @@ +import copy +import json + +import pytest +from botocore.exceptions import ClientError from localstack_snapshot.snapshots.transformer import RegexTransformer from tests.aws.services.cloudformation.conftest import skip_if_legacy_engine from localstack.testing.pytest import markers -from localstack.utils.strings import long_uid +from localstack.utils.strings import long_uid, short_uid @skip_if_legacy_engine() @@ -123,3 +128,64 @@ def test_update_parameter_default_value_with_dynamic_overrides( capture_update_process( snapshot, template_1, template_2, p1={"TopicName": name1}, p2={"TopicName": name2} ) + + @markers.aws.validated + def test_parameter_type_change(self, snapshot, capture_update_process): + snapshot.add_transformer(snapshot.transform.key_value("PhysicalResourceId")) + + template1 = { + "Parameters": { + "Value": { + "Type": "Number", + }, + }, + "Resources": { + "MyParameter": { + "Type": "AWS::SSM::Parameter", + "Properties": { + "Type": "String", + "Value": {"Ref": "Value"}, + }, + }, + }, + } + template2 = copy.deepcopy(template1) + template2["Parameters"]["Value"]["Type"] = "String" + + capture_update_process( + snapshot, template1, template2, p1={"Value": "123"}, p2={"Value": "456"} + ) + + @markers.aws.validated + def test_invalid_parameter_type(self, snapshot, aws_client): + template = { + "Parameters": { + "Value": { + "Type": "Number", + }, + }, + "Resources": { + "MyParameter": { + "Type": "AWS::SSM::Parameter", + "Properties": { + "Type": "String", + "Value": short_uid(), + }, + }, + }, + } + + stack_name = f"stack-{short_uid()}" + cs_name = f"cs-{short_uid()}" + with pytest.raises(ClientError) as exc_info: + aws_client.cloudformation.create_change_set( + ChangeSetName=cs_name, + StackName=stack_name, + ChangeSetType="CREATE", + TemplateBody=json.dumps(template), + Parameters=[ + {"ParameterKey": "Value", "ParameterValue": "not-a-number"}, + ], + ) + + snapshot.match("error", exc_info.value.response) diff --git a/tests/aws/services/cloudformation/test_change_set_parameters.snapshot.json b/tests/aws/services/cloudformation/test_change_set_parameters.snapshot.json index cdb8fb837e17a..55b2d7e63ffde 100644 --- a/tests/aws/services/cloudformation/test_change_set_parameters.snapshot.json +++ b/tests/aws/services/cloudformation/test_change_set_parameters.snapshot.json @@ -1926,5 +1926,461 @@ "Tags": [] } } + }, + "tests/aws/services/cloudformation/test_change_set_parameters.py::TestChangeSetParameters::test_invalid_parameter_type": { + "recorded-date": "06-10-2025, 20:45:59", + "recorded-content": { + "error": { + "Error": { + "Code": "ValidationError", + "Message": "Parameter 'Value' must be a number.", + "Type": "Sender" + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + } + } + }, + "tests/aws/services/cloudformation/test_change_set_parameters.py::TestChangeSetParameters::test_parameter_type_change": { + "recorded-date": "06-10-2025, 20:55:52", + "recorded-content": { + "create-change-set-1": { + "Id": "arn::cloudformation::111111111111:changeSet/", + "StackId": "", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "describe-change-set-1-prop-values": { + "Capabilities": [ + "CAPABILITY_IAM", + "CAPABILITY_NAMED_IAM", + "CAPABILITY_AUTO_EXPAND" + ], + "ChangeSetId": "arn::cloudformation::111111111111:changeSet/", + "ChangeSetName": "", + "Changes": [ + { + "ResourceChange": { + "Action": "Add", + "AfterContext": { + "Properties": { + "Value": "123", + "Type": "String" + } + }, + "Details": [], + "LogicalResourceId": "MyParameter", + "ResourceType": "AWS::SSM::Parameter", + "Scope": [] + }, + "Type": "Resource" + } + ], + "CreationTime": "datetime", + "ExecutionStatus": "AVAILABLE", + "IncludeNestedStacks": false, + "NotificationARNs": [], + "Parameters": [ + { + "ParameterKey": "Value", + "ParameterValue": "123" + } + ], + "RollbackConfiguration": {}, + "StackId": "", + "StackName": "", + "Status": "CREATE_COMPLETE", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "describe-change-set-1": { + "Capabilities": [ + "CAPABILITY_IAM", + "CAPABILITY_NAMED_IAM", + "CAPABILITY_AUTO_EXPAND" + ], + "ChangeSetId": "arn::cloudformation::111111111111:changeSet/", + "ChangeSetName": "", + "Changes": [ + { + "ResourceChange": { + "Action": "Add", + "Details": [], + "LogicalResourceId": "MyParameter", + "ResourceType": "AWS::SSM::Parameter", + "Scope": [] + }, + "Type": "Resource" + } + ], + "CreationTime": "datetime", + "ExecutionStatus": "AVAILABLE", + "IncludeNestedStacks": false, + "NotificationARNs": [], + "Parameters": [ + { + "ParameterKey": "Value", + "ParameterValue": "123" + } + ], + "RollbackConfiguration": {}, + "StackId": "", + "StackName": "", + "Status": "CREATE_COMPLETE", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "execute-change-set-1": { + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "post-create-1-describe": { + "Capabilities": [ + "CAPABILITY_IAM", + "CAPABILITY_NAMED_IAM", + "CAPABILITY_AUTO_EXPAND" + ], + "ChangeSetId": "arn::cloudformation::111111111111:changeSet/", + "CreationTime": "datetime", + "DisableRollback": false, + "DriftInformation": { + "StackDriftStatus": "NOT_CHECKED" + }, + "EnableTerminationProtection": false, + "LastUpdatedTime": "datetime", + "NotificationARNs": [], + "Parameters": [ + { + "ParameterKey": "Value", + "ParameterValue": "123" + } + ], + "RollbackConfiguration": {}, + "StackId": "", + "StackName": "", + "StackStatus": "CREATE_COMPLETE", + "Tags": [] + }, + "create-change-set-2": { + "Id": "arn::cloudformation::111111111111:changeSet/", + "StackId": "", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "describe-change-set-2-prop-values": { + "Capabilities": [ + "CAPABILITY_IAM", + "CAPABILITY_NAMED_IAM", + "CAPABILITY_AUTO_EXPAND" + ], + "ChangeSetId": "arn::cloudformation::111111111111:changeSet/", + "ChangeSetName": "", + "Changes": [ + { + "ResourceChange": { + "Action": "Modify", + "AfterContext": { + "Properties": { + "Value": "456", + "Type": "String" + } + }, + "BeforeContext": { + "Properties": { + "Value": "123", + "Type": "String" + } + }, + "Details": [ + { + "CausingEntity": "Value", + "ChangeSource": "ParameterReference", + "Evaluation": "Static", + "Target": { + "AfterValue": "456", + "Attribute": "Properties", + "AttributeChangeType": "Modify", + "BeforeValue": "123", + "Name": "Value", + "Path": "/Properties/Value", + "RequiresRecreation": "Never" + } + }, + { + "ChangeSource": "DirectModification", + "Evaluation": "Dynamic", + "Target": { + "AfterValue": "456", + "Attribute": "Properties", + "AttributeChangeType": "Modify", + "BeforeValue": "123", + "Name": "Value", + "Path": "/Properties/Value", + "RequiresRecreation": "Never" + } + } + ], + "LogicalResourceId": "MyParameter", + "PhysicalResourceId": "", + "Replacement": "False", + "ResourceType": "AWS::SSM::Parameter", + "Scope": [ + "Properties" + ] + }, + "Type": "Resource" + } + ], + "CreationTime": "datetime", + "ExecutionStatus": "AVAILABLE", + "IncludeNestedStacks": false, + "NotificationARNs": [], + "Parameters": [ + { + "ParameterKey": "Value", + "ParameterValue": "456" + } + ], + "RollbackConfiguration": {}, + "StackId": "", + "StackName": "", + "Status": "CREATE_COMPLETE", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "describe-change-set-2": { + "Capabilities": [ + "CAPABILITY_IAM", + "CAPABILITY_NAMED_IAM", + "CAPABILITY_AUTO_EXPAND" + ], + "ChangeSetId": "arn::cloudformation::111111111111:changeSet/", + "ChangeSetName": "", + "Changes": [ + { + "ResourceChange": { + "Action": "Modify", + "Details": [ + { + "CausingEntity": "Value", + "ChangeSource": "ParameterReference", + "Evaluation": "Static", + "Target": { + "Attribute": "Properties", + "Name": "Value", + "RequiresRecreation": "Never" + } + }, + { + "ChangeSource": "DirectModification", + "Evaluation": "Dynamic", + "Target": { + "Attribute": "Properties", + "Name": "Value", + "RequiresRecreation": "Never" + } + } + ], + "LogicalResourceId": "MyParameter", + "PhysicalResourceId": "", + "Replacement": "False", + "ResourceType": "AWS::SSM::Parameter", + "Scope": [ + "Properties" + ] + }, + "Type": "Resource" + } + ], + "CreationTime": "datetime", + "ExecutionStatus": "AVAILABLE", + "IncludeNestedStacks": false, + "NotificationARNs": [], + "Parameters": [ + { + "ParameterKey": "Value", + "ParameterValue": "456" + } + ], + "RollbackConfiguration": {}, + "StackId": "", + "StackName": "", + "Status": "CREATE_COMPLETE", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "execute-change-set-2": { + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "post-create-2-describe": { + "Capabilities": [ + "CAPABILITY_IAM", + "CAPABILITY_NAMED_IAM", + "CAPABILITY_AUTO_EXPAND" + ], + "ChangeSetId": "arn::cloudformation::111111111111:changeSet/", + "CreationTime": "datetime", + "DisableRollback": false, + "DriftInformation": { + "StackDriftStatus": "NOT_CHECKED" + }, + "EnableTerminationProtection": false, + "LastUpdatedTime": "datetime", + "NotificationARNs": [], + "Parameters": [ + { + "ParameterKey": "Value", + "ParameterValue": "456" + } + ], + "RollbackConfiguration": {}, + "StackId": "", + "StackName": "", + "StackStatus": "UPDATE_COMPLETE", + "Tags": [] + }, + "delete-describe": { + "Capabilities": [ + "CAPABILITY_IAM", + "CAPABILITY_NAMED_IAM", + "CAPABILITY_AUTO_EXPAND" + ], + "CreationTime": "datetime", + "DeletionTime": "datetime", + "DisableRollback": false, + "DriftInformation": { + "StackDriftStatus": "NOT_CHECKED" + }, + "LastUpdatedTime": "datetime", + "NotificationARNs": [], + "Parameters": [ + { + "ParameterKey": "Value", + "ParameterValue": "456" + } + ], + "RollbackConfiguration": {}, + "StackId": "", + "StackName": "", + "StackStatus": "DELETE_COMPLETE", + "Tags": [] + }, + "per-resource-events": { + "MyParameter": [ + { + "LogicalResourceId": "MyParameter", + "PhysicalResourceId": "", + "ResourceStatus": "CREATE_IN_PROGRESS", + "ResourceType": "AWS::SSM::Parameter", + "Timestamp": "timestamp" + }, + { + "LogicalResourceId": "MyParameter", + "PhysicalResourceId": "", + "ResourceStatus": "CREATE_COMPLETE", + "ResourceType": "AWS::SSM::Parameter", + "Timestamp": "timestamp" + }, + { + "LogicalResourceId": "MyParameter", + "PhysicalResourceId": "", + "ResourceStatus": "UPDATE_IN_PROGRESS", + "ResourceType": "AWS::SSM::Parameter", + "Timestamp": "timestamp" + }, + { + "LogicalResourceId": "MyParameter", + "PhysicalResourceId": "", + "ResourceStatus": "UPDATE_COMPLETE", + "ResourceType": "AWS::SSM::Parameter", + "Timestamp": "timestamp" + }, + { + "LogicalResourceId": "MyParameter", + "PhysicalResourceId": "", + "ResourceStatus": "DELETE_IN_PROGRESS", + "ResourceType": "AWS::SSM::Parameter", + "Timestamp": "timestamp" + }, + { + "LogicalResourceId": "MyParameter", + "PhysicalResourceId": "", + "ResourceStatus": "DELETE_COMPLETE", + "ResourceType": "AWS::SSM::Parameter", + "Timestamp": "timestamp" + } + ], + "Stack": [ + { + "LogicalResourceId": "", + "PhysicalResourceId": "", + "ResourceStatus": "REVIEW_IN_PROGRESS", + "ResourceType": "AWS::CloudFormation::Stack", + "Timestamp": "timestamp" + }, + { + "LogicalResourceId": "", + "PhysicalResourceId": "", + "ResourceStatus": "CREATE_IN_PROGRESS", + "ResourceType": "AWS::CloudFormation::Stack", + "Timestamp": "timestamp" + }, + { + "LogicalResourceId": "", + "PhysicalResourceId": "", + "ResourceStatus": "CREATE_COMPLETE", + "ResourceType": "AWS::CloudFormation::Stack", + "Timestamp": "timestamp" + }, + { + "LogicalResourceId": "", + "PhysicalResourceId": "", + "ResourceStatus": "UPDATE_IN_PROGRESS", + "ResourceType": "AWS::CloudFormation::Stack", + "Timestamp": "timestamp" + }, + { + "LogicalResourceId": "", + "PhysicalResourceId": "", + "ResourceStatus": "UPDATE_COMPLETE", + "ResourceType": "AWS::CloudFormation::Stack", + "Timestamp": "timestamp" + }, + { + "LogicalResourceId": "", + "PhysicalResourceId": "", + "ResourceStatus": "DELETE_IN_PROGRESS", + "ResourceType": "AWS::CloudFormation::Stack", + "Timestamp": "timestamp" + }, + { + "LogicalResourceId": "", + "PhysicalResourceId": "", + "ResourceStatus": "DELETE_COMPLETE", + "ResourceType": "AWS::CloudFormation::Stack", + "Timestamp": "timestamp" + } + ] + } + } } } diff --git a/tests/aws/services/cloudformation/test_change_set_parameters.validation.json b/tests/aws/services/cloudformation/test_change_set_parameters.validation.json index 36c85e0e750ce..dc624db1e38cd 100644 --- a/tests/aws/services/cloudformation/test_change_set_parameters.validation.json +++ b/tests/aws/services/cloudformation/test_change_set_parameters.validation.json @@ -1,4 +1,22 @@ { + "tests/aws/services/cloudformation/test_change_set_parameters.py::TestChangeSetParameters::test_invalid_parameter_type": { + "last_validated_date": "2025-10-06T20:45:59+00:00", + "durations_in_seconds": { + "setup": 0.92, + "call": 0.33, + "teardown": 0.01, + "total": 1.26 + } + }, + "tests/aws/services/cloudformation/test_change_set_parameters.py::TestChangeSetParameters::test_parameter_type_change": { + "last_validated_date": "2025-10-06T20:55:52+00:00", + "durations_in_seconds": { + "setup": 0.99, + "call": 27.31, + "teardown": 0.17, + "total": 28.47 + } + }, "tests/aws/services/cloudformation/test_change_set_parameters.py::TestChangeSetParameters::test_update_parameter_default_value": { "last_validated_date": "2025-04-17T15:35:43+00:00" }, diff --git a/tests/aws/services/cloudformation/test_change_sets.py b/tests/aws/services/cloudformation/test_change_sets.py index 81df75f995049..9a2ed1d89f22a 100644 --- a/tests/aws/services/cloudformation/test_change_sets.py +++ b/tests/aws/services/cloudformation/test_change_sets.py @@ -1,5 +1,6 @@ import copy import json +import os import pytest from botocore.exceptions import WaiterError @@ -780,6 +781,55 @@ def test_single_resource_static_update( parameter = aws_client.ssm.get_parameter(Name=parameter_name)["Parameter"] snapshot.match("parameter-2", parameter) + @markers.aws.validated + @markers.snapshot.skip_snapshot_verify(paths=["$..PhysicalResourceId"]) + def test_queue_update( + self, aws_client, deploy_cfn_template, capture_per_resource_events, snapshot + ): + """ + A test where one of the templates creates a resource without any specified properties. We + make sure the second operation on that resource is an UPDATE not CREATE. + """ + snapshot.add_transformer(snapshot.transform.cloudformation_api()) + + template1 = os.path.join( + os.path.dirname(__file__), "../../templates/sqs_queue_update_1.yaml" + ) + template2 = os.path.join( + os.path.dirname(__file__), "../../templates/sqs_queue_update_2.yaml" + ) + + # Deploy order: + # - 1 + # - 2 + # - 1 + + stack = deploy_cfn_template(template_path=template1) + outputs = stack.outputs + + queue_url = outputs["QueueUrl"] + + queue_attributes = aws_client.sqs.get_queue_attributes( + QueueUrl=queue_url, AttributeNames=["All"] + ) + snapshot.match("queue-attributes-1", queue_attributes) + + deploy_cfn_template(template_path=template2, is_update=True, stack_name=stack.stack_id) + queue_attributes = aws_client.sqs.get_queue_attributes( + QueueUrl=queue_url, AttributeNames=["All"] + ) + snapshot.match("queue-attributes-2", queue_attributes) + + deploy_cfn_template(template_path=template1, is_update=True, stack_name=stack.stack_id) + queue_attributes = aws_client.sqs.get_queue_attributes( + QueueUrl=queue_url, AttributeNames=["All"] + ) + snapshot.match("queue-attributes-3", queue_attributes) + + per_resource_events = capture_per_resource_events(stack.stack_id) + + snapshot.match("events", per_resource_events["StandardQueue"]) + @skip_if_legacy_engine() @markers.aws.validated diff --git a/tests/aws/services/cloudformation/test_change_sets.snapshot.json b/tests/aws/services/cloudformation/test_change_sets.snapshot.json index 308f620d46395..0744e8ff4496b 100644 --- a/tests/aws/services/cloudformation/test_change_sets.snapshot.json +++ b/tests/aws/services/cloudformation/test_change_sets.snapshot.json @@ -5950,5 +5950,114 @@ } } } + }, + "tests/aws/services/cloudformation/test_change_sets.py::TestCaptureUpdateProcess::test_queue_update": { + "recorded-date": "05-12-2025, 10:45:20", + "recorded-content": { + "queue-attributes-1": { + "Attributes": { + "ApproximateNumberOfMessages": "0", + "ApproximateNumberOfMessagesDelayed": "0", + "ApproximateNumberOfMessagesNotVisible": "0", + "CreatedTimestamp": "timestamp", + "DelaySeconds": "0", + "LastModifiedTimestamp": "timestamp", + "MaximumMessageSize": "1048576", + "MessageRetentionPeriod": "345600", + "QueueArn": "arn::sqs::111111111111:", + "ReceiveMessageWaitTimeSeconds": "0", + "SqsManagedSseEnabled": "true", + "VisibilityTimeout": "30" + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "queue-attributes-2": { + "Attributes": { + "ApproximateNumberOfMessages": "0", + "ApproximateNumberOfMessagesDelayed": "0", + "ApproximateNumberOfMessagesNotVisible": "0", + "CreatedTimestamp": "timestamp", + "DelaySeconds": "0", + "LastModifiedTimestamp": "timestamp", + "MaximumMessageSize": "4321", + "MessageRetentionPeriod": "17539", + "QueueArn": "arn::sqs::111111111111:", + "ReceiveMessageWaitTimeSeconds": "17", + "SqsManagedSseEnabled": "true", + "VisibilityTimeout": "30" + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "queue-attributes-3": { + "Attributes": { + "ApproximateNumberOfMessages": "0", + "ApproximateNumberOfMessagesDelayed": "0", + "ApproximateNumberOfMessagesNotVisible": "0", + "CreatedTimestamp": "timestamp", + "DelaySeconds": "0", + "LastModifiedTimestamp": "timestamp", + "MaximumMessageSize": "262144", + "MessageRetentionPeriod": "345600", + "QueueArn": "arn::sqs::111111111111:", + "ReceiveMessageWaitTimeSeconds": "0", + "SqsManagedSseEnabled": "true", + "VisibilityTimeout": "30" + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "events": [ + { + "PhysicalResourceId": "https://sqs..amazonaws.com/111111111111/", + "LogicalResourceId": "StandardQueue", + "ResourceType": "AWS::SQS::Queue", + "ResourceStatus": "CREATE_IN_PROGRESS", + "Timestamp": "timestamp" + }, + { + "PhysicalResourceId": "https://sqs..amazonaws.com/111111111111/", + "LogicalResourceId": "StandardQueue", + "ResourceType": "AWS::SQS::Queue", + "ResourceStatus": "CREATE_COMPLETE", + "Timestamp": "timestamp" + }, + { + "PhysicalResourceId": "https://sqs..amazonaws.com/111111111111/", + "LogicalResourceId": "StandardQueue", + "ResourceType": "AWS::SQS::Queue", + "ResourceStatus": "UPDATE_IN_PROGRESS", + "Timestamp": "timestamp" + }, + { + "PhysicalResourceId": "https://sqs..amazonaws.com/111111111111/", + "LogicalResourceId": "StandardQueue", + "ResourceType": "AWS::SQS::Queue", + "ResourceStatus": "UPDATE_COMPLETE", + "Timestamp": "timestamp" + }, + { + "PhysicalResourceId": "https://sqs..amazonaws.com/111111111111/", + "LogicalResourceId": "StandardQueue", + "ResourceType": "AWS::SQS::Queue", + "ResourceStatus": "UPDATE_IN_PROGRESS", + "Timestamp": "timestamp" + }, + { + "PhysicalResourceId": "https://sqs..amazonaws.com/111111111111/", + "LogicalResourceId": "StandardQueue", + "ResourceType": "AWS::SQS::Queue", + "ResourceStatus": "UPDATE_COMPLETE", + "Timestamp": "timestamp" + } + ] + } } } diff --git a/tests/aws/services/cloudformation/test_change_sets.validation.json b/tests/aws/services/cloudformation/test_change_sets.validation.json index 5f4ecab525235..fe51926659666 100644 --- a/tests/aws/services/cloudformation/test_change_sets.validation.json +++ b/tests/aws/services/cloudformation/test_change_sets.validation.json @@ -89,6 +89,15 @@ "total": 125.07 } }, + "tests/aws/services/cloudformation/test_change_sets.py::TestCaptureUpdateProcess::test_queue_update": { + "last_validated_date": "2025-12-05T10:45:54+00:00", + "durations_in_seconds": { + "setup": 0.96, + "call": 123.03, + "teardown": 33.91, + "total": 157.9 + } + }, "tests/aws/services/cloudformation/test_change_sets.py::TestCaptureUpdateProcess::test_single_resource_static_update": { "last_validated_date": "2025-08-05T14:26:48+00:00", "durations_in_seconds": { diff --git a/tests/aws/services/cloudformation/test_cloudformation_ui.py b/tests/aws/services/cloudformation/test_cloudformation_ui.py deleted file mode 100644 index 9974d55dbf9ab..0000000000000 --- a/tests/aws/services/cloudformation/test_cloudformation_ui.py +++ /dev/null @@ -1,22 +0,0 @@ -import requests - -from localstack import config -from localstack.testing.pytest import markers - -CLOUDFORMATION_UI_PATH = "/_localstack/cloudformation/deploy" - - -class TestCloudFormationUi: - @markers.aws.only_localstack - def test_get_cloudformation_ui(self): - # note: we get the external service url here because the UI is hosted on the external - # URL, however if `LOCALSTACK_HOST` is set to a hostname that does not resolve to - # `127.0.0.1` this test will fail. - cfn_ui_url = config.external_service_url() + CLOUDFORMATION_UI_PATH - response = requests.get(cfn_ui_url) - - # we simply test that the UI is available at the right path and that it returns HTML. - assert response.ok - assert "content-type" in response.headers - # this is a bit fragile but assert that the file returned contains at least something related to the UI - assert b"LocalStack" in response.content diff --git a/tests/aws/services/cloudformation/test_template_engine.py b/tests/aws/services/cloudformation/test_template_engine.py index 52e4876cea994..7b84e3608731d 100644 --- a/tests/aws/services/cloudformation/test_template_engine.py +++ b/tests/aws/services/cloudformation/test_template_engine.py @@ -1317,3 +1317,29 @@ def test_stack_id(self, deploy_cfn_template, snapshot): snapshot.add_transformer(snapshot.transform.regex(stack.stack_id, "")) snapshot.match("StackId", stack.outputs["StackId"]) + + +@markers.aws.validated +@skip_if_legacy_engine() +def test_no_type(aws_client, snapshot): + template = { + "Resources": { + "Foo": { + "Properties": { + "Name": "foo", + }, + }, + }, + } + + stack_name = f"stack-{short_uid()}" + change_set_name = f"cs-{short_uid()}" + with pytest.raises(ClientError) as e: + aws_client.cloudformation.create_change_set( + ChangeSetName=change_set_name, + StackName=stack_name, + TemplateBody=json.dumps(template), + ChangeSetType="CREATE", + ) + + snapshot.match("error", e.value) diff --git a/tests/aws/services/cloudformation/test_template_engine.snapshot.json b/tests/aws/services/cloudformation/test_template_engine.snapshot.json index bc433c691614c..1a5dbd704fc76 100644 --- a/tests/aws/services/cloudformation/test_template_engine.snapshot.json +++ b/tests/aws/services/cloudformation/test_template_engine.snapshot.json @@ -700,5 +700,11 @@ "TopicName": "" } } + }, + "tests/aws/services/cloudformation/test_template_engine.py::test_no_type": { + "recorded-date": "15-12-2025, 10:55:28", + "recorded-content": { + "error": "An error occurred (ValidationError) when calling the CreateChangeSet operation: Template format error: [/Resources/Foo] Every Resources object must contain a Type member." + } } } diff --git a/tests/aws/services/cloudformation/test_template_engine.validation.json b/tests/aws/services/cloudformation/test_template_engine.validation.json index 79bece0983398..4919222874297 100644 --- a/tests/aws/services/cloudformation/test_template_engine.validation.json +++ b/tests/aws/services/cloudformation/test_template_engine.validation.json @@ -151,5 +151,14 @@ "teardown": 50.06, "total": 90.44 } + }, + "tests/aws/services/cloudformation/test_template_engine.py::test_no_type": { + "last_validated_date": "2025-12-15T10:55:28+00:00", + "durations_in_seconds": { + "setup": 0.75, + "call": 0.27, + "teardown": 0.0, + "total": 1.02 + } } } diff --git a/tests/aws/services/cloudwatch/test_cloudwatch.py b/tests/aws/services/cloudwatch/test_cloudwatch.py index b95c6b6742baa..a89510d380072 100644 --- a/tests/aws/services/cloudwatch/test_cloudwatch.py +++ b/tests/aws/services/cloudwatch/test_cloudwatch.py @@ -1,6 +1,7 @@ import gzip import json import logging +import re import threading import time from datetime import UTC, datetime, timedelta, timezone @@ -10,6 +11,7 @@ import pytest import requests from botocore.exceptions import ClientError +from localstack_snapshot.snapshots.transformer import SortingTransformer from localstack import config from localstack.services.cloudwatch.provider import PATH_GET_RAW_METRICS @@ -671,6 +673,122 @@ def test_store_tags(self, aws_cloudwatch_client, cleanups, snapshot): ) snapshot.match("list_tags_for_resource_post_untag", list_tags_for_resource_post_untag) + @markers.aws.validated + @pytest.mark.skipif(is_old_provider(), reason="New test for v2 provider") + def test_tagging_metric_alarm(self, aws_cloudwatch_client, snapshot): + # Sort tags by key value in snapshots + snapshot.add_transformer(SortingTransformer("Tags", lambda o: o["Key"])) + alarm_name = f"a-{short_uid()}" + metric_name = "store_tags" + namespace = f"test-ns-{short_uid()}" + put_metric_alarm = aws_cloudwatch_client.put_metric_alarm( + AlarmName=alarm_name, + Namespace=namespace, + MetricName=metric_name, + EvaluationPeriods=1, + ComparisonOperator="GreaterThanThreshold", + Period=60, + Statistic="Sum", + Threshold=30, + Tags=[{"Key": "Environment", "Value": "Production"}], + ) + snapshot.match("put_metric_alarm", put_metric_alarm) + + describe_alarms = aws_cloudwatch_client.describe_alarms(AlarmNames=[alarm_name]) + alarm = describe_alarms["MetricAlarms"][0] + alarm_arn = alarm["AlarmArn"] + + list_tags_for_resource_after_creation = aws_cloudwatch_client.list_tags_for_resource( + ResourceARN=alarm_arn + ) + snapshot.match( + "list_tags_for_resource_after_creation", list_tags_for_resource_after_creation + ) + + # add tags + tags = [{"Key": "tag1", "Value": "foo"}, {"Key": "tag2", "Value": "bar"}] + response = aws_cloudwatch_client.tag_resource(ResourceARN=alarm_arn, Tags=tags) + assert response["ResponseMetadata"]["HTTPStatusCode"] == 200 + list_tags_for_resource_updated = aws_cloudwatch_client.list_tags_for_resource( + ResourceARN=alarm_arn + ) + snapshot.match("list_tags_for_resource_updated", list_tags_for_resource_updated) + response = aws_cloudwatch_client.untag_resource(ResourceARN=alarm_arn, TagKeys=["tag1"]) + assert response["ResponseMetadata"]["HTTPStatusCode"] == 200 + list_tags_for_resource_post_untag = aws_cloudwatch_client.list_tags_for_resource( + ResourceARN=alarm_arn + ) + snapshot.match("list_tags_for_resource_post_untag", list_tags_for_resource_post_untag) + + # delete alarm + aws_cloudwatch_client.delete_alarms(AlarmNames=[alarm_name]) + list_tags_for_deleted_resource = aws_cloudwatch_client.list_tags_for_resource( + ResourceARN=alarm_arn + ) + snapshot.match("list_tags_for_deleted_resource", list_tags_for_deleted_resource) + + @markers.aws.validated + @pytest.mark.skipif(is_old_provider(), reason="New test for v2 provider") + def test_tagging_composite_alarm(self, aws_cloudwatch_client, snapshot): + # Sort tags by key value in snapshots + snapshot.add_transformer(SortingTransformer("Tags", lambda o: o["Key"])) + snapshot.add_transformer(snapshot.transform.cloudwatch_api()) + composite_alarm_name = f"composite-a-{short_uid()}" + alarm_name = f"a-{short_uid()}" + metric_name = "something" + namespace = f"test-ns-{short_uid()}" + alarm_rule = f'ALARM("{alarm_name}")' + aws_cloudwatch_client.put_metric_alarm( + AlarmName=alarm_name, + Namespace=namespace, + MetricName=metric_name, + EvaluationPeriods=1, + ComparisonOperator="GreaterThanThreshold", + Period=60, + Statistic="Sum", + Threshold=30, + ) + aws_cloudwatch_client.put_composite_alarm( + AlarmName=composite_alarm_name, + AlarmRule=alarm_rule, + Tags=[{"Key": "Environment", "Value": "Production"}], + ) + describe_alarms = aws_cloudwatch_client.describe_alarms( + AlarmTypes=["CompositeAlarm"], AlarmNames=[composite_alarm_name] + ) + alarm = describe_alarms["CompositeAlarms"][0] + alarm_arn = alarm["AlarmArn"] + + list_tags_for_resource_after_creation = aws_cloudwatch_client.list_tags_for_resource( + ResourceARN=alarm_arn + ) + snapshot.match( + "list_tags_for_resource_after_creation ", list_tags_for_resource_after_creation + ) + + # add tags + tags = [{"Key": "tag1", "Value": "foo"}, {"Key": "tag2", "Value": "bar"}] + response = aws_cloudwatch_client.tag_resource(ResourceARN=alarm_arn, Tags=tags) + assert response["ResponseMetadata"]["HTTPStatusCode"] == 200 + list_tags_for_resource_updated = aws_cloudwatch_client.list_tags_for_resource( + ResourceARN=alarm_arn + ) + snapshot.match("list_tags_for_resource_updated", list_tags_for_resource_updated) + response = aws_cloudwatch_client.untag_resource(ResourceARN=alarm_arn, TagKeys=["tag1"]) + assert response["ResponseMetadata"]["HTTPStatusCode"] == 200 + list_tags_for_resource_post_untag = aws_cloudwatch_client.list_tags_for_resource( + ResourceARN=alarm_arn + ) + snapshot.match("list_tags_for_resource_post_untag", list_tags_for_resource_post_untag) + + # delete alarm + aws_cloudwatch_client.delete_alarms(AlarmNames=[composite_alarm_name]) + list_tags_for_deleted_resource = aws_cloudwatch_client.list_tags_for_resource( + ResourceARN=alarm_arn + ) + snapshot.match("list_tags_for_deleted_resource", list_tags_for_deleted_resource) + aws_cloudwatch_client.delete_alarms(AlarmNames=[alarm_name]) + @markers.aws.validated def test_list_metrics_uniqueness(self, aws_cloudwatch_client): """ @@ -1234,6 +1352,7 @@ def _check_composite_alarm_ok_message( "$..NewStateReason", "$..describe-alarms-for-metric..StateReason", # reason contains datapoint + date "$..describe-alarms-for-metric..StateReasonData.evaluatedDatapoints", + "$.alarm-triggered-sqs-msg.ActionExecutedAfterMuteWindow", ] ) @pytest.mark.skipif( @@ -1247,7 +1366,6 @@ def test_put_metric_alarm( aws_client, cleanups, sns_create_sqs_subscription, - aws_cloudwatch_client, ): topic_arn_alarm = sns_create_topic()["TopicArn"] @@ -1290,9 +1408,11 @@ def test_put_metric_alarm( "Unit": "Seconds", }, ] + # by sending two alarms, sometimes the alarm scheduler will trigger right at the time the metrics are being + # added, meaning the alarm will not go off instantly # create alarm with action for "ALARM" - aws_cloudwatch_client.put_metric_alarm( + aws_client.cloudwatch.put_metric_alarm( AlarmName=alarm_name, AlarmDescription="testing cloudwatch alarms", MetricName=metric_name, @@ -1310,11 +1430,11 @@ def test_put_metric_alarm( TreatMissingData="ignore", # notBreaching had some downsides, as depending on the alarm evaluation interval it would first go into OK ) - cleanups.append(lambda: aws_cloudwatch_client.delete_alarms(AlarmNames=[alarm_name])) - response = aws_cloudwatch_client.describe_alarms(AlarmNames=[alarm_name]) + cleanups.append(lambda: aws_client.cloudwatch.delete_alarms(AlarmNames=[alarm_name])) + response = aws_client.cloudwatch.describe_alarms(AlarmNames=[alarm_name]) snapshot.match("describe-alarm", response) - aws_cloudwatch_client.put_metric_data(Namespace=namespace, MetricData=data) + aws_client.cloudwatch.put_metric_data(Namespace=namespace, MetricData=data) retry( _sqs_messages_snapshot, retries=60, @@ -1328,13 +1448,13 @@ def test_put_metric_alarm( ) # describe alarm history - history = aws_cloudwatch_client.describe_alarm_history( + history = aws_client.cloudwatch.describe_alarm_history( AlarmName=alarm_name, HistoryItemType="StateUpdate" ) snapshot.match("describe-alarm-history", history) # describe alarms for metric - alarms = aws_cloudwatch_client.describe_alarms_for_metric( + alarms = aws_client.cloudwatch.describe_alarms_for_metric( MetricName=metric_name, Namespace=namespace, Dimensions=dimension, @@ -1515,9 +1635,7 @@ def test_enable_disable_alarm_actions( assert response["MetricAlarms"][0]["ActionsEnabled"] @markers.aws.validated - def test_aws_sqs_metrics_created( - self, sqs_create_queue, snapshot, aws_client, aws_cloudwatch_client - ): + def test_aws_sqs_metrics_created(self, sqs_create_queue, snapshot, aws_client): snapshot.add_transformer(snapshot.transform.cloudwatch_api()) sqs_url = sqs_create_queue() sqs_arn = aws_client.sqs.get_queue_attributes( @@ -1553,13 +1671,13 @@ def _create_metric(metric_id: str) -> dict: empty["MetricStat"]["Metric"]["MetricName"] = "NumberOfEmptyReceives" def contains_sent_messages_metrics() -> int: - res = aws_cloudwatch_client.list_metrics(Dimensions=dimensions) + res = aws_client.cloudwatch.list_metrics(Dimensions=dimensions) metrics = [metric["MetricName"] for metric in res["Metrics"]] if all( m in metrics for m in ["NumberOfMessagesSent", "SentMessageSize", "NumberOfEmptyReceives"] ): - res = aws_cloudwatch_client.get_metric_data( + res = aws_client.cloudwatch.get_metric_data( MetricDataQueries=[sent, sent_size, empty], StartTime=datetime.now(tz=UTC) - timedelta(hours=1), EndTime=datetime.now(tz=UTC), @@ -1575,7 +1693,7 @@ def contains_sent_messages_metrics() -> int: assert poll_condition(lambda: contains_sent_messages_metrics(), interval=1, timeout=120) - response = aws_cloudwatch_client.get_metric_data( + response = aws_client.cloudwatch.get_metric_data( MetricDataQueries=[sent, sent_size, empty], StartTime=datetime.now(tz=UTC) - timedelta(hours=1), EndTime=datetime.now(tz=UTC), @@ -1584,7 +1702,9 @@ def contains_sent_messages_metrics() -> int: snapshot.match("get_metric_data", response) # receive + delete message - sqs_messages = aws_client.sqs.receive_message(QueueUrl=sqs_url)["Messages"] + sqs_messages = aws_client.sqs.receive_message(QueueUrl=sqs_url, WaitTimeSeconds=5)[ + "Messages" + ] assert len(sqs_messages) == 1 receipt_handle = sqs_messages[0]["ReceiptHandle"] aws_client.sqs.delete_message(QueueUrl=sqs_url, ReceiptHandle=receipt_handle) @@ -1596,10 +1716,10 @@ def contains_sent_messages_metrics() -> int: msg_deleted["MetricStat"]["Metric"]["MetricName"] = "NumberOfMessagesDeleted" def contains_receive_delete_metrics() -> int: - res = aws_cloudwatch_client.list_metrics(Dimensions=dimensions) + res = aws_client.cloudwatch.list_metrics(Dimensions=dimensions) metrics = [metric["MetricName"] for metric in res["Metrics"]] if all(m in metrics for m in ["NumberOfMessagesReceived", "NumberOfMessagesDeleted"]): - res = aws_cloudwatch_client.get_metric_data( + res = aws_client.cloudwatch.get_metric_data( MetricDataQueries=[msg_received, msg_deleted], StartTime=datetime.now(tz=UTC) - timedelta(hours=1), EndTime=datetime.now(tz=UTC), @@ -1611,7 +1731,7 @@ def contains_receive_delete_metrics() -> int: assert poll_condition(lambda: contains_receive_delete_metrics(), interval=1, timeout=120) - response = aws_cloudwatch_client.get_metric_data( + response = aws_client.cloudwatch.get_metric_data( MetricDataQueries=[msg_received, msg_deleted], StartTime=datetime.now(tz=UTC) - timedelta(hours=1), EndTime=datetime.now(tz=UTC), @@ -2535,8 +2655,6 @@ def assert_results(): retry(assert_results, retries=10, sleep=1.0, sleep_before=2 if is_aws_cloud() else 0.0) @markers.aws.validated - # we're not testing multi protocols for this test because we're not snapshotting any CloudWatch response - # and are only testing Lambda logic def test_alarm_lambda_target( self, aws_client, create_lambda_function, cleanups, account_id, snapshot ): @@ -2975,6 +3093,8 @@ def test_basic_operations_multiple_protocols( payload=input_values, ) assert response.status_code == 200 + # Check if x-amzn-RequestId is in the response headers - case-sensitive check + assert "x-amzn-RequestId" in dict(response.headers) get_metric_input = { "MetricDataQueries": [ @@ -3024,6 +3144,36 @@ def _get_metric_data_sum(): ) snapshot.match("get-metric-data", response) + # we need special assertions for raw timestamp values, based on the protocol: + if protocol == "query": + timestamp = response["GetMetricDataResponse"]["GetMetricDataResult"][ + "MetricDataResults" + ]["member"][0]["Timestamps"]["member"] + assert re.match(r"^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}Z$", timestamp) + + elif protocol == "json": + timestamp = response["MetricDataResults"][0]["Timestamps"][0] + assert isinstance(timestamp, float) + # assert this format: 1765977780.0 + assert re.match(r"^\d{10}\.0", str(timestamp)) + else: + timestamp = response["MetricDataResults"][0]["Timestamps"][0] + assert isinstance(timestamp, datetime) + assert timestamp.microsecond == 0 + assert timestamp.year == now.year + assert now.day - 1 <= timestamp.day <= now.day + 1 + + # we need to decode more for CBOR, to verify we encode it the same way as AWS (datetime format + proper + # underlying format (float) + # See https://smithy.io/2.0/additional-specs/protocols/smithy-rpc-v2.html#timestamp-type-serialization + # https://datatracker.ietf.org/doc/html/rfc8949.html#section-3.4 + response_raw = http_client.post_raw( + operation="GetMetricData", + payload=get_metric_input, + ) + # assert that the timestamp is encoded as a Tag (6 major type) with Double of length 8 + assert b"Timestamps\x9f\xc1\xfbA" in response_raw.content + @markers.aws.validated @pytest.mark.skipif(is_old_provider(), reason="Wrong behavior in v1 in SetAlarmState") @pytest.mark.parametrize("protocol", ["json", "smithy-rpc-v2-cbor", "query"]) @@ -3097,18 +3247,22 @@ def _check_alarm_triggered( def _sqs_messages_snapshot(expected_state, sqs_client, sqs_queue, snapshot, identifier): result = sqs_client.receive_message(QueueUrl=sqs_queue, WaitTimeSeconds=2, VisibilityTimeout=0) found_msg = None - receipt_handle = None + other_messages = [] for msg in result["Messages"]: body = json.loads(msg["Body"]) message = json.loads(body["Message"]) + receipt_handle = msg["ReceiptHandle"] + sqs_client.delete_message(QueueUrl=sqs_queue, ReceiptHandle=receipt_handle) + if message["NewStateValue"] == expected_state: found_msg = message - receipt_handle = msg["ReceiptHandle"] break + else: + other_messages.append(msg) + assert found_msg, ( - f"no message found for {expected_state}. Got {len(result['Messages'])} messages.\n{json.dumps(result)}" + f"no message found for {expected_state}. Got {len(other_messages)} messages.\n{other_messages}" ) - sqs_client.delete_message(QueueUrl=sqs_queue, ReceiptHandle=receipt_handle) snapshot.match(f"{identifier}-sqs-msg", found_msg) diff --git a/tests/aws/services/cloudwatch/test_cloudwatch.snapshot.json b/tests/aws/services/cloudwatch/test_cloudwatch.snapshot.json index 93b4c21669080..2b9decda1abe0 100644 --- a/tests/aws/services/cloudwatch/test_cloudwatch.snapshot.json +++ b/tests/aws/services/cloudwatch/test_cloudwatch.snapshot.json @@ -43,7 +43,7 @@ } }, "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudWatchMultiProtocol::test_basic_operations_multiple_protocols[json]": { - "recorded-date": "18-09-2025, 13:56:03", + "recorded-date": "06-10-2025, 14:45:54", "recorded-content": { "describe-alarms": { "CompositeAlarms": [], @@ -76,7 +76,7 @@ } }, "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudWatchMultiProtocol::test_basic_operations_multiple_protocols[smithy-rpc-v2-cbor]": { - "recorded-date": "18-09-2025, 13:56:06", + "recorded-date": "06-10-2025, 14:45:56", "recorded-content": { "describe-alarms": { "CompositeAlarms": [], @@ -109,7 +109,7 @@ } }, "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudWatchMultiProtocol::test_basic_operations_multiple_protocols[query]": { - "recorded-date": "18-09-2025, 13:56:09", + "recorded-date": "06-10-2025, 14:45:59", "recorded-content": { "describe-alarms": { "DescribeAlarmsResponse": { @@ -1875,10 +1875,48 @@ } } }, - "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_put_metric_alarm[query]": { - "recorded-date": "19-09-2025, 21:08:24", + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_breaching_alarm_actions[query]": { + "recorded-date": "19-09-2025, 21:11:41", "recorded-content": { - "describe-alarm": { + "alarm-1-sqs-msg": { + "AWSAccountId": "111111111111", + "AlarmActions": [ + "arn::sns::111111111111:" + ], + "AlarmArn": "arn::cloudwatch::111111111111:alarm:", + "AlarmConfigurationUpdatedTimestamp": "date", + "AlarmDescription": "testing cloudwatch alarms", + "AlarmName": "", + "InsufficientDataActions": [], + "NewStateReason": "Threshold Crossed: no datapoints were received for 2 periods and 2 missing datapoints were treated as [Breaching].", + "NewStateValue": "ALARM", + "OKActions": [ + "arn::sns::111111111111:" + ], + "OldStateValue": "INSUFFICIENT_DATA", + "Region": "", + "StateChangeTime": "date", + "Trigger": { + "ComparisonOperator": "GreaterThanThreshold", + "Dimensions": [ + { + "name": "InstanceId", + "value": "abc" + } + ], + "EvaluateLowSampleCountPercentile": "", + "EvaluationPeriods": 2, + "MetricName": "my-metric101", + "Namespace": "", + "Period": 10, + "Statistic": "AVERAGE", + "StatisticType": "Statistic", + "Threshold": 2.0, + "TreatMissingData": "breaching", + "Unit": "Seconds" + } + }, + "alarm-1-describe": { "CompositeAlarms": [], "MetricAlarms": [ { @@ -1897,21 +1935,38 @@ "Value": "abc" } ], - "EvaluationPeriods": 1, + "EvaluationPeriods": 2, "InsufficientDataActions": [], - "MetricName": "my-metric1", + "MetricName": "my-metric101", "Namespace": "", "OKActions": [ "arn::sns::111111111111:" ], "Period": 10, - "StateReason": "Unchecked: Initial alarm creation", + "StateReason": "Threshold Crossed: no datapoints were received for 2 periods and 2 missing datapoints were treated as [Breaching].", + "StateReasonData": { + "version": "1.0", + "queryDate": "date", + "unit": "Seconds", + "statistic": "Average", + "period": 10, + "recentDatapoints": [], + "threshold": 2.0, + "evaluatedDatapoints": [ + { + "timestamp": "date" + }, + { + "timestamp": "date" + } + ] + }, "StateTransitionedTimestamp": "timestamp", "StateUpdatedTimestamp": "timestamp", - "StateValue": "INSUFFICIENT_DATA", + "StateValue": "ALARM", "Statistic": "Average", - "Threshold": 21.0, - "TreatMissingData": "ignore", + "Threshold": 2.0, + "TreatMissingData": "breaching", "Unit": "Seconds" } ], @@ -1919,8 +1974,13 @@ "HTTPHeaders": {}, "HTTPStatusCode": 200 } - }, - "alarm-triggered-sqs-msg": { + } + } + }, + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_breaching_alarm_actions[json]": { + "recorded-date": "19-09-2025, 21:12:42", + "recorded-content": { + "alarm-1-sqs-msg": { "AWSAccountId": "111111111111", "AlarmActions": [ "arn::sns::111111111111:" @@ -1930,7 +1990,7 @@ "AlarmDescription": "testing cloudwatch alarms", "AlarmName": "", "InsufficientDataActions": [], - "NewStateReason": "Threshold Crossed: 1 datapoint [21.5 (MM/DD/YY HH:MM:SS)] was greater than the threshold (21.0).", + "NewStateReason": "Threshold Crossed: no datapoints were received for 2 periods and 2 missing datapoints were treated as [Breaching].", "NewStateValue": "ALARM", "OKActions": [ "arn::sns::111111111111:" @@ -1947,63 +2007,121 @@ } ], "EvaluateLowSampleCountPercentile": "", - "EvaluationPeriods": 1, - "MetricName": "my-metric1", + "EvaluationPeriods": 2, + "MetricName": "my-metric101", "Namespace": "", "Period": 10, "Statistic": "AVERAGE", "StatisticType": "Statistic", - "Threshold": 21.0, - "TreatMissingData": "ignore", + "Threshold": 2.0, + "TreatMissingData": "breaching", "Unit": "Seconds" } }, - "describe-alarm-history": { - "AlarmHistoryItems": [ + "alarm-1-describe": { + "CompositeAlarms": [], + "MetricAlarms": [ { + "ActionsEnabled": true, + "AlarmActions": [ + "arn::sns::111111111111:" + ], + "AlarmArn": "arn::cloudwatch::111111111111:alarm:", + "AlarmConfigurationUpdatedTimestamp": "timestamp", + "AlarmDescription": "testing cloudwatch alarms", "AlarmName": "", - "AlarmType": "MetricAlarm", - "HistoryData": { + "ComparisonOperator": "GreaterThanThreshold", + "Dimensions": [ + { + "Name": "InstanceId", + "Value": "abc" + } + ], + "EvaluationPeriods": 2, + "InsufficientDataActions": [], + "MetricName": "my-metric101", + "Namespace": "", + "OKActions": [ + "arn::sns::111111111111:" + ], + "Period": 10, + "StateReason": "Threshold Crossed: no datapoints were received for 2 periods and 2 missing datapoints were treated as [Breaching].", + "StateReasonData": { "version": "1.0", - "oldState": { - "stateValue": "INSUFFICIENT_DATA", - "stateReason": "Unchecked: Initial alarm creation" - }, - "newState": { - "stateValue": "ALARM", - "stateReason": "Threshold Crossed: 1 datapoint [21.5 (MM/DD/YY HH:MM:SS)] was greater than the threshold (21.0).", - "stateReasonData": { - "version": "1.0", - "queryDate": "date", - "startDate": "date", - "unit": "Seconds", - "statistic": "Average", - "period": 10, - "recentDatapoints": [ - 21.5 - ], - "threshold": 21.0, - "evaluatedDatapoints": [ - { - "timestamp": "date", - "sampleCount": 2.0, - "value": 21.5 - } - ] + "queryDate": "date", + "unit": "Seconds", + "statistic": "Average", + "period": 10, + "recentDatapoints": [], + "threshold": 2.0, + "evaluatedDatapoints": [ + { + "timestamp": "date" + }, + { + "timestamp": "date" } - } + ] }, - "HistoryItemType": "StateUpdate", - "HistorySummary": "Alarm updated from INSUFFICIENT_DATA to ALARM", - "Timestamp": "timestamp" + "StateTransitionedTimestamp": "timestamp", + "StateUpdatedTimestamp": "timestamp", + "StateValue": "ALARM", + "Statistic": "Average", + "Threshold": 2.0, + "TreatMissingData": "breaching", + "Unit": "Seconds" } ], "ResponseMetadata": { "HTTPHeaders": {}, "HTTPStatusCode": 200 } + } + } + }, + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_breaching_alarm_actions[smithy-rpc-v2-cbor]": { + "recorded-date": "19-09-2025, 21:13:17", + "recorded-content": { + "alarm-1-sqs-msg": { + "AWSAccountId": "111111111111", + "AlarmActions": [ + "arn::sns::111111111111:" + ], + "AlarmArn": "arn::cloudwatch::111111111111:alarm:", + "AlarmConfigurationUpdatedTimestamp": "date", + "AlarmDescription": "testing cloudwatch alarms", + "AlarmName": "", + "InsufficientDataActions": [], + "NewStateReason": "Threshold Crossed: no datapoints were received for 2 periods and 2 missing datapoints were treated as [Breaching].", + "NewStateValue": "ALARM", + "OKActions": [ + "arn::sns::111111111111:" + ], + "OldStateValue": "INSUFFICIENT_DATA", + "Region": "", + "StateChangeTime": "date", + "Trigger": { + "ComparisonOperator": "GreaterThanThreshold", + "Dimensions": [ + { + "name": "InstanceId", + "value": "abc" + } + ], + "EvaluateLowSampleCountPercentile": "", + "EvaluationPeriods": 2, + "MetricName": "my-metric101", + "Namespace": "", + "Period": 10, + "Statistic": "AVERAGE", + "StatisticType": "Statistic", + "Threshold": 2.0, + "TreatMissingData": "breaching", + "Unit": "Seconds" + } }, - "describe-alarms-for-metric": { + "alarm-1-describe": { + "CompositeAlarms": [], "MetricAlarms": [ { "ActionsEnabled": true, @@ -2021,31 +2139,29 @@ "Value": "abc" } ], - "EvaluationPeriods": 1, + "EvaluationPeriods": 2, "InsufficientDataActions": [], - "MetricName": "my-metric1", + "MetricName": "my-metric101", "Namespace": "", "OKActions": [ "arn::sns::111111111111:" ], "Period": 10, - "StateReason": "Threshold Crossed: 1 datapoint [21.5 (MM/DD/YY HH:MM:SS)] was greater than the threshold (21.0).", + "StateReason": "Threshold Crossed: no datapoints were received for 2 periods and 2 missing datapoints were treated as [Breaching].", "StateReasonData": { "version": "1.0", "queryDate": "date", - "startDate": "date", "unit": "Seconds", "statistic": "Average", "period": 10, - "recentDatapoints": [ - 21.5 - ], - "threshold": 21.0, + "recentDatapoints": [], + "threshold": 2.0, "evaluatedDatapoints": [ { - "timestamp": "date", - "sampleCount": 2.0, - "value": 21.5 + "timestamp": "date" + }, + { + "timestamp": "date" } ] }, @@ -2053,8 +2169,8 @@ "StateUpdatedTimestamp": "timestamp", "StateValue": "ALARM", "Statistic": "Average", - "Threshold": 21.0, - "TreatMissingData": "ignore", + "Threshold": 2.0, + "TreatMissingData": "breaching", "Unit": "Seconds" } ], @@ -2065,10 +2181,10 @@ } } }, - "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_put_metric_alarm[json]": { - "recorded-date": "19-09-2025, 21:08:43", + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_enable_disable_alarm_actions[query]": { + "recorded-date": "19-09-2025, 21:17:31", "recorded-content": { - "describe-alarm": { + "describe_alarm": { "CompositeAlarms": [], "MetricAlarms": [ { @@ -2087,9 +2203,9 @@ "Value": "abc" } ], - "EvaluationPeriods": 1, + "EvaluationPeriods": 2, "InsufficientDataActions": [], - "MetricName": "my-metric1", + "MetricName": "my-metric101", "Namespace": "", "OKActions": [ "arn::sns::111111111111:" @@ -2100,7 +2216,7 @@ "StateUpdatedTimestamp": "timestamp", "StateValue": "INSUFFICIENT_DATA", "Statistic": "Average", - "Threshold": 21.0, + "Threshold": 2.0, "TreatMissingData": "ignore", "Unit": "Seconds" } @@ -2110,7 +2226,7 @@ "HTTPStatusCode": 200 } }, - "alarm-triggered-sqs-msg": { + "alarm-state-sqs-msg": { "AWSAccountId": "111111111111", "AlarmActions": [ "arn::sns::111111111111:" @@ -2120,7 +2236,7 @@ "AlarmDescription": "testing cloudwatch alarms", "AlarmName": "", "InsufficientDataActions": [], - "NewStateReason": "Threshold Crossed: 1 datapoint [21.5 (MM/DD/YY HH:MM:SS)] was greater than the threshold (21.0).", + "NewStateReason": "testing alarm", "NewStateValue": "ALARM", "OKActions": [ "arn::sns::111111111111:" @@ -2137,55 +2253,52 @@ } ], "EvaluateLowSampleCountPercentile": "", - "EvaluationPeriods": 1, - "MetricName": "my-metric1", + "EvaluationPeriods": 2, + "MetricName": "my-metric101", "Namespace": "", "Period": 10, "Statistic": "AVERAGE", "StatisticType": "Statistic", - "Threshold": 21.0, + "Threshold": 2.0, "TreatMissingData": "ignore", "Unit": "Seconds" } }, - "describe-alarm-history": { - "AlarmHistoryItems": [ + "alarm-state-describe": { + "CompositeAlarms": [], + "MetricAlarms": [ { + "ActionsEnabled": true, + "AlarmActions": [ + "arn::sns::111111111111:" + ], + "AlarmArn": "arn::cloudwatch::111111111111:alarm:", + "AlarmConfigurationUpdatedTimestamp": "timestamp", + "AlarmDescription": "testing cloudwatch alarms", "AlarmName": "", - "AlarmType": "MetricAlarm", - "HistoryData": { - "version": "1.0", - "oldState": { - "stateValue": "INSUFFICIENT_DATA", - "stateReason": "Unchecked: Initial alarm creation" - }, - "newState": { - "stateValue": "ALARM", - "stateReason": "Threshold Crossed: 1 datapoint [21.5 (MM/DD/YY HH:MM:SS)] was greater than the threshold (21.0).", - "stateReasonData": { - "version": "1.0", - "queryDate": "date", - "startDate": "date", - "unit": "Seconds", - "statistic": "Average", - "period": 10, - "recentDatapoints": [ - 21.5 - ], - "threshold": 21.0, - "evaluatedDatapoints": [ - { - "timestamp": "date", - "sampleCount": 2.0, - "value": 21.5 - } - ] - } + "ComparisonOperator": "GreaterThanThreshold", + "Dimensions": [ + { + "Name": "InstanceId", + "Value": "abc" } - }, - "HistoryItemType": "StateUpdate", - "HistorySummary": "Alarm updated from INSUFFICIENT_DATA to ALARM", - "Timestamp": "timestamp" + ], + "EvaluationPeriods": 2, + "InsufficientDataActions": [], + "MetricName": "my-metric101", + "Namespace": "", + "OKActions": [ + "arn::sns::111111111111:" + ], + "Period": 10, + "StateReason": "testing alarm", + "StateTransitionedTimestamp": "timestamp", + "StateUpdatedTimestamp": "timestamp", + "StateValue": "ALARM", + "Statistic": "Average", + "Threshold": 2.0, + "TreatMissingData": "ignore", + "Unit": "Seconds" } ], "ResponseMetadata": { @@ -2193,7 +2306,92 @@ "HTTPStatusCode": 200 } }, - "describe-alarms-for-metric": { + "describe_alarm_disabled": { + "CompositeAlarms": [], + "MetricAlarms": [ + { + "ActionsEnabled": false, + "AlarmActions": [ + "arn::sns::111111111111:" + ], + "AlarmArn": "arn::cloudwatch::111111111111:alarm:", + "AlarmConfigurationUpdatedTimestamp": "timestamp", + "AlarmDescription": "testing cloudwatch alarms", + "AlarmName": "", + "ComparisonOperator": "GreaterThanThreshold", + "Dimensions": [ + { + "Name": "InstanceId", + "Value": "abc" + } + ], + "EvaluationPeriods": 2, + "InsufficientDataActions": [], + "MetricName": "my-metric101", + "Namespace": "", + "OKActions": [ + "arn::sns::111111111111:" + ], + "Period": 10, + "StateReason": "testing OK state", + "StateTransitionedTimestamp": "timestamp", + "StateUpdatedTimestamp": "timestamp", + "StateValue": "OK", + "Statistic": "Average", + "Threshold": 2.0, + "TreatMissingData": "ignore", + "Unit": "Seconds" + } + ], + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "ok-state-action-disabled-describe": { + "CompositeAlarms": [], + "MetricAlarms": [ + { + "ActionsEnabled": false, + "AlarmActions": [ + "arn::sns::111111111111:" + ], + "AlarmArn": "arn::cloudwatch::111111111111:alarm:", + "AlarmConfigurationUpdatedTimestamp": "timestamp", + "AlarmDescription": "testing cloudwatch alarms", + "AlarmName": "", + "ComparisonOperator": "GreaterThanThreshold", + "Dimensions": [ + { + "Name": "InstanceId", + "Value": "abc" + } + ], + "EvaluationPeriods": 2, + "InsufficientDataActions": [], + "MetricName": "my-metric101", + "Namespace": "", + "OKActions": [ + "arn::sns::111111111111:" + ], + "Period": 10, + "StateReason": "testing OK state", + "StateTransitionedTimestamp": "timestamp", + "StateUpdatedTimestamp": "timestamp", + "StateValue": "OK", + "Statistic": "Average", + "Threshold": 2.0, + "TreatMissingData": "ignore", + "Unit": "Seconds" + } + ], + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "describe_alarm_enabled": { + "CompositeAlarms": [], "MetricAlarms": [ { "ActionsEnabled": true, @@ -2211,39 +2409,20 @@ "Value": "abc" } ], - "EvaluationPeriods": 1, + "EvaluationPeriods": 2, "InsufficientDataActions": [], - "MetricName": "my-metric1", + "MetricName": "my-metric101", "Namespace": "", "OKActions": [ "arn::sns::111111111111:" ], "Period": 10, - "StateReason": "Threshold Crossed: 1 datapoint [21.5 (MM/DD/YY HH:MM:SS)] was greater than the threshold (21.0).", - "StateReasonData": { - "version": "1.0", - "queryDate": "date", - "startDate": "date", - "unit": "Seconds", - "statistic": "Average", - "period": 10, - "recentDatapoints": [ - 21.5 - ], - "threshold": 21.0, - "evaluatedDatapoints": [ - { - "timestamp": "date", - "sampleCount": 2.0, - "value": 21.5 - } - ] - }, + "StateReason": "testing OK state", "StateTransitionedTimestamp": "timestamp", "StateUpdatedTimestamp": "timestamp", - "StateValue": "ALARM", + "StateValue": "OK", "Statistic": "Average", - "Threshold": 21.0, + "Threshold": 2.0, "TreatMissingData": "ignore", "Unit": "Seconds" } @@ -2255,10 +2434,10 @@ } } }, - "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_put_metric_alarm[smithy-rpc-v2-cbor]": { - "recorded-date": "19-09-2025, 21:09:02", + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_enable_disable_alarm_actions[json]": { + "recorded-date": "19-09-2025, 21:17:46", "recorded-content": { - "describe-alarm": { + "describe_alarm": { "CompositeAlarms": [], "MetricAlarms": [ { @@ -2277,9 +2456,9 @@ "Value": "abc" } ], - "EvaluationPeriods": 1, + "EvaluationPeriods": 2, "InsufficientDataActions": [], - "MetricName": "my-metric1", + "MetricName": "my-metric101", "Namespace": "", "OKActions": [ "arn::sns::111111111111:" @@ -2290,7 +2469,7 @@ "StateUpdatedTimestamp": "timestamp", "StateValue": "INSUFFICIENT_DATA", "Statistic": "Average", - "Threshold": 21.0, + "Threshold": 2.0, "TreatMissingData": "ignore", "Unit": "Seconds" } @@ -2300,7 +2479,7 @@ "HTTPStatusCode": 200 } }, - "alarm-triggered-sqs-msg": { + "alarm-state-sqs-msg": { "AWSAccountId": "111111111111", "AlarmActions": [ "arn::sns::111111111111:" @@ -2310,7 +2489,7 @@ "AlarmDescription": "testing cloudwatch alarms", "AlarmName": "", "InsufficientDataActions": [], - "NewStateReason": "Threshold Crossed: 1 datapoint [21.5 (MM/DD/YY HH:MM:SS)] was greater than the threshold (21.0).", + "NewStateReason": "testing alarm", "NewStateValue": "ALARM", "OKActions": [ "arn::sns::111111111111:" @@ -2327,63 +2506,19 @@ } ], "EvaluateLowSampleCountPercentile": "", - "EvaluationPeriods": 1, - "MetricName": "my-metric1", + "EvaluationPeriods": 2, + "MetricName": "my-metric101", "Namespace": "", "Period": 10, "Statistic": "AVERAGE", "StatisticType": "Statistic", - "Threshold": 21.0, + "Threshold": 2.0, "TreatMissingData": "ignore", "Unit": "Seconds" } }, - "describe-alarm-history": { - "AlarmHistoryItems": [ - { - "AlarmName": "", - "AlarmType": "MetricAlarm", - "HistoryData": { - "version": "1.0", - "oldState": { - "stateValue": "INSUFFICIENT_DATA", - "stateReason": "Unchecked: Initial alarm creation" - }, - "newState": { - "stateValue": "ALARM", - "stateReason": "Threshold Crossed: 1 datapoint [21.5 (MM/DD/YY HH:MM:SS)] was greater than the threshold (21.0).", - "stateReasonData": { - "version": "1.0", - "queryDate": "date", - "startDate": "date", - "unit": "Seconds", - "statistic": "Average", - "period": 10, - "recentDatapoints": [ - 21.5 - ], - "threshold": 21.0, - "evaluatedDatapoints": [ - { - "timestamp": "date", - "sampleCount": 2.0, - "value": 21.5 - } - ] - } - } - }, - "HistoryItemType": "StateUpdate", - "HistorySummary": "Alarm updated from INSUFFICIENT_DATA to ALARM", - "Timestamp": "timestamp" - } - ], - "ResponseMetadata": { - "HTTPHeaders": {}, - "HTTPStatusCode": 200 - } - }, - "describe-alarms-for-metric": { + "alarm-state-describe": { + "CompositeAlarms": [], "MetricAlarms": [ { "ActionsEnabled": true, @@ -2401,39 +2536,20 @@ "Value": "abc" } ], - "EvaluationPeriods": 1, + "EvaluationPeriods": 2, "InsufficientDataActions": [], - "MetricName": "my-metric1", + "MetricName": "my-metric101", "Namespace": "", "OKActions": [ "arn::sns::111111111111:" ], "Period": 10, - "StateReason": "Threshold Crossed: 1 datapoint [21.5 (MM/DD/YY HH:MM:SS)] was greater than the threshold (21.0).", - "StateReasonData": { - "version": "1.0", - "queryDate": "date", - "startDate": "date", - "unit": "Seconds", - "statistic": "Average", - "period": 10, - "recentDatapoints": [ - 21.5 - ], - "threshold": 21.0, - "evaluatedDatapoints": [ - { - "timestamp": "date", - "sampleCount": 2.0, - "value": 21.5 - } - ] - }, + "StateReason": "testing alarm", "StateTransitionedTimestamp": "timestamp", "StateUpdatedTimestamp": "timestamp", "StateValue": "ALARM", "Statistic": "Average", - "Threshold": 21.0, + "Threshold": 2.0, "TreatMissingData": "ignore", "Unit": "Seconds" } @@ -2442,55 +2558,12 @@ "HTTPHeaders": {}, "HTTPStatusCode": 200 } - } - } - }, - "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_breaching_alarm_actions[query]": { - "recorded-date": "19-09-2025, 21:11:41", - "recorded-content": { - "alarm-1-sqs-msg": { - "AWSAccountId": "111111111111", - "AlarmActions": [ - "arn::sns::111111111111:" - ], - "AlarmArn": "arn::cloudwatch::111111111111:alarm:", - "AlarmConfigurationUpdatedTimestamp": "date", - "AlarmDescription": "testing cloudwatch alarms", - "AlarmName": "", - "InsufficientDataActions": [], - "NewStateReason": "Threshold Crossed: no datapoints were received for 2 periods and 2 missing datapoints were treated as [Breaching].", - "NewStateValue": "ALARM", - "OKActions": [ - "arn::sns::111111111111:" - ], - "OldStateValue": "INSUFFICIENT_DATA", - "Region": "", - "StateChangeTime": "date", - "Trigger": { - "ComparisonOperator": "GreaterThanThreshold", - "Dimensions": [ - { - "name": "InstanceId", - "value": "abc" - } - ], - "EvaluateLowSampleCountPercentile": "", - "EvaluationPeriods": 2, - "MetricName": "my-metric101", - "Namespace": "", - "Period": 10, - "Statistic": "AVERAGE", - "StatisticType": "Statistic", - "Threshold": 2.0, - "TreatMissingData": "breaching", - "Unit": "Seconds" - } }, - "alarm-1-describe": { + "describe_alarm_disabled": { "CompositeAlarms": [], "MetricAlarms": [ { - "ActionsEnabled": true, + "ActionsEnabled": false, "AlarmActions": [ "arn::sns::111111111111:" ], @@ -2513,30 +2586,13 @@ "arn::sns::111111111111:" ], "Period": 10, - "StateReason": "Threshold Crossed: no datapoints were received for 2 periods and 2 missing datapoints were treated as [Breaching].", - "StateReasonData": { - "version": "1.0", - "queryDate": "date", - "unit": "Seconds", - "statistic": "Average", - "period": 10, - "recentDatapoints": [], - "threshold": 2.0, - "evaluatedDatapoints": [ - { - "timestamp": "date" - }, - { - "timestamp": "date" - } - ] - }, + "StateReason": "testing OK state", "StateTransitionedTimestamp": "timestamp", "StateUpdatedTimestamp": "timestamp", - "StateValue": "ALARM", + "StateValue": "OK", "Statistic": "Average", "Threshold": 2.0, - "TreatMissingData": "breaching", + "TreatMissingData": "ignore", "Unit": "Seconds" } ], @@ -2544,55 +2600,12 @@ "HTTPHeaders": {}, "HTTPStatusCode": 200 } - } - } - }, - "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_breaching_alarm_actions[json]": { - "recorded-date": "19-09-2025, 21:12:42", - "recorded-content": { - "alarm-1-sqs-msg": { - "AWSAccountId": "111111111111", - "AlarmActions": [ - "arn::sns::111111111111:" - ], - "AlarmArn": "arn::cloudwatch::111111111111:alarm:", - "AlarmConfigurationUpdatedTimestamp": "date", - "AlarmDescription": "testing cloudwatch alarms", - "AlarmName": "", - "InsufficientDataActions": [], - "NewStateReason": "Threshold Crossed: no datapoints were received for 2 periods and 2 missing datapoints were treated as [Breaching].", - "NewStateValue": "ALARM", - "OKActions": [ - "arn::sns::111111111111:" - ], - "OldStateValue": "INSUFFICIENT_DATA", - "Region": "", - "StateChangeTime": "date", - "Trigger": { - "ComparisonOperator": "GreaterThanThreshold", - "Dimensions": [ - { - "name": "InstanceId", - "value": "abc" - } - ], - "EvaluateLowSampleCountPercentile": "", - "EvaluationPeriods": 2, - "MetricName": "my-metric101", - "Namespace": "", - "Period": 10, - "Statistic": "AVERAGE", - "StatisticType": "Statistic", - "Threshold": 2.0, - "TreatMissingData": "breaching", - "Unit": "Seconds" - } }, - "alarm-1-describe": { + "ok-state-action-disabled-describe": { "CompositeAlarms": [], "MetricAlarms": [ { - "ActionsEnabled": true, + "ActionsEnabled": false, "AlarmActions": [ "arn::sns::111111111111:" ], @@ -2615,30 +2628,13 @@ "arn::sns::111111111111:" ], "Period": 10, - "StateReason": "Threshold Crossed: no datapoints were received for 2 periods and 2 missing datapoints were treated as [Breaching].", - "StateReasonData": { - "version": "1.0", - "queryDate": "date", - "unit": "Seconds", - "statistic": "Average", - "period": 10, - "recentDatapoints": [], - "threshold": 2.0, - "evaluatedDatapoints": [ - { - "timestamp": "date" - }, - { - "timestamp": "date" - } - ] - }, + "StateReason": "testing OK state", "StateTransitionedTimestamp": "timestamp", "StateUpdatedTimestamp": "timestamp", - "StateValue": "ALARM", + "StateValue": "OK", "Statistic": "Average", "Threshold": 2.0, - "TreatMissingData": "breaching", + "TreatMissingData": "ignore", "Unit": "Seconds" } ], @@ -2646,51 +2642,8 @@ "HTTPHeaders": {}, "HTTPStatusCode": 200 } - } - } - }, - "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_breaching_alarm_actions[smithy-rpc-v2-cbor]": { - "recorded-date": "19-09-2025, 21:13:17", - "recorded-content": { - "alarm-1-sqs-msg": { - "AWSAccountId": "111111111111", - "AlarmActions": [ - "arn::sns::111111111111:" - ], - "AlarmArn": "arn::cloudwatch::111111111111:alarm:", - "AlarmConfigurationUpdatedTimestamp": "date", - "AlarmDescription": "testing cloudwatch alarms", - "AlarmName": "", - "InsufficientDataActions": [], - "NewStateReason": "Threshold Crossed: no datapoints were received for 2 periods and 2 missing datapoints were treated as [Breaching].", - "NewStateValue": "ALARM", - "OKActions": [ - "arn::sns::111111111111:" - ], - "OldStateValue": "INSUFFICIENT_DATA", - "Region": "", - "StateChangeTime": "date", - "Trigger": { - "ComparisonOperator": "GreaterThanThreshold", - "Dimensions": [ - { - "name": "InstanceId", - "value": "abc" - } - ], - "EvaluateLowSampleCountPercentile": "", - "EvaluationPeriods": 2, - "MetricName": "my-metric101", - "Namespace": "", - "Period": 10, - "Statistic": "AVERAGE", - "StatisticType": "Statistic", - "Threshold": 2.0, - "TreatMissingData": "breaching", - "Unit": "Seconds" - } }, - "alarm-1-describe": { + "describe_alarm_enabled": { "CompositeAlarms": [], "MetricAlarms": [ { @@ -2717,30 +2670,13 @@ "arn::sns::111111111111:" ], "Period": 10, - "StateReason": "Threshold Crossed: no datapoints were received for 2 periods and 2 missing datapoints were treated as [Breaching].", - "StateReasonData": { - "version": "1.0", - "queryDate": "date", - "unit": "Seconds", - "statistic": "Average", - "period": 10, - "recentDatapoints": [], - "threshold": 2.0, - "evaluatedDatapoints": [ - { - "timestamp": "date" - }, - { - "timestamp": "date" - } - ] - }, + "StateReason": "testing OK state", "StateTransitionedTimestamp": "timestamp", "StateUpdatedTimestamp": "timestamp", - "StateValue": "ALARM", + "StateValue": "OK", "Statistic": "Average", "Threshold": 2.0, - "TreatMissingData": "breaching", + "TreatMissingData": "ignore", "Unit": "Seconds" } ], @@ -2751,8 +2687,8 @@ } } }, - "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_enable_disable_alarm_actions[query]": { - "recorded-date": "19-09-2025, 21:17:31", + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_enable_disable_alarm_actions[smithy-rpc-v2-cbor]": { + "recorded-date": "19-09-2025, 21:18:00", "recorded-content": { "describe_alarm": { "CompositeAlarms": [], @@ -3004,718 +2940,8 @@ } } }, - "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_enable_disable_alarm_actions[json]": { - "recorded-date": "19-09-2025, 21:17:46", - "recorded-content": { - "describe_alarm": { - "CompositeAlarms": [], - "MetricAlarms": [ - { - "ActionsEnabled": true, - "AlarmActions": [ - "arn::sns::111111111111:" - ], - "AlarmArn": "arn::cloudwatch::111111111111:alarm:", - "AlarmConfigurationUpdatedTimestamp": "timestamp", - "AlarmDescription": "testing cloudwatch alarms", - "AlarmName": "", - "ComparisonOperator": "GreaterThanThreshold", - "Dimensions": [ - { - "Name": "InstanceId", - "Value": "abc" - } - ], - "EvaluationPeriods": 2, - "InsufficientDataActions": [], - "MetricName": "my-metric101", - "Namespace": "", - "OKActions": [ - "arn::sns::111111111111:" - ], - "Period": 10, - "StateReason": "Unchecked: Initial alarm creation", - "StateTransitionedTimestamp": "timestamp", - "StateUpdatedTimestamp": "timestamp", - "StateValue": "INSUFFICIENT_DATA", - "Statistic": "Average", - "Threshold": 2.0, - "TreatMissingData": "ignore", - "Unit": "Seconds" - } - ], - "ResponseMetadata": { - "HTTPHeaders": {}, - "HTTPStatusCode": 200 - } - }, - "alarm-state-sqs-msg": { - "AWSAccountId": "111111111111", - "AlarmActions": [ - "arn::sns::111111111111:" - ], - "AlarmArn": "arn::cloudwatch::111111111111:alarm:", - "AlarmConfigurationUpdatedTimestamp": "date", - "AlarmDescription": "testing cloudwatch alarms", - "AlarmName": "", - "InsufficientDataActions": [], - "NewStateReason": "testing alarm", - "NewStateValue": "ALARM", - "OKActions": [ - "arn::sns::111111111111:" - ], - "OldStateValue": "INSUFFICIENT_DATA", - "Region": "", - "StateChangeTime": "date", - "Trigger": { - "ComparisonOperator": "GreaterThanThreshold", - "Dimensions": [ - { - "name": "InstanceId", - "value": "abc" - } - ], - "EvaluateLowSampleCountPercentile": "", - "EvaluationPeriods": 2, - "MetricName": "my-metric101", - "Namespace": "", - "Period": 10, - "Statistic": "AVERAGE", - "StatisticType": "Statistic", - "Threshold": 2.0, - "TreatMissingData": "ignore", - "Unit": "Seconds" - } - }, - "alarm-state-describe": { - "CompositeAlarms": [], - "MetricAlarms": [ - { - "ActionsEnabled": true, - "AlarmActions": [ - "arn::sns::111111111111:" - ], - "AlarmArn": "arn::cloudwatch::111111111111:alarm:", - "AlarmConfigurationUpdatedTimestamp": "timestamp", - "AlarmDescription": "testing cloudwatch alarms", - "AlarmName": "", - "ComparisonOperator": "GreaterThanThreshold", - "Dimensions": [ - { - "Name": "InstanceId", - "Value": "abc" - } - ], - "EvaluationPeriods": 2, - "InsufficientDataActions": [], - "MetricName": "my-metric101", - "Namespace": "", - "OKActions": [ - "arn::sns::111111111111:" - ], - "Period": 10, - "StateReason": "testing alarm", - "StateTransitionedTimestamp": "timestamp", - "StateUpdatedTimestamp": "timestamp", - "StateValue": "ALARM", - "Statistic": "Average", - "Threshold": 2.0, - "TreatMissingData": "ignore", - "Unit": "Seconds" - } - ], - "ResponseMetadata": { - "HTTPHeaders": {}, - "HTTPStatusCode": 200 - } - }, - "describe_alarm_disabled": { - "CompositeAlarms": [], - "MetricAlarms": [ - { - "ActionsEnabled": false, - "AlarmActions": [ - "arn::sns::111111111111:" - ], - "AlarmArn": "arn::cloudwatch::111111111111:alarm:", - "AlarmConfigurationUpdatedTimestamp": "timestamp", - "AlarmDescription": "testing cloudwatch alarms", - "AlarmName": "", - "ComparisonOperator": "GreaterThanThreshold", - "Dimensions": [ - { - "Name": "InstanceId", - "Value": "abc" - } - ], - "EvaluationPeriods": 2, - "InsufficientDataActions": [], - "MetricName": "my-metric101", - "Namespace": "", - "OKActions": [ - "arn::sns::111111111111:" - ], - "Period": 10, - "StateReason": "testing OK state", - "StateTransitionedTimestamp": "timestamp", - "StateUpdatedTimestamp": "timestamp", - "StateValue": "OK", - "Statistic": "Average", - "Threshold": 2.0, - "TreatMissingData": "ignore", - "Unit": "Seconds" - } - ], - "ResponseMetadata": { - "HTTPHeaders": {}, - "HTTPStatusCode": 200 - } - }, - "ok-state-action-disabled-describe": { - "CompositeAlarms": [], - "MetricAlarms": [ - { - "ActionsEnabled": false, - "AlarmActions": [ - "arn::sns::111111111111:" - ], - "AlarmArn": "arn::cloudwatch::111111111111:alarm:", - "AlarmConfigurationUpdatedTimestamp": "timestamp", - "AlarmDescription": "testing cloudwatch alarms", - "AlarmName": "", - "ComparisonOperator": "GreaterThanThreshold", - "Dimensions": [ - { - "Name": "InstanceId", - "Value": "abc" - } - ], - "EvaluationPeriods": 2, - "InsufficientDataActions": [], - "MetricName": "my-metric101", - "Namespace": "", - "OKActions": [ - "arn::sns::111111111111:" - ], - "Period": 10, - "StateReason": "testing OK state", - "StateTransitionedTimestamp": "timestamp", - "StateUpdatedTimestamp": "timestamp", - "StateValue": "OK", - "Statistic": "Average", - "Threshold": 2.0, - "TreatMissingData": "ignore", - "Unit": "Seconds" - } - ], - "ResponseMetadata": { - "HTTPHeaders": {}, - "HTTPStatusCode": 200 - } - }, - "describe_alarm_enabled": { - "CompositeAlarms": [], - "MetricAlarms": [ - { - "ActionsEnabled": true, - "AlarmActions": [ - "arn::sns::111111111111:" - ], - "AlarmArn": "arn::cloudwatch::111111111111:alarm:", - "AlarmConfigurationUpdatedTimestamp": "timestamp", - "AlarmDescription": "testing cloudwatch alarms", - "AlarmName": "", - "ComparisonOperator": "GreaterThanThreshold", - "Dimensions": [ - { - "Name": "InstanceId", - "Value": "abc" - } - ], - "EvaluationPeriods": 2, - "InsufficientDataActions": [], - "MetricName": "my-metric101", - "Namespace": "", - "OKActions": [ - "arn::sns::111111111111:" - ], - "Period": 10, - "StateReason": "testing OK state", - "StateTransitionedTimestamp": "timestamp", - "StateUpdatedTimestamp": "timestamp", - "StateValue": "OK", - "Statistic": "Average", - "Threshold": 2.0, - "TreatMissingData": "ignore", - "Unit": "Seconds" - } - ], - "ResponseMetadata": { - "HTTPHeaders": {}, - "HTTPStatusCode": 200 - } - } - } - }, - "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_enable_disable_alarm_actions[smithy-rpc-v2-cbor]": { - "recorded-date": "19-09-2025, 21:18:00", - "recorded-content": { - "describe_alarm": { - "CompositeAlarms": [], - "MetricAlarms": [ - { - "ActionsEnabled": true, - "AlarmActions": [ - "arn::sns::111111111111:" - ], - "AlarmArn": "arn::cloudwatch::111111111111:alarm:", - "AlarmConfigurationUpdatedTimestamp": "timestamp", - "AlarmDescription": "testing cloudwatch alarms", - "AlarmName": "", - "ComparisonOperator": "GreaterThanThreshold", - "Dimensions": [ - { - "Name": "InstanceId", - "Value": "abc" - } - ], - "EvaluationPeriods": 2, - "InsufficientDataActions": [], - "MetricName": "my-metric101", - "Namespace": "", - "OKActions": [ - "arn::sns::111111111111:" - ], - "Period": 10, - "StateReason": "Unchecked: Initial alarm creation", - "StateTransitionedTimestamp": "timestamp", - "StateUpdatedTimestamp": "timestamp", - "StateValue": "INSUFFICIENT_DATA", - "Statistic": "Average", - "Threshold": 2.0, - "TreatMissingData": "ignore", - "Unit": "Seconds" - } - ], - "ResponseMetadata": { - "HTTPHeaders": {}, - "HTTPStatusCode": 200 - } - }, - "alarm-state-sqs-msg": { - "AWSAccountId": "111111111111", - "AlarmActions": [ - "arn::sns::111111111111:" - ], - "AlarmArn": "arn::cloudwatch::111111111111:alarm:", - "AlarmConfigurationUpdatedTimestamp": "date", - "AlarmDescription": "testing cloudwatch alarms", - "AlarmName": "", - "InsufficientDataActions": [], - "NewStateReason": "testing alarm", - "NewStateValue": "ALARM", - "OKActions": [ - "arn::sns::111111111111:" - ], - "OldStateValue": "INSUFFICIENT_DATA", - "Region": "", - "StateChangeTime": "date", - "Trigger": { - "ComparisonOperator": "GreaterThanThreshold", - "Dimensions": [ - { - "name": "InstanceId", - "value": "abc" - } - ], - "EvaluateLowSampleCountPercentile": "", - "EvaluationPeriods": 2, - "MetricName": "my-metric101", - "Namespace": "", - "Period": 10, - "Statistic": "AVERAGE", - "StatisticType": "Statistic", - "Threshold": 2.0, - "TreatMissingData": "ignore", - "Unit": "Seconds" - } - }, - "alarm-state-describe": { - "CompositeAlarms": [], - "MetricAlarms": [ - { - "ActionsEnabled": true, - "AlarmActions": [ - "arn::sns::111111111111:" - ], - "AlarmArn": "arn::cloudwatch::111111111111:alarm:", - "AlarmConfigurationUpdatedTimestamp": "timestamp", - "AlarmDescription": "testing cloudwatch alarms", - "AlarmName": "", - "ComparisonOperator": "GreaterThanThreshold", - "Dimensions": [ - { - "Name": "InstanceId", - "Value": "abc" - } - ], - "EvaluationPeriods": 2, - "InsufficientDataActions": [], - "MetricName": "my-metric101", - "Namespace": "", - "OKActions": [ - "arn::sns::111111111111:" - ], - "Period": 10, - "StateReason": "testing alarm", - "StateTransitionedTimestamp": "timestamp", - "StateUpdatedTimestamp": "timestamp", - "StateValue": "ALARM", - "Statistic": "Average", - "Threshold": 2.0, - "TreatMissingData": "ignore", - "Unit": "Seconds" - } - ], - "ResponseMetadata": { - "HTTPHeaders": {}, - "HTTPStatusCode": 200 - } - }, - "describe_alarm_disabled": { - "CompositeAlarms": [], - "MetricAlarms": [ - { - "ActionsEnabled": false, - "AlarmActions": [ - "arn::sns::111111111111:" - ], - "AlarmArn": "arn::cloudwatch::111111111111:alarm:", - "AlarmConfigurationUpdatedTimestamp": "timestamp", - "AlarmDescription": "testing cloudwatch alarms", - "AlarmName": "", - "ComparisonOperator": "GreaterThanThreshold", - "Dimensions": [ - { - "Name": "InstanceId", - "Value": "abc" - } - ], - "EvaluationPeriods": 2, - "InsufficientDataActions": [], - "MetricName": "my-metric101", - "Namespace": "", - "OKActions": [ - "arn::sns::111111111111:" - ], - "Period": 10, - "StateReason": "testing OK state", - "StateTransitionedTimestamp": "timestamp", - "StateUpdatedTimestamp": "timestamp", - "StateValue": "OK", - "Statistic": "Average", - "Threshold": 2.0, - "TreatMissingData": "ignore", - "Unit": "Seconds" - } - ], - "ResponseMetadata": { - "HTTPHeaders": {}, - "HTTPStatusCode": 200 - } - }, - "ok-state-action-disabled-describe": { - "CompositeAlarms": [], - "MetricAlarms": [ - { - "ActionsEnabled": false, - "AlarmActions": [ - "arn::sns::111111111111:" - ], - "AlarmArn": "arn::cloudwatch::111111111111:alarm:", - "AlarmConfigurationUpdatedTimestamp": "timestamp", - "AlarmDescription": "testing cloudwatch alarms", - "AlarmName": "", - "ComparisonOperator": "GreaterThanThreshold", - "Dimensions": [ - { - "Name": "InstanceId", - "Value": "abc" - } - ], - "EvaluationPeriods": 2, - "InsufficientDataActions": [], - "MetricName": "my-metric101", - "Namespace": "", - "OKActions": [ - "arn::sns::111111111111:" - ], - "Period": 10, - "StateReason": "testing OK state", - "StateTransitionedTimestamp": "timestamp", - "StateUpdatedTimestamp": "timestamp", - "StateValue": "OK", - "Statistic": "Average", - "Threshold": 2.0, - "TreatMissingData": "ignore", - "Unit": "Seconds" - } - ], - "ResponseMetadata": { - "HTTPHeaders": {}, - "HTTPStatusCode": 200 - } - }, - "describe_alarm_enabled": { - "CompositeAlarms": [], - "MetricAlarms": [ - { - "ActionsEnabled": true, - "AlarmActions": [ - "arn::sns::111111111111:" - ], - "AlarmArn": "arn::cloudwatch::111111111111:alarm:", - "AlarmConfigurationUpdatedTimestamp": "timestamp", - "AlarmDescription": "testing cloudwatch alarms", - "AlarmName": "", - "ComparisonOperator": "GreaterThanThreshold", - "Dimensions": [ - { - "Name": "InstanceId", - "Value": "abc" - } - ], - "EvaluationPeriods": 2, - "InsufficientDataActions": [], - "MetricName": "my-metric101", - "Namespace": "", - "OKActions": [ - "arn::sns::111111111111:" - ], - "Period": 10, - "StateReason": "testing OK state", - "StateTransitionedTimestamp": "timestamp", - "StateUpdatedTimestamp": "timestamp", - "StateValue": "OK", - "Statistic": "Average", - "Threshold": 2.0, - "TreatMissingData": "ignore", - "Unit": "Seconds" - } - ], - "ResponseMetadata": { - "HTTPHeaders": {}, - "HTTPStatusCode": 200 - } - } - } - }, - "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_aws_sqs_metrics_created[query]": { - "recorded-date": "19-09-2025, 21:27:01", - "recorded-content": { - "get_metric_data": { - "Messages": [], - "MetricDataResults": [ - { - "Id": "sent", - "Label": "NumberOfMessagesSent", - "StatusCode": "Complete", - "Timestamps": "timestamp", - "Values": [ - 1.0 - ] - }, - { - "Id": "sent_size", - "Label": "SentMessageSize", - "StatusCode": "Complete", - "Timestamps": "timestamp", - "Values": [ - 5.0 - ] - }, - { - "Id": "empty_receives", - "Label": "NumberOfEmptyReceives", - "StatusCode": "Complete", - "Timestamps": "timestamp", - "Values": [ - 1.0 - ] - } - ], - "ResponseMetadata": { - "HTTPHeaders": {}, - "HTTPStatusCode": 200 - } - }, - "get_metric_data_2": { - "Messages": [], - "MetricDataResults": [ - { - "Id": "num_msg_received", - "Label": "NumberOfMessagesReceived", - "StatusCode": "Complete", - "Timestamps": "timestamp", - "Values": [ - 1.0 - ] - }, - { - "Id": "num_msg_deleted", - "Label": "NumberOfMessagesDeleted", - "StatusCode": "Complete", - "Timestamps": "timestamp", - "Values": [ - 1.0 - ] - } - ], - "ResponseMetadata": { - "HTTPHeaders": {}, - "HTTPStatusCode": 200 - } - } - } - }, - "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_aws_sqs_metrics_created[json]": { - "recorded-date": "19-09-2025, 21:29:00", - "recorded-content": { - "get_metric_data": { - "Messages": [], - "MetricDataResults": [ - { - "Id": "sent", - "Label": "NumberOfMessagesSent", - "StatusCode": "Complete", - "Timestamps": "timestamp", - "Values": [ - 1.0 - ] - }, - { - "Id": "sent_size", - "Label": "SentMessageSize", - "StatusCode": "Complete", - "Timestamps": "timestamp", - "Values": [ - 5.0 - ] - }, - { - "Id": "empty_receives", - "Label": "NumberOfEmptyReceives", - "StatusCode": "Complete", - "Timestamps": "timestamp", - "Values": [ - 1.0 - ] - } - ], - "ResponseMetadata": { - "HTTPHeaders": {}, - "HTTPStatusCode": 200 - } - }, - "get_metric_data_2": { - "Messages": [], - "MetricDataResults": [ - { - "Id": "num_msg_received", - "Label": "NumberOfMessagesReceived", - "StatusCode": "Complete", - "Timestamps": "timestamp", - "Values": [ - 1.0 - ] - }, - { - "Id": "num_msg_deleted", - "Label": "NumberOfMessagesDeleted", - "StatusCode": "Complete", - "Timestamps": "timestamp", - "Values": [ - 1.0 - ] - } - ], - "ResponseMetadata": { - "HTTPHeaders": {}, - "HTTPStatusCode": 200 - } - } - } - }, - "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_aws_sqs_metrics_created[smithy-rpc-v2-cbor]": { - "recorded-date": "19-09-2025, 21:31:00", - "recorded-content": { - "get_metric_data": { - "Messages": [], - "MetricDataResults": [ - { - "Id": "sent", - "Label": "NumberOfMessagesSent", - "StatusCode": "Complete", - "Timestamps": "timestamp", - "Values": [ - 1.0 - ] - }, - { - "Id": "sent_size", - "Label": "SentMessageSize", - "StatusCode": "Complete", - "Timestamps": "timestamp", - "Values": [ - 5.0 - ] - }, - { - "Id": "empty_receives", - "Label": "NumberOfEmptyReceives", - "StatusCode": "Complete", - "Timestamps": "timestamp", - "Values": [ - 1.0 - ] - } - ], - "ResponseMetadata": { - "HTTPHeaders": {}, - "HTTPStatusCode": 200 - } - }, - "get_metric_data_2": { - "Messages": [], - "MetricDataResults": [ - { - "Id": "num_msg_received", - "Label": "NumberOfMessagesReceived", - "StatusCode": "Complete", - "Timestamps": "timestamp", - "Values": [ - 1.0 - ] - }, - { - "Id": "num_msg_deleted", - "Label": "NumberOfMessagesDeleted", - "StatusCode": "Complete", - "Timestamps": "timestamp", - "Values": [ - 1.0 - ] - } - ], - "ResponseMetadata": { - "HTTPHeaders": {}, - "HTTPStatusCode": 200 - } - } - } - }, - "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_invalid_dashboard_name[query]": { - "recorded-date": "19-09-2025, 21:32:13", + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_invalid_dashboard_name[query]": { + "recorded-date": "19-09-2025, 21:32:13", "recorded-content": { "error-invalid-dashboardname": { "Error": { @@ -4124,13 +3350,153 @@ "HTTPStatusCode": 200 } }, - "stop_metric_stream": { + "stop_metric_stream": { + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "delete_metric_stream": { + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_insight_rule[query]": { + "recorded-date": "19-09-2025, 21:45:12", + "recorded-content": { + "create_insight_rule": { + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "describe_insight_rule": { + "InsightRules": [ + { + "ApplyOnTransformedLogs": false, + "Definition": { + "Schema": { + "Name": "", + "Version": 1 + }, + "LogGroupNames": [ + "API-Gateway-Access-Logs*" + ], + "LogFormat": "CLF", + "Fields": { + "4": "IpAddress", + "7": "StatusCode" + }, + "Contribution": { + "Keys": [ + "IpAddress" + ], + "Filters": [ + { + "Match": "StatusCode", + "EqualTo": 200 + } + ] + }, + "AggregateOn": "Count" + }, + "ManagedRule": false, + "Name": "", + "Schema": "/1", + "State": "ENABLED" + } + ], + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "disable_insight_rule": { + "Failures": [], + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "enable_insight_rule": { + "Failures": [], + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "get_insight_rule_report": { + "AggregateValue": 0.0, + "AggregationStatistic": "SampleCount", + "ApproximateUniqueCount": 0, + "Contributors": [], + "KeyLabels": [ + "IpAddress" + ], + "MetricDatapoints": [ + { + "Timestamp": "timestamp", + "UniqueContributors": 0.0 + }, + { + "Timestamp": "timestamp", + "UniqueContributors": 0.0 + }, + { + "Timestamp": "timestamp", + "UniqueContributors": 0.0 + }, + { + "Timestamp": "timestamp", + "UniqueContributors": 0.0 + }, + { + "Timestamp": "timestamp", + "UniqueContributors": 0.0 + }, + { + "Timestamp": "timestamp", + "UniqueContributors": 0.0 + }, + { + "Timestamp": "timestamp", + "UniqueContributors": 0.0 + }, + { + "Timestamp": "timestamp", + "UniqueContributors": 0.0 + }, + { + "Timestamp": "timestamp", + "UniqueContributors": 0.0 + }, + { + "Timestamp": "timestamp", + "UniqueContributors": 0.0 + }, + { + "Timestamp": "timestamp", + "UniqueContributors": 0.0 + }, + { + "Timestamp": "timestamp", + "UniqueContributors": 0.0 + }, + { + "Timestamp": "timestamp", + "UniqueContributors": 0.0 + } + ], "ResponseMetadata": { "HTTPHeaders": {}, "HTTPStatusCode": 200 } }, - "delete_metric_stream": { + "delete_insight_rule": { + "Failures": [], "ResponseMetadata": { "HTTPHeaders": {}, "HTTPStatusCode": 200 @@ -4138,8 +3504,8 @@ } } }, - "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_insight_rule[query]": { - "recorded-date": "19-09-2025, 21:45:12", + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_insight_rule[json]": { + "recorded-date": "19-09-2025, 21:45:14", "recorded-content": { "create_insight_rule": { "ResponseMetadata": { @@ -4278,8 +3644,8 @@ } } }, - "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_insight_rule[json]": { - "recorded-date": "19-09-2025, 21:45:14", + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_insight_rule[smithy-rpc-v2-cbor]": { + "recorded-date": "19-09-2025, 21:45:15", "recorded-content": { "create_insight_rule": { "ResponseMetadata": { @@ -4408,201 +3774,443 @@ "HTTPHeaders": {}, "HTTPStatusCode": 200 } - }, - "delete_insight_rule": { - "Failures": [], - "ResponseMetadata": { - "HTTPHeaders": {}, - "HTTPStatusCode": 200 - } + }, + "delete_insight_rule": { + "Failures": [], + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_anomaly_detector_lifecycle[query]": { + "recorded-date": "19-09-2025, 21:45:48", + "recorded-content": { + "create_anomaly_detector": { + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "describe_anomaly_detector": { + "AnomalyDetectors": [ + { + "Configuration": { + "ExcludedTimeRanges": [] + }, + "Dimensions": [ + { + "Name": "DimensionName", + "Value": "DimensionValue" + } + ], + "MetricName": "MyMetric", + "Namespace": "MyNamespace", + "SingleMetricAnomalyDetector": { + "AccountId": "111111111111", + "Dimensions": [ + { + "Name": "DimensionName", + "Value": "DimensionValue" + } + ], + "MetricName": "MyMetric", + "Namespace": "MyNamespace", + "Stat": "Sum" + }, + "Stat": "Sum", + "StateValue": "PENDING_TRAINING" + } + ], + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "delete_anomaly_detector": { + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_anomaly_detector_lifecycle[json]": { + "recorded-date": "19-09-2025, 21:45:48", + "recorded-content": { + "create_anomaly_detector": { + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "describe_anomaly_detector": { + "AnomalyDetectors": [ + { + "Configuration": { + "ExcludedTimeRanges": [] + }, + "Dimensions": [ + { + "Name": "DimensionName", + "Value": "DimensionValue" + } + ], + "MetricName": "MyMetric", + "Namespace": "MyNamespace", + "SingleMetricAnomalyDetector": { + "AccountId": "111111111111", + "Dimensions": [ + { + "Name": "DimensionName", + "Value": "DimensionValue" + } + ], + "MetricName": "MyMetric", + "Namespace": "MyNamespace", + "Stat": "Sum" + }, + "Stat": "Sum", + "StateValue": "PENDING_TRAINING" + } + ], + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "delete_anomaly_detector": { + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_anomaly_detector_lifecycle[smithy-rpc-v2-cbor]": { + "recorded-date": "19-09-2025, 21:45:48", + "recorded-content": { + "create_anomaly_detector": { + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "describe_anomaly_detector": { + "AnomalyDetectors": [ + { + "Configuration": { + "ExcludedTimeRanges": [] + }, + "Dimensions": [ + { + "Name": "DimensionName", + "Value": "DimensionValue" + } + ], + "MetricName": "MyMetric", + "Namespace": "MyNamespace", + "SingleMetricAnomalyDetector": { + "AccountId": "111111111111", + "Dimensions": [ + { + "Name": "DimensionName", + "Value": "DimensionValue" + } + ], + "MetricName": "MyMetric", + "Namespace": "MyNamespace", + "Stat": "Sum" + }, + "Stat": "Sum", + "StateValue": "PENDING_TRAINING" + } + ], + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "delete_anomaly_detector": { + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_describe_minimal_metric_alarm[query]": { + "recorded-date": "19-09-2025, 21:47:20", + "recorded-content": { + "describe_minimal_metric_alarm": { + "CompositeAlarms": [], + "MetricAlarms": [ + { + "ActionsEnabled": true, + "AlarmActions": [], + "AlarmArn": "arn::cloudwatch::111111111111:alarm:", + "AlarmConfigurationUpdatedTimestamp": "timestamp", + "AlarmName": "", + "ComparisonOperator": "GreaterThanThreshold", + "Dimensions": [], + "EvaluationPeriods": 1, + "InsufficientDataActions": [], + "MetricName": "", + "Namespace": "", + "OKActions": [], + "Period": 10, + "StateReason": "Unchecked: Initial alarm creation", + "StateTransitionedTimestamp": "timestamp", + "StateUpdatedTimestamp": "timestamp", + "StateValue": "INSUFFICIENT_DATA", + "Statistic": "Sum", + "Threshold": 30.0 + } + ], + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } } } }, - "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_insight_rule[smithy-rpc-v2-cbor]": { - "recorded-date": "19-09-2025, 21:45:15", + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_describe_minimal_metric_alarm[json]": { + "recorded-date": "19-09-2025, 21:47:20", "recorded-content": { - "create_insight_rule": { - "ResponseMetadata": { - "HTTPHeaders": {}, - "HTTPStatusCode": 200 - } - }, - "describe_insight_rule": { - "InsightRules": [ + "describe_minimal_metric_alarm": { + "CompositeAlarms": [], + "MetricAlarms": [ { - "ApplyOnTransformedLogs": false, - "Definition": { - "Schema": { - "Name": "", - "Version": 1 - }, - "LogGroupNames": [ - "API-Gateway-Access-Logs*" - ], - "LogFormat": "CLF", - "Fields": { - "4": "IpAddress", - "7": "StatusCode" - }, - "Contribution": { - "Keys": [ - "IpAddress" - ], - "Filters": [ - { - "Match": "StatusCode", - "EqualTo": 200 - } - ] - }, - "AggregateOn": "Count" - }, - "ManagedRule": false, - "Name": "", - "Schema": "/1", - "State": "ENABLED" + "ActionsEnabled": true, + "AlarmActions": [], + "AlarmArn": "arn::cloudwatch::111111111111:alarm:", + "AlarmConfigurationUpdatedTimestamp": "timestamp", + "AlarmName": "", + "ComparisonOperator": "GreaterThanThreshold", + "Dimensions": [], + "EvaluationPeriods": 1, + "InsufficientDataActions": [], + "MetricName": "", + "Namespace": "", + "OKActions": [], + "Period": 10, + "StateReason": "Unchecked: Initial alarm creation", + "StateTransitionedTimestamp": "timestamp", + "StateUpdatedTimestamp": "timestamp", + "StateValue": "INSUFFICIENT_DATA", + "Statistic": "Sum", + "Threshold": 30.0 } ], "ResponseMetadata": { "HTTPHeaders": {}, "HTTPStatusCode": 200 } - }, - "disable_insight_rule": { - "Failures": [], - "ResponseMetadata": { - "HTTPHeaders": {}, - "HTTPStatusCode": 200 - } - }, - "enable_insight_rule": { - "Failures": [], + } + } + }, + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_describe_minimal_metric_alarm[smithy-rpc-v2-cbor]": { + "recorded-date": "19-09-2025, 21:47:21", + "recorded-content": { + "describe_minimal_metric_alarm": { + "CompositeAlarms": [], + "MetricAlarms": [ + { + "ActionsEnabled": true, + "AlarmActions": [], + "AlarmArn": "arn::cloudwatch::111111111111:alarm:", + "AlarmConfigurationUpdatedTimestamp": "timestamp", + "AlarmName": "", + "ComparisonOperator": "GreaterThanThreshold", + "Dimensions": [], + "EvaluationPeriods": 1, + "InsufficientDataActions": [], + "MetricName": "", + "Namespace": "", + "OKActions": [], + "Period": 10, + "StateReason": "Unchecked: Initial alarm creation", + "StateTransitionedTimestamp": "timestamp", + "StateUpdatedTimestamp": "timestamp", + "StateValue": "INSUFFICIENT_DATA", + "Statistic": "Sum", + "Threshold": 30.0 + } + ], "ResponseMetadata": { "HTTPHeaders": {}, "HTTPStatusCode": 200 } - }, - "get_insight_rule_report": { - "AggregateValue": 0.0, - "AggregationStatistic": "SampleCount", - "ApproximateUniqueCount": 0, - "Contributors": [], - "KeyLabels": [ - "IpAddress" - ], - "MetricDatapoints": [ - { - "Timestamp": "timestamp", - "UniqueContributors": 0.0 - }, + } + } + }, + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_get_metric_data_with_zero_and_labels[query]": { + "recorded-date": "19-09-2025, 22:46:59", + "recorded-content": { + "get_metric_data_with_zero_and_labels": { + "Messages": [], + "MetricDataResults": [ { - "Timestamp": "timestamp", - "UniqueContributors": 0.0 + "Id": "result_Average", + "Label": "metric1 Average", + "StatusCode": "Complete", + "Timestamps": "timestamp", + "Values": [ + 19.416666666666668 + ] }, { - "Timestamp": "timestamp", - "UniqueContributors": 0.0 + "Id": "result_Sum", + "Label": "metric1 Sum", + "StatusCode": "Complete", + "Timestamps": "timestamp", + "Values": [ + 116.5 + ] }, { - "Timestamp": "timestamp", - "UniqueContributors": 0.0 + "Id": "result_Minimum", + "Label": "metric1 Minimum", + "StatusCode": "Complete", + "Timestamps": "timestamp", + "Values": [ + 0.0 + ] }, { - "Timestamp": "timestamp", - "UniqueContributors": 0.0 - }, + "Id": "result_Maximum", + "Label": "metric1 Maximum", + "StatusCode": "Complete", + "Timestamps": "timestamp", + "Values": [ + 100.0 + ] + } + ], + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_get_metric_data_with_zero_and_labels[json]": { + "recorded-date": "19-09-2025, 22:47:00", + "recorded-content": { + "get_metric_data_with_zero_and_labels": { + "Messages": [], + "MetricDataResults": [ { - "Timestamp": "timestamp", - "UniqueContributors": 0.0 + "Id": "result_Average", + "Label": "metric1 Average", + "StatusCode": "Complete", + "Timestamps": "timestamp", + "Values": [ + 19.416666666666668 + ] }, { - "Timestamp": "timestamp", - "UniqueContributors": 0.0 + "Id": "result_Sum", + "Label": "metric1 Sum", + "StatusCode": "Complete", + "Timestamps": "timestamp", + "Values": [ + 116.5 + ] }, { - "Timestamp": "timestamp", - "UniqueContributors": 0.0 + "Id": "result_Minimum", + "Label": "metric1 Minimum", + "StatusCode": "Complete", + "Timestamps": "timestamp", + "Values": [ + 0.0 + ] }, { - "Timestamp": "timestamp", - "UniqueContributors": 0.0 - }, + "Id": "result_Maximum", + "Label": "metric1 Maximum", + "StatusCode": "Complete", + "Timestamps": "timestamp", + "Values": [ + 100.0 + ] + } + ], + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_get_metric_data_with_zero_and_labels[smithy-rpc-v2-cbor]": { + "recorded-date": "19-09-2025, 22:47:02", + "recorded-content": { + "get_metric_data_with_zero_and_labels": { + "Messages": [], + "MetricDataResults": [ { - "Timestamp": "timestamp", - "UniqueContributors": 0.0 + "Id": "result_Average", + "Label": "metric1 Average", + "StatusCode": "Complete", + "Timestamps": "timestamp", + "Values": [ + 19.416666666666668 + ] }, { - "Timestamp": "timestamp", - "UniqueContributors": 0.0 + "Id": "result_Sum", + "Label": "metric1 Sum", + "StatusCode": "Complete", + "Timestamps": "timestamp", + "Values": [ + 116.5 + ] }, { - "Timestamp": "timestamp", - "UniqueContributors": 0.0 + "Id": "result_Minimum", + "Label": "metric1 Minimum", + "StatusCode": "Complete", + "Timestamps": "timestamp", + "Values": [ + 0.0 + ] }, { - "Timestamp": "timestamp", - "UniqueContributors": 0.0 + "Id": "result_Maximum", + "Label": "metric1 Maximum", + "StatusCode": "Complete", + "Timestamps": "timestamp", + "Values": [ + 100.0 + ] } ], "ResponseMetadata": { "HTTPHeaders": {}, "HTTPStatusCode": 200 } - }, - "delete_insight_rule": { - "Failures": [], - "ResponseMetadata": { - "HTTPHeaders": {}, - "HTTPStatusCode": 200 - } } } }, - "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_anomaly_detector_lifecycle[query]": { - "recorded-date": "19-09-2025, 21:45:48", + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_get_metric_statistics[query]": { + "recorded-date": "19-09-2025, 22:47:57", "recorded-content": { - "create_anomaly_detector": { - "ResponseMetadata": { - "HTTPHeaders": {}, - "HTTPStatusCode": 200 - } - }, - "describe_anomaly_detector": { - "AnomalyDetectors": [ + "get_metric_statistics": { + "Datapoints": [ { - "Configuration": { - "ExcludedTimeRanges": [] - }, - "Dimensions": [ - { - "Name": "DimensionName", - "Value": "DimensionValue" - } - ], - "MetricName": "MyMetric", - "Namespace": "MyNamespace", - "SingleMetricAnomalyDetector": { - "AccountId": "111111111111", - "Dimensions": [ - { - "Name": "DimensionName", - "Value": "DimensionValue" - } - ], - "MetricName": "MyMetric", - "Namespace": "MyNamespace", - "Stat": "Sum" - }, - "Stat": "Sum", - "StateValue": "PENDING_TRAINING" + "Average": 4.5, + "Maximum": 9.0, + "Minimum": 0.0, + "SampleCount": 10.0, + "Sum": 45.0, + "Timestamp": "timestamp", + "Unit": "None" } ], - "ResponseMetadata": { - "HTTPHeaders": {}, - "HTTPStatusCode": 200 - } - }, - "delete_anomaly_detector": { + "Label": "metric", "ResponseMetadata": { "HTTPHeaders": {}, "HTTPStatusCode": 200 @@ -4610,51 +4218,74 @@ } } }, - "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_anomaly_detector_lifecycle[json]": { - "recorded-date": "19-09-2025, 21:45:48", + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_get_metric_statistics[json]": { + "recorded-date": "19-09-2025, 22:48:01", "recorded-content": { - "create_anomaly_detector": { + "get_metric_statistics": { + "Datapoints": [ + { + "Average": 4.5, + "Maximum": 9.0, + "Minimum": 0.0, + "SampleCount": 10.0, + "Sum": 45.0, + "Timestamp": "timestamp", + "Unit": "None" + } + ], + "Label": "metric", "ResponseMetadata": { "HTTPHeaders": {}, "HTTPStatusCode": 200 } - }, - "describe_anomaly_detector": { - "AnomalyDetectors": [ + } + } + }, + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_get_metric_statistics[smithy-rpc-v2-cbor]": { + "recorded-date": "19-09-2025, 22:48:04", + "recorded-content": { + "get_metric_statistics": { + "Datapoints": [ { - "Configuration": { - "ExcludedTimeRanges": [] - }, - "Dimensions": [ - { - "Name": "DimensionName", - "Value": "DimensionValue" - } - ], - "MetricName": "MyMetric", - "Namespace": "MyNamespace", - "SingleMetricAnomalyDetector": { - "AccountId": "111111111111", - "Dimensions": [ - { - "Name": "DimensionName", - "Value": "DimensionValue" - } - ], - "MetricName": "MyMetric", - "Namespace": "MyNamespace", - "Stat": "Sum" - }, - "Stat": "Sum", - "StateValue": "PENDING_TRAINING" + "Average": 4.5, + "Maximum": 9.0, + "Minimum": 0.0, + "SampleCount": 10.0, + "Sum": 45.0, + "Timestamp": "timestamp", + "Unit": "None" } ], + "Label": "metric", "ResponseMetadata": { "HTTPHeaders": {}, "HTTPStatusCode": 200 } - }, - "delete_anomaly_detector": { + } + } + }, + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_handle_different_units[query]": { + "recorded-date": "19-09-2025, 22:56:18", + "recorded-content": { + "get_metric_statistics_with_different_units": { + "Datapoints": [ + { + "Average": 10.0, + "Timestamp": "timestamp", + "Unit": "None" + }, + { + "Average": 5.0, + "Timestamp": "timestamp", + "Unit": "Count" + }, + { + "Average": 1.0, + "Timestamp": "timestamp", + "Unit": "Seconds" + } + ], + "Label": "m-test", "ResponseMetadata": { "HTTPHeaders": {}, "HTTPStatusCode": 200 @@ -4662,51 +4293,57 @@ } } }, - "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_anomaly_detector_lifecycle[smithy-rpc-v2-cbor]": { - "recorded-date": "19-09-2025, 21:45:48", + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_handle_different_units[json]": { + "recorded-date": "19-09-2025, 22:56:20", "recorded-content": { - "create_anomaly_detector": { + "get_metric_statistics_with_different_units": { + "Datapoints": [ + { + "Average": 10.0, + "Timestamp": "timestamp", + "Unit": "None" + }, + { + "Average": 5.0, + "Timestamp": "timestamp", + "Unit": "Count" + }, + { + "Average": 1.0, + "Timestamp": "timestamp", + "Unit": "Seconds" + } + ], + "Label": "m-test", "ResponseMetadata": { "HTTPHeaders": {}, "HTTPStatusCode": 200 } - }, - "describe_anomaly_detector": { - "AnomalyDetectors": [ + } + } + }, + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_handle_different_units[smithy-rpc-v2-cbor]": { + "recorded-date": "19-09-2025, 22:56:22", + "recorded-content": { + "get_metric_statistics_with_different_units": { + "Datapoints": [ { - "Configuration": { - "ExcludedTimeRanges": [] - }, - "Dimensions": [ - { - "Name": "DimensionName", - "Value": "DimensionValue" - } - ], - "MetricName": "MyMetric", - "Namespace": "MyNamespace", - "SingleMetricAnomalyDetector": { - "AccountId": "111111111111", - "Dimensions": [ - { - "Name": "DimensionName", - "Value": "DimensionValue" - } - ], - "MetricName": "MyMetric", - "Namespace": "MyNamespace", - "Stat": "Sum" - }, - "Stat": "Sum", - "StateValue": "PENDING_TRAINING" + "Average": 10.0, + "Timestamp": "timestamp", + "Unit": "None" + }, + { + "Average": 5.0, + "Timestamp": "timestamp", + "Unit": "Count" + }, + { + "Average": 1.0, + "Timestamp": "timestamp", + "Unit": "Seconds" } ], - "ResponseMetadata": { - "HTTPHeaders": {}, - "HTTPStatusCode": 200 - } - }, - "delete_anomaly_detector": { + "Label": "m-test", "ResponseMetadata": { "HTTPHeaders": {}, "HTTPStatusCode": 200 @@ -4714,32 +4351,20 @@ } } }, - "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_describe_minimal_metric_alarm[query]": { - "recorded-date": "19-09-2025, 21:47:20", + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_get_metric_data_with_different_units[query]": { + "recorded-date": "19-09-2025, 22:57:24", "recorded-content": { - "describe_minimal_metric_alarm": { - "CompositeAlarms": [], - "MetricAlarms": [ + "get_metric_data_with_different_units": { + "Messages": [], + "MetricDataResults": [ { - "ActionsEnabled": true, - "AlarmActions": [], - "AlarmArn": "arn::cloudwatch::111111111111:alarm:", - "AlarmConfigurationUpdatedTimestamp": "timestamp", - "AlarmName": "", - "ComparisonOperator": "GreaterThanThreshold", - "Dimensions": [], - "EvaluationPeriods": 1, - "InsufficientDataActions": [], - "MetricName": "", - "Namespace": "", - "OKActions": [], - "Period": 10, - "StateReason": "Unchecked: Initial alarm creation", - "StateTransitionedTimestamp": "timestamp", - "StateUpdatedTimestamp": "timestamp", - "StateValue": "INSUFFICIENT_DATA", - "Statistic": "Sum", - "Threshold": 30.0 + "Id": "m1", + "Label": "m-test", + "StatusCode": "Complete", + "Timestamps": "timestamp", + "Values": [ + 1.0 + ] } ], "ResponseMetadata": { @@ -4749,32 +4374,20 @@ } } }, - "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_describe_minimal_metric_alarm[json]": { - "recorded-date": "19-09-2025, 21:47:20", + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_get_metric_data_with_different_units[json]": { + "recorded-date": "19-09-2025, 22:57:26", "recorded-content": { - "describe_minimal_metric_alarm": { - "CompositeAlarms": [], - "MetricAlarms": [ + "get_metric_data_with_different_units": { + "Messages": [], + "MetricDataResults": [ { - "ActionsEnabled": true, - "AlarmActions": [], - "AlarmArn": "arn::cloudwatch::111111111111:alarm:", - "AlarmConfigurationUpdatedTimestamp": "timestamp", - "AlarmName": "", - "ComparisonOperator": "GreaterThanThreshold", - "Dimensions": [], - "EvaluationPeriods": 1, - "InsufficientDataActions": [], - "MetricName": "", - "Namespace": "", - "OKActions": [], - "Period": 10, - "StateReason": "Unchecked: Initial alarm creation", - "StateTransitionedTimestamp": "timestamp", - "StateUpdatedTimestamp": "timestamp", - "StateValue": "INSUFFICIENT_DATA", - "Statistic": "Sum", - "Threshold": 30.0 + "Id": "m1", + "Label": "m-test", + "StatusCode": "Complete", + "Timestamps": "timestamp", + "Values": [ + 1.0 + ] } ], "ResponseMetadata": { @@ -4784,32 +4397,20 @@ } } }, - "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_describe_minimal_metric_alarm[smithy-rpc-v2-cbor]": { - "recorded-date": "19-09-2025, 21:47:21", + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_get_metric_data_with_different_units[smithy-rpc-v2-cbor]": { + "recorded-date": "19-09-2025, 22:57:28", "recorded-content": { - "describe_minimal_metric_alarm": { - "CompositeAlarms": [], - "MetricAlarms": [ + "get_metric_data_with_different_units": { + "Messages": [], + "MetricDataResults": [ { - "ActionsEnabled": true, - "AlarmActions": [], - "AlarmArn": "arn::cloudwatch::111111111111:alarm:", - "AlarmConfigurationUpdatedTimestamp": "timestamp", - "AlarmName": "", - "ComparisonOperator": "GreaterThanThreshold", - "Dimensions": [], - "EvaluationPeriods": 1, - "InsufficientDataActions": [], - "MetricName": "", - "Namespace": "", - "OKActions": [], - "Period": 10, - "StateReason": "Unchecked: Initial alarm creation", - "StateTransitionedTimestamp": "timestamp", - "StateUpdatedTimestamp": "timestamp", - "StateValue": "INSUFFICIENT_DATA", - "Statistic": "Sum", - "Threshold": 30.0 + "Id": "m1", + "Label": "m-test", + "StatusCode": "Complete", + "Timestamps": "timestamp", + "Values": [ + 1.0 + ] } ], "ResponseMetadata": { @@ -4819,46 +4420,25 @@ } } }, - "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_get_metric_data_with_zero_and_labels[query]": { - "recorded-date": "19-09-2025, 22:46:59", + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_get_metric_data_different_units_no_unit_in_query[query-metric_data0]": { + "recorded-date": "19-09-2025, 22:59:13", "recorded-content": { - "get_metric_data_with_zero_and_labels": { + "get_metric_data_with_no_unit_specified": { "Messages": [], "MetricDataResults": [ { - "Id": "result_Average", - "Label": "metric1 Average", - "StatusCode": "Complete", - "Timestamps": "timestamp", - "Values": [ - 19.416666666666668 - ] - }, - { - "Id": "result_Sum", - "Label": "metric1 Sum", - "StatusCode": "Complete", - "Timestamps": "timestamp", - "Values": [ - 116.5 - ] - }, - { - "Id": "result_Minimum", - "Label": "metric1 Minimum", - "StatusCode": "Complete", - "Timestamps": "timestamp", - "Values": [ - 0.0 - ] - }, - { - "Id": "result_Maximum", - "Label": "metric1 Maximum", + "Id": "m1", + "Label": "m-test", + "Messages": [ + { + "Code": "MultipleUnits", + "Value": "Multiple units returned: '[Milliseconds, Seconds]'" + } + ], "StatusCode": "Complete", "Timestamps": "timestamp", "Values": [ - 100.0 + 60000.0 ] } ], @@ -4869,46 +4449,25 @@ } } }, - "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_get_metric_data_with_zero_and_labels[json]": { - "recorded-date": "19-09-2025, 22:47:00", + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_get_metric_data_different_units_no_unit_in_query[query-metric_data1]": { + "recorded-date": "19-09-2025, 22:59:15", "recorded-content": { - "get_metric_data_with_zero_and_labels": { + "get_metric_data_with_no_unit_specified": { "Messages": [], "MetricDataResults": [ { - "Id": "result_Average", - "Label": "metric1 Average", - "StatusCode": "Complete", - "Timestamps": "timestamp", - "Values": [ - 19.416666666666668 - ] - }, - { - "Id": "result_Sum", - "Label": "metric1 Sum", - "StatusCode": "Complete", - "Timestamps": "timestamp", - "Values": [ - 116.5 - ] - }, - { - "Id": "result_Minimum", - "Label": "metric1 Minimum", - "StatusCode": "Complete", - "Timestamps": "timestamp", - "Values": [ - 0.0 - ] - }, - { - "Id": "result_Maximum", - "Label": "metric1 Maximum", + "Id": "m1", + "Label": "m-test", + "Messages": [ + { + "Code": "MultipleUnits", + "Value": "Multiple units returned: '[Milliseconds, Seconds]'" + } + ], "StatusCode": "Complete", "Timestamps": "timestamp", "Values": [ - 100.0 + 120000.0 ] } ], @@ -4919,46 +4478,83 @@ } } }, - "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_get_metric_data_with_zero_and_labels[smithy-rpc-v2-cbor]": { - "recorded-date": "19-09-2025, 22:47:02", + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_get_metric_data_different_units_no_unit_in_query[query-metric_data2]": { + "recorded-date": "19-09-2025, 22:59:17", "recorded-content": { - "get_metric_data_with_zero_and_labels": { + "get_metric_data_with_no_unit_specified": { "Messages": [], "MetricDataResults": [ { - "Id": "result_Average", - "Label": "metric1 Average", - "StatusCode": "Complete", - "Timestamps": "timestamp", - "Values": [ - 19.416666666666668 - ] - }, - { - "Id": "result_Sum", - "Label": "metric1 Sum", + "Id": "m1", + "Label": "m-test", + "Messages": [ + { + "Code": "MultipleUnits", + "Value": "Multiple units returned: '[Count, Milliseconds, Seconds]'" + } + ], "StatusCode": "Complete", "Timestamps": "timestamp", "Values": [ - 116.5 + 5.0 ] - }, + } + ], + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_get_metric_data_different_units_no_unit_in_query[json-metric_data0]": { + "recorded-date": "19-09-2025, 22:59:20", + "recorded-content": { + "get_metric_data_with_no_unit_specified": { + "Messages": [], + "MetricDataResults": [ { - "Id": "result_Minimum", - "Label": "metric1 Minimum", + "Id": "m1", + "Label": "m-test", + "Messages": [ + { + "Code": "MultipleUnits", + "Value": "Multiple units returned: '[Milliseconds, Seconds]'" + } + ], "StatusCode": "Complete", "Timestamps": "timestamp", "Values": [ - 0.0 + 60000.0 ] - }, + } + ], + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_get_metric_data_different_units_no_unit_in_query[json-metric_data1]": { + "recorded-date": "19-09-2025, 22:59:22", + "recorded-content": { + "get_metric_data_with_no_unit_specified": { + "Messages": [], + "MetricDataResults": [ { - "Id": "result_Maximum", - "Label": "metric1 Maximum", + "Id": "m1", + "Label": "m-test", + "Messages": [ + { + "Code": "MultipleUnits", + "Value": "Multiple units returned: '[Milliseconds, Seconds]'" + } + ], "StatusCode": "Complete", "Timestamps": "timestamp", "Values": [ - 100.0 + 120000.0 ] } ], @@ -4969,22 +4565,28 @@ } } }, - "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_get_metric_statistics[query]": { - "recorded-date": "19-09-2025, 22:47:57", + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_get_metric_data_different_units_no_unit_in_query[json-metric_data2]": { + "recorded-date": "19-09-2025, 22:59:24", "recorded-content": { - "get_metric_statistics": { - "Datapoints": [ + "get_metric_data_with_no_unit_specified": { + "Messages": [], + "MetricDataResults": [ { - "Average": 4.5, - "Maximum": 9.0, - "Minimum": 0.0, - "SampleCount": 10.0, - "Sum": 45.0, - "Timestamp": "timestamp", - "Unit": "None" + "Id": "m1", + "Label": "m-test", + "Messages": [ + { + "Code": "MultipleUnits", + "Value": "Multiple units returned: '[Count, Milliseconds, Seconds]'" + } + ], + "StatusCode": "Complete", + "Timestamps": "timestamp", + "Values": [ + 5.0 + ] } ], - "Label": "metric", "ResponseMetadata": { "HTTPHeaders": {}, "HTTPStatusCode": 200 @@ -4992,22 +4594,28 @@ } } }, - "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_get_metric_statistics[json]": { - "recorded-date": "19-09-2025, 22:48:01", + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_get_metric_data_different_units_no_unit_in_query[smithy-rpc-v2-cbor-metric_data0]": { + "recorded-date": "19-09-2025, 22:59:27", "recorded-content": { - "get_metric_statistics": { - "Datapoints": [ + "get_metric_data_with_no_unit_specified": { + "Messages": [], + "MetricDataResults": [ { - "Average": 4.5, - "Maximum": 9.0, - "Minimum": 0.0, - "SampleCount": 10.0, - "Sum": 45.0, - "Timestamp": "timestamp", - "Unit": "None" + "Id": "m1", + "Label": "m-test", + "Messages": [ + { + "Code": "MultipleUnits", + "Value": "Multiple units returned: '[Milliseconds, Seconds]'" + } + ], + "StatusCode": "Complete", + "Timestamps": "timestamp", + "Values": [ + 60000.0 + ] } ], - "Label": "metric", "ResponseMetadata": { "HTTPHeaders": {}, "HTTPStatusCode": 200 @@ -5015,22 +4623,28 @@ } } }, - "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_get_metric_statistics[smithy-rpc-v2-cbor]": { - "recorded-date": "19-09-2025, 22:48:04", + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_get_metric_data_different_units_no_unit_in_query[smithy-rpc-v2-cbor-metric_data1]": { + "recorded-date": "19-09-2025, 22:59:29", "recorded-content": { - "get_metric_statistics": { - "Datapoints": [ + "get_metric_data_with_no_unit_specified": { + "Messages": [], + "MetricDataResults": [ { - "Average": 4.5, - "Maximum": 9.0, - "Minimum": 0.0, - "SampleCount": 10.0, - "Sum": 45.0, - "Timestamp": "timestamp", - "Unit": "None" + "Id": "m1", + "Label": "m-test", + "Messages": [ + { + "Code": "MultipleUnits", + "Value": "Multiple units returned: '[Milliseconds, Seconds]'" + } + ], + "StatusCode": "Complete", + "Timestamps": "timestamp", + "Values": [ + 120000.0 + ] } ], - "Label": "metric", "ResponseMetadata": { "HTTPHeaders": {}, "HTTPStatusCode": 200 @@ -5038,28 +4652,28 @@ } } }, - "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_handle_different_units[query]": { - "recorded-date": "19-09-2025, 22:56:18", + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_get_metric_data_different_units_no_unit_in_query[smithy-rpc-v2-cbor-metric_data2]": { + "recorded-date": "19-09-2025, 22:59:31", "recorded-content": { - "get_metric_statistics_with_different_units": { - "Datapoints": [ - { - "Average": 10.0, - "Timestamp": "timestamp", - "Unit": "None" - }, - { - "Average": 5.0, - "Timestamp": "timestamp", - "Unit": "Count" - }, + "get_metric_data_with_no_unit_specified": { + "Messages": [], + "MetricDataResults": [ { - "Average": 1.0, - "Timestamp": "timestamp", - "Unit": "Seconds" + "Id": "m1", + "Label": "m-test", + "Messages": [ + { + "Code": "MultipleUnits", + "Value": "Multiple units returned: '[Count, Milliseconds, Seconds]'" + } + ], + "StatusCode": "Complete", + "Timestamps": "timestamp", + "Values": [ + 5.0 + ] } ], - "Label": "m-test", "ResponseMetadata": { "HTTPHeaders": {}, "HTTPStatusCode": 200 @@ -5067,28 +4681,31 @@ } } }, - "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_handle_different_units[json]": { - "recorded-date": "19-09-2025, 22:56:20", + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_label_generation[query-input_pairs0]": { + "recorded-date": "19-09-2025, 23:00:36", "recorded-content": { - "get_metric_statistics_with_different_units": { - "Datapoints": [ - { - "Average": 10.0, - "Timestamp": "timestamp", - "Unit": "None" - }, + "label_generation": { + "Messages": [], + "MetricDataResults": [ { - "Average": 5.0, - "Timestamp": "timestamp", - "Unit": "Count" + "Id": "result_Sum_60_Seconds", + "Label": "metric1 Sum 60", + "StatusCode": "Complete", + "Timestamps": "timestamp", + "Values": [ + 109.0 + ] }, { - "Average": 1.0, - "Timestamp": "timestamp", - "Unit": "Seconds" + "Id": "result_Minimum_30_Seconds", + "Label": "metric1 Minimum 30", + "StatusCode": "Complete", + "Timestamps": "timestamp", + "Values": [ + 0.0 + ] } ], - "Label": "m-test", "ResponseMetadata": { "HTTPHeaders": {}, "HTTPStatusCode": 200 @@ -5096,28 +4713,31 @@ } } }, - "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_handle_different_units[smithy-rpc-v2-cbor]": { - "recorded-date": "19-09-2025, 22:56:22", + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_label_generation[query-input_pairs1]": { + "recorded-date": "19-09-2025, 23:00:37", "recorded-content": { - "get_metric_statistics_with_different_units": { - "Datapoints": [ - { - "Average": 10.0, - "Timestamp": "timestamp", - "Unit": "None" - }, + "label_generation": { + "Messages": [], + "MetricDataResults": [ { - "Average": 5.0, - "Timestamp": "timestamp", - "Unit": "Count" + "Id": "result_Sum_60_Seconds", + "Label": "metric1 Sum", + "StatusCode": "Complete", + "Timestamps": "timestamp", + "Values": [ + 109.0 + ] }, { - "Average": 1.0, - "Timestamp": "timestamp", - "Unit": "Seconds" + "Id": "result_Minimum_60_Seconds", + "Label": "metric1 Minimum", + "StatusCode": "Complete", + "Timestamps": "timestamp", + "Values": [ + 0.0 + ] } ], - "Label": "m-test", "ResponseMetadata": { "HTTPHeaders": {}, "HTTPStatusCode": 200 @@ -5125,19 +4745,28 @@ } } }, - "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_get_metric_data_with_different_units[query]": { - "recorded-date": "19-09-2025, 22:57:24", + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_label_generation[query-input_pairs2]": { + "recorded-date": "19-09-2025, 23:00:39", "recorded-content": { - "get_metric_data_with_different_units": { + "label_generation": { "Messages": [], "MetricDataResults": [ { - "Id": "m1", - "Label": "m-test", + "Id": "result_Sum_60_Seconds", + "Label": "metric1 60", "StatusCode": "Complete", "Timestamps": "timestamp", "Values": [ - 1.0 + 109.0 + ] + }, + { + "Id": "result_Sum_30_Seconds", + "Label": "metric1 30", + "StatusCode": "Complete", + "Timestamps": "timestamp", + "Values": [ + 109.0 ] } ], @@ -5148,20 +4777,27 @@ } } }, - "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_get_metric_data_with_different_units[json]": { - "recorded-date": "19-09-2025, 22:57:26", + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_label_generation[query-input_pairs3]": { + "recorded-date": "19-09-2025, 23:00:40", "recorded-content": { - "get_metric_data_with_different_units": { + "label_generation": { "Messages": [], "MetricDataResults": [ { - "Id": "m1", - "Label": "m-test", + "Id": "result_Sum_60_Seconds", + "Label": "metric1 Sum 60", "StatusCode": "Complete", "Timestamps": "timestamp", "Values": [ - 1.0 + 109.0 ] + }, + { + "Id": "result_Minimum_30_Milliseconds", + "Label": "metric1 Minimum 30", + "StatusCode": "Complete", + "Timestamps": "timestamp", + "Values": [] } ], "ResponseMetadata": { @@ -5171,20 +4807,27 @@ } } }, - "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_get_metric_data_with_different_units[smithy-rpc-v2-cbor]": { - "recorded-date": "19-09-2025, 22:57:28", + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_label_generation[query-input_pairs4]": { + "recorded-date": "19-09-2025, 23:00:42", "recorded-content": { - "get_metric_data_with_different_units": { + "label_generation": { "Messages": [], "MetricDataResults": [ { - "Id": "m1", - "Label": "m-test", + "Id": "result_Sum_60_Seconds", + "Label": "metric1 Sum", "StatusCode": "Complete", "Timestamps": "timestamp", "Values": [ - 1.0 + 109.0 ] + }, + { + "Id": "result_Minimum_60_Milliseconds", + "Label": "metric1 Minimum", + "StatusCode": "Complete", + "Timestamps": "timestamp", + "Values": [] } ], "ResponseMetadata": { @@ -5194,26 +4837,27 @@ } } }, - "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_get_metric_data_different_units_no_unit_in_query[query-metric_data0]": { - "recorded-date": "19-09-2025, 22:59:13", + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_label_generation[query-input_pairs5]": { + "recorded-date": "19-09-2025, 23:00:44", "recorded-content": { - "get_metric_data_with_no_unit_specified": { + "label_generation": { "Messages": [], "MetricDataResults": [ { - "Id": "m1", - "Label": "m-test", - "Messages": [ - { - "Code": "MultipleUnits", - "Value": "Multiple units returned: '[Milliseconds, Seconds]'" - } - ], + "Id": "result_Sum_60_Seconds", + "Label": "metric1 60", "StatusCode": "Complete", "Timestamps": "timestamp", "Values": [ - 60000.0 + 109.0 ] + }, + { + "Id": "result_Sum_30_Milliseconds", + "Label": "metric1 30", + "StatusCode": "Complete", + "Timestamps": "timestamp", + "Values": [] } ], "ResponseMetadata": { @@ -5223,26 +4867,27 @@ } } }, - "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_get_metric_data_different_units_no_unit_in_query[query-metric_data1]": { - "recorded-date": "19-09-2025, 22:59:15", + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_label_generation[query-input_pairs6]": { + "recorded-date": "19-09-2025, 23:00:45", "recorded-content": { - "get_metric_data_with_no_unit_specified": { + "label_generation": { "Messages": [], "MetricDataResults": [ { - "Id": "m1", - "Label": "m-test", - "Messages": [ - { - "Code": "MultipleUnits", - "Value": "Multiple units returned: '[Milliseconds, Seconds]'" - } - ], + "Id": "result_Sum_60_Seconds", + "Label": "metric1", "StatusCode": "Complete", "Timestamps": "timestamp", "Values": [ - 120000.0 + 109.0 ] + }, + { + "Id": "result_Sum_60_Milliseconds", + "Label": "metric1", + "StatusCode": "Complete", + "Timestamps": "timestamp", + "Values": [] } ], "ResponseMetadata": { @@ -5252,25 +4897,28 @@ } } }, - "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_get_metric_data_different_units_no_unit_in_query[query-metric_data2]": { - "recorded-date": "19-09-2025, 22:59:17", + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_label_generation[json-input_pairs0]": { + "recorded-date": "19-09-2025, 23:00:46", "recorded-content": { - "get_metric_data_with_no_unit_specified": { + "label_generation": { "Messages": [], "MetricDataResults": [ { - "Id": "m1", - "Label": "m-test", - "Messages": [ - { - "Code": "MultipleUnits", - "Value": "Multiple units returned: '[Count, Milliseconds, Seconds]'" - } - ], + "Id": "result_Sum_60_Seconds", + "Label": "metric1 Sum 60", "StatusCode": "Complete", "Timestamps": "timestamp", "Values": [ - 5.0 + 109.0 + ] + }, + { + "Id": "result_Minimum_30_Seconds", + "Label": "metric1 Minimum 30", + "StatusCode": "Complete", + "Timestamps": "timestamp", + "Values": [ + 0.0 ] } ], @@ -5281,25 +4929,28 @@ } } }, - "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_get_metric_data_different_units_no_unit_in_query[json-metric_data0]": { - "recorded-date": "19-09-2025, 22:59:20", + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_label_generation[json-input_pairs1]": { + "recorded-date": "19-09-2025, 23:00:47", "recorded-content": { - "get_metric_data_with_no_unit_specified": { + "label_generation": { "Messages": [], "MetricDataResults": [ { - "Id": "m1", - "Label": "m-test", - "Messages": [ - { - "Code": "MultipleUnits", - "Value": "Multiple units returned: '[Milliseconds, Seconds]'" - } - ], + "Id": "result_Sum_60_Seconds", + "Label": "metric1 Sum", "StatusCode": "Complete", "Timestamps": "timestamp", "Values": [ - 60000.0 + 109.0 + ] + }, + { + "Id": "result_Minimum_60_Seconds", + "Label": "metric1 Minimum", + "StatusCode": "Complete", + "Timestamps": "timestamp", + "Values": [ + 0.0 ] } ], @@ -5310,25 +4961,28 @@ } } }, - "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_get_metric_data_different_units_no_unit_in_query[json-metric_data1]": { - "recorded-date": "19-09-2025, 22:59:22", + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_label_generation[json-input_pairs2]": { + "recorded-date": "19-09-2025, 23:00:49", "recorded-content": { - "get_metric_data_with_no_unit_specified": { + "label_generation": { "Messages": [], "MetricDataResults": [ { - "Id": "m1", - "Label": "m-test", - "Messages": [ - { - "Code": "MultipleUnits", - "Value": "Multiple units returned: '[Milliseconds, Seconds]'" - } - ], + "Id": "result_Sum_60_Seconds", + "Label": "metric1 60", "StatusCode": "Complete", "Timestamps": "timestamp", "Values": [ - 120000.0 + 109.0 + ] + }, + { + "Id": "result_Sum_30_Seconds", + "Label": "metric1 30", + "StatusCode": "Complete", + "Timestamps": "timestamp", + "Values": [ + 109.0 ] } ], @@ -5339,26 +4993,27 @@ } } }, - "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_get_metric_data_different_units_no_unit_in_query[json-metric_data2]": { - "recorded-date": "19-09-2025, 22:59:24", + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_label_generation[json-input_pairs3]": { + "recorded-date": "19-09-2025, 23:00:50", "recorded-content": { - "get_metric_data_with_no_unit_specified": { + "label_generation": { "Messages": [], "MetricDataResults": [ { - "Id": "m1", - "Label": "m-test", - "Messages": [ - { - "Code": "MultipleUnits", - "Value": "Multiple units returned: '[Count, Milliseconds, Seconds]'" - } - ], + "Id": "result_Sum_60_Seconds", + "Label": "metric1 Sum 60", "StatusCode": "Complete", "Timestamps": "timestamp", "Values": [ - 5.0 + 109.0 ] + }, + { + "Id": "result_Minimum_30_Milliseconds", + "Label": "metric1 Minimum 30", + "StatusCode": "Complete", + "Timestamps": "timestamp", + "Values": [] } ], "ResponseMetadata": { @@ -5368,26 +5023,27 @@ } } }, - "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_get_metric_data_different_units_no_unit_in_query[smithy-rpc-v2-cbor-metric_data0]": { - "recorded-date": "19-09-2025, 22:59:27", + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_label_generation[json-input_pairs4]": { + "recorded-date": "19-09-2025, 23:00:52", "recorded-content": { - "get_metric_data_with_no_unit_specified": { + "label_generation": { "Messages": [], "MetricDataResults": [ { - "Id": "m1", - "Label": "m-test", - "Messages": [ - { - "Code": "MultipleUnits", - "Value": "Multiple units returned: '[Milliseconds, Seconds]'" - } - ], + "Id": "result_Sum_60_Seconds", + "Label": "metric1 Sum", "StatusCode": "Complete", "Timestamps": "timestamp", "Values": [ - 60000.0 + 109.0 ] + }, + { + "Id": "result_Minimum_60_Milliseconds", + "Label": "metric1 Minimum", + "StatusCode": "Complete", + "Timestamps": "timestamp", + "Values": [] } ], "ResponseMetadata": { @@ -5397,26 +5053,27 @@ } } }, - "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_get_metric_data_different_units_no_unit_in_query[smithy-rpc-v2-cbor-metric_data1]": { - "recorded-date": "19-09-2025, 22:59:29", + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_label_generation[json-input_pairs5]": { + "recorded-date": "19-09-2025, 23:00:53", "recorded-content": { - "get_metric_data_with_no_unit_specified": { + "label_generation": { "Messages": [], "MetricDataResults": [ { - "Id": "m1", - "Label": "m-test", - "Messages": [ - { - "Code": "MultipleUnits", - "Value": "Multiple units returned: '[Milliseconds, Seconds]'" - } - ], + "Id": "result_Sum_60_Seconds", + "Label": "metric1 60", "StatusCode": "Complete", "Timestamps": "timestamp", "Values": [ - 120000.0 + 109.0 ] + }, + { + "Id": "result_Sum_30_Milliseconds", + "Label": "metric1 30", + "StatusCode": "Complete", + "Timestamps": "timestamp", + "Values": [] } ], "ResponseMetadata": { @@ -5426,26 +5083,27 @@ } } }, - "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_get_metric_data_different_units_no_unit_in_query[smithy-rpc-v2-cbor-metric_data2]": { - "recorded-date": "19-09-2025, 22:59:31", - "recorded-content": { - "get_metric_data_with_no_unit_specified": { - "Messages": [], - "MetricDataResults": [ - { - "Id": "m1", - "Label": "m-test", - "Messages": [ - { - "Code": "MultipleUnits", - "Value": "Multiple units returned: '[Count, Milliseconds, Seconds]'" - } - ], + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_label_generation[json-input_pairs6]": { + "recorded-date": "19-09-2025, 23:00:55", + "recorded-content": { + "label_generation": { + "Messages": [], + "MetricDataResults": [ + { + "Id": "result_Sum_60_Seconds", + "Label": "metric1", "StatusCode": "Complete", "Timestamps": "timestamp", "Values": [ - 5.0 + 109.0 ] + }, + { + "Id": "result_Sum_60_Milliseconds", + "Label": "metric1", + "StatusCode": "Complete", + "Timestamps": "timestamp", + "Values": [] } ], "ResponseMetadata": { @@ -5455,8 +5113,8 @@ } } }, - "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_label_generation[query-input_pairs0]": { - "recorded-date": "19-09-2025, 23:00:36", + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_label_generation[smithy-rpc-v2-cbor-input_pairs0]": { + "recorded-date": "19-09-2025, 23:00:56", "recorded-content": { "label_generation": { "Messages": [], @@ -5487,8 +5145,8 @@ } } }, - "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_label_generation[query-input_pairs1]": { - "recorded-date": "19-09-2025, 23:00:37", + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_label_generation[smithy-rpc-v2-cbor-input_pairs1]": { + "recorded-date": "19-09-2025, 23:00:58", "recorded-content": { "label_generation": { "Messages": [], @@ -5519,8 +5177,8 @@ } } }, - "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_label_generation[query-input_pairs2]": { - "recorded-date": "19-09-2025, 23:00:39", + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_label_generation[smithy-rpc-v2-cbor-input_pairs2]": { + "recorded-date": "19-09-2025, 23:00:59", "recorded-content": { "label_generation": { "Messages": [], @@ -5551,8 +5209,8 @@ } } }, - "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_label_generation[query-input_pairs3]": { - "recorded-date": "19-09-2025, 23:00:40", + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_label_generation[smithy-rpc-v2-cbor-input_pairs3]": { + "recorded-date": "19-09-2025, 23:01:01", "recorded-content": { "label_generation": { "Messages": [], @@ -5581,8 +5239,8 @@ } } }, - "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_label_generation[query-input_pairs4]": { - "recorded-date": "19-09-2025, 23:00:42", + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_label_generation[smithy-rpc-v2-cbor-input_pairs4]": { + "recorded-date": "19-09-2025, 23:01:02", "recorded-content": { "label_generation": { "Messages": [], @@ -5611,8 +5269,8 @@ } } }, - "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_label_generation[query-input_pairs5]": { - "recorded-date": "19-09-2025, 23:00:44", + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_label_generation[smithy-rpc-v2-cbor-input_pairs5]": { + "recorded-date": "19-09-2025, 23:01:03", "recorded-content": { "label_generation": { "Messages": [], @@ -5641,8 +5299,8 @@ } } }, - "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_label_generation[query-input_pairs6]": { - "recorded-date": "19-09-2025, 23:00:45", + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_label_generation[smithy-rpc-v2-cbor-input_pairs6]": { + "recorded-date": "19-09-2025, 23:01:05", "recorded-content": { "label_generation": { "Messages": [], @@ -5671,63 +5329,223 @@ } } }, - "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_label_generation[json-input_pairs0]": { - "recorded-date": "19-09-2025, 23:00:46", + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_get_metric_with_null_dimensions[query]": { + "recorded-date": "19-09-2025, 23:02:11", "recorded-content": { - "label_generation": { + "get_metric_with_null_dimensions": { "Messages": [], "MetricDataResults": [ { - "Id": "result_Sum_60_Seconds", - "Label": "metric1 Sum 60", + "Id": "", + "Label": "", "StatusCode": "Complete", "Timestamps": "timestamp", - "Values": [ - 109.0 - ] - }, + "Values": [] + } + ], + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_get_metric_with_null_dimensions[json]": { + "recorded-date": "19-09-2025, 23:02:13", + "recorded-content": { + "get_metric_with_null_dimensions": { + "Messages": [], + "MetricDataResults": [ { - "Id": "result_Minimum_30_Seconds", - "Label": "metric1 Minimum 30", + "Id": "", + "Label": "", "StatusCode": "Complete", "Timestamps": "timestamp", - "Values": [ - 0.0 - ] + "Values": [] + } + ], + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_get_metric_with_null_dimensions[smithy-rpc-v2-cbor]": { + "recorded-date": "19-09-2025, 23:02:15", + "recorded-content": { + "get_metric_with_null_dimensions": { + "Messages": [], + "MetricDataResults": [ + { + "Id": "", + "Label": "", + "StatusCode": "Complete", + "Timestamps": "timestamp", + "Values": [] + } + ], + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_get_metric_with_no_results[query]": { + "recorded-date": "19-09-2025, 23:04:56", + "recorded-content": { + "result": { + "Messages": [], + "MetricDataResults": [ + { + "Id": "result", + "Label": "", + "StatusCode": "Complete", + "Timestamps": "timestamp", + "Values": [] + } + ], + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_get_metric_with_no_results[json]": { + "recorded-date": "19-09-2025, 23:05:05", + "recorded-content": { + "result": { + "Messages": [], + "MetricDataResults": [ + { + "Id": "result", + "Label": "", + "StatusCode": "Complete", + "Timestamps": "timestamp", + "Values": [] + } + ], + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_get_metric_with_no_results[smithy-rpc-v2-cbor]": { + "recorded-date": "19-09-2025, 23:05:13", + "recorded-content": { + "result": { + "Messages": [], + "MetricDataResults": [ + { + "Id": "result", + "Label": "", + "StatusCode": "Complete", + "Timestamps": "timestamp", + "Values": [] + } + ], + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_delete_alarm[query]": { + "recorded-date": "19-09-2025, 23:06:53", + "recorded-content": { + "describe-alarm": { + "CompositeAlarms": [], + "MetricAlarms": [ + { + "ActionsEnabled": true, + "AlarmActions": [], + "AlarmArn": "arn::cloudwatch::111111111111:alarm:", + "AlarmConfigurationUpdatedTimestamp": "timestamp", + "AlarmName": "", + "ComparisonOperator": "GreaterThanThreshold", + "Dimensions": [], + "EvaluationPeriods": 1, + "InsufficientDataActions": [], + "MetricName": "metric1", + "Namespace": "", + "OKActions": [], + "Period": 60, + "StateReason": "Unchecked: Initial alarm creation", + "StateTransitionedTimestamp": "timestamp", + "StateUpdatedTimestamp": "timestamp", + "StateValue": "INSUFFICIENT_DATA", + "Statistic": "Sum", + "Threshold": 30.0 + } + ], + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "delete-alarm": { + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "describe-after-delete": { + "CompositeAlarms": [], + "MetricAlarms": [], + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_delete_alarm[json]": { + "recorded-date": "19-09-2025, 23:06:54", + "recorded-content": { + "describe-alarm": { + "CompositeAlarms": [], + "MetricAlarms": [ + { + "ActionsEnabled": true, + "AlarmActions": [], + "AlarmArn": "arn::cloudwatch::111111111111:alarm:", + "AlarmConfigurationUpdatedTimestamp": "timestamp", + "AlarmName": "", + "ComparisonOperator": "GreaterThanThreshold", + "Dimensions": [], + "EvaluationPeriods": 1, + "InsufficientDataActions": [], + "MetricName": "metric1", + "Namespace": "", + "OKActions": [], + "Period": 60, + "StateReason": "Unchecked: Initial alarm creation", + "StateTransitionedTimestamp": "timestamp", + "StateUpdatedTimestamp": "timestamp", + "StateValue": "INSUFFICIENT_DATA", + "Statistic": "Sum", + "Threshold": 30.0 } ], "ResponseMetadata": { "HTTPHeaders": {}, "HTTPStatusCode": 200 } - } - } - }, - "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_label_generation[json-input_pairs1]": { - "recorded-date": "19-09-2025, 23:00:47", - "recorded-content": { - "label_generation": { - "Messages": [], - "MetricDataResults": [ - { - "Id": "result_Sum_60_Seconds", - "Label": "metric1 Sum", - "StatusCode": "Complete", - "Timestamps": "timestamp", - "Values": [ - 109.0 - ] - }, - { - "Id": "result_Minimum_60_Seconds", - "Label": "metric1 Minimum", - "StatusCode": "Complete", - "Timestamps": "timestamp", - "Values": [ - 0.0 - ] - } - ], + }, + "delete-alarm": { + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "describe-after-delete": { + "CompositeAlarms": [], + "MetricAlarms": [], "ResponseMetadata": { "HTTPHeaders": {}, "HTTPStatusCode": 200 @@ -5735,61 +5553,48 @@ } } }, - "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_label_generation[json-input_pairs2]": { - "recorded-date": "19-09-2025, 23:00:49", + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_delete_alarm[smithy-rpc-v2-cbor]": { + "recorded-date": "19-09-2025, 23:06:55", "recorded-content": { - "label_generation": { - "Messages": [], - "MetricDataResults": [ - { - "Id": "result_Sum_60_Seconds", - "Label": "metric1 60", - "StatusCode": "Complete", - "Timestamps": "timestamp", - "Values": [ - 109.0 - ] - }, + "describe-alarm": { + "CompositeAlarms": [], + "MetricAlarms": [ { - "Id": "result_Sum_30_Seconds", - "Label": "metric1 30", - "StatusCode": "Complete", - "Timestamps": "timestamp", - "Values": [ - 109.0 - ] + "ActionsEnabled": true, + "AlarmActions": [], + "AlarmArn": "arn::cloudwatch::111111111111:alarm:", + "AlarmConfigurationUpdatedTimestamp": "timestamp", + "AlarmName": "", + "ComparisonOperator": "GreaterThanThreshold", + "Dimensions": [], + "EvaluationPeriods": 1, + "InsufficientDataActions": [], + "MetricName": "metric1", + "Namespace": "", + "OKActions": [], + "Period": 60, + "StateReason": "Unchecked: Initial alarm creation", + "StateTransitionedTimestamp": "timestamp", + "StateUpdatedTimestamp": "timestamp", + "StateValue": "INSUFFICIENT_DATA", + "Statistic": "Sum", + "Threshold": 30.0 } ], "ResponseMetadata": { "HTTPHeaders": {}, "HTTPStatusCode": 200 } - } - } - }, - "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_label_generation[json-input_pairs3]": { - "recorded-date": "19-09-2025, 23:00:50", - "recorded-content": { - "label_generation": { - "Messages": [], - "MetricDataResults": [ - { - "Id": "result_Sum_60_Seconds", - "Label": "metric1 Sum 60", - "StatusCode": "Complete", - "Timestamps": "timestamp", - "Values": [ - 109.0 - ] - }, - { - "Id": "result_Minimum_30_Milliseconds", - "Label": "metric1 Minimum 30", - "StatusCode": "Complete", - "Timestamps": "timestamp", - "Values": [] - } - ], + }, + "delete-alarm": { + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "describe-after-delete": { + "CompositeAlarms": [], + "MetricAlarms": [], "ResponseMetadata": { "HTTPHeaders": {}, "HTTPStatusCode": 200 @@ -5797,57 +5602,58 @@ } } }, - "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_label_generation[json-input_pairs4]": { - "recorded-date": "19-09-2025, 23:00:52", + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_multiple_dimensions_statistics[query]": { + "recorded-date": "19-09-2025, 23:07:39", "recorded-content": { - "label_generation": { + "get-metric-stats-max": { "Messages": [], "MetricDataResults": [ { - "Id": "result_Sum_60_Seconds", - "Label": "metric1 Sum", + "Id": "result1", + "Label": "http.server.requests.count", "StatusCode": "Complete", "Timestamps": "timestamp", "Values": [ - 109.0 + 5.0 ] - }, - { - "Id": "result_Minimum_60_Milliseconds", - "Label": "metric1 Minimum", - "StatusCode": "Complete", - "Timestamps": "timestamp", - "Values": [] } ], "ResponseMetadata": { "HTTPHeaders": {}, "HTTPStatusCode": 200 } - } - } - }, - "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_label_generation[json-input_pairs5]": { - "recorded-date": "19-09-2025, 23:00:53", - "recorded-content": { - "label_generation": { - "Messages": [], - "MetricDataResults": [ - { - "Id": "result_Sum_60_Seconds", - "Label": "metric1 60", - "StatusCode": "Complete", - "Timestamps": "timestamp", - "Values": [ - 109.0 - ] - }, + }, + "list-metrics": { + "Metrics": [ { - "Id": "result_Sum_30_Milliseconds", - "Label": "metric1 30", - "StatusCode": "Complete", - "Timestamps": "timestamp", - "Values": [] + "Dimensions": [ + { + "Name": "error", + "Value": "none" + }, + { + "Name": "exception", + "Value": "none" + }, + { + "Name": "method", + "Value": "GET" + }, + { + "Name": "outcome", + "Value": "SUCCESS" + }, + { + "Name": "status", + "Value": "200" + }, + { + "Name": "uri", + "Value": "/greetings" + } + ], + "MetricName": "http.server.requests.count", + "Namespace": "" } ], "ResponseMetadata": { @@ -5857,59 +5663,58 @@ } } }, - "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_label_generation[json-input_pairs6]": { - "recorded-date": "19-09-2025, 23:00:55", + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_multiple_dimensions_statistics[json]": { + "recorded-date": "19-09-2025, 23:07:47", "recorded-content": { - "label_generation": { + "get-metric-stats-max": { "Messages": [], "MetricDataResults": [ { - "Id": "result_Sum_60_Seconds", - "Label": "metric1", + "Id": "result1", + "Label": "http.server.requests.count", "StatusCode": "Complete", "Timestamps": "timestamp", "Values": [ - 109.0 + 5.0 ] - }, - { - "Id": "result_Sum_60_Milliseconds", - "Label": "metric1", - "StatusCode": "Complete", - "Timestamps": "timestamp", - "Values": [] } ], "ResponseMetadata": { "HTTPHeaders": {}, "HTTPStatusCode": 200 } - } - } - }, - "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_label_generation[smithy-rpc-v2-cbor-input_pairs0]": { - "recorded-date": "19-09-2025, 23:00:56", - "recorded-content": { - "label_generation": { - "Messages": [], - "MetricDataResults": [ - { - "Id": "result_Sum_60_Seconds", - "Label": "metric1 Sum 60", - "StatusCode": "Complete", - "Timestamps": "timestamp", - "Values": [ - 109.0 - ] - }, + }, + "list-metrics": { + "Metrics": [ { - "Id": "result_Minimum_30_Seconds", - "Label": "metric1 Minimum 30", - "StatusCode": "Complete", - "Timestamps": "timestamp", - "Values": [ - 0.0 - ] + "Dimensions": [ + { + "Name": "error", + "Value": "none" + }, + { + "Name": "exception", + "Value": "none" + }, + { + "Name": "method", + "Value": "GET" + }, + { + "Name": "outcome", + "Value": "SUCCESS" + }, + { + "Name": "status", + "Value": "200" + }, + { + "Name": "uri", + "Value": "/greetings" + } + ], + "MetricName": "http.server.requests.count", + "Namespace": "" } ], "ResponseMetadata": { @@ -5919,29 +5724,58 @@ } } }, - "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_label_generation[smithy-rpc-v2-cbor-input_pairs1]": { - "recorded-date": "19-09-2025, 23:00:58", + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_multiple_dimensions_statistics[smithy-rpc-v2-cbor]": { + "recorded-date": "19-09-2025, 23:07:59", "recorded-content": { - "label_generation": { + "get-metric-stats-max": { "Messages": [], "MetricDataResults": [ { - "Id": "result_Sum_60_Seconds", - "Label": "metric1 Sum", + "Id": "result1", + "Label": "http.server.requests.count", "StatusCode": "Complete", "Timestamps": "timestamp", "Values": [ - 109.0 + 5.0 ] - }, + } + ], + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "list-metrics": { + "Metrics": [ { - "Id": "result_Minimum_60_Seconds", - "Label": "metric1 Minimum", - "StatusCode": "Complete", - "Timestamps": "timestamp", - "Values": [ - 0.0 - ] + "Dimensions": [ + { + "Name": "error", + "Value": "none" + }, + { + "Name": "exception", + "Value": "none" + }, + { + "Name": "method", + "Value": "GET" + }, + { + "Name": "outcome", + "Value": "SUCCESS" + }, + { + "Name": "status", + "Value": "200" + }, + { + "Name": "uri", + "Value": "/greetings" + } + ], + "MetricName": "http.server.requests.count", + "Namespace": "" } ], "ResponseMetadata": { @@ -5951,31 +5785,34 @@ } } }, - "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_label_generation[smithy-rpc-v2-cbor-input_pairs2]": { - "recorded-date": "19-09-2025, 23:00:59", + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_invalid_amount_of_datapoints[query]": { + "recorded-date": "19-09-2025, 23:08:52", "recorded-content": { - "label_generation": { - "Messages": [], - "MetricDataResults": [ - { - "Id": "result_Sum_60_Seconds", - "Label": "metric1 60", - "StatusCode": "Complete", - "Timestamps": "timestamp", - "Values": [ - 109.0 - ] - }, - { - "Id": "result_Sum_30_Seconds", - "Label": "metric1 30", - "StatusCode": "Complete", - "Timestamps": "timestamp", - "Values": [ - 109.0 - ] - } - ], + "error-invalid-amount-datapoints": { + "Error": { + "Code": "InvalidParameterCombination", + "Message": "You have requested up to 86400 datapoints, which exceeds the limit of 1440. You may reduce the datapoints requested by increasing Period, or decreasing the time range.", + "Type": "Sender" + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + }, + "error-invalid-time-frame": { + "Error": { + "Code": "InvalidParameterValue", + "Message": "The parameter StartTime must be less than the parameter EndTime.", + "Type": "Sender" + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + }, + "get-metric-statitics": { + "Datapoints": [], + "Label": "metric_name", "ResponseMetadata": { "HTTPHeaders": {}, "HTTPStatusCode": 200 @@ -5983,29 +5820,38 @@ } } }, - "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_label_generation[smithy-rpc-v2-cbor-input_pairs3]": { - "recorded-date": "19-09-2025, 23:01:01", + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_invalid_amount_of_datapoints[json]": { + "recorded-date": "19-09-2025, 23:08:53", "recorded-content": { - "label_generation": { - "Messages": [], - "MetricDataResults": [ - { - "Id": "result_Sum_60_Seconds", - "Label": "metric1 Sum 60", - "StatusCode": "Complete", - "Timestamps": "timestamp", - "Values": [ - 109.0 - ] - }, - { - "Id": "result_Minimum_30_Milliseconds", - "Label": "metric1 Minimum 30", - "StatusCode": "Complete", - "Timestamps": "timestamp", - "Values": [] - } - ], + "error-invalid-amount-datapoints": { + "Error": { + "Code": "InvalidParameterCombination", + "Message": "You have requested up to 86400 datapoints, which exceeds the limit of 1440. You may reduce the datapoints requested by increasing Period, or decreasing the time range.", + "QueryErrorCode": "InvalidParameterCombinationException", + "Type": "Sender" + }, + "message": "You have requested up to 86400 datapoints, which exceeds the limit of 1440. You may reduce the datapoints requested by increasing Period, or decreasing the time range.", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + }, + "error-invalid-time-frame": { + "Error": { + "Code": "InvalidParameterValue", + "Message": "The parameter StartTime must be less than the parameter EndTime.", + "QueryErrorCode": "InvalidParameterValueException", + "Type": "Sender" + }, + "message": "The parameter StartTime must be less than the parameter EndTime.", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + }, + "get-metric-statitics": { + "Datapoints": [], + "Label": "metric_name", "ResponseMetadata": { "HTTPHeaders": {}, "HTTPStatusCode": 200 @@ -6013,57 +5859,125 @@ } } }, - "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_label_generation[smithy-rpc-v2-cbor-input_pairs4]": { - "recorded-date": "19-09-2025, 23:01:02", + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_invalid_amount_of_datapoints[smithy-rpc-v2-cbor]": { + "recorded-date": "19-09-2025, 23:08:54", "recorded-content": { - "label_generation": { - "Messages": [], - "MetricDataResults": [ - { - "Id": "result_Sum_60_Seconds", - "Label": "metric1 Sum", - "StatusCode": "Complete", - "Timestamps": "timestamp", - "Values": [ - 109.0 - ] - }, + "error-invalid-amount-datapoints": { + "Error": { + "Code": "InvalidParameterCombination", + "Message": "You have requested up to 86400 datapoints, which exceeds the limit of 1440. You may reduce the datapoints requested by increasing Period, or decreasing the time range.", + "QueryErrorCode": "InvalidParameterCombinationException", + "Type": "Sender" + }, + "message": "You have requested up to 86400 datapoints, which exceeds the limit of 1440. You may reduce the datapoints requested by increasing Period, or decreasing the time range.", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + }, + "error-invalid-time-frame": { + "Error": { + "Code": "InvalidParameterValue", + "Message": "The parameter StartTime must be less than the parameter EndTime.", + "QueryErrorCode": "InvalidParameterValueException", + "Type": "Sender" + }, + "message": "The parameter StartTime must be less than the parameter EndTime.", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + }, + "get-metric-statitics": { + "Datapoints": [], + "Label": "metric_name", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_set_alarm[query]": { + "recorded-date": "22-09-2025, 19:14:19", + "recorded-content": { + "triggered-alarm": { + "CompositeAlarms": [], + "MetricAlarms": [ { - "Id": "result_Minimum_60_Milliseconds", - "Label": "metric1 Minimum", - "StatusCode": "Complete", - "Timestamps": "timestamp", - "Values": [] + "ActionsEnabled": true, + "AlarmActions": [ + "arn::sns::111111111111:" + ], + "AlarmArn": "arn::cloudwatch::111111111111:alarm:", + "AlarmConfigurationUpdatedTimestamp": "timestamp", + "AlarmDescription": "Test Alarm when CPU exceeds 50 percent", + "AlarmName": "", + "ComparisonOperator": "GreaterThanThreshold", + "Dimensions": [ + { + "Name": "InstanceId", + "Value": "i-0317828c84edbe100" + } + ], + "EvaluationPeriods": 2, + "InsufficientDataActions": [], + "MetricName": "CPUUtilization-3", + "Namespace": "", + "OKActions": [ + "" + ], + "Period": 300, + "StateReason": "testing alarm", + "StateTransitionedTimestamp": "timestamp", + "StateUpdatedTimestamp": "timestamp", + "StateValue": "ALARM", + "Statistic": "Average", + "Threshold": 50.0, + "TreatMissingData": "ignore", + "Unit": "Percent" } ], "ResponseMetadata": { "HTTPHeaders": {}, "HTTPStatusCode": 200 } - } - } - }, - "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_label_generation[smithy-rpc-v2-cbor-input_pairs5]": { - "recorded-date": "19-09-2025, 23:01:03", - "recorded-content": { - "label_generation": { - "Messages": [], - "MetricDataResults": [ - { - "Id": "result_Sum_60_Seconds", - "Label": "metric1 60", - "StatusCode": "Complete", - "Timestamps": "timestamp", - "Values": [ - 109.0 - ] - }, + }, + "reset-alarm": { + "CompositeAlarms": [], + "MetricAlarms": [ { - "Id": "result_Sum_30_Milliseconds", - "Label": "metric1 30", - "StatusCode": "Complete", - "Timestamps": "timestamp", - "Values": [] + "ActionsEnabled": true, + "AlarmActions": [ + "arn::sns::111111111111:" + ], + "AlarmArn": "arn::cloudwatch::111111111111:alarm:", + "AlarmConfigurationUpdatedTimestamp": "timestamp", + "AlarmDescription": "Test Alarm when CPU exceeds 50 percent", + "AlarmName": "", + "ComparisonOperator": "GreaterThanThreshold", + "Dimensions": [ + { + "Name": "InstanceId", + "Value": "i-0317828c84edbe100" + } + ], + "EvaluationPeriods": 2, + "InsufficientDataActions": [], + "MetricName": "CPUUtilization-3", + "Namespace": "", + "OKActions": [ + "" + ], + "Period": 300, + "StateReason": "resetting alarm", + "StateTransitionedTimestamp": "timestamp", + "StateUpdatedTimestamp": "timestamp", + "StateValue": "OK", + "Statistic": "Average", + "Threshold": 50.0, + "TreatMissingData": "ignore", + "Unit": "Percent" } ], "ResponseMetadata": { @@ -6073,48 +5987,86 @@ } } }, - "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_label_generation[smithy-rpc-v2-cbor-input_pairs6]": { - "recorded-date": "19-09-2025, 23:01:05", + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_set_alarm[json]": { + "recorded-date": "22-09-2025, 19:14:26", "recorded-content": { - "label_generation": { - "Messages": [], - "MetricDataResults": [ - { - "Id": "result_Sum_60_Seconds", - "Label": "metric1", - "StatusCode": "Complete", - "Timestamps": "timestamp", - "Values": [ - 109.0 - ] - }, + "triggered-alarm": { + "CompositeAlarms": [], + "MetricAlarms": [ { - "Id": "result_Sum_60_Milliseconds", - "Label": "metric1", - "StatusCode": "Complete", - "Timestamps": "timestamp", - "Values": [] + "ActionsEnabled": true, + "AlarmActions": [ + "arn::sns::111111111111:" + ], + "AlarmArn": "arn::cloudwatch::111111111111:alarm:", + "AlarmConfigurationUpdatedTimestamp": "timestamp", + "AlarmDescription": "Test Alarm when CPU exceeds 50 percent", + "AlarmName": "", + "ComparisonOperator": "GreaterThanThreshold", + "Dimensions": [ + { + "Name": "InstanceId", + "Value": "i-0317828c84edbe100" + } + ], + "EvaluationPeriods": 2, + "InsufficientDataActions": [], + "MetricName": "CPUUtilization-3", + "Namespace": "", + "OKActions": [ + "" + ], + "Period": 300, + "StateReason": "testing alarm", + "StateTransitionedTimestamp": "timestamp", + "StateUpdatedTimestamp": "timestamp", + "StateValue": "ALARM", + "Statistic": "Average", + "Threshold": 50.0, + "TreatMissingData": "ignore", + "Unit": "Percent" } ], "ResponseMetadata": { "HTTPHeaders": {}, "HTTPStatusCode": 200 } - } - } - }, - "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_get_metric_with_null_dimensions[query]": { - "recorded-date": "19-09-2025, 23:02:11", - "recorded-content": { - "get_metric_with_null_dimensions": { - "Messages": [], - "MetricDataResults": [ + }, + "reset-alarm": { + "CompositeAlarms": [], + "MetricAlarms": [ { - "Id": "", - "Label": "", - "StatusCode": "Complete", - "Timestamps": "timestamp", - "Values": [] + "ActionsEnabled": true, + "AlarmActions": [ + "arn::sns::111111111111:" + ], + "AlarmArn": "arn::cloudwatch::111111111111:alarm:", + "AlarmConfigurationUpdatedTimestamp": "timestamp", + "AlarmDescription": "Test Alarm when CPU exceeds 50 percent", + "AlarmName": "", + "ComparisonOperator": "GreaterThanThreshold", + "Dimensions": [ + { + "Name": "InstanceId", + "Value": "i-0317828c84edbe100" + } + ], + "EvaluationPeriods": 2, + "InsufficientDataActions": [], + "MetricName": "CPUUtilization-3", + "Namespace": "", + "OKActions": [ + "" + ], + "Period": 300, + "StateReason": "resetting alarm", + "StateTransitionedTimestamp": "timestamp", + "StateUpdatedTimestamp": "timestamp", + "StateValue": "OK", + "Statistic": "Average", + "Threshold": 50.0, + "TreatMissingData": "ignore", + "Unit": "Percent" } ], "ResponseMetadata": { @@ -6124,39 +6076,86 @@ } } }, - "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_get_metric_with_null_dimensions[json]": { - "recorded-date": "19-09-2025, 23:02:13", + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_set_alarm[smithy-rpc-v2-cbor]": { + "recorded-date": "22-09-2025, 19:14:33", "recorded-content": { - "get_metric_with_null_dimensions": { - "Messages": [], - "MetricDataResults": [ + "triggered-alarm": { + "CompositeAlarms": [], + "MetricAlarms": [ { - "Id": "", - "Label": "", - "StatusCode": "Complete", - "Timestamps": "timestamp", - "Values": [] + "ActionsEnabled": true, + "AlarmActions": [ + "arn::sns::111111111111:" + ], + "AlarmArn": "arn::cloudwatch::111111111111:alarm:", + "AlarmConfigurationUpdatedTimestamp": "timestamp", + "AlarmDescription": "Test Alarm when CPU exceeds 50 percent", + "AlarmName": "", + "ComparisonOperator": "GreaterThanThreshold", + "Dimensions": [ + { + "Name": "InstanceId", + "Value": "i-0317828c84edbe100" + } + ], + "EvaluationPeriods": 2, + "InsufficientDataActions": [], + "MetricName": "CPUUtilization-3", + "Namespace": "", + "OKActions": [ + "" + ], + "Period": 300, + "StateReason": "testing alarm", + "StateTransitionedTimestamp": "timestamp", + "StateUpdatedTimestamp": "timestamp", + "StateValue": "ALARM", + "Statistic": "Average", + "Threshold": 50.0, + "TreatMissingData": "ignore", + "Unit": "Percent" } ], "ResponseMetadata": { "HTTPHeaders": {}, "HTTPStatusCode": 200 } - } - } - }, - "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_get_metric_with_null_dimensions[smithy-rpc-v2-cbor]": { - "recorded-date": "19-09-2025, 23:02:15", - "recorded-content": { - "get_metric_with_null_dimensions": { - "Messages": [], - "MetricDataResults": [ + }, + "reset-alarm": { + "CompositeAlarms": [], + "MetricAlarms": [ { - "Id": "", - "Label": "", - "StatusCode": "Complete", - "Timestamps": "timestamp", - "Values": [] + "ActionsEnabled": true, + "AlarmActions": [ + "arn::sns::111111111111:" + ], + "AlarmArn": "arn::cloudwatch::111111111111:alarm:", + "AlarmConfigurationUpdatedTimestamp": "timestamp", + "AlarmDescription": "Test Alarm when CPU exceeds 50 percent", + "AlarmName": "", + "ComparisonOperator": "GreaterThanThreshold", + "Dimensions": [ + { + "Name": "InstanceId", + "Value": "i-0317828c84edbe100" + } + ], + "EvaluationPeriods": 2, + "InsufficientDataActions": [], + "MetricName": "CPUUtilization-3", + "Namespace": "", + "OKActions": [ + "" + ], + "Period": 300, + "StateReason": "resetting alarm", + "StateTransitionedTimestamp": "timestamp", + "StateUpdatedTimestamp": "timestamp", + "StateValue": "OK", + "Statistic": "Average", + "Threshold": 50.0, + "TreatMissingData": "ignore", + "Unit": "Percent" } ], "ResponseMetadata": { @@ -6166,144 +6165,128 @@ } } }, - "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_get_metric_with_no_results[query]": { - "recorded-date": "19-09-2025, 23:04:56", + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_set_alarm_invalid_input[query]": { + "recorded-date": "22-09-2025, 19:16:47", "recorded-content": { - "result": { - "Messages": [], - "MetricDataResults": [ - { - "Id": "result", - "Label": "", - "StatusCode": "Complete", - "Timestamps": "timestamp", - "Values": [] - } - ], + "error-invalid-state": { + "Error": { + "Code": "ValidationError", + "Message": "1 validation error detected: Value 'INVALID' at 'stateValue' failed to satisfy constraint: Member must satisfy enum value set: [INSUFFICIENT_DATA, ALARM, OK]", + "Type": "Sender" + }, "ResponseMetadata": { "HTTPHeaders": {}, - "HTTPStatusCode": 200 + "HTTPStatusCode": 400 } - } - } - }, - "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_get_metric_with_no_results[json]": { - "recorded-date": "19-09-2025, 23:05:05", - "recorded-content": { - "result": { - "Messages": [], - "MetricDataResults": [ - { - "Id": "result", - "Label": "", - "StatusCode": "Complete", - "Timestamps": "timestamp", - "Values": [] - } - ], + }, + "error-resource-not-found": { + "Error": { + "Code": "ResourceNotFound", + "Type": "Sender" + }, "ResponseMetadata": { "HTTPHeaders": {}, - "HTTPStatusCode": 200 + "HTTPStatusCode": 404 } } } }, - "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_get_metric_with_no_results[smithy-rpc-v2-cbor]": { - "recorded-date": "19-09-2025, 23:05:13", + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_set_alarm_invalid_input[json]": { + "recorded-date": "22-09-2025, 19:16:48", "recorded-content": { - "result": { - "Messages": [], - "MetricDataResults": [ - { - "Id": "result", - "Label": "", - "StatusCode": "Complete", - "Timestamps": "timestamp", - "Values": [] - } - ], + "error-invalid-state": { + "Error": { + "Code": "ValidationError", + "Message": "1 validation error detected: Value 'INVALID' at 'stateValue' failed to satisfy constraint: Member must satisfy enum value set: [INSUFFICIENT_DATA, ALARM, OK]", + "QueryErrorCode": "ValidationException", + "Type": "Sender" + }, "ResponseMetadata": { "HTTPHeaders": {}, - "HTTPStatusCode": 200 + "HTTPStatusCode": 400 + } + }, + "error-resource-not-found": { + "Error": { + "Code": "ResourceNotFound", + "Message": "", + "QueryErrorCode": "ResourceNotFound", + "Type": "Sender" + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 404 } } } }, - "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_delete_alarm[query]": { - "recorded-date": "19-09-2025, 23:06:53", + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_set_alarm_invalid_input[smithy-rpc-v2-cbor]": { + "recorded-date": "22-09-2025, 19:16:48", "recorded-content": { - "describe-alarm": { - "CompositeAlarms": [], - "MetricAlarms": [ - { - "ActionsEnabled": true, - "AlarmActions": [], - "AlarmArn": "arn::cloudwatch::111111111111:alarm:", - "AlarmConfigurationUpdatedTimestamp": "timestamp", - "AlarmName": "", - "ComparisonOperator": "GreaterThanThreshold", - "Dimensions": [], - "EvaluationPeriods": 1, - "InsufficientDataActions": [], - "MetricName": "metric1", - "Namespace": "", - "OKActions": [], - "Period": 60, - "StateReason": "Unchecked: Initial alarm creation", - "StateTransitionedTimestamp": "timestamp", - "StateUpdatedTimestamp": "timestamp", - "StateValue": "INSUFFICIENT_DATA", - "Statistic": "Sum", - "Threshold": 30.0 - } - ], - "ResponseMetadata": { - "HTTPHeaders": {}, - "HTTPStatusCode": 200 - } - }, - "delete-alarm": { + "error-invalid-state": { + "Error": { + "Code": "ValidationError", + "Message": "1 validation error detected: Value 'INVALID' at 'stateValue' failed to satisfy constraint: Member must satisfy enum value set: [INSUFFICIENT_DATA, ALARM, OK]", + "QueryErrorCode": "ValidationException", + "Type": "Sender" + }, "ResponseMetadata": { "HTTPHeaders": {}, - "HTTPStatusCode": 200 + "HTTPStatusCode": 400 } }, - "describe-after-delete": { - "CompositeAlarms": [], - "MetricAlarms": [], + "error-resource-not-found": { + "Error": { + "Code": "ResourceNotFound", + "Message": "", + "QueryErrorCode": "ResourceNotFound", + "Type": "Sender" + }, "ResponseMetadata": { "HTTPHeaders": {}, - "HTTPStatusCode": 200 + "HTTPStatusCode": 404 } } } }, - "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_delete_alarm[json]": { - "recorded-date": "19-09-2025, 23:06:54", + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_put_metric_alarm": { + "recorded-date": "26-02-2026, 10:14:11", "recorded-content": { "describe-alarm": { "CompositeAlarms": [], "MetricAlarms": [ { "ActionsEnabled": true, - "AlarmActions": [], + "AlarmActions": [ + "arn::sns::111111111111:" + ], "AlarmArn": "arn::cloudwatch::111111111111:alarm:", "AlarmConfigurationUpdatedTimestamp": "timestamp", + "AlarmDescription": "testing cloudwatch alarms", "AlarmName": "", "ComparisonOperator": "GreaterThanThreshold", - "Dimensions": [], + "Dimensions": [ + { + "Name": "InstanceId", + "Value": "abc" + } + ], "EvaluationPeriods": 1, "InsufficientDataActions": [], - "MetricName": "metric1", + "MetricName": "my-metric1", "Namespace": "", - "OKActions": [], - "Period": 60, + "OKActions": [ + "arn::sns::111111111111:" + ], + "Period": 10, "StateReason": "Unchecked: Initial alarm creation", "StateTransitionedTimestamp": "timestamp", "StateUpdatedTimestamp": "timestamp", "StateValue": "INSUFFICIENT_DATA", - "Statistic": "Sum", - "Threshold": 30.0 + "Statistic": "Average", + "Threshold": 21.0, + "TreatMissingData": "ignore", + "Unit": "Seconds" } ], "ResponseMetadata": { @@ -6311,85 +6294,184 @@ "HTTPStatusCode": 200 } }, - "delete-alarm": { - "ResponseMetadata": { - "HTTPHeaders": {}, - "HTTPStatusCode": 200 + "alarm-triggered-sqs-msg": { + "AWSAccountId": "111111111111", + "ActionExecutedAfterMuteWindow": false, + "AlarmActions": [ + "arn::sns::111111111111:" + ], + "AlarmArn": "arn::cloudwatch::111111111111:alarm:", + "AlarmConfigurationUpdatedTimestamp": "date", + "AlarmDescription": "testing cloudwatch alarms", + "AlarmName": "", + "InsufficientDataActions": [], + "NewStateReason": "Threshold Crossed: 1 datapoint [21.5 (MM/DD/YY HH:MM:SS)] was greater than the threshold (21.0).", + "NewStateValue": "ALARM", + "OKActions": [ + "arn::sns::111111111111:" + ], + "OldStateValue": "INSUFFICIENT_DATA", + "Region": "", + "StateChangeTime": "date", + "Trigger": { + "ComparisonOperator": "GreaterThanThreshold", + "Dimensions": [ + { + "name": "InstanceId", + "value": "abc" + } + ], + "EvaluateLowSampleCountPercentile": "", + "EvaluationPeriods": 1, + "MetricName": "my-metric1", + "Namespace": "", + "Period": 10, + "Statistic": "AVERAGE", + "StatisticType": "Statistic", + "Threshold": 21.0, + "TreatMissingData": "ignore", + "Unit": "Seconds" } }, - "describe-after-delete": { - "CompositeAlarms": [], - "MetricAlarms": [], + "describe-alarm-history": { + "AlarmHistoryItems": [ + { + "AlarmName": "", + "AlarmType": "MetricAlarm", + "HistoryData": { + "version": "1.0", + "oldState": { + "stateValue": "INSUFFICIENT_DATA", + "stateReason": "Unchecked: Initial alarm creation" + }, + "newState": { + "stateValue": "ALARM", + "stateReason": "Threshold Crossed: 1 datapoint [21.5 (MM/DD/YY HH:MM:SS)] was greater than the threshold (21.0).", + "stateReasonData": { + "version": "1.0", + "queryDate": "date", + "startDate": "date", + "unit": "Seconds", + "statistic": "Average", + "period": 10, + "recentDatapoints": [ + 21.5 + ], + "threshold": 21.0, + "evaluatedDatapoints": [ + { + "timestamp": "date", + "sampleCount": 2.0, + "value": 21.5 + } + ] + } + } + }, + "HistoryItemType": "StateUpdate", + "HistorySummary": "Alarm updated from INSUFFICIENT_DATA to ALARM", + "Timestamp": "timestamp" + } + ], "ResponseMetadata": { "HTTPHeaders": {}, "HTTPStatusCode": 200 } - } - } - }, - "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_delete_alarm[smithy-rpc-v2-cbor]": { - "recorded-date": "19-09-2025, 23:06:55", - "recorded-content": { - "describe-alarm": { - "CompositeAlarms": [], + }, + "describe-alarms-for-metric": { "MetricAlarms": [ { "ActionsEnabled": true, - "AlarmActions": [], + "AlarmActions": [ + "arn::sns::111111111111:" + ], "AlarmArn": "arn::cloudwatch::111111111111:alarm:", "AlarmConfigurationUpdatedTimestamp": "timestamp", + "AlarmDescription": "testing cloudwatch alarms", "AlarmName": "", "ComparisonOperator": "GreaterThanThreshold", - "Dimensions": [], + "Dimensions": [ + { + "Name": "InstanceId", + "Value": "abc" + } + ], "EvaluationPeriods": 1, "InsufficientDataActions": [], - "MetricName": "metric1", + "MetricName": "my-metric1", "Namespace": "", - "OKActions": [], - "Period": 60, - "StateReason": "Unchecked: Initial alarm creation", + "OKActions": [ + "arn::sns::111111111111:" + ], + "Period": 10, + "StateReason": "Threshold Crossed: 1 datapoint [21.5 (MM/DD/YY HH:MM:SS)] was greater than the threshold (21.0).", + "StateReasonData": { + "version": "1.0", + "queryDate": "date", + "startDate": "date", + "unit": "Seconds", + "statistic": "Average", + "period": 10, + "recentDatapoints": [ + 21.5 + ], + "threshold": 21.0, + "evaluatedDatapoints": [ + { + "timestamp": "date", + "sampleCount": 2.0, + "value": 21.5 + } + ] + }, "StateTransitionedTimestamp": "timestamp", "StateUpdatedTimestamp": "timestamp", - "StateValue": "INSUFFICIENT_DATA", - "Statistic": "Sum", - "Threshold": 30.0 + "StateValue": "ALARM", + "Statistic": "Average", + "Threshold": 21.0, + "TreatMissingData": "ignore", + "Unit": "Seconds" } ], "ResponseMetadata": { "HTTPHeaders": {}, "HTTPStatusCode": 200 } - }, - "delete-alarm": { - "ResponseMetadata": { - "HTTPHeaders": {}, - "HTTPStatusCode": 200 - } - }, - "describe-after-delete": { - "CompositeAlarms": [], - "MetricAlarms": [], - "ResponseMetadata": { - "HTTPHeaders": {}, - "HTTPStatusCode": 200 - } } } }, - "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_multiple_dimensions_statistics[query]": { - "recorded-date": "19-09-2025, 23:07:39", + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_aws_sqs_metrics_created": { + "recorded-date": "26-02-2026, 12:06:25", "recorded-content": { - "get-metric-stats-max": { + "get_metric_data": { "Messages": [], "MetricDataResults": [ { - "Id": "result1", - "Label": "http.server.requests.count", + "Id": "sent", + "Label": "NumberOfMessagesSent", + "StatusCode": "Complete", + "Timestamps": "timestamp", + "Values": [ + 1.0 + ] + }, + { + "Id": "sent_size", + "Label": "SentMessageSize", "StatusCode": "Complete", "Timestamps": "timestamp", "Values": [ 5.0 ] + }, + { + "Id": "empty_receives", + "Label": "NumberOfEmptyReceives", + "StatusCode": "Complete", + "Timestamps": "timestamp", + "Values": [ + 1.0 + ] } ], "ResponseMetadata": { @@ -6397,37 +6479,26 @@ "HTTPStatusCode": 200 } }, - "list-metrics": { - "Metrics": [ + "get_metric_data_2": { + "Messages": [], + "MetricDataResults": [ { - "Dimensions": [ - { - "Name": "error", - "Value": "none" - }, - { - "Name": "exception", - "Value": "none" - }, - { - "Name": "method", - "Value": "GET" - }, - { - "Name": "outcome", - "Value": "SUCCESS" - }, - { - "Name": "status", - "Value": "200" - }, - { - "Name": "uri", - "Value": "/greetings" - } - ], - "MetricName": "http.server.requests.count", - "Namespace": "" + "Id": "num_msg_received", + "Label": "NumberOfMessagesReceived", + "StatusCode": "Complete", + "Timestamps": "timestamp", + "Values": [ + 1.0 + ] + }, + { + "Id": "num_msg_deleted", + "Label": "NumberOfMessagesDeleted", + "StatusCode": "Complete", + "Timestamps": "timestamp", + "Values": [ + 1.0 + ] } ], "ResponseMetadata": { @@ -6437,81 +6508,40 @@ } } }, - "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_multiple_dimensions_statistics[json]": { - "recorded-date": "19-09-2025, 23:07:47", + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_tagging_metric_alarm[query]": { + "recorded-date": "17-02-2026, 12:33:44", "recorded-content": { - "get-metric-stats-max": { - "Messages": [], - "MetricDataResults": [ - { - "Id": "result1", - "Label": "http.server.requests.count", - "StatusCode": "Complete", - "Timestamps": "timestamp", - "Values": [ - 5.0 - ] - } - ], + "put_metric_alarm": { "ResponseMetadata": { "HTTPHeaders": {}, "HTTPStatusCode": 200 } }, - "list-metrics": { - "Metrics": [ + "list_tags_for_resource_after_creation": { + "Tags": [ { - "Dimensions": [ - { - "Name": "error", - "Value": "none" - }, - { - "Name": "exception", - "Value": "none" - }, - { - "Name": "method", - "Value": "GET" - }, - { - "Name": "outcome", - "Value": "SUCCESS" - }, - { - "Name": "status", - "Value": "200" - }, - { - "Name": "uri", - "Value": "/greetings" - } - ], - "MetricName": "http.server.requests.count", - "Namespace": "" + "Key": "Environment", + "Value": "Production" } ], "ResponseMetadata": { "HTTPHeaders": {}, "HTTPStatusCode": 200 } - } - } - }, - "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_multiple_dimensions_statistics[smithy-rpc-v2-cbor]": { - "recorded-date": "19-09-2025, 23:07:59", - "recorded-content": { - "get-metric-stats-max": { - "Messages": [], - "MetricDataResults": [ + }, + "list_tags_for_resource_updated": { + "Tags": [ { - "Id": "result1", - "Label": "http.server.requests.count", - "StatusCode": "Complete", - "Timestamps": "timestamp", - "Values": [ - 5.0 - ] + "Key": "Environment", + "Value": "Production" + }, + { + "Key": "tag1", + "Value": "foo" + }, + { + "Key": "tag2", + "Value": "bar" } ], "ResponseMetadata": { @@ -6519,113 +6549,90 @@ "HTTPStatusCode": 200 } }, - "list-metrics": { - "Metrics": [ - { - "Dimensions": [ - { - "Name": "error", - "Value": "none" - }, - { - "Name": "exception", - "Value": "none" - }, - { - "Name": "method", - "Value": "GET" - }, - { - "Name": "outcome", - "Value": "SUCCESS" - }, - { - "Name": "status", - "Value": "200" - }, - { - "Name": "uri", - "Value": "/greetings" - } - ], - "MetricName": "http.server.requests.count", - "Namespace": "" + "list_tags_for_resource_post_untag": { + "Tags": [ + { + "Key": "Environment", + "Value": "Production" + }, + { + "Key": "tag2", + "Value": "bar" } ], "ResponseMetadata": { "HTTPHeaders": {}, "HTTPStatusCode": 200 } + }, + "list_tags_for_deleted_resource": { + "Tags": [], + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } } } }, - "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_invalid_amount_of_datapoints[query]": { - "recorded-date": "19-09-2025, 23:08:52", + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_tagging_metric_alarm[json]": { + "recorded-date": "17-02-2026, 12:33:45", "recorded-content": { - "error-invalid-amount-datapoints": { - "Error": { - "Code": "InvalidParameterCombination", - "Message": "You have requested up to 86400 datapoints, which exceeds the limit of 1440. You may reduce the datapoints requested by increasing Period, or decreasing the time range.", - "Type": "Sender" - }, + "put_metric_alarm": { "ResponseMetadata": { "HTTPHeaders": {}, - "HTTPStatusCode": 400 + "HTTPStatusCode": 200 } }, - "error-invalid-time-frame": { - "Error": { - "Code": "InvalidParameterValue", - "Message": "The parameter StartTime must be less than the parameter EndTime.", - "Type": "Sender" - }, + "list_tags_for_resource_after_creation": { + "Tags": [ + { + "Key": "Environment", + "Value": "Production" + } + ], "ResponseMetadata": { "HTTPHeaders": {}, - "HTTPStatusCode": 400 + "HTTPStatusCode": 200 } }, - "get-metric-statitics": { - "Datapoints": [], - "Label": "metric_name", + "list_tags_for_resource_updated": { + "Tags": [ + { + "Key": "Environment", + "Value": "Production" + }, + { + "Key": "tag1", + "Value": "foo" + }, + { + "Key": "tag2", + "Value": "bar" + } + ], "ResponseMetadata": { "HTTPHeaders": {}, "HTTPStatusCode": 200 } - } - } - }, - "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_invalid_amount_of_datapoints[json]": { - "recorded-date": "19-09-2025, 23:08:53", - "recorded-content": { - "error-invalid-amount-datapoints": { - "Error": { - "Code": "InvalidParameterCombination", - "Message": "You have requested up to 86400 datapoints, which exceeds the limit of 1440. You may reduce the datapoints requested by increasing Period, or decreasing the time range.", - "QueryErrorCode": "InvalidParameterCombinationException", - "Type": "Sender" - }, - "message": "You have requested up to 86400 datapoints, which exceeds the limit of 1440. You may reduce the datapoints requested by increasing Period, or decreasing the time range.", - "ResponseMetadata": { - "HTTPHeaders": {}, - "HTTPStatusCode": 400 - } }, - "error-invalid-time-frame": { - "Error": { - "Code": "InvalidParameterValue", - "Message": "The parameter StartTime must be less than the parameter EndTime.", - "QueryErrorCode": "InvalidParameterValueException", - "Type": "Sender" - }, - "message": "The parameter StartTime must be less than the parameter EndTime.", + "list_tags_for_resource_post_untag": { + "Tags": [ + { + "Key": "Environment", + "Value": "Production" + }, + { + "Key": "tag2", + "Value": "bar" + } + ], "ResponseMetadata": { "HTTPHeaders": {}, - "HTTPStatusCode": 400 + "HTTPStatusCode": 200 } }, - "get-metric-statitics": { - "Datapoints": [], - "Label": "metric_name", + "list_tags_for_deleted_resource": { + "Tags": [], "ResponseMetadata": { "HTTPHeaders": {}, "HTTPStatusCode": 200 @@ -6633,83 +6640,40 @@ } } }, - "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_invalid_amount_of_datapoints[smithy-rpc-v2-cbor]": { - "recorded-date": "19-09-2025, 23:08:54", + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_tagging_metric_alarm[smithy-rpc-v2-cbor]": { + "recorded-date": "17-02-2026, 12:33:45", "recorded-content": { - "error-invalid-amount-datapoints": { - "Error": { - "Code": "InvalidParameterCombination", - "Message": "You have requested up to 86400 datapoints, which exceeds the limit of 1440. You may reduce the datapoints requested by increasing Period, or decreasing the time range.", - "QueryErrorCode": "InvalidParameterCombinationException", - "Type": "Sender" - }, - "message": "You have requested up to 86400 datapoints, which exceeds the limit of 1440. You may reduce the datapoints requested by increasing Period, or decreasing the time range.", - "ResponseMetadata": { - "HTTPHeaders": {}, - "HTTPStatusCode": 400 - } - }, - "error-invalid-time-frame": { - "Error": { - "Code": "InvalidParameterValue", - "Message": "The parameter StartTime must be less than the parameter EndTime.", - "QueryErrorCode": "InvalidParameterValueException", - "Type": "Sender" - }, - "message": "The parameter StartTime must be less than the parameter EndTime.", + "put_metric_alarm": { "ResponseMetadata": { "HTTPHeaders": {}, - "HTTPStatusCode": 400 + "HTTPStatusCode": 200 } }, - "get-metric-statitics": { - "Datapoints": [], - "Label": "metric_name", + "list_tags_for_resource_after_creation": { + "Tags": [ + { + "Key": "Environment", + "Value": "Production" + } + ], "ResponseMetadata": { "HTTPHeaders": {}, "HTTPStatusCode": 200 } - } - } - }, - "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_set_alarm[query]": { - "recorded-date": "22-09-2025, 19:14:19", - "recorded-content": { - "triggered-alarm": { - "CompositeAlarms": [], - "MetricAlarms": [ + }, + "list_tags_for_resource_updated": { + "Tags": [ { - "ActionsEnabled": true, - "AlarmActions": [ - "arn::sns::111111111111:" - ], - "AlarmArn": "arn::cloudwatch::111111111111:alarm:", - "AlarmConfigurationUpdatedTimestamp": "timestamp", - "AlarmDescription": "Test Alarm when CPU exceeds 50 percent", - "AlarmName": "", - "ComparisonOperator": "GreaterThanThreshold", - "Dimensions": [ - { - "Name": "InstanceId", - "Value": "i-0317828c84edbe100" - } - ], - "EvaluationPeriods": 2, - "InsufficientDataActions": [], - "MetricName": "CPUUtilization-3", - "Namespace": "", - "OKActions": [ - "" - ], - "Period": 300, - "StateReason": "testing alarm", - "StateTransitionedTimestamp": "timestamp", - "StateUpdatedTimestamp": "timestamp", - "StateValue": "ALARM", - "Statistic": "Average", - "Threshold": 50.0, - "TreatMissingData": "ignore", - "Unit": "Percent" + "Key": "Environment", + "Value": "Production" + }, + { + "Key": "tag1", + "Value": "foo" + }, + { + "Key": "tag2", + "Value": "bar" } ], "ResponseMetadata": { @@ -6717,88 +6681,39 @@ "HTTPStatusCode": 200 } }, - "reset-alarm": { - "CompositeAlarms": [], - "MetricAlarms": [ + "list_tags_for_resource_post_untag": { + "Tags": [ { - "ActionsEnabled": true, - "AlarmActions": [ - "arn::sns::111111111111:" - ], - "AlarmArn": "arn::cloudwatch::111111111111:alarm:", - "AlarmConfigurationUpdatedTimestamp": "timestamp", - "AlarmDescription": "Test Alarm when CPU exceeds 50 percent", - "AlarmName": "", - "ComparisonOperator": "GreaterThanThreshold", - "Dimensions": [ - { - "Name": "InstanceId", - "Value": "i-0317828c84edbe100" - } - ], - "EvaluationPeriods": 2, - "InsufficientDataActions": [], - "MetricName": "CPUUtilization-3", - "Namespace": "", - "OKActions": [ - "" - ], - "Period": 300, - "StateReason": "resetting alarm", - "StateTransitionedTimestamp": "timestamp", - "StateUpdatedTimestamp": "timestamp", - "StateValue": "OK", - "Statistic": "Average", - "Threshold": 50.0, - "TreatMissingData": "ignore", - "Unit": "Percent" + "Key": "Environment", + "Value": "Production" + }, + { + "Key": "tag2", + "Value": "bar" } ], "ResponseMetadata": { "HTTPHeaders": {}, "HTTPStatusCode": 200 } - } - } - }, - "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_set_alarm[json]": { - "recorded-date": "22-09-2025, 19:14:26", - "recorded-content": { - "triggered-alarm": { - "CompositeAlarms": [], - "MetricAlarms": [ - { - "ActionsEnabled": true, - "AlarmActions": [ - "arn::sns::111111111111:" - ], - "AlarmArn": "arn::cloudwatch::111111111111:alarm:", - "AlarmConfigurationUpdatedTimestamp": "timestamp", - "AlarmDescription": "Test Alarm when CPU exceeds 50 percent", - "AlarmName": "", - "ComparisonOperator": "GreaterThanThreshold", - "Dimensions": [ - { - "Name": "InstanceId", - "Value": "i-0317828c84edbe100" - } - ], - "EvaluationPeriods": 2, - "InsufficientDataActions": [], - "MetricName": "CPUUtilization-3", - "Namespace": "", - "OKActions": [ - "" - ], - "Period": 300, - "StateReason": "testing alarm", - "StateTransitionedTimestamp": "timestamp", - "StateUpdatedTimestamp": "timestamp", - "StateValue": "ALARM", - "Statistic": "Average", - "Threshold": 50.0, - "TreatMissingData": "ignore", - "Unit": "Percent" + }, + "list_tags_for_deleted_resource": { + "Tags": [], + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_tagging_composite_alarm[query]": { + "recorded-date": "17-02-2026, 12:33:17", + "recorded-content": { + "list_tags_for_resource_after_creation ": { + "Tags": [ + { + "Key": "Environment", + "Value": "Production" } ], "ResponseMetadata": { @@ -6806,88 +6721,59 @@ "HTTPStatusCode": 200 } }, - "reset-alarm": { - "CompositeAlarms": [], - "MetricAlarms": [ + "list_tags_for_resource_updated": { + "Tags": [ { - "ActionsEnabled": true, - "AlarmActions": [ - "arn::sns::111111111111:" - ], - "AlarmArn": "arn::cloudwatch::111111111111:alarm:", - "AlarmConfigurationUpdatedTimestamp": "timestamp", - "AlarmDescription": "Test Alarm when CPU exceeds 50 percent", - "AlarmName": "", - "ComparisonOperator": "GreaterThanThreshold", - "Dimensions": [ - { - "Name": "InstanceId", - "Value": "i-0317828c84edbe100" - } - ], - "EvaluationPeriods": 2, - "InsufficientDataActions": [], - "MetricName": "CPUUtilization-3", - "Namespace": "", - "OKActions": [ - "" - ], - "Period": 300, - "StateReason": "resetting alarm", - "StateTransitionedTimestamp": "timestamp", - "StateUpdatedTimestamp": "timestamp", - "StateValue": "OK", - "Statistic": "Average", - "Threshold": 50.0, - "TreatMissingData": "ignore", - "Unit": "Percent" + "Key": "Environment", + "Value": "Production" + }, + { + "Key": "tag1", + "Value": "foo" + }, + { + "Key": "tag2", + "Value": "bar" + } + ], + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "list_tags_for_resource_post_untag": { + "Tags": [ + { + "Key": "Environment", + "Value": "Production" + }, + { + "Key": "tag2", + "Value": "bar" } ], "ResponseMetadata": { "HTTPHeaders": {}, "HTTPStatusCode": 200 } + }, + "list_tags_for_deleted_resource": { + "Tags": [], + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } } } }, - "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_set_alarm[smithy-rpc-v2-cbor]": { - "recorded-date": "22-09-2025, 19:14:33", + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_tagging_composite_alarm[json]": { + "recorded-date": "17-02-2026, 12:33:18", "recorded-content": { - "triggered-alarm": { - "CompositeAlarms": [], - "MetricAlarms": [ + "list_tags_for_resource_after_creation ": { + "Tags": [ { - "ActionsEnabled": true, - "AlarmActions": [ - "arn::sns::111111111111:" - ], - "AlarmArn": "arn::cloudwatch::111111111111:alarm:", - "AlarmConfigurationUpdatedTimestamp": "timestamp", - "AlarmDescription": "Test Alarm when CPU exceeds 50 percent", - "AlarmName": "", - "ComparisonOperator": "GreaterThanThreshold", - "Dimensions": [ - { - "Name": "InstanceId", - "Value": "i-0317828c84edbe100" - } - ], - "EvaluationPeriods": 2, - "InsufficientDataActions": [], - "MetricName": "CPUUtilization-3", - "Namespace": "", - "OKActions": [ - "" - ], - "Period": 300, - "StateReason": "testing alarm", - "StateTransitionedTimestamp": "timestamp", - "StateUpdatedTimestamp": "timestamp", - "StateValue": "ALARM", - "Statistic": "Average", - "Threshold": 50.0, - "TreatMissingData": "ignore", - "Unit": "Percent" + "Key": "Environment", + "Value": "Production" } ], "ResponseMetadata": { @@ -6895,130 +6781,107 @@ "HTTPStatusCode": 200 } }, - "reset-alarm": { - "CompositeAlarms": [], - "MetricAlarms": [ + "list_tags_for_resource_updated": { + "Tags": [ { - "ActionsEnabled": true, - "AlarmActions": [ - "arn::sns::111111111111:" - ], - "AlarmArn": "arn::cloudwatch::111111111111:alarm:", - "AlarmConfigurationUpdatedTimestamp": "timestamp", - "AlarmDescription": "Test Alarm when CPU exceeds 50 percent", - "AlarmName": "", - "ComparisonOperator": "GreaterThanThreshold", - "Dimensions": [ - { - "Name": "InstanceId", - "Value": "i-0317828c84edbe100" - } - ], - "EvaluationPeriods": 2, - "InsufficientDataActions": [], - "MetricName": "CPUUtilization-3", - "Namespace": "", - "OKActions": [ - "" - ], - "Period": 300, - "StateReason": "resetting alarm", - "StateTransitionedTimestamp": "timestamp", - "StateUpdatedTimestamp": "timestamp", - "StateValue": "OK", - "Statistic": "Average", - "Threshold": 50.0, - "TreatMissingData": "ignore", - "Unit": "Percent" + "Key": "Environment", + "Value": "Production" + }, + { + "Key": "tag1", + "Value": "foo" + }, + { + "Key": "tag2", + "Value": "bar" } ], "ResponseMetadata": { "HTTPHeaders": {}, "HTTPStatusCode": 200 } - } - } - }, - "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_set_alarm_invalid_input[query]": { - "recorded-date": "22-09-2025, 19:16:47", - "recorded-content": { - "error-invalid-state": { - "Error": { - "Code": "ValidationError", - "Message": "1 validation error detected: Value 'INVALID' at 'stateValue' failed to satisfy constraint: Member must satisfy enum value set: [INSUFFICIENT_DATA, ALARM, OK]", - "Type": "Sender" - }, + }, + "list_tags_for_resource_post_untag": { + "Tags": [ + { + "Key": "Environment", + "Value": "Production" + }, + { + "Key": "tag2", + "Value": "bar" + } + ], "ResponseMetadata": { "HTTPHeaders": {}, - "HTTPStatusCode": 400 + "HTTPStatusCode": 200 } }, - "error-resource-not-found": { - "Error": { - "Code": "ResourceNotFound", - "Type": "Sender" - }, + "list_tags_for_deleted_resource": { + "Tags": [], "ResponseMetadata": { "HTTPHeaders": {}, - "HTTPStatusCode": 404 + "HTTPStatusCode": 200 } } } }, - "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_set_alarm_invalid_input[json]": { - "recorded-date": "22-09-2025, 19:16:48", + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_tagging_composite_alarm[smithy-rpc-v2-cbor]": { + "recorded-date": "17-02-2026, 12:33:18", "recorded-content": { - "error-invalid-state": { - "Error": { - "Code": "ValidationError", - "Message": "1 validation error detected: Value 'INVALID' at 'stateValue' failed to satisfy constraint: Member must satisfy enum value set: [INSUFFICIENT_DATA, ALARM, OK]", - "QueryErrorCode": "ValidationException", - "Type": "Sender" - }, + "list_tags_for_resource_after_creation ": { + "Tags": [ + { + "Key": "Environment", + "Value": "Production" + } + ], "ResponseMetadata": { "HTTPHeaders": {}, - "HTTPStatusCode": 400 + "HTTPStatusCode": 200 } }, - "error-resource-not-found": { - "Error": { - "Code": "ResourceNotFound", - "Message": "", - "QueryErrorCode": "ResourceNotFound", - "Type": "Sender" - }, + "list_tags_for_resource_updated": { + "Tags": [ + { + "Key": "Environment", + "Value": "Production" + }, + { + "Key": "tag1", + "Value": "foo" + }, + { + "Key": "tag2", + "Value": "bar" + } + ], "ResponseMetadata": { "HTTPHeaders": {}, - "HTTPStatusCode": 404 + "HTTPStatusCode": 200 } - } - } - }, - "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_set_alarm_invalid_input[smithy-rpc-v2-cbor]": { - "recorded-date": "22-09-2025, 19:16:48", - "recorded-content": { - "error-invalid-state": { - "Error": { - "Code": "ValidationError", - "Message": "1 validation error detected: Value 'INVALID' at 'stateValue' failed to satisfy constraint: Member must satisfy enum value set: [INSUFFICIENT_DATA, ALARM, OK]", - "QueryErrorCode": "ValidationException", - "Type": "Sender" - }, + }, + "list_tags_for_resource_post_untag": { + "Tags": [ + { + "Key": "Environment", + "Value": "Production" + }, + { + "Key": "tag2", + "Value": "bar" + } + ], "ResponseMetadata": { "HTTPHeaders": {}, - "HTTPStatusCode": 400 + "HTTPStatusCode": 200 } }, - "error-resource-not-found": { - "Error": { - "Code": "ResourceNotFound", - "Message": "", - "QueryErrorCode": "ResourceNotFound", - "Type": "Sender" - }, + "list_tags_for_deleted_resource": { + "Tags": [], "ResponseMetadata": { "HTTPHeaders": {}, - "HTTPStatusCode": 404 + "HTTPStatusCode": 200 } } } diff --git a/tests/aws/services/cloudwatch/test_cloudwatch.validation.json b/tests/aws/services/cloudwatch/test_cloudwatch.validation.json index c80899f39e84a..47634cdfa5ec3 100644 --- a/tests/aws/services/cloudwatch/test_cloudwatch.validation.json +++ b/tests/aws/services/cloudwatch/test_cloudwatch.validation.json @@ -1,29 +1,29 @@ { "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudWatchMultiProtocol::test_basic_operations_multiple_protocols[json]": { - "last_validated_date": "2025-09-18T13:56:03+00:00", + "last_validated_date": "2025-12-17T13:53:06+00:00", "durations_in_seconds": { - "setup": 0.48, - "call": 3.45, + "setup": 0.56, + "call": 3.57, "teardown": 0.0, - "total": 3.93 + "total": 4.13 } }, "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudWatchMultiProtocol::test_basic_operations_multiple_protocols[query]": { - "last_validated_date": "2025-09-18T13:56:09+00:00", + "last_validated_date": "2025-12-17T13:53:13+00:00", "durations_in_seconds": { "setup": 0.0, - "call": 3.05, + "call": 3.0, "teardown": 0.0, - "total": 3.05 + "total": 3.0 } }, "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudWatchMultiProtocol::test_basic_operations_multiple_protocols[smithy-rpc-v2-cbor]": { - "last_validated_date": "2025-09-18T13:56:06+00:00", + "last_validated_date": "2025-12-17T13:53:10+00:00", "durations_in_seconds": { "setup": 0.0, - "call": 3.05, + "call": 3.15, "teardown": 0.0, - "total": 3.05 + "total": 3.15 } }, "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudWatchMultiProtocol::test_exception_serializing_with_no_shape_in_spec[json]": { @@ -110,31 +110,13 @@ "total": 0.35 } }, - "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_aws_sqs_metrics_created[json]": { - "last_validated_date": "2025-09-19T21:29:01+00:00", - "durations_in_seconds": { - "setup": 0.0, - "call": 119.29, - "teardown": 0.17, - "total": 119.46 - } - }, - "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_aws_sqs_metrics_created[query]": { - "last_validated_date": "2025-09-19T21:27:01+00:00", + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_aws_sqs_metrics_created": { + "last_validated_date": "2026-02-26T12:06:25+00:00", "durations_in_seconds": { - "setup": 0.53, - "call": 100.09, + "setup": 0.5, + "call": 90.98, "teardown": 0.19, - "total": 100.81 - } - }, - "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_aws_sqs_metrics_created[smithy-rpc-v2-cbor]": { - "last_validated_date": "2025-09-19T21:31:00+00:00", - "durations_in_seconds": { - "setup": 0.0, - "call": 119.3, - "teardown": 0.22, - "total": 119.52 + "total": 91.67 } }, "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_breaching_alarm_actions[json]": { @@ -1298,31 +1280,13 @@ "total": 1.37 } }, - "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_put_metric_alarm[json]": { - "last_validated_date": "2025-09-19T21:08:43+00:00", + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_put_metric_alarm": { + "last_validated_date": "2026-02-26T10:14:12+00:00", "durations_in_seconds": { - "setup": 0.14, - "call": 17.57, - "teardown": 1.17, - "total": 18.88 - } - }, - "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_put_metric_alarm[query]": { - "last_validated_date": "2025-09-19T21:08:24+00:00", - "durations_in_seconds": { - "setup": 0.96, - "call": 18.11, - "teardown": 1.08, - "total": 20.15 - } - }, - "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_put_metric_alarm[smithy-rpc-v2-cbor]": { - "last_validated_date": "2025-09-19T21:09:02+00:00", - "durations_in_seconds": { - "setup": 0.16, - "call": 17.47, - "teardown": 1.2, - "total": 18.83 + "setup": 1.02, + "call": 54.49, + "teardown": 1.48, + "total": 56.99 } }, "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_put_metric_alarm_escape_character[json]": { @@ -1514,6 +1478,60 @@ "total": 1.63 } }, + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_tagging_composite_alarm[json]": { + "last_validated_date": "2026-02-17T12:33:18+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 1.02, + "teardown": 0.0, + "total": 1.02 + } + }, + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_tagging_composite_alarm[query]": { + "last_validated_date": "2026-02-17T12:33:17+00:00", + "durations_in_seconds": { + "setup": 0.18, + "call": 0.78, + "teardown": 0.0, + "total": 0.96 + } + }, + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_tagging_composite_alarm[smithy-rpc-v2-cbor]": { + "last_validated_date": "2026-02-17T12:33:18+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.76, + "teardown": 0.0, + "total": 0.76 + } + }, + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_tagging_metric_alarm[json]": { + "last_validated_date": "2026-02-17T12:33:45+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.57, + "teardown": 0.0, + "total": 0.57 + } + }, + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_tagging_metric_alarm[query]": { + "last_validated_date": "2026-02-17T12:33:44+00:00", + "durations_in_seconds": { + "setup": 0.2, + "call": 0.67, + "teardown": 0.0, + "total": 0.87 + } + }, + "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_tagging_metric_alarm[smithy-rpc-v2-cbor]": { + "last_validated_date": "2026-02-17T12:33:45+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.6, + "teardown": 0.0, + "total": 0.6 + } + }, "tests/aws/services/cloudwatch/test_cloudwatch.py::TestCloudwatch::test_trigger_composite_alarm[json]": { "last_validated_date": "2025-09-19T21:03:36+00:00", "durations_in_seconds": { diff --git a/tests/aws/services/cloudwatch/utils.py b/tests/aws/services/cloudwatch/utils.py index f735a33c151f4..85af14e89c517 100644 --- a/tests/aws/services/cloudwatch/utils.py +++ b/tests/aws/services/cloudwatch/utils.py @@ -5,7 +5,9 @@ import xmltodict from botocore.auth import SigV4Auth from botocore.serialize import create_serializer -from cbor2._decoder import loads as cbor2_loads + +# import the unpatched cbor2 on purpose to avoid being polluted by Kinesis-only patches +from cbor2 import loads as cbor2_loads from requests import Response from localstack import constants @@ -45,9 +47,9 @@ def _build_headers(self, operation: str, query_mode: bool = False) -> dict: ... def _serialize_body(self, body: dict, operation: str) -> str | bytes: # here we use the Botocore serializer directly, since it has some complex behavior, # and we know CloudWatch supports it by default - query_serializer = create_serializer(self.protocol) + protocol_serializer = create_serializer(self.protocol) operation_model = self.service_model.operation_model(operation) - request = query_serializer.serialize_to_request(body, operation_model) + request = protocol_serializer.serialize_to_request(body, operation_model) return request["body"] @property diff --git a/tests/aws/services/dynamodb/test_dynamodb.py b/tests/aws/services/dynamodb/test_dynamodb.py index 9da8ff06096c4..8f3ebbb09bd54 100644 --- a/tests/aws/services/dynamodb/test_dynamodb.py +++ b/tests/aws/services/dynamodb/test_dynamodb.py @@ -11,6 +11,7 @@ from botocore.config import Config from botocore.exceptions import ClientError from localstack_snapshot.snapshots.transformer import SortingTransformer +from localstack_snapshot.snapshots.transformer_utility import TransformerUtility from localstack import config from localstack.aws.api.dynamodb import ( @@ -1490,32 +1491,101 @@ def test_create_duplicate_table(self, dynamodb_create_table_with_parameters, sna ) snapshot.match("Error", ctx.value) - @markers.aws.only_localstack( - reason="timing issues - needs a check to see if table is successfully deleted" + @markers.aws.validated + @markers.snapshot.skip_snapshot_verify( + paths=[ + "$..TableDescription.TableStatus", # DDBLocal directly goes to ACTIVE status + "$..Table.ProvisionedThroughput.LastDecreaseDateTime", # Not returned by DDBLocal + "$..Table.ProvisionedThroughput.LastIncreaseDateTime", # Not returned by DDBLocal + # The following attributes (prefixed TableDescription) are returned by DDBLocal DeleteTable but not in parity with AWS + "$..TableDescription.AttributeDefinitions", + "$..TableDescription.CreationDateTime", + "$..TableDescription.KeySchema", + "$..TableDescription.ProvisionedThroughput.LastDecreaseDateTime", + "$..TableDescription.ProvisionedThroughput.LastIncreaseDateTime", + "$..TableDescription.TableId", + ] ) - def test_delete_table(self, dynamodb_create_table, aws_client): + def test_table_crud(self, aws_client, cleanups, snapshot, dynamodb_wait_for_table_active): + snapshot.add_transformer( + [ + TransformerUtility.key_value("TableName"), + TransformerUtility.key_value("TableArn"), + ] + ) + table_name = f"test-ddb-table-{short_uid()}" - tables_before = len(aws_client.dynamodb.list_tables()["TableNames"]) + # CreateTable + response = aws_client.dynamodb.create_table( + TableName=table_name, + KeySchema=[{"AttributeName": "id", "KeyType": "HASH"}], + AttributeDefinitions=[{"AttributeName": "id", "AttributeType": "S"}], + ProvisionedThroughput={"ReadCapacityUnits": 5, "WriteCapacityUnits": 5}, + ) + cleanups.append(lambda: aws_client.dynamodb.delete_table(TableName=table_name)) + snapshot.match("create-table", response) - dynamodb_create_table( - table_name=table_name, - partition_key=PARTITION_KEY, + dynamodb_wait_for_table_active(table_name=table_name) + + # ListTables + assert table_name in aws_client.dynamodb.list_tables()["TableNames"] + + # DescribeTable + response = aws_client.dynamodb.describe_table(TableName=table_name) + snapshot.match("describe-table", response) + + # DeleteTable + response = aws_client.dynamodb.delete_table(TableName=table_name) + snapshot.match("delete-table", response) + + # ListTable: after DeleteTable + retry( + lambda: table_name not in aws_client.dynamodb.list_tables()["TableNames"], + sleep=1, + retries=30, ) - table_list = aws_client.dynamodb.list_tables() - # TODO: fix assertion, to enable parallel test execution! - assert tables_before + 1 == len(table_list["TableNames"]) - assert table_name in table_list["TableNames"] + # DeleteTable: delete non-existent table + with pytest.raises(ClientError) as exc: + aws_client.dynamodb.delete_table(TableName="non-existent") + snapshot.match("delete-non-existent-table", exc.value.response) - aws_client.dynamodb.delete_table(TableName=table_name) + @markers.aws.validated + @markers.snapshot.skip_snapshot_verify( + paths=[ + "$..TableDescription.TableStatus", # DDBLocal directly goes to ACTIVE status + "$..Table.ProvisionedThroughput.LastDecreaseDateTime", # Not returned by DDBLocal + "$..Table.ProvisionedThroughput.LastIncreaseDateTime", # Not returned by DDBLocal + ] + ) + def test_table_warm_throughput( + self, dynamodb_create_table_with_parameters, snapshot, aws_client + ): + """ + This test ensures that WarmThroughput params provided to CreateTable are reflected in DescribeTable + """ - table_list = aws_client.dynamodb.list_tables() - assert tables_before == len(table_list["TableNames"]) + snapshot.add_transformer( + [ + TransformerUtility.key_value("TableName"), + TransformerUtility.key_value("TableArn"), + ] + ) - with pytest.raises(Exception) as ctx: - aws_client.dynamodb.delete_table(TableName=table_name) - assert ctx.match("ResourceNotFoundException") + table_name = f"test-ddb-table-{short_uid()}" + + response = dynamodb_create_table_with_parameters( + TableName=table_name, + KeySchema=[{"AttributeName": "id", "KeyType": "HASH"}], + AttributeDefinitions=[{"AttributeName": "id", "AttributeType": "S"}], + ProvisionedThroughput={"ReadCapacityUnits": 5, "WriteCapacityUnits": 5}, + WarmThroughput={"ReadUnitsPerSecond": 1000, "WriteUnitsPerSecond": 1200}, + ) + snapshot.match("create-table", response) + + response = aws_client.dynamodb.describe_table(TableName=table_name) + snapshot.match("describe-table", response) @markers.aws.validated def test_transaction_write_items( @@ -1557,6 +1627,42 @@ def test_transaction_write_items( ) snapshot.match("Response", response) + table_name_arn = f"test-ddb-table-{short_uid()}" + table = dynamodb_create_table_with_parameters( + TableName=table_name_arn, + KeySchema=[{"AttributeName": "id", "KeyType": "HASH"}], + AttributeDefinitions=[{"AttributeName": "id", "AttributeType": "S"}], + ProvisionedThroughput={"ReadCapacityUnits": 5, "WriteCapacityUnits": 5}, + Tags=TEST_DDB_TAGS, + ) + + table_arn = table["TableDescription"]["TableArn"] + response_arn = aws_client.dynamodb.transact_write_items( + TransactItems=[ + { + "ConditionCheck": { + "TableName": table_arn, + "ConditionExpression": "attribute_not_exists(id)", + "Key": {"id": {"S": "test1"}}, + } + }, + {"Put": {"TableName": table_arn, "Item": {"id": {"S": "test2"}}}}, + { + "Update": { + "TableName": table_arn, + "Key": {"id": {"S": "test3"}}, + "UpdateExpression": "SET attr1 = :v1, attr2 = :v2", + "ExpressionAttributeValues": { + ":v1": {"S": "value1"}, + ":v2": {"S": "value2"}, + }, + } + }, + {"Delete": {"TableName": table_arn, "Key": {"id": {"S": "test4"}}}}, + ] + ) + snapshot.match("Response_using_table_arn", response_arn) + @markers.aws.validated def test_transaction_write_canceled( self, dynamodb_create_table_with_parameters, snapshot, aws_client @@ -1636,6 +1742,18 @@ def test_transact_get_items(self, dynamodb_create_table, snapshot, aws_client): ) snapshot.match("TransactGetItems", result) + table_name_arn = f"test-ddb-table-{short_uid()}" + table = dynamodb_create_table( + table_name=table_name_arn, + partition_key=PARTITION_KEY, + ) + table_arn = table["TableDescription"]["TableArn"] + aws_client.dynamodb.put_item(TableName=table_name_arn, Item={"id": {"S": "Sarah"}}) + result = aws_client.dynamodb.transact_get_items( + TransactItems=[{"Get": {"Key": {"id": {"S": "Sarah"}}, "TableName": table_arn}}] + ) + snapshot.match("TransactGetItems-with-TableArn", result) + @markers.aws.validated def test_batch_write_items(self, dynamodb_create_table_with_parameters, snapshot, aws_client): table_name = f"test-ddb-table-{short_uid()}" @@ -1947,9 +2065,14 @@ def test_dynamodb_create_table_with_sse_specification( assert result["TableDescription"]["SSEDescription"]["KMSMasterKeyArn"] == kms_master_key_arn @markers.aws.validated + @markers.snapshot.skip_snapshot_verify( + paths=["$..KeyMetadata.CurrentKeyMaterialId"] # Not supported by LS + ) def test_dynamodb_create_table_with_partial_sse_specification( self, dynamodb_create_table_with_parameters, snapshot, aws_client ): + snapshot.add_transformer(TransformerUtility.key_value("CurrentKeyMaterialId")) + table_name = f"test_table_{short_uid()}" sse_specification = {"Enabled": True} @@ -1979,9 +2102,14 @@ def test_dynamodb_create_table_with_partial_sse_specification( assert "SSESpecification" not in result["Table"] @markers.aws.validated + @markers.snapshot.skip_snapshot_verify( + paths=["$..KeyMetadata.CurrentKeyMaterialId"] # Not supported by LS + ) def test_dynamodb_update_table_without_sse_specification_change( self, dynamodb_create_table_with_parameters, snapshot, aws_client ): + snapshot.add_transformer(TransformerUtility.key_value("CurrentKeyMaterialId")) + table_name = f"test_table_{short_uid()}" sse_specification = {"Enabled": True} @@ -2284,6 +2412,7 @@ def test_data_encoding_consistency( paths=[ "$..PointInTimeRecoveryDescription..EarliestRestorableDateTime", "$..PointInTimeRecoveryDescription..LatestRestorableDateTime", + "$..ContinuousBackupsDescription.PointInTimeRecoveryDescription.RecoveryPeriodInDays", ] ) @markers.aws.validated @@ -2638,6 +2767,8 @@ def _get_records_amount(record_amount: int): @pytest.mark.parametrize("billing_mode", ["PAY_PER_REQUEST", "PROVISIONED"]) @markers.snapshot.skip_snapshot_verify( paths=[ + # Warm throughput for GSI is not implemented in LS. DDB Local doesn't support it either. + "$..Table.GlobalSecondaryIndexes..WarmThroughput", # LS returns those and not AWS, probably because no changes happened there yet "$..ProvisionedThroughput.LastDecreaseDateTime", "$..ProvisionedThroughput.LastIncreaseDateTime", @@ -2696,3 +2827,22 @@ def test_gsi_with_billing_mode( describe_table = aws_client.dynamodb.describe_table(TableName=table_name) snapshot.match("describe-table", describe_table) + + @markers.aws.validated + def test_dynamodb_describe_contributor_insights( + self, dynamodb_create_table, snapshot, aws_client + ): + table_name = f"test-ddb-table-{short_uid()}" + + snapshot.add_transformers_list( + [ + snapshot.transform.key_value("TableName"), + ] + ) + + dynamodb_create_table( + table_name=table_name, + partition_key=PARTITION_KEY, + ) + result = aws_client.dynamodb.describe_contributor_insights(TableName=table_name) + snapshot.match("describe-contributor-insights-disabled", result) diff --git a/tests/aws/services/dynamodb/test_dynamodb.snapshot.json b/tests/aws/services/dynamodb/test_dynamodb.snapshot.json index 0906a5c394a25..fd99f9432264c 100644 --- a/tests/aws/services/dynamodb/test_dynamodb.snapshot.json +++ b/tests/aws/services/dynamodb/test_dynamodb.snapshot.json @@ -1,6 +1,6 @@ { "tests/aws/services/dynamodb/test_dynamodb.py::TestDynamoDB::test_valid_local_secondary_index": { - "recorded-date": "23-08-2023, 16:32:11", + "recorded-date": "08-10-2025, 12:33:08", "recorded-content": { "Items": { "Count": 1, @@ -26,7 +26,7 @@ } }, "tests/aws/services/dynamodb/test_dynamodb.py::TestDynamoDB::test_return_values_in_put_item": { - "recorded-date": "23-08-2023, 16:32:21", + "recorded-date": "08-10-2025, 12:33:15", "recorded-content": { "PutFirstItem": { "ResponseMetadata": { @@ -77,7 +77,7 @@ } }, "tests/aws/services/dynamodb/test_dynamodb.py::TestDynamoDB::test_empty_and_binary_values": { - "recorded-date": "23-08-2023, 16:32:29", + "recorded-date": "08-10-2025, 12:33:22", "recorded-content": { "PutFirstItem": { "ResponseMetadata": { @@ -94,7 +94,7 @@ } }, "tests/aws/services/dynamodb/test_dynamodb.py::TestDynamoDB::test_batch_write_binary": { - "recorded-date": "23-08-2023, 16:32:35", + "recorded-date": "08-10-2025, 12:33:28", "recorded-content": { "Response": { "UnprocessedItems": {}, @@ -106,7 +106,7 @@ } }, "tests/aws/services/dynamodb/test_dynamodb.py::TestDynamoDB::test_dynamodb_execute_transaction": { - "recorded-date": "23-08-2023, 16:32:44", + "recorded-date": "08-10-2025, 12:33:37", "recorded-content": { "ExecutedTransaction": { "Responses": [], @@ -138,7 +138,7 @@ } }, "tests/aws/services/dynamodb/test_dynamodb.py::TestDynamoDB::test_dynamodb_batch_execute_statement": { - "recorded-date": "23-08-2023, 16:32:51", + "recorded-date": "08-10-2025, 12:33:43", "recorded-content": { "ExecutedStatement": { "Responses": [ @@ -170,7 +170,7 @@ } }, "tests/aws/services/dynamodb/test_dynamodb.py::TestDynamoDB::test_dynamodb_partiql_missing": { - "recorded-date": "23-08-2023, 16:33:00", + "recorded-date": "08-10-2025, 12:33:58", "recorded-content": { "FirstNameNotMissing": [ { @@ -185,30 +185,36 @@ } }, "tests/aws/services/dynamodb/test_dynamodb.py::TestDynamoDB::test_create_duplicate_table": { - "recorded-date": "23-08-2023, 16:33:08", + "recorded-date": "08-10-2025, 12:35:25", "recorded-content": { "Error": "An error occurred (ResourceInUseException) when calling the CreateTable operation: Table already exists: " } }, "tests/aws/services/dynamodb/test_dynamodb.py::TestDynamoDB::test_transaction_write_items": { - "recorded-date": "23-08-2023, 16:33:16", + "recorded-date": "07-01-2026, 10:30:09", "recorded-content": { "Response": { "ResponseMetadata": { "HTTPHeaders": {}, "HTTPStatusCode": 200 } + }, + "Response_using_table_arn": { + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } } } }, "tests/aws/services/dynamodb/test_dynamodb.py::TestDynamoDB::test_transaction_write_canceled": { - "recorded-date": "23-08-2023, 16:33:24", + "recorded-date": "08-10-2025, 12:35:51", "recorded-content": { "Error": "An error occurred (TransactionCanceledException) when calling the TransactWriteItems operation: Transaction cancelled, please refer cancellation reasons for specific reasons [ConditionalCheckFailed, None]" } }, "tests/aws/services/dynamodb/test_dynamodb.py::TestDynamoDB::test_transaction_write_binary_data": { - "recorded-date": "23-08-2023, 16:33:31", + "recorded-date": "08-10-2025, 12:35:59", "recorded-content": { "WriteResponse": { "ResponseMetadata": { @@ -227,7 +233,7 @@ } }, "tests/aws/services/dynamodb/test_dynamodb.py::TestDynamoDB::test_transact_get_items": { - "recorded-date": "23-08-2023, 16:33:37", + "recorded-date": "08-01-2026, 19:22:29", "recorded-content": { "TransactGetItems": { "Responses": [ @@ -243,11 +249,26 @@ "HTTPHeaders": {}, "HTTPStatusCode": 200 } + }, + "TransactGetItems-with-TableArn": { + "Responses": [ + { + "Item": { + "id": { + "S": "Sarah" + } + } + } + ], + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } } } }, "tests/aws/services/dynamodb/test_dynamodb.py::TestDynamoDB::test_batch_write_items": { - "recorded-date": "23-08-2023, 16:33:43", + "recorded-date": "08-10-2025, 12:36:12", "recorded-content": { "BatchWriteResponse": { "UnprocessedItems": {}, @@ -259,13 +280,13 @@ } }, "tests/aws/services/dynamodb/test_dynamodb.py::TestDynamoDB::test_dynamodb_pay_per_request": { - "recorded-date": "23-08-2023, 16:33:43", + "recorded-date": "08-10-2025, 12:36:20", "recorded-content": { "Error": "An error occurred (ValidationException) when calling the CreateTable operation: One or more parameter values were invalid: Neither ReadCapacityUnits nor WriteCapacityUnits can be specified when BillingMode is PAY_PER_REQUEST" } }, "tests/aws/services/dynamodb/test_dynamodb.py::TestDynamoDB::test_dynamodb_create_table_with_partial_sse_specification": { - "recorded-date": "10-01-2024, 12:59:51", + "recorded-date": "08-10-2025, 14:03:41", "recorded-content": { "SSEDescription": { "KMSMasterKeyArn": "arn::kms::111111111111:key/", @@ -277,6 +298,7 @@ "AWSAccountId": "111111111111", "Arn": "arn::kms::111111111111:key/", "CreationDate": "datetime", + "CurrentKeyMaterialId": "", "CustomerMasterKeySpec": "SYMMETRIC_DEFAULT", "Description": "Default key that protects my DynamoDB data when no other key is defined", "Enabled": true, @@ -304,7 +326,7 @@ } }, "tests/aws/services/dynamodb/test_dynamodb.py::TestDynamoDB::test_dynamodb_get_batch_items": { - "recorded-date": "23-08-2023, 16:33:58", + "recorded-date": "08-10-2025, 12:37:20", "recorded-content": { "Response": { "Responses": { @@ -319,7 +341,7 @@ } }, "tests/aws/services/dynamodb/test_dynamodb.py::TestDynamoDB::test_dynamodb_idempotent_writing": { - "recorded-date": "23-08-2023, 16:39:54", + "recorded-date": "08-10-2025, 12:37:34", "recorded-content": { "Response1": { "ResponseMetadata": { @@ -336,13 +358,13 @@ } }, "tests/aws/services/dynamodb/test_dynamodb.py::TestDynamoDB::test_batch_write_not_matching_schema": { - "recorded-date": "23-08-2023, 16:34:26", + "recorded-date": "08-10-2025, 12:37:41", "recorded-content": { "ValidationException": "An error occurred (ValidationException) when calling the BatchWriteItem operation: The provided key element does not match the schema" } }, "tests/aws/services/dynamodb/test_dynamodb.py::TestDynamoDB::test_data_encoding_consistency": { - "recorded-date": "24-08-2023, 10:56:37", + "recorded-date": "08-10-2025, 12:37:49", "recorded-content": { "GetItem": { "data": { @@ -391,7 +413,7 @@ } }, "tests/aws/services/dynamodb/test_dynamodb.py::TestDynamoDB::test_continuous_backup_update": { - "recorded-date": "23-08-2023, 16:34:39", + "recorded-date": "08-10-2025, 12:38:00", "recorded-content": { "update-continuous-backup": { "ContinuousBackupsDescription": { @@ -399,7 +421,8 @@ "PointInTimeRecoveryDescription": { "EarliestRestorableDateTime": "datetime", "LatestRestorableDateTime": "datetime", - "PointInTimeRecoveryStatus": "ENABLED" + "PointInTimeRecoveryStatus": "ENABLED", + "RecoveryPeriodInDays": 35 } }, "ResponseMetadata": { @@ -413,7 +436,8 @@ "PointInTimeRecoveryDescription": { "EarliestRestorableDateTime": "datetime", "LatestRestorableDateTime": "datetime", - "PointInTimeRecoveryStatus": "ENABLED" + "PointInTimeRecoveryStatus": "ENABLED", + "RecoveryPeriodInDays": 35 } }, "ResponseMetadata": { @@ -424,7 +448,7 @@ } }, "tests/aws/services/dynamodb/test_dynamodb.py::TestDynamoDB::test_batch_write_not_existing_table": { - "recorded-date": "22-10-2023, 20:45:30", + "recorded-date": "08-10-2025, 12:37:41", "recorded-content": { "exc-not-found-transact-write-items": { "Error": { @@ -440,7 +464,7 @@ } }, "tests/aws/services/dynamodb/test_dynamodb.py::TestDynamoDB::test_batch_write_items_streaming": { - "recorded-date": "22-10-2023, 23:23:09", + "recorded-date": "08-10-2025, 12:36:19", "recorded-content": { "create-table": { "TableDescription": { @@ -636,11 +660,11 @@ } }, "tests/aws/services/dynamodb/test_dynamodb.py::TestDynamoDB::test_dynamodb_streams_describe_with_exclusive_start_shard_id": { - "recorded-date": "22-10-2023, 22:27:28", + "recorded-date": "08-10-2025, 12:37:28", "recorded-content": {} }, "tests/aws/services/dynamodb/test_dynamodb.py::TestDynamoDB::test_dynamodb_stream_stream_view_type": { - "recorded-date": "31-05-2024, 14:49:57", + "recorded-date": "08-10-2025, 12:34:09", "recorded-content": { "create-table": { "TableDescription": { @@ -831,7 +855,7 @@ } }, "tests/aws/services/dynamodb/test_dynamodb.py::TestDynamoDB::test_return_values_on_conditions_check_failure": { - "recorded-date": "03-01-2024, 17:52:20", + "recorded-date": "08-10-2025, 12:45:55", "recorded-content": { "items": { "Error": { @@ -857,7 +881,7 @@ } }, "tests/aws/services/dynamodb/test_dynamodb.py::TestDynamoDB::test_transact_write_items_streaming": { - "recorded-date": "31-05-2024, 14:47:04", + "recorded-date": "08-10-2025, 12:46:04", "recorded-content": { "create-table": { "TableDescription": { @@ -1129,7 +1153,7 @@ } }, "tests/aws/services/dynamodb/test_dynamodb.py::TestDynamoDB::test_transact_write_items_streaming_for_different_tables": { - "recorded-date": "02-04-2024, 21:45:36", + "recorded-date": "08-10-2025, 12:46:18", "recorded-content": { "create-table-stream": { "TableDescription": { @@ -1419,7 +1443,7 @@ } }, "tests/aws/services/dynamodb/test_dynamodb.py::TestDynamoDB::test_dynamodb_update_table_without_sse_specification_change": { - "recorded-date": "17-12-2024, 10:40:03", + "recorded-date": "08-10-2025, 14:06:57", "recorded-content": { "create_table_sse_description": { "KMSMasterKeyArn": "arn::kms::111111111111:key/", @@ -1431,6 +1455,7 @@ "AWSAccountId": "111111111111", "Arn": "arn::kms::111111111111:key/", "CreationDate": "datetime", + "CurrentKeyMaterialId": "", "CustomerMasterKeySpec": "SYMMETRIC_DEFAULT", "Description": "Default key that protects my DynamoDB data when no other key is defined", "Enabled": true, @@ -1458,7 +1483,7 @@ } }, "tests/aws/services/dynamodb/test_dynamodb.py::TestDynamoDB::test_dynamodb_execute_statement_empy_parameter": { - "recorded-date": "03-01-2025, 09:24:27", + "recorded-date": "08-10-2025, 12:33:51", "recorded-content": { "invalid-param-error": { "Error": { @@ -1473,7 +1498,7 @@ } }, "tests/aws/services/dynamodb/test_dynamodb.py::TestDynamoDB::test_gsi_with_billing_mode[PAY_PER_REQUEST]": { - "recorded-date": "08-01-2025, 18:17:06", + "recorded-date": "08-10-2025, 12:46:32", "recorded-content": { "create-table-with-gsi": { "TableDescription": { @@ -1576,6 +1601,11 @@ "NumberOfDecreasesToday": 0, "ReadCapacityUnits": 0, "WriteCapacityUnits": 0 + }, + "WarmThroughput": { + "ReadUnitsPerSecond": 12000, + "Status": "ACTIVE", + "WriteUnitsPerSecond": 4000 } } ], @@ -1595,7 +1625,12 @@ "TableId": "", "TableName": "", "TableSizeBytes": 0, - "TableStatus": "" + "TableStatus": "", + "WarmThroughput": { + "ReadUnitsPerSecond": 12000, + "Status": "ACTIVE", + "WriteUnitsPerSecond": 4000 + } }, "ResponseMetadata": { "HTTPHeaders": {}, @@ -1605,7 +1640,7 @@ } }, "tests/aws/services/dynamodb/test_dynamodb.py::TestDynamoDB::test_gsi_with_billing_mode[PROVISIONED]": { - "recorded-date": "08-01-2025, 18:17:21", + "recorded-date": "08-10-2025, 12:46:48", "recorded-content": { "create-table-with-gsi": { "TableDescription": { @@ -1701,6 +1736,11 @@ "NumberOfDecreasesToday": 0, "ReadCapacityUnits": 1, "WriteCapacityUnits": 1 + }, + "WarmThroughput": { + "ReadUnitsPerSecond": 1, + "Status": "ACTIVE", + "WriteUnitsPerSecond": 1 } } ], @@ -1720,7 +1760,12 @@ "TableId": "", "TableName": "", "TableSizeBytes": 0, - "TableStatus": "" + "TableStatus": "", + "WarmThroughput": { + "ReadUnitsPerSecond": 5, + "Status": "ACTIVE", + "WriteUnitsPerSecond": 5 + } }, "ResponseMetadata": { "HTTPHeaders": {}, @@ -1730,7 +1775,7 @@ } }, "tests/aws/services/dynamodb/test_dynamodb.py::TestDynamoDB::test_streams_on_global_tables": { - "recorded-date": "22-05-2025, 12:44:58", + "recorded-date": "08-10-2025, 12:35:17", "recorded-content": { "region-streams": { "Streams": [ @@ -1870,5 +1915,210 @@ } } } + }, + "tests/aws/services/dynamodb/test_dynamodb.py::TestDynamoDB::test_dynamodb_describe_contributor_insights": { + "recorded-date": "08-10-2025, 12:46:55", + "recorded-content": { + "describe-contributor-insights-disabled": { + "ContributorInsightsStatus": "DISABLED", + "TableName": "", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/dynamodb/test_dynamodb.py::TestDynamoDB::test_table_crud": { + "recorded-date": "08-10-2025, 12:35:32", + "recorded-content": { + "create-table": { + "TableDescription": { + "AttributeDefinitions": [ + { + "AttributeName": "id", + "AttributeType": "S" + } + ], + "CreationDateTime": "datetime", + "DeletionProtectionEnabled": false, + "ItemCount": 0, + "KeySchema": [ + { + "AttributeName": "id", + "KeyType": "HASH" + } + ], + "ProvisionedThroughput": { + "NumberOfDecreasesToday": 0, + "ReadCapacityUnits": 5, + "WriteCapacityUnits": 5 + }, + "TableArn": "arn::dynamodb::111111111111:table/", + "TableId": "", + "TableName": "", + "TableSizeBytes": 0, + "TableStatus": "CREATING" + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "describe-table": { + "Table": { + "AttributeDefinitions": [ + { + "AttributeName": "id", + "AttributeType": "S" + } + ], + "CreationDateTime": "datetime", + "DeletionProtectionEnabled": false, + "ItemCount": 0, + "KeySchema": [ + { + "AttributeName": "id", + "KeyType": "HASH" + } + ], + "ProvisionedThroughput": { + "NumberOfDecreasesToday": 0, + "ReadCapacityUnits": 5, + "WriteCapacityUnits": 5 + }, + "TableArn": "arn::dynamodb::111111111111:table/", + "TableId": "", + "TableName": "", + "TableSizeBytes": 0, + "TableStatus": "ACTIVE", + "WarmThroughput": { + "ReadUnitsPerSecond": 5, + "Status": "ACTIVE", + "WriteUnitsPerSecond": 5 + } + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "delete-table": { + "TableDescription": { + "DeletionProtectionEnabled": false, + "ItemCount": 0, + "ProvisionedThroughput": { + "NumberOfDecreasesToday": 0, + "ReadCapacityUnits": 5, + "WriteCapacityUnits": 5 + }, + "TableArn": "arn::dynamodb::111111111111:table/", + "TableId": "", + "TableName": "", + "TableSizeBytes": 0, + "TableStatus": "DELETING" + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "delete-non-existent-table": { + "Error": { + "Code": "ResourceNotFoundException", + "Message": "Requested resource not found: Table: non-existent not found" + }, + "message": "Requested resource not found: Table: non-existent not found", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + } + } + }, + "tests/aws/services/dynamodb/test_dynamodb.py::TestDynamoDB::test_table_warm_throughput": { + "recorded-date": "08-10-2025, 12:35:39", + "recorded-content": { + "create-table": { + "TableDescription": { + "AttributeDefinitions": [ + { + "AttributeName": "id", + "AttributeType": "S" + } + ], + "CreationDateTime": "datetime", + "DeletionProtectionEnabled": false, + "ItemCount": 0, + "KeySchema": [ + { + "AttributeName": "id", + "KeyType": "HASH" + } + ], + "ProvisionedThroughput": { + "NumberOfDecreasesToday": 0, + "ReadCapacityUnits": 5, + "WriteCapacityUnits": 5 + }, + "TableArn": "arn::dynamodb::111111111111:table/", + "TableId": "", + "TableName": "", + "TableSizeBytes": 0, + "TableStatus": "CREATING", + "WarmThroughput": { + "ReadUnitsPerSecond": 1000, + "Status": "UPDATING", + "WriteUnitsPerSecond": 1200 + } + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "describe-table": { + "Table": { + "AttributeDefinitions": [ + { + "AttributeName": "id", + "AttributeType": "S" + } + ], + "CreationDateTime": "datetime", + "DeletionProtectionEnabled": false, + "ItemCount": 0, + "KeySchema": [ + { + "AttributeName": "id", + "KeyType": "HASH" + } + ], + "ProvisionedThroughput": { + "NumberOfDecreasesToday": 0, + "ReadCapacityUnits": 5, + "WriteCapacityUnits": 5 + }, + "TableArn": "arn::dynamodb::111111111111:table/", + "TableId": "", + "TableName": "", + "TableSizeBytes": 0, + "TableStatus": "ACTIVE", + "WarmThroughput": { + "ReadUnitsPerSecond": 1000, + "Status": "ACTIVE", + "WriteUnitsPerSecond": 1200 + } + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/dynamodb/test_dynamodb.py::TestDynamoDB::test_stream_destination_records": { + "recorded-date": "08-10-2025, 12:45:48", + "recorded-content": {} } } diff --git a/tests/aws/services/dynamodb/test_dynamodb.validation.json b/tests/aws/services/dynamodb/test_dynamodb.validation.json index d06d442ccea4f..48d1c39790524 100644 --- a/tests/aws/services/dynamodb/test_dynamodb.validation.json +++ b/tests/aws/services/dynamodb/test_dynamodb.validation.json @@ -1,72 +1,213 @@ { "tests/aws/services/dynamodb/test_dynamodb.py::TestDynamoDB::test_batch_write_binary": { - "last_validated_date": "2023-08-23T14:32:35+00:00" + "last_validated_date": "2025-10-08T12:33:28+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 6.15, + "teardown": 0.41, + "total": 6.56 + } }, "tests/aws/services/dynamodb/test_dynamodb.py::TestDynamoDB::test_batch_write_items": { - "last_validated_date": "2023-08-23T14:33:43+00:00" + "last_validated_date": "2025-10-08T12:36:12+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 5.2, + "teardown": 0.34, + "total": 5.54 + } }, "tests/aws/services/dynamodb/test_dynamodb.py::TestDynamoDB::test_batch_write_items_streaming": { - "last_validated_date": "2023-10-22T21:23:09+00:00" + "last_validated_date": "2025-10-08T12:36:19+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 7.08, + "teardown": 0.41, + "total": 7.49 + } }, "tests/aws/services/dynamodb/test_dynamodb.py::TestDynamoDB::test_batch_write_not_existing_table": { - "last_validated_date": "2023-10-22T18:45:30+00:00" + "last_validated_date": "2025-10-08T12:37:41+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.21, + "teardown": 0.0, + "total": 0.21 + } }, "tests/aws/services/dynamodb/test_dynamodb.py::TestDynamoDB::test_batch_write_not_matching_schema": { - "last_validated_date": "2023-08-23T14:34:26+00:00" + "last_validated_date": "2025-10-08T12:37:41+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 6.37, + "teardown": 0.5, + "total": 6.87 + } }, "tests/aws/services/dynamodb/test_dynamodb.py::TestDynamoDB::test_continuous_backup_update": { - "last_validated_date": "2023-08-23T14:34:39+00:00" + "last_validated_date": "2025-10-08T12:38:00+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 10.06, + "teardown": 0.41, + "total": 10.47 + } }, "tests/aws/services/dynamodb/test_dynamodb.py::TestDynamoDB::test_create_duplicate_table": { - "last_validated_date": "2023-08-23T14:33:08+00:00" + "last_validated_date": "2025-10-08T12:35:25+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 5.98, + "teardown": 2.68, + "total": 8.66 + } }, "tests/aws/services/dynamodb/test_dynamodb.py::TestDynamoDB::test_data_encoding_consistency": { - "last_validated_date": "2023-08-24T08:56:37+00:00" + "last_validated_date": "2025-10-08T12:37:49+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 7.8, + "teardown": 0.34, + "total": 8.14 + } }, "tests/aws/services/dynamodb/test_dynamodb.py::TestDynamoDB::test_dynamodb_batch_execute_statement": { - "last_validated_date": "2023-08-23T14:32:51+00:00" + "last_validated_date": "2025-10-08T12:33:43+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 4.75, + "teardown": 2.14, + "total": 6.89 + } }, "tests/aws/services/dynamodb/test_dynamodb.py::TestDynamoDB::test_dynamodb_create_table_with_partial_sse_specification": { - "last_validated_date": "2024-01-10T12:59:50+00:00" + "last_validated_date": "2025-10-08T14:03:41+00:00", + "durations_in_seconds": { + "setup": 0.67, + "call": 7.68, + "teardown": 0.3, + "total": 8.65 + } + }, + "tests/aws/services/dynamodb/test_dynamodb.py::TestDynamoDB::test_dynamodb_describe_contributor_insights": { + "last_validated_date": "2025-10-08T12:46:55+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 6.54, + "teardown": 0.49, + "total": 7.03 + } }, "tests/aws/services/dynamodb/test_dynamodb.py::TestDynamoDB::test_dynamodb_execute_statement_empy_parameter": { - "last_validated_date": "2025-01-03T09:24:27+00:00" + "last_validated_date": "2025-10-08T12:33:51+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 6.77, + "teardown": 0.35, + "total": 7.12 + } }, "tests/aws/services/dynamodb/test_dynamodb.py::TestDynamoDB::test_dynamodb_execute_transaction": { - "last_validated_date": "2023-08-23T14:32:44+00:00" + "last_validated_date": "2025-10-08T12:33:37+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 7.99, + "teardown": 0.41, + "total": 8.4 + } }, "tests/aws/services/dynamodb/test_dynamodb.py::TestDynamoDB::test_dynamodb_get_batch_items": { - "last_validated_date": "2023-08-23T14:33:58+00:00" + "last_validated_date": "2025-10-08T12:37:20+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 4.7, + "teardown": 0.4, + "total": 5.1 + } }, "tests/aws/services/dynamodb/test_dynamodb.py::TestDynamoDB::test_dynamodb_idempotent_writing": { - "last_validated_date": "2023-08-23T14:39:54+00:00" + "last_validated_date": "2025-10-08T12:37:34+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 5.81, + "teardown": 0.42, + "total": 6.23 + } }, "tests/aws/services/dynamodb/test_dynamodb.py::TestDynamoDB::test_dynamodb_partiql_missing": { - "last_validated_date": "2023-08-23T14:33:00+00:00" + "last_validated_date": "2025-10-08T12:33:58+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 6.34, + "teardown": 1.54, + "total": 7.88 + } }, "tests/aws/services/dynamodb/test_dynamodb.py::TestDynamoDB::test_dynamodb_pay_per_request": { - "last_validated_date": "2023-08-23T14:33:43+00:00" + "last_validated_date": "2025-10-08T12:36:20+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.18, + "teardown": 0.17, + "total": 0.35 + } }, "tests/aws/services/dynamodb/test_dynamodb.py::TestDynamoDB::test_dynamodb_stream_records_with_update_item": { "last_validated_date": "2024-06-26T14:28:26+00:00" }, "tests/aws/services/dynamodb/test_dynamodb.py::TestDynamoDB::test_dynamodb_stream_stream_view_type": { - "last_validated_date": "2024-05-31T14:49:56+00:00" + "last_validated_date": "2025-10-08T12:34:09+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 10.26, + "teardown": 0.38, + "total": 10.64 + } }, "tests/aws/services/dynamodb/test_dynamodb.py::TestDynamoDB::test_dynamodb_streams_describe_with_exclusive_start_shard_id": { - "last_validated_date": "2023-10-22T20:27:28+00:00" + "last_validated_date": "2025-10-08T12:37:28+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 6.84, + "teardown": 0.46, + "total": 7.3 + } }, "tests/aws/services/dynamodb/test_dynamodb.py::TestDynamoDB::test_dynamodb_update_table_without_sse_specification_change": { - "last_validated_date": "2024-12-17T10:39:19+00:00" + "last_validated_date": "2025-10-08T14:06:57+00:00", + "durations_in_seconds": { + "setup": 0.77, + "call": 7.22, + "teardown": 39.29, + "total": 47.28 + } }, "tests/aws/services/dynamodb/test_dynamodb.py::TestDynamoDB::test_empty_and_binary_values": { - "last_validated_date": "2023-08-23T14:32:29+00:00" + "last_validated_date": "2025-10-08T12:33:22+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 6.36, + "teardown": 0.0, + "total": 6.36 + } }, "tests/aws/services/dynamodb/test_dynamodb.py::TestDynamoDB::test_gsi_with_billing_mode[PAY_PER_REQUEST]": { - "last_validated_date": "2025-01-08T18:17:06+00:00" + "last_validated_date": "2025-10-08T12:46:32+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 14.17, + "teardown": 0.51, + "total": 14.68 + } }, "tests/aws/services/dynamodb/test_dynamodb.py::TestDynamoDB::test_gsi_with_billing_mode[PROVISIONED]": { - "last_validated_date": "2025-01-08T18:17:21+00:00" + "last_validated_date": "2025-10-08T12:46:48+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 15.33, + "teardown": 0.33, + "total": 15.66 + } }, "tests/aws/services/dynamodb/test_dynamodb.py::TestDynamoDB::test_kinesis_streaming_destination_crud": { "last_validated_date": "2025-07-23T13:31:04+00:00", @@ -78,33 +219,120 @@ } }, "tests/aws/services/dynamodb/test_dynamodb.py::TestDynamoDB::test_return_values_in_put_item": { - "last_validated_date": "2023-08-23T14:32:21+00:00" + "last_validated_date": "2025-10-08T12:33:15+00:00", + "durations_in_seconds": { + "setup": 6.35, + "call": 0.92, + "teardown": 0.19, + "total": 7.46 + } }, "tests/aws/services/dynamodb/test_dynamodb.py::TestDynamoDB::test_return_values_on_conditions_check_failure": { - "last_validated_date": "2024-01-03T17:52:19+00:00" + "last_validated_date": "2025-10-08T12:45:55+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 6.6, + "teardown": 0.34, + "total": 6.94 + } + }, + "tests/aws/services/dynamodb/test_dynamodb.py::TestDynamoDB::test_stream_destination_records": { + "last_validated_date": "2025-10-08T12:45:49+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 468.26, + "teardown": 0.62, + "total": 468.88 + } }, "tests/aws/services/dynamodb/test_dynamodb.py::TestDynamoDB::test_streams_on_global_tables": { - "last_validated_date": "2025-05-22T12:44:55+00:00" + "last_validated_date": "2025-10-08T12:35:17+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 64.24, + "teardown": 3.24, + "total": 67.48 + } + }, + "tests/aws/services/dynamodb/test_dynamodb.py::TestDynamoDB::test_table_crud": { + "last_validated_date": "2025-10-08T12:35:32+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 6.7, + "teardown": 0.21, + "total": 6.91 + } + }, + "tests/aws/services/dynamodb/test_dynamodb.py::TestDynamoDB::test_table_warm_throughput": { + "last_validated_date": "2025-10-08T12:35:39+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 6.84, + "teardown": 0.33, + "total": 7.17 + } }, "tests/aws/services/dynamodb/test_dynamodb.py::TestDynamoDB::test_transact_get_items": { - "last_validated_date": "2023-08-23T14:33:37+00:00" + "last_validated_date": "2026-01-08T19:22:29+00:00", + "durations_in_seconds": { + "setup": 0.66, + "call": 17.33, + "teardown": 0.67, + "total": 18.66 + } }, "tests/aws/services/dynamodb/test_dynamodb.py::TestDynamoDB::test_transact_write_items_streaming": { - "last_validated_date": "2024-05-31T14:47:04+00:00" + "last_validated_date": "2025-10-08T12:46:04+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 8.54, + "teardown": 0.32, + "total": 8.86 + } }, "tests/aws/services/dynamodb/test_dynamodb.py::TestDynamoDB::test_transact_write_items_streaming_for_different_tables": { - "last_validated_date": "2024-04-02T21:45:36+00:00" + "last_validated_date": "2025-10-08T12:46:18+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 12.7, + "teardown": 0.77, + "total": 13.47 + } }, "tests/aws/services/dynamodb/test_dynamodb.py::TestDynamoDB::test_transaction_write_binary_data": { - "last_validated_date": "2023-08-23T14:33:31+00:00" + "last_validated_date": "2025-10-08T12:35:59+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 7.62, + "teardown": 0.33, + "total": 7.95 + } }, "tests/aws/services/dynamodb/test_dynamodb.py::TestDynamoDB::test_transaction_write_canceled": { - "last_validated_date": "2023-08-23T14:33:24+00:00" + "last_validated_date": "2025-10-08T12:35:51+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 5.79, + "teardown": 0.4, + "total": 6.19 + } }, "tests/aws/services/dynamodb/test_dynamodb.py::TestDynamoDB::test_transaction_write_items": { - "last_validated_date": "2023-08-23T14:33:16+00:00" + "last_validated_date": "2026-01-07T10:30:09+00:00", + "durations_in_seconds": { + "setup": 0.62, + "call": 13.46, + "teardown": 0.55, + "total": 14.63 + } }, "tests/aws/services/dynamodb/test_dynamodb.py::TestDynamoDB::test_valid_local_secondary_index": { - "last_validated_date": "2023-08-23T14:32:11+00:00" + "last_validated_date": "2025-10-08T12:33:08+00:00", + "durations_in_seconds": { + "setup": 0.89, + "call": 8.17, + "teardown": 0.49, + "total": 9.55 + } } } diff --git a/tests/aws/services/dynamodbstreams/test_dynamodb_streams.py b/tests/aws/services/dynamodbstreams/test_dynamodb_streams.py index cb1eb03fe0154..65d132c406d6c 100644 --- a/tests/aws/services/dynamodbstreams/test_dynamodb_streams.py +++ b/tests/aws/services/dynamodbstreams/test_dynamodb_streams.py @@ -24,7 +24,6 @@ class TestDynamoDBStreams: paths=[ "$..Table.ProvisionedThroughput.LastDecreaseDateTime", "$..Table.ProvisionedThroughput.LastIncreaseDateTime", - "$..Table.Replicas", ] ) def test_table_v2_stream(self, aws_client, infrastructure_setup, snapshot): diff --git a/tests/aws/services/dynamodbstreams/test_dynamodb_streams.snapshot.json b/tests/aws/services/dynamodbstreams/test_dynamodb_streams.snapshot.json index 129c09529015e..3d1602474b5d0 100644 --- a/tests/aws/services/dynamodbstreams/test_dynamodb_streams.snapshot.json +++ b/tests/aws/services/dynamodbstreams/test_dynamodb_streams.snapshot.json @@ -35,7 +35,7 @@ } }, "tests/aws/services/dynamodbstreams/test_dynamodb_streams.py::TestDynamoDBStreams::test_table_v2_stream": { - "recorded-date": "12-06-2024, 21:57:48", + "recorded-date": "13-10-2025, 19:03:15", "recorded-content": { "global-table-v2": { "Table": { @@ -73,7 +73,12 @@ "TableId": "", "TableName": "", "TableSizeBytes": 0, - "TableStatus": "" + "TableStatus": "", + "WarmThroughput": { + "ReadUnitsPerSecond": 12000, + "Status": "", + "WriteUnitsPerSecond": 4000 + } }, "ResponseMetadata": { "HTTPHeaders": {}, diff --git a/tests/aws/services/dynamodbstreams/test_dynamodb_streams.validation.json b/tests/aws/services/dynamodbstreams/test_dynamodb_streams.validation.json index da11f399f14e0..22c9c9d7fa3c0 100644 --- a/tests/aws/services/dynamodbstreams/test_dynamodb_streams.validation.json +++ b/tests/aws/services/dynamodbstreams/test_dynamodb_streams.validation.json @@ -6,6 +6,12 @@ "last_validated_date": "2024-11-20T11:02:24+00:00" }, "tests/aws/services/dynamodbstreams/test_dynamodb_streams.py::TestDynamoDBStreams::test_table_v2_stream": { - "last_validated_date": "2024-06-12T21:57:48+00:00" + "last_validated_date": "2025-10-13T19:03:15+00:00", + "durations_in_seconds": { + "setup": 0.47, + "call": 52.37, + "teardown": 0.01, + "total": 52.85 + } } } diff --git a/tests/aws/services/ec2/test_ec2.py b/tests/aws/services/ec2/test_ec2.py index a9e0ae8e70ec9..589576154c875 100644 --- a/tests/aws/services/ec2/test_ec2.py +++ b/tests/aws/services/ec2/test_ec2.py @@ -4,7 +4,6 @@ import pytest from botocore.exceptions import ClientError from localstack_snapshot.snapshots.transformer import SortingTransformer -from moto.ec2.models import ec2_backends from moto.ec2.utils import ( random_security_group_id, random_subnet_id, @@ -668,6 +667,7 @@ def test_create_subnet_with_custom_id_and_vpc_id(self, cleanups, aws_client, cre assert subnet["Tags"][0]["Key"] == TAG_KEY_CUSTOM_ID assert subnet["Tags"][0]["Value"] == custom_subnet_id + @markers.requires_in_process @markers.aws.only_localstack @pytest.mark.parametrize("strategy", ["tag", "id_manager"]) @pytest.mark.parametrize("default_vpc", [True, False]) @@ -984,28 +984,7 @@ def test_raise_duplicate_launch_template_name(create_launch_template): assert e.value.response["Error"]["Code"] == "InvalidLaunchTemplateName.AlreadyExistsException" -@pytest.fixture -def pickle_backends(): - def _can_pickle(*args) -> bool: - import dill - - try: - for i in args: - dill.dumps(i) - except TypeError: - return False - return True - - return _can_pickle - - -@markers.aws.only_localstack -def test_pickle_ec2_backend(pickle_backends, aws_client): - _ = aws_client.ec2.describe_account_attributes() - pickle_backends(ec2_backends) - assert pickle_backends(ec2_backends) - - +@markers.requires_in_process @markers.aws.only_localstack def test_create_specific_vpc_id(account_id, region_name, create_vpc, set_resource_custom_id): cidr_block = "10.0.0.0/16" diff --git a/tests/aws/services/es/test_es.py b/tests/aws/services/es/test_es.py index c8f1118edbbb5..4cb8c3c3246d1 100644 --- a/tests/aws/services/es/test_es.py +++ b/tests/aws/services/es/test_es.py @@ -11,6 +11,8 @@ elasticsearch_package, opensearch_package, ) +from localstack.testing import config as test_config +from localstack.testing.aws.util import is_aws_cloud from localstack.testing.pytest import markers from localstack.utils.common import safe_requests as requests from localstack.utils.common import short_uid, start_worker_thread @@ -50,11 +52,14 @@ def run_install(*args): @pytest.fixture(autouse=True) def elasticsearch(): + if is_aws_cloud() or test_config.TEST_SKIP_LOCALSTACK_START: + # we don't install the dependencies if LocalStack is not running in process + return + if not installed.is_set(): install_async() assert installed.wait(timeout=5 * 60), "gave up waiting for elasticsearch to install" - yield def try_cluster_health(cluster_url: str): diff --git a/tests/aws/services/events/event_pattern_templates/content_anything_but_ignorecase_list_missing_NEG.json5 b/tests/aws/services/events/event_pattern_templates/content_anything_but_ignorecase_list_missing_NEG.json5 new file mode 100644 index 0000000000000..bfcefe970b6e8 --- /dev/null +++ b/tests/aws/services/events/event_pattern_templates/content_anything_but_ignorecase_list_missing_NEG.json5 @@ -0,0 +1,17 @@ +// Based on https://docs.aws.amazon.com/eventbridge/latest/userguide/eb-event-patterns-content-based-filtering.html#eb-filtering-anything-but +{ + "Event": { + "id": "1", + "source": "test-source", + "detail-type": "test-detail-type", + "account": "123456789012", + "region": "us-east-2", + "time": "2022-07-13T13:48:01Z", + "detail": {} + }, + "EventPattern": { + "detail": { + "state" : [{ "anything-but": { "equals-ignore-case": ["initializing", "stopped"] }}] + } + } +} diff --git a/tests/aws/services/events/event_pattern_templates/content_anything_but_ignorecase_list_null.json5 b/tests/aws/services/events/event_pattern_templates/content_anything_but_ignorecase_list_null.json5 new file mode 100644 index 0000000000000..1ad070e089648 --- /dev/null +++ b/tests/aws/services/events/event_pattern_templates/content_anything_but_ignorecase_list_null.json5 @@ -0,0 +1,19 @@ +// Based on https://docs.aws.amazon.com/eventbridge/latest/userguide/eb-event-patterns-content-based-filtering.html#eb-filtering-anything-but +{ + "Event": { + "id": "1", + "source": "test-source", + "detail-type": "test-detail-type", + "account": "123456789012", + "region": "us-east-2", + "time": "2022-07-13T13:48:01Z", + "detail": { + "state": null + } + }, + "EventPattern": { + "detail": { + "state" : [{ "anything-but": { "equals-ignore-case": ["initializing", "stopped"] }}] + } + } +} diff --git a/tests/aws/services/events/event_pattern_templates/content_anything_but_ignorecase_missing_NEG.json5 b/tests/aws/services/events/event_pattern_templates/content_anything_but_ignorecase_missing_NEG.json5 new file mode 100644 index 0000000000000..de4dd8683bbb4 --- /dev/null +++ b/tests/aws/services/events/event_pattern_templates/content_anything_but_ignorecase_missing_NEG.json5 @@ -0,0 +1,17 @@ +// Based on https://docs.aws.amazon.com/eventbridge/latest/userguide/eb-event-patterns-content-based-filtering.html#eb-filtering-anything-but +{ + "Event": { + "id": "1", + "source": "test-source", + "detail-type": "test-detail-type", + "account": "123456789012", + "region": "us-east-2", + "time": "2022-07-13T13:48:01Z", + "detail": {} + }, + "EventPattern": { + "detail": { + "state" : [{ "anything-but": { "equals-ignore-case": "initializing" }}] + } + } +} diff --git a/tests/aws/services/events/event_pattern_templates/content_anything_but_ignorecase_null.json5 b/tests/aws/services/events/event_pattern_templates/content_anything_but_ignorecase_null.json5 new file mode 100644 index 0000000000000..1767b0a6fff44 --- /dev/null +++ b/tests/aws/services/events/event_pattern_templates/content_anything_but_ignorecase_null.json5 @@ -0,0 +1,19 @@ +// Based on https://docs.aws.amazon.com/eventbridge/latest/userguide/eb-event-patterns-content-based-filtering.html#eb-filtering-anything-but +{ + "Event": { + "id": "1", + "source": "test-source", + "detail-type": "test-detail-type", + "account": "123456789012", + "region": "us-east-2", + "time": "2022-07-13T13:48:01Z", + "detail": { + "state": null + } + }, + "EventPattern": { + "detail": { + "state" : [{ "anything-but": { "equals-ignore-case": "initializing" }}] + } + } +} diff --git a/tests/aws/services/events/event_pattern_templates/content_anything_but_string_list_missing_NEG.json5 b/tests/aws/services/events/event_pattern_templates/content_anything_but_string_list_missing_NEG.json5 new file mode 100644 index 0000000000000..f0801cb59d4ab --- /dev/null +++ b/tests/aws/services/events/event_pattern_templates/content_anything_but_string_list_missing_NEG.json5 @@ -0,0 +1,17 @@ +// Based on https://docs.aws.amazon.com/eventbridge/latest/userguide/eb-event-patterns-content-based-filtering.html#eb-filtering-anything-but +{ + "Event": { + "id": "1", + "source": "test-source", + "detail-type": "test-detail-type", + "account": "123456789012", + "region": "us-east-2", + "time": "2022-07-13T13:48:01Z", + "detail": {} + }, + "EventPattern": { + "detail": { + "state": [ { "anything-but": [ "stopped", "overloaded" ] } ] + } + } +} diff --git a/tests/aws/services/events/event_pattern_templates/content_anything_but_string_list_null.json5 b/tests/aws/services/events/event_pattern_templates/content_anything_but_string_list_null.json5 new file mode 100644 index 0000000000000..a0267aa546757 --- /dev/null +++ b/tests/aws/services/events/event_pattern_templates/content_anything_but_string_list_null.json5 @@ -0,0 +1,19 @@ +// Based on https://docs.aws.amazon.com/eventbridge/latest/userguide/eb-event-patterns-content-based-filtering.html#eb-filtering-anything-but +{ + "Event": { + "id": "1", + "source": "test-source", + "detail-type": "test-detail-type", + "account": "123456789012", + "region": "us-east-2", + "time": "2022-07-13T13:48:01Z", + "detail": { + "state": null + } + }, + "EventPattern": { + "detail": { + "state": [ { "anything-but": [ "stopped", "running" ] } ] + } + } +} diff --git a/tests/aws/services/events/event_pattern_templates/content_anything_but_string_list_null_type_EXC.json5 b/tests/aws/services/events/event_pattern_templates/content_anything_but_string_list_null_type_EXC.json5 new file mode 100644 index 0000000000000..3bbef69085000 --- /dev/null +++ b/tests/aws/services/events/event_pattern_templates/content_anything_but_string_list_null_type_EXC.json5 @@ -0,0 +1,19 @@ +// Based on https://docs.aws.amazon.com/eventbridge/latest/userguide/eb-event-patterns-content-based-filtering.html#eb-filtering-anything-but +{ + "Event": { + "id": "1", + "source": "test-source", + "detail-type": "test-detail-type", + "account": "123456789012", + "region": "us-east-2", + "time": "2022-07-13T13:48:01Z", + "detail": { + "state": "pending" + } + }, + "EventPattern": { + "detail": { + "state": [ { "anything-but": [ "stopped", null ] } ] + } + } +} diff --git a/tests/aws/services/events/event_pattern_templates/content_anything_but_string_missing_NEG.json5 b/tests/aws/services/events/event_pattern_templates/content_anything_but_string_missing_NEG.json5 new file mode 100644 index 0000000000000..f9c051678cfe0 --- /dev/null +++ b/tests/aws/services/events/event_pattern_templates/content_anything_but_string_missing_NEG.json5 @@ -0,0 +1,17 @@ +// Based on https://docs.aws.amazon.com/eventbridge/latest/userguide/eb-event-patterns-content-based-filtering.html#eb-filtering-anything-but +{ + "Event": { + "id": "1", + "source": "test-source", + "detail-type": "test-detail-type", + "account": "123456789012", + "region": "us-east-2", + "time": "2022-07-13T13:48:01Z", + "detail": {} + }, + "EventPattern": { + "detail": { + "state": [ { "anything-but": "initializing" } ] + } + } +} diff --git a/tests/aws/services/events/event_pattern_templates/content_anything_but_string_null_type_EXC.json5 b/tests/aws/services/events/event_pattern_templates/content_anything_but_string_null_type_EXC.json5 new file mode 100644 index 0000000000000..5445373362fae --- /dev/null +++ b/tests/aws/services/events/event_pattern_templates/content_anything_but_string_null_type_EXC.json5 @@ -0,0 +1,19 @@ +// Based on https://docs.aws.amazon.com/eventbridge/latest/userguide/eb-event-patterns-content-based-filtering.html#eb-filtering-anything-but +{ + "Event": { + "id": "1", + "source": "test-source", + "detail-type": "test-detail-type", + "account": "123456789012", + "region": "us-east-2", + "time": "2022-07-13T13:48:01Z", + "detail": { + "state": null + } + }, + "EventPattern": { + "detail": { + "state": [ { "anything-but": null } ] + } + } +} diff --git a/tests/aws/services/events/event_pattern_templates/content_anything_prefix_int_value.json5 b/tests/aws/services/events/event_pattern_templates/content_anything_prefix_int_value.json5 new file mode 100644 index 0000000000000..98c949e5d6efb --- /dev/null +++ b/tests/aws/services/events/event_pattern_templates/content_anything_prefix_int_value.json5 @@ -0,0 +1,19 @@ +// Based on https://docs.aws.amazon.com/eventbridge/latest/userguide/eb-event-patterns-content-based-filtering.html#eb-filtering-anything-but +{ + "Event": { + "id": "1", + "source": "test-source", + "detail-type": "test-detail-type", + "account": "123456789012", + "region": "us-east-2", + "time": "2022-07-13T13:48:01Z", + "detail": { + "state": 12 + } + }, + "EventPattern": { + "detail": { + "state": [ { "anything-but": { "prefix": "init" } } ] + } + } +} diff --git a/tests/aws/services/events/event_pattern_templates/content_anything_prefix_list_int.json5 b/tests/aws/services/events/event_pattern_templates/content_anything_prefix_list_int.json5 new file mode 100644 index 0000000000000..dfc91d45784d0 --- /dev/null +++ b/tests/aws/services/events/event_pattern_templates/content_anything_prefix_list_int.json5 @@ -0,0 +1,19 @@ +// Based on https://docs.aws.amazon.com/eventbridge/latest/userguide/eb-event-patterns-content-based-filtering.html#eb-filtering-anything-but +{ + "Event": { + "id": "1", + "source": "test-source", + "detail-type": "test-detail-type", + "account": "123456789012", + "region": "us-east-2", + "time": "2022-07-13T13:48:01Z", + "detail": { + "state": 12 + } + }, + "EventPattern": { + "detail": { + "state": [ { "anything-but": { "prefix": ["init", "test"] } } ] + } + } +} diff --git a/tests/aws/services/events/event_pattern_templates/content_anything_prefix_list_missing_NEG.json5 b/tests/aws/services/events/event_pattern_templates/content_anything_prefix_list_missing_NEG.json5 new file mode 100644 index 0000000000000..89d953c3cf0d1 --- /dev/null +++ b/tests/aws/services/events/event_pattern_templates/content_anything_prefix_list_missing_NEG.json5 @@ -0,0 +1,17 @@ +// Based on https://docs.aws.amazon.com/eventbridge/latest/userguide/eb-event-patterns-content-based-filtering.html#eb-filtering-anything-but +{ + "Event": { + "id": "1", + "source": "test-source", + "detail-type": "test-detail-type", + "account": "123456789012", + "region": "us-east-2", + "time": "2022-07-13T13:48:01Z", + "detail": {} + }, + "EventPattern": { + "detail": { + "state": [ { "anything-but": { "prefix": ["init", "post"] } } ] + } + } +} diff --git a/tests/aws/services/events/event_pattern_templates/content_anything_prefix_list_null.json5 b/tests/aws/services/events/event_pattern_templates/content_anything_prefix_list_null.json5 new file mode 100644 index 0000000000000..38269ae490e32 --- /dev/null +++ b/tests/aws/services/events/event_pattern_templates/content_anything_prefix_list_null.json5 @@ -0,0 +1,19 @@ +// Based on https://docs.aws.amazon.com/eventbridge/latest/userguide/eb-event-patterns-content-based-filtering.html#eb-filtering-anything-but +{ + "Event": { + "id": "1", + "source": "test-source", + "detail-type": "test-detail-type", + "account": "123456789012", + "region": "us-east-2", + "time": "2022-07-13T13:48:01Z", + "detail": { + "state": null + } + }, + "EventPattern": { + "detail": { + "state": [ { "anything-but": { "prefix": ["init", "test"] } } ] + } + } +} diff --git a/tests/aws/services/events/event_pattern_templates/content_anything_prefix_missing_NEG.json5 b/tests/aws/services/events/event_pattern_templates/content_anything_prefix_missing_NEG.json5 new file mode 100644 index 0000000000000..5495b5b2d9642 --- /dev/null +++ b/tests/aws/services/events/event_pattern_templates/content_anything_prefix_missing_NEG.json5 @@ -0,0 +1,17 @@ +// Based on https://docs.aws.amazon.com/eventbridge/latest/userguide/eb-event-patterns-content-based-filtering.html#eb-filtering-anything-but +{ + "Event": { + "id": "1", + "source": "test-source", + "detail-type": "test-detail-type", + "account": "123456789012", + "region": "us-east-2", + "time": "2022-07-13T13:48:01Z", + "detail": {} + }, + "EventPattern": { + "detail": { + "state": [ { "anything-but": { "prefix": "init" } } ] + } + } +} diff --git a/tests/aws/services/events/event_pattern_templates/content_anything_prefix_null.json5 b/tests/aws/services/events/event_pattern_templates/content_anything_prefix_null.json5 new file mode 100644 index 0000000000000..5e6eac0e8522c --- /dev/null +++ b/tests/aws/services/events/event_pattern_templates/content_anything_prefix_null.json5 @@ -0,0 +1,19 @@ +// Based on https://docs.aws.amazon.com/eventbridge/latest/userguide/eb-event-patterns-content-based-filtering.html#eb-filtering-anything-but +{ + "Event": { + "id": "1", + "source": "test-source", + "detail-type": "test-detail-type", + "account": "123456789012", + "region": "us-east-2", + "time": "2022-07-13T13:48:01Z", + "detail": { + "state": null + } + }, + "EventPattern": { + "detail": { + "state": [ { "anything-but": { "prefix": "init" } } ] + } + } +} diff --git a/tests/aws/services/events/event_pattern_templates/content_anything_suffix_list_missing_NEG.json5 b/tests/aws/services/events/event_pattern_templates/content_anything_suffix_list_missing_NEG.json5 new file mode 100644 index 0000000000000..a1d44c76c52cd --- /dev/null +++ b/tests/aws/services/events/event_pattern_templates/content_anything_suffix_list_missing_NEG.json5 @@ -0,0 +1,17 @@ +// Based on https://docs.aws.amazon.com/eventbridge/latest/userguide/eb-event-patterns-content-based-filtering.html#eb-filtering-anything-but +{ + "Event": { + "id": "1", + "source": "test-source", + "detail-type": "test-detail-type", + "account": "123456789012", + "region": "us-east-2", + "time": "2022-07-13T13:48:01Z", + "detail": {} + }, + "EventPattern": { + "detail": { + "FileName": [ { "anything-but": { "suffix": [".txt", ".jpg"] } } ] + } + } +} diff --git a/tests/aws/services/events/event_pattern_templates/content_anything_suffix_list_null.json5 b/tests/aws/services/events/event_pattern_templates/content_anything_suffix_list_null.json5 new file mode 100644 index 0000000000000..ebd6b6c1f16f3 --- /dev/null +++ b/tests/aws/services/events/event_pattern_templates/content_anything_suffix_list_null.json5 @@ -0,0 +1,19 @@ +// Based on https://docs.aws.amazon.com/eventbridge/latest/userguide/eb-event-patterns-content-based-filtering.html#eb-filtering-anything-but +{ + "Event": { + "id": "1", + "source": "test-source", + "detail-type": "test-detail-type", + "account": "123456789012", + "region": "us-east-2", + "time": "2022-07-13T13:48:01Z", + "detail": { + "FileName": null + } + }, + "EventPattern": { + "detail": { + "FileName": [ { "anything-but": { "suffix": [".txt", ".jpg"] } } ] + } + } +} diff --git a/tests/aws/services/events/event_pattern_templates/content_anything_suffix_list_null_type_EXC.json5 b/tests/aws/services/events/event_pattern_templates/content_anything_suffix_list_null_type_EXC.json5 new file mode 100644 index 0000000000000..70c01f5e1c6ae --- /dev/null +++ b/tests/aws/services/events/event_pattern_templates/content_anything_suffix_list_null_type_EXC.json5 @@ -0,0 +1,19 @@ +// Based on https://docs.aws.amazon.com/eventbridge/latest/userguide/eb-event-patterns-content-based-filtering.html#eb-filtering-anything-but +{ + "Event": { + "id": "1", + "source": "test-source", + "detail-type": "test-detail-type", + "account": "123456789012", + "region": "us-east-2", + "time": "2022-07-13T13:48:01Z", + "detail": { + "FileName": "file.txt.bak" + } + }, + "EventPattern": { + "detail": { + "FileName": [ { "anything-but": { "suffix": [null, ".txt"] } } ] + } + } +} diff --git a/tests/aws/services/events/event_pattern_templates/content_anything_suffix_missing_NEG.json5 b/tests/aws/services/events/event_pattern_templates/content_anything_suffix_missing_NEG.json5 new file mode 100644 index 0000000000000..0b250afca0b84 --- /dev/null +++ b/tests/aws/services/events/event_pattern_templates/content_anything_suffix_missing_NEG.json5 @@ -0,0 +1,17 @@ +// Based on https://docs.aws.amazon.com/eventbridge/latest/userguide/eb-event-patterns-content-based-filtering.html#eb-filtering-anything-but +{ + "Event": { + "id": "1", + "source": "test-source", + "detail-type": "test-detail-type", + "account": "123456789012", + "region": "us-east-2", + "time": "2022-07-13T13:48:01Z", + "detail": {} + }, + "EventPattern": { + "detail": { + "FileName": [ { "anything-but": { "suffix": ".txt" } } ] + } + } +} diff --git a/tests/aws/services/events/event_pattern_templates/content_anything_suffix_null.json5 b/tests/aws/services/events/event_pattern_templates/content_anything_suffix_null.json5 new file mode 100644 index 0000000000000..69cf795fbed84 --- /dev/null +++ b/tests/aws/services/events/event_pattern_templates/content_anything_suffix_null.json5 @@ -0,0 +1,19 @@ +// Based on https://docs.aws.amazon.com/eventbridge/latest/userguide/eb-event-patterns-content-based-filtering.html#eb-filtering-anything-but +{ + "Event": { + "id": "1", + "source": "test-source", + "detail-type": "test-detail-type", + "account": "123456789012", + "region": "us-east-2", + "time": "2022-07-13T13:48:01Z", + "detail": { + "FileName": null + } + }, + "EventPattern": { + "detail": { + "FileName": [ { "anything-but": { "suffix": ".txt" } } ] + } + } +} diff --git a/tests/aws/services/events/event_pattern_templates/content_anything_wildcard_int.json5 b/tests/aws/services/events/event_pattern_templates/content_anything_wildcard_int.json5 new file mode 100644 index 0000000000000..efc2c6bf92bd8 --- /dev/null +++ b/tests/aws/services/events/event_pattern_templates/content_anything_wildcard_int.json5 @@ -0,0 +1,19 @@ +// Based on https://docs.aws.amazon.com/eventbridge/latest/userguide/eb-event-patterns-content-based-filtering.html#eb-filtering-anything-but +{ + "Event": { + "id": "1", + "source": "test-source", + "detail-type": "test-detail-type", + "account": "123456789012", + "region": "us-east-2", + "time": "2022-07-13T13:48:01Z", + "detail": { + "FilePath": 123 + } + }, + "EventPattern": { + "detail": { + "FilePath": [ { "anything-but": { "wildcard": "*/dir/*" } } ] + } + } +} diff --git a/tests/aws/services/events/event_pattern_templates/content_anything_wildcard_list_missing_NEG.json5 b/tests/aws/services/events/event_pattern_templates/content_anything_wildcard_list_missing_NEG.json5 new file mode 100644 index 0000000000000..4455f194e5e15 --- /dev/null +++ b/tests/aws/services/events/event_pattern_templates/content_anything_wildcard_list_missing_NEG.json5 @@ -0,0 +1,17 @@ +// Based on https://docs.aws.amazon.com/eventbridge/latest/userguide/eb-event-patterns-content-based-filtering.html#eb-filtering-anything-but +{ + "Event": { + "id": "1", + "source": "test-source", + "detail-type": "test-detail-type", + "account": "123456789012", + "region": "us-east-2", + "time": "2022-07-13T13:48:01Z", + "detail": {} + }, + "EventPattern": { + "detail": { + "state": [ { "anything-but": { "wildcard": ["*/init/*", "*/dir/*"] } } ] + } + } +} diff --git a/tests/aws/services/events/event_pattern_templates/content_anything_wildcard_list_null.json5 b/tests/aws/services/events/event_pattern_templates/content_anything_wildcard_list_null.json5 new file mode 100644 index 0000000000000..7c9e91cd5096b --- /dev/null +++ b/tests/aws/services/events/event_pattern_templates/content_anything_wildcard_list_null.json5 @@ -0,0 +1,19 @@ +// Based on https://docs.aws.amazon.com/eventbridge/latest/userguide/eb-event-patterns-content-based-filtering.html#eb-filtering-anything-but +{ + "Event": { + "id": "1", + "source": "test-source", + "detail-type": "test-detail-type", + "account": "123456789012", + "region": "us-east-2", + "time": "2022-07-13T13:48:01Z", + "detail": { + "state": null + } + }, + "EventPattern": { + "detail": { + "state": [ { "anything-but": { "wildcard": ["*/init/*", "*/dir/*"] } } ] + } + } +} diff --git a/tests/aws/services/events/event_pattern_templates/content_anything_wildcard_missing_NEG.json5 b/tests/aws/services/events/event_pattern_templates/content_anything_wildcard_missing_NEG.json5 new file mode 100644 index 0000000000000..b03e6dbbb15bd --- /dev/null +++ b/tests/aws/services/events/event_pattern_templates/content_anything_wildcard_missing_NEG.json5 @@ -0,0 +1,17 @@ +// Based on https://docs.aws.amazon.com/eventbridge/latest/userguide/eb-event-patterns-content-based-filtering.html#eb-filtering-anything-but +{ + "Event": { + "id": "1", + "source": "test-source", + "detail-type": "test-detail-type", + "account": "123456789012", + "region": "us-east-2", + "time": "2022-07-13T13:48:01Z", + "detail": {} + }, + "EventPattern": { + "detail": { + "FilePath": [ { "anything-but": { "wildcard": "*/init/*" } } ] + } + } +} diff --git a/tests/aws/services/events/event_pattern_templates/content_anything_wildcard_null.json5 b/tests/aws/services/events/event_pattern_templates/content_anything_wildcard_null.json5 new file mode 100644 index 0000000000000..606da0a9675b2 --- /dev/null +++ b/tests/aws/services/events/event_pattern_templates/content_anything_wildcard_null.json5 @@ -0,0 +1,19 @@ +// Based on https://docs.aws.amazon.com/eventbridge/latest/userguide/eb-event-patterns-content-based-filtering.html#eb-filtering-anything-but +{ + "Event": { + "id": "1", + "source": "test-source", + "detail-type": "test-detail-type", + "account": "123456789012", + "region": "us-east-2", + "time": "2022-07-13T13:48:01Z", + "detail": { + "FilePath": null + } + }, + "EventPattern": { + "detail": { + "FilePath": [ { "anything-but": { "wildcard": "*/dir/*" } } ] + } + } +} diff --git a/tests/aws/services/events/event_pattern_templates/content_ip_address_bad_type_NEG.json5 b/tests/aws/services/events/event_pattern_templates/content_ip_address_bad_type_NEG.json5 new file mode 100644 index 0000000000000..0f1dbb8e7fb96 --- /dev/null +++ b/tests/aws/services/events/event_pattern_templates/content_ip_address_bad_type_NEG.json5 @@ -0,0 +1,19 @@ +// Based on https://docs.aws.amazon.com/eventbridge/latest/userguide/eb-event-patterns-content-based-filtering.html#eb-filtering-ip-matching +{ + "Event": { + "id": "1", + "source": "test-source", + "detail-type": "test-detail-type", + "account": "123456789012", + "region": "us-east-2", + "time": "2022-07-13T13:48:01Z", + "detail": { + "sourceIPAddress": 123 + } + }, + "EventPattern": { + "detail": { + "sourceIPAddress": [ { "cidr": "10.0.0.0/24" } ] + } + } +} diff --git a/tests/aws/services/events/test_events.py b/tests/aws/services/events/test_events.py index 67cfbd6d426fa..26e920f870132 100644 --- a/tests/aws/services/events/test_events.py +++ b/tests/aws/services/events/test_events.py @@ -40,6 +40,7 @@ "payload": {"acc_id": "0a787ecb-4015", "sf_id": "baz"}, "listsingle": ["HIGH"], "listmulti": ["ACTIVE", "INACTIVE"], + "valid": True, } TEST_EVENT_DETAIL = { diff --git a/tests/aws/services/events/test_events_inputs.py b/tests/aws/services/events/test_events_inputs.py index 68c9925d16985..4f1ef2ffc9cc7 100644 --- a/tests/aws/services/events/test_events_inputs.py +++ b/tests/aws/services/events/test_events_inputs.py @@ -500,6 +500,7 @@ def test_input_transformer_predefined_variables( '{"multi_replacement": "users//second/"}', # TODO known limitation due to sqs message handling sting with new line # '" single list item\n multiple list items"', + '"Command is !"', ], ) def test_input_transformer_nested_keys_replacement( @@ -529,6 +530,7 @@ def test_input_transformer_nested_keys_replacement( "systemstring": "$.detail.awsAccountId", # with resolve to empty value "listsingle": "$.detail.listsingle", "listmulti": "$.detail.listmulti", + "valid": "$.detail.valid", } input_transformer = { "InputPathsMap": input_path_map, diff --git a/tests/aws/services/events/test_events_inputs.snapshot.json b/tests/aws/services/events/test_events_inputs.snapshot.json index cf6ee9653ff58..5f401e3d1fcfe 100644 --- a/tests/aws/services/events/test_events_inputs.snapshot.json +++ b/tests/aws/services/events/test_events_inputs.snapshot.json @@ -511,5 +511,18 @@ } ] } + }, + "tests/aws/services/events/test_events_inputs.py::TestInputTransformer::test_input_transformer_nested_keys_replacement[\"Command is !\"]": { + "recorded-date": "08-10-2025, 09:20:09", + "recorded-content": { + "input-transformed-messages": [ + { + "MessageId": "", + "ReceiptHandle": "", + "MD5OfBody": "", + "Body": "\"Command is true!\"" + } + ] + } } } diff --git a/tests/aws/services/events/test_events_inputs.validation.json b/tests/aws/services/events/test_events_inputs.validation.json index 7a2e137c1e527..67442bda914da 100644 --- a/tests/aws/services/events/test_events_inputs.validation.json +++ b/tests/aws/services/events/test_events_inputs.validation.json @@ -1,104 +1,275 @@ { "tests/aws/services/events/test_events_inputs.py::TestInputPath::test_put_events_with_input_path": { - "last_validated_date": "2024-05-13T12:27:07+00:00" + "last_validated_date": "2025-10-08T11:09:55+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 1.27, + "teardown": 1.23, + "total": 2.5 + } }, "tests/aws/services/events/test_events_inputs.py::TestInputPath::test_put_events_with_input_path_max_level_depth": { - "last_validated_date": "2024-05-13T12:27:13+00:00" + "last_validated_date": "2025-10-08T11:10:02+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 1.25, + "teardown": 1.03, + "total": 2.28 + } }, "tests/aws/services/events/test_events_inputs.py::TestInputPath::test_put_events_with_input_path_multiple_targets": { - "last_validated_date": "2024-05-13T12:27:16+00:00" + "last_validated_date": "2025-10-08T11:10:05+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 1.95, + "teardown": 1.43, + "total": 3.38 + } }, "tests/aws/services/events/test_events_inputs.py::TestInputPath::test_put_events_with_input_path_nested[event_detail0]": { - "last_validated_date": "2024-05-13T12:27:09+00:00" + "last_validated_date": "2025-10-08T11:09:57+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 1.27, + "teardown": 1.01, + "total": 2.28 + } }, "tests/aws/services/events/test_events_inputs.py::TestInputPath::test_put_events_with_input_path_nested[event_detail1]": { - "last_validated_date": "2024-05-13T12:27:11+00:00" + "last_validated_date": "2025-10-08T11:09:59+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 1.24, + "teardown": 1.01, + "total": 2.25 + } }, "tests/aws/services/events/test_events_inputs.py::TestInputTransformer::test_input_transformer_nested_keys_replacement": { "last_validated_date": "2024-12-06T11:07:17+00:00" }, "tests/aws/services/events/test_events_inputs.py::TestInputTransformer::test_input_transformer_nested_keys_replacement[\" multiple list items\"]": { - "last_validated_date": "2024-12-13T18:03:28+00:00" + "last_validated_date": "2025-10-08T11:10:49+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 1.3, + "teardown": 1.06, + "total": 2.36 + } }, "tests/aws/services/events/test_events_inputs.py::TestInputTransformer::test_input_transformer_nested_keys_replacement[\" single list item multiple list items system account id payload user id\"]": { - "last_validated_date": "2024-12-13T18:03:32+00:00" + "last_validated_date": "2025-10-08T11:10:54+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 1.28, + "teardown": 1.05, + "total": 2.33 + } }, "tests/aws/services/events/test_events_inputs.py::TestInputTransformer::test_input_transformer_nested_keys_replacement[\" single list item\"\\n\" multiple list items\"\\n\" system account id\"\\n\" payload\"\\n\" user id\"]": { "last_validated_date": "2024-12-13T17:27:50+00:00" }, "tests/aws/services/events/test_events_inputs.py::TestInputTransformer::test_input_transformer_nested_keys_replacement[\" single list item\"]": { - "last_validated_date": "2024-12-13T18:03:25+00:00" + "last_validated_date": "2025-10-08T11:10:47+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 1.29, + "teardown": 1.05, + "total": 2.34 + } + }, + "tests/aws/services/events/test_events_inputs.py::TestInputTransformer::test_input_transformer_nested_keys_replacement[\"Command is !\"]": { + "last_validated_date": "2025-10-08T11:11:00+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 1.28, + "teardown": 1.14, + "total": 2.42 + } }, "tests/aws/services/events/test_events_inputs.py::TestInputTransformer::test_input_transformer_nested_keys_replacement[\"Payload of with path users-service/users/ and \"]": { - "last_validated_date": "2024-12-13T18:03:14+00:00" + "last_validated_date": "2025-10-08T11:10:32+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 1.26, + "teardown": 1.16, + "total": 2.42 + } }, "tests/aws/services/events/test_events_inputs.py::TestInputTransformer::test_input_transformer_nested_keys_replacement[\"Payload of with path users-service/users/\"]": { "last_validated_date": "2024-12-13T13:20:30+00:00" }, "tests/aws/services/events/test_events_inputs.py::TestInputTransformer::test_input_transformer_nested_keys_replacement[{\"id\" : \"\"}]": { - "last_validated_date": "2024-12-16T12:26:02+00:00" + "last_validated_date": "2025-10-08T11:10:37+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 1.24, + "teardown": 1.08, + "total": 2.32 + } }, "tests/aws/services/events/test_events_inputs.py::TestInputTransformer::test_input_transformer_nested_keys_replacement[{\"id\" : }]": { - "last_validated_date": "2024-12-13T18:03:16+00:00" + "last_validated_date": "2025-10-08T11:10:35+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 1.28, + "teardown": 1.03, + "total": 2.31 + } }, "tests/aws/services/events/test_events_inputs.py::TestInputTransformer::test_input_transformer_nested_keys_replacement[{\"id\": }]": { "last_validated_date": "2024-12-13T14:56:24+00:00" }, "tests/aws/services/events/test_events_inputs.py::TestInputTransformer::test_input_transformer_nested_keys_replacement[{\"method\": \"PUT\", \"nested\": {\"level1\": {\"level2\": {\"level3\": \"users-service/users/\"} } }, \"bod\": \"\"}]": { - "last_validated_date": "2024-12-13T18:03:23+00:00" + "last_validated_date": "2025-10-08T11:10:45+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 1.38, + "teardown": 1.04, + "total": 2.42 + } }, "tests/aws/services/events/test_events_inputs.py::TestInputTransformer::test_input_transformer_nested_keys_replacement[{\"method\": \"PUT\", \"path\": \"users-service/users/\", \"bod\": \"\"}]": { "last_validated_date": "2024-12-13T13:20:32+00:00" }, "tests/aws/services/events/test_events_inputs.py::TestInputTransformer::test_input_transformer_nested_keys_replacement[{\"method\": \"PUT\", \"path\": \"users-service/users/\", \"bod\": }]": { - "last_validated_date": "2024-12-13T18:03:12+00:00" + "last_validated_date": "2025-10-08T11:10:30+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 1.46, + "teardown": 1.06, + "total": 2.52 + } }, "tests/aws/services/events/test_events_inputs.py::TestInputTransformer::test_input_transformer_nested_keys_replacement[{\"method\": \"PUT\", \"path\": \"users-service/users/\", \"bod\": [, \"hardcoded\"]}]": { - "last_validated_date": "2024-12-13T18:03:21+00:00" + "last_validated_date": "2025-10-08T11:10:42+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 1.47, + "teardown": 1.53, + "total": 3.0 + } }, "tests/aws/services/events/test_events_inputs.py::TestInputTransformer::test_input_transformer_nested_keys_replacement[{\"method\": \"PUT\", \"path\": \"users-service/users/\", \"id\": \"\", \"body\": }]": { "last_validated_date": "2024-12-13T14:54:39+00:00" }, "tests/aws/services/events/test_events_inputs.py::TestInputTransformer::test_input_transformer_nested_keys_replacement[{\"method\": \"PUT\", \"path\": \"users-service/users/\", \"id\": , \"body\": }]": { - "last_validated_date": "2024-12-13T18:03:18+00:00" + "last_validated_date": "2025-10-08T11:10:39+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 1.28, + "teardown": 1.02, + "total": 2.3 + } }, "tests/aws/services/events/test_events_inputs.py::TestInputTransformer::test_input_transformer_nested_keys_replacement[{\"multi_replacement\": \"users//second/\"}]": { - "last_validated_date": "2024-12-13T18:03:35+00:00" + "last_validated_date": "2025-10-08T11:10:57+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 1.92, + "teardown": 1.05, + "total": 2.97 + } }, "tests/aws/services/events/test_events_inputs.py::TestInputTransformer::test_input_transformer_nested_keys_replacement[{\"singlelistitem\": }]": { - "last_validated_date": "2024-12-13T18:03:30+00:00" + "last_validated_date": "2025-10-08T11:10:52+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 1.28, + "teardown": 1.17, + "total": 2.45 + } }, "tests/aws/services/events/test_events_inputs.py::TestInputTransformer::test_input_transformer_nested_keys_replacement_not_valid[{\"not_valid\": \"users-service/users/\", \"bod\": }]": { - "last_validated_date": "2024-12-13T14:55:05+00:00" + "last_validated_date": "2025-10-08T11:11:07+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 6.22, + "teardown": 1.08, + "total": 7.3 + } }, "tests/aws/services/events/test_events_inputs.py::TestInputTransformer::test_input_transformer_nested_keys_replacement_not_valid[{\"payload\": \"\"}]": { - "last_validated_date": "2024-12-13T14:55:13+00:00" + "last_validated_date": "2025-10-08T11:11:14+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 6.17, + "teardown": 1.06, + "total": 7.23 + } }, "tests/aws/services/events/test_events_inputs.py::TestInputTransformer::test_input_transformer_nested_keys_replacement_not_valid[{\"singlelistitem\": \"\"}]": { - "last_validated_date": "2024-12-13T17:19:20+00:00" + "last_validated_date": "2025-10-08T11:11:22+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 6.17, + "teardown": 1.52, + "total": 7.69 + } }, "tests/aws/services/events/test_events_inputs.py::TestInputTransformer::test_input_transformer_predefined_variables[\"Message containing all pre defined variables \"]": { - "last_validated_date": "2024-06-11T08:33:10+00:00" + "last_validated_date": "2025-10-08T11:10:25+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 1.71, + "teardown": 1.15, + "total": 2.86 + } }, "tests/aws/services/events/test_events_inputs.py::TestInputTransformer::test_input_transformer_predefined_variables[{\"originalEvent\": , \"originalEventJson\": }]": { - "last_validated_date": "2024-06-11T08:33:13+00:00" + "last_validated_date": "2025-10-08T11:10:27+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 1.34, + "teardown": 1.02, + "total": 2.36 + } }, "tests/aws/services/events/test_events_inputs.py::TestInputTransformer::test_put_events_with_input_transformer_input_template_json": { - "last_validated_date": "2024-06-11T08:33:04+00:00" + "last_validated_date": "2025-10-08T11:10:20+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 3.1, + "teardown": 2.07, + "total": 5.17 + } }, "tests/aws/services/events/test_events_inputs.py::TestInputTransformer::test_put_events_with_input_transformer_input_template_string": { "last_validated_date": "2024-05-13T12:27:20+00:00" }, "tests/aws/services/events/test_events_inputs.py::TestInputTransformer::test_put_events_with_input_transformer_input_template_string[\"Event of type, at time , info extracted from detail \"]": { - "last_validated_date": "2024-06-11T08:32:56+00:00" + "last_validated_date": "2025-10-08T11:10:10+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 2.6, + "teardown": 2.31, + "total": 4.91 + } }, "tests/aws/services/events/test_events_inputs.py::TestInputTransformer::test_put_events_with_input_transformer_input_template_string[\"{[/Check with special starting characters for event of type\"]": { - "last_validated_date": "2024-06-11T08:33:00+00:00" + "last_validated_date": "2025-10-08T11:10:15+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 2.76, + "teardown": 2.05, + "total": 4.81 + } }, "tests/aws/services/events/test_events_inputs.py::TestInputTransformer::test_put_events_with_input_transformer_missing_keys": { - "last_validated_date": "2025-03-12T10:19:13+00:00" + "last_validated_date": "2025-10-08T11:10:22+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 1.3, + "teardown": 0.91, + "total": 2.21 + } }, "tests/aws/services/events/test_events_inputs.py::test_put_event_input_path_and_input_transformer": { - "last_validated_date": "2025-03-12T10:19:01+00:00" + "last_validated_date": "2025-10-08T11:09:52+00:00", + "durations_in_seconds": { + "setup": 0.58, + "call": 1.76, + "teardown": 1.39, + "total": 3.73 + } } } diff --git a/tests/aws/services/events/test_events_patterns.snapshot.json b/tests/aws/services/events/test_events_patterns.snapshot.json index 3dbc5cd4f1301..dd25607688d8e 100644 --- a/tests/aws/services/events/test_events_patterns.snapshot.json +++ b/tests/aws/services/events/test_events_patterns.snapshot.json @@ -1,22 +1,22 @@ { "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_wildcard_repeating]": { - "recorded-date": "22-01-2025, 10:56:14", + "recorded-date": "15-10-2025, 13:11:55", "recorded-content": {} }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[list_within_dict]": { - "recorded-date": "22-01-2025, 10:56:14", + "recorded-date": "15-10-2025, 13:11:56", "recorded-content": {} }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_suffix_NEG]": { - "recorded-date": "22-01-2025, 10:56:14", + "recorded-date": "15-10-2025, 13:11:56", "recorded-content": {} }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[complex_multi_match]": { - "recorded-date": "22-01-2025, 10:56:15", + "recorded-date": "15-10-2025, 13:11:56", "recorded-content": {} }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[int_nolist_EXC]": { - "recorded-date": "22-01-2025, 10:56:15", + "recorded-date": "15-10-2025, 13:11:56", "recorded-content": { "int_nolist_EXC": { "exception_message": { @@ -35,39 +35,39 @@ } }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[arrays]": { - "recorded-date": "22-01-2025, 10:56:17", + "recorded-date": "15-10-2025, 13:11:58", "recorded-content": {} }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_wildcard_repeating_NEG]": { - "recorded-date": "22-01-2025, 10:56:17", + "recorded-date": "15-10-2025, 13:11:59", "recorded-content": {} }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_but_ignorecase_list_NEG]": { - "recorded-date": "22-01-2025, 10:56:17", + "recorded-date": "15-10-2025, 13:11:59", "recorded-content": {} }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_wildcard_simplified]": { - "recorded-date": "22-01-2025, 10:56:17", + "recorded-date": "15-10-2025, 13:11:59", "recorded-content": {} }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[or-exists]": { - "recorded-date": "22-01-2025, 10:56:17", + "recorded-date": "15-10-2025, 13:11:59", "recorded-content": {} }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_wildcard_nonrepeating]": { - "recorded-date": "22-01-2025, 10:56:17", + "recorded-date": "15-10-2025, 13:11:59", "recorded-content": {} }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[complex_multi_match_NEG]": { - "recorded-date": "22-01-2025, 10:56:18", + "recorded-date": "15-10-2025, 13:12:00", "recorded-content": {} }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_but_string]": { - "recorded-date": "22-01-2025, 10:56:18", + "recorded-date": "15-10-2025, 13:12:00", "recorded-content": {} }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_numeric_operatorcasing_EXC]": { - "recorded-date": "22-01-2025, 10:56:18", + "recorded-date": "15-10-2025, 13:12:01", "recorded-content": { "content_numeric_operatorcasing_EXC": { "exception_message": { @@ -86,19 +86,19 @@ } }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_but_number_list_NEG]": { - "recorded-date": "22-01-2025, 10:56:19", + "recorded-date": "15-10-2025, 13:12:01", "recorded-content": {} }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_ip_address]": { - "recorded-date": "22-01-2025, 10:56:19", + "recorded-date": "15-10-2025, 13:12:02", "recorded-content": {} }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_prefix_NEG]": { - "recorded-date": "22-01-2025, 10:56:19", + "recorded-date": "15-10-2025, 13:12:02", "recorded-content": {} }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[string_nolist_EXC]": { - "recorded-date": "22-01-2025, 10:56:20", + "recorded-date": "15-10-2025, 13:12:02", "recorded-content": { "string_nolist_EXC": { "exception_message": { @@ -117,27 +117,27 @@ } }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[exists_dynamodb_NEG]": { - "recorded-date": "22-01-2025, 10:56:20", + "recorded-date": "15-10-2025, 13:12:03", "recorded-content": {} }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_but_string_NEG]": { - "recorded-date": "22-01-2025, 10:56:20", + "recorded-date": "15-10-2025, 13:12:03", "recorded-content": {} }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[boolean_NEG]": { - "recorded-date": "22-01-2025, 10:56:20", + "recorded-date": "15-10-2025, 13:12:03", "recorded-content": {} }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[exists_dynamodb]": { - "recorded-date": "22-01-2025, 10:56:20", + "recorded-date": "15-10-2025, 13:12:03", "recorded-content": {} }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[or-exists-parent]": { - "recorded-date": "22-01-2025, 10:56:21", + "recorded-date": "15-10-2025, 13:12:03", "recorded-content": {} }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[arrays_empty_EXC]": { - "recorded-date": "22-01-2025, 10:56:21", + "recorded-date": "15-10-2025, 13:12:03", "recorded-content": { "arrays_empty_EXC": { "exception_message": { @@ -156,55 +156,55 @@ } }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[nested_json_NEG]": { - "recorded-date": "22-01-2025, 10:56:21", + "recorded-date": "15-10-2025, 13:12:04", "recorded-content": {} }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[dot_joining_pattern]": { - "recorded-date": "22-01-2025, 10:56:21", + "recorded-date": "15-10-2025, 13:12:04", "recorded-content": {} }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[operator_multiple_list]": { - "recorded-date": "22-01-2025, 10:56:21", + "recorded-date": "15-10-2025, 13:12:04", "recorded-content": {} }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_but_string_list]": { - "recorded-date": "22-01-2025, 10:56:21", + "recorded-date": "15-10-2025, 13:12:04", "recorded-content": {} }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[dynamodb]": { - "recorded-date": "22-01-2025, 10:56:22", + "recorded-date": "15-10-2025, 13:12:05", "recorded-content": {} }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_but_ignorecase]": { - "recorded-date": "22-01-2025, 10:56:22", + "recorded-date": "15-10-2025, 13:12:05", "recorded-content": {} }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[string_empty]": { - "recorded-date": "22-01-2025, 10:56:22", + "recorded-date": "15-10-2025, 13:12:05", "recorded-content": {} }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[complex_many_rules]": { - "recorded-date": "22-01-2025, 10:56:22", + "recorded-date": "15-10-2025, 13:12:05", "recorded-content": {} }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[null_value]": { - "recorded-date": "22-01-2025, 10:56:23", + "recorded-date": "15-10-2025, 13:12:06", "recorded-content": {} }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_but_number_list]": { - "recorded-date": "22-01-2025, 10:56:23", + "recorded-date": "15-10-2025, 13:12:06", "recorded-content": {} }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_wildcard_nonrepeating_NEG]": { - "recorded-date": "22-01-2025, 10:56:23", + "recorded-date": "15-10-2025, 13:12:07", "recorded-content": {} }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_but_number_NEG]": { - "recorded-date": "22-01-2025, 10:56:23", + "recorded-date": "15-10-2025, 13:12:07", "recorded-content": {} }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[operator_case_sensitive_EXC]": { - "recorded-date": "22-01-2025, 10:56:24", + "recorded-date": "15-10-2025, 13:12:07", "recorded-content": { "operator_case_sensitive_EXC": { "exception_message": { @@ -223,15 +223,15 @@ } }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_exists]": { - "recorded-date": "22-01-2025, 10:56:24", + "recorded-date": "15-10-2025, 13:12:07", "recorded-content": {} }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_ip_address_NEG]": { - "recorded-date": "22-01-2025, 10:56:24", + "recorded-date": "15-10-2025, 13:12:07", "recorded-content": {} }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_numeric_EXC]": { - "recorded-date": "22-01-2025, 10:56:25", + "recorded-date": "15-10-2025, 13:12:09", "recorded-content": { "content_numeric_EXC": { "exception_message": { @@ -250,87 +250,87 @@ } }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[complex_or_NEG]": { - "recorded-date": "22-01-2025, 10:56:25", + "recorded-date": "15-10-2025, 13:12:09", "recorded-content": {} }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[complex_or]": { - "recorded-date": "22-01-2025, 10:56:25", + "recorded-date": "15-10-2025, 13:12:09", "recorded-content": {} }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_numeric_and_NEG]": { - "recorded-date": "22-01-2025, 10:56:26", + "recorded-date": "15-10-2025, 13:12:10", "recorded-content": {} }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[dot_joining_event]": { - "recorded-date": "22-01-2025, 10:56:26", + "recorded-date": "15-10-2025, 13:12:10", "recorded-content": {} }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_suffix_NEG]": { - "recorded-date": "22-01-2025, 10:56:26", + "recorded-date": "15-10-2025, 13:12:10", "recorded-content": {} }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_prefix_ignorecase]": { - "recorded-date": "22-01-2025, 10:56:27", + "recorded-date": "15-10-2025, 13:12:11", "recorded-content": {} }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_suffix_ignorecase]": { - "recorded-date": "22-01-2025, 10:56:27", + "recorded-date": "15-10-2025, 13:12:11", "recorded-content": {} }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[null_value_NEG]": { - "recorded-date": "22-01-2025, 10:56:27", + "recorded-date": "15-10-2025, 13:12:11", "recorded-content": {} }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[dot_joining_pattern_NEG]": { - "recorded-date": "22-01-2025, 10:56:27", + "recorded-date": "15-10-2025, 13:12:11", "recorded-content": {} }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_prefix]": { - "recorded-date": "22-01-2025, 10:56:27", + "recorded-date": "15-10-2025, 13:12:11", "recorded-content": {} }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[sample1]": { - "recorded-date": "22-01-2025, 10:56:27", + "recorded-date": "15-10-2025, 13:12:12", "recorded-content": {} }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[key_case_sensitive_NEG]": { - "recorded-date": "22-01-2025, 10:56:27", + "recorded-date": "15-10-2025, 13:12:12", "recorded-content": {} }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[dot_joining_event_NEG]": { - "recorded-date": "22-01-2025, 10:56:27", + "recorded-date": "15-10-2025, 13:12:12", "recorded-content": {} }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[prefix]": { - "recorded-date": "22-01-2025, 10:56:28", + "recorded-date": "15-10-2025, 13:12:12", "recorded-content": {} }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_suffix]": { - "recorded-date": "22-01-2025, 10:56:28", + "recorded-date": "15-10-2025, 13:12:13", "recorded-content": {} }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_but_ignorecase_list]": { - "recorded-date": "22-01-2025, 10:56:29", + "recorded-date": "15-10-2025, 13:12:14", "recorded-content": {} }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_prefix_NEG]": { - "recorded-date": "22-01-2025, 10:56:29", + "recorded-date": "15-10-2025, 13:12:14", "recorded-content": {} }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[string]": { - "recorded-date": "22-01-2025, 10:56:29", + "recorded-date": "15-10-2025, 13:12:15", "recorded-content": {} }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[arrays_empty_null_NEG]": { - "recorded-date": "22-01-2025, 10:56:30", + "recorded-date": "15-10-2025, 13:12:15", "recorded-content": {} }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_suffix_ignorecase_NEG]": { - "recorded-date": "22-01-2025, 10:56:30", + "recorded-date": "15-10-2025, 13:12:16", "recorded-content": {} }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_wildcard_complex_EXC]": { - "recorded-date": "22-01-2025, 10:56:31", + "recorded-date": "15-10-2025, 13:12:16", "recorded-content": { "content_wildcard_complex_EXC": { "exception_message": { @@ -349,55 +349,55 @@ } }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_but_string_list_NEG]": { - "recorded-date": "22-01-2025, 10:56:32", + "recorded-date": "15-10-2025, 13:12:18", "recorded-content": {} }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_prefix]": { - "recorded-date": "22-01-2025, 10:56:33", + "recorded-date": "15-10-2025, 13:12:19", "recorded-content": {} }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_ignorecase_NEG]": { - "recorded-date": "22-01-2025, 10:56:33", + "recorded-date": "15-10-2025, 13:12:19", "recorded-content": {} }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[minimal]": { - "recorded-date": "22-01-2025, 10:56:33", + "recorded-date": "15-10-2025, 13:12:19", "recorded-content": {} }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_exists_false]": { - "recorded-date": "22-01-2025, 10:56:34", + "recorded-date": "15-10-2025, 13:12:21", "recorded-content": {} }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[number_comparison_float]": { - "recorded-date": "22-01-2025, 10:56:35", + "recorded-date": "15-10-2025, 13:12:21", "recorded-content": {} }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_but_ignorecase_NEG]": { - "recorded-date": "22-01-2025, 10:56:35", + "recorded-date": "15-10-2025, 13:12:22", "recorded-content": {} }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_suffix]": { - "recorded-date": "22-01-2025, 10:56:35", + "recorded-date": "15-10-2025, 13:12:22", "recorded-content": {} }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[arrays_NEG]": { - "recorded-date": "22-01-2025, 10:56:36", + "recorded-date": "15-10-2025, 13:12:23", "recorded-content": {} }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_ignorecase]": { - "recorded-date": "22-01-2025, 10:56:37", + "recorded-date": "15-10-2025, 13:12:24", "recorded-content": {} }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_exists_false_NEG]": { - "recorded-date": "22-01-2025, 10:56:37", + "recorded-date": "15-10-2025, 13:12:24", "recorded-content": {} }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_exists_NEG]": { - "recorded-date": "22-01-2025, 10:56:37", + "recorded-date": "15-10-2025, 13:12:24", "recorded-content": {} }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_numeric_syntax_EXC]": { - "recorded-date": "22-01-2025, 10:56:38", + "recorded-date": "15-10-2025, 13:12:25", "recorded-content": { "content_numeric_syntax_EXC": { "exception_message": { @@ -416,19 +416,19 @@ } }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_numeric_and]": { - "recorded-date": "22-01-2025, 10:56:38", + "recorded-date": "15-10-2025, 13:12:25", "recorded-content": {} }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[boolean]": { - "recorded-date": "22-01-2025, 10:56:38", + "recorded-date": "15-10-2025, 13:12:25", "recorded-content": {} }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_but_number]": { - "recorded-date": "22-01-2025, 10:56:38", + "recorded-date": "15-10-2025, 13:12:26", "recorded-content": {} }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[or-anything-but]": { - "recorded-date": "22-01-2025, 10:56:38", + "recorded-date": "15-10-2025, 13:12:26", "recorded-content": {} }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern_source": { @@ -580,7 +580,7 @@ } }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_wildcard_repeating_star_EXC]": { - "recorded-date": "22-01-2025, 10:56:17", + "recorded-date": "15-10-2025, 13:12:00", "recorded-content": { "content_wildcard_repeating_star_EXC": { "exception_message": { @@ -599,7 +599,7 @@ } }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_ignorecase_EXC]": { - "recorded-date": "22-01-2025, 10:56:23", + "recorded-date": "15-10-2025, 13:12:06", "recorded-content": { "content_ignorecase_EXC": { "exception_message": { @@ -618,7 +618,7 @@ } }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_ip_address_EXC]": { - "recorded-date": "22-01-2025, 10:56:34", + "recorded-date": "15-10-2025, 13:12:20", "recorded-content": { "content_ip_address_EXC": { "exception_message": { @@ -637,7 +637,7 @@ } }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_but_ignorecase_EXC]": { - "recorded-date": "22-01-2025, 10:56:24", + "recorded-date": "15-10-2025, 13:12:07", "recorded-content": { "content_anything_but_ignorecase_EXC": { "exception_message": { @@ -656,7 +656,7 @@ } }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_but_ignorecase_list_EXC]": { - "recorded-date": "22-01-2025, 10:56:29", + "recorded-date": "15-10-2025, 13:12:13", "recorded-content": { "content_anything_but_ignorecase_list_EXC": { "exception_message": { @@ -675,7 +675,7 @@ } }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_ignorecase_list_EXC]": { - "recorded-date": "22-01-2025, 10:56:31", + "recorded-date": "15-10-2025, 13:12:17", "recorded-content": { "content_ignorecase_list_EXC": { "exception_message": { @@ -754,27 +754,27 @@ } }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_but_string_null]": { - "recorded-date": "22-01-2025, 10:56:25", + "recorded-date": "15-10-2025, 13:12:09", "recorded-content": {} }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_wildcard_NEG]": { - "recorded-date": "22-01-2025, 10:56:17", + "recorded-date": "15-10-2025, 13:11:59", "recorded-content": {} }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_wildcard_list]": { - "recorded-date": "22-01-2025, 10:56:18", + "recorded-date": "15-10-2025, 13:12:01", "recorded-content": {} }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_wildcard_list_NEG]": { - "recorded-date": "22-01-2025, 10:56:23", + "recorded-date": "15-10-2025, 13:12:06", "recorded-content": {} }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_wildcard]": { - "recorded-date": "22-01-2025, 10:56:34", + "recorded-date": "15-10-2025, 13:12:20", "recorded-content": {} }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_wildcard_int_EXC]": { - "recorded-date": "22-01-2025, 10:56:33", + "recorded-date": "15-10-2025, 13:12:20", "recorded-content": { "content_wildcard_int_EXC": { "exception_message": { @@ -793,7 +793,7 @@ } }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_wildcard_list_EXC]": { - "recorded-date": "22-01-2025, 10:56:36", + "recorded-date": "15-10-2025, 13:12:23", "recorded-content": { "content_wildcard_list_EXC": { "exception_message": { @@ -812,7 +812,7 @@ } }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_wildcard_list_type_EXC]": { - "recorded-date": "22-01-2025, 10:56:16", + "recorded-date": "15-10-2025, 13:11:58", "recorded-content": { "content_anything_wildcard_list_type_EXC": { "exception_message": { @@ -831,7 +831,7 @@ } }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_wildcard_type_EXC]": { - "recorded-date": "22-01-2025, 10:56:32", + "recorded-date": "15-10-2025, 13:12:18", "recorded-content": { "content_anything_wildcard_type_EXC": { "exception_message": { @@ -850,7 +850,7 @@ } }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_suffix_list_type_EXC]": { - "recorded-date": "22-01-2025, 10:56:14", + "recorded-date": "15-10-2025, 13:11:56", "recorded-content": { "content_anything_suffix_list_type_EXC": { "exception_message": { @@ -869,15 +869,15 @@ } }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_prefix_list]": { - "recorded-date": "22-01-2025, 10:56:17", + "recorded-date": "15-10-2025, 13:11:59", "recorded-content": {} }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_prefix_list_NEG]": { - "recorded-date": "22-01-2025, 10:56:17", + "recorded-date": "15-10-2025, 13:11:59", "recorded-content": {} }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_suffix_int_EXC]": { - "recorded-date": "22-01-2025, 10:56:22", + "recorded-date": "15-10-2025, 13:12:05", "recorded-content": { "content_anything_suffix_int_EXC": { "exception_message": { @@ -896,15 +896,15 @@ } }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_suffix_list]": { - "recorded-date": "22-01-2025, 10:56:27", + "recorded-date": "15-10-2025, 13:12:11", "recorded-content": {} }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_suffix_list_NEG]": { - "recorded-date": "22-01-2025, 10:56:31", + "recorded-date": "15-10-2025, 13:12:17", "recorded-content": {} }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_prefix_list_type_EXC]": { - "recorded-date": "22-01-2025, 10:56:33", + "recorded-date": "15-10-2025, 13:12:19", "recorded-content": { "content_anything_prefix_list_type_EXC": { "exception_message": { @@ -923,7 +923,7 @@ } }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_prefix_int_EXC]": { - "recorded-date": "22-01-2025, 10:56:36", + "recorded-date": "15-10-2025, 13:12:22", "recorded-content": { "content_anything_prefix_int_EXC": { "exception_message": { @@ -942,7 +942,7 @@ } }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_prefix_list_EXC]": { - "recorded-date": "22-01-2025, 10:56:19", + "recorded-date": "15-10-2025, 13:12:02", "recorded-content": { "content_prefix_list_EXC": { "exception_message": { @@ -961,7 +961,7 @@ } }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_prefix_int_EXC]": { - "recorded-date": "22-01-2025, 10:56:26", + "recorded-date": "15-10-2025, 13:12:09", "recorded-content": { "content_prefix_int_EXC": { "exception_message": { @@ -980,7 +980,7 @@ } }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_suffix_int_EXC]": { - "recorded-date": "22-01-2025, 10:56:30", + "recorded-date": "15-10-2025, 13:12:16", "recorded-content": { "content_suffix_int_EXC": { "exception_message": { @@ -999,7 +999,7 @@ } }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_suffix_list_EXC]": { - "recorded-date": "22-01-2025, 10:56:34", + "recorded-date": "15-10-2025, 13:12:21", "recorded-content": { "content_suffix_list_EXC": { "exception_message": { @@ -1018,7 +1018,7 @@ } }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_prefix_ignorecase_EXC]": { - "recorded-date": "22-01-2025, 10:56:30", + "recorded-date": "15-10-2025, 13:12:15", "recorded-content": { "content_anything_prefix_ignorecase_EXC": { "exception_message": { @@ -1037,7 +1037,7 @@ } }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_suffix_ignorecase_EXC]": { - "recorded-date": "22-01-2025, 10:56:32", + "recorded-date": "15-10-2025, 13:12:18", "recorded-content": { "content_anything_suffix_ignorecase_EXC": { "exception_message": { @@ -1056,7 +1056,7 @@ } }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_ip_address_bad_mask_EXC]": { - "recorded-date": "22-01-2025, 10:56:15", + "recorded-date": "15-10-2025, 13:11:57", "recorded-content": { "content_ip_address_bad_mask_EXC": { "exception_message": { @@ -1075,15 +1075,15 @@ } }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_ip_address_v6_NEG]": { - "recorded-date": "22-01-2025, 10:56:20", + "recorded-date": "15-10-2025, 13:12:03", "recorded-content": {} }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_ip_address_v6]": { - "recorded-date": "22-01-2025, 10:56:21", + "recorded-date": "15-10-2025, 13:12:04", "recorded-content": {} }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_ip_address_bad_ip_EXC]": { - "recorded-date": "22-01-2025, 10:56:28", + "recorded-date": "15-10-2025, 13:12:12", "recorded-content": { "content_ip_address_bad_ip_EXC": { "exception_message": { @@ -1102,7 +1102,7 @@ } }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_ip_address_type_EXC]": { - "recorded-date": "22-01-2025, 10:56:35", + "recorded-date": "15-10-2025, 13:12:22", "recorded-content": { "content_ip_address_type_EXC": { "exception_message": { @@ -1121,7 +1121,7 @@ } }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_ip_address_v6_bad_ip_EXC]": { - "recorded-date": "22-01-2025, 10:56:37", + "recorded-date": "15-10-2025, 13:12:23", "recorded-content": { "content_ip_address_v6_bad_ip_EXC": { "exception_message": { @@ -1144,7 +1144,7 @@ "recorded-content": {} }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[exists_list_empty_NEG]": { - "recorded-date": "22-01-2025, 10:56:16", + "recorded-date": "15-10-2025, 13:11:58", "recorded-content": {} }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_plain_string_payload": { @@ -1163,15 +1163,15 @@ } }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[or-numeric-anything-but_NEG]": { - "recorded-date": "22-01-2025, 10:56:19", + "recorded-date": "15-10-2025, 13:12:02", "recorded-content": {} }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[or-numeric-anything-but]": { - "recorded-date": "22-01-2025, 10:56:33", + "recorded-date": "15-10-2025, 13:12:19", "recorded-content": {} }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[numeric-string_NEG]": { - "recorded-date": "22-01-2025, 10:56:25", + "recorded-date": "15-10-2025, 13:12:08", "recorded-content": {} }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_invalid_event_payload": { @@ -1190,11 +1190,11 @@ } }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[numeric-null_NEG]": { - "recorded-date": "22-01-2025, 10:56:32", + "recorded-date": "15-10-2025, 13:12:18", "recorded-content": {} }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[numeric-int-float]": { - "recorded-date": "22-01-2025, 10:56:25", + "recorded-date": "15-10-2025, 13:12:09", "recorded-content": {} }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_array_event_payload": { @@ -1213,7 +1213,7 @@ } }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_prefix_empty_EXC]": { - "recorded-date": "22-01-2025, 10:56:14", + "recorded-date": "15-10-2025, 13:11:55", "recorded-content": { "content_anything_prefix_empty_EXC": { "exception_message": { @@ -1232,35 +1232,35 @@ } }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_ignorecase_empty_NEG]": { - "recorded-date": "22-01-2025, 10:56:14", + "recorded-date": "15-10-2025, 13:11:55", "recorded-content": {} }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_prefix_empty]": { - "recorded-date": "22-01-2025, 10:56:15", + "recorded-date": "15-10-2025, 13:11:56", "recorded-content": {} }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_wildcard_empty_NEG]": { - "recorded-date": "22-01-2025, 10:56:16", + "recorded-date": "15-10-2025, 13:11:58", "recorded-content": {} }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_wildcard_empty]": { - "recorded-date": "22-01-2025, 10:56:22", + "recorded-date": "15-10-2025, 13:12:05", "recorded-content": {} }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_ignorecase_empty]": { - "recorded-date": "22-01-2025, 10:56:22", + "recorded-date": "15-10-2025, 13:12:05", "recorded-content": {} }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_but_number_zero]": { - "recorded-date": "22-01-2025, 10:56:27", + "recorded-date": "15-10-2025, 13:12:11", "recorded-content": {} }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_suffix_empty]": { - "recorded-date": "22-01-2025, 10:56:29", + "recorded-date": "15-10-2025, 13:12:14", "recorded-content": {} }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_suffix_empty_EXC]": { - "recorded-date": "22-01-2025, 10:56:37", + "recorded-date": "15-10-2025, 13:12:24", "recorded-content": { "content_anything_suffix_empty_EXC": { "exception_message": { @@ -1279,7 +1279,7 @@ } }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_numeric_number_EXC]": { - "recorded-date": "22-01-2025, 10:56:28", + "recorded-date": "15-10-2025, 13:12:13", "recorded-content": { "content_numeric_number_EXC": { "exception_message": { @@ -1315,5 +1315,154 @@ } } } + }, + "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_suffix_list_null]": { + "recorded-date": "15-10-2025, 13:11:57", + "recorded-content": {} + }, + "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_wildcard_null]": { + "recorded-date": "15-10-2025, 13:11:58", + "recorded-content": {} + }, + "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_but_ignorecase_list_missing_NEG]": { + "recorded-date": "15-10-2025, 13:11:58", + "recorded-content": {} + }, + "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_but_string_list_null]": { + "recorded-date": "15-10-2025, 13:11:59", + "recorded-content": {} + }, + "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_prefix_null]": { + "recorded-date": "15-10-2025, 13:12:01", + "recorded-content": {} + }, + "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_but_string_missing_NEG]": { + "recorded-date": "15-10-2025, 13:12:06", + "recorded-content": {} + }, + "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_but_string_null_type_EXC]": { + "recorded-date": "15-10-2025, 13:12:08", + "recorded-content": { + "content_anything_but_string_null_type_EXC": { + "exception_message": { + "Error": { + "Code": "InvalidEventPatternException", + "Message": "Event pattern is not valid. Reason: Value of anything-but must be an array or single string/number value.", + "MessageRaw": "Event pattern is not valid. Reason: Value of anything-but must be an array or single string/number value.\n at [Source: (String)\"{\"detail\": {\"state\": [{\"anything-but\": null}]}}\"; line: 1, column: 44]" + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + }, + "exception_type": "" + } + } + }, + "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_but_ignorecase_missing_NEG]": { + "recorded-date": "15-10-2025, 13:12:10", + "recorded-content": {} + }, + "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_suffix_list_missing_NEG]": { + "recorded-date": "15-10-2025, 13:12:11", + "recorded-content": {} + }, + "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_but_ignorecase_null]": { + "recorded-date": "15-10-2025, 13:12:11", + "recorded-content": {} + }, + "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_wildcard_list_missing_NEG]": { + "recorded-date": "15-10-2025, 13:12:13", + "recorded-content": {} + }, + "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_but_string_list_null_type_EXC]": { + "recorded-date": "15-10-2025, 13:12:14", + "recorded-content": { + "content_anything_but_string_list_null_type_EXC": { + "exception_message": { + "Error": { + "Code": "InvalidEventPatternException", + "Message": "Event pattern is not valid. Reason: Inside anything but list, start|null|boolean is not supported.", + "MessageRaw": "Event pattern is not valid. Reason: Inside anything but list, start|null|boolean is not supported.\n at [Source: (String)\"{\"detail\": {\"state\": [{\"anything-but\": [\"stopped\", null]}]}}\"; line: 1, column: 56]\n at [Source: (String)\"{\"detail\": {\"state\": [{\"anything-but\": [\"stopped\", null]}]}}\"; line: 1, column: 56]" + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + }, + "exception_type": "" + } + } + }, + "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_wildcard_list_null]": { + "recorded-date": "15-10-2025, 13:12:14", + "recorded-content": {} + }, + "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_suffix_null]": { + "recorded-date": "15-10-2025, 13:12:15", + "recorded-content": {} + }, + "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_suffix_list_null_type_EXC]": { + "recorded-date": "15-10-2025, 13:12:17", + "recorded-content": { + "content_anything_suffix_list_null_type_EXC": { + "exception_message": { + "Error": { + "Code": "InvalidEventPatternException", + "Message": "Event pattern is not valid. Reason: prefix/suffix match pattern must be a string", + "MessageRaw": "Event pattern is not valid. Reason: prefix/suffix match pattern must be a string\n at [Source: (String)\"{\"detail\": {\"FileName\": [{\"anything-but\": {\"suffix\": [null, \".txt\"]}}]}}\"; line: 1, column: 59]\n at [Source: (String)\"{\"detail\": {\"FileName\": [{\"anything-but\": {\"suffix\": [null, \".txt\"]}}]}}\"; line: 1, column: 59]" + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + }, + "exception_type": "" + } + } + }, + "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_wildcard_missing_NEG]": { + "recorded-date": "15-10-2025, 13:12:18", + "recorded-content": {} + }, + "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_suffix_missing_NEG]": { + "recorded-date": "15-10-2025, 13:12:21", + "recorded-content": {} + }, + "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_but_ignorecase_list_null]": { + "recorded-date": "15-10-2025, 13:12:22", + "recorded-content": {} + }, + "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_prefix_list_missing_NEG]": { + "recorded-date": "15-10-2025, 13:12:25", + "recorded-content": {} + }, + "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_prefix_missing_NEG]": { + "recorded-date": "15-10-2025, 13:12:25", + "recorded-content": {} + }, + "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_but_string_list_missing_NEG]": { + "recorded-date": "15-10-2025, 13:12:26", + "recorded-content": {} + }, + "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_prefix_list_null]": { + "recorded-date": "15-10-2025, 13:12:26", + "recorded-content": {} + }, + "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_prefix_int_value]": { + "recorded-date": "15-10-2025, 13:12:01", + "recorded-content": {} + }, + "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_prefix_list_int]": { + "recorded-date": "15-10-2025, 13:12:15", + "recorded-content": {} + }, + "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_ip_address_bad_type_NEG]": { + "recorded-date": "15-10-2025, 13:12:04", + "recorded-content": {} + }, + "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_wildcard_int]": { + "recorded-date": "15-10-2025, 13:12:10", + "recorded-content": {} } } diff --git a/tests/aws/services/events/test_events_patterns.validation.json b/tests/aws/services/events/test_events_patterns.validation.json index e4d69240f1b7a..93c607ce4bfd3 100644 --- a/tests/aws/services/events/test_events_patterns.validation.json +++ b/tests/aws/services/events/test_events_patterns.validation.json @@ -3,394 +3,1402 @@ "last_validated_date": "2024-12-06T09:49:56+00:00" }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[arrays]": { - "last_validated_date": "2025-01-22T10:56:17+00:00" + "last_validated_date": "2025-10-15T13:11:58+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.1, + "teardown": 0.0, + "total": 0.1 + } }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[arrays_NEG]": { - "last_validated_date": "2025-01-22T10:56:36+00:00" + "last_validated_date": "2025-10-15T13:12:23+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.43, + "teardown": 0.0, + "total": 0.43 + } }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[arrays_empty_EXC]": { - "last_validated_date": "2025-01-22T10:56:21+00:00" + "last_validated_date": "2025-10-15T13:12:03+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.11, + "teardown": 0.0, + "total": 0.11 + } }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[arrays_empty_null_NEG]": { - "last_validated_date": "2025-01-22T10:56:30+00:00" + "last_validated_date": "2025-10-15T13:12:15+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.1, + "teardown": 0.0, + "total": 0.1 + } }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[boolean]": { - "last_validated_date": "2025-01-22T10:56:38+00:00" + "last_validated_date": "2025-10-15T13:12:25+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.1, + "teardown": 0.0, + "total": 0.1 + } }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[boolean_NEG]": { - "last_validated_date": "2025-01-22T10:56:20+00:00" + "last_validated_date": "2025-10-15T13:12:03+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.11, + "teardown": 0.0, + "total": 0.11 + } }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[complex_many_rules]": { - "last_validated_date": "2025-01-22T10:56:22+00:00" + "last_validated_date": "2025-10-15T13:12:05+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.11, + "teardown": 0.0, + "total": 0.11 + } }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[complex_multi_match]": { - "last_validated_date": "2025-01-22T10:56:15+00:00" + "last_validated_date": "2025-10-15T13:11:56+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.43, + "teardown": 0.0, + "total": 0.43 + } }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[complex_multi_match_NEG]": { - "last_validated_date": "2025-01-22T10:56:18+00:00" + "last_validated_date": "2025-10-15T13:12:00+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.48, + "teardown": 0.0, + "total": 0.48 + } }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[complex_or]": { - "last_validated_date": "2025-01-22T10:56:25+00:00" + "last_validated_date": "2025-10-15T13:12:09+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.11, + "teardown": 0.0, + "total": 0.11 + } }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[complex_or_NEG]": { - "last_validated_date": "2025-01-22T10:56:25+00:00" + "last_validated_date": "2025-10-15T13:12:09+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.43, + "teardown": 0.0, + "total": 0.43 + } }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_but_ignorecase]": { - "last_validated_date": "2025-01-22T10:56:22+00:00" + "last_validated_date": "2025-10-15T13:12:05+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.1, + "teardown": 0.0, + "total": 0.1 + } }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_but_ignorecase_EXC]": { - "last_validated_date": "2025-01-22T10:56:24+00:00" + "last_validated_date": "2025-10-15T13:12:07+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.11, + "teardown": 0.0, + "total": 0.11 + } }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_but_ignorecase_NEG]": { - "last_validated_date": "2025-01-22T10:56:35+00:00" + "last_validated_date": "2025-10-15T13:12:22+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.53, + "teardown": 0.0, + "total": 0.53 + } }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_but_ignorecase_list]": { - "last_validated_date": "2025-01-22T10:56:29+00:00" + "last_validated_date": "2025-10-15T13:12:14+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.43, + "teardown": 0.0, + "total": 0.43 + } }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_but_ignorecase_list_EXC]": { - "last_validated_date": "2025-01-22T10:56:29+00:00" + "last_validated_date": "2025-10-15T13:12:13+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.55, + "teardown": 0.0, + "total": 0.55 + } }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_but_ignorecase_list_NEG]": { - "last_validated_date": "2025-01-22T10:56:17+00:00" + "last_validated_date": "2025-10-15T13:11:59+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.1, + "teardown": 0.0, + "total": 0.1 + } + }, + "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_but_ignorecase_list_missing_NEG]": { + "last_validated_date": "2025-10-15T13:11:58+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.1, + "teardown": 0.0, + "total": 0.1 + } + }, + "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_but_ignorecase_list_null]": { + "last_validated_date": "2025-10-15T13:12:22+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.1, + "teardown": 0.0, + "total": 0.1 + } + }, + "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_but_ignorecase_missing_NEG]": { + "last_validated_date": "2025-10-15T13:12:10+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.1, + "teardown": 0.0, + "total": 0.1 + } + }, + "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_but_ignorecase_null]": { + "last_validated_date": "2025-10-15T13:12:11+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.1, + "teardown": 0.0, + "total": 0.1 + } }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_but_number]": { - "last_validated_date": "2025-01-22T10:56:38+00:00" + "last_validated_date": "2025-10-15T13:12:26+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.1, + "teardown": 0.0, + "total": 0.1 + } }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_but_number_NEG]": { - "last_validated_date": "2025-01-22T10:56:23+00:00" + "last_validated_date": "2025-10-15T13:12:07+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.1, + "teardown": 0.0, + "total": 0.1 + } }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_but_number_list]": { - "last_validated_date": "2025-01-22T10:56:23+00:00" + "last_validated_date": "2025-10-15T13:12:06+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.1, + "teardown": 0.0, + "total": 0.1 + } }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_but_number_list_NEG]": { - "last_validated_date": "2025-01-22T10:56:19+00:00" + "last_validated_date": "2025-10-15T13:12:01+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.44, + "teardown": 0.0, + "total": 0.44 + } }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_but_number_zero]": { - "last_validated_date": "2025-01-22T10:56:27+00:00" + "last_validated_date": "2025-10-15T13:12:11+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.1, + "teardown": 0.0, + "total": 0.1 + } }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_but_string]": { - "last_validated_date": "2025-01-22T10:56:18+00:00" + "last_validated_date": "2025-10-15T13:12:00+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.1, + "teardown": 0.0, + "total": 0.1 + } }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_but_string_NEG]": { - "last_validated_date": "2025-01-22T10:56:20+00:00" + "last_validated_date": "2025-10-15T13:12:03+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.1, + "teardown": 0.0, + "total": 0.1 + } }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_but_string_list]": { - "last_validated_date": "2025-01-22T10:56:21+00:00" + "last_validated_date": "2025-10-15T13:12:04+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.1, + "teardown": 0.0, + "total": 0.1 + } }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_but_string_list_NEG]": { - "last_validated_date": "2025-01-22T10:56:32+00:00" + "last_validated_date": "2025-10-15T13:12:18+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.43, + "teardown": 0.0, + "total": 0.43 + } + }, + "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_but_string_list_missing_NEG]": { + "last_validated_date": "2025-10-15T13:12:26+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.1, + "teardown": 0.0, + "total": 0.1 + } + }, + "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_but_string_list_null]": { + "last_validated_date": "2025-10-15T13:11:59+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.1, + "teardown": 0.0, + "total": 0.1 + } + }, + "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_but_string_list_null_type_EXC]": { + "last_validated_date": "2025-10-15T13:12:14+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.1, + "teardown": 0.0, + "total": 0.1 + } + }, + "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_but_string_missing_NEG]": { + "last_validated_date": "2025-10-15T13:12:06+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.1, + "teardown": 0.0, + "total": 0.1 + } }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_but_string_null]": { - "last_validated_date": "2025-01-22T10:56:25+00:00" + "last_validated_date": "2025-10-15T13:12:09+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.11, + "teardown": 0.0, + "total": 0.11 + } + }, + "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_but_string_null_type_EXC]": { + "last_validated_date": "2025-10-15T13:12:08+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.43, + "teardown": 0.0, + "total": 0.43 + } }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_prefix]": { - "last_validated_date": "2025-01-22T10:56:27+00:00" + "last_validated_date": "2025-10-15T13:12:11+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.1, + "teardown": 0.0, + "total": 0.1 + } }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_prefix_NEG]": { - "last_validated_date": "2025-01-22T10:56:19+00:00" + "last_validated_date": "2025-10-15T13:12:02+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.1, + "teardown": 0.0, + "total": 0.1 + } }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_prefix_empty_EXC]": { - "last_validated_date": "2025-01-22T10:56:14+00:00" + "last_validated_date": "2025-10-15T13:11:55+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.11, + "teardown": 0.0, + "total": 0.11 + } }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_prefix_ignorecase_EXC]": { - "last_validated_date": "2025-01-22T10:56:30+00:00" + "last_validated_date": "2025-10-15T13:12:15+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.11, + "teardown": 0.0, + "total": 0.11 + } }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_prefix_int_EXC]": { - "last_validated_date": "2025-01-22T10:56:36+00:00" + "last_validated_date": "2025-10-15T13:12:22+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.11, + "teardown": 0.0, + "total": 0.11 + } + }, + "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_prefix_int_value]": { + "last_validated_date": "2025-10-15T13:12:01+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.1, + "teardown": 0.0, + "total": 0.1 + } }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_prefix_list]": { - "last_validated_date": "2025-01-22T10:56:17+00:00" + "last_validated_date": "2025-10-15T13:11:59+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.11, + "teardown": 0.0, + "total": 0.11 + } }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_prefix_list_NEG]": { - "last_validated_date": "2025-01-22T10:56:17+00:00" + "last_validated_date": "2025-10-15T13:11:59+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.1, + "teardown": 0.0, + "total": 0.1 + } + }, + "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_prefix_list_int]": { + "last_validated_date": "2025-10-15T13:12:15+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.1, + "teardown": 0.0, + "total": 0.1 + } + }, + "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_prefix_list_missing_NEG]": { + "last_validated_date": "2025-10-15T13:12:25+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.1, + "teardown": 0.0, + "total": 0.1 + } + }, + "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_prefix_list_null]": { + "last_validated_date": "2025-10-15T13:12:26+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.11, + "teardown": 0.0, + "total": 0.11 + } }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_prefix_list_type_EXC]": { - "last_validated_date": "2025-01-22T10:56:33+00:00" + "last_validated_date": "2025-10-15T13:12:19+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.11, + "teardown": 0.0, + "total": 0.11 + } + }, + "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_prefix_missing_NEG]": { + "last_validated_date": "2025-10-15T13:12:25+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.1, + "teardown": 0.0, + "total": 0.1 + } + }, + "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_prefix_null]": { + "last_validated_date": "2025-10-15T13:12:01+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.1, + "teardown": 0.0, + "total": 0.1 + } }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_suffix]": { - "last_validated_date": "2025-01-22T10:56:28+00:00" + "last_validated_date": "2025-10-15T13:12:13+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.1, + "teardown": 0.0, + "total": 0.1 + } }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_suffix_NEG]": { - "last_validated_date": "2025-01-22T10:56:26+00:00" + "last_validated_date": "2025-10-15T13:12:10+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.1, + "teardown": 0.0, + "total": 0.1 + } }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_suffix_empty_EXC]": { - "last_validated_date": "2025-01-22T10:56:37+00:00" + "last_validated_date": "2025-10-15T13:12:24+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.11, + "teardown": 0.0, + "total": 0.11 + } }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_suffix_ignorecase_EXC]": { - "last_validated_date": "2025-01-22T10:56:32+00:00" + "last_validated_date": "2025-10-15T13:12:18+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.11, + "teardown": 0.0, + "total": 0.11 + } }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_suffix_int_EXC]": { - "last_validated_date": "2025-01-22T10:56:22+00:00" + "last_validated_date": "2025-10-15T13:12:05+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.11, + "teardown": 0.0, + "total": 0.11 + } }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_suffix_list]": { - "last_validated_date": "2025-01-22T10:56:27+00:00" + "last_validated_date": "2025-10-15T13:12:11+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.1, + "teardown": 0.0, + "total": 0.1 + } }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_suffix_list_NEG]": { - "last_validated_date": "2025-01-22T10:56:31+00:00" + "last_validated_date": "2025-10-15T13:12:17+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.46, + "teardown": 0.0, + "total": 0.46 + } + }, + "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_suffix_list_missing_NEG]": { + "last_validated_date": "2025-10-15T13:12:11+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.1, + "teardown": 0.0, + "total": 0.1 + } + }, + "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_suffix_list_null]": { + "last_validated_date": "2025-10-15T13:11:57+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.55, + "teardown": 0.0, + "total": 0.55 + } + }, + "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_suffix_list_null_type_EXC]": { + "last_validated_date": "2025-10-15T13:12:17+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.11, + "teardown": 0.0, + "total": 0.11 + } }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_suffix_list_type_EXC]": { - "last_validated_date": "2025-01-22T10:56:14+00:00" + "last_validated_date": "2025-10-15T13:11:56+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.11, + "teardown": 0.0, + "total": 0.11 + } + }, + "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_suffix_missing_NEG]": { + "last_validated_date": "2025-10-15T13:12:21+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.1, + "teardown": 0.0, + "total": 0.1 + } + }, + "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_suffix_null]": { + "last_validated_date": "2025-10-15T13:12:15+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.1, + "teardown": 0.0, + "total": 0.1 + } }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_wildcard]": { - "last_validated_date": "2025-01-22T10:56:34+00:00" + "last_validated_date": "2025-10-15T13:12:20+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.43, + "teardown": 0.0, + "total": 0.43 + } }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_wildcard_NEG]": { - "last_validated_date": "2025-01-22T10:56:17+00:00" + "last_validated_date": "2025-10-15T13:11:59+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.1, + "teardown": 0.0, + "total": 0.1 + } }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_wildcard_empty]": { - "last_validated_date": "2025-01-22T10:56:22+00:00" + "last_validated_date": "2025-10-15T13:12:05+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.1, + "teardown": 0.0, + "total": 0.1 + } + }, + "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_wildcard_int]": { + "last_validated_date": "2025-10-15T13:12:10+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.1, + "teardown": 0.0, + "total": 0.1 + } }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_wildcard_list]": { - "last_validated_date": "2025-01-22T10:56:18+00:00" + "last_validated_date": "2025-10-15T13:12:01+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.1, + "teardown": 0.0, + "total": 0.1 + } }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_wildcard_list_NEG]": { - "last_validated_date": "2025-01-22T10:56:23+00:00" + "last_validated_date": "2025-10-15T13:12:06+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.1, + "teardown": 0.0, + "total": 0.1 + } + }, + "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_wildcard_list_missing_NEG]": { + "last_validated_date": "2025-10-15T13:12:13+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.1, + "teardown": 0.0, + "total": 0.1 + } + }, + "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_wildcard_list_null]": { + "last_validated_date": "2025-10-15T13:12:14+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.1, + "teardown": 0.0, + "total": 0.1 + } }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_wildcard_list_type_EXC]": { - "last_validated_date": "2025-01-22T10:56:16+00:00" + "last_validated_date": "2025-10-15T13:11:58+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.11, + "teardown": 0.0, + "total": 0.11 + } + }, + "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_wildcard_missing_NEG]": { + "last_validated_date": "2025-10-15T13:12:18+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.43, + "teardown": 0.0, + "total": 0.43 + } + }, + "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_wildcard_null]": { + "last_validated_date": "2025-10-15T13:11:58+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.44, + "teardown": 0.0, + "total": 0.44 + } }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_anything_wildcard_type_EXC]": { - "last_validated_date": "2025-01-22T10:56:32+00:00" + "last_validated_date": "2025-10-15T13:12:18+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.11, + "teardown": 0.0, + "total": 0.11 + } }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_exists]": { - "last_validated_date": "2025-01-22T10:56:24+00:00" + "last_validated_date": "2025-10-15T13:12:07+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.43, + "teardown": 0.0, + "total": 0.43 + } }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_exists_NEG]": { - "last_validated_date": "2025-01-22T10:56:37+00:00" + "last_validated_date": "2025-10-15T13:12:24+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.1, + "teardown": 0.0, + "total": 0.1 + } }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_exists_false]": { - "last_validated_date": "2025-01-22T10:56:34+00:00" + "last_validated_date": "2025-10-15T13:12:21+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.43, + "teardown": 0.01, + "total": 0.44 + } }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_exists_false_NEG]": { - "last_validated_date": "2025-01-22T10:56:37+00:00" + "last_validated_date": "2025-10-15T13:12:24+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.1, + "teardown": 0.0, + "total": 0.1 + } }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_ignorecase]": { - "last_validated_date": "2025-01-22T10:56:37+00:00" + "last_validated_date": "2025-10-15T13:12:24+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.43, + "teardown": 0.01, + "total": 0.44 + } }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_ignorecase_EXC]": { - "last_validated_date": "2025-01-22T10:56:23+00:00" + "last_validated_date": "2025-10-15T13:12:06+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.11, + "teardown": 0.0, + "total": 0.11 + } }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_ignorecase_NEG]": { - "last_validated_date": "2025-01-22T10:56:33+00:00" + "last_validated_date": "2025-10-15T13:12:19+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.1, + "teardown": 0.0, + "total": 0.1 + } }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_ignorecase_empty]": { - "last_validated_date": "2025-01-22T10:56:22+00:00" + "last_validated_date": "2025-10-15T13:12:05+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.1, + "teardown": 0.0, + "total": 0.1 + } }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_ignorecase_empty_NEG]": { - "last_validated_date": "2025-01-22T10:56:14+00:00" + "last_validated_date": "2025-10-15T13:11:55+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.44, + "teardown": 0.0, + "total": 0.44 + } }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_ignorecase_list_EXC]": { - "last_validated_date": "2025-01-22T10:56:31+00:00" + "last_validated_date": "2025-10-15T13:12:17+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.43, + "teardown": 0.0, + "total": 0.43 + } }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_ip_address]": { - "last_validated_date": "2025-01-22T10:56:19+00:00" + "last_validated_date": "2025-10-15T13:12:02+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.43, + "teardown": 0.0, + "total": 0.43 + } }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_ip_address_EXC]": { - "last_validated_date": "2025-01-22T10:56:34+00:00" + "last_validated_date": "2025-10-15T13:12:20+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.1, + "teardown": 0.0, + "total": 0.1 + } }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_ip_address_NEG]": { - "last_validated_date": "2025-01-22T10:56:24+00:00" + "last_validated_date": "2025-10-15T13:12:07+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.11, + "teardown": 0.0, + "total": 0.11 + } }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_ip_address_bad_ip_EXC]": { - "last_validated_date": "2025-01-22T10:56:28+00:00" + "last_validated_date": "2025-10-15T13:12:12+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.1, + "teardown": 0.0, + "total": 0.1 + } }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_ip_address_bad_mask_EXC]": { - "last_validated_date": "2025-01-22T10:56:15+00:00" + "last_validated_date": "2025-10-15T13:11:57+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.1, + "teardown": 0.0, + "total": 0.1 + } + }, + "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_ip_address_bad_type_NEG]": { + "last_validated_date": "2025-10-15T13:12:04+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.43, + "teardown": 0.0, + "total": 0.43 + } }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_ip_address_type_EXC]": { - "last_validated_date": "2025-01-22T10:56:35+00:00" + "last_validated_date": "2025-10-15T13:12:22+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.11, + "teardown": 0.0, + "total": 0.11 + } }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_ip_address_v6]": { - "last_validated_date": "2025-01-22T10:56:21+00:00" + "last_validated_date": "2025-10-15T13:12:04+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.1, + "teardown": 0.0, + "total": 0.1 + } }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_ip_address_v6_NEG]": { - "last_validated_date": "2025-01-22T10:56:20+00:00" + "last_validated_date": "2025-10-15T13:12:03+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.44, + "teardown": 0.0, + "total": 0.44 + } }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_ip_address_v6_bad_ip_EXC]": { - "last_validated_date": "2025-01-22T10:56:37+00:00" + "last_validated_date": "2025-10-15T13:12:23+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.11, + "teardown": 0.0, + "total": 0.11 + } }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_numeric_EXC]": { - "last_validated_date": "2025-01-22T10:56:25+00:00" + "last_validated_date": "2025-10-15T13:12:09+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.11, + "teardown": 0.0, + "total": 0.11 + } }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_numeric_and]": { - "last_validated_date": "2025-01-22T10:56:38+00:00" + "last_validated_date": "2025-10-15T13:12:25+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.43, + "teardown": 0.0, + "total": 0.43 + } }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_numeric_and_NEG]": { - "last_validated_date": "2025-01-22T10:56:26+00:00" + "last_validated_date": "2025-10-15T13:12:10+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.43, + "teardown": 0.0, + "total": 0.43 + } }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_numeric_number_EXC]": { - "last_validated_date": "2025-01-22T10:56:28+00:00" + "last_validated_date": "2025-10-15T13:12:13+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.11, + "teardown": 0.0, + "total": 0.11 + } }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_numeric_operatorcasing_EXC]": { - "last_validated_date": "2025-01-22T10:56:18+00:00" + "last_validated_date": "2025-10-15T13:12:01+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.11, + "teardown": 0.0, + "total": 0.11 + } }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_numeric_syntax_EXC]": { - "last_validated_date": "2025-01-22T10:56:38+00:00" + "last_validated_date": "2025-10-15T13:12:25+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.43, + "teardown": 0.0, + "total": 0.43 + } }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_prefix]": { - "last_validated_date": "2025-01-22T10:56:33+00:00" + "last_validated_date": "2025-10-15T13:12:19+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.48, + "teardown": 0.0, + "total": 0.48 + } }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_prefix_NEG]": { - "last_validated_date": "2025-01-22T10:56:29+00:00" + "last_validated_date": "2025-10-15T13:12:14+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.43, + "teardown": 0.0, + "total": 0.43 + } }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_prefix_empty]": { - "last_validated_date": "2025-01-22T10:56:15+00:00" + "last_validated_date": "2025-10-15T13:11:56+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.11, + "teardown": 0.0, + "total": 0.11 + } }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_prefix_ignorecase]": { - "last_validated_date": "2025-01-22T10:56:27+00:00" + "last_validated_date": "2025-10-15T13:12:11+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.1, + "teardown": 0.0, + "total": 0.1 + } }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_prefix_int_EXC]": { - "last_validated_date": "2025-01-22T10:56:26+00:00" + "last_validated_date": "2025-10-15T13:12:09+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.11, + "teardown": 0.0, + "total": 0.11 + } }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_prefix_list_EXC]": { - "last_validated_date": "2025-01-22T10:56:19+00:00" + "last_validated_date": "2025-10-15T13:12:02+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.11, + "teardown": 0.0, + "total": 0.11 + } }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_suffix]": { - "last_validated_date": "2025-01-22T10:56:35+00:00" + "last_validated_date": "2025-10-15T13:12:22+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.1, + "teardown": 0.0, + "total": 0.1 + } }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_suffix_NEG]": { - "last_validated_date": "2025-01-22T10:56:14+00:00" + "last_validated_date": "2025-10-15T13:11:56+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.1, + "teardown": 0.01, + "total": 0.11 + } }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_suffix_empty]": { - "last_validated_date": "2025-01-22T10:56:29+00:00" + "last_validated_date": "2025-10-15T13:12:14+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.1, + "teardown": 0.0, + "total": 0.1 + } }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_suffix_ignorecase]": { - "last_validated_date": "2025-01-22T10:56:27+00:00" + "last_validated_date": "2025-10-15T13:12:11+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.1, + "teardown": 0.0, + "total": 0.1 + } }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_suffix_ignorecase_NEG]": { - "last_validated_date": "2025-01-22T10:56:30+00:00" + "last_validated_date": "2025-10-15T13:12:16+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.43, + "teardown": 0.0, + "total": 0.43 + } }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_suffix_int_EXC]": { - "last_validated_date": "2025-01-22T10:56:30+00:00" + "last_validated_date": "2025-10-15T13:12:16+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.11, + "teardown": 0.0, + "total": 0.11 + } }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_suffix_list_EXC]": { - "last_validated_date": "2025-01-22T10:56:34+00:00" + "last_validated_date": "2025-10-15T13:12:21+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.11, + "teardown": 0.0, + "total": 0.11 + } }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_wildcard_complex_EXC]": { - "last_validated_date": "2025-01-22T10:56:31+00:00" + "last_validated_date": "2025-10-15T13:12:16+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.43, + "teardown": 0.0, + "total": 0.43 + } }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_wildcard_empty_NEG]": { - "last_validated_date": "2025-01-22T10:56:16+00:00" + "last_validated_date": "2025-10-15T13:11:58+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.1, + "teardown": 0.0, + "total": 0.1 + } }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_wildcard_int_EXC]": { - "last_validated_date": "2025-01-22T10:56:33+00:00" + "last_validated_date": "2025-10-15T13:12:20+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.51, + "teardown": 0.0, + "total": 0.51 + } }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_wildcard_list_EXC]": { - "last_validated_date": "2025-01-22T10:56:36+00:00" + "last_validated_date": "2025-10-15T13:12:23+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.42, + "teardown": 0.0, + "total": 0.42 + } }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_wildcard_nonrepeating]": { - "last_validated_date": "2025-01-22T10:56:17+00:00" + "last_validated_date": "2025-10-15T13:11:59+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.11, + "teardown": 0.0, + "total": 0.11 + } }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_wildcard_nonrepeating_NEG]": { - "last_validated_date": "2025-01-22T10:56:23+00:00" + "last_validated_date": "2025-10-15T13:12:07+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.44, + "teardown": 0.0, + "total": 0.44 + } }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_wildcard_repeating]": { - "last_validated_date": "2025-01-22T10:56:14+00:00" + "last_validated_date": "2025-10-15T13:11:55+00:00", + "durations_in_seconds": { + "setup": 0.48, + "call": 0.46, + "teardown": 0.0, + "total": 0.94 + } }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_wildcard_repeating_NEG]": { - "last_validated_date": "2025-01-22T10:56:17+00:00" + "last_validated_date": "2025-10-15T13:11:59+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.1, + "teardown": 0.0, + "total": 0.1 + } }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_wildcard_repeating_star_EXC]": { - "last_validated_date": "2025-01-22T10:56:17+00:00" + "last_validated_date": "2025-10-15T13:12:00+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.41, + "teardown": 0.0, + "total": 0.41 + } }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[content_wildcard_simplified]": { - "last_validated_date": "2025-01-22T10:56:17+00:00" + "last_validated_date": "2025-10-15T13:11:59+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.11, + "teardown": 0.0, + "total": 0.11 + } }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[dot_joining_event]": { - "last_validated_date": "2025-01-22T10:56:26+00:00" + "last_validated_date": "2025-10-15T13:12:10+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.1, + "teardown": 0.0, + "total": 0.1 + } }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[dot_joining_event_NEG]": { - "last_validated_date": "2025-01-22T10:56:27+00:00" + "last_validated_date": "2025-10-15T13:12:12+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.1, + "teardown": 0.0, + "total": 0.1 + } }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[dot_joining_pattern]": { - "last_validated_date": "2025-01-22T10:56:21+00:00" + "last_validated_date": "2025-10-15T13:12:04+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.1, + "teardown": 0.0, + "total": 0.1 + } }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[dot_joining_pattern_NEG]": { - "last_validated_date": "2025-01-22T10:56:27+00:00" + "last_validated_date": "2025-10-15T13:12:11+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.1, + "teardown": 0.0, + "total": 0.1 + } }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[dynamodb]": { - "last_validated_date": "2025-01-22T10:56:22+00:00" + "last_validated_date": "2025-10-15T13:12:05+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.1, + "teardown": 0.0, + "total": 0.1 + } }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[empty_prefix]": { "last_validated_date": "2025-01-21T13:16:50+00:00" }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[exists_dynamodb]": { - "last_validated_date": "2025-01-22T10:56:20+00:00" + "last_validated_date": "2025-10-15T13:12:03+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.1, + "teardown": 0.0, + "total": 0.1 + } }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[exists_dynamodb_NEG]": { - "last_validated_date": "2025-01-22T10:56:20+00:00" + "last_validated_date": "2025-10-15T13:12:03+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.11, + "teardown": 0.0, + "total": 0.11 + } }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[exists_list_empty_NEG]": { - "last_validated_date": "2025-01-22T10:56:16+00:00" + "last_validated_date": "2025-10-15T13:11:58+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.43, + "teardown": 0.0, + "total": 0.43 + } }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[int_nolist_EXC]": { - "last_validated_date": "2025-01-22T10:56:15+00:00" + "last_validated_date": "2025-10-15T13:11:56+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.1, + "teardown": 0.0, + "total": 0.1 + } }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[key_case_sensitive_NEG]": { - "last_validated_date": "2025-01-22T10:56:27+00:00" + "last_validated_date": "2025-10-15T13:12:12+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.1, + "teardown": 0.0, + "total": 0.1 + } }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[list_within_dict]": { - "last_validated_date": "2025-01-22T10:56:14+00:00" + "last_validated_date": "2025-10-15T13:11:56+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.1, + "teardown": 0.0, + "total": 0.1 + } }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[minimal]": { - "last_validated_date": "2025-01-22T10:56:33+00:00" + "last_validated_date": "2025-10-15T13:12:19+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.1, + "teardown": 0.0, + "total": 0.1 + } }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[nested_json_NEG]": { - "last_validated_date": "2025-01-22T10:56:21+00:00" + "last_validated_date": "2025-10-15T13:12:04+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.1, + "teardown": 0.0, + "total": 0.1 + } }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[null_value]": { - "last_validated_date": "2025-01-22T10:56:23+00:00" + "last_validated_date": "2025-10-15T13:12:06+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.43, + "teardown": 0.0, + "total": 0.43 + } }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[null_value_NEG]": { - "last_validated_date": "2025-01-22T10:56:27+00:00" + "last_validated_date": "2025-10-15T13:12:11+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.1, + "teardown": 0.0, + "total": 0.1 + } }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[number_comparison_float]": { - "last_validated_date": "2025-01-22T10:56:35+00:00" + "last_validated_date": "2025-10-15T13:12:21+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.44, + "teardown": 0.0, + "total": 0.44 + } }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[numeric-int-float]": { - "last_validated_date": "2025-01-22T10:56:25+00:00" + "last_validated_date": "2025-10-15T13:12:09+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.1, + "teardown": 0.0, + "total": 0.1 + } }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[numeric-null_NEG]": { - "last_validated_date": "2025-01-22T10:56:32+00:00" + "last_validated_date": "2025-10-15T13:12:18+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.1, + "teardown": 0.0, + "total": 0.1 + } }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[numeric-string_NEG]": { - "last_validated_date": "2025-01-22T10:56:25+00:00" + "last_validated_date": "2025-10-15T13:12:08+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.54, + "teardown": 0.0, + "total": 0.54 + } }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[operator_case_sensitive_EXC]": { - "last_validated_date": "2025-01-22T10:56:24+00:00" + "last_validated_date": "2025-10-15T13:12:07+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.1, + "teardown": 0.0, + "total": 0.1 + } }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[operator_multiple_list]": { - "last_validated_date": "2025-01-22T10:56:21+00:00" + "last_validated_date": "2025-10-15T13:12:04+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.1, + "teardown": 0.0, + "total": 0.1 + } }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[or-anything-but]": { - "last_validated_date": "2025-01-22T10:56:38+00:00" + "last_validated_date": "2025-10-15T13:12:26+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.1, + "teardown": 0.01, + "total": 0.11 + } }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[or-exists-parent]": { - "last_validated_date": "2025-01-22T10:56:21+00:00" + "last_validated_date": "2025-10-15T13:12:03+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.1, + "teardown": 0.0, + "total": 0.1 + } }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[or-exists]": { - "last_validated_date": "2025-01-22T10:56:17+00:00" + "last_validated_date": "2025-10-15T13:11:59+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.1, + "teardown": 0.0, + "total": 0.1 + } }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[or-numeric-anything-but]": { - "last_validated_date": "2025-01-22T10:56:33+00:00" + "last_validated_date": "2025-10-15T13:12:19+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.11, + "teardown": 0.0, + "total": 0.11 + } }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[or-numeric-anything-but_NEG]": { - "last_validated_date": "2025-01-22T10:56:19+00:00" + "last_validated_date": "2025-10-15T13:12:02+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.1, + "teardown": 0.0, + "total": 0.1 + } }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[prefix]": { - "last_validated_date": "2025-01-22T10:56:28+00:00" + "last_validated_date": "2025-10-15T13:12:12+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.44, + "teardown": 0.0, + "total": 0.44 + } }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[sample1]": { - "last_validated_date": "2025-01-22T10:56:27+00:00" + "last_validated_date": "2025-10-15T13:12:12+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.24, + "teardown": 0.0, + "total": 0.24 + } }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[string]": { - "last_validated_date": "2025-01-22T10:56:29+00:00" + "last_validated_date": "2025-10-15T13:12:15+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.1, + "teardown": 0.01, + "total": 0.11 + } }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[string_empty]": { - "last_validated_date": "2025-01-22T10:56:22+00:00" + "last_validated_date": "2025-10-15T13:12:05+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.1, + "teardown": 0.0, + "total": 0.1 + } }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern[string_nolist_EXC]": { - "last_validated_date": "2025-01-22T10:56:20+00:00" + "last_validated_date": "2025-10-15T13:12:02+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.1, + "teardown": 0.0, + "total": 0.1 + } }, "tests/aws/services/events/test_events_patterns.py::TestEventPattern::test_event_pattern_source": { "last_validated_date": "2024-07-11T13:55:39+00:00" diff --git a/tests/aws/services/events/test_events_schedule.py b/tests/aws/services/events/test_events_schedule.py index a091238382526..e0aa3fdd78bd4 100644 --- a/tests/aws/services/events/test_events_schedule.py +++ b/tests/aws/services/events/test_events_schedule.py @@ -416,9 +416,11 @@ def tests_scheduled_rule_does_not_trigger_on_put_events( "DetailType": "core.update-account-command", "Detail": json.dumps({"command": ["update-account"]}), } - aws_client.events.put_events(Entries=[test_event]) + for _ in range(3): + aws_client.events.put_events(Entries=[test_event]) messages = aws_client.sqs.receive_message( QueueUrl=queue_url, WaitTimeSeconds=10 if is_aws_cloud() else 3 ) - assert not messages.get("Messages") + # we switch the assertion to take into account that the rule might trigger instantly + assert len(messages.get("Messages") or []) < 2 diff --git a/tests/aws/services/events/test_events_schedule.validation.json b/tests/aws/services/events/test_events_schedule.validation.json index 2dce0326ca018..22391bc81e5ea 100644 --- a/tests/aws/services/events/test_events_schedule.validation.json +++ b/tests/aws/services/events/test_events_schedule.validation.json @@ -69,12 +69,12 @@ "last_validated_date": "2025-01-22T13:22:43+00:00" }, "tests/aws/services/events/test_events_schedule.py::TestScheduleCron::tests_scheduled_rule_does_not_trigger_on_put_events": { - "last_validated_date": "2025-06-04T19:23:59+00:00", + "last_validated_date": "2026-02-27T22:37:04+00:00", "durations_in_seconds": { - "setup": 0.56, - "call": 11.78, - "teardown": 1.18, - "total": 13.52 + "setup": 0.01, + "call": 11.95, + "teardown": 0.9, + "total": 12.86 } }, "tests/aws/services/events/test_events_schedule.py::TestScheduleRate::test_put_rule_with_invalid_schedule_rate[ rate(10 minutes)]": { diff --git a/tests/aws/services/events/test_events_targets.py b/tests/aws/services/events/test_events_targets.py index bddbb5612d835..61329317d3e9a 100644 --- a/tests/aws/services/events/test_events_targets.py +++ b/tests/aws/services/events/test_events_targets.py @@ -4,6 +4,7 @@ import base64 import json +import threading import time import aws_cdk as cdk @@ -41,6 +42,7 @@ class TestEventsTargetApiDestination: # TODO validate against AWS & use common fixtures + @markers.requires_in_process # uses pytest httpserver @markers.aws.only_localstack @pytest.mark.skipif(is_old_provider(), reason="not supported by the old provider") @pytest.mark.parametrize("auth", API_DESTINATION_AUTHS) @@ -157,11 +159,7 @@ def _handler(_request: Request): ] aws_client.events.put_events(Entries=entries) - # clean up - aws_client.events.delete_connection(Name=connection_name) - aws_client.events.delete_api_destination(Name=dest_name) - clean_up(rule_name=rule_name, target_ids=target_id) - + # Wait for event delivery before cleanup to_recv = 2 if auth["type"] == "OAUTH_CLIENT_CREDENTIALS" else 1 assert poll_condition(lambda: len(httpserver.log) >= to_recv, timeout=5) @@ -205,6 +203,113 @@ def _handler(_request: Request): assert oauth_request.headers["oauthheader"] == "value2" assert oauth_request.args["oauthquery"] == "value3" + # Clean up after verification + aws_client.events.delete_connection(Name=connection_name) + aws_client.events.delete_api_destination(Name=dest_name) + clean_up(rule_name=rule_name, target_ids=target_id) + + @markers.requires_in_process # uses pytest httpserver + @markers.aws.only_localstack + @pytest.mark.skipif(is_old_provider(), reason="not supported by the old provider") + def test_put_events_returns_immediately_with_slow_api_destination( + self, httpserver: HTTPServer, aws_client, clean_up + ): + """ + Test that put_events returns immediately even when the target API destination + is blocked and cannot respond. This validates the fix for GitHub issue #12107. + + The test verifies that: + 1. put_events returns successfully while the API destination handler is blocked + 2. The event is eventually delivered to the destination asynchronously + """ + # Create a blocking event to control when the handler can respond + blocking_event = threading.Event() + + # Create an endpoint that blocks until the event is set + def _blocking_handler(_request: Request): + # Block until event is set (with timeout for test cleanup) + if not blocking_event.wait(timeout=20.0): + raise TimeoutError("Test timed out waiting for blocking event") + return Response(json.dumps({"status": "received"}), mimetype="application/json") + + httpserver.expect_request("").respond_with_handler(_blocking_handler) + http_endpoint = httpserver.url_for("/") + + # Create connection with BASIC auth (simplest for this test) + connection_name = f"test-conn-{short_uid()}" + connection_arn = aws_client.events.create_connection( + Name=connection_name, + AuthorizationType="BASIC", + AuthParameters={ + "BasicAuthParameters": { + "Username": "user", + "Password": "pass", + }, + }, + )["ConnectionArn"] + + # Create API destination + dest_name = f"test-dest-{short_uid()}" + dest_arn = aws_client.events.create_api_destination( + Name=dest_name, + ConnectionArn=connection_arn, + InvocationEndpoint=http_endpoint, + HttpMethod="POST", + )["ApiDestinationArn"] + + # Create rule and target + rule_name = f"test-rule-{short_uid()}" + target_id = f"target-{short_uid()}" + pattern = json.dumps({"source": ["test.async"], "detail-type": ["async.test"]}) + + aws_client.events.put_rule(Name=rule_name, EventPattern=pattern) + aws_client.events.put_targets( + Rule=rule_name, + Targets=[ + { + "Id": target_id, + "Arn": dest_arn, + "Input": '{"test": "async_behavior"}', + } + ], + ) + + # Send event - this should return immediately even though handler is blocked + response = aws_client.events.put_events( + Entries=[ + { + "Source": "test.async", + "DetailType": "async.test", + "Detail": '{"message": "testing async behavior"}', + } + ] + ) + + # Verify the event was accepted (EventId returned) even while handler is blocked + # This proves put_events is non-blocking + assert response["FailedEntryCount"] == 0 + assert len(response["Entries"]) == 1 + assert "EventId" in response["Entries"][0] + + # Now unblock the handler so the event can be delivered + blocking_event.set() + + # Verify the event is eventually delivered to the destination + # (this proves background processing is working) + assert poll_condition(lambda: len(httpserver.log) >= 1, timeout=10), ( + "Event was not delivered to the API destination within 10 seconds" + ) + + # Verify the correct data was sent to the endpoint + event_request, _ = httpserver.log[0] + event_data = event_request.get_json(force=True) + assert event_data["test"] == "async_behavior" + + # Clean up + aws_client.events.delete_connection(Name=connection_name) + aws_client.events.delete_api_destination(Name=dest_name) + clean_up(rule_name=rule_name, target_ids=target_id) + class TestEventsTargetApiGateway: @markers.aws.validated diff --git a/tests/aws/services/firehose/test_firehose.py b/tests/aws/services/firehose/test_firehose.py index c830d5770ba12..5ed44c9c8a719 100644 --- a/tests/aws/services/firehose/test_firehose.py +++ b/tests/aws/services/firehose/test_firehose.py @@ -10,6 +10,7 @@ from localstack.testing.aws.util import is_aws_cloud from localstack.testing.pytest import markers from localstack.utils.aws import arns +from localstack.utils.aws.arns import iam_role_arn, s3_bucket_arn from localstack.utils.strings import short_uid, to_bytes, to_str from localstack.utils.sync import poll_condition, retry from tests.aws.services.firehose.helper_functions import get_firehose_iam_documents @@ -38,6 +39,7 @@ def handler(event, context): @pytest.mark.parametrize("lambda_processor_enabled", [True, False]) @markers.aws.unknown +@markers.requires_in_process # uses pytest httpserver def test_kinesis_firehose_http( aws_client, lambda_processor_enabled: bool, @@ -588,3 +590,78 @@ def assert_s3_contents(): retry_options["sleep_before"] = 10 retry(assert_s3_contents, **retry_options) + + +class TestFirehoseResourceTagging: + @pytest.fixture + def delivery_stream( + self, + aws_client, + s3_bucket, + create_iam_role_and_attach_policy, + account_id, + region_name, + firehose_create_delivery_stream, + ): + """Factory fixture to create a sample delivery stream with required pre-reqs.""" + + def _delivery_stream(tags: list[dict[str, str]] = None): + document = { + "Version": "2012-10-17", + "Statement": [ + { + "Effect": "Allow", + "Principal": {"Service": "firehose.amazonaws.com"}, + "Action": "sts:AssumeRole", + } + ], + } + role_name = f"role-{short_uid()}" + create_iam_role_and_attach_policy( + RoleName=role_name, + RoleDefinition=document, + PolicyArn="arn:aws:iam::aws:policy/AmazonS3FullAccess", + ) + + stream_name = f"stream-{short_uid()}" + + kwargs = { + "DeliveryStreamName": stream_name, + "DeliveryStreamType": "DirectPut", + "S3DestinationConfiguration": { + "RoleARN": iam_role_arn(role_name, account_id, region_name), + "BucketARN": s3_bucket_arn(s3_bucket, region_name), + }, + } + + if tags is not None: + kwargs["Tags"] = tags + + firehose_create_delivery_stream(**kwargs) + + return stream_name + + yield _delivery_stream + + @markers.aws.validated + def test_resource_tagging(self, aws_client, snapshot, delivery_stream): + stream_name = delivery_stream(tags=[{"Key": "subject", "Value": "taboo"}]) + + response = aws_client.firehose.list_tags_for_delivery_stream(DeliveryStreamName=stream_name) + snapshot.match("list-tags-1", response) + + response = aws_client.firehose.untag_delivery_stream( + DeliveryStreamName=stream_name, TagKeys=["subject", "moment"] + ) + snapshot.match("remove-tags", response) + + response = aws_client.firehose.list_tags_for_delivery_stream(DeliveryStreamName=stream_name) + snapshot.match("list-tags-2", response) + + response = aws_client.firehose.tag_delivery_stream( + DeliveryStreamName=stream_name, Tags=[{"Key": "feeling", "Value": "uncomfortable"}] + ) + snapshot.match("add-tags", response) + + response = aws_client.firehose.list_tags_for_delivery_stream(DeliveryStreamName=stream_name) + snapshot.match("list-tags-3", response) diff --git a/tests/aws/services/firehose/test_firehose.snapshot.json b/tests/aws/services/firehose/test_firehose.snapshot.json index 3ae5658d02344..a906dc1ad5449 100644 --- a/tests/aws/services/firehose/test_firehose.snapshot.json +++ b/tests/aws/services/firehose/test_firehose.snapshot.json @@ -11,5 +11,56 @@ } } } + }, + "tests/aws/services/firehose/test_firehose.py::TestFirehoseResourceTagging::test_resource_tagging": { + "recorded-date": "05-03-2026, 08:34:26", + "recorded-content": { + "list-tags-1": { + "HasMoreTags": false, + "Tags": [ + { + "Key": "subject", + "Value": "taboo" + } + ], + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "remove-tags": { + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "list-tags-2": { + "HasMoreTags": false, + "Tags": [], + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "add-tags": { + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "list-tags-3": { + "HasMoreTags": false, + "Tags": [ + { + "Key": "feeling", + "Value": "uncomfortable" + } + ], + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } } } diff --git a/tests/aws/services/firehose/test_firehose.validation.json b/tests/aws/services/firehose/test_firehose.validation.json index d864164ae54ad..eb4b52e9fe708 100644 --- a/tests/aws/services/firehose/test_firehose.validation.json +++ b/tests/aws/services/firehose/test_firehose.validation.json @@ -4,5 +4,14 @@ }, "tests/aws/services/firehose/test_firehose.py::TestFirehoseIntegration::test_multiple_delivery_streams_with_kinesis_as_source": { "last_validated_date": "2024-01-25T10:54:39+00:00" + }, + "tests/aws/services/firehose/test_firehose.py::TestFirehoseResourceTagging::test_resource_tagging": { + "last_validated_date": "2026-03-02T13:20:05+00:00", + "durations_in_seconds": { + "setup": 2.44, + "call": 23.89, + "teardown": 23.4, + "total": 49.73 + } } } diff --git a/tests/aws/services/cloudformation/resource_providers/iam/aws_iam_user/templates/user_basic.yaml b/tests/aws/services/iam/resource_providers/aws_iam_user/templates/user_basic.yaml similarity index 100% rename from tests/aws/services/cloudformation/resource_providers/iam/aws_iam_user/templates/user_basic.yaml rename to tests/aws/services/iam/resource_providers/aws_iam_user/templates/user_basic.yaml diff --git a/tests/aws/services/cloudformation/resource_providers/iam/aws_iam_user/templates/user_basic_autogenerated.yaml b/tests/aws/services/iam/resource_providers/aws_iam_user/templates/user_basic_autogenerated.yaml similarity index 100% rename from tests/aws/services/cloudformation/resource_providers/iam/aws_iam_user/templates/user_basic_autogenerated.yaml rename to tests/aws/services/iam/resource_providers/aws_iam_user/templates/user_basic_autogenerated.yaml diff --git a/tests/aws/services/cloudformation/resource_providers/iam/aws_iam_user/templates/user_full.yaml b/tests/aws/services/iam/resource_providers/aws_iam_user/templates/user_full.yaml similarity index 100% rename from tests/aws/services/cloudformation/resource_providers/iam/aws_iam_user/templates/user_full.yaml rename to tests/aws/services/iam/resource_providers/aws_iam_user/templates/user_full.yaml diff --git a/tests/aws/services/cloudformation/resource_providers/iam/aws_iam_user/templates/user_getatt.yaml b/tests/aws/services/iam/resource_providers/aws_iam_user/templates/user_getatt.yaml similarity index 100% rename from tests/aws/services/cloudformation/resource_providers/iam/aws_iam_user/templates/user_getatt.yaml rename to tests/aws/services/iam/resource_providers/aws_iam_user/templates/user_getatt.yaml diff --git a/tests/aws/services/cloudformation/resource_providers/iam/aws_iam_user/templates/user_getatt_exploration.yaml b/tests/aws/services/iam/resource_providers/aws_iam_user/templates/user_getatt_exploration.yaml similarity index 100% rename from tests/aws/services/cloudformation/resource_providers/iam/aws_iam_user/templates/user_getatt_exploration.yaml rename to tests/aws/services/iam/resource_providers/aws_iam_user/templates/user_getatt_exploration.yaml diff --git a/tests/aws/services/cloudformation/resource_providers/iam/aws_iam_user/templates/user_update.yaml b/tests/aws/services/iam/resource_providers/aws_iam_user/templates/user_update.yaml similarity index 100% rename from tests/aws/services/cloudformation/resource_providers/iam/aws_iam_user/templates/user_update.yaml rename to tests/aws/services/iam/resource_providers/aws_iam_user/templates/user_update.yaml diff --git a/tests/aws/services/cloudformation/resource_providers/iam/aws_iam_user/test_basic_user.py b/tests/aws/services/iam/resource_providers/aws_iam_user/test_basic_user.py similarity index 100% rename from tests/aws/services/cloudformation/resource_providers/iam/aws_iam_user/test_basic_user.py rename to tests/aws/services/iam/resource_providers/aws_iam_user/test_basic_user.py diff --git a/tests/aws/services/cloudformation/resource_providers/iam/aws_iam_user/test_basic_user.snapshot.json b/tests/aws/services/iam/resource_providers/aws_iam_user/test_basic_user.snapshot.json similarity index 80% rename from tests/aws/services/cloudformation/resource_providers/iam/aws_iam_user/test_basic_user.snapshot.json rename to tests/aws/services/iam/resource_providers/aws_iam_user/test_basic_user.snapshot.json index e1c6e9dc25597..11d09d2ae4fad 100644 --- a/tests/aws/services/cloudformation/resource_providers/iam/aws_iam_user/test_basic_user.snapshot.json +++ b/tests/aws/services/iam/resource_providers/aws_iam_user/test_basic_user.snapshot.json @@ -1,5 +1,5 @@ { - "tests/aws/services/cloudformation/resource_providers/iam/aws_iam_user/test_basic_user.py::TestBasicCRD::test_black_box": { + "tests/aws/services/iam/resource_providers/aws_iam_user/test_basic_user.py::TestBasicCRD::test_black_box": { "recorded-date": "28-06-2023, 22:01:50", "recorded-content": { "stack-outputs": { @@ -8,7 +8,7 @@ "describe-resource": { "User": { "Arn": "arn::iam::111111111111:user/", - "CreateDate": "datetime", + "CreateDate": "", "Path": "/", "UserId": "", "UserName": "" @@ -20,7 +20,7 @@ } } }, - "tests/aws/services/cloudformation/resource_providers/iam/aws_iam_user/test_basic_user.py::TestUpdates::test_update_without_replacement": { + "tests/aws/services/iam/resource_providers/aws_iam_user/test_basic_user.py::TestUpdates::test_update_without_replacement": { "recorded-date": "28-06-2023, 22:31:43", "recorded-content": { "stack-outputs-before-update": { @@ -29,7 +29,7 @@ "describe-resource-before-update": { "User": { "Arn": "arn::iam::111111111111:user/", - "CreateDate": "datetime", + "CreateDate": "", "Path": "/", "UserId": "", "UserName": "" @@ -42,7 +42,7 @@ "describe-resource-after-update": { "User": { "Arn": "arn::iam::111111111111:user/-updated", - "CreateDate": "datetime", + "CreateDate": "", "Path": "/", "UserId": "", "UserName": "-updated" @@ -57,7 +57,7 @@ } } }, - "tests/aws/services/cloudformation/resource_providers/iam/aws_iam_user/test_basic_user.py::TestBasicCRD::test_autogenerated_values": { + "tests/aws/services/iam/resource_providers/aws_iam_user/test_basic_user.py::TestBasicCRD::test_autogenerated_values": { "recorded-date": "28-06-2023, 22:54:57", "recorded-content": { "stack_outputs": { @@ -66,7 +66,7 @@ "autogenerated-get-user": { "User": { "Arn": "arn::iam::111111111111:user/", - "CreateDate": "datetime", + "CreateDate": "", "Path": "/", "UserId": "", "UserName": "" @@ -78,7 +78,7 @@ } } }, - "tests/aws/services/cloudformation/resource_providers/iam/aws_iam_user/test_basic_user.py::TestBasicCRD::test_getatt": { + "tests/aws/services/iam/resource_providers/aws_iam_user/test_basic_user.py::TestBasicCRD::test_getatt": { "recorded-date": "05-07-2023, 14:15:12", "recorded-content": { "stack-outputs": { @@ -88,7 +88,7 @@ "describe-resource": { "User": { "Arn": "arn::iam::111111111111:user/", - "CreateDate": "datetime", + "CreateDate": "", "Path": "/", "UserId": "", "UserName": "" @@ -103,7 +103,7 @@ "DriftInformation": { "StackResourceDriftStatus": "NOT_CHECKED" }, - "LastUpdatedTimestamp": "timestamp", + "LastUpdatedTimestamp": "", "LogicalResourceId": "MyResource", "Metadata": {}, "PhysicalResourceId": "", diff --git a/tests/aws/services/iam/resource_providers/aws_iam_user/test_basic_user.validation.json b/tests/aws/services/iam/resource_providers/aws_iam_user/test_basic_user.validation.json new file mode 100644 index 0000000000000..102dee48e5e6a --- /dev/null +++ b/tests/aws/services/iam/resource_providers/aws_iam_user/test_basic_user.validation.json @@ -0,0 +1,14 @@ +{ + "tests/aws/services/iam/resource_providers/aws_iam_user/test_basic_user.py::TestBasicCRD::test_autogenerated_values": { + "last_validated_date": "2023-06-28T20:54:57+00:00" + }, + "tests/aws/services/iam/resource_providers/aws_iam_user/test_basic_user.py::TestBasicCRD::test_black_box": { + "last_validated_date": "2023-06-28T20:01:50+00:00" + }, + "tests/aws/services/iam/resource_providers/aws_iam_user/test_basic_user.py::TestBasicCRD::test_getatt": { + "last_validated_date": "2023-07-05T12:15:12+00:00" + }, + "tests/aws/services/iam/resource_providers/aws_iam_user/test_basic_user.py::TestUpdates::test_update_without_replacement": { + "last_validated_date": "2023-06-28T20:31:43+00:00" + } +} diff --git a/tests/aws/services/cloudformation/resource_providers/iam/aws_iam_user/test_exploration.py b/tests/aws/services/iam/resource_providers/aws_iam_user/test_exploration.py similarity index 100% rename from tests/aws/services/cloudformation/resource_providers/iam/aws_iam_user/test_exploration.py rename to tests/aws/services/iam/resource_providers/aws_iam_user/test_exploration.py diff --git a/tests/aws/services/cloudformation/resource_providers/iam/aws_iam_user/test_parity.py b/tests/aws/services/iam/resource_providers/aws_iam_user/test_parity.py similarity index 100% rename from tests/aws/services/cloudformation/resource_providers/iam/aws_iam_user/test_parity.py rename to tests/aws/services/iam/resource_providers/aws_iam_user/test_parity.py diff --git a/tests/aws/services/cloudformation/resource_providers/iam/aws_iam_user/test_parity.snapshot.json b/tests/aws/services/iam/resource_providers/aws_iam_user/test_parity.snapshot.json similarity index 81% rename from tests/aws/services/cloudformation/resource_providers/iam/aws_iam_user/test_parity.snapshot.json rename to tests/aws/services/iam/resource_providers/aws_iam_user/test_parity.snapshot.json index cc28d998b40b0..c0838bbf3ac2a 100644 --- a/tests/aws/services/cloudformation/resource_providers/iam/aws_iam_user/test_parity.snapshot.json +++ b/tests/aws/services/iam/resource_providers/aws_iam_user/test_parity.snapshot.json @@ -1,5 +1,5 @@ { - "tests/aws/services/cloudformation/resource_providers/iam/aws_iam_user/test_parity.py::TestParity::test_create_with_full_properties": { + "tests/aws/services/iam/resource_providers/aws_iam_user/test_parity.py::TestParity::test_create_with_full_properties": { "recorded-date": "29-06-2023, 13:59:27", "recorded-content": { "stack-outputs": { @@ -8,7 +8,7 @@ "describe-user-resource": { "User": { "Arn": "arn::iam::111111111111:user/", - "CreateDate": "datetime", + "CreateDate": "", "Path": "/", "UserId": "", "UserName": "" @@ -22,14 +22,14 @@ "Groups": [ { "Arn": "arn::iam::111111111111:group/", - "CreateDate": "datetime", + "CreateDate": "", "GroupId": "", "GroupName": "", "Path": "/" }, { "Arn": "arn::iam::111111111111:group/", - "CreateDate": "datetime", + "CreateDate": "", "GroupId": "", "GroupName": "", "Path": "/" diff --git a/tests/aws/services/iam/resource_providers/aws_iam_user/test_parity.validation.json b/tests/aws/services/iam/resource_providers/aws_iam_user/test_parity.validation.json new file mode 100644 index 0000000000000..844553ba7c906 --- /dev/null +++ b/tests/aws/services/iam/resource_providers/aws_iam_user/test_parity.validation.json @@ -0,0 +1,5 @@ +{ + "tests/aws/services/iam/resource_providers/aws_iam_user/test_parity.py::TestParity::test_create_with_full_properties": { + "last_validated_date": "2023-06-29T11:59:27+00:00" + } +} diff --git a/tests/aws/services/cloudformation/resource_providers/iam/test_iam.py b/tests/aws/services/iam/resource_providers/test_iam.py similarity index 56% rename from tests/aws/services/cloudformation/resource_providers/iam/test_iam.py rename to tests/aws/services/iam/resource_providers/test_iam.py index 9edac28396e11..65778e06d776e 100644 --- a/tests/aws/services/cloudformation/resource_providers/iam/test_iam.py +++ b/tests/aws/services/iam/resource_providers/test_iam.py @@ -13,7 +13,7 @@ def test_delete_role_detaches_role_policy(deploy_cfn_template, aws_client): role_name = f"LsRole{short_uid()}" stack = deploy_cfn_template( template_path=os.path.join( - os.path.dirname(__file__), "../../../../templates/iam_role_policy.yaml" + os.path.dirname(__file__), "../../../templates/iam_role_policy.yaml" ), parameters={"RoleName": role_name}, ) @@ -26,7 +26,7 @@ def test_delete_role_detaches_role_policy(deploy_cfn_template, aws_client): is_update=True, stack_name=stack.stack_name, template_path=os.path.join( - os.path.dirname(__file__), "../../../../templates/iam_role_policy.yaml" + os.path.dirname(__file__), "../../../templates/iam_role_policy.yaml" ), parameters={"RoleName": f"role-{short_uid()}"}, ) @@ -46,7 +46,7 @@ def test_policy_attachments(deploy_cfn_template, aws_client): linked_role_id = short_uid() deploy_cfn_template( template_path=os.path.join( - os.path.dirname(__file__), "../../../../templates/iam_policy_attachments.yaml" + os.path.dirname(__file__), "../../../templates/iam_policy_attachments.yaml" ), template_mapping={ "role_name": role_name, @@ -119,7 +119,7 @@ def test_iam_user_access_key(deploy_cfn_template, snapshot, aws_client): user_name = f"user-{short_uid()}" stack = deploy_cfn_template( template_path=os.path.join( - os.path.dirname(__file__), "../../../../templates/iam_access_key.yaml" + os.path.dirname(__file__), "../../../templates/iam_access_key.yaml" ), parameters={"UserName": user_name}, ) @@ -133,7 +133,7 @@ def test_iam_user_access_key(deploy_cfn_template, snapshot, aws_client): stack_name=stack.stack_name, is_update=True, template_path=os.path.join( - os.path.dirname(__file__), "../../../../templates/iam_access_key.yaml" + os.path.dirname(__file__), "../../../templates/iam_access_key.yaml" ), parameters={"UserName": user_name, "Status": "Inactive", "Serial": "2"}, ) @@ -158,7 +158,7 @@ def test_update_inline_policy(deploy_cfn_template, snapshot, aws_client): stack = deploy_cfn_template( template_path=os.path.join( - os.path.dirname(__file__), "../../../../templates/iam_policy_role.yaml" + os.path.dirname(__file__), "../../../templates/iam_policy_role.yaml" ), parameters={ "PolicyName": policy_name, @@ -179,7 +179,7 @@ def test_update_inline_policy(deploy_cfn_template, snapshot, aws_client): deploy_cfn_template( template_path=os.path.join( - os.path.dirname(__file__), "../../../../templates/iam_policy_role_updated.yaml" + os.path.dirname(__file__), "../../../templates/iam_policy_role_updated.yaml" ), parameters={ "PolicyName": policy_name, @@ -223,9 +223,7 @@ def test_managed_policy_with_empty_resource(deploy_cfn_template, snapshot, aws_c "policyName": f"managed-policy-{short_uid()}", } - template_path = os.path.join( - os.path.dirname(__file__), "../../../../templates/dynamodb_iam.yaml" - ) + template_path = os.path.join(os.path.dirname(__file__), "../../../templates/dynamodb_iam.yaml") stack = deploy_cfn_template(template_path=template_path, parameters=parameters) @@ -245,7 +243,7 @@ def test_managed_policy_with_empty_resource(deploy_cfn_template, snapshot, aws_c def test_server_certificate(deploy_cfn_template, snapshot, aws_client): stack = deploy_cfn_template( template_path=os.path.join( - os.path.dirname(__file__), "../../../../templates/iam_server_certificate.yaml" + os.path.dirname(__file__), "../../../templates/iam_server_certificate.yaml" ), parameters={"certificateName": f"server-certificate-{short_uid()}"}, ) @@ -275,7 +273,7 @@ def test_server_certificate(deploy_cfn_template, snapshot, aws_client): def test_cfn_handle_iam_role_resource_no_role_name(deploy_cfn_template, aws_client): stack = deploy_cfn_template( template_path=os.path.join( - os.path.dirname(__file__), "../../../../templates/iam_role_defaults.yml" + os.path.dirname(__file__), "../../../templates/iam_role_defaults.yml" ) ) role_path_prefix = "/test-role-prefix/" @@ -296,9 +294,7 @@ def test_updating_stack_with_iam_role(deploy_cfn_template, aws_client): # Create stack and wait for 'CREATE_COMPLETE' status of the stack stack = deploy_cfn_template( - template_path=os.path.join( - os.path.dirname(__file__), "../../../../templates/template7.json" - ), + template_path=os.path.join(os.path.dirname(__file__), "../../../templates/template7.json"), parameters={ "LambdaRoleName": lambda_role_name, "LambdaFunctionName": lambda_function_name, @@ -318,9 +314,7 @@ def test_updating_stack_with_iam_role(deploy_cfn_template, aws_client): # Update stack and wait for 'UPDATE_COMPLETE' status of the stack stack = deploy_cfn_template( is_update=True, - template_path=os.path.join( - os.path.dirname(__file__), "../../../../templates/template7.json" - ), + template_path=os.path.join(os.path.dirname(__file__), "../../../templates/template7.json"), stack_name=stack.stack_name, parameters={ "LambdaRoleName": lambda_role_name_new, @@ -333,3 +327,213 @@ def test_updating_stack_with_iam_role(deploy_cfn_template, aws_client): "Role" ) assert stack.outputs["TestStackRoleName"] == lambda_role_name_new + + +@markers.aws.validated +def test_managedpolicy_with_fn_sub_json_string(deploy_cfn_template, snapshot, aws_client): + snapshot.add_transformer(snapshot.transform.iam_api()) + + policy_name = f"test-policy-{short_uid()}" + + template_json = { + "AWSTemplateFormatVersion": "2010-09-09", + "Parameters": {"ClusterName": {"Type": "String", "Default": "test-cluster"}}, + "Resources": { + "TestPolicy": { + "Type": "AWS::IAM::ManagedPolicy", + "Properties": { + "ManagedPolicyName": policy_name, + "PolicyDocument": { + "Fn::Sub": json.dumps( + { + "Version": "2012-10-17", + "Statement": [ + { + "Effect": "Allow", + "Action": "s3:GetObject", + "Resource": "arn:${AWS::Partition}:s3:::bucket-${ClusterName}-${AWS::Region}/*", + } + ], + } + ) + }, + }, + } + }, + "Outputs": {"PolicyArn": {"Value": {"Ref": "TestPolicy"}}}, + } + + stack = deploy_cfn_template( + template=json.dumps(template_json), parameters={"ClusterName": "my-cluster"} + ) + + policy_arn = stack.outputs["PolicyArn"] + policy_version = aws_client.iam.get_policy_version( + PolicyArn=policy_arn, + VersionId=aws_client.iam.get_policy(PolicyArn=policy_arn)["Policy"]["DefaultVersionId"], + )["PolicyVersion"] + + snapshot.match("policy_document", policy_version["Document"]) + + +@markers.aws.validated +def test_managedpolicy_with_fn_sub_multiline_yaml(deploy_cfn_template, snapshot, aws_client): + snapshot.add_transformer(snapshot.transform.iam_api()) + + policy_name = f"test-policy-{short_uid()}" + + template_yaml = f""" +AWSTemplateFormatVersion: "2010-09-09" +Parameters: + ClusterName: + Type: String + Default: "test-cluster" +Resources: + TestPolicy: + Type: AWS::IAM::ManagedPolicy + Properties: + ManagedPolicyName: {policy_name} + PolicyDocument: !Sub | + {{ + "Version": "2012-10-17", + "Statement": [ + {{ + "Effect": "Allow", + "Action": "eks:DescribeCluster", + "Resource": "arn:${{AWS::Partition}}:eks:${{AWS::Region}}:${{AWS::AccountId}}:cluster/${{ClusterName}}" + }} + ] + }} +Outputs: + PolicyArn: + Value: !Ref TestPolicy +""" + + stack = deploy_cfn_template(template=template_yaml, parameters={"ClusterName": "my-cluster"}) + + policy_arn = stack.outputs["PolicyArn"] + policy_version = aws_client.iam.get_policy_version( + PolicyArn=policy_arn, + VersionId=aws_client.iam.get_policy(PolicyArn=policy_arn)["Policy"]["DefaultVersionId"], + )["PolicyVersion"] + + snapshot.match("policy_document_multiline", policy_version["Document"]) + + +@markers.aws.validated +def test_managedpolicy_with_fn_sub_and_arrays(deploy_cfn_template, snapshot, aws_client): + snapshot.add_transformer(snapshot.transform.iam_api()) + + policy_name = f"test-policy-{short_uid()}" + + template = { + "AWSTemplateFormatVersion": "2010-09-09", + "Parameters": {"BucketName": {"Type": "String", "Default": "my-bucket"}}, + "Resources": { + "TestPolicy": { + "Type": "AWS::IAM::ManagedPolicy", + "Properties": { + "ManagedPolicyName": policy_name, + "PolicyDocument": { + "Fn::Sub": json.dumps( + { + "Version": "2012-10-17", + "Statement": [ + { + "Effect": "Allow", + "Action": ["s3:GetObject", "s3:PutObject"], + "Resource": [ + "arn:${AWS::Partition}:s3:::${BucketName}/*", + "arn:${AWS::Partition}:s3:::${BucketName}-${AWS::Region}/*", + ], + } + ], + } + ) + }, + }, + } + }, + "Outputs": {"PolicyArn": {"Value": {"Ref": "TestPolicy"}}}, + } + + stack = deploy_cfn_template( + template=json.dumps(template), parameters={"BucketName": "test-bucket"} + ) + + policy_arn = stack.outputs["PolicyArn"] + policy_version = aws_client.iam.get_policy_version( + PolicyArn=policy_arn, + VersionId=aws_client.iam.get_policy(PolicyArn=policy_arn)["Policy"]["DefaultVersionId"], + )["PolicyVersion"] + + snapshot.match("policy_with_arrays", policy_version["Document"]) + + +@markers.aws.validated +def test_inline_policy_with_fn_sub_json_string(deploy_cfn_template, snapshot, aws_client): + """ + Test inline IAM Policy (AWS::IAM::Policy) with Fn::Sub returning a JSON string. + + Verifies that inline policies also handle JSON strings from Fn::Sub correctly. + """ + snapshot.add_transformer(snapshot.transform.iam_api()) + + role_name = f"test-role-{short_uid()}" + policy_name = f"test-policy-{short_uid()}" + + template = { + "AWSTemplateFormatVersion": "2010-09-09", + "Resources": { + "TestRole": { + "Type": "AWS::IAM::Role", + "Properties": { + "RoleName": role_name, + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Effect": "Allow", + "Principal": {"Service": "lambda.amazonaws.com"}, + "Action": "sts:AssumeRole", + } + ], + }, + }, + }, + "TestPolicy": { + "Type": "AWS::IAM::Policy", + "Properties": { + "PolicyName": policy_name, + "Roles": [{"Ref": "TestRole"}], + "PolicyDocument": { + "Fn::Sub": json.dumps( + { + "Version": "2012-10-17", + "Statement": [ + { + "Effect": "Allow", + "Action": "s3:GetObject", + "Resource": "arn:${AWS::Partition}:s3:::my-bucket-${AWS::Region}/*", + } + ], + } + ) + }, + }, + }, + }, + } + + deploy_cfn_template(template=json.dumps(template)) + + # Verify the inline policy was attached to the role + policies = aws_client.iam.list_role_policies(RoleName=role_name) + assert policy_name in policies["PolicyNames"] + + # Get the policy document + policy_doc = aws_client.iam.get_role_policy(RoleName=role_name, PolicyName=policy_name)[ + "PolicyDocument" + ] + + snapshot.match("inline_policy_document", policy_doc) diff --git a/tests/aws/services/cloudformation/resource_providers/iam/test_iam.snapshot.json b/tests/aws/services/iam/resource_providers/test_iam.snapshot.json similarity index 67% rename from tests/aws/services/cloudformation/resource_providers/iam/test_iam.snapshot.json rename to tests/aws/services/iam/resource_providers/test_iam.snapshot.json index 044291d4e7cf1..2027856d4de0d 100644 --- a/tests/aws/services/cloudformation/resource_providers/iam/test_iam.snapshot.json +++ b/tests/aws/services/iam/resource_providers/test_iam.snapshot.json @@ -1,24 +1,24 @@ { - "tests/aws/services/cloudformation/resource_providers/iam/test_iam.py::test_iam_username_defaultname": { - "recorded-date": "31-05-2022, 11:29:45", + "tests/aws/services/iam/resource_providers/test_iam.py::test_iam_username_defaultname": { + "recorded-date": "10-02-2026, 15:51:18", "recorded-content": { "get_iam_user": { "User": { + "Arn": "arn::iam::111111111111:user/", + "CreateDate": "", "Path": "/", - "UserName": "", "UserId": "", - "Arn": "arn::iam::111111111111:user/", - "CreateDate": "datetime" + "UserName": "" }, "ResponseMetadata": { - "HTTPStatusCode": 200, - "HTTPHeaders": {} + "HTTPHeaders": {}, + "HTTPStatusCode": 200 } } } }, - "tests/aws/services/cloudformation/resource_providers/iam/test_iam.py::test_managed_policy_with_empty_resource": { - "recorded-date": "11-07-2023, 18:10:41", + "tests/aws/services/iam/resource_providers/test_iam.py::test_managed_policy_with_empty_resource": { + "recorded-date": "10-02-2026, 15:56:19", "recorded-content": { "outputs": { "PolicyArn": "arn::iam::111111111111:policy/", @@ -30,7 +30,7 @@ "Policy": { "Arn": "arn::iam::111111111111:policy/", "AttachmentCount": 0, - "CreateDate": "datetime", + "CreateDate": "", "DefaultVersionId": "v1", "IsAttachable": true, "Path": "/", @@ -38,7 +38,7 @@ "PolicyId": "", "PolicyName": "", "Tags": [], - "UpdateDate": "datetime" + "UpdateDate": "" }, "ResponseMetadata": { "HTTPHeaders": {}, @@ -47,8 +47,8 @@ } } }, - "tests/aws/services/cloudformation/resource_providers/iam/test_iam.py::test_iam_user_access_key": { - "recorded-date": "11-07-2023, 08:23:54", + "tests/aws/services/iam/resource_providers/test_iam.py::test_iam_user_access_key": { + "recorded-date": "10-02-2026, 15:52:59", "recorded-content": { "key_outputs": { "AccessKeyId": "", @@ -56,20 +56,20 @@ }, "access_key": { "AccessKeyId": "", - "CreateDate": "datetime", + "CreateDate": "", "Status": "Active", "UserName": "" }, "access_key_updated": { "AccessKeyId": "", - "CreateDate": "datetime", + "CreateDate": "", "Status": "Inactive", "UserName": "" } } }, - "tests/aws/services/cloudformation/resource_providers/iam/test_iam.py::test_update_inline_policy": { - "recorded-date": "05-04-2023, 11:55:22", + "tests/aws/services/iam/resource_providers/test_iam.py::test_update_inline_policy": { + "recorded-date": "10-02-2026, 15:54:55", "recorded-content": { "user_inline_policy": { "PolicyDocument": { @@ -155,8 +155,8 @@ } } }, - "tests/aws/services/cloudformation/resource_providers/iam/test_iam.py::test_server_certificate": { - "recorded-date": "13-03-2024, 20:20:07", + "tests/aws/services/iam/resource_providers/test_iam.py::test_server_certificate": { + "recorded-date": "10-02-2026, 15:58:53", "recorded-content": { "outputs": { "Arn": "arn::iam::111111111111:server-certificate/", @@ -167,11 +167,11 @@ "CertificateBody": "-----BEGIN CERTIFICATE-----\nMIIEHTCCAwWgAwIBAgIDAJojMA0GCSqGSIb3DQEBCwUAMIGLMQswCQYDVQQGEwJV\nUzETMBEGA1UECAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwNU2FuIEZyYW5jaXNjbzEX\nMBUGA1UECgwOTXlPcmdhbml6YXRpb24xHTAbBgNVBAsMFE15T3JnYW5pemF0aW9u\nYWxVbml0MRcwFQYDVQQDDA5NeSBvd24gUm9vdCBDQTAeFw0yMTAzMTExNTAwNDla\nFw0zMDAzMDkxNTAwNDlaMIGIMQswCQYDVQQGEwJVUzETMBEGA1UECAwKQ2FsaWZv\ncm5pYTEWMBQGA1UEBwwNU2FuIEZyYW5jaXNjbzEXMBUGA1UECgwOTXlPcmdhbml6\nYXRpb24xHTAbBgNVBAsMFE15T3JnYW5pemF0aW9uYWxVbml0MRQwEgYDVQQDDAtl\neGFtcGxlLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMnKQhQG\npRuxcO5RF8VMyAmWe4rs4XWeodVQflYtJVY+mCg/JidmgYe1EYXvE2Qqf1Xzi2O2\noEJJSAs/s+Wb91yzunnoHVR/5uTHdjN2e6HRhEmUFlJuconjlmBxVKe1LG4Ra8yr\nJA+E0tS2kzrGCLNcFpghQ982GJjuvRWm9nAAsCJPm7N8a/Gm1opMdUkiH1b/3d47\n0wugisz6fYRHQ61UIYfjNUWlg/tV1thGOScAB2RyusQJdTB422BQAlpD4TTX8uj8\nWd0GhYjpM8DWWpSUOFsoYOHBc3bPr7ctpOoIG8gZcs56zDwZi9CVda4viS/8HPnC\nr8jXaQW1pqwP8ekCAwEAAaOBijCBhzAJBgNVHRMEAjAAMB0GA1UdDgQWBBTaOaPu\nXmtLDTJVv++VYBiQr9gHCTAfBgNVHSMEGDAWgBTaOaPuXmtLDTJVv++VYBiQr9gH\nCTATBgNVHSUEDDAKBggrBgEFBQcDATALBgNVHQ8EBAMCB4AwGAYDVR0RBBEwD4IN\nKi5leGFtcGxlLmNvbTANBgkqhkiG9w0BAQsFAAOCAQEAWIZu4sma7MmWTXSMwKSP\nstQDWdIvcwthD8ozHkLsNdl5eKqOEndAc0wb7mSk1z8rRkSsd0D0T2zaKyduCYrs\neBAMhS2+NnHWcXxhn0VOkmXhw5kO8Un14KIptRH0y8FIqHMJ8LrSiK9g9fWCRlI9\ng7eBipu43hzGyMiBP3K0EQ4m49QXlIEwG3OIWak5hdR29h3cD6xXMXaUtlOswsAN\n3PDG/gcjZWZpkwPlaVzwjV8MRsYLmQIYdHPr/qF1FWddYPvK89T0nzpgiuFdBOTY\nW6I1TeTAXFXG2Qf4trXsh5vsFNAisxlRF3mkpixYP5OmVXTOyN7cCOSPOUh6Uctv\neg==\n-----END CERTIFICATE-----", "ServerCertificateMetadata": { "Arn": "arn::iam::111111111111:server-certificate/", - "Expiration": "datetime", + "Expiration": "", "Path": "/", "ServerCertificateId": "", "ServerCertificateName": "", - "UploadDate": "datetime" + "UploadDate": "" }, "Tags": [] }, @@ -192,5 +192,71 @@ } } } + }, + "tests/aws/services/iam/resource_providers/test_iam.py::test_managedpolicy_with_fn_sub_json_string": { + "recorded-date": "10-02-2026, 16:02:06", + "recorded-content": { + "policy_document": { + "Statement": [ + { + "Action": "s3:GetObject", + "Effect": "Allow", + "Resource": "arn::s3:::bucket-my-cluster-/*" + } + ], + "Version": "2012-10-17" + } + } + }, + "tests/aws/services/iam/resource_providers/test_iam.py::test_managedpolicy_with_fn_sub_multiline_yaml": { + "recorded-date": "10-02-2026, 16:02:38", + "recorded-content": { + "policy_document_multiline": { + "Statement": [ + { + "Action": "eks:DescribeCluster", + "Effect": "Allow", + "Resource": "arn::eks::111111111111:cluster/my-cluster" + } + ], + "Version": "2012-10-17" + } + } + }, + "tests/aws/services/iam/resource_providers/test_iam.py::test_managedpolicy_with_fn_sub_and_arrays": { + "recorded-date": "10-02-2026, 16:03:09", + "recorded-content": { + "policy_with_arrays": { + "Statement": [ + { + "Action": [ + "s3:GetObject", + "s3:PutObject" + ], + "Effect": "Allow", + "Resource": [ + "arn::s3:::test-bucket/*", + "arn::s3:::test-bucket-/*" + ] + } + ], + "Version": "2012-10-17" + } + } + }, + "tests/aws/services/iam/resource_providers/test_iam.py::test_inline_policy_with_fn_sub_json_string": { + "recorded-date": "10-02-2026, 16:03:58", + "recorded-content": { + "inline_policy_document": { + "Statement": [ + { + "Action": "s3:GetObject", + "Effect": "Allow", + "Resource": "arn::s3:::my-bucket-/*" + } + ], + "Version": "2012-10-17" + } + } } } diff --git a/tests/aws/services/iam/resource_providers/test_iam.validation.json b/tests/aws/services/iam/resource_providers/test_iam.validation.json new file mode 100644 index 0000000000000..1664ad8e4023c --- /dev/null +++ b/tests/aws/services/iam/resource_providers/test_iam.validation.json @@ -0,0 +1,119 @@ +{ + "tests/aws/services/iam/resource_providers/test_iam.py::test_cfn_handle_iam_role_resource_no_role_name": { + "last_validated_date": "2026-02-10T15:59:36+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 42.14, + "teardown": 0.29, + "total": 42.43 + } + }, + "tests/aws/services/iam/resource_providers/test_iam.py::test_delete_role_detaches_role_policy": { + "last_validated_date": "2026-02-10T15:48:42+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 81.93, + "teardown": 13.76, + "total": 95.69 + } + }, + "tests/aws/services/iam/resource_providers/test_iam.py::test_iam_user_access_key": { + "last_validated_date": "2026-02-10T15:53:40+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 61.62, + "teardown": 41.76, + "total": 103.38 + } + }, + "tests/aws/services/iam/resource_providers/test_iam.py::test_iam_username_defaultname": { + "last_validated_date": "2026-02-10T15:51:57+00:00", + "durations_in_seconds": { + "setup": 0.55, + "call": 46.37, + "teardown": 39.4, + "total": 86.32 + } + }, + "tests/aws/services/iam/resource_providers/test_iam.py::test_inline_policy_with_fn_sub_json_string": { + "last_validated_date": "2026-02-10T16:04:14+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 43.9, + "teardown": 16.02, + "total": 59.92 + } + }, + "tests/aws/services/iam/resource_providers/test_iam.py::test_managed_policy_with_empty_resource": { + "last_validated_date": "2026-02-10T15:56:37+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 42.49, + "teardown": 17.74, + "total": 60.23 + } + }, + "tests/aws/services/iam/resource_providers/test_iam.py::test_managedpolicy_with_fn_sub_and_arrays": { + "last_validated_date": "2026-02-10T16:03:14+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 26.86, + "teardown": 4.79, + "total": 31.65 + } + }, + "tests/aws/services/iam/resource_providers/test_iam.py::test_managedpolicy_with_fn_sub_json_string": { + "last_validated_date": "2026-02-10T16:02:11+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 27.12, + "teardown": 4.76, + "total": 31.88 + } + }, + "tests/aws/services/iam/resource_providers/test_iam.py::test_managedpolicy_with_fn_sub_multiline_yaml": { + "last_validated_date": "2026-02-10T16:02:43+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 26.71, + "teardown": 4.78, + "total": 31.49 + } + }, + "tests/aws/services/iam/resource_providers/test_iam.py::test_policy_attachments": { + "last_validated_date": "2026-02-10T15:50:31+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 66.78, + "teardown": 41.88, + "total": 108.66 + } + }, + "tests/aws/services/iam/resource_providers/test_iam.py::test_server_certificate": { + "last_validated_date": "2026-02-10T15:58:54+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 136.18, + "teardown": 0.72, + "total": 136.9 + } + }, + "tests/aws/services/iam/resource_providers/test_iam.py::test_update_inline_policy": { + "last_validated_date": "2026-02-10T15:55:37+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 74.43, + "teardown": 41.78, + "total": 116.21 + } + }, + "tests/aws/services/iam/resource_providers/test_iam.py::test_updating_stack_with_iam_role": { + "last_validated_date": "2026-02-10T16:01:39+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 95.95, + "teardown": 27.18, + "total": 123.13 + } + } +} diff --git a/tests/aws/services/kms/test_kms.py b/tests/aws/services/kms/test_kms.py index ed8ec0ed43bbb..3a528d5103288 100644 --- a/tests/aws/services/kms/test_kms.py +++ b/tests/aws/services/kms/test_kms.py @@ -6,14 +6,18 @@ from datetime import datetime from random import getrandbits +import cbor2 import pytest +from asn1crypto import cms from botocore.config import Config from botocore.exceptions import ClientError from cryptography.hazmat.backends import default_backend from cryptography.hazmat.primitives import hashes, hmac, serialization from cryptography.hazmat.primitives.asymmetric import ec, padding, rsa, utils +from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes from cryptography.hazmat.primitives.keywrap import aes_key_wrap_with_padding from cryptography.hazmat.primitives.serialization import load_der_public_key +from localstack_snapshot.snapshots.transformer import RegexTransformer from localstack.services.kms.models import ( HEADER_LEN, @@ -23,7 +27,7 @@ _serialize_ciphertext_blob, ) from localstack.services.kms.utils import get_hash_algorithm -from localstack.testing.aws.util import in_default_partition +from localstack.testing.aws.util import in_default_partition, is_aws_cloud from localstack.testing.pytest import markers from localstack.utils.crypto import encrypt from localstack.utils.strings import short_uid, to_str @@ -55,6 +59,18 @@ def get_signature_kwargs(signing_algorithm, message_type): return kwargs +def generate_encrypted_symmetric_key_material(public_key: bytes) -> bytes: + symmetric_key_material = bytes(getrandbits(8) for _ in range(32)) + public_key = load_der_public_key(public_key) + encrypted_key = public_key.encrypt( + symmetric_key_material, + padding.OAEP( + mgf=padding.MGF1(algorithm=hashes.SHA256()), algorithm=hashes.SHA256(), label=None + ), + ) + return encrypted_key + + @pytest.fixture(scope="class") def kms_client_for_region(aws_client_factory): def _kms_client( @@ -72,32 +88,31 @@ def user_arn(aws_client): def _get_all_key_ids(kms_client): ids = set() - next_token = None + next_marker = None while True: - kwargs = {"nextToken": next_token} if next_token else {} + kwargs = {"Marker": next_marker} if next_marker else {} response = kms_client.list_keys(**kwargs) for key in response["Keys"]: ids.add(key["KeyId"]) - if "nextToken" not in response: + if "NextMarker" not in response: break - next_token = response["nextToken"] + next_marker = response["NextMarker"] return ids def _get_alias(kms_client, alias_name, key_id=None): - next_token = None - # TODO potential bug on pagination on "nextToken" attribute key + next_marker = None while True: - kwargs = {"nextToken": next_token} if next_token else {} + kwargs = {"Marker": next_marker} if next_marker else {} if key_id: kwargs["KeyId"] = key_id response = kms_client.list_aliases(**kwargs) for alias in response["Aliases"]: if alias["AliasName"] == alias_name: return alias - if "nextToken" not in response: + if "NextMarker" not in response: break - next_token = response["nextToken"] + next_marker = response["NextMarker"] return None @@ -138,21 +153,6 @@ def test_create_key( assert f":{region_name}:" in response["Arn"] assert f":{account_id}:" in response["Arn"] - @markers.aws.only_localstack - def test_unsupported_rotate_key_on_demand_with_imported_key_material( - self, kms_create_key, aws_client, snapshot - ): - key_id = kms_create_key(Origin="EXTERNAL")["KeyId"] - - with pytest.raises(ClientError) as e: - aws_client.kms.rotate_key_on_demand(KeyId=key_id) - - assert e.value.response["ResponseMetadata"]["HTTPStatusCode"] == 501 - assert ( - e.value.response["Error"]["Message"] - == "Rotation of imported keys is not supported yet." - ) - @markers.aws.validated def test_tag_existing_key_and_untag( self, kms_client_for_region, kms_create_key, snapshot, region_name @@ -523,6 +523,34 @@ def test_get_key_invalid_uuid(self, snapshot, aws_client): aws_client.kms.describe_key(KeyId="mrk-fake-key-id") snapshot.match("describe-key-with-invalid-uuid-mrk", e.value.response) + @markers.aws.only_localstack + def test_create_key_custom_key_material_rsa_2048(self, kms_create_key, aws_client): + rsa_key = rsa.generate_private_key(public_exponent=65537, key_size=2048) + raw_private_key = rsa_key.private_bytes( + serialization.Encoding.DER, + serialization.PrivateFormat.PKCS8, + serialization.NoEncryption(), + ) + raw_public_key = rsa_key.public_key().public_bytes( + serialization.Encoding.DER, + serialization.PublicFormat.SubjectPublicKeyInfo, + ) + + custom_key_tag_value = base64.b64encode(raw_private_key).decode("utf-8") + + key_spec = "RSA_2048" + key_usage = "SIGN_VERIFY" + + key_id = kms_create_key( + KeySpec=key_spec, + KeyUsage=key_usage, + Tags=[ + {"TagKey": "_custom_key_material_", "TagValue": custom_key_tag_value}, + ], + )["KeyId"] + public_key = aws_client.kms.get_public_key(KeyId=key_id)["PublicKey"] + assert public_key == raw_public_key + @markers.aws.validated def test_list_keys(self, kms_create_key, aws_client): created_key = kms_create_key() @@ -1273,6 +1301,19 @@ def test_replicate_key( response = us_east_1_kms_client.describe_key(KeyId=key_id) snapshot.match("describe-key-from-region", response) + # ensure the key has completed replicating. + def _replicated_key_creation_is_complete(): + return ( + us_west_1_kms_client.describe_key(KeyId=key_id)["KeyMetadata"]["KeyState"] + == "Enabled" + ) + + assert poll_condition( + condition=_replicated_key_creation_is_complete, + timeout=120, + interval=5 if is_aws_cloud() else 0.5, + ) + # describe replicated key response = us_west_1_kms_client.describe_key(KeyId=key_id) snapshot.match("describe-replicated-key", response) @@ -1304,6 +1345,39 @@ def test_key_rotation_status(self, kms_key, aws_client): aws_client.kms.disable_key_rotation(KeyId=key_id) assert aws_client.kms.get_key_rotation_status(KeyId=key_id)["KeyRotationEnabled"] is False + @markers.aws.validated + def test_key_rotation_updates_current_key_material_id_for_aws_symmetric_keys( + self, kms_create_key, aws_client, snapshot + ): + key_id = kms_create_key( + KeyUsage="ENCRYPT_DECRYPT", KeySpec="SYMMETRIC_DEFAULT", Description="test-key" + )["KeyId"] + describe_key_before = aws_client.kms.describe_key(KeyId=key_id) + snapshot.match("describe-key-before-rotation", describe_key_before) + + aws_client.kms.rotate_key_on_demand(KeyId=key_id) + + def _assert_on_demand_rotation_updates_material(): + response = aws_client.kms.describe_key(KeyId=key_id) + return ( + response["KeyMetadata"]["CurrentKeyMaterialId"] + != describe_key_before["KeyMetadata"]["CurrentKeyMaterialId"] + ) + + assert poll_condition( + condition=_assert_on_demand_rotation_updates_material, + timeout=90, + interval=5 if is_aws_cloud() else 0.5, + ) + + describe_key_after = aws_client.kms.describe_key(KeyId=key_id) + snapshot.match("describe-key-after-rotation", describe_key_after) + + assert ( + describe_key_before["KeyMetadata"]["CurrentKeyMaterialId"] + != describe_key_after["KeyMetadata"]["CurrentKeyMaterialId"] + ) + @markers.aws.validated def test_key_rotations_encryption_decryption(self, kms_create_key, aws_client, snapshot): key_id = kms_create_key(KeyUsage="ENCRYPT_DECRYPT", KeySpec="SYMMETRIC_DEFAULT")["KeyId"] @@ -1341,7 +1415,7 @@ def test_key_rotations_encryption_decryption(self, kms_create_key, aws_client, s EncryptionAlgorithm="SYMMETRIC_DEFAULT", ) - snapshot.match("bad-ciphertext", e.value) + snapshot.match("bad-ciphertext", e.value.response) @markers.aws.validated def test_key_rotations_limits(self, kms_create_key, aws_client, snapshot): @@ -1361,6 +1435,15 @@ def _assert_on_demand_rotation_completed(): aws_client.kms.rotate_key_on_demand(KeyId=key_id) snapshot.match("error-response", e.value.response) + @markers.aws.validated + def test_rotate_on_demand_returns_arn_for_key_id(self, kms_create_key, aws_client, snapshot): + aws_kms_key = kms_create_key(KeyUsage="ENCRYPT_DECRYPT", KeySpec="SYMMETRIC_DEFAULT") + aws_key_rotate_on_demand_response = aws_client.kms.rotate_key_on_demand( + KeyId=aws_kms_key["KeyId"] + ) + snapshot.match("rotate-on-demand-aws-key", aws_key_rotate_on_demand_response) + assert aws_key_rotate_on_demand_response["KeyId"] == aws_kms_key["Arn"] + @markers.aws.validated def test_rotate_key_on_demand_modifies_key_material(self, kms_create_key, aws_client, snapshot): key_id = kms_create_key(KeyUsage="ENCRYPT_DECRYPT", KeySpec="SYMMETRIC_DEFAULT")["KeyId"] @@ -1464,17 +1547,315 @@ def test_rotate_key_on_demand_raises_error_given_non_symmetric_key( snapshot.match("error-response", e.value.response) @markers.aws.validated - @pytest.mark.skip( - reason="This needs to be fixed as AWS introduced support for on demand rotation of imported keys." - ) - def test_rotate_key_on_demand_raises_error_given_key_with_imported_key_material( + def test_rotate_key_on_demand_updates_current_key_material_for_external_keys( + self, kms_create_key, aws_client, snapshot + ): + snapshot.add_transformer( + snapshot.transform.key_value("ImportToken", reference_replacement=False) + ) + snapshot.add_transformer( + snapshot.transform.key_value("PublicKey", reference_replacement=False) + ) + + create_key_response = kms_create_key( + Origin="EXTERNAL", KeyUsage="ENCRYPT_DECRYPT", Description="test-key" + ) + key_id = create_key_response["KeyId"] + snapshot.match("create-kms-external-key", create_key_response) + + # Get the parameters required to import key material into our KMS key. + get_parameters_response = aws_client.kms.get_parameters_for_import( + KeyId=key_id, WrappingAlgorithm="RSAES_OAEP_SHA_256", WrappingKeySpec="RSA_2048" + ) + assert get_parameters_response["KeyId"] == create_key_response["Arn"] + assert get_parameters_response["ImportToken"] + assert get_parameters_response["PublicKey"] + assert isinstance(get_parameters_response["ParametersValidTo"], datetime) + snapshot.match("get-import-parameters-response", get_parameters_response) + + # Create initial key material to use in external KMS key. + initial_key_material = generate_encrypted_symmetric_key_material( + get_parameters_response["PublicKey"] + ) + describe_empty_key_response = aws_client.kms.describe_key(KeyId=key_id) + snapshot.match("describe-empty-key-response", describe_empty_key_response) + + # Import the initial key material. + import_key_material_response = aws_client.kms.import_key_material( + KeyId=key_id, + ImportToken=get_parameters_response["ImportToken"], + EncryptedKeyMaterial=initial_key_material, + ExpirationModel="KEY_MATERIAL_DOES_NOT_EXPIRE", + ) + snapshot.match("import-key-material-response", import_key_material_response) + + # On initial import of material, it should automatically update the CurrentKeyMaterialId + describe_key_with_material_response = aws_client.kms.describe_key(KeyId=key_id) + assert "CurrentKeyMaterialId" in describe_key_with_material_response["KeyMetadata"] + current_key_material_id = describe_key_with_material_response["KeyMetadata"][ + "CurrentKeyMaterialId" + ] + snapshot.match("describe-key-with-material-response", describe_key_with_material_response) + + # Encrypt/Decrypt using key material. + plaintext = b"Hello World!1/?" + encrypted_response = aws_client.kms.encrypt( + Plaintext=plaintext, KeyId=key_id, EncryptionAlgorithm="SYMMETRIC_DEFAULT" + ) + snapshot.match("kms-encrypt-initial-response", encrypted_response) + initial_ciphertext = encrypted_response["CiphertextBlob"] + + decrypted_response = aws_client.kms.decrypt( + CiphertextBlob=initial_ciphertext, + KeyId=key_id, + ) + assert decrypted_response["Plaintext"] == plaintext + + # Import new key material and ensure that the key uses the new material after on-demand rotation. + new_get_parameters_response = aws_client.kms.get_parameters_for_import( + KeyId=key_id, WrappingAlgorithm="RSAES_OAEP_SHA_256", WrappingKeySpec="RSA_2048" + ) + new_key_material = generate_encrypted_symmetric_key_material( + new_get_parameters_response["PublicKey"] + ) + import_new_key_material_response = aws_client.kms.import_key_material( + KeyId=key_id, + ImportToken=new_get_parameters_response["ImportToken"], + EncryptedKeyMaterial=new_key_material, + ExpirationModel="KEY_MATERIAL_DOES_NOT_EXPIRE", + ImportType="NEW_KEY_MATERIAL", # Defaults to this if the key is empty, but will default to EXISTING_KEY_MATERIAL afterwards. + ) + + snapshot.match("import-new-key-material-response", import_new_key_material_response) + describe_key_with_material_response = aws_client.kms.describe_key(KeyId=key_id) + snapshot.match( + "describe-key-with-new-material-response", describe_key_with_material_response + ) + + # Rotate to the new key material. + rotate_on_demand_response = aws_client.kms.rotate_key_on_demand(KeyId=key_id) + snapshot.match("rotate-key-on-demand-response", rotate_on_demand_response) + + def _assert_on_demand_rotation_updates_material(): + response = aws_client.kms.describe_key(KeyId=key_id) + return response["KeyMetadata"]["CurrentKeyMaterialId"] != current_key_material_id + + assert poll_condition( + condition=_assert_on_demand_rotation_updates_material, + timeout=90, + interval=5 if is_aws_cloud() else 0.5, + ) + + describe_key_after_rotate_response = aws_client.kms.describe_key(KeyId=key_id) + snapshot.match("describe-key-after-rotation", describe_key_after_rotate_response) + + # Encrypt/Decrypt using the new key material. + new_encrypted_response = aws_client.kms.encrypt( + Plaintext=plaintext, KeyId=key_id, EncryptionAlgorithm="SYMMETRIC_DEFAULT" + ) + snapshot.match("kms-encrypt-rotated-key-response", new_encrypted_response) + new_ciphertext = new_encrypted_response["CiphertextBlob"] + + assert new_ciphertext != initial_ciphertext + new_decrypted_response = aws_client.kms.decrypt( + CiphertextBlob=new_ciphertext, + KeyId=key_id, + EncryptionAlgorithm="SYMMETRIC_DEFAULT", + ) + assert new_decrypted_response["Plaintext"] == plaintext + + @markers.aws.unknown + def test_rotate_key_on_demand_for_external_keys_decrypts_with_previous_material( + self, kms_create_key, aws_client, snapshot + ): + snapshot.add_transformer( + snapshot.transform.key_value("ImportToken", reference_replacement=False) + ) + snapshot.add_transformer( + snapshot.transform.key_value("PublicKey", reference_replacement=False) + ) + + create_key_response = kms_create_key( + Origin="EXTERNAL", KeyUsage="ENCRYPT_DECRYPT", Description="test-key" + ) + key_id = create_key_response["KeyId"] + snapshot.match("create-kms-external-key", create_key_response) + + get_parameters_response = aws_client.kms.get_parameters_for_import( + KeyId=key_id, WrappingAlgorithm="RSAES_OAEP_SHA_256", WrappingKeySpec="RSA_2048" + ) + assert get_parameters_response["ImportToken"] + assert get_parameters_response["PublicKey"] + assert isinstance(get_parameters_response["ParametersValidTo"], datetime) + + initial_key_material = generate_encrypted_symmetric_key_material( + get_parameters_response["PublicKey"] + ) + + # Import the initial key material. + import_key_material_response = aws_client.kms.import_key_material( + KeyId=key_id, + ImportToken=get_parameters_response["ImportToken"], + EncryptedKeyMaterial=initial_key_material, + ExpirationModel="KEY_MATERIAL_DOES_NOT_EXPIRE", + ) + snapshot.match("import-key-material-response", import_key_material_response) + + initial_key_material_id = import_key_material_response["KeyMaterialId"] + + # Encrypt with initial material, rotate to a new key, then ensure it decrypts with the correct key. + plaintext = b"Hello World!1/?" + encrypted_response = aws_client.kms.encrypt( + Plaintext=plaintext, KeyId=key_id, EncryptionAlgorithm="SYMMETRIC_DEFAULT" + ) + snapshot.match("kms-encrypt-initial-response", encrypted_response) + initial_ciphertext = encrypted_response["CiphertextBlob"] + + # Import new key material + new_get_parameters_response = aws_client.kms.get_parameters_for_import( + KeyId=key_id, WrappingAlgorithm="RSAES_OAEP_SHA_256", WrappingKeySpec="RSA_2048" + ) + new_key_material = generate_encrypted_symmetric_key_material( + new_get_parameters_response["PublicKey"] + ) + aws_client.kms.import_key_material( + KeyId=key_id, + ImportToken=new_get_parameters_response["ImportToken"], + EncryptedKeyMaterial=new_key_material, + ExpirationModel="KEY_MATERIAL_DOES_NOT_EXPIRE", + ImportType="NEW_KEY_MATERIAL", + ) + + # Rotate to the new key material. + rotate_on_demand_response = aws_client.kms.rotate_key_on_demand(KeyId=key_id) + snapshot.match("rotate-key-on-demand-response", rotate_on_demand_response) + + def _assert_on_demand_rotation_updates_material(): + response = aws_client.kms.describe_key(KeyId=key_id) + return response["KeyMetadata"]["CurrentKeyMaterialId"] != initial_key_material_id + + assert poll_condition( + condition=_assert_on_demand_rotation_updates_material, + timeout=90, + interval=5 if is_aws_cloud() else 0.5, + ) + + decrypted_response = aws_client.kms.decrypt( + CiphertextBlob=initial_ciphertext, + KeyId=key_id, + ) + assert decrypted_response["Plaintext"] == plaintext + + @markers.aws.validated + def test_import_key_material_raises_if_there_is_already_key_material_pending( + self, kms_create_key, aws_client, snapshot + ): + snapshot.add_transformer(RegexTransformer(r"[a-f0-9]{64}", "")) + create_key_response = kms_create_key( + Origin="EXTERNAL", KeyUsage="ENCRYPT_DECRYPT", Description="test-key" + ) + key_id = create_key_response["KeyId"] + + get_parameters_response = aws_client.kms.get_parameters_for_import( + KeyId=key_id, WrappingAlgorithm="RSAES_OAEP_SHA_256", WrappingKeySpec="RSA_2048" + ) + assert get_parameters_response["ImportToken"] + assert get_parameters_response["PublicKey"] + + initial_key_material = generate_encrypted_symmetric_key_material( + get_parameters_response["PublicKey"] + ) + import_initial = aws_client.kms.import_key_material( + KeyId=key_id, + ImportToken=get_parameters_response["ImportToken"], + EncryptedKeyMaterial=initial_key_material, + ExpirationModel="KEY_MATERIAL_DOES_NOT_EXPIRE", + ) + snapshot.match("import-initial-material-response", import_initial) + + get_parameters_response = aws_client.kms.get_parameters_for_import( + KeyId=key_id, WrappingAlgorithm="RSAES_OAEP_SHA_256", WrappingKeySpec="RSA_2048" + ) + assert get_parameters_response["ImportToken"] + assert get_parameters_response["PublicKey"] + + pending_key_material = generate_encrypted_symmetric_key_material( + get_parameters_response["PublicKey"] + ) + import_pending = aws_client.kms.import_key_material( + KeyId=key_id, + ImportToken=get_parameters_response["ImportToken"], + EncryptedKeyMaterial=pending_key_material, + ExpirationModel="KEY_MATERIAL_DOES_NOT_EXPIRE", + ImportType="NEW_KEY_MATERIAL", + ) + snapshot.match("import-pending-material-response", import_pending) + + get_parameters_response = aws_client.kms.get_parameters_for_import( + KeyId=key_id, WrappingAlgorithm="RSAES_OAEP_SHA_256", WrappingKeySpec="RSA_2048" + ) + assert get_parameters_response["ImportToken"] + assert get_parameters_response["PublicKey"] + + final_key_material = generate_encrypted_symmetric_key_material( + get_parameters_response["PublicKey"] + ) + with pytest.raises(ClientError) as e: + aws_client.kms.import_key_material( + KeyId=key_id, + ImportToken=get_parameters_response["ImportToken"], + EncryptedKeyMaterial=final_key_material, + ExpirationModel="KEY_MATERIAL_DOES_NOT_EXPIRE", + ImportType="NEW_KEY_MATERIAL", + ) + snapshot.match("existing-pending-material-error", e.value.response) + + @markers.aws.validated + def test_rotate_key_on_demand_raises_for_no_pending_key_material( self, kms_create_key, aws_client, snapshot ): - key_id = kms_create_key(Origin="EXTERNAL")["KeyId"] + create_key_response = kms_create_key( + Origin="EXTERNAL", KeyUsage="ENCRYPT_DECRYPT", Description="test-key" + ) + key_id = create_key_response["KeyId"] + + get_parameters_response = aws_client.kms.get_parameters_for_import( + KeyId=key_id, WrappingAlgorithm="RSAES_OAEP_SHA_256", WrappingKeySpec="RSA_2048" + ) + assert get_parameters_response["ImportToken"] + assert get_parameters_response["PublicKey"] + + initial_key_material = generate_encrypted_symmetric_key_material( + get_parameters_response["PublicKey"] + ) + + aws_client.kms.import_key_material( + KeyId=key_id, + ImportToken=get_parameters_response["ImportToken"], + EncryptedKeyMaterial=initial_key_material, + ExpirationModel="KEY_MATERIAL_DOES_NOT_EXPIRE", + ) + + with pytest.raises(ClientError) as e: + aws_client.kms.rotate_key_on_demand(KeyId=key_id) + snapshot.match("rotate-key-on-demand-invalid-state-error", e.value.response) + + @markers.aws.validated + @pytest.mark.parametrize( + "key_spec", ["SYMMETRIC_DEFAULT", "RSA_4096"] + ) # Check with a non-default key spec to test ordering of raised errors. + def test_rotate_key_on_demand_on_external_key_with_no_key_material( + self, kms_create_key, aws_client, snapshot, key_spec + ): + create_key_response = kms_create_key( + Origin="EXTERNAL", KeyUsage="ENCRYPT_DECRYPT", Description="test-key" + ) + key_id = create_key_response["KeyId"] + snapshot.match("create-kms-external-key", create_key_response) with pytest.raises(ClientError) as e: aws_client.kms.rotate_key_on_demand(KeyId=key_id) - snapshot.match("error-response", e.value.response) + snapshot.match(f"rotate-key-on-demand-error-response-{key_spec}", e.value.response) @markers.aws.validated @pytest.mark.parametrize("rotation_period_in_days", [90, 180]) @@ -2096,6 +2477,107 @@ def test_encrypt_decrypt_encryption_context(self, kms_create_key, snapshot, aws_ ) snapshot.match("decrypt_response_with_invalid_ciphertext", e.value.response) + @markers.aws.only_localstack + def test_decrypt_recipient(self, kms_create_key, aws_client): + """ + Test that decryption to a Nitro recipient creates a correct PKCS7 envelope to that recipient. This is done + as an only-Localstack test because of the difficulty of spinning up a true Nitro enclave to generate a real + attestation for real AWS. + """ + + # Setup + key_id = kms_create_key(KeyUsage="ENCRYPT_DECRYPT", KeySpec="SYMMETRIC_DEFAULT")["KeyId"] + message = b"test message 123 !%$@ 1234567890" + ciphertext = aws_client.kms.encrypt( + KeyId=key_id, + Plaintext=base64.b64encode(message), + EncryptionAlgorithm="SYMMETRIC_DEFAULT", + )["CiphertextBlob"] + + # Set up our fake attestation. For now we just build a mini-attestation with only the public key, and + # skipping the other fields in it and the wrapping signature; in the future we could provide a more complete one. + rsa_key = rsa.generate_private_key( + public_exponent=65537, + key_size=2048, + backend=default_backend(), + ) + der_public_key = rsa_key.public_key().public_bytes( + encoding=serialization.Encoding.DER, + format=serialization.PublicFormat.SubjectPublicKeyInfo, + ) + inner_attestation = cbor2.dumps({"public_key": der_public_key}) + wrapped_attestation = cbor2.dumps(["", "", inner_attestation, ""]) + recipient = {"AttestationDocument": wrapped_attestation} + + # Do the KMS call + ciphertext_for_recipient = aws_client.kms.decrypt( + KeyId=key_id, + CiphertextBlob=ciphertext, + EncryptionAlgorithm="SYMMETRIC_DEFAULT", + Recipient=recipient, + )["CiphertextForRecipient"] + + # Decrypt the PKCS7 envelope to recover the plaintext. Hazmat's pkcs7_decrypt_pem() doesn't support the RSA-OAEP + # with SHA-256 that AWS uses, so we use as1ncrypto to unpack the envelope and then Hazmat to decrypt + # the session key and then the plaintext. + + # Parse the PKCS7 envelope + content_info = cms.ContentInfo.load(ciphertext_for_recipient) + enveloped_data = content_info["content"] + + # Extract the encrypted session key and encrypted content + recipient_info = enveloped_data["recipient_infos"][0].chosen + encrypted_session_key = recipient_info["encrypted_key"].native + encrypted_content_info = enveloped_data["encrypted_content_info"] + encrypted_content = encrypted_content_info["encrypted_content"].native + + # Get the IV from the content encryption algorithm parameters + iv = encrypted_content_info["content_encryption_algorithm"]["parameters"].native + + # Decrypt the session key + session_key = rsa_key.decrypt( + encrypted_session_key, + padding.OAEP( + mgf=padding.MGF1(algorithm=hashes.SHA256()), algorithm=hashes.SHA256(), label=None + ), + ) + + # Decrypt the content using the session key and iv + cipher = Cipher(algorithms.AES(session_key), modes.CBC(iv), backend=default_backend()) + decryptor = cipher.decryptor() + plaintext = decryptor.update(encrypted_content) + decryptor.finalize() + + # Make sure we did the decryption correctly + assert base64.b64decode(plaintext) == message + + @markers.aws.only_localstack + def test_decrypt_recipient_invalid_attestation(self, kms_create_key, aws_client): + """ + Test that if we are unable to extract the public key from the attestation, we ignore the recipient + and provide the plaintext in the response. + """ + + # Setup + key_id = kms_create_key(KeyUsage="ENCRYPT_DECRYPT", KeySpec="SYMMETRIC_DEFAULT")["KeyId"] + message = b"test message 123 !%$@ 1234567890" + ciphertext = aws_client.kms.encrypt( + KeyId=key_id, + Plaintext=base64.b64encode(message), + EncryptionAlgorithm="SYMMETRIC_DEFAULT", + )["CiphertextBlob"] + + # Invalid attestation document + recipient = {"AttestationDocument": base64.b64encode(b"invalidattestation")} + plaintext = aws_client.kms.decrypt( + KeyId=key_id, + CiphertextBlob=ciphertext, + EncryptionAlgorithm="SYMMETRIC_DEFAULT", + Recipient=recipient, + )["Plaintext"] + + # Still get the plaintext back + assert base64.b64decode(plaintext) == message + @markers.aws.validated def test_get_parameters_for_import(self, kms_create_key, snapshot, aws_client): sign_verify_key = kms_create_key( @@ -2120,6 +2602,19 @@ def test_get_parameters_for_import(self, kms_create_key, snapshot, aws_client): ) snapshot.match("response-error", e.value.response) + @markers.aws.validated + def test_get_parameters_for_import_raises_for_non_external_kms_keys( + self, kms_create_key, aws_client, snapshot + ): + aws_kms_key = kms_create_key() + with pytest.raises(ClientError) as e: + aws_client.kms.get_parameters_for_import( + KeyId=aws_kms_key["KeyId"], + WrappingAlgorithm="RSAES_OAEP_SHA_256", + WrappingKeySpec="RSA_2048", + ) + snapshot.match("get-import-parameters-error", e.value.response) + @markers.aws.validated def test_derive_shared_secret(self, kms_create_key, aws_client, snapshot): snapshot.add_transformer( @@ -2185,6 +2680,41 @@ def test_derive_shared_secret(self, kms_create_key, aws_client, snapshot): ) snapshot.match("response-invalid-public-key", e.value.response) + @markers.aws.validated + def test_derive_shared_secret_matches_openssl(self, kms_create_key, aws_client, snapshot): + snapshot.add_transformer( + snapshot.transform.key_value("SharedSecret", reference_replacement=False) + ) + + create_key = kms_create_key(KeySpec="ECC_NIST_P256", KeyUsage="KEY_AGREEMENT") + key_id = create_key["KeyId"] + + public_key = aws_client.kms.get_public_key(KeyId=key_id) + public_key_der = public_key["PublicKey"] + + local_private_key = ec.generate_private_key(ec.SECP256R1()) + local_public_key = local_private_key.public_key() + + local_public_key_der = local_public_key.public_bytes( + encoding=serialization.Encoding.DER, + format=serialization.PublicFormat.SubjectPublicKeyInfo, + ) + peer_public_key = load_der_public_key(public_key_der) + local_shared_secret = local_private_key.exchange(ec.ECDH(), peer_public_key) + + derived_shared_secret_resp = aws_client.kms.derive_shared_secret( + KeyId=key_id, + KeyAgreementAlgorithm="ECDH", + PublicKey=local_public_key_der, + ) + shared_secret = derived_shared_secret_resp["SharedSecret"] + + assert shared_secret == local_shared_secret, ( + f"KMS secret length: {len(shared_secret)}, OpenSSL secret length: {len(local_shared_secret)}" + ) + + snapshot.match("derived-shared-key-resp", derived_shared_secret_resp) + @markers.aws.validated @markers.snapshot.skip_snapshot_verify(paths=["$..CurrentKeyMaterialId"]) def test_describe_with_alias_arn(self, kms_create_key, aws_client, snapshot): diff --git a/tests/aws/services/kms/test_kms.snapshot.json b/tests/aws/services/kms/test_kms.snapshot.json index 2a3cfaae82d17..50b243450ab2a 100644 --- a/tests/aws/services/kms/test_kms.snapshot.json +++ b/tests/aws/services/kms/test_kms.snapshot.json @@ -165,12 +165,13 @@ } }, "tests/aws/services/kms/test_kms.py::TestKMS::test_create_key": { - "recorded-date": "13-04-2023, 11:29:30", + "recorded-date": "10-11-2025, 14:51:11", "recorded-content": { "describe-key": { "AWSAccountId": "111111111111", "Arn": "arn::kms::111111111111:key/", "CreationDate": "datetime", + "CurrentKeyMaterialId": "", "CustomerMasterKeySpec": "SYMMETRIC_DEFAULT", "Description": "test key 123", "Enabled": true, @@ -188,7 +189,7 @@ } }, "tests/aws/services/kms/test_kms.py::TestKMS::test_get_key_in_different_region": { - "recorded-date": "14-06-2024, 13:34:43", + "recorded-date": "10-11-2025, 14:57:15", "recorded-content": { "describe-key-diff-region-with-id": { "Error": { @@ -217,6 +218,7 @@ "AWSAccountId": "111111111111", "Arn": "arn::kms::111111111111:key/", "CreationDate": "datetime", + "CurrentKeyMaterialId": "", "CustomerMasterKeySpec": "SYMMETRIC_DEFAULT", "Description": "test key 123", "Enabled": true, @@ -241,6 +243,7 @@ "AWSAccountId": "111111111111", "Arn": "arn::kms::111111111111:key/", "CreationDate": "datetime", + "CurrentKeyMaterialId": "", "CustomerMasterKeySpec": "SYMMETRIC_DEFAULT", "Description": "test key 123", "Enabled": true, @@ -339,7 +342,7 @@ } }, "tests/aws/services/kms/test_kms.py::TestKMS::test_replicate_key": { - "recorded-date": "11-04-2024, 15:51:52", + "recorded-date": "10-11-2025, 16:44:08", "recorded-content": { "describe-key-from-different-region": { "Error": { @@ -409,6 +412,7 @@ "AWSAccountId": "111111111111", "Arn": "arn::kms::111111111111:key/", "CreationDate": "datetime", + "CurrentKeyMaterialId": "", "CustomerMasterKeySpec": "SYMMETRIC_DEFAULT", "Description": "test replicated key", "Enabled": true, @@ -446,16 +450,17 @@ "AWSAccountId": "111111111111", "Arn": "arn::kms:ap-southeast-1:111111111111:key/", "CreationDate": "datetime", + "CurrentKeyMaterialId": "", "CustomerMasterKeySpec": "SYMMETRIC_DEFAULT", "Description": "", - "Enabled": false, + "Enabled": true, "EncryptionAlgorithms": [ "SYMMETRIC_DEFAULT" ], "KeyId": "", "KeyManager": "CUSTOMER", "KeySpec": "SYMMETRIC_DEFAULT", - "KeyState": "Creating", + "KeyState": "Enabled", "KeyUsage": "ENCRYPT_DECRYPT", "MultiRegion": true, "MultiRegionConfiguration": { @@ -848,7 +853,7 @@ } }, "tests/aws/services/kms/test_kms.py::TestKMS::test_hmac_create_key": { - "recorded-date": "13-04-2023, 11:34:18", + "recorded-date": "10-11-2025, 17:24:11", "recorded-content": { "create-hmac-key": { "AWSAccountId": "111111111111", @@ -1208,7 +1213,7 @@ } }, "tests/aws/services/kms/test_kms.py::TestKMS::test_import_key_symmetric": { - "recorded-date": "24-01-2024, 10:44:12", + "recorded-date": "10-11-2025, 14:57:58", "recorded-content": { "created-key": { "AWSAccountId": "111111111111", @@ -1278,6 +1283,7 @@ "AWSAccountId": "111111111111", "Arn": "arn::kms::111111111111:key/", "CreationDate": "datetime", + "CurrentKeyMaterialId": "", "CustomerMasterKeySpec": "SYMMETRIC_DEFAULT", "Description": "", "Enabled": true, @@ -1303,6 +1309,7 @@ "AWSAccountId": "111111111111", "Arn": "arn::kms::111111111111:key/", "CreationDate": "datetime", + "CurrentKeyMaterialId": "", "CustomerMasterKeySpec": "SYMMETRIC_DEFAULT", "Description": "", "Enabled": false, @@ -1336,7 +1343,7 @@ } }, "tests/aws/services/kms/test_kms.py::TestKMS::test_import_key_asymmetric": { - "recorded-date": "24-01-2024, 10:44:14", + "recorded-date": "10-11-2025, 16:00:07", "recorded-content": { "created-key": { "AWSAccountId": "111111111111", @@ -1685,12 +1692,13 @@ } }, "tests/aws/services/kms/test_kms.py::TestKMS::test_create_multi_region_key": { - "recorded-date": "11-04-2024, 14:46:26", + "recorded-date": "10-11-2025, 16:02:52", "recorded-content": { "create_multi_region_key": { "AWSAccountId": "111111111111", "Arn": "arn::kms::111111111111:key/", "CreationDate": "datetime", + "CurrentKeyMaterialId": "", "CustomerMasterKeySpec": "SYMMETRIC_DEFAULT", "Description": "test multi region key", "Enabled": true, @@ -1716,12 +1724,13 @@ } }, "tests/aws/services/kms/test_kms.py::TestKMS::test_non_multi_region_keys_should_not_have_multi_region_properties": { - "recorded-date": "11-04-2024, 15:47:59", + "recorded-date": "10-11-2025, 16:04:38", "recorded-content": { "non_multi_region_keys_should_not_have_multi_region_properties": { "AWSAccountId": "111111111111", "Arn": "arn::kms::111111111111:key/", "CreationDate": "datetime", + "CurrentKeyMaterialId": "", "CustomerMasterKeySpec": "SYMMETRIC_DEFAULT", "Description": "test non multi region key", "Enabled": true, @@ -2060,7 +2069,7 @@ } }, "tests/aws/services/kms/test_kms.py::TestKMS::test_rotate_key_on_demand_with_symmetric_key_and_automatic_rotation_disabled": { - "recorded-date": "12-03-2025, 19:05:50", + "recorded-date": "10-11-2025, 17:37:46", "recorded-content": { "rotate-on-demand-response": { "KeyId": "", @@ -2197,9 +2206,18 @@ "recorded-content": {} }, "tests/aws/services/kms/test_kms.py::TestKMS::test_key_rotations_encryption_decryption": { - "recorded-date": "03-04-2025, 09:34:48", + "recorded-date": "09-02-2026, 19:06:42", "recorded-content": { - "bad-ciphertext": "An error occurred (InvalidCiphertextException) when calling the Decrypt operation: " + "bad-ciphertext": { + "Error": { + "Code": "InvalidCiphertextException", + "Message": "" + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + } } }, "tests/aws/services/kms/test_kms.py::TestKMS::test_key_rotations_limits": { @@ -3211,5 +3229,442 @@ } } } + }, + "tests/aws/services/kms/test_kms.py::TestKMS::test_rotate_key_on_demand_on_external_key_with_no_key_material[SYMMETRIC_DEFAULT]": { + "recorded-date": "05-11-2025, 16:12:01", + "recorded-content": { + "create-kms-external-key": { + "AWSAccountId": "111111111111", + "Arn": "arn::kms::111111111111:key/", + "CreationDate": "datetime", + "CustomerMasterKeySpec": "SYMMETRIC_DEFAULT", + "Description": "test-key", + "Enabled": false, + "EncryptionAlgorithms": [ + "SYMMETRIC_DEFAULT" + ], + "KeyId": "", + "KeyManager": "CUSTOMER", + "KeySpec": "SYMMETRIC_DEFAULT", + "KeyState": "PendingImport", + "KeyUsage": "ENCRYPT_DECRYPT", + "MultiRegion": false, + "Origin": "EXTERNAL" + }, + "rotate-key-on-demand-error-response-SYMMETRIC_DEFAULT": { + "Error": { + "Code": "KMSInvalidStateException", + "Message": "arn::kms::111111111111:key/ is pending import." + }, + "message": "arn::kms::111111111111:key/ is pending import.", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + } + } + }, + "tests/aws/services/kms/test_kms.py::TestKMS::test_rotate_key_on_demand_on_external_key_with_no_key_material[RSA_4096]": { + "recorded-date": "05-11-2025, 16:12:01", + "recorded-content": { + "create-kms-external-key": { + "AWSAccountId": "111111111111", + "Arn": "arn::kms::111111111111:key/", + "CreationDate": "datetime", + "CustomerMasterKeySpec": "SYMMETRIC_DEFAULT", + "Description": "test-key", + "Enabled": false, + "EncryptionAlgorithms": [ + "SYMMETRIC_DEFAULT" + ], + "KeyId": "", + "KeyManager": "CUSTOMER", + "KeySpec": "SYMMETRIC_DEFAULT", + "KeyState": "PendingImport", + "KeyUsage": "ENCRYPT_DECRYPT", + "MultiRegion": false, + "Origin": "EXTERNAL" + }, + "rotate-key-on-demand-error-response-RSA_4096": { + "Error": { + "Code": "KMSInvalidStateException", + "Message": "arn::kms::111111111111:key/ is pending import." + }, + "message": "arn::kms::111111111111:key/ is pending import.", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + } + } + }, + "tests/aws/services/kms/test_kms.py::TestKMS::test_rotate_on_demand_returns_arn_for_key_id": { + "recorded-date": "06-11-2025, 11:07:58", + "recorded-content": { + "rotate-on-demand-aws-key": { + "KeyId": "", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/kms/test_kms.py::TestKMS::test_rotate_key_on_demand_updates_current_key_material_for_external_keys": { + "recorded-date": "09-11-2025, 16:21:58", + "recorded-content": { + "create-kms-external-key": { + "AWSAccountId": "111111111111", + "Arn": "arn::kms::111111111111:key/", + "CreationDate": "datetime", + "CustomerMasterKeySpec": "SYMMETRIC_DEFAULT", + "Description": "test-key", + "Enabled": false, + "EncryptionAlgorithms": [ + "SYMMETRIC_DEFAULT" + ], + "KeyId": "", + "KeyManager": "CUSTOMER", + "KeySpec": "SYMMETRIC_DEFAULT", + "KeyState": "PendingImport", + "KeyUsage": "ENCRYPT_DECRYPT", + "MultiRegion": false, + "Origin": "EXTERNAL" + }, + "get-import-parameters-response": { + "ImportToken": "import-token", + "KeyId": "arn::kms::111111111111:key/", + "ParametersValidTo": "datetime", + "PublicKey": "public-key", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "describe-empty-key-response": { + "KeyMetadata": { + "AWSAccountId": "111111111111", + "Arn": "arn::kms::111111111111:key/", + "CreationDate": "datetime", + "CustomerMasterKeySpec": "SYMMETRIC_DEFAULT", + "Description": "test-key", + "Enabled": false, + "EncryptionAlgorithms": [ + "SYMMETRIC_DEFAULT" + ], + "KeyId": "", + "KeyManager": "CUSTOMER", + "KeySpec": "SYMMETRIC_DEFAULT", + "KeyState": "PendingImport", + "KeyUsage": "ENCRYPT_DECRYPT", + "MultiRegion": false, + "Origin": "EXTERNAL" + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "import-key-material-response": { + "KeyId": "arn::kms::111111111111:key/", + "KeyMaterialId": "", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "describe-key-with-material-response": { + "KeyMetadata": { + "AWSAccountId": "111111111111", + "Arn": "arn::kms::111111111111:key/", + "CreationDate": "datetime", + "CurrentKeyMaterialId": "", + "CustomerMasterKeySpec": "SYMMETRIC_DEFAULT", + "Description": "test-key", + "Enabled": true, + "EncryptionAlgorithms": [ + "SYMMETRIC_DEFAULT" + ], + "ExpirationModel": "KEY_MATERIAL_DOES_NOT_EXPIRE", + "KeyId": "", + "KeyManager": "CUSTOMER", + "KeySpec": "SYMMETRIC_DEFAULT", + "KeyState": "Enabled", + "KeyUsage": "ENCRYPT_DECRYPT", + "MultiRegion": false, + "Origin": "EXTERNAL" + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "kms-encrypt-initial-response": { + "CiphertextBlob": "ciphertext-blob", + "EncryptionAlgorithm": "SYMMETRIC_DEFAULT", + "KeyId": "arn::kms::111111111111:key/", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "import-new-key-material-response": { + "KeyId": "arn::kms::111111111111:key/", + "KeyMaterialId": "", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "describe-key-with-new-material-response": { + "KeyMetadata": { + "AWSAccountId": "111111111111", + "Arn": "arn::kms::111111111111:key/", + "CreationDate": "datetime", + "CurrentKeyMaterialId": "", + "CustomerMasterKeySpec": "SYMMETRIC_DEFAULT", + "Description": "test-key", + "Enabled": true, + "EncryptionAlgorithms": [ + "SYMMETRIC_DEFAULT" + ], + "ExpirationModel": "KEY_MATERIAL_DOES_NOT_EXPIRE", + "KeyId": "", + "KeyManager": "CUSTOMER", + "KeySpec": "SYMMETRIC_DEFAULT", + "KeyState": "Enabled", + "KeyUsage": "ENCRYPT_DECRYPT", + "MultiRegion": false, + "Origin": "EXTERNAL" + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "rotate-key-on-demand-response": { + "KeyId": "arn::kms::111111111111:key/", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "describe-key-after-rotation": { + "KeyMetadata": { + "AWSAccountId": "111111111111", + "Arn": "arn::kms::111111111111:key/", + "CreationDate": "datetime", + "CurrentKeyMaterialId": "", + "CustomerMasterKeySpec": "SYMMETRIC_DEFAULT", + "Description": "test-key", + "Enabled": true, + "EncryptionAlgorithms": [ + "SYMMETRIC_DEFAULT" + ], + "ExpirationModel": "KEY_MATERIAL_DOES_NOT_EXPIRE", + "KeyId": "", + "KeyManager": "CUSTOMER", + "KeySpec": "SYMMETRIC_DEFAULT", + "KeyState": "Enabled", + "KeyUsage": "ENCRYPT_DECRYPT", + "MultiRegion": false, + "Origin": "EXTERNAL" + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "kms-encrypt-rotated-key-response": { + "CiphertextBlob": "ciphertext-blob", + "EncryptionAlgorithm": "SYMMETRIC_DEFAULT", + "KeyId": "arn::kms::111111111111:key/", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/kms/test_kms.py::TestKMS::test_get_parameters_for_import_raises_for_non_external_kms_keys": { + "recorded-date": "10-11-2025, 23:21:24", + "recorded-content": { + "get-import-parameters-error": { + "Error": { + "Code": "UnsupportedOperationException", + "Message": " origin is AWS_KMS which is not valid for this operation." + }, + "message": " origin is AWS_KMS which is not valid for this operation.", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + } + } + }, + "tests/aws/services/kms/test_kms.py::TestKMS::test_import_key_material_raises_if_there_is_already_key_material_pending": { + "recorded-date": "10-11-2025, 23:15:45", + "recorded-content": { + "import-initial-material-response": { + "KeyId": "", + "KeyMaterialId": "", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "import-pending-material-response": { + "KeyId": "", + "KeyMaterialId": "", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "existing-pending-material-error": { + "Error": { + "Code": "KMSInvalidStateException", + "Message": "New key material (id: ) cannot be imported into KMS key , because another key material (id: ) is pending rotation." + }, + "message": "New key material (id: ) cannot be imported into KMS key , because another key material (id: ) is pending rotation.", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + } + } + }, + "tests/aws/services/kms/test_kms.py::TestKMS::test_rotate_key_on_demand_for_external_keys_decrypts_with_previous_material": { + "recorded-date": "12-11-2025, 21:00:07", + "recorded-content": { + "create-kms-external-key": { + "AWSAccountId": "111111111111", + "Arn": "arn::kms::111111111111:key/", + "CreationDate": "datetime", + "CustomerMasterKeySpec": "SYMMETRIC_DEFAULT", + "Description": "test-key", + "Enabled": false, + "EncryptionAlgorithms": [ + "SYMMETRIC_DEFAULT" + ], + "KeyId": "", + "KeyManager": "CUSTOMER", + "KeySpec": "SYMMETRIC_DEFAULT", + "KeyState": "PendingImport", + "KeyUsage": "ENCRYPT_DECRYPT", + "MultiRegion": false, + "Origin": "EXTERNAL" + }, + "import-key-material-response": { + "KeyId": "arn::kms::111111111111:key/", + "KeyMaterialId": "", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "kms-encrypt-initial-response": { + "CiphertextBlob": "ciphertext-blob", + "EncryptionAlgorithm": "SYMMETRIC_DEFAULT", + "KeyId": "arn::kms::111111111111:key/", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "rotate-key-on-demand-response": { + "KeyId": "arn::kms::111111111111:key/", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/kms/test_kms.py::TestKMS::test_rotate_key_on_demand_raises_for_no_pending_key_material": { + "recorded-date": "19-11-2025, 10:21:48", + "recorded-content": { + "rotate-key-on-demand-invalid-state-error": { + "Error": { + "Code": "KMSInvalidStateException", + "Message": "No available key material pending rotation for the key: ." + }, + "message": "No available key material pending rotation for the key: .", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + } + } + }, + "tests/aws/services/kms/test_kms.py::TestKMS::test_key_rotation_updates_current_key_material_id_for_aws_symmetric_keys": { + "recorded-date": "19-11-2025, 10:55:13", + "recorded-content": { + "describe-key-before-rotation": { + "KeyMetadata": { + "AWSAccountId": "111111111111", + "Arn": "arn::kms::111111111111:key/", + "CreationDate": "datetime", + "CurrentKeyMaterialId": "", + "CustomerMasterKeySpec": "SYMMETRIC_DEFAULT", + "Description": "test-key", + "Enabled": true, + "EncryptionAlgorithms": [ + "SYMMETRIC_DEFAULT" + ], + "KeyId": "", + "KeyManager": "CUSTOMER", + "KeySpec": "SYMMETRIC_DEFAULT", + "KeyState": "Enabled", + "KeyUsage": "ENCRYPT_DECRYPT", + "MultiRegion": false, + "Origin": "AWS_KMS" + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "describe-key-after-rotation": { + "KeyMetadata": { + "AWSAccountId": "111111111111", + "Arn": "arn::kms::111111111111:key/", + "CreationDate": "datetime", + "CurrentKeyMaterialId": "", + "CustomerMasterKeySpec": "SYMMETRIC_DEFAULT", + "Description": "test-key", + "Enabled": true, + "EncryptionAlgorithms": [ + "SYMMETRIC_DEFAULT" + ], + "KeyId": "", + "KeyManager": "CUSTOMER", + "KeySpec": "SYMMETRIC_DEFAULT", + "KeyState": "Enabled", + "KeyUsage": "ENCRYPT_DECRYPT", + "MultiRegion": false, + "Origin": "AWS_KMS" + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/kms/test_kms.py::TestKMS::test_derive_shared_secret_matches_openssl": { + "recorded-date": "14-11-2025, 06:17:43", + "recorded-content": { + "derived-shared-key-resp": { + "KeyAgreementAlgorithm": "ECDH", + "KeyId": "", + "KeyOrigin": "AWS_KMS", + "SharedSecret": "shared-secret", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } } } diff --git a/tests/aws/services/kms/test_kms.validation.json b/tests/aws/services/kms/test_kms.validation.json index aa83a4a410612..d06d7323d49c6 100644 --- a/tests/aws/services/kms/test_kms.validation.json +++ b/tests/aws/services/kms/test_kms.validation.json @@ -21,7 +21,13 @@ "last_validated_date": "2024-04-11T15:52:40+00:00" }, "tests/aws/services/kms/test_kms.py::TestKMS::test_create_key": { - "last_validated_date": "2024-04-11T15:26:14+00:00" + "last_validated_date": "2025-11-10T14:51:11+00:00", + "durations_in_seconds": { + "setup": 1.51, + "call": 0.36, + "teardown": 0.05, + "total": 1.92 + } }, "tests/aws/services/kms/test_kms.py::TestKMS::test_create_key_with_invalid_tag_key[lowercase_prefix]": { "last_validated_date": "2025-01-22T13:37:31+00:00" @@ -42,11 +48,26 @@ "last_validated_date": "2024-04-11T15:53:50+00:00" }, "tests/aws/services/kms/test_kms.py::TestKMS::test_create_multi_region_key": { - "last_validated_date": "2024-04-11T15:53:40+00:00" + "last_validated_date": "2025-11-10T16:02:52+00:00", + "durations_in_seconds": { + "setup": 1.19, + "call": 0.35, + "teardown": 0.05, + "total": 1.59 + } }, "tests/aws/services/kms/test_kms.py::TestKMS::test_derive_shared_secret": { "last_validated_date": "2024-12-25T14:45:00+00:00" }, + "tests/aws/services/kms/test_kms.py::TestKMS::test_derive_shared_secret_matches_openssl": { + "last_validated_date": "2025-11-14T06:17:43+00:00", + "durations_in_seconds": { + "setup": 1.43, + "call": 1.75, + "teardown": 0.38, + "total": 3.56 + } + }, "tests/aws/services/kms/test_kms.py::TestKMS::test_describe_and_list_sign_key": { "last_validated_date": "2024-04-11T15:53:27+00:00" }, @@ -144,7 +165,13 @@ } }, "tests/aws/services/kms/test_kms.py::TestKMS::test_get_key_in_different_region": { - "last_validated_date": "2024-06-14T13:35:20+00:00" + "last_validated_date": "2025-11-10T14:57:15+00:00", + "durations_in_seconds": { + "setup": 0.93, + "call": 1.45, + "teardown": 0.2, + "total": 2.58 + } }, "tests/aws/services/kms/test_kms.py::TestKMS::test_get_key_invalid_uuid": { "last_validated_date": "2024-04-11T15:52:33+00:00" @@ -152,6 +179,15 @@ "tests/aws/services/kms/test_kms.py::TestKMS::test_get_parameters_for_import": { "last_validated_date": "2024-04-11T15:54:23+00:00" }, + "tests/aws/services/kms/test_kms.py::TestKMS::test_get_parameters_for_import_raises_for_non_external_kms_keys": { + "last_validated_date": "2025-11-10T23:21:24+00:00", + "durations_in_seconds": { + "setup": 1.01, + "call": 0.31, + "teardown": 0.05, + "total": 1.37 + } + }, "tests/aws/services/kms/test_kms.py::TestKMS::test_get_public_key": { "last_validated_date": "2024-04-11T15:53:25+00:00" }, @@ -159,13 +195,25 @@ "last_validated_date": "2024-04-11T15:53:55+00:00" }, "tests/aws/services/kms/test_kms.py::TestKMS::test_hmac_create_key": { - "last_validated_date": "2024-04-10T20:40:13+00:00" + "last_validated_date": "2025-11-10T17:24:11+00:00", + "durations_in_seconds": { + "setup": 1.02, + "call": 0.36, + "teardown": 0.05, + "total": 1.43 + } }, "tests/aws/services/kms/test_kms.py::TestKMS::test_hmac_create_key_invalid_operations": { "last_validated_date": "2023-04-13T09:31:06+00:00" }, "tests/aws/services/kms/test_kms.py::TestKMS::test_import_key_asymmetric": { - "last_validated_date": "2024-04-11T15:53:35+00:00" + "last_validated_date": "2025-11-10T16:00:07+00:00", + "durations_in_seconds": { + "setup": 1.59, + "call": 0.64, + "teardown": 0.05, + "total": 2.28 + } }, "tests/aws/services/kms/test_kms.py::TestKMS::test_import_key_ecc_keys[ECC_NIST_P256]": { "last_validated_date": "2025-08-04T08:10:22+00:00", @@ -239,6 +287,15 @@ "total": 3.24 } }, + "tests/aws/services/kms/test_kms.py::TestKMS::test_import_key_material_raises_if_there_is_already_key_material_pending": { + "last_validated_date": "2025-11-10T23:15:45+00:00", + "durations_in_seconds": { + "setup": 0.93, + "call": 0.62, + "teardown": 0.05, + "total": 1.6 + } + }, "tests/aws/services/kms/test_kms.py::TestKMS::test_import_key_rsa_aes_wrap_sha256": { "last_validated_date": "2025-07-22T06:11:13+00:00", "durations_in_seconds": { @@ -249,7 +306,13 @@ } }, "tests/aws/services/kms/test_kms.py::TestKMS::test_import_key_symmetric": { - "last_validated_date": "2024-04-11T15:53:31+00:00" + "last_validated_date": "2025-11-10T14:57:58+00:00", + "durations_in_seconds": { + "setup": 0.86, + "call": 0.68, + "teardown": 0.05, + "total": 1.59 + } }, "tests/aws/services/kms/test_kms.py::TestKMS::test_invalid_generate_mac[HMAC_224-HMAC_SHA_256]": { "last_validated_date": "2024-04-11T15:54:11+00:00" @@ -278,8 +341,23 @@ "tests/aws/services/kms/test_kms.py::TestKMS::test_key_rotation_status": { "last_validated_date": "2024-04-11T15:53:48+00:00" }, + "tests/aws/services/kms/test_kms.py::TestKMS::test_key_rotation_updates_current_key_material_id_for_aws_symmetric_keys": { + "last_validated_date": "2025-11-19T10:55:13+00:00", + "durations_in_seconds": { + "setup": 0.92, + "call": 65.88, + "teardown": 0.05, + "total": 66.85 + } + }, "tests/aws/services/kms/test_kms.py::TestKMS::test_key_rotations_encryption_decryption": { - "last_validated_date": "2025-04-03T09:34:47+00:00" + "last_validated_date": "2026-02-09T19:06:42+00:00", + "durations_in_seconds": { + "setup": 0.49, + "call": 1.13, + "teardown": 0.12, + "total": 1.74 + } }, "tests/aws/services/kms/test_kms.py::TestKMS::test_key_rotations_limits": { "last_validated_date": "2025-04-03T11:10:33+00:00" @@ -297,7 +375,13 @@ "last_validated_date": "2024-04-11T15:52:34+00:00" }, "tests/aws/services/kms/test_kms.py::TestKMS::test_non_multi_region_keys_should_not_have_multi_region_properties": { - "last_validated_date": "2024-04-11T15:53:41+00:00" + "last_validated_date": "2025-11-10T16:04:38+00:00", + "durations_in_seconds": { + "setup": 1.22, + "call": 0.3, + "teardown": 0.05, + "total": 1.57 + } }, "tests/aws/services/kms/test_kms.py::TestKMS::test_plaintext_size_for_encrypt": { "last_validated_date": "2024-04-11T15:54:20+00:00" @@ -312,7 +396,13 @@ "last_validated_date": "2025-06-09T12:53:24+00:00" }, "tests/aws/services/kms/test_kms.py::TestKMS::test_replicate_key": { - "last_validated_date": "2024-04-11T15:53:44+00:00" + "last_validated_date": "2025-11-10T16:44:08+00:00", + "durations_in_seconds": { + "setup": 1.01, + "call": 64.64, + "teardown": 0.34, + "total": 65.99 + } }, "tests/aws/services/kms/test_kms.py::TestKMS::test_replicate_replica_key_should_fail": { "last_validated_date": "2025-09-08T16:34:57+00:00", @@ -329,9 +419,36 @@ "tests/aws/services/kms/test_kms.py::TestKMS::test_revoke_grant": { "last_validated_date": "2024-04-11T15:52:44+00:00" }, + "tests/aws/services/kms/test_kms.py::TestKMS::test_rotate_key_on_demand_for_external_keys_decrypts_with_previous_material": { + "last_validated_date": "2025-11-12T21:00:07+00:00", + "durations_in_seconds": { + "setup": 0.91, + "call": 66.22, + "teardown": 0.05, + "total": 67.18 + } + }, "tests/aws/services/kms/test_kms.py::TestKMS::test_rotate_key_on_demand_modifies_key_material": { "last_validated_date": "2025-03-08T09:24:15+00:00" }, + "tests/aws/services/kms/test_kms.py::TestKMS::test_rotate_key_on_demand_on_external_key_with_no_key_material[RSA_4096]": { + "last_validated_date": "2025-11-05T16:12:01+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.1, + "teardown": 0.05, + "total": 0.15 + } + }, + "tests/aws/services/kms/test_kms.py::TestKMS::test_rotate_key_on_demand_on_external_key_with_no_key_material[SYMMETRIC_DEFAULT]": { + "last_validated_date": "2025-11-05T16:12:01+00:00", + "durations_in_seconds": { + "setup": 0.83, + "call": 0.21, + "teardown": 0.05, + "total": 1.09 + } + }, "tests/aws/services/kms/test_kms.py::TestKMS::test_rotate_key_on_demand_raises_error_given_key_is_disabled": { "last_validated_date": "2025-03-08T09:26:50+00:00" }, @@ -344,12 +461,45 @@ "tests/aws/services/kms/test_kms.py::TestKMS::test_rotate_key_on_demand_raises_error_given_non_symmetric_key": { "last_validated_date": "2025-03-08T09:27:44+00:00" }, + "tests/aws/services/kms/test_kms.py::TestKMS::test_rotate_key_on_demand_raises_for_no_pending_key_material": { + "last_validated_date": "2025-11-19T10:21:48+00:00", + "durations_in_seconds": { + "setup": 0.78, + "call": 0.39, + "teardown": 0.05, + "total": 1.22 + } + }, + "tests/aws/services/kms/test_kms.py::TestKMS::test_rotate_key_on_demand_updates_current_key_material_for_external_keys": { + "last_validated_date": "2025-11-09T16:21:58+00:00", + "durations_in_seconds": { + "setup": 0.96, + "call": 61.39, + "teardown": 0.05, + "total": 62.4 + } + }, "tests/aws/services/kms/test_kms.py::TestKMS::test_rotate_key_on_demand_with_symmetric_key_and_automatic_rotation_disabled": { - "last_validated_date": "2025-03-12T19:05:50+00:00" + "last_validated_date": "2025-11-10T17:37:46+00:00", + "durations_in_seconds": { + "setup": 1.18, + "call": 6.38, + "teardown": 0.05, + "total": 7.61 + } }, "tests/aws/services/kms/test_kms.py::TestKMS::test_rotate_key_on_demand_with_symmetric_key_and_automatic_rotation_enabled": { "last_validated_date": "2025-03-12T19:07:01+00:00" }, + "tests/aws/services/kms/test_kms.py::TestKMS::test_rotate_on_demand_returns_arn_for_key_id": { + "last_validated_date": "2025-11-06T11:07:58+00:00", + "durations_in_seconds": { + "setup": 0.91, + "call": 0.31, + "teardown": 0.05, + "total": 1.27 + } + }, "tests/aws/services/kms/test_kms.py::TestKMS::test_schedule_and_cancel_key_deletion": { "last_validated_date": "2024-04-11T15:52:36+00:00" }, diff --git a/tests/aws/services/lambda_/event_source_mapping/test_cfn_resource.snapshot.json b/tests/aws/services/lambda_/event_source_mapping/test_cfn_resource.snapshot.json index 618589334f8f8..44a2cb355001c 100644 --- a/tests/aws/services/lambda_/event_source_mapping/test_cfn_resource.snapshot.json +++ b/tests/aws/services/lambda_/event_source_mapping/test_cfn_resource.snapshot.json @@ -1,6 +1,6 @@ { "tests/aws/services/lambda_/event_source_mapping/test_cfn_resource.py::test_adding_tags": { - "recorded-date": "19-05-2025, 09:32:18", + "recorded-date": "25-11-2025, 15:44:31", "recorded-content": { "event-source-mapping-tags": { "Tags": { diff --git a/tests/aws/services/lambda_/event_source_mapping/test_cfn_resource.validation.json b/tests/aws/services/lambda_/event_source_mapping/test_cfn_resource.validation.json index 2a6ef1af1c4db..b923c943582f4 100644 --- a/tests/aws/services/lambda_/event_source_mapping/test_cfn_resource.validation.json +++ b/tests/aws/services/lambda_/event_source_mapping/test_cfn_resource.validation.json @@ -1,11 +1,11 @@ { "tests/aws/services/lambda_/event_source_mapping/test_cfn_resource.py::test_adding_tags": { - "last_validated_date": "2025-05-19T09:33:12+00:00", + "last_validated_date": "2025-11-25T15:45:22+00:00", "durations_in_seconds": { - "setup": 0.54, - "call": 69.88, - "teardown": 54.76, - "total": 125.18 + "setup": 0.68, + "call": 103.05, + "teardown": 51.44, + "total": 155.17 } } } diff --git a/tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_dynamodbstreams.py b/tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_dynamodbstreams.py index e09b430e37002..102b626993f1e 100644 --- a/tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_dynamodbstreams.py +++ b/tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_dynamodbstreams.py @@ -309,7 +309,7 @@ def test_disabled_dynamodb_event_source_mapping( retry( check_expected_lambda_log_events_length, retries=10, - sleep=3, + sleep=5 if is_aws_cloud() else 1, function_name=function_name, expected_length=1, logs_client=aws_client.logs, @@ -371,12 +371,6 @@ def test_deletion_event_source_mapping_with_dynamodb( list_esm = aws_client.lambda_.list_event_source_mappings(EventSourceArn=latest_stream_arn) snapshot.match("list_event_source_mapping_result", list_esm) - # TODO re-record snapshot, now TableId is returned but new WarmThroughput property is not - @markers.snapshot.skip_snapshot_verify( - paths=[ - "$..TableDescription.TableId", - ], - ) @markers.aws.validated def test_dynamodb_event_source_mapping_with_sns_on_failure_destination_config( self, @@ -486,12 +480,6 @@ def verify_failure_received(): snapshot.match("failure_sns_message", failure_sns_message) - # TODO re-record snapshot, now TableId is returned but new WarmThroughput property is not - @markers.snapshot.skip_snapshot_verify( - paths=[ - "$..TableDescription.TableId", - ], - ) @markers.aws.validated def test_dynamodb_event_source_mapping_with_on_failure_destination_config( self, @@ -572,10 +560,8 @@ def verify_failure_received(): messages = retry(verify_failure_received, retries=15, sleep=sleep, sleep_before=5) snapshot.match("destination_queue_messages", messages) - # FIXME UpdateTable is not returning a WarmThroughput property @markers.snapshot.skip_snapshot_verify( paths=[ - "$..TableDescription.WarmThroughput", "$..requestContext.requestId", # TODO there is an extra uuid in the snapshot when run in CI on itest-ddb-v2-provider step, need to look why ], ) @@ -948,7 +934,6 @@ def test_dynamodb_invalid_event_filter( @markers.snapshot.skip_snapshot_verify( paths=[ - "$..TableDescription.TableId", "$..Records", # TODO Figure out why there is an extra log record ], ) @@ -1095,6 +1080,8 @@ def test_dynamodb_report_batch_item_failure_scenarios( ): snapshot.add_transformer(snapshot.transform.key_value("MD5OfBody")) snapshot.add_transformer(snapshot.transform.key_value("ReceiptHandle")) + snapshot.add_transformer(snapshot.transform.key_value("startSequenceNumber")) + snapshot.add_transformer(snapshot.transform.key_value("endSequenceNumber")) function_name = f"lambda_func-{short_uid()}" table_name = f"test-table-{short_uid()}" @@ -1149,11 +1136,14 @@ def verify_failure_received(): messages = retry(verify_failure_received, retries=15, sleep=sleep, sleep_before=5) snapshot.match("destination_queue_messages", messages) - events = get_lambda_log_events(function_name, logs_client=aws_client.logs) - # This will filter out exception messages being added to the log stream - invocation_events = [event for event in events if "Records" in event] - snapshot.match("dynamodb_events", invocation_events) + def _get_events(): + events = get_lambda_log_events(function_name, logs_client=aws_client.logs) + invocation_events = [event for event in events if "Records" in event] + assert len(invocation_events) == 4 + return invocation_events + + snapshot.match("dynamodb_events", retry(_get_events, retries=10)) @markers.aws.validated @pytest.mark.parametrize( diff --git a/tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_dynamodbstreams.snapshot.json b/tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_dynamodbstreams.snapshot.json index 709bfc346d2f0..a7c4133bd05f3 100644 --- a/tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_dynamodbstreams.snapshot.json +++ b/tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_dynamodbstreams.snapshot.json @@ -1,6 +1,6 @@ { "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_dynamodbstreams.py::TestDynamoDBEventSourceMapping::test_dynamodb_event_source_mapping": { - "recorded-date": "22-02-2025, 03:03:03", + "recorded-date": "25-11-2025, 15:47:40", "recorded-content": { "create-table-result": { "TableDescription": { @@ -100,7 +100,7 @@ } }, "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_dynamodbstreams.py::TestDynamoDBEventSourceMapping::test_disabled_dynamodb_event_source_mapping": { - "recorded-date": "12-10-2024, 10:57:16", + "recorded-date": "25-11-2025, 17:53:07", "recorded-content": { "dynamodb_create_table_result": { "TableDescription": { @@ -199,7 +199,7 @@ } }, "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_dynamodbstreams.py::TestDynamoDBEventSourceMapping::test_deletion_event_source_mapping_with_dynamodb": { - "recorded-date": "12-10-2024, 10:57:49", + "recorded-date": "25-11-2025, 15:49:36", "recorded-content": { "create_dynamodb_table_response": { "TableDescription": { @@ -302,7 +302,7 @@ } }, "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_dynamodbstreams.py::TestDynamoDBEventSourceMapping::test_dynamodb_event_source_mapping_with_on_failure_destination_config": { - "recorded-date": "12-10-2024, 11:01:18", + "recorded-date": "25-11-2025, 15:53:08", "recorded-content": { "create_table_response": { "TableDescription": { @@ -376,7 +376,12 @@ "TableId": "", "TableName": "", "TableSizeBytes": 0, - "TableStatus": "UPDATING" + "TableStatus": "UPDATING", + "WarmThroughput": { + "ReadUnitsPerSecond": 12000, + "Status": "ACTIVE", + "WriteUnitsPerSecond": 4000 + } }, "ResponseMetadata": { "HTTPHeaders": {}, @@ -451,7 +456,7 @@ } }, "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_dynamodbstreams.py::TestDynamoDBEventSourceMapping::test_dynamodb_invalid_event_filter[single-string]": { - "recorded-date": "12-10-2024, 11:21:25", + "recorded-date": "25-11-2025, 16:06:35", "recorded-content": { "exception_event_source_creation": { "Error": { @@ -468,7 +473,7 @@ } }, "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_dynamodbstreams.py::TestDynamoDBEventSourceMapping::test_dynamodb_invalid_event_filter[[{\"eventName\": [\"INSERT\"=123}]]": { - "recorded-date": "12-10-2024, 11:21:41", + "recorded-date": "25-11-2025, 16:06:50", "recorded-content": { "exception_event_source_creation": { "Error": { @@ -485,7 +490,7 @@ } }, "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_dynamodbstreams.py::TestDynamoDBEventSourceMapping::test_duplicate_event_source_mappings": { - "recorded-date": "12-10-2024, 10:55:48", + "recorded-date": "25-11-2025, 15:47:54", "recorded-content": { "create-table-result": { "TableDescription": { @@ -564,7 +569,7 @@ } }, "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_dynamodbstreams.py::TestDynamoDBEventSourceMapping::test_dynamodb_event_filter[insert_same_entry_twice]": { - "recorded-date": "12-10-2024, 11:03:08", + "recorded-date": "25-11-2025, 15:56:13", "recorded-content": { "table_creation_response": { "TableDescription": { @@ -708,7 +713,7 @@ } }, "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_dynamodbstreams.py::TestDynamoDBEventSourceMapping::test_dynamodb_event_filter[content_or_filter]": { - "recorded-date": "12-10-2024, 11:05:33", + "recorded-date": "25-11-2025, 15:57:25", "recorded-content": { "table_creation_response": { "TableDescription": { @@ -1024,7 +1029,7 @@ } }, "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_dynamodbstreams.py::TestDynamoDBEventSourceMapping::test_dynamodb_event_filter[content_filter_type]": { - "recorded-date": "12-10-2024, 11:08:12", + "recorded-date": "25-11-2025, 15:59:22", "recorded-content": { "table_creation_response": { "TableDescription": { @@ -1174,7 +1179,7 @@ } }, "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_dynamodbstreams.py::TestDynamoDBEventSourceMapping::test_dynamodb_event_filter[exists_filter_type]": { - "recorded-date": "12-10-2024, 11:10:06", + "recorded-date": "25-11-2025, 16:01:13", "recorded-content": { "table_creation_response": { "TableDescription": { @@ -1326,7 +1331,7 @@ } }, "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_dynamodbstreams.py::TestDynamoDBEventSourceMapping::test_dynamodb_event_filter[exists_false_filter]": { - "recorded-date": "05-12-2024, 15:58:42", + "recorded-date": "25-11-2025, 16:02:27", "recorded-content": { "table_creation_response": { "TableDescription": { @@ -1501,7 +1506,7 @@ } }, "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_dynamodbstreams.py::TestDynamoDBEventSourceMapping::test_dynamodb_event_filter[numeric_filter]": { - "recorded-date": "05-12-2024, 16:01:14", + "recorded-date": "25-11-2025, 16:04:16", "recorded-content": { "table_creation_response": { "TableDescription": { @@ -1659,7 +1664,7 @@ } }, "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_dynamodbstreams.py::TestDynamoDBEventSourceMapping::test_dynamodb_event_filter[prefix_filter]": { - "recorded-date": "12-10-2024, 11:11:06", + "recorded-date": "25-11-2025, 16:05:14", "recorded-content": { "table_creation_response": { "TableDescription": { @@ -1811,7 +1816,7 @@ } }, "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_dynamodbstreams.py::TestDynamoDBEventSourceMapping::test_dynamodb_event_filter[date_time_conversion]": { - "recorded-date": "12-10-2024, 11:20:10", + "recorded-date": "25-11-2025, 16:06:22", "recorded-content": { "table_creation_response": { "TableDescription": { @@ -1977,7 +1982,7 @@ } }, "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_dynamodbstreams.py::TestDynamoDBEventSourceMapping::test_dynamodb_event_source_mapping_with_sns_on_failure_destination_config": { - "recorded-date": "12-10-2024, 10:59:12", + "recorded-date": "25-11-2025, 15:51:38", "recorded-content": { "create_table_response": { "TableDescription": { @@ -2051,7 +2056,12 @@ "TableId": "", "TableName": "", "TableSizeBytes": 0, - "TableStatus": "UPDATING" + "TableStatus": "UPDATING", + "WarmThroughput": { + "ReadUnitsPerSecond": 12000, + "Status": "ACTIVE", + "WriteUnitsPerSecond": 4000 + } }, "ResponseMetadata": { "HTTPHeaders": {}, @@ -2123,7 +2133,7 @@ } }, "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_dynamodbstreams.py::TestDynamoDBEventSourceMapping::test_dynamodb_report_batch_item_failures": { - "recorded-date": "12-10-2024, 11:25:25", + "recorded-date": "25-11-2025, 16:08:24", "recorded-content": { "create_table_response": { "TableDescription": { @@ -2197,7 +2207,12 @@ "TableId": "", "TableName": "", "TableSizeBytes": 0, - "TableStatus": "UPDATING" + "TableStatus": "UPDATING", + "WarmThroughput": { + "ReadUnitsPerSecond": 12000, + "Status": "ACTIVE", + "WriteUnitsPerSecond": 4000 + } }, "ResponseMetadata": { "HTTPHeaders": {}, @@ -2698,7 +2713,7 @@ } }, "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_dynamodbstreams.py::TestDynamoDBEventSourceMapping::test_dynamodb_report_batch_item_failure_scenarios[empty_string_item_identifier_failure]": { - "recorded-date": "12-10-2024, 11:30:34", + "recorded-date": "25-11-2025, 20:01:25", "recorded-content": { "create-table-result": { "TableDescription": { @@ -2902,7 +2917,7 @@ } }, "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_dynamodbstreams.py::TestDynamoDBEventSourceMapping::test_dynamodb_report_batch_item_failure_scenarios[null_item_identifier_failure]": { - "recorded-date": "12-10-2024, 11:33:20", + "recorded-date": "25-11-2025, 20:03:19", "recorded-content": { "create-table-result": { "TableDescription": { @@ -3106,7 +3121,7 @@ } }, "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_dynamodbstreams.py::TestDynamoDBEventSourceMapping::test_dynamodb_report_batch_item_failure_scenarios[invalid_key_foo_failure]": { - "recorded-date": "12-10-2024, 11:35:08", + "recorded-date": "25-11-2025, 20:04:44", "recorded-content": { "create-table-result": { "TableDescription": { @@ -3310,7 +3325,7 @@ } }, "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_dynamodbstreams.py::TestDynamoDBEventSourceMapping::test_dynamodb_report_batch_item_failure_scenarios[invalid_key_foo_null_value_failure]": { - "recorded-date": "14-10-2024, 21:33:18", + "recorded-date": "25-11-2025, 20:06:23", "recorded-content": { "create-table-result": { "TableDescription": { @@ -3514,7 +3529,7 @@ } }, "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_dynamodbstreams.py::TestDynamoDBEventSourceMapping::test_dynamodb_report_batch_item_failure_scenarios[unhandled_exception_in_function]": { - "recorded-date": "12-10-2024, 11:39:13", + "recorded-date": "25-11-2025, 20:08:17", "recorded-content": { "create-table-result": { "TableDescription": { @@ -3718,7 +3733,7 @@ } }, "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_dynamodbstreams.py::TestDynamoDBEventSourceMapping::test_dynamodb_report_batch_item_success_scenarios[empty_list_success]": { - "recorded-date": "12-10-2024, 11:40:57", + "recorded-date": "25-11-2025, 16:19:58", "recorded-content": { "create-table-result": { "TableDescription": { @@ -3792,7 +3807,7 @@ } }, "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_dynamodbstreams.py::TestDynamoDBEventSourceMapping::test_dynamodb_report_batch_item_success_scenarios[null_success]": { - "recorded-date": "12-10-2024, 11:42:06", + "recorded-date": "25-11-2025, 16:21:35", "recorded-content": { "create-table-result": { "TableDescription": { @@ -3866,7 +3881,7 @@ } }, "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_dynamodbstreams.py::TestDynamoDBEventSourceMapping::test_dynamodb_report_batch_item_success_scenarios[empty_dict_success]": { - "recorded-date": "12-10-2024, 11:43:06", + "recorded-date": "25-11-2025, 16:23:20", "recorded-content": { "create-table-result": { "TableDescription": { @@ -3940,7 +3955,7 @@ } }, "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_dynamodbstreams.py::TestDynamoDBEventSourceMapping::test_dynamodb_report_batch_item_success_scenarios[empty_batch_item_failure_success]": { - "recorded-date": "12-10-2024, 11:44:06", + "recorded-date": "25-11-2025, 16:25:03", "recorded-content": { "create-table-result": { "TableDescription": { @@ -4014,7 +4029,7 @@ } }, "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_dynamodbstreams.py::TestDynamoDBEventSourceMapping::test_dynamodb_report_batch_item_success_scenarios[null_batch_item_failure_success]": { - "recorded-date": "12-10-2024, 11:45:51", + "recorded-date": "25-11-2025, 16:26:14", "recorded-content": { "create-table-result": { "TableDescription": { @@ -4088,7 +4103,7 @@ } }, "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_dynamodbstreams.py::TestDynamoDBEventSourceMapping::test_dynamodb_report_batch_item_failure_scenarios[item_identifier_not_present_failure]": { - "recorded-date": "12-10-2024, 11:27:29", + "recorded-date": "25-11-2025, 20:00:14", "recorded-content": { "create-table-result": { "TableDescription": { @@ -4292,7 +4307,7 @@ } }, "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_dynamodbstreams.py::TestDynamoDBEventSourceMapping::test_dynamodb_event_source_mapping_with_s3_on_failure_destination": { - "recorded-date": "03-01-2025, 16:42:26", + "recorded-date": "25-11-2025, 15:54:54", "recorded-content": { "create_table_response": { "TableDescription": { @@ -4461,7 +4476,7 @@ } }, "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_dynamodbstreams.py::TestDynamoDBEventSourceMapping::test_esm_with_not_existing_dynamodb_stream": { - "recorded-date": "26-02-2025, 03:08:09", + "recorded-date": "25-11-2025, 15:45:36", "recorded-content": { "error": { "Error": { diff --git a/tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_dynamodbstreams.validation.json b/tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_dynamodbstreams.validation.json index 0bfbdbc8c52c6..ca93743bfff31 100644 --- a/tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_dynamodbstreams.validation.json +++ b/tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_dynamodbstreams.validation.json @@ -1,95 +1,275 @@ { "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_dynamodbstreams.py::TestDynamoDBEventSourceMapping::test_deletion_event_source_mapping_with_dynamodb": { - "last_validated_date": "2024-10-12T10:57:32+00:00" + "last_validated_date": "2025-11-25T15:49:36+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 13.26, + "teardown": 4.32, + "total": 17.58 + } }, "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_dynamodbstreams.py::TestDynamoDBEventSourceMapping::test_disabled_dynamodb_event_source_mapping": { - "last_validated_date": "2024-10-12T10:57:15+00:00" + "last_validated_date": "2025-11-25T17:53:08+00:00", + "durations_in_seconds": { + "setup": 11.58, + "call": 173.47, + "teardown": 1.62, + "total": 186.67 + } }, "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_dynamodbstreams.py::TestDynamoDBEventSourceMapping::test_duplicate_event_source_mappings": { - "last_validated_date": "2024-10-12T10:55:43+00:00" + "last_validated_date": "2025-11-25T15:47:54+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 11.93, + "teardown": 2.17, + "total": 14.1 + } }, "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_dynamodbstreams.py::TestDynamoDBEventSourceMapping::test_dynamodb_event_filter[content_filter_type]": { - "last_validated_date": "2024-10-12T11:08:10+00:00" + "last_validated_date": "2025-11-25T15:59:22+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 115.45, + "teardown": 0.92, + "total": 116.37 + } }, "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_dynamodbstreams.py::TestDynamoDBEventSourceMapping::test_dynamodb_event_filter[content_multiple_filters]": { "last_validated_date": "2024-10-12T11:07:06+00:00" }, "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_dynamodbstreams.py::TestDynamoDBEventSourceMapping::test_dynamodb_event_filter[content_or_filter]": { - "last_validated_date": "2024-10-12T11:05:31+00:00" + "last_validated_date": "2025-11-25T15:57:25+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 71.88, + "teardown": 0.93, + "total": 72.81 + } }, "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_dynamodbstreams.py::TestDynamoDBEventSourceMapping::test_dynamodb_event_filter[date_time_conversion]": { - "last_validated_date": "2024-10-12T11:19:06+00:00" + "last_validated_date": "2025-11-25T16:06:22+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 67.38, + "teardown": 0.94, + "total": 68.32 + } }, "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_dynamodbstreams.py::TestDynamoDBEventSourceMapping::test_dynamodb_event_filter[exists_false_filter]": { - "last_validated_date": "2024-12-05T15:58:41+00:00" + "last_validated_date": "2025-11-25T16:02:27+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 73.12, + "teardown": 0.94, + "total": 74.06 + } }, "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_dynamodbstreams.py::TestDynamoDBEventSourceMapping::test_dynamodb_event_filter[exists_filter_type]": { - "last_validated_date": "2024-10-12T11:10:04+00:00" + "last_validated_date": "2025-11-25T16:01:13+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 110.57, + "teardown": 0.9, + "total": 111.47 + } }, "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_dynamodbstreams.py::TestDynamoDBEventSourceMapping::test_dynamodb_event_filter[insert_same_entry_twice]": { - "last_validated_date": "2024-10-12T11:03:06+00:00" + "last_validated_date": "2025-11-25T15:56:13+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 77.37, + "teardown": 0.91, + "total": 78.28 + } }, "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_dynamodbstreams.py::TestDynamoDBEventSourceMapping::test_dynamodb_event_filter[numeric_filter]": { - "last_validated_date": "2024-12-05T16:01:13+00:00" + "last_validated_date": "2025-11-25T16:04:16+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 107.3, + "teardown": 0.9, + "total": 108.2 + } }, "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_dynamodbstreams.py::TestDynamoDBEventSourceMapping::test_dynamodb_event_filter[prefix_filter]": { - "last_validated_date": "2024-10-12T11:11:04+00:00" + "last_validated_date": "2025-11-25T16:05:14+00:00", + "durations_in_seconds": { + "setup": 0.01, + "call": 57.15, + "teardown": 0.96, + "total": 58.12 + } }, "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_dynamodbstreams.py::TestDynamoDBEventSourceMapping::test_dynamodb_event_source_mapping": { - "last_validated_date": "2025-02-22T03:03:01+00:00" + "last_validated_date": "2025-11-25T15:47:40+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 121.88, + "teardown": 1.83, + "total": 123.71 + } }, "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_dynamodbstreams.py::TestDynamoDBEventSourceMapping::test_dynamodb_event_source_mapping_with_on_failure_destination_config": { - "last_validated_date": "2024-10-12T11:01:14+00:00" + "last_validated_date": "2025-11-25T15:53:08+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 87.98, + "teardown": 2.06, + "total": 90.04 + } }, "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_dynamodbstreams.py::TestDynamoDBEventSourceMapping::test_dynamodb_event_source_mapping_with_s3_on_failure_destination": { - "last_validated_date": "2025-01-03T16:42:22+00:00" + "last_validated_date": "2025-11-25T15:54:54+00:00", + "durations_in_seconds": { + "setup": 0.71, + "call": 102.3, + "teardown": 2.95, + "total": 105.96 + } }, "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_dynamodbstreams.py::TestDynamoDBEventSourceMapping::test_dynamodb_event_source_mapping_with_sns_on_failure_destination_config": { - "last_validated_date": "2024-10-12T10:59:07+00:00" + "last_validated_date": "2025-11-25T15:51:38+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 119.5, + "teardown": 3.1, + "total": 122.6 + } }, "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_dynamodbstreams.py::TestDynamoDBEventSourceMapping::test_dynamodb_invalid_event_filter[[{\"eventName\": [\"INSERT\"=123}]]": { - "last_validated_date": "2024-10-12T11:21:39+00:00" + "last_validated_date": "2025-11-25T16:06:50+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 13.98, + "teardown": 1.05, + "total": 15.03 + } }, "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_dynamodbstreams.py::TestDynamoDBEventSourceMapping::test_dynamodb_invalid_event_filter[single-string]": { - "last_validated_date": "2024-10-12T11:21:23+00:00" + "last_validated_date": "2025-11-25T16:06:35+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 11.83, + "teardown": 1.11, + "total": 12.94 + } }, "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_dynamodbstreams.py::TestDynamoDBEventSourceMapping::test_dynamodb_report_batch_item_failure_scenarios[empty_string_item_identifier_failure]": { - "last_validated_date": "2024-10-12T11:30:32+00:00" + "last_validated_date": "2025-11-25T20:01:25+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 69.81, + "teardown": 0.84, + "total": 70.65 + } }, "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_dynamodbstreams.py::TestDynamoDBEventSourceMapping::test_dynamodb_report_batch_item_failure_scenarios[invalid_key_foo_failure]": { - "last_validated_date": "2024-10-12T11:35:06+00:00" + "last_validated_date": "2025-11-25T20:04:44+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 83.59, + "teardown": 0.82, + "total": 84.41 + } }, "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_dynamodbstreams.py::TestDynamoDBEventSourceMapping::test_dynamodb_report_batch_item_failure_scenarios[invalid_key_foo_null_value_failure]": { - "last_validated_date": "2024-10-14T21:33:15+00:00" + "last_validated_date": "2025-11-25T20:06:23+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 98.17, + "teardown": 0.89, + "total": 99.06 + } }, "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_dynamodbstreams.py::TestDynamoDBEventSourceMapping::test_dynamodb_report_batch_item_failure_scenarios[item_identifier_not_present_failure]": { - "last_validated_date": "2024-10-12T11:27:26+00:00" + "last_validated_date": "2025-11-25T20:00:14+00:00", + "durations_in_seconds": { + "setup": 10.94, + "call": 69.24, + "teardown": 0.82, + "total": 81.0 + } }, "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_dynamodbstreams.py::TestDynamoDBEventSourceMapping::test_dynamodb_report_batch_item_failure_scenarios[null_item_identifier_failure]": { - "last_validated_date": "2024-10-12T11:33:17+00:00" + "last_validated_date": "2025-11-25T20:03:19+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 113.33, + "teardown": 1.21, + "total": 114.54 + } }, "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_dynamodbstreams.py::TestDynamoDBEventSourceMapping::test_dynamodb_report_batch_item_failure_scenarios[unhandled_exception_in_function]": { - "last_validated_date": "2024-10-12T11:39:10+00:00" + "last_validated_date": "2025-11-25T20:08:17+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 112.91, + "teardown": 1.4, + "total": 114.31 + } }, "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_dynamodbstreams.py::TestDynamoDBEventSourceMapping::test_dynamodb_report_batch_item_failures": { - "last_validated_date": "2024-10-12T11:25:21+00:00" + "last_validated_date": "2025-11-25T16:08:24+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 92.56, + "teardown": 1.75, + "total": 94.31 + } }, "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_dynamodbstreams.py::TestDynamoDBEventSourceMapping::test_dynamodb_report_batch_item_success_scenarios[empty_batch_item_failure_success]": { - "last_validated_date": "2024-10-12T11:44:04+00:00" + "last_validated_date": "2025-11-25T16:25:03+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 101.66, + "teardown": 0.95, + "total": 102.61 + } }, "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_dynamodbstreams.py::TestDynamoDBEventSourceMapping::test_dynamodb_report_batch_item_success_scenarios[empty_dict_success]": { - "last_validated_date": "2024-10-12T11:43:04+00:00" + "last_validated_date": "2025-11-25T16:23:20+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 104.0, + "teardown": 0.91, + "total": 104.91 + } }, "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_dynamodbstreams.py::TestDynamoDBEventSourceMapping::test_dynamodb_report_batch_item_success_scenarios[empty_list_success]": { - "last_validated_date": "2024-10-12T11:40:54+00:00" + "last_validated_date": "2025-11-25T16:19:58+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 128.73, + "teardown": 1.21, + "total": 129.94 + } }, "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_dynamodbstreams.py::TestDynamoDBEventSourceMapping::test_dynamodb_report_batch_item_success_scenarios[null_batch_item_failure_success]": { - "last_validated_date": "2024-10-12T11:45:49+00:00" + "last_validated_date": "2025-11-25T16:26:14+00:00", + "durations_in_seconds": { + "setup": 0.01, + "call": 70.12, + "teardown": 0.91, + "total": 71.04 + } }, "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_dynamodbstreams.py::TestDynamoDBEventSourceMapping::test_dynamodb_report_batch_item_success_scenarios[null_success]": { - "last_validated_date": "2024-10-12T11:42:04+00:00" + "last_validated_date": "2025-11-25T16:21:35+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 96.77, + "teardown": 0.92, + "total": 97.69 + } }, "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_dynamodbstreams.py::TestDynamoDBEventSourceMapping::test_esm_with_not_existing_dynamodb_stream": { - "last_validated_date": "2025-02-26T03:08:08+00:00" + "last_validated_date": "2025-11-25T15:45:36+00:00", + "durations_in_seconds": { + "setup": 10.88, + "call": 2.16, + "teardown": 0.8, + "total": 13.84 + } } } diff --git a/tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_kinesis.py b/tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_kinesis.py index 5ef258af7dcf8..014fff29328d4 100644 --- a/tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_kinesis.py +++ b/tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_kinesis.py @@ -378,6 +378,10 @@ def test_kinesis_event_source_trim_horizon( stream_summary = aws_client.kinesis.describe_stream_summary(StreamName=stream_name) assert stream_summary["StreamDescriptionSummary"]["OpenShardCount"] == 1 + if is_aws_cloud(): + # 😿 + time.sleep(5) + # insert some records before event source mapping created for i in range(num_batches - 1): aws_client.kinesis.put_records( @@ -652,13 +656,22 @@ def verify_failure_received(): sqs_payload = retry(verify_failure_received, retries=15, sleep=sleep, sleep_before=5) snapshot.match("sqs_payload", sqs_payload) - batched_records = get_lambda_log_events(function_name, logs_client=aws_client.logs) - flattened_records = [ - record for batch in batched_records for record in batch.get("Records", []) - ] - sorted_records = sorted(flattened_records, key=lambda item: item["kinesis"]["partitionKey"]) + def _verify_messages_received(): + events = get_lambda_log_events(function_name, logs_client=aws_client.logs) + + # This will filter out exception messages being added to the log stream + batched_records = [event for event in events if "Records" in event] + assert len(batched_records) >= 5 + flattened_records = [ + record for batch in batched_records for record in batch.get("Records", []) + ] + sorted_records = sorted( + flattened_records, key=lambda item: item["kinesis"]["partitionKey"] + ) - snapshot.match("kinesis_records", {"Records": sorted_records}) + snapshot.match("kinesis_records", {"Records": sorted_records}) + + retry(_verify_messages_received) @markers.aws.validated @pytest.mark.parametrize( @@ -753,11 +766,15 @@ def verify_failure_received(): sqs_payload = retry(verify_failure_received, retries=15, sleep=sleep, sleep_before=5) snapshot.match("sqs_payload", sqs_payload) - events = get_lambda_log_events(function_name, logs_client=aws_client.logs) + def _get_events(): + events = get_lambda_log_events(function_name, logs_client=aws_client.logs) - # This will filter out exception messages being added to the log stream - invocation_events = [event for event in events if "Records" in event] - snapshot.match("kinesis_events", invocation_events) + # This will filter out exception messages being added to the log stream + invocation_events = [event for event in events if "Records" in event] + assert len(invocation_events) == 3 + return invocation_events + + snapshot.match("kinesis_events", retry(_get_events)) @markers.aws.validated def test_kinesis_event_source_mapping_with_sns_on_failure_destination_config( @@ -1231,21 +1248,17 @@ def _patched_stream_parameters(self): "StreamDescription" ]["StreamARN"] - aws_client.kinesis.put_record( - Data="stream-data", - PartitionKey="test", - StreamName=stream_name, + retry( + lambda: aws_client.kinesis.put_record( + Data="stream-data", + PartitionKey="test", + StreamName=stream_name, + ) ) # Ensure that the first record has expired time.sleep(wait_before_processing) - # The first record in the batch will have expired with the remaining batch not exceeding any age-limits. - aws_client.kinesis.put_records( - Records=[{"Data": f"stream-data-{i + 1}", "PartitionKey": "test"} for i in range(5)], - StreamName=stream_name, - ) - destination_queue_url = sqs_create_queue() create_lambda_function( func_name=function_name, @@ -1260,6 +1273,12 @@ def _patched_stream_parameters(self): dead_letter_queue_arn = sqs_get_queue_arn(dead_letter_queue) destination_config = {"OnFailure": {"Destination": dead_letter_queue_arn}} + # The first record in the batch will have expired with the remaining batch not exceeding any age-limits. + aws_client.kinesis.put_records( + Records=[{"Data": f"stream-data-{i + 1}", "PartitionKey": "test"} for i in range(5)], + StreamName=stream_name, + ) + create_event_source_mapping_response = create_event_source_mapping( FunctionName=function_name, BatchSize=10, diff --git a/tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_kinesis.snapshot.json b/tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_kinesis.snapshot.json index 809b9f0d539cd..67bc897ea781d 100644 --- a/tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_kinesis.snapshot.json +++ b/tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_kinesis.snapshot.json @@ -1,6 +1,6 @@ { "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_kinesis.py::TestKinesisSource::test_create_kinesis_event_source_mapping": { - "recorded-date": "12-10-2024, 11:47:16", + "recorded-date": "25-11-2025, 16:27:42", "recorded-content": { "create_event_source_mapping_response": { "BatchSize": 100, @@ -195,7 +195,7 @@ } }, "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_kinesis.py::TestKinesisSource::test_kinesis_event_source_mapping_with_async_invocation": { - "recorded-date": "11-12-2024, 09:54:54", + "recorded-date": "25-11-2025, 16:30:35", "recorded-content": { "create_event_source_mapping_response": { "BatchSize": 10, @@ -562,7 +562,7 @@ } }, "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_kinesis.py::TestKinesisSource::test_kinesis_event_source_trim_horizon": { - "recorded-date": "12-10-2024, 11:50:52", + "recorded-date": "25-11-2025, 17:33:31", "recorded-content": { "create_event_source_mapping_response": { "BatchSize": 10, @@ -1096,7 +1096,7 @@ } }, "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_kinesis.py::TestKinesisSource::test_disable_kinesis_event_source_mapping": { - "recorded-date": "12-10-2024, 11:54:22", + "recorded-date": "25-11-2025, 16:34:05", "recorded-content": { "create_event_source_mapping_response": { "BatchSize": 10, @@ -1293,7 +1293,7 @@ } }, "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_kinesis.py::TestKinesisSource::test_kinesis_event_source_mapping_with_on_failure_destination_config": { - "recorded-date": "12-10-2024, 12:29:14", + "recorded-date": "25-11-2025, 16:35:32", "recorded-content": { "create_event_source_mapping_response": { "BatchSize": 1, @@ -1363,7 +1363,7 @@ } }, "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_kinesis.py::TestKinesisEventFiltering::test_kinesis_event_filtering_json_pattern": { - "recorded-date": "12-10-2024, 13:31:54", + "recorded-date": "25-11-2025, 17:06:08", "recorded-content": { "create_event_source_mapping_response": { "BatchSize": 1, @@ -1447,7 +1447,7 @@ } }, "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_kinesis.py::TestKinesisSource::test_duplicate_event_source_mappings": { - "recorded-date": "12-10-2024, 11:48:49", + "recorded-date": "25-11-2025, 16:29:02", "recorded-content": { "create": { "BatchSize": 100, @@ -1490,7 +1490,7 @@ } }, "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_kinesis.py::TestKinesisSource::test_create_kinesis_event_source_mapping_multiple_lambdas_single_kinesis_event_stream": { - "recorded-date": "12-10-2024, 13:58:19", + "recorded-date": "25-11-2025, 17:33:15", "recorded-content": { "create_event_source_mapping_response-a": { "BatchSize": 100, @@ -1587,7 +1587,7 @@ } }, "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_kinesis.py::TestKinesisSource::test_kinesis_event_source_mapping_with_sns_on_failure_destination_config": { - "recorded-date": "12-10-2024, 13:17:57", + "recorded-date": "25-11-2025, 16:48:33", "recorded-content": { "create_event_source_mapping_response": { "BatchSize": 1, @@ -1654,7 +1654,7 @@ } }, "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_kinesis.py::TestKinesisSource::test_kinesis_report_batch_item_failures": { - "recorded-date": "12-10-2024, 14:17:06", + "recorded-date": "25-11-2025, 19:03:18", "recorded-content": { "create_event_source_mapping_response": { "BatchSize": 3, @@ -1890,7 +1890,7 @@ } }, "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_kinesis.py::TestKinesisSource::test_kinesis_report_batch_item_success_scenarios[empty_list_success]": { - "recorded-date": "12-10-2024, 13:21:25", + "recorded-date": "25-11-2025, 16:52:37", "recorded-content": { "create_event_source_mapping_response": { "BatchSize": 1, @@ -1945,7 +1945,7 @@ } }, "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_kinesis.py::TestKinesisSource::test_kinesis_report_batch_item_success_scenarios[null_success]": { - "recorded-date": "12-10-2024, 13:23:15", + "recorded-date": "25-11-2025, 16:53:51", "recorded-content": { "create_event_source_mapping_response": { "BatchSize": 1, @@ -2000,7 +2000,7 @@ } }, "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_kinesis.py::TestKinesisSource::test_kinesis_report_batch_item_success_scenarios[empty_dict_success]": { - "recorded-date": "12-10-2024, 13:25:13", + "recorded-date": "25-11-2025, 16:55:22", "recorded-content": { "create_event_source_mapping_response": { "BatchSize": 1, @@ -2055,7 +2055,7 @@ } }, "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_kinesis.py::TestKinesisSource::test_kinesis_report_batch_item_success_scenarios[empty_batch_item_failure_success]": { - "recorded-date": "12-10-2024, 13:27:12", + "recorded-date": "25-11-2025, 16:56:44", "recorded-content": { "create_event_source_mapping_response": { "BatchSize": 1, @@ -2110,7 +2110,7 @@ } }, "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_kinesis.py::TestKinesisSource::test_kinesis_report_batch_item_success_scenarios[null_batch_item_failure_success]": { - "recorded-date": "12-10-2024, 13:28:05", + "recorded-date": "25-11-2025, 16:58:22", "recorded-content": { "create_event_source_mapping_response": { "BatchSize": 1, @@ -2165,7 +2165,7 @@ } }, "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_kinesis.py::TestKinesisSource::test_kinesis_report_batch_item_failure_scenarios[empty_string_item_identifier_failure]": { - "recorded-date": "12-10-2024, 13:08:09", + "recorded-date": "25-11-2025, 21:22:47", "recorded-content": { "create_event_source_mapping_response": { "BatchSize": 1, @@ -2299,7 +2299,7 @@ } }, "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_kinesis.py::TestKinesisSource::test_kinesis_report_batch_item_failure_scenarios[null_item_identifier_failure]": { - "recorded-date": "12-10-2024, 13:10:20", + "recorded-date": "25-11-2025, 21:24:21", "recorded-content": { "create_event_source_mapping_response": { "BatchSize": 1, @@ -2433,7 +2433,7 @@ } }, "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_kinesis.py::TestKinesisSource::test_kinesis_report_batch_item_failure_scenarios[invalid_key_foo_failure]": { - "recorded-date": "12-10-2024, 13:13:18", + "recorded-date": "25-11-2025, 21:25:25", "recorded-content": { "create_event_source_mapping_response": { "BatchSize": 1, @@ -2567,7 +2567,7 @@ } }, "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_kinesis.py::TestKinesisSource::test_kinesis_report_batch_item_failure_scenarios[invalid_key_foo_null_value_failure]": { - "recorded-date": "12-10-2024, 13:14:13", + "recorded-date": "25-11-2025, 21:26:14", "recorded-content": { "create_event_source_mapping_response": { "BatchSize": 1, @@ -2701,7 +2701,7 @@ } }, "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_kinesis.py::TestKinesisSource::test_kinesis_report_batch_item_failure_scenarios[unhandled_exception_in_function]": { - "recorded-date": "14-10-2024, 18:10:16", + "recorded-date": "25-11-2025, 21:27:32", "recorded-content": { "create_event_source_mapping_response": { "BatchSize": 1, @@ -2835,7 +2835,7 @@ } }, "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_kinesis.py::TestKinesisSource::test_kinesis_report_batch_item_failure_scenarios[item_identifier_not_present_failure]": { - "recorded-date": "12-10-2024, 13:06:13", + "recorded-date": "25-11-2025, 21:21:12", "recorded-content": { "create_event_source_mapping_response": { "BatchSize": 1, @@ -2969,7 +2969,7 @@ } }, "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_kinesis.py::TestKinesisSource::test_kinesis_report_batch_item_success_scenarios[empty_string_success]": { - "recorded-date": "12-10-2024, 13:19:37", + "recorded-date": "25-11-2025, 16:51:42", "recorded-content": { "create_event_source_mapping_response": { "BatchSize": 1, @@ -3024,7 +3024,7 @@ } }, "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_kinesis.py::TestKinesisSource::test_kinesis_empty_provided": { - "recorded-date": "11-10-2024, 11:04:55", + "recorded-date": "25-11-2025, 17:03:32", "recorded-content": { "create_event_source_mapping_response": { "BatchSize": 1, @@ -3081,7 +3081,7 @@ } }, "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_kinesis.py::TestKinesisSource::test_kinesis_event_source_mapping_with_s3_on_failure_destination": { - "recorded-date": "03-01-2025, 14:50:27", + "recorded-date": "25-11-2025, 16:50:20", "recorded-content": { "create_event_source_mapping_response": { "BatchSize": 1, @@ -3158,7 +3158,7 @@ } }, "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_kinesis.py::TestKinesisSource::test_esm_with_not_existing_kinesis_stream": { - "recorded-date": "26-02-2025, 03:05:30", + "recorded-date": "25-11-2025, 16:26:16", "recorded-content": { "error": { "Error": { @@ -3175,7 +3175,7 @@ } }, "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_kinesis.py::TestKinesisSource::test_kinesis_maximum_record_age_exceeded[expire-while-retrying]": { - "recorded-date": "13-04-2025, 15:00:55", + "recorded-date": "25-11-2025, 16:59:40", "recorded-content": { "create_event_source_mapping_response": { "BatchSize": 1, @@ -3213,7 +3213,7 @@ "requestId": "", "functionArn": "arn::lambda::111111111111:function:", "condition": "RecordAgeExceeded", - "approximateInvokeCount": 1 + "approximateInvokeCount": 8 }, "version": "1.0", "timestamp": "", @@ -3240,7 +3240,7 @@ } }, "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_kinesis.py::TestKinesisSource::test_kinesis_maximum_record_age_exceeded[expire-before-ingestion]": { - "recorded-date": "13-04-2025, 16:29:29", + "recorded-date": "25-11-2025, 17:01:42", "recorded-content": { "create_event_source_mapping_response": { "BatchSize": 1, @@ -3305,7 +3305,7 @@ } }, "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_kinesis.py::TestKinesisSource::test_kinesis_maximum_record_age_exceeded_discard_records": { - "recorded-date": "13-04-2025, 17:05:16", + "recorded-date": "25-11-2025, 18:15:46", "recorded-content": { "create_event_source_mapping_response": { "BatchSize": 10, diff --git a/tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_kinesis.validation.json b/tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_kinesis.validation.json index 4f3d4284e0547..76f6d770b45fa 100644 --- a/tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_kinesis.validation.json +++ b/tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_kinesis.validation.json @@ -1,86 +1,260 @@ { "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_kinesis.py::TestKinesisEventFiltering::test_kinesis_event_filtering_json_pattern": { - "last_validated_date": "2024-12-13T14:48:09+00:00" + "last_validated_date": "2025-11-25T17:06:08+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 153.83, + "teardown": 2.61, + "total": 156.44 + } }, "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_kinesis.py::TestKinesisSource::test_create_kinesis_event_source_mapping": { - "last_validated_date": "2024-12-13T14:01:07+00:00" + "last_validated_date": "2025-11-25T16:27:42+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 84.38, + "teardown": 1.2, + "total": 85.58 + } }, "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_kinesis.py::TestKinesisSource::test_create_kinesis_event_source_mapping_multiple_lambdas_single_kinesis_event_stream": { - "last_validated_date": "2024-12-13T14:02:48+00:00" + "last_validated_date": "2025-11-25T17:33:16+00:00", + "durations_in_seconds": { + "setup": 11.22, + "call": 92.09, + "teardown": 2.12, + "total": 105.43 + } }, "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_kinesis.py::TestKinesisSource::test_disable_kinesis_event_source_mapping": { - "last_validated_date": "2024-12-13T14:10:20+00:00" + "last_validated_date": "2025-11-25T16:34:05+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 197.42, + "teardown": 1.38, + "total": 198.8 + } }, "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_kinesis.py::TestKinesisSource::test_duplicate_event_source_mappings": { - "last_validated_date": "2024-12-13T14:03:01+00:00" + "last_validated_date": "2025-11-25T16:29:02+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 9.37, + "teardown": 2.02, + "total": 11.39 + } }, "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_kinesis.py::TestKinesisSource::test_esm_with_not_existing_kinesis_stream": { - "last_validated_date": "2025-02-26T03:05:29+00:00" + "last_validated_date": "2025-11-25T16:26:16+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 2.18, + "teardown": 0.39, + "total": 2.57 + } }, "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_kinesis.py::TestKinesisSource::test_kinesis_empty_provided": { - "last_validated_date": "2024-12-13T14:45:29+00:00" + "last_validated_date": "2025-11-25T17:03:32+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 103.36, + "teardown": 1.17, + "total": 104.53 + } }, "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_kinesis.py::TestKinesisSource::test_kinesis_event_source_mapping_with_async_invocation": { - "last_validated_date": "2024-12-13T14:04:46+00:00" + "last_validated_date": "2025-11-25T16:30:35+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 92.33, + "teardown": 1.15, + "total": 93.48 + } + }, + "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_kinesis.py::TestKinesisSource::test_kinesis_event_source_mapping_with_on_failure_destination_config": { + "last_validated_date": "2025-11-25T16:35:32+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 84.61, + "teardown": 2.35, + "total": 86.96 + } }, "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_kinesis.py::TestKinesisSource::test_kinesis_event_source_mapping_with_s3_on_failure_destination": { - "last_validated_date": "2025-01-03T14:50:23+00:00" + "last_validated_date": "2025-11-25T16:50:20+00:00", + "durations_in_seconds": { + "setup": 0.78, + "call": 103.02, + "teardown": 3.28, + "total": 107.08 + } }, "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_kinesis.py::TestKinesisSource::test_kinesis_event_source_mapping_with_sns_on_failure_destination_config": { - "last_validated_date": "2024-12-13T14:35:43+00:00" + "last_validated_date": "2025-11-25T16:48:33+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 107.83, + "teardown": 3.07, + "total": 110.9 + } }, "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_kinesis.py::TestKinesisSource::test_kinesis_event_source_trim_horizon": { - "last_validated_date": "2024-12-13T14:06:49+00:00" + "last_validated_date": "2025-11-25T17:33:32+00:00", + "durations_in_seconds": { + "setup": 11.15, + "call": 95.7, + "teardown": 1.63, + "total": 108.48 + } }, "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_kinesis.py::TestKinesisSource::test_kinesis_maximum_record_age_exceeded": { "last_validated_date": "2025-04-13T15:57:25+00:00" }, "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_kinesis.py::TestKinesisSource::test_kinesis_maximum_record_age_exceeded[expire-before-ingestion]": { - "last_validated_date": "2025-04-13T16:29:25+00:00" + "last_validated_date": "2025-11-25T17:01:42+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 119.95, + "teardown": 1.62, + "total": 121.57 + } + }, + "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_kinesis.py::TestKinesisSource::test_kinesis_maximum_record_age_exceeded[expire-while-retrying]": { + "last_validated_date": "2025-11-25T16:59:40+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 76.3, + "teardown": 1.69, + "total": 77.99 + } }, "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_kinesis.py::TestKinesisSource::test_kinesis_maximum_record_age_exceeded[expire-with-mixed-arrival-batch]": { "last_validated_date": "2025-04-13T16:39:43+00:00" }, "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_kinesis.py::TestKinesisSource::test_kinesis_maximum_record_age_exceeded_discard_records": { - "last_validated_date": "2025-04-23T21:42:09+00:00" + "last_validated_date": "2025-11-25T18:15:47+00:00", + "durations_in_seconds": { + "setup": 11.3, + "call": 161.14, + "teardown": 2.18, + "total": 174.62 + } }, "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_kinesis.py::TestKinesisSource::test_kinesis_report_batch_item_failure_scenarios[empty_string_item_identifier_failure]": { - "last_validated_date": "2024-12-13T14:23:18+00:00" + "last_validated_date": "2025-11-25T21:22:47+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 93.51, + "teardown": 1.0, + "total": 94.51 + } }, "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_kinesis.py::TestKinesisSource::test_kinesis_report_batch_item_failure_scenarios[invalid_key_foo_failure]": { - "last_validated_date": "2024-12-13T14:27:36+00:00" + "last_validated_date": "2025-11-25T21:25:25+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 62.92, + "teardown": 1.0, + "total": 63.92 + } }, "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_kinesis.py::TestKinesisSource::test_kinesis_report_batch_item_failure_scenarios[invalid_key_foo_null_value_failure]": { - "last_validated_date": "2024-12-13T14:31:32+00:00" + "last_validated_date": "2025-11-25T21:26:14+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 47.63, + "teardown": 1.07, + "total": 48.7 + } }, "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_kinesis.py::TestKinesisSource::test_kinesis_report_batch_item_failure_scenarios[item_identifier_not_present_failure]": { - "last_validated_date": "2024-12-13T14:20:08+00:00" + "last_validated_date": "2025-11-25T21:21:12+00:00", + "durations_in_seconds": { + "setup": 11.0, + "call": 78.58, + "teardown": 1.0, + "total": 90.58 + } }, "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_kinesis.py::TestKinesisSource::test_kinesis_report_batch_item_failure_scenarios[null_item_identifier_failure]": { - "last_validated_date": "2024-12-13T14:25:26+00:00" + "last_validated_date": "2025-11-25T21:24:21+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 93.26, + "teardown": 1.03, + "total": 94.29 + } }, "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_kinesis.py::TestKinesisSource::test_kinesis_report_batch_item_failure_scenarios[unhandled_exception_in_function]": { - "last_validated_date": "2024-12-13T14:34:41+00:00" + "last_validated_date": "2025-11-25T21:27:33+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 77.2, + "teardown": 1.77, + "total": 78.97 + } }, "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_kinesis.py::TestKinesisSource::test_kinesis_report_batch_item_failures": { - "last_validated_date": "2024-12-13T14:18:13+00:00" + "last_validated_date": "2025-11-25T19:03:19+00:00", + "durations_in_seconds": { + "setup": 11.23, + "call": 118.12, + "teardown": 2.25, + "total": 131.6 + } }, "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_kinesis.py::TestKinesisSource::test_kinesis_report_batch_item_success_scenarios[empty_batch_item_failure_success]": { - "last_validated_date": "2024-12-13T14:42:49+00:00" + "last_validated_date": "2025-11-25T16:56:44+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 80.81, + "teardown": 1.14, + "total": 81.95 + } }, "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_kinesis.py::TestKinesisSource::test_kinesis_report_batch_item_success_scenarios[empty_dict_success]": { - "last_validated_date": "2024-12-13T14:41:30+00:00" + "last_validated_date": "2025-11-25T16:55:22+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 89.38, + "teardown": 1.2, + "total": 90.58 + } }, "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_kinesis.py::TestKinesisSource::test_kinesis_report_batch_item_success_scenarios[empty_list_success]": { - "last_validated_date": "2024-12-13T14:38:21+00:00" + "last_validated_date": "2025-11-25T16:52:37+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 54.19, + "teardown": 1.17, + "total": 55.36 + } }, "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_kinesis.py::TestKinesisSource::test_kinesis_report_batch_item_success_scenarios[empty_string_success]": { - "last_validated_date": "2024-12-13T14:37:20+00:00" + "last_validated_date": "2025-11-25T16:51:42+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 80.53, + "teardown": 1.21, + "total": 81.74 + } }, "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_kinesis.py::TestKinesisSource::test_kinesis_report_batch_item_success_scenarios[null_batch_item_failure_success]": { - "last_validated_date": "2024-12-13T14:44:14+00:00" + "last_validated_date": "2025-11-25T16:58:22+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 97.16, + "teardown": 1.13, + "total": 98.29 + } }, "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_kinesis.py::TestKinesisSource::test_kinesis_report_batch_item_success_scenarios[null_success]": { - "last_validated_date": "2024-12-13T14:39:47+00:00" + "last_validated_date": "2025-11-25T16:53:51+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 73.11, + "teardown": 1.21, + "total": 74.32 + } } } diff --git a/tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_sqs.snapshot.json b/tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_sqs.snapshot.json index cae128ced9d5c..905e1db02b77b 100644 --- a/tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_sqs.snapshot.json +++ b/tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_sqs.snapshot.json @@ -1,6 +1,6 @@ { "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_sqs.py::test_failing_lambda_retries_after_visibility_timeout": { - "recorded-date": "12-10-2024, 13:32:32", + "recorded-date": "25-11-2025, 17:06:47", "recorded-content": { "get_destination_queue_url": { "QueueUrl": "", @@ -100,7 +100,7 @@ } }, "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_sqs.py::test_redrive_policy_with_failing_lambda": { - "recorded-date": "12-10-2024, 13:33:30", + "recorded-date": "25-11-2025, 17:07:40", "recorded-content": { "get_destination_queue_url": { "QueueUrl": "", @@ -201,7 +201,7 @@ } }, "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_sqs.py::test_sqs_queue_as_lambda_dead_letter_queue": { - "recorded-date": "12-10-2024, 13:33:41", + "recorded-date": "25-11-2025, 17:07:49", "recorded-content": { "lambda-response-dlq-config": { "TargetArn": "arn::sqs::111111111111:" @@ -531,7 +531,7 @@ } }, "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_sqs.py::test_report_batch_item_failures_on_lambda_error": { - "recorded-date": "12-10-2024, 13:34:40", + "recorded-date": "25-11-2025, 17:08:10", "recorded-content": { "dlq_messages": [ { @@ -553,7 +553,7 @@ } }, "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_sqs.py::test_report_batch_item_failures_invalid_result_json_batch_fails": { - "recorded-date": "12-10-2024, 13:35:12", + "recorded-date": "25-11-2025, 17:08:43", "recorded-content": { "get_destination_queue_url": { "QueueUrl": "", @@ -666,7 +666,7 @@ } }, "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_sqs.py::test_report_batch_item_failures_empty_json_batch_succeeds": { - "recorded-date": "12-10-2024, 13:35:43", + "recorded-date": "25-11-2025, 17:09:13", "recorded-content": { "get_destination_queue_url": { "QueueUrl": "", @@ -714,7 +714,7 @@ } }, "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_sqs.py::TestSQSEventSourceMapping::test_event_source_mapping_default_batch_size": { - "recorded-date": "12-10-2024, 13:37:20", + "recorded-date": "25-11-2025, 17:10:49", "recorded-content": { "create-event-source-mapping": { "BatchSize": 10, @@ -759,7 +759,7 @@ } }, "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_sqs.py::TestSQSEventSourceMapping::test_sqs_event_source_mapping": { - "recorded-date": "12-10-2024, 13:38:02", + "recorded-date": "25-11-2025, 17:11:30", "recorded-content": { "create-event-source-mapping-response": { "BatchSize": 10, @@ -1304,7 +1304,7 @@ } }, "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_sqs.py::TestSQSEventSourceMapping::test_sqs_invalid_event_filter[None]": { - "recorded-date": "12-10-2024, 13:43:37", + "recorded-date": "25-11-2025, 17:22:25", "recorded-content": { "create_event_source_mapping_exception": { "Error": { @@ -1321,7 +1321,7 @@ } }, "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_sqs.py::TestSQSEventSourceMapping::test_sqs_invalid_event_filter[simple string]": { - "recorded-date": "12-10-2024, 13:43:42", + "recorded-date": "25-11-2025, 17:22:28", "recorded-content": { "create_event_source_mapping_exception": { "Error": { @@ -1338,7 +1338,7 @@ } }, "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_sqs.py::TestSQSEventSourceMapping::test_sqs_invalid_event_filter[invalid_filter2]": { - "recorded-date": "12-10-2024, 13:43:47", + "recorded-date": "25-11-2025, 17:22:31", "recorded-content": { "create_event_source_mapping_exception": { "Error": { @@ -1355,7 +1355,7 @@ } }, "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_sqs.py::TestSQSEventSourceMapping::test_sqs_invalid_event_filter[invalid_filter3]": { - "recorded-date": "12-10-2024, 13:43:52", + "recorded-date": "25-11-2025, 17:22:34", "recorded-content": { "create_event_source_mapping_exception": { "Error": { @@ -1372,7 +1372,7 @@ } }, "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_sqs.py::test_message_body_and_attributes_passed_correctly": { - "recorded-date": "12-10-2024, 13:32:53", + "recorded-date": "25-11-2025, 17:07:07", "recorded-content": { "get_destination_queue_url": { "QueueUrl": "", @@ -1418,8 +1418,8 @@ "dataType": "String" } }, - "md5OfBody": "", "md5OfMessageAttributes": "d25a6aea97eb8f585bfa92d314504a92", + "md5OfBody": "", "eventSource": "aws:sqs", "eventSourceARN": "arn::sqs::111111111111:", "awsRegion": "" @@ -1440,7 +1440,7 @@ } }, "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_sqs.py::TestSQSEventSourceMapping::test_sqs_event_source_mapping_update": { - "recorded-date": "12-10-2024, 13:45:45", + "recorded-date": "25-11-2025, 23:41:34", "recorded-content": { "create-event-source-mapping-response": { "BatchSize": 10, @@ -1578,7 +1578,7 @@ } }, "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_sqs.py::TestSQSEventSourceMapping::test_duplicate_event_source_mappings": { - "recorded-date": "12-10-2024, 13:45:56", + "recorded-date": "25-11-2025, 17:24:03", "recorded-content": { "create": { "BatchSize": 10, @@ -1611,7 +1611,7 @@ } }, "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_sqs.py::test_fifo_message_group_parallelism": { - "recorded-date": "12-10-2024, 13:37:01", + "recorded-date": "25-11-2025, 17:10:34", "recorded-content": { "create_esm_disabled": { "BatchSize": 1, @@ -1664,7 +1664,7 @@ } }, "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_sqs.py::TestSQSEventSourceMapping::test_sqs_event_source_mapping_batch_size[15]": { - "recorded-date": "11-12-2024, 13:42:57", + "recorded-date": "25-11-2025, 17:12:32", "recorded-content": { "create-event-source-mapping-response": { "BatchSize": 15, @@ -1785,8 +1785,8 @@ "ApproximateFirstReceiveTimestamp": "" }, "messageAttributes": {}, - "md5OfBody": "", "md5OfMessageAttributes": null, + "md5OfBody": "", "eventSource": "aws:sqs", "eventSourceARN": "arn::sqs::111111111111:", "awsRegion": "" @@ -1819,8 +1819,8 @@ "ApproximateFirstReceiveTimestamp": "" }, "messageAttributes": {}, - "md5OfBody": "", "md5OfMessageAttributes": null, + "md5OfBody": "", "eventSource": "aws:sqs", "eventSourceARN": "arn::sqs::111111111111:", "awsRegion": "" @@ -1836,8 +1836,8 @@ "ApproximateFirstReceiveTimestamp": "" }, "messageAttributes": {}, - "md5OfBody": "", "md5OfMessageAttributes": null, + "md5OfBody": "", "eventSource": "aws:sqs", "eventSourceARN": "arn::sqs::111111111111:", "awsRegion": "" @@ -1853,8 +1853,8 @@ "ApproximateFirstReceiveTimestamp": "" }, "messageAttributes": {}, - "md5OfBody": "", "md5OfMessageAttributes": null, + "md5OfBody": "", "eventSource": "aws:sqs", "eventSourceARN": "arn::sqs::111111111111:", "awsRegion": "" @@ -1921,8 +1921,8 @@ "ApproximateFirstReceiveTimestamp": "" }, "messageAttributes": {}, - "md5OfMessageAttributes": null, "md5OfBody": "", + "md5OfMessageAttributes": null, "eventSource": "aws:sqs", "eventSourceARN": "arn::sqs::111111111111:", "awsRegion": "" @@ -2023,8 +2023,8 @@ "ApproximateFirstReceiveTimestamp": "" }, "messageAttributes": {}, - "md5OfBody": "", "md5OfMessageAttributes": null, + "md5OfBody": "", "eventSource": "aws:sqs", "eventSourceARN": "arn::sqs::111111111111:", "awsRegion": "" @@ -2033,7 +2033,7 @@ } }, "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_sqs.py::TestSQSEventSourceMapping::test_sqs_event_source_mapping_batching_reserved_concurrency": { - "recorded-date": "25-02-2025, 16:35:01", + "recorded-date": "25-11-2025, 17:15:56", "recorded-content": { "put_concurrency_resp": { "ReservedConcurrentExecutions": 2, @@ -2579,7 +2579,7 @@ } }, "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_sqs.py::TestSQSEventSourceMapping::test_sqs_event_source_mapping_batch_size[100]": { - "recorded-date": "11-12-2024, 13:43:49", + "recorded-date": "25-11-2025, 17:13:27", "recorded-content": { "create-event-source-mapping-response": { "BatchSize": 100, @@ -2700,8 +2700,8 @@ "ApproximateFirstReceiveTimestamp": "" }, "messageAttributes": {}, - "md5OfBody": "", "md5OfMessageAttributes": null, + "md5OfBody": "", "eventSource": "aws:sqs", "eventSourceARN": "arn::sqs::111111111111:", "awsRegion": "" @@ -2717,8 +2717,8 @@ "ApproximateFirstReceiveTimestamp": "" }, "messageAttributes": {}, - "md5OfMessageAttributes": null, "md5OfBody": "", + "md5OfMessageAttributes": null, "eventSource": "aws:sqs", "eventSourceARN": "arn::sqs::111111111111:", "awsRegion": "" @@ -2751,8 +2751,8 @@ "ApproximateFirstReceiveTimestamp": "" }, "messageAttributes": {}, - "md5OfMessageAttributes": null, "md5OfBody": "", + "md5OfMessageAttributes": null, "eventSource": "aws:sqs", "eventSourceARN": "arn::sqs::111111111111:", "awsRegion": "" @@ -2768,8 +2768,8 @@ "ApproximateFirstReceiveTimestamp": "" }, "messageAttributes": {}, - "md5OfMessageAttributes": null, "md5OfBody": "", + "md5OfMessageAttributes": null, "eventSource": "aws:sqs", "eventSourceARN": "arn::sqs::111111111111:", "awsRegion": "" @@ -2948,7 +2948,7 @@ } }, "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_sqs.py::TestSQSEventSourceMapping::test_sqs_event_source_mapping_batch_size[1000]": { - "recorded-date": "11-12-2024, 13:44:40", + "recorded-date": "25-11-2025, 17:14:22", "recorded-content": { "create-event-source-mapping-response": { "BatchSize": 1000, @@ -3120,8 +3120,8 @@ "ApproximateFirstReceiveTimestamp": "" }, "messageAttributes": {}, - "md5OfMessageAttributes": null, "md5OfBody": "", + "md5OfMessageAttributes": null, "eventSource": "aws:sqs", "eventSourceARN": "arn::sqs::111111111111:", "awsRegion": "" @@ -3154,8 +3154,8 @@ "ApproximateFirstReceiveTimestamp": "" }, "messageAttributes": {}, - "md5OfMessageAttributes": null, "md5OfBody": "", + "md5OfMessageAttributes": null, "eventSource": "aws:sqs", "eventSourceARN": "arn::sqs::111111111111:", "awsRegion": "" @@ -3205,8 +3205,8 @@ "ApproximateFirstReceiveTimestamp": "" }, "messageAttributes": {}, - "md5OfMessageAttributes": null, "md5OfBody": "", + "md5OfMessageAttributes": null, "eventSource": "aws:sqs", "eventSourceARN": "arn::sqs::111111111111:", "awsRegion": "" @@ -3273,8 +3273,8 @@ "ApproximateFirstReceiveTimestamp": "" }, "messageAttributes": {}, - "md5OfMessageAttributes": null, "md5OfBody": "", + "md5OfMessageAttributes": null, "eventSource": "aws:sqs", "eventSourceARN": "arn::sqs::111111111111:", "awsRegion": "" @@ -3307,8 +3307,8 @@ "ApproximateFirstReceiveTimestamp": "" }, "messageAttributes": {}, - "md5OfMessageAttributes": null, "md5OfBody": "", + "md5OfMessageAttributes": null, "eventSource": "aws:sqs", "eventSourceARN": "arn::sqs::111111111111:", "awsRegion": "" @@ -3317,7 +3317,7 @@ } }, "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_sqs.py::TestSQSEventSourceMapping::test_sqs_event_source_mapping_batch_size[10000]": { - "recorded-date": "11-12-2024, 13:45:32", + "recorded-date": "25-11-2025, 17:15:08", "recorded-content": { "create-event-source-mapping-response": { "BatchSize": 10000, @@ -3438,8 +3438,8 @@ "ApproximateFirstReceiveTimestamp": "" }, "messageAttributes": {}, - "md5OfMessageAttributes": null, "md5OfBody": "", + "md5OfMessageAttributes": null, "eventSource": "aws:sqs", "eventSourceARN": "arn::sqs::111111111111:", "awsRegion": "" @@ -3489,8 +3489,8 @@ "ApproximateFirstReceiveTimestamp": "" }, "messageAttributes": {}, - "md5OfMessageAttributes": null, "md5OfBody": "", + "md5OfMessageAttributes": null, "eventSource": "aws:sqs", "eventSourceARN": "arn::sqs::111111111111:", "awsRegion": "" @@ -3608,8 +3608,8 @@ "ApproximateFirstReceiveTimestamp": "" }, "messageAttributes": {}, - "md5OfMessageAttributes": null, "md5OfBody": "", + "md5OfMessageAttributes": null, "eventSource": "aws:sqs", "eventSourceARN": "arn::sqs::111111111111:", "awsRegion": "" @@ -3625,8 +3625,8 @@ "ApproximateFirstReceiveTimestamp": "" }, "messageAttributes": {}, - "md5OfMessageAttributes": null, "md5OfBody": "", + "md5OfMessageAttributes": null, "eventSource": "aws:sqs", "eventSourceARN": "arn::sqs::111111111111:", "awsRegion": "" @@ -3934,7 +3934,7 @@ } }, "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_sqs.py::TestSQSEventSourceMapping::test_sqs_event_filter[numeric-bigger]": { - "recorded-date": "10-12-2024, 19:37:10", + "recorded-date": "25-11-2025, 17:19:29", "recorded-content": { "create_event_source_mapping_response": { "BatchSize": 10, @@ -3998,7 +3998,7 @@ } }, "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_sqs.py::TestSQSEventSourceMapping::test_sqs_event_filter[numeric-smaller]": { - "recorded-date": "10-12-2024, 19:37:55", + "recorded-date": "25-11-2025, 17:20:06", "recorded-content": { "create_event_source_mapping_response": { "BatchSize": 10, @@ -4062,7 +4062,7 @@ } }, "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_sqs.py::TestSQSEventSourceMapping::test_sqs_event_filter[numeric-range]": { - "recorded-date": "10-12-2024, 19:38:28", + "recorded-date": "25-11-2025, 17:20:56", "recorded-content": { "create_event_source_mapping_response": { "BatchSize": 10, @@ -4189,7 +4189,7 @@ } }, "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_sqs.py::TestSQSEventSourceMapping::test_sqs_event_filter[single]": { - "recorded-date": "10-12-2024, 19:34:32", + "recorded-date": "25-11-2025, 17:16:37", "recorded-content": { "create_event_source_mapping_response": { "BatchSize": 10, @@ -4248,7 +4248,7 @@ } }, "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_sqs.py::TestSQSEventSourceMapping::test_sqs_event_filter[or]": { - "recorded-date": "10-12-2024, 19:35:19", + "recorded-date": "25-11-2025, 17:17:10", "recorded-content": { "create_event_source_mapping_response": { "BatchSize": 10, @@ -4308,7 +4308,7 @@ } }, "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_sqs.py::TestSQSEventSourceMapping::test_sqs_event_filter[and]": { - "recorded-date": "10-12-2024, 19:35:54", + "recorded-date": "25-11-2025, 17:17:56", "recorded-content": { "create_event_source_mapping_response": { "BatchSize": 10, @@ -4372,7 +4372,7 @@ } }, "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_sqs.py::TestSQSEventSourceMapping::test_sqs_event_filter[exists]": { - "recorded-date": "10-12-2024, 19:36:24", + "recorded-date": "25-11-2025, 17:18:46", "recorded-content": { "create_event_source_mapping_response": { "BatchSize": 10, @@ -4441,7 +4441,7 @@ "recorded-content": {} }, "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_sqs.py::TestSQSEventSourceMapping::test_sqs_event_filter[valid-json-filter]": { - "recorded-date": "10-12-2024, 19:40:28", + "recorded-date": "25-11-2025, 17:22:22", "recorded-content": { "create_event_source_mapping_response": { "BatchSize": 10, @@ -4500,7 +4500,7 @@ } }, "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_sqs.py::TestSQSEventSourceMapping::test_sqs_event_filter[prefix]": { - "recorded-date": "10-12-2024, 19:47:22", + "recorded-date": "25-11-2025, 17:21:46", "recorded-content": { "create_event_source_mapping_response": { "BatchSize": 10, @@ -4561,7 +4561,7 @@ } }, "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_sqs.py::test_esm_with_not_existing_sqs_queue": { - "recorded-date": "26-02-2025, 03:01:33", + "recorded-date": "25-11-2025, 17:06:11", "recorded-content": { "error": { "Error": { diff --git a/tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_sqs.validation.json b/tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_sqs.validation.json index 6c608cee264c9..437e272f9130d 100644 --- a/tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_sqs.validation.json +++ b/tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_sqs.validation.json @@ -1,21 +1,45 @@ { "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_sqs.py::TestSQSEventSourceMapping::test_duplicate_event_source_mappings": { - "last_validated_date": "2024-10-12T13:45:52+00:00" + "last_validated_date": "2025-11-25T17:24:03+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 4.62, + "teardown": 2.5, + "total": 7.12 + } }, "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_sqs.py::TestSQSEventSourceMapping::test_event_source_mapping_default_batch_size": { - "last_validated_date": "2024-10-12T13:37:18+00:00" + "last_validated_date": "2025-11-25T17:10:49+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 14.06, + "teardown": 1.25, + "total": 15.31 + } }, "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_sqs.py::TestSQSEventSourceMapping::test_sqs_event_filter[and-filter]": { "last_validated_date": "2024-12-10T17:37:02+00:00" }, "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_sqs.py::TestSQSEventSourceMapping::test_sqs_event_filter[and]": { - "last_validated_date": "2024-12-10T19:35:53+00:00" + "last_validated_date": "2025-11-25T17:17:56+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 44.5, + "teardown": 0.78, + "total": 45.28 + } }, "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_sqs.py::TestSQSEventSourceMapping::test_sqs_event_filter[exists-filter]": { "last_validated_date": "2024-12-10T17:37:40+00:00" }, "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_sqs.py::TestSQSEventSourceMapping::test_sqs_event_filter[exists]": { - "last_validated_date": "2024-12-10T19:36:23+00:00" + "last_validated_date": "2025-11-25T17:18:46+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 48.86, + "teardown": 1.12, + "total": 49.98 + } }, "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_sqs.py::TestSQSEventSourceMapping::test_sqs_event_filter[filter0-item_matching0-item_not_matching0]": { "last_validated_date": "2024-10-12T13:38:37+00:00" @@ -42,96 +66,258 @@ "last_validated_date": "2024-10-12T13:43:31+00:00" }, "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_sqs.py::TestSQSEventSourceMapping::test_sqs_event_filter[numeric-bigger]": { - "last_validated_date": "2024-12-10T19:37:09+00:00" + "last_validated_date": "2025-11-25T17:19:29+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 43.09, + "teardown": 0.73, + "total": 43.82 + } }, "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_sqs.py::TestSQSEventSourceMapping::test_sqs_event_filter[numeric-prefix]": { "last_validated_date": "2024-12-10T17:40:32+00:00" }, "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_sqs.py::TestSQSEventSourceMapping::test_sqs_event_filter[numeric-range]": { - "last_validated_date": "2024-12-10T19:38:27+00:00" + "last_validated_date": "2025-11-25T17:20:56+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 48.79, + "teardown": 0.78, + "total": 49.57 + } }, "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_sqs.py::TestSQSEventSourceMapping::test_sqs_event_filter[numeric-smaller]": { - "last_validated_date": "2024-12-10T19:37:54+00:00" + "last_validated_date": "2025-11-25T17:20:06+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 36.08, + "teardown": 0.76, + "total": 36.84 + } }, "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_sqs.py::TestSQSEventSourceMapping::test_sqs_event_filter[or-filter]": { "last_validated_date": "2024-12-10T17:36:19+00:00" }, "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_sqs.py::TestSQSEventSourceMapping::test_sqs_event_filter[or]": { - "last_validated_date": "2024-12-10T19:35:18+00:00" + "last_validated_date": "2025-11-25T17:17:10+00:00", + "durations_in_seconds": { + "setup": 0.01, + "call": 32.75, + "teardown": 0.78, + "total": 33.54 + } }, "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_sqs.py::TestSQSEventSourceMapping::test_sqs_event_filter[prefix]": { - "last_validated_date": "2024-12-10T19:47:21+00:00" + "last_validated_date": "2025-11-25T17:21:46+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 48.97, + "teardown": 0.79, + "total": 49.76 + } }, "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_sqs.py::TestSQSEventSourceMapping::test_sqs_event_filter[single-filter]": { "last_validated_date": "2024-12-10T17:35:39+00:00" }, "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_sqs.py::TestSQSEventSourceMapping::test_sqs_event_filter[single]": { - "last_validated_date": "2024-12-10T19:34:31+00:00" + "last_validated_date": "2025-11-25T17:16:37+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 40.12, + "teardown": 0.78, + "total": 40.9 + } }, "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_sqs.py::TestSQSEventSourceMapping::test_sqs_event_filter[valid-json-filter]": { - "last_validated_date": "2024-12-10T19:40:27+00:00" + "last_validated_date": "2025-11-25T17:22:22+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 35.36, + "teardown": 0.84, + "total": 36.2 + } }, "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_sqs.py::TestSQSEventSourceMapping::test_sqs_event_source_mapping": { - "last_validated_date": "2024-11-25T15:46:54+00:00" + "last_validated_date": "2025-11-25T17:11:30+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 40.34, + "teardown": 0.77, + "total": 41.11 + } }, "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_sqs.py::TestSQSEventSourceMapping::test_sqs_event_source_mapping_batch_size[10000]": { - "last_validated_date": "2024-12-11T13:45:31+00:00" + "last_validated_date": "2025-11-25T17:15:08+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 44.35, + "teardown": 1.29, + "total": 45.64 + } }, "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_sqs.py::TestSQSEventSourceMapping::test_sqs_event_source_mapping_batch_size[1000]": { - "last_validated_date": "2024-12-11T13:44:38+00:00" + "last_validated_date": "2025-11-25T17:14:22+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 53.64, + "teardown": 1.26, + "total": 54.9 + } }, "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_sqs.py::TestSQSEventSourceMapping::test_sqs_event_source_mapping_batch_size[100]": { - "last_validated_date": "2024-12-11T13:43:48+00:00" + "last_validated_date": "2025-11-25T17:13:27+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 53.8, + "teardown": 1.28, + "total": 55.08 + } }, "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_sqs.py::TestSQSEventSourceMapping::test_sqs_event_source_mapping_batch_size[15]": { - "last_validated_date": "2024-12-11T13:42:55+00:00" + "last_validated_date": "2025-11-25T17:12:32+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 60.49, + "teardown": 1.49, + "total": 61.98 + } }, "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_sqs.py::TestSQSEventSourceMapping::test_sqs_event_source_mapping_batching_reserved_concurrency": { - "last_validated_date": "2025-02-25T16:34:59+00:00" + "last_validated_date": "2025-11-25T17:15:56+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 46.6, + "teardown": 1.32, + "total": 47.92 + } }, "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_sqs.py::TestSQSEventSourceMapping::test_sqs_event_source_mapping_update": { - "last_validated_date": "2024-10-12T13:45:43+00:00" + "last_validated_date": "2025-11-25T23:41:35+00:00", + "durations_in_seconds": { + "setup": 11.14, + "call": 93.47, + "teardown": 1.32, + "total": 105.93 + } }, "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_sqs.py::TestSQSEventSourceMapping::test_sqs_invalid_event_filter[None]": { - "last_validated_date": "2024-10-12T13:43:35+00:00" + "last_validated_date": "2025-11-25T17:22:25+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 2.29, + "teardown": 0.58, + "total": 2.87 + } }, "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_sqs.py::TestSQSEventSourceMapping::test_sqs_invalid_event_filter[invalid_filter2]": { - "last_validated_date": "2024-10-12T13:43:45+00:00" + "last_validated_date": "2025-11-25T17:22:31+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 2.29, + "teardown": 0.89, + "total": 3.18 + } }, "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_sqs.py::TestSQSEventSourceMapping::test_sqs_invalid_event_filter[invalid_filter3]": { - "last_validated_date": "2024-10-12T13:43:50+00:00" + "last_validated_date": "2025-11-25T17:22:34+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 2.26, + "teardown": 0.88, + "total": 3.14 + } }, "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_sqs.py::TestSQSEventSourceMapping::test_sqs_invalid_event_filter[simple string]": { - "last_validated_date": "2024-10-12T13:43:40+00:00" + "last_validated_date": "2025-11-25T17:22:28+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 2.28, + "teardown": 0.94, + "total": 3.22 + } }, "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_sqs.py::test_esm_with_not_existing_sqs_queue": { - "last_validated_date": "2025-02-26T03:01:32+00:00" + "last_validated_date": "2025-11-25T17:06:11+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 2.14, + "teardown": 0.39, + "total": 2.53 + } }, "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_sqs.py::test_failing_lambda_retries_after_visibility_timeout": { - "last_validated_date": "2024-11-25T12:12:47+00:00" + "last_validated_date": "2025-11-25T17:06:47+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 34.6, + "teardown": 1.4, + "total": 36.0 + } }, "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_sqs.py::test_fifo_message_group_parallelism": { - "last_validated_date": "2024-10-12T13:37:00+00:00" + "last_validated_date": "2025-11-25T17:10:34+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 80.67, + "teardown": 0.62, + "total": 81.29 + } }, "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_sqs.py::test_message_body_and_attributes_passed_correctly": { - "last_validated_date": "2024-10-12T13:32:50+00:00" + "last_validated_date": "2025-11-25T17:07:07+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 18.79, + "teardown": 1.4, + "total": 20.19 + } }, "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_sqs.py::test_redrive_policy_with_failing_lambda": { - "last_validated_date": "2024-10-12T13:33:27+00:00" + "last_validated_date": "2025-11-25T17:07:40+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 31.89, + "teardown": 1.4, + "total": 33.29 + } }, "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_sqs.py::test_report_batch_item_failures": { "last_validated_date": "2025-03-03T11:31:14+00:00" }, "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_sqs.py::test_report_batch_item_failures_empty_json_batch_succeeds": { - "last_validated_date": "2024-10-12T13:35:40+00:00" + "last_validated_date": "2025-11-25T17:09:13+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 28.44, + "teardown": 1.45, + "total": 29.89 + } }, "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_sqs.py::test_report_batch_item_failures_invalid_result_json_batch_fails": { - "last_validated_date": "2024-10-12T13:35:09+00:00" + "last_validated_date": "2025-11-25T17:08:43+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 31.06, + "teardown": 1.43, + "total": 32.49 + } }, "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_sqs.py::test_report_batch_item_failures_on_lambda_error": { - "last_validated_date": "2024-10-12T13:34:37+00:00" + "last_validated_date": "2025-11-25T17:08:10+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 19.89, + "teardown": 1.27, + "total": 21.16 + } }, "tests/aws/services/lambda_/event_source_mapping/test_lambda_integration_sqs.py::test_sqs_queue_as_lambda_dead_letter_queue": { - "last_validated_date": "2024-10-12T13:33:39+00:00" + "last_validated_date": "2025-11-25T17:07:49+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 7.62, + "teardown": 1.19, + "total": 8.81 + } } } diff --git a/tests/aws/services/lambda_/functions/common/echo/dotnet/Makefile b/tests/aws/services/lambda_/functions/common/echo/dotnet/Makefile index 31704c534390c..58cab0cd7beb5 100644 --- a/tests/aws/services/lambda_/functions/common/echo/dotnet/Makefile +++ b/tests/aws/services/lambda_/functions/common/echo/dotnet/Makefile @@ -9,13 +9,13 @@ endif FUNCTION_ARCHITECTURE ?= $(ARCHITECTURE) # Target Dotnet framework version -FRAMEWORK ?= net8.0 +FRAMEWORK ?= net10.0 # Workaround for a Docker race condition causing an I/O error upon zipping to /out/handler.zip if # two builds are executed in short succession. Example: `make -C dotnet build && make -C dotnet6 build` BUILD_DIR ?= build-$(FRAMEWORK) -# https://gallery.ecr.aws/sam/build-dotnet8 -IMAGE ?= public.ecr.aws/sam/build-dotnet8:1.112.0 +# https://gallery.ecr.aws/sam/build-dotnet10 +IMAGE ?= public.ecr.aws/sam/build-dotnet10:1.151.0 # Emulated builds with Dotnet8 are currently (2024-03-19) broken as discussed in many issues: # https://github.com/NuGet/Home/issues/12227 @@ -27,10 +27,10 @@ IMAGE ?= public.ecr.aws/sam/build-dotnet8:1.112.0 build: mkdir -p $(BUILD_DIR) && \ - docker run --rm -v $$(pwd)/src:/app -v $$(pwd)/$(BUILD_DIR):/out $(IMAGE) bash -c "mkdir -p /app2 && cp /app/* /app2 && cd /app2 && dotnet lambda package --framework $(FRAMEWORK) --function-architecture $(FUNCTION_ARCHITECTURE) -o ../out/handler.zip" && \ + docker run --rm -v $$(pwd)/src:/app -v $$(pwd)/$(BUILD_DIR):/out $(IMAGE) bash -c "mkdir -p /app2 && cp -r /app/* /app2 && cd /app2 && dotnet lambda package --framework $(FRAMEWORK) --function-architecture $(FUNCTION_ARCHITECTURE) -o ../out/handler.zip" && \ cp $(BUILD_DIR)/handler.zip handler.zip clean: - $(RM) -r $(BUILD_DIR) handler.zip + $(RM) -rf $(BUILD_DIR) handler.zip .PHONY: build clean diff --git a/tests/aws/services/lambda_/functions/common/echo/dotnet/src/dotnet.csproj b/tests/aws/services/lambda_/functions/common/echo/dotnet/src/dotnet.csproj index 1bd07d2e45a5a..980d160b3d02a 100644 --- a/tests/aws/services/lambda_/functions/common/echo/dotnet/src/dotnet.csproj +++ b/tests/aws/services/lambda_/functions/common/echo/dotnet/src/dotnet.csproj @@ -1,13 +1,13 @@  - net6.0;net8.0 + net6.0;net8.0;net10.0 true Lambda - + - + diff --git a/tests/aws/services/lambda_/functions/common/echo/dotnet10/Makefile b/tests/aws/services/lambda_/functions/common/echo/dotnet10/Makefile new file mode 100644 index 0000000000000..adf6948db981c --- /dev/null +++ b/tests/aws/services/lambda_/functions/common/echo/dotnet10/Makefile @@ -0,0 +1,20 @@ +UNAME := $(shell uname -m) +ifeq ($(UNAME),x86_64) + ARCHITECTURE ?= x86_64 +else + ARCHITECTURE ?= arm64 +endif + +# Target Dotnet framework version +FRAMEWORK ?= net10.0 + +# Forward build for different Dotnet framework version to avoid code duplication +build: + cd ../dotnet && $(MAKE) clean build ARCHITECTURE=$(ARCHITECTURE) FRAMEWORK=$(FRAMEWORK) + mv ../dotnet/handler.zip . + +clean: + $(RM) -rf build handler.zip + cd ../dotnet && $(MAKE) clean + +.PHONY: build clean diff --git a/tests/aws/services/lambda_/functions/common/echo/dotnet6/Makefile b/tests/aws/services/lambda_/functions/common/echo/dotnet6/Makefile index 43573df40d616..95f945b450e31 100644 --- a/tests/aws/services/lambda_/functions/common/echo/dotnet6/Makefile +++ b/tests/aws/services/lambda_/functions/common/echo/dotnet6/Makefile @@ -14,7 +14,7 @@ build: mv ../dotnet/handler.zip . clean: - $(RM) -r build handler.zip + $(RM) -rf build handler.zip cd ../dotnet && $(MAKE) clean FRAMEWORK=$(FRAMEWORK) .PHONY: build clean diff --git a/tests/aws/services/lambda_/functions/common/echo/dotnet8/Makefile b/tests/aws/services/lambda_/functions/common/echo/dotnet8/Makefile index f7c7f2ec8908c..6d9e57e759ee0 100644 --- a/tests/aws/services/lambda_/functions/common/echo/dotnet8/Makefile +++ b/tests/aws/services/lambda_/functions/common/echo/dotnet8/Makefile @@ -14,7 +14,7 @@ build: mv ../dotnet/handler.zip . clean: - $(RM) -r build handler.zip + $(RM) -rf build handler.zip cd ../dotnet && $(MAKE) clean .PHONY: build clean diff --git a/tests/aws/services/lambda_/functions/common/echo/java/Makefile b/tests/aws/services/lambda_/functions/common/echo/java/Makefile index 6916941cbe138..a827eefbe5bbe 100644 --- a/tests/aws/services/lambda_/functions/common/echo/java/Makefile +++ b/tests/aws/services/lambda_/functions/common/echo/java/Makefile @@ -7,6 +7,6 @@ build: cp build/handler.zip handler.zip clean: - $(RM) -r build handler.zip + $(RM) -rf build handler.zip .PHONY: build clean diff --git a/tests/aws/services/lambda_/functions/common/echo/nodejs/Makefile b/tests/aws/services/lambda_/functions/common/echo/nodejs/Makefile index c3b2190a84a3a..705b003b3eaf8 100644 --- a/tests/aws/services/lambda_/functions/common/echo/nodejs/Makefile +++ b/tests/aws/services/lambda_/functions/common/echo/nodejs/Makefile @@ -3,6 +3,6 @@ build: cp -r ./src/* build/ clean: - $(RM) -r build handler.zip + $(RM) -rf build handler.zip .PHONY: build clean diff --git a/tests/aws/services/lambda_/functions/common/echo/provided/Makefile b/tests/aws/services/lambda_/functions/common/echo/provided/Makefile index 09d0587c47e0e..3406319b9eab3 100644 --- a/tests/aws/services/lambda_/functions/common/echo/provided/Makefile +++ b/tests/aws/services/lambda_/functions/common/echo/provided/Makefile @@ -3,6 +3,6 @@ build: cp -r ./src/* build/ clean: - $(RM) -r build handler.zip + $(RM) -rf build handler.zip .PHONY: build clean diff --git a/tests/aws/services/lambda_/functions/common/echo/provided/src/bootstrap b/tests/aws/services/lambda_/functions/common/echo/provided/src/bootstrap index b0be430f83a5b..d29aee6058074 100755 --- a/tests/aws/services/lambda_/functions/common/echo/provided/src/bootstrap +++ b/tests/aws/services/lambda_/functions/common/echo/provided/src/bootstrap @@ -19,5 +19,5 @@ do RESPONSE=$($(echo "$_HANDLER" | cut -d. -f2) "$EVENT_DATA") # Send the response (using stdin to circumvent max input length) - echo ${RESPONSE} | curl -X POST "http://${AWS_LAMBDA_RUNTIME_API}/2018-06-01/runtime/invocation/$REQUEST_ID/response" --data @'-' + echo "$RESPONSE" | curl -X POST "http://${AWS_LAMBDA_RUNTIME_API}/2018-06-01/runtime/invocation/${REQUEST_ID}/response" --data @'-' done diff --git a/tests/aws/services/lambda_/functions/common/echo/provided/src/function.sh b/tests/aws/services/lambda_/functions/common/echo/provided/src/function.sh index 641726e064c0d..8315ed7bc33bc 100755 --- a/tests/aws/services/lambda_/functions/common/echo/provided/src/function.sh +++ b/tests/aws/services/lambda_/functions/common/echo/provided/src/function.sh @@ -1,7 +1,7 @@ function handler () { - EVENT_DATA=$1 + EVENT_DATA="$1" echo "$EVENT_DATA" 1>&2; - RESPONSE=$EVENT_DATA + RESPONSE="$EVENT_DATA" - echo $RESPONSE + echo "$RESPONSE" } diff --git a/tests/aws/services/lambda_/functions/common/echo/python/Makefile b/tests/aws/services/lambda_/functions/common/echo/python/Makefile index c3b2190a84a3a..705b003b3eaf8 100644 --- a/tests/aws/services/lambda_/functions/common/echo/python/Makefile +++ b/tests/aws/services/lambda_/functions/common/echo/python/Makefile @@ -3,6 +3,6 @@ build: cp -r ./src/* build/ clean: - $(RM) -r build handler.zip + $(RM) -rf build handler.zip .PHONY: build clean diff --git a/tests/aws/services/lambda_/functions/common/endpointinjection/dotnet/Makefile b/tests/aws/services/lambda_/functions/common/endpointinjection/dotnet/Makefile index 31704c534390c..58cab0cd7beb5 100644 --- a/tests/aws/services/lambda_/functions/common/endpointinjection/dotnet/Makefile +++ b/tests/aws/services/lambda_/functions/common/endpointinjection/dotnet/Makefile @@ -9,13 +9,13 @@ endif FUNCTION_ARCHITECTURE ?= $(ARCHITECTURE) # Target Dotnet framework version -FRAMEWORK ?= net8.0 +FRAMEWORK ?= net10.0 # Workaround for a Docker race condition causing an I/O error upon zipping to /out/handler.zip if # two builds are executed in short succession. Example: `make -C dotnet build && make -C dotnet6 build` BUILD_DIR ?= build-$(FRAMEWORK) -# https://gallery.ecr.aws/sam/build-dotnet8 -IMAGE ?= public.ecr.aws/sam/build-dotnet8:1.112.0 +# https://gallery.ecr.aws/sam/build-dotnet10 +IMAGE ?= public.ecr.aws/sam/build-dotnet10:1.151.0 # Emulated builds with Dotnet8 are currently (2024-03-19) broken as discussed in many issues: # https://github.com/NuGet/Home/issues/12227 @@ -27,10 +27,10 @@ IMAGE ?= public.ecr.aws/sam/build-dotnet8:1.112.0 build: mkdir -p $(BUILD_DIR) && \ - docker run --rm -v $$(pwd)/src:/app -v $$(pwd)/$(BUILD_DIR):/out $(IMAGE) bash -c "mkdir -p /app2 && cp /app/* /app2 && cd /app2 && dotnet lambda package --framework $(FRAMEWORK) --function-architecture $(FUNCTION_ARCHITECTURE) -o ../out/handler.zip" && \ + docker run --rm -v $$(pwd)/src:/app -v $$(pwd)/$(BUILD_DIR):/out $(IMAGE) bash -c "mkdir -p /app2 && cp -r /app/* /app2 && cd /app2 && dotnet lambda package --framework $(FRAMEWORK) --function-architecture $(FUNCTION_ARCHITECTURE) -o ../out/handler.zip" && \ cp $(BUILD_DIR)/handler.zip handler.zip clean: - $(RM) -r $(BUILD_DIR) handler.zip + $(RM) -rf $(BUILD_DIR) handler.zip .PHONY: build clean diff --git a/tests/aws/services/lambda_/functions/common/endpointinjection/dotnet/src/dotnet.csproj b/tests/aws/services/lambda_/functions/common/endpointinjection/dotnet/src/dotnet.csproj index 3db7fab8de15c..8cb7e5da3e315 100644 --- a/tests/aws/services/lambda_/functions/common/endpointinjection/dotnet/src/dotnet.csproj +++ b/tests/aws/services/lambda_/functions/common/endpointinjection/dotnet/src/dotnet.csproj @@ -1,14 +1,14 @@  - net6.0;net8.0 + net6.0;net8.0;net10.0 true Lambda - + - + diff --git a/tests/aws/services/lambda_/functions/common/endpointinjection/dotnet10/Makefile b/tests/aws/services/lambda_/functions/common/endpointinjection/dotnet10/Makefile new file mode 100644 index 0000000000000..89991b37bd4a7 --- /dev/null +++ b/tests/aws/services/lambda_/functions/common/endpointinjection/dotnet10/Makefile @@ -0,0 +1,20 @@ +UNAME := $(shell uname -m) +ifeq ($(UNAME),x86_64) + ARCHITECTURE ?= x86_64 +else + ARCHITECTURE ?= arm64 +endif + +# Target Dotnet framework version +FRAMEWORK ?= net10.0 + +# Forward build for different Dotnet framework version to avoid code duplication +build: + cd ../dotnet && $(MAKE) clean build ARCHITECTURE=$(ARCHITECTURE) FRAMEWORK=$(FRAMEWORK) + mv ../dotnet/handler.zip . + +clean: + $(RM) -rf build handler.zip + cd ../dotnet && $(MAKE) clean FRAMEWORK=$(FRAMEWORK) + +.PHONY: build clean diff --git a/tests/aws/services/lambda_/functions/common/endpointinjection/dotnet6/Makefile b/tests/aws/services/lambda_/functions/common/endpointinjection/dotnet6/Makefile index 43573df40d616..95f945b450e31 100644 --- a/tests/aws/services/lambda_/functions/common/endpointinjection/dotnet6/Makefile +++ b/tests/aws/services/lambda_/functions/common/endpointinjection/dotnet6/Makefile @@ -14,7 +14,7 @@ build: mv ../dotnet/handler.zip . clean: - $(RM) -r build handler.zip + $(RM) -rf build handler.zip cd ../dotnet && $(MAKE) clean FRAMEWORK=$(FRAMEWORK) .PHONY: build clean diff --git a/tests/aws/services/lambda_/functions/common/endpointinjection/dotnet8/Makefile b/tests/aws/services/lambda_/functions/common/endpointinjection/dotnet8/Makefile index 7ec1ea467ff87..df0b572919fce 100644 --- a/tests/aws/services/lambda_/functions/common/endpointinjection/dotnet8/Makefile +++ b/tests/aws/services/lambda_/functions/common/endpointinjection/dotnet8/Makefile @@ -14,7 +14,7 @@ build: mv ../dotnet/handler.zip . clean: - $(RM) -r build handler.zip + $(RM) -rf build handler.zip cd ../dotnet && $(MAKE) clean FRAMEWORK=$(FRAMEWORK) .PHONY: build clean diff --git a/tests/aws/services/lambda_/functions/common/endpointinjection/java/Makefile b/tests/aws/services/lambda_/functions/common/endpointinjection/java/Makefile index 6916941cbe138..a827eefbe5bbe 100644 --- a/tests/aws/services/lambda_/functions/common/endpointinjection/java/Makefile +++ b/tests/aws/services/lambda_/functions/common/endpointinjection/java/Makefile @@ -7,6 +7,6 @@ build: cp build/handler.zip handler.zip clean: - $(RM) -r build handler.zip + $(RM) -rf build handler.zip .PHONY: build clean diff --git a/tests/aws/services/lambda_/functions/common/endpointinjection/java8.al2/Makefile b/tests/aws/services/lambda_/functions/common/endpointinjection/java8.al2/Makefile index 6916941cbe138..a827eefbe5bbe 100644 --- a/tests/aws/services/lambda_/functions/common/endpointinjection/java8.al2/Makefile +++ b/tests/aws/services/lambda_/functions/common/endpointinjection/java8.al2/Makefile @@ -7,6 +7,6 @@ build: cp build/handler.zip handler.zip clean: - $(RM) -r build handler.zip + $(RM) -rf build handler.zip .PHONY: build clean diff --git a/tests/aws/services/lambda_/functions/common/endpointinjection/nodejs/Makefile b/tests/aws/services/lambda_/functions/common/endpointinjection/nodejs/Makefile index c3b2190a84a3a..705b003b3eaf8 100644 --- a/tests/aws/services/lambda_/functions/common/endpointinjection/nodejs/Makefile +++ b/tests/aws/services/lambda_/functions/common/endpointinjection/nodejs/Makefile @@ -3,6 +3,6 @@ build: cp -r ./src/* build/ clean: - $(RM) -r build handler.zip + $(RM) -rf build handler.zip .PHONY: build clean diff --git a/tests/aws/services/lambda_/functions/common/endpointinjection/nodejs16.x/Makefile b/tests/aws/services/lambda_/functions/common/endpointinjection/nodejs16.x/Makefile index c3b2190a84a3a..705b003b3eaf8 100644 --- a/tests/aws/services/lambda_/functions/common/endpointinjection/nodejs16.x/Makefile +++ b/tests/aws/services/lambda_/functions/common/endpointinjection/nodejs16.x/Makefile @@ -3,6 +3,6 @@ build: cp -r ./src/* build/ clean: - $(RM) -r build handler.zip + $(RM) -rf build handler.zip .PHONY: build clean diff --git a/tests/aws/services/lambda_/functions/common/endpointinjection/python/Makefile b/tests/aws/services/lambda_/functions/common/endpointinjection/python/Makefile index 4426ee52bf0ef..493fcad61fbea 100644 --- a/tests/aws/services/lambda_/functions/common/endpointinjection/python/Makefile +++ b/tests/aws/services/lambda_/functions/common/endpointinjection/python/Makefile @@ -4,6 +4,6 @@ build: cp -r ./src/* build/ clean: - $(RM) -r build handler.zip + $(RM) -rf build handler.zip .PHONY: build clean diff --git a/tests/aws/services/lambda_/functions/common/endpointinjection_extra/provided/Makefile b/tests/aws/services/lambda_/functions/common/endpointinjection_extra/provided/Makefile index bccba26238a6c..90fc86e61283c 100644 --- a/tests/aws/services/lambda_/functions/common/endpointinjection_extra/provided/Makefile +++ b/tests/aws/services/lambda_/functions/common/endpointinjection_extra/provided/Makefile @@ -21,6 +21,6 @@ build: docker run --rm --platform $(DOCKER_PLATFORM) -v $$(pwd)/src:/app -v $$(pwd)/build:/out $(DOCKER_GOLANG_IMAGE) /bin/bash -c "cd /app && GOOS=linux GOARCH=$(GOARCH) CGO_ENABLED=0 go build -trimpath -ldflags=-buildid= -o /out/bootstrap main.go && chown $$(id -u):$$(id -g) /out/bootstrap" clean: - $(RM) -r build handler.zip + $(RM) -rf build handler.zip .PHONY: build clean diff --git a/tests/aws/services/lambda_/functions/common/introspection/dotnet/Makefile b/tests/aws/services/lambda_/functions/common/introspection/dotnet/Makefile index 31704c534390c..58cab0cd7beb5 100644 --- a/tests/aws/services/lambda_/functions/common/introspection/dotnet/Makefile +++ b/tests/aws/services/lambda_/functions/common/introspection/dotnet/Makefile @@ -9,13 +9,13 @@ endif FUNCTION_ARCHITECTURE ?= $(ARCHITECTURE) # Target Dotnet framework version -FRAMEWORK ?= net8.0 +FRAMEWORK ?= net10.0 # Workaround for a Docker race condition causing an I/O error upon zipping to /out/handler.zip if # two builds are executed in short succession. Example: `make -C dotnet build && make -C dotnet6 build` BUILD_DIR ?= build-$(FRAMEWORK) -# https://gallery.ecr.aws/sam/build-dotnet8 -IMAGE ?= public.ecr.aws/sam/build-dotnet8:1.112.0 +# https://gallery.ecr.aws/sam/build-dotnet10 +IMAGE ?= public.ecr.aws/sam/build-dotnet10:1.151.0 # Emulated builds with Dotnet8 are currently (2024-03-19) broken as discussed in many issues: # https://github.com/NuGet/Home/issues/12227 @@ -27,10 +27,10 @@ IMAGE ?= public.ecr.aws/sam/build-dotnet8:1.112.0 build: mkdir -p $(BUILD_DIR) && \ - docker run --rm -v $$(pwd)/src:/app -v $$(pwd)/$(BUILD_DIR):/out $(IMAGE) bash -c "mkdir -p /app2 && cp /app/* /app2 && cd /app2 && dotnet lambda package --framework $(FRAMEWORK) --function-architecture $(FUNCTION_ARCHITECTURE) -o ../out/handler.zip" && \ + docker run --rm -v $$(pwd)/src:/app -v $$(pwd)/$(BUILD_DIR):/out $(IMAGE) bash -c "mkdir -p /app2 && cp -r /app/* /app2 && cd /app2 && dotnet lambda package --framework $(FRAMEWORK) --function-architecture $(FUNCTION_ARCHITECTURE) -o ../out/handler.zip" && \ cp $(BUILD_DIR)/handler.zip handler.zip clean: - $(RM) -r $(BUILD_DIR) handler.zip + $(RM) -rf $(BUILD_DIR) handler.zip .PHONY: build clean diff --git a/tests/aws/services/lambda_/functions/common/introspection/dotnet/src/dotnet.csproj b/tests/aws/services/lambda_/functions/common/introspection/dotnet/src/dotnet.csproj index 1bd07d2e45a5a..980d160b3d02a 100644 --- a/tests/aws/services/lambda_/functions/common/introspection/dotnet/src/dotnet.csproj +++ b/tests/aws/services/lambda_/functions/common/introspection/dotnet/src/dotnet.csproj @@ -1,13 +1,13 @@  - net6.0;net8.0 + net6.0;net8.0;net10.0 true Lambda - + - + diff --git a/tests/aws/services/lambda_/functions/common/introspection/dotnet10/Makefile b/tests/aws/services/lambda_/functions/common/introspection/dotnet10/Makefile new file mode 100644 index 0000000000000..89991b37bd4a7 --- /dev/null +++ b/tests/aws/services/lambda_/functions/common/introspection/dotnet10/Makefile @@ -0,0 +1,20 @@ +UNAME := $(shell uname -m) +ifeq ($(UNAME),x86_64) + ARCHITECTURE ?= x86_64 +else + ARCHITECTURE ?= arm64 +endif + +# Target Dotnet framework version +FRAMEWORK ?= net10.0 + +# Forward build for different Dotnet framework version to avoid code duplication +build: + cd ../dotnet && $(MAKE) clean build ARCHITECTURE=$(ARCHITECTURE) FRAMEWORK=$(FRAMEWORK) + mv ../dotnet/handler.zip . + +clean: + $(RM) -rf build handler.zip + cd ../dotnet && $(MAKE) clean FRAMEWORK=$(FRAMEWORK) + +.PHONY: build clean diff --git a/tests/aws/services/lambda_/functions/common/introspection/dotnet6/Makefile b/tests/aws/services/lambda_/functions/common/introspection/dotnet6/Makefile index 43573df40d616..95f945b450e31 100644 --- a/tests/aws/services/lambda_/functions/common/introspection/dotnet6/Makefile +++ b/tests/aws/services/lambda_/functions/common/introspection/dotnet6/Makefile @@ -14,7 +14,7 @@ build: mv ../dotnet/handler.zip . clean: - $(RM) -r build handler.zip + $(RM) -rf build handler.zip cd ../dotnet && $(MAKE) clean FRAMEWORK=$(FRAMEWORK) .PHONY: build clean diff --git a/tests/aws/services/lambda_/functions/common/introspection/dotnet8/Makefile b/tests/aws/services/lambda_/functions/common/introspection/dotnet8/Makefile index 7ec1ea467ff87..df0b572919fce 100644 --- a/tests/aws/services/lambda_/functions/common/introspection/dotnet8/Makefile +++ b/tests/aws/services/lambda_/functions/common/introspection/dotnet8/Makefile @@ -14,7 +14,7 @@ build: mv ../dotnet/handler.zip . clean: - $(RM) -r build handler.zip + $(RM) -rf build handler.zip cd ../dotnet && $(MAKE) clean FRAMEWORK=$(FRAMEWORK) .PHONY: build clean diff --git a/tests/aws/services/lambda_/functions/common/introspection/java/Makefile b/tests/aws/services/lambda_/functions/common/introspection/java/Makefile index 6916941cbe138..a827eefbe5bbe 100644 --- a/tests/aws/services/lambda_/functions/common/introspection/java/Makefile +++ b/tests/aws/services/lambda_/functions/common/introspection/java/Makefile @@ -7,6 +7,6 @@ build: cp build/handler.zip handler.zip clean: - $(RM) -r build handler.zip + $(RM) -rf build handler.zip .PHONY: build clean diff --git a/tests/aws/services/lambda_/functions/common/introspection/nodejs/Makefile b/tests/aws/services/lambda_/functions/common/introspection/nodejs/Makefile index c3b2190a84a3a..705b003b3eaf8 100644 --- a/tests/aws/services/lambda_/functions/common/introspection/nodejs/Makefile +++ b/tests/aws/services/lambda_/functions/common/introspection/nodejs/Makefile @@ -3,6 +3,6 @@ build: cp -r ./src/* build/ clean: - $(RM) -r build handler.zip + $(RM) -rf build handler.zip .PHONY: build clean diff --git a/tests/aws/services/lambda_/functions/common/introspection/provided/Makefile b/tests/aws/services/lambda_/functions/common/introspection/provided/Makefile index 61f2768c515b2..b0ff7673251d6 100644 --- a/tests/aws/services/lambda_/functions/common/introspection/provided/Makefile +++ b/tests/aws/services/lambda_/functions/common/introspection/provided/Makefile @@ -10,6 +10,9 @@ DOCKER_PLATFORM ?= linux/$(ARCHITECTURE) # https://github.com/cargo-lambda/cargo-lambda/blob/7b0977e6fd9a6b03d8f6ddf71eff5a5b9999e0c0/crates/cargo-lambda-build/src/target_arch.rs#L10 ifeq ($(ARCHITECTURE),arm64) # ARM builds are finally fixed since 1.76.0: https://github.com/rust-lang/rust/issues/77071 + # TODO: Migrate to -gnu once we can avoid the following issue for the runtime provided.al2. + # It might require using the official build image (https://gallery.ecr.aws/sam/emulation-provided.al2), but + # that seems not worth fixing before provided.al2 deprecation 2026-06. # The suffix -musl instead of -gnu is required for the runtime `provided.al2` to fix a GLIBC version not found error: # /var/task/bootstrap: /lib64/libc.so.6: version `GLIBC_2.28' not found (required by /var/task/bootstrap) # https://github.com/awslabs/aws-lambda-rust-runtime/issues/17#issuecomment-645064821 @@ -18,15 +21,17 @@ else RUST_TARGET ?= x86_64-unknown-linux-musl endif -# https://hub.docker.com/_/rust/tags -DOCKER_RUST_IMAGE ?= rust:1.76.0 +# https://github.com/cargo-lambda/cargo-lambda/pkgs/container/cargo-lambda +DOCKER_RUST_IMAGE ?= ghcr.io/cargo-lambda/cargo-lambda:1.8.6 +# TODO: consider migrating to AWS SAM-based build (easier and better parity): +# https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/building-rust.html build: mkdir -p build && \ - docker run --rm --platform=$(DOCKER_PLATFORM) -v $$(pwd)/src:/app -v $$(pwd)/build:/out:cached $(DOCKER_RUST_IMAGE) \ - bash -c "rustup target add $(RUST_TARGET) && mkdir -p /app2 && cp -r /app/* /app2 && cd /app2 && cargo build --release --target $(RUST_TARGET) && cp ./target/$(RUST_TARGET)/release/bootstrap /out && chown $$(id -u):$$(id -g) /out/bootstrap" + docker run --rm -v $$(pwd)/src:/app -v $$(pwd)/build:/out:cached $(DOCKER_RUST_IMAGE) \ + bash -c "rustup target add $(RUST_TARGET) && mkdir -p /app2 && cp -r /app/* /app2 && cd /app2 && cargo lambda build --target $(RUST_TARGET) && cp ./target/lambda/bootstrap/bootstrap /out && chown $$(id -u):$$(id -g) /out/bootstrap" clean: - $(RM) -r build handler.zip + $(RM) -rf build handler.zip .PHONY: build clean diff --git a/tests/aws/services/lambda_/functions/common/introspection/provided/src/Cargo.lock b/tests/aws/services/lambda_/functions/common/introspection/provided/src/Cargo.lock index 66d5cd706f319..a6614af3621d0 100644 --- a/tests/aws/services/lambda_/functions/common/introspection/provided/src/Cargo.lock +++ b/tests/aws/services/lambda_/functions/common/introspection/provided/src/Cargo.lock @@ -1,22 +1,16 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. -version = 3 +version = 4 [[package]] -name = "addr2line" -version = "0.21.0" +name = "aho-corasick" +version = "1.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb" +checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301" dependencies = [ - "gimli", + "memchr", ] -[[package]] -name = "adler" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" - [[package]] name = "async-stream" version = "0.3.3" @@ -39,31 +33,22 @@ dependencies = [ ] [[package]] -name = "autocfg" -version = "1.1.0" +name = "atomic-waker" +version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" +checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" [[package]] -name = "backtrace" -version = "0.3.69" +name = "autocfg" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2089b7e3f35b9dd2d0ed921ead4f6d318c27680d4a5bd167b3ee120edb105837" -dependencies = [ - "addr2line", - "cc", - "cfg-if", - "libc", - "miniz_oxide", - "object", - "rustc-demangle", -] +checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" [[package]] name = "base64" -version = "0.20.0" +version = "0.22.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ea22880d78093b0cbe17c89f64a7d457941e65759157ec6cb31a31d652b05e5" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" [[package]] name = "bitflags" @@ -82,27 +67,15 @@ dependencies = [ [[package]] name = "bytes" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4872d67bab6358e59559027aa3b9157c53d9358c51423c17554809a8858e0f8" - -[[package]] -name = "cc" -version = "1.0.89" +version = "1.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0ba8f7aaa012f30d5b2861462f6708eccd49c3c39863fe083a308035f63d723" +checksum = "1e748733b7cbc798e1434b6ac524f0c1ff2ab456fe201501e6497c8417a4fc33" [[package]] name = "cfg-if" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" - -[[package]] -name = "fnv" -version = "1.0.7" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" +checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" [[package]] name = "futures" @@ -121,9 +94,9 @@ dependencies = [ [[package]] name = "futures-channel" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78" +checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" dependencies = [ "futures-core", "futures-sink", @@ -131,9 +104,9 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d" +checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" [[package]] name = "futures-executor" @@ -148,38 +121,38 @@ dependencies = [ [[package]] name = "futures-io" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1" +checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" [[package]] name = "futures-macro" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" +checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" dependencies = [ "proc-macro2", "quote", - "syn 2.0.52", + "syn 2.0.114", ] [[package]] name = "futures-sink" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5" +checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7" [[package]] name = "futures-task" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004" +checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" [[package]] name = "futures-util" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48" +checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" dependencies = [ "futures-channel", "futures-core", @@ -194,47 +167,43 @@ dependencies = [ ] [[package]] -name = "gimli" -version = "0.28.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" - -[[package]] -name = "hermit-abi" -version = "0.1.19" +name = "http" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" +checksum = "e3ba2a386d7f85a81f119ad7498ebe444d2e22c2af0b86b069416ace48b3311a" dependencies = [ - "libc", + "bytes", + "itoa", ] [[package]] -name = "http" -version = "0.2.12" +name = "http-body" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "601cbb57e577e2f5ef5be8e7b83f0f63994f25aa94d673e54a92d5c516d101f1" +checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" dependencies = [ "bytes", - "fnv", - "itoa", + "http", ] [[package]] -name = "http-body" -version = "0.4.4" +name = "http-body-util" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ff4f84919677303da5f147645dbea6b1881f368d03ac84e1dc09031ebd7b2c6" +checksum = "b021d93e26becf5dc7e1b75b1bed1fd93124b374ceb73f43d4d4eafec896a64a" dependencies = [ "bytes", + "futures-core", "http", + "http-body", "pin-project-lite", ] [[package]] name = "http-serde" -version = "1.1.3" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f560b665ad9f1572cfcaf034f7fb84338a7ce945216d64a90fd81f046a3caee" +checksum = "0f056c8559e3757392c8d091e796416e4649d8e49e88b8d76df6c002f05027fd" dependencies = [ "http", "serde", @@ -242,21 +211,36 @@ dependencies = [ [[package]] name = "httparse" -version = "1.8.0" +version = "1.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904" +checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87" [[package]] -name = "httpdate" -version = "1.0.2" +name = "hyper" +version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4a1e36c821dbe04574f602848a19f742f4fb3c98d40449f11bcad18d6b17421" +checksum = "2ab2d4f250c3d7b1c9fcdff1cece94ea4e2dfbec68614f7b87cb205f24ca9d11" +dependencies = [ + "atomic-waker", + "bytes", + "futures-channel", + "futures-core", + "http", + "http-body", + "httparse", + "itoa", + "pin-project-lite", + "pin-utils", + "smallvec", + "tokio", + "want", +] [[package]] -name = "hyper" -version = "0.14.28" +name = "hyper-util" +version = "0.1.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf96e135eb83a2a8ddf766e426a841d8ddd7449d5f00d34ea02b41d2f19eef80" +checksum = "727805d60e7938b76b826a6ef209eb70eaa1812794f9424d4a4e2d740662df5f" dependencies = [ "bytes", "futures-channel", @@ -264,38 +248,37 @@ dependencies = [ "futures-util", "http", "http-body", - "httparse", - "httpdate", - "itoa", + "hyper", + "libc", "pin-project-lite", "socket2", "tokio", "tower-service", "tracing", - "want", ] [[package]] name = "itoa" -version = "1.0.1" +version = "1.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1aab8fc367588b89dcee83ab0fd66b72b50b72fa1904d7095045ace2b0c81c35" +checksum = "92ecc6618181def0457392ccd0ee51198e065e016d1d527a7ac1b6dc7c1f09d2" [[package]] name = "lambda_runtime" -version = "0.8.3" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "deca8f65d7ce9a8bfddebb49d7d91b22e788a59ca0c5190f26794ab80ed7a702" +checksum = "dc0b4409eea054e4c06f0101fed547b2cf208e8eca9dc6d41dead4114577852b" dependencies = [ "async-stream", "base64", "bytes", "futures", "http", - "http-body", + "http-body-util", "http-serde", "hyper", "lambda_runtime_api_client", + "pin-project", "serde", "serde_json", "serde_path_to_error", @@ -307,21 +290,34 @@ dependencies = [ [[package]] name = "lambda_runtime_api_client" -version = "0.8.0" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "690c5ae01f3acac8c9c3348b556fc443054e9b7f1deaf53e9ebab716282bf0ed" +checksum = "7b4873061514cb57ffb6a599b77c46c65d6d783efe9bad8fd56b7cba7f0459ef" dependencies = [ + "bytes", + "futures-channel", + "futures-util", "http", + "http-body", + "http-body-util", "hyper", - "tokio", - "tower-service", + "hyper-util", + "tower", + "tracing", + "tracing-subscriber", ] +[[package]] +name = "lazy_static" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" + [[package]] name = "libc" -version = "0.2.153" +version = "0.2.180" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" +checksum = "bcc35a38544a891a5f7c865aca548a982ccb3b8650a5b06d0fd33a10283c56fc" [[package]] name = "lock_api" @@ -335,63 +331,41 @@ dependencies = [ [[package]] name = "log" -version = "0.4.17" +version = "0.4.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "memchr" -version = "2.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" +checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897" [[package]] -name = "miniz_oxide" -version = "0.7.2" +name = "matchers" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d811f3e15f28568be3407c8e7fdb6514c1cda3cb30683f15b6a1a1dc4ea14a7" +checksum = "d1525a2a28c7f4fa0fc98bb91ae755d1e2d1505079e05539e35bc876b5d65ae9" dependencies = [ - "adler", + "regex-automata", ] [[package]] -name = "mio" -version = "0.8.11" +name = "memchr" +version = "2.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4a650543ca06a924e8b371db273b2756685faae30f8487da1b56505a8f78b0c" -dependencies = [ - "libc", - "wasi", - "windows-sys 0.48.0", -] +checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273" [[package]] -name = "num_cpus" -version = "1.13.1" +name = "mio" +version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19e64526ebdee182341572e50e9ad03965aa510cd94427a4549448f285e957a1" +checksum = "a69bcab0ad47271a0234d9422b131806bf3968021e5dc9328caf2d4cd58557fc" dependencies = [ - "hermit-abi", "libc", -] - -[[package]] -name = "object" -version = "0.32.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6a622008b6e321afc04970976f62ee297fdbaa6f95318ca343e3eebb9648441" -dependencies = [ - "memchr", + "wasi", + "windows-sys 0.61.2", ] [[package]] name = "once_cell" -version = "1.19.0" +version = "1.21.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" +checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" [[package]] name = "parking_lot" @@ -438,9 +412,9 @@ dependencies = [ [[package]] name = "pin-project-lite" -version = "0.2.13" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58" +checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" [[package]] name = "pin-utils" @@ -450,18 +424,18 @@ checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" [[package]] name = "proc-macro2" -version = "1.0.78" +version = "1.0.105" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2422ad645d89c99f8f3e6b88a9fdeca7fabeac836b1002371c4367c8f984aae" +checksum = "535d180e0ecab6268a3e718bb9fd44db66bbbc256257165fc699dadf70d16fe7" dependencies = [ "unicode-ident", ] [[package]] name = "quote" -version = "1.0.35" +version = "1.0.43" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" +checksum = "dc74d9a594b72ae6656596548f56f667211f8a97b3d4c3d467150794690dc40a" dependencies = [ "proc-macro2", ] @@ -476,16 +450,21 @@ dependencies = [ ] [[package]] -name = "rustc-demangle" -version = "0.1.23" +name = "regex-automata" +version = "0.4.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" +checksum = "5276caf25ac86c8d810222b3dbb938e512c55c6831a10f3e6ed1c93b84041f1c" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] [[package]] -name = "ryu" -version = "1.0.9" +name = "regex-syntax" +version = "0.8.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73b4b750c782965c211b42f022f59af1fbceabdd026623714f104152f1ec149f" +checksum = "7a2d987857b319362043e95f5353c0535c1f58eec5336fdfcf626430af7def58" [[package]] name = "scopeguard" @@ -495,33 +474,45 @@ checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" [[package]] name = "serde" -version = "1.0.197" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" +dependencies = [ + "serde_core", + "serde_derive", +] + +[[package]] +name = "serde_core" +version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fb1c873e1b9b056a4dc4c0c198b24c3ffa059243875552b2bd0933b1aee4ce2" +checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.197" +version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7eb0b34b42edc17f6b7cac84a52a1c5f0e1bb2227e997ca9011ea3dd34e8610b" +checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" dependencies = [ "proc-macro2", "quote", - "syn 2.0.52", + "syn 2.0.114", ] [[package]] name = "serde_json" -version = "1.0.114" +version = "1.0.149" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5f09b1bd632ef549eaa9f60a1f8de742bdbc698e6cee2095fc84dde5f549ae0" +checksum = "83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86" dependencies = [ "itoa", - "ryu", + "memchr", "serde", + "serde_core", + "zmij", ] [[package]] @@ -534,6 +525,15 @@ dependencies = [ "serde", ] +[[package]] +name = "sharded-slab" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" +dependencies = [ + "lazy_static", +] + [[package]] name = "signal-hook-registry" version = "1.4.0" @@ -545,24 +545,24 @@ dependencies = [ [[package]] name = "slab" -version = "0.4.6" +version = "0.4.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb703cfe953bccee95685111adeedb76fabe4e97549a58d16f03ea7b9367bb32" +checksum = "7a2ae44ef20feb57a68b23d846850f861394c2e02dc425a50098ae8c90267589" [[package]] name = "smallvec" -version = "1.8.0" +version = "1.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2dd574626839106c320a323308629dcb1acfc96e32a8cba364ddc61ac23ee83" +checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" [[package]] name = "socket2" -version = "0.5.6" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05ffd9c0a93b7543e062e759284fcf5f5e3b098501104bfbdde4d404db792871" +checksum = "17129e116933cf371d018bb80ae557e889637989d8638274fb25622827b03881" dependencies = [ "libc", - "windows-sys 0.52.0", + "windows-sys 0.60.2", ] [[package]] @@ -578,43 +578,56 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.52" +version = "2.0.114" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b699d15b36d1f02c3e7c69f8ffef53de37aefae075d8488d4ba1a7788d574a07" +checksum = "d4d107df263a3013ef9b1879b0df87d706ff80f65a86ea879bd9c31f9b307c2a" dependencies = [ "proc-macro2", "quote", "unicode-ident", ] +[[package]] +name = "sync_wrapper" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bf256ce5efdfa370213c1dabab5935a12e49f2c58d15e9eac2870d3b4f27263" + +[[package]] +name = "thread_local" +version = "1.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f60246a4944f24f6e018aa17cdeffb7818b76356965d03b07d6a9886e8962185" +dependencies = [ + "cfg-if", +] + [[package]] name = "tokio" -version = "1.36.0" +version = "1.49.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61285f6515fa018fb2d1e46eb21223fff441ee8db5d0f1435e8ab4f5cdb80931" +checksum = "72a2903cd7736441aac9df9d7688bd0ce48edccaadf181c3b90be801e81d3d86" dependencies = [ - "backtrace", "bytes", "libc", "mio", - "num_cpus", "parking_lot", "pin-project-lite", "signal-hook-registry", "socket2", "tokio-macros", - "windows-sys 0.48.0", + "windows-sys 0.61.2", ] [[package]] name = "tokio-macros" -version = "2.2.0" +version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b" +checksum = "af407857209536a95c8e56f8231ef2c2e2aff839b22e07a1ffcbc617e9db9fa5" dependencies = [ "proc-macro2", "quote", - "syn 2.0.52", + "syn 2.0.114", ] [[package]] @@ -630,36 +643,35 @@ dependencies = [ [[package]] name = "tower" -version = "0.4.12" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a89fd63ad6adf737582df5db40d286574513c69a11dac5214dc3b5603d6713e" +checksum = "d039ad9159c98b70ecfd540b2573b97f7f52c3e8d9f8ad57a24b916a536975f9" dependencies = [ "futures-core", "futures-util", - "pin-project", "pin-project-lite", + "sync_wrapper", "tower-layer", "tower-service", - "tracing", ] [[package]] name = "tower-layer" -version = "0.3.1" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "343bc9466d3fe6b0f960ef45960509f84480bf4fd96f92901afe7ff3df9d3a62" +checksum = "121c2a6cda46980bb0fcd1647ffaf6cd3fc79a013de288782836f6df9c48780e" [[package]] name = "tower-service" -version = "0.3.1" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "360dfd1d6d30e05fda32ace2c8c70e9c0a9da713275777f5a4dbb8a1893930c6" +checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" [[package]] name = "tracing" -version = "0.1.40" +version = "0.1.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" +checksum = "63e71662fa4b2a2c3a26f570f037eb95bb1f85397f3cd8076caed2f026a6d100" dependencies = [ "log", "pin-project-lite", @@ -669,49 +681,83 @@ dependencies = [ [[package]] name = "tracing-attributes" -version = "0.1.27" +version = "0.1.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" +checksum = "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da" dependencies = [ "proc-macro2", "quote", - "syn 2.0.52", + "syn 2.0.114", ] [[package]] name = "tracing-core" -version = "0.1.32" +version = "0.1.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db97caf9d906fbde555dd62fa95ddba9eecfd14cb388e4f491a66d74cd5fb79a" +dependencies = [ + "once_cell", + "valuable", +] + +[[package]] +name = "tracing-serde" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" +checksum = "704b1aeb7be0d0a84fc9828cae51dab5970fee5088f83d1dd7ee6f6246fc6ff1" dependencies = [ + "serde", + "tracing-core", +] + +[[package]] +name = "tracing-subscriber" +version = "0.3.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f30143827ddab0d256fd843b7a66d164e9f271cfa0dde49142c5ca0ca291f1e" +dependencies = [ + "matchers", "once_cell", + "regex-automata", + "serde", + "serde_json", + "sharded-slab", + "thread_local", + "tracing", + "tracing-core", + "tracing-serde", ] [[package]] name = "try-lock" -version = "0.2.3" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59547bce71d9c38b83d9c0e92b6066c4253371f15005def0c30d9657f50c7642" +checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" [[package]] name = "unicode-ident" -version = "1.0.12" +version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" +checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5" [[package]] name = "unicode-xid" -version = "0.2.3" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" + +[[package]] +name = "valuable" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "957e51f3646910546462e67d5f7599b9e4fb8acdd304b087a6494730f9eebf04" +checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65" [[package]] name = "want" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ce8a968cb1cd110d136ff8b819a556d6fb6d919363c61534f6860c7eb172ba0" +checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" dependencies = [ - "log", "try-lock", ] @@ -721,6 +767,12 @@ version = "0.11.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" +[[package]] +name = "windows-link" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" + [[package]] name = "windows-sys" version = "0.36.1" @@ -736,63 +788,44 @@ dependencies = [ [[package]] name = "windows-sys" -version = "0.48.0" +version = "0.60.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb" dependencies = [ - "windows-targets 0.48.5", + "windows-targets", ] [[package]] name = "windows-sys" -version = "0.52.0" +version = "0.61.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" dependencies = [ - "windows-targets 0.52.4", + "windows-link", ] [[package]] name = "windows-targets" -version = "0.48.5" +version = "0.53.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" +checksum = "4945f9f551b88e0d65f3db0bc25c33b8acea4d9e41163edf90dcd0b19f9069f3" dependencies = [ - "windows_aarch64_gnullvm 0.48.5", - "windows_aarch64_msvc 0.48.5", - "windows_i686_gnu 0.48.5", - "windows_i686_msvc 0.48.5", - "windows_x86_64_gnu 0.48.5", - "windows_x86_64_gnullvm 0.48.5", - "windows_x86_64_msvc 0.48.5", + "windows-link", + "windows_aarch64_gnullvm", + "windows_aarch64_msvc 0.53.1", + "windows_i686_gnu 0.53.1", + "windows_i686_gnullvm", + "windows_i686_msvc 0.53.1", + "windows_x86_64_gnu 0.53.1", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc 0.53.1", ] -[[package]] -name = "windows-targets" -version = "0.52.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7dd37b7e5ab9018759f893a1952c9420d060016fc19a472b4bb20d1bdd694d1b" -dependencies = [ - "windows_aarch64_gnullvm 0.52.4", - "windows_aarch64_msvc 0.52.4", - "windows_i686_gnu 0.52.4", - "windows_i686_msvc 0.52.4", - "windows_x86_64_gnu 0.52.4", - "windows_x86_64_gnullvm 0.52.4", - "windows_x86_64_msvc 0.52.4", -] - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" - [[package]] name = "windows_aarch64_gnullvm" -version = "0.52.4" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bcf46cf4c365c6f2d1cc93ce535f2c8b244591df96ceee75d8e83deb70a9cac9" +checksum = "a9d8416fa8b42f5c947f8482c43e7d89e73a173cead56d044f6a56104a6d1b53" [[package]] name = "windows_aarch64_msvc" @@ -802,15 +835,9 @@ checksum = "9bb8c3fd39ade2d67e9874ac4f3db21f0d710bee00fe7cab16949ec184eeaa47" [[package]] name = "windows_aarch64_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.52.4" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da9f259dd3bcf6990b55bffd094c4f7235817ba4ceebde8e6d11cd0c5633b675" +checksum = "b9d782e804c2f632e395708e99a94275910eb9100b2114651e04744e9b125006" [[package]] name = "windows_i686_gnu" @@ -820,15 +847,15 @@ checksum = "180e6ccf01daf4c426b846dfc66db1fc518f074baa793aa7d9b9aaeffad6a3b6" [[package]] name = "windows_i686_gnu" -version = "0.48.5" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" +checksum = "960e6da069d81e09becb0ca57a65220ddff016ff2d6af6a223cf372a506593a3" [[package]] -name = "windows_i686_gnu" -version = "0.52.4" +name = "windows_i686_gnullvm" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b474d8268f99e0995f25b9f095bc7434632601028cf86590aea5c8a5cb7801d3" +checksum = "fa7359d10048f68ab8b09fa71c3daccfb0e9b559aed648a8f95469c27057180c" [[package]] name = "windows_i686_msvc" @@ -838,15 +865,9 @@ checksum = "e2e7917148b2812d1eeafaeb22a97e4813dfa60a3f8f78ebe204bcc88f12f024" [[package]] name = "windows_i686_msvc" -version = "0.48.5" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" - -[[package]] -name = "windows_i686_msvc" -version = "0.52.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1515e9a29e5bed743cb4415a9ecf5dfca648ce85ee42e15873c3cd8610ff8e02" +checksum = "1e7ac75179f18232fe9c285163565a57ef8d3c89254a30685b57d83a38d326c2" [[package]] name = "windows_x86_64_gnu" @@ -856,27 +877,15 @@ checksum = "4dcd171b8776c41b97521e5da127a2d86ad280114807d0b2ab1e462bc764d9e1" [[package]] name = "windows_x86_64_gnu" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.52.4" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5eee091590e89cc02ad514ffe3ead9eb6b660aedca2183455434b93546371a03" +checksum = "9c3842cdd74a865a8066ab39c8a7a473c0778a3f29370b5fd6b4b9aa7df4a499" [[package]] name = "windows_x86_64_gnullvm" -version = "0.48.5" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.52.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77ca79f2451b49fa9e2af39f0747fe999fcda4f5e241b2898624dca97a1f2177" +checksum = "0ffa179e2d07eee8ad8f57493436566c7cc30ac536a3379fdf008f47f6bb7ae1" [[package]] name = "windows_x86_64_msvc" @@ -886,12 +895,12 @@ checksum = "c811ca4a8c853ef420abd8592ba53ddbbac90410fab6903b3e79972a631f7680" [[package]] name = "windows_x86_64_msvc" -version = "0.48.5" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" +checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650" [[package]] -name = "windows_x86_64_msvc" -version = "0.52.4" +name = "zmij" +version = "1.0.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32b752e52a2da0ddfbdbcc6fceadfeede4c939ed16d13e648833a61dfb611ed8" +checksum = "ac93432f5b761b22864c774aac244fa5c0fd877678a4c37ebf6cf42208f9c9ec" diff --git a/tests/aws/services/lambda_/functions/common/introspection/provided/src/Cargo.toml b/tests/aws/services/lambda_/functions/common/introspection/provided/src/Cargo.toml index 40e75bde46b15..f76843110508d 100644 --- a/tests/aws/services/lambda_/functions/common/introspection/provided/src/Cargo.toml +++ b/tests/aws/services/lambda_/functions/common/introspection/provided/src/Cargo.toml @@ -5,10 +5,13 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html +# Upgrade dependencies: +# 1. cargo install cargo-edit +# 2. cargo upgrade -i [dependencies] # https://crates.io/crates/lambda_runtime -lambda_runtime = "0.8.3" +lambda_runtime = "1.0.2" # https://crates.io/crates/serde_json -serde_json = "1.0.108" +serde_json = "1.0.149" # https://crates.io/crates/tokio -tokio = { version = "1.34.0", features = ["full"] } +tokio = { version = "1.49.0", features = ["full"] } diff --git a/tests/aws/services/lambda_/functions/common/introspection/python/Makefile b/tests/aws/services/lambda_/functions/common/introspection/python/Makefile index 4426ee52bf0ef..493fcad61fbea 100644 --- a/tests/aws/services/lambda_/functions/common/introspection/python/Makefile +++ b/tests/aws/services/lambda_/functions/common/introspection/python/Makefile @@ -4,6 +4,6 @@ build: cp -r ./src/* build/ clean: - $(RM) -r build handler.zip + $(RM) -rf build handler.zip .PHONY: build clean diff --git a/tests/aws/services/lambda_/functions/common/kinesis_sdkv2/Makefile b/tests/aws/services/lambda_/functions/common/kinesis_sdkv2/Makefile new file mode 100644 index 0000000000000..1fd2a9d5903cd --- /dev/null +++ b/tests/aws/services/lambda_/functions/common/kinesis_sdkv2/Makefile @@ -0,0 +1,10 @@ +# Top-level Makefile to invoke all make targets in sub-directories + +# Based on https://stackoverflow.com/a/72209214/6875981 +SUBDIRS := $(patsubst %/,%,$(wildcard */)) + +.PHONY: all $(MAKECMDGOALS) $(SUBDIRS) +$(MAKECMDGOALS) all: $(SUBDIRS) + +$(SUBDIRS): + $(MAKE) -C $@ $(MAKECMDGOALS) diff --git a/tests/aws/services/lambda_/functions/common/kinesis_sdkv2/java17/Makefile b/tests/aws/services/lambda_/functions/common/kinesis_sdkv2/java17/Makefile index 6916941cbe138..a827eefbe5bbe 100644 --- a/tests/aws/services/lambda_/functions/common/kinesis_sdkv2/java17/Makefile +++ b/tests/aws/services/lambda_/functions/common/kinesis_sdkv2/java17/Makefile @@ -7,6 +7,6 @@ build: cp build/handler.zip handler.zip clean: - $(RM) -r build handler.zip + $(RM) -rf build handler.zip .PHONY: build clean diff --git a/tests/aws/services/lambda_/functions/common/uncaughtexception/dotnet/Makefile b/tests/aws/services/lambda_/functions/common/uncaughtexception/dotnet/Makefile index 31704c534390c..58cab0cd7beb5 100644 --- a/tests/aws/services/lambda_/functions/common/uncaughtexception/dotnet/Makefile +++ b/tests/aws/services/lambda_/functions/common/uncaughtexception/dotnet/Makefile @@ -9,13 +9,13 @@ endif FUNCTION_ARCHITECTURE ?= $(ARCHITECTURE) # Target Dotnet framework version -FRAMEWORK ?= net8.0 +FRAMEWORK ?= net10.0 # Workaround for a Docker race condition causing an I/O error upon zipping to /out/handler.zip if # two builds are executed in short succession. Example: `make -C dotnet build && make -C dotnet6 build` BUILD_DIR ?= build-$(FRAMEWORK) -# https://gallery.ecr.aws/sam/build-dotnet8 -IMAGE ?= public.ecr.aws/sam/build-dotnet8:1.112.0 +# https://gallery.ecr.aws/sam/build-dotnet10 +IMAGE ?= public.ecr.aws/sam/build-dotnet10:1.151.0 # Emulated builds with Dotnet8 are currently (2024-03-19) broken as discussed in many issues: # https://github.com/NuGet/Home/issues/12227 @@ -27,10 +27,10 @@ IMAGE ?= public.ecr.aws/sam/build-dotnet8:1.112.0 build: mkdir -p $(BUILD_DIR) && \ - docker run --rm -v $$(pwd)/src:/app -v $$(pwd)/$(BUILD_DIR):/out $(IMAGE) bash -c "mkdir -p /app2 && cp /app/* /app2 && cd /app2 && dotnet lambda package --framework $(FRAMEWORK) --function-architecture $(FUNCTION_ARCHITECTURE) -o ../out/handler.zip" && \ + docker run --rm -v $$(pwd)/src:/app -v $$(pwd)/$(BUILD_DIR):/out $(IMAGE) bash -c "mkdir -p /app2 && cp -r /app/* /app2 && cd /app2 && dotnet lambda package --framework $(FRAMEWORK) --function-architecture $(FUNCTION_ARCHITECTURE) -o ../out/handler.zip" && \ cp $(BUILD_DIR)/handler.zip handler.zip clean: - $(RM) -r $(BUILD_DIR) handler.zip + $(RM) -rf $(BUILD_DIR) handler.zip .PHONY: build clean diff --git a/tests/aws/services/lambda_/functions/common/uncaughtexception/dotnet/src/dotnet.csproj b/tests/aws/services/lambda_/functions/common/uncaughtexception/dotnet/src/dotnet.csproj index 1bd07d2e45a5a..980d160b3d02a 100644 --- a/tests/aws/services/lambda_/functions/common/uncaughtexception/dotnet/src/dotnet.csproj +++ b/tests/aws/services/lambda_/functions/common/uncaughtexception/dotnet/src/dotnet.csproj @@ -1,13 +1,13 @@  - net6.0;net8.0 + net6.0;net8.0;net10.0 true Lambda - + - + diff --git a/tests/aws/services/lambda_/functions/common/uncaughtexception/dotnet10/Makefile b/tests/aws/services/lambda_/functions/common/uncaughtexception/dotnet10/Makefile new file mode 100644 index 0000000000000..89991b37bd4a7 --- /dev/null +++ b/tests/aws/services/lambda_/functions/common/uncaughtexception/dotnet10/Makefile @@ -0,0 +1,20 @@ +UNAME := $(shell uname -m) +ifeq ($(UNAME),x86_64) + ARCHITECTURE ?= x86_64 +else + ARCHITECTURE ?= arm64 +endif + +# Target Dotnet framework version +FRAMEWORK ?= net10.0 + +# Forward build for different Dotnet framework version to avoid code duplication +build: + cd ../dotnet && $(MAKE) clean build ARCHITECTURE=$(ARCHITECTURE) FRAMEWORK=$(FRAMEWORK) + mv ../dotnet/handler.zip . + +clean: + $(RM) -rf build handler.zip + cd ../dotnet && $(MAKE) clean FRAMEWORK=$(FRAMEWORK) + +.PHONY: build clean diff --git a/tests/aws/services/lambda_/functions/common/uncaughtexception/dotnet6/Makefile b/tests/aws/services/lambda_/functions/common/uncaughtexception/dotnet6/Makefile index 43573df40d616..95f945b450e31 100644 --- a/tests/aws/services/lambda_/functions/common/uncaughtexception/dotnet6/Makefile +++ b/tests/aws/services/lambda_/functions/common/uncaughtexception/dotnet6/Makefile @@ -14,7 +14,7 @@ build: mv ../dotnet/handler.zip . clean: - $(RM) -r build handler.zip + $(RM) -rf build handler.zip cd ../dotnet && $(MAKE) clean FRAMEWORK=$(FRAMEWORK) .PHONY: build clean diff --git a/tests/aws/services/lambda_/functions/common/uncaughtexception/dotnet8/Makefile b/tests/aws/services/lambda_/functions/common/uncaughtexception/dotnet8/Makefile index 7ec1ea467ff87..df0b572919fce 100644 --- a/tests/aws/services/lambda_/functions/common/uncaughtexception/dotnet8/Makefile +++ b/tests/aws/services/lambda_/functions/common/uncaughtexception/dotnet8/Makefile @@ -14,7 +14,7 @@ build: mv ../dotnet/handler.zip . clean: - $(RM) -r build handler.zip + $(RM) -rf build handler.zip cd ../dotnet && $(MAKE) clean FRAMEWORK=$(FRAMEWORK) .PHONY: build clean diff --git a/tests/aws/services/lambda_/functions/common/uncaughtexception/java/Makefile b/tests/aws/services/lambda_/functions/common/uncaughtexception/java/Makefile index 6916941cbe138..a827eefbe5bbe 100644 --- a/tests/aws/services/lambda_/functions/common/uncaughtexception/java/Makefile +++ b/tests/aws/services/lambda_/functions/common/uncaughtexception/java/Makefile @@ -7,6 +7,6 @@ build: cp build/handler.zip handler.zip clean: - $(RM) -r build handler.zip + $(RM) -rf build handler.zip .PHONY: build clean diff --git a/tests/aws/services/lambda_/functions/common/uncaughtexception/nodejs/Makefile b/tests/aws/services/lambda_/functions/common/uncaughtexception/nodejs/Makefile index c3b2190a84a3a..705b003b3eaf8 100644 --- a/tests/aws/services/lambda_/functions/common/uncaughtexception/nodejs/Makefile +++ b/tests/aws/services/lambda_/functions/common/uncaughtexception/nodejs/Makefile @@ -3,6 +3,6 @@ build: cp -r ./src/* build/ clean: - $(RM) -r build handler.zip + $(RM) -rf build handler.zip .PHONY: build clean diff --git a/tests/aws/services/lambda_/functions/common/uncaughtexception/provided/Makefile b/tests/aws/services/lambda_/functions/common/uncaughtexception/provided/Makefile index 61f2768c515b2..b0ff7673251d6 100644 --- a/tests/aws/services/lambda_/functions/common/uncaughtexception/provided/Makefile +++ b/tests/aws/services/lambda_/functions/common/uncaughtexception/provided/Makefile @@ -10,6 +10,9 @@ DOCKER_PLATFORM ?= linux/$(ARCHITECTURE) # https://github.com/cargo-lambda/cargo-lambda/blob/7b0977e6fd9a6b03d8f6ddf71eff5a5b9999e0c0/crates/cargo-lambda-build/src/target_arch.rs#L10 ifeq ($(ARCHITECTURE),arm64) # ARM builds are finally fixed since 1.76.0: https://github.com/rust-lang/rust/issues/77071 + # TODO: Migrate to -gnu once we can avoid the following issue for the runtime provided.al2. + # It might require using the official build image (https://gallery.ecr.aws/sam/emulation-provided.al2), but + # that seems not worth fixing before provided.al2 deprecation 2026-06. # The suffix -musl instead of -gnu is required for the runtime `provided.al2` to fix a GLIBC version not found error: # /var/task/bootstrap: /lib64/libc.so.6: version `GLIBC_2.28' not found (required by /var/task/bootstrap) # https://github.com/awslabs/aws-lambda-rust-runtime/issues/17#issuecomment-645064821 @@ -18,15 +21,17 @@ else RUST_TARGET ?= x86_64-unknown-linux-musl endif -# https://hub.docker.com/_/rust/tags -DOCKER_RUST_IMAGE ?= rust:1.76.0 +# https://github.com/cargo-lambda/cargo-lambda/pkgs/container/cargo-lambda +DOCKER_RUST_IMAGE ?= ghcr.io/cargo-lambda/cargo-lambda:1.8.6 +# TODO: consider migrating to AWS SAM-based build (easier and better parity): +# https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/building-rust.html build: mkdir -p build && \ - docker run --rm --platform=$(DOCKER_PLATFORM) -v $$(pwd)/src:/app -v $$(pwd)/build:/out:cached $(DOCKER_RUST_IMAGE) \ - bash -c "rustup target add $(RUST_TARGET) && mkdir -p /app2 && cp -r /app/* /app2 && cd /app2 && cargo build --release --target $(RUST_TARGET) && cp ./target/$(RUST_TARGET)/release/bootstrap /out && chown $$(id -u):$$(id -g) /out/bootstrap" + docker run --rm -v $$(pwd)/src:/app -v $$(pwd)/build:/out:cached $(DOCKER_RUST_IMAGE) \ + bash -c "rustup target add $(RUST_TARGET) && mkdir -p /app2 && cp -r /app/* /app2 && cd /app2 && cargo lambda build --target $(RUST_TARGET) && cp ./target/lambda/bootstrap/bootstrap /out && chown $$(id -u):$$(id -g) /out/bootstrap" clean: - $(RM) -r build handler.zip + $(RM) -rf build handler.zip .PHONY: build clean diff --git a/tests/aws/services/lambda_/functions/common/uncaughtexception/provided/src/Cargo.lock b/tests/aws/services/lambda_/functions/common/uncaughtexception/provided/src/Cargo.lock index 9726e78122d90..3e2e61a1e250c 100644 --- a/tests/aws/services/lambda_/functions/common/uncaughtexception/provided/src/Cargo.lock +++ b/tests/aws/services/lambda_/functions/common/uncaughtexception/provided/src/Cargo.lock @@ -1,12 +1,15 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. -version = 3 +version = 4 [[package]] -name = "adler" -version = "1.0.2" +name = "aho-corasick" +version = "1.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" +checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301" +dependencies = [ + "memchr", +] [[package]] name = "async-stream" @@ -26,20 +29,26 @@ checksum = "10f203db73a71dfa2fb6dd22763990fa26f3d2625a6da2da900d23b87d26be27" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 1.0.92", ] +[[package]] +name = "atomic-waker" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" + [[package]] name = "autocfg" -version = "1.1.0" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" +checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" [[package]] name = "base64" -version = "0.13.0" +version = "0.22.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" [[package]] name = "bitflags" @@ -56,236 +65,223 @@ dependencies = [ "tokio", ] -[[package]] -name = "byteorder" -version = "1.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" - [[package]] name = "bytes" -version = "1.1.0" +version = "1.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4872d67bab6358e59559027aa3b9157c53d9358c51423c17554809a8858e0f8" +checksum = "1e748733b7cbc798e1434b6ac524f0c1ff2ab456fe201501e6497c8417a4fc33" [[package]] name = "cfg-if" -version = "1.0.0" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" [[package]] -name = "crc32fast" -version = "1.3.2" +name = "futures" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d" +checksum = "65bc07b1a8bc7c85c5f2e110c476c7389b4554ba72af57d8445ea63a576b0876" dependencies = [ - "cfg-if", + "futures-channel", + "futures-core", + "futures-executor", + "futures-io", + "futures-sink", + "futures-task", + "futures-util", ] [[package]] -name = "crossbeam-channel" -version = "0.5.4" +name = "futures-channel" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5aaa7bd5fb665c6864b5f963dd9097905c54125909c7aa94c9e18507cdbe6c53" +checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" dependencies = [ - "cfg-if", - "crossbeam-utils", + "futures-core", + "futures-sink", ] [[package]] -name = "crossbeam-utils" -version = "0.8.8" +name = "futures-core" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0bf124c720b7686e3c2663cf54062ab0f68a88af2fb6a030e87e30bf721fcb38" -dependencies = [ - "cfg-if", - "lazy_static", -] +checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" [[package]] -name = "flate2" -version = "1.0.23" +name = "futures-executor" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b39522e96686d38f4bc984b9198e3a0613264abaebaff2c5c918bfa6b6da09af" +checksum = "1e28d1d997f585e54aebc3f97d39e72338912123a67330d723fdbb564d646c9f" dependencies = [ - "cfg-if", - "crc32fast", - "libc", - "miniz_oxide", + "futures-core", + "futures-task", + "futures-util", ] [[package]] -name = "fnv" -version = "1.0.7" +name = "futures-io" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" +checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" [[package]] -name = "futures-channel" -version = "0.3.21" +name = "futures-macro" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3083ce4b914124575708913bca19bfe887522d6e2e6d0952943f5eac4a74010" +checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" dependencies = [ - "futures-core", + "proc-macro2", + "quote", + "syn 2.0.114", ] -[[package]] -name = "futures-core" -version = "0.3.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c09fd04b7e4073ac7156a9539b57a484a8ea920f79c7c675d05d289ab6110d3" - [[package]] name = "futures-sink" -version = "0.3.21" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21163e139fa306126e6eedaf49ecdb4588f939600f0b1e770f4205ee4b7fa868" +checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7" [[package]] name = "futures-task" -version = "0.3.21" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57c66a976bf5909d801bbef33416c41372779507e7a6b3a5e25e4749c58f776a" +checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" [[package]] name = "futures-util" -version = "0.3.21" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8b7abd5d659d9b90c8cba917f6ec750a74e2dc23902ef9cd4cc8c8b22e6036a" +checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" dependencies = [ + "futures-channel", "futures-core", + "futures-io", + "futures-macro", + "futures-sink", "futures-task", + "memchr", "pin-project-lite", "pin-utils", + "slab", ] [[package]] -name = "getrandom" -version = "0.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9be70c98951c83b8d2f8f60d7065fa6d5146873094452a1008da8c2f1e4205ad" -dependencies = [ - "cfg-if", - "libc", - "wasi 0.10.2+wasi-snapshot-preview1", -] - -[[package]] -name = "hashbrown" -version = "0.11.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e" - -[[package]] -name = "hdrhistogram" -version = "7.5.0" +name = "http" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31672b7011be2c4f7456c4ddbcb40e7e9a4a9fad8efe49a6ebaf5f307d0109c0" +checksum = "e3ba2a386d7f85a81f119ad7498ebe444d2e22c2af0b86b069416ace48b3311a" dependencies = [ - "base64", - "byteorder", - "crossbeam-channel", - "flate2", - "nom", - "num-traits", + "bytes", + "itoa", ] [[package]] -name = "hermit-abi" -version = "0.1.19" +name = "http-body" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" +checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" dependencies = [ - "libc", + "bytes", + "http", ] [[package]] -name = "http" -version = "0.2.7" +name = "http-body-util" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff8670570af52249509a86f5e3e18a08c60b177071826898fde8997cf5f6bfbb" +checksum = "b021d93e26becf5dc7e1b75b1bed1fd93124b374ceb73f43d4d4eafec896a64a" dependencies = [ "bytes", - "fnv", - "itoa", + "futures-core", + "http", + "http-body", + "pin-project-lite", ] [[package]] -name = "http-body" -version = "0.4.4" +name = "http-serde" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ff4f84919677303da5f147645dbea6b1881f368d03ac84e1dc09031ebd7b2c6" +checksum = "0f056c8559e3757392c8d091e796416e4649d8e49e88b8d76df6c002f05027fd" dependencies = [ - "bytes", "http", - "pin-project-lite", + "serde", ] [[package]] name = "httparse" -version = "1.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "496ce29bb5a52785b44e0f7ca2847ae0bb839c9bd28f69acac9b99d461c0c04c" - -[[package]] -name = "httpdate" -version = "1.0.2" +version = "1.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4a1e36c821dbe04574f602848a19f742f4fb3c98d40449f11bcad18d6b17421" +checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87" [[package]] name = "hyper" -version = "0.14.18" +version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b26ae0a80afebe130861d90abf98e3814a4f28a4c6ffeb5ab8ebb2be311e0ef2" +checksum = "2ab2d4f250c3d7b1c9fcdff1cece94ea4e2dfbec68614f7b87cb205f24ca9d11" dependencies = [ + "atomic-waker", "bytes", "futures-channel", "futures-core", - "futures-util", "http", "http-body", "httparse", - "httpdate", "itoa", "pin-project-lite", - "socket2", + "pin-utils", + "smallvec", "tokio", - "tower-service", - "tracing", "want", ] [[package]] -name = "indexmap" -version = "1.8.1" +name = "hyper-util" +version = "0.1.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f647032dfaa1f8b6dc29bd3edb7bbef4861b8b8007ebb118d6db284fd59f6ee" +checksum = "727805d60e7938b76b826a6ef209eb70eaa1812794f9424d4a4e2d740662df5f" dependencies = [ - "autocfg", - "hashbrown", + "bytes", + "futures-channel", + "futures-core", + "futures-util", + "http", + "http-body", + "hyper", + "libc", + "pin-project-lite", + "socket2", + "tokio", + "tower-service", + "tracing", ] [[package]] name = "itoa" -version = "1.0.1" +version = "1.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1aab8fc367588b89dcee83ab0fd66b72b50b72fa1904d7095045ace2b0c81c35" +checksum = "92ecc6618181def0457392ccd0ee51198e065e016d1d527a7ac1b6dc7c1f09d2" [[package]] name = "lambda_runtime" -version = "0.5.1" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c73464e59463e91bf179195a308738477df90240173649d5dd2a1f3a2e4a2d2" +checksum = "dc0b4409eea054e4c06f0101fed547b2cf208e8eca9dc6d41dead4114577852b" dependencies = [ "async-stream", + "base64", "bytes", + "futures", "http", + "http-body-util", + "http-serde", "hyper", "lambda_runtime_api_client", + "pin-project", "serde", "serde_json", + "serde_path_to_error", "tokio", "tokio-stream", "tower", @@ -294,27 +290,34 @@ dependencies = [ [[package]] name = "lambda_runtime_api_client" -version = "0.5.0" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e921024b5eb4e2f0800a5d6e25c7ed554562aa62f02cf5f60a48c26c8a678974" +checksum = "7b4873061514cb57ffb6a599b77c46c65d6d783efe9bad8fd56b7cba7f0459ef" dependencies = [ + "bytes", + "futures-channel", + "futures-util", "http", + "http-body", + "http-body-util", "hyper", - "tokio", - "tower-service", + "hyper-util", + "tower", + "tracing", + "tracing-subscriber", ] [[package]] name = "lazy_static" -version = "1.4.0" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" [[package]] name = "libc" -version = "0.2.153" +version = "0.2.180" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" +checksum = "bcc35a38544a891a5f7c865aca548a982ccb3b8650a5b06d0fd33a10283c56fc" [[package]] name = "lock_api" @@ -328,74 +331,41 @@ dependencies = [ [[package]] name = "log" -version = "0.4.17" +version = "0.4.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" -dependencies = [ - "cfg-if", -] +checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897" [[package]] -name = "memchr" -version = "2.5.0" +name = "matchers" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" - -[[package]] -name = "minimal-lexical" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" - -[[package]] -name = "miniz_oxide" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2b29bd4bc3f33391105ebee3589c19197c4271e3e5a9ec9bfe8127eeff8f082" +checksum = "d1525a2a28c7f4fa0fc98bb91ae755d1e2d1505079e05539e35bc876b5d65ae9" dependencies = [ - "adler", + "regex-automata", ] [[package]] -name = "mio" -version = "0.8.11" +name = "memchr" +version = "2.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4a650543ca06a924e8b371db273b2756685faae30f8487da1b56505a8f78b0c" -dependencies = [ - "libc", - "log", - "wasi 0.11.0+wasi-snapshot-preview1", - "windows-sys 0.48.0", -] +checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273" [[package]] -name = "nom" -version = "7.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8903e5a29a317527874d0402f867152a3d21c908bb0b933e416c65e301d4c36" -dependencies = [ - "memchr", - "minimal-lexical", -] - -[[package]] -name = "num-traits" -version = "0.2.15" +name = "mio" +version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd" +checksum = "a69bcab0ad47271a0234d9422b131806bf3968021e5dc9328caf2d4cd58557fc" dependencies = [ - "autocfg", + "libc", + "wasi", + "windows-sys 0.61.2", ] [[package]] -name = "num_cpus" -version = "1.13.1" +name = "once_cell" +version = "1.21.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19e64526ebdee182341572e50e9ad03965aa510cd94427a4549448f285e957a1" -dependencies = [ - "hermit-abi", - "libc", -] +checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" [[package]] name = "parking_lot" @@ -437,14 +407,14 @@ checksum = "744b6f092ba29c3650faf274db506afd39944f48420f6c86b17cfe0ee1cb36bb" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 1.0.92", ] [[package]] name = "pin-project-lite" -version = "0.2.9" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116" +checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" [[package]] name = "pin-utils" @@ -452,74 +422,49 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" -[[package]] -name = "ppv-lite86" -version = "0.2.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb9f9e6e233e5c4a35559a617bf40a4ec447db2e84c20b55a6f83167b7e57872" - [[package]] name = "proc-macro2" -version = "1.0.37" +version = "1.0.105" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec757218438d5fda206afc041538b2f6d889286160d649a86a24d37e1235afd1" +checksum = "535d180e0ecab6268a3e718bb9fd44db66bbbc256257165fc699dadf70d16fe7" dependencies = [ - "unicode-xid", + "unicode-ident", ] [[package]] name = "quote" -version = "1.0.18" +version = "1.0.43" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1feb54ed693b93a84e14094943b84b7c4eae204c512b7ccb95ab0c66d278ad1" +checksum = "dc74d9a594b72ae6656596548f56f667211f8a97b3d4c3d467150794690dc40a" dependencies = [ "proc-macro2", ] [[package]] -name = "rand" -version = "0.8.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" -dependencies = [ - "libc", - "rand_chacha", - "rand_core", -] - -[[package]] -name = "rand_chacha" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" -dependencies = [ - "ppv-lite86", - "rand_core", -] - -[[package]] -name = "rand_core" -version = "0.6.3" +name = "redox_syscall" +version = "0.2.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d34f1408f55294453790c48b2f1ebbb1c5b4b7563eb1f418bcfcfdbb06ebb4e7" +checksum = "62f25bc4c7e55e0b0b7a1d43fb893f4fa1361d0abe38b9ce4f323c2adfe6ef42" dependencies = [ - "getrandom", + "bitflags", ] [[package]] -name = "redox_syscall" -version = "0.2.13" +name = "regex-automata" +version = "0.4.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62f25bc4c7e55e0b0b7a1d43fb893f4fa1361d0abe38b9ce4f323c2adfe6ef42" +checksum = "5276caf25ac86c8d810222b3dbb938e512c55c6831a10f3e6ed1c93b84041f1c" dependencies = [ - "bitflags", + "aho-corasick", + "memchr", + "regex-syntax", ] [[package]] -name = "ryu" -version = "1.0.9" +name = "regex-syntax" +version = "0.8.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73b4b750c782965c211b42f022f59af1fbceabdd026623714f104152f1ec149f" +checksum = "7a2d987857b319362043e95f5353c0535c1f58eec5336fdfcf626430af7def58" [[package]] name = "scopeguard" @@ -529,33 +474,65 @@ checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" [[package]] name = "serde" -version = "1.0.137" +version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61ea8d54c77f8315140a05f4c7237403bf38b72704d031543aa1d16abbf517d1" +checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" +dependencies = [ + "serde_core", + "serde_derive", +] + +[[package]] +name = "serde_core" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.137" +version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f26faba0c3959972377d3b2d306ee9f71faee9714294e41bb777f83f88578be" +checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.114", ] [[package]] name = "serde_json" -version = "1.0.81" +version = "1.0.149" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + +[[package]] +name = "serde_path_to_error" +version = "0.1.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b7ce2b32a1aed03c558dc61a5cd328f15aff2dbc17daad8fb8af04d2100e15c" +checksum = "10a9ff822e371bb5403e391ecd83e182e0e77ba7f6fe0160b795797109d1b457" dependencies = [ "itoa", - "ryu", "serde", + "serde_core", +] + +[[package]] +name = "sharded-slab" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" +dependencies = [ + "lazy_static", ] [[package]] @@ -569,24 +546,24 @@ dependencies = [ [[package]] name = "slab" -version = "0.4.6" +version = "0.4.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb703cfe953bccee95685111adeedb76fabe4e97549a58d16f03ea7b9367bb32" +checksum = "7a2ae44ef20feb57a68b23d846850f861394c2e02dc425a50098ae8c90267589" [[package]] name = "smallvec" -version = "1.8.0" +version = "1.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2dd574626839106c320a323308629dcb1acfc96e32a8cba364ddc61ac23ee83" +checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" [[package]] name = "socket2" -version = "0.4.4" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "66d72b759436ae32898a2af0a14218dbf55efde3feeb170eb623637db85ee1e0" +checksum = "17129e116933cf371d018bb80ae557e889637989d8638274fb25622827b03881" dependencies = [ "libc", - "winapi", + "windows-sys 0.60.2", ] [[package]] @@ -600,34 +577,58 @@ dependencies = [ "unicode-xid", ] +[[package]] +name = "syn" +version = "2.0.114" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4d107df263a3013ef9b1879b0df87d706ff80f65a86ea879bd9c31f9b307c2a" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "sync_wrapper" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bf256ce5efdfa370213c1dabab5935a12e49f2c58d15e9eac2870d3b4f27263" + +[[package]] +name = "thread_local" +version = "1.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f60246a4944f24f6e018aa17cdeffb7818b76356965d03b07d6a9886e8962185" +dependencies = [ + "cfg-if", +] + [[package]] name = "tokio" -version = "1.18.5" +version = "1.49.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e050c618355082ae5a89ec63bbf897225d5ffe84c7c4e036874e4d185a5044e" +checksum = "72a2903cd7736441aac9df9d7688bd0ce48edccaadf181c3b90be801e81d3d86" dependencies = [ "bytes", "libc", - "memchr", "mio", - "num_cpus", "parking_lot", "pin-project-lite", "signal-hook-registry", "socket2", "tokio-macros", - "winapi", + "windows-sys 0.61.2", ] [[package]] name = "tokio-macros" -version = "1.7.0" +version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b557f72f448c511a979e2564e55d74e6c4432fc96ff4f6241bc6bded342643b7" +checksum = "af407857209536a95c8e56f8231ef2c2e2aff839b22e07a1ffcbc617e9db9fa5" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.114", ] [[package]] @@ -641,59 +642,38 @@ dependencies = [ "tokio", ] -[[package]] -name = "tokio-util" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0edfdeb067411dba2044da6d1cb2df793dd35add7888d73c16e3381ded401764" -dependencies = [ - "bytes", - "futures-core", - "futures-sink", - "pin-project-lite", - "tokio", -] - [[package]] name = "tower" -version = "0.4.12" +version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a89fd63ad6adf737582df5db40d286574513c69a11dac5214dc3b5603d6713e" +checksum = "ebe5ef63511595f1344e2d5cfa636d973292adc0eec1f0ad45fae9f0851ab1d4" dependencies = [ "futures-core", "futures-util", - "hdrhistogram", - "indexmap", - "pin-project", "pin-project-lite", - "rand", - "slab", - "tokio", - "tokio-util", + "sync_wrapper", "tower-layer", "tower-service", - "tracing", ] [[package]] name = "tower-layer" -version = "0.3.1" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "343bc9466d3fe6b0f960ef45960509f84480bf4fd96f92901afe7ff3df9d3a62" +checksum = "121c2a6cda46980bb0fcd1647ffaf6cd3fc79a013de288782836f6df9c48780e" [[package]] name = "tower-service" -version = "0.3.1" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "360dfd1d6d30e05fda32ace2c8c70e9c0a9da713275777f5a4dbb8a1893930c6" +checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" [[package]] name = "tracing" -version = "0.1.34" +version = "0.1.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d0ecdcb44a79f0fe9844f0c4f33a342cbcbb5117de8001e6ba0dc2351327d09" +checksum = "63e71662fa4b2a2c3a26f570f037eb95bb1f85397f3cd8076caed2f026a6d100" dependencies = [ - "cfg-if", "log", "pin-project-lite", "tracing-attributes", @@ -702,79 +682,97 @@ dependencies = [ [[package]] name = "tracing-attributes" -version = "0.1.21" +version = "0.1.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc6b8ad3567499f98a1db7a752b07a7c8c7c7c34c332ec00effb2b0027974b7c" +checksum = "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.114", ] [[package]] name = "tracing-core" -version = "0.1.26" +version = "0.1.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f54c8ca710e81886d498c2fd3331b56c93aa248d49de2222ad2742247c60072f" +checksum = "db97caf9d906fbde555dd62fa95ddba9eecfd14cb388e4f491a66d74cd5fb79a" dependencies = [ - "lazy_static", + "once_cell", + "valuable", ] [[package]] -name = "try-lock" -version = "0.2.3" +name = "tracing-serde" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59547bce71d9c38b83d9c0e92b6066c4253371f15005def0c30d9657f50c7642" +checksum = "704b1aeb7be0d0a84fc9828cae51dab5970fee5088f83d1dd7ee6f6246fc6ff1" +dependencies = [ + "serde", + "tracing-core", +] [[package]] -name = "unicode-xid" -version = "0.2.3" +name = "tracing-subscriber" +version = "0.3.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f30143827ddab0d256fd843b7a66d164e9f271cfa0dde49142c5ca0ca291f1e" +dependencies = [ + "matchers", + "once_cell", + "regex-automata", + "serde", + "serde_json", + "sharded-slab", + "thread_local", + "tracing", + "tracing-core", + "tracing-serde", +] + +[[package]] +name = "try-lock" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "957e51f3646910546462e67d5f7599b9e4fb8acdd304b087a6494730f9eebf04" +checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" [[package]] -name = "want" -version = "0.3.0" +name = "unicode-ident" +version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ce8a968cb1cd110d136ff8b819a556d6fb6d919363c61534f6860c7eb172ba0" -dependencies = [ - "log", - "try-lock", -] +checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5" [[package]] -name = "wasi" -version = "0.10.2+wasi-snapshot-preview1" +name = "unicode-xid" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6" +checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" [[package]] -name = "wasi" -version = "0.11.0+wasi-snapshot-preview1" +name = "valuable" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" +checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65" [[package]] -name = "winapi" -version = "0.3.9" +name = "want" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" dependencies = [ - "winapi-i686-pc-windows-gnu", - "winapi-x86_64-pc-windows-gnu", + "try-lock", ] [[package]] -name = "winapi-i686-pc-windows-gnu" -version = "0.4.0" +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] -name = "winapi-x86_64-pc-windows-gnu" -version = "0.4.0" +name = "windows-link" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" [[package]] name = "windows-sys" @@ -791,33 +789,44 @@ dependencies = [ [[package]] name = "windows-sys" -version = "0.48.0" +version = "0.60.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb" dependencies = [ "windows-targets", ] +[[package]] +name = "windows-sys" +version = "0.61.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" +dependencies = [ + "windows-link", +] + [[package]] name = "windows-targets" -version = "0.48.5" +version = "0.53.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" +checksum = "4945f9f551b88e0d65f3db0bc25c33b8acea4d9e41163edf90dcd0b19f9069f3" dependencies = [ + "windows-link", "windows_aarch64_gnullvm", - "windows_aarch64_msvc 0.48.5", - "windows_i686_gnu 0.48.5", - "windows_i686_msvc 0.48.5", - "windows_x86_64_gnu 0.48.5", + "windows_aarch64_msvc 0.53.1", + "windows_i686_gnu 0.53.1", + "windows_i686_gnullvm", + "windows_i686_msvc 0.53.1", + "windows_x86_64_gnu 0.53.1", "windows_x86_64_gnullvm", - "windows_x86_64_msvc 0.48.5", + "windows_x86_64_msvc 0.53.1", ] [[package]] name = "windows_aarch64_gnullvm" -version = "0.48.5" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" +checksum = "a9d8416fa8b42f5c947f8482c43e7d89e73a173cead56d044f6a56104a6d1b53" [[package]] name = "windows_aarch64_msvc" @@ -827,9 +836,9 @@ checksum = "9bb8c3fd39ade2d67e9874ac4f3db21f0d710bee00fe7cab16949ec184eeaa47" [[package]] name = "windows_aarch64_msvc" -version = "0.48.5" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" +checksum = "b9d782e804c2f632e395708e99a94275910eb9100b2114651e04744e9b125006" [[package]] name = "windows_i686_gnu" @@ -839,9 +848,15 @@ checksum = "180e6ccf01daf4c426b846dfc66db1fc518f074baa793aa7d9b9aaeffad6a3b6" [[package]] name = "windows_i686_gnu" -version = "0.48.5" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "960e6da069d81e09becb0ca57a65220ddff016ff2d6af6a223cf372a506593a3" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" +checksum = "fa7359d10048f68ab8b09fa71c3daccfb0e9b559aed648a8f95469c27057180c" [[package]] name = "windows_i686_msvc" @@ -851,9 +866,9 @@ checksum = "e2e7917148b2812d1eeafaeb22a97e4813dfa60a3f8f78ebe204bcc88f12f024" [[package]] name = "windows_i686_msvc" -version = "0.48.5" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" +checksum = "1e7ac75179f18232fe9c285163565a57ef8d3c89254a30685b57d83a38d326c2" [[package]] name = "windows_x86_64_gnu" @@ -863,15 +878,15 @@ checksum = "4dcd171b8776c41b97521e5da127a2d86ad280114807d0b2ab1e462bc764d9e1" [[package]] name = "windows_x86_64_gnu" -version = "0.48.5" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" +checksum = "9c3842cdd74a865a8066ab39c8a7a473c0778a3f29370b5fd6b4b9aa7df4a499" [[package]] name = "windows_x86_64_gnullvm" -version = "0.48.5" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" +checksum = "0ffa179e2d07eee8ad8f57493436566c7cc30ac536a3379fdf008f47f6bb7ae1" [[package]] name = "windows_x86_64_msvc" @@ -881,6 +896,12 @@ checksum = "c811ca4a8c853ef420abd8592ba53ddbbac90410fab6903b3e79972a631f7680" [[package]] name = "windows_x86_64_msvc" -version = "0.48.5" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650" + +[[package]] +name = "zmij" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" +checksum = "bd8f3f50b848df28f887acb68e41201b5aea6bc8a8dacc00fb40635ff9a72fea" diff --git a/tests/aws/services/lambda_/functions/common/uncaughtexception/provided/src/Cargo.toml b/tests/aws/services/lambda_/functions/common/uncaughtexception/provided/src/Cargo.toml index f6df3fcf493cd..40e624f079fd1 100644 --- a/tests/aws/services/lambda_/functions/common/uncaughtexception/provided/src/Cargo.toml +++ b/tests/aws/services/lambda_/functions/common/uncaughtexception/provided/src/Cargo.toml @@ -6,6 +6,6 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -lambda_runtime = "0.5" +lambda_runtime = "1.0" serde_json = "1.0" -tokio = { version = "1.18", features = ["full"] } +tokio = { version = "1.49", features = ["full"] } diff --git a/tests/aws/services/lambda_/functions/common/uncaughtexception/python/Makefile b/tests/aws/services/lambda_/functions/common/uncaughtexception/python/Makefile index 4426ee52bf0ef..493fcad61fbea 100644 --- a/tests/aws/services/lambda_/functions/common/uncaughtexception/python/Makefile +++ b/tests/aws/services/lambda_/functions/common/uncaughtexception/python/Makefile @@ -4,6 +4,6 @@ build: cp -r ./src/* build/ clean: - $(RM) -r build handler.zip + $(RM) -rf build handler.zip .PHONY: build clean diff --git a/tests/aws/services/lambda_/functions/common/uncaughtexception_extra/provided/Makefile b/tests/aws/services/lambda_/functions/common/uncaughtexception_extra/provided/Makefile index bccba26238a6c..90fc86e61283c 100644 --- a/tests/aws/services/lambda_/functions/common/uncaughtexception_extra/provided/Makefile +++ b/tests/aws/services/lambda_/functions/common/uncaughtexception_extra/provided/Makefile @@ -21,6 +21,6 @@ build: docker run --rm --platform $(DOCKER_PLATFORM) -v $$(pwd)/src:/app -v $$(pwd)/build:/out $(DOCKER_GOLANG_IMAGE) /bin/bash -c "cd /app && GOOS=linux GOARCH=$(GOARCH) CGO_ENABLED=0 go build -trimpath -ldflags=-buildid= -o /out/bootstrap main.go && chown $$(id -u):$$(id -g) /out/bootstrap" clean: - $(RM) -r build handler.zip + $(RM) -rf build handler.zip .PHONY: build clean diff --git a/tests/aws/services/lambda_/functions/lambda_invocation_type_failure.py b/tests/aws/services/lambda_/functions/lambda_invocation_type_failure.py new file mode 100644 index 0000000000000..6240255127695 --- /dev/null +++ b/tests/aws/services/lambda_/functions/lambda_invocation_type_failure.py @@ -0,0 +1,14 @@ +import os +import time + +init_type = os.environ["AWS_LAMBDA_INITIALIZATION_TYPE"] + +if init_type == "provisioned-concurrency": + raise Exception("Intentional failure upon provisioned concurrency initialization") + + +def handler(event, context): + if event.get("wait"): + time.sleep(event["wait"]) + print(f"{init_type=}") + return init_type diff --git a/tests/aws/services/lambda_/functions/lambda_process_inspection.py b/tests/aws/services/lambda_/functions/lambda_process_inspection.py index 8aa03169bcc80..8302879daca7d 100644 --- a/tests/aws/services/lambda_/functions/lambda_process_inspection.py +++ b/tests/aws/services/lambda_/functions/lambda_process_inspection.py @@ -1,8 +1,13 @@ +import os + + def handler(event, context): - pid = event.get("pid") - with open(f"/proc/{pid}/environ", mode="rt") as f: - environment = f.read() - environment = environment.split("\x00") - env_partition = [env.partition("=") for env in environment if env] - env_dict = {env[0]: env[2] for env in env_partition} - return {"environment": env_dict} + return {"environment": dict(os.environ)} + # TODO: rework init env snapshotting test case because /proc/1 introspection does not work anymore at AWS + # pid = event.get("pid") + # with open(f"/proc/{pid}/environ", mode="rt") as f: + # environment = f.read() + # environment = environment.split("\x00") + # env_partition = [env.partition("=") for env in environment if env] + # env_dict = {env[0]: env[2] for env in env_partition} + # return {"environment": env_dict} diff --git a/tests/aws/services/lambda_/test_lambda.py b/tests/aws/services/lambda_/test_lambda.py index b4f4fa90c4f55..9d2a17fcd5784 100644 --- a/tests/aws/services/lambda_/test_lambda.py +++ b/tests/aws/services/lambda_/test_lambda.py @@ -12,7 +12,6 @@ import time from concurrent.futures import ThreadPoolExecutor from io import BytesIO -from typing import TypeVar import pytest import requests @@ -27,6 +26,7 @@ from localstack.services.lambda_.runtimes import RUNTIMES_AGGREGATED from localstack.testing.aws.lambda_utils import ( concurrency_update_done, + concurrency_update_failed, get_invoke_init_type, update_done, ) @@ -119,6 +119,9 @@ TEST_LAMBDA_INTROSPECT_PYTHON = os.path.join(THIS_FOLDER, "functions/lambda_introspect.py") TEST_LAMBDA_ULIMITS = os.path.join(THIS_FOLDER, "functions/lambda_ulimits.py") TEST_LAMBDA_INVOCATION_TYPE = os.path.join(THIS_FOLDER, "functions/lambda_invocation_type.py") +TEST_LAMBDA_INVOCATION_TYPE_FAILURE = os.path.join( + THIS_FOLDER, "functions/lambda_invocation_type_failure.py" +) TEST_LAMBDA_VERSION = os.path.join(THIS_FOLDER, "functions/lambda_version.py") TEST_LAMBDA_CONTEXT_REQID = os.path.join(THIS_FOLDER, "functions/lambda_context.py") TEST_LAMBDA_PROCESS_INSPECTION = os.path.join(THIS_FOLDER, "functions/lambda_process_inspection.py") @@ -147,10 +150,8 @@ "dns", ] -T = TypeVar("T") - -def read_streams(payload: T) -> T: +def read_streams[T](payload: T) -> T: new_payload = {} for k, v in payload.items(): if isinstance(v, dict): @@ -264,6 +265,7 @@ def _check_print_in_logs(): retry(_check_print_in_logs, retries=10) + @markers.requires_in_process @markers.aws.only_localstack def test_lambda_too_large_response_but_with_custom_limit( self, caplog, create_lambda_function, aws_client, monkeypatch @@ -452,6 +454,11 @@ class TestLambdaBehavior: "$..Payload.paths._var_task_gid", "$..Payload.paths._var_task_owner", "$..Payload.paths._var_task_uid", + # TODO fix runtime environment + "$..Payload.paths._tmp_gid", + "$..Payload.paths._tmp_mode", + "$..Payload.paths._tmp_owner", + "$..Payload.paths._tmp_uid", ], ) @markers.aws.validated @@ -476,6 +483,10 @@ def test_runtime_introspection_x86(self, create_lambda_function, snapshot, aws_c "$..Payload.paths._var_task_gid", "$..Payload.paths._var_task_owner", "$..Payload.paths._var_task_uid", + "$..Payload.paths._tmp_gid", + "$..Payload.paths._tmp_mode", + "$..Payload.paths._tmp_owner", + "$..Payload.paths._tmp_uid", ], ) @markers.aws.validated @@ -502,7 +513,7 @@ def test_runtime_ulimits(self, create_lambda_function, snapshot, monkeypatch, aw monkeypatch.setattr( config, "LAMBDA_DOCKER_FLAGS", - "--ulimit nofile=1024:1024 --ulimit nproc=742:742 --ulimit core=-1:-1 --ulimit stack=8388608:-1 --ulimit memlock=65536:65536", + "--ulimit nofile=1024:1024 --ulimit nproc=742:742 --ulimit core=10737418240 --ulimit stack=8388608:-1 --ulimit memlock=65536:65536", ) func_name = f"test_lambda_ulimits_{short_uid()}" @@ -611,9 +622,18 @@ def test_lambda_cache_local( snapshot.match("second_invoke_result", second_invoke_result) @markers.aws.validated + @markers.snapshot.skip_snapshot_verify( + paths=[ + # TODO the current error is Sandbox.Timedout. This is likely to change when the feature goes live? + "$..Payload.errorType", + "$..Payload.errorMessage", + ] + ) def test_lambda_invoke_with_timeout(self, create_lambda_function, snapshot, aws_client): # Snapshot generation could be flaky against AWS with a small timeout margin (e.g., 1.02 instead of 1.00) - regex = re.compile(r".*\s(?P[-a-z0-9]+) Task timed out after \d.\d+ seconds") + regex = re.compile( + r".*\s(?P[-a-z0-9]+)( Error:)? Task timed out after \d.\d+ seconds" + ) snapshot.add_transformer( KeyValueBasedTransformer( lambda k, v: regex.search(v).group("uuid") if k == "errorMessage" else None, @@ -774,38 +794,14 @@ def assert_events(): @markers.aws.validated @markers.snapshot.skip_snapshot_verify( paths=[ - # not set directly on init in lambda, but only on runtime processes - "$..Payload.environment.AWS_ACCESS_KEY_ID", - "$..Payload.environment.AWS_SECRET_ACCESS_KEY", - "$..Payload.environment.AWS_SESSION_TOKEN", - "$..Payload.environment.AWS_XRAY_DAEMON_ADDRESS", - # variables set by default in the image/docker - "$..Payload.environment.HOME", - "$..Payload.environment.HOSTNAME", - # LocalStack specific variables + "$..Payload.environment.AWS_CONTAINER_AUTHORIZATION_TOKEN", + "$..Payload.environment.AWS_CONTAINER_CREDENTIALS_FULL_URI", "$..Payload.environment.AWS_ENDPOINT_URL", "$..Payload.environment.AWS_LAMBDA_FUNCTION_TIMEOUT", "$..Payload.environment.EDGE_PORT", - "$..Payload.environment.LOCALSTACK_FUNCTION_ACCOUNT_ID", "$..Payload.environment.LOCALSTACK_HOSTNAME", - "$..Payload.environment.LOCALSTACK_INIT_LOG_LEVEL", - "$..Payload.environment.LOCALSTACK_RUNTIME_ENDPOINT", - "$..Payload.environment.LOCALSTACK_RUNTIME_ID", - "$..Payload.environment.LOCALSTACK_USER", - "$..Payload.environment.LOCALSTACK_POST_INVOKE_WAIT_MS", - "$..Payload.environment.LOCALSTACK_MAX_PAYLOAD_SIZE", - "$..Payload.environment.LOCALSTACK_CHMOD_PATHS", - # internal AWS lambda functionality - "$..Payload.environment._AWS_XRAY_DAEMON_ADDRESS", - "$..Payload.environment._LAMBDA_CONSOLE_SOCKET", - "$..Payload.environment._LAMBDA_CONTROL_SOCKET", - "$..Payload.environment._LAMBDA_DIRECT_INVOKE_SOCKET", - "$..Payload.environment._LAMBDA_LOG_FD", - "$..Payload.environment._LAMBDA_RUNTIME_LOAD_TIME", - "$..Payload.environment._LAMBDA_SB_ID", - "$..Payload.environment._LAMBDA_SHARED_MEM_FD", - "$..Payload.environment._LAMBDA_TELEMETRY_API_PASSPHRASE", - "$..Payload.environment._X_AMZN_TRACE_ID", + # Missing in Python Lambda images (3.12, 3.13, 3.14) since around 2026-02-18 + "$..Payload.environment.LC_CTYPE", ] ) @markers.requires_in_process @@ -825,12 +821,17 @@ def test_lambda_init_environment( snapshot.transform.key_value("AWS_LAMBDA_LOG_STREAM_NAME", "log-stream-name"), snapshot.transform.key_value("_X_AMZN_TRACE_ID", "xray-trace-id"), snapshot.transform.key_value("_LAMBDA_RUNTIME_LOAD_TIME", "runtime-load-time"), + snapshot.transform.key_value("AWS_SECRET_ACCESS_KEY", "aws-secret-access-key"), + snapshot.transform.key_value("AWS_ACCESS_KEY_ID", "aws-access-key-id"), + snapshot.transform.key_value("AWS_SESSION_TOKEN", "aws-session-token"), + snapshot.transform.key_value("_AWS_XRAY_DAEMON_ADDRESS", "xray-daemon-address"), ] ) create_result = create_lambda_function( func_name=func_name, + # TODO: rework init env snapshotting test case because /proc/1 introspection does not work anymore at AWS handler_file=TEST_LAMBDA_PROCESS_INSPECTION, - runtime=Runtime.python3_12, + runtime=Runtime.python3_14, client=aws_client.lambda_, ) snapshot.match("create-result", create_result) @@ -1276,6 +1277,8 @@ def test_lambda_url_invocation_exception(self, create_lambda_function, snapshot, assert result.status_code == 502 @markers.aws.validated + # TODO Add error message + @markers.snapshot.skip_snapshot_verify(paths=["$..content.Message"]) def test_lambda_url_persists_after_alias_delete( self, create_lambda_function, snapshot, aws_client ): @@ -1406,6 +1409,8 @@ def test_lambda_url_non_existing_url(self): "$..headers.x-forwarded-for", "$..headers.x-amzn-trace-id", "$..origin", # TODO: LS Lambda should populate this value for AWS parity + # The value of Accept-Encoding can change when the zstandard package is present + "$..headers.accept-encoding", ] ) @markers.aws.validated @@ -1439,6 +1444,8 @@ def test_lambda_url_echo_http_fixture_default( @markers.snapshot.skip_snapshot_verify( paths=[ "$..content.headers.domain", # TODO: LS Lambda should populate this value for AWS parity + # The value of Accept-Encoding can change when the zstandard package is present + "$..headers.accept-encoding", "$..origin", # TODO: LS Lambda should populate this value for AWS parity ] ) @@ -1464,6 +1471,8 @@ def test_lambda_url_echo_http_fixture_trim_x_headers( @markers.snapshot.skip_snapshot_verify( paths=[ "$..origin", # FIXME: LS does not populate the value + # The value of Accept-Encoding can change when the zstandard package is present + "$..headers.accept-encoding", ] ) def test_lambda_url_form_payload(self, create_echo_http_server, snapshot, aws_client): @@ -1970,6 +1979,7 @@ def test_lambda_runtime_wrapper_not_found(self, aws_client, create_lambda_functi ) snapshot.match("invocation_error", result) + @markers.requires_in_process @markers.aws.only_localstack( reason="Can only induce Lambda-internal Docker error in LocalStack" ) @@ -1999,6 +2009,7 @@ def test_lambda_runtime_startup_timeout( r"retries: \d\): \[[^]]*\] Timeout while starting up lambda environment .*" ) + @markers.requires_in_process @markers.aws.only_localstack( reason="Can only induce Lambda-internal Docker error in LocalStack" ) @@ -2636,6 +2647,74 @@ def test_provisioned_concurrency(self, create_lambda_function, snapshot, aws_cli result2 = json.load(invoke_result2["Payload"]) assert result2 == "on-demand" + @markers.aws.validated + def test_provisioned_concurrency_init_failure( + self, create_lambda_function, snapshot, aws_client + ): + """Put provisioned concurrency on a Lambda function that fails upon initialization. + The intended failure only triggers for initialization of provisioned concurrency. + """ + min_concurrent_executions = 10 + 1 + check_concurrency_quota(aws_client, min_concurrent_executions) + + func_name = f"test_lambda_{short_uid()}" + create_function_response = create_lambda_function( + func_name=func_name, + runtime=Runtime.python3_12, + handler_file=TEST_LAMBDA_INVOCATION_TYPE_FAILURE, + # Provisioned concurrency requires publishing + Publish=True, + ) + version = create_function_response["CreateFunctionResponse"]["Version"] + + put_provisioned = aws_client.lambda_.put_provisioned_concurrency_config( + FunctionName=func_name, Qualifier=version, ProvisionedConcurrentExecutions=1 + ) + snapshot.match("put_provisioned", put_provisioned) + + get_provisioned_prewait = aws_client.lambda_.get_provisioned_concurrency_config( + FunctionName=func_name, Qualifier=version + ) + snapshot.match("get_provisioned_prewait", get_provisioned_prewait) + + # Invokes should be served on-demand during provisioned concurrency initialization + assert get_invoke_init_type(aws_client.lambda_, func_name, version) == "on-demand" + + # AWS attempts initialization a total of 6 times according to CloudWatch logs + wait_time = 10 if is_aws_cloud() else 1 + assert wait_until( + concurrency_update_failed(aws_client.lambda_, func_name, version), + wait=wait_time, + max_retries=80, + ) + + get_provisioned_postwait = aws_client.lambda_.get_provisioned_concurrency_config( + FunctionName=func_name, Qualifier=version + ) + snapshot.match("get_provisioned_postwait", get_provisioned_postwait) + + log_group_name = f"/aws/lambda/{func_name}" + + def _log_stream_available(): + result = aws_client.logs.describe_log_streams(logGroupName=log_group_name)["logStreams"] + # We are expecting 7 log streams: total 6 provisioned init attempts + 1 on-demand + # TODO: assert and implement 6 total initialization attempts in LS (LS only attempts once) + num_expected_log_streams = 7 if is_aws_cloud() else 2 + return len(result) >= num_expected_log_streams + + wait_until(_log_stream_available, strategy="linear") + + logs = aws_client.logs.filter_log_events(logGroupName=log_group_name) + expected_error_msg = ( + "[ERROR] Exception: Intentional failure upon provisioned concurrency initialization" + ) + # TODO: implement and enable this validation in LS + if is_aws_cloud(): + assert any(expected_error_msg in e["message"] for e in logs["events"]) + + # Invokes should not be scheduled to failed provisioned concurrency + assert get_invoke_init_type(aws_client.lambda_, func_name, version) == "on-demand" + @markers.aws.validated def test_provisioned_concurrency_on_alias(self, create_lambda_function, snapshot, aws_client): """ @@ -2894,6 +2973,7 @@ def test_reserved_concurrency( snapshot.add_transformer( snapshot.transform.key_value("SenderId", "", reference_replacement=False) ) + snapshot.add_transformer(snapshot.transform.key_value("AWSTraceHeader")) func_name = f"test_lambda_{short_uid()}" create_lambda_function( @@ -3363,10 +3443,16 @@ def test_lambda_alias_moving( FunctionVersion=second_publish_response["Version"], ) snapshot.match("update_alias_response", update_alias_response) + # check if alias moved to 2 - invocation_result_qualifier_v2 = aws_client.lambda_.invoke( - FunctionName=function_name, Qualifier=create_alias_response["Name"], Payload=b"{}" - ) + def _invoke_qualifier_v2(): + result = aws_client.lambda_.invoke( + FunctionName=function_name, Qualifier=create_alias_response["Name"], Payload=b"{}" + ) + assert result["ExecutedVersion"] == "2" + return result + + invocation_result_qualifier_v2 = retry(_invoke_qualifier_v2) snapshot.match("invocation_result_qualifier_v2", invocation_result_qualifier_v2) with pytest.raises(aws_client.lambda_.exceptions.ResourceNotFoundException) as e: aws_client.lambda_.invoke( diff --git a/tests/aws/services/lambda_/test_lambda.snapshot.json b/tests/aws/services/lambda_/test_lambda.snapshot.json index 7bfb46a72e5b8..643df3f381722 100644 --- a/tests/aws/services/lambda_/test_lambda.snapshot.json +++ b/tests/aws/services/lambda_/test_lambda.snapshot.json @@ -152,7 +152,7 @@ } }, "tests/aws/services/lambda_/test_lambda.py::TestLambdaBehavior::test_lambda_cache_local[nodejs]": { - "recorded-date": "08-04-2024, 16:55:57", + "recorded-date": "24-11-2025, 23:08:41", "recorded-content": { "first_invoke_result": { "ExecutedVersion": "$LATEST", @@ -179,7 +179,7 @@ } }, "tests/aws/services/lambda_/test_lambda.py::TestLambdaBehavior::test_lambda_cache_local[python]": { - "recorded-date": "08-04-2024, 16:56:00", + "recorded-date": "24-11-2025, 23:08:44", "recorded-content": { "first_invoke_result": { "ExecutedVersion": "$LATEST", @@ -206,7 +206,7 @@ } }, "tests/aws/services/lambda_/test_lambda.py::TestLambdaBehavior::test_lambda_invoke_with_timeout": { - "recorded-date": "08-04-2024, 16:56:05", + "recorded-date": "25-11-2025, 00:39:45", "recorded-content": { "create-result": { "CreateEventSourceMappingResponse": null, @@ -261,7 +261,8 @@ "ExecutedVersion": "$LATEST", "FunctionError": "Unhandled", "Payload": { - "errorMessage": "date Task timed out after 1.00 seconds" + "errorType": "Sandbox.Timedout", + "errorMessage": "RequestId: Error: Task timed out after 1.00 seconds" }, "StatusCode": 200, "ResponseMetadata": { @@ -272,7 +273,7 @@ } }, "tests/aws/services/lambda_/test_lambda.py::TestLambdaBehavior::test_lambda_invoke_no_timeout": { - "recorded-date": "08-04-2024, 16:56:14", + "recorded-date": "24-11-2025, 23:08:55", "recorded-content": { "create-result": { "CreateEventSourceMappingResponse": null, @@ -335,7 +336,7 @@ } }, "tests/aws/services/lambda_/test_lambda.py::TestLambdaBaseFeatures::test_function_state": { - "recorded-date": "08-04-2024, 16:55:21", + "recorded-date": "24-11-2025, 23:08:11", "recorded-content": { "create-fn-response": { "Architectures": [ @@ -431,7 +432,7 @@ } }, "tests/aws/services/lambda_/test_lambda.py::TestLambdaFeatures::test_invocation_with_logs[python3.10]": { - "recorded-date": "08-04-2024, 16:57:44", + "recorded-date": "24-11-2025, 23:11:20", "recorded-content": { "invoke": { "ExecutedVersion": "$LATEST", @@ -454,7 +455,7 @@ } }, "tests/aws/services/lambda_/test_lambda.py::TestLambdaFeatures::test_invocation_with_logs[nodejs16.x]": { - "recorded-date": "08-04-2024, 16:57:41", + "recorded-date": "24-11-2025, 23:11:18", "recorded-content": { "invoke": { "ExecutedVersion": "$LATEST", @@ -491,7 +492,7 @@ } }, "tests/aws/services/lambda_/test_lambda.py::TestLambdaFeatures::test_invocation_type_request_response[python3.10]": { - "recorded-date": "08-04-2024, 16:57:51", + "recorded-date": "24-11-2025, 23:11:26", "recorded-content": { "invoke-result": { "ExecutedVersion": "$LATEST", @@ -505,7 +506,7 @@ } }, "tests/aws/services/lambda_/test_lambda.py::TestLambdaFeatures::test_invocation_type_request_response[nodejs16.x]": { - "recorded-date": "08-04-2024, 16:57:48", + "recorded-date": "24-11-2025, 23:11:23", "recorded-content": { "invoke-result": { "ExecutedVersion": "$LATEST", @@ -532,7 +533,7 @@ } }, "tests/aws/services/lambda_/test_lambda.py::TestLambdaFeatures::test_invocation_type_event[python3.10]": { - "recorded-date": "08-04-2024, 16:58:09", + "recorded-date": "24-11-2025, 23:11:39", "recorded-content": { "invoke-result": { "Payload": "", @@ -545,7 +546,7 @@ } }, "tests/aws/services/lambda_/test_lambda.py::TestLambdaFeatures::test_invocation_type_event[nodejs16.x]": { - "recorded-date": "08-04-2024, 16:57:59", + "recorded-date": "24-11-2025, 23:11:31", "recorded-content": { "invoke-result": { "Payload": "", @@ -689,7 +690,7 @@ } }, "tests/aws/services/lambda_/test_lambda.py::TestLambdaFeatures::test_invocation_with_qualifier": { - "recorded-date": "08-04-2024, 16:58:22", + "recorded-date": "24-11-2025, 23:12:27", "recorded-content": { "creation-response": { "Architectures": [ @@ -769,7 +770,7 @@ } }, "tests/aws/services/lambda_/test_lambda.py::TestLambdaFeatures::test_upload_lambda_from_s3": { - "recorded-date": "08-04-2024, 16:58:27", + "recorded-date": "24-11-2025, 23:12:31", "recorded-content": { "creation-response": { "Architectures": [ @@ -917,7 +918,7 @@ } }, "tests/aws/services/lambda_/test_lambda.py::TestLambdaConcurrency::test_lambda_concurrency_block": { - "recorded-date": "08-04-2024, 17:02:07", + "recorded-date": "24-11-2025, 23:16:40", "recorded-content": { "v1_result": { "Architectures": [ @@ -1033,7 +1034,7 @@ } }, "tests/aws/services/lambda_/test_lambda.py::TestLambdaVersions::test_lambda_versions_with_code_changes": { - "recorded-date": "08-04-2024, 17:10:52", + "recorded-date": "24-11-2025, 23:26:21", "recorded-content": { "create_response": { "Architectures": [ @@ -1343,7 +1344,7 @@ } }, "tests/aws/services/lambda_/test_lambda.py::TestLambdaAliases::test_lambda_alias_moving": { - "recorded-date": "08-04-2024, 17:11:05", + "recorded-date": "25-11-2025, 23:37:28", "recorded-content": { "create_response": { "Architectures": [ @@ -1576,7 +1577,7 @@ } }, "tests/aws/services/lambda_/test_lambda.py::TestLambdaAliases::test_alias_routingconfig": { - "recorded-date": "08-04-2024, 17:11:17", + "recorded-date": "24-11-2025, 23:27:57", "recorded-content": { "create_alias_response": { "AliasArn": "arn::lambda::111111111111:function:", @@ -1597,7 +1598,7 @@ } }, "tests/aws/services/lambda_/test_lambda.py::TestLambdaBaseFeatures::test_lambda_different_iam_keys_environment": { - "recorded-date": "08-04-2024, 16:55:38", + "recorded-date": "24-11-2025, 23:08:26", "recorded-content": { "create-result": { "CreateEventSourceMappingResponse": null, @@ -2278,7 +2279,7 @@ } }, "tests/aws/services/lambda_/test_lambda.py::TestLambdaURL::test_lambda_url_invocation_exception": { - "recorded-date": "08-04-2024, 16:57:23", + "recorded-date": "24-11-2025, 23:09:56", "recorded-content": { "get_fn_result": { "Code": { @@ -2362,7 +2363,7 @@ } }, "tests/aws/services/lambda_/test_lambda.py::TestLambdaConcurrency::test_lambda_concurrency_crud": { - "recorded-date": "22-05-2025, 08:04:13", + "recorded-date": "24-11-2025, 23:14:18", "recorded-content": { "get_function_concurrency_default": { "ResponseMetadata": { @@ -2393,15 +2394,15 @@ } }, "tests/aws/services/lambda_/test_lambda.py::TestLambdaPermissions::test_lambda_permission_url_invocation": { - "recorded-date": "08-04-2024, 16:57:38", + "recorded-date": "24-11-2025, 23:11:15", "recorded-content": { "lambda_url_invocation_missing_permission": { - "Message": "Forbidden" + "Message": "Forbidden. For troubleshooting Function URL authorization issues, see: https://docs.aws.amazon.com/lambda/latest/dg/urls-auth.html" } } }, "tests/aws/services/lambda_/test_lambda.py::TestLambdaURL::test_lambda_url_invocation[dict]": { - "recorded-date": "08-04-2024, 16:56:29", + "recorded-date": "24-11-2025, 23:09:04", "recorded-content": { "create_lambda_url_config": { "AuthType": "NONE", @@ -2444,7 +2445,7 @@ } }, "tests/aws/services/lambda_/test_lambda.py::TestLambdaURL::test_lambda_url_invocation[http-response]": { - "recorded-date": "08-04-2024, 16:56:33", + "recorded-date": "24-11-2025, 23:09:07", "recorded-content": { "create_lambda_url_config": { "AuthType": "NONE", @@ -2485,7 +2486,7 @@ } }, "tests/aws/services/lambda_/test_lambda.py::TestLambdaURL::test_lambda_url_invocation[http-response-json]": { - "recorded-date": "08-04-2024, 16:56:37", + "recorded-date": "24-11-2025, 23:09:11", "recorded-content": { "create_lambda_url_config": { "AuthType": "NONE", @@ -2528,7 +2529,7 @@ } }, "tests/aws/services/lambda_/test_lambda.py::TestLambdaURL::test_lambda_url_invocation[list-mixed]": { - "recorded-date": "08-04-2024, 16:56:41", + "recorded-date": "24-11-2025, 23:09:13", "recorded-content": { "create_lambda_url_config": { "AuthType": "NONE", @@ -2569,7 +2570,7 @@ } }, "tests/aws/services/lambda_/test_lambda.py::TestLambdaURL::test_lambda_url_invocation[string]": { - "recorded-date": "08-04-2024, 16:56:45", + "recorded-date": "24-11-2025, 23:09:17", "recorded-content": { "create_lambda_url_config": { "AuthType": "NONE", @@ -2610,7 +2611,7 @@ } }, "tests/aws/services/lambda_/test_lambda.py::TestLambdaURL::test_lambda_url_invocation[integer]": { - "recorded-date": "08-04-2024, 16:56:49", + "recorded-date": "24-11-2025, 23:09:20", "recorded-content": { "create_lambda_url_config": { "AuthType": "NONE", @@ -2651,7 +2652,7 @@ } }, "tests/aws/services/lambda_/test_lambda.py::TestLambdaURL::test_lambda_url_invocation[float]": { - "recorded-date": "08-04-2024, 16:56:53", + "recorded-date": "24-11-2025, 23:09:23", "recorded-content": { "create_lambda_url_config": { "AuthType": "NONE", @@ -2692,7 +2693,7 @@ } }, "tests/aws/services/lambda_/test_lambda.py::TestLambdaURL::test_lambda_url_invocation[boolean]": { - "recorded-date": "08-04-2024, 16:56:57", + "recorded-date": "24-11-2025, 23:09:26", "recorded-content": { "create_lambda_url_config": { "AuthType": "NONE", @@ -2733,7 +2734,7 @@ } }, "tests/aws/services/lambda_/test_lambda.py::TestLambdaBehavior::test_runtime_introspection_arm": { - "recorded-date": "08-04-2024, 16:55:44", + "recorded-date": "24-11-2025, 23:08:31", "recorded-content": { "invoke_runtime_arm_introspection": { "ExecutedVersion": "$LATEST", @@ -2746,17 +2747,17 @@ "pwd": "/var/task", "paths": { "_var_task_mode": "drwxr-xr-x", - "_var_task_uid": 998, - "_var_task_owner": "slicer", - "_var_task_gid": 995, + "_var_task_uid": 0, + "_var_task_owner": "root", + "_var_task_gid": 0, "_opt_mode": "drwxr-xr-x", "_opt_uid": 0, "_opt_owner": "root", "_opt_gid": 0, - "_tmp_mode": "drwx------", - "_tmp_uid": 993, - "_tmp_owner": "sbx_user1051", - "_tmp_gid": 990, + "_tmp_mode": "drwxrwxrwt", + "_tmp_uid": 0, + "_tmp_owner": "root", + "_tmp_gid": 0, "_lambda-entrypoint.sh_mode": "-rwxr-xr-x", "_lambda-entrypoint.sh_uid": 0, "_lambda-entrypoint.sh_owner": "root", @@ -2772,7 +2773,7 @@ } }, "tests/aws/services/lambda_/test_lambda.py::TestLambdaBehavior::test_runtime_introspection_x86": { - "recorded-date": "08-04-2024, 16:55:41", + "recorded-date": "24-11-2025, 23:08:29", "recorded-content": { "invoke_runtime_x86_introspection": { "ExecutedVersion": "$LATEST", @@ -2785,17 +2786,17 @@ "pwd": "/var/task", "paths": { "_var_task_mode": "drwxr-xr-x", - "_var_task_uid": 998, - "_var_task_owner": "slicer", - "_var_task_gid": 995, + "_var_task_uid": 0, + "_var_task_owner": "root", + "_var_task_gid": 0, "_opt_mode": "drwxr-xr-x", "_opt_uid": 0, "_opt_owner": "root", "_opt_gid": 0, - "_tmp_mode": "drwx------", - "_tmp_uid": 993, - "_tmp_owner": "sbx_user1051", - "_tmp_gid": 990, + "_tmp_mode": "drwxrwxrwt", + "_tmp_uid": 0, + "_tmp_owner": "root", + "_tmp_gid": 0, "_lambda-entrypoint.sh_mode": "-rwxr-xr-x", "_lambda-entrypoint.sh_uid": 0, "_lambda-entrypoint.sh_owner": "root", @@ -2811,7 +2812,7 @@ } }, "tests/aws/services/lambda_/test_lambda.py::TestLambdaBehavior::test_runtime_ulimits": { - "recorded-date": "16-04-2024, 08:12:12", + "recorded-date": "24-11-2025, 23:08:34", "recorded-content": { "invoke_runtime_ulimits": { "ExecutedVersion": "$LATEST", @@ -2821,8 +2822,8 @@ -1 ], "RLIMIT_CORE": [ - -1, - -1 + 10737418240, + 10737418240 ], "RLIMIT_CPU": [ -1, @@ -2866,7 +2867,7 @@ } }, "tests/aws/services/lambda_/test_lambda.py::TestLambdaConcurrency::test_reserved_concurrency": { - "recorded-date": "08-04-2024, 17:08:11", + "recorded-date": "25-11-2025, 11:20:35", "recorded-content": { "fn": { "Architectures": [ @@ -2958,7 +2959,7 @@ }, "msg": { "Attributes": { - "AWSTraceHeader": "Root=1-6614247a-4513533344453f9a2d077845;Parent=282ed520d6ca75c8;Sampled=0", + "AWSTraceHeader": "", "ApproximateFirstReceiveTimestamp": "timestamp", "ApproximateReceiveCount": "1", "SenderId": "", @@ -2982,7 +2983,7 @@ } }, "tests/aws/services/lambda_/test_lambda.py::TestLambdaConcurrency::test_reserved_concurrency_async_queue": { - "recorded-date": "26-03-2025, 10:53:54", + "recorded-date": "24-11-2025, 23:23:27", "recorded-content": { "fn": { "Architectures": [ @@ -3052,7 +3053,7 @@ } }, "tests/aws/services/lambda_/test_lambda.py::TestLambdaConcurrency::test_provisioned_concurrency": { - "recorded-date": "08-04-2024, 17:04:21", + "recorded-date": "24-11-2025, 23:18:51", "recorded-content": { "put_provisioned_5": { "AllocatedProvisionedConcurrentExecutions": 0, @@ -3090,7 +3091,7 @@ } }, "tests/aws/services/lambda_/test_lambda.py::TestLambdaConcurrency::test_reserved_provisioned_overlap": { - "recorded-date": "08-04-2024, 17:10:37", + "recorded-date": "24-11-2025, 23:26:07", "recorded-content": { "put_provisioned_5": { "AllocatedProvisionedConcurrentExecutions": 0, @@ -3230,11 +3231,11 @@ } }, "tests/aws/services/lambda_/test_lambda.py::TestRequestIdHandling::test_request_id_format": { - "recorded-date": "08-04-2024, 17:11:17", + "recorded-date": "24-11-2025, 23:27:57", "recorded-content": {} }, "tests/aws/services/lambda_/test_lambda.py::TestRequestIdHandling::test_request_id_invoke": { - "recorded-date": "08-04-2024, 17:11:26", + "recorded-date": "24-11-2025, 23:28:05", "recorded-content": { "invoke_result": { "ExecutedVersion": "$LATEST", @@ -3256,7 +3257,7 @@ } }, "tests/aws/services/lambda_/test_lambda.py::TestRequestIdHandling::test_request_id_async_invoke_with_retry": { - "recorded-date": "08-04-2024, 17:13:39", + "recorded-date": "24-11-2025, 23:30:18", "recorded-content": { "invoke_result": { "Payload": "", @@ -3273,7 +3274,7 @@ } }, "tests/aws/services/lambda_/test_lambda.py::TestRequestIdHandling::test_request_id_invoke_url": { - "recorded-date": "08-04-2024, 17:11:35", + "recorded-date": "24-11-2025, 23:28:15", "recorded-content": { "create_lambda_url_config": { "AuthType": "NONE", @@ -3333,7 +3334,7 @@ } }, "tests/aws/services/lambda_/test_lambda.py::TestLambdaErrors::test_lambda_runtime_error": { - "recorded-date": "24-02-2025, 16:26:37", + "recorded-date": "24-11-2025, 23:12:34", "recorded-content": { "invocation_error": { "ExecutedVersion": "$LATEST", @@ -3348,7 +3349,7 @@ " File \"\", line 1360, in _find_and_load\n", " File \"\", line 1331, in _find_and_load_unlocked\n", " File \"\", line 935, in _load_unlocked\n", - " File \"\", line 1022, in exec_module\n", + " File \"\", line 1027, in exec_module\n", " File \"\", line 488, in _call_with_frames_removed\n", " File \"/var/task/lambda_runtime_error.py\", line 1, in \n raise Exception(\"Runtime startup fails\")\n" ] @@ -3362,14 +3363,14 @@ } }, "tests/aws/services/lambda_/test_lambda.py::TestLambdaFeatures::test_invoke_exceptions": { - "recorded-date": "08-04-2024, 16:57:45", + "recorded-date": "24-11-2025, 23:11:21", "recorded-content": { "invoke_function_doesnotexist": { "Error": { "Code": "ResourceNotFoundException", - "Message": "Function not found: arn::lambda::111111111111:function:doesnotexist" + "Message": "Function not found: arn::lambda::111111111111:function:doesnotexist:$LATEST" }, - "Message": "Function not found: arn::lambda::111111111111:function:doesnotexist", + "Message": "Function not found: arn::lambda::111111111111:function:doesnotexist:$LATEST", "Type": "User", "ResponseMetadata": { "HTTPHeaders": {}, @@ -3379,7 +3380,7 @@ } }, "tests/aws/services/lambda_/test_lambda.py::TestLambdaErrors::test_lambda_runtime_wrapper_not_found": { - "recorded-date": "08-04-2024, 16:59:29", + "recorded-date": "24-11-2025, 23:13:27", "recorded-content": { "invocation_error": { "ExecutedVersion": "$LATEST", @@ -3397,7 +3398,7 @@ } }, "tests/aws/services/lambda_/test_lambda.py::TestLambdaErrors::test_lambda_runtime_exit": { - "recorded-date": "08-04-2024, 16:58:35", + "recorded-date": "24-11-2025, 23:12:36", "recorded-content": { "invocation_error": { "ExecutedVersion": "$LATEST", @@ -3415,7 +3416,7 @@ } }, "tests/aws/services/lambda_/test_lambda.py::TestLambdaErrors::test_lambda_handler_exit": { - "recorded-date": "08-04-2024, 16:59:26", + "recorded-date": "24-11-2025, 23:13:24", "recorded-content": { "invocation_error": { "ExecutedVersion": "$LATEST", @@ -3433,7 +3434,7 @@ } }, "tests/aws/services/lambda_/test_lambda.py::TestLambdaErrors::test_lambda_handler_error": { - "recorded-date": "08-04-2024, 16:59:23", + "recorded-date": "24-11-2025, 23:13:22", "recorded-content": { "invocation_error": { "ExecutedVersion": "$LATEST", @@ -3455,13 +3456,14 @@ } }, "tests/aws/services/lambda_/test_lambda.py::TestLambdaErrors::test_lambda_runtime_exit_segfault": { - "recorded-date": "08-04-2024, 16:59:20", + "recorded-date": "24-11-2025, 23:13:19", "recorded-content": { "invocation_error": { "ExecutedVersion": "$LATEST", "FunctionError": "Unhandled", "Payload": { - "errorMessage": "date Task timed out after 30.13 seconds" + "errorType": "Sandbox.Timedout", + "errorMessage": "RequestId: Error: Task timed out after 30.00 seconds" }, "StatusCode": 200, "ResponseMetadata": { @@ -3472,15 +3474,15 @@ } }, "tests/aws/services/lambda_/test_lambda.py::TestLambdaErrors::test_lambda_invoke_payload_encoding_error[body-n\\x87r\\x9e\\xe9\\xb5\\xd7I\\xee\\x9bmt]": { - "recorded-date": "08-04-2024, 16:59:32", + "recorded-date": "24-11-2025, 23:13:29", "recorded-content": { "invoke_function_invalid_payload_body": { "Error": { "Code": "InvalidRequestContentException", - "Message": "Could not parse request body into json: Could not parse payload into json: Invalid UTF-8 start byte 0x87\n at [Source: (byte[])\"n\ufffdr\ufffd\ufffd\ufffdI\ufffdmt\"; line: 1, column: 3]" + "Message": "Could not parse request body into json: Could not parse payload into json: Invalid UTF-8 start byte 0x87\n at [Source: REDACTED (`StreamReadFeature.INCLUDE_SOURCE_IN_LOCATION` disabled); line: 1, column: 3]" }, "Type": "User", - "message": "Could not parse request body into json: Could not parse payload into json: Invalid UTF-8 start byte 0x87\n at [Source: (byte[])\"n\ufffdr\ufffd\ufffd\ufffdI\ufffdmt\"; line: 1, column: 3]", + "message": "Could not parse request body into json: Could not parse payload into json: Invalid UTF-8 start byte 0x87\n at [Source: REDACTED (`StreamReadFeature.INCLUDE_SOURCE_IN_LOCATION` disabled); line: 1, column: 3]", "ResponseMetadata": { "HTTPHeaders": {}, "HTTPStatusCode": 400 @@ -3489,15 +3491,15 @@ } }, "tests/aws/services/lambda_/test_lambda.py::TestLambdaErrors::test_lambda_invoke_payload_encoding_error[message-\\x99\\xeb,j\\x07\\xa1zYh]": { - "recorded-date": "08-04-2024, 16:59:35", + "recorded-date": "24-11-2025, 23:13:31", "recorded-content": { "invoke_function_invalid_payload_message": { "Error": { "Code": "InvalidRequestContentException", - "Message": "Could not parse request body into json: Could not parse payload into json: Unexpected character ((CTRL-CHAR, code 153)): expected a valid value (JSON String, Number, Array, Object or token 'null', 'true' or 'false')\n at [Source: (byte[])\"\ufffd\ufffd,j\u0007\ufffdzYh\"; line: 1, column: 2]" + "Message": "Could not parse request body into json: Could not parse payload into json: Unexpected character ((CTRL-CHAR, code 153)): expected a valid value (JSON String, Number, Array, Object or token 'null', 'true' or 'false')\n at [Source: REDACTED (`StreamReadFeature.INCLUDE_SOURCE_IN_LOCATION` disabled); line: 1, column: 1]" }, "Type": "User", - "message": "Could not parse request body into json: Could not parse payload into json: Unexpected character ((CTRL-CHAR, code 153)): expected a valid value (JSON String, Number, Array, Object or token 'null', 'true' or 'false')\n at [Source: (byte[])\"\ufffd\ufffd,j\u0007\ufffdzYh\"; line: 1, column: 2]", + "message": "Could not parse request body into json: Could not parse payload into json: Unexpected character ((CTRL-CHAR, code 153)): expected a valid value (JSON String, Number, Array, Object or token 'null', 'true' or 'false')\n at [Source: REDACTED (`StreamReadFeature.INCLUDE_SOURCE_IN_LOCATION` disabled); line: 1, column: 1]", "ResponseMetadata": { "HTTPHeaders": {}, "HTTPStatusCode": 400 @@ -3506,23 +3508,23 @@ } }, "tests/aws/services/lambda_/test_lambda.py::TestLambdaBaseFeatures::test_assume_role[1]": { - "recorded-date": "08-04-2024, 16:55:26", + "recorded-date": "24-11-2025, 23:08:16", "recorded-content": { "invoke-result-assumed-role-arn": "arn::sts::111111111111:assumed-role/lambda-autogenerated-/@lambda_function" } }, "tests/aws/services/lambda_/test_lambda.py::TestLambdaBaseFeatures::test_assume_role[2]": { - "recorded-date": "08-04-2024, 16:55:32", + "recorded-date": "24-11-2025, 23:08:21", "recorded-content": { "invoke-result-assumed-role-arn": "arn::sts::111111111111:assumed-role/lambda-autogenerated-/" } }, "tests/aws/services/lambda_/test_lambda.py::TestLambdaBaseFeatures::test_large_payloads": { - "recorded-date": "08-04-2024, 16:55:07", + "recorded-date": "24-11-2025, 23:08:00", "recorded-content": {} }, "tests/aws/services/lambda_/test_lambda.py::TestLambdaBehavior::test_mixed_architecture": { - "recorded-date": "15-05-2024, 12:55:53", + "recorded-date": "24-11-2025, 23:08:39", "recorded-content": { "create_function_response": { "CreateEventSourceMappingResponse": null, @@ -3623,7 +3625,7 @@ } }, "tests/aws/services/lambda_/test_lambda.py::TestLambdaConcurrency::test_lambda_provisioned_concurrency_scheduling": { - "recorded-date": "16-04-2024, 08:03:42", + "recorded-date": "24-11-2025, 23:23:20", "recorded-content": { "get_provisioned_postwait": { "AllocatedProvisionedConcurrentExecutions": 1, @@ -3639,7 +3641,7 @@ } }, "tests/aws/services/lambda_/test_lambda.py::TestLambdaBehavior::test_lambda_init_environment": { - "recorded-date": "08-04-2024, 16:56:25", + "recorded-date": "18-02-2026, 11:19:29", "recorded-content": { "create-result": { "CreateEventSourceMappingResponse": null, @@ -3668,7 +3670,7 @@ "PackageType": "Zip", "RevisionId": "", "Role": "arn::iam::111111111111:role/", - "Runtime": "python3.12", + "Runtime": "python3.14", "RuntimeVersionConfig": { "RuntimeVersionArn": "arn::lambda:::runtime:" }, @@ -3694,35 +3696,35 @@ "ExecutedVersion": "$LATEST", "Payload": { "environment": { - "PATH": "/var/lang/bin:/usr/local/bin:/usr/bin/:/bin:/opt/bin", - "LD_LIBRARY_PATH": "/var/lang/lib:/lib64:/usr/lib64:/var/runtime:/var/runtime/lib:/var/task:/var/task/lib:/opt/lib", - "_LAMBDA_TELEMETRY_API_PASSPHRASE": "", - "LANG": "en_US.UTF-8", - "TZ": ":UTC", + "AWS_LAMBDA_FUNCTION_VERSION": "$LATEST", + "AWS_EXECUTION_ENV": "AWS_Lambda_python3.14", + "AWS_DEFAULT_REGION": "", + "AWS_LAMBDA_LOG_STREAM_NAME": "", + "AWS_REGION": "", + "PWD": "/var/task", "_HANDLER": "handler.handler", - "_LAMBDA_DIRECT_INVOKE_SOCKET": "9", - "_LAMBDA_CONTROL_SOCKET": "11", - "_LAMBDA_CONSOLE_SOCKET": "12", + "TZ": ":UTC", "LAMBDA_TASK_ROOT": "/var/task", - "LAMBDA_RUNTIME_DIR": "/var/runtime", - "_LAMBDA_LOG_FD": "18", - "_LAMBDA_SB_ID": "0", - "_LAMBDA_SHARED_MEM_FD": "8", - "AWS_REGION": "", - "AWS_DEFAULT_REGION": "", + "LANG": "en_US.UTF-8", + "AWS_SECRET_ACCESS_KEY": "", "AWS_LAMBDA_LOG_GROUP_NAME": "/aws/lambda/", - "AWS_LAMBDA_LOG_STREAM_NAME": "", - "AWS_LAMBDA_FUNCTION_NAME": "", + "AWS_LAMBDA_RUNTIME_API": ":9001", "AWS_LAMBDA_FUNCTION_MEMORY_SIZE": "128", - "AWS_LAMBDA_FUNCTION_VERSION": "$LATEST", - "_AWS_XRAY_DAEMON_ADDRESS": "169.254.79.129", - "_AWS_XRAY_DAEMON_PORT": "2000", - "AWS_XRAY_DAEMON_ADDRESS": "169.254.79.129:2000", - "AWS_XRAY_CONTEXT_MISSING": "LOG_ERROR", - "_X_AMZN_TRACE_ID": "", - "AWS_EXECUTION_ENV": "AWS_Lambda_rapid", + "LAMBDA_RUNTIME_DIR": "/var/runtime", + "_AWS_XRAY_DAEMON_ADDRESS": "", + "AWS_XRAY_DAEMON_ADDRESS": ":2000", + "SHLVL": "0", + "AWS_ACCESS_KEY_ID": "", + "LD_LIBRARY_PATH": "/var/lang/lib:/lib64:/usr/lib64:/var/runtime:/var/runtime/lib:/var/task:/var/task/lib:/opt/lib", + "AWS_LAMBDA_FUNCTION_NAME": "", + "PATH": "/var/lang/bin:/usr/local/bin:/usr/bin/:/bin:/opt/bin", "AWS_LAMBDA_INITIALIZATION_TYPE": "on-demand", - "_LAMBDA_RUNTIME_LOAD_TIME": "" + "AWS_SESSION_TOKEN": "", + "AWS_XRAY_CONTEXT_MISSING": "LOG_ERROR", + "_AWS_XRAY_DAEMON_PORT": "2000", + "LC_CTYPE": "C.UTF-8", + "PYTHONPATH": "/var/runtime", + "_X_AMZN_TRACE_ID": "" } }, "StatusCode": 200, @@ -3734,7 +3736,7 @@ } }, "tests/aws/services/lambda_/test_lambda.py::TestLambdaBaseFeatures::test_lambda_too_large_response": { - "recorded-date": "08-04-2024, 16:55:18", + "recorded-date": "24-11-2025, 23:08:09", "recorded-content": { "invoke_result": { "ExecutedVersion": "$LATEST", @@ -3765,7 +3767,7 @@ } }, "tests/aws/services/lambda_/test_lambda.py::TestLambdaVersions::test_lambda_handler_update": { - "recorded-date": "08-04-2024, 17:10:59", + "recorded-date": "24-11-2025, 23:26:26", "recorded-content": { "invoke_result_handler_one": { "ExecutedVersion": "$LATEST", @@ -3901,7 +3903,7 @@ } }, "tests/aws/services/lambda_/test_lambda.py::TestLambdaURL::test_lambda_url_invalid_invoke_mode": { - "recorded-date": "08-04-2024, 16:57:26", + "recorded-date": "24-11-2025, 23:11:02", "recorded-content": { "invoke_function_invalid_invoke_type": { "Error": { @@ -3916,7 +3918,7 @@ } }, "tests/aws/services/lambda_/test_lambda.py::TestLambdaURL::test_lambda_update_function_url_config": { - "recorded-date": "08-04-2024, 16:57:18", + "recorded-date": "24-11-2025, 23:09:53", "recorded-content": { "create_lambda_url_config": { "AuthType": "NONE", @@ -3992,7 +3994,7 @@ } }, "tests/aws/services/lambda_/test_lambda.py::TestLambdaURL::test_lambda_url_echo_invoke[RESPONSE_STREAM]": { - "recorded-date": "08-04-2024, 16:57:10", + "recorded-date": "24-11-2025, 23:09:46", "recorded-content": { "create_lambda_url_config": { "AuthType": "NONE", @@ -4026,7 +4028,7 @@ } }, "tests/aws/services/lambda_/test_lambda.py::TestLambdaURL::test_lambda_url_echo_invoke[BUFFERED]": { - "recorded-date": "08-04-2024, 16:57:05", + "recorded-date": "24-11-2025, 23:09:43", "recorded-content": { "create_lambda_url_config": { "AuthType": "NONE", @@ -4060,7 +4062,7 @@ } }, "tests/aws/services/lambda_/test_lambda.py::TestLambdaURL::test_lambda_url_echo_invoke[None]": { - "recorded-date": "08-04-2024, 16:57:02", + "recorded-date": "24-11-2025, 23:09:39", "recorded-content": { "create_lambda_url_config": { "AuthType": "NONE", @@ -4093,7 +4095,7 @@ } }, "tests/aws/services/lambda_/test_lambda.py::TestLambdaURL::test_lambda_url_echo_http_fixture_default": { - "recorded-date": "18-07-2024, 14:18:08", + "recorded-date": "24-11-2025, 23:11:05", "recorded-content": { "url_response": { "args": { @@ -4126,7 +4128,7 @@ } }, "tests/aws/services/lambda_/test_lambda.py::TestLambdaURL::test_lambda_url_echo_http_fixture_trim_x_headers": { - "recorded-date": "08-04-2024, 16:57:34", + "recorded-date": "24-11-2025, 23:11:08", "recorded-content": { "url_response": { "args": { @@ -4152,15 +4154,15 @@ } }, "tests/aws/services/lambda_/test_lambda.py::TestLambdaBaseFeatures::test_lambda_large_response": { - "recorded-date": "08-04-2024, 16:55:12", + "recorded-date": "24-11-2025, 23:08:04", "recorded-content": {} }, "tests/aws/services/lambda_/test_lambda.py::TestLambdaURL::test_lambda_url_headers_and_status": { - "recorded-date": "08-04-2024, 16:57:14", + "recorded-date": "24-11-2025, 23:09:49", "recorded-content": {} }, "tests/aws/services/lambda_/test_lambda.py::TestLambdaCleanup::test_recreate_function": { - "recorded-date": "15-05-2024, 10:16:45", + "recorded-date": "24-11-2025, 23:13:45", "recorded-content": { "create_function_response_one": { "CreateEventSourceMappingResponse": null, @@ -4263,7 +4265,7 @@ } }, "tests/aws/services/lambda_/test_lambda.py::TestLambdaVersions::test_async_invoke_queue_upon_function_update": { - "recorded-date": "15-05-2024, 17:38:05", + "recorded-date": "24-11-2025, 23:27:40", "recorded-content": { "async_invoke_history_sorted": [ "01-sleep--variant-1", @@ -4304,7 +4306,7 @@ } }, "tests/aws/services/lambda_/test_lambda.py::TestLambdaURL::test_lambda_url_form_payload": { - "recorded-date": "13-06-2024, 21:01:16", + "recorded-date": "24-11-2025, 23:11:12", "recorded-content": { "url_response": { "args": {}, @@ -4329,55 +4331,55 @@ "recorded-content": {} }, "tests/aws/services/lambda_/test_lambda.py::TestLambdaMultiAccounts::test_get_lambda_layer": { - "recorded-date": "14-06-2024, 15:16:46", + "recorded-date": "24-11-2025, 23:13:51", "recorded-content": {} }, "tests/aws/services/lambda_/test_lambda.py::TestLambdaMultiAccounts::test_get_function": { - "recorded-date": "14-06-2024, 15:16:50", + "recorded-date": "24-11-2025, 23:13:53", "recorded-content": {} }, "tests/aws/services/lambda_/test_lambda.py::TestLambdaMultiAccounts::test_get_function_configuration": { - "recorded-date": "14-06-2024, 15:16:53", + "recorded-date": "24-11-2025, 23:13:56", "recorded-content": {} }, "tests/aws/services/lambda_/test_lambda.py::TestLambdaMultiAccounts::test_list_versions_by_function": { - "recorded-date": "14-06-2024, 15:16:56", + "recorded-date": "24-11-2025, 23:13:58", "recorded-content": {} }, "tests/aws/services/lambda_/test_lambda.py::TestLambdaMultiAccounts::test_function_concurrency": { - "recorded-date": "14-06-2024, 15:16:59", + "recorded-date": "24-11-2025, 23:14:01", "recorded-content": {} }, "tests/aws/services/lambda_/test_lambda.py::TestLambdaMultiAccounts::test_function_alias": { - "recorded-date": "14-06-2024, 15:17:03", + "recorded-date": "24-11-2025, 23:14:04", "recorded-content": {} }, "tests/aws/services/lambda_/test_lambda.py::TestLambdaMultiAccounts::test_function_tags": { - "recorded-date": "14-06-2024, 15:17:07", + "recorded-date": "24-11-2025, 23:14:07", "recorded-content": {} }, "tests/aws/services/lambda_/test_lambda.py::TestLambdaMultiAccounts::test_function_invocation": { - "recorded-date": "14-06-2024, 15:17:10", + "recorded-date": "24-11-2025, 23:14:10", "recorded-content": {} }, "tests/aws/services/lambda_/test_lambda.py::TestLambdaMultiAccounts::test_publish_version": { - "recorded-date": "14-06-2024, 15:17:14", + "recorded-date": "24-11-2025, 23:14:13", "recorded-content": {} }, "tests/aws/services/lambda_/test_lambda.py::TestLambdaMultiAccounts::test_delete_function": { - "recorded-date": "14-06-2024, 15:17:17", + "recorded-date": "24-11-2025, 23:14:15", "recorded-content": {} }, "tests/aws/services/lambda_/test_lambda.py::TestLambdaURL::test_lambda_url_invocation_custom_id": { - "recorded-date": "05-08-2024, 12:24:48", + "recorded-date": "24-11-2025, 23:09:33", "recorded-content": {} }, "tests/aws/services/lambda_/test_lambda.py::TestLambdaURL::test_lambda_url_invocation_custom_id_aliased": { - "recorded-date": "05-08-2024, 12:48:07", + "recorded-date": "24-11-2025, 23:09:36", "recorded-content": {} }, "tests/aws/services/lambda_/test_lambda.py::TestLambdaURL::test_lambda_url_persists_after_alias_delete": { - "recorded-date": "05-08-2024, 13:57:04", + "recorded-date": "24-11-2025, 23:11:00", "recorded-content": { "create_lambda_url_config": { "AuthType": "NONE", @@ -4401,7 +4403,7 @@ }, "invoke_deleted_alias_url_response_delayed": { "content": { - "Message": null + "Message": "Forbidden. For troubleshooting Function URL authorization issues, see: https://docs.aws.amazon.com/lambda/latest/dg/urls-auth.html" }, "headers": { "x-amzn-ErrorType": "AccessDeniedException" @@ -4411,7 +4413,7 @@ } }, "tests/aws/services/lambda_/test_lambda.py::TestLambdaFeatures::test_invocation_type_no_return_payload[python-RequestResponse]": { - "recorded-date": "09-10-2024, 16:15:57", + "recorded-date": "24-11-2025, 23:11:49", "recorded-content": { "invoke-result": { "ExecutedVersion": "$LATEST", @@ -4425,7 +4427,7 @@ } }, "tests/aws/services/lambda_/test_lambda.py::TestLambdaFeatures::test_invocation_type_no_return_payload[python-Event]": { - "recorded-date": "09-10-2024, 16:16:05", + "recorded-date": "24-11-2025, 23:11:57", "recorded-content": { "invoke-result": { "Payload": "", @@ -4438,7 +4440,7 @@ } }, "tests/aws/services/lambda_/test_lambda.py::TestLambdaFeatures::test_invocation_type_no_return_payload[nodejs-RequestResponse]": { - "recorded-date": "09-10-2024, 16:16:14", + "recorded-date": "24-11-2025, 23:12:06", "recorded-content": { "invoke-result": { "ExecutedVersion": "$LATEST", @@ -4452,7 +4454,7 @@ } }, "tests/aws/services/lambda_/test_lambda.py::TestLambdaFeatures::test_invocation_type_no_return_payload[nodejs-Event]": { - "recorded-date": "09-10-2024, 16:16:28", + "recorded-date": "24-11-2025, 23:12:16", "recorded-content": { "invoke-result": { "Payload": "", @@ -4465,7 +4467,7 @@ } }, "tests/aws/services/lambda_/test_lambda.py::TestLambdaConcurrency::test_provisioned_concurrency_on_alias": { - "recorded-date": "07-05-2025, 09:26:54", + "recorded-date": "24-11-2025, 23:21:03", "recorded-content": { "put_provisioned_5": { "AllocatedProvisionedConcurrentExecutions": 0, @@ -4503,7 +4505,7 @@ } }, "tests/aws/services/lambda_/test_lambda.py::TestLambdaConcurrency::test_lambda_concurrency_update": { - "recorded-date": "22-05-2025, 14:11:12", + "recorded-date": "24-11-2025, 23:14:20", "recorded-content": { "put_function_concurrency": { "ReservedConcurrentExecutions": 3, @@ -4582,7 +4584,7 @@ } }, "tests/aws/services/lambda_/test_lambda.py::TestLambdaBehavior::test_lambda_host_prefix_api_operation": { - "recorded-date": "26-05-2025, 16:38:54", + "recorded-date": "24-11-2025, 23:09:01", "recorded-content": { "invoke-result": { "ExecutedVersion": "$LATEST", @@ -4606,10 +4608,53 @@ } }, "tests/aws/services/lambda_/test_lambda.py::TestLambdaURL::test_function_url_with_response_streaming": { - "recorded-date": "30-07-2025, 20:58:56", + "recorded-date": "24-11-2025, 23:09:29", "recorded-content": { "response_status": 200, "response_data": "Hello, world!" } + }, + "tests/aws/services/lambda_/test_lambda.py::TestLambdaURL::test_lambda_url_non_existing_url": { + "recorded-date": "24-11-2025, 23:11:02", + "recorded-content": {} + }, + "tests/aws/services/lambda_/test_lambda.py::TestLambdaConcurrency::test_provisioned_concurrency_init_failure": { + "recorded-date": "17-02-2026, 09:40:04", + "recorded-content": { + "put_provisioned": { + "AllocatedProvisionedConcurrentExecutions": 0, + "AvailableProvisionedConcurrentExecutions": 0, + "LastModified": "date", + "RequestedProvisionedConcurrentExecutions": 1, + "Status": "IN_PROGRESS", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 202 + } + }, + "get_provisioned_prewait": { + "AllocatedProvisionedConcurrentExecutions": 0, + "AvailableProvisionedConcurrentExecutions": 0, + "LastModified": "date", + "RequestedProvisionedConcurrentExecutions": 1, + "Status": "IN_PROGRESS", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "get_provisioned_postwait": { + "AllocatedProvisionedConcurrentExecutions": 0, + "AvailableProvisionedConcurrentExecutions": 0, + "LastModified": "date", + "RequestedProvisionedConcurrentExecutions": 1, + "Status": "FAILED", + "StatusReason": "FUNCTION_ERROR_INIT_FAILURE", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } } } diff --git a/tests/aws/services/lambda_/test_lambda.validation.json b/tests/aws/services/lambda_/test_lambda.validation.json index 764252f6734aa..4c2c4448f5261 100644 --- a/tests/aws/services/lambda_/test_lambda.validation.json +++ b/tests/aws/services/lambda_/test_lambda.validation.json @@ -1,120 +1,351 @@ { "tests/aws/services/lambda_/test_lambda.py::TestLambdaAliases::test_alias_routingconfig": { - "last_validated_date": "2024-04-08T17:11:17+00:00" + "last_validated_date": "2025-11-24T23:27:57+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 10.8, + "teardown": 0.56, + "total": 11.36 + } }, "tests/aws/services/lambda_/test_lambda.py::TestLambdaAliases::test_lambda_alias_moving": { - "last_validated_date": "2024-04-08T17:11:05+00:00" + "last_validated_date": "2025-11-25T23:37:28+00:00", + "durations_in_seconds": { + "setup": 11.16, + "call": 7.47, + "teardown": 1.06, + "total": 19.69 + } }, "tests/aws/services/lambda_/test_lambda.py::TestLambdaBaseFeatures::test_assume_role[1]": { - "last_validated_date": "2024-04-08T16:55:25+00:00" + "last_validated_date": "2025-11-24T23:08:16+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 4.38, + "teardown": 0.52, + "total": 4.9 + } }, "tests/aws/services/lambda_/test_lambda.py::TestLambdaBaseFeatures::test_assume_role[2]": { - "last_validated_date": "2024-04-08T16:55:31+00:00" + "last_validated_date": "2025-11-24T23:08:21+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 4.49, + "teardown": 0.48, + "total": 4.97 + } }, "tests/aws/services/lambda_/test_lambda.py::TestLambdaBaseFeatures::test_function_state": { - "last_validated_date": "2024-04-08T16:55:20+00:00" + "last_validated_date": "2025-11-24T23:08:11+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 1.78, + "teardown": 0.21, + "total": 1.99 + } }, "tests/aws/services/lambda_/test_lambda.py::TestLambdaBaseFeatures::test_lambda_different_iam_keys_environment": { - "last_validated_date": "2024-04-08T16:55:37+00:00" + "last_validated_date": "2025-11-24T23:08:26+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 4.58, + "teardown": 0.54, + "total": 5.12 + } }, "tests/aws/services/lambda_/test_lambda.py::TestLambdaBaseFeatures::test_lambda_large_response": { - "last_validated_date": "2024-04-08T16:55:11+00:00" + "last_validated_date": "2025-11-24T23:08:04+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 3.51, + "teardown": 0.31, + "total": 3.82 + } }, "tests/aws/services/lambda_/test_lambda.py::TestLambdaBaseFeatures::test_lambda_too_large_response": { - "last_validated_date": "2024-04-08T16:55:18+00:00" + "last_validated_date": "2025-11-24T23:08:09+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 5.3, + "teardown": 0.35, + "total": 5.65 + } }, "tests/aws/services/lambda_/test_lambda.py::TestLambdaBaseFeatures::test_large_payloads": { - "last_validated_date": "2024-04-08T16:55:06+00:00" + "last_validated_date": "2025-11-24T23:08:00+00:00", + "durations_in_seconds": { + "setup": 11.1, + "call": 5.22, + "teardown": 0.57, + "total": 16.89 + } }, "tests/aws/services/lambda_/test_lambda.py::TestLambdaBehavior::test_lambda_cache_local[nodejs]": { - "last_validated_date": "2024-04-08T16:55:56+00:00" + "last_validated_date": "2025-11-24T23:08:41+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 2.13, + "teardown": 0.34, + "total": 2.47 + } }, "tests/aws/services/lambda_/test_lambda.py::TestLambdaBehavior::test_lambda_cache_local[python]": { - "last_validated_date": "2024-04-08T16:55:59+00:00" + "last_validated_date": "2025-11-24T23:08:44+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 2.17, + "teardown": 0.49, + "total": 2.66 + } }, "tests/aws/services/lambda_/test_lambda.py::TestLambdaBehavior::test_lambda_host_prefix_api_operation": { - "last_validated_date": "2025-05-26T16:38:53+00:00" + "last_validated_date": "2025-11-24T23:09:01+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 3.38, + "teardown": 0.56, + "total": 3.94 + } }, "tests/aws/services/lambda_/test_lambda.py::TestLambdaBehavior::test_lambda_init_environment": { - "last_validated_date": "2024-04-08T16:56:25+00:00" + "last_validated_date": "2026-02-18T11:19:29+00:00", + "durations_in_seconds": { + "setup": 12.32, + "call": 3.18, + "teardown": 1.93, + "total": 17.43 + } }, "tests/aws/services/lambda_/test_lambda.py::TestLambdaBehavior::test_lambda_invoke_no_timeout": { - "last_validated_date": "2024-04-08T16:56:14+00:00" + "last_validated_date": "2025-11-24T23:08:55+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 6.59, + "teardown": 0.32, + "total": 6.91 + } }, "tests/aws/services/lambda_/test_lambda.py::TestLambdaBehavior::test_lambda_invoke_timed_out_environment_reuse": { "last_validated_date": "2024-04-08T16:56:22+00:00" }, "tests/aws/services/lambda_/test_lambda.py::TestLambdaBehavior::test_lambda_invoke_with_timeout": { - "last_validated_date": "2024-04-08T16:56:04+00:00" + "last_validated_date": "2025-11-25T00:39:46+00:00", + "durations_in_seconds": { + "setup": 11.18, + "call": 3.78, + "teardown": 1.05, + "total": 16.01 + } }, "tests/aws/services/lambda_/test_lambda.py::TestLambdaBehavior::test_mixed_architecture": { - "last_validated_date": "2024-05-15T12:55:52+00:00" + "last_validated_date": "2025-11-24T23:08:39+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 4.18, + "teardown": 0.52, + "total": 4.7 + } }, "tests/aws/services/lambda_/test_lambda.py::TestLambdaBehavior::test_runtime_introspection_arm": { - "last_validated_date": "2024-04-08T16:55:44+00:00" + "last_validated_date": "2025-11-24T23:08:31+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 2.13, + "teardown": 0.5, + "total": 2.63 + } }, "tests/aws/services/lambda_/test_lambda.py::TestLambdaBehavior::test_runtime_introspection_x86": { - "last_validated_date": "2024-04-08T16:55:41+00:00" + "last_validated_date": "2025-11-24T23:08:29+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 2.08, + "teardown": 0.49, + "total": 2.57 + } }, "tests/aws/services/lambda_/test_lambda.py::TestLambdaBehavior::test_runtime_ulimits": { - "last_validated_date": "2024-04-16T08:12:11+00:00" + "last_validated_date": "2025-11-24T23:08:34+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 2.06, + "teardown": 0.62, + "total": 2.68 + } }, "tests/aws/services/lambda_/test_lambda.py::TestLambdaCleanup::test_recreate_function": { - "last_validated_date": "2024-05-15T10:16:44+00:00" + "last_validated_date": "2025-11-24T23:13:45+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 13.09, + "teardown": 0.44, + "total": 13.53 + } }, "tests/aws/services/lambda_/test_lambda.py::TestLambdaConcurrency::test_lambda_concurrency_block": { - "last_validated_date": "2024-04-08T17:02:06+00:00" + "last_validated_date": "2025-11-24T23:16:40+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 138.97, + "teardown": 0.72, + "total": 139.69 + } }, "tests/aws/services/lambda_/test_lambda.py::TestLambdaConcurrency::test_lambda_concurrency_crud": { - "last_validated_date": "2025-05-22T08:04:13+00:00" + "last_validated_date": "2025-11-24T23:14:18+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 2.14, + "teardown": 0.49, + "total": 2.63 + } }, "tests/aws/services/lambda_/test_lambda.py::TestLambdaConcurrency::test_lambda_concurrency_update": { - "last_validated_date": "2025-05-22T14:11:12+00:00" + "last_validated_date": "2025-11-24T23:14:20+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 2.14, + "teardown": 0.49, + "total": 2.63 + } }, "tests/aws/services/lambda_/test_lambda.py::TestLambdaConcurrency::test_lambda_provisioned_concurrency_moves_with_alias": { "last_validated_date": "2023-03-21T07:47:38+00:00" }, "tests/aws/services/lambda_/test_lambda.py::TestLambdaConcurrency::test_lambda_provisioned_concurrency_scheduling": { - "last_validated_date": "2024-04-16T08:03:41+00:00" + "last_validated_date": "2025-11-24T23:23:20+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 136.09, + "teardown": 0.73, + "total": 136.82 + } }, "tests/aws/services/lambda_/test_lambda.py::TestLambdaConcurrency::test_provisioned_concurrency": { - "last_validated_date": "2024-04-08T17:04:20+00:00" + "last_validated_date": "2025-11-24T23:18:51+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 130.34, + "teardown": 0.81, + "total": 131.15 + } + }, + "tests/aws/services/lambda_/test_lambda.py::TestLambdaConcurrency::test_provisioned_concurrency_init_failure": { + "last_validated_date": "2026-02-17T09:40:06+00:00", + "durations_in_seconds": { + "setup": 12.05, + "call": 323.08, + "teardown": 2.23, + "total": 337.36 + } }, "tests/aws/services/lambda_/test_lambda.py::TestLambdaConcurrency::test_provisioned_concurrency_on_alias": { - "last_validated_date": "2025-05-07T09:26:54+00:00" + "last_validated_date": "2025-11-24T23:21:03+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 130.7, + "teardown": 0.67, + "total": 131.37 + } }, "tests/aws/services/lambda_/test_lambda.py::TestLambdaConcurrency::test_reserved_concurrency": { - "last_validated_date": "2024-04-08T17:08:10+00:00" + "last_validated_date": "2025-11-25T11:20:35+00:00", + "durations_in_seconds": { + "setup": 11.64, + "call": 6.88, + "teardown": 1.57, + "total": 20.09 + } }, "tests/aws/services/lambda_/test_lambda.py::TestLambdaConcurrency::test_reserved_concurrency_async_queue": { - "last_validated_date": "2025-03-26T10:54:29+00:00" + "last_validated_date": "2025-11-24T23:23:27+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 6.88, + "teardown": 0.86, + "total": 7.74 + } }, "tests/aws/services/lambda_/test_lambda.py::TestLambdaConcurrency::test_reserved_provisioned_overlap": { - "last_validated_date": "2024-04-08T17:10:36+00:00" + "last_validated_date": "2025-11-24T23:26:07+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 141.12, + "teardown": 0.75, + "total": 141.87 + } }, "tests/aws/services/lambda_/test_lambda.py::TestLambdaErrors::test_lambda_handler_error": { - "last_validated_date": "2024-04-08T16:59:22+00:00" + "last_validated_date": "2025-11-24T23:13:22+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 2.18, + "teardown": 0.32, + "total": 2.5 + } }, "tests/aws/services/lambda_/test_lambda.py::TestLambdaErrors::test_lambda_handler_exit": { - "last_validated_date": "2024-04-08T16:59:25+00:00" + "last_validated_date": "2025-11-24T23:13:24+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 2.11, + "teardown": 0.56, + "total": 2.67 + } }, "tests/aws/services/lambda_/test_lambda.py::TestLambdaErrors::test_lambda_invoke_payload_encoding_error[body-n\\x87r\\x9e\\xe9\\xb5\\xd7I\\xee\\x9bmt]": { - "last_validated_date": "2024-04-08T16:59:31+00:00" + "last_validated_date": "2025-11-24T23:13:29+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 2.01, + "teardown": 0.3, + "total": 2.31 + } }, "tests/aws/services/lambda_/test_lambda.py::TestLambdaErrors::test_lambda_invoke_payload_encoding_error[message-\\x99\\xeb,j\\x07\\xa1zYh]": { - "last_validated_date": "2024-04-08T16:59:34+00:00" + "last_validated_date": "2025-11-24T23:13:31+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 1.93, + "teardown": 0.53, + "total": 2.46 + } }, "tests/aws/services/lambda_/test_lambda.py::TestLambdaErrors::test_lambda_runtime_error": { - "last_validated_date": "2025-02-24T16:26:36+00:00" + "last_validated_date": "2025-11-24T23:12:34+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 2.33, + "teardown": 0.61, + "total": 2.94 + } }, "tests/aws/services/lambda_/test_lambda.py::TestLambdaErrors::test_lambda_runtime_exit": { - "last_validated_date": "2024-04-08T16:58:35+00:00" + "last_validated_date": "2025-11-24T23:12:36+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 2.23, + "teardown": 0.37, + "total": 2.6 + } }, "tests/aws/services/lambda_/test_lambda.py::TestLambdaErrors::test_lambda_runtime_exit_segfault": { - "last_validated_date": "2024-04-08T16:59:19+00:00" + "last_validated_date": "2025-11-24T23:13:19+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 42.13, + "teardown": 0.61, + "total": 42.74 + } }, "tests/aws/services/lambda_/test_lambda.py::TestLambdaErrors::test_lambda_runtime_wrapper_not_found": { - "last_validated_date": "2024-04-08T16:59:28+00:00" + "last_validated_date": "2025-11-24T23:13:27+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 1.93, + "teardown": 0.41, + "total": 2.34 + } }, "tests/aws/services/lambda_/test_lambda.py::TestLambdaFeatures::test_invocation_type_dry_run[nodejs16.x]": { "last_validated_date": "2022-09-09T17:15:38+00:00" @@ -123,186 +354,504 @@ "last_validated_date": "2023-04-26T17:37:23+00:00" }, "tests/aws/services/lambda_/test_lambda.py::TestLambdaFeatures::test_invocation_type_event[nodejs16.x]": { - "last_validated_date": "2024-04-08T16:57:59+00:00" + "last_validated_date": "2025-11-24T23:11:31+00:00", + "durations_in_seconds": { + "setup": 1.71, + "call": 3.09, + "teardown": 0.44, + "total": 5.24 + } }, "tests/aws/services/lambda_/test_lambda.py::TestLambdaFeatures::test_invocation_type_event[python3.10]": { - "last_validated_date": "2024-04-08T16:58:09+00:00" + "last_validated_date": "2025-11-24T23:11:39+00:00", + "durations_in_seconds": { + "setup": 1.96, + "call": 5.36, + "teardown": 0.38, + "total": 7.7 + } }, "tests/aws/services/lambda_/test_lambda.py::TestLambdaFeatures::test_invocation_type_event_error": { "last_validated_date": "2023-09-04T20:49:02+00:00" }, "tests/aws/services/lambda_/test_lambda.py::TestLambdaFeatures::test_invocation_type_no_return_payload[nodejs-Event]": { - "last_validated_date": "2024-10-09T16:16:27+00:00" + "last_validated_date": "2025-11-24T23:12:16+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 10.05, + "teardown": 0.42, + "total": 10.47 + } }, "tests/aws/services/lambda_/test_lambda.py::TestLambdaFeatures::test_invocation_type_no_return_payload[nodejs-RequestResponse]": { - "last_validated_date": "2024-10-09T16:16:13+00:00" + "last_validated_date": "2025-11-24T23:12:06+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 8.84, + "teardown": 0.35, + "total": 9.19 + } }, "tests/aws/services/lambda_/test_lambda.py::TestLambdaFeatures::test_invocation_type_no_return_payload[python-Event]": { - "last_validated_date": "2024-10-09T16:16:05+00:00" + "last_validated_date": "2025-11-24T23:11:57+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 7.08, + "teardown": 0.3, + "total": 7.38 + } }, "tests/aws/services/lambda_/test_lambda.py::TestLambdaFeatures::test_invocation_type_no_return_payload[python-RequestResponse]": { - "last_validated_date": "2024-10-09T16:15:57+00:00" + "last_validated_date": "2025-11-24T23:11:49+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 9.87, + "teardown": 0.37, + "total": 10.24 + } }, "tests/aws/services/lambda_/test_lambda.py::TestLambdaFeatures::test_invocation_type_request_response[nodejs16.x]": { - "last_validated_date": "2024-04-08T16:57:47+00:00" + "last_validated_date": "2025-11-24T23:11:23+00:00", + "durations_in_seconds": { + "setup": 1.82, + "call": 0.39, + "teardown": 0.5, + "total": 2.71 + } }, "tests/aws/services/lambda_/test_lambda.py::TestLambdaFeatures::test_invocation_type_request_response[python3.10]": { - "last_validated_date": "2024-04-08T16:57:50+00:00" + "last_validated_date": "2025-11-24T23:11:26+00:00", + "durations_in_seconds": { + "setup": 1.8, + "call": 0.41, + "teardown": 0.53, + "total": 2.74 + } }, "tests/aws/services/lambda_/test_lambda.py::TestLambdaFeatures::test_invocation_with_logs[nodejs16.x]": { - "last_validated_date": "2024-04-08T16:57:40+00:00" + "last_validated_date": "2025-11-24T23:11:18+00:00", + "durations_in_seconds": { + "setup": 1.78, + "call": 0.47, + "teardown": 0.57, + "total": 2.82 + } }, "tests/aws/services/lambda_/test_lambda.py::TestLambdaFeatures::test_invocation_with_logs[python3.10]": { - "last_validated_date": "2024-04-08T16:57:44+00:00" + "last_validated_date": "2025-11-24T23:11:20+00:00", + "durations_in_seconds": { + "setup": 1.87, + "call": 0.34, + "teardown": 0.49, + "total": 2.7 + } }, "tests/aws/services/lambda_/test_lambda.py::TestLambdaFeatures::test_invocation_with_qualifier": { - "last_validated_date": "2024-04-08T16:58:20+00:00" + "last_validated_date": "2025-11-24T23:12:27+00:00", + "durations_in_seconds": { + "setup": 0.67, + "call": 8.66, + "teardown": 1.07, + "total": 10.4 + } }, "tests/aws/services/lambda_/test_lambda.py::TestLambdaFeatures::test_invoke_exceptions": { - "last_validated_date": "2024-04-08T16:57:45+00:00" + "last_validated_date": "2025-11-24T23:11:21+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.12, + "teardown": 0.0, + "total": 0.12 + } }, "tests/aws/services/lambda_/test_lambda.py::TestLambdaFeatures::test_lambda_with_context": { "last_validated_date": "2022-09-09T18:19:33+00:00" }, "tests/aws/services/lambda_/test_lambda.py::TestLambdaFeatures::test_upload_lambda_from_s3": { - "last_validated_date": "2024-04-08T16:58:25+00:00" + "last_validated_date": "2025-11-24T23:12:31+00:00", + "durations_in_seconds": { + "setup": 0.61, + "call": 2.5, + "teardown": 1.06, + "total": 4.17 + } }, "tests/aws/services/lambda_/test_lambda.py::TestLambdaMultiAccounts::test_cross_account_access": { "last_validated_date": "2024-06-14T12:09:31+00:00" }, "tests/aws/services/lambda_/test_lambda.py::TestLambdaMultiAccounts::test_delete_function": { - "last_validated_date": "2024-06-14T15:17:16+00:00" + "last_validated_date": "2025-11-24T23:14:15+00:00", + "durations_in_seconds": { + "setup": 1.9, + "call": 0.31, + "teardown": 0.36, + "total": 2.57 + } }, "tests/aws/services/lambda_/test_lambda.py::TestLambdaMultiAccounts::test_function_alias": { - "last_validated_date": "2024-06-14T15:17:02+00:00" + "last_validated_date": "2025-11-24T23:14:04+00:00", + "durations_in_seconds": { + "setup": 1.89, + "call": 0.45, + "teardown": 0.51, + "total": 2.85 + } }, "tests/aws/services/lambda_/test_lambda.py::TestLambdaMultiAccounts::test_function_concurrency": { - "last_validated_date": "2024-06-14T15:16:58+00:00" + "last_validated_date": "2025-11-24T23:14:01+00:00", + "durations_in_seconds": { + "setup": 1.81, + "call": 0.21, + "teardown": 0.51, + "total": 2.53 + } }, "tests/aws/services/lambda_/test_lambda.py::TestLambdaMultiAccounts::test_function_invocation": { - "last_validated_date": "2024-06-14T15:17:09+00:00" + "last_validated_date": "2025-11-24T23:14:10+00:00", + "durations_in_seconds": { + "setup": 1.86, + "call": 0.47, + "teardown": 0.6, + "total": 2.93 + } }, "tests/aws/services/lambda_/test_lambda.py::TestLambdaMultiAccounts::test_function_tags": { - "last_validated_date": "2024-06-14T15:17:06+00:00" + "last_validated_date": "2025-11-24T23:14:07+00:00", + "durations_in_seconds": { + "setup": 1.8, + "call": 0.37, + "teardown": 0.78, + "total": 2.95 + } }, "tests/aws/services/lambda_/test_lambda.py::TestLambdaMultiAccounts::test_get_function": { - "last_validated_date": "2024-06-14T15:16:49+00:00" + "last_validated_date": "2025-11-24T23:13:53+00:00", + "durations_in_seconds": { + "setup": 1.82, + "call": 0.19, + "teardown": 0.51, + "total": 2.52 + } }, "tests/aws/services/lambda_/test_lambda.py::TestLambdaMultiAccounts::test_get_function_configuration": { - "last_validated_date": "2024-06-14T15:16:52+00:00" + "last_validated_date": "2025-11-24T23:13:56+00:00", + "durations_in_seconds": { + "setup": 1.81, + "call": 0.18, + "teardown": 0.57, + "total": 2.56 + } }, "tests/aws/services/lambda_/test_lambda.py::TestLambdaMultiAccounts::test_get_lambda_layer": { - "last_validated_date": "2024-06-14T15:16:46+00:00" + "last_validated_date": "2025-11-24T23:13:51+00:00", + "durations_in_seconds": { + "setup": 5.4, + "call": 0.33, + "teardown": 0.0, + "total": 5.73 + } }, "tests/aws/services/lambda_/test_lambda.py::TestLambdaMultiAccounts::test_list_versions_by_function": { - "last_validated_date": "2024-06-14T15:16:55+00:00" + "last_validated_date": "2025-11-24T23:13:58+00:00", + "durations_in_seconds": { + "setup": 1.79, + "call": 0.16, + "teardown": 0.51, + "total": 2.46 + } }, "tests/aws/services/lambda_/test_lambda.py::TestLambdaMultiAccounts::test_publish_version": { - "last_validated_date": "2024-06-14T15:17:13+00:00" + "last_validated_date": "2025-11-24T23:14:13+00:00", + "durations_in_seconds": { + "setup": 1.87, + "call": 0.49, + "teardown": 0.65, + "total": 3.01 + } }, "tests/aws/services/lambda_/test_lambda.py::TestLambdaPermissions::test_lambda_permission_url_invocation": { - "last_validated_date": "2024-04-08T16:57:37+00:00" + "last_validated_date": "2025-11-24T23:11:15+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 2.26, + "teardown": 0.53, + "total": 2.79 + } }, "tests/aws/services/lambda_/test_lambda.py::TestLambdaURL::test_function_url_with_response_streaming": { - "last_validated_date": "2025-07-30T21:16:00+00:00", + "last_validated_date": "2025-11-24T23:09:29+00:00", "durations_in_seconds": { - "setup": 10.91, - "call": 3.45, - "teardown": 0.83, - "total": 15.19 + "setup": 0.0, + "call": 2.87, + "teardown": 0.52, + "total": 3.39 } }, "tests/aws/services/lambda_/test_lambda.py::TestLambdaURL::test_lambda_update_function_url_config": { - "last_validated_date": "2024-04-08T16:57:17+00:00" + "last_validated_date": "2025-11-24T23:09:53+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 3.1, + "teardown": 0.53, + "total": 3.63 + } }, "tests/aws/services/lambda_/test_lambda.py::TestLambdaURL::test_lambda_url_echo_http_fixture": { "last_validated_date": "2024-03-28T22:20:14+00:00" }, "tests/aws/services/lambda_/test_lambda.py::TestLambdaURL::test_lambda_url_echo_http_fixture_default": { - "last_validated_date": "2024-07-18T14:18:07+00:00" + "last_validated_date": "2025-11-24T23:11:05+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 2.52, + "teardown": 0.58, + "total": 3.1 + } }, "tests/aws/services/lambda_/test_lambda.py::TestLambdaURL::test_lambda_url_echo_http_fixture_trim_x_headers": { - "last_validated_date": "2024-04-08T16:57:34+00:00" + "last_validated_date": "2025-11-24T23:11:08+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 2.54, + "teardown": 0.51, + "total": 3.05 + } }, "tests/aws/services/lambda_/test_lambda.py::TestLambdaURL::test_lambda_url_echo_invoke[BUFFERED]": { - "last_validated_date": "2024-04-08T16:57:05+00:00" + "last_validated_date": "2025-11-24T23:09:43+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 2.72, + "teardown": 0.54, + "total": 3.26 + } }, "tests/aws/services/lambda_/test_lambda.py::TestLambdaURL::test_lambda_url_echo_invoke[None]": { - "last_validated_date": "2024-04-08T16:57:01+00:00" + "last_validated_date": "2025-11-24T23:09:39+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 2.83, + "teardown": 0.52, + "total": 3.35 + } }, "tests/aws/services/lambda_/test_lambda.py::TestLambdaURL::test_lambda_url_echo_invoke[RESPONSE_STREAM]": { - "last_validated_date": "2024-04-08T16:57:09+00:00" + "last_validated_date": "2025-11-24T23:09:46+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 2.7, + "teardown": 0.56, + "total": 3.26 + } }, "tests/aws/services/lambda_/test_lambda.py::TestLambdaURL::test_lambda_url_form_payload": { - "last_validated_date": "2024-06-13T21:01:15+00:00" + "last_validated_date": "2025-11-24T23:11:12+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 3.25, + "teardown": 0.55, + "total": 3.8 + } }, "tests/aws/services/lambda_/test_lambda.py::TestLambdaURL::test_lambda_url_headers_and_status": { - "last_validated_date": "2024-04-08T16:57:13+00:00" + "last_validated_date": "2025-11-24T23:09:49+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 2.82, + "teardown": 0.56, + "total": 3.38 + } }, "tests/aws/services/lambda_/test_lambda.py::TestLambdaURL::test_lambda_url_invalid_invoke_mode": { - "last_validated_date": "2024-04-08T16:57:25+00:00" + "last_validated_date": "2025-11-24T23:11:02+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 1.73, + "teardown": 0.35, + "total": 2.08 + } }, "tests/aws/services/lambda_/test_lambda.py::TestLambdaURL::test_lambda_url_invocation[boolean]": { - "last_validated_date": "2024-04-08T16:56:56+00:00" + "last_validated_date": "2025-11-24T23:09:26+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 2.42, + "teardown": 0.51, + "total": 2.93 + } }, "tests/aws/services/lambda_/test_lambda.py::TestLambdaURL::test_lambda_url_invocation[dict]": { - "last_validated_date": "2024-04-08T16:56:29+00:00" + "last_validated_date": "2025-11-24T23:09:04+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 2.61, + "teardown": 0.53, + "total": 3.14 + } }, "tests/aws/services/lambda_/test_lambda.py::TestLambdaURL::test_lambda_url_invocation[float]": { - "last_validated_date": "2024-04-08T16:56:52+00:00" + "last_validated_date": "2025-11-24T23:09:23+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 2.57, + "teardown": 0.48, + "total": 3.05 + } }, "tests/aws/services/lambda_/test_lambda.py::TestLambdaURL::test_lambda_url_invocation[http-response-json]": { - "last_validated_date": "2024-04-08T16:56:36+00:00" + "last_validated_date": "2025-11-24T23:09:11+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 2.56, + "teardown": 0.49, + "total": 3.05 + } }, "tests/aws/services/lambda_/test_lambda.py::TestLambdaURL::test_lambda_url_invocation[http-response]": { - "last_validated_date": "2024-04-08T16:56:32+00:00" + "last_validated_date": "2025-11-24T23:09:07+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 2.48, + "teardown": 0.49, + "total": 2.97 + } }, "tests/aws/services/lambda_/test_lambda.py::TestLambdaURL::test_lambda_url_invocation[integer]": { - "last_validated_date": "2024-04-08T16:56:48+00:00" + "last_validated_date": "2025-11-24T23:09:20+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 2.8, + "teardown": 0.52, + "total": 3.32 + } }, "tests/aws/services/lambda_/test_lambda.py::TestLambdaURL::test_lambda_url_invocation[list-mixed]": { - "last_validated_date": "2024-04-08T16:56:40+00:00" + "last_validated_date": "2025-11-24T23:09:14+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 2.5, + "teardown": 0.48, + "total": 2.98 + } }, "tests/aws/services/lambda_/test_lambda.py::TestLambdaURL::test_lambda_url_invocation[string]": { - "last_validated_date": "2024-04-08T16:56:44+00:00" + "last_validated_date": "2025-11-24T23:09:17+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 2.59, + "teardown": 0.56, + "total": 3.15 + } }, "tests/aws/services/lambda_/test_lambda.py::TestLambdaURL::test_lambda_url_invocation_custom_id": { - "last_validated_date": "2024-08-05T12:24:46+00:00" + "last_validated_date": "2025-11-24T23:09:33+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 2.67, + "teardown": 0.59, + "total": 3.26 + } }, "tests/aws/services/lambda_/test_lambda.py::TestLambdaURL::test_lambda_url_invocation_custom_id_aliased": { - "last_validated_date": "2024-08-05T12:48:05+00:00" + "last_validated_date": "2025-11-24T23:09:36+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 2.85, + "teardown": 0.57, + "total": 3.42 + } }, "tests/aws/services/lambda_/test_lambda.py::TestLambdaURL::test_lambda_url_invocation_exception": { - "last_validated_date": "2024-04-08T16:57:22+00:00" + "last_validated_date": "2025-11-24T23:09:56+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 2.88, + "teardown": 0.5, + "total": 3.38 + } }, "tests/aws/services/lambda_/test_lambda.py::TestLambdaURL::test_lambda_url_non_existing_url": { - "last_validated_date": "2024-04-11T17:16:39+00:00" + "last_validated_date": "2025-11-24T23:11:02+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.29, + "teardown": 0.0, + "total": 0.29 + } }, "tests/aws/services/lambda_/test_lambda.py::TestLambdaURL::test_lambda_url_persists_after_alias_delete": { - "last_validated_date": "2024-08-05T13:57:02+00:00" + "last_validated_date": "2025-11-24T23:11:00+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 62.73, + "teardown": 0.65, + "total": 63.38 + } }, "tests/aws/services/lambda_/test_lambda.py::TestLambdaVersions::test_async_invoke_queue_upon_function_update": { - "last_validated_date": "2024-05-15T18:29:38+00:00" + "last_validated_date": "2025-11-24T23:27:40+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 71.82, + "teardown": 1.85, + "total": 73.67 + } }, "tests/aws/services/lambda_/test_lambda.py::TestLambdaVersions::test_function_update_during_invoke": { "last_validated_date": "2024-05-15T19:05:04+00:00" }, "tests/aws/services/lambda_/test_lambda.py::TestLambdaVersions::test_lambda_handler_update": { - "last_validated_date": "2024-04-08T17:10:58+00:00" + "last_validated_date": "2025-11-24T23:26:26+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 4.64, + "teardown": 0.65, + "total": 5.29 + } }, "tests/aws/services/lambda_/test_lambda.py::TestLambdaVersions::test_lambda_versions_with_code_changes": { - "last_validated_date": "2024-04-08T17:10:52+00:00" + "last_validated_date": "2025-11-24T23:26:21+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 12.8, + "teardown": 0.46, + "total": 13.26 + } }, "tests/aws/services/lambda_/test_lambda.py::TestRequestIdHandling::test_request_id_async_invoke_with_retry": { - "last_validated_date": "2024-04-08T17:13:38+00:00" + "last_validated_date": "2025-11-24T23:30:19+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 122.59, + "teardown": 1.51, + "total": 124.1 + } }, "tests/aws/services/lambda_/test_lambda.py::TestRequestIdHandling::test_request_id_format": { - "last_validated_date": "2024-04-08T17:11:17+00:00" + "last_validated_date": "2025-11-24T23:27:57+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.16, + "teardown": 0.0, + "total": 0.16 + } }, "tests/aws/services/lambda_/test_lambda.py::TestRequestIdHandling::test_request_id_invoke": { - "last_validated_date": "2024-04-08T17:11:26+00:00" + "last_validated_date": "2025-11-24T23:28:05+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 6.99, + "teardown": 0.42, + "total": 7.41 + } }, "tests/aws/services/lambda_/test_lambda.py::TestRequestIdHandling::test_request_id_invoke_url": { - "last_validated_date": "2024-04-08T17:11:34+00:00" + "last_validated_date": "2025-11-24T23:28:15+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 9.54, + "teardown": 0.38, + "total": 9.92 + } } } diff --git a/tests/aws/services/lambda_/test_lambda_api.py b/tests/aws/services/lambda_/test_lambda_api.py index 9b1ce6970f5ed..4f6b0a89ab080 100644 --- a/tests/aws/services/lambda_/test_lambda_api.py +++ b/tests/aws/services/lambda_/test_lambda_api.py @@ -11,6 +11,7 @@ import base64 import io +import itertools import json import logging import re @@ -51,6 +52,7 @@ from localstack.utils import testutil from localstack.utils.aws import arns from localstack.utils.aws.arns import ( + capacity_provider_arn, get_partition, lambda_event_source_mapping_arn, lambda_function_arn, @@ -102,11 +104,6 @@ def test_create_deprecated_function_runtime_with_validation_disabled( func_name=function_name, runtime=Runtime.python3_7, role=lambda_su_role, - MemorySize=256, - Timeout=5, - LoggingConfig={ - "LogFormat": LogFormat.JSON, - }, ) @markers.aws.validated @@ -126,11 +123,6 @@ def test_create_deprecated_function_runtime_with_validation_enabled( func_name=function_name, runtime=runtime, role=lambda_su_role, - MemorySize=256, - Timeout=5, - LoggingConfig={ - "LogFormat": LogFormat.JSON, - }, ) snapshot.match("deprecation_error", e.value.response) @@ -323,9 +315,11 @@ def test_function_partial_advanced_logging_configuration_update( class TestLambdaFunction: @markers.snapshot.skip_snapshot_verify( - # The RuntimeVersionArn is currently a hardcoded id and therefore does not reflect the ARN resource update - # for different runtime versions" - paths=["$..RuntimeVersionConfig.RuntimeVersionArn"] + paths=[ + # The RuntimeVersionArn is currently a hardcoded id and therefore does not reflect the ARN resource update + # for different runtime versions" + "$..RuntimeVersionConfig.RuntimeVersionArn", + ] ) @markers.aws.validated def test_function_lifecycle(self, snapshot, create_lambda_function, lambda_su_role, aws_client): @@ -971,8 +965,12 @@ def test_function_name_and_qualifier_validation( "function_name_too_long-invoke", "incomplete_arn-invoke", ) + and not is_aws_cloud() ): - pytest.skip("skipping test case") + pytest.skip("Not implemented") + + if request.node.callspec.id == "incomplete_arn-create_function": + pytest.skip("Works against AWS") function_name = test_case["FunctionName"].format( region_name=region_name, account_id=account_id @@ -2761,6 +2759,9 @@ def test_function_revisions_version_and_alias( assert rev_a1_create_alias != rev_a2_update_alias @markers.aws.validated + @pytest.mark.skip( + reason="The API on AWS has changed significantly and this test needs re-writing" + ) def test_function_revisions_permissions(self, create_lambda_function, snapshot, aws_client): """Tests revision id lifecycle for adding and removing permissions""" # rev1: create function @@ -2992,8 +2993,8 @@ def test_tag_lifecycle(self, snapshot, aws_client, resource_arn_fixture, request @pytest.mark.parametrize( "create_resource_arn", - [lambda_function_arn, lambda_event_source_mapping_arn], - ids=["lambda_function", "event_source_mapping"], + [lambda_function_arn, lambda_event_source_mapping_arn, capacity_provider_arn], + ids=["lambda_function", "event_source_mapping", "capacity_provider"], ) @markers.aws.validated def test_tag_exceptions( @@ -3953,6 +3954,13 @@ def _wait_provisioned(): class TestLambdaPermissions: + @markers.snapshot.skip_snapshot_verify( + paths=[ + # TODO: adjust validation to new AWS behavior, raising function not found under a certain condition + "get_policy_fn_doesnotexist..Error.Message", + "get_policy_fn_doesnotexist..Message", + ] + ) @markers.aws.validated def test_permission_exceptions( self, create_lambda_function, account_id, snapshot, aws_client, region_name @@ -4146,6 +4154,7 @@ def test_add_lambda_permission_aws( snapshot.match("get_policy", get_policy_result) @markers.aws.validated + @markers.snapshot.skip_snapshot_verify(["$..RevisionId"]) # TODO fix in follow up def test_lambda_permission_fn_versioning( self, create_lambda_function, account_id, snapshot, aws_client, region_name ): @@ -4799,6 +4808,7 @@ def test_create_url_config_custom_id_tag(self, create_lambda_function, aws_clien # region changes, https vs http, etc assert f"://{custom_id_value}.lambda-url." in url_config_created["FunctionUrl"] + @markers.requires_in_process @markers.aws.only_localstack def test_create_url_config_custom_id_tag_invalid_id( self, create_lambda_function, aws_client, caplog @@ -5482,7 +5492,9 @@ def test_account_settings_total_code_size_config_update( class TestLambdaEventSourceMappings: @markers.aws.validated - def test_event_source_mapping_exceptions(self, snapshot, aws_client): + def test_event_source_mapping_exceptions( + self, snapshot, aws_client, region_name, secondary_region_name + ): with pytest.raises(aws_client.lambda_.exceptions.ResourceNotFoundException) as e: aws_client.lambda_.get_event_source_mapping(UUID=long_uid()) snapshot.match("get_unknown_uuid", e.value.response) @@ -5499,7 +5511,7 @@ def test_event_source_mapping_exceptions(self, snapshot, aws_client): aws_client.lambda_.list_event_source_mappings() aws_client.lambda_.list_event_source_mappings(FunctionName="doesnotexist") aws_client.lambda_.list_event_source_mappings( - EventSourceArn="arn:aws:sqs:us-east-1:111111111111:somequeue" + EventSourceArn=f"arn:aws:sqs:{region_name}:111111111111:somequeue" ) with pytest.raises(aws_client.lambda_.exceptions.InvalidParameterValueException) as e: @@ -5509,17 +5521,17 @@ def test_event_source_mapping_exceptions(self, snapshot, aws_client): with pytest.raises(aws_client.lambda_.exceptions.InvalidParameterValueException) as e: aws_client.lambda_.create_event_source_mapping( FunctionName="doesnotexist", - EventSourceArn="arn:aws:sqs:us-east-1:111111111111:somequeue", + EventSourceArn=f"arn:aws:sqs:{region_name}:111111111111:somequeue", ) snapshot.match("create_unknown_params", e.value.response) with pytest.raises(aws_client.lambda_.exceptions.InvalidParameterValueException) as e: aws_client.lambda_.create_event_source_mapping( FunctionName="doesnotexist", - EventSourceArn="arn:aws:sqs:us-east-1:111111111111:somequeue", + EventSourceArn=f"arn:aws:sqs:{region_name}:111111111111:somequeue", DestinationConfig={ "OnSuccess": { - "Destination": "arn:aws:sqs:us-east-1:111111111111:someotherqueue" + "Destination": f"arn:aws:sqs:{region_name}:111111111111:someotherqueue" } }, ) @@ -5532,18 +5544,16 @@ def test_event_source_mapping_exceptions(self, snapshot, aws_client): @markers.snapshot.skip_snapshot_verify( paths=[ # all dynamodb service issues not related to lambda - "$..TableDescription.DeletionProtectionEnabled", "$..TableDescription.ProvisionedThroughput.LastDecreaseDateTime", "$..TableDescription.ProvisionedThroughput.LastIncreaseDateTime", "$..TableDescription.TableStatus", - "$..TableDescription.TableId", - "$..UUID", ] ) @markers.aws.validated - def test_event_source_mapping_lifecycle( + def test_event_source_mapping_lifecycle_delete_function( self, create_lambda_function, + create_event_source_mapping, snapshot, sqs_create_queue, cleanups, @@ -5575,7 +5585,7 @@ def test_event_source_mapping_lifecycle( role=lambda_su_role, ) # "minimal" - create_response = aws_client.lambda_.create_event_source_mapping( + create_response = create_event_source_mapping( FunctionName=function_name, EventSourceArn=stream_arn, DestinationConfig={"OnFailure": {"Destination": destination_queue_arn}}, @@ -5584,48 +5594,42 @@ def test_event_source_mapping_lifecycle( MaximumBatchingWindowInSeconds=1, MaximumRetryAttempts=1, ) + uuid = create_response["UUID"] - cleanups.append(lambda: aws_client.lambda_.delete_event_source_mapping(UUID=uuid)) snapshot.match("create_response", create_response) # the stream might not be active immediately(!) - def check_esm_active(): - return aws_client.lambda_.get_event_source_mapping(UUID=uuid)["State"] != "Creating" - - assert wait_until(check_esm_active) + _await_event_source_mapping_enabled(aws_client.lambda_, uuid) get_response = aws_client.lambda_.get_event_source_mapping(UUID=uuid) snapshot.match("get_response", get_response) - # + + delete_function_response = aws_client.lambda_.delete_function(FunctionName=function_name) + snapshot.match("delete_function_response", delete_function_response) + + def _assert_function_deleted(): + with pytest.raises(aws_client.lambda_.exceptions.ResourceNotFoundException): + aws_client.lambda_.get_function(FunctionName=function_name) + return True + + wait_until(_assert_function_deleted) + + get_response_post_delete = aws_client.lambda_.get_event_source_mapping(UUID=uuid) + snapshot.match("get_response_post_delete", get_response_post_delete) + delete_response = aws_client.lambda_.delete_event_source_mapping(UUID=uuid) snapshot.match("delete_response", delete_response) - # TODO: continue here after initial CRUD PR - # check what happens when we delete the function - # check behavior in relation to version/alias - # wait until the stream is actually active - # - # lambda_client.update_event_source_mapping() - # - # lambda_client.list_event_source_mappings(FunctionName=function_name) - # lambda_client.list_event_source_mappings(FunctionName=function_name, EventSourceArn=queue_arn) - # lambda_client.list_event_source_mappings(EventSourceArn=queue_arn) - # - # lambda_client.delete_event_source_mapping(UUID=uuid) - @markers.snapshot.skip_snapshot_verify( paths=[ # all dynamodb service issues not related to lambda - "$..TableDescription.DeletionProtectionEnabled", "$..TableDescription.ProvisionedThroughput.LastDecreaseDateTime", "$..TableDescription.ProvisionedThroughput.LastIncreaseDateTime", "$..TableDescription.TableStatus", - "$..TableDescription.TableId", - "$..UUID", ] ) @markers.aws.validated - def test_event_source_mapping_lifecycle_delete_function( + def test_event_source_mapping_lifecycle( self, create_lambda_function, snapshot, @@ -5668,33 +5672,35 @@ def test_event_source_mapping_lifecycle_delete_function( MaximumBatchingWindowInSeconds=1, MaximumRetryAttempts=1, ) - uuid = create_response["UUID"] cleanups.append(lambda: aws_client.lambda_.delete_event_source_mapping(UUID=uuid)) snapshot.match("create_response", create_response) # the stream might not be active immediately(!) - _await_event_source_mapping_enabled(aws_client.lambda_, uuid) + def check_esm_active(): + return aws_client.lambda_.get_event_source_mapping(UUID=uuid)["State"] != "Creating" + + assert wait_until(check_esm_active) get_response = aws_client.lambda_.get_event_source_mapping(UUID=uuid) snapshot.match("get_response", get_response) - - delete_function_response = aws_client.lambda_.delete_function(FunctionName=function_name) - snapshot.match("delete_function_response", delete_function_response) - - def _assert_function_deleted(): - with pytest.raises(aws_client.lambda_.exceptions.ResourceNotFoundException): - aws_client.lambda_.get_function(FunctionName=function_name) - return True - - wait_until(_assert_function_deleted) - - get_response_post_delete = aws_client.lambda_.get_event_source_mapping(UUID=uuid) - snapshot.match("get_response_post_delete", get_response_post_delete) # delete_response = aws_client.lambda_.delete_event_source_mapping(UUID=uuid) snapshot.match("delete_response", delete_response) + # TODO: continue here after initial CRUD PR + # check what happens when we delete the function + # check behavior in relation to version/alias + # wait until the stream is actually active + # + # lambda_client.update_event_source_mapping() + # + # lambda_client.list_event_source_mappings(FunctionName=function_name) + # lambda_client.list_event_source_mappings(FunctionName=function_name, EventSourceArn=queue_arn) + # lambda_client.list_event_source_mappings(EventSourceArn=queue_arn) + # + # lambda_client.delete_event_source_mapping(UUID=uuid) + @markers.aws.validated def test_function_name_variations( self, @@ -5739,10 +5745,10 @@ def _create_esm(snapshot_scope: str, tested_name: str): aws_client.lambda_.delete_event_source_mapping(UUID=result["UUID"]) def _assert_esm_deleted(): - with pytest.raises(aws_client.lambda_.exceptions.ResourceNotFoundException): + try: aws_client.lambda_.get_event_source_mapping(UUID=result["UUID"]) - - return True + except aws_client.lambda_.exceptions.ResourceNotFoundException: + return True wait_until(_assert_esm_deleted) @@ -5853,6 +5859,7 @@ def test_create_event_filter_criteria_validation( create_lambda_function, lambda_su_role, dynamodb_create_table, + create_event_source_mapping, snapshot, aws_client, ): @@ -5875,14 +5882,17 @@ def test_create_event_filter_criteria_validation( StreamSpecification={"StreamEnabled": True, "StreamViewType": "NEW_AND_OLD_IMAGES"}, ) stream_arn = update_table_response["TableDescription"]["LatestStreamArn"] + _await_dynamodb_table_active(aws_client.dynamodb, table_name) - response = aws_client.lambda_.create_event_source_mapping( + response = create_event_source_mapping( FunctionName=function_name, EventSourceArn=stream_arn, StartingPosition="LATEST", FilterCriteria={"Filters": []}, ) snapshot.match("response-with-empty-filters", response) + # Wait until ESM is enabled to mitigate cleanup failure + _await_event_source_mapping_enabled(aws_client.lambda_, response["UUID"]) with pytest.raises(ParamValidationError): aws_client.lambda_.create_event_source_mapping( @@ -6203,7 +6213,7 @@ class TestLambdaLayer: @markers.lambda_runtime_update @markers.aws.validated # AWS only allows a max of 15 compatible runtimes, split runtimes and run two tests - @pytest.mark.parametrize("runtimes", [ALL_RUNTIMES[:14], ALL_RUNTIMES[14:]]) + @pytest.mark.parametrize("runtimes", list(itertools.batched(ALL_RUNTIMES, 15, strict=False))) def test_layer_compatibilities(self, snapshot, dummylayer, cleanups, aws_client, runtimes): """Creates a single layer which is compatible with all""" layer_name = f"testlayer-{short_uid()}" @@ -6861,6 +6871,7 @@ def test_layer_policy_lifecycle( "get_layer_version_policy_postdeletes2", get_layer_version_policy_postdeletes2 ) + @markers.requires_in_process @markers.aws.only_localstack(reason="Deterministic id generation is LS only") def test_layer_deterministic_version( self, dummylayer, cleanups, aws_client, account_id, region_name, set_resource_custom_id diff --git a/tests/aws/services/lambda_/test_lambda_api.snapshot.json b/tests/aws/services/lambda_/test_lambda_api.snapshot.json index 38f613018c362..35b46fa355c5e 100644 --- a/tests/aws/services/lambda_/test_lambda_api.snapshot.json +++ b/tests/aws/services/lambda_/test_lambda_api.snapshot.json @@ -1,6 +1,6 @@ { "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_lifecycle": { - "recorded-date": "12-09-2024, 11:29:18", + "recorded-date": "25-11-2025, 02:26:54", "recorded-content": { "create_response": { "CreateEventSourceMappingResponse": null, @@ -307,6 +307,7 @@ } }, "delete_response": { + "StatusCode": 204, "ResponseMetadata": { "HTTPHeaders": {}, "HTTPStatusCode": 204 @@ -327,7 +328,7 @@ } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_redundant_updates": { - "recorded-date": "12-09-2024, 11:29:23", + "recorded-date": "25-11-2025, 02:27:00", "recorded-content": { "create_response": { "CreateEventSourceMappingResponse": null, @@ -622,7 +623,7 @@ } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_ops_with_arn_qualifier_mismatch[delete_function]": { - "recorded-date": "12-09-2024, 11:29:23", + "recorded-date": "25-11-2025, 02:27:00", "recorded-content": { "not_match_exception": { "Error": { @@ -651,7 +652,7 @@ } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_ops_with_arn_qualifier_mismatch[get_function]": { - "recorded-date": "12-09-2024, 11:29:23", + "recorded-date": "25-11-2025, 02:27:01", "recorded-content": { "not_match_exception": { "Error": { @@ -680,7 +681,7 @@ } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_ops_with_arn_qualifier_mismatch[get_function_configuration]": { - "recorded-date": "12-09-2024, 11:29:24", + "recorded-date": "25-11-2025, 02:27:01", "recorded-content": { "not_match_exception": { "Error": { @@ -709,7 +710,7 @@ } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_ops_on_nonexisting_version[get_function]": { - "recorded-date": "12-09-2024, 11:29:26", + "recorded-date": "25-11-2025, 02:27:03", "recorded-content": { "version_not_found_exception": { "Error": { @@ -726,7 +727,7 @@ } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_ops_on_nonexisting_version[get_function_configuration]": { - "recorded-date": "12-09-2024, 11:29:28", + "recorded-date": "25-11-2025, 02:27:06", "recorded-content": { "version_not_found_exception": { "Error": { @@ -743,7 +744,7 @@ } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_ops_on_nonexisting_version[get_function_event_invoke_config]": { - "recorded-date": "12-09-2024, 11:29:30", + "recorded-date": "25-11-2025, 02:27:08", "recorded-content": { "version_not_found_exception": { "Error": { @@ -760,7 +761,7 @@ } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_delete_on_nonexisting_version": { - "recorded-date": "12-09-2024, 11:29:32", + "recorded-date": "25-11-2025, 02:27:11", "recorded-content": { "delete_function_response_non_existent": { "Error": { @@ -789,7 +790,7 @@ } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_ops_on_nonexisting_fn[delete_function]": { - "recorded-date": "12-09-2024, 11:29:32", + "recorded-date": "25-11-2025, 02:27:12", "recorded-content": { "not_found_exception": { "Error": { @@ -806,7 +807,7 @@ } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_ops_on_nonexisting_fn[get_function]": { - "recorded-date": "12-09-2024, 11:29:32", + "recorded-date": "25-11-2025, 02:27:12", "recorded-content": { "not_found_exception": { "Error": { @@ -823,7 +824,7 @@ } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_ops_on_nonexisting_fn[get_function_configuration]": { - "recorded-date": "12-09-2024, 11:29:33", + "recorded-date": "25-11-2025, 02:27:12", "recorded-content": { "not_found_exception": { "Error": { @@ -840,7 +841,7 @@ } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_ops_on_nonexisting_fn[get_function_url_config]": { - "recorded-date": "12-09-2024, 11:29:33", + "recorded-date": "25-11-2025, 02:27:12", "recorded-content": { "not_found_exception": { "Error": { @@ -857,7 +858,7 @@ } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_ops_on_nonexisting_fn[get_function_code_signing_config]": { - "recorded-date": "12-09-2024, 11:29:33", + "recorded-date": "25-11-2025, 02:27:12", "recorded-content": { "not_found_exception": { "Error": { @@ -874,7 +875,7 @@ } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_ops_on_nonexisting_fn[get_function_event_invoke_config]": { - "recorded-date": "12-09-2024, 11:29:33", + "recorded-date": "25-11-2025, 02:27:13", "recorded-content": { "not_found_exception": { "Error": { @@ -891,7 +892,7 @@ } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_ops_on_nonexisting_fn[get_function_concurrency]": { - "recorded-date": "12-09-2024, 11:29:33", + "recorded-date": "25-11-2025, 02:27:13", "recorded-content": { "not_found_exception": { "Error": { @@ -908,7 +909,7 @@ } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_get_function_wrong_region[get_function]": { - "recorded-date": "12-09-2024, 11:29:35", + "recorded-date": "25-11-2025, 02:27:15", "recorded-content": { "wrong_region_exception": { "Error": { @@ -925,7 +926,7 @@ } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_get_function_wrong_region[get_function_configuration]": { - "recorded-date": "12-09-2024, 11:29:37", + "recorded-date": "25-11-2025, 02:27:17", "recorded-content": { "wrong_region_exception": { "Error": { @@ -942,7 +943,7 @@ } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_get_function_wrong_region[get_function_url_config]": { - "recorded-date": "12-09-2024, 11:29:39", + "recorded-date": "25-11-2025, 02:27:20", "recorded-content": { "wrong_region_exception": { "Error": { @@ -959,7 +960,7 @@ } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_get_function_wrong_region[get_function_code_signing_config]": { - "recorded-date": "12-09-2024, 11:29:41", + "recorded-date": "25-11-2025, 02:27:22", "recorded-content": { "wrong_region_exception": { "Error": { @@ -976,7 +977,7 @@ } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_get_function_wrong_region[get_function_event_invoke_config]": { - "recorded-date": "12-09-2024, 11:29:43", + "recorded-date": "25-11-2025, 02:27:24", "recorded-content": { "wrong_region_exception": { "Error": { @@ -993,7 +994,7 @@ } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_get_function_wrong_region[get_function_concurrency]": { - "recorded-date": "12-09-2024, 11:29:46", + "recorded-date": "25-11-2025, 02:27:27", "recorded-content": { "wrong_region_exception": { "Error": { @@ -1010,7 +1011,7 @@ } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_get_function_wrong_region[delete_function]": { - "recorded-date": "12-09-2024, 11:29:48", + "recorded-date": "25-11-2025, 02:27:29", "recorded-content": { "wrong_region_exception": { "Error": { @@ -1027,7 +1028,7 @@ } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_get_function_wrong_region[invoke]": { - "recorded-date": "12-09-2024, 11:29:50", + "recorded-date": "25-11-2025, 02:27:32", "recorded-content": { "wrong_region_exception": { "Error": { @@ -1044,7 +1045,7 @@ } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_lambda_code_location_zipfile": { - "recorded-date": "12-09-2024, 11:29:52", + "recorded-date": "25-11-2025, 02:27:35", "recorded-content": { "create-response-zip-file": { "Architectures": [ @@ -1234,7 +1235,7 @@ } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_lambda_code_location_s3": { - "recorded-date": "12-09-2024, 11:29:57", + "recorded-date": "25-11-2025, 02:27:41", "recorded-content": { "create_response_s3": { "Architectures": [ @@ -1424,7 +1425,7 @@ } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaVersions::test_publish_version_on_create": { - "recorded-date": "10-04-2024, 09:12:04", + "recorded-date": "25-11-2025, 02:38:24", "recorded-content": { "create_response": { "Architectures": [ @@ -1806,7 +1807,7 @@ } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaVersions::test_version_lifecycle": { - "recorded-date": "12-07-2024, 11:43:40", + "recorded-date": "25-11-2025, 02:38:32", "recorded-content": { "create_response": { "Architectures": [ @@ -2641,7 +2642,7 @@ } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaVersions::test_publish_with_wrong_sha256": { - "recorded-date": "10-04-2024, 09:12:15", + "recorded-date": "25-11-2025, 02:38:35", "recorded-content": { "create_response": { "Architectures": [ @@ -2791,7 +2792,7 @@ } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaVersions::test_publish_with_update": { - "recorded-date": "10-04-2024, 09:12:18", + "recorded-date": "25-11-2025, 02:38:38", "recorded-content": { "create_response": { "Architectures": [ @@ -3029,7 +3030,7 @@ } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaAlias::test_alias_lifecycle": { - "recorded-date": "21-11-2024, 13:44:49", + "recorded-date": "25-11-2025, 02:38:45", "recorded-content": { "create_response": { "Architectures": [ @@ -3621,7 +3622,7 @@ } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaAlias::test_notfound_and_invalid_routingconfigs": { - "recorded-date": "21-11-2024, 13:45:06", + "recorded-date": "25-11-2025, 21:33:38", "recorded-content": { "create_response": { "Architectures": [ @@ -3847,7 +3848,7 @@ "routing_config_exc_version_latest": { "Error": { "Code": "ValidationException", - "Message": "1 validation error detected: Value '{$LATEST=0.5}' at 'routingConfig.additionalVersionWeights' failed to satisfy constraint: Map keys must satisfy constraint: [Member must have length less than or equal to 1024, Member must have length greater than or equal to 1, Member must satisfy regular expression pattern: [0-9]+, Member must not be null]" + "Message": "1 validation error detected: Value '{$LATEST=0.5}' at 'routingConfig.additionalVersionWeights' failed to satisfy constraint: Map keys must satisfy constraint: [Member must have length less than or equal to 1024, Member must have length greater than or equal to 1, Member must satisfy regular expression pattern: [0-9]+]" }, "ResponseMetadata": { "HTTPHeaders": {}, @@ -3931,7 +3932,7 @@ } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaTag::test_create_tag_on_fn_create": { - "recorded-date": "10-04-2024, 09:13:05", + "recorded-date": "25-11-2025, 02:39:21", "recorded-content": { "get_function_result": { "Code": { @@ -4114,7 +4115,7 @@ } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaTag::test_tag_nonexisting_resource": { - "recorded-date": "10-04-2024, 09:13:14", + "recorded-date": "25-11-2025, 02:39:54", "recorded-content": { "pre_delete_get_function": { "Code": { @@ -4206,7 +4207,7 @@ } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaEventInvokeConfig::test_lambda_eventinvokeconfig_exceptions": { - "recorded-date": "10-04-2024, 09:13:39", + "recorded-date": "25-11-2025, 21:39:31", "recorded-content": { "fn_version_result": { "Architectures": [ @@ -4377,7 +4378,7 @@ "put_destination_invalid_arn_pattern": { "Error": { "Code": "ValidationException", - "Message": "1 validation error detected: Value 'arn::_-/!lambda::111111111111:function:' at 'destinationConfig.onFailure.destination' failed to satisfy constraint: Member must satisfy regular expression pattern: ^$|arn:(aws[a-zA-Z0-9-]*):([a-zA-Z0-9\\-])+:([a-z]{2}((-gov)|(-iso(b?)))?-[a-z]+-\\d{1})?:(\\d{12})?:(.*)" + "Message": "1 validation error detected: Value 'arn::_-/!lambda::111111111111:function:' at 'destinationConfig.onFailure.destination' failed to satisfy constraint: Member must satisfy regular expression pattern: $|kafka://([^.]([a-zA-Z0-9\\-_.]{0,248}))|arn:(aws[a-zA-Z0-9-]*):([a-zA-Z0-9\\-])+:((eusc-)?[a-z]{2}((-gov)|(-iso([a-z]?)))?-[a-z]+-\\d{1})?:(\\d{12})?:(.*)" }, "ResponseMetadata": { "HTTPHeaders": {}, @@ -4867,7 +4868,7 @@ } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaReservedConcurrency::test_function_concurrency_exceptions": { - "recorded-date": "10-04-2024, 09:13:44", + "recorded-date": "25-11-2025, 02:40:18", "recorded-content": { "put_function_concurrency_with_function_name_doesnotexist": { "Error": { @@ -4908,7 +4909,7 @@ } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaReservedConcurrency::test_function_concurrency": { - "recorded-date": "10-04-2024, 09:13:51", + "recorded-date": "25-11-2025, 02:40:29", "recorded-content": { "put_function_concurrency_with_reserved_0": { "ReservedConcurrentExecutions": 0, @@ -4946,7 +4947,7 @@ } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaPermissions::test_add_lambda_permission_aws": { - "recorded-date": "10-04-2024, 09:16:23", + "recorded-date": "25-11-2025, 02:42:56", "recorded-content": { "create_lambda": { "CreateEventSourceMappingResponse": null, @@ -5047,7 +5048,7 @@ } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaPermissions::test_remove_multi_permissions": { - "recorded-date": "10-04-2024, 09:16:38", + "recorded-date": "25-11-2025, 02:43:09", "recorded-content": { "add_permission_1": { "Statement": { @@ -5191,7 +5192,7 @@ } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaPermissions::test_create_multiple_lambda_permissions": { - "recorded-date": "10-04-2024, 09:16:41", + "recorded-date": "25-11-2025, 02:43:12", "recorded-content": { "add_permission_response_1": { "Statement": { @@ -5257,7 +5258,7 @@ } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaUrl::test_url_config_lifecycle": { - "recorded-date": "21-11-2024, 13:44:13", + "recorded-date": "25-11-2025, 02:43:27", "recorded-content": { "url_creation": { "AuthType": "NONE", @@ -5336,7 +5337,7 @@ } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaSizeLimits::test_large_lambda": { - "recorded-date": "10-04-2024, 09:18:29", + "recorded-date": "25-11-2025, 02:46:01", "recorded-content": { "create_function_large_zip": { "Architectures": [ @@ -5384,7 +5385,7 @@ } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaSizeLimits::test_large_environment_variables_fails": { - "recorded-date": "10-04-2024, 09:18:46", + "recorded-date": "25-11-2025, 02:46:19", "recorded-content": { "failed_create_fn_result": { "Error": { @@ -5401,7 +5402,7 @@ } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaSizeLimits::test_large_environment_fails_multiple_keys": { - "recorded-date": "10-04-2024, 09:19:04", + "recorded-date": "25-11-2025, 02:46:36", "recorded-content": { "failured_create_fn_result_multi_key": { "Error": { @@ -5418,7 +5419,7 @@ } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaSizeLimits::test_lambda_envvars_near_limit_succeeds": { - "recorded-date": "10-04-2024, 09:19:07", + "recorded-date": "25-11-2025, 02:46:39", "recorded-content": { "successful_create_fn_result": { "CreateEventSourceMappingResponse": null, @@ -5474,7 +5475,7 @@ } }, "tests/aws/services/lambda_/test_lambda_api.py::TestCodeSigningConfig::test_function_code_signing_config": { - "recorded-date": "10-04-2024, 09:19:11", + "recorded-date": "25-11-2025, 02:46:42", "recorded-content": { "create_code_signing_config": { "CodeSigningConfig": { @@ -5590,7 +5591,7 @@ } }, "tests/aws/services/lambda_/test_lambda_api.py::TestCodeSigningConfig::test_code_signing_not_found_excs": { - "recorded-date": "10-04-2024, 09:19:16", + "recorded-date": "25-11-2025, 02:46:47", "recorded-content": { "create_code_signing_config": { "CodeSigningConfig": { @@ -5769,7 +5770,7 @@ } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaAccountSettings::test_account_settings": { - "recorded-date": "10-04-2024, 09:19:17", + "recorded-date": "25-11-2025, 02:46:47", "recorded-content": { "acc_settings_modded": { "AccountLimit": [ @@ -5791,7 +5792,7 @@ } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaEventSourceMappings::test_event_source_mapping_exceptions": { - "recorded-date": "05-12-2024, 10:52:30", + "recorded-date": "27-11-2025, 01:04:32", "recorded-content": { "get_unknown_uuid": { "Error": { @@ -5868,7 +5869,7 @@ } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaEventSourceMappings::test_event_source_mapping_lifecycle": { - "recorded-date": "14-10-2024, 12:36:57", + "recorded-date": "25-11-2025, 02:47:33", "recorded-content": { "update_table_response": { "TableDescription": { @@ -5906,7 +5907,12 @@ "TableId": "", "TableName": "", "TableSizeBytes": 0, - "TableStatus": "UPDATING" + "TableStatus": "UPDATING", + "WarmThroughput": { + "ReadUnitsPerSecond": 12000, + "Status": "ACTIVE", + "WriteUnitsPerSecond": 4000 + } }, "ResponseMetadata": { "HTTPHeaders": {}, @@ -6000,12 +6006,12 @@ } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaTags::test_tag_exceptions": { - "recorded-date": "24-10-2024, 15:22:29", + "recorded-date": "25-11-2025, 02:48:27", "recorded-content": { "tag_lambda_invalidarn": { "Error": { "Code": "ValidationException", - "Message": "1 validation error detected: Value 'arn::something' at 'resource' failed to satisfy constraint: Member must satisfy regular expression pattern: arn:(aws[a-zA-Z-]*):lambda:[a-z]{2}((-gov)|(-iso([a-z]?)))?-[a-z]+-\\d{1}:\\d{12}:(function:[a-zA-Z0-9-_]+(:(\\$LATEST|[a-zA-Z0-9-_]+))?|layer:([a-zA-Z0-9-_]+)|code-signing-config:csc-[a-z0-9]{17}|event-source-mapping:[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12})" + "Message": "1 validation error detected: Value 'arn::something' at 'resource' failed to satisfy constraint: Member must satisfy regular expression pattern: arn:(aws[a-zA-Z-]*):lambda:(eusc-)?[a-z]{2}((-gov)|(-iso([a-z]?)))?-[a-z]+-\\d{1}:\\d{12}:(function:[a-zA-Z0-9-_]+(:(\\$LATEST|[a-zA-Z0-9-_]+))?|layer:([a-zA-Z0-9-_]+)|code-signing-config:csc-[a-z0-9]{17}|event-source-mapping:[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}|capacity-provider:[a-zA-Z0-9-_]+)" }, "ResponseMetadata": { "HTTPHeaders": {}, @@ -6074,7 +6080,7 @@ } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaTags::test_tag_limits": { - "recorded-date": "28-10-2024, 14:16:38", + "recorded-date": "25-11-2025, 02:48:31", "recorded-content": { "tag_lambda_too_many_tags": { "Error": { @@ -6282,7 +6288,7 @@ } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaTags::test_tag_lifecycle": { - "recorded-date": "24-10-2024, 15:22:49", + "recorded-date": "25-11-2025, 02:48:38", "recorded-content": { "list_tags_response_postfncreate": { "Tags": { @@ -6641,7 +6647,7 @@ } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaProvisionedConcurrency::test_provisioned_concurrency_exceptions": { - "recorded-date": "10-04-2024, 09:13:57", + "recorded-date": "25-11-2025, 02:40:34", "recorded-content": { "publish_version_result": { "Architectures": [ @@ -6894,7 +6900,7 @@ } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaProvisionedConcurrency::test_lambda_provisioned_lifecycle": { - "recorded-date": "10-04-2024, 09:16:15", + "recorded-date": "25-11-2025, 02:42:49", "recorded-content": { "publish_version_result": { "Architectures": [ @@ -7044,7 +7050,7 @@ } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaSizeLimits::test_oversized_request_create_lambda": { - "recorded-date": "10-04-2024, 09:17:14", + "recorded-date": "25-11-2025, 02:44:03", "recorded-content": { "invalid_param_exc": { "Error": { @@ -7059,7 +7065,7 @@ } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaTags::test_tag_versions": { - "recorded-date": "24-10-2024, 15:22:40", + "recorded-date": "25-11-2025, 02:48:33", "recorded-content": { "tag_resource_exception": { "Error": { @@ -7088,7 +7094,7 @@ } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaUrl::test_url_config_list_paging": { - "recorded-date": "21-11-2024, 13:44:10", + "recorded-date": "25-11-2025, 02:43:23", "recorded-content": { "fn_version_result": { "Architectures": [ @@ -7212,7 +7218,7 @@ } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaUrl::test_url_config_exceptions": { - "recorded-date": "21-11-2024, 13:44:05", + "recorded-date": "25-11-2025, 02:43:19", "recorded-content": { "fn_version_result": { "Architectures": [ @@ -7650,7 +7656,7 @@ } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaPermissions::test_permission_exceptions": { - "recorded-date": "10-04-2024, 09:16:20", + "recorded-date": "25-11-2025, 02:42:53", "recorded-content": { "add_permission_invalid_statement_id": { "Error": { @@ -7701,9 +7707,9 @@ "get_policy_fn_doesnotexist": { "Error": { "Code": "ResourceNotFoundException", - "Message": "Function not found: arn::lambda::111111111111:function:doesnotexist" + "Message": "The resource you requested does not exist." }, - "Message": "Function not found: arn::lambda::111111111111:function:doesnotexist", + "Message": "The resource you requested does not exist.", "Type": "User", "ResponseMetadata": { "HTTPHeaders": {}, @@ -7773,7 +7779,7 @@ "add_permission_fn_qualifier_invalid": { "Error": { "Code": "ValidationException", - "Message": "1 validation error detected: Value 'invalid-qualifier-with-?-char' at 'qualifier' failed to satisfy constraint: Member must satisfy regular expression pattern: (|[a-zA-Z0-9$_-]+)" + "Message": "1 validation error detected: Value 'invalid-qualifier-with-?-char' at 'qualifier' failed to satisfy constraint: Member must satisfy regular expression pattern: \\$(LATEST(\\.PUBLISHED)?)|[a-zA-Z0-9-_$]+" }, "ResponseMetadata": { "HTTPHeaders": {}, @@ -7831,7 +7837,7 @@ } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaSizeLimits::test_oversized_unzipped_lambda": { - "recorded-date": "10-04-2024, 09:17:47", + "recorded-date": "25-11-2025, 02:45:12", "recorded-content": { "invalid_param_exc": { "Error": { @@ -7848,7 +7854,7 @@ } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_create_lambda_exceptions": { - "recorded-date": "01-04-2025, 13:08:21", + "recorded-date": "12-01-2026, 15:31:24", "recorded-content": { "invalid_role_arn_exc": { "Error": { @@ -7863,10 +7869,10 @@ "invalid_runtime_exc": { "Error": { "Code": "InvalidParameterValueException", - "Message": "Value non-existent-runtime at 'runtime' failed to satisfy constraint: Member must satisfy enum value set: [nodejs20.x, provided.al2023, python3.12, python3.13, nodejs22.x, java17, nodejs16.x, dotnet8, python3.10, java11, python3.11, dotnet6, java21, nodejs18.x, provided.al2, ruby3.3, ruby3.4, java8.al2, ruby3.2, python3.8, python3.9] or be a valid ARN" + "Message": "Value non-existent-runtime at 'runtime' failed to satisfy constraint: Member must satisfy enum value set: [nodejs20.x, python3.14, provided.al2023, python3.12, python3.13, nodejs24.x, nodejs22.x, java25, python3.10, python3.11, java21, ruby3.3, ruby3.4, ruby3.2, python3.8, python3.9, java17, nodejs16.x, dotnet10, dotnet8, java11, dotnet6, nodejs18.x, provided.al2, java8.al2] or be a valid ARN" }, "Type": "User", - "message": "Value non-existent-runtime at 'runtime' failed to satisfy constraint: Member must satisfy enum value set: [nodejs20.x, provided.al2023, python3.12, python3.13, nodejs22.x, java17, nodejs16.x, dotnet8, python3.10, java11, python3.11, dotnet6, java21, nodejs18.x, provided.al2, ruby3.3, ruby3.4, java8.al2, ruby3.2, python3.8, python3.9] or be a valid ARN", + "message": "Value non-existent-runtime at 'runtime' failed to satisfy constraint: Member must satisfy enum value set: [nodejs20.x, python3.14, provided.al2023, python3.12, python3.13, nodejs24.x, nodejs22.x, java25, python3.10, python3.11, java21, ruby3.3, ruby3.4, ruby3.2, python3.8, python3.9, java17, nodejs16.x, dotnet10, dotnet8, java11, dotnet6, nodejs18.x, provided.al2, java8.al2] or be a valid ARN", "ResponseMetadata": { "HTTPHeaders": {}, "HTTPStatusCode": 400 @@ -7875,10 +7881,10 @@ "uppercase_runtime_exc": { "Error": { "Code": "InvalidParameterValueException", - "Message": "Value PYTHON3.9 at 'runtime' failed to satisfy constraint: Member must satisfy enum value set: [nodejs20.x, provided.al2023, python3.12, python3.13, nodejs22.x, java17, nodejs16.x, dotnet8, python3.10, java11, python3.11, dotnet6, java21, nodejs18.x, provided.al2, ruby3.3, ruby3.4, java8.al2, ruby3.2, python3.8, python3.9] or be a valid ARN" + "Message": "Value PYTHON3.9 at 'runtime' failed to satisfy constraint: Member must satisfy enum value set: [nodejs20.x, python3.14, provided.al2023, python3.12, python3.13, nodejs24.x, nodejs22.x, java25, python3.10, python3.11, java21, ruby3.3, ruby3.4, ruby3.2, python3.8, python3.9, java17, nodejs16.x, dotnet10, dotnet8, java11, dotnet6, nodejs18.x, provided.al2, java8.al2] or be a valid ARN" }, "Type": "User", - "message": "Value PYTHON3.9 at 'runtime' failed to satisfy constraint: Member must satisfy enum value set: [nodejs20.x, provided.al2023, python3.12, python3.13, nodejs22.x, java17, nodejs16.x, dotnet8, python3.10, java11, python3.11, dotnet6, java21, nodejs18.x, provided.al2, ruby3.3, ruby3.4, java8.al2, ruby3.2, python3.8, python3.9] or be a valid ARN", + "message": "Value PYTHON3.9 at 'runtime' failed to satisfy constraint: Member must satisfy enum value set: [nodejs20.x, python3.14, provided.al2023, python3.12, python3.13, nodejs24.x, nodejs22.x, java25, python3.10, python3.11, java21, ruby3.3, ruby3.4, ruby3.2, python3.8, python3.9, java17, nodejs16.x, dotnet10, dotnet8, java11, dotnet6, nodejs18.x, provided.al2, java8.al2] or be a valid ARN", "ResponseMetadata": { "HTTPHeaders": {}, "HTTPStatusCode": 400 @@ -7920,7 +7926,7 @@ } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_update_lambda_exceptions": { - "recorded-date": "01-04-2025, 13:09:51", + "recorded-date": "12-01-2026, 15:31:27", "recorded-content": { "invalid_role_arn_exc": { "Error": { @@ -7935,10 +7941,10 @@ "invalid_runtime_exc": { "Error": { "Code": "InvalidParameterValueException", - "Message": "Value non-existent-runtime at 'runtime' failed to satisfy constraint: Member must satisfy enum value set: [nodejs20.x, provided.al2023, python3.12, python3.13, nodejs22.x, java17, nodejs16.x, dotnet8, python3.10, java11, python3.11, dotnet6, java21, nodejs18.x, provided.al2, ruby3.3, ruby3.4, java8.al2, ruby3.2, python3.8, python3.9] or be a valid ARN" + "Message": "Value non-existent-runtime at 'runtime' failed to satisfy constraint: Member must satisfy enum value set: [nodejs20.x, python3.14, provided.al2023, python3.12, python3.13, nodejs24.x, nodejs22.x, java25, python3.10, python3.11, java21, ruby3.3, ruby3.4, ruby3.2, python3.8, python3.9, java17, nodejs16.x, dotnet10, dotnet8, java11, dotnet6, nodejs18.x, provided.al2, java8.al2] or be a valid ARN" }, "Type": "User", - "message": "Value non-existent-runtime at 'runtime' failed to satisfy constraint: Member must satisfy enum value set: [nodejs20.x, provided.al2023, python3.12, python3.13, nodejs22.x, java17, nodejs16.x, dotnet8, python3.10, java11, python3.11, dotnet6, java21, nodejs18.x, provided.al2, ruby3.3, ruby3.4, java8.al2, ruby3.2, python3.8, python3.9] or be a valid ARN", + "message": "Value non-existent-runtime at 'runtime' failed to satisfy constraint: Member must satisfy enum value set: [nodejs20.x, python3.14, provided.al2023, python3.12, python3.13, nodejs24.x, nodejs22.x, java25, python3.10, python3.11, java21, ruby3.3, ruby3.4, ruby3.2, python3.8, python3.9, java17, nodejs16.x, dotnet10, dotnet8, java11, dotnet6, nodejs18.x, provided.al2, java8.al2] or be a valid ARN", "ResponseMetadata": { "HTTPHeaders": {}, "HTTPStatusCode": 400 @@ -7947,10 +7953,10 @@ "uppercase_runtime_exc": { "Error": { "Code": "InvalidParameterValueException", - "Message": "Value PYTHON3.9 at 'runtime' failed to satisfy constraint: Member must satisfy enum value set: [nodejs20.x, provided.al2023, python3.12, python3.13, nodejs22.x, java17, nodejs16.x, dotnet8, python3.10, java11, python3.11, dotnet6, java21, nodejs18.x, provided.al2, ruby3.3, ruby3.4, java8.al2, ruby3.2, python3.8, python3.9] or be a valid ARN" + "Message": "Value PYTHON3.9 at 'runtime' failed to satisfy constraint: Member must satisfy enum value set: [nodejs20.x, python3.14, provided.al2023, python3.12, python3.13, nodejs24.x, nodejs22.x, java25, python3.10, python3.11, java21, ruby3.3, ruby3.4, ruby3.2, python3.8, python3.9, java17, nodejs16.x, dotnet10, dotnet8, java11, dotnet6, nodejs18.x, provided.al2, java8.al2] or be a valid ARN" }, "Type": "User", - "message": "Value PYTHON3.9 at 'runtime' failed to satisfy constraint: Member must satisfy enum value set: [nodejs20.x, provided.al2023, python3.12, python3.13, nodejs22.x, java17, nodejs16.x, dotnet8, python3.10, java11, python3.11, dotnet6, java21, nodejs18.x, provided.al2, ruby3.3, ruby3.4, java8.al2, ruby3.2, python3.8, python3.9] or be a valid ARN", + "message": "Value PYTHON3.9 at 'runtime' failed to satisfy constraint: Member must satisfy enum value set: [nodejs20.x, python3.14, provided.al2023, python3.12, python3.13, nodejs24.x, nodejs22.x, java25, python3.10, python3.11, java21, ruby3.3, ruby3.4, ruby3.2, python3.8, python3.9, java17, nodejs16.x, dotnet10, dotnet8, java11, dotnet6, nodejs18.x, provided.al2, java8.al2] or be a valid ARN", "ResponseMetadata": { "HTTPHeaders": {}, "HTTPStatusCode": 400 @@ -7959,7 +7965,7 @@ } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_list_functions": { - "recorded-date": "12-09-2024, 11:30:20", + "recorded-date": "25-11-2025, 02:28:15", "recorded-content": { "create_response_1": { "CreateEventSourceMappingResponse": null, @@ -8260,7 +8266,7 @@ } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaLayer::test_layer_exceptions": { - "recorded-date": "01-04-2025, 13:19:20", + "recorded-date": "12-01-2026, 15:31:58", "recorded-content": { "publish_result": { "CompatibleArchitectures": [ @@ -8287,7 +8293,7 @@ "list_layers_exc_compatibleruntime_invalid": { "Error": { "Code": "ValidationException", - "Message": "1 validation error detected: Value 'runtimedoesnotexist' at 'compatibleRuntime' failed to satisfy constraint: Member must satisfy enum value set: [ruby2.6, dotnetcore1.0, python3.7, nodejs8.10, nasa, ruby2.7, python2.7-greengrass, dotnetcore2.0, python3.8, java21, dotnet6, dotnetcore2.1, python3.9, java11, nodejs6.10, provided, dotnetcore3.1, dotnet8, java25, java17, nodejs, nodejs4.3, java8.al2, go1.x, dotnet10, nodejs20.x, go1.9, byol, nodejs10.x, provided.al2023, nodejs22.x, python3.10, java8, nodejs12.x, python3.11, nodejs24.x, nodejs8.x, python3.12, nodejs14.x, nodejs8.9, python3.13, python3.14, nodejs16.x, provided.al2, nodejs4.3-edge, nodejs18.x, ruby3.2, python3.4, ruby3.3, ruby3.4, ruby2.5, python3.6, python2.7]" + "Message": "1 validation error detected: Value 'runtimedoesnotexist' at 'compatibleRuntime' failed to satisfy constraint: Member must satisfy enum value set: [ruby3.5, ruby2.6, dotnetcore1.0, python3.7, nodejs8.10, nasa, ruby2.7, python2.7-greengrass, dotnetcore2.0, python3.8, java21, dotnet6, dotnetcore2.1, python3.9, java11, nodejs6.10, provided, dotnetcore3.1, dotnet8, java25, java17, nodejs, nodejs4.3, java8.al2, go1.x, dotnet10, nodejs20.x, go1.9, byol, nodejs10.x, provided.al2023, nodejs22.x, python3.10, java8, nodejs12.x, python3.11, nodejs24.x, nodejs8.x, python3.12, nodejs14.x, nodejs8.9, nodejs26.x, python3.13, python3.14, nodejs16.x, python3.15, provided.al2, nodejs4.3-edge, nodejs18.x, ruby3.2, python3.4, ruby3.3, ruby3.4, ruby2.5, python3.6, python2.7]" }, "ResponseMetadata": { "HTTPHeaders": {}, @@ -8362,7 +8368,7 @@ "get_layer_version_by_arn_exc_invalidarn": { "Error": { "Code": "ValidationException", - "Message": "1 validation error detected: Value 'arn::lambda::111111111111:layer:' at 'arn' failed to satisfy constraint: Member must satisfy regular expression pattern: (arn:(aws[a-zA-Z-]*)?:lambda:[a-z]{2}((-gov)|(-iso([a-z]?)))?-[a-z]+-\\d{1}:\\d{12}:layer:[a-zA-Z0-9-_]+:[0-9]+)|(arn:[a-zA-Z0-9-]+:lambda:::awslayer:[a-zA-Z0-9-_]+)" + "Message": "1 validation error detected: Value 'arn::lambda::111111111111:layer:' at 'arn' failed to satisfy constraint: Member must satisfy regular expression pattern: (arn:(aws[a-zA-Z-]*)?:lambda:(eusc-)?[a-z]{2}((-gov)|(-iso([a-z]?)))?-[a-z]+-\\d{1}:\\d{12}:layer:[a-zA-Z0-9-_]+:[0-9]+)|(arn:[a-zA-Z0-9-]+:lambda:::awslayer:[a-zA-Z0-9-_]+)" }, "ResponseMetadata": { "HTTPHeaders": {}, @@ -8438,7 +8444,7 @@ "publish_layer_version_exc_invalid_runtime_arch": { "Error": { "Code": "ValidationException", - "Message": "2 validation errors detected: Value '[invalidruntime]' at 'compatibleRuntimes' failed to satisfy constraint: Member must satisfy enum value set: [nodejs20.x, provided.al2023, python3.12, python3.13, nodejs22.x, java17, nodejs16.x, dotnet8, python3.10, java11, python3.11, dotnet6, java21, nodejs18.x, provided.al2, ruby3.3, ruby3.4, java8.al2, ruby3.2, python3.8, python3.9]; Value '[invalidarch]' at 'compatibleArchitectures' failed to satisfy constraint: Member must satisfy constraint: [Member must satisfy enum value set: [x86_64, arm64]]" + "Message": "2 validation errors detected: Value '[invalidruntime]' at 'compatibleRuntimes' failed to satisfy constraint: Member must satisfy enum value set: [nodejs20.x, python3.14, provided.al2023, python3.12, python3.13, nodejs24.x, nodejs22.x, java25, python3.10, python3.11, java21, ruby3.3, ruby3.4, ruby3.2, python3.8, python3.9, java17, nodejs16.x, dotnet10, dotnet8, java11, dotnet6, nodejs18.x, provided.al2, java8.al2]; Value '[invalidarch]' at 'compatibleArchitectures' failed to satisfy constraint: Member must satisfy constraint: [Member must satisfy enum value set: [x86_64, arm64], Member must not be null]" }, "ResponseMetadata": { "HTTPHeaders": {}, @@ -8448,7 +8454,7 @@ "publish_layer_version_exc_partially_invalid_values": { "Error": { "Code": "ValidationException", - "Message": "2 validation errors detected: Value '[invalidruntime, invalidruntime2, nodejs20.x]' at 'compatibleRuntimes' failed to satisfy constraint: Member must satisfy enum value set: [nodejs20.x, provided.al2023, python3.12, python3.13, nodejs22.x, java17, nodejs16.x, dotnet8, python3.10, java11, python3.11, dotnet6, java21, nodejs18.x, provided.al2, ruby3.3, ruby3.4, java8.al2, ruby3.2, python3.8, python3.9]; Value '[invalidarch, x86_64]' at 'compatibleArchitectures' failed to satisfy constraint: Member must satisfy constraint: [Member must satisfy enum value set: [x86_64, arm64]]" + "Message": "2 validation errors detected: Value '[invalidruntime, invalidruntime2, nodejs20.x]' at 'compatibleRuntimes' failed to satisfy constraint: Member must satisfy enum value set: [nodejs20.x, python3.14, provided.al2023, python3.12, python3.13, nodejs24.x, nodejs22.x, java25, python3.10, python3.11, java21, ruby3.3, ruby3.4, ruby3.2, python3.8, python3.9, java17, nodejs16.x, dotnet10, dotnet8, java11, dotnet6, nodejs18.x, provided.al2, java8.al2]; Value '[invalidarch, x86_64]' at 'compatibleArchitectures' failed to satisfy constraint: Member must satisfy constraint: [Member must satisfy enum value set: [x86_64, arm64], Member must not be null]" }, "ResponseMetadata": { "HTTPHeaders": {}, @@ -8458,7 +8464,7 @@ } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaLayer::test_layer_lifecycle": { - "recorded-date": "10-04-2024, 09:24:17", + "recorded-date": "25-11-2025, 02:50:43", "recorded-content": { "get_fn_result": { "Code": { @@ -8882,7 +8888,7 @@ } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaLayer::test_layer_policy_exceptions": { - "recorded-date": "10-04-2024, 09:24:29", + "recorded-date": "25-11-2025, 02:50:51", "recorded-content": { "publish_result": { "CompatibleArchitectures": [ @@ -9065,7 +9071,7 @@ } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaLayer::test_layer_policy_lifecycle": { - "recorded-date": "10-04-2024, 09:24:35", + "recorded-date": "25-11-2025, 02:50:55", "recorded-content": { "publish_result": { "CompatibleArchitectures": [ @@ -9193,7 +9199,7 @@ } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaLayer::test_layer_s3_content": { - "recorded-date": "10-04-2024, 09:24:23", + "recorded-date": "25-11-2025, 02:50:45", "recorded-content": { "publish_layer_result": { "Content": { @@ -9214,7 +9220,7 @@ } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaLayer::test_layer_function_exceptions": { - "recorded-date": "10-04-2024, 09:23:19", + "recorded-date": "25-11-2025, 21:58:40", "recorded-content": { "publish_result": { "CompatibleArchitectures": [ @@ -9390,7 +9396,7 @@ "add_layer_arn_without_version_exc": { "Error": { "Code": "ValidationException", - "Message": "1 validation error detected: Value '[arn::lambda::111111111111:layer:]' at 'layers' failed to satisfy constraint: Member must satisfy constraint: [Member must have length less than or equal to 140, Member must have length greater than or equal to 1, Member must satisfy regular expression pattern: (arn:[a-zA-Z0-9-]+:lambda:[a-z]{2}((-gov)|(-iso(b?)))?-[a-z]+-\\d{1}:\\d{12}:layer:[a-zA-Z0-9-_]+:[0-9]+)|(arn:[a-zA-Z0-9-]+:lambda:::awslayer:[a-zA-Z0-9-_]+), Member must not be null]" + "Message": "1 validation error detected: Value '[arn::lambda::111111111111:layer:]' at 'layers' failed to satisfy constraint: Member must satisfy constraint: [Member must have length less than or equal to 2048, Member must have length greater than or equal to 1, Member must satisfy regular expression pattern: (arn:(aws[a-zA-Z-]*)?:lambda:(eusc-)?[a-z]{2}((-gov)|(-iso([a-z]?)))?-[a-z]+-\\d{1}:\\d{12}:layer:[a-zA-Z0-9-_]+:[0-9]+)|(arn:[a-zA-Z0-9-]+:lambda:::awslayer:[a-zA-Z0-9-_]+), Member must not be null]" }, "ResponseMetadata": { "HTTPHeaders": {}, @@ -9412,7 +9418,7 @@ } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaImages::test_lambda_image_crud": { - "recorded-date": "10-04-2024, 09:10:21", + "recorded-date": "25-11-2025, 02:37:05", "recorded-content": { "create-image-response": { "Architectures": [ @@ -9698,7 +9704,7 @@ } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaImages::test_lambda_image_and_image_config_crud": { - "recorded-date": "10-04-2024, 09:11:14", + "recorded-date": "25-11-2025, 02:37:44", "recorded-content": { "create-image-with-config-response": { "Architectures": [ @@ -10170,7 +10176,7 @@ } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaImages::test_lambda_zip_file_to_image": { - "recorded-date": "10-04-2024, 09:10:38", + "recorded-date": "25-11-2025, 02:37:15", "recorded-content": { "create-image-response": { "Architectures": [ @@ -10410,7 +10416,7 @@ } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaAccountSettings::test_account_settings_total_code_size": { - "recorded-date": "10-04-2024, 09:19:29", + "recorded-date": "25-11-2025, 02:46:59", "recorded-content": { "total_code_size_diff_create_function": 276, "total_code_size_diff_update_function": 276, @@ -10419,7 +10425,7 @@ } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaAccountSettings::test_account_settings_total_code_size_config_update": { - "recorded-date": "10-04-2024, 09:19:35", + "recorded-date": "25-11-2025, 02:47:04", "recorded-content": { "is_total_code_size_diff_create_function_more_than_200": true, "total_code_size_diff_update_function_configuration": 0, @@ -10427,7 +10433,7 @@ } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaEventInvokeConfig::test_lambda_eventinvokeconfig_lifecycle": { - "recorded-date": "10-04-2024, 09:13:21", + "recorded-date": "25-11-2025, 02:40:00", "recorded-content": { "put_invokeconfig_retries_0": { "DestinationConfig": { @@ -10794,7 +10800,7 @@ } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaPermissions::test_add_lambda_permission_fields": { - "recorded-date": "10-04-2024, 09:16:33", + "recorded-date": "25-11-2025, 02:43:05", "recorded-content": { "add_permission_principal_wildcard": { "Statement": { @@ -10913,7 +10919,7 @@ } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaPermissions::test_lambda_permission_fn_versioning": { - "recorded-date": "10-04-2024, 09:16:29", + "recorded-date": "25-11-2025, 21:46:15", "recorded-content": { "add_permission": { "Statement": { @@ -11079,7 +11085,7 @@ } ] }, - "RevisionId": "", + "RevisionId": "", "ResponseMetadata": { "HTTPHeaders": {}, "HTTPStatusCode": 200 @@ -11149,10 +11155,10 @@ "add_permission_alias_revision_exception": { "Error": { "Code": "PreconditionFailedException", - "Message": "The Revision Id provided does not match the latest Revision Id. Call the GetFunction/GetAlias API to retrieve the latest Revision Id" + "Message": "The Revision Id provided does not match the latest Revision Id. Call the GetPolicy API to retrieve the latest Revision Id" }, "Type": "User", - "message": "The Revision Id provided does not match the latest Revision Id. Call the GetFunction/GetAlias API to retrieve the latest Revision Id", + "message": "The Revision Id provided does not match the latest Revision Id. Call the GetPolicy API to retrieve the latest Revision Id", "ResponseMetadata": { "HTTPHeaders": {}, "HTTPStatusCode": 412 @@ -11206,7 +11212,7 @@ } ] }, - "RevisionId": "", + "RevisionId": "", "ResponseMetadata": { "HTTPHeaders": {}, "HTTPStatusCode": 200 @@ -11554,7 +11560,7 @@ } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaRevisions::test_function_revisions_basic": { - "recorded-date": "10-04-2024, 09:12:53", + "recorded-date": "25-11-2025, 02:39:11", "recorded-content": { "create_function_response_rev1": { "CreateEventSourceMappingResponse": null, @@ -11879,7 +11885,7 @@ } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaRevisions::test_function_revisions_version_and_alias": { - "recorded-date": "10-04-2024, 09:12:58", + "recorded-date": "25-11-2025, 02:39:15", "recorded-content": { "create_function_response_rev1": { "CreateEventSourceMappingResponse": null, @@ -12279,79 +12285,33 @@ } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaRevisions::test_function_revisions_permissions": { - "recorded-date": "10-04-2024, 09:13:02", + "recorded-date": "25-11-2025, 03:29:57", "recorded-content": { "add_permission_revision_exception": { "Error": { "Code": "PreconditionFailedException", - "Message": "The Revision Id provided does not match the latest Revision Id. Call the GetFunction/GetAlias API to retrieve the latest Revision Id" + "Message": "The Revision Id provided does not match the latest Revision Id. Call the GetPolicy API to retrieve the latest Revision Id" }, "Type": "User", - "message": "The Revision Id provided does not match the latest Revision Id. Call the GetFunction/GetAlias API to retrieve the latest Revision Id", + "message": "The Revision Id provided does not match the latest Revision Id. Call the GetPolicy API to retrieve the latest Revision Id", "ResponseMetadata": { - "HTTPHeaders": {}, - "HTTPStatusCode": 412 - } - }, - "add_permission_response": { - "Statement": { - "Sid": "s3", - "Effect": "Allow", - "Principal": { - "Service": "s3.amazonaws.com" + "HTTPHeaders": { + "connection": "keep-alive", + "content-length": "149", + "content-type": "application/json", + "date": "Tue, 25 Nov 2025 03:22:17 GMT", + "x-amzn-errortype": "PreconditionFailedException", + "x-amzn-requestid": "9f89d509-063e-4b8c-a3ae-1848cc7c0701" }, - "Action": "lambda:InvokeFunction", - "Resource": "arn::lambda::111111111111:function:" - }, - "ResponseMetadata": { - "HTTPHeaders": {}, - "HTTPStatusCode": 201 - } - }, - "get_policy_response_rev3": { - "Policy": { - "Version": "2012-10-17", - "Id": "default", - "Statement": [ - { - "Sid": "s3", - "Effect": "Allow", - "Principal": { - "Service": "s3.amazonaws.com" - }, - "Action": "lambda:InvokeFunction", - "Resource": "arn::lambda::111111111111:function:" - } - ] - }, - "RevisionId": "", - "ResponseMetadata": { - "HTTPHeaders": {}, - "HTTPStatusCode": 200 - } - }, - "remove_permission_revision_exception": { - "Error": { - "Code": "PreconditionFailedException", - "Message": "The Revision Id provided does not match the latest Revision Id. Call the GetFunction/GetAlias API to retrieve the latest Revision Id" - }, - "Type": "User", - "message": "The Revision Id provided does not match the latest Revision Id. Call the GetFunction/GetAlias API to retrieve the latest Revision Id", - "ResponseMetadata": { - "HTTPHeaders": {}, - "HTTPStatusCode": 412 - } - }, - "remove_permission_response": { - "ResponseMetadata": { - "HTTPHeaders": {}, - "HTTPStatusCode": 204 + "HTTPStatusCode": 412, + "RequestId": "9f89d509-063e-4b8c-a3ae-1848cc7c0701", + "RetryAttempts": 0 } } } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaLayer::test_layer_function_quota_exception": { - "recorded-date": "10-04-2024, 09:23:59", + "recorded-date": "25-11-2025, 02:50:21", "recorded-content": { "create_function_with_six_layers": { "Error": { @@ -12368,7 +12328,7 @@ } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaEventSourceMappings::test_create_event_source_validation": { - "recorded-date": "03-03-2025, 17:07:45", + "recorded-date": "25-11-2025, 02:48:02", "recorded-content": { "no_starting_position": { "Error": { @@ -12407,7 +12367,7 @@ } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaSnapStart::test_snapstart_exceptions": { - "recorded-date": "31-03-2025, 16:15:53", + "recorded-date": "25-11-2025, 02:51:34", "recorded-content": { "create_function_invalid_snapstart_apply": { "Error": { @@ -12422,7 +12382,7 @@ } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaImages::test_lambda_image_versions": { - "recorded-date": "10-04-2024, 09:11:51", + "recorded-date": "25-11-2025, 02:38:13", "recorded-content": { "create_image_response": { "Architectures": [ @@ -12881,7 +12841,7 @@ } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaSnapStart::test_snapstart_lifecycle[java11]": { - "recorded-date": "01-04-2025, 13:30:54", + "recorded-date": "12-01-2026, 15:32:08", "recorded-content": { "create_function_response": { "Architectures": [ @@ -13025,7 +12985,7 @@ } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaSnapStart::test_snapstart_lifecycle[java17]": { - "recorded-date": "01-04-2025, 13:30:58", + "recorded-date": "12-01-2026, 15:32:14", "recorded-content": { "create_function_response": { "Architectures": [ @@ -13169,7 +13129,7 @@ } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_vpc_config": { - "recorded-date": "12-09-2024, 11:34:43", + "recorded-date": "25-11-2025, 02:35:52", "recorded-content": { "create_response": { "CreateEventSourceMappingResponse": null, @@ -13522,7 +13482,7 @@ } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaLayer::test_layer_compatibilities[runtimes0]": { - "recorded-date": "01-04-2025, 13:12:59", + "recorded-date": "12-01-2026, 15:31:31", "recorded-content": { "publish_result": { "CompatibleArchitectures": [ @@ -13530,20 +13490,21 @@ "x86_64" ], "CompatibleRuntimes": [ + "nodejs24.x", "nodejs22.x", "nodejs20.x", "nodejs18.x", "nodejs16.x", "nodejs14.x", "nodejs12.x", + "python3.14", "python3.13", "python3.12", "python3.11", "python3.10", "python3.9", "python3.8", - "python3.7", - "java21" + "python3.7" ], "Content": { "CodeSha256": "", @@ -13563,7 +13524,7 @@ } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaLayer::test_layer_compatibilities[runtimes1]": { - "recorded-date": "01-04-2025, 13:13:03", + "recorded-date": "12-01-2026, 15:31:37", "recorded-content": { "publish_result": { "CompatibleArchitectures": [ @@ -13571,10 +13532,13 @@ "x86_64" ], "CompatibleRuntimes": [ + "java25", + "java21", "java17", "java11", "java8.al2", "java8", + "dotnet10", "dotnet8", "dotnet6", "dotnetcore3.1", @@ -13582,10 +13546,7 @@ "ruby3.4", "ruby3.3", "ruby3.2", - "ruby2.7", - "provided.al2023", - "provided.al2", - "provided" + "ruby2.7" ], "Content": { "CodeSha256": "", @@ -13605,7 +13566,7 @@ } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaProvisionedConcurrency::test_provisioned_concurrency_limits": { - "recorded-date": "10-04-2024, 09:14:00", + "recorded-date": "25-11-2025, 02:40:37", "recorded-content": { "put_provisioned_concurrency_account_limit_exceeded": { "Error": { @@ -13632,7 +13593,7 @@ } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaReservedConcurrency::test_function_concurrency_limits": { - "recorded-date": "10-04-2024, 09:13:47", + "recorded-date": "25-11-2025, 02:40:20", "recorded-content": { "put_function_concurrency_account_limit_exceeded": { "Error": { @@ -13659,7 +13620,7 @@ } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaSnapStart::test_snapstart_lifecycle[java21]": { - "recorded-date": "01-04-2025, 13:31:02", + "recorded-date": "12-01-2026, 15:32:21", "recorded-content": { "create_function_response": { "Architectures": [ @@ -13803,7 +13764,7 @@ } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaSizeLimits::test_oversized_zipped_create_lambda": { - "recorded-date": "10-04-2024, 09:17:26", + "recorded-date": "25-11-2025, 02:44:37", "recorded-content": { "invalid_param_exc": { "Error": { @@ -13818,7 +13779,7 @@ } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_arns": { - "recorded-date": "12-09-2024, 11:30:01", + "recorded-date": "25-11-2025, 02:27:51", "recorded-content": { "create-function-arn-response": { "CreateEventSourceMappingResponse": null, @@ -13921,7 +13882,7 @@ "invalid_function_name_exc": { "Error": { "Code": "ValidationException", - "Message": "1 validation error detected: Value 'invalid:function:name' at 'functionName' failed to satisfy constraint: Member must satisfy regular expression pattern: (arn:(aws[a-zA-Z-]*)?:lambda:)?([a-z]{2}((-gov)|(-iso([a-z]?)))?-[a-z]+-\\d{1}:)?(\\d{12}:)?(function:)?([a-zA-Z0-9-_]+)(:(\\$LATEST|[a-zA-Z0-9-_]+))?" + "Message": "1 validation error detected: Value 'invalid:function:name' at 'functionName' failed to satisfy constraint: Member must satisfy regular expression pattern: (arn:(aws[a-zA-Z-]*)?:lambda:)?((eusc-)?[a-z]{2}((-gov)|(-iso([a-z]?)))?-[a-z]+-\\d{1}:)?(\\d{12}:)?(function:)?([a-zA-Z0-9-_]+)(:(\\$LATEST|[a-zA-Z0-9-_]+))?" }, "ResponseMetadata": { "HTTPHeaders": {}, @@ -13975,7 +13936,7 @@ } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaEventSourceMappings::test_function_name_variations": { - "recorded-date": "14-10-2024, 12:46:37", + "recorded-date": "25-11-2025, 03:20:35", "recorded-content": { "name_only_create_esm": { "BatchSize": 10, @@ -14092,7 +14053,7 @@ } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaAlias::test_alias_naming": { - "recorded-date": "21-11-2024, 13:45:11", + "recorded-date": "25-11-2025, 02:39:05", "recorded-content": { "create_response": { "Architectures": [ @@ -14224,12 +14185,12 @@ } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_invalid_invoke": { - "recorded-date": "12-09-2024, 11:34:43", + "recorded-date": "25-11-2025, 02:35:53", "recorded-content": { "invoke_function_name_pattern_exc": { "Error": { "Code": "ValidationException", - "Message": "1 validation error detected: Value 'arn::lambda::123400000000@function:myfn' at 'functionName' failed to satisfy constraint: Member must satisfy regular expression pattern: (arn:(aws[a-zA-Z-]*)?:lambda:)?([a-z]{2}((-gov)|(-iso([a-z]?)))?-[a-z]+-\\d{1}:)?(\\d{12}:)?(function:)?([a-zA-Z0-9-_\\.]+)(:(\\$LATEST|[a-zA-Z0-9-_]+))?" + "Message": "1 validation error detected: Value 'arn::lambda::123400000000@function:myfn' at 'functionName' failed to satisfy constraint: Member must satisfy regular expression pattern: (arn:(aws[a-zA-Z-]*)?:lambda:)?((eusc-)?[a-z]{2}((-gov)|(-iso([a-z]?)))?-[a-z]+-\\d{1}:)?(\\d{12}:)?(function:)?([a-zA-Z0-9-_\\.]+)(:(\\$LATEST(\\.PUBLISHED)?|[a-zA-Z0-9-_]+))?" }, "ResponseMetadata": { "HTTPHeaders": {}, @@ -14239,7 +14200,7 @@ } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_lambda_concurrent_code_updates": { - "recorded-date": "12-09-2024, 11:34:47", + "recorded-date": "25-11-2025, 02:35:57", "recorded-content": { "create-function-response": { "Architectures": [ @@ -14299,7 +14260,7 @@ } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_lambda_concurrent_config_updates": { - "recorded-date": "12-09-2024, 11:34:50", + "recorded-date": "25-11-2025, 02:36:01", "recorded-content": { "create-function-response": { "CreateEventSourceMappingResponse": null, @@ -14365,7 +14326,7 @@ } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLoggingConfig::test_function_advanced_logging_configuration": { - "recorded-date": "19-04-2024, 08:20:18", + "recorded-date": "25-11-2025, 02:26:24", "recorded-content": { "create_response": { "CreateEventSourceMappingResponse": null, @@ -14617,7 +14578,7 @@ } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLoggingConfig::test_advanced_logging_configuration_format_switch": { - "recorded-date": "17-04-2024, 14:16:55", + "recorded-date": "25-11-2025, 02:26:30", "recorded-content": { "create_response": { "CreateEventSourceMappingResponse": null, @@ -14955,7 +14916,7 @@ } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLoggingConfig::test_function_partial_advanced_logging_configuration_update[partial_config0]": { - "recorded-date": "17-04-2024, 14:17:01", + "recorded-date": "25-11-2025, 02:26:35", "recorded-content": { "create_response": { "CreateEventSourceMappingResponse": null, @@ -15201,7 +15162,7 @@ } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLoggingConfig::test_function_partial_advanced_logging_configuration_update[partial_config1]": { - "recorded-date": "17-04-2024, 14:17:06", + "recorded-date": "25-11-2025, 02:26:39", "recorded-content": { "create_response": { "CreateEventSourceMappingResponse": null, @@ -15447,7 +15408,7 @@ } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLoggingConfig::test_function_partial_advanced_logging_configuration_update[partial_config2]": { - "recorded-date": "17-04-2024, 14:17:11", + "recorded-date": "25-11-2025, 02:26:44", "recorded-content": { "create_response": { "CreateEventSourceMappingResponse": null, @@ -15693,7 +15654,7 @@ } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLoggingConfig::test_function_partial_advanced_logging_configuration_update[partial_config3]": { - "recorded-date": "17-04-2024, 14:17:17", + "recorded-date": "25-11-2025, 02:26:48", "recorded-content": { "create_response": { "CreateEventSourceMappingResponse": null, @@ -15935,11 +15896,11 @@ } }, "tests/aws/services/lambda_/test_lambda_api.py::TestPartialARNMatching::test_update_function_configuration_full_arn": { - "recorded-date": "05-06-2024, 11:49:05", + "recorded-date": "25-11-2025, 02:26:17", "recorded-content": {} }, "tests/aws/services/lambda_/test_lambda_api.py::TestRuntimeValidation::test_create_deprecated_function_runtime_with_validation_enabled[java8]": { - "recorded-date": "01-04-2025, 13:02:29", + "recorded-date": "12-01-2026, 15:31:21", "recorded-content": { "deprecation_error": { "Error": { @@ -15956,7 +15917,7 @@ } }, "tests/aws/services/lambda_/test_lambda_api.py::TestRuntimeValidation::test_create_deprecated_function_runtime_with_validation_enabled[go1.x]": { - "recorded-date": "01-04-2025, 13:02:29", + "recorded-date": "12-01-2026, 15:31:21", "recorded-content": { "deprecation_error": { "Error": { @@ -15973,7 +15934,7 @@ } }, "tests/aws/services/lambda_/test_lambda_api.py::TestRuntimeValidation::test_create_deprecated_function_runtime_with_validation_enabled[provided]": { - "recorded-date": "01-04-2025, 13:02:30", + "recorded-date": "12-01-2026, 15:31:21", "recorded-content": { "deprecation_error": { "Error": { @@ -15990,7 +15951,7 @@ } }, "tests/aws/services/lambda_/test_lambda_api.py::TestRuntimeValidation::test_create_deprecated_function_runtime_with_validation_enabled[ruby2.7]": { - "recorded-date": "01-04-2025, 13:02:30", + "recorded-date": "12-01-2026, 15:31:21", "recorded-content": { "deprecation_error": { "Error": { @@ -16007,7 +15968,7 @@ } }, "tests/aws/services/lambda_/test_lambda_api.py::TestRuntimeValidation::test_create_deprecated_function_runtime_with_validation_enabled[nodejs14.x]": { - "recorded-date": "01-04-2025, 13:02:30", + "recorded-date": "12-01-2026, 15:31:22", "recorded-content": { "deprecation_error": { "Error": { @@ -16024,7 +15985,7 @@ } }, "tests/aws/services/lambda_/test_lambda_api.py::TestRuntimeValidation::test_create_deprecated_function_runtime_with_validation_enabled[python3.7]": { - "recorded-date": "01-04-2025, 13:02:30", + "recorded-date": "12-01-2026, 15:31:22", "recorded-content": { "deprecation_error": { "Error": { @@ -16041,7 +16002,7 @@ } }, "tests/aws/services/lambda_/test_lambda_api.py::TestRuntimeValidation::test_create_deprecated_function_runtime_with_validation_enabled[dotnetcore3.1]": { - "recorded-date": "01-04-2025, 13:02:31", + "recorded-date": "12-01-2026, 15:31:22", "recorded-content": { "deprecation_error": { "Error": { @@ -16058,7 +16019,7 @@ } }, "tests/aws/services/lambda_/test_lambda_api.py::TestRuntimeValidation::test_create_deprecated_function_runtime_with_validation_enabled[nodejs12.x]": { - "recorded-date": "01-04-2025, 13:02:31", + "recorded-date": "12-01-2026, 15:31:22", "recorded-content": { "deprecation_error": { "Error": { @@ -16075,149 +16036,149 @@ } }, "tests/aws/services/lambda_/test_lambda_api.py::TestPartialARNMatching::test_cross_region_arn_function_access": { - "recorded-date": "11-06-2024, 13:06:45", + "recorded-date": "25-11-2025, 02:26:19", "recorded-content": {} }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[function_name_is_single_invalid-get_function]": { - "recorded-date": "12-09-2024, 11:30:01", + "recorded-date": "25-11-2025, 02:27:51", "recorded-content": { "get_function_exception": { "Code": "ValidationException", "Count": 1, "Errors": [ - "Value '*' at 'functionName' failed to satisfy constraint: Member must satisfy regular expression pattern: (arn:(aws[a-zA-Z-]*)?:lambda:)?([a-z]{2}((-gov)|(-iso([a-z]?)))?-[a-z]+-\\d{1}:)?(\\d{12}:)?(function:)?([a-zA-Z0-9-_\\.]+)(:(\\$LATEST|[a-zA-Z0-9-_]+))?" + "Value '*' at 'functionName' failed to satisfy constraint: Member must satisfy regular expression pattern: (arn:(aws[a-zA-Z-]*)?:lambda:)?((eusc-)?[a-z]{2}((-gov)|(-iso([a-z]?)))?-[a-z]+-\\d{1}:)?(\\d{12}:)?(function:)?([a-zA-Z0-9-_\\.]+)(:(\\$LATEST(\\.PUBLISHED)?|[a-zA-Z0-9-_]+))?" ] } } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[function_name_is_single_invalid-delete_function]": { - "recorded-date": "12-09-2024, 11:30:02", + "recorded-date": "25-11-2025, 02:27:51", "recorded-content": { "delete_function_exception": { "Code": "ValidationException", "Count": 1, "Errors": [ - "Value '*' at 'functionName' failed to satisfy constraint: Member must satisfy regular expression pattern: (arn:(aws[a-zA-Z-]*)?:lambda:)?([a-z]{2}((-gov)|(-iso([a-z]?)))?-[a-z]+-\\d{1}:)?(\\d{12}:)?(function:)?([a-zA-Z0-9-_]+)(:(\\$LATEST|[a-zA-Z0-9-_]+))?" + "Value '*' at 'functionName' failed to satisfy constraint: Member must satisfy regular expression pattern: (arn:(aws[a-zA-Z-]*)?:lambda:)?((eusc-)?[a-z]{2}((-gov)|(-iso([a-z]?)))?-[a-z]+-\\d{1}:)?(\\d{12}:)?(function:)?([a-zA-Z0-9-_\\.]+)(:(\\$LATEST(\\.PUBLISHED)?|[a-zA-Z0-9-_]+))?" ] } } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[function_name_is_single_invalid-invoke]": { - "recorded-date": "12-09-2024, 11:30:02", + "recorded-date": "25-11-2025, 02:27:51", "recorded-content": { "invoke_exception": { "Code": "ValidationException", "Count": 1, "Errors": [ - "Value '*' at 'functionName' failed to satisfy constraint: Member must satisfy regular expression pattern: (arn:(aws[a-zA-Z-]*)?:lambda:)?([a-z]{2}((-gov)|(-iso([a-z]?)))?-[a-z]+-\\d{1}:)?(\\d{12}:)?(function:)?([a-zA-Z0-9-_\\.]+)(:(\\$LATEST|[a-zA-Z0-9-_]+))?" + "Value '*' at 'functionName' failed to satisfy constraint: Member must satisfy regular expression pattern: (arn:(aws[a-zA-Z-]*)?:lambda:)?((eusc-)?[a-z]{2}((-gov)|(-iso([a-z]?)))?-[a-z]+-\\d{1}:)?(\\d{12}:)?(function:)?([a-zA-Z0-9-_\\.]+)(:(\\$LATEST(\\.PUBLISHED)?|[a-zA-Z0-9-_]+))?" ] } } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[function_name_is_single_invalid-create_function]": { - "recorded-date": "12-09-2024, 11:30:02", + "recorded-date": "25-11-2025, 02:27:52", "recorded-content": { "create_function_exception": { "Code": "ValidationException", "Count": 1, "Errors": [ - "Value '*' at 'functionName' failed to satisfy constraint: Member must satisfy regular expression pattern: (arn:(aws[a-zA-Z-]*)?:lambda:)?([a-z]{2}((-gov)|(-iso([a-z]?)))?-[a-z]+-\\d{1}:)?(\\d{12}:)?(function:)?([a-zA-Z0-9-_]+)(:(\\$LATEST|[a-zA-Z0-9-_]+))?" + "Value '*' at 'functionName' failed to satisfy constraint: Member must satisfy regular expression pattern: (arn:(aws[a-zA-Z-]*)?:lambda:)?((eusc-)?[a-z]{2}((-gov)|(-iso([a-z]?)))?-[a-z]+-\\d{1}:)?(\\d{12}:)?(function:)?([a-zA-Z0-9-_]+)(:(\\$LATEST|[a-zA-Z0-9-_]+))?" ] } } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[invalid_characters_in_function_name-get_function]": { - "recorded-date": "12-09-2024, 11:30:01", + "recorded-date": "25-11-2025, 02:27:51", "recorded-content": { "get_function_exception": { "Code": "ValidationException", "Count": 1, "Errors": [ - "Value 'my-function!' at 'functionName' failed to satisfy constraint: Member must satisfy regular expression pattern: (arn:(aws[a-zA-Z-]*)?:lambda:)?([a-z]{2}((-gov)|(-iso([a-z]?)))?-[a-z]+-\\d{1}:)?(\\d{12}:)?(function:)?([a-zA-Z0-9-_\\.]+)(:(\\$LATEST|[a-zA-Z0-9-_]+))?" + "Value 'my-function!' at 'functionName' failed to satisfy constraint: Member must satisfy regular expression pattern: (arn:(aws[a-zA-Z-]*)?:lambda:)?((eusc-)?[a-z]{2}((-gov)|(-iso([a-z]?)))?-[a-z]+-\\d{1}:)?(\\d{12}:)?(function:)?([a-zA-Z0-9-_\\.]+)(:(\\$LATEST(\\.PUBLISHED)?|[a-zA-Z0-9-_]+))?" ] } } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[invalid_characters_in_function_name-delete_function]": { - "recorded-date": "12-09-2024, 11:30:01", + "recorded-date": "25-11-2025, 02:27:51", "recorded-content": { "delete_function_exception": { "Code": "ValidationException", "Count": 1, "Errors": [ - "Value 'my-function!' at 'functionName' failed to satisfy constraint: Member must satisfy regular expression pattern: (arn:(aws[a-zA-Z-]*)?:lambda:)?([a-z]{2}((-gov)|(-iso([a-z]?)))?-[a-z]+-\\d{1}:)?(\\d{12}:)?(function:)?([a-zA-Z0-9-_]+)(:(\\$LATEST|[a-zA-Z0-9-_]+))?" + "Value 'my-function!' at 'functionName' failed to satisfy constraint: Member must satisfy regular expression pattern: (arn:(aws[a-zA-Z-]*)?:lambda:)?((eusc-)?[a-z]{2}((-gov)|(-iso([a-z]?)))?-[a-z]+-\\d{1}:)?(\\d{12}:)?(function:)?([a-zA-Z0-9-_\\.]+)(:(\\$LATEST(\\.PUBLISHED)?|[a-zA-Z0-9-_]+))?" ] } } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[invalid_characters_in_function_name-invoke]": { - "recorded-date": "12-09-2024, 11:30:01", + "recorded-date": "25-11-2025, 02:27:51", "recorded-content": { "invoke_exception": { "Code": "ValidationException", "Count": 1, "Errors": [ - "Value 'my-function!' at 'functionName' failed to satisfy constraint: Member must satisfy regular expression pattern: (arn:(aws[a-zA-Z-]*)?:lambda:)?([a-z]{2}((-gov)|(-iso([a-z]?)))?-[a-z]+-\\d{1}:)?(\\d{12}:)?(function:)?([a-zA-Z0-9-_\\.]+)(:(\\$LATEST|[a-zA-Z0-9-_]+))?" + "Value 'my-function!' at 'functionName' failed to satisfy constraint: Member must satisfy regular expression pattern: (arn:(aws[a-zA-Z-]*)?:lambda:)?((eusc-)?[a-z]{2}((-gov)|(-iso([a-z]?)))?-[a-z]+-\\d{1}:)?(\\d{12}:)?(function:)?([a-zA-Z0-9-_\\.]+)(:(\\$LATEST(\\.PUBLISHED)?|[a-zA-Z0-9-_]+))?" ] } } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[invalid_characters_in_function_name-create_function]": { - "recorded-date": "12-09-2024, 11:30:01", + "recorded-date": "25-11-2025, 02:27:51", "recorded-content": { "create_function_exception": { "Code": "ValidationException", "Count": 1, "Errors": [ - "Value 'my-function!' at 'functionName' failed to satisfy constraint: Member must satisfy regular expression pattern: (arn:(aws[a-zA-Z-]*)?:lambda:)?([a-z]{2}((-gov)|(-iso([a-z]?)))?-[a-z]+-\\d{1}:)?(\\d{12}:)?(function:)?([a-zA-Z0-9-_]+)(:(\\$LATEST|[a-zA-Z0-9-_]+))?" + "Value 'my-function!' at 'functionName' failed to satisfy constraint: Member must satisfy regular expression pattern: (arn:(aws[a-zA-Z-]*)?:lambda:)?((eusc-)?[a-z]{2}((-gov)|(-iso([a-z]?)))?-[a-z]+-\\d{1}:)?(\\d{12}:)?(function:)?([a-zA-Z0-9-_]+)(:(\\$LATEST|[a-zA-Z0-9-_]+))?" ] } } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[invalid_characters_in_qualifier-get_function]": { - "recorded-date": "12-09-2024, 11:30:02", + "recorded-date": "25-11-2025, 02:27:52", "recorded-content": { "get_function_exception": { "Code": "ValidationException", "Count": 1, "Errors": [ - "Value 'invalid!' at 'qualifier' failed to satisfy constraint: Member must satisfy regular expression pattern: (|[a-zA-Z0-9$_-]+)" + "Value 'invalid!' at 'qualifier' failed to satisfy constraint: Member must satisfy regular expression pattern: \\$(LATEST(\\.PUBLISHED)?)|[a-zA-Z0-9-_$]+" ] } } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[invalid_characters_in_qualifier-delete_function]": { - "recorded-date": "12-09-2024, 11:30:02", + "recorded-date": "25-11-2025, 02:27:52", "recorded-content": { "delete_function_exception": { "Code": "ValidationException", "Count": 1, "Errors": [ - "Value 'invalid!' at 'qualifier' failed to satisfy constraint: Member must satisfy regular expression pattern: (|[a-zA-Z0-9$_-]+)" + "Value 'invalid!' at 'qualifier' failed to satisfy constraint: Member must satisfy regular expression pattern: \\$(LATEST(\\.PUBLISHED)?)|[a-zA-Z0-9-_$]+" ] } } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[invalid_characters_in_qualifier-invoke]": { - "recorded-date": "12-09-2024, 11:30:02", + "recorded-date": "25-11-2025, 02:27:52", "recorded-content": { "invoke_exception": { "Code": "ValidationException", "Count": 1, "Errors": [ - "Value 'invalid!' at 'qualifier' failed to satisfy constraint: Member must satisfy regular expression pattern: (|[a-zA-Z0-9$_-]+)" + "Value 'invalid!' at 'qualifier' failed to satisfy constraint: Member must satisfy regular expression pattern: \\$(LATEST(\\.PUBLISHED)?)|[a-zA-Z0-9-_$]+" ] } } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[invalid_characters_in_qualifier-create_function]": { - "recorded-date": "12-09-2024, 11:30:02", + "recorded-date": "25-11-2025, 02:27:52", "recorded-content": { "create_function_exception": { "Code": "ValidationException", "Count": 1, "Errors": [ - "Value 'my-function:invalid!' at 'functionName' failed to satisfy constraint: Member must satisfy regular expression pattern: (arn:(aws[a-zA-Z-]*)?:lambda:)?([a-z]{2}((-gov)|(-iso([a-z]?)))?-[a-z]+-\\d{1}:)?(\\d{12}:)?(function:)?([a-zA-Z0-9-_]+)(:(\\$LATEST|[a-zA-Z0-9-_]+))?" + "Value 'my-function:invalid!' at 'functionName' failed to satisfy constraint: Member must satisfy regular expression pattern: (arn:(aws[a-zA-Z-]*)?:lambda:)?((eusc-)?[a-z]{2}((-gov)|(-iso([a-z]?)))?-[a-z]+-\\d{1}:)?(\\d{12}:)?(function:)?([a-zA-Z0-9-_]+)(:(\\$LATEST|[a-zA-Z0-9-_]+))?" ] } } @@ -16271,151 +16232,151 @@ } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[invalid_account_id_in_partial_arn-get_function]": { - "recorded-date": "12-09-2024, 11:30:02", + "recorded-date": "25-11-2025, 02:27:53", "recorded-content": { "get_function_exception": { "Code": "ValidationException", "Count": 1, "Errors": [ - "Value 'invalid-account:function:my-function' at 'functionName' failed to satisfy constraint: Member must satisfy regular expression pattern: (arn:(aws[a-zA-Z-]*)?:lambda:)?([a-z]{2}((-gov)|(-iso([a-z]?)))?-[a-z]+-\\d{1}:)?(\\d{12}:)?(function:)?([a-zA-Z0-9-_\\.]+)(:(\\$LATEST|[a-zA-Z0-9-_]+))?" + "Value 'invalid-account:function:my-function' at 'functionName' failed to satisfy constraint: Member must satisfy regular expression pattern: (arn:(aws[a-zA-Z-]*)?:lambda:)?((eusc-)?[a-z]{2}((-gov)|(-iso([a-z]?)))?-[a-z]+-\\d{1}:)?(\\d{12}:)?(function:)?([a-zA-Z0-9-_\\.]+)(:(\\$LATEST(\\.PUBLISHED)?|[a-zA-Z0-9-_]+))?" ] } } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[invalid_account_id_in_partial_arn-delete_function]": { - "recorded-date": "12-09-2024, 11:30:02", + "recorded-date": "25-11-2025, 02:27:53", "recorded-content": { "delete_function_exception": { "Code": "ValidationException", "Count": 1, "Errors": [ - "Value 'invalid-account:function:my-function' at 'functionName' failed to satisfy constraint: Member must satisfy regular expression pattern: (arn:(aws[a-zA-Z-]*)?:lambda:)?([a-z]{2}((-gov)|(-iso([a-z]?)))?-[a-z]+-\\d{1}:)?(\\d{12}:)?(function:)?([a-zA-Z0-9-_]+)(:(\\$LATEST|[a-zA-Z0-9-_]+))?" + "Value 'invalid-account:function:my-function' at 'functionName' failed to satisfy constraint: Member must satisfy regular expression pattern: (arn:(aws[a-zA-Z-]*)?:lambda:)?((eusc-)?[a-z]{2}((-gov)|(-iso([a-z]?)))?-[a-z]+-\\d{1}:)?(\\d{12}:)?(function:)?([a-zA-Z0-9-_\\.]+)(:(\\$LATEST(\\.PUBLISHED)?|[a-zA-Z0-9-_]+))?" ] } } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[invalid_account_id_in_partial_arn-invoke]": { - "recorded-date": "12-09-2024, 11:30:02", + "recorded-date": "25-11-2025, 02:27:53", "recorded-content": { "invoke_exception": { "Code": "ValidationException", "Count": 1, "Errors": [ - "Value 'invalid-account:function:my-function' at 'functionName' failed to satisfy constraint: Member must satisfy regular expression pattern: (arn:(aws[a-zA-Z-]*)?:lambda:)?([a-z]{2}((-gov)|(-iso([a-z]?)))?-[a-z]+-\\d{1}:)?(\\d{12}:)?(function:)?([a-zA-Z0-9-_\\.]+)(:(\\$LATEST|[a-zA-Z0-9-_]+))?" + "Value 'invalid-account:function:my-function' at 'functionName' failed to satisfy constraint: Member must satisfy regular expression pattern: (arn:(aws[a-zA-Z-]*)?:lambda:)?((eusc-)?[a-z]{2}((-gov)|(-iso([a-z]?)))?-[a-z]+-\\d{1}:)?(\\d{12}:)?(function:)?([a-zA-Z0-9-_\\.]+)(:(\\$LATEST(\\.PUBLISHED)?|[a-zA-Z0-9-_]+))?" ] } } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[invalid_account_id_in_partial_arn-create_function]": { - "recorded-date": "12-09-2024, 11:30:03", + "recorded-date": "25-11-2025, 02:27:53", "recorded-content": { "create_function_exception": { "Code": "ValidationException", "Count": 1, "Errors": [ - "Value 'invalid-account:function:my-function' at 'functionName' failed to satisfy constraint: Member must satisfy regular expression pattern: (arn:(aws[a-zA-Z-]*)?:lambda:)?([a-z]{2}((-gov)|(-iso([a-z]?)))?-[a-z]+-\\d{1}:)?(\\d{12}:)?(function:)?([a-zA-Z0-9-_]+)(:(\\$LATEST|[a-zA-Z0-9-_]+))?" + "Value 'invalid-account:function:my-function' at 'functionName' failed to satisfy constraint: Member must satisfy regular expression pattern: (arn:(aws[a-zA-Z-]*)?:lambda:)?((eusc-)?[a-z]{2}((-gov)|(-iso([a-z]?)))?-[a-z]+-\\d{1}:)?(\\d{12}:)?(function:)?([a-zA-Z0-9-_]+)(:(\\$LATEST|[a-zA-Z0-9-_]+))?" ] } } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[invalid_region_in_arn-get_function]": { - "recorded-date": "12-09-2024, 11:30:03", + "recorded-date": "25-11-2025, 02:27:53", "recorded-content": { "get_function_exception": { "Code": "ValidationException", "Count": 1, "Errors": [ - "Value 'arn::lambda:invalid-region:111111111111:function:my-function' at 'functionName' failed to satisfy constraint: Member must satisfy regular expression pattern: (arn:(aws[a-zA-Z-]*)?:lambda:)?([a-z]{2}((-gov)|(-iso([a-z]?)))?-[a-z]+-\\d{1}:)?(\\d{12}:)?(function:)?([a-zA-Z0-9-_\\.]+)(:(\\$LATEST|[a-zA-Z0-9-_]+))?" + "Value 'arn::lambda:invalid-region:111111111111:function:my-function' at 'functionName' failed to satisfy constraint: Member must satisfy regular expression pattern: (arn:(aws[a-zA-Z-]*)?:lambda:)?((eusc-)?[a-z]{2}((-gov)|(-iso([a-z]?)))?-[a-z]+-\\d{1}:)?(\\d{12}:)?(function:)?([a-zA-Z0-9-_\\.]+)(:(\\$LATEST(\\.PUBLISHED)?|[a-zA-Z0-9-_]+))?" ] } } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[invalid_region_in_arn-delete_function]": { - "recorded-date": "12-09-2024, 11:30:03", + "recorded-date": "25-11-2025, 02:27:53", "recorded-content": { "delete_function_exception": { "Code": "ValidationException", "Count": 1, "Errors": [ - "Value 'arn::lambda:invalid-region:111111111111:function:my-function' at 'functionName' failed to satisfy constraint: Member must satisfy regular expression pattern: (arn:(aws[a-zA-Z-]*)?:lambda:)?([a-z]{2}((-gov)|(-iso([a-z]?)))?-[a-z]+-\\d{1}:)?(\\d{12}:)?(function:)?([a-zA-Z0-9-_]+)(:(\\$LATEST|[a-zA-Z0-9-_]+))?" + "Value 'arn::lambda:invalid-region:111111111111:function:my-function' at 'functionName' failed to satisfy constraint: Member must satisfy regular expression pattern: (arn:(aws[a-zA-Z-]*)?:lambda:)?((eusc-)?[a-z]{2}((-gov)|(-iso([a-z]?)))?-[a-z]+-\\d{1}:)?(\\d{12}:)?(function:)?([a-zA-Z0-9-_\\.]+)(:(\\$LATEST(\\.PUBLISHED)?|[a-zA-Z0-9-_]+))?" ] } } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[invalid_region_in_arn-invoke]": { - "recorded-date": "12-09-2024, 11:30:03", + "recorded-date": "25-11-2025, 02:27:54", "recorded-content": { "invoke_exception": { "Code": "ValidationException", "Count": 1, "Errors": [ - "Value 'arn::lambda:invalid-region:111111111111:function:my-function' at 'functionName' failed to satisfy constraint: Member must satisfy regular expression pattern: (arn:(aws[a-zA-Z-]*)?:lambda:)?([a-z]{2}((-gov)|(-iso([a-z]?)))?-[a-z]+-\\d{1}:)?(\\d{12}:)?(function:)?([a-zA-Z0-9-_\\.]+)(:(\\$LATEST|[a-zA-Z0-9-_]+))?" + "Value 'arn::lambda:invalid-region:111111111111:function:my-function' at 'functionName' failed to satisfy constraint: Member must satisfy regular expression pattern: (arn:(aws[a-zA-Z-]*)?:lambda:)?((eusc-)?[a-z]{2}((-gov)|(-iso([a-z]?)))?-[a-z]+-\\d{1}:)?(\\d{12}:)?(function:)?([a-zA-Z0-9-_\\.]+)(:(\\$LATEST(\\.PUBLISHED)?|[a-zA-Z0-9-_]+))?" ] } } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[invalid_region_in_arn-create_function]": { - "recorded-date": "12-09-2024, 11:30:03", + "recorded-date": "25-11-2025, 02:27:54", "recorded-content": { "create_function_exception": { "Code": "ValidationException", "Count": 1, "Errors": [ - "Value 'arn::lambda:invalid-region:111111111111:function:my-function' at 'functionName' failed to satisfy constraint: Member must satisfy regular expression pattern: (arn:(aws[a-zA-Z-]*)?:lambda:)?([a-z]{2}((-gov)|(-iso([a-z]?)))?-[a-z]+-\\d{1}:)?(\\d{12}:)?(function:)?([a-zA-Z0-9-_]+)(:(\\$LATEST|[a-zA-Z0-9-_]+))?" + "Value 'arn::lambda:invalid-region:111111111111:function:my-function' at 'functionName' failed to satisfy constraint: Member must satisfy regular expression pattern: (arn:(aws[a-zA-Z-]*)?:lambda:)?((eusc-)?[a-z]{2}((-gov)|(-iso([a-z]?)))?-[a-z]+-\\d{1}:)?(\\d{12}:)?(function:)?([a-zA-Z0-9-_]+)(:(\\$LATEST|[a-zA-Z0-9-_]+))?" ] } } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[non_lambda_arn-get_function]": { - "recorded-date": "12-09-2024, 11:30:03", + "recorded-date": "25-11-2025, 02:27:54", "recorded-content": { "get_function_exception": { "Code": "ValidationException", "Count": 1, "Errors": [ - "Value 'arn::ec2::111111111111:instance:i-1234567890abcdef0' at 'functionName' failed to satisfy constraint: Member must satisfy regular expression pattern: (arn:(aws[a-zA-Z-]*)?:lambda:)?([a-z]{2}((-gov)|(-iso([a-z]?)))?-[a-z]+-\\d{1}:)?(\\d{12}:)?(function:)?([a-zA-Z0-9-_\\.]+)(:(\\$LATEST|[a-zA-Z0-9-_]+))?" + "Value 'arn::ec2::111111111111:instance:i-1234567890abcdef0' at 'functionName' failed to satisfy constraint: Member must satisfy regular expression pattern: (arn:(aws[a-zA-Z-]*)?:lambda:)?((eusc-)?[a-z]{2}((-gov)|(-iso([a-z]?)))?-[a-z]+-\\d{1}:)?(\\d{12}:)?(function:)?([a-zA-Z0-9-_\\.]+)(:(\\$LATEST(\\.PUBLISHED)?|[a-zA-Z0-9-_]+))?" ] } } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[non_lambda_arn-delete_function]": { - "recorded-date": "12-09-2024, 11:30:03", + "recorded-date": "25-11-2025, 02:27:54", "recorded-content": { "delete_function_exception": { "Code": "ValidationException", "Count": 1, "Errors": [ - "Value 'arn::ec2::111111111111:instance:i-1234567890abcdef0' at 'functionName' failed to satisfy constraint: Member must satisfy regular expression pattern: (arn:(aws[a-zA-Z-]*)?:lambda:)?([a-z]{2}((-gov)|(-iso([a-z]?)))?-[a-z]+-\\d{1}:)?(\\d{12}:)?(function:)?([a-zA-Z0-9-_]+)(:(\\$LATEST|[a-zA-Z0-9-_]+))?" + "Value 'arn::ec2::111111111111:instance:i-1234567890abcdef0' at 'functionName' failed to satisfy constraint: Member must satisfy regular expression pattern: (arn:(aws[a-zA-Z-]*)?:lambda:)?((eusc-)?[a-z]{2}((-gov)|(-iso([a-z]?)))?-[a-z]+-\\d{1}:)?(\\d{12}:)?(function:)?([a-zA-Z0-9-_\\.]+)(:(\\$LATEST(\\.PUBLISHED)?|[a-zA-Z0-9-_]+))?" ] } } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[non_lambda_arn-invoke]": { - "recorded-date": "12-09-2024, 11:30:03", + "recorded-date": "25-11-2025, 02:27:54", "recorded-content": { "invoke_exception": { "Code": "ValidationException", "Count": 1, "Errors": [ - "Value 'arn::ec2::111111111111:instance:i-1234567890abcdef0' at 'functionName' failed to satisfy constraint: Member must satisfy regular expression pattern: (arn:(aws[a-zA-Z-]*)?:lambda:)?([a-z]{2}((-gov)|(-iso([a-z]?)))?-[a-z]+-\\d{1}:)?(\\d{12}:)?(function:)?([a-zA-Z0-9-_\\.]+)(:(\\$LATEST|[a-zA-Z0-9-_]+))?" + "Value 'arn::ec2::111111111111:instance:i-1234567890abcdef0' at 'functionName' failed to satisfy constraint: Member must satisfy regular expression pattern: (arn:(aws[a-zA-Z-]*)?:lambda:)?((eusc-)?[a-z]{2}((-gov)|(-iso([a-z]?)))?-[a-z]+-\\d{1}:)?(\\d{12}:)?(function:)?([a-zA-Z0-9-_\\.]+)(:(\\$LATEST(\\.PUBLISHED)?|[a-zA-Z0-9-_]+))?" ] } } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[non_lambda_arn-create_function]": { - "recorded-date": "12-09-2024, 11:30:03", + "recorded-date": "25-11-2025, 02:27:54", "recorded-content": { "create_function_exception": { "Code": "ValidationException", "Count": 1, "Errors": [ - "Value 'arn::ec2::111111111111:instance:i-1234567890abcdef0' at 'functionName' failed to satisfy constraint: Member must satisfy regular expression pattern: (arn:(aws[a-zA-Z-]*)?:lambda:)?([a-z]{2}((-gov)|(-iso([a-z]?)))?-[a-z]+-\\d{1}:)?(\\d{12}:)?(function:)?([a-zA-Z0-9-_]+)(:(\\$LATEST|[a-zA-Z0-9-_]+))?" + "Value 'arn::ec2::111111111111:instance:i-1234567890abcdef0' at 'functionName' failed to satisfy constraint: Member must satisfy regular expression pattern: (arn:(aws[a-zA-Z-]*)?:lambda:)?((eusc-)?[a-z]{2}((-gov)|(-iso([a-z]?)))?-[a-z]+-\\d{1}:)?(\\d{12}:)?(function:)?([a-zA-Z0-9-_]+)(:(\\$LATEST|[a-zA-Z0-9-_]+))?" ] } } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[function_name_too_long-get_function]": { - "recorded-date": "12-09-2024, 11:30:03", + "recorded-date": "25-11-2025, 02:27:54", "recorded-content": { "get_function_exception": { "Code": "ResourceNotFoundException", @@ -16424,7 +16385,7 @@ } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[function_name_too_long-delete_function]": { - "recorded-date": "12-09-2024, 11:30:03", + "recorded-date": "25-11-2025, 02:27:55", "recorded-content": { "delete_function_exception": { "Code": "ResourceNotFoundException", @@ -16433,7 +16394,7 @@ } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[function_name_too_long-invoke]": { - "recorded-date": "12-09-2024, 11:30:03", + "recorded-date": "25-11-2025, 02:27:55", "recorded-content": { "invoke_exception": { "Code": "ResourceNotFoundException", @@ -16442,7 +16403,7 @@ } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[function_name_too_long-create_function]": { - "recorded-date": "12-09-2024, 11:30:03", + "recorded-date": "25-11-2025, 02:27:55", "recorded-content": { "create_function_exception": { "Code": "InvalidParameterValueException", @@ -16454,108 +16415,102 @@ } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[function_name_too_long_and_invalid_region-get_function]": { - "recorded-date": "12-09-2024, 11:30:04", + "recorded-date": "25-11-2025, 02:27:55", "recorded-content": { "get_function_exception": { "Code": "ValidationException", - "Count": 2, + "Count": 1, "Errors": [ - "Value 'arn::lambda:invalid-region:111111111111:function:my-function' at 'functionName' failed to satisfy constraint: Member must have length less than or equal to 170", - "Value 'arn::lambda:invalid-region:111111111111:function:my-function' at 'functionName' failed to satisfy constraint: Member must satisfy regular expression pattern: (arn:(aws[a-zA-Z-]*)?:lambda:)?([a-z]{2}((-gov)|(-iso([a-z]?)))?-[a-z]+-\\d{1}:)?(\\d{12}:)?(function:)?([a-zA-Z0-9-_\\.]+)(:(\\$LATEST|[a-zA-Z0-9-_]+))?" + "Value 'arn::lambda:invalid-region:111111111111:function:my-function' at 'functionName' failed to satisfy constraint: Member must satisfy regular expression pattern: (arn:(aws[a-zA-Z-]*)?:lambda:)?((eusc-)?[a-z]{2}((-gov)|(-iso([a-z]?)))?-[a-z]+-\\d{1}:)?(\\d{12}:)?(function:)?([a-zA-Z0-9-_\\.]+)(:(\\$LATEST(\\.PUBLISHED)?|[a-zA-Z0-9-_]+))?" ] } } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[function_name_too_long_and_invalid_region-delete_function]": { - "recorded-date": "12-09-2024, 11:30:04", + "recorded-date": "25-11-2025, 02:27:55", "recorded-content": { "delete_function_exception": { "Code": "ValidationException", - "Count": 2, + "Count": 1, "Errors": [ - "Value 'arn::lambda:invalid-region:111111111111:function:my-functionaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' at 'functionName' failed to satisfy constraint: Member must have length less than or equal to 140", - "Value 'arn::lambda:invalid-region:111111111111:function:my-functionaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' at 'functionName' failed to satisfy constraint: Member must satisfy regular expression pattern: (arn:(aws[a-zA-Z-]*)?:lambda:)?([a-z]{2}((-gov)|(-iso([a-z]?)))?-[a-z]+-\\d{1}:)?(\\d{12}:)?(function:)?([a-zA-Z0-9-_]+)(:(\\$LATEST|[a-zA-Z0-9-_]+))?" + "Value 'arn::lambda:invalid-region:111111111111:function:my-functionaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' at 'functionName' failed to satisfy constraint: Member must satisfy regular expression pattern: (arn:(aws[a-zA-Z-]*)?:lambda:)?((eusc-)?[a-z]{2}((-gov)|(-iso([a-z]?)))?-[a-z]+-\\d{1}:)?(\\d{12}:)?(function:)?([a-zA-Z0-9-_\\.]+)(:(\\$LATEST(\\.PUBLISHED)?|[a-zA-Z0-9-_]+))?" ] } } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[function_name_too_long_and_invalid_region-invoke]": { - "recorded-date": "12-09-2024, 11:30:04", + "recorded-date": "25-11-2025, 02:27:55", "recorded-content": { "invoke_exception": { "Code": "ValidationException", - "Count": 2, + "Count": 1, "Errors": [ - "Value 'arn::lambda:invalid-region:111111111111:function:my-function' at 'functionName' failed to satisfy constraint: Member must have length less than or equal to 170", - "Value 'arn::lambda:invalid-region:111111111111:function:my-function' at 'functionName' failed to satisfy constraint: Member must satisfy regular expression pattern: (arn:(aws[a-zA-Z-]*)?:lambda:)?([a-z]{2}((-gov)|(-iso([a-z]?)))?-[a-z]+-\\d{1}:)?(\\d{12}:)?(function:)?([a-zA-Z0-9-_\\.]+)(:(\\$LATEST|[a-zA-Z0-9-_]+))?" + "Value 'arn::lambda:invalid-region:111111111111:function:my-function' at 'functionName' failed to satisfy constraint: Member must satisfy regular expression pattern: (arn:(aws[a-zA-Z-]*)?:lambda:)?((eusc-)?[a-z]{2}((-gov)|(-iso([a-z]?)))?-[a-z]+-\\d{1}:)?(\\d{12}:)?(function:)?([a-zA-Z0-9-_\\.]+)(:(\\$LATEST(\\.PUBLISHED)?|[a-zA-Z0-9-_]+))?" ] } } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[function_name_too_long_and_invalid_region-create_function]": { - "recorded-date": "12-09-2024, 11:30:04", + "recorded-date": "25-11-2025, 02:27:55", "recorded-content": { "create_function_exception": { "Code": "ValidationException", "Count": 2, "Errors": [ "Value 'arn::lambda:invalid-region:111111111111:function:my-functionaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' at 'functionName' failed to satisfy constraint: Member must have length less than or equal to 140", - "Value 'arn::lambda:invalid-region:111111111111:function:my-functionaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' at 'functionName' failed to satisfy constraint: Member must satisfy regular expression pattern: (arn:(aws[a-zA-Z-]*)?:lambda:)?([a-z]{2}((-gov)|(-iso([a-z]?)))?-[a-z]+-\\d{1}:)?(\\d{12}:)?(function:)?([a-zA-Z0-9-_]+)(:(\\$LATEST|[a-zA-Z0-9-_]+))?" + "Value 'arn::lambda:invalid-region:111111111111:function:my-functionaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' at 'functionName' failed to satisfy constraint: Member must satisfy regular expression pattern: (arn:(aws[a-zA-Z-]*)?:lambda:)?((eusc-)?[a-z]{2}((-gov)|(-iso([a-z]?)))?-[a-z]+-\\d{1}:)?(\\d{12}:)?(function:)?([a-zA-Z0-9-_]+)(:(\\$LATEST|[a-zA-Z0-9-_]+))?" ] } } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[full_arn_and_qualifier_too_long_and_invalid_region-get_function]": { - "recorded-date": "12-09-2024, 11:30:04", + "recorded-date": "25-11-2025, 02:27:56", "recorded-content": { "get_function_exception": { "Code": "ValidationException", - "Count": 3, + "Count": 2, "Errors": [ "Value '' at 'qualifier' failed to satisfy constraint: Member must have length less than or equal to 128", - "Value 'arn::lambda:invalid-region:111111111111:function:my-function-' at 'functionName' failed to satisfy constraint: Member must have length less than or equal to 170", - "Value 'arn::lambda:invalid-region:111111111111:function:my-function-' at 'functionName' failed to satisfy constraint: Member must satisfy regular expression pattern: (arn:(aws[a-zA-Z-]*)?:lambda:)?([a-z]{2}((-gov)|(-iso([a-z]?)))?-[a-z]+-\\d{1}:)?(\\d{12}:)?(function:)?([a-zA-Z0-9-_\\.]+)(:(\\$LATEST|[a-zA-Z0-9-_]+))?" + "Value 'arn::lambda:invalid-region:111111111111:function:my-function-' at 'functionName' failed to satisfy constraint: Member must satisfy regular expression pattern: (arn:(aws[a-zA-Z-]*)?:lambda:)?((eusc-)?[a-z]{2}((-gov)|(-iso([a-z]?)))?-[a-z]+-\\d{1}:)?(\\d{12}:)?(function:)?([a-zA-Z0-9-_\\.]+)(:(\\$LATEST(\\.PUBLISHED)?|[a-zA-Z0-9-_]+))?" ] } } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[full_arn_and_qualifier_too_long_and_invalid_region-delete_function]": { - "recorded-date": "12-09-2024, 11:30:04", + "recorded-date": "25-11-2025, 02:27:56", "recorded-content": { "delete_function_exception": { "Code": "ValidationException", - "Count": 3, + "Count": 2, "Errors": [ "Value '' at 'qualifier' failed to satisfy constraint: Member must have length less than or equal to 128", - "Value 'arn::lambda:invalid-region:111111111111:function:my-function-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' at 'functionName' failed to satisfy constraint: Member must have length less than or equal to 140", - "Value 'arn::lambda:invalid-region:111111111111:function:my-function-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' at 'functionName' failed to satisfy constraint: Member must satisfy regular expression pattern: (arn:(aws[a-zA-Z-]*)?:lambda:)?([a-z]{2}((-gov)|(-iso([a-z]?)))?-[a-z]+-\\d{1}:)?(\\d{12}:)?(function:)?([a-zA-Z0-9-_]+)(:(\\$LATEST|[a-zA-Z0-9-_]+))?" + "Value 'arn::lambda:invalid-region:111111111111:function:my-function-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' at 'functionName' failed to satisfy constraint: Member must satisfy regular expression pattern: (arn:(aws[a-zA-Z-]*)?:lambda:)?((eusc-)?[a-z]{2}((-gov)|(-iso([a-z]?)))?-[a-z]+-\\d{1}:)?(\\d{12}:)?(function:)?([a-zA-Z0-9-_\\.]+)(:(\\$LATEST(\\.PUBLISHED)?|[a-zA-Z0-9-_]+))?" ] } } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[full_arn_and_qualifier_too_long_and_invalid_region-invoke]": { - "recorded-date": "12-09-2024, 11:30:04", + "recorded-date": "25-11-2025, 02:27:56", "recorded-content": { "invoke_exception": { "Code": "ValidationException", - "Count": 3, + "Count": 2, "Errors": [ "Value '' at 'qualifier' failed to satisfy constraint: Member must have length less than or equal to 128", - "Value 'arn::lambda:invalid-region:111111111111:function:my-function-' at 'functionName' failed to satisfy constraint: Member must have length less than or equal to 170", - "Value 'arn::lambda:invalid-region:111111111111:function:my-function-' at 'functionName' failed to satisfy constraint: Member must satisfy regular expression pattern: (arn:(aws[a-zA-Z-]*)?:lambda:)?([a-z]{2}((-gov)|(-iso([a-z]?)))?-[a-z]+-\\d{1}:)?(\\d{12}:)?(function:)?([a-zA-Z0-9-_\\.]+)(:(\\$LATEST|[a-zA-Z0-9-_]+))?" + "Value 'arn::lambda:invalid-region:111111111111:function:my-function-' at 'functionName' failed to satisfy constraint: Member must satisfy regular expression pattern: (arn:(aws[a-zA-Z-]*)?:lambda:)?((eusc-)?[a-z]{2}((-gov)|(-iso([a-z]?)))?-[a-z]+-\\d{1}:)?(\\d{12}:)?(function:)?([a-zA-Z0-9-_\\.]+)(:(\\$LATEST(\\.PUBLISHED)?|[a-zA-Z0-9-_]+))?" ] } } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[full_arn_and_qualifier_too_long_and_invalid_region-create_function]": { - "recorded-date": "12-09-2024, 11:30:04", + "recorded-date": "25-11-2025, 02:27:56", "recorded-content": { "create_function_exception": { "Code": "ValidationException", "Count": 2, "Errors": [ "Value 'arn::lambda:invalid-region:111111111111:function:my-function-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa:' at 'functionName' failed to satisfy constraint: Member must have length less than or equal to 140", - "Value 'arn::lambda:invalid-region:111111111111:function:my-function-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa:' at 'functionName' failed to satisfy constraint: Member must satisfy regular expression pattern: (arn:(aws[a-zA-Z-]*)?:lambda:)?([a-z]{2}((-gov)|(-iso([a-z]?)))?-[a-z]+-\\d{1}:)?(\\d{12}:)?(function:)?([a-zA-Z0-9-_]+)(:(\\$LATEST|[a-zA-Z0-9-_]+))?" + "Value 'arn::lambda:invalid-region:111111111111:function:my-function-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa:' at 'functionName' failed to satisfy constraint: Member must satisfy regular expression pattern: (arn:(aws[a-zA-Z-]*)?:lambda:)?((eusc-)?[a-z]{2}((-gov)|(-iso([a-z]?)))?-[a-z]+-\\d{1}:)?(\\d{12}:)?(function:)?([a-zA-Z0-9-_]+)(:(\\$LATEST|[a-zA-Z0-9-_]+))?" ] } } @@ -16592,55 +16547,55 @@ "recorded-content": {} }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[full_arn_with_multiple_qualifiers-get_function]": { - "recorded-date": "12-09-2024, 11:30:04", + "recorded-date": "25-11-2025, 02:27:56", "recorded-content": { "get_function_exception": { "Code": "ValidationException", "Count": 1, "Errors": [ - "Value 'arn::lambda::111111111111:function:my-function:1:2' at 'functionName' failed to satisfy constraint: Member must satisfy regular expression pattern: (arn:(aws[a-zA-Z-]*)?:lambda:)?([a-z]{2}((-gov)|(-iso([a-z]?)))?-[a-z]+-\\d{1}:)?(\\d{12}:)?(function:)?([a-zA-Z0-9-_\\.]+)(:(\\$LATEST|[a-zA-Z0-9-_]+))?" + "Value 'arn::lambda::111111111111:function:my-function:1:2' at 'functionName' failed to satisfy constraint: Member must satisfy regular expression pattern: (arn:(aws[a-zA-Z-]*)?:lambda:)?((eusc-)?[a-z]{2}((-gov)|(-iso([a-z]?)))?-[a-z]+-\\d{1}:)?(\\d{12}:)?(function:)?([a-zA-Z0-9-_\\.]+)(:(\\$LATEST(\\.PUBLISHED)?|[a-zA-Z0-9-_]+))?" ] } } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[full_arn_with_multiple_qualifiers-delete_function]": { - "recorded-date": "12-09-2024, 11:30:04", + "recorded-date": "25-11-2025, 02:27:56", "recorded-content": { "delete_function_exception": { "Code": "ValidationException", "Count": 1, "Errors": [ - "Value 'arn::lambda::111111111111:function:my-function:1:2' at 'functionName' failed to satisfy constraint: Member must satisfy regular expression pattern: (arn:(aws[a-zA-Z-]*)?:lambda:)?([a-z]{2}((-gov)|(-iso([a-z]?)))?-[a-z]+-\\d{1}:)?(\\d{12}:)?(function:)?([a-zA-Z0-9-_]+)(:(\\$LATEST|[a-zA-Z0-9-_]+))?" + "Value 'arn::lambda::111111111111:function:my-function:1:2' at 'functionName' failed to satisfy constraint: Member must satisfy regular expression pattern: (arn:(aws[a-zA-Z-]*)?:lambda:)?((eusc-)?[a-z]{2}((-gov)|(-iso([a-z]?)))?-[a-z]+-\\d{1}:)?(\\d{12}:)?(function:)?([a-zA-Z0-9-_\\.]+)(:(\\$LATEST(\\.PUBLISHED)?|[a-zA-Z0-9-_]+))?" ] } } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[full_arn_with_multiple_qualifiers-invoke]": { - "recorded-date": "12-09-2024, 11:30:04", + "recorded-date": "25-11-2025, 02:27:56", "recorded-content": { "invoke_exception": { "Code": "ValidationException", "Count": 1, "Errors": [ - "Value 'arn::lambda::111111111111:function:my-function:1:2' at 'functionName' failed to satisfy constraint: Member must satisfy regular expression pattern: (arn:(aws[a-zA-Z-]*)?:lambda:)?([a-z]{2}((-gov)|(-iso([a-z]?)))?-[a-z]+-\\d{1}:)?(\\d{12}:)?(function:)?([a-zA-Z0-9-_\\.]+)(:(\\$LATEST|[a-zA-Z0-9-_]+))?" + "Value 'arn::lambda::111111111111:function:my-function:1:2' at 'functionName' failed to satisfy constraint: Member must satisfy regular expression pattern: (arn:(aws[a-zA-Z-]*)?:lambda:)?((eusc-)?[a-z]{2}((-gov)|(-iso([a-z]?)))?-[a-z]+-\\d{1}:)?(\\d{12}:)?(function:)?([a-zA-Z0-9-_\\.]+)(:(\\$LATEST(\\.PUBLISHED)?|[a-zA-Z0-9-_]+))?" ] } } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[full_arn_with_multiple_qualifiers-create_function]": { - "recorded-date": "12-09-2024, 11:30:05", + "recorded-date": "25-11-2025, 02:27:56", "recorded-content": { "create_function_exception": { "Code": "ValidationException", "Count": 1, "Errors": [ - "Value 'arn::lambda::111111111111:function:my-function:1:2' at 'functionName' failed to satisfy constraint: Member must satisfy regular expression pattern: (arn:(aws[a-zA-Z-]*)?:lambda:)?([a-z]{2}((-gov)|(-iso([a-z]?)))?-[a-z]+-\\d{1}:)?(\\d{12}:)?(function:)?([a-zA-Z0-9-_]+)(:(\\$LATEST|[a-zA-Z0-9-_]+))?" + "Value 'arn::lambda::111111111111:function:my-function:1:2' at 'functionName' failed to satisfy constraint: Member must satisfy regular expression pattern: (arn:(aws[a-zA-Z-]*)?:lambda:)?((eusc-)?[a-z]{2}((-gov)|(-iso([a-z]?)))?-[a-z]+-\\d{1}:)?(\\d{12}:)?(function:)?([a-zA-Z0-9-_]+)(:(\\$LATEST|[a-zA-Z0-9-_]+))?" ] } } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[incomplete_arn-get_function]": { - "recorded-date": "12-09-2024, 11:30:05", + "recorded-date": "25-11-2025, 02:27:57", "recorded-content": { "get_function_exception": { "Code": "ResourceNotFoundException", @@ -16649,7 +16604,7 @@ } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[incomplete_arn-delete_function]": { - "recorded-date": "12-09-2024, 11:30:05", + "recorded-date": "25-11-2025, 02:27:57", "recorded-content": { "delete_function_exception": { "Code": "ResourceNotFoundException", @@ -16658,7 +16613,7 @@ } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[incomplete_arn-invoke]": { - "recorded-date": "12-09-2024, 11:30:05", + "recorded-date": "25-11-2025, 02:27:57", "recorded-content": { "invoke_exception": { "Code": "ResourceNotFoundException", @@ -16667,59 +16622,59 @@ } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[incomplete_arn-create_function]": { - "recorded-date": "12-09-2024, 11:30:05", + "recorded-date": "25-11-2025, 02:27:57", "recorded-content": {} }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[partial_arn_with_extra_qualifier-get_function]": { - "recorded-date": "12-09-2024, 11:30:05", + "recorded-date": "25-11-2025, 02:27:57", "recorded-content": { "get_function_exception": { "Code": "ValidationException", "Count": 1, "Errors": [ - "Value 'function:my-function:$LATEST:extra' at 'functionName' failed to satisfy constraint: Member must satisfy regular expression pattern: (arn:(aws[a-zA-Z-]*)?:lambda:)?([a-z]{2}((-gov)|(-iso([a-z]?)))?-[a-z]+-\\d{1}:)?(\\d{12}:)?(function:)?([a-zA-Z0-9-_\\.]+)(:(\\$LATEST|[a-zA-Z0-9-_]+))?" + "Value 'function:my-function:$LATEST:extra' at 'functionName' failed to satisfy constraint: Member must satisfy regular expression pattern: (arn:(aws[a-zA-Z-]*)?:lambda:)?((eusc-)?[a-z]{2}((-gov)|(-iso([a-z]?)))?-[a-z]+-\\d{1}:)?(\\d{12}:)?(function:)?([a-zA-Z0-9-_\\.]+)(:(\\$LATEST(\\.PUBLISHED)?|[a-zA-Z0-9-_]+))?" ] } } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[partial_arn_with_extra_qualifier-delete_function]": { - "recorded-date": "12-09-2024, 11:30:05", + "recorded-date": "25-11-2025, 02:27:57", "recorded-content": { "delete_function_exception": { "Code": "ValidationException", "Count": 1, "Errors": [ - "Value 'function:my-function:$LATEST:extra' at 'functionName' failed to satisfy constraint: Member must satisfy regular expression pattern: (arn:(aws[a-zA-Z-]*)?:lambda:)?([a-z]{2}((-gov)|(-iso([a-z]?)))?-[a-z]+-\\d{1}:)?(\\d{12}:)?(function:)?([a-zA-Z0-9-_]+)(:(\\$LATEST|[a-zA-Z0-9-_]+))?" + "Value 'function:my-function:$LATEST:extra' at 'functionName' failed to satisfy constraint: Member must satisfy regular expression pattern: (arn:(aws[a-zA-Z-]*)?:lambda:)?((eusc-)?[a-z]{2}((-gov)|(-iso([a-z]?)))?-[a-z]+-\\d{1}:)?(\\d{12}:)?(function:)?([a-zA-Z0-9-_\\.]+)(:(\\$LATEST(\\.PUBLISHED)?|[a-zA-Z0-9-_]+))?" ] } } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[partial_arn_with_extra_qualifier-invoke]": { - "recorded-date": "12-09-2024, 11:30:05", + "recorded-date": "25-11-2025, 02:27:57", "recorded-content": { "invoke_exception": { "Code": "ValidationException", "Count": 1, "Errors": [ - "Value 'function:my-function:$LATEST:extra' at 'functionName' failed to satisfy constraint: Member must satisfy regular expression pattern: (arn:(aws[a-zA-Z-]*)?:lambda:)?([a-z]{2}((-gov)|(-iso([a-z]?)))?-[a-z]+-\\d{1}:)?(\\d{12}:)?(function:)?([a-zA-Z0-9-_\\.]+)(:(\\$LATEST|[a-zA-Z0-9-_]+))?" + "Value 'function:my-function:$LATEST:extra' at 'functionName' failed to satisfy constraint: Member must satisfy regular expression pattern: (arn:(aws[a-zA-Z-]*)?:lambda:)?((eusc-)?[a-z]{2}((-gov)|(-iso([a-z]?)))?-[a-z]+-\\d{1}:)?(\\d{12}:)?(function:)?([a-zA-Z0-9-_\\.]+)(:(\\$LATEST(\\.PUBLISHED)?|[a-zA-Z0-9-_]+))?" ] } } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[partial_arn_with_extra_qualifier-create_function]": { - "recorded-date": "12-09-2024, 11:30:05", + "recorded-date": "25-11-2025, 02:27:58", "recorded-content": { "create_function_exception": { "Code": "ValidationException", "Count": 1, "Errors": [ - "Value 'function:my-function:$LATEST:extra' at 'functionName' failed to satisfy constraint: Member must satisfy regular expression pattern: (arn:(aws[a-zA-Z-]*)?:lambda:)?([a-z]{2}((-gov)|(-iso([a-z]?)))?-[a-z]+-\\d{1}:)?(\\d{12}:)?(function:)?([a-zA-Z0-9-_]+)(:(\\$LATEST|[a-zA-Z0-9-_]+))?" + "Value 'function:my-function:$LATEST:extra' at 'functionName' failed to satisfy constraint: Member must satisfy regular expression pattern: (arn:(aws[a-zA-Z-]*)?:lambda:)?((eusc-)?[a-z]{2}((-gov)|(-iso([a-z]?)))?-[a-z]+-\\d{1}:)?(\\d{12}:)?(function:)?([a-zA-Z0-9-_]+)(:(\\$LATEST|[a-zA-Z0-9-_]+))?" ] } } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[latest_version_with_additional_qualifier-get_function]": { - "recorded-date": "12-09-2024, 11:30:05", + "recorded-date": "25-11-2025, 02:27:58", "recorded-content": { "get_function_exception": { "Code": "InvalidParameterValueException", @@ -16728,7 +16683,7 @@ } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[latest_version_with_additional_qualifier-delete_function]": { - "recorded-date": "12-09-2024, 11:30:05", + "recorded-date": "25-11-2025, 02:27:58", "recorded-content": { "delete_function_exception": { "Code": "InvalidParameterValueException", @@ -16737,7 +16692,7 @@ } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[latest_version_with_additional_qualifier-invoke]": { - "recorded-date": "12-09-2024, 11:30:05", + "recorded-date": "25-11-2025, 02:27:58", "recorded-content": { "invoke_exception": { "Code": "InvalidParameterValueException", @@ -16746,19 +16701,19 @@ } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[latest_version_with_additional_qualifier-create_function]": { - "recorded-date": "12-09-2024, 11:30:05", + "recorded-date": "25-11-2025, 02:27:58", "recorded-content": { "create_function_exception": { "Code": "ValidationException", "Count": 1, "Errors": [ - "Value 'arn::lambda::111111111111:function:my-function:$LATEST:1' at 'functionName' failed to satisfy constraint: Member must satisfy regular expression pattern: (arn:(aws[a-zA-Z-]*)?:lambda:)?([a-z]{2}((-gov)|(-iso([a-z]?)))?-[a-z]+-\\d{1}:)?(\\d{12}:)?(function:)?([a-zA-Z0-9-_]+)(:(\\$LATEST|[a-zA-Z0-9-_]+))?" + "Value 'arn::lambda::111111111111:function:my-function:$LATEST:1' at 'functionName' failed to satisfy constraint: Member must satisfy regular expression pattern: (arn:(aws[a-zA-Z-]*)?:lambda:)?((eusc-)?[a-z]{2}((-gov)|(-iso([a-z]?)))?-[a-z]+-\\d{1}:)?(\\d{12}:)?(function:)?([a-zA-Z0-9-_]+)(:(\\$LATEST|[a-zA-Z0-9-_]+))?" ] } } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[lowercase_latest_qualifier-get_function]": { - "recorded-date": "12-09-2024, 11:30:05", + "recorded-date": "25-11-2025, 02:27:58", "recorded-content": { "get_function_exception": { "Code": "ResourceNotFoundException", @@ -16767,11 +16722,16 @@ } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[lowercase_latest_qualifier-delete_function]": { - "recorded-date": "12-09-2024, 11:30:05", - "recorded-content": {} + "recorded-date": "25-11-2025, 02:27:58", + "recorded-content": { + "delete_function_exception": { + "Code": "ResourceNotFoundException", + "Message": "Function not found: arn::lambda::111111111111:function:my-function" + } + } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[lowercase_latest_qualifier-invoke]": { - "recorded-date": "12-09-2024, 11:30:06", + "recorded-date": "25-11-2025, 02:27:59", "recorded-content": { "invoke_exception": { "Code": "ResourceNotFoundException", @@ -16780,163 +16740,163 @@ } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[lowercase_latest_qualifier-create_function]": { - "recorded-date": "12-09-2024, 11:30:06", + "recorded-date": "25-11-2025, 02:27:59", "recorded-content": { "create_function_exception": { "Code": "ValidationException", "Count": 1, "Errors": [ - "Value 'arn::lambda::111111111111:function:my-function:$latest' at 'functionName' failed to satisfy constraint: Member must satisfy regular expression pattern: (arn:(aws[a-zA-Z-]*)?:lambda:)?([a-z]{2}((-gov)|(-iso([a-z]?)))?-[a-z]+-\\d{1}:)?(\\d{12}:)?(function:)?([a-zA-Z0-9-_]+)(:(\\$LATEST|[a-zA-Z0-9-_]+))?" + "Value 'arn::lambda::111111111111:function:my-function:$latest' at 'functionName' failed to satisfy constraint: Member must satisfy regular expression pattern: (arn:(aws[a-zA-Z-]*)?:lambda:)?((eusc-)?[a-z]{2}((-gov)|(-iso([a-z]?)))?-[a-z]+-\\d{1}:)?(\\d{12}:)?(function:)?([a-zA-Z0-9-_]+)(:(\\$LATEST|[a-zA-Z0-9-_]+))?" ] } } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[missing_region_in_arn-get_function]": { - "recorded-date": "12-09-2024, 11:30:06", + "recorded-date": "25-11-2025, 02:27:59", "recorded-content": { "get_function_exception": { "Code": "ValidationException", "Count": 1, "Errors": [ - "Value 'arn::lambda::111111111111:function:my-function' at 'functionName' failed to satisfy constraint: Member must satisfy regular expression pattern: (arn:(aws[a-zA-Z-]*)?:lambda:)?([a-z]{2}((-gov)|(-iso([a-z]?)))?-[a-z]+-\\d{1}:)?(\\d{12}:)?(function:)?([a-zA-Z0-9-_\\.]+)(:(\\$LATEST|[a-zA-Z0-9-_]+))?" + "Value 'arn::lambda::111111111111:function:my-function' at 'functionName' failed to satisfy constraint: Member must satisfy regular expression pattern: (arn:(aws[a-zA-Z-]*)?:lambda:)?((eusc-)?[a-z]{2}((-gov)|(-iso([a-z]?)))?-[a-z]+-\\d{1}:)?(\\d{12}:)?(function:)?([a-zA-Z0-9-_\\.]+)(:(\\$LATEST(\\.PUBLISHED)?|[a-zA-Z0-9-_]+))?" ] } } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[missing_region_in_arn-delete_function]": { - "recorded-date": "12-09-2024, 11:30:06", + "recorded-date": "25-11-2025, 02:27:59", "recorded-content": { "delete_function_exception": { "Code": "ValidationException", "Count": 1, "Errors": [ - "Value 'arn::lambda::111111111111:function:my-function' at 'functionName' failed to satisfy constraint: Member must satisfy regular expression pattern: (arn:(aws[a-zA-Z-]*)?:lambda:)?([a-z]{2}((-gov)|(-iso([a-z]?)))?-[a-z]+-\\d{1}:)?(\\d{12}:)?(function:)?([a-zA-Z0-9-_]+)(:(\\$LATEST|[a-zA-Z0-9-_]+))?" + "Value 'arn::lambda::111111111111:function:my-function' at 'functionName' failed to satisfy constraint: Member must satisfy regular expression pattern: (arn:(aws[a-zA-Z-]*)?:lambda:)?((eusc-)?[a-z]{2}((-gov)|(-iso([a-z]?)))?-[a-z]+-\\d{1}:)?(\\d{12}:)?(function:)?([a-zA-Z0-9-_\\.]+)(:(\\$LATEST(\\.PUBLISHED)?|[a-zA-Z0-9-_]+))?" ] } } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[missing_region_in_arn-invoke]": { - "recorded-date": "12-09-2024, 11:30:06", + "recorded-date": "25-11-2025, 02:27:59", "recorded-content": { "invoke_exception": { "Code": "ValidationException", "Count": 1, "Errors": [ - "Value 'arn::lambda::111111111111:function:my-function' at 'functionName' failed to satisfy constraint: Member must satisfy regular expression pattern: (arn:(aws[a-zA-Z-]*)?:lambda:)?([a-z]{2}((-gov)|(-iso([a-z]?)))?-[a-z]+-\\d{1}:)?(\\d{12}:)?(function:)?([a-zA-Z0-9-_\\.]+)(:(\\$LATEST|[a-zA-Z0-9-_]+))?" + "Value 'arn::lambda::111111111111:function:my-function' at 'functionName' failed to satisfy constraint: Member must satisfy regular expression pattern: (arn:(aws[a-zA-Z-]*)?:lambda:)?((eusc-)?[a-z]{2}((-gov)|(-iso([a-z]?)))?-[a-z]+-\\d{1}:)?(\\d{12}:)?(function:)?([a-zA-Z0-9-_\\.]+)(:(\\$LATEST(\\.PUBLISHED)?|[a-zA-Z0-9-_]+))?" ] } } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[missing_region_in_arn-create_function]": { - "recorded-date": "12-09-2024, 11:30:06", + "recorded-date": "25-11-2025, 02:27:59", "recorded-content": { "create_function_exception": { "Code": "ValidationException", "Count": 1, "Errors": [ - "Value 'arn::lambda::111111111111:function:my-function' at 'functionName' failed to satisfy constraint: Member must satisfy regular expression pattern: (arn:(aws[a-zA-Z-]*)?:lambda:)?([a-z]{2}((-gov)|(-iso([a-z]?)))?-[a-z]+-\\d{1}:)?(\\d{12}:)?(function:)?([a-zA-Z0-9-_]+)(:(\\$LATEST|[a-zA-Z0-9-_]+))?" + "Value 'arn::lambda::111111111111:function:my-function' at 'functionName' failed to satisfy constraint: Member must satisfy regular expression pattern: (arn:(aws[a-zA-Z-]*)?:lambda:)?((eusc-)?[a-z]{2}((-gov)|(-iso([a-z]?)))?-[a-z]+-\\d{1}:)?(\\d{12}:)?(function:)?([a-zA-Z0-9-_]+)(:(\\$LATEST|[a-zA-Z0-9-_]+))?" ] } } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[missing_account_id_in_arn-get_function]": { - "recorded-date": "12-09-2024, 11:30:06", + "recorded-date": "25-11-2025, 02:27:59", "recorded-content": { "get_function_exception": { "Code": "ValidationException", "Count": 1, "Errors": [ - "Value 'arn::lambda:::function:my-function' at 'functionName' failed to satisfy constraint: Member must satisfy regular expression pattern: (arn:(aws[a-zA-Z-]*)?:lambda:)?([a-z]{2}((-gov)|(-iso([a-z]?)))?-[a-z]+-\\d{1}:)?(\\d{12}:)?(function:)?([a-zA-Z0-9-_\\.]+)(:(\\$LATEST|[a-zA-Z0-9-_]+))?" + "Value 'arn::lambda:::function:my-function' at 'functionName' failed to satisfy constraint: Member must satisfy regular expression pattern: (arn:(aws[a-zA-Z-]*)?:lambda:)?((eusc-)?[a-z]{2}((-gov)|(-iso([a-z]?)))?-[a-z]+-\\d{1}:)?(\\d{12}:)?(function:)?([a-zA-Z0-9-_\\.]+)(:(\\$LATEST(\\.PUBLISHED)?|[a-zA-Z0-9-_]+))?" ] } } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[missing_account_id_in_arn-delete_function]": { - "recorded-date": "12-09-2024, 11:30:06", + "recorded-date": "25-11-2025, 02:27:59", "recorded-content": { "delete_function_exception": { "Code": "ValidationException", "Count": 1, "Errors": [ - "Value 'arn::lambda:::function:my-function' at 'functionName' failed to satisfy constraint: Member must satisfy regular expression pattern: (arn:(aws[a-zA-Z-]*)?:lambda:)?([a-z]{2}((-gov)|(-iso([a-z]?)))?-[a-z]+-\\d{1}:)?(\\d{12}:)?(function:)?([a-zA-Z0-9-_]+)(:(\\$LATEST|[a-zA-Z0-9-_]+))?" + "Value 'arn::lambda:::function:my-function' at 'functionName' failed to satisfy constraint: Member must satisfy regular expression pattern: (arn:(aws[a-zA-Z-]*)?:lambda:)?((eusc-)?[a-z]{2}((-gov)|(-iso([a-z]?)))?-[a-z]+-\\d{1}:)?(\\d{12}:)?(function:)?([a-zA-Z0-9-_\\.]+)(:(\\$LATEST(\\.PUBLISHED)?|[a-zA-Z0-9-_]+))?" ] } } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[missing_account_id_in_arn-invoke]": { - "recorded-date": "12-09-2024, 11:30:06", + "recorded-date": "25-11-2025, 02:28:00", "recorded-content": { "invoke_exception": { "Code": "ValidationException", "Count": 1, "Errors": [ - "Value 'arn::lambda:::function:my-function' at 'functionName' failed to satisfy constraint: Member must satisfy regular expression pattern: (arn:(aws[a-zA-Z-]*)?:lambda:)?([a-z]{2}((-gov)|(-iso([a-z]?)))?-[a-z]+-\\d{1}:)?(\\d{12}:)?(function:)?([a-zA-Z0-9-_\\.]+)(:(\\$LATEST|[a-zA-Z0-9-_]+))?" + "Value 'arn::lambda:::function:my-function' at 'functionName' failed to satisfy constraint: Member must satisfy regular expression pattern: (arn:(aws[a-zA-Z-]*)?:lambda:)?((eusc-)?[a-z]{2}((-gov)|(-iso([a-z]?)))?-[a-z]+-\\d{1}:)?(\\d{12}:)?(function:)?([a-zA-Z0-9-_\\.]+)(:(\\$LATEST(\\.PUBLISHED)?|[a-zA-Z0-9-_]+))?" ] } } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[missing_account_id_in_arn-create_function]": { - "recorded-date": "12-09-2024, 11:30:06", + "recorded-date": "25-11-2025, 02:28:00", "recorded-content": { "create_function_exception": { "Code": "ValidationException", "Count": 1, "Errors": [ - "Value 'arn::lambda:::function:my-function' at 'functionName' failed to satisfy constraint: Member must satisfy regular expression pattern: (arn:(aws[a-zA-Z-]*)?:lambda:)?([a-z]{2}((-gov)|(-iso([a-z]?)))?-[a-z]+-\\d{1}:)?(\\d{12}:)?(function:)?([a-zA-Z0-9-_]+)(:(\\$LATEST|[a-zA-Z0-9-_]+))?" + "Value 'arn::lambda:::function:my-function' at 'functionName' failed to satisfy constraint: Member must satisfy regular expression pattern: (arn:(aws[a-zA-Z-]*)?:lambda:)?((eusc-)?[a-z]{2}((-gov)|(-iso([a-z]?)))?-[a-z]+-\\d{1}:)?(\\d{12}:)?(function:)?([a-zA-Z0-9-_]+)(:(\\$LATEST|[a-zA-Z0-9-_]+))?" ] } } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[misspelled_latest_in_arn-get_function]": { - "recorded-date": "12-09-2024, 11:30:06", + "recorded-date": "25-11-2025, 02:28:00", "recorded-content": { "get_function_exception": { "Code": "ValidationException", "Count": 1, "Errors": [ - "Value 'arn::lambda::111111111111:function:my-function:$LATES' at 'functionName' failed to satisfy constraint: Member must satisfy regular expression pattern: (arn:(aws[a-zA-Z-]*)?:lambda:)?([a-z]{2}((-gov)|(-iso([a-z]?)))?-[a-z]+-\\d{1}:)?(\\d{12}:)?(function:)?([a-zA-Z0-9-_\\.]+)(:(\\$LATEST|[a-zA-Z0-9-_]+))?" + "Value 'arn::lambda::111111111111:function:my-function:$LATES' at 'functionName' failed to satisfy constraint: Member must satisfy regular expression pattern: (arn:(aws[a-zA-Z-]*)?:lambda:)?((eusc-)?[a-z]{2}((-gov)|(-iso([a-z]?)))?-[a-z]+-\\d{1}:)?(\\d{12}:)?(function:)?([a-zA-Z0-9-_\\.]+)(:(\\$LATEST(\\.PUBLISHED)?|[a-zA-Z0-9-_]+))?" ] } } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[misspelled_latest_in_arn-delete_function]": { - "recorded-date": "12-09-2024, 11:30:06", + "recorded-date": "25-11-2025, 02:28:00", "recorded-content": { "delete_function_exception": { "Code": "ValidationException", "Count": 1, "Errors": [ - "Value 'arn::lambda::111111111111:function:my-function:$LATES' at 'functionName' failed to satisfy constraint: Member must satisfy regular expression pattern: (arn:(aws[a-zA-Z-]*)?:lambda:)?([a-z]{2}((-gov)|(-iso([a-z]?)))?-[a-z]+-\\d{1}:)?(\\d{12}:)?(function:)?([a-zA-Z0-9-_]+)(:(\\$LATEST|[a-zA-Z0-9-_]+))?" + "Value 'arn::lambda::111111111111:function:my-function:$LATES' at 'functionName' failed to satisfy constraint: Member must satisfy regular expression pattern: (arn:(aws[a-zA-Z-]*)?:lambda:)?((eusc-)?[a-z]{2}((-gov)|(-iso([a-z]?)))?-[a-z]+-\\d{1}:)?(\\d{12}:)?(function:)?([a-zA-Z0-9-_\\.]+)(:(\\$LATEST(\\.PUBLISHED)?|[a-zA-Z0-9-_]+))?" ] } } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[misspelled_latest_in_arn-invoke]": { - "recorded-date": "12-09-2024, 11:30:06", + "recorded-date": "25-11-2025, 02:28:00", "recorded-content": { "invoke_exception": { "Code": "ValidationException", "Count": 1, "Errors": [ - "Value 'arn::lambda::111111111111:function:my-function:$LATES' at 'functionName' failed to satisfy constraint: Member must satisfy regular expression pattern: (arn:(aws[a-zA-Z-]*)?:lambda:)?([a-z]{2}((-gov)|(-iso([a-z]?)))?-[a-z]+-\\d{1}:)?(\\d{12}:)?(function:)?([a-zA-Z0-9-_\\.]+)(:(\\$LATEST|[a-zA-Z0-9-_]+))?" + "Value 'arn::lambda::111111111111:function:my-function:$LATES' at 'functionName' failed to satisfy constraint: Member must satisfy regular expression pattern: (arn:(aws[a-zA-Z-]*)?:lambda:)?((eusc-)?[a-z]{2}((-gov)|(-iso([a-z]?)))?-[a-z]+-\\d{1}:)?(\\d{12}:)?(function:)?([a-zA-Z0-9-_\\.]+)(:(\\$LATEST(\\.PUBLISHED)?|[a-zA-Z0-9-_]+))?" ] } } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[misspelled_latest_in_arn-create_function]": { - "recorded-date": "12-09-2024, 11:30:06", + "recorded-date": "25-11-2025, 02:28:00", "recorded-content": { "create_function_exception": { "Code": "ValidationException", "Count": 1, "Errors": [ - "Value 'arn::lambda::111111111111:function:my-function:$LATES' at 'functionName' failed to satisfy constraint: Member must satisfy regular expression pattern: (arn:(aws[a-zA-Z-]*)?:lambda:)?([a-z]{2}((-gov)|(-iso([a-z]?)))?-[a-z]+-\\d{1}:)?(\\d{12}:)?(function:)?([a-zA-Z0-9-_]+)(:(\\$LATEST|[a-zA-Z0-9-_]+))?" + "Value 'arn::lambda::111111111111:function:my-function:$LATES' at 'functionName' failed to satisfy constraint: Member must satisfy regular expression pattern: (arn:(aws[a-zA-Z-]*)?:lambda:)?((eusc-)?[a-z]{2}((-gov)|(-iso([a-z]?)))?-[a-z]+-\\d{1}:)?(\\d{12}:)?(function:)?([a-zA-Z0-9-_]+)(:(\\$LATEST|[a-zA-Z0-9-_]+))?" ] } } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[qualifier_too_long-get_function]": { - "recorded-date": "12-09-2024, 11:30:02", + "recorded-date": "25-11-2025, 02:27:52", "recorded-content": { "get_function_exception": { "Code": "ValidationException", @@ -16948,7 +16908,7 @@ } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[qualifier_too_long-delete_function]": { - "recorded-date": "12-09-2024, 11:30:02", + "recorded-date": "25-11-2025, 02:27:52", "recorded-content": { "delete_function_exception": { "Code": "ValidationException", @@ -16960,7 +16920,7 @@ } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[qualifier_too_long-invoke]": { - "recorded-date": "12-09-2024, 11:30:02", + "recorded-date": "25-11-2025, 02:27:53", "recorded-content": { "invoke_exception": { "Code": "ValidationException", @@ -16972,7 +16932,7 @@ } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[qualifier_too_long-create_function]": { - "recorded-date": "12-09-2024, 11:30:02", + "recorded-date": "25-11-2025, 02:27:53", "recorded-content": { "create_function_exception": { "Code": "ValidationException", @@ -17122,7 +17082,7 @@ } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaRecursion::test_put_function_recursion_config_allow": { - "recorded-date": "12-09-2024, 11:35:20", + "recorded-date": "25-11-2025, 02:36:04", "recorded-content": { "put_recursion_config_response": { "RecursiveLoop": "Allow", @@ -17141,7 +17101,7 @@ } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaRecursion::test_put_function_recursion_config_default_terminate": { - "recorded-date": "12-09-2024, 11:35:22", + "recorded-date": "25-11-2025, 02:36:11", "recorded-content": { "get_recursion_default_terminate_response": { "RecursiveLoop": "Terminate", @@ -17153,7 +17113,7 @@ } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaRecursion::test_put_function_recursion_config_invalid_value": { - "recorded-date": "12-09-2024, 11:35:24", + "recorded-date": "25-11-2025, 02:36:14", "recorded-content": { "put_recursion_invalid_value_error": { "Error": { @@ -17168,7 +17128,7 @@ } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaTag::test_tag_lifecycle[lambda_function]": { - "recorded-date": "23-10-2024, 10:51:15", + "recorded-date": "25-11-2025, 02:39:44", "recorded-content": { "tag_single_response": { "ResponseMetadata": { @@ -17283,7 +17243,7 @@ } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaTag::test_tag_lifecycle[event_source_mapping]": { - "recorded-date": "23-10-2024, 10:51:27", + "recorded-date": "25-11-2025, 02:39:50", "recorded-content": { "tag_single_response": { "ResponseMetadata": { @@ -17398,7 +17358,7 @@ } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaTag::test_create_tag_on_esm_create": { - "recorded-date": "24-10-2024, 14:16:07", + "recorded-date": "25-11-2025, 02:39:41", "recorded-content": { "get_event_source_mapping_with_tag": true, "list_tags_result": { @@ -17413,7 +17373,7 @@ } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaTag::test_tag_exceptions[lambda_function]": { - "recorded-date": "24-10-2024, 12:42:56", + "recorded-date": "25-11-2025, 21:37:01", "recorded-content": { "not_found_exception_tag": { "Error": { @@ -17466,7 +17426,7 @@ "invalid_arn_exception": { "Error": { "Code": "ValidationException", - "Message": "1 validation error detected: Value 'arn::lambda::111111111111:foobar:' at 'resource' failed to satisfy constraint: Member must satisfy regular expression pattern: arn:(aws[a-zA-Z-]*):lambda:[a-z]{2}((-gov)|(-iso([a-z]?)))?-[a-z]+-\\d{1}:\\d{12}:(function:[a-zA-Z0-9-_]+(:(\\$LATEST|[a-zA-Z0-9-_]+))?|layer:([a-zA-Z0-9-_]+)|code-signing-config:csc-[a-z0-9]{17}|event-source-mapping:[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12})" + "Message": "1 validation error detected: Value 'arn::lambda::111111111111:foobar:' at 'resource' failed to satisfy constraint: Member must satisfy regular expression pattern: arn:(aws[a-zA-Z-]*):lambda:(eusc-)?[a-z]{2}((-gov)|(-iso([a-z]?)))?-[a-z]+-\\d{1}:\\d{12}:(function:[a-zA-Z0-9-_]+(:(\\$LATEST|[a-zA-Z0-9-_]+))?|layer:([a-zA-Z0-9-_]+)|code-signing-config:csc-[a-z0-9]{17}|event-source-mapping:[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}|capacity-provider:[a-zA-Z0-9-_]+)" }, "ResponseMetadata": { "HTTPHeaders": {}, @@ -17476,7 +17436,7 @@ } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaTag::test_tag_exceptions[event_source_mapping]": { - "recorded-date": "24-10-2024, 12:42:57", + "recorded-date": "25-11-2025, 21:37:01", "recorded-content": { "not_found_exception_tag": { "Error": { @@ -17517,7 +17477,7 @@ "aliased_arn_exception": { "Error": { "Code": "ValidationException", - "Message": "1 validation error detected: Value 'arn::lambda::111111111111:event-source-mapping::alias' at 'resource' failed to satisfy constraint: Member must satisfy regular expression pattern: arn:(aws[a-zA-Z-]*):lambda:[a-z]{2}((-gov)|(-iso([a-z]?)))?-[a-z]+-\\d{1}:\\d{12}:(function:[a-zA-Z0-9-_]+(:(\\$LATEST|[a-zA-Z0-9-_]+))?|layer:([a-zA-Z0-9-_]+)|code-signing-config:csc-[a-z0-9]{17}|event-source-mapping:[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12})" + "Message": "1 validation error detected: Value 'arn::lambda::111111111111:event-source-mapping::alias' at 'resource' failed to satisfy constraint: Member must satisfy regular expression pattern: arn:(aws[a-zA-Z-]*):lambda:(eusc-)?[a-z]{2}((-gov)|(-iso([a-z]?)))?-[a-z]+-\\d{1}:\\d{12}:(function:[a-zA-Z0-9-_]+(:(\\$LATEST|[a-zA-Z0-9-_]+))?|layer:([a-zA-Z0-9-_]+)|code-signing-config:csc-[a-z0-9]{17}|event-source-mapping:[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}|capacity-provider:[a-zA-Z0-9-_]+)" }, "ResponseMetadata": { "HTTPHeaders": {}, @@ -17527,7 +17487,7 @@ "invalid_arn_exception": { "Error": { "Code": "ValidationException", - "Message": "1 validation error detected: Value 'arn::lambda::111111111111:foobar:' at 'resource' failed to satisfy constraint: Member must satisfy regular expression pattern: arn:(aws[a-zA-Z-]*):lambda:[a-z]{2}((-gov)|(-iso([a-z]?)))?-[a-z]+-\\d{1}:\\d{12}:(function:[a-zA-Z0-9-_]+(:(\\$LATEST|[a-zA-Z0-9-_]+))?|layer:([a-zA-Z0-9-_]+)|code-signing-config:csc-[a-z0-9]{17}|event-source-mapping:[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12})" + "Message": "1 validation error detected: Value 'arn::lambda::111111111111:foobar:' at 'resource' failed to satisfy constraint: Member must satisfy regular expression pattern: arn:(aws[a-zA-Z-]*):lambda:(eusc-)?[a-z]{2}((-gov)|(-iso([a-z]?)))?-[a-z]+-\\d{1}:\\d{12}:(function:[a-zA-Z0-9-_]+(:(\\$LATEST|[a-zA-Z0-9-_]+))?|layer:([a-zA-Z0-9-_]+)|code-signing-config:csc-[a-z0-9]{17}|event-source-mapping:[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}|capacity-provider:[a-zA-Z0-9-_]+)" }, "ResponseMetadata": { "HTTPHeaders": {}, @@ -17537,7 +17497,7 @@ } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaEventSourceMappings::test_event_source_mapping_lifecycle_delete_function": { - "recorded-date": "12-10-2024, 10:00:01", + "recorded-date": "25-11-2025, 02:47:20", "recorded-content": { "update_table_response": { "TableDescription": { @@ -17575,7 +17535,12 @@ "TableId": "", "TableName": "", "TableSizeBytes": 0, - "TableStatus": "UPDATING" + "TableStatus": "UPDATING", + "WarmThroughput": { + "ReadUnitsPerSecond": 12000, + "Status": "ACTIVE", + "WriteUnitsPerSecond": 4000 + } }, "ResponseMetadata": { "HTTPHeaders": {}, @@ -17639,6 +17604,7 @@ } }, "delete_function_response": { + "StatusCode": 204, "ResponseMetadata": { "HTTPHeaders": {}, "HTTPStatusCode": 204 @@ -17703,7 +17669,7 @@ } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaUrl::test_url_config_deletion_without_qualifier": { - "recorded-date": "21-11-2024, 13:44:17", + "recorded-date": "25-11-2025, 02:43:31", "recorded-content": { "url_creation": { "AuthType": "NONE", @@ -17782,7 +17748,7 @@ } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaAlias::test_non_existent_alias_deletion": { - "recorded-date": "21-11-2024, 13:44:51", + "recorded-date": "25-11-2025, 02:38:47", "recorded-content": { "create_response": { "Architectures": [ @@ -17841,7 +17807,7 @@ } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaAlias::test_non_existent_alias_update": { - "recorded-date": "21-11-2024, 13:44:53", + "recorded-date": "25-11-2025, 02:38:49", "recorded-content": { "create_response": { "Architectures": [ @@ -17906,7 +17872,7 @@ } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaEventSourceMappings::test_create_event_filter_criteria_validation": { - "recorded-date": "11-12-2024, 11:29:54", + "recorded-date": "18-12-2025, 15:04:51", "recorded-content": { "response-with-empty-filters": { "BatchSize": 100, @@ -17937,7 +17903,7 @@ } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaSnapStart::test_snapstart_lifecycle[python3.13]": { - "recorded-date": "01-04-2025, 13:31:11", + "recorded-date": "12-01-2026, 15:32:37", "recorded-content": { "create_function_response": { "Architectures": [ @@ -18081,7 +18047,7 @@ } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaSnapStart::test_snapstart_lifecycle[python3.12]": { - "recorded-date": "01-04-2025, 13:31:07", + "recorded-date": "12-01-2026, 15:32:31", "recorded-content": { "create_function_response": { "Architectures": [ @@ -18225,7 +18191,7 @@ } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_invalid_vpc_config_subnet": { - "recorded-date": "20-02-2025, 17:53:33", + "recorded-date": "25-11-2025, 02:35:53", "recorded-content": { "create-response-non-existent-subnet-id": { "Error": { @@ -18242,7 +18208,7 @@ "create-response-invalid-format-subnet-id": { "Error": { "Code": "ValidationException", - "Message": "1 validation error detected: Value '[]' at 'vpcConfig.subnetIds' failed to satisfy constraint: Member must satisfy constraint: [Member must have length less than or equal to 1024, Member must have length greater than or equal to 0, Member must satisfy regular expression pattern: ^subnet-[0-9a-z]*$]" + "Message": "1 validation error detected: Value '[]' at 'vpcConfig.subnetIds' failed to satisfy constraint: Member must satisfy constraint: [Member must have length less than or equal to 1024, Member must have length greater than or equal to 0, Member must satisfy regular expression pattern: subnet-[0-9a-z]*]" }, "ResponseMetadata": { "HTTPHeaders": {}, @@ -18252,7 +18218,7 @@ } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_invalid_vpc_config_security_group": { - "recorded-date": "20-02-2025, 17:57:29", + "recorded-date": "25-11-2025, 02:35:53", "recorded-content": { "create-response-non-existent-security-group": { "Error": { @@ -18269,7 +18235,7 @@ "create-response-invalid-format-security-group": { "Error": { "Code": "ValidationException", - "Message": "1 validation error detected: Value '[]' at 'vpcConfig.securityGroupIds' failed to satisfy constraint: Member must satisfy constraint: [Member must have length less than or equal to 1024, Member must have length greater than or equal to 0, Member must satisfy regular expression pattern: ^sg-[0-9a-zA-Z]*$]" + "Message": "1 validation error detected: Value '[]' at 'vpcConfig.securityGroupIds' failed to satisfy constraint: Member must satisfy constraint: [Member must have length less than or equal to 1024, Member must have length greater than or equal to 0, Member must satisfy regular expression pattern: sg-[0-9a-zA-Z]*]" }, "ResponseMetadata": { "HTTPHeaders": {}, @@ -18279,7 +18245,7 @@ } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaEventSourceMappings::test_create_event_source_validation_kinesis": { - "recorded-date": "03-03-2025, 16:49:40", + "recorded-date": "25-11-2025, 02:48:10", "recorded-content": { "no_starting_position": { "Error": { @@ -18306,7 +18272,7 @@ } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaSnapStart::test_snapstart_lifecycle[dotnet8]": { - "recorded-date": "01-04-2025, 13:31:15", + "recorded-date": "12-01-2026, 15:32:49", "recorded-content": { "create_function_response": { "Architectures": [ @@ -18450,7 +18416,7 @@ } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaSnapStart::test_snapstart_update_function_configuration[java11]": { - "recorded-date": "01-04-2025, 13:40:26", + "recorded-date": "12-01-2026, 15:33:06", "recorded-content": { "create_function_response": { "Architectures": [ @@ -18542,7 +18508,7 @@ } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaSnapStart::test_snapstart_update_function_configuration[java17]": { - "recorded-date": "01-04-2025, 13:40:32", + "recorded-date": "12-01-2026, 15:33:11", "recorded-content": { "create_function_response": { "Architectures": [ @@ -18634,7 +18600,7 @@ } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaSnapStart::test_snapstart_update_function_configuration[java21]": { - "recorded-date": "01-04-2025, 13:40:35", + "recorded-date": "12-01-2026, 15:33:15", "recorded-content": { "create_function_response": { "Architectures": [ @@ -18726,7 +18692,7 @@ } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaSnapStart::test_snapstart_update_function_configuration[python3.12]": { - "recorded-date": "01-04-2025, 13:40:40", + "recorded-date": "12-01-2026, 15:33:21", "recorded-content": { "create_function_response": { "Architectures": [ @@ -18818,7 +18784,7 @@ } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaSnapStart::test_snapstart_update_function_configuration[python3.13]": { - "recorded-date": "01-04-2025, 13:40:44", + "recorded-date": "12-01-2026, 15:33:24", "recorded-content": { "create_function_response": { "Architectures": [ @@ -18910,7 +18876,7 @@ } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaSnapStart::test_snapstart_update_function_configuration[dotnet8]": { - "recorded-date": "01-04-2025, 13:40:47", + "recorded-date": "12-01-2026, 15:33:28", "recorded-content": { "create_function_response": { "Architectures": [ @@ -19002,7 +18968,7 @@ } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_lambda_code_location_s3_errors": { - "recorded-date": "21-07-2025, 17:45:01", + "recorded-date": "25-11-2025, 02:27:45", "recorded-content": { "create-error-wrong-bucket": { "Error": { @@ -19053,5 +19019,568 @@ } } } + }, + "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaSnapStart::test_snapstart_lifecycle[java25]": { + "recorded-date": "12-01-2026, 15:32:25", + "recorded-content": { + "create_function_response": { + "Architectures": [ + "x86_64" + ], + "CodeSha256": "", + "CodeSize": "", + "Description": "", + "EphemeralStorage": { + "Size": 512 + }, + "FunctionArn": "arn::lambda::111111111111:function:", + "FunctionName": "", + "Handler": "echo.Handler", + "LastModified": "date", + "LoggingConfig": { + "LogFormat": "Text", + "LogGroup": "/aws/lambda/" + }, + "MemorySize": 1024, + "PackageType": "Zip", + "RevisionId": "", + "Role": "arn::iam::111111111111:role/", + "Runtime": "java25", + "RuntimeVersionConfig": { + "RuntimeVersionArn": "arn::lambda:::runtime:" + }, + "SnapStart": { + "ApplyOn": "None", + "OptimizationStatus": "Off" + }, + "State": "Pending", + "StateReason": "The function is being created.", + "StateReasonCode": "Creating", + "Timeout": 5, + "TracingConfig": { + "Mode": "PassThrough" + }, + "Version": "$LATEST", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 201 + } + }, + "get_function_response_latest": { + "Code": { + "Location": "", + "RepositoryType": "S3" + }, + "Configuration": { + "Architectures": [ + "x86_64" + ], + "CodeSha256": "", + "CodeSize": "", + "Description": "", + "EphemeralStorage": { + "Size": 512 + }, + "FunctionArn": "arn::lambda::111111111111:function:", + "FunctionName": "", + "Handler": "echo.Handler", + "LastModified": "date", + "LastUpdateStatus": "Successful", + "LoggingConfig": { + "LogFormat": "Text", + "LogGroup": "/aws/lambda/" + }, + "MemorySize": 1024, + "PackageType": "Zip", + "RevisionId": "", + "Role": "arn::iam::111111111111:role/", + "Runtime": "java25", + "RuntimeVersionConfig": { + "RuntimeVersionArn": "arn::lambda:::runtime:" + }, + "SnapStart": { + "ApplyOn": "None", + "OptimizationStatus": "Off" + }, + "State": "Active", + "Timeout": 5, + "TracingConfig": { + "Mode": "PassThrough" + }, + "Version": "$LATEST" + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "get_function_response_version_1": { + "Code": { + "Location": "", + "RepositoryType": "S3" + }, + "Configuration": { + "Architectures": [ + "x86_64" + ], + "CodeSha256": "", + "CodeSize": "", + "Description": "version1", + "EphemeralStorage": { + "Size": 512 + }, + "FunctionArn": "arn::lambda::111111111111:function::1", + "FunctionName": "", + "Handler": "echo.Handler", + "LastModified": "date", + "LastUpdateStatus": "Successful", + "LoggingConfig": { + "LogFormat": "Text", + "LogGroup": "/aws/lambda/" + }, + "MemorySize": 1024, + "PackageType": "Zip", + "RevisionId": "", + "Role": "arn::iam::111111111111:role/", + "Runtime": "java25", + "RuntimeVersionConfig": { + "RuntimeVersionArn": "arn::lambda:::runtime:" + }, + "SnapStart": { + "ApplyOn": "None", + "OptimizationStatus": "Off" + }, + "State": "Active", + "Timeout": 5, + "TracingConfig": { + "Mode": "PassThrough" + }, + "Version": "1" + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaSnapStart::test_snapstart_update_function_configuration[java25]": { + "recorded-date": "12-01-2026, 15:33:18", + "recorded-content": { + "create_function_response": { + "Architectures": [ + "x86_64" + ], + "CodeSha256": "", + "CodeSize": "", + "Description": "", + "EphemeralStorage": { + "Size": 512 + }, + "FunctionArn": "arn::lambda::111111111111:function:", + "FunctionName": "", + "Handler": "echo.Handler", + "LastModified": "date", + "LoggingConfig": { + "LogFormat": "Text", + "LogGroup": "/aws/lambda/" + }, + "MemorySize": 1024, + "PackageType": "Zip", + "RevisionId": "", + "Role": "arn::iam::111111111111:role/", + "Runtime": "java25", + "RuntimeVersionConfig": { + "RuntimeVersionArn": "arn::lambda:::runtime:" + }, + "SnapStart": { + "ApplyOn": "None", + "OptimizationStatus": "Off" + }, + "State": "Pending", + "StateReason": "The function is being created.", + "StateReasonCode": "Creating", + "Timeout": 5, + "TracingConfig": { + "Mode": "PassThrough" + }, + "Version": "$LATEST", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 201 + } + }, + "update_function_response": { + "Architectures": [ + "x86_64" + ], + "CodeSha256": "", + "CodeSize": "", + "Description": "", + "EphemeralStorage": { + "Size": 512 + }, + "FunctionArn": "arn::lambda::111111111111:function:", + "FunctionName": "", + "Handler": "echo.Handler", + "LastModified": "date", + "LastUpdateStatus": "InProgress", + "LastUpdateStatusReason": "The function is being created.", + "LastUpdateStatusReasonCode": "Creating", + "LoggingConfig": { + "LogFormat": "Text", + "LogGroup": "/aws/lambda/" + }, + "MemorySize": 1024, + "PackageType": "Zip", + "RevisionId": "", + "Role": "arn::iam::111111111111:role/", + "Runtime": "java25", + "RuntimeVersionConfig": { + "RuntimeVersionArn": "arn::lambda:::runtime:" + }, + "SnapStart": { + "ApplyOn": "PublishedVersions", + "OptimizationStatus": "Off" + }, + "State": "Active", + "Timeout": 5, + "TracingConfig": { + "Mode": "PassThrough" + }, + "Version": "$LATEST", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaLayer::test_layer_compatibilities[runtimes2]": { + "recorded-date": "12-01-2026, 15:31:43", + "recorded-content": { + "publish_result": { + "CompatibleArchitectures": [ + "arm64", + "x86_64" + ], + "CompatibleRuntimes": [ + "provided.al2023", + "provided.al2", + "provided" + ], + "Content": { + "CodeSha256": "", + "CodeSize": "", + "Location": "" + }, + "CreatedDate": "date", + "Description": "", + "LayerArn": "arn::lambda::111111111111:layer:", + "LayerVersionArn": "arn::lambda::111111111111:layer::1", + "Version": 1, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 201 + } + } + } + }, + "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaTag::test_tag_exceptions[capacity_provider]": { + "recorded-date": "25-11-2025, 21:37:02", + "recorded-content": { + "not_found_exception_tag": { + "Error": { + "Code": "ResourceNotFoundException", + "Message": "Capacity provider not found: arn::lambda::111111111111:capacity-provider:" + }, + "Message": "Capacity provider not found: arn::lambda::111111111111:capacity-provider:", + "Type": "User", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 404 + } + }, + "not_found_exception_untag": { + "Error": { + "Code": "ResourceNotFoundException", + "Message": "Capacity provider not found: arn::lambda::111111111111:capacity-provider:" + }, + "Message": "Capacity provider not found: arn::lambda::111111111111:capacity-provider:", + "Type": "User", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 404 + } + }, + "not_found_exception_list": { + "Error": { + "Code": "ResourceNotFoundException", + "Message": "Capacity provider not found: arn::lambda::111111111111:capacity-provider:" + }, + "Message": "Capacity provider not found: arn::lambda::111111111111:capacity-provider:", + "Type": "User", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 404 + } + }, + "aliased_arn_exception": { + "Error": { + "Code": "ValidationException", + "Message": "1 validation error detected: Value 'arn::lambda::111111111111:capacity-provider::alias' at 'resource' failed to satisfy constraint: Member must satisfy regular expression pattern: arn:(aws[a-zA-Z-]*):lambda:(eusc-)?[a-z]{2}((-gov)|(-iso([a-z]?)))?-[a-z]+-\\d{1}:\\d{12}:(function:[a-zA-Z0-9-_]+(:(\\$LATEST|[a-zA-Z0-9-_]+))?|layer:([a-zA-Z0-9-_]+)|code-signing-config:csc-[a-z0-9]{17}|event-source-mapping:[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}|capacity-provider:[a-zA-Z0-9-_]+)" + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + }, + "invalid_arn_exception": { + "Error": { + "Code": "ValidationException", + "Message": "1 validation error detected: Value 'arn::lambda::111111111111:foobar:' at 'resource' failed to satisfy constraint: Member must satisfy regular expression pattern: arn:(aws[a-zA-Z-]*):lambda:(eusc-)?[a-z]{2}((-gov)|(-iso([a-z]?)))?-[a-z]+-\\d{1}:\\d{12}:(function:[a-zA-Z0-9-_]+(:(\\$LATEST|[a-zA-Z0-9-_]+))?|layer:([a-zA-Z0-9-_]+)|code-signing-config:csc-[a-z0-9]{17}|event-source-mapping:[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}|capacity-provider:[a-zA-Z0-9-_]+)" + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + } + } + }, + "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaSnapStart::test_snapstart_lifecycle[dotnet10]": { + "recorded-date": "12-01-2026, 15:33:00", + "recorded-content": { + "create_function_response": { + "Architectures": [ + "x86_64" + ], + "CodeSha256": "", + "CodeSize": "", + "Description": "", + "EphemeralStorage": { + "Size": 512 + }, + "FunctionArn": "arn::lambda::111111111111:function:", + "FunctionName": "", + "Handler": "dotnet::Dotnet.Function::FunctionHandler", + "LastModified": "date", + "LoggingConfig": { + "LogFormat": "Text", + "LogGroup": "/aws/lambda/" + }, + "MemorySize": 1024, + "PackageType": "Zip", + "RevisionId": "", + "Role": "arn::iam::111111111111:role/", + "Runtime": "dotnet10", + "RuntimeVersionConfig": { + "RuntimeVersionArn": "arn::lambda:::runtime:" + }, + "SnapStart": { + "ApplyOn": "None", + "OptimizationStatus": "Off" + }, + "State": "Pending", + "StateReason": "The function is being created.", + "StateReasonCode": "Creating", + "Timeout": 5, + "TracingConfig": { + "Mode": "PassThrough" + }, + "Version": "$LATEST", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 201 + } + }, + "get_function_response_latest": { + "Code": { + "Location": "", + "RepositoryType": "S3" + }, + "Configuration": { + "Architectures": [ + "x86_64" + ], + "CodeSha256": "", + "CodeSize": "", + "Description": "", + "EphemeralStorage": { + "Size": 512 + }, + "FunctionArn": "arn::lambda::111111111111:function:", + "FunctionName": "", + "Handler": "dotnet::Dotnet.Function::FunctionHandler", + "LastModified": "date", + "LastUpdateStatus": "Successful", + "LoggingConfig": { + "LogFormat": "Text", + "LogGroup": "/aws/lambda/" + }, + "MemorySize": 1024, + "PackageType": "Zip", + "RevisionId": "", + "Role": "arn::iam::111111111111:role/", + "Runtime": "dotnet10", + "RuntimeVersionConfig": { + "RuntimeVersionArn": "arn::lambda:::runtime:" + }, + "SnapStart": { + "ApplyOn": "None", + "OptimizationStatus": "Off" + }, + "State": "Active", + "Timeout": 5, + "TracingConfig": { + "Mode": "PassThrough" + }, + "Version": "$LATEST" + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "get_function_response_version_1": { + "Code": { + "Location": "", + "RepositoryType": "S3" + }, + "Configuration": { + "Architectures": [ + "x86_64" + ], + "CodeSha256": "", + "CodeSize": "", + "Description": "version1", + "EphemeralStorage": { + "Size": 512 + }, + "FunctionArn": "arn::lambda::111111111111:function::1", + "FunctionName": "", + "Handler": "dotnet::Dotnet.Function::FunctionHandler", + "LastModified": "date", + "LastUpdateStatus": "Successful", + "LoggingConfig": { + "LogFormat": "Text", + "LogGroup": "/aws/lambda/" + }, + "MemorySize": 1024, + "PackageType": "Zip", + "RevisionId": "", + "Role": "arn::iam::111111111111:role/", + "Runtime": "dotnet10", + "RuntimeVersionConfig": { + "RuntimeVersionArn": "arn::lambda:::runtime:" + }, + "SnapStart": { + "ApplyOn": "None", + "OptimizationStatus": "Off" + }, + "State": "Active", + "Timeout": 5, + "TracingConfig": { + "Mode": "PassThrough" + }, + "Version": "1" + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaSnapStart::test_snapstart_update_function_configuration[dotnet10]": { + "recorded-date": "12-01-2026, 15:33:33", + "recorded-content": { + "create_function_response": { + "Architectures": [ + "x86_64" + ], + "CodeSha256": "", + "CodeSize": "", + "Description": "", + "EphemeralStorage": { + "Size": 512 + }, + "FunctionArn": "arn::lambda::111111111111:function:", + "FunctionName": "", + "Handler": "dotnet::Dotnet.Function::FunctionHandler", + "LastModified": "date", + "LoggingConfig": { + "LogFormat": "Text", + "LogGroup": "/aws/lambda/" + }, + "MemorySize": 1024, + "PackageType": "Zip", + "RevisionId": "", + "Role": "arn::iam::111111111111:role/", + "Runtime": "dotnet10", + "RuntimeVersionConfig": { + "RuntimeVersionArn": "arn::lambda:::runtime:" + }, + "SnapStart": { + "ApplyOn": "None", + "OptimizationStatus": "Off" + }, + "State": "Pending", + "StateReason": "The function is being created.", + "StateReasonCode": "Creating", + "Timeout": 5, + "TracingConfig": { + "Mode": "PassThrough" + }, + "Version": "$LATEST", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 201 + } + }, + "update_function_response": { + "Architectures": [ + "x86_64" + ], + "CodeSha256": "", + "CodeSize": "", + "Description": "", + "EphemeralStorage": { + "Size": 512 + }, + "FunctionArn": "arn::lambda::111111111111:function:", + "FunctionName": "", + "Handler": "dotnet::Dotnet.Function::FunctionHandler", + "LastModified": "date", + "LastUpdateStatus": "InProgress", + "LastUpdateStatusReason": "The function is being created.", + "LastUpdateStatusReasonCode": "Creating", + "LoggingConfig": { + "LogFormat": "Text", + "LogGroup": "/aws/lambda/" + }, + "MemorySize": 1024, + "PackageType": "Zip", + "RevisionId": "", + "Role": "arn::iam::111111111111:role/", + "Runtime": "dotnet10", + "RuntimeVersionConfig": { + "RuntimeVersionArn": "arn::lambda:::runtime:" + }, + "SnapStart": { + "ApplyOn": "PublishedVersions", + "OptimizationStatus": "Off" + }, + "State": "Active", + "Timeout": 5, + "TracingConfig": { + "Mode": "PassThrough" + }, + "Version": "$LATEST", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } } } diff --git a/tests/aws/services/lambda_/test_lambda_api.validation.json b/tests/aws/services/lambda_/test_lambda_api.validation.json index 3613c25e301fe..1827100b42221 100644 --- a/tests/aws/services/lambda_/test_lambda_api.validation.json +++ b/tests/aws/services/lambda_/test_lambda_api.validation.json @@ -1,72 +1,198 @@ { "tests/aws/services/lambda_/test_lambda_api.py::TestCodeSigningConfig::test_code_signing_not_found_excs": { - "last_validated_date": "2024-04-10T09:19:15+00:00" + "last_validated_date": "2025-11-25T02:46:47+00:00", + "durations_in_seconds": { + "setup": 0.01, + "call": 3.41, + "teardown": 0.79, + "total": 4.21 + } }, "tests/aws/services/lambda_/test_lambda_api.py::TestCodeSigningConfig::test_function_code_signing_config": { - "last_validated_date": "2024-04-10T09:19:10+00:00" + "last_validated_date": "2025-11-25T02:46:42+00:00", + "durations_in_seconds": { + "setup": 0.01, + "call": 2.77, + "teardown": 0.65, + "total": 3.43 + } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaAccountSettings::test_account_settings": { - "last_validated_date": "2024-04-10T09:19:17+00:00" + "last_validated_date": "2025-11-25T02:46:47+00:00", + "durations_in_seconds": { + "setup": 0.01, + "call": 0.11, + "teardown": 0.01, + "total": 0.13 + } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaAccountSettings::test_account_settings_total_code_size": { - "last_validated_date": "2024-04-10T09:19:28+00:00" + "last_validated_date": "2025-11-25T02:46:59+00:00", + "durations_in_seconds": { + "setup": 0.01, + "call": 10.87, + "teardown": 0.97, + "total": 11.85 + } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaAccountSettings::test_account_settings_total_code_size_config_update": { - "last_validated_date": "2024-04-10T09:19:34+00:00" + "last_validated_date": "2025-11-25T02:47:04+00:00", + "durations_in_seconds": { + "setup": 0.02, + "call": 4.47, + "teardown": 0.82, + "total": 5.31 + } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaAlias::test_alias_lifecycle": { - "last_validated_date": "2024-11-21T13:44:48+00:00" + "last_validated_date": "2025-11-25T02:38:45+00:00", + "durations_in_seconds": { + "setup": 0.01, + "call": 6.7, + "teardown": 0.46, + "total": 7.17 + } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaAlias::test_alias_naming": { - "last_validated_date": "2024-11-21T13:45:11+00:00" + "last_validated_date": "2025-11-25T02:39:05+00:00", + "durations_in_seconds": { + "setup": 0.01, + "call": 2.82, + "teardown": 0.28, + "total": 3.11 + } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaAlias::test_non_existent_alias_deletion": { - "last_validated_date": "2024-11-21T13:44:51+00:00" + "last_validated_date": "2025-11-25T02:38:47+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 1.96, + "teardown": 0.3, + "total": 2.26 + } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaAlias::test_non_existent_alias_update": { - "last_validated_date": "2024-11-21T13:44:53+00:00" + "last_validated_date": "2025-11-25T02:38:49+00:00", + "durations_in_seconds": { + "setup": 0.01, + "call": 2.07, + "teardown": 0.33, + "total": 2.41 + } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaAlias::test_notfound_and_invalid_routingconfigs": { - "last_validated_date": "2024-11-21T13:45:05+00:00" + "last_validated_date": "2025-11-25T21:33:39+00:00", + "durations_in_seconds": { + "setup": 10.94, + "call": 11.71, + "teardown": 0.73, + "total": 23.38 + } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaEventInvokeConfig::test_lambda_eventinvokeconfig_exceptions": { - "last_validated_date": "2024-04-10T09:13:37+00:00" + "last_validated_date": "2025-11-25T21:39:32+00:00", + "durations_in_seconds": { + "setup": 11.1, + "call": 12.72, + "teardown": 1.59, + "total": 25.41 + } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaEventInvokeConfig::test_lambda_eventinvokeconfig_lifecycle": { - "last_validated_date": "2024-04-10T09:13:20+00:00" + "last_validated_date": "2025-11-25T02:40:00+00:00", + "durations_in_seconds": { + "setup": 0.01, + "call": 4.94, + "teardown": 0.61, + "total": 5.56 + } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaEventSourceMappings::test_create_event_filter_criteria_validation": { - "last_validated_date": "2024-12-11T11:29:51+00:00" + "last_validated_date": "2025-12-18T15:07:44+00:00", + "durations_in_seconds": { + "setup": 12.13, + "call": 22.59, + "teardown": 2.65, + "total": 37.37 + } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaEventSourceMappings::test_create_event_source_self_managed": { "last_validated_date": "2024-09-03T20:58:27+00:00" }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaEventSourceMappings::test_create_event_source_validation": { - "last_validated_date": "2025-03-03T17:07:41+00:00" + "last_validated_date": "2025-11-25T02:48:02+00:00", + "durations_in_seconds": { + "setup": 0.01, + "call": 10.38, + "teardown": 2.09, + "total": 12.48 + } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaEventSourceMappings::test_create_event_source_validation_kinesis": { - "last_validated_date": "2025-03-03T16:49:39+00:00" + "last_validated_date": "2025-11-25T02:48:10+00:00", + "durations_in_seconds": { + "setup": 0.01, + "call": 7.63, + "teardown": 0.78, + "total": 8.42 + } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaEventSourceMappings::test_event_source_mapping_exceptions": { - "last_validated_date": "2024-12-05T10:52:30+00:00" + "last_validated_date": "2025-11-27T01:04:32+00:00", + "durations_in_seconds": { + "setup": 0.45, + "call": 1.36, + "teardown": 0.01, + "total": 1.82 + } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaEventSourceMappings::test_event_source_mapping_lifecycle": { - "last_validated_date": "2024-10-14T12:36:54+00:00" + "last_validated_date": "2025-11-25T02:47:33+00:00", + "durations_in_seconds": { + "setup": 0.01, + "call": 11.24, + "teardown": 1.17, + "total": 12.42 + } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaEventSourceMappings::test_event_source_mapping_lifecycle_delete_function": { - "last_validated_date": "2024-10-12T09:59:58+00:00" + "last_validated_date": "2025-11-25T02:47:20+00:00", + "durations_in_seconds": { + "setup": 0.01, + "call": 14.42, + "teardown": 0.96, + "total": 15.39 + } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaEventSourceMappings::test_function_name_variations": { - "last_validated_date": "2024-10-14T12:46:32+00:00" + "last_validated_date": "2025-11-25T03:20:36+00:00", + "durations_in_seconds": { + "setup": 11.3, + "call": 206.47, + "teardown": 2.75, + "total": 220.52 + } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_advance_logging_configuration_format_switch": { "last_validated_date": "2024-04-10T08:58:47+00:00" }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_create_lambda_exceptions": { - "last_validated_date": "2025-04-01T13:08:49+00:00" + "last_validated_date": "2026-01-12T15:31:24+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 1.3, + "teardown": 0.01, + "total": 1.31 + } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_delete_on_nonexisting_version": { - "last_validated_date": "2024-09-12T11:29:32+00:00" + "last_validated_date": "2025-11-25T02:27:11+00:00", + "durations_in_seconds": { + "setup": 0.01, + "call": 2.45, + "teardown": 0.64, + "total": 3.1 + } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_advanced_configuration": { "last_validated_date": "2024-03-28T09:54:41+00:00" @@ -75,34 +201,94 @@ "last_validated_date": "2024-04-10T08:59:14+00:00" }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_arns": { - "last_validated_date": "2024-09-12T11:30:00+00:00" + "last_validated_date": "2025-11-25T02:27:51+00:00", + "durations_in_seconds": { + "setup": 0.02, + "call": 4.21, + "teardown": 1.2, + "total": 5.43 + } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_lifecycle": { - "last_validated_date": "2024-09-12T11:29:18+00:00" + "last_validated_date": "2025-11-25T02:26:54+00:00", + "durations_in_seconds": { + "setup": 0.01, + "call": 5.8, + "teardown": 0.39, + "total": 6.2 + } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[full_arn_and_qualifier_too_long_and_invalid_region-create_function]": { - "last_validated_date": "2024-09-12T11:30:04+00:00" + "last_validated_date": "2025-11-25T02:27:56+00:00", + "durations_in_seconds": { + "setup": 0.01, + "call": 0.09, + "teardown": 0.01, + "total": 0.11 + } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[full_arn_and_qualifier_too_long_and_invalid_region-delete_function]": { - "last_validated_date": "2024-09-12T11:30:04+00:00" + "last_validated_date": "2025-11-25T02:27:56+00:00", + "durations_in_seconds": { + "setup": 0.01, + "call": 0.08, + "teardown": 0.01, + "total": 0.1 + } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[full_arn_and_qualifier_too_long_and_invalid_region-get_function]": { - "last_validated_date": "2024-09-12T11:30:04+00:00" + "last_validated_date": "2025-11-25T02:27:56+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.08, + "teardown": 0.01, + "total": 0.09 + } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[full_arn_and_qualifier_too_long_and_invalid_region-invoke]": { - "last_validated_date": "2024-09-12T11:30:04+00:00" + "last_validated_date": "2025-11-25T02:27:56+00:00", + "durations_in_seconds": { + "setup": 0.01, + "call": 0.13, + "teardown": 0.01, + "total": 0.15 + } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[full_arn_with_multiple_qualifiers-create_function]": { - "last_validated_date": "2024-09-12T11:30:05+00:00" + "last_validated_date": "2025-11-25T02:27:56+00:00", + "durations_in_seconds": { + "setup": 0.01, + "call": 0.15, + "teardown": 0.01, + "total": 0.17 + } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[full_arn_with_multiple_qualifiers-delete_function]": { - "last_validated_date": "2024-09-12T11:30:04+00:00" + "last_validated_date": "2025-11-25T02:27:56+00:00", + "durations_in_seconds": { + "setup": 0.01, + "call": 0.08, + "teardown": 0.01, + "total": 0.1 + } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[full_arn_with_multiple_qualifiers-get_function]": { - "last_validated_date": "2024-09-12T11:30:04+00:00" + "last_validated_date": "2025-11-25T02:27:56+00:00", + "durations_in_seconds": { + "setup": 0.01, + "call": 0.14, + "teardown": 0.01, + "total": 0.16 + } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[full_arn_with_multiple_qualifiers-invoke]": { - "last_validated_date": "2024-09-12T11:30:04+00:00" + "last_validated_date": "2025-11-25T02:27:56+00:00", + "durations_in_seconds": { + "setup": 0.01, + "call": 0.08, + "teardown": 0.01, + "total": 0.1 + } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[function_name_and_qualifier_too_long-delete_function]": { "last_validated_date": "2024-08-22T15:10:43+00:00" @@ -114,190 +300,571 @@ "last_validated_date": "2024-08-22T15:10:44+00:00" }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[function_name_is_single_invalid-create_function]": { - "last_validated_date": "2024-09-12T11:30:02+00:00" + "last_validated_date": "2025-11-25T02:27:52+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.13, + "teardown": 0.01, + "total": 0.14 + } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[function_name_is_single_invalid-delete_function]": { - "last_validated_date": "2024-09-12T11:30:02+00:00" + "last_validated_date": "2025-11-25T02:27:51+00:00", + "durations_in_seconds": { + "setup": 0.01, + "call": 0.09, + "teardown": 0.01, + "total": 0.11 + } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[function_name_is_single_invalid-get_function]": { - "last_validated_date": "2024-09-12T11:30:01+00:00" + "last_validated_date": "2025-11-25T02:27:51+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.1, + "teardown": 0.01, + "total": 0.11 + } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[function_name_is_single_invalid-invoke]": { - "last_validated_date": "2024-09-12T11:30:02+00:00" + "last_validated_date": "2025-11-25T02:27:52+00:00", + "durations_in_seconds": { + "setup": 0.01, + "call": 0.13, + "teardown": 0.01, + "total": 0.15 + } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[function_name_too_long-create_function]": { - "last_validated_date": "2024-09-12T11:30:03+00:00" + "last_validated_date": "2025-11-25T02:27:55+00:00", + "durations_in_seconds": { + "setup": 0.01, + "call": 0.24, + "teardown": 0.01, + "total": 0.26 + } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[function_name_too_long-delete_function]": { - "last_validated_date": "2024-09-12T11:30:03+00:00" + "last_validated_date": "2025-11-25T02:27:55+00:00", + "durations_in_seconds": { + "setup": 0.12, + "call": 0.17, + "teardown": 0.01, + "total": 0.3 + } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[function_name_too_long-get_function]": { - "last_validated_date": "2024-09-12T11:30:03+00:00" + "last_validated_date": "2025-11-25T02:27:54+00:00", + "durations_in_seconds": { + "setup": 0.01, + "call": 0.11, + "teardown": 0.01, + "total": 0.13 + } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[function_name_too_long-invoke]": { - "last_validated_date": "2024-08-22T15:20:33+00:00" + "last_validated_date": "2025-11-25T02:27:55+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.15, + "teardown": 0.01, + "total": 0.16 + } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[function_name_too_long_and_invalid_region-create_function]": { - "last_validated_date": "2024-09-12T11:30:04+00:00" + "last_validated_date": "2025-11-25T02:27:55+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.08, + "teardown": 0.01, + "total": 0.09 + } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[function_name_too_long_and_invalid_region-delete_function]": { - "last_validated_date": "2024-09-12T11:30:04+00:00" + "last_validated_date": "2025-11-25T02:27:55+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.11, + "teardown": 0.01, + "total": 0.12 + } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[function_name_too_long_and_invalid_region-get_function]": { - "last_validated_date": "2024-09-12T11:30:04+00:00" + "last_validated_date": "2025-11-25T02:27:55+00:00", + "durations_in_seconds": { + "setup": 0.01, + "call": 0.08, + "teardown": 0.01, + "total": 0.1 + } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[function_name_too_long_and_invalid_region-invoke]": { - "last_validated_date": "2024-09-12T11:30:04+00:00" + "last_validated_date": "2025-11-25T02:27:55+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.11, + "teardown": 0.01, + "total": 0.12 + } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[incomplete_arn-delete_function]": { - "last_validated_date": "2024-09-12T11:30:05+00:00" + "last_validated_date": "2025-11-25T02:27:57+00:00", + "durations_in_seconds": { + "setup": 0.01, + "call": 0.18, + "teardown": 0.01, + "total": 0.2 + } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[incomplete_arn-get_function]": { - "last_validated_date": "2024-09-12T11:30:05+00:00" + "last_validated_date": "2025-11-25T02:27:57+00:00", + "durations_in_seconds": { + "setup": 0.01, + "call": 0.13, + "teardown": 0.01, + "total": 0.15 + } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[incomplete_arn-invoke]": { - "last_validated_date": "2024-08-22T15:20:38+00:00" + "last_validated_date": "2025-11-25T02:27:57+00:00", + "durations_in_seconds": { + "setup": 0.01, + "call": 0.09, + "teardown": 0.01, + "total": 0.11 + } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[invalid_account_id_in_partial_arn-create_function]": { - "last_validated_date": "2024-09-12T11:30:03+00:00" + "last_validated_date": "2025-11-25T02:27:53+00:00", + "durations_in_seconds": { + "setup": 0.01, + "call": 0.08, + "teardown": 0.01, + "total": 0.1 + } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[invalid_account_id_in_partial_arn-delete_function]": { - "last_validated_date": "2024-09-12T11:30:02+00:00" + "last_validated_date": "2025-11-25T02:27:53+00:00", + "durations_in_seconds": { + "setup": 0.01, + "call": 0.08, + "teardown": 0.01, + "total": 0.1 + } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[invalid_account_id_in_partial_arn-get_function]": { - "last_validated_date": "2024-09-12T11:30:02+00:00" + "last_validated_date": "2025-11-25T02:27:53+00:00", + "durations_in_seconds": { + "setup": 0.01, + "call": 0.08, + "teardown": 0.01, + "total": 0.1 + } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[invalid_account_id_in_partial_arn-invoke]": { - "last_validated_date": "2024-09-12T11:30:02+00:00" + "last_validated_date": "2025-11-25T02:27:53+00:00", + "durations_in_seconds": { + "setup": 0.01, + "call": 0.1, + "teardown": 0.01, + "total": 0.12 + } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[invalid_characters_in_function_name-create_function]": { - "last_validated_date": "2024-09-12T11:30:01+00:00" + "last_validated_date": "2025-11-25T02:27:51+00:00", + "durations_in_seconds": { + "setup": 0.01, + "call": 0.13, + "teardown": 0.01, + "total": 0.15 + } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[invalid_characters_in_function_name-delete_function]": { - "last_validated_date": "2024-09-12T11:30:01+00:00" + "last_validated_date": "2025-11-25T02:27:51+00:00", + "durations_in_seconds": { + "setup": 0.01, + "call": 0.09, + "teardown": 0.01, + "total": 0.11 + } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[invalid_characters_in_function_name-get_function]": { - "last_validated_date": "2024-09-12T11:30:01+00:00" + "last_validated_date": "2025-11-25T02:27:51+00:00", + "durations_in_seconds": { + "setup": 0.01, + "call": 0.12, + "teardown": 0.01, + "total": 0.14 + } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[invalid_characters_in_function_name-invoke]": { - "last_validated_date": "2024-09-12T11:30:01+00:00" + "last_validated_date": "2025-11-25T02:27:51+00:00", + "durations_in_seconds": { + "setup": 0.01, + "call": 0.15, + "teardown": 0.01, + "total": 0.17 + } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[invalid_characters_in_qualifier-create_function]": { - "last_validated_date": "2024-09-12T11:30:02+00:00" + "last_validated_date": "2025-11-25T02:27:52+00:00", + "durations_in_seconds": { + "setup": 0.01, + "call": 0.11, + "teardown": 0.01, + "total": 0.13 + } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[invalid_characters_in_qualifier-delete_function]": { - "last_validated_date": "2024-09-12T11:30:02+00:00" + "last_validated_date": "2025-11-25T02:27:52+00:00", + "durations_in_seconds": { + "setup": 0.01, + "call": 0.11, + "teardown": 0.01, + "total": 0.13 + } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[invalid_characters_in_qualifier-get_function]": { - "last_validated_date": "2024-09-12T11:30:02+00:00" + "last_validated_date": "2025-11-25T02:27:52+00:00", + "durations_in_seconds": { + "setup": 0.01, + "call": 0.13, + "teardown": 0.01, + "total": 0.15 + } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[invalid_characters_in_qualifier-invoke]": { - "last_validated_date": "2024-09-12T11:30:02+00:00" + "last_validated_date": "2025-11-25T02:27:52+00:00", + "durations_in_seconds": { + "setup": 0.01, + "call": 0.11, + "teardown": 0.01, + "total": 0.13 + } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[invalid_region_in_arn-create_function]": { - "last_validated_date": "2024-09-12T11:30:03+00:00" + "last_validated_date": "2025-11-25T02:27:54+00:00", + "durations_in_seconds": { + "setup": 0.01, + "call": 0.08, + "teardown": 0.01, + "total": 0.1 + } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[invalid_region_in_arn-delete_function]": { - "last_validated_date": "2024-09-12T11:30:03+00:00" + "last_validated_date": "2025-11-25T02:27:53+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.14, + "teardown": 0.01, + "total": 0.15 + } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[invalid_region_in_arn-get_function]": { - "last_validated_date": "2024-09-12T11:30:03+00:00" + "last_validated_date": "2025-11-25T02:27:53+00:00", + "durations_in_seconds": { + "setup": 0.01, + "call": 0.08, + "teardown": 0.01, + "total": 0.1 + } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[invalid_region_in_arn-invoke]": { - "last_validated_date": "2024-09-12T11:30:03+00:00" + "last_validated_date": "2025-11-25T02:27:54+00:00", + "durations_in_seconds": { + "setup": 0.01, + "call": 0.11, + "teardown": 0.01, + "total": 0.13 + } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[latest_version_with_additional_qualifier-create_function]": { - "last_validated_date": "2024-09-12T11:30:05+00:00" + "last_validated_date": "2025-11-25T02:27:58+00:00", + "durations_in_seconds": { + "setup": 0.01, + "call": 0.24, + "teardown": 0.01, + "total": 0.26 + } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[latest_version_with_additional_qualifier-delete_function]": { - "last_validated_date": "2024-09-12T11:30:05+00:00" + "last_validated_date": "2025-11-25T02:27:58+00:00", + "durations_in_seconds": { + "setup": 0.01, + "call": 0.08, + "teardown": 0.01, + "total": 0.1 + } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[latest_version_with_additional_qualifier-get_function]": { - "last_validated_date": "2024-09-12T11:30:05+00:00" + "last_validated_date": "2025-11-25T02:27:58+00:00", + "durations_in_seconds": { + "setup": 0.01, + "call": 0.08, + "teardown": 0.01, + "total": 0.1 + } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[latest_version_with_additional_qualifier-invoke]": { - "last_validated_date": "2024-09-12T11:30:05+00:00" + "last_validated_date": "2025-11-25T02:27:58+00:00", + "durations_in_seconds": { + "setup": 0.01, + "call": 0.08, + "teardown": 0.01, + "total": 0.1 + } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[lowercase_latest_qualifier-create_function]": { - "last_validated_date": "2024-09-12T11:30:06+00:00" + "last_validated_date": "2025-11-25T02:27:59+00:00", + "durations_in_seconds": { + "setup": 0.01, + "call": 0.16, + "teardown": 0.01, + "total": 0.18 + } + }, + "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[lowercase_latest_qualifier-delete_function]": { + "last_validated_date": "2025-11-25T02:27:58+00:00", + "durations_in_seconds": { + "setup": 0.01, + "call": 0.18, + "teardown": 0.01, + "total": 0.2 + } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[lowercase_latest_qualifier-get_function]": { - "last_validated_date": "2024-09-12T11:30:05+00:00" + "last_validated_date": "2025-11-25T02:27:58+00:00", + "durations_in_seconds": { + "setup": 0.01, + "call": 0.14, + "teardown": 0.01, + "total": 0.16 + } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[lowercase_latest_qualifier-invoke]": { - "last_validated_date": "2024-09-12T11:30:06+00:00" + "last_validated_date": "2025-11-25T02:27:59+00:00", + "durations_in_seconds": { + "setup": 0.01, + "call": 0.09, + "teardown": 0.01, + "total": 0.11 + } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[missing_account_id_in_arn-create_function]": { - "last_validated_date": "2024-09-12T11:30:06+00:00" + "last_validated_date": "2025-11-25T02:28:00+00:00", + "durations_in_seconds": { + "setup": 0.01, + "call": 0.1, + "teardown": 0.01, + "total": 0.12 + } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[missing_account_id_in_arn-delete_function]": { - "last_validated_date": "2024-09-12T11:30:06+00:00" + "last_validated_date": "2025-11-25T02:27:59+00:00", + "durations_in_seconds": { + "setup": 0.01, + "call": 0.11, + "teardown": 0.01, + "total": 0.13 + } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[missing_account_id_in_arn-get_function]": { - "last_validated_date": "2024-09-12T11:30:06+00:00" + "last_validated_date": "2025-11-25T02:27:59+00:00", + "durations_in_seconds": { + "setup": 0.01, + "call": 0.08, + "teardown": 0.01, + "total": 0.1 + } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[missing_account_id_in_arn-invoke]": { - "last_validated_date": "2024-09-12T11:30:06+00:00" + "last_validated_date": "2025-11-25T02:28:00+00:00", + "durations_in_seconds": { + "setup": 0.01, + "call": 0.09, + "teardown": 0.01, + "total": 0.11 + } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[missing_region_in_arn-create_function]": { - "last_validated_date": "2024-09-12T11:30:06+00:00" + "last_validated_date": "2025-11-25T02:27:59+00:00", + "durations_in_seconds": { + "setup": 0.01, + "call": 0.12, + "teardown": 0.01, + "total": 0.14 + } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[missing_region_in_arn-delete_function]": { - "last_validated_date": "2024-09-12T11:30:06+00:00" + "last_validated_date": "2025-11-25T02:27:59+00:00", + "durations_in_seconds": { + "setup": 0.01, + "call": 0.08, + "teardown": 0.01, + "total": 0.1 + } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[missing_region_in_arn-get_function]": { - "last_validated_date": "2024-09-12T11:30:06+00:00" + "last_validated_date": "2025-11-25T02:27:59+00:00", + "durations_in_seconds": { + "setup": 0.01, + "call": 0.14, + "teardown": 0.01, + "total": 0.16 + } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[missing_region_in_arn-invoke]": { - "last_validated_date": "2024-09-12T11:30:06+00:00" + "last_validated_date": "2025-11-25T02:27:59+00:00", + "durations_in_seconds": { + "setup": 0.01, + "call": 0.08, + "teardown": 0.01, + "total": 0.1 + } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[misspelled_latest_in_arn-create_function]": { - "last_validated_date": "2024-09-12T11:30:06+00:00" + "last_validated_date": "2025-11-25T02:28:00+00:00", + "durations_in_seconds": { + "setup": 0.01, + "call": 0.08, + "teardown": 0.01, + "total": 0.1 + } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[misspelled_latest_in_arn-delete_function]": { - "last_validated_date": "2024-09-12T11:30:06+00:00" + "last_validated_date": "2025-11-25T02:28:00+00:00", + "durations_in_seconds": { + "setup": 0.01, + "call": 0.08, + "teardown": 0.01, + "total": 0.1 + } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[misspelled_latest_in_arn-get_function]": { - "last_validated_date": "2024-09-12T11:30:06+00:00" + "last_validated_date": "2025-11-25T02:28:00+00:00", + "durations_in_seconds": { + "setup": 0.01, + "call": 0.08, + "teardown": 0.01, + "total": 0.1 + } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[misspelled_latest_in_arn-invoke]": { - "last_validated_date": "2024-09-12T11:30:06+00:00" + "last_validated_date": "2025-11-25T02:28:00+00:00", + "durations_in_seconds": { + "setup": 0.01, + "call": 0.08, + "teardown": 0.01, + "total": 0.1 + } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[non_lambda_arn-create_function]": { - "last_validated_date": "2024-09-12T11:30:03+00:00" + "last_validated_date": "2025-11-25T02:27:54+00:00", + "durations_in_seconds": { + "setup": 0.01, + "call": 0.08, + "teardown": 0.01, + "total": 0.1 + } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[non_lambda_arn-delete_function]": { - "last_validated_date": "2024-09-12T11:30:03+00:00" + "last_validated_date": "2025-11-25T02:27:54+00:00", + "durations_in_seconds": { + "setup": 0.01, + "call": 0.08, + "teardown": 0.01, + "total": 0.1 + } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[non_lambda_arn-get_function]": { - "last_validated_date": "2024-09-12T11:30:03+00:00" + "last_validated_date": "2025-11-25T02:27:54+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.19, + "teardown": 0.01, + "total": 0.2 + } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[non_lambda_arn-invoke]": { - "last_validated_date": "2024-09-12T11:30:03+00:00" + "last_validated_date": "2025-11-25T02:27:54+00:00", + "durations_in_seconds": { + "setup": 0.01, + "call": 0.08, + "teardown": 0.01, + "total": 0.1 + } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[partial_arn_with_extra_qualifier-create_function]": { - "last_validated_date": "2024-09-12T11:30:05+00:00" + "last_validated_date": "2025-11-25T02:27:58+00:00", + "durations_in_seconds": { + "setup": 0.01, + "call": 0.18, + "teardown": 0.02, + "total": 0.21 + } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[partial_arn_with_extra_qualifier-delete_function]": { - "last_validated_date": "2024-09-12T11:30:05+00:00" + "last_validated_date": "2025-11-25T02:27:57+00:00", + "durations_in_seconds": { + "setup": 0.01, + "call": 0.09, + "teardown": 0.01, + "total": 0.11 + } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[partial_arn_with_extra_qualifier-get_function]": { - "last_validated_date": "2024-09-12T11:30:05+00:00" + "last_validated_date": "2025-11-25T02:27:57+00:00", + "durations_in_seconds": { + "setup": 0.01, + "call": 0.08, + "teardown": 0.01, + "total": 0.1 + } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[partial_arn_with_extra_qualifier-invoke]": { - "last_validated_date": "2024-09-12T11:30:05+00:00" + "last_validated_date": "2025-11-25T02:27:57+00:00", + "durations_in_seconds": { + "setup": 0.01, + "call": 0.15, + "teardown": 0.01, + "total": 0.17 + } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[qualifier_too_long-create_function]": { - "last_validated_date": "2024-09-12T11:30:02+00:00" + "last_validated_date": "2025-11-25T02:27:53+00:00", + "durations_in_seconds": { + "setup": 0.01, + "call": 0.08, + "teardown": 0.01, + "total": 0.1 + } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[qualifier_too_long-delete_function]": { - "last_validated_date": "2024-09-12T11:30:02+00:00" + "last_validated_date": "2025-11-25T02:27:52+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.13, + "teardown": 0.01, + "total": 0.14 + } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[qualifier_too_long-get_function]": { - "last_validated_date": "2024-09-12T11:30:02+00:00" + "last_validated_date": "2025-11-25T02:27:52+00:00", + "durations_in_seconds": { + "setup": 0.01, + "call": 0.11, + "teardown": 0.01, + "total": 0.13 + } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[qualifier_too_long-invoke]": { - "last_validated_date": "2024-09-12T11:30:02+00:00" + "last_validated_date": "2025-11-25T02:27:53+00:00", + "durations_in_seconds": { + "setup": 0.01, + "call": 0.11, + "teardown": 0.01, + "total": 0.13 + } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_function_name_and_qualifier_validation[qualifier_too_long0-create_function]": { "last_validated_date": "2024-08-22T15:07:10+00:00" @@ -333,372 +900,1128 @@ "last_validated_date": "2024-04-10T08:59:09+00:00" }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_get_function_wrong_region[delete_function]": { - "last_validated_date": "2024-09-12T11:29:47+00:00" + "last_validated_date": "2025-11-25T02:27:29+00:00", + "durations_in_seconds": { + "setup": 0.01, + "call": 1.82, + "teardown": 0.62, + "total": 2.45 + } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_get_function_wrong_region[get_function]": { - "last_validated_date": "2024-09-12T11:29:35+00:00" + "last_validated_date": "2025-11-25T02:27:15+00:00", + "durations_in_seconds": { + "setup": 0.01, + "call": 1.71, + "teardown": 0.54, + "total": 2.26 + } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_get_function_wrong_region[get_function_code_signing_config]": { - "last_validated_date": "2024-09-12T11:29:41+00:00" + "last_validated_date": "2025-11-25T02:27:22+00:00", + "durations_in_seconds": { + "setup": 0.01, + "call": 1.73, + "teardown": 0.61, + "total": 2.35 + } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_get_function_wrong_region[get_function_concurrency]": { - "last_validated_date": "2024-09-12T11:29:45+00:00" + "last_validated_date": "2025-11-25T02:27:27+00:00", + "durations_in_seconds": { + "setup": 0.01, + "call": 1.79, + "teardown": 0.64, + "total": 2.44 + } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_get_function_wrong_region[get_function_configuration]": { - "last_validated_date": "2024-09-12T11:29:37+00:00" + "last_validated_date": "2025-11-25T02:27:17+00:00", + "durations_in_seconds": { + "setup": 0.01, + "call": 1.81, + "teardown": 0.55, + "total": 2.37 + } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_get_function_wrong_region[get_function_event_invoke_config]": { - "last_validated_date": "2024-09-12T11:29:43+00:00" + "last_validated_date": "2025-11-25T02:27:24+00:00", + "durations_in_seconds": { + "setup": 0.01, + "call": 1.75, + "teardown": 0.59, + "total": 2.35 + } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_get_function_wrong_region[get_function_url_config]": { - "last_validated_date": "2024-09-12T11:29:39+00:00" + "last_validated_date": "2025-11-25T02:27:20+00:00", + "durations_in_seconds": { + "setup": 0.01, + "call": 1.86, + "teardown": 0.6, + "total": 2.47 + } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_get_function_wrong_region[invoke]": { - "last_validated_date": "2024-09-12T11:29:49+00:00" + "last_validated_date": "2025-11-25T02:27:32+00:00", + "durations_in_seconds": { + "setup": 0.01, + "call": 1.85, + "teardown": 0.53, + "total": 2.39 + } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_invalid_invoke": { - "last_validated_date": "2024-09-12T11:34:43+00:00" + "last_validated_date": "2025-11-25T02:35:53+00:00", + "durations_in_seconds": { + "setup": 0.01, + "call": 0.08, + "teardown": 0.01, + "total": 0.1 + } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_invalid_vpc_config": { "last_validated_date": "2025-02-20T17:44:18+00:00" }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_invalid_vpc_config_security_group": { - "last_validated_date": "2025-02-20T17:57:29+00:00" + "last_validated_date": "2025-11-25T02:35:53+00:00", + "durations_in_seconds": { + "setup": 0.01, + "call": 0.26, + "teardown": 0.01, + "total": 0.28 + } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_invalid_vpc_config_subnet": { - "last_validated_date": "2025-02-20T17:53:33+00:00" + "last_validated_date": "2025-11-25T02:35:53+00:00", + "durations_in_seconds": { + "setup": 0.01, + "call": 0.7, + "teardown": 0.01, + "total": 0.72 + } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_lambda_code_location_s3": { - "last_validated_date": "2024-09-12T11:29:56+00:00" + "last_validated_date": "2025-11-25T02:27:41+00:00", + "durations_in_seconds": { + "setup": 0.81, + "call": 3.37, + "teardown": 1.14, + "total": 5.32 + } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_lambda_code_location_s3_errors": { - "last_validated_date": "2025-07-21T17:45:02+00:00", + "last_validated_date": "2025-11-25T02:27:45+00:00", "durations_in_seconds": { - "setup": 13.8, - "call": 2.63, - "teardown": 1.73, - "total": 18.16 + "setup": 0.77, + "call": 2.72, + "teardown": 1.06, + "total": 4.55 } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_lambda_code_location_zipfile": { - "last_validated_date": "2024-09-12T11:29:52+00:00" + "last_validated_date": "2025-11-25T02:27:35+00:00", + "durations_in_seconds": { + "setup": 0.01, + "call": 3.18, + "teardown": 0.32, + "total": 3.51 + } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_lambda_concurrent_code_updates": { - "last_validated_date": "2024-09-12T11:34:46+00:00" + "last_validated_date": "2025-11-25T02:35:57+00:00", + "durations_in_seconds": { + "setup": 0.01, + "call": 3.46, + "teardown": 0.25, + "total": 3.72 + } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_lambda_concurrent_config_updates": { - "last_validated_date": "2024-09-12T11:34:50+00:00" + "last_validated_date": "2025-11-25T02:36:01+00:00", + "durations_in_seconds": { + "setup": 0.01, + "call": 3.58, + "teardown": 0.54, + "total": 4.13 + } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_list_functions": { - "last_validated_date": "2024-09-12T11:30:19+00:00" + "last_validated_date": "2025-11-25T02:28:15+00:00", + "durations_in_seconds": { + "setup": 0.01, + "call": 10.93, + "teardown": 1.18, + "total": 12.12 + } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_ops_on_nonexisting_fn[delete_function]": { - "last_validated_date": "2024-09-12T11:29:32+00:00" + "last_validated_date": "2025-11-25T02:27:12+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.24, + "teardown": 0.01, + "total": 0.25 + } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_ops_on_nonexisting_fn[get_function]": { - "last_validated_date": "2024-09-12T11:29:32+00:00" + "last_validated_date": "2025-11-25T02:27:12+00:00", + "durations_in_seconds": { + "setup": 0.01, + "call": 0.13, + "teardown": 0.01, + "total": 0.15 + } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_ops_on_nonexisting_fn[get_function_code_signing_config]": { - "last_validated_date": "2024-09-12T11:29:33+00:00" + "last_validated_date": "2025-11-25T02:27:12+00:00", + "durations_in_seconds": { + "setup": 0.01, + "call": 0.1, + "teardown": 0.01, + "total": 0.12 + } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_ops_on_nonexisting_fn[get_function_concurrency]": { - "last_validated_date": "2024-09-12T11:29:33+00:00" + "last_validated_date": "2025-11-25T02:27:13+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.1, + "teardown": 0.01, + "total": 0.11 + } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_ops_on_nonexisting_fn[get_function_configuration]": { - "last_validated_date": "2024-09-12T11:29:33+00:00" + "last_validated_date": "2025-11-25T02:27:12+00:00", + "durations_in_seconds": { + "setup": 0.01, + "call": 0.22, + "teardown": 0.01, + "total": 0.24 + } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_ops_on_nonexisting_fn[get_function_event_invoke_config]": { - "last_validated_date": "2024-09-12T11:29:33+00:00" + "last_validated_date": "2025-11-25T02:27:13+00:00", + "durations_in_seconds": { + "setup": 0.01, + "call": 0.12, + "teardown": 0.01, + "total": 0.14 + } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_ops_on_nonexisting_fn[get_function_url_config]": { - "last_validated_date": "2024-09-12T11:29:33+00:00" + "last_validated_date": "2025-11-25T02:27:12+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.2, + "teardown": 0.01, + "total": 0.21 + } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_ops_on_nonexisting_version[get_function]": { - "last_validated_date": "2024-09-12T11:29:25+00:00" + "last_validated_date": "2025-11-25T02:27:03+00:00", + "durations_in_seconds": { + "setup": 0.01, + "call": 1.88, + "teardown": 0.54, + "total": 2.43 + } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_ops_on_nonexisting_version[get_function_configuration]": { - "last_validated_date": "2024-09-12T11:29:27+00:00" + "last_validated_date": "2025-11-25T02:27:06+00:00", + "durations_in_seconds": { + "setup": 0.01, + "call": 1.8, + "teardown": 0.64, + "total": 2.45 + } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_ops_on_nonexisting_version[get_function_event_invoke_config]": { - "last_validated_date": "2024-09-12T11:29:29+00:00" + "last_validated_date": "2025-11-25T02:27:08+00:00", + "durations_in_seconds": { + "setup": 0.01, + "call": 1.91, + "teardown": 0.56, + "total": 2.48 + } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_ops_with_arn_qualifier_mismatch[delete_function]": { - "last_validated_date": "2024-09-12T11:29:23+00:00" + "last_validated_date": "2025-11-25T02:27:00+00:00", + "durations_in_seconds": { + "setup": 0.01, + "call": 0.19, + "teardown": 0.01, + "total": 0.21 + } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_ops_with_arn_qualifier_mismatch[get_function]": { - "last_validated_date": "2024-09-12T11:29:23+00:00" + "last_validated_date": "2025-11-25T02:27:01+00:00", + "durations_in_seconds": { + "setup": 0.01, + "call": 0.19, + "teardown": 0.01, + "total": 0.21 + } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_ops_with_arn_qualifier_mismatch[get_function_configuration]": { - "last_validated_date": "2024-09-12T11:29:24+00:00" + "last_validated_date": "2025-11-25T02:27:01+00:00", + "durations_in_seconds": { + "setup": 0.01, + "call": 0.19, + "teardown": 0.01, + "total": 0.21 + } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_redundant_updates": { - "last_validated_date": "2024-09-12T11:29:23+00:00" + "last_validated_date": "2025-11-25T02:27:00+00:00", + "durations_in_seconds": { + "setup": 0.01, + "call": 5.22, + "teardown": 0.56, + "total": 5.79 + } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_update_lambda_exceptions": { - "last_validated_date": "2025-04-01T13:10:29+00:00" + "last_validated_date": "2026-01-12T15:31:27+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 2.59, + "teardown": 0.39, + "total": 2.98 + } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaFunction::test_vpc_config": { - "last_validated_date": "2024-09-12T11:34:40+00:00" + "last_validated_date": "2025-11-25T02:35:52+00:00", + "durations_in_seconds": { + "setup": 0.01, + "call": 453.58, + "teardown": 3.34, + "total": 456.93 + } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaImages::test_lambda_image_and_image_config_crud": { - "last_validated_date": "2024-04-10T09:11:13+00:00" + "last_validated_date": "2025-11-25T02:37:44+00:00", + "durations_in_seconds": { + "setup": 0.01, + "call": 29.02, + "teardown": 0.36, + "total": 29.39 + } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaImages::test_lambda_image_crud": { - "last_validated_date": "2024-04-10T09:10:21+00:00" + "last_validated_date": "2025-11-25T02:37:05+00:00", + "durations_in_seconds": { + "setup": 1.08, + "call": 50.01, + "teardown": 0.24, + "total": 51.33 + } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaImages::test_lambda_image_versions": { - "last_validated_date": "2024-04-10T09:11:50+00:00" + "last_validated_date": "2025-11-25T02:38:15+00:00", + "durations_in_seconds": { + "setup": 0.01, + "call": 28.73, + "teardown": 2.36, + "total": 31.1 + } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaImages::test_lambda_zip_file_to_image": { - "last_validated_date": "2024-04-10T09:10:37+00:00" + "last_validated_date": "2025-11-25T02:37:15+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 9.45, + "teardown": 0.28, + "total": 9.73 + } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaLayer::test_layer_compatibilities[runtimes0]": { - "last_validated_date": "2025-04-01T13:14:56+00:00" + "last_validated_date": "2026-01-12T15:31:31+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 4.08, + "teardown": 0.27, + "total": 4.35 + } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaLayer::test_layer_compatibilities[runtimes1]": { - "last_validated_date": "2025-04-01T13:15:00+00:00" + "last_validated_date": "2026-01-12T15:31:37+00:00", + "durations_in_seconds": { + "setup": 0.01, + "call": 5.66, + "teardown": 0.27, + "total": 5.94 + } + }, + "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaLayer::test_layer_compatibilities[runtimes2]": { + "last_validated_date": "2026-01-12T15:31:43+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 5.66, + "teardown": 0.28, + "total": 5.94 + } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaLayer::test_layer_exceptions": { - "last_validated_date": "2025-04-01T13:19:40+00:00" + "last_validated_date": "2026-01-12T15:31:58+00:00", + "durations_in_seconds": { + "setup": 0.01, + "call": 14.31, + "teardown": 0.42, + "total": 14.74 + } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaLayer::test_layer_function_exceptions": { - "last_validated_date": "2024-04-10T09:23:18+00:00" + "last_validated_date": "2025-11-25T21:58:40+00:00", + "durations_in_seconds": { + "setup": 11.09, + "call": 36.8, + "teardown": 1.54, + "total": 49.43 + } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaLayer::test_layer_function_quota_exception": { - "last_validated_date": "2024-04-10T09:23:58+00:00" + "last_validated_date": "2025-11-25T02:50:21+00:00", + "durations_in_seconds": { + "setup": 0.01, + "call": 43.13, + "teardown": 0.46, + "total": 43.6 + } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaLayer::test_layer_lifecycle": { - "last_validated_date": "2024-04-10T09:24:16+00:00" + "last_validated_date": "2025-11-25T02:50:43+00:00", + "durations_in_seconds": { + "setup": 0.01, + "call": 20.73, + "teardown": 0.81, + "total": 21.55 + } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaLayer::test_layer_policy_exceptions": { - "last_validated_date": "2024-04-10T09:24:29+00:00" + "last_validated_date": "2025-11-25T02:50:51+00:00", + "durations_in_seconds": { + "setup": 0.01, + "call": 5.76, + "teardown": 0.12, + "total": 5.89 + } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaLayer::test_layer_policy_lifecycle": { - "last_validated_date": "2024-04-10T09:24:34+00:00" + "last_validated_date": "2025-11-25T02:50:55+00:00", + "durations_in_seconds": { + "setup": 0.01, + "call": 4.03, + "teardown": 0.1, + "total": 4.14 + } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaLayer::test_layer_s3_content": { - "last_validated_date": "2024-04-10T09:24:22+00:00" + "last_validated_date": "2025-11-25T02:50:45+00:00", + "durations_in_seconds": { + "setup": 0.01, + "call": 1.99, + "teardown": 0.84, + "total": 2.84 + } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaPermissions::test_add_lambda_permission_aws": { - "last_validated_date": "2024-04-10T09:16:22+00:00" + "last_validated_date": "2025-11-25T02:42:56+00:00", + "durations_in_seconds": { + "setup": 0.01, + "call": 2.3, + "teardown": 0.61, + "total": 2.92 + } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaPermissions::test_add_lambda_permission_fields": { - "last_validated_date": "2024-04-10T09:16:33+00:00" + "last_validated_date": "2025-11-25T02:43:05+00:00", + "durations_in_seconds": { + "setup": 0.01, + "call": 3.47, + "teardown": 0.72, + "total": 4.2 + } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaPermissions::test_create_multiple_lambda_permissions": { - "last_validated_date": "2024-04-10T09:16:40+00:00" + "last_validated_date": "2025-11-25T02:43:12+00:00", + "durations_in_seconds": { + "setup": 0.01, + "call": 2.21, + "teardown": 0.84, + "total": 3.06 + } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaPermissions::test_lambda_permission_fn_versioning": { - "last_validated_date": "2024-04-10T09:16:28+00:00" + "last_validated_date": "2025-11-25T21:46:15+00:00", + "durations_in_seconds": { + "setup": 10.92, + "call": 4.0, + "teardown": 1.05, + "total": 15.97 + } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaPermissions::test_permission_exceptions": { - "last_validated_date": "2024-04-10T09:16:19+00:00" + "last_validated_date": "2025-11-25T02:42:53+00:00", + "durations_in_seconds": { + "setup": 0.01, + "call": 3.62, + "teardown": 0.37, + "total": 4.0 + } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaPermissions::test_remove_multi_permissions": { - "last_validated_date": "2024-04-10T09:16:37+00:00" + "last_validated_date": "2025-11-25T02:43:09+00:00", + "durations_in_seconds": { + "setup": 0.01, + "call": 2.84, + "teardown": 0.87, + "total": 3.72 + } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaProvisionedConcurrency::test_lambda_provisioned_lifecycle": { - "last_validated_date": "2024-04-10T09:16:14+00:00" + "last_validated_date": "2025-11-25T02:42:49+00:00", + "durations_in_seconds": { + "setup": 0.01, + "call": 131.69, + "teardown": 0.99, + "total": 132.69 + } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaProvisionedConcurrency::test_provisioned_concurrency_exceptions": { - "last_validated_date": "2024-04-10T09:13:56+00:00" + "last_validated_date": "2025-11-25T02:40:34+00:00", + "durations_in_seconds": { + "setup": 0.01, + "call": 3.8, + "teardown": 0.78, + "total": 4.59 + } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaProvisionedConcurrency::test_provisioned_concurrency_limits": { - "last_validated_date": "2024-04-10T09:13:59+00:00" + "last_validated_date": "2025-11-25T02:40:37+00:00", + "durations_in_seconds": { + "setup": 0.01, + "call": 2.19, + "teardown": 0.77, + "total": 2.97 + } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaRecursion::test_put_function_recursion_config_allow": { - "last_validated_date": "2024-09-12T11:35:19+00:00" + "last_validated_date": "2025-11-25T02:36:04+00:00", + "durations_in_seconds": { + "setup": 0.01, + "call": 2.01, + "teardown": 0.62, + "total": 2.64 + } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaRecursion::test_put_function_recursion_config_default_terminate": { - "last_validated_date": "2024-09-12T11:35:21+00:00" + "last_validated_date": "2025-11-25T02:36:11+00:00", + "durations_in_seconds": { + "setup": 0.01, + "call": 1.74, + "teardown": 5.69, + "total": 7.44 + } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaRecursion::test_put_function_recursion_config_invalid_value": { - "last_validated_date": "2024-09-12T11:35:23+00:00" + "last_validated_date": "2025-11-25T02:36:14+00:00", + "durations_in_seconds": { + "setup": 0.01, + "call": 1.8, + "teardown": 0.5, + "total": 2.31 + } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaReservedConcurrency::test_function_concurrency": { - "last_validated_date": "2024-04-10T09:13:50+00:00" + "last_validated_date": "2025-11-25T02:40:29+00:00", + "durations_in_seconds": { + "setup": 0.01, + "call": 2.85, + "teardown": 5.8, + "total": 8.66 + } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaReservedConcurrency::test_function_concurrency_exceptions": { - "last_validated_date": "2024-04-10T09:13:43+00:00" + "last_validated_date": "2025-11-25T02:40:18+00:00", + "durations_in_seconds": { + "setup": 0.01, + "call": 2.1, + "teardown": 0.53, + "total": 2.64 + } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaReservedConcurrency::test_function_concurrency_limits": { - "last_validated_date": "2024-04-10T09:13:46+00:00" + "last_validated_date": "2025-11-25T02:40:20+00:00", + "durations_in_seconds": { + "setup": 0.01, + "call": 2.02, + "teardown": 0.73, + "total": 2.76 + } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaRevisions::test_function_revisions_basic": { - "last_validated_date": "2024-04-10T09:12:52+00:00" + "last_validated_date": "2025-11-25T02:39:11+00:00", + "durations_in_seconds": { + "setup": 0.01, + "call": 5.96, + "teardown": 0.6, + "total": 6.57 + } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaRevisions::test_function_revisions_permissions": { "last_validated_date": "2024-04-10T09:13:01+00:00" }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaRevisions::test_function_revisions_version_and_alias": { - "last_validated_date": "2024-04-10T09:12:57+00:00" + "last_validated_date": "2025-11-25T02:39:15+00:00", + "durations_in_seconds": { + "setup": 0.01, + "call": 3.21, + "teardown": 0.68, + "total": 3.9 + } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaSizeLimits::test_lambda_envvars_near_limit_succeeds": { - "last_validated_date": "2024-04-10T09:19:06+00:00" + "last_validated_date": "2025-11-25T02:46:39+00:00", + "durations_in_seconds": { + "setup": 0.01, + "call": 2.08, + "teardown": 0.62, + "total": 2.71 + } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaSizeLimits::test_large_environment_fails_multiple_keys": { - "last_validated_date": "2024-04-10T09:19:04+00:00" + "last_validated_date": "2025-11-25T02:46:36+00:00", + "durations_in_seconds": { + "setup": 0.01, + "call": 17.47, + "teardown": 0.01, + "total": 17.49 + } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaSizeLimits::test_large_environment_variables_fails": { - "last_validated_date": "2024-04-10T09:18:46+00:00" + "last_validated_date": "2025-11-25T02:46:19+00:00", + "durations_in_seconds": { + "setup": 0.01, + "call": 17.69, + "teardown": 0.01, + "total": 17.71 + } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaSizeLimits::test_large_lambda": { - "last_validated_date": "2024-04-10T09:18:27+00:00" + "last_validated_date": "2025-11-25T02:46:01+00:00", + "durations_in_seconds": { + "setup": 0.79, + "call": 46.62, + "teardown": 1.36, + "total": 48.77 + } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaSizeLimits::test_oversized_request_create_lambda": { - "last_validated_date": "2024-04-10T09:17:14+00:00" + "last_validated_date": "2025-11-25T02:44:03+00:00", + "durations_in_seconds": { + "setup": 0.01, + "call": 31.16, + "teardown": 0.01, + "total": 31.18 + } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaSizeLimits::test_oversized_unzipped_lambda": { - "last_validated_date": "2024-04-10T09:17:46+00:00" + "last_validated_date": "2025-11-25T02:45:12+00:00", + "durations_in_seconds": { + "setup": 0.83, + "call": 33.16, + "teardown": 0.86, + "total": 34.85 + } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaSizeLimits::test_oversized_zipped_create_lambda": { - "last_validated_date": "2024-04-10T09:17:26+00:00" + "last_validated_date": "2025-11-25T02:44:37+00:00", + "durations_in_seconds": { + "setup": 0.01, + "call": 34.79, + "teardown": 0.01, + "total": 34.81 + } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaSnapStart::test_snapstart_exceptions": { - "last_validated_date": "2025-03-31T16:15:53+00:00" + "last_validated_date": "2025-11-25T02:51:34+00:00", + "durations_in_seconds": { + "setup": 0.01, + "call": 0.11, + "teardown": 0.01, + "total": 0.13 + } + }, + "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaSnapStart::test_snapstart_lifecycle[dotnet10]": { + "last_validated_date": "2026-01-12T15:33:00+00:00", + "durations_in_seconds": { + "setup": 4.89, + "call": 5.82, + "teardown": 0.44, + "total": 11.15 + } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaSnapStart::test_snapstart_lifecycle[dotnet8]": { - "last_validated_date": "2025-04-01T13:31:14+00:00" + "last_validated_date": "2026-01-12T15:32:49+00:00", + "durations_in_seconds": { + "setup": 5.66, + "call": 5.86, + "teardown": 0.46, + "total": 11.98 + } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaSnapStart::test_snapstart_lifecycle[java11]": { - "last_validated_date": "2025-04-01T13:30:54+00:00" + "last_validated_date": "2026-01-12T15:32:08+00:00", + "durations_in_seconds": { + "setup": 6.05, + "call": 3.45, + "teardown": 0.54, + "total": 10.04 + } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaSnapStart::test_snapstart_lifecycle[java17]": { - "last_validated_date": "2025-04-01T13:30:57+00:00" + "last_validated_date": "2026-01-12T15:32:14+00:00", + "durations_in_seconds": { + "setup": 0.01, + "call": 5.74, + "teardown": 0.49, + "total": 6.24 + } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaSnapStart::test_snapstart_lifecycle[java21]": { - "last_validated_date": "2025-04-01T13:31:02+00:00" + "last_validated_date": "2026-01-12T15:32:21+00:00", + "durations_in_seconds": { + "setup": 0.01, + "call": 6.29, + "teardown": 0.45, + "total": 6.75 + } + }, + "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaSnapStart::test_snapstart_lifecycle[java25]": { + "last_validated_date": "2026-01-12T15:32:25+00:00", + "durations_in_seconds": { + "setup": 0.01, + "call": 3.39, + "teardown": 0.45, + "total": 3.85 + } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaSnapStart::test_snapstart_lifecycle[python3.12]": { - "last_validated_date": "2025-04-01T13:31:06+00:00" + "last_validated_date": "2026-01-12T15:32:31+00:00", + "durations_in_seconds": { + "setup": 0.04, + "call": 5.65, + "teardown": 0.6, + "total": 6.29 + } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaSnapStart::test_snapstart_lifecycle[python3.13]": { - "last_validated_date": "2025-04-01T13:31:10+00:00" + "last_validated_date": "2026-01-12T15:32:37+00:00", + "durations_in_seconds": { + "setup": 0.01, + "call": 5.63, + "teardown": 0.5, + "total": 6.14 + } + }, + "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaSnapStart::test_snapstart_update_function_configuration[dotnet10]": { + "last_validated_date": "2026-01-12T15:33:33+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 5.45, + "teardown": 0.41, + "total": 5.86 + } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaSnapStart::test_snapstart_update_function_configuration[dotnet8]": { - "last_validated_date": "2025-04-01T13:42:13+00:00" + "last_validated_date": "2026-01-12T15:33:28+00:00", + "durations_in_seconds": { + "setup": 0.01, + "call": 2.92, + "teardown": 0.37, + "total": 3.3 + } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaSnapStart::test_snapstart_update_function_configuration[java11]": { - "last_validated_date": "2025-04-01T13:41:52+00:00" + "last_validated_date": "2026-01-12T15:33:06+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 5.33, + "teardown": 0.38, + "total": 5.71 + } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaSnapStart::test_snapstart_update_function_configuration[java17]": { - "last_validated_date": "2025-04-01T13:41:56+00:00" + "last_validated_date": "2026-01-12T15:33:11+00:00", + "durations_in_seconds": { + "setup": 0.01, + "call": 5.17, + "teardown": 0.4, + "total": 5.58 + } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaSnapStart::test_snapstart_update_function_configuration[java21]": { - "last_validated_date": "2025-04-01T13:42:01+00:00" + "last_validated_date": "2026-01-12T15:33:15+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 2.78, + "teardown": 0.45, + "total": 3.23 + } + }, + "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaSnapStart::test_snapstart_update_function_configuration[java25]": { + "last_validated_date": "2026-01-12T15:33:18+00:00", + "durations_in_seconds": { + "setup": 0.01, + "call": 2.76, + "teardown": 0.51, + "total": 3.28 + } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaSnapStart::test_snapstart_update_function_configuration[python3.12]": { - "last_validated_date": "2025-04-01T13:42:04+00:00" + "last_validated_date": "2026-01-12T15:33:21+00:00", + "durations_in_seconds": { + "setup": 0.01, + "call": 2.78, + "teardown": 0.36, + "total": 3.15 + } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaSnapStart::test_snapstart_update_function_configuration[python3.13]": { - "last_validated_date": "2025-04-01T13:42:08+00:00" + "last_validated_date": "2026-01-12T15:33:24+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 2.76, + "teardown": 0.37, + "total": 3.13 + } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaTag::test_create_tag_on_esm_create": { - "last_validated_date": "2024-10-24T14:16:05+00:00" + "last_validated_date": "2025-11-25T02:39:41+00:00", + "durations_in_seconds": { + "setup": 0.01, + "call": 18.83, + "teardown": 0.87, + "total": 19.71 + } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaTag::test_create_tag_on_fn_create": { - "last_validated_date": "2024-04-10T09:13:04+00:00" + "last_validated_date": "2025-11-25T02:39:21+00:00", + "durations_in_seconds": { + "setup": 0.01, + "call": 1.88, + "teardown": 0.63, + "total": 2.52 + } + }, + "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaTag::test_tag_exceptions[capacity_provider]": { + "last_validated_date": "2025-11-25T21:37:02+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.48, + "teardown": 0.01, + "total": 0.49 + } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaTag::test_tag_exceptions[event_source_mapping]": { - "last_validated_date": "2024-10-24T12:42:57+00:00" + "last_validated_date": "2025-11-25T21:37:01+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.52, + "teardown": 0.01, + "total": 0.53 + } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaTag::test_tag_exceptions[lambda_function]": { - "last_validated_date": "2024-10-24T12:42:56+00:00" + "last_validated_date": "2025-11-25T21:37:01+00:00", + "durations_in_seconds": { + "setup": 0.37, + "call": 0.6, + "teardown": 0.01, + "total": 0.98 + } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaTag::test_tag_lifecycle": { "last_validated_date": "2024-04-10T09:13:09+00:00" }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaTag::test_tag_lifecycle[event_source_mapping]": { - "last_validated_date": "2024-10-23T10:51:25+00:00" + "last_validated_date": "2025-11-25T02:39:50+00:00", + "durations_in_seconds": { + "setup": 0.01, + "call": 4.29, + "teardown": 1.09, + "total": 5.39 + } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaTag::test_tag_lifecycle[lambda_function]": { - "last_validated_date": "2024-10-23T10:51:14+00:00" + "last_validated_date": "2025-11-25T02:39:44+00:00", + "durations_in_seconds": { + "setup": 0.01, + "call": 3.16, + "teardown": 0.66, + "total": 3.83 + } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaTag::test_tag_nonexisting_resource": { - "last_validated_date": "2024-04-10T09:13:13+00:00" + "last_validated_date": "2025-11-25T02:39:54+00:00", + "durations_in_seconds": { + "setup": 1.95, + "call": 0.59, + "teardown": 0.44, + "total": 2.98 + } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaTags::test_tag_exceptions": { - "last_validated_date": "2024-10-24T15:22:27+00:00" + "last_validated_date": "2025-11-25T02:48:27+00:00", + "durations_in_seconds": { + "setup": 0.01, + "call": 2.86, + "teardown": 0.76, + "total": 3.63 + } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaTags::test_tag_lifecycle": { - "last_validated_date": "2024-10-24T15:22:47+00:00" + "last_validated_date": "2025-11-25T02:48:38+00:00", + "durations_in_seconds": { + "setup": 0.01, + "call": 3.94, + "teardown": 0.59, + "total": 4.54 + } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaTags::test_tag_limits": { - "last_validated_date": "2024-10-28T14:16:36+00:00" + "last_validated_date": "2025-11-25T02:48:31+00:00", + "durations_in_seconds": { + "setup": 0.01, + "call": 2.95, + "teardown": 0.64, + "total": 3.6 + } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaTags::test_tag_versions": { - "last_validated_date": "2024-10-24T15:22:38+00:00" + "last_validated_date": "2025-11-25T02:48:33+00:00", + "durations_in_seconds": { + "setup": 0.01, + "call": 2.06, + "teardown": 0.78, + "total": 2.85 + } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaUrl::test_url_config_deletion_without_qualifier": { - "last_validated_date": "2024-11-21T13:44:17+00:00" + "last_validated_date": "2025-11-25T02:43:31+00:00", + "durations_in_seconds": { + "setup": 0.02, + "call": 3.98, + "teardown": 0.34, + "total": 4.34 + } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaUrl::test_url_config_exceptions": { - "last_validated_date": "2024-11-21T13:44:04+00:00" + "last_validated_date": "2025-11-25T02:43:19+00:00", + "durations_in_seconds": { + "setup": 0.01, + "call": 6.43, + "teardown": 0.58, + "total": 7.02 + } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaUrl::test_url_config_lifecycle": { - "last_validated_date": "2024-11-21T13:44:13+00:00" + "last_validated_date": "2025-11-25T02:43:27+00:00", + "durations_in_seconds": { + "setup": 0.01, + "call": 3.03, + "teardown": 0.64, + "total": 3.68 + } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaUrl::test_url_config_list_paging": { - "last_validated_date": "2024-11-21T13:44:09+00:00" + "last_validated_date": "2025-11-25T02:43:23+00:00", + "durations_in_seconds": { + "setup": 0.01, + "call": 3.68, + "teardown": 0.74, + "total": 4.43 + } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaVersions::test_publish_version_on_create": { - "last_validated_date": "2024-04-10T09:12:04+00:00" + "last_validated_date": "2025-11-25T02:38:24+00:00", + "durations_in_seconds": { + "setup": 0.01, + "call": 8.73, + "teardown": 0.32, + "total": 9.06 + } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaVersions::test_publish_with_update": { - "last_validated_date": "2024-04-10T09:12:17+00:00" + "last_validated_date": "2025-11-25T02:38:38+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 2.48, + "teardown": 0.37, + "total": 2.85 + } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaVersions::test_publish_with_wrong_sha256": { - "last_validated_date": "2024-04-10T09:12:14+00:00" + "last_validated_date": "2025-11-25T02:38:35+00:00", + "durations_in_seconds": { + "setup": 0.01, + "call": 2.31, + "teardown": 0.42, + "total": 2.74 + } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLambdaVersions::test_version_lifecycle": { - "last_validated_date": "2024-07-12T11:43:40+00:00" + "last_validated_date": "2025-11-25T02:38:32+00:00", + "durations_in_seconds": { + "setup": 0.01, + "call": 7.33, + "teardown": 0.42, + "total": 7.76 + } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLoggingConfig::test_advanced_logging_configuration_format_switch": { - "last_validated_date": "2024-04-17T14:16:55+00:00" + "last_validated_date": "2025-11-25T02:26:30+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 5.69, + "teardown": 0.54, + "total": 6.23 + } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLoggingConfig::test_function_advanced_logging_configuration": { - "last_validated_date": "2024-04-19T08:20:18+00:00" + "last_validated_date": "2025-11-25T02:26:24+00:00", + "durations_in_seconds": { + "setup": 0.01, + "call": 3.91, + "teardown": 0.58, + "total": 4.5 + } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLoggingConfig::test_function_partial_advanced_logging_configuration_update[partial_config0]": { - "last_validated_date": "2024-04-17T14:17:00+00:00" + "last_validated_date": "2025-11-25T02:26:35+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 4.44, + "teardown": 0.55, + "total": 4.99 + } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLoggingConfig::test_function_partial_advanced_logging_configuration_update[partial_config1]": { - "last_validated_date": "2024-04-17T14:17:05+00:00" + "last_validated_date": "2025-11-25T02:26:39+00:00", + "durations_in_seconds": { + "setup": 0.01, + "call": 3.77, + "teardown": 0.52, + "total": 4.3 + } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLoggingConfig::test_function_partial_advanced_logging_configuration_update[partial_config2]": { - "last_validated_date": "2024-04-17T14:17:11+00:00" + "last_validated_date": "2025-11-25T02:26:44+00:00", + "durations_in_seconds": { + "setup": 0.01, + "call": 3.89, + "teardown": 0.54, + "total": 4.44 + } }, "tests/aws/services/lambda_/test_lambda_api.py::TestLoggingConfig::test_function_partial_advanced_logging_configuration_update[partial_config3]": { - "last_validated_date": "2024-04-17T14:17:16+00:00" + "last_validated_date": "2025-11-25T02:26:48+00:00", + "durations_in_seconds": { + "setup": 0.01, + "call": 3.82, + "teardown": 0.53, + "total": 4.36 + } }, "tests/aws/services/lambda_/test_lambda_api.py::TestPartialARNMatching::test_cross_region_arn_function_access": { - "last_validated_date": "2024-06-11T13:06:44+00:00" + "last_validated_date": "2025-11-25T02:26:19+00:00", + "durations_in_seconds": { + "setup": 0.02, + "call": 2.18, + "teardown": 0.61, + "total": 2.81 + } }, "tests/aws/services/lambda_/test_lambda_api.py::TestPartialARNMatching::test_update_function_configuration_full_arn": { - "last_validated_date": "2024-06-05T11:49:05+00:00" + "last_validated_date": "2025-11-25T02:26:17+00:00", + "durations_in_seconds": { + "setup": 0.05, + "call": 6.97, + "teardown": 0.6, + "total": 7.62 + } }, "tests/aws/services/lambda_/test_lambda_api.py::TestRuntimeValidation::test_create_deprecated_function_runtime_with_validation_enabled[dotnetcore3.1]": { - "last_validated_date": "2025-04-01T13:06:04+00:00" + "last_validated_date": "2026-01-12T15:31:22+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.25, + "teardown": 0.01, + "total": 0.26 + } }, "tests/aws/services/lambda_/test_lambda_api.py::TestRuntimeValidation::test_create_deprecated_function_runtime_with_validation_enabled[go1.x]": { - "last_validated_date": "2025-04-01T13:06:03+00:00" + "last_validated_date": "2026-01-12T15:31:21+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.26, + "teardown": 0.01, + "total": 0.27 + } }, "tests/aws/services/lambda_/test_lambda_api.py::TestRuntimeValidation::test_create_deprecated_function_runtime_with_validation_enabled[java8]": { - "last_validated_date": "2025-04-01T13:06:03+00:00" + "last_validated_date": "2026-01-12T15:31:21+00:00", + "durations_in_seconds": { + "setup": 12.06, + "call": 0.7, + "teardown": 0.01, + "total": 12.77 + } }, "tests/aws/services/lambda_/test_lambda_api.py::TestRuntimeValidation::test_create_deprecated_function_runtime_with_validation_enabled[nodejs12.x]": { - "last_validated_date": "2025-04-01T13:06:05+00:00" + "last_validated_date": "2026-01-12T15:31:22+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.27, + "teardown": 0.01, + "total": 0.28 + } }, "tests/aws/services/lambda_/test_lambda_api.py::TestRuntimeValidation::test_create_deprecated_function_runtime_with_validation_enabled[nodejs14.x]": { - "last_validated_date": "2025-04-01T13:06:04+00:00" + "last_validated_date": "2026-01-12T15:31:22+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.27, + "teardown": 0.01, + "total": 0.28 + } }, "tests/aws/services/lambda_/test_lambda_api.py::TestRuntimeValidation::test_create_deprecated_function_runtime_with_validation_enabled[provided]": { - "last_validated_date": "2025-04-01T13:06:04+00:00" + "last_validated_date": "2026-01-12T15:31:21+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.25, + "teardown": 0.01, + "total": 0.26 + } }, "tests/aws/services/lambda_/test_lambda_api.py::TestRuntimeValidation::test_create_deprecated_function_runtime_with_validation_enabled[python3.7]": { - "last_validated_date": "2025-04-01T13:06:04+00:00" + "last_validated_date": "2026-01-12T15:31:22+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.26, + "teardown": 0.01, + "total": 0.27 + } }, "tests/aws/services/lambda_/test_lambda_api.py::TestRuntimeValidation::test_create_deprecated_function_runtime_with_validation_enabled[ruby2.7]": { - "last_validated_date": "2025-04-01T13:06:04+00:00" + "last_validated_date": "2026-01-12T15:31:21+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.25, + "teardown": 0.01, + "total": 0.26 + } } } diff --git a/tests/aws/services/lambda_/test_lambda_common.py b/tests/aws/services/lambda_/test_lambda_common.py index 0e44a03549ec6..685b34785b35f 100644 --- a/tests/aws/services/lambda_/test_lambda_common.py +++ b/tests/aws/services/lambda_/test_lambda_common.py @@ -132,7 +132,7 @@ def _invoke_with_payload(payload): "$..environment.AWS_EXECUTION_ENV", # Only rust runtime "$..environment.LD_LIBRARY_PATH", # Only rust runtime (additional /var/lang/bin) "$..environment.PATH", # Only rust runtime (additional /var/lang/bin) - "$..environment.LC_CTYPE", # Only python3.11 (part of a broken image rollout, likely rolled back) + "$..environment.LC_CTYPE", # Only missing in Python 3.12, 3.13, and 3.14 "$..environment.RUBYLIB", # Changed around 2025-06-17 # Newer Nodejs images explicitly disable a temporary performance workaround for Nodejs 20 on certain hosts: # https://nodejs.org/api/cli.html#uv_use_io_uringvalue @@ -145,6 +145,8 @@ def _invoke_with_payload(payload): "$..environment.DOTNET_VERSION", # Changed from 127.0.0.1:9001 to 169.254.100.1:9001 around 2024-11, which would require network changes "$..environment.AWS_LAMBDA_RUNTIME_API", + # Only Ruby runtimes, changed + "$..environment.GEM_PATH", ] ) @markers.aws.validated diff --git a/tests/aws/services/lambda_/test_lambda_common.snapshot.json b/tests/aws/services/lambda_/test_lambda_common.snapshot.json index fa2db765c511b..7e06639ce3cab 100644 --- a/tests/aws/services/lambda_/test_lambda_common.snapshot.json +++ b/tests/aws/services/lambda_/test_lambda_common.snapshot.json @@ -1,70 +1,70 @@ { "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_echo_invoke[python3.8]": { - "recorded-date": "31-03-2025, 12:14:56", + "recorded-date": "12-01-2026, 15:34:58", "recorded-content": {} }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_echo_invoke[java11]": { - "recorded-date": "31-03-2025, 12:15:23", + "recorded-date": "12-01-2026, 15:35:26", "recorded-content": {} }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_echo_invoke[provided.al2]": { - "recorded-date": "31-03-2025, 12:17:30", + "recorded-date": "12-01-2026, 16:40:09", "recorded-content": {} }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_echo_invoke[java8.al2]": { - "recorded-date": "31-03-2025, 12:15:42", + "recorded-date": "12-01-2026, 15:35:32", "recorded-content": {} }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_echo_invoke[ruby3.2]": { - "recorded-date": "31-03-2025, 12:15:54", + "recorded-date": "12-01-2026, 15:35:40", "recorded-content": {} }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_echo_invoke[python3.11]": { - "recorded-date": "31-03-2025, 12:14:05", + "recorded-date": "12-01-2026, 15:34:39", "recorded-content": {} }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_echo_invoke[java17]": { - "recorded-date": "31-03-2025, 12:15:14", + "recorded-date": "12-01-2026, 15:35:18", "recorded-content": {} }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_echo_invoke[nodejs18.x]": { - "recorded-date": "31-03-2025, 12:13:11", + "recorded-date": "12-01-2026, 15:34:02", "recorded-content": {} }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_echo_invoke[java21]": { - "recorded-date": "31-03-2025, 12:15:05", + "recorded-date": "12-01-2026, 15:35:12", "recorded-content": {} }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_echo_invoke[provided.al2023]": { - "recorded-date": "31-03-2025, 12:17:17", + "recorded-date": "12-01-2026, 16:39:59", "recorded-content": {} }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_echo_invoke[python3.9]": { - "recorded-date": "31-03-2025, 12:14:39", + "recorded-date": "12-01-2026, 15:34:52", "recorded-content": {} }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_echo_invoke[python3.10]": { - "recorded-date": "31-03-2025, 12:14:20", + "recorded-date": "12-01-2026, 15:34:47", "recorded-content": {} }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_echo_invoke[python3.12]": { - "recorded-date": "31-03-2025, 12:13:57", + "recorded-date": "12-01-2026, 15:34:31", "recorded-content": {} }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_echo_invoke[nodejs20.x]": { - "recorded-date": "31-03-2025, 12:12:59", + "recorded-date": "12-01-2026, 15:33:56", "recorded-content": {} }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_echo_invoke[dotnet6]": { - "recorded-date": "31-03-2025, 12:16:46", + "recorded-date": "12-01-2026, 15:36:08", "recorded-content": {} }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_echo_invoke[nodejs16.x]": { - "recorded-date": "31-03-2025, 12:13:31", + "recorded-date": "12-01-2026, 15:34:10", "recorded-content": {} }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_introspection_invoke[python3.8]": { - "recorded-date": "17-06-2025, 09:51:26", + "recorded-date": "12-01-2026, 15:37:41", "recorded-content": { "create_function_result": { "Architectures": [ @@ -135,12 +135,12 @@ "AWS_LAMBDA_INITIALIZATION_TYPE": "on-demand", "AWS_LAMBDA_LOG_GROUP_NAME": "/aws/lambda/", "AWS_LAMBDA_LOG_STREAM_NAME": "", - "AWS_LAMBDA_RUNTIME_API": "127.0.0.1:9001", + "AWS_LAMBDA_RUNTIME_API": "169.254.100.1:9001", "AWS_REGION": "", "AWS_SECRET_ACCESS_KEY": "", "AWS_SESSION_TOKEN": "", "AWS_XRAY_CONTEXT_MISSING": "LOG_ERROR", - "AWS_XRAY_DAEMON_ADDRESS": "169.254.79.129:2000", + "AWS_XRAY_DAEMON_ADDRESS": "169.254.100.1:2000", "LAMBDA_RUNTIME_DIR": "/var/runtime", "LAMBDA_TASK_ROOT": "/var/task", "LANG": "en_US.UTF-8", @@ -151,7 +151,7 @@ "SHLVL": "0", "TEST_KEY": "TEST_VAL", "TZ": ":UTC", - "_AWS_XRAY_DAEMON_ADDRESS": "169.254.79.129", + "_AWS_XRAY_DAEMON_ADDRESS": "169.254.100.1", "_AWS_XRAY_DAEMON_PORT": "2000", "_HANDLER": "handler.handler", "_X_AMZN_TRACE_ID": "" @@ -179,12 +179,12 @@ "AWS_LAMBDA_INITIALIZATION_TYPE": "on-demand", "AWS_LAMBDA_LOG_GROUP_NAME": "/aws/lambda/", "AWS_LAMBDA_LOG_STREAM_NAME": "", - "AWS_LAMBDA_RUNTIME_API": "127.0.0.1:9001", + "AWS_LAMBDA_RUNTIME_API": "169.254.100.1:9001", "AWS_REGION": "", "AWS_SECRET_ACCESS_KEY": "", "AWS_SESSION_TOKEN": "", "AWS_XRAY_CONTEXT_MISSING": "LOG_ERROR", - "AWS_XRAY_DAEMON_ADDRESS": "169.254.79.129:2000", + "AWS_XRAY_DAEMON_ADDRESS": "169.254.100.1:2000", "LAMBDA_RUNTIME_DIR": "/var/runtime", "LAMBDA_TASK_ROOT": "/var/task", "LANG": "en_US.UTF-8", @@ -195,7 +195,7 @@ "SHLVL": "0", "TEST_KEY": "TEST_VAL", "TZ": ":UTC", - "_AWS_XRAY_DAEMON_ADDRESS": "169.254.79.129", + "_AWS_XRAY_DAEMON_ADDRESS": "169.254.100.1", "_AWS_XRAY_DAEMON_PORT": "2000", "_HANDLER": "handler.handler", "_X_AMZN_TRACE_ID": "" @@ -205,7 +205,7 @@ } }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_introspection_invoke[java11]": { - "recorded-date": "17-06-2025, 09:51:40", + "recorded-date": "12-01-2026, 15:38:12", "recorded-content": { "create_function_result": { "Architectures": [ @@ -344,7 +344,7 @@ } }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_introspection_invoke[provided.al2]": { - "recorded-date": "17-06-2025, 09:52:11", + "recorded-date": "13-01-2026, 14:03:50", "recorded-content": { "create_function_result": { "Architectures": [ @@ -477,7 +477,7 @@ } }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_introspection_invoke[java8.al2]": { - "recorded-date": "17-06-2025, 09:51:44", + "recorded-date": "12-01-2026, 15:38:19", "recorded-content": { "create_function_result": { "Architectures": [ @@ -616,7 +616,7 @@ } }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_introspection_invoke[ruby3.2]": { - "recorded-date": "17-06-2025, 09:51:47", + "recorded-date": "12-01-2026, 15:38:25", "recorded-content": { "create_function_result": { "Architectures": [ @@ -701,7 +701,7 @@ "LD_LIBRARY_PATH": "/var/lang/lib:/var/lang/lib:/lib64:/usr/lib64:/var/runtime:/var/runtime/lib:/var/task:/var/task/lib:/opt/lib", "PATH": "/var/lang/bin:/var/lang/bin:/usr/local/bin:/usr/bin/:/bin:/opt/bin", "PWD": "/var/task", - "RUBYLIB": "/var/runtime/gems/aws_lambda_ric-3.0.0/lib:/var/task:/var/runtime/lib:/opt/ruby/lib", + "RUBYLIB": "/var/runtime/gems/aws_lambda_ric-3.1.3/lib:/var/task:/var/runtime/lib:/opt/ruby/lib", "SHLVL": "0", "TEST_KEY": "TEST_VAL", "TZ": ":UTC", @@ -747,7 +747,7 @@ "LD_LIBRARY_PATH": "/var/lang/lib:/var/lang/lib:/lib64:/usr/lib64:/var/runtime:/var/runtime/lib:/var/task:/var/task/lib:/opt/lib", "PATH": "/var/lang/bin:/var/lang/bin:/usr/local/bin:/usr/bin/:/bin:/opt/bin", "PWD": "/var/task", - "RUBYLIB": "/var/runtime/gems/aws_lambda_ric-3.0.0/lib:/var/task:/var/runtime/lib:/opt/ruby/lib", + "RUBYLIB": "/var/runtime/gems/aws_lambda_ric-3.1.3/lib:/var/task:/var/runtime/lib:/opt/ruby/lib", "SHLVL": "0", "TEST_KEY": "TEST_VAL", "TZ": ":UTC", @@ -761,7 +761,7 @@ } }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_introspection_invoke[python3.11]": { - "recorded-date": "17-06-2025, 09:51:17", + "recorded-date": "12-01-2026, 15:37:29", "recorded-content": { "create_function_result": { "Architectures": [ @@ -902,7 +902,7 @@ } }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_introspection_invoke[java17]": { - "recorded-date": "17-06-2025, 09:51:36", + "recorded-date": "12-01-2026, 15:38:06", "recorded-content": { "create_function_result": { "Architectures": [ @@ -1037,7 +1037,7 @@ } }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_introspection_invoke[nodejs18.x]": { - "recorded-date": "17-06-2025, 09:51:05", + "recorded-date": "12-01-2026, 15:37:02", "recorded-content": { "create_function_result": { "Architectures": [ @@ -1178,7 +1178,7 @@ } }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_introspection_invoke[java21]": { - "recorded-date": "17-06-2025, 09:51:33", + "recorded-date": "12-01-2026, 15:37:59", "recorded-content": { "create_function_result": { "Architectures": [ @@ -1313,7 +1313,7 @@ } }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_introspection_invoke[provided.al2023]": { - "recorded-date": "17-06-2025, 09:52:07", + "recorded-date": "13-01-2026, 14:03:37", "recorded-content": { "create_function_result": { "Architectures": [ @@ -1383,20 +1383,20 @@ "AWS_LAMBDA_INITIALIZATION_TYPE": "on-demand", "AWS_LAMBDA_LOG_GROUP_NAME": "/aws/lambda/", "AWS_LAMBDA_LOG_STREAM_NAME": "", - "AWS_LAMBDA_RUNTIME_API": "127.0.0.1:9001", + "AWS_LAMBDA_RUNTIME_API": "169.254.100.1:9001", "AWS_REGION": "", "AWS_SECRET_ACCESS_KEY": "", "AWS_SESSION_TOKEN": "", "AWS_XRAY_CONTEXT_MISSING": "LOG_ERROR", - "AWS_XRAY_DAEMON_ADDRESS": "169.254.79.129:2000", + "AWS_XRAY_DAEMON_ADDRESS": "169.254.100.1:2000", "LAMBDA_RUNTIME_DIR": "/var/runtime", "LAMBDA_TASK_ROOT": "/var/task", "LANG": "en_US.UTF-8", - "LD_LIBRARY_PATH": "/lib64:/usr/lib64:/var/runtime:/var/runtime/lib:/var/task:/var/task/lib:/opt/lib", - "PATH": "/usr/local/bin:/usr/bin/:/bin:/opt/bin", + "LD_LIBRARY_PATH": "/var/lang/lib:/lib64:/usr/lib64:/var/runtime:/var/runtime/lib:/var/task:/var/task/lib:/opt/lib", + "PATH": "/var/lang/bin:/usr/local/bin:/usr/bin/:/bin:/opt/bin", "TEST_KEY": "TEST_VAL", "TZ": ":UTC", - "_AWS_XRAY_DAEMON_ADDRESS": "169.254.79.129", + "_AWS_XRAY_DAEMON_ADDRESS": "169.254.100.1", "_AWS_XRAY_DAEMON_PORT": "2000", "_HANDLER": "function.handler", "_X_AMZN_TRACE_ID": "" @@ -1423,20 +1423,20 @@ "AWS_LAMBDA_INITIALIZATION_TYPE": "on-demand", "AWS_LAMBDA_LOG_GROUP_NAME": "/aws/lambda/", "AWS_LAMBDA_LOG_STREAM_NAME": "", - "AWS_LAMBDA_RUNTIME_API": "127.0.0.1:9001", + "AWS_LAMBDA_RUNTIME_API": "169.254.100.1:9001", "AWS_REGION": "", "AWS_SECRET_ACCESS_KEY": "", "AWS_SESSION_TOKEN": "", "AWS_XRAY_CONTEXT_MISSING": "LOG_ERROR", - "AWS_XRAY_DAEMON_ADDRESS": "169.254.79.129:2000", + "AWS_XRAY_DAEMON_ADDRESS": "169.254.100.1:2000", "LAMBDA_RUNTIME_DIR": "/var/runtime", "LAMBDA_TASK_ROOT": "/var/task", "LANG": "en_US.UTF-8", - "LD_LIBRARY_PATH": "/lib64:/usr/lib64:/var/runtime:/var/runtime/lib:/var/task:/var/task/lib:/opt/lib", - "PATH": "/usr/local/bin:/usr/bin/:/bin:/opt/bin", + "LD_LIBRARY_PATH": "/var/lang/lib:/lib64:/usr/lib64:/var/runtime:/var/runtime/lib:/var/task:/var/task/lib:/opt/lib", + "PATH": "/var/lang/bin:/usr/local/bin:/usr/bin/:/bin:/opt/bin", "TEST_KEY": "TEST_VAL", "TZ": ":UTC", - "_AWS_XRAY_DAEMON_ADDRESS": "169.254.79.129", + "_AWS_XRAY_DAEMON_ADDRESS": "169.254.100.1", "_AWS_XRAY_DAEMON_PORT": "2000", "_HANDLER": "function.handler", "_X_AMZN_TRACE_ID": "" @@ -1446,7 +1446,7 @@ } }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_introspection_invoke[python3.9]": { - "recorded-date": "17-06-2025, 09:51:23", + "recorded-date": "12-01-2026, 15:37:38", "recorded-content": { "create_function_result": { "Architectures": [ @@ -1587,7 +1587,7 @@ } }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_introspection_invoke[python3.10]": { - "recorded-date": "17-06-2025, 09:51:20", + "recorded-date": "12-01-2026, 15:37:35", "recorded-content": { "create_function_result": { "Architectures": [ @@ -1728,7 +1728,7 @@ } }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_introspection_invoke[python3.12]": { - "recorded-date": "17-06-2025, 09:51:14", + "recorded-date": "12-01-2026, 15:37:23", "recorded-content": { "create_function_result": { "Architectures": [ @@ -1871,7 +1871,7 @@ } }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_introspection_invoke[nodejs20.x]": { - "recorded-date": "17-06-2025, 09:51:01", + "recorded-date": "12-01-2026, 15:36:56", "recorded-content": { "create_function_result": { "Architectures": [ @@ -2010,7 +2010,7 @@ } }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_introspection_invoke[dotnet6]": { - "recorded-date": "17-06-2025, 09:51:57", + "recorded-date": "12-01-2026, 15:38:44", "recorded-content": { "create_function_result": { "Architectures": [ @@ -2081,12 +2081,12 @@ "AWS_LAMBDA_INITIALIZATION_TYPE": "on-demand", "AWS_LAMBDA_LOG_GROUP_NAME": "/aws/lambda/", "AWS_LAMBDA_LOG_STREAM_NAME": "", - "AWS_LAMBDA_RUNTIME_API": "127.0.0.1:9001", + "AWS_LAMBDA_RUNTIME_API": "169.254.100.1:9001", "AWS_REGION": "", "AWS_SECRET_ACCESS_KEY": "", "AWS_SESSION_TOKEN": "", "AWS_XRAY_CONTEXT_MISSING": "LOG_ERROR", - "AWS_XRAY_DAEMON_ADDRESS": "169.254.79.129:2000", + "AWS_XRAY_DAEMON_ADDRESS": "169.254.100.1:2000", "DOTNET_ROOT": "/var/lang/bin", "LAMBDA_RUNTIME_DIR": "/var/runtime", "LAMBDA_RUNTIME_NAME": "dotnet6", @@ -2098,10 +2098,10 @@ "SHLVL": "0", "TEST_KEY": "TEST_VAL", "TZ": ":UTC", - "_AWS_XRAY_DAEMON_ADDRESS": "169.254.79.129", + "_AWS_XRAY_DAEMON_ADDRESS": "169.254.100.1", "_AWS_XRAY_DAEMON_PORT": "2000", "_HANDLER": "dotnet::Dotnet.Function::FunctionHandler", - "_LAMBDA_TELEMETRY_LOG_FD": "3", + "_LAMBDA_TELEMETRY_LOG_FD": "62", "_X_AMZN_TRACE_ID": "" }, "packages": [] @@ -2127,12 +2127,12 @@ "AWS_LAMBDA_INITIALIZATION_TYPE": "on-demand", "AWS_LAMBDA_LOG_GROUP_NAME": "/aws/lambda/", "AWS_LAMBDA_LOG_STREAM_NAME": "", - "AWS_LAMBDA_RUNTIME_API": "127.0.0.1:9001", + "AWS_LAMBDA_RUNTIME_API": "169.254.100.1:9001", "AWS_REGION": "", "AWS_SECRET_ACCESS_KEY": "", "AWS_SESSION_TOKEN": "", "AWS_XRAY_CONTEXT_MISSING": "LOG_ERROR", - "AWS_XRAY_DAEMON_ADDRESS": "169.254.79.129:2000", + "AWS_XRAY_DAEMON_ADDRESS": "169.254.100.1:2000", "DOTNET_ROOT": "/var/lang/bin", "LAMBDA_RUNTIME_DIR": "/var/runtime", "LAMBDA_RUNTIME_NAME": "dotnet6", @@ -2144,10 +2144,10 @@ "SHLVL": "0", "TEST_KEY": "TEST_VAL", "TZ": ":UTC", - "_AWS_XRAY_DAEMON_ADDRESS": "169.254.79.129", + "_AWS_XRAY_DAEMON_ADDRESS": "169.254.100.1", "_AWS_XRAY_DAEMON_PORT": "2000", "_HANDLER": "dotnet::Dotnet.Function::FunctionHandler", - "_LAMBDA_TELEMETRY_LOG_FD": "3", + "_LAMBDA_TELEMETRY_LOG_FD": "62", "_X_AMZN_TRACE_ID": "" }, "packages": [] @@ -2155,7 +2155,7 @@ } }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_introspection_invoke[nodejs16.x]": { - "recorded-date": "17-06-2025, 09:51:08", + "recorded-date": "12-01-2026, 15:37:08", "recorded-content": { "create_function_result": { "Architectures": [ @@ -2225,12 +2225,12 @@ "AWS_LAMBDA_INITIALIZATION_TYPE": "on-demand", "AWS_LAMBDA_LOG_GROUP_NAME": "/aws/lambda/", "AWS_LAMBDA_LOG_STREAM_NAME": "", - "AWS_LAMBDA_RUNTIME_API": "127.0.0.1:9001", + "AWS_LAMBDA_RUNTIME_API": "169.254.100.1:9001", "AWS_REGION": "", "AWS_SECRET_ACCESS_KEY": "", "AWS_SESSION_TOKEN": "", "AWS_XRAY_CONTEXT_MISSING": "LOG_ERROR", - "AWS_XRAY_DAEMON_ADDRESS": "169.254.79.129:2000", + "AWS_XRAY_DAEMON_ADDRESS": "169.254.100.1:2000", "LAMBDA_RUNTIME_DIR": "/var/runtime", "LAMBDA_TASK_ROOT": "/var/task", "LANG": "en_US.UTF-8", @@ -2242,7 +2242,7 @@ "SHLVL": "0", "TEST_KEY": "TEST_VAL", "TZ": ":UTC", - "_AWS_XRAY_DAEMON_ADDRESS": "169.254.79.129", + "_AWS_XRAY_DAEMON_ADDRESS": "169.254.100.1", "_AWS_XRAY_DAEMON_PORT": "2000", "_HANDLER": "index.handler", "_X_AMZN_TRACE_ID": "" @@ -2269,12 +2269,12 @@ "AWS_LAMBDA_INITIALIZATION_TYPE": "on-demand", "AWS_LAMBDA_LOG_GROUP_NAME": "/aws/lambda/", "AWS_LAMBDA_LOG_STREAM_NAME": "", - "AWS_LAMBDA_RUNTIME_API": "127.0.0.1:9001", + "AWS_LAMBDA_RUNTIME_API": "169.254.100.1:9001", "AWS_REGION": "", "AWS_SECRET_ACCESS_KEY": "", "AWS_SESSION_TOKEN": "", "AWS_XRAY_CONTEXT_MISSING": "LOG_ERROR", - "AWS_XRAY_DAEMON_ADDRESS": "169.254.79.129:2000", + "AWS_XRAY_DAEMON_ADDRESS": "169.254.100.1:2000", "LAMBDA_RUNTIME_DIR": "/var/runtime", "LAMBDA_TASK_ROOT": "/var/task", "LANG": "en_US.UTF-8", @@ -2286,7 +2286,7 @@ "SHLVL": "0", "TEST_KEY": "TEST_VAL", "TZ": ":UTC", - "_AWS_XRAY_DAEMON_ADDRESS": "169.254.79.129", + "_AWS_XRAY_DAEMON_ADDRESS": "169.254.100.1", "_AWS_XRAY_DAEMON_PORT": "2000", "_HANDLER": "index.handler", "_X_AMZN_TRACE_ID": "" @@ -2296,7 +2296,7 @@ } }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_uncaught_exception_invoke[python3.8]": { - "recorded-date": "31-03-2025, 12:22:12", + "recorded-date": "12-01-2026, 15:40:49", "recorded-content": { "create_function_result": { "Architectures": [ @@ -2358,7 +2358,7 @@ } }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_uncaught_exception_invoke[java11]": { - "recorded-date": "31-03-2025, 12:22:27", + "recorded-date": "12-01-2026, 15:41:17", "recorded-content": { "create_function_result": { "Architectures": [ @@ -2420,7 +2420,7 @@ } }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_uncaught_exception_invoke[provided.al2]": { - "recorded-date": "31-03-2025, 12:26:16", + "recorded-date": "13-01-2026, 14:03:02", "recorded-content": { "create_function_result": { "Architectures": [ @@ -2481,7 +2481,7 @@ } }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_uncaught_exception_invoke[java8.al2]": { - "recorded-date": "31-03-2025, 12:22:31", + "recorded-date": "12-01-2026, 15:41:24", "recorded-content": { "create_function_result": { "Architectures": [ @@ -2543,7 +2543,7 @@ } }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_uncaught_exception_invoke[ruby3.2]": { - "recorded-date": "31-03-2025, 12:22:34", + "recorded-date": "12-01-2026, 15:41:30", "recorded-content": { "create_function_result": { "Architectures": [ @@ -2605,7 +2605,7 @@ } }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_uncaught_exception_invoke[python3.11]": { - "recorded-date": "31-03-2025, 12:22:04", + "recorded-date": "12-01-2026, 15:40:35", "recorded-content": { "create_function_result": { "Architectures": [ @@ -2668,7 +2668,7 @@ } }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_uncaught_exception_invoke[java17]": { - "recorded-date": "31-03-2025, 12:22:24", + "recorded-date": "12-01-2026, 15:41:13", "recorded-content": { "create_function_result": { "Architectures": [ @@ -2730,7 +2730,7 @@ } }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_uncaught_exception_invoke[nodejs18.x]": { - "recorded-date": "31-03-2025, 12:21:54", + "recorded-date": "12-01-2026, 15:40:11", "recorded-content": { "create_function_result": { "Architectures": [ @@ -2792,7 +2792,7 @@ } }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_uncaught_exception_invoke[java21]": { - "recorded-date": "31-03-2025, 12:22:21", + "recorded-date": "12-01-2026, 15:41:08", "recorded-content": { "create_function_result": { "Architectures": [ @@ -2854,7 +2854,7 @@ } }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_uncaught_exception_invoke[provided.al2023]": { - "recorded-date": "31-03-2025, 12:26:03", + "recorded-date": "13-01-2026, 14:02:49", "recorded-content": { "create_function_result": { "Architectures": [ @@ -2915,7 +2915,7 @@ } }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_uncaught_exception_invoke[python3.9]": { - "recorded-date": "31-03-2025, 12:22:09", + "recorded-date": "12-01-2026, 15:40:44", "recorded-content": { "create_function_result": { "Architectures": [ @@ -2978,7 +2978,7 @@ } }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_uncaught_exception_invoke[python3.10]": { - "recorded-date": "31-03-2025, 12:22:07", + "recorded-date": "12-01-2026, 15:40:38", "recorded-content": { "create_function_result": { "Architectures": [ @@ -3041,7 +3041,7 @@ } }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_uncaught_exception_invoke[python3.12]": { - "recorded-date": "31-03-2025, 12:22:02", + "recorded-date": "12-01-2026, 15:40:30", "recorded-content": { "create_function_result": { "Architectures": [ @@ -3104,7 +3104,7 @@ } }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_uncaught_exception_invoke[nodejs20.x]": { - "recorded-date": "31-03-2025, 12:21:51", + "recorded-date": "12-01-2026, 15:40:05", "recorded-content": { "create_function_result": { "Architectures": [ @@ -3166,7 +3166,7 @@ } }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_uncaught_exception_invoke[dotnet6]": { - "recorded-date": "31-03-2025, 12:22:49", + "recorded-date": "12-01-2026, 15:41:49", "recorded-content": { "create_function_result": { "Architectures": [ @@ -3228,7 +3228,7 @@ } }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_uncaught_exception_invoke[nodejs16.x]": { - "recorded-date": "31-03-2025, 12:21:57", + "recorded-date": "12-01-2026, 15:40:16", "recorded-content": { "create_function_result": { "Architectures": [ @@ -3290,7 +3290,7 @@ } }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_runtime_wrapper_invoke[python3.8]": { - "recorded-date": "31-03-2025, 12:26:39", + "recorded-date": "12-01-2026, 15:43:02", "recorded-content": { "create_function_result": { "Architectures": [ @@ -3343,7 +3343,7 @@ } }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_runtime_wrapper_invoke[java11]": { - "recorded-date": "31-03-2025, 12:26:57", + "recorded-date": "12-01-2026, 15:42:47", "recorded-content": { "create_function_result": { "Architectures": [ @@ -3396,7 +3396,7 @@ } }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_runtime_wrapper_invoke[java8.al2]": { - "recorded-date": "31-03-2025, 12:27:11", + "recorded-date": "12-01-2026, 15:44:02", "recorded-content": { "create_function_result": { "Architectures": [ @@ -3449,7 +3449,7 @@ } }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_runtime_wrapper_invoke[ruby3.2]": { - "recorded-date": "31-03-2025, 12:26:45", + "recorded-date": "12-01-2026, 15:43:45", "recorded-content": { "create_function_result": { "Architectures": [ @@ -3502,7 +3502,7 @@ } }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_runtime_wrapper_invoke[python3.11]": { - "recorded-date": "31-03-2025, 12:26:19", + "recorded-date": "12-01-2026, 15:44:14", "recorded-content": { "create_function_result": { "Architectures": [ @@ -3555,7 +3555,7 @@ } }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_runtime_wrapper_invoke[java17]": { - "recorded-date": "31-03-2025, 12:26:29", + "recorded-date": "12-01-2026, 15:44:26", "recorded-content": { "create_function_result": { "Architectures": [ @@ -3608,7 +3608,7 @@ } }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_runtime_wrapper_invoke[nodejs18.x]": { - "recorded-date": "31-03-2025, 12:26:41", + "recorded-date": "12-01-2026, 15:43:56", "recorded-content": { "create_function_result": { "Architectures": [ @@ -3661,7 +3661,7 @@ } }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_runtime_wrapper_invoke[java21]": { - "recorded-date": "31-03-2025, 12:27:07", + "recorded-date": "12-01-2026, 15:43:08", "recorded-content": { "create_function_result": { "Architectures": [ @@ -3714,7 +3714,7 @@ } }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_runtime_wrapper_invoke[python3.9]": { - "recorded-date": "31-03-2025, 12:27:16", + "recorded-date": "12-01-2026, 15:43:31", "recorded-content": { "create_function_result": { "Architectures": [ @@ -3767,7 +3767,7 @@ } }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_runtime_wrapper_invoke[python3.10]": { - "recorded-date": "31-03-2025, 12:27:14", + "recorded-date": "12-01-2026, 15:44:20", "recorded-content": { "create_function_result": { "Architectures": [ @@ -3820,7 +3820,7 @@ } }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_runtime_wrapper_invoke[python3.12]": { - "recorded-date": "31-03-2025, 12:27:00", + "recorded-date": "12-01-2026, 15:44:09", "recorded-content": { "create_function_result": { "Architectures": [ @@ -3873,7 +3873,7 @@ } }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_runtime_wrapper_invoke[nodejs20.x]": { - "recorded-date": "31-03-2025, 12:26:50", + "recorded-date": "12-01-2026, 15:42:41", "recorded-content": { "create_function_result": { "Architectures": [ @@ -3926,7 +3926,7 @@ } }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_runtime_wrapper_invoke[dotnet6]": { - "recorded-date": "31-03-2025, 12:26:33", + "recorded-date": "12-01-2026, 15:44:35", "recorded-content": { "create_function_result": { "Architectures": [ @@ -3979,7 +3979,7 @@ } }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_runtime_wrapper_invoke[nodejs16.x]": { - "recorded-date": "31-03-2025, 12:26:25", + "recorded-date": "12-01-2026, 15:43:51", "recorded-content": { "create_function_result": { "Architectures": [ @@ -4032,47 +4032,47 @@ } }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaCallingLocalstack::test_manual_endpoint_injection[nodejs20.x]": { - "recorded-date": "31-03-2025, 17:43:04", + "recorded-date": "12-01-2026, 15:44:41", "recorded-content": {} }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaCallingLocalstack::test_manual_endpoint_injection[nodejs18.x]": { - "recorded-date": "31-03-2025, 17:42:22", + "recorded-date": "12-01-2026, 15:47:01", "recorded-content": {} }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaCallingLocalstack::test_manual_endpoint_injection[nodejs16.x]": { - "recorded-date": "31-03-2025, 17:44:41", + "recorded-date": "12-01-2026, 15:46:54", "recorded-content": {} }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaCallingLocalstack::test_manual_endpoint_injection[python3.8]": { - "recorded-date": "31-03-2025, 17:43:58", + "recorded-date": "12-01-2026, 15:45:37", "recorded-content": {} }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaCallingLocalstack::test_manual_endpoint_injection[python3.9]": { - "recorded-date": "31-03-2025, 17:44:04", + "recorded-date": "12-01-2026, 15:46:31", "recorded-content": {} }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaCallingLocalstack::test_manual_endpoint_injection[python3.10]": { - "recorded-date": "31-03-2025, 17:42:25", + "recorded-date": "12-01-2026, 15:48:10", "recorded-content": {} }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaCallingLocalstack::test_manual_endpoint_injection[python3.11]": { - "recorded-date": "31-03-2025, 17:43:22", + "recorded-date": "12-01-2026, 15:48:04", "recorded-content": {} }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaCallingLocalstack::test_manual_endpoint_injection[python3.12]": { - "recorded-date": "31-03-2025, 17:44:01", + "recorded-date": "12-01-2026, 15:47:58", "recorded-content": {} }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaCallingLocalstack::test_manual_endpoint_injection[ruby3.2]": { - "recorded-date": "31-03-2025, 17:43:19", + "recorded-date": "12-01-2026, 15:46:48", "recorded-content": {} }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_echo_invoke[dotnet8]": { - "recorded-date": "31-03-2025, 12:17:03", + "recorded-date": "12-01-2026, 15:36:17", "recorded-content": {} }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_introspection_invoke[dotnet8]": { - "recorded-date": "17-06-2025, 09:52:01", + "recorded-date": "12-01-2026, 15:38:53", "recorded-content": { "create_function_result": { "Architectures": [ @@ -4219,7 +4219,7 @@ } }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_uncaught_exception_invoke[dotnet8]": { - "recorded-date": "31-03-2025, 12:22:56", + "recorded-date": "12-01-2026, 15:42:01", "recorded-content": { "create_function_result": { "Architectures": [ @@ -4281,7 +4281,7 @@ } }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_runtime_wrapper_invoke[dotnet8]": { - "recorded-date": "31-03-2025, 12:27:03", + "recorded-date": "12-01-2026, 15:44:06", "recorded-content": { "create_function_result": { "Architectures": [ @@ -4334,35 +4334,35 @@ } }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaCallingLocalstack::test_manual_endpoint_injection[java17]": { - "recorded-date": "31-03-2025, 17:42:41", + "recorded-date": "12-01-2026, 15:48:25", "recorded-content": {} }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaCallingLocalstack::test_manual_endpoint_injection[java21]": { - "recorded-date": "31-03-2025, 17:43:01", + "recorded-date": "12-01-2026, 15:45:52", "recorded-content": {} }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaCallingLocalstack::test_manual_endpoint_injection[java11]": { - "recorded-date": "31-03-2025, 17:44:31", + "recorded-date": "12-01-2026, 15:45:23", "recorded-content": {} }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaCallingLocalstack::test_manual_endpoint_injection[java8.al2]": { - "recorded-date": "31-03-2025, 17:43:50", + "recorded-date": "12-01-2026, 15:47:38", "recorded-content": {} }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaCallingLocalstack::test_manual_endpoint_injection[dotnet6]": { - "recorded-date": "31-03-2025, 17:43:15", + "recorded-date": "12-01-2026, 15:59:26", "recorded-content": {} }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaCallingLocalstack::test_manual_endpoint_injection[dotnet8]": { - "recorded-date": "31-03-2025, 17:43:54", + "recorded-date": "12-01-2026, 15:59:12", "recorded-content": {} }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_echo_invoke[ruby3.3]": { - "recorded-date": "31-03-2025, 12:16:02", + "recorded-date": "12-01-2026, 15:35:49", "recorded-content": {} }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_introspection_invoke[ruby3.3]": { - "recorded-date": "17-06-2025, 09:51:50", + "recorded-date": "12-01-2026, 15:38:31", "recorded-content": { "create_function_result": { "Architectures": [ @@ -4447,7 +4447,7 @@ "LD_LIBRARY_PATH": "/var/lang/lib:/var/lang/lib:/lib64:/usr/lib64:/var/runtime:/var/runtime/lib:/var/task:/var/task/lib:/opt/lib", "PATH": "/var/lang/bin:/var/lang/bin:/usr/local/bin:/usr/bin/:/bin:/opt/bin", "PWD": "/var/task", - "RUBYLIB": "/var/runtime/gems/aws_lambda_ric-3.0.0/lib:/var/task:/var/runtime/lib:/opt/ruby/lib", + "RUBYLIB": "/var/runtime/gems/aws_lambda_ric-3.1.3/lib:/var/task:/var/runtime/lib:/opt/ruby/lib", "SHLVL": "0", "TEST_KEY": "TEST_VAL", "TZ": ":UTC", @@ -4493,7 +4493,7 @@ "LD_LIBRARY_PATH": "/var/lang/lib:/var/lang/lib:/lib64:/usr/lib64:/var/runtime:/var/runtime/lib:/var/task:/var/task/lib:/opt/lib", "PATH": "/var/lang/bin:/var/lang/bin:/usr/local/bin:/usr/bin/:/bin:/opt/bin", "PWD": "/var/task", - "RUBYLIB": "/var/runtime/gems/aws_lambda_ric-3.0.0/lib:/var/task:/var/runtime/lib:/opt/ruby/lib", + "RUBYLIB": "/var/runtime/gems/aws_lambda_ric-3.1.3/lib:/var/task:/var/runtime/lib:/opt/ruby/lib", "SHLVL": "0", "TEST_KEY": "TEST_VAL", "TZ": ":UTC", @@ -4507,7 +4507,7 @@ } }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_uncaught_exception_invoke[ruby3.3]": { - "recorded-date": "31-03-2025, 12:22:37", + "recorded-date": "12-01-2026, 15:41:35", "recorded-content": { "create_function_result": { "Architectures": [ @@ -4569,7 +4569,7 @@ } }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_runtime_wrapper_invoke[ruby3.3]": { - "recorded-date": "31-03-2025, 12:26:22", + "recorded-date": "12-01-2026, 15:44:29", "recorded-content": { "create_function_result": { "Architectures": [ @@ -4622,15 +4622,15 @@ } }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaCallingLocalstack::test_manual_endpoint_injection[ruby3.3]": { - "recorded-date": "31-03-2025, 17:44:35", + "recorded-date": "12-01-2026, 15:48:33", "recorded-content": {} }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_echo_invoke[python3.13]": { - "recorded-date": "31-03-2025, 12:13:46", + "recorded-date": "12-01-2026, 15:34:23", "recorded-content": {} }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_introspection_invoke[python3.13]": { - "recorded-date": "17-06-2025, 09:51:11", + "recorded-date": "12-01-2026, 15:37:17", "recorded-content": { "create_function_result": { "Architectures": [ @@ -4773,7 +4773,7 @@ } }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_uncaught_exception_invoke[python3.13]": { - "recorded-date": "31-03-2025, 12:21:59", + "recorded-date": "12-01-2026, 15:40:25", "recorded-content": { "create_function_result": { "Architectures": [ @@ -4836,7 +4836,7 @@ } }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_runtime_wrapper_invoke[python3.13]": { - "recorded-date": "31-03-2025, 12:26:53", + "recorded-date": "12-01-2026, 15:43:37", "recorded-content": { "create_function_result": { "Architectures": [ @@ -4889,15 +4889,15 @@ } }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaCallingLocalstack::test_manual_endpoint_injection[python3.13]": { - "recorded-date": "31-03-2025, 17:44:38", + "recorded-date": "12-01-2026, 15:46:37", "recorded-content": {} }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_echo_invoke[nodejs22.x]": { - "recorded-date": "31-03-2025, 12:12:50", + "recorded-date": "12-01-2026, 15:33:51", "recorded-content": {} }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_introspection_invoke[nodejs22.x]": { - "recorded-date": "17-06-2025, 09:50:58", + "recorded-date": "12-01-2026, 15:36:50", "recorded-content": { "create_function_result": { "Architectures": [ @@ -5036,7 +5036,7 @@ } }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_uncaught_exception_invoke[nodejs22.x]": { - "recorded-date": "31-03-2025, 12:21:49", + "recorded-date": "12-01-2026, 15:40:00", "recorded-content": { "create_function_result": { "Architectures": [ @@ -5098,7 +5098,7 @@ } }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_runtime_wrapper_invoke[nodejs22.x]": { - "recorded-date": "31-03-2025, 12:26:36", + "recorded-date": "12-01-2026, 15:42:56", "recorded-content": { "create_function_result": { "Architectures": [ @@ -5151,15 +5151,15 @@ } }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaCallingLocalstack::test_manual_endpoint_injection[nodejs22.x]": { - "recorded-date": "31-03-2025, 17:42:44", + "recorded-date": "12-01-2026, 15:45:30", "recorded-content": {} }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_echo_invoke[ruby3.4]": { - "recorded-date": "31-03-2025, 12:16:24", + "recorded-date": "12-01-2026, 15:35:55", "recorded-content": {} }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_introspection_invoke[ruby3.4]": { - "recorded-date": "17-06-2025, 09:51:54", + "recorded-date": "12-01-2026, 15:38:34", "recorded-content": { "create_function_result": { "Architectures": [ @@ -5244,7 +5244,7 @@ "LD_LIBRARY_PATH": "/var/lang/lib:/var/lang/lib:/lib64:/usr/lib64:/var/runtime:/var/runtime/lib:/var/task:/var/task/lib:/opt/lib", "PATH": "/var/lang/bin:/var/lang/bin:/usr/local/bin:/usr/bin/:/bin:/opt/bin", "PWD": "/var/task", - "RUBYLIB": "/var/runtime/gems/aws_lambda_ric-3.0.0/lib:/var/task:/var/runtime/lib:/opt/ruby/lib", + "RUBYLIB": "/var/runtime/gems/aws_lambda_ric-3.1.3/lib:/var/task:/var/runtime/lib:/opt/ruby/lib", "SHLVL": "0", "TEST_KEY": "TEST_VAL", "TZ": ":UTC", @@ -5290,7 +5290,7 @@ "LD_LIBRARY_PATH": "/var/lang/lib:/var/lang/lib:/lib64:/usr/lib64:/var/runtime:/var/runtime/lib:/var/task:/var/task/lib:/opt/lib", "PATH": "/var/lang/bin:/var/lang/bin:/usr/local/bin:/usr/bin/:/bin:/opt/bin", "PWD": "/var/task", - "RUBYLIB": "/var/runtime/gems/aws_lambda_ric-3.0.0/lib:/var/task:/var/runtime/lib:/opt/ruby/lib", + "RUBYLIB": "/var/runtime/gems/aws_lambda_ric-3.1.3/lib:/var/task:/var/runtime/lib:/opt/ruby/lib", "SHLVL": "0", "TEST_KEY": "TEST_VAL", "TZ": ":UTC", @@ -5304,7 +5304,7 @@ } }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_uncaught_exception_invoke[ruby3.4]": { - "recorded-date": "31-03-2025, 12:22:40", + "recorded-date": "12-01-2026, 15:41:39", "recorded-content": { "create_function_result": { "Architectures": [ @@ -5366,7 +5366,7 @@ } }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_runtime_wrapper_invoke[ruby3.4]": { - "recorded-date": "31-03-2025, 12:26:47", + "recorded-date": "12-01-2026, 15:42:53", "recorded-content": { "create_function_result": { "Architectures": [ @@ -5419,7 +5419,1062 @@ } }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaCallingLocalstack::test_manual_endpoint_injection[ruby3.4]": { - "recorded-date": "31-03-2025, 17:43:08", + "recorded-date": "12-01-2026, 15:45:27", + "recorded-content": {} + }, + "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_echo_invoke[nodejs24.x]": { + "recorded-date": "12-01-2026, 15:33:43", + "recorded-content": {} + }, + "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_echo_invoke[java25]": { + "recorded-date": "12-01-2026, 15:35:04", + "recorded-content": {} + }, + "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_echo_invoke[python3.14]": { + "recorded-date": "12-01-2026, 15:34:15", + "recorded-content": {} + }, + "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_introspection_invoke[python3.14]": { + "recorded-date": "12-01-2026, 15:37:12", + "recorded-content": { + "create_function_result": { + "Architectures": [ + "x86_64" + ], + "CodeSha256": "", + "CodeSize": "", + "Description": "", + "Environment": { + "Variables": { + "TEST_KEY": "TEST_VAL" + } + }, + "EphemeralStorage": { + "Size": 512 + }, + "FunctionArn": "arn::lambda::111111111111:function:", + "FunctionName": "", + "Handler": "handler.handler", + "LastModified": "date", + "LoggingConfig": { + "LogFormat": "Text", + "LogGroup": "/aws/lambda/" + }, + "MemorySize": 1024, + "PackageType": "Zip", + "RevisionId": "", + "Role": "arn::iam::111111111111:role/", + "Runtime": "python3.14", + "RuntimeVersionConfig": { + "RuntimeVersionArn": "arn::lambda:::runtime:" + }, + "SnapStart": { + "ApplyOn": "None", + "OptimizationStatus": "Off" + }, + "State": "Pending", + "StateReason": "The function is being created.", + "StateReasonCode": "Creating", + "Timeout": 3, + "TracingConfig": { + "Mode": "PassThrough" + }, + "Version": "$LATEST", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 201 + } + }, + "invocation_result_payload": { + "ctx": { + "aws_request_id": "", + "function_name": "", + "function_version": "$LATEST", + "invoked_function_arn": "arn::lambda::111111111111:function:", + "log_group_name": "/aws/lambda/", + "log_stream_name": "", + "memory_limit_in_mb": "1024", + "remaining_time_in_millis": "" + }, + "environment": { + "AWS_ACCESS_KEY_ID": "", + "AWS_DEFAULT_REGION": "", + "AWS_EXECUTION_ENV": "AWS_Lambda_python3.14", + "AWS_LAMBDA_FUNCTION_MEMORY_SIZE": "1024", + "AWS_LAMBDA_FUNCTION_NAME": "", + "AWS_LAMBDA_FUNCTION_VERSION": "$LATEST", + "AWS_LAMBDA_INITIALIZATION_TYPE": "on-demand", + "AWS_LAMBDA_LOG_GROUP_NAME": "/aws/lambda/", + "AWS_LAMBDA_LOG_STREAM_NAME": "", + "AWS_LAMBDA_RUNTIME_API": "169.254.100.1:9001", + "AWS_REGION": "", + "AWS_SECRET_ACCESS_KEY": "", + "AWS_SESSION_TOKEN": "", + "AWS_XRAY_CONTEXT_MISSING": "LOG_ERROR", + "AWS_XRAY_DAEMON_ADDRESS": "169.254.100.1:2000", + "LAMBDA_RUNTIME_DIR": "/var/runtime", + "LAMBDA_TASK_ROOT": "/var/task", + "LANG": "en_US.UTF-8", + "LC_CTYPE": "C.UTF-8", + "LD_LIBRARY_PATH": "/var/lang/lib:/lib64:/usr/lib64:/var/runtime:/var/runtime/lib:/var/task:/var/task/lib:/opt/lib", + "PATH": "/var/lang/bin:/usr/local/bin:/usr/bin/:/bin:/opt/bin", + "PWD": "/var/task", + "PYTHONPATH": "/var/runtime", + "SHLVL": "0", + "TEST_KEY": "TEST_VAL", + "TZ": ":UTC", + "_AWS_XRAY_DAEMON_ADDRESS": "169.254.100.1", + "_AWS_XRAY_DAEMON_PORT": "2000", + "_HANDLER": "handler.handler", + "_X_AMZN_TRACE_ID": "" + }, + "packages": [] + }, + "invocation_result_payload_qualified": { + "ctx": { + "aws_request_id": "", + "function_name": "", + "function_version": "$LATEST", + "invoked_function_arn": "arn::lambda::111111111111:function::$LATEST", + "log_group_name": "/aws/lambda/", + "log_stream_name": "", + "memory_limit_in_mb": "1024", + "remaining_time_in_millis": "" + }, + "environment": { + "AWS_ACCESS_KEY_ID": "", + "AWS_DEFAULT_REGION": "", + "AWS_EXECUTION_ENV": "AWS_Lambda_python3.14", + "AWS_LAMBDA_FUNCTION_MEMORY_SIZE": "1024", + "AWS_LAMBDA_FUNCTION_NAME": "", + "AWS_LAMBDA_FUNCTION_VERSION": "$LATEST", + "AWS_LAMBDA_INITIALIZATION_TYPE": "on-demand", + "AWS_LAMBDA_LOG_GROUP_NAME": "/aws/lambda/", + "AWS_LAMBDA_LOG_STREAM_NAME": "", + "AWS_LAMBDA_RUNTIME_API": "169.254.100.1:9001", + "AWS_REGION": "", + "AWS_SECRET_ACCESS_KEY": "", + "AWS_SESSION_TOKEN": "", + "AWS_XRAY_CONTEXT_MISSING": "LOG_ERROR", + "AWS_XRAY_DAEMON_ADDRESS": "169.254.100.1:2000", + "LAMBDA_RUNTIME_DIR": "/var/runtime", + "LAMBDA_TASK_ROOT": "/var/task", + "LANG": "en_US.UTF-8", + "LC_CTYPE": "C.UTF-8", + "LD_LIBRARY_PATH": "/var/lang/lib:/lib64:/usr/lib64:/var/runtime:/var/runtime/lib:/var/task:/var/task/lib:/opt/lib", + "PATH": "/var/lang/bin:/usr/local/bin:/usr/bin/:/bin:/opt/bin", + "PWD": "/var/task", + "PYTHONPATH": "/var/runtime", + "SHLVL": "0", + "TEST_KEY": "TEST_VAL", + "TZ": ":UTC", + "_AWS_XRAY_DAEMON_ADDRESS": "169.254.100.1", + "_AWS_XRAY_DAEMON_PORT": "2000", + "_HANDLER": "handler.handler", + "_X_AMZN_TRACE_ID": "" + }, + "packages": [] + } + } + }, + "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_introspection_invoke[java25]": { + "recorded-date": "12-01-2026, 15:37:53", + "recorded-content": { + "create_function_result": { + "Architectures": [ + "x86_64" + ], + "CodeSha256": "", + "CodeSize": "", + "Description": "", + "Environment": { + "Variables": { + "TEST_KEY": "TEST_VAL" + } + }, + "EphemeralStorage": { + "Size": 512 + }, + "FunctionArn": "arn::lambda::111111111111:function:", + "FunctionName": "", + "Handler": "echo.Handler", + "LastModified": "date", + "LoggingConfig": { + "LogFormat": "Text", + "LogGroup": "/aws/lambda/" + }, + "MemorySize": 1024, + "PackageType": "Zip", + "RevisionId": "", + "Role": "arn::iam::111111111111:role/", + "Runtime": "java25", + "RuntimeVersionConfig": { + "RuntimeVersionArn": "arn::lambda:::runtime:" + }, + "SnapStart": { + "ApplyOn": "None", + "OptimizationStatus": "Off" + }, + "State": "Pending", + "StateReason": "The function is being created.", + "StateReasonCode": "Creating", + "Timeout": 3, + "TracingConfig": { + "Mode": "PassThrough" + }, + "Version": "$LATEST", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 201 + } + }, + "invocation_result_payload": { + "ctx": { + "aws_request_id": "", + "function_name": "", + "function_version": "$LATEST", + "invoked_function_arn": "arn::lambda::111111111111:function:", + "log_group_name": "/aws/lambda/", + "log_stream_name": "", + "memory_limit_in_mb": "1024", + "remaining_time_in_millis": "" + }, + "environment": { + "AWS_ACCESS_KEY_ID": "", + "AWS_DEFAULT_REGION": "", + "AWS_EXECUTION_ENV": "AWS_Lambda_java25", + "AWS_LAMBDA_FUNCTION_MEMORY_SIZE": "1024", + "AWS_LAMBDA_FUNCTION_NAME": "", + "AWS_LAMBDA_FUNCTION_VERSION": "$LATEST", + "AWS_LAMBDA_INITIALIZATION_TYPE": "on-demand", + "AWS_LAMBDA_LOG_GROUP_NAME": "/aws/lambda/", + "AWS_LAMBDA_LOG_STREAM_NAME": "", + "AWS_LAMBDA_RUNTIME_API": "169.254.100.1:9001", + "AWS_REGION": "", + "AWS_SECRET_ACCESS_KEY": "", + "AWS_SESSION_TOKEN": "", + "AWS_XRAY_CONTEXT_MISSING": "LOG_ERROR", + "AWS_XRAY_DAEMON_ADDRESS": "169.254.100.1:2000", + "LAMBDA_RUNTIME_DIR": "/var/runtime", + "LAMBDA_TASK_ROOT": "/var/task", + "LANG": "en_US.UTF-8", + "LD_LIBRARY_PATH": "/var/lang/lib:/lib64:/usr/lib64:/var/runtime:/var/runtime/lib:/var/task:/var/task/lib:/opt/lib", + "PATH": "/var/lang/bin:/usr/local/bin:/usr/bin/:/bin:/opt/bin", + "TEST_KEY": "TEST_VAL", + "TZ": ":UTC", + "_AWS_XRAY_DAEMON_ADDRESS": "169.254.100.1", + "_AWS_XRAY_DAEMON_PORT": "2000", + "_HANDLER": "echo.Handler", + "_LAMBDA_TELEMETRY_LOG_FD": "62" + }, + "packages": [] + }, + "invocation_result_payload_qualified": { + "ctx": { + "aws_request_id": "", + "function_name": "", + "function_version": "$LATEST", + "invoked_function_arn": "arn::lambda::111111111111:function::$LATEST", + "log_group_name": "/aws/lambda/", + "log_stream_name": "", + "memory_limit_in_mb": "1024", + "remaining_time_in_millis": "" + }, + "environment": { + "AWS_ACCESS_KEY_ID": "", + "AWS_DEFAULT_REGION": "", + "AWS_EXECUTION_ENV": "AWS_Lambda_java25", + "AWS_LAMBDA_FUNCTION_MEMORY_SIZE": "1024", + "AWS_LAMBDA_FUNCTION_NAME": "", + "AWS_LAMBDA_FUNCTION_VERSION": "$LATEST", + "AWS_LAMBDA_INITIALIZATION_TYPE": "on-demand", + "AWS_LAMBDA_LOG_GROUP_NAME": "/aws/lambda/", + "AWS_LAMBDA_LOG_STREAM_NAME": "", + "AWS_LAMBDA_RUNTIME_API": "169.254.100.1:9001", + "AWS_REGION": "", + "AWS_SECRET_ACCESS_KEY": "", + "AWS_SESSION_TOKEN": "", + "AWS_XRAY_CONTEXT_MISSING": "LOG_ERROR", + "AWS_XRAY_DAEMON_ADDRESS": "169.254.100.1:2000", + "LAMBDA_RUNTIME_DIR": "/var/runtime", + "LAMBDA_TASK_ROOT": "/var/task", + "LANG": "en_US.UTF-8", + "LD_LIBRARY_PATH": "/var/lang/lib:/lib64:/usr/lib64:/var/runtime:/var/runtime/lib:/var/task:/var/task/lib:/opt/lib", + "PATH": "/var/lang/bin:/usr/local/bin:/usr/bin/:/bin:/opt/bin", + "TEST_KEY": "TEST_VAL", + "TZ": ":UTC", + "_AWS_XRAY_DAEMON_ADDRESS": "169.254.100.1", + "_AWS_XRAY_DAEMON_PORT": "2000", + "_HANDLER": "echo.Handler", + "_LAMBDA_TELEMETRY_LOG_FD": "62" + }, + "packages": [] + } + } + }, + "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_uncaught_exception_invoke[python3.14]": { + "recorded-date": "12-01-2026, 15:40:19", + "recorded-content": { + "create_function_result": { + "Architectures": [ + "x86_64" + ], + "CodeSha256": "", + "CodeSize": "", + "Description": "", + "EphemeralStorage": { + "Size": 512 + }, + "FunctionArn": "arn::lambda::111111111111:function:", + "FunctionName": "", + "Handler": "handler.handler", + "LastModified": "date", + "LoggingConfig": { + "LogFormat": "Text", + "LogGroup": "/aws/lambda/" + }, + "MemorySize": 1024, + "PackageType": "Zip", + "RevisionId": "", + "Role": "arn::iam::111111111111:role/", + "Runtime": "python3.14", + "RuntimeVersionConfig": { + "RuntimeVersionArn": "arn::lambda:::runtime:" + }, + "SnapStart": { + "ApplyOn": "None", + "OptimizationStatus": "Off" + }, + "State": "Pending", + "StateReason": "The function is being created.", + "StateReasonCode": "Creating", + "Timeout": 3, + "TracingConfig": { + "Mode": "PassThrough" + }, + "Version": "$LATEST", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 201 + } + }, + "error_result": { + "ExecutedVersion": "$LATEST", + "FunctionError": "Unhandled", + "Payload": { + "errorMessage": "Failed: some_error_msg", + "errorType": "Exception", + "requestId": "", + "stackTrace": "" + }, + "StatusCode": 200, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_uncaught_exception_invoke[java25]": { + "recorded-date": "12-01-2026, 15:41:02", + "recorded-content": { + "create_function_result": { + "Architectures": [ + "x86_64" + ], + "CodeSha256": "", + "CodeSize": "", + "Description": "", + "EphemeralStorage": { + "Size": 512 + }, + "FunctionArn": "arn::lambda::111111111111:function:", + "FunctionName": "", + "Handler": "echo.Handler", + "LastModified": "date", + "LoggingConfig": { + "LogFormat": "Text", + "LogGroup": "/aws/lambda/" + }, + "MemorySize": 1024, + "PackageType": "Zip", + "RevisionId": "", + "Role": "arn::iam::111111111111:role/", + "Runtime": "java25", + "RuntimeVersionConfig": { + "RuntimeVersionArn": "arn::lambda:::runtime:" + }, + "SnapStart": { + "ApplyOn": "None", + "OptimizationStatus": "Off" + }, + "State": "Pending", + "StateReason": "The function is being created.", + "StateReasonCode": "Creating", + "Timeout": 3, + "TracingConfig": { + "Mode": "PassThrough" + }, + "Version": "$LATEST", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 201 + } + }, + "error_result": { + "ExecutedVersion": "$LATEST", + "FunctionError": "Unhandled", + "Payload": { + "errorMessage": "Error: some_error_msg", + "errorType": "java.lang.RuntimeException", + "stackTrace": "" + }, + "StatusCode": 200, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_runtime_wrapper_invoke[python3.14]": { + "recorded-date": "12-01-2026, 15:43:25", + "recorded-content": { + "create_function_result": { + "Architectures": [ + "x86_64" + ], + "CodeSha256": "", + "CodeSize": "", + "Description": "", + "Environment": { + "Variables": { + "AWS_LAMBDA_EXEC_WRAPPER": "/var/task/environment_wrapper" + } + }, + "EphemeralStorage": { + "Size": 512 + }, + "FunctionArn": "arn::lambda::111111111111:function:", + "FunctionName": "", + "Handler": "handler.handler", + "LastModified": "date", + "LoggingConfig": { + "LogFormat": "Text", + "LogGroup": "/aws/lambda/" + }, + "MemorySize": 1024, + "PackageType": "Zip", + "RevisionId": "", + "Role": "arn::iam::111111111111:role/", + "Runtime": "python3.14", + "RuntimeVersionConfig": { + "RuntimeVersionArn": "arn::lambda:::runtime:" + }, + "SnapStart": { + "ApplyOn": "None", + "OptimizationStatus": "Off" + }, + "State": "Pending", + "StateReason": "The function is being created.", + "StateReasonCode": "Creating", + "Timeout": 3, + "TracingConfig": { + "Mode": "PassThrough" + }, + "Version": "$LATEST", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 201 + } + } + } + }, + "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_runtime_wrapper_invoke[java25]": { + "recorded-date": "12-01-2026, 15:43:19", + "recorded-content": { + "create_function_result": { + "Architectures": [ + "x86_64" + ], + "CodeSha256": "", + "CodeSize": "", + "Description": "", + "Environment": { + "Variables": { + "AWS_LAMBDA_EXEC_WRAPPER": "/var/task/environment_wrapper" + } + }, + "EphemeralStorage": { + "Size": 512 + }, + "FunctionArn": "arn::lambda::111111111111:function:", + "FunctionName": "", + "Handler": "echo.Handler", + "LastModified": "date", + "LoggingConfig": { + "LogFormat": "Text", + "LogGroup": "/aws/lambda/" + }, + "MemorySize": 1024, + "PackageType": "Zip", + "RevisionId": "", + "Role": "arn::iam::111111111111:role/", + "Runtime": "java25", + "RuntimeVersionConfig": { + "RuntimeVersionArn": "arn::lambda:::runtime:" + }, + "SnapStart": { + "ApplyOn": "None", + "OptimizationStatus": "Off" + }, + "State": "Pending", + "StateReason": "The function is being created.", + "StateReasonCode": "Creating", + "Timeout": 3, + "TracingConfig": { + "Mode": "PassThrough" + }, + "Version": "$LATEST", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 201 + } + } + } + }, + "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaCallingLocalstack::test_manual_endpoint_injection[python3.14]": { + "recorded-date": "12-01-2026, 15:46:25", + "recorded-content": {} + }, + "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaCallingLocalstack::test_manual_endpoint_injection[java25]": { + "recorded-date": "12-01-2026, 15:46:21", + "recorded-content": {} + }, + "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_introspection_invoke[nodejs24.x]": { + "recorded-date": "12-01-2026, 15:36:47", + "recorded-content": { + "create_function_result": { + "Architectures": [ + "x86_64" + ], + "CodeSha256": "", + "CodeSize": "", + "Description": "", + "Environment": { + "Variables": { + "TEST_KEY": "TEST_VAL" + } + }, + "EphemeralStorage": { + "Size": 512 + }, + "FunctionArn": "arn::lambda::111111111111:function:", + "FunctionName": "", + "Handler": "index.handler", + "LastModified": "date", + "LoggingConfig": { + "LogFormat": "Text", + "LogGroup": "/aws/lambda/" + }, + "MemorySize": 1024, + "PackageType": "Zip", + "RevisionId": "", + "Role": "arn::iam::111111111111:role/", + "Runtime": "nodejs24.x", + "RuntimeVersionConfig": { + "RuntimeVersionArn": "arn::lambda:::runtime:" + }, + "SnapStart": { + "ApplyOn": "None", + "OptimizationStatus": "Off" + }, + "State": "Pending", + "StateReason": "The function is being created.", + "StateReasonCode": "Creating", + "Timeout": 3, + "TracingConfig": { + "Mode": "PassThrough" + }, + "Version": "$LATEST", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 201 + } + }, + "invocation_result_payload": { + "ctx": { + "aws_request_id": "", + "function_name": "", + "function_version": "$LATEST", + "invoked_function_arn": "arn::lambda::111111111111:function:", + "log_group_name": "/aws/lambda/", + "log_stream_name": "", + "remaining_time_in_millis": "" + }, + "environment": { + "AWS_ACCESS_KEY_ID": "", + "AWS_DEFAULT_REGION": "", + "AWS_EXECUTION_ENV": "AWS_Lambda_nodejs24.x", + "AWS_LAMBDA_FUNCTION_MEMORY_SIZE": "1024", + "AWS_LAMBDA_FUNCTION_NAME": "", + "AWS_LAMBDA_FUNCTION_VERSION": "$LATEST", + "AWS_LAMBDA_INITIALIZATION_TYPE": "on-demand", + "AWS_LAMBDA_LOG_GROUP_NAME": "/aws/lambda/", + "AWS_LAMBDA_LOG_STREAM_NAME": "", + "AWS_LAMBDA_RUNTIME_API": "169.254.100.1:9001", + "AWS_REGION": "", + "AWS_SECRET_ACCESS_KEY": "", + "AWS_SESSION_TOKEN": "", + "AWS_XRAY_CONTEXT_MISSING": "LOG_ERROR", + "AWS_XRAY_DAEMON_ADDRESS": "169.254.100.1:2000", + "LAMBDA_RUNTIME_DIR": "/var/runtime", + "LAMBDA_TASK_ROOT": "/var/task", + "LANG": "en_US.UTF-8", + "LD_LIBRARY_PATH": "/var/lang/lib:/lib64:/usr/lib64:/var/runtime:/var/runtime/lib:/var/task:/var/task/lib:/opt/lib", + "NODE_PATH": "/opt/nodejs/node24/node_modules:/opt/nodejs/node_modules:/var/runtime/node_modules:/var/runtime:/var/task", + "PATH": "/var/lang/bin:/usr/local/bin:/usr/bin/:/bin:/opt/bin", + "PWD": "/var/task", + "SHLVL": "0", + "TEST_KEY": "TEST_VAL", + "TZ": ":UTC", + "_AWS_XRAY_DAEMON_ADDRESS": "169.254.100.1", + "_AWS_XRAY_DAEMON_PORT": "2000", + "_HANDLER": "index.handler", + "_X_AMZN_TRACE_ID": "" + }, + "packages": [] + }, + "invocation_result_payload_qualified": { + "ctx": { + "aws_request_id": "", + "function_name": "", + "function_version": "$LATEST", + "invoked_function_arn": "arn::lambda::111111111111:function::$LATEST", + "log_group_name": "/aws/lambda/", + "log_stream_name": "", + "remaining_time_in_millis": "" + }, + "environment": { + "AWS_ACCESS_KEY_ID": "", + "AWS_DEFAULT_REGION": "", + "AWS_EXECUTION_ENV": "AWS_Lambda_nodejs24.x", + "AWS_LAMBDA_FUNCTION_MEMORY_SIZE": "1024", + "AWS_LAMBDA_FUNCTION_NAME": "", + "AWS_LAMBDA_FUNCTION_VERSION": "$LATEST", + "AWS_LAMBDA_INITIALIZATION_TYPE": "on-demand", + "AWS_LAMBDA_LOG_GROUP_NAME": "/aws/lambda/", + "AWS_LAMBDA_LOG_STREAM_NAME": "", + "AWS_LAMBDA_RUNTIME_API": "169.254.100.1:9001", + "AWS_REGION": "", + "AWS_SECRET_ACCESS_KEY": "", + "AWS_SESSION_TOKEN": "", + "AWS_XRAY_CONTEXT_MISSING": "LOG_ERROR", + "AWS_XRAY_DAEMON_ADDRESS": "169.254.100.1:2000", + "LAMBDA_RUNTIME_DIR": "/var/runtime", + "LAMBDA_TASK_ROOT": "/var/task", + "LANG": "en_US.UTF-8", + "LD_LIBRARY_PATH": "/var/lang/lib:/lib64:/usr/lib64:/var/runtime:/var/runtime/lib:/var/task:/var/task/lib:/opt/lib", + "NODE_PATH": "/opt/nodejs/node24/node_modules:/opt/nodejs/node_modules:/var/runtime/node_modules:/var/runtime:/var/task", + "PATH": "/var/lang/bin:/usr/local/bin:/usr/bin/:/bin:/opt/bin", + "PWD": "/var/task", + "SHLVL": "0", + "TEST_KEY": "TEST_VAL", + "TZ": ":UTC", + "_AWS_XRAY_DAEMON_ADDRESS": "169.254.100.1", + "_AWS_XRAY_DAEMON_PORT": "2000", + "_HANDLER": "index.handler", + "_X_AMZN_TRACE_ID": "" + }, + "packages": [] + } + } + }, + "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_uncaught_exception_invoke[nodejs24.x]": { + "recorded-date": "12-01-2026, 15:39:54", + "recorded-content": { + "create_function_result": { + "Architectures": [ + "x86_64" + ], + "CodeSha256": "", + "CodeSize": "", + "Description": "", + "EphemeralStorage": { + "Size": 512 + }, + "FunctionArn": "arn::lambda::111111111111:function:", + "FunctionName": "", + "Handler": "index.handler", + "LastModified": "date", + "LoggingConfig": { + "LogFormat": "Text", + "LogGroup": "/aws/lambda/" + }, + "MemorySize": 1024, + "PackageType": "Zip", + "RevisionId": "", + "Role": "arn::iam::111111111111:role/", + "Runtime": "nodejs24.x", + "RuntimeVersionConfig": { + "RuntimeVersionArn": "arn::lambda:::runtime:" + }, + "SnapStart": { + "ApplyOn": "None", + "OptimizationStatus": "Off" + }, + "State": "Pending", + "StateReason": "The function is being created.", + "StateReasonCode": "Creating", + "Timeout": 3, + "TracingConfig": { + "Mode": "PassThrough" + }, + "Version": "$LATEST", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 201 + } + }, + "error_result": { + "ExecutedVersion": "$LATEST", + "FunctionError": "Unhandled", + "Payload": { + "errorType": "Error", + "errorMessage": "Error: some_error_msg", + "trace": "" + }, + "StatusCode": 200, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_runtime_wrapper_invoke[nodejs24.x]": { + "recorded-date": "12-01-2026, 15:43:42", + "recorded-content": { + "create_function_result": { + "Architectures": [ + "x86_64" + ], + "CodeSha256": "", + "CodeSize": "", + "Description": "", + "Environment": { + "Variables": { + "AWS_LAMBDA_EXEC_WRAPPER": "/var/task/environment_wrapper" + } + }, + "EphemeralStorage": { + "Size": 512 + }, + "FunctionArn": "arn::lambda::111111111111:function:", + "FunctionName": "", + "Handler": "index.handler", + "LastModified": "date", + "LoggingConfig": { + "LogFormat": "Text", + "LogGroup": "/aws/lambda/" + }, + "MemorySize": 1024, + "PackageType": "Zip", + "RevisionId": "", + "Role": "arn::iam::111111111111:role/", + "Runtime": "nodejs24.x", + "RuntimeVersionConfig": { + "RuntimeVersionArn": "arn::lambda:::runtime:" + }, + "SnapStart": { + "ApplyOn": "None", + "OptimizationStatus": "Off" + }, + "State": "Pending", + "StateReason": "The function is being created.", + "StateReasonCode": "Creating", + "Timeout": 3, + "TracingConfig": { + "Mode": "PassThrough" + }, + "Version": "$LATEST", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 201 + } + } + } + }, + "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaCallingLocalstack::test_manual_endpoint_injection[nodejs24.x]": { + "recorded-date": "12-01-2026, 15:46:43", + "recorded-content": {} + }, + "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_echo_invoke[dotnet10]": { + "recorded-date": "12-01-2026, 15:36:25", + "recorded-content": {} + }, + "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_introspection_invoke[dotnet10]": { + "recorded-date": "12-01-2026, 15:39:07", + "recorded-content": { + "create_function_result": { + "Architectures": [ + "x86_64" + ], + "CodeSha256": "", + "CodeSize": "", + "Description": "", + "Environment": { + "Variables": { + "TEST_KEY": "TEST_VAL" + } + }, + "EphemeralStorage": { + "Size": 512 + }, + "FunctionArn": "arn::lambda::111111111111:function:", + "FunctionName": "", + "Handler": "dotnet::Dotnet.Function::FunctionHandler", + "LastModified": "date", + "LoggingConfig": { + "LogFormat": "Text", + "LogGroup": "/aws/lambda/" + }, + "MemorySize": 1024, + "PackageType": "Zip", + "RevisionId": "", + "Role": "arn::iam::111111111111:role/", + "Runtime": "dotnet10", + "RuntimeVersionConfig": { + "RuntimeVersionArn": "arn::lambda:::runtime:" + }, + "SnapStart": { + "ApplyOn": "None", + "OptimizationStatus": "Off" + }, + "State": "Pending", + "StateReason": "The function is being created.", + "StateReasonCode": "Creating", + "Timeout": 3, + "TracingConfig": { + "Mode": "PassThrough" + }, + "Version": "$LATEST", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 201 + } + }, + "invocation_result_payload": { + "ctx": { + "aws_request_id": "", + "function_name": "", + "function_version": "$LATEST", + "invoked_function_arn": "arn::lambda::111111111111:function:", + "log_group_name": "/aws/lambda/", + "log_stream_name": "", + "memory_limit_in_mb": "1024", + "remaining_time_in_millis": "" + }, + "environment": { + "AWS_ACCESS_KEY_ID": "", + "AWS_DEFAULT_REGION": "", + "AWS_EXECUTION_ENV": "AWS_Lambda_dotnet10", + "AWS_LAMBDA_FUNCTION_MEMORY_SIZE": "1024", + "AWS_LAMBDA_FUNCTION_NAME": "", + "AWS_LAMBDA_FUNCTION_VERSION": "$LATEST", + "AWS_LAMBDA_INITIALIZATION_TYPE": "on-demand", + "AWS_LAMBDA_LOG_GROUP_NAME": "/aws/lambda/", + "AWS_LAMBDA_LOG_STREAM_NAME": "", + "AWS_LAMBDA_RUNTIME_API": "169.254.100.1:9001", + "AWS_REGION": "", + "AWS_SECRET_ACCESS_KEY": "", + "AWS_SESSION_TOKEN": "", + "AWS_XRAY_CONTEXT_MISSING": "LOG_ERROR", + "AWS_XRAY_DAEMON_ADDRESS": "169.254.100.1:2000", + "DOTNET_ROOT": "/var/lang/bin", + "LAMBDA_RUNTIME_DIR": "/var/runtime", + "LAMBDA_RUNTIME_NAME": "dotnet10", + "LAMBDA_TASK_ROOT": "/var/task", + "LANG": "en_US.UTF-8", + "LD_LIBRARY_PATH": "/var/lang/lib:/lib64:/usr/lib64:/var/runtime:/var/runtime/lib:/var/task:/var/task/lib:/opt/lib", + "PATH": "/var/lang/bin:/usr/local/bin:/usr/bin/:/bin:/opt/bin", + "PWD": "/var/task", + "SHLVL": "0", + "TEST_KEY": "TEST_VAL", + "TZ": ":UTC", + "_AWS_XRAY_DAEMON_ADDRESS": "169.254.100.1", + "_AWS_XRAY_DAEMON_PORT": "2000", + "_HANDLER": "dotnet::Dotnet.Function::FunctionHandler", + "_LAMBDA_TELEMETRY_LOG_FD": "62", + "_X_AMZN_TRACE_ID": "" + }, + "packages": [] + }, + "invocation_result_payload_qualified": { + "ctx": { + "aws_request_id": "", + "function_name": "", + "function_version": "$LATEST", + "invoked_function_arn": "arn::lambda::111111111111:function::$LATEST", + "log_group_name": "/aws/lambda/", + "log_stream_name": "", + "memory_limit_in_mb": "1024", + "remaining_time_in_millis": "" + }, + "environment": { + "AWS_ACCESS_KEY_ID": "", + "AWS_DEFAULT_REGION": "", + "AWS_EXECUTION_ENV": "AWS_Lambda_dotnet10", + "AWS_LAMBDA_FUNCTION_MEMORY_SIZE": "1024", + "AWS_LAMBDA_FUNCTION_NAME": "", + "AWS_LAMBDA_FUNCTION_VERSION": "$LATEST", + "AWS_LAMBDA_INITIALIZATION_TYPE": "on-demand", + "AWS_LAMBDA_LOG_GROUP_NAME": "/aws/lambda/", + "AWS_LAMBDA_LOG_STREAM_NAME": "", + "AWS_LAMBDA_RUNTIME_API": "169.254.100.1:9001", + "AWS_REGION": "", + "AWS_SECRET_ACCESS_KEY": "", + "AWS_SESSION_TOKEN": "", + "AWS_XRAY_CONTEXT_MISSING": "LOG_ERROR", + "AWS_XRAY_DAEMON_ADDRESS": "169.254.100.1:2000", + "DOTNET_ROOT": "/var/lang/bin", + "LAMBDA_RUNTIME_DIR": "/var/runtime", + "LAMBDA_RUNTIME_NAME": "dotnet10", + "LAMBDA_TASK_ROOT": "/var/task", + "LANG": "en_US.UTF-8", + "LD_LIBRARY_PATH": "/var/lang/lib:/lib64:/usr/lib64:/var/runtime:/var/runtime/lib:/var/task:/var/task/lib:/opt/lib", + "PATH": "/var/lang/bin:/usr/local/bin:/usr/bin/:/bin:/opt/bin", + "PWD": "/var/task", + "SHLVL": "0", + "TEST_KEY": "TEST_VAL", + "TZ": ":UTC", + "_AWS_XRAY_DAEMON_ADDRESS": "169.254.100.1", + "_AWS_XRAY_DAEMON_PORT": "2000", + "_HANDLER": "dotnet::Dotnet.Function::FunctionHandler", + "_LAMBDA_TELEMETRY_LOG_FD": "62", + "_X_AMZN_TRACE_ID": "" + }, + "packages": [] + } + } + }, + "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_uncaught_exception_invoke[dotnet10]": { + "recorded-date": "12-01-2026, 15:42:13", + "recorded-content": { + "create_function_result": { + "Architectures": [ + "x86_64" + ], + "CodeSha256": "", + "CodeSize": "", + "Description": "", + "EphemeralStorage": { + "Size": 512 + }, + "FunctionArn": "arn::lambda::111111111111:function:", + "FunctionName": "", + "Handler": "dotnet::Dotnet.Function::FunctionHandler", + "LastModified": "date", + "LoggingConfig": { + "LogFormat": "Text", + "LogGroup": "/aws/lambda/" + }, + "MemorySize": 1024, + "PackageType": "Zip", + "RevisionId": "", + "Role": "arn::iam::111111111111:role/", + "Runtime": "dotnet10", + "RuntimeVersionConfig": { + "RuntimeVersionArn": "arn::lambda:::runtime:" + }, + "SnapStart": { + "ApplyOn": "None", + "OptimizationStatus": "Off" + }, + "State": "Pending", + "StateReason": "The function is being created.", + "StateReasonCode": "Creating", + "Timeout": 3, + "TracingConfig": { + "Mode": "PassThrough" + }, + "Version": "$LATEST", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 201 + } + }, + "error_result": { + "ExecutedVersion": "$LATEST", + "FunctionError": "Unhandled", + "Payload": { + "errorType": "Exception", + "errorMessage": "Error: some_error_msg", + "stackTrace": "" + }, + "StatusCode": 200, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_runtime_wrapper_invoke[dotnet10]": { + "recorded-date": "12-01-2026, 15:43:14", + "recorded-content": { + "create_function_result": { + "Architectures": [ + "x86_64" + ], + "CodeSha256": "", + "CodeSize": "", + "Description": "", + "Environment": { + "Variables": { + "AWS_LAMBDA_EXEC_WRAPPER": "/var/task/environment_wrapper" + } + }, + "EphemeralStorage": { + "Size": 512 + }, + "FunctionArn": "arn::lambda::111111111111:function:", + "FunctionName": "", + "Handler": "dotnet::Dotnet.Function::FunctionHandler", + "LastModified": "date", + "LoggingConfig": { + "LogFormat": "Text", + "LogGroup": "/aws/lambda/" + }, + "MemorySize": 1024, + "PackageType": "Zip", + "RevisionId": "", + "Role": "arn::iam::111111111111:role/", + "Runtime": "dotnet10", + "RuntimeVersionConfig": { + "RuntimeVersionArn": "arn::lambda:::runtime:" + }, + "SnapStart": { + "ApplyOn": "None", + "OptimizationStatus": "Off" + }, + "State": "Pending", + "StateReason": "The function is being created.", + "StateReasonCode": "Creating", + "Timeout": 3, + "TracingConfig": { + "Mode": "PassThrough" + }, + "Version": "$LATEST", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 201 + } + } + } + }, + "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaCallingLocalstack::test_manual_endpoint_injection[dotnet10]": { + "recorded-date": "12-01-2026, 15:58:58", "recorded-content": {} } } diff --git a/tests/aws/services/lambda_/test_lambda_common.validation.json b/tests/aws/services/lambda_/test_lambda_common.validation.json index f17afd9193b9c..f5dd662ec0f68 100644 --- a/tests/aws/services/lambda_/test_lambda_common.validation.json +++ b/tests/aws/services/lambda_/test_lambda_common.validation.json @@ -1,431 +1,1091 @@ { + "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaCallingLocalstack::test_manual_endpoint_injection[dotnet10]": { + "last_validated_date": "2026-01-12T15:58:58+00:00", + "durations_in_seconds": { + "setup": 7.03, + "call": 7.98, + "teardown": 0.71, + "total": 15.72 + } + }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaCallingLocalstack::test_manual_endpoint_injection[dotnet6]": { - "last_validated_date": "2025-03-31T17:43:14+00:00" + "last_validated_date": "2026-01-12T15:59:27+00:00", + "durations_in_seconds": { + "setup": 5.57, + "call": 7.45, + "teardown": 1.99, + "total": 15.01 + } }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaCallingLocalstack::test_manual_endpoint_injection[dotnet8]": { - "last_validated_date": "2025-03-31T17:43:54+00:00" + "last_validated_date": "2026-01-12T15:59:12+00:00", + "durations_in_seconds": { + "setup": 6.03, + "call": 7.24, + "teardown": 0.7, + "total": 13.97 + } }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaCallingLocalstack::test_manual_endpoint_injection[java11]": { - "last_validated_date": "2025-03-31T17:44:30+00:00" + "last_validated_date": "2026-01-12T15:45:23+00:00", + "durations_in_seconds": { + "setup": 18.52, + "call": 22.14, + "teardown": 0.77, + "total": 41.43 + } }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaCallingLocalstack::test_manual_endpoint_injection[java17]": { - "last_validated_date": "2025-03-31T17:42:41+00:00" + "last_validated_date": "2026-01-12T15:48:25+00:00", + "durations_in_seconds": { + "setup": 0.01, + "call": 14.25, + "teardown": 0.78, + "total": 15.04 + } }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaCallingLocalstack::test_manual_endpoint_injection[java21]": { - "last_validated_date": "2025-03-31T17:43:00+00:00" + "last_validated_date": "2026-01-12T15:45:52+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 14.37, + "teardown": 0.8, + "total": 15.17 + } + }, + "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaCallingLocalstack::test_manual_endpoint_injection[java25]": { + "last_validated_date": "2026-01-12T15:46:21+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 14.15, + "teardown": 0.7, + "total": 14.85 + } }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaCallingLocalstack::test_manual_endpoint_injection[java8.al2]": { - "last_validated_date": "2025-03-31T17:43:49+00:00" + "last_validated_date": "2026-01-12T15:47:38+00:00", + "durations_in_seconds": { + "setup": 13.48, + "call": 22.69, + "teardown": 0.72, + "total": 36.89 + } }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaCallingLocalstack::test_manual_endpoint_injection[nodejs16.x]": { - "last_validated_date": "2025-03-31T17:44:41+00:00" + "last_validated_date": "2026-01-12T15:46:54+00:00", + "durations_in_seconds": { + "setup": 0.04, + "call": 5.72, + "teardown": 0.8, + "total": 6.56 + } }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaCallingLocalstack::test_manual_endpoint_injection[nodejs18.x]": { - "last_validated_date": "2025-03-31T17:42:21+00:00" + "last_validated_date": "2026-01-12T15:47:01+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 5.64, + "teardown": 0.71, + "total": 6.35 + } }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaCallingLocalstack::test_manual_endpoint_injection[nodejs20.x]": { - "last_validated_date": "2025-03-31T17:43:04+00:00" + "last_validated_date": "2026-01-12T15:44:41+00:00", + "durations_in_seconds": { + "setup": 0.04, + "call": 5.34, + "teardown": 0.8, + "total": 6.18 + } }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaCallingLocalstack::test_manual_endpoint_injection[nodejs22.x]": { - "last_validated_date": "2025-03-31T17:42:44+00:00" + "last_validated_date": "2026-01-12T15:45:30+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 2.83, + "teardown": 0.68, + "total": 3.51 + } + }, + "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaCallingLocalstack::test_manual_endpoint_injection[nodejs24.x]": { + "last_validated_date": "2026-01-12T15:46:43+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 5.29, + "teardown": 0.82, + "total": 6.11 + } }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaCallingLocalstack::test_manual_endpoint_injection[python3.10]": { - "last_validated_date": "2025-03-31T17:42:24+00:00" + "last_validated_date": "2026-01-12T15:48:10+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 5.44, + "teardown": 0.71, + "total": 6.15 + } }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaCallingLocalstack::test_manual_endpoint_injection[python3.11]": { - "last_validated_date": "2025-03-31T17:43:21+00:00" + "last_validated_date": "2026-01-12T15:48:04+00:00", + "durations_in_seconds": { + "setup": 0.01, + "call": 5.43, + "teardown": 0.7, + "total": 6.14 + } }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaCallingLocalstack::test_manual_endpoint_injection[python3.12]": { - "last_validated_date": "2025-03-31T17:44:00+00:00" + "last_validated_date": "2026-01-12T15:47:58+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 5.55, + "teardown": 0.68, + "total": 6.23 + } }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaCallingLocalstack::test_manual_endpoint_injection[python3.13]": { - "last_validated_date": "2025-03-31T17:44:37+00:00" + "last_validated_date": "2026-01-12T15:46:37+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 5.45, + "teardown": 0.7, + "total": 6.15 + } + }, + "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaCallingLocalstack::test_manual_endpoint_injection[python3.14]": { + "last_validated_date": "2026-01-12T15:46:25+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 3.06, + "teardown": 0.79, + "total": 3.85 + } }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaCallingLocalstack::test_manual_endpoint_injection[python3.8]": { - "last_validated_date": "2025-03-31T17:43:57+00:00" + "last_validated_date": "2026-01-12T15:45:37+00:00", + "durations_in_seconds": { + "setup": 0.04, + "call": 5.51, + "teardown": 0.81, + "total": 6.36 + } }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaCallingLocalstack::test_manual_endpoint_injection[python3.9]": { - "last_validated_date": "2025-03-31T17:44:04+00:00" + "last_validated_date": "2026-01-12T15:46:31+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 5.45, + "teardown": 0.8, + "total": 6.25 + } }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaCallingLocalstack::test_manual_endpoint_injection[ruby3.2]": { - "last_validated_date": "2025-03-31T17:43:18+00:00" + "last_validated_date": "2026-01-12T15:46:48+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 3.97, + "teardown": 0.74, + "total": 4.71 + } }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaCallingLocalstack::test_manual_endpoint_injection[ruby3.3]": { - "last_validated_date": "2025-03-31T17:44:34+00:00" + "last_validated_date": "2026-01-12T15:48:33+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 7.08, + "teardown": 0.71, + "total": 7.79 + } }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaCallingLocalstack::test_manual_endpoint_injection[ruby3.4]": { - "last_validated_date": "2025-03-31T17:43:07+00:00" + "last_validated_date": "2026-01-12T15:45:27+00:00", + "durations_in_seconds": { + "setup": 0.04, + "call": 3.63, + "teardown": 0.72, + "total": 4.39 + } + }, + "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_echo_invoke[dotnet10]": { + "last_validated_date": "2026-01-12T15:36:25+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 7.92, + "teardown": 0.36, + "total": 8.28 + } }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_echo_invoke[dotnet6]": { - "last_validated_date": "2025-03-31T12:16:46+00:00" + "last_validated_date": "2026-01-12T15:36:08+00:00", + "durations_in_seconds": { + "setup": 5.52, + "call": 7.92, + "teardown": 0.43, + "total": 13.87 + } }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_echo_invoke[dotnet8]": { - "last_validated_date": "2025-03-31T12:17:03+00:00" + "last_validated_date": "2026-01-12T15:36:17+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 7.8, + "teardown": 0.38, + "total": 8.18 + } }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_echo_invoke[java11]": { - "last_validated_date": "2025-03-31T12:15:22+00:00" + "last_validated_date": "2026-01-12T15:35:26+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 7.65, + "teardown": 0.34, + "total": 7.99 + } }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_echo_invoke[java17]": { - "last_validated_date": "2025-03-31T12:15:13+00:00" + "last_validated_date": "2026-01-12T15:35:18+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 5.28, + "teardown": 0.39, + "total": 5.67 + } }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_echo_invoke[java21]": { - "last_validated_date": "2025-03-31T12:15:05+00:00" + "last_validated_date": "2026-01-12T15:35:12+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 7.83, + "teardown": 0.36, + "total": 8.19 + } + }, + "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_echo_invoke[java25]": { + "last_validated_date": "2026-01-12T15:35:04+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 5.26, + "teardown": 0.36, + "total": 5.62 + } }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_echo_invoke[java8.al2]": { - "last_validated_date": "2025-03-31T12:15:42+00:00" + "last_validated_date": "2026-01-12T15:35:32+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 5.36, + "teardown": 0.38, + "total": 5.74 + } }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_echo_invoke[nodejs16.x]": { - "last_validated_date": "2025-03-31T12:13:31+00:00" + "last_validated_date": "2026-01-12T15:34:10+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 7.58, + "teardown": 0.38, + "total": 7.96 + } }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_echo_invoke[nodejs18.x]": { - "last_validated_date": "2025-03-31T12:13:11+00:00" + "last_validated_date": "2026-01-12T15:34:02+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 5.05, + "teardown": 0.36, + "total": 5.41 + } }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_echo_invoke[nodejs20.x]": { - "last_validated_date": "2025-03-31T12:12:59+00:00" + "last_validated_date": "2026-01-12T15:33:56+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 5.03, + "teardown": 0.36, + "total": 5.39 + } }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_echo_invoke[nodejs22.x]": { - "last_validated_date": "2025-03-31T12:12:50+00:00" + "last_validated_date": "2026-01-12T15:33:51+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 7.6, + "teardown": 0.36, + "total": 7.96 + } + }, + "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_echo_invoke[nodejs24.x]": { + "last_validated_date": "2026-01-12T15:33:43+00:00", + "durations_in_seconds": { + "setup": 0.04, + "call": 8.99, + "teardown": 0.37, + "total": 9.4 + } }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_echo_invoke[provided.al2023]": { - "last_validated_date": "2025-03-31T12:17:17+00:00" + "last_validated_date": "2026-01-12T16:39:59+00:00", + "durations_in_seconds": { + "setup": 11.96, + "call": 8.92, + "teardown": 0.39, + "total": 21.27 + } }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_echo_invoke[provided.al2]": { - "last_validated_date": "2025-03-31T12:17:30+00:00" + "last_validated_date": "2026-01-12T16:40:10+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 9.86, + "teardown": 1.08, + "total": 10.94 + } }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_echo_invoke[python3.10]": { - "last_validated_date": "2025-03-31T12:14:20+00:00" + "last_validated_date": "2026-01-12T15:34:47+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 7.48, + "teardown": 0.36, + "total": 7.84 + } }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_echo_invoke[python3.11]": { - "last_validated_date": "2025-03-31T12:14:05+00:00" + "last_validated_date": "2026-01-12T15:34:39+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 7.39, + "teardown": 0.39, + "total": 7.78 + } }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_echo_invoke[python3.12]": { - "last_validated_date": "2025-03-31T12:13:57+00:00" + "last_validated_date": "2026-01-12T15:34:31+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 7.64, + "teardown": 0.4, + "total": 8.04 + } }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_echo_invoke[python3.13]": { - "last_validated_date": "2025-03-31T12:13:45+00:00" + "last_validated_date": "2026-01-12T15:34:23+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 7.53, + "teardown": 0.35, + "total": 7.88 + } + }, + "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_echo_invoke[python3.14]": { + "last_validated_date": "2026-01-12T15:34:15+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 5.3, + "teardown": 0.37, + "total": 5.67 + } }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_echo_invoke[python3.8]": { - "last_validated_date": "2025-03-31T12:14:56+00:00" + "last_validated_date": "2026-01-12T15:34:58+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 5.55, + "teardown": 0.46, + "total": 6.01 + } }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_echo_invoke[python3.9]": { - "last_validated_date": "2025-03-31T12:14:39+00:00" + "last_validated_date": "2026-01-12T15:34:52+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 5.06, + "teardown": 0.35, + "total": 5.41 + } }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_echo_invoke[ruby3.2]": { - "last_validated_date": "2025-03-31T12:15:53+00:00" + "last_validated_date": "2026-01-12T15:35:40+00:00", + "durations_in_seconds": { + "setup": 0.04, + "call": 7.75, + "teardown": 0.37, + "total": 8.16 + } }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_echo_invoke[ruby3.3]": { - "last_validated_date": "2025-03-31T12:16:02+00:00" + "last_validated_date": "2026-01-12T15:35:49+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 9.06, + "teardown": 0.36, + "total": 9.42 + } }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_echo_invoke[ruby3.4]": { - "last_validated_date": "2025-03-31T12:16:24+00:00" + "last_validated_date": "2026-01-12T15:35:55+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 5.03, + "teardown": 0.41, + "total": 5.44 + } + }, + "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_introspection_invoke[dotnet10]": { + "last_validated_date": "2026-01-12T15:39:07+00:00", + "durations_in_seconds": { + "setup": 7.8, + "call": 5.39, + "teardown": 0.35, + "total": 13.54 + } }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_introspection_invoke[dotnet6]": { - "last_validated_date": "2025-06-17T09:54:42+00:00", + "last_validated_date": "2026-01-12T15:38:44+00:00", "durations_in_seconds": { - "setup": 0.0, - "call": 2.97, - "teardown": 0.37, - "total": 3.34 + "setup": 5.98, + "call": 3.2, + "teardown": 0.36, + "total": 9.54 } }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_introspection_invoke[dotnet8]": { - "last_validated_date": "2025-06-17T09:54:45+00:00", + "last_validated_date": "2026-01-12T15:38:53+00:00", "durations_in_seconds": { - "setup": 0.0, - "call": 3.14, - "teardown": 0.35, - "total": 3.49 + "setup": 5.89, + "call": 3.19, + "teardown": 0.39, + "total": 9.47 } }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_introspection_invoke[java11]": { - "last_validated_date": "2025-06-17T09:54:24+00:00", + "last_validated_date": "2026-01-12T15:38:12+00:00", "durations_in_seconds": { "setup": 0.0, - "call": 3.48, - "teardown": 0.38, - "total": 3.86 + "call": 5.99, + "teardown": 0.37, + "total": 6.36 } }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_introspection_invoke[java17]": { - "last_validated_date": "2025-06-17T09:54:20+00:00", + "last_validated_date": "2026-01-12T15:38:06+00:00", "durations_in_seconds": { "setup": 0.0, - "call": 3.21, - "teardown": 0.4, - "total": 3.61 + "call": 5.92, + "teardown": 0.38, + "total": 6.3 } }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_introspection_invoke[java21]": { - "last_validated_date": "2025-06-17T09:54:17+00:00", + "last_validated_date": "2026-01-12T15:37:59+00:00", "durations_in_seconds": { "setup": 0.0, - "call": 3.45, - "teardown": 0.36, - "total": 3.81 + "call": 5.86, + "teardown": 0.4, + "total": 6.26 + } + }, + "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_introspection_invoke[java25]": { + "last_validated_date": "2026-01-12T15:37:53+00:00", + "durations_in_seconds": { + "setup": 8.32, + "call": 3.24, + "teardown": 0.39, + "total": 11.95 } }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_introspection_invoke[java8.al2]": { - "last_validated_date": "2025-06-17T09:54:28+00:00", + "last_validated_date": "2026-01-12T15:38:19+00:00", "durations_in_seconds": { "setup": 0.0, - "call": 3.87, - "teardown": 0.37, - "total": 4.24 + "call": 6.3, + "teardown": 0.35, + "total": 6.65 } }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_introspection_invoke[nodejs16.x]": { - "last_validated_date": "2025-06-17T09:53:53+00:00", + "last_validated_date": "2026-01-12T15:37:08+00:00", "durations_in_seconds": { "setup": 0.0, - "call": 2.92, - "teardown": 0.34, - "total": 3.26 + "call": 5.56, + "teardown": 0.39, + "total": 5.95 } }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_introspection_invoke[nodejs18.x]": { - "last_validated_date": "2025-06-17T09:53:50+00:00", + "last_validated_date": "2026-01-12T15:37:02+00:00", "durations_in_seconds": { "setup": 0.0, - "call": 2.9, - "teardown": 0.34, - "total": 3.24 + "call": 5.56, + "teardown": 0.4, + "total": 5.96 } }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_introspection_invoke[nodejs20.x]": { - "last_validated_date": "2025-06-17T09:53:47+00:00", + "last_validated_date": "2026-01-12T15:36:56+00:00", "durations_in_seconds": { - "setup": 0.0, - "call": 2.91, - "teardown": 0.37, - "total": 3.28 + "setup": 0.01, + "call": 5.45, + "teardown": 0.34, + "total": 5.8 } }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_introspection_invoke[nodejs22.x]": { - "last_validated_date": "2025-06-17T09:53:44+00:00", + "last_validated_date": "2026-01-12T15:36:50+00:00", "durations_in_seconds": { - "setup": 11.98, - "call": 3.16, - "teardown": 0.35, - "total": 15.49 + "setup": 0.0, + "call": 2.86, + "teardown": 0.4, + "total": 3.26 + } + }, + "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_introspection_invoke[nodejs24.x]": { + "last_validated_date": "2026-01-12T15:36:47+00:00", + "durations_in_seconds": { + "setup": 0.04, + "call": 2.92, + "teardown": 0.41, + "total": 3.37 } }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_introspection_invoke[provided.al2023]": { - "last_validated_date": "2025-06-17T09:54:51+00:00", + "last_validated_date": "2026-01-13T14:03:37+00:00", "durations_in_seconds": { - "setup": 0.0, - "call": 5.57, - "teardown": 0.4, - "total": 5.97 + "setup": 12.11, + "call": 15.08, + "teardown": 0.33, + "total": 27.52 } }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_introspection_invoke[provided.al2]": { - "last_validated_date": "2025-06-17T09:54:58+00:00", + "last_validated_date": "2026-01-13T14:03:51+00:00", "durations_in_seconds": { "setup": 0.0, - "call": 5.13, - "teardown": 1.61, - "total": 6.74 + "call": 12.86, + "teardown": 1.22, + "total": 14.08 } }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_introspection_invoke[python3.10]": { - "last_validated_date": "2025-06-17T09:54:06+00:00", + "last_validated_date": "2026-01-12T15:37:35+00:00", "durations_in_seconds": { "setup": 0.0, - "call": 2.9, - "teardown": 0.35, - "total": 3.25 + "call": 5.45, + "teardown": 0.4, + "total": 5.85 } }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_introspection_invoke[python3.11]": { - "last_validated_date": "2025-06-17T09:54:03+00:00", + "last_validated_date": "2026-01-12T15:37:29+00:00", "durations_in_seconds": { "setup": 0.0, - "call": 2.67, - "teardown": 0.42, - "total": 3.09 + "call": 5.26, + "teardown": 0.37, + "total": 5.63 } }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_introspection_invoke[python3.12]": { - "last_validated_date": "2025-06-17T09:54:00+00:00", + "last_validated_date": "2026-01-12T15:37:23+00:00", "durations_in_seconds": { "setup": 0.0, - "call": 2.83, - "teardown": 0.38, - "total": 3.21 + "call": 5.38, + "teardown": 0.37, + "total": 5.75 } }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_introspection_invoke[python3.13]": { - "last_validated_date": "2025-06-17T09:53:57+00:00", + "last_validated_date": "2026-01-12T15:37:18+00:00", "durations_in_seconds": { "setup": 0.0, - "call": 2.83, - "teardown": 0.35, - "total": 3.18 + "call": 5.47, + "teardown": 0.37, + "total": 5.84 + } + }, + "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_introspection_invoke[python3.14]": { + "last_validated_date": "2026-01-12T15:37:12+00:00", + "durations_in_seconds": { + "setup": 0.04, + "call": 3.05, + "teardown": 0.36, + "total": 3.45 } }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_introspection_invoke[python3.8]": { - "last_validated_date": "2025-06-17T09:54:13+00:00", + "last_validated_date": "2026-01-12T15:37:41+00:00", "durations_in_seconds": { "setup": 0.0, - "call": 2.97, - "teardown": 0.34, - "total": 3.31 + "call": 2.83, + "teardown": 0.37, + "total": 3.2 } }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_introspection_invoke[python3.9]": { - "last_validated_date": "2025-06-17T09:54:09+00:00", + "last_validated_date": "2026-01-12T15:37:38+00:00", "durations_in_seconds": { "setup": 0.0, - "call": 2.82, - "teardown": 0.36, - "total": 3.18 + "call": 2.74, + "teardown": 0.37, + "total": 3.11 } }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_introspection_invoke[ruby3.2]": { - "last_validated_date": "2025-06-17T09:54:31+00:00", + "last_validated_date": "2026-01-12T15:38:25+00:00", "durations_in_seconds": { - "setup": 0.0, - "call": 2.85, - "teardown": 0.36, - "total": 3.21 + "setup": 0.03, + "call": 5.62, + "teardown": 0.37, + "total": 6.02 } }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_introspection_invoke[ruby3.3]": { - "last_validated_date": "2025-06-17T09:54:35+00:00", + "last_validated_date": "2026-01-12T15:38:31+00:00", "durations_in_seconds": { "setup": 0.0, - "call": 3.02, - "teardown": 0.36, - "total": 3.38 + "call": 5.57, + "teardown": 0.43, + "total": 6.0 } }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_introspection_invoke[ruby3.4]": { - "last_validated_date": "2025-06-17T09:54:38+00:00", + "last_validated_date": "2026-01-12T15:38:34+00:00", "durations_in_seconds": { "setup": 0.0, - "call": 2.97, - "teardown": 0.35, - "total": 3.32 + "call": 2.99, + "teardown": 0.39, + "total": 3.38 + } + }, + "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_runtime_wrapper_invoke[dotnet10]": { + "last_validated_date": "2026-01-12T15:43:14+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 6.05, + "teardown": 0.4, + "total": 6.45 } }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_runtime_wrapper_invoke[dotnet6]": { - "last_validated_date": "2025-03-31T12:26:32+00:00" + "last_validated_date": "2026-01-12T15:44:35+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 5.52, + "teardown": 0.35, + "total": 5.87 + } }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_runtime_wrapper_invoke[dotnet8]": { - "last_validated_date": "2025-03-31T12:27:03+00:00" + "last_validated_date": "2026-01-12T15:44:06+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 2.97, + "teardown": 0.38, + "total": 3.35 + } }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_runtime_wrapper_invoke[java11]": { - "last_validated_date": "2025-03-31T12:26:57+00:00" + "last_validated_date": "2026-01-12T15:42:47+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 5.79, + "teardown": 0.36, + "total": 6.15 + } }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_runtime_wrapper_invoke[java17]": { - "last_validated_date": "2025-03-31T12:26:29+00:00" + "last_validated_date": "2026-01-12T15:44:26+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 5.62, + "teardown": 0.48, + "total": 6.1 + } }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_runtime_wrapper_invoke[java21]": { - "last_validated_date": "2025-03-31T12:27:06+00:00" + "last_validated_date": "2026-01-12T15:43:08+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 5.94, + "teardown": 0.49, + "total": 6.43 + } + }, + "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_runtime_wrapper_invoke[java25]": { + "last_validated_date": "2026-01-12T15:43:19+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 4.53, + "teardown": 0.38, + "total": 4.91 + } }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_runtime_wrapper_invoke[java8.al2]": { - "last_validated_date": "2025-03-31T12:27:10+00:00" + "last_validated_date": "2026-01-12T15:44:02+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 6.22, + "teardown": 0.36, + "total": 6.58 + } }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_runtime_wrapper_invoke[nodejs16.x]": { - "last_validated_date": "2025-03-31T12:26:24+00:00" + "last_validated_date": "2026-01-12T15:43:51+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 5.39, + "teardown": 0.37, + "total": 5.76 + } }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_runtime_wrapper_invoke[nodejs18.x]": { - "last_validated_date": "2025-03-31T12:26:41+00:00" + "last_validated_date": "2026-01-12T15:43:56+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 4.22, + "teardown": 0.35, + "total": 4.57 + } }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_runtime_wrapper_invoke[nodejs20.x]": { - "last_validated_date": "2025-03-31T12:26:50+00:00" + "last_validated_date": "2026-01-12T15:42:41+00:00", + "durations_in_seconds": { + "setup": 0.01, + "call": 5.25, + "teardown": 0.36, + "total": 5.62 + } }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_runtime_wrapper_invoke[nodejs22.x]": { - "last_validated_date": "2025-03-31T12:26:35+00:00" + "last_validated_date": "2026-01-12T15:42:56+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 2.62, + "teardown": 0.35, + "total": 2.97 + } + }, + "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_runtime_wrapper_invoke[nodejs24.x]": { + "last_validated_date": "2026-01-12T15:43:42+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 5.24, + "teardown": 0.35, + "total": 5.59 + } }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_runtime_wrapper_invoke[python3.10]": { - "last_validated_date": "2025-03-31T12:27:13+00:00" + "last_validated_date": "2026-01-12T15:44:20+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 5.11, + "teardown": 0.37, + "total": 5.48 + } }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_runtime_wrapper_invoke[python3.11]": { - "last_validated_date": "2025-03-31T12:26:18+00:00" + "last_validated_date": "2026-01-12T15:44:14+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 5.12, + "teardown": 0.36, + "total": 5.48 + } }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_runtime_wrapper_invoke[python3.12]": { - "last_validated_date": "2025-03-31T12:27:00+00:00" + "last_validated_date": "2026-01-12T15:44:09+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 2.62, + "teardown": 0.36, + "total": 2.98 + } }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_runtime_wrapper_invoke[python3.13]": { - "last_validated_date": "2025-03-31T12:26:53+00:00" + "last_validated_date": "2026-01-12T15:43:37+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 5.4, + "teardown": 0.38, + "total": 5.78 + } + }, + "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_runtime_wrapper_invoke[python3.14]": { + "last_validated_date": "2026-01-12T15:43:25+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 5.35, + "teardown": 0.4, + "total": 5.75 + } }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_runtime_wrapper_invoke[python3.8]": { - "last_validated_date": "2025-03-31T12:26:38+00:00" + "last_validated_date": "2026-01-12T15:43:02+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 5.44, + "teardown": 0.38, + "total": 5.82 + } }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_runtime_wrapper_invoke[python3.9]": { - "last_validated_date": "2025-03-31T12:27:16+00:00" + "last_validated_date": "2026-01-12T15:43:31+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 5.29, + "teardown": 0.36, + "total": 5.65 + } }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_runtime_wrapper_invoke[ruby3.2]": { - "last_validated_date": "2025-03-31T12:26:44+00:00" + "last_validated_date": "2026-01-12T15:43:45+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 2.82, + "teardown": 0.35, + "total": 3.17 + } }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_runtime_wrapper_invoke[ruby3.3]": { - "last_validated_date": "2025-03-31T12:26:21+00:00" + "last_validated_date": "2026-01-12T15:44:29+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 2.91, + "teardown": 0.36, + "total": 3.27 + } }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_runtime_wrapper_invoke[ruby3.4]": { - "last_validated_date": "2025-03-31T12:26:47+00:00" + "last_validated_date": "2026-01-12T15:42:53+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 5.49, + "teardown": 0.36, + "total": 5.85 + } + }, + "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_uncaught_exception_invoke[dotnet10]": { + "last_validated_date": "2026-01-12T15:42:13+00:00", + "durations_in_seconds": { + "setup": 5.87, + "call": 5.9, + "teardown": 0.35, + "total": 12.12 + } }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_uncaught_exception_invoke[dotnet6]": { - "last_validated_date": "2025-03-31T12:22:48+00:00" + "last_validated_date": "2026-01-12T15:41:49+00:00", + "durations_in_seconds": { + "setup": 4.82, + "call": 5.45, + "teardown": 0.35, + "total": 10.62 + } }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_uncaught_exception_invoke[dotnet8]": { - "last_validated_date": "2025-03-31T12:22:56+00:00" + "last_validated_date": "2026-01-12T15:42:01+00:00", + "durations_in_seconds": { + "setup": 5.69, + "call": 5.21, + "teardown": 0.44, + "total": 11.34 + } }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_uncaught_exception_invoke[java11]": { - "last_validated_date": "2025-03-31T12:22:27+00:00" + "last_validated_date": "2026-01-12T15:41:17+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 3.42, + "teardown": 0.36, + "total": 3.78 + } }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_uncaught_exception_invoke[java17]": { - "last_validated_date": "2025-03-31T12:22:23+00:00" + "last_validated_date": "2026-01-12T15:41:13+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 5.44, + "teardown": 0.35, + "total": 5.79 + } }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_uncaught_exception_invoke[java21]": { - "last_validated_date": "2025-03-31T12:22:21+00:00" + "last_validated_date": "2026-01-12T15:41:08+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 5.43, + "teardown": 0.41, + "total": 5.84 + } + }, + "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_uncaught_exception_invoke[java25]": { + "last_validated_date": "2026-01-12T15:41:02+00:00", + "durations_in_seconds": { + "setup": 6.59, + "call": 5.86, + "teardown": 0.34, + "total": 12.79 + } }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_uncaught_exception_invoke[java8.al2]": { - "last_validated_date": "2025-03-31T12:22:31+00:00" + "last_validated_date": "2026-01-12T15:41:24+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 6.09, + "teardown": 0.49, + "total": 6.58 + } }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_uncaught_exception_invoke[nodejs16.x]": { - "last_validated_date": "2025-03-31T12:21:56+00:00" + "last_validated_date": "2026-01-12T15:40:16+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 5.05, + "teardown": 0.38, + "total": 5.43 + } }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_uncaught_exception_invoke[nodejs18.x]": { - "last_validated_date": "2025-03-31T12:21:54+00:00" + "last_validated_date": "2026-01-12T15:40:11+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 5.15, + "teardown": 0.35, + "total": 5.5 + } }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_uncaught_exception_invoke[nodejs20.x]": { - "last_validated_date": "2025-03-31T12:21:51+00:00" + "last_validated_date": "2026-01-12T15:40:05+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 5.06, + "teardown": 0.35, + "total": 5.41 + } }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_uncaught_exception_invoke[nodejs22.x]": { - "last_validated_date": "2025-03-31T12:21:48+00:00" + "last_validated_date": "2026-01-12T15:40:00+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 5.08, + "teardown": 0.37, + "total": 5.45 + } + }, + "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_uncaught_exception_invoke[nodejs24.x]": { + "last_validated_date": "2026-01-12T15:39:54+00:00", + "durations_in_seconds": { + "setup": 0.04, + "call": 5.16, + "teardown": 0.37, + "total": 5.57 + } }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_uncaught_exception_invoke[provided.al2023]": { - "last_validated_date": "2025-03-31T12:26:02+00:00" + "last_validated_date": "2026-01-13T14:02:49+00:00", + "durations_in_seconds": { + "setup": 12.22, + "call": 13.39, + "teardown": 0.37, + "total": 25.98 + } }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_uncaught_exception_invoke[provided.al2]": { - "last_validated_date": "2025-03-31T12:26:16+00:00" + "last_validated_date": "2026-01-13T14:03:03+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 12.72, + "teardown": 1.19, + "total": 13.91 + } }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_uncaught_exception_invoke[python3.10]": { - "last_validated_date": "2025-03-31T12:22:07+00:00" + "last_validated_date": "2026-01-12T15:40:38+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 2.48, + "teardown": 0.49, + "total": 2.97 + } }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_uncaught_exception_invoke[python3.11]": { - "last_validated_date": "2025-03-31T12:22:04+00:00" + "last_validated_date": "2026-01-12T15:40:35+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 4.97, + "teardown": 0.37, + "total": 5.34 + } }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_uncaught_exception_invoke[python3.12]": { - "last_validated_date": "2025-03-31T12:22:02+00:00" + "last_validated_date": "2026-01-12T15:40:30+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 5.03, + "teardown": 0.36, + "total": 5.39 + } }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_uncaught_exception_invoke[python3.13]": { - "last_validated_date": "2025-03-31T12:21:59+00:00" + "last_validated_date": "2026-01-12T15:40:25+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 4.96, + "teardown": 0.37, + "total": 5.33 + } + }, + "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_uncaught_exception_invoke[python3.14]": { + "last_validated_date": "2026-01-12T15:40:19+00:00", + "durations_in_seconds": { + "setup": 0.04, + "call": 2.51, + "teardown": 0.36, + "total": 2.91 + } }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_uncaught_exception_invoke[python3.8]": { - "last_validated_date": "2025-03-31T12:22:12+00:00" + "last_validated_date": "2026-01-12T15:40:49+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 5.05, + "teardown": 0.34, + "total": 5.39 + } }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_uncaught_exception_invoke[python3.9]": { - "last_validated_date": "2025-03-31T12:22:09+00:00" + "last_validated_date": "2026-01-12T15:40:44+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 4.98, + "teardown": 0.36, + "total": 5.34 + } }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_uncaught_exception_invoke[ruby3.2]": { - "last_validated_date": "2025-03-31T12:22:34+00:00" + "last_validated_date": "2026-01-12T15:41:30+00:00", + "durations_in_seconds": { + "setup": 0.03, + "call": 5.32, + "teardown": 0.35, + "total": 5.7 + } }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_uncaught_exception_invoke[ruby3.3]": { - "last_validated_date": "2025-03-31T12:22:37+00:00" + "last_validated_date": "2026-01-12T15:41:35+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 5.48, + "teardown": 0.38, + "total": 5.86 + } }, "tests/aws/services/lambda_/test_lambda_common.py::TestLambdaRuntimesCommon::test_uncaught_exception_invoke[ruby3.4]": { - "last_validated_date": "2025-03-31T12:22:40+00:00" + "last_validated_date": "2026-01-12T15:41:39+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 2.87, + "teardown": 0.39, + "total": 3.26 + } } } diff --git a/tests/aws/services/lambda_/test_lambda_destinations.py b/tests/aws/services/lambda_/test_lambda_destinations.py index f392b7158a77e..cff5c908cc8be 100644 --- a/tests/aws/services/lambda_/test_lambda_destinations.py +++ b/tests/aws/services/lambda_/test_lambda_destinations.py @@ -238,7 +238,9 @@ def receive_message(): receive_message_result = retry(receive_message, retries=120, sleep=3) snapshot.match("receive_message_result", receive_message_result) - @markers.snapshot.skip_snapshot_verify(paths=["$..Body.requestContext.functionArn"]) + @markers.snapshot.skip_snapshot_verify( + paths=["$..Body.requestContext.functionArn", "$..Messages..Attributes.AWSTraceHeader"] + ) @markers.aws.validated @markers.requires_in_process def test_retries( @@ -264,6 +266,7 @@ def test_retries( "MD5OfBody", value_replacement="", reference_replacement=False ) ) + snapshot.add_transformer(snapshot.transform.key_value("AWSTraceHeader")) test_delay_base = 60 if not is_aws_cloud(): @@ -357,7 +360,13 @@ def msg_in_queue(): assert len(set(request_ids)) == 1 # all 3 are equal @markers.snapshot.skip_snapshot_verify( - paths=["$..SenderId", "$..Body.requestContext.functionArn"] + paths=[ + # TODO since LS SQS uses the account id as SenderId, it is the same in both events, while it differs on AWS + "$..SenderId", + # TODO LS SQS uses the account id as SenderId, which in turn get mixed up with the account id in arn + "$..Body.requestContext.functionArn", + "$..Attributes.AWSTraceHeader", + ] ) @markers.aws.validated def test_maxeventage( @@ -384,6 +393,7 @@ def test_maxeventage( "MD5OfBody", value_replacement="", reference_replacement=False ) ) + snapshot.add_transformer(snapshot.transform.key_value("AWSTraceHeader")) queue_name = f"destination-queue-{short_uid()}" fn_name = f"retry-fn-{short_uid()}" diff --git a/tests/aws/services/lambda_/test_lambda_destinations.snapshot.json b/tests/aws/services/lambda_/test_lambda_destinations.snapshot.json index 0775ff1fc5f4b..c7f94c277a0b4 100644 --- a/tests/aws/services/lambda_/test_lambda_destinations.snapshot.json +++ b/tests/aws/services/lambda_/test_lambda_destinations.snapshot.json @@ -62,7 +62,7 @@ } }, "tests/aws/services/lambda_/test_lambda_destinations.py::TestLambdaDestinationSqs::test_assess_lambda_destination_invocation[payload0]": { - "recorded-date": "21-03-2024, 12:26:43", + "recorded-date": "24-11-2025, 23:11:08", "recorded-content": { "put_function_event_invoke_config": { "DestinationConfig": { @@ -125,7 +125,7 @@ } }, "tests/aws/services/lambda_/test_lambda_destinations.py::TestLambdaDestinationSqs::test_assess_lambda_destination_invocation[payload1]": { - "recorded-date": "21-03-2024, 12:26:48", + "recorded-date": "24-11-2025, 23:11:12", "recorded-content": { "put_function_event_invoke_config": { "DestinationConfig": { @@ -186,7 +186,7 @@ } }, "tests/aws/services/lambda_/test_lambda_destinations.py::TestLambdaDLQ::test_dead_letter_queue": { - "recorded-date": "17-06-2024, 11:49:58", + "recorded-date": "24-11-2025, 23:11:05", "recorded-content": { "create_lambda_with_dlq": { "CreateEventSourceMappingResponse": null, @@ -344,22 +344,23 @@ "START RequestId: Version: $LATEST", "Lambda log message - print function", "[INFO]\tdate\t\tLambda log message - logging module", - "LAMBDA_WARNING: Unhandled exception. The most likely cause is an issue in the function code. However, in rare cases, a Lambda runtime update can cause unexpected function behavior. For functions using managed runtimes, runtime updates can be triggered by a function change, or can be applied automatically. To determine if the runtime has been updated, check the runtime version in the INIT_START log entry. If this error correlates with a change in the runtime version, you may be able to mitigate this error by temporarily rolling back to the previous runtime version. For more information, see https://docs.aws.amazon.com/lambda/latest/dg/runtimes-update.html", "[ERROR] Exception: Test exception (this is intentional)", "Traceback (most recent call last):", "\u00a0\u00a0File \"/var/task/handler.py\", line 55, in handler", - "\u00a0\u00a0\u00a0\u00a0raise Exception(\"Test exception (this is intentional)\")END RequestId: " + "\u00a0\u00a0\u00a0\u00a0raise Exception(\"Test exception (this is intentional)\")", + "END RequestId: " ] } } }, "tests/aws/services/lambda_/test_lambda_destinations.py::TestLambdaDestinationSqs::test_retries": { - "recorded-date": "22-03-2023, 18:50:18", + "recorded-date": "25-11-2025, 22:18:25", "recorded-content": { "queue_destination_payload": { "Messages": [ { "Attributes": { + "AWSTraceHeader": "", "ApproximateFirstReceiveTimestamp": "timestamp", "ApproximateReceiveCount": "2", "SenderId": "", @@ -404,10 +405,11 @@ } }, "tests/aws/services/lambda_/test_lambda_destinations.py::TestLambdaDestinationSqs::test_maxeventage": { - "recorded-date": "22-03-2023, 18:52:05", + "recorded-date": "27-11-2025, 02:28:57", "recorded-content": { "no_retry_failure_message": { "Attributes": { + "AWSTraceHeader": "", "ApproximateFirstReceiveTimestamp": "timestamp", "ApproximateReceiveCount": "1", "SenderId": "", @@ -445,6 +447,7 @@ }, "single_retry_failure_message": { "Attributes": { + "AWSTraceHeader": "", "ApproximateFirstReceiveTimestamp": "timestamp", "ApproximateReceiveCount": "1", "SenderId": "", @@ -483,7 +486,7 @@ } }, "tests/aws/services/lambda_/test_lambda_destinations.py::TestLambdaDestinationSqs::test_lambda_destination_default_retries": { - "recorded-date": "21-03-2024, 12:24:09", + "recorded-date": "24-11-2025, 23:14:10", "recorded-content": { "put_function_event_invoke_config": { "DestinationConfig": { @@ -543,7 +546,7 @@ } }, "tests/aws/services/lambda_/test_lambda_destinations.py::TestLambdaDestinationEventbridge::test_invoke_lambda_eventbridge": { - "recorded-date": "19-11-2024, 08:49:47", + "recorded-date": "24-11-2025, 23:21:20", "recorded-content": { "lambda_destination_event_bus_success": { "account": "111111111111", diff --git a/tests/aws/services/lambda_/test_lambda_destinations.validation.json b/tests/aws/services/lambda_/test_lambda_destinations.validation.json index 01ad2cef6650d..d4e405d4aff96 100644 --- a/tests/aws/services/lambda_/test_lambda_destinations.validation.json +++ b/tests/aws/services/lambda_/test_lambda_destinations.validation.json @@ -1,23 +1,65 @@ { "tests/aws/services/lambda_/test_lambda_destinations.py::TestLambdaDLQ::test_dead_letter_queue": { - "last_validated_date": "2024-06-17T11:49:58+00:00" + "last_validated_date": "2025-11-24T23:11:05+00:00", + "durations_in_seconds": { + "setup": 11.02, + "call": 176.18, + "teardown": 0.76, + "total": 187.96 + } }, "tests/aws/services/lambda_/test_lambda_destinations.py::TestLambdaDestinationEventbridge::test_invoke_lambda_eventbridge": { - "last_validated_date": "2024-11-19T08:54:21+00:00" + "last_validated_date": "2025-11-24T23:22:15+00:00", + "durations_in_seconds": { + "setup": 100.97, + "call": 21.64, + "teardown": 55.12, + "total": 177.73 + } }, "tests/aws/services/lambda_/test_lambda_destinations.py::TestLambdaDestinationSqs::test_assess_lambda_destination_invocation[payload0]": { - "last_validated_date": "2024-03-21T12:26:43+00:00" + "last_validated_date": "2025-11-24T23:11:09+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 2.93, + "teardown": 0.6, + "total": 3.53 + } }, "tests/aws/services/lambda_/test_lambda_destinations.py::TestLambdaDestinationSqs::test_assess_lambda_destination_invocation[payload1]": { - "last_validated_date": "2024-03-21T12:26:48+00:00" + "last_validated_date": "2025-11-24T23:11:13+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 3.09, + "teardown": 0.74, + "total": 3.83 + } }, "tests/aws/services/lambda_/test_lambda_destinations.py::TestLambdaDestinationSqs::test_lambda_destination_default_retries": { - "last_validated_date": "2024-03-21T12:24:09+00:00" + "last_validated_date": "2025-11-24T23:14:11+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 177.39, + "teardown": 0.87, + "total": 178.26 + } }, "tests/aws/services/lambda_/test_lambda_destinations.py::TestLambdaDestinationSqs::test_maxeventage": { - "last_validated_date": "2023-03-22T17:52:05+00:00" + "last_validated_date": "2025-11-27T02:28:58+00:00", + "durations_in_seconds": { + "setup": 11.21, + "call": 72.08, + "teardown": 1.45, + "total": 84.74 + } }, "tests/aws/services/lambda_/test_lambda_destinations.py::TestLambdaDestinationSqs::test_retries": { - "last_validated_date": "2023-03-22T17:50:18+00:00" + "last_validated_date": "2025-11-25T22:18:25+00:00", + "durations_in_seconds": { + "setup": 10.92, + "call": 218.7, + "teardown": 1.26, + "total": 230.88 + } } } diff --git a/tests/aws/services/lambda_/test_lambda_developer_tools.py b/tests/aws/services/lambda_/test_lambda_developer_tools.py index 97e2025fd8d08..102daf9d23a2e 100644 --- a/tests/aws/services/lambda_/test_lambda_developer_tools.py +++ b/tests/aws/services/lambda_/test_lambda_developer_tools.py @@ -36,6 +36,7 @@ class TestHotReloading: ids=["nodejs20.x", "python3.12"], ) @markers.aws.only_localstack + @markers.requires_in_process def test_hot_reloading( self, create_lambda_function_aws, @@ -165,6 +166,7 @@ def test_hot_reloading_error_path_not_absolute( Runtime=Runtime.python3_12, ) + @markers.requires_in_process @markers.aws.only_localstack def test_hot_reloading_environment_placeholder( self, create_lambda_function_aws, lambda_su_role, cleanups, aws_client, monkeypatch @@ -198,6 +200,7 @@ def test_hot_reloading_environment_placeholder( class TestDockerFlags: + @markers.requires_in_process @markers.aws.only_localstack def test_additional_docker_flags(self, create_lambda_function, monkeypatch, aws_client): env_value = short_uid() @@ -214,6 +217,7 @@ def test_additional_docker_flags(self, create_lambda_function, monkeypatch, aws_ result_data = json.load(result["Payload"]) assert {"Hello": env_value} == result_data + @markers.requires_in_process @markers.aws.only_localstack def test_lambda_docker_networks(self, lambda_su_role, monkeypatch, aws_client, cleanups): function_name = f"test-network-{short_uid()}" diff --git a/tests/aws/services/lambda_/test_lambda_integration_xray.snapshot.json b/tests/aws/services/lambda_/test_lambda_integration_xray.snapshot.json new file mode 100644 index 0000000000000..c8fb4f96a01fc --- /dev/null +++ b/tests/aws/services/lambda_/test_lambda_integration_xray.snapshot.json @@ -0,0 +1,6 @@ +{ + "tests/aws/services/lambda_/test_lambda_integration_xray.py::test_xray_trace_propagation": { + "recorded-date": "24-11-2025, 23:08:06", + "recorded-content": {} + } +} diff --git a/tests/aws/services/lambda_/test_lambda_integration_xray.validation.json b/tests/aws/services/lambda_/test_lambda_integration_xray.validation.json new file mode 100644 index 0000000000000..a84c2234ed5e1 --- /dev/null +++ b/tests/aws/services/lambda_/test_lambda_integration_xray.validation.json @@ -0,0 +1,29 @@ +{ + "tests/aws/services/lambda_/test_lambda_integration_xray.py::test_traceid_outside_handler[Active]": { + "last_validated_date": "2025-11-24T23:08:01+00:00", + "durations_in_seconds": { + "setup": 10.9, + "call": 3.31, + "teardown": 0.57, + "total": 14.78 + } + }, + "tests/aws/services/lambda_/test_lambda_integration_xray.py::test_traceid_outside_handler[PassThrough]": { + "last_validated_date": "2025-11-24T23:08:04+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 3.02, + "teardown": 0.28, + "total": 3.3 + } + }, + "tests/aws/services/lambda_/test_lambda_integration_xray.py::test_xray_trace_propagation": { + "last_validated_date": "2025-11-24T23:08:07+00:00", + "durations_in_seconds": { + "setup": 0.3, + "call": 1.91, + "teardown": 1.1, + "total": 3.31 + } + } +} diff --git a/tests/aws/services/lambda_/test_lambda_performance.validation.json b/tests/aws/services/lambda_/test_lambda_performance.validation.json index 98ef9fb3d805a..75d4e556934a4 100644 --- a/tests/aws/services/lambda_/test_lambda_performance.validation.json +++ b/tests/aws/services/lambda_/test_lambda_performance.validation.json @@ -1,14 +1,56 @@ { + "tests/aws/services/lambda_/test_lambda_performance.py::test_invoke_warm_start": { + "last_validated_date": "2025-11-24T23:08:24+00:00", + "durations_in_seconds": { + "setup": 10.76, + "call": 23.36, + "teardown": 0.74, + "total": 34.86 + } + }, + "tests/aws/services/lambda_/test_lambda_performance.py::test_lambda_event_invoke": { + "last_validated_date": "2025-11-24T23:42:48+00:00", + "durations_in_seconds": { + "setup": 0.57, + "call": 2017.8, + "teardown": 2.58, + "total": 2020.95 + } + }, "tests/aws/services/lambda_/test_lambda_performance.py::test_number_of_function_versions_async": { - "last_validated_date": "2024-02-08T17:18:44+00:00" + "last_validated_date": "2025-11-24T23:08:48+00:00", + "durations_in_seconds": { + "setup": 0.64, + "call": 10.83, + "teardown": 1.51, + "total": 12.98 + } }, "tests/aws/services/lambda_/test_lambda_performance.py::test_number_of_function_versions_sync": { - "last_validated_date": "2024-02-08T17:01:53+00:00" + "last_validated_date": "2025-11-24T23:08:35+00:00", + "durations_in_seconds": { + "setup": 0.65, + "call": 8.5, + "teardown": 1.5, + "total": 10.65 + } }, "tests/aws/services/lambda_/test_lambda_performance.py::test_number_of_functions_async": { - "last_validated_date": "2024-02-08T17:55:20+00:00" + "last_validated_date": "2025-11-24T23:09:07+00:00", + "durations_in_seconds": { + "setup": 0.59, + "call": 8.85, + "teardown": 2.01, + "total": 11.45 + } }, "tests/aws/services/lambda_/test_lambda_performance.py::test_number_of_functions_sync": { - "last_validated_date": "2024-02-08T17:50:10+00:00" + "last_validated_date": "2025-11-24T23:08:56+00:00", + "durations_in_seconds": { + "setup": 0.57, + "call": 5.6, + "teardown": 1.9, + "total": 8.07 + } } } diff --git a/tests/aws/services/lambda_/test_lambda_runtimes.snapshot.json b/tests/aws/services/lambda_/test_lambda_runtimes.snapshot.json index 314aec2afb7e4..6d02d54a1ba6d 100644 --- a/tests/aws/services/lambda_/test_lambda_runtimes.snapshot.json +++ b/tests/aws/services/lambda_/test_lambda_runtimes.snapshot.json @@ -1,6 +1,6 @@ { "tests/aws/services/lambda_/test_lambda_runtimes.py::TestNodeJSRuntimes::test_invoke_nodejs_es6_lambda[nodejs20.x]": { - "recorded-date": "26-11-2024, 09:42:35", + "recorded-date": "25-11-2025, 02:26:40", "recorded-content": { "creation-result": { "CreateEventSourceMappingResponse": null, @@ -66,7 +66,7 @@ } }, "tests/aws/services/lambda_/test_lambda_runtimes.py::TestNodeJSRuntimes::test_invoke_nodejs_es6_lambda[nodejs18.x]": { - "recorded-date": "26-11-2024, 09:42:45", + "recorded-date": "25-11-2025, 02:26:46", "recorded-content": { "creation-result": { "CreateEventSourceMappingResponse": null, @@ -132,7 +132,7 @@ } }, "tests/aws/services/lambda_/test_lambda_runtimes.py::TestNodeJSRuntimes::test_invoke_nodejs_es6_lambda[nodejs16.x]": { - "recorded-date": "26-11-2024, 09:42:54", + "recorded-date": "25-11-2025, 02:27:00", "recorded-content": { "creation-result": { "CreateEventSourceMappingResponse": null, @@ -198,7 +198,7 @@ } }, "tests/aws/services/lambda_/test_lambda_runtimes.py::TestJavaRuntimes::test_java_runtime_with_lib": { - "recorded-date": "26-11-2024, 09:43:08", + "recorded-date": "25-11-2025, 02:27:16", "recorded-content": { "create-result-jar-with-lib": { "CreateEventSourceMappingResponse": null, @@ -377,7 +377,7 @@ } }, "tests/aws/services/lambda_/test_lambda_runtimes.py::TestJavaRuntimes::test_stream_handler[java21]": { - "recorded-date": "26-11-2024, 09:43:11", + "recorded-date": "25-11-2025, 02:27:23", "recorded-content": { "invoke_result": { "ExecutedVersion": "$LATEST", @@ -391,7 +391,7 @@ } }, "tests/aws/services/lambda_/test_lambda_runtimes.py::TestJavaRuntimes::test_stream_handler[java17]": { - "recorded-date": "26-11-2024, 09:43:14", + "recorded-date": "25-11-2025, 02:27:26", "recorded-content": { "invoke_result": { "ExecutedVersion": "$LATEST", @@ -405,7 +405,7 @@ } }, "tests/aws/services/lambda_/test_lambda_runtimes.py::TestJavaRuntimes::test_stream_handler[java11]": { - "recorded-date": "26-11-2024, 09:43:17", + "recorded-date": "25-11-2025, 02:27:29", "recorded-content": { "invoke_result": { "ExecutedVersion": "$LATEST", @@ -419,7 +419,7 @@ } }, "tests/aws/services/lambda_/test_lambda_runtimes.py::TestJavaRuntimes::test_stream_handler[java8.al2]": { - "recorded-date": "26-11-2024, 09:43:20", + "recorded-date": "25-11-2025, 02:27:33", "recorded-content": { "invoke_result": { "ExecutedVersion": "$LATEST", @@ -433,7 +433,7 @@ } }, "tests/aws/services/lambda_/test_lambda_runtimes.py::TestJavaRuntimes::test_serializable_input_object[java21]": { - "recorded-date": "26-11-2024, 09:43:37", + "recorded-date": "25-11-2025, 02:28:00", "recorded-content": { "create-result": { "CreateEventSourceMappingResponse": null, @@ -500,7 +500,7 @@ } }, "tests/aws/services/lambda_/test_lambda_runtimes.py::TestJavaRuntimes::test_serializable_input_object[java17]": { - "recorded-date": "26-11-2024, 09:43:52", + "recorded-date": "25-11-2025, 02:28:10", "recorded-content": { "create-result": { "CreateEventSourceMappingResponse": null, @@ -567,7 +567,7 @@ } }, "tests/aws/services/lambda_/test_lambda_runtimes.py::TestJavaRuntimes::test_serializable_input_object[java11]": { - "recorded-date": "26-11-2024, 09:44:07", + "recorded-date": "25-11-2025, 02:28:21", "recorded-content": { "create-result": { "CreateEventSourceMappingResponse": null, @@ -634,7 +634,7 @@ } }, "tests/aws/services/lambda_/test_lambda_runtimes.py::TestJavaRuntimes::test_serializable_input_object[java8.al2]": { - "recorded-date": "26-11-2024, 09:44:22", + "recorded-date": "25-11-2025, 02:28:32", "recorded-content": { "create-result": { "CreateEventSourceMappingResponse": null, @@ -701,7 +701,7 @@ } }, "tests/aws/services/lambda_/test_lambda_runtimes.py::TestJavaRuntimes::test_java_custom_handler_method_specification[cloud.localstack.sample.LambdaHandlerWithInterfaceAndCustom::handleRequestCustom-CUSTOM]": { - "recorded-date": "26-11-2024, 09:44:29", + "recorded-date": "25-11-2025, 02:28:38", "recorded-content": { "create-result": { "CreateEventSourceMappingResponse": null, @@ -764,7 +764,7 @@ } }, "tests/aws/services/lambda_/test_lambda_runtimes.py::TestJavaRuntimes::test_java_custom_handler_method_specification[cloud.localstack.sample.LambdaHandlerWithInterfaceAndCustom-INTERFACE]": { - "recorded-date": "26-11-2024, 09:44:39", + "recorded-date": "25-11-2025, 02:28:52", "recorded-content": { "create-result": { "CreateEventSourceMappingResponse": null, @@ -827,7 +827,7 @@ } }, "tests/aws/services/lambda_/test_lambda_runtimes.py::TestJavaRuntimes::test_java_custom_handler_method_specification[cloud.localstack.sample.LambdaHandlerWithInterfaceAndCustom::handleRequest-INTERFACE]": { - "recorded-date": "26-11-2024, 09:44:50", + "recorded-date": "25-11-2025, 02:28:58", "recorded-content": { "create-result": { "CreateEventSourceMappingResponse": null, @@ -890,7 +890,7 @@ } }, "tests/aws/services/lambda_/test_lambda_runtimes.py::TestJavaRuntimes::test_java_lambda_subscribe_sns_topic": { - "recorded-date": "26-11-2024, 09:45:22", + "recorded-date": "25-11-2025, 02:29:22", "recorded-content": { "get-function": { "Code": { @@ -966,47 +966,47 @@ } }, "tests/aws/services/lambda_/test_lambda_runtimes.py::TestPythonRuntimes::test_handler_in_submodule[python3.12]": { - "recorded-date": "26-11-2024, 09:45:27", + "recorded-date": "25-11-2025, 02:29:31", "recorded-content": {} }, "tests/aws/services/lambda_/test_lambda_runtimes.py::TestPythonRuntimes::test_handler_in_submodule[python3.11]": { - "recorded-date": "26-11-2024, 09:45:30", + "recorded-date": "25-11-2025, 02:29:34", "recorded-content": {} }, "tests/aws/services/lambda_/test_lambda_runtimes.py::TestPythonRuntimes::test_handler_in_submodule[python3.10]": { - "recorded-date": "26-11-2024, 09:45:32", + "recorded-date": "25-11-2025, 02:29:37", "recorded-content": {} }, "tests/aws/services/lambda_/test_lambda_runtimes.py::TestPythonRuntimes::test_handler_in_submodule[python3.9]": { - "recorded-date": "26-11-2024, 09:45:35", + "recorded-date": "25-11-2025, 02:29:39", "recorded-content": {} }, "tests/aws/services/lambda_/test_lambda_runtimes.py::TestPythonRuntimes::test_handler_in_submodule[python3.8]": { - "recorded-date": "26-11-2024, 09:45:38", + "recorded-date": "25-11-2025, 02:29:42", "recorded-content": {} }, "tests/aws/services/lambda_/test_lambda_runtimes.py::TestPythonRuntimes::test_python_runtime_correct_versions[python3.12]": { - "recorded-date": "26-11-2024, 09:45:42", + "recorded-date": "25-11-2025, 02:29:50", "recorded-content": {} }, "tests/aws/services/lambda_/test_lambda_runtimes.py::TestPythonRuntimes::test_python_runtime_correct_versions[python3.11]": { - "recorded-date": "26-11-2024, 09:45:45", + "recorded-date": "25-11-2025, 02:29:52", "recorded-content": {} }, "tests/aws/services/lambda_/test_lambda_runtimes.py::TestPythonRuntimes::test_python_runtime_correct_versions[python3.10]": { - "recorded-date": "26-11-2024, 09:45:47", + "recorded-date": "25-11-2025, 02:29:55", "recorded-content": {} }, "tests/aws/services/lambda_/test_lambda_runtimes.py::TestPythonRuntimes::test_python_runtime_correct_versions[python3.9]": { - "recorded-date": "26-11-2024, 09:45:49", + "recorded-date": "25-11-2025, 02:29:58", "recorded-content": {} }, "tests/aws/services/lambda_/test_lambda_runtimes.py::TestPythonRuntimes::test_python_runtime_correct_versions[python3.8]": { - "recorded-date": "26-11-2024, 09:45:51", + "recorded-date": "25-11-2025, 02:30:00", "recorded-content": {} }, "tests/aws/services/lambda_/test_lambda_runtimes.py::TestGoProvidedRuntimes::test_uncaught_exception_invoke[provided.al2023]": { - "recorded-date": "26-11-2024, 09:46:26", + "recorded-date": "25-11-2025, 02:30:08", "recorded-content": { "create_function_result": { "Architectures": [ @@ -1067,7 +1067,7 @@ } }, "tests/aws/services/lambda_/test_lambda_runtimes.py::TestGoProvidedRuntimes::test_uncaught_exception_invoke[provided.al2]": { - "recorded-date": "26-11-2024, 09:46:32", + "recorded-date": "25-11-2025, 02:30:15", "recorded-content": { "create_function_result": { "Architectures": [ @@ -1128,23 +1128,23 @@ } }, "tests/aws/services/lambda_/test_lambda_runtimes.py::TestGoProvidedRuntimes::test_manual_endpoint_injection[provided.al2023]": { - "recorded-date": "26-11-2024, 09:46:59", + "recorded-date": "25-11-2025, 02:30:24", "recorded-content": {} }, "tests/aws/services/lambda_/test_lambda_runtimes.py::TestGoProvidedRuntimes::test_manual_endpoint_injection[provided.al2]": { - "recorded-date": "26-11-2024, 09:47:11", + "recorded-date": "25-11-2025, 02:30:33", "recorded-content": {} }, "tests/aws/services/lambda_/test_lambda_runtimes.py::TestPythonRuntimes::test_handler_in_submodule[python3.13]": { - "recorded-date": "26-11-2024, 09:45:25", + "recorded-date": "25-11-2025, 02:29:28", "recorded-content": {} }, "tests/aws/services/lambda_/test_lambda_runtimes.py::TestPythonRuntimes::test_python_runtime_correct_versions[python3.13]": { - "recorded-date": "26-11-2024, 09:45:40", + "recorded-date": "25-11-2025, 02:29:48", "recorded-content": {} }, "tests/aws/services/lambda_/test_lambda_runtimes.py::TestNodeJSRuntimes::test_invoke_nodejs_es6_lambda[nodejs22.x]": { - "recorded-date": "26-11-2024, 09:42:29", + "recorded-date": "25-11-2025, 02:26:34", "recorded-content": { "creation-result": { "CreateEventSourceMappingResponse": null, @@ -1210,7 +1210,7 @@ } }, "tests/aws/services/lambda_/test_lambda_runtimes.py::TestCloudwatchLogs::test_multi_line_prints": { - "recorded-date": "02-04-2025, 12:35:33", + "recorded-date": "25-11-2025, 02:30:38", "recorded-content": { "log-events": [ { @@ -1271,5 +1271,160 @@ } ] } + }, + "tests/aws/services/lambda_/test_lambda_runtimes.py::TestPythonRuntimes::test_handler_in_submodule[python3.14]": { + "recorded-date": "25-11-2025, 02:29:25", + "recorded-content": {} + }, + "tests/aws/services/lambda_/test_lambda_runtimes.py::TestPythonRuntimes::test_python_runtime_correct_versions[python3.14]": { + "recorded-date": "25-11-2025, 02:29:45", + "recorded-content": {} + }, + "tests/aws/services/lambda_/test_lambda_runtimes.py::TestJavaRuntimes::test_stream_handler[java25]": { + "recorded-date": "25-11-2025, 02:27:19", + "recorded-content": { + "invoke_result": { + "ExecutedVersion": "$LATEST", + "Payload": {}, + "StatusCode": 200, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/lambda_/test_lambda_runtimes.py::TestJavaRuntimes::test_serializable_input_object[java25]": { + "recorded-date": "25-11-2025, 02:27:50", + "recorded-content": { + "create-result": { + "CreateEventSourceMappingResponse": null, + "CreateFunctionResponse": { + "Architectures": [ + "x86_64" + ], + "CodeSha256": "<:1>", + "CodeSize": "", + "Description": "", + "Environment": { + "Variables": {} + }, + "EphemeralStorage": { + "Size": 512 + }, + "FunctionArn": "arn::lambda::111111111111:function:", + "FunctionName": "", + "Handler": "cloud.localstack.awssdkv1.sample.SerializedInputLambdaHandler", + "LastModified": "date", + "LoggingConfig": { + "LogFormat": "Text", + "LogGroup": "/aws/lambda/" + }, + "MemorySize": 128, + "PackageType": "Zip", + "RevisionId": "", + "Role": "arn::iam::111111111111:role/", + "Runtime": "java25", + "RuntimeVersionConfig": { + "RuntimeVersionArn": "arn::lambda:::runtime:" + }, + "SnapStart": { + "ApplyOn": "None", + "OptimizationStatus": "Off" + }, + "State": "Pending", + "StateReason": "The function is being created.", + "StateReasonCode": "Creating", + "Timeout": 30, + "TracingConfig": { + "Mode": "PassThrough" + }, + "Version": "$LATEST", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 201 + } + } + }, + "invoke-result": { + "ExecutedVersion": "$LATEST", + "Payload": { + "bucket": "test_bucket", + "key": "test_key", + "validated": true + }, + "StatusCode": 200, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/lambda_/test_lambda_runtimes.py::TestNodeJSRuntimes::test_invoke_nodejs_es6_lambda[nodejs24.x]": { + "recorded-date": "25-11-2025, 02:26:24", + "recorded-content": { + "creation-result": { + "CreateEventSourceMappingResponse": null, + "CreateFunctionResponse": { + "Architectures": [ + "x86_64" + ], + "CodeSha256": "<:1>", + "CodeSize": "", + "Description": "", + "Environment": { + "Variables": {} + }, + "EphemeralStorage": { + "Size": 512 + }, + "FunctionArn": "arn::lambda::111111111111:function:", + "FunctionName": "", + "Handler": "lambda_handler_es6.handler", + "LastModified": "date", + "LoggingConfig": { + "LogFormat": "Text", + "LogGroup": "/aws/lambda/" + }, + "MemorySize": 128, + "PackageType": "Zip", + "RevisionId": "", + "Role": "arn::iam::111111111111:role/", + "Runtime": "nodejs24.x", + "RuntimeVersionConfig": { + "RuntimeVersionArn": "arn::lambda:::runtime:" + }, + "SnapStart": { + "ApplyOn": "None", + "OptimizationStatus": "Off" + }, + "State": "Pending", + "StateReason": "The function is being created.", + "StateReasonCode": "Creating", + "Timeout": 30, + "TracingConfig": { + "Mode": "PassThrough" + }, + "Version": "$LATEST", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 201 + } + } + }, + "invocation-result": { + "ExecutedVersion": "$LATEST", + "Payload": { + "statusCode": 200, + "body": "\"response from localstack lambda: {\\\"event_type\\\":\\\"test_lambda\\\"}\"" + }, + "StatusCode": 200, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } } } diff --git a/tests/aws/services/lambda_/test_lambda_runtimes.validation.json b/tests/aws/services/lambda_/test_lambda_runtimes.validation.json index 4d29b8b622534..6ce946784dd34 100644 --- a/tests/aws/services/lambda_/test_lambda_runtimes.validation.json +++ b/tests/aws/services/lambda_/test_lambda_runtimes.validation.json @@ -1,104 +1,353 @@ { "tests/aws/services/lambda_/test_lambda_runtimes.py::TestCloudwatchLogs::test_multi_line_prints": { - "last_validated_date": "2025-04-02T12:35:33+00:00" + "last_validated_date": "2025-11-25T02:30:39+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 4.69, + "teardown": 1.55, + "total": 6.24 + } }, "tests/aws/services/lambda_/test_lambda_runtimes.py::TestGoProvidedRuntimes::test_manual_endpoint_injection[provided.al2023]": { - "last_validated_date": "2024-11-26T09:46:59+00:00" + "last_validated_date": "2025-11-25T02:30:24+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 8.99, + "teardown": 0.35, + "total": 9.34 + } }, "tests/aws/services/lambda_/test_lambda_runtimes.py::TestGoProvidedRuntimes::test_manual_endpoint_injection[provided.al2]": { - "last_validated_date": "2024-11-26T09:47:11+00:00" + "last_validated_date": "2025-11-25T02:30:33+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 8.16, + "teardown": 0.42, + "total": 8.58 + } }, "tests/aws/services/lambda_/test_lambda_runtimes.py::TestGoProvidedRuntimes::test_uncaught_exception_invoke[provided.al2023]": { - "last_validated_date": "2024-11-26T09:46:26+00:00" + "last_validated_date": "2025-11-25T02:30:08+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 7.01, + "teardown": 0.21, + "total": 7.22 + } }, "tests/aws/services/lambda_/test_lambda_runtimes.py::TestGoProvidedRuntimes::test_uncaught_exception_invoke[provided.al2]": { - "last_validated_date": "2024-11-26T09:46:31+00:00" + "last_validated_date": "2025-11-25T02:30:15+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 7.33, + "teardown": 0.21, + "total": 7.54 + } }, "tests/aws/services/lambda_/test_lambda_runtimes.py::TestJavaRuntimes::test_java_custom_handler_method_specification[cloud.localstack.sample.LambdaHandlerWithInterfaceAndCustom-INTERFACE]": { - "last_validated_date": "2024-11-26T09:44:39+00:00" + "last_validated_date": "2025-11-25T02:28:52+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 13.14, + "teardown": 0.35, + "total": 13.49 + } }, "tests/aws/services/lambda_/test_lambda_runtimes.py::TestJavaRuntimes::test_java_custom_handler_method_specification[cloud.localstack.sample.LambdaHandlerWithInterfaceAndCustom::handleRequest-INTERFACE]": { - "last_validated_date": "2024-11-26T09:44:50+00:00" + "last_validated_date": "2025-11-25T02:28:58+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 6.08, + "teardown": 0.32, + "total": 6.4 + } }, "tests/aws/services/lambda_/test_lambda_runtimes.py::TestJavaRuntimes::test_java_custom_handler_method_specification[cloud.localstack.sample.LambdaHandlerWithInterfaceAndCustom::handleRequestCustom-CUSTOM]": { - "last_validated_date": "2024-11-26T09:44:29+00:00" + "last_validated_date": "2025-11-25T02:28:38+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 5.9, + "teardown": 0.36, + "total": 6.26 + } }, "tests/aws/services/lambda_/test_lambda_runtimes.py::TestJavaRuntimes::test_java_lambda_subscribe_sns_topic": { - "last_validated_date": "2024-11-26T09:45:21+00:00" + "last_validated_date": "2025-11-25T02:29:22+00:00", + "durations_in_seconds": { + "setup": 0.59, + "call": 22.15, + "teardown": 1.56, + "total": 24.3 + } }, "tests/aws/services/lambda_/test_lambda_runtimes.py::TestJavaRuntimes::test_java_runtime_with_lib": { - "last_validated_date": "2024-11-26T09:43:07+00:00" + "last_validated_date": "2025-11-25T02:27:16+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 14.09, + "teardown": 1.37, + "total": 15.46 + } }, "tests/aws/services/lambda_/test_lambda_runtimes.py::TestJavaRuntimes::test_serializable_input_object[java11]": { - "last_validated_date": "2024-11-26T09:44:07+00:00" + "last_validated_date": "2025-11-25T02:28:21+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 10.04, + "teardown": 0.68, + "total": 10.72 + } }, "tests/aws/services/lambda_/test_lambda_runtimes.py::TestJavaRuntimes::test_serializable_input_object[java17]": { - "last_validated_date": "2024-11-26T09:43:52+00:00" + "last_validated_date": "2025-11-25T02:28:10+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 9.91, + "teardown": 0.63, + "total": 10.54 + } }, "tests/aws/services/lambda_/test_lambda_runtimes.py::TestJavaRuntimes::test_serializable_input_object[java21]": { - "last_validated_date": "2024-11-26T09:43:37+00:00" + "last_validated_date": "2025-11-25T02:28:00+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 9.41, + "teardown": 0.61, + "total": 10.02 + } + }, + "tests/aws/services/lambda_/test_lambda_runtimes.py::TestJavaRuntimes::test_serializable_input_object[java25]": { + "last_validated_date": "2025-11-25T02:27:50+00:00", + "durations_in_seconds": { + "setup": 0.04, + "call": 16.2, + "teardown": 0.66, + "total": 16.9 + } }, "tests/aws/services/lambda_/test_lambda_runtimes.py::TestJavaRuntimes::test_serializable_input_object[java8.al2]": { - "last_validated_date": "2024-11-26T09:44:22+00:00" + "last_validated_date": "2025-11-25T02:28:32+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 10.43, + "teardown": 0.56, + "total": 10.99 + } }, "tests/aws/services/lambda_/test_lambda_runtimes.py::TestJavaRuntimes::test_stream_handler[java11]": { - "last_validated_date": "2024-11-26T09:43:16+00:00" + "last_validated_date": "2025-11-25T02:27:29+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 2.62, + "teardown": 0.59, + "total": 3.21 + } }, "tests/aws/services/lambda_/test_lambda_runtimes.py::TestJavaRuntimes::test_stream_handler[java17]": { - "last_validated_date": "2024-11-26T09:43:13+00:00" + "last_validated_date": "2025-11-25T02:27:26+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 2.57, + "teardown": 0.65, + "total": 3.22 + } }, "tests/aws/services/lambda_/test_lambda_runtimes.py::TestJavaRuntimes::test_stream_handler[java21]": { - "last_validated_date": "2024-11-26T09:43:11+00:00" + "last_validated_date": "2025-11-25T02:27:23+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 2.8, + "teardown": 0.81, + "total": 3.61 + } + }, + "tests/aws/services/lambda_/test_lambda_runtimes.py::TestJavaRuntimes::test_stream_handler[java25]": { + "last_validated_date": "2025-11-25T02:27:19+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 3.07, + "teardown": 0.62, + "total": 3.69 + } }, "tests/aws/services/lambda_/test_lambda_runtimes.py::TestJavaRuntimes::test_stream_handler[java8.al2]": { - "last_validated_date": "2024-11-26T09:43:19+00:00" + "last_validated_date": "2025-11-25T02:27:33+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 2.93, + "teardown": 0.55, + "total": 3.48 + } }, "tests/aws/services/lambda_/test_lambda_runtimes.py::TestNodeJSRuntimes::test_invoke_nodejs_es6_lambda[nodejs16.x]": { - "last_validated_date": "2024-11-26T09:42:54+00:00" + "last_validated_date": "2025-11-25T02:27:00+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 14.06, + "teardown": 0.37, + "total": 14.43 + } }, "tests/aws/services/lambda_/test_lambda_runtimes.py::TestNodeJSRuntimes::test_invoke_nodejs_es6_lambda[nodejs18.x]": { - "last_validated_date": "2024-11-26T09:42:44+00:00" + "last_validated_date": "2025-11-25T02:26:46+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 5.48, + "teardown": 0.36, + "total": 5.84 + } }, "tests/aws/services/lambda_/test_lambda_runtimes.py::TestNodeJSRuntimes::test_invoke_nodejs_es6_lambda[nodejs20.x]": { - "last_validated_date": "2024-11-26T09:42:35+00:00" + "last_validated_date": "2025-11-25T02:26:40+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 5.52, + "teardown": 0.32, + "total": 5.84 + } }, "tests/aws/services/lambda_/test_lambda_runtimes.py::TestNodeJSRuntimes::test_invoke_nodejs_es6_lambda[nodejs22.x]": { - "last_validated_date": "2024-11-26T09:42:29+00:00" + "last_validated_date": "2025-11-25T02:26:34+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 9.62, + "teardown": 0.51, + "total": 10.13 + } + }, + "tests/aws/services/lambda_/test_lambda_runtimes.py::TestNodeJSRuntimes::test_invoke_nodejs_es6_lambda[nodejs24.x]": { + "last_validated_date": "2025-11-25T02:26:24+00:00", + "durations_in_seconds": { + "setup": 11.2, + "call": 10.48, + "teardown": 0.4, + "total": 22.08 + } }, "tests/aws/services/lambda_/test_lambda_runtimes.py::TestPythonRuntimes::test_handler_in_submodule[python3.10]": { - "last_validated_date": "2024-11-26T09:45:32+00:00" + "last_validated_date": "2025-11-25T02:29:37+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 2.42, + "teardown": 0.49, + "total": 2.91 + } }, "tests/aws/services/lambda_/test_lambda_runtimes.py::TestPythonRuntimes::test_handler_in_submodule[python3.11]": { - "last_validated_date": "2024-11-26T09:45:29+00:00" + "last_validated_date": "2025-11-25T02:29:34+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 2.15, + "teardown": 0.7, + "total": 2.85 + } }, "tests/aws/services/lambda_/test_lambda_runtimes.py::TestPythonRuntimes::test_handler_in_submodule[python3.12]": { - "last_validated_date": "2024-11-26T09:45:27+00:00" + "last_validated_date": "2025-11-25T02:29:31+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 2.22, + "teardown": 0.34, + "total": 2.56 + } }, "tests/aws/services/lambda_/test_lambda_runtimes.py::TestPythonRuntimes::test_handler_in_submodule[python3.13]": { - "last_validated_date": "2024-11-26T09:45:24+00:00" + "last_validated_date": "2025-11-25T02:29:28+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 2.39, + "teardown": 0.83, + "total": 3.22 + } + }, + "tests/aws/services/lambda_/test_lambda_runtimes.py::TestPythonRuntimes::test_handler_in_submodule[python3.14]": { + "last_validated_date": "2025-11-25T02:29:25+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 2.33, + "teardown": 0.29, + "total": 2.62 + } }, "tests/aws/services/lambda_/test_lambda_runtimes.py::TestPythonRuntimes::test_handler_in_submodule[python3.8]": { - "last_validated_date": "2024-11-26T09:45:37+00:00" + "last_validated_date": "2025-11-25T02:29:42+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 2.29, + "teardown": 0.6, + "total": 2.89 + } }, "tests/aws/services/lambda_/test_lambda_runtimes.py::TestPythonRuntimes::test_handler_in_submodule[python3.9]": { - "last_validated_date": "2024-11-26T09:45:35+00:00" + "last_validated_date": "2025-11-25T02:29:39+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 2.26, + "teardown": 0.61, + "total": 2.87 + } }, "tests/aws/services/lambda_/test_lambda_runtimes.py::TestPythonRuntimes::test_python_runtime_correct_versions[python3.10]": { - "last_validated_date": "2024-11-26T09:45:47+00:00" + "last_validated_date": "2025-11-25T02:29:55+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 1.95, + "teardown": 0.55, + "total": 2.5 + } }, "tests/aws/services/lambda_/test_lambda_runtimes.py::TestPythonRuntimes::test_python_runtime_correct_versions[python3.11]": { - "last_validated_date": "2024-11-26T09:45:44+00:00" + "last_validated_date": "2025-11-25T02:29:52+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 2.01, + "teardown": 0.28, + "total": 2.29 + } }, "tests/aws/services/lambda_/test_lambda_runtimes.py::TestPythonRuntimes::test_python_runtime_correct_versions[python3.12]": { - "last_validated_date": "2024-11-26T09:45:42+00:00" + "last_validated_date": "2025-11-25T02:29:50+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 1.93, + "teardown": 0.52, + "total": 2.45 + } }, "tests/aws/services/lambda_/test_lambda_runtimes.py::TestPythonRuntimes::test_python_runtime_correct_versions[python3.13]": { - "last_validated_date": "2024-11-26T09:45:40+00:00" + "last_validated_date": "2025-11-25T02:29:48+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 2.04, + "teardown": 0.61, + "total": 2.65 + } + }, + "tests/aws/services/lambda_/test_lambda_runtimes.py::TestPythonRuntimes::test_python_runtime_correct_versions[python3.14]": { + "last_validated_date": "2025-11-25T02:29:45+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 2.11, + "teardown": 0.57, + "total": 2.68 + } }, "tests/aws/services/lambda_/test_lambda_runtimes.py::TestPythonRuntimes::test_python_runtime_correct_versions[python3.8]": { - "last_validated_date": "2024-11-26T09:45:51+00:00" + "last_validated_date": "2025-11-25T02:30:00+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 2.21, + "teardown": 0.57, + "total": 2.78 + } }, "tests/aws/services/lambda_/test_lambda_runtimes.py::TestPythonRuntimes::test_python_runtime_correct_versions[python3.9]": { - "last_validated_date": "2024-11-26T09:45:49+00:00" + "last_validated_date": "2025-11-25T02:29:58+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 1.99, + "teardown": 0.55, + "total": 2.54 + } } } diff --git a/tests/aws/services/lambda_/test_lambda_unzip_crash.py b/tests/aws/services/lambda_/test_lambda_unzip_crash.py new file mode 100644 index 0000000000000..cab2074f7a8a6 --- /dev/null +++ b/tests/aws/services/lambda_/test_lambda_unzip_crash.py @@ -0,0 +1,76 @@ +import tempfile +from pathlib import Path +from unittest.mock import patch + +import pytest + +from localstack.services.lambda_.invocation.lambda_models import S3Code +from localstack.testing.pytest import markers +from localstack.utils.strings import short_uid + + +class TestLambdaUnzipCrash: + @markers.aws.only_localstack + def test_unzip_crash_leaves_no_corrupted_files( + self, aws_client, tmp_path, monkeypatch, account_id + ): + """ + Integration test to test fix for issue https://github.com/localstack/localstack/issues/13555 + Simulates what happens when we crash during Lambda code unzipping. + Makes sure no corrupted file is left. + """ + + unzip_call_count = 0 + function_id = f"test-unzip-crash-{short_uid()}" + + def crashing_unzip(zip_file, target_dir): + """Unzip that crashes after writing partial content""" + nonlocal unzip_call_count + unzip_call_count += 1 + + target_path = Path(target_dir) + target_path.mkdir(parents=True, exist_ok=True) + (target_path / "handler.py").write_text("# CORRUPTED - partial unpack\n") + + raise RuntimeError("Simulated crash during unzip") + + s3_code = S3Code( + id=function_id, + account_id=account_id, + s3_bucket="test-bucket", + s3_key="test.zip", + s3_object_version=None, + code_sha256="abc123", + code_size=1024, + ) + + def mock_download(self, target_file): + target_file.write(b"fake-zip") + target_file.flush() + + # Patch unzip and download + with patch( + "localstack.services.lambda_.invocation.lambda_models.unzip", side_effect=crashing_unzip + ): + with patch.object(S3Code, "_download_archive_to_file", mock_download): + # This will trigger the unzip operation (which will crash) + try: + s3_code.prepare_for_execution() + except RuntimeError: + pass + + # Check what's on disk + target_code_dir = ( + Path(tempfile.gettempdir()) / "lambda" / "test-bucket" / function_id / "code" + ) + + if target_code_dir.exists(): + handler_file = target_code_dir / "handler.py" + if handler_file.exists(): + content = handler_file.read_text() + if "CORRUPTED" in content: + pytest.fail( + f"Crash during unzip left corrupted files on disk at {target_code_dir}!" + ) + + assert unzip_call_count >= 1, "Unzip should have been called" diff --git a/tests/aws/services/logs/test_logs.py b/tests/aws/services/logs/test_logs.py deleted file mode 100644 index bf3abb3a5294f..0000000000000 --- a/tests/aws/services/logs/test_logs.py +++ /dev/null @@ -1,658 +0,0 @@ -import base64 -import gzip -import json -import re - -import pytest -from localstack_snapshot.pytest.snapshot import is_aws -from localstack_snapshot.snapshots.transformer import KeyValueBasedTransformer - -from localstack.aws.api.lambda_ import Runtime -from localstack.constants import APPLICATION_AMZ_JSON_1_1 -from localstack.testing.config import TEST_AWS_REGION_NAME -from localstack.testing.pytest import markers -from localstack.utils import testutil -from localstack.utils.aws import arns -from localstack.utils.aws.arns import get_partition -from localstack.utils.common import now_utc, poll_condition, retry, short_uid -from tests.aws.services.lambda_.test_lambda import TEST_LAMBDA_PYTHON_ECHO - -logs_role = { - "Statement": { - "Effect": "Allow", - "Principal": {"Service": f"logs.{TEST_AWS_REGION_NAME}.amazonaws.com"}, - "Action": "sts:AssumeRole", - } -} -kinesis_permission = { - "Version": "2012-10-17", - "Statement": [{"Effect": "Allow", "Action": "kinesis:PutRecord", "Resource": "*"}], -} -s3_firehose_role = { - "Statement": { - "Sid": "", - "Effect": "Allow", - "Principal": {"Service": "firehose.amazonaws.com"}, - "Action": "sts:AssumeRole", - } -} -s3_firehose_permission = { - "Version": "2012-10-17", - "Statement": [{"Effect": "Allow", "Action": ["s3:*", "s3-object-lambda:*"], "Resource": "*"}], -} - -firehose_permission = { - "Version": "2012-10-17", - "Statement": [{"Effect": "Allow", "Action": ["firehose:*"], "Resource": "*"}], -} - - -@pytest.fixture -def logs_log_group(aws_client): - name = f"test-log-group-{short_uid()}" - aws_client.logs.create_log_group(logGroupName=name) - yield name - aws_client.logs.delete_log_group(logGroupName=name) - - -@pytest.fixture -def logs_log_stream(logs_log_group, aws_client): - name = f"test-log-stream-{short_uid()}" - aws_client.logs.create_log_stream(logGroupName=logs_log_group, logStreamName=name) - yield name - aws_client.logs.delete_log_stream(logStreamName=name, logGroupName=logs_log_group) - - -class TestCloudWatchLogs: - # TODO make creation and description atomic to avoid possible flake? - @markers.aws.validated - def test_create_and_delete_log_group(self, aws_client): - test_name = f"test-log-group-{short_uid()}" - log_groups_before = aws_client.logs.describe_log_groups( - logGroupNamePrefix="test-log-group-" - ).get("logGroups", []) - - aws_client.logs.create_log_group(logGroupName=test_name) - - log_groups_between = aws_client.logs.describe_log_groups( - logGroupNamePrefix="test-log-group-" - ).get("logGroups", []) - assert poll_condition( - lambda: len(log_groups_between) == len(log_groups_before) + 1, timeout=5.0, interval=0.5 - ) - - aws_client.logs.delete_log_group(logGroupName=test_name) - - log_groups_after = aws_client.logs.describe_log_groups( - logGroupNamePrefix="test-log-group-" - ).get("logGroups", []) - assert poll_condition( - lambda: len(log_groups_after) == len(log_groups_between) - 1, timeout=5.0, interval=0.5 - ) - assert len(log_groups_after) == len(log_groups_before) - - @markers.aws.validated - def test_resource_does_not_exist(self, aws_client, snapshot, cleanups): - log_group_name = f"log-group-{short_uid()}" - log_stream_name = f"log-stream-{short_uid()}" - with pytest.raises(Exception) as ctx: - aws_client.logs.get_log_events( - logGroupName=log_group_name, logStreamName=log_stream_name - ) - snapshot.match("error-log-group-does-not-exist", ctx.value.response) - - aws_client.logs.create_log_group(logGroupName=log_group_name) - cleanups.append(lambda: aws_client.logs.delete_log_group(logGroupName=log_group_name)) - - with pytest.raises(Exception) as ctx: - aws_client.logs.get_log_events( - logGroupName=log_group_name, logStreamName=log_stream_name - ) - snapshot.match("error-log-stream-does-not-exist", ctx.value.response) - - @markers.aws.validated - def test_list_tags_log_group(self, snapshot, aws_client): - test_name = f"test-log-group-{short_uid()}" - try: - aws_client.logs.create_log_group(logGroupName=test_name, tags={"env": "testing1"}) - response = aws_client.logs.list_tags_log_group(logGroupName=test_name) - snapshot.match("list_tags_after_create_log_group", response) - - # get group arn, to use the tag-resource api - log_group_arn = aws_client.logs.describe_log_groups(logGroupNamePrefix=test_name)[ - "logGroups" - ][0]["arn"].rstrip(":*") - - # add a tag - new api - aws_client.logs.tag_resource( - resourceArn=log_group_arn, tags={"test1": "val1", "test2": "val2"} - ) - - response = aws_client.logs.list_tags_log_group(logGroupName=test_name) - response_2 = aws_client.logs.list_tags_for_resource(resourceArn=log_group_arn) - - snapshot.match("list_tags_log_group_after_tag_resource", response) - snapshot.match("list_tags_for_resource_after_tag_resource", response_2) - # values should be the same - assert response["tags"] == response_2["tags"] - - # add a tag - old api - aws_client.logs.tag_log_group(logGroupName=test_name, tags={"test3": "val3"}) - - response = aws_client.logs.list_tags_log_group(logGroupName=test_name) - response_2 = aws_client.logs.list_tags_for_resource(resourceArn=log_group_arn) - - snapshot.match("list_tags_log_group_after_tag_log_group", response) - snapshot.match("list_tags_for_resource_after_tag_log_group", response_2) - assert response["tags"] == response_2["tags"] - - # untag - use both apis - aws_client.logs.untag_log_group(logGroupName=test_name, tags=["test3"]) - aws_client.logs.untag_resource(resourceArn=log_group_arn, tagKeys=["env", "test1"]) - - response = aws_client.logs.list_tags_log_group(logGroupName=test_name) - response_2 = aws_client.logs.list_tags_for_resource(resourceArn=log_group_arn) - snapshot.match("list_tags_log_group_after_untag", response) - snapshot.match("list_tags_for_resource_after_untag", response_2) - - assert response["tags"] == response_2["tags"] - - finally: - # clean up - aws_client.logs.delete_log_group(logGroupName=test_name) - - @markers.snapshot.skip_snapshot_verify( - paths=[ - # TODO 'describe-log-groups' returns different attributes on AWS when using - # 'logGroupNamePattern' compared to 'logGroupNamePrefix' (for the same log group) - # seems like a weird issue on AWS side, we just exclude the paths here for this particular call - "$..describe-log-groups-pattern.logGroups..metricFilterCount", - "$..describe-log-groups-pattern.logGroups..storedBytes", - "$..describe-log-groups-pattern.nextToken", - ] - ) - @markers.aws.validated - def test_create_and_delete_log_stream(self, logs_log_group, aws_client, region_name, snapshot): - snapshot.add_transformer(snapshot.transform.logs_api()) - test_name = f"test-log-stream-{short_uid()}" - - # filter for prefix/entire name here - response = aws_client.logs.describe_log_groups(logGroupNamePrefix=logs_log_group) - snapshot.match("describe-log-groups-prefix", response) - - # pattern for the short-uid - # for some reason, this does not work immediately on AWS - assert poll_condition( - lambda: len( - aws_client.logs.describe_log_groups( - logGroupNamePattern=logs_log_group.split("-")[-1] - ).get("logGroups") - ) - == 1, - timeout=5.0, - interval=0.5, - ) - response = aws_client.logs.describe_log_groups( - logGroupNamePattern=logs_log_group.split("-")[-1] - ) - snapshot.match("describe-log-groups-pattern", response) - - # using prefix + pattern should raise error - with pytest.raises(Exception) as ctx: - aws_client.logs.describe_log_groups( - logGroupNamePattern=logs_log_group, logGroupNamePrefix=logs_log_group - ) - snapshot.match("error-describe-logs-group", ctx.value.response) - - aws_client.logs.create_log_stream(logGroupName=logs_log_group, logStreamName=test_name) - log_streams_between = aws_client.logs.describe_log_streams(logGroupName=logs_log_group).get( - "logStreams", [] - ) - - snapshot.match("logs_log_group", log_streams_between) - - # using log-group-name and log-group-identifier should raise exception - with pytest.raises(Exception) as ctx: - aws_client.logs.describe_log_streams( - logGroupName=logs_log_group, logGroupIdentifier=logs_log_group - ) - snapshot.match("error-describe-logs-streams", ctx.value.response) - - # log group identifier using the name of the log-group - response = aws_client.logs.describe_log_streams(logGroupIdentifier=logs_log_group).get( - "logStreams" - ) - snapshot.match("log_group_identifier", response) - # log group identifier using arn - response = aws_client.logs.describe_log_streams( - logGroupIdentifier=arns.log_group_arn( - logs_log_group, - account_id=aws_client.sts.get_caller_identity()["Account"], - region_name=region_name, - ) - ).get("logStreams") - snapshot.match("log_group_identifier-arn", response) - - aws_client.logs.delete_log_stream(logGroupName=logs_log_group, logStreamName=test_name) - - log_streams_after = aws_client.logs.describe_log_streams(logGroupName=logs_log_group).get( - "logStreams", [] - ) - assert len(log_streams_after) == 0 - - @markers.aws.validated - def test_put_events_multi_bytes_msg(self, logs_log_group, logs_log_stream, aws_client): - body_msg = "🙀 - 参よ - 日本語" - events = [{"timestamp": now_utc(millis=True), "message": body_msg}] - response = aws_client.logs.put_log_events( - logGroupName=logs_log_group, logStreamName=logs_log_stream, logEvents=events - ) - assert response["ResponseMetadata"]["HTTPStatusCode"] == 200 - - def get_log_events(): - events = aws_client.logs.get_log_events( - logGroupName=logs_log_group, logStreamName=logs_log_stream - )["events"] - assert events[0]["message"] == body_msg - - retry( - get_log_events, - retries=20 if is_aws() else 3, - sleep=5 if is_aws() else 1, - sleep_before=3 if is_aws() else 0, - ) - - @markers.aws.validated - def test_filter_log_events_response_header(self, logs_log_group, logs_log_stream, aws_client): - events = [ - {"timestamp": now_utc(millis=True), "message": "log message 1"}, - {"timestamp": now_utc(millis=True), "message": "log message 2"}, - ] - response = aws_client.logs.put_log_events( - logGroupName=logs_log_group, logStreamName=logs_log_stream, logEvents=events - ) - assert response["ResponseMetadata"]["HTTPStatusCode"] == 200 - - response = aws_client.logs.filter_log_events(logGroupName=logs_log_group) - assert response["ResponseMetadata"]["HTTPStatusCode"] == 200 - assert ( - response["ResponseMetadata"]["HTTPHeaders"]["content-type"] == APPLICATION_AMZ_JSON_1_1 - ) - - @markers.aws.validated - @markers.snapshot.skip_snapshot_verify( - paths=[ - "$..Statement.Condition.StringEquals", - "$..add_permission.ResponseMetadata.HTTPStatusCode", - ] - ) - def test_put_subscription_filter_lambda( - self, - logs_log_group, - logs_log_stream, - create_lambda_function, - snapshot, - aws_client, - region_name, - ): - snapshot.add_transformer(snapshot.transform.lambda_api()) - # special replacements for this test case: - snapshot.add_transformer(snapshot.transform.key_value("logGroupName")) - snapshot.add_transformer(snapshot.transform.key_value("logStreamName")) - snapshot.add_transformer( - KeyValueBasedTransformer( - lambda k, v: ( - v - if k == "id" and (isinstance(v, str) and re.match(re.compile(r"^[0-9]+$"), v)) - else None - ), - replacement="id", - replace_reference=False, - ), - ) - - test_lambda_name = f"test-lambda-function-{short_uid()}" - func_arn = create_lambda_function( - handler_file=TEST_LAMBDA_PYTHON_ECHO, - func_name=test_lambda_name, - runtime=Runtime.python3_12, - )["CreateFunctionResponse"]["FunctionArn"] - aws_client.lambda_.invoke(FunctionName=test_lambda_name, Payload=b"{}") - # get account-id to set the correct policy - account_id = aws_client.sts.get_caller_identity()["Account"] - result = aws_client.lambda_.add_permission( - FunctionName=test_lambda_name, - StatementId=test_lambda_name, - Principal=f"logs.{region_name}.amazonaws.com", - Action="lambda:InvokeFunction", - SourceArn=f"arn:{get_partition(region_name)}:logs:{region_name}:{account_id}:log-group:{logs_log_group}:*", - SourceAccount=account_id, - ) - - snapshot.match("add_permission", result) - - result = aws_client.logs.put_subscription_filter( - logGroupName=logs_log_group, - filterName="test", - filterPattern="", - destinationArn=func_arn, - ) - snapshot.match("put_subscription_filter", result) - - aws_client.logs.put_log_events( - logGroupName=logs_log_group, - logStreamName=logs_log_stream, - logEvents=[ - {"timestamp": now_utc(millis=True), "message": "test"}, - {"timestamp": now_utc(millis=True), "message": "test 2"}, - ], - ) - - response = aws_client.logs.describe_subscription_filters(logGroupName=logs_log_group) - assert len(response["subscriptionFilters"]) == 1 - snapshot.match("describe_subscription_filter", response) - - def check_invocation(): - events = testutil.list_all_log_events( - log_group_name=f"/aws/lambda/{test_lambda_name}", logs_client=aws_client.logs - ) - # we only are interested in events that contain "awslogs" - filtered_events = [] - for e in events: - if "awslogs" in e["message"]: - # the message will look like this: - # {"messageType":"DATA_MESSAGE","owner":"000000000000","logGroup":"log-group", - # "logStream":"log-stream","subscriptionFilters":["test"], - # "logEvents":[{"id":"7","timestamp":1679056073581,"message":"test"}, - # {"id":"8","timestamp":1679056073581,"message":"test 2"}]} - data = json.loads(e["message"])["awslogs"]["data"].encode("utf-8") - decoded_data = gzip.decompress(base64.b64decode(data)).decode("utf-8") - for log_event in json.loads(decoded_data)["logEvents"]: - filtered_events.append(log_event) - assert len(filtered_events) == 2 - - filtered_events.sort(key=lambda k: k.get("message")) - snapshot.match("list_all_log_events", filtered_events) - - retry(check_invocation, retries=6, sleep=3.0) - - @markers.aws.validated - def test_put_subscription_filter_firehose( - self, logs_log_group, logs_log_stream, s3_bucket, create_iam_role_with_policy, aws_client - ): - try: - firehose_name = f"test-firehose-{short_uid()}" - s3_bucket_arn = f"arn:aws:s3:::{s3_bucket}" - - role = f"test-firehose-s3-role-{short_uid()}" - policy_name = f"test-firehose-s3-role-policy-{short_uid()}" - role_arn = create_iam_role_with_policy( - RoleName=role, - PolicyName=policy_name, - RoleDefinition=s3_firehose_role, - PolicyDefinition=s3_firehose_permission, - ) - - # TODO AWS has troubles creating the delivery stream the first time - # policy is not accepted at first, so we try again - def create_delivery_stream(): - aws_client.firehose.create_delivery_stream( - DeliveryStreamName=firehose_name, - S3DestinationConfiguration={ - "BucketARN": s3_bucket_arn, - "RoleARN": role_arn, - "BufferingHints": {"SizeInMBs": 1, "IntervalInSeconds": 60}, - }, - ) - - retry(create_delivery_stream, retries=5, sleep=10.0) - - response = aws_client.firehose.describe_delivery_stream( - DeliveryStreamName=firehose_name - ) - firehose_arn = response["DeliveryStreamDescription"]["DeliveryStreamARN"] - - role = f"test-firehose-role-{short_uid()}" - policy_name = f"test-firehose-role-policy-{short_uid()}" - role_arn_logs = create_iam_role_with_policy( - RoleName=role, - PolicyName=policy_name, - RoleDefinition=logs_role, - PolicyDefinition=firehose_permission, - ) - - def check_stream_active(): - state = aws_client.firehose.describe_delivery_stream( - DeliveryStreamName=firehose_name - )["DeliveryStreamDescription"]["DeliveryStreamStatus"] - if state != "ACTIVE": - raise Exception(f"DeliveryStreamStatus is {state}") - - retry(check_stream_active, retries=60, sleep=30.0) - - aws_client.logs.put_subscription_filter( - logGroupName=logs_log_group, - filterName="Destination", - filterPattern="", - destinationArn=firehose_arn, - roleArn=role_arn_logs, - ) - - aws_client.logs.put_log_events( - logGroupName=logs_log_group, - logStreamName=logs_log_stream, - logEvents=[ - {"timestamp": now_utc(millis=True), "message": "test"}, - {"timestamp": now_utc(millis=True), "message": "test 2"}, - ], - ) - - def list_objects(): - response = aws_client.s3.list_objects(Bucket=s3_bucket) - assert len(response["Contents"]) >= 1 - - retry(list_objects, retries=60, sleep=30.0) - response = aws_client.s3.list_objects(Bucket=s3_bucket) - key = response["Contents"][-1]["Key"] - response = aws_client.s3.get_object(Bucket=s3_bucket, Key=key) - content = gzip.decompress(response["Body"].read()).decode("utf-8") - assert "DATA_MESSAGE" in content - assert "test" in content - assert "test 2" in content - - finally: - # clean up - aws_client.firehose.delete_delivery_stream( - DeliveryStreamName=firehose_name, AllowForceDelete=True - ) - - @markers.aws.validated - def test_put_subscription_filter_kinesis( - self, logs_log_group, logs_log_stream, create_iam_role_with_policy, aws_client - ): - kinesis_name = f"test-kinesis-{short_uid()}" - filter_name = "Destination" - aws_client.kinesis.create_stream(StreamName=kinesis_name, ShardCount=1) - - try: - result = aws_client.kinesis.describe_stream(StreamName=kinesis_name)[ - "StreamDescription" - ] - kinesis_arn = result["StreamARN"] - role = f"test-kinesis-role-{short_uid()}" - policy_name = f"test-kinesis-role-policy-{short_uid()}" - role_arn = create_iam_role_with_policy( - RoleName=role, - PolicyName=policy_name, - RoleDefinition=logs_role, - PolicyDefinition=kinesis_permission, - ) - - # wait for stream-status "ACTIVE" - status = result["StreamStatus"] - if status != "ACTIVE": - - def check_stream_active(): - state = aws_client.kinesis.describe_stream(StreamName=kinesis_name)[ - "StreamDescription" - ]["StreamStatus"] - if state != "ACTIVE": - raise Exception(f"StreamStatus is {state}") - - retry(check_stream_active, retries=6, sleep=1.0, sleep_before=2.0) - - def put_subscription_filter(): - aws_client.logs.put_subscription_filter( - logGroupName=logs_log_group, - filterName=filter_name, - filterPattern="", - destinationArn=kinesis_arn, - roleArn=role_arn, - ) - - # for a weird reason the put_subscription_filter fails on AWS the first time, - # even-though we check for ACTIVE state... - retry(put_subscription_filter, retries=6, sleep=3.0) - - def put_event(): - aws_client.logs.put_log_events( - logGroupName=logs_log_group, - logStreamName=logs_log_stream, - logEvents=[ - {"timestamp": now_utc(millis=True), "message": "test"}, - {"timestamp": now_utc(millis=True), "message": "test 2"}, - ], - ) - - retry(put_event, retries=6, sleep=3.0) - - shard_iterator = aws_client.kinesis.get_shard_iterator( - StreamName=kinesis_name, - ShardId="shardId-000000000000", - ShardIteratorType="TRIM_HORIZON", - )["ShardIterator"] - - response = aws_client.kinesis.get_records(ShardIterator=shard_iterator) - # AWS sends messages as health checks - assert len(response["Records"]) >= 1 - found = False - for record in response["Records"]: - data = record["Data"] - unzipped_data = gzip.decompress(data) - json_data = json.loads(unzipped_data) - if "test" in json.dumps(json_data["logEvents"]): - assert len(json_data["logEvents"]) == 2 - assert json_data["logEvents"][0]["message"] == "test" - assert json_data["logEvents"][1]["message"] == "test 2" - found = True - - assert found - # clean up - finally: - aws_client.kinesis.delete_stream(StreamName=kinesis_name, EnforceConsumerDeletion=True) - aws_client.logs.delete_subscription_filter( - logGroupName=logs_log_group, filterName=filter_name - ) - - @pytest.mark.skip("TODO: failing against community - filters are only in pro -> move test?") - @markers.aws.validated - def test_metric_filters(self, logs_log_group, logs_log_stream, aws_client): - basic_filter_name = f"test-filter-basic-{short_uid()}" - json_filter_name = f"test-filter-json-{short_uid()}" - namespace_name = f"test-metric-namespace-{short_uid()}" - basic_metric_name = f"test-basic-metric-{short_uid()}" - json_metric_name = f"test-json-metric-{short_uid()}" - basic_transforms = { - "metricNamespace": namespace_name, - "metricName": basic_metric_name, - "metricValue": "1", - "defaultValue": 0, - } - json_transforms = { - "metricNamespace": namespace_name, - "metricName": json_metric_name, - "metricValue": "1", - "defaultValue": 0, - } - aws_client.logs.put_metric_filter( - logGroupName=logs_log_group, - filterName=basic_filter_name, - filterPattern=" ", - metricTransformations=[basic_transforms], - ) - aws_client.logs.put_metric_filter( - logGroupName=logs_log_group, - filterName=json_filter_name, - filterPattern='{$.message = "test"}', - metricTransformations=[json_transforms], - ) - - response = aws_client.logs.describe_metric_filters( - logGroupName=logs_log_group, filterNamePrefix="test-filter-" - ) - assert response["ResponseMetadata"]["HTTPStatusCode"] == 200 - filter_names = [_filter["filterName"] for _filter in response["metricFilters"]] - assert basic_filter_name in filter_names - assert json_filter_name in filter_names - - # put log events and assert metrics being published - events = [ - {"timestamp": now_utc(millis=True), "message": "log message 1"}, - {"timestamp": now_utc(millis=True), "message": "log message 2"}, - ] - aws_client.logs.put_log_events( - logGroupName=logs_log_group, logStreamName=logs_log_stream, logEvents=events - ) - - # list metrics - def list_metrics(): - res = aws_client.cloudwatch.list_metrics(Namespace=namespace_name) - assert len(res["Metrics"]) == 2 - - retry( - list_metrics, - retries=20 if is_aws() else 3, - sleep=5 if is_aws() else 1, - sleep_before=3 if is_aws() else 0, - ) - - # delete filters - aws_client.logs.delete_metric_filter( - logGroupName=logs_log_group, filterName=basic_filter_name - ) - aws_client.logs.delete_metric_filter( - logGroupName=logs_log_group, filterName=json_filter_name - ) - - response = aws_client.logs.describe_metric_filters( - logGroupName=logs_log_group, filterNamePrefix="test-filter-" - ) - assert response["ResponseMetadata"]["HTTPStatusCode"] == 200 - filter_names = [_filter["filterName"] for _filter in response["metricFilters"]] - assert basic_filter_name not in filter_names - assert json_filter_name not in filter_names - - @markers.aws.needs_fixing - def test_delivery_logs_for_sns(self, sns_create_topic, sns_subscription, aws_client): - topic_name = f"test-logs-{short_uid()}" - contact = "+10123456789" - - topic_arn = sns_create_topic(Name=topic_name)["TopicArn"] - sns_subscription(TopicArn=topic_arn, Protocol="sms", Endpoint=contact) - - message = "Good news everyone!" - aws_client.sns.publish(Message=message, TopicArn=topic_arn) - logs_group_name = topic_arn.replace("arn:aws:", "").replace(":", "/") - - def log_group_exists(): - # TODO on AWS the log group is not created, probably need iam role - # see also https://repost.aws/knowledge-center/monitor-sns-texts-cloudwatch - response = aws_client.logs.describe_log_streams(logGroupName=logs_group_name) - assert response["ResponseMetadata"]["HTTPStatusCode"] == 200 - - retry( - log_group_exists, - retries=20 if is_aws() else 3, - sleep=5 if is_aws() else 1, - sleep_before=3 if is_aws() else 0, - ) diff --git a/tests/aws/services/logs/test_logs.snapshot.json b/tests/aws/services/logs/test_logs.snapshot.json deleted file mode 100644 index 9f6e7b429a931..0000000000000 --- a/tests/aws/services/logs/test_logs.snapshot.json +++ /dev/null @@ -1,245 +0,0 @@ -{ - "tests/aws/services/logs/test_logs.py::TestCloudWatchLogs::test_put_subscription_filter_lambda": { - "recorded-date": "17-03-2023, 13:55:00", - "recorded-content": { - "add_permission": { - "Statement": { - "Sid": "", - "Effect": "Allow", - "Principal": { - "Service": "logs..amazonaws.com" - }, - "Action": "lambda:InvokeFunction", - "Resource": "arn::lambda::111111111111:function:", - "Condition": { - "StringEquals": { - "AWS:SourceAccount": "111111111111" - }, - "ArnLike": { - "AWS:SourceArn": "arn::logs::111111111111:log-group::" - } - } - }, - "ResponseMetadata": { - "HTTPHeaders": {}, - "HTTPStatusCode": 201 - } - }, - "put_subscription_filter": { - "ResponseMetadata": { - "HTTPHeaders": {}, - "HTTPStatusCode": 200 - } - }, - "describe_subscription_filter": { - "subscriptionFilters": [ - { - "creationTime": "timestamp", - "destinationArn": "arn::lambda::111111111111:function:", - "distribution": "ByLogStream", - "filterName": "test", - "filterPattern": "", - "logGroupName": "" - } - ], - "ResponseMetadata": { - "HTTPHeaders": {}, - "HTTPStatusCode": 200 - } - }, - "list_all_log_events": [ - { - "id": "id", - "timestamp": "timestamp", - "message": "test" - }, - { - "id": "id", - "timestamp": "timestamp", - "message": "test 2" - } - ] - } - }, - "tests/aws/services/logs/test_logs.py::TestCloudWatchLogs::test_list_tags_log_group": { - "recorded-date": "22-12-2022, 17:46:54", - "recorded-content": { - "list_tags_after_create_log_group": { - "tags": { - "env": "testing1" - }, - "ResponseMetadata": { - "HTTPHeaders": {}, - "HTTPStatusCode": 200 - } - }, - "list_tags_log_group_after_tag_resource": { - "tags": { - "env": "testing1", - "test1": "val1", - "test2": "val2" - }, - "ResponseMetadata": { - "HTTPHeaders": {}, - "HTTPStatusCode": 200 - } - }, - "list_tags_for_resource_after_tag_resource": { - "tags": { - "env": "testing1", - "test1": "val1", - "test2": "val2" - }, - "ResponseMetadata": { - "HTTPHeaders": {}, - "HTTPStatusCode": 200 - } - }, - "list_tags_log_group_after_tag_log_group": { - "tags": { - "env": "testing1", - "test1": "val1", - "test2": "val2", - "test3": "val3" - }, - "ResponseMetadata": { - "HTTPHeaders": {}, - "HTTPStatusCode": 200 - } - }, - "list_tags_for_resource_after_tag_log_group": { - "tags": { - "env": "testing1", - "test1": "val1", - "test2": "val2", - "test3": "val3" - }, - "ResponseMetadata": { - "HTTPHeaders": {}, - "HTTPStatusCode": 200 - } - }, - "list_tags_log_group_after_untag": { - "tags": { - "test2": "val2" - }, - "ResponseMetadata": { - "HTTPHeaders": {}, - "HTTPStatusCode": 200 - } - }, - "list_tags_for_resource_after_untag": { - "tags": { - "test2": "val2" - }, - "ResponseMetadata": { - "HTTPHeaders": {}, - "HTTPStatusCode": 200 - } - } - } - }, - "tests/aws/services/logs/test_logs.py::TestCloudWatchLogs::test_create_and_delete_log_stream": { - "recorded-date": "06-04-2023, 11:42:42", - "recorded-content": { - "describe-log-groups-prefix": { - "logGroups": [ - { - "arn": "arn::logs::111111111111:log-group::*", - "creationTime": "timestamp", - "logGroupName": "", - "metricFilterCount": 0, - "storedBytes": 0 - } - ], - "ResponseMetadata": { - "HTTPHeaders": {}, - "HTTPStatusCode": 200 - } - }, - "describe-log-groups-pattern": { - "logGroups": [ - { - "arn": "arn::logs::111111111111:log-group::*", - "creationTime": "timestamp", - "logGroupName": "" - } - ], - "nextToken": "", - "ResponseMetadata": { - "HTTPHeaders": {}, - "HTTPStatusCode": 200 - } - }, - "error-describe-logs-group": { - "Error": { - "Code": "InvalidParameterException", - "Message": "LogGroup name prefix and LogGroup name pattern are mutually exclusive parameters." - }, - "ResponseMetadata": { - "HTTPHeaders": {}, - "HTTPStatusCode": 400 - } - }, - "logs_log_group": [ - { - "logStreamName": "", - "creationTime": "timestamp", - "arn": "arn::logs::111111111111:log-group::log-stream:", - "storedBytes": 0 - } - ], - "error-describe-logs-streams": { - "Error": { - "Code": "ValidationException", - "Message": "LogGroup name and LogGroup ARN are mutually exclusive parameters." - }, - "ResponseMetadata": { - "HTTPHeaders": {}, - "HTTPStatusCode": 400 - } - }, - "log_group_identifier": [ - { - "logStreamName": "", - "creationTime": "timestamp", - "arn": "arn::logs::111111111111:log-group::log-stream:", - "storedBytes": 0 - } - ], - "log_group_identifier-arn": [ - { - "logStreamName": "", - "creationTime": "timestamp", - "arn": "arn::logs::111111111111:log-group::log-stream:", - "storedBytes": 0 - } - ] - } - }, - "tests/aws/services/logs/test_logs.py::TestCloudWatchLogs::test_resource_does_not_exist": { - "recorded-date": "05-09-2024, 16:43:20", - "recorded-content": { - "error-log-group-does-not-exist": { - "Error": { - "Code": "ResourceNotFoundException", - "Message": "The specified log group does not exist." - }, - "ResponseMetadata": { - "HTTPHeaders": {}, - "HTTPStatusCode": 400 - } - }, - "error-log-stream-does-not-exist": { - "Error": { - "Code": "ResourceNotFoundException", - "Message": "The specified log stream does not exist." - }, - "ResponseMetadata": { - "HTTPHeaders": {}, - "HTTPStatusCode": 400 - } - } - } - } -} diff --git a/tests/aws/services/logs/test_logs.validation.json b/tests/aws/services/logs/test_logs.validation.json deleted file mode 100644 index 4be0d1979501c..0000000000000 --- a/tests/aws/services/logs/test_logs.validation.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "tests/aws/services/logs/test_logs.py::TestCloudWatchLogs::test_create_and_delete_log_group": { - "last_validated_date": "2024-05-24T13:57:11+00:00" - }, - "tests/aws/services/logs/test_logs.py::TestCloudWatchLogs::test_create_and_delete_log_stream": { - "last_validated_date": "2023-04-06T09:42:42+00:00" - }, - "tests/aws/services/logs/test_logs.py::TestCloudWatchLogs::test_filter_log_events_response_header": { - "last_validated_date": "2024-05-24T13:58:30+00:00" - }, - "tests/aws/services/logs/test_logs.py::TestCloudWatchLogs::test_list_tags_log_group": { - "last_validated_date": "2022-12-22T16:46:54+00:00" - }, - "tests/aws/services/logs/test_logs.py::TestCloudWatchLogs::test_metric_filters": { - "last_validated_date": "2024-05-24T14:17:33+00:00" - }, - "tests/aws/services/logs/test_logs.py::TestCloudWatchLogs::test_put_events_multi_bytes_msg": { - "last_validated_date": "2024-05-24T14:23:19+00:00" - }, - "tests/aws/services/logs/test_logs.py::TestCloudWatchLogs::test_put_subscription_filter_lambda": { - "last_validated_date": "2023-03-17T12:55:00+00:00" - }, - "tests/aws/services/logs/test_logs.py::TestCloudWatchLogs::test_resource_does_not_exist": { - "last_validated_date": "2024-09-05T16:43:20+00:00" - } -} diff --git a/tests/aws/services/logs/test_logs_delivery.py b/tests/aws/services/logs/test_logs_delivery.py new file mode 100644 index 0000000000000..95fe9b4901f44 --- /dev/null +++ b/tests/aws/services/logs/test_logs_delivery.py @@ -0,0 +1,549 @@ +"""Tests for CloudWatch Logs - Delivery operations (vended logs delivery).""" + +import json + +import pytest + +from localstack.testing.pytest import markers +from localstack.utils.common import short_uid + + +def get_delivery_destination_policy(region: str, account_id: str) -> str: + """Generate a delivery destination policy document.""" + return json.dumps( + { + "Version": "2012-10-17", + "Statement": [ + { + "Sid": "AllowLogDeliveryActions", + "Effect": "Allow", + "Principal": {"AWS": f"arn:aws:iam::{account_id}:root"}, + "Action": "logs:CreateDelivery", + "Resource": [ + f"arn:aws:logs:{region}:{account_id}:delivery-source:*", + f"arn:aws:logs:{region}:{account_id}:delivery:*", + f"arn:aws:logs:{region}:{account_id}:delivery-destination:*", + ], + } + ], + } + ) + + +class TestDeliveryDestinations: + """Tests for delivery destination operations.""" + + @markers.aws.validated + @markers.snapshot.skip_snapshot_verify(paths=["$..deliveryDestination.tags"]) + def test_put_delivery_destination(self, aws_client, snapshot, cleanups, s3_bucket): + """Test creating a delivery destination.""" + snapshot.add_transformer(snapshot.transform.logs_api()) + destination_name = f"test-dd-{short_uid()}" + + response = aws_client.logs.put_delivery_destination( + name=destination_name, + outputFormat="json", + deliveryDestinationConfiguration={ + "destinationResourceArn": f"arn:aws:s3:::{s3_bucket}" + }, + tags={"key1": "value1"}, + ) + cleanups.append(lambda: aws_client.logs.delete_delivery_destination(name=destination_name)) + snapshot.add_transformer(snapshot.transform.regex(destination_name, "")) + snapshot.add_transformer(snapshot.transform.regex(s3_bucket, "")) + snapshot.match("put-delivery-destination", response) + + @markers.aws.validated + def test_put_delivery_destination_invalid_format(self, aws_client, snapshot, s3_bucket): + """Test creating a delivery destination with invalid output format.""" + with pytest.raises(Exception) as ctx: + aws_client.logs.put_delivery_destination( + name=f"test-dd-{short_uid()}", + outputFormat="foobar", # Invalid format + deliveryDestinationConfiguration={ + "destinationResourceArn": f"arn:aws:s3:::{s3_bucket}" + }, + ) + snapshot.match("error-invalid-format", ctx.value.response) + + @markers.aws.validated + def test_put_delivery_destination_update( + self, aws_client, snapshot, cleanups, s3_bucket, s3_create_bucket + ): + """Test updating a delivery destination.""" + destination_name = f"test-dd-{short_uid()}" + second_bucket = s3_create_bucket() + + snapshot.add_transformer(snapshot.transform.logs_api()) + snapshot.add_transformer(snapshot.transform.regex(destination_name, "")) + snapshot.add_transformer(snapshot.transform.regex(second_bucket, "")) + + # Create initial destination + aws_client.logs.put_delivery_destination( + name=destination_name, + deliveryDestinationConfiguration={ + "destinationResourceArn": f"arn:aws:s3:::{s3_bucket}" + }, + ) + cleanups.append(lambda: aws_client.logs.delete_delivery_destination(name=destination_name)) + + # Update destination resource + response = aws_client.logs.put_delivery_destination( + name=destination_name, + deliveryDestinationConfiguration={ + "destinationResourceArn": f"arn:aws:s3:::{second_bucket}" + }, + ) + snapshot.match("put-delivery-destination-update", response) + + @markers.aws.validated + def test_get_delivery_destination(self, aws_client, snapshot, cleanups, s3_bucket): + """Test getting a delivery destination.""" + + destination_name = f"test-dd-{short_uid()}" + snapshot.add_transformer(snapshot.transform.logs_api()) + snapshot.add_transformer(snapshot.transform.regex(destination_name, "")) + snapshot.add_transformer(snapshot.transform.regex(s3_bucket, "")) + + aws_client.logs.put_delivery_destination( + name=destination_name, + deliveryDestinationConfiguration={ + "destinationResourceArn": f"arn:aws:s3:::{s3_bucket}" + }, + ) + cleanups.append(lambda: aws_client.logs.delete_delivery_destination(name=destination_name)) + + response = aws_client.logs.get_delivery_destination(name=destination_name) + snapshot.match("get-delivery-destination", response) + assert response["deliveryDestination"]["name"] == destination_name + + @markers.aws.validated + def test_get_delivery_destination_not_found(self, aws_client, snapshot): + """Test getting a non-existent delivery destination.""" + with pytest.raises(Exception) as ctx: + aws_client.logs.get_delivery_destination(name="foobar") + snapshot.match("error-not-found", ctx.value.response) + + @markers.aws.validated + def test_describe_delivery_destinations(self, aws_client, snapshot, cleanups, s3_bucket): + """Test describing delivery destinations.""" + snapshot.add_transformer(snapshot.transform.logs_api()) + snapshot.add_transformer(snapshot.transform.regex(s3_bucket, "")) + destinations = [] + + for i in range(2): + destination_name = f"test-dd-{short_uid()}-{i}" + aws_client.logs.put_delivery_destination( + name=destination_name, + deliveryDestinationConfiguration={ + "destinationResourceArn": f"arn:aws:s3:::{s3_bucket}" + }, + ) + destinations.append(destination_name) + cleanups.append( + lambda dn=destination_name: aws_client.logs.delete_delivery_destination(name=dn) + ) + snapshot.add_transformer( + snapshot.transform.regex(destination_name, f"") + ) + + response = aws_client.logs.describe_delivery_destinations() + descriptions = [ + desc for desc in response["deliveryDestinations"] if desc["name"] in destinations + ] + + snapshot.match("describe-delivery-destinations", descriptions) + + @markers.aws.validated + def test_delete_delivery_destination(self, aws_client, snapshot, cleanups, s3_bucket): + """Test deleting a delivery destination.""" + snapshot.add_transformer(snapshot.transform.logs_api()) + destination_name = f"test-dd-{short_uid()}" + + aws_client.logs.put_delivery_destination( + name=destination_name, + deliveryDestinationConfiguration={ + "destinationResourceArn": f"arn:aws:s3:::{s3_bucket}" + }, + ) + + # Delete destination + aws_client.logs.delete_delivery_destination(name=destination_name) + + # Verify deletion + with pytest.raises(Exception) as ctx: + aws_client.logs.get_delivery_destination(name=destination_name) + snapshot.match("error-after-delete", ctx.value.response) + + @markers.aws.validated + def test_delete_delivery_destination_not_found(self, aws_client, snapshot): + """Test deleting a non-existent delivery destination.""" + with pytest.raises(Exception) as ctx: + aws_client.logs.delete_delivery_destination(name="foobar") + snapshot.match("error-not-found", ctx.value.response) + + +class TestDeliveryDestinationPolicies: + """Tests for delivery destination policy operations.""" + + @markers.aws.validated + def test_put_delivery_destination_policy( + self, aws_client, account_id, s3_bucket, region_name, snapshot, cleanups + ): + """Test putting a policy on a delivery destination.""" + destination_name = f"test-dd-{short_uid()}" + snapshot.add_transformer(snapshot.transform.logs_api()) + snapshot.add_transformer(snapshot.transform.regex(s3_bucket, "")) + + aws_client.logs.put_delivery_destination( + name=destination_name, + deliveryDestinationConfiguration={ + "destinationResourceArn": f"arn:aws:s3:::{s3_bucket}" + }, + ) + cleanups.append(lambda: aws_client.logs.delete_delivery_destination(name=destination_name)) + + policy = get_delivery_destination_policy(region_name, account_id) + response = aws_client.logs.put_delivery_destination_policy( + deliveryDestinationName=destination_name, + deliveryDestinationPolicy=policy, + ) + snapshot.match("put-delivery-destination-policy", response) + + @markers.aws.validated + def test_get_delivery_destination_policy( + self, aws_client, account_id, s3_bucket, region_name, snapshot, cleanups + ): + """Test getting a delivery destination policy.""" + snapshot.add_transformer(snapshot.transform.logs_api()) + destination_name = f"test-dd-{short_uid()}" + + aws_client.logs.put_delivery_destination( + name=destination_name, + deliveryDestinationConfiguration={ + "destinationResourceArn": f"arn:aws:s3:::{s3_bucket}" + }, + ) + cleanups.append(lambda: aws_client.logs.delete_delivery_destination(name=destination_name)) + + policy = get_delivery_destination_policy(region_name, account_id) + aws_client.logs.put_delivery_destination_policy( + deliveryDestinationName=destination_name, + deliveryDestinationPolicy=policy, + ) + + response = aws_client.logs.get_delivery_destination_policy( + deliveryDestinationName=destination_name + ) + snapshot.match("get-delivery-destination-policy", response) + + @markers.aws.validated + def test_delete_delivery_destination_policy( + self, aws_client, account_id, s3_bucket, region_name, snapshot, cleanups + ): + """Test deleting a delivery destination policy.""" + snapshot.add_transformer(snapshot.transform.logs_api()) + destination_name = f"test-dd-{short_uid()}" + + aws_client.logs.put_delivery_destination( + name=destination_name, + deliveryDestinationConfiguration={ + "destinationResourceArn": f"arn:aws:s3:::{s3_bucket}" + }, + ) + cleanups.append(lambda: aws_client.logs.delete_delivery_destination(name=destination_name)) + + policy = get_delivery_destination_policy(region_name, account_id) + aws_client.logs.put_delivery_destination_policy( + deliveryDestinationName=destination_name, + deliveryDestinationPolicy=policy, + ) + + # Delete policy + aws_client.logs.delete_delivery_destination_policy(deliveryDestinationName=destination_name) + + # Verify deletion + response = aws_client.logs.get_delivery_destination_policy( + deliveryDestinationName=destination_name + ) + assert response["policy"] == {} + + +class TestDeliverySources: + """Tests for delivery source operations.""" + + @markers.aws.needs_fixing # requires pro services + def test_put_delivery_source(self, aws_client, account_id, snapshot, cleanups): + """Test creating a delivery source.""" + source_name = f"test-ds-{short_uid()}" + snapshot.add_transformer(snapshot.transform.logs_api()) + snapshot.add_transformer(snapshot.transform.regex(source_name, "")) + + response = aws_client.logs.put_delivery_source( + name=source_name, + resourceArn=f"arn:aws:cloudfront::{account_id}:distribution/E1Q5F5862X9VJ5", + logType="ACCESS_LOGS", + tags={"key1": "value1"}, + ) + cleanups.append(lambda: aws_client.logs.delete_delivery_source(name=source_name)) + snapshot.match("put-delivery-source", response) + + @markers.aws.validated + def test_put_delivery_source_invalid_resource(self, aws_client, snapshot): + """Test creating a delivery source with invalid resource ARN.""" + with pytest.raises(Exception) as ctx: + aws_client.logs.put_delivery_source( + name=f"test-ds-{short_uid()}", + resourceArn="arn:aws:s3:::test-s3-bucket", # S3 cannot be a source + logType="ACCESS_LOGS", + ) + snapshot.match("error-invalid-resource", ctx.value.response) + + @markers.aws.needs_fixing # requires pro services + def test_get_delivery_source(self, aws_client, snapshot, cleanups, account_id): + """Test getting a delivery source.""" + source_name = f"test-ds-{short_uid()}" + snapshot.add_transformer(snapshot.transform.logs_api()) + snapshot.add_transformer(snapshot.transform.regex(source_name, "")) + + aws_client.logs.put_delivery_source( + name=source_name, + resourceArn=f"arn:aws:cloudfront::{account_id}:distribution/E1Q5F5862X9VJ5", + logType="ACCESS_LOGS", + ) + cleanups.append(lambda: aws_client.logs.delete_delivery_source(name=source_name)) + + response = aws_client.logs.get_delivery_source(name=source_name) + snapshot.match("get-delivery-source", response) + + @markers.aws.validated + @markers.snapshot.skip_snapshot_verify(paths=["$..Error.Message"]) + def test_get_delivery_source_not_found(self, aws_client, snapshot): + """Test getting a non-existent delivery source.""" + with pytest.raises(Exception) as ctx: + aws_client.logs.get_delivery_source(name="foobar") + snapshot.match("error-not-found", ctx.value.response) + + @markers.aws.needs_fixing # requires pro services + def test_describe_delivery_sources(self, aws_client, snapshot, cleanups): + """Test describing delivery sources.""" + snapshot.add_transformer(snapshot.transform.logs_api()) + sources = [] + + for i in range(2): + source_name = f"test-ds-{short_uid()}-{i}" + aws_client.logs.put_delivery_source( + name=source_name, + resourceArn="arn:aws:cloudfront::123456789012:distribution/E19DL18TOXN9JU", + logType="ACCESS_LOGS", + ) + sources.append(source_name) + snapshot.add_transformer(snapshot.transform.regex(source_name, f"")) + cleanups.append(lambda sn=source_name: aws_client.logs.delete_delivery_source(name=sn)) + + response = aws_client.logs.describe_delivery_sources() + snapshot.match("describe-delivery-sources", response) + assert len(response["deliverySources"]) >= 2 + + @markers.aws.needs_fixing # requires pro services + def test_delete_delivery_source(self, aws_client, snapshot, cleanups): + """Test deleting a delivery source.""" + snapshot.add_transformer(snapshot.transform.logs_api()) + source_name = f"test-ds-{short_uid()}" + + aws_client.logs.put_delivery_source( + name=source_name, + resourceArn="arn:aws:cloudfront::123456789012:distribution/E1Q5F5862X9VJ5", + logType="ACCESS_LOGS", + ) + + # Delete source + aws_client.logs.delete_delivery_source(name=source_name) + + # Verify deletion + with pytest.raises(Exception) as ctx: + aws_client.logs.get_delivery_source(name=source_name) + snapshot.match("error-after-delete", ctx.value.response) + + +class TestDeliveries: + """Tests for delivery operations (linking sources to destinations).""" + + @markers.aws.needs_fixing # requires pro services + def test_create_delivery( + self, aws_client, account_id, s3_bucket, region_name, snapshot, cleanups + ): + """Test creating a delivery.""" + source_name = f"test-ds-{short_uid()}" + destination_name = f"test-dd-{short_uid()}" + + snapshot.add_transformer(snapshot.transform.logs_api()) + snapshot.add_transformer(snapshot.transform.key_value("id")) + snapshot.add_transformer(snapshot.transform.regex(source_name, "")) + snapshot.add_transformer(snapshot.transform.regex(destination_name, "")) + + # Create source + aws_client.logs.put_delivery_source( + name=source_name, + resourceArn=f"arn:aws:cloudfront::{account_id}:distribution/E19DL18TOXN9JU", + logType="ACCESS_LOGS", + ) + cleanups.append(lambda: aws_client.logs.delete_delivery_source(name=source_name)) + + # Create destination + aws_client.logs.put_delivery_destination( + name=destination_name, + deliveryDestinationConfiguration={ + "destinationResourceArn": f"arn:aws:s3:::{s3_bucket}" + }, + ) + cleanups.append(lambda: aws_client.logs.delete_delivery_destination(name=destination_name)) + + # Create delivery + destination_arn = ( + f"arn:aws:logs:{region_name}:{account_id}:delivery-destination:{destination_name}" + ) + response = aws_client.logs.create_delivery( + deliverySourceName=source_name, + deliveryDestinationArn=destination_arn, + recordFields=["date"], + fieldDelimiter=",", + s3DeliveryConfiguration={ + "suffixPath": f"AWSLogs/{account_id}/CloudFront/", + "enableHiveCompatiblePath": True, + }, + tags={"key1": "value1"}, + ) + delivery_id = response["delivery"]["id"] + cleanups.append(lambda: aws_client.logs.delete_delivery(id=delivery_id)) + snapshot.match("create-delivery", response) + + @markers.aws.needs_fixing # requires pro services + def test_get_delivery(self, aws_client, account_id, s3_bucket, region_name, snapshot, cleanups): + """Test getting a delivery.""" + snapshot.add_transformer(snapshot.transform.logs_api()) + source_name = f"test-ds-{short_uid()}" + destination_name = f"test-dd-{short_uid()}" + + snapshot.add_transformer(snapshot.transform.key_value("id")) + snapshot.add_transformer(snapshot.transform.regex(source_name, "")) + snapshot.add_transformer(snapshot.transform.regex(destination_name, "")) + + # Create source and destination + aws_client.logs.put_delivery_source( + name=source_name, + resourceArn=f"arn:aws:cloudfront::{account_id}:distribution/E19DL18TOXN9JU", + logType="ACCESS_LOGS", + ) + cleanups.append(lambda: aws_client.logs.delete_delivery_source(name=source_name)) + + aws_client.logs.put_delivery_destination( + name=destination_name, + deliveryDestinationConfiguration={ + "destinationResourceArn": f"arn:aws:s3:::{s3_bucket}" + }, + ) + cleanups.append(lambda: aws_client.logs.delete_delivery_destination(name=destination_name)) + + # Create delivery + destination_arn = ( + f"arn:aws:logs:{region_name}:{account_id}:delivery-destination:{destination_name}" + ) + create_response = aws_client.logs.create_delivery( + deliverySourceName=source_name, + deliveryDestinationArn=destination_arn, + ) + delivery_id = create_response["delivery"]["id"] + cleanups.append(lambda: aws_client.logs.delete_delivery(id=delivery_id)) + + # Get delivery + response = aws_client.logs.get_delivery(id=delivery_id) + snapshot.match("get-delivery", response) + + @markers.aws.needs_fixing # requires pro services + def test_describe_deliveries( + self, aws_client, account_id, s3_bucket, region_name, snapshot, cleanups + ): + """Test describing deliveries.""" + source_name = f"test-ds-{short_uid()}" + destination_name = f"test-dd-{short_uid()}" + snapshot.add_transformer(snapshot.transform.logs_api()) + snapshot.add_transformer(snapshot.transform.key_value("id")) + snapshot.add_transformer(snapshot.transform.regex(source_name, "")) + snapshot.add_transformer(snapshot.transform.regex(destination_name, "")) + + # Create source + aws_client.logs.put_delivery_source( + name=source_name, + resourceArn=f"arn:aws:cloudfront::{account_id}:distribution/E19DL18TOXN9JU", + logType="ACCESS_LOGS", + ) + cleanups.append(lambda: aws_client.logs.delete_delivery_source(name=source_name)) + + # Create two destinations and deliveries + aws_client.logs.put_delivery_destination( + name=destination_name, + deliveryDestinationConfiguration={ + "destinationResourceArn": f"arn:aws:s3:::{s3_bucket}" + }, + ) + cleanups.append( + lambda dn=destination_name: aws_client.logs.delete_delivery_destination(name=dn) + ) + + destination_arn = ( + f"arn:aws:logs:{region_name}:{account_id}:delivery-destination:{destination_name}" + ) + create_response = aws_client.logs.create_delivery( + deliverySourceName=source_name, + deliveryDestinationArn=destination_arn, + ) + delivery_id = create_response["delivery"]["id"] + cleanups.append(lambda: aws_client.logs.delete_delivery(id=delivery_id)) + + response = aws_client.logs.describe_deliveries() + descriptions = [desc for desc in response["deliveries"] if desc["id"] == delivery_id] + snapshot.match("describe-deliveries", descriptions) + + @markers.aws.needs_fixing # requires pro services + def test_delete_delivery( + self, aws_client, account_id, s3_bucket, region_name, snapshot, cleanups + ): + """Test deleting a delivery.""" + snapshot.add_transformer(snapshot.transform.logs_api()) + source_name = f"test-ds-{short_uid()}" + destination_name = f"test-dd-{short_uid()}" + + # Create source and destination + aws_client.logs.put_delivery_source( + name=source_name, + resourceArn=f"arn:aws:cloudfront::{account_id}:distribution/E19DL18TOXN9JU", + logType="ACCESS_LOGS", + ) + cleanups.append(lambda: aws_client.logs.delete_delivery_source(name=source_name)) + + aws_client.logs.put_delivery_destination( + name=destination_name, + deliveryDestinationConfiguration={ + "destinationResourceArn": f"arn:aws:s3:::{s3_bucket}" + }, + ) + cleanups.append(lambda: aws_client.logs.delete_delivery_destination(name=destination_name)) + + # Create delivery + destination_arn = ( + f"arn:aws:logs:{region_name}:{account_id}:delivery-destination:{destination_name}" + ) + create_response = aws_client.logs.create_delivery( + deliverySourceName=source_name, + deliveryDestinationArn=destination_arn, + ) + delivery_id = create_response["delivery"]["id"] + + # Delete delivery + aws_client.logs.delete_delivery(id=delivery_id) + + # Verify deletion + with pytest.raises(Exception) as ctx: + aws_client.logs.get_delivery(id=delivery_id) + snapshot.match("error-after-delete", ctx.value.response) diff --git a/tests/aws/services/logs/test_logs_delivery.snapshot.json b/tests/aws/services/logs/test_logs_delivery.snapshot.json new file mode 100644 index 0000000000000..d32aff83be339 --- /dev/null +++ b/tests/aws/services/logs/test_logs_delivery.snapshot.json @@ -0,0 +1,482 @@ +{ + "tests/aws/services/logs/test_logs_delivery.py::TestDeliveryDestinations::test_put_delivery_destination": { + "recorded-date": "04-02-2026, 18:41:17", + "recorded-content": { + "put-delivery-destination": { + "deliveryDestination": { + "arn": "arn::logs::111111111111:delivery-destination:", + "deliveryDestinationConfiguration": { + "destinationResourceArn": "arn::s3:::" + }, + "deliveryDestinationType": "S3", + "name": "", + "outputFormat": "json" + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/logs/test_logs_delivery.py::TestDeliveryDestinations::test_put_delivery_destination_invalid_format": { + "recorded-date": "04-02-2026, 18:42:27", + "recorded-content": { + "error-invalid-format": { + "Error": { + "Code": "ValidationException", + "Message": "1 validation error detected: Value 'foobar' at 'outputFormat' failed to satisfy constraint: Member must satisfy enum value set: [w3c, raw, json, plain, parquet]" + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + } + } + }, + "tests/aws/services/logs/test_logs_delivery.py::TestDeliveryDestinations::test_put_delivery_destination_update": { + "recorded-date": "04-02-2026, 18:45:52", + "recorded-content": { + "put-delivery-destination-update": { + "deliveryDestination": { + "arn": "arn::logs::111111111111:delivery-destination:", + "deliveryDestinationConfiguration": { + "destinationResourceArn": "arn::s3:::" + }, + "deliveryDestinationType": "S3", + "name": "" + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/logs/test_logs_delivery.py::TestDeliveryDestinations::test_get_delivery_destination": { + "recorded-date": "04-02-2026, 18:47:50", + "recorded-content": { + "get-delivery-destination": { + "deliveryDestination": { + "arn": "arn::logs::111111111111:delivery-destination:", + "deliveryDestinationConfiguration": { + "destinationResourceArn": "arn::s3:::" + }, + "deliveryDestinationType": "S3", + "name": "" + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/logs/test_logs_delivery.py::TestDeliveryDestinations::test_get_delivery_destination_not_found": { + "recorded-date": "04-02-2026, 18:48:32", + "recorded-content": { + "error-not-found": { + "Error": { + "Code": "ResourceNotFoundException", + "Message": "Requested Delivery Destination does not exist in this account." + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + } + } + }, + "tests/aws/services/logs/test_logs_delivery.py::TestDeliveryDestinations::test_describe_delivery_destinations": { + "recorded-date": "04-02-2026, 18:54:13", + "recorded-content": { + "describe-delivery-destinations": [ + { + "name": "", + "arn": "arn::logs::111111111111:delivery-destination:", + "deliveryDestinationType": "S3", + "deliveryDestinationConfiguration": { + "destinationResourceArn": "arn::s3:::" + } + }, + { + "name": "", + "arn": "arn::logs::111111111111:delivery-destination:", + "deliveryDestinationType": "S3", + "deliveryDestinationConfiguration": { + "destinationResourceArn": "arn::s3:::" + } + } + ] + } + }, + "tests/aws/services/logs/test_logs_delivery.py::TestDeliveryDestinations::test_delete_delivery_destination": { + "recorded-date": "04-02-2026, 18:57:39", + "recorded-content": { + "error-after-delete": { + "Error": { + "Code": "ResourceNotFoundException", + "Message": "Requested Delivery Destination does not exist in this account." + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + } + } + }, + "tests/aws/services/logs/test_logs_delivery.py::TestDeliveryDestinations::test_delete_delivery_destination_not_found": { + "recorded-date": "04-02-2026, 18:58:37", + "recorded-content": { + "error-not-found": { + "Error": { + "Code": "ResourceNotFoundException", + "Message": "Requested Delivery Destination does not exist in this account." + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + } + } + }, + "tests/aws/services/logs/test_logs_delivery.py::TestDeliveryDestinationPolicies::test_put_delivery_destination_policy": { + "recorded-date": "04-02-2026, 19:02:04", + "recorded-content": { + "put-delivery-destination-policy": { + "policy": { + "deliveryDestinationPolicy": { + "Version": "2012-10-17", + "Statement": [ + { + "Sid": "AllowLogDeliveryActions", + "Effect": "Allow", + "Principal": { + "AWS": "arn::iam::111111111111:root" + }, + "Action": "logs:CreateDelivery", + "Resource": [ + "arn::logs::111111111111:delivery-source:*", + "arn::logs::111111111111:delivery:*", + "arn::logs::111111111111:delivery-destination:*" + ] + } + ] + } + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/logs/test_logs_delivery.py::TestDeliveryDestinationPolicies::test_get_delivery_destination_policy": { + "recorded-date": "04-02-2026, 19:03:14", + "recorded-content": { + "get-delivery-destination-policy": { + "policy": { + "deliveryDestinationPolicy": { + "Version": "2012-10-17", + "Statement": [ + { + "Sid": "AllowLogDeliveryActions", + "Effect": "Allow", + "Principal": { + "AWS": "arn::iam::111111111111:root" + }, + "Action": "logs:CreateDelivery", + "Resource": [ + "arn::logs::111111111111:delivery-source:*", + "arn::logs::111111111111:delivery:*", + "arn::logs::111111111111:delivery-destination:*" + ] + } + ] + } + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/logs/test_logs_delivery.py::TestDeliveryDestinationPolicies::test_delete_delivery_destination_policy": { + "recorded-date": "04-02-2026, 19:09:00", + "recorded-content": {} + }, + "tests/aws/services/logs/test_logs_delivery.py::TestDeliverySources::test_put_delivery_source": { + "recorded-date": "04-02-2026, 19:21:24", + "recorded-content": { + "put-delivery-source": { + "deliverySource": { + "arn": "arn::logs::111111111111:delivery-source:", + "logType": "ACCESS_LOGS", + "name": "", + "resourceArns": [ + "arn::cloudfront::111111111111:distribution/E1Q5F5862X9VJ5" + ], + "service": "cloudfront", + "tags": { + "key1": "value1" + } + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/logs/test_logs_delivery.py::TestDeliverySources::test_put_delivery_source_invalid_resource": { + "recorded-date": "04-02-2026, 19:22:17", + "recorded-content": { + "error-invalid-resource": { + "Error": { + "Code": "ResourceNotFoundException", + "Message": "Cannot access provided service." + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + } + } + }, + "tests/aws/services/logs/test_logs_delivery.py::TestDeliverySources::test_get_delivery_source": { + "recorded-date": "04-02-2026, 19:28:05", + "recorded-content": { + "get-delivery-source": { + "deliverySource": { + "arn": "arn::logs::111111111111:delivery-source:", + "logType": "ACCESS_LOGS", + "name": "", + "resourceArns": [ + "arn::cloudfront::111111111111:distribution/E1Q5F5862X9VJ5" + ], + "service": "cloudfront" + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/logs/test_logs_delivery.py::TestDeliverySources::test_get_delivery_source_not_found": { + "recorded-date": "04-02-2026, 19:28:39", + "recorded-content": { + "error-not-found": { + "Error": { + "Code": "ResourceNotFoundException", + "Message": "Requested Delivery Source does not exist in this account." + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + } + } + }, + "tests/aws/services/logs/test_logs_delivery.py::TestDeliverySources::test_describe_delivery_sources": { + "recorded-date": "04-02-2026, 19:32:38", + "recorded-content": { + "describe-delivery-sources": { + "deliverySources": [ + { + "arn": "arn::logs::111111111111:delivery-source:", + "logType": "ACCESS_LOGS", + "name": "", + "resourceArns": [ + "arn::cloudfront::123456789012:distribution/E19DL18TOXN9JU" + ], + "service": "cloudfront" + }, + { + "arn": "arn::logs::111111111111:delivery-source:", + "logType": "ACCESS_LOGS", + "name": "", + "resourceArns": [ + "arn::cloudfront::123456789012:distribution/E19DL18TOXN9JU" + ], + "service": "cloudfront" + } + ], + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/logs/test_logs_delivery.py::TestDeliverySources::test_delete_delivery_source": { + "recorded-date": "04-02-2026, 19:33:56", + "recorded-content": { + "error-after-delete": { + "Error": { + "Code": "ResourceNotFoundException", + "Message": "Requested Delivery Source does not exist in this account.." + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + } + } + }, + "tests/aws/services/logs/test_logs_delivery.py::TestDeliveries::test_create_delivery": { + "recorded-date": "04-02-2026, 19:50:15", + "recorded-content": { + "create-delivery": { + "delivery": { + "arn": "arn::logs::111111111111:delivery:", + "deliveryDestinationArn": "arn::logs::111111111111:delivery-destination:", + "deliveryDestinationType": "S3", + "deliverySourceName": "", + "fieldDelimiter": ",", + "id": "", + "recordFields": [ + "date" + ], + "s3DeliveryConfiguration": { + "enableHiveCompatiblePath": true, + "suffixPath": "AWSLogs/111111111111/CloudFront/" + }, + "tags": { + "key1": "value1" + } + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/logs/test_logs_delivery.py::TestDeliveries::test_get_delivery": { + "recorded-date": "04-02-2026, 19:51:24", + "recorded-content": { + "get-delivery": { + "delivery": { + "arn": "arn::logs::111111111111:delivery:", + "deliveryDestinationArn": "arn::logs::111111111111:delivery-destination:", + "deliveryDestinationType": "S3", + "deliverySourceName": "", + "id": "", + "recordFields": [ + "date", + "time", + "x-edge-location", + "sc-bytes", + "c-ip", + "cs-method", + "cs(Host)", + "cs-uri-stem", + "sc-status", + "cs(Referer)", + "cs(User-Agent)", + "cs-uri-query", + "cs(Cookie)", + "x-edge-result-type", + "x-edge-request-id", + "x-host-header", + "cs-protocol", + "cs-bytes", + "time-taken", + "x-forwarded-for", + "ssl-protocol", + "ssl-cipher", + "x-edge-response-result-type", + "cs-protocol-version", + "fle-status", + "fle-encrypted-fields", + "c-port", + "time-to-first-byte", + "x-edge-detailed-result-type", + "sc-content-type", + "sc-content-len", + "sc-range-start", + "sc-range-end" + ], + "s3DeliveryConfiguration": { + "enableHiveCompatiblePath": false, + "suffixPath": "AWSLogs/{account-id}/CloudFront/" + } + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/logs/test_logs_delivery.py::TestDeliveries::test_describe_deliveries": { + "recorded-date": "04-02-2026, 20:05:35", + "recorded-content": { + "describe-deliveries": [ + { + "id": "", + "arn": "arn::logs::111111111111:delivery:", + "deliverySourceName": "", + "deliveryDestinationArn": "arn::logs::111111111111:delivery-destination:", + "deliveryDestinationType": "S3", + "recordFields": [ + "date", + "time", + "x-edge-location", + "sc-bytes", + "c-ip", + "cs-method", + "cs(Host)", + "cs-uri-stem", + "sc-status", + "cs(Referer)", + "cs(User-Agent)", + "cs-uri-query", + "cs(Cookie)", + "x-edge-result-type", + "x-edge-request-id", + "x-host-header", + "cs-protocol", + "cs-bytes", + "time-taken", + "x-forwarded-for", + "ssl-protocol", + "ssl-cipher", + "x-edge-response-result-type", + "cs-protocol-version", + "fle-status", + "fle-encrypted-fields", + "c-port", + "time-to-first-byte", + "x-edge-detailed-result-type", + "sc-content-type", + "sc-content-len", + "sc-range-start", + "sc-range-end" + ], + "s3DeliveryConfiguration": { + "suffixPath": "AWSLogs/{account-id}/CloudFront/", + "enableHiveCompatiblePath": false + } + } + ] + } + }, + "tests/aws/services/logs/test_logs_delivery.py::TestDeliveries::test_delete_delivery": { + "recorded-date": "04-02-2026, 20:06:50", + "recorded-content": { + "error-after-delete": { + "Error": { + "Code": "ResourceNotFoundException", + "Message": "Requested Delivery does not exist in this account." + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + } + } + } +} diff --git a/tests/aws/services/logs/test_logs_delivery.validation.json b/tests/aws/services/logs/test_logs_delivery.validation.json new file mode 100644 index 0000000000000..4087640cdd050 --- /dev/null +++ b/tests/aws/services/logs/test_logs_delivery.validation.json @@ -0,0 +1,119 @@ +{ + "tests/aws/services/logs/test_logs_delivery.py::TestDeliveryDestinationPolicies::test_delete_delivery_destination_policy": { + "last_validated_date": "2026-02-04T19:09:01+00:00", + "durations_in_seconds": { + "setup": 0.82, + "call": 0.9, + "teardown": 0.57, + "total": 2.29 + } + }, + "tests/aws/services/logs/test_logs_delivery.py::TestDeliveryDestinationPolicies::test_get_delivery_destination_policy": { + "last_validated_date": "2026-02-04T19:03:14+00:00", + "durations_in_seconds": { + "setup": 0.95, + "call": 0.73, + "teardown": 0.68, + "total": 2.36 + } + }, + "tests/aws/services/logs/test_logs_delivery.py::TestDeliveryDestinationPolicies::test_put_delivery_destination_policy": { + "last_validated_date": "2026-02-04T19:02:04+00:00", + "durations_in_seconds": { + "setup": 0.88, + "call": 0.62, + "teardown": 0.74, + "total": 2.24 + } + }, + "tests/aws/services/logs/test_logs_delivery.py::TestDeliveryDestinations::test_delete_delivery_destination": { + "last_validated_date": "2026-02-04T18:57:39+00:00", + "durations_in_seconds": { + "setup": 0.89, + "call": 0.78, + "teardown": 0.49, + "total": 2.16 + } + }, + "tests/aws/services/logs/test_logs_delivery.py::TestDeliveryDestinations::test_delete_delivery_destination_not_found": { + "last_validated_date": "2026-02-04T18:58:37+00:00", + "durations_in_seconds": { + "setup": 0.37, + "call": 0.44, + "teardown": 0.0, + "total": 0.81 + } + }, + "tests/aws/services/logs/test_logs_delivery.py::TestDeliveryDestinations::test_describe_delivery_destinations": { + "last_validated_date": "2026-02-04T18:54:13+00:00", + "durations_in_seconds": { + "setup": 0.85, + "call": 0.82, + "teardown": 0.82, + "total": 2.49 + } + }, + "tests/aws/services/logs/test_logs_delivery.py::TestDeliveryDestinations::test_get_delivery_destination": { + "last_validated_date": "2026-02-04T18:47:50+00:00", + "durations_in_seconds": { + "setup": 0.87, + "call": 0.64, + "teardown": 0.67, + "total": 2.18 + } + }, + "tests/aws/services/logs/test_logs_delivery.py::TestDeliveryDestinations::test_get_delivery_destination_not_found": { + "last_validated_date": "2026-02-04T18:48:32+00:00", + "durations_in_seconds": { + "setup": 0.36, + "call": 0.42, + "teardown": 0.0, + "total": 0.78 + } + }, + "tests/aws/services/logs/test_logs_delivery.py::TestDeliveryDestinations::test_put_delivery_destination": { + "last_validated_date": "2026-02-04T18:41:17+00:00", + "durations_in_seconds": { + "setup": 0.88, + "call": 0.49, + "teardown": 0.69, + "total": 2.06 + } + }, + "tests/aws/services/logs/test_logs_delivery.py::TestDeliveryDestinations::test_put_delivery_destination_invalid_format": { + "last_validated_date": "2026-02-04T18:42:27+00:00", + "durations_in_seconds": { + "setup": 0.94, + "call": 0.39, + "teardown": 0.52, + "total": 1.85 + } + }, + "tests/aws/services/logs/test_logs_delivery.py::TestDeliveryDestinations::test_put_delivery_destination_update": { + "last_validated_date": "2026-02-04T18:45:52+00:00", + "durations_in_seconds": { + "setup": 0.87, + "call": 1.09, + "teardown": 1.18, + "total": 3.14 + } + }, + "tests/aws/services/logs/test_logs_delivery.py::TestDeliverySources::test_get_delivery_source_not_found": { + "last_validated_date": "2026-02-04T19:28:51+00:00", + "durations_in_seconds": { + "setup": 0.37, + "call": 0.43, + "teardown": 0.0, + "total": 0.8 + } + }, + "tests/aws/services/logs/test_logs_delivery.py::TestDeliverySources::test_put_delivery_source_invalid_resource": { + "last_validated_date": "2026-02-04T19:22:17+00:00", + "durations_in_seconds": { + "setup": 0.39, + "call": 0.43, + "teardown": 0.0, + "total": 0.82 + } + } +} diff --git a/tests/aws/services/logs/test_logs_destinations.py b/tests/aws/services/logs/test_logs_destinations.py new file mode 100644 index 0000000000000..9b3d447c3d232 --- /dev/null +++ b/tests/aws/services/logs/test_logs_destinations.py @@ -0,0 +1,313 @@ +"""Tests for CloudWatch Logs - Destination operations (cross-account log delivery).""" + +import json + +import pytest + +from localstack.testing.aws.util import is_aws_cloud +from localstack.testing.pytest import markers +from localstack.utils.common import short_uid +from localstack.utils.sync import retry + +ACCESS_POLICY_DOC = json.dumps( + { + "Version": "2012-10-17", + "Statement": [ + { + "Effect": "Allow", + "Principal": {"AWS": "logs.amazonaws.com"}, + "Action": "logs:PutSubscriptionFilter", + "Resource": "destination_arn", + } + ], + } +) + + +@pytest.fixture +def kinesis_stream_arn(aws_client, kinesis_create_stream, wait_for_stream_ready) -> str: + stream_name = kinesis_create_stream() + wait_for_stream_ready(stream_name) + return aws_client.kinesis.describe_stream(StreamName=stream_name)["StreamDescription"][ + "StreamARN" + ] + + +@pytest.fixture +def destination_role(aws_client, create_iam_role_with_policy, kinesis_stream_arn): + role = create_iam_role_with_policy( + RoleName=f"role-logs-{short_uid()}", + PolicyName=f"policy-logs-{short_uid()}", + RoleDefinition={ + "Version": "2012-10-17", + "Statement": [ + { + "Effect": "Allow", + "Principal": {"Service": "logs.amazonaws.com"}, + "Action": "sts:AssumeRole", + } + ], + }, + PolicyDefinition={ + "Version": "2012-10-17", + "Statement": [ + {"Effect": "Allow", "Action": "kinesis:*", "Resource": kinesis_stream_arn} + ], + }, + ) + + if is_aws_cloud(): + # This operation is to confirm role propagation withing AWS + def _assume_role(): + try: + aws_client.sts.assume_role( + RoleArn=role, + RoleSessionName="check", + ) + return True + except Exception: + # AccessDenied means role exists but we can't assume it (expected for service roles) + # Other errors might mean role not propagated yet + return False + + retry(_assume_role, sleep_before=1, sleep=2, retries=10) + return role + + +def _retry_put_destination(aws_client, **kwargs): + def put_destination(): + resp = aws_client.logs.put_destination( + destinationName=kwargs["destinationName"], + targetArn=kwargs["targetArn"], + roleArn=kwargs["roleArn"], + tags=kwargs.get("tags", {"tag": "test"}), + ) + return resp + + return retry(put_destination, retries=5, sleep=3 if is_aws_cloud() else 1) + + +class TestDestinations: + """Tests for destination operations.""" + + @markers.aws.validated + def test_put_destination( + self, aws_client, snapshot, cleanups, kinesis_stream_arn, destination_role + ): + """Test creating a destination.""" + destination_name = f"test-destination-{short_uid()}" + role_arn = destination_role + target_arn = kinesis_stream_arn + + snapshot.add_transformer(snapshot.transform.logs_api()) + snapshot.add_transformer(snapshot.transform.regex(destination_name, "")) + snapshot.add_transformer(snapshot.transform.regex(role_arn.split("/")[-1], "")) + snapshot.add_transformer( + snapshot.transform.regex(target_arn.split("/")[-1], "") + ) + + response = _retry_put_destination( + aws_client, + destinationName=destination_name, + targetArn=target_arn, + roleArn=role_arn, + tags={"Name": destination_name}, + ) + cleanups.append( + lambda: aws_client.logs.delete_destination(destinationName=destination_name) + ) + + # IAM Role takes time to propagate in AWS causing a client error + snapshot.match("put-destination", response) + + @markers.aws.validated + def test_describe_destinations_empty(self, aws_client, snapshot): + """Test describing destinations when none exist with a given prefix.""" + response = aws_client.logs.describe_destinations( + DestinationNamePrefix=f"non-existent-{short_uid()}" + ) + snapshot.match("describe-destinations-empty", response) + + @markers.aws.validated + def test_describe_destinations_with_prefix( + self, aws_client, snapshot, destination_role, kinesis_stream_arn, cleanups + ): + """Test describing destinations with prefix filter.""" + prefix = f"test-dest-{short_uid()}" + role_arn = destination_role + target_arn = kinesis_stream_arn + + snapshot.add_transformer(snapshot.transform.logs_api()) + snapshot.add_transformer(snapshot.transform.regex(prefix, "")) + snapshot.add_transformer(snapshot.transform.regex(role_arn.split("/")[-1], "")) + snapshot.add_transformer( + snapshot.transform.regex(target_arn.split("/")[-1], "") + ) + + _retry_put_destination( + aws_client, + destinationName=prefix, + targetArn=target_arn, + roleArn=role_arn, + tags={"Name": prefix}, + ) + cleanups.append(lambda: aws_client.logs.delete_destination(destinationName=prefix)) + + response = aws_client.logs.describe_destinations(DestinationNamePrefix=prefix) + snapshot.match("describe-destinations", response) + + @markers.aws.validated + def test_update_destination( + self, aws_client, snapshot, destination_role, kinesis_stream_arn, cleanups + ): + """Test updating a destination's target and role ARNs.""" + destination_name = f"test-destination-{short_uid()}" + snapshot.add_transformer(snapshot.transform.logs_api()) + snapshot.add_transformer(snapshot.transform.regex(destination_name, "")) + snapshot.add_transformer( + snapshot.transform.regex(destination_role.split("/")[-1], "") + ) + snapshot.add_transformer( + snapshot.transform.regex(kinesis_stream_arn.split("/")[-1], "") + ) + + _retry_put_destination( + aws_client, + destinationName=destination_name, + roleArn=destination_role, + targetArn=kinesis_stream_arn, + ) + cleanups.append( + lambda: aws_client.logs.delete_destination(destinationName=destination_name) + ) + + response = aws_client.logs.describe_destinations(DestinationNamePrefix=destination_name) + snapshot.match("original-description", response) + + # Update destination + _retry_put_destination( + aws_client, + destinationName=destination_name, + roleArn=destination_role, + targetArn=kinesis_stream_arn, + tags={"tag1": "value1"}, + ) + + # Verify update + response = aws_client.logs.describe_destinations(DestinationNamePrefix=destination_name) + snapshot.match("updated-description", response) + + @markers.aws.validated + def test_put_destination_policy( + self, aws_client, snapshot, destination_role, kinesis_stream_arn, cleanups + ): + """Test setting an access policy on a destination.""" + destination_name = f"test-destination-{short_uid()}" + snapshot.add_transformer(snapshot.transform.logs_api()) + snapshot.add_transformer(snapshot.transform.regex(destination_name, "")) + snapshot.add_transformer( + snapshot.transform.regex(destination_role.split("/")[-1], "") + ) + snapshot.add_transformer( + snapshot.transform.regex(kinesis_stream_arn.split("/")[-1], "") + ) + + _retry_put_destination( + aws_client, + destinationName=destination_name, + targetArn=kinesis_stream_arn, + roleArn=destination_role, + ) + cleanups.append( + lambda: aws_client.logs.delete_destination(destinationName=destination_name) + ) + + # Put access policy + policy = ACCESS_POLICY_DOC.replace("destination_arn", kinesis_stream_arn) + + response = aws_client.logs.put_destination_policy( + destinationName=destination_name, accessPolicy=policy + ) + snapshot.match("put-destination-policy", response) + + # Verify policy is set + response = aws_client.logs.describe_destinations(DestinationNamePrefix=destination_name) + snapshot.match("destination-with-policy", response) + + @markers.aws.validated + def test_delete_destination( + self, aws_client, destination_role, kinesis_stream_arn, snapshot, cleanups + ): + """Test deleting a destination.""" + destination_name = f"test-dest-{short_uid()}" + snapshot.add_transformer(snapshot.transform.logs_api()) + snapshot.add_transformer(snapshot.transform.regex(destination_name, "")) + snapshot.add_transformer( + snapshot.transform.regex(destination_role.split("/")[-1], "") + ) + snapshot.add_transformer( + snapshot.transform.regex(kinesis_stream_arn.split("/")[-1], "") + ) + + _retry_put_destination( + aws_client, + destinationName=destination_name, + targetArn=kinesis_stream_arn, + roleArn=destination_role, + ) + + # Delete destination + response = aws_client.logs.delete_destination(destinationName=destination_name) + snapshot.match("delete-destination", response) + + # Verify deletion + response = aws_client.logs.describe_destinations(DestinationNamePrefix=destination_name) + snapshot.match("no-destination-found", response) + + +class TestDestinationsTags: + """Tests for destination tagging operations.""" + + @markers.aws.validated + @pytest.mark.skip(reason="TODO list tags returns empty") + def test_destination_tags( + self, aws_client, snapshot, cleanups, destination_role, kinesis_stream_arn + ): + """Test tagging operations on destinations.""" + destination_name = f"test-destination-{short_uid()}" + snapshot.add_transformer(snapshot.transform.logs_api()) + snapshot.add_transformer(snapshot.transform.regex(destination_name, "")) + snapshot.add_transformer( + snapshot.transform.regex(destination_role.split("/")[-1], "") + ) + snapshot.add_transformer( + snapshot.transform.regex(kinesis_stream_arn.split("/")[-1], "") + ) + + # Create destination with initial tag + response = _retry_put_destination( + aws_client, + destinationName=destination_name, + targetArn=kinesis_stream_arn, + roleArn=destination_role, + tags={"key1": "val1"}, + ) + destination_arn = response["destination"]["arn"] + cleanups.append( + lambda: aws_client.logs.delete_destination(destinationName=destination_name) + ) + + # Add more tags + aws_client.logs.tag_resource(resourceArn=destination_arn, tags={"key2": "val2"}) + + # List tags + response = aws_client.logs.list_tags_for_resource(resourceArn=destination_arn) + snapshot.match("list-tags-after-add", response) + assert response["tags"] == {"key1": "val1", "key2": "val2"} + + # Remove a tag + aws_client.logs.untag_resource(resourceArn=destination_arn, tagKeys=["key2"]) + + response = aws_client.logs.list_tags_for_resource(resourceArn=destination_arn) + snapshot.match("list-tags-after-remove", response) + assert response["tags"] == {"key1": "val1"} diff --git a/tests/aws/services/logs/test_logs_destinations.snapshot.json b/tests/aws/services/logs/test_logs_destinations.snapshot.json new file mode 100644 index 0000000000000..63dd3ac37e65f --- /dev/null +++ b/tests/aws/services/logs/test_logs_destinations.snapshot.json @@ -0,0 +1,168 @@ +{ + "tests/aws/services/logs/test_logs_destinations.py::TestDestinations::test_put_destination": { + "recorded-date": "05-02-2026, 15:14:39", + "recorded-content": { + "put-destination": { + "destination": { + "arn": "arn::logs::111111111111:destination:", + "creationTime": "timestamp", + "destinationName": "", + "roleArn": "arn::iam::111111111111:role/", + "targetArn": "arn::kinesis::111111111111:stream/" + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/logs/test_logs_destinations.py::TestDestinations::test_describe_destinations_empty": { + "recorded-date": "04-02-2026, 21:49:47", + "recorded-content": { + "describe-destinations-empty": { + "destinations": [], + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/logs/test_logs_destinations.py::TestDestinations::test_describe_destinations_with_prefix": { + "recorded-date": "05-02-2026, 15:15:49", + "recorded-content": { + "describe-destinations": { + "destinations": [ + { + "arn": "arn::logs::111111111111:destination:", + "creationTime": "timestamp", + "destinationName": "", + "roleArn": "arn::iam::111111111111:role/", + "targetArn": "arn::kinesis::111111111111:stream/" + } + ], + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/logs/test_logs_destinations.py::TestDestinations::test_update_destination": { + "recorded-date": "05-02-2026, 15:16:48", + "recorded-content": { + "original-description": { + "destinations": [ + { + "arn": "arn::logs::111111111111:destination:", + "creationTime": "timestamp", + "destinationName": "", + "roleArn": "arn::iam::111111111111:role/", + "targetArn": "arn::kinesis::111111111111:stream/" + } + ], + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "updated-description": { + "destinations": [ + { + "arn": "arn::logs::111111111111:destination:", + "creationTime": "timestamp", + "destinationName": "", + "roleArn": "arn::iam::111111111111:role/", + "targetArn": "arn::kinesis::111111111111:stream/" + } + ], + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/logs/test_logs_destinations.py::TestDestinations::test_put_destination_policy": { + "recorded-date": "18-02-2026, 19:55:08", + "recorded-content": { + "put-destination-policy": { + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "destination-with-policy": { + "destinations": [ + { + "accessPolicy": { + "Version": "2012-10-17", + "Statement": [ + { + "Effect": "Allow", + "Principal": { + "AWS": "logs.amazonaws.com" + }, + "Action": "logs:PutSubscriptionFilter", + "Resource": "arn::kinesis::111111111111:stream/" + } + ] + }, + "arn": "arn::logs::111111111111:destination:", + "creationTime": "timestamp", + "destinationName": "", + "roleArn": "arn::iam::111111111111:role/", + "targetArn": "arn::kinesis::111111111111:stream/" + } + ], + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/logs/test_logs_destinations.py::TestDestinations::test_delete_destination": { + "recorded-date": "05-02-2026, 15:41:43", + "recorded-content": { + "delete-destination": { + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "no-destination-found": { + "destinations": [], + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/logs/test_logs_destinations.py::TestDestinationsTags::test_destination_tags": { + "recorded-date": "05-02-2026, 15:45:33", + "recorded-content": { + "list-tags-after-add": { + "tags": { + "key1": "val1", + "key2": "val2" + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "list-tags-after-remove": { + "tags": { + "key1": "val1" + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + } +} diff --git a/tests/aws/services/logs/test_logs_destinations.validation.json b/tests/aws/services/logs/test_logs_destinations.validation.json new file mode 100644 index 0000000000000..ef5e13e7e66d7 --- /dev/null +++ b/tests/aws/services/logs/test_logs_destinations.validation.json @@ -0,0 +1,65 @@ +{ + "tests/aws/services/logs/test_logs_destinations.py::TestDestinations::test_delete_destination": { + "last_validated_date": "2026-02-05T15:41:43+00:00", + "durations_in_seconds": { + "setup": 7.86, + "call": 10.18, + "teardown": 0.68, + "total": 18.72 + } + }, + "tests/aws/services/logs/test_logs_destinations.py::TestDestinations::test_describe_destinations_empty": { + "last_validated_date": "2026-02-04T21:49:47+00:00", + "durations_in_seconds": { + "setup": 0.38, + "call": 0.38, + "teardown": 0.0, + "total": 0.76 + } + }, + "tests/aws/services/logs/test_logs_destinations.py::TestDestinations::test_describe_destinations_with_prefix": { + "last_validated_date": "2026-02-05T15:15:49+00:00", + "durations_in_seconds": { + "setup": 6.65, + "call": 10.14, + "teardown": 0.81, + "total": 17.6 + } + }, + "tests/aws/services/logs/test_logs_destinations.py::TestDestinations::test_put_destination": { + "last_validated_date": "2026-02-05T15:14:39+00:00", + "durations_in_seconds": { + "setup": 7.3, + "call": 6.85, + "teardown": 0.83, + "total": 14.98 + } + }, + "tests/aws/services/logs/test_logs_destinations.py::TestDestinations::test_put_destination_policy": { + "last_validated_date": "2026-02-18T19:55:08+00:00", + "durations_in_seconds": { + "setup": 6.6, + "call": 10.21, + "teardown": 0.76, + "total": 17.57 + } + }, + "tests/aws/services/logs/test_logs_destinations.py::TestDestinations::test_update_destination": { + "last_validated_date": "2026-02-05T15:16:48+00:00", + "durations_in_seconds": { + "setup": 6.66, + "call": 7.16, + "teardown": 0.95, + "total": 14.77 + } + }, + "tests/aws/services/logs/test_logs_destinations.py::TestDestinationsTags::test_destination_tags": { + "last_validated_date": "2026-02-05T15:45:33+00:00", + "durations_in_seconds": { + "setup": 6.12, + "call": 7.15, + "teardown": 0.94, + "total": 14.21 + } + } +} diff --git a/tests/aws/services/logs/test_logs_events.py b/tests/aws/services/logs/test_logs_events.py new file mode 100644 index 0000000000000..97a44bc704b38 --- /dev/null +++ b/tests/aws/services/logs/test_logs_events.py @@ -0,0 +1,270 @@ +"""Tests for CloudWatch Logs - Log Event operations.""" + +import pytest +from localstack_snapshot.pytest.snapshot import is_aws + +from localstack.testing.pytest import markers +from localstack.utils.common import now_utc, retry, short_uid + + +class TestLogsEvents: + """Tests for put and get log event operations.""" + + @markers.aws.validated + def test_put_log_events_basic(self, logs_log_group, logs_log_stream, aws_client): + """Test basic log event insertion.""" + timestamp = now_utc(millis=True) + messages = [ + {"timestamp": timestamp, "message": "hello"}, + {"timestamp": timestamp, "message": "world"}, + ] + + response = aws_client.logs.put_log_events( + logGroupName=logs_log_group, logStreamName=logs_log_stream, logEvents=messages + ) + assert response["ResponseMetadata"]["HTTPStatusCode"] == 200 + + # Verify nextSequenceToken is returned + next_sequence_token = response.get("nextSequenceToken") + if next_sequence_token: + assert isinstance(next_sequence_token, str) + + @markers.aws.validated + def test_put_events_multi_bytes_msg(self, logs_log_group, logs_log_stream, aws_client): + """Test log events with multi-byte characters (Unicode).""" + body_msg = "🙀 - 参よ - 日本語" + events = [{"timestamp": now_utc(millis=True), "message": body_msg}] + + response = aws_client.logs.put_log_events( + logGroupName=logs_log_group, logStreamName=logs_log_stream, logEvents=events + ) + assert response["ResponseMetadata"]["HTTPStatusCode"] == 200 + + def get_log_events(): + events = aws_client.logs.get_log_events( + logGroupName=logs_log_group, logStreamName=logs_log_stream + )["events"] + assert events[0]["message"] == body_msg + + retry( + get_log_events, + retries=20 if is_aws() else 3, + sleep=5 if is_aws() else 1, + sleep_before=3 if is_aws() else 0, + ) + + @markers.aws.validated + def test_put_log_events_to_invalid_stream(self, logs_log_group, aws_client, snapshot): + """Test that putting events to non-existent stream raises error.""" + with pytest.raises(Exception) as ctx: + aws_client.logs.put_log_events( + logGroupName=logs_log_group, + logStreamName="invalid-stream", + logEvents=[{"timestamp": now_utc(millis=True), "message": "test"}], + ) + snapshot.match("error-invalid-stream", ctx.value.response) + + @markers.aws.validated + def test_put_log_events_wrong_order( + self, logs_log_group, logs_log_stream, aws_client, snapshot + ): + """Test that events in wrong chronological order are rejected.""" + ts_1 = now_utc(millis=True) + ts_2 = now_utc(millis=True) - 86400000 * 2 # 2 days ago + + messages = [ + {"message": "Message 0", "timestamp": ts_1}, + {"message": "Message 1", "timestamp": ts_2}, # Older timestamp after newer one + ] + + with pytest.raises(Exception) as ctx: + aws_client.logs.put_log_events( + logGroupName=logs_log_group, logStreamName=logs_log_stream, logEvents=messages + ) + snapshot.match("error-wrong-order", ctx.value.response) + + @markers.aws.validated + def test_put_log_events_too_old(self, logs_log_group, logs_log_stream, aws_client, snapshot): + """Test that events with timestamps too far in the past are rejected.""" + # Event from 15 days ago + timestamp = now_utc(millis=True) - 86400000 * 30 + + messages = [{"message": "Old message", "timestamp": timestamp}] + + response = aws_client.logs.put_log_events( + logGroupName=logs_log_group, logStreamName=logs_log_stream, logEvents=messages + ) + snapshot.add_transformer(snapshot.transform.key_value("nextSequenceToken")) + snapshot.add_transformer( + snapshot.transform.key_value("tooOldLogEventEndIndex", reference_replacement=False) + ) + snapshot.match("response-too-old", response) + + @markers.aws.validated + def test_put_log_events_too_new(self, logs_log_group, logs_log_stream, aws_client, snapshot): + """Test that events with timestamps too far in the future are rejected.""" + # Event 3 hours in the future (>180 minutes) + timestamp = now_utc(millis=True) + 86400000 * 1 + + messages = [{"message": "Future message", "timestamp": timestamp}] + + response = aws_client.logs.put_log_events( + logGroupName=logs_log_group, logStreamName=logs_log_stream, logEvents=messages + ) + snapshot.add_transformer(snapshot.transform.key_value("nextSequenceToken")) + snapshot.add_transformer( + snapshot.transform.key_value("tooNewLogEventStartIndex", reference_replacement=False) + ) + snapshot.match("response-too-new", response) + + @markers.aws.validated + def test_get_log_events_basic(self, logs_log_group, logs_log_stream, aws_client): + """Test basic log event retrieval.""" + timestamp = now_utc(millis=True) + messages = [ + {"timestamp": timestamp, "message": "message 1"}, + {"timestamp": timestamp + 100, "message": "message 2"}, + ] + + aws_client.logs.put_log_events( + logGroupName=logs_log_group, logStreamName=logs_log_stream, logEvents=messages + ) + + def verify_events(): + response = aws_client.logs.get_log_events( + logGroupName=logs_log_group, logStreamName=logs_log_stream + ) + events = response["events"] + assert len(events) == 2 + assert events[0]["message"] == "message 1" + assert events[1]["message"] == "message 2" + + retry( + verify_events, + retries=20 if is_aws() else 3, + sleep=5 if is_aws() else 1, + sleep_before=3 if is_aws() else 0, + ) + + @markers.aws.validated + def test_get_log_events_start_from_head(self, logs_log_group, logs_log_stream, aws_client): + """Test log event retrieval with startFromHead=True.""" + timestamp = now_utc(millis=True) + messages = [ + {"timestamp": timestamp + i * 100, "message": f"message {i}"} for i in range(20) + ] + + aws_client.logs.put_log_events( + logGroupName=logs_log_group, logStreamName=logs_log_stream, logEvents=messages + ) + + def verify_events(): + response = aws_client.logs.get_log_events( + logGroupName=logs_log_group, + logStreamName=logs_log_stream, + limit=10, + startFromHead=True, + ) + events = response["events"] + assert len(events) == 10 + # First event should be message 0 when starting from head + assert events[0]["message"] == "message 0" + return response + + retry( + verify_events, + retries=20 if is_aws() else 3, + sleep=5 if is_aws() else 1, + sleep_before=3 if is_aws() else 0, + ) + + @markers.aws.validated + def test_get_log_events_invalid_token( + self, logs_log_group, logs_log_stream, aws_client, snapshot + ): + """Test that invalid nextToken is rejected.""" + with pytest.raises(Exception) as ctx: + aws_client.logs.get_log_events( + logGroupName=logs_log_group, + logStreamName=logs_log_stream, + nextToken="invalid-token", + ) + snapshot.match("error-invalid-token", ctx.value.response) + + @markers.aws.validated + def test_get_log_events_limit_validation( + self, logs_log_group, logs_log_stream, aws_client, snapshot + ): + """Test that limit over 10000 is rejected.""" + with pytest.raises(Exception) as ctx: + aws_client.logs.get_log_events( + logGroupName=logs_log_group, logStreamName=logs_log_stream, limit=10001 + ) + snapshot.match("error-limit-exceeded", ctx.value.response) + + @markers.aws.validated + def test_get_log_events_using_log_group_identifier( + self, logs_log_group, logs_log_stream, aws_client, region_name, account_id + ): + """Test getting log events using logGroupIdentifier parameter.""" + timestamp = now_utc(millis=True) + messages = [{"timestamp": timestamp, "message": "test message"}] + + aws_client.logs.put_log_events( + logGroupName=logs_log_group, logStreamName=logs_log_stream, logEvents=messages + ) + + def verify_events(): + # Using logGroupName + response1 = aws_client.logs.get_log_events( + logGroupName=logs_log_group, logStreamName=logs_log_stream + ) + assert len(response1["events"]) >= 1 + + # Using logGroupIdentifier with name + response2 = aws_client.logs.get_log_events( + logGroupIdentifier=logs_log_group, logStreamName=logs_log_stream + ) + assert len(response2["events"]) >= 1 + + # Using logGroupIdentifier with ARN + log_group_arn = f"arn:aws:logs:{region_name}:{account_id}:log-group:{logs_log_group}" + response3 = aws_client.logs.get_log_events( + logGroupIdentifier=log_group_arn, logStreamName=logs_log_stream + ) + assert len(response3["events"]) >= 1 + + retry( + verify_events, + retries=20 if is_aws() else 3, + sleep=5 if is_aws() else 1, + sleep_before=3 if is_aws() else 0, + ) + + +class TestLogsEventsErrors: + """Tests for log event error handling.""" + + @markers.aws.validated + def test_resource_does_not_exist(self, aws_client, snapshot, cleanups): + """Test error handling when log group or stream doesn't exist.""" + log_group_name = f"log-group-{short_uid()}" + log_stream_name = f"log-stream-{short_uid()}" + + # Log group doesn't exist + with pytest.raises(Exception) as ctx: + aws_client.logs.get_log_events( + logGroupName=log_group_name, logStreamName=log_stream_name + ) + snapshot.match("error-log-group-does-not-exist", ctx.value.response) + + # Create log group + aws_client.logs.create_log_group(logGroupName=log_group_name) + cleanups.append(lambda: aws_client.logs.delete_log_group(logGroupName=log_group_name)) + + # Log stream doesn't exist + with pytest.raises(Exception) as ctx: + aws_client.logs.get_log_events( + logGroupName=log_group_name, logStreamName=log_stream_name + ) + snapshot.match("error-log-stream-does-not-exist", ctx.value.response) diff --git a/tests/aws/services/logs/test_logs_events.snapshot.json b/tests/aws/services/logs/test_logs_events.snapshot.json new file mode 100644 index 0000000000000..c0e7fa7fd67cd --- /dev/null +++ b/tests/aws/services/logs/test_logs_events.snapshot.json @@ -0,0 +1,117 @@ +{ + "tests/aws/services/logs/test_logs_events.py::TestLogsEvents::test_put_log_events_to_invalid_stream": { + "recorded-date": "03-02-2026, 21:36:32", + "recorded-content": { + "error-invalid-stream": { + "Error": { + "Code": "ResourceNotFoundException", + "Message": "The specified log stream does not exist." + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + } + } + }, + "tests/aws/services/logs/test_logs_events.py::TestLogsEvents::test_put_log_events_wrong_order": { + "recorded-date": "03-02-2026, 21:36:33", + "recorded-content": { + "error-wrong-order": { + "Error": { + "Code": "InvalidParameterException", + "Message": "Log events in a single PutLogEvents request must be in chronological order." + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + } + } + }, + "tests/aws/services/logs/test_logs_events.py::TestLogsEvents::test_put_log_events_too_old": { + "recorded-date": "11-02-2026, 21:19:57", + "recorded-content": { + "response-too-old": { + "nextSequenceToken": "", + "rejectedLogEventsInfo": { + "tooOldLogEventEndIndex": "too-old-log-event-end-index" + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/logs/test_logs_events.py::TestLogsEvents::test_put_log_events_too_new": { + "recorded-date": "11-02-2026, 21:20:15", + "recorded-content": { + "response-too-new": { + "nextSequenceToken": "", + "rejectedLogEventsInfo": { + "tooNewLogEventStartIndex": "too-new-log-event-start-index" + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/logs/test_logs_events.py::TestLogsEvents::test_get_log_events_invalid_token": { + "recorded-date": "03-02-2026, 21:36:41", + "recorded-content": { + "error-invalid-token": { + "Error": { + "Code": "InvalidParameterException", + "Message": "The specified nextToken is invalid." + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + } + } + }, + "tests/aws/services/logs/test_logs_events.py::TestLogsEvents::test_get_log_events_limit_validation": { + "recorded-date": "03-02-2026, 21:36:42", + "recorded-content": { + "error-limit-exceeded": { + "Error": { + "Code": "InvalidParameterException", + "Message": "1 validation error detected: Value '10001' at 'limit' failed to satisfy constraint: Member must have value less than or equal to 10000" + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + } + } + }, + "tests/aws/services/logs/test_logs_events.py::TestLogsEventsErrors::test_resource_does_not_exist": { + "recorded-date": "03-02-2026, 21:37:12", + "recorded-content": { + "error-log-group-does-not-exist": { + "Error": { + "Code": "ResourceNotFoundException", + "Message": "The specified log group does not exist." + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + }, + "error-log-stream-does-not-exist": { + "Error": { + "Code": "ResourceNotFoundException", + "Message": "The specified log stream does not exist." + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + } + } + } +} diff --git a/tests/aws/services/logs/test_logs_events.validation.json b/tests/aws/services/logs/test_logs_events.validation.json new file mode 100644 index 0000000000000..7a8e1d16ec80f --- /dev/null +++ b/tests/aws/services/logs/test_logs_events.validation.json @@ -0,0 +1,110 @@ +{ + "tests/aws/services/logs/test_logs_events.py::TestLogsEvents::test_get_log_events_basic": { + "last_validated_date": "2026-02-03T21:36:38+00:00", + "durations_in_seconds": { + "setup": 0.18, + "call": 3.2, + "teardown": 0.21, + "total": 3.59 + } + }, + "tests/aws/services/logs/test_logs_events.py::TestLogsEvents::test_get_log_events_invalid_token": { + "last_validated_date": "2026-02-03T21:36:42+00:00", + "durations_in_seconds": { + "setup": 0.18, + "call": 0.07, + "teardown": 0.21, + "total": 0.46 + } + }, + "tests/aws/services/logs/test_logs_events.py::TestLogsEvents::test_get_log_events_limit_validation": { + "last_validated_date": "2026-02-03T21:36:42+00:00", + "durations_in_seconds": { + "setup": 0.18, + "call": 0.07, + "teardown": 0.49, + "total": 0.74 + } + }, + "tests/aws/services/logs/test_logs_events.py::TestLogsEvents::test_get_log_events_start_from_head": { + "last_validated_date": "2026-02-03T21:36:41+00:00", + "durations_in_seconds": { + "setup": 0.18, + "call": 3.19, + "teardown": 0.21, + "total": 3.58 + } + }, + "tests/aws/services/logs/test_logs_events.py::TestLogsEvents::test_get_log_events_using_log_group_identifier": { + "last_validated_date": "2026-02-03T21:36:46+00:00", + "durations_in_seconds": { + "setup": 0.19, + "call": 3.7, + "teardown": 0.22, + "total": 4.11 + } + }, + "tests/aws/services/logs/test_logs_events.py::TestLogsEvents::test_put_events_multi_bytes_msg": { + "last_validated_date": "2026-02-03T21:36:32+00:00", + "durations_in_seconds": { + "setup": 0.18, + "call": 3.2, + "teardown": 0.21, + "total": 3.59 + } + }, + "tests/aws/services/logs/test_logs_events.py::TestLogsEvents::test_put_log_events_basic": { + "last_validated_date": "2026-02-03T21:36:28+00:00", + "durations_in_seconds": { + "setup": 0.49, + "call": 0.09, + "teardown": 0.23, + "total": 0.81 + } + }, + "tests/aws/services/logs/test_logs_events.py::TestLogsEvents::test_put_log_events_to_invalid_stream": { + "last_validated_date": "2026-02-03T21:36:33+00:00", + "durations_in_seconds": { + "setup": 0.46, + "call": 0.08, + "teardown": 0.11, + "total": 0.65 + } + }, + "tests/aws/services/logs/test_logs_events.py::TestLogsEvents::test_put_log_events_too_new": { + "last_validated_date": "2026-02-11T21:20:16+00:00", + "durations_in_seconds": { + "setup": 1.14, + "call": 0.16, + "teardown": 0.28, + "total": 1.58 + } + }, + "tests/aws/services/logs/test_logs_events.py::TestLogsEvents::test_put_log_events_too_old": { + "last_validated_date": "2026-02-11T21:19:58+00:00", + "durations_in_seconds": { + "setup": 1.07, + "call": 0.1, + "teardown": 0.3, + "total": 1.47 + } + }, + "tests/aws/services/logs/test_logs_events.py::TestLogsEvents::test_put_log_events_wrong_order": { + "last_validated_date": "2026-02-03T21:36:33+00:00", + "durations_in_seconds": { + "setup": 0.19, + "call": 0.07, + "teardown": 0.21, + "total": 0.47 + } + }, + "tests/aws/services/logs/test_logs_events.py::TestLogsEventsErrors::test_resource_does_not_exist": { + "last_validated_date": "2026-02-03T21:37:12+00:00", + "durations_in_seconds": { + "setup": 0.35, + "call": 0.54, + "teardown": 0.14, + "total": 1.03 + } + } +} diff --git a/tests/aws/services/logs/test_logs_export_tasks.py b/tests/aws/services/logs/test_logs_export_tasks.py new file mode 100644 index 0000000000000..3f39b47454d68 --- /dev/null +++ b/tests/aws/services/logs/test_logs_export_tasks.py @@ -0,0 +1,225 @@ +"""Tests for CloudWatch Logs - Export Task operations.""" + +import copy +import json + +import pytest +from botocore.exceptions import ClientError + +from localstack.testing.pytest import markers +from localstack.utils.common import now_utc, short_uid + +S3_POLICY = { + "Version": "2012-10-17", + "Statement": [ + { + "Action": "s3:GetBucketAcl", + "Effect": "Allow", + "Resource": "arn:aws:s3:::{BUCKET_NAME}", + "Principal": {"Service": "logs.amazonaws.com"}, + }, + { + "Action": "s3:PutObject", + "Effect": "Allow", + "Resource": "arn:aws:s3:::{BUCKET_NAME}/*", + "Principal": {"Service": "logs.amazonaws.com"}, + }, + ], +} + + +@pytest.fixture +def export_bucket(aws_client, s3_bucket, region_name): + """Create an S3 bucket configured for CloudWatch Logs export.""" + bucket_name = s3_bucket + + # Get account ID for policy + + # Configure bucket policy for CloudWatch Logs access + policy = copy.deepcopy(S3_POLICY) + policy["Statement"][0]["Resource"] = f"arn:aws:s3:::{bucket_name}" + policy["Statement"][1]["Resource"] = f"arn:aws:s3:::{bucket_name}/*" + + aws_client.s3.put_bucket_policy(Bucket=bucket_name, Policy=json.dumps(policy)) + + return bucket_name + + +@pytest.mark.skip(reason="TODO: Moto logs searches in memory the bucket which is impossible") +class TestExportTasks: + """Tests for export task operations.""" + + @markers.aws.validated + def test_create_export_task(self, logs_log_group, export_bucket, aws_client, snapshot): + """Test creating an export task.""" + snapshot.add_transformer(snapshot.transform.logs_api()) + from_time = 1611316574 # Fixed timestamp for reproducibility + to_time = 1642852574 + + response = aws_client.logs.create_export_task( + logGroupName=logs_log_group, + fromTime=from_time, + to=to_time, + destination=export_bucket, + ) + snapshot.match("create-export-task", response) + + task_id = response["taskId"] + + # Try to cancel the task (cleanup) + try: + aws_client.logs.cancel_export_task(taskId=task_id) + except ClientError as exc: + # Task might have already finished + if "already finished" not in exc.response["Error"]["Message"]: + raise + + @markers.aws.validated + def test_create_export_task_with_prefix( + self, logs_log_group, export_bucket, aws_client, snapshot + ): + """Test creating an export task with a destination prefix.""" + snapshot.add_transformer(snapshot.transform.logs_api()) + from_time = 1611316574 + to_time = 1642852574 + prefix = f"custom-prefix-{short_uid()}" + + response = aws_client.logs.create_export_task( + logGroupName=logs_log_group, + fromTime=from_time, + to=to_time, + destination=export_bucket, + destinationPrefix=prefix, + ) + snapshot.match("create-export-task-with-prefix", response) + + task_id = response["taskId"] + + # Try to cancel the task (cleanup) + try: + aws_client.logs.cancel_export_task(taskId=task_id) + except ClientError: + pass + + @markers.aws.validated + def test_create_export_task_bucket_not_found(self, logs_log_group, aws_client, snapshot): + """Test that creating an export task with non-existent bucket fails.""" + with pytest.raises(Exception) as ctx: + aws_client.logs.create_export_task( + logGroupName=logs_log_group, + fromTime=1611316574, + to=1642852574, + destination=f"non-existent-bucket-{short_uid()}", + ) + snapshot.match("error-bucket-not-found", ctx.value.response) + + @markers.aws.validated + def test_create_export_task_log_group_not_found(self, export_bucket, aws_client, snapshot): + """Test that creating an export task with non-existent log group fails.""" + with pytest.raises(Exception) as ctx: + aws_client.logs.create_export_task( + logGroupName=f"non-existent-log-group-{short_uid()}", + fromTime=1611316574, + to=1642852574, + destination=export_bucket, + ) + snapshot.match("error-log-group-not-found", ctx.value.response) + + @markers.aws.validated + def test_describe_export_tasks(self, logs_log_group, export_bucket, aws_client, snapshot): + """Test describing export tasks.""" + snapshot.add_transformer(snapshot.transform.logs_api()) + from_time = 1611316574 + to_time = 1642852574 + + # Create an export task + response = aws_client.logs.create_export_task( + logGroupName=logs_log_group, + fromTime=from_time, + to=to_time, + destination=export_bucket, + ) + task_id = response["taskId"] + + # Describe export tasks + response = aws_client.logs.describe_export_tasks(taskId=task_id) + snapshot.match("describe-export-tasks", response) + + # Cleanup + try: + aws_client.logs.cancel_export_task(taskId=task_id) + except ClientError: + pass + + @markers.aws.validated + def test_describe_export_tasks_not_found(self, aws_client, snapshot): + """Test describing a non-existent export task.""" + response = aws_client.logs.describe_export_tasks(taskId="non-existent-task-id") + snapshot.match("task-not-found", response) + + @markers.aws.validated + def test_cancel_export_task_not_found(self, aws_client, snapshot): + """Test cancelling a non-existent export task.""" + with pytest.raises(Exception) as ctx: + aws_client.logs.cancel_export_task(taskId=f"{short_uid()}-{short_uid()}") + snapshot.match("error-cancel-not-found", ctx.value.response) + + +@pytest.mark.skip(reason="TODO: Moto logs searches in memory the bucket which is impossible") +class TestExportTasksWithLogs: + """Tests for export tasks with actual log data.""" + + @markers.aws.validated + def test_create_export_task_with_logs( + self, logs_log_group, export_bucket, aws_client, snapshot + ): + """Test exporting actual log events to S3.""" + snapshot.add_transformer(snapshot.transform.logs_api()) + + # Create log stream and put events + log_stream_name = f"test-stream-{short_uid()}" + aws_client.logs.create_log_stream( + logGroupName=logs_log_group, logStreamName=log_stream_name + ) + + timestamp = now_utc(millis=True) + messages = [ + {"timestamp": timestamp + i * 100, "message": f"test message {i}"} for i in range(10) + ] + aws_client.logs.put_log_events( + logGroupName=logs_log_group, logStreamName=log_stream_name, logEvents=messages + ) + + # Create export task with time range that includes our logs + from_time = timestamp - 86400000 # 1 day before + to_time = timestamp + 86400000 # 1 day after + + response = aws_client.logs.create_export_task( + logGroupName=logs_log_group, + fromTime=from_time, + to=to_time, + destination=export_bucket, + ) + task_id = response["taskId"] + snapshot.match("create-export-with-logs", response) + + # Describe the task + response = aws_client.logs.describe_export_tasks(taskId=task_id) + snapshot.match("describe-export-with-logs", response) + task = response["exportTasks"][0] + + # Status should be one of: PENDING, RUNNING, COMPLETED, CANCELLED, FAILED + assert task["status"]["code"] in [ + "PENDING", + "RUNNING", + "COMPLETED", + "CANCELLED", + "FAILED", + "active", + ] + + # Cleanup + try: + aws_client.logs.cancel_export_task(taskId=task_id) + except ClientError: + pass diff --git a/tests/aws/services/logs/test_logs_export_tasks.snapshot.json b/tests/aws/services/logs/test_logs_export_tasks.snapshot.json new file mode 100644 index 0000000000000..41c2db1832aac --- /dev/null +++ b/tests/aws/services/logs/test_logs_export_tasks.snapshot.json @@ -0,0 +1,105 @@ +{ + "tests/aws/services/logs/test_logs_export_tasks.py::TestExportTasks::test_create_export_task": { + "recorded-date": "05-02-2026, 16:27:17", + "recorded-content": { + "create-export-task": { + "taskId": "", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/logs/test_logs_export_tasks.py::TestExportTasks::test_create_export_task_bucket_not_found": { + "recorded-date": "05-02-2026, 17:16:29", + "recorded-content": { + "error-bucket-not-found": { + "Error": { + "Code": "InvalidParameterException", + "Message": "The given bucket does not exist. Please make sure the bucket is valid." + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + } + } + }, + "tests/aws/services/logs/test_logs_export_tasks.py::TestExportTasks::test_create_export_task_log_group_not_found": { + "recorded-date": "05-02-2026, 17:17:07", + "recorded-content": { + "error-log-group-not-found": { + "Error": { + "Code": "ResourceNotFoundException", + "Message": "The specified log group does not exist." + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + } + } + }, + "tests/aws/services/logs/test_logs_export_tasks.py::TestExportTasks::test_describe_export_tasks_not_found": { + "recorded-date": "05-02-2026, 17:28:02", + "recorded-content": { + "task-not-found": { + "exportTasks": [], + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/logs/test_logs_export_tasks.py::TestExportTasks::test_cancel_export_task_not_found": { + "recorded-date": "05-02-2026, 17:30:40", + "recorded-content": { + "error-cancel-not-found": { + "Error": { + "Code": "ResourceNotFoundException", + "Message": "The specified export task does not exist." + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + } + } + }, + "tests/aws/services/logs/test_logs_export_tasks.py::TestExportTasksWithLogs::test_create_export_task_with_logs": { + "recorded-date": "05-02-2026, 17:32:58", + "recorded-content": { + "create-export-with-logs": { + "taskId": "", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "describe-export-with-logs": { + "exportTasks": [ + { + "destination": "test-bucket-d5301391", + "destinationPrefix": "exportedlogs", + "executionInfo": { + "creationTime": "timestamp" + }, + "from": 1770226377833, + "logGroupName": "", + "status": { + "code": "PENDING" + }, + "taskId": "", + "to": 1770399177833 + } + ], + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + } +} diff --git a/tests/aws/services/logs/test_logs_export_tasks.validation.json b/tests/aws/services/logs/test_logs_export_tasks.validation.json new file mode 100644 index 0000000000000..e2992f774a5d2 --- /dev/null +++ b/tests/aws/services/logs/test_logs_export_tasks.validation.json @@ -0,0 +1,56 @@ +{ + "tests/aws/services/logs/test_logs_export_tasks.py::TestExportTasks::test_cancel_export_task_not_found": { + "last_validated_date": "2026-02-05T17:30:40+00:00", + "durations_in_seconds": { + "setup": 0.36, + "call": 0.34, + "teardown": 0.0, + "total": 0.7 + } + }, + "tests/aws/services/logs/test_logs_export_tasks.py::TestExportTasks::test_create_export_task": { + "last_validated_date": "2026-02-05T16:27:18+00:00", + "durations_in_seconds": { + "setup": 1.37, + "call": 0.42, + "teardown": 0.89, + "total": 2.68 + } + }, + "tests/aws/services/logs/test_logs_export_tasks.py::TestExportTasks::test_create_export_task_bucket_not_found": { + "last_validated_date": "2026-02-05T17:16:29+00:00", + "durations_in_seconds": { + "setup": 0.74, + "call": 0.74, + "teardown": 0.14, + "total": 1.62 + } + }, + "tests/aws/services/logs/test_logs_export_tasks.py::TestExportTasks::test_create_export_task_log_group_not_found": { + "last_validated_date": "2026-02-05T17:17:08+00:00", + "durations_in_seconds": { + "setup": 1.08, + "call": 0.38, + "teardown": 0.49, + "total": 1.95 + } + }, + "tests/aws/services/logs/test_logs_export_tasks.py::TestExportTasks::test_describe_export_tasks_not_found": { + "last_validated_date": "2026-02-05T17:28:02+00:00", + "durations_in_seconds": { + "setup": 0.65, + "call": 0.39, + "teardown": 0.0, + "total": 1.04 + } + }, + "tests/aws/services/logs/test_logs_export_tasks.py::TestExportTasksWithLogs::test_create_export_task_with_logs": { + "last_validated_date": "2026-02-05T17:32:59+00:00", + "durations_in_seconds": { + "setup": 1.4, + "call": 0.7, + "teardown": 0.93, + "total": 3.03 + } + } +} diff --git a/tests/aws/services/logs/test_logs_filter_events.py b/tests/aws/services/logs/test_logs_filter_events.py new file mode 100644 index 0000000000000..3d2ea0b7ad68c --- /dev/null +++ b/tests/aws/services/logs/test_logs_filter_events.py @@ -0,0 +1,290 @@ +"""Tests for CloudWatch Logs - Filter Log Events operations.""" + +import pytest +from botocore.exceptions import ClientError +from localstack_snapshot.pytest.snapshot import is_aws + +from localstack.constants import APPLICATION_AMZ_JSON_1_1 +from localstack.testing.pytest import markers +from localstack.utils.common import now_utc, retry + + +class TestFilterLogEvents: + """Tests for filter_log_events operation.""" + + @markers.aws.validated + def test_filter_log_events_basic(self, logs_log_group, logs_log_stream, aws_client): + """Test basic filter log events operation.""" + timestamp = now_utc(millis=True) + events = [ + {"timestamp": timestamp, "message": "log message 1"}, + {"timestamp": timestamp + 100, "message": "log message 2"}, + ] + + aws_client.logs.put_log_events( + logGroupName=logs_log_group, logStreamName=logs_log_stream, logEvents=events + ) + + def verify_filter(): + response = aws_client.logs.filter_log_events(logGroupName=logs_log_group) + assert len(response["events"]) >= 2 + + retry( + verify_filter, + retries=20 if is_aws() else 3, + sleep=5 if is_aws() else 1, + sleep_before=3 if is_aws() else 0, + ) + + @markers.aws.validated + def test_filter_log_events_response_header(self, logs_log_group, logs_log_stream, aws_client): + """Test that filter_log_events returns correct content-type header.""" + events = [ + {"timestamp": now_utc(millis=True), "message": "log message 1"}, + {"timestamp": now_utc(millis=True), "message": "log message 2"}, + ] + aws_client.logs.put_log_events( + logGroupName=logs_log_group, logStreamName=logs_log_stream, logEvents=events + ) + + response = aws_client.logs.filter_log_events(logGroupName=logs_log_group) + assert response["ResponseMetadata"]["HTTPStatusCode"] == 200 + assert ( + response["ResponseMetadata"]["HTTPHeaders"]["content-type"] == APPLICATION_AMZ_JSON_1_1 + ) + + @markers.aws.validated + def test_filter_log_events_with_log_stream_names( + self, logs_log_group, logs_log_stream, aws_client + ): + """Test filtering by specific log stream names.""" + timestamp = now_utc(millis=True) + events = [ + {"timestamp": timestamp, "message": "test message"}, + ] + + aws_client.logs.put_log_events( + logGroupName=logs_log_group, logStreamName=logs_log_stream, logEvents=events + ) + + def verify_filter(): + response = aws_client.logs.filter_log_events( + logGroupName=logs_log_group, + logStreamNames=[logs_log_stream], + ) + assert len(response["events"]) >= 1 + + retry( + verify_filter, + retries=20 if is_aws() else 3, + sleep=5 if is_aws() else 1, + sleep_before=3 if is_aws() else 0, + ) + + @markers.aws.validated + def test_filter_log_events_interleaved(self, logs_log_group, logs_log_stream, aws_client): + """Test filter log events with interleaved parameter.""" + timestamp = now_utc(millis=True) + messages = [ + {"timestamp": timestamp, "message": "hello"}, + {"timestamp": timestamp + 100, "message": "world"}, + ] + + aws_client.logs.put_log_events( + logGroupName=logs_log_group, logStreamName=logs_log_stream, logEvents=messages + ) + + def verify_filter(): + response = aws_client.logs.filter_log_events( + logGroupName=logs_log_group, + logStreamNames=[logs_log_stream], + interleaved=True, + ) + events = response["events"] + assert len(events) >= 2 + for event in events: + assert "eventId" in event + assert "timestamp" in event + assert "message" in event + + retry( + verify_filter, + retries=20 if is_aws() else 3, + sleep=5 if is_aws() else 1, + sleep_before=3 if is_aws() else 0, + ) + + @markers.aws.validated + def test_filter_log_events_pagination(self, logs_log_group, logs_log_stream, aws_client): + """Test filter log events pagination.""" + timestamp = now_utc(millis=True) + messages = [ + {"timestamp": timestamp + i * 100, "message": f"Message number {i}"} for i in range(25) + ] + + aws_client.logs.put_log_events( + logGroupName=logs_log_group, logStreamName=logs_log_stream, logEvents=messages + ) + + def verify_pagination(): + # Get first page + response = aws_client.logs.filter_log_events( + logGroupName=logs_log_group, + logStreamNames=[logs_log_stream], + limit=20, + ) + events = response["events"] + assert len(events) == 20 + assert "nextToken" in response + + # Get second page + response2 = aws_client.logs.filter_log_events( + logGroupName=logs_log_group, + logStreamNames=[logs_log_stream], + limit=20, + nextToken=response["nextToken"], + ) + events2 = response2["events"] + assert len(events + events2) == 25 + + retry( + verify_pagination, + retries=20 if is_aws() else 3, + sleep=5 if is_aws() else 1, + sleep_before=3 if is_aws() else 0, + ) + + @markers.aws.validated + @pytest.mark.skip(reason="TODO Raise error") + def test_filter_log_events_unknown_token( + self, logs_log_group, logs_log_stream, aws_client, snapshot + ): + """Test filter log events with unknown/invalid token.""" + with pytest.raises(ClientError) as ctx: + aws_client.logs.filter_log_events( + logGroupName=logs_log_group, + logStreamNames=[logs_log_stream], + limit=20, + nextToken="invalid-token", + ) + snapshot.match("invalid-token", ctx.value.response) + + @markers.aws.validated + def test_filter_log_events_limit_validation(self, logs_log_group, aws_client, snapshot): + """Test that limit over 10000 is rejected.""" + with pytest.raises(Exception) as ctx: + aws_client.logs.filter_log_events(logGroupName=logs_log_group, limit=10001) + snapshot.match("error-limit-exceeded", ctx.value.response) + + +@pytest.mark.skip(reason="filtering is only supported in pro") +class TestFilterLogEventsPatterns: + """Tests for filter log events with filter patterns.""" + + @pytest.fixture(autouse=True) + def setup_log_events(self, logs_log_group, logs_log_stream, aws_client): + """Set up common log events for pattern testing.""" + self.log_group = logs_log_group + self.log_stream = logs_log_stream + self.client = aws_client.logs + + timestamp = now_utc(millis=True) + messages = [ + {"timestamp": timestamp, "message": "hello"}, + {"timestamp": timestamp + 100, "message": "world"}, + {"timestamp": timestamp + 200, "message": "hello world"}, + {"timestamp": timestamp + 300, "message": "goodbye world"}, + {"timestamp": timestamp + 400, "message": "hello cruela"}, + {"timestamp": timestamp + 500, "message": "goodbye cruel world"}, + ] + self.client.put_log_events( + logGroupName=logs_log_group, logStreamName=logs_log_stream, logEvents=messages + ) + + @markers.aws.validated + def test_filter_simple_word_pattern(self): + """Test filtering with a simple word pattern.""" + + def verify_filter(): + events = self.client.filter_log_events( + logGroupName=self.log_group, + logStreamNames=[self.log_stream], + filterPattern="hello", + )["events"] + messages = [e["message"] for e in events] + assert "hello" in messages or "hello world" in messages or "hello cruela" in messages + # Only messages containing "hello" should be returned + for msg in messages: + assert "hello" in msg + + retry( + verify_filter, + retries=20 if is_aws() else 3, + sleep=5 if is_aws() else 1, + sleep_before=3 if is_aws() else 0, + ) + + @markers.aws.validated + def test_filter_multiple_words_pattern(self): + """Test filtering with multiple words pattern.""" + + def verify_filter(): + events = self.client.filter_log_events( + logGroupName=self.log_group, + logStreamNames=[self.log_stream], + filterPattern="goodbye world", + )["events"] + messages = [e["message"] for e in events] + # Messages containing both "goodbye" and "world" should be returned + for msg in messages: + assert "goodbye" in msg and "world" in msg + + retry( + verify_filter, + retries=20 if is_aws() else 3, + sleep=5 if is_aws() else 1, + sleep_before=3 if is_aws() else 0, + ) + + @markers.aws.validated + def test_filter_quoted_pattern(self): + """Test filtering with a quoted phrase pattern.""" + + def verify_filter(): + events = self.client.filter_log_events( + logGroupName=self.log_group, + logStreamNames=[self.log_stream], + filterPattern='"hello cruel"', + )["events"] + messages = [e["message"] for e in events] + # Only exact phrase matches should be returned + for msg in messages: + assert "hello cruel" in msg + + retry( + verify_filter, + retries=20 if is_aws() else 3, + sleep=5 if is_aws() else 1, + sleep_before=3 if is_aws() else 0, + ) + + @markers.aws.validated + def test_filter_json_pattern(self): + """Test filtering with a JSON-style pattern (treated as no-filter in Moto).""" + + def verify_filter(): + events = self.client.filter_log_events( + logGroupName=self.log_group, + logStreamNames=[self.log_stream], + filterPattern='{$.message = "hello"}', + )["events"] + # JSON patterns may or may not be fully supported + # Just verify that the call succeeds + assert isinstance(events, list) + + retry( + verify_filter, + retries=20 if is_aws() else 3, + sleep=5 if is_aws() else 1, + sleep_before=3 if is_aws() else 0, + ) diff --git a/tests/aws/services/logs/test_logs_filter_events.snapshot.json b/tests/aws/services/logs/test_logs_filter_events.snapshot.json new file mode 100644 index 0000000000000..df94ade53375a --- /dev/null +++ b/tests/aws/services/logs/test_logs_filter_events.snapshot.json @@ -0,0 +1,32 @@ +{ + "tests/aws/services/logs/test_logs_filter_events.py::TestFilterLogEvents::test_filter_log_events_limit_validation": { + "recorded-date": "05-02-2026, 18:50:36", + "recorded-content": { + "error-limit-exceeded": { + "Error": { + "Code": "InvalidParameterException", + "Message": "1 validation error detected: Value '10001' at 'limit' failed to satisfy constraint: Member must have value less than or equal to 10000" + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + } + } + }, + "tests/aws/services/logs/test_logs_filter_events.py::TestFilterLogEvents::test_filter_log_events_unknown_token": { + "recorded-date": "05-02-2026, 18:50:36", + "recorded-content": { + "invalid-token": { + "Error": { + "Code": "InvalidParameterException", + "Message": "The specified nextToken is invalid." + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + } + } + } +} diff --git a/tests/aws/services/logs/test_logs_filter_events.validation.json b/tests/aws/services/logs/test_logs_filter_events.validation.json new file mode 100644 index 0000000000000..5f9a70a1e9294 --- /dev/null +++ b/tests/aws/services/logs/test_logs_filter_events.validation.json @@ -0,0 +1,101 @@ +{ + "tests/aws/services/logs/test_logs_filter_events.py::TestFilterLogEvents::test_filter_log_events_basic": { + "last_validated_date": "2026-02-05T18:50:23+00:00", + "durations_in_seconds": { + "setup": 0.48, + "call": 3.25, + "teardown": 0.22, + "total": 3.95 + } + }, + "tests/aws/services/logs/test_logs_filter_events.py::TestFilterLogEvents::test_filter_log_events_interleaved": { + "last_validated_date": "2026-02-05T18:50:31+00:00", + "durations_in_seconds": { + "setup": 0.19, + "call": 3.2, + "teardown": 0.22, + "total": 3.61 + } + }, + "tests/aws/services/logs/test_logs_filter_events.py::TestFilterLogEvents::test_filter_log_events_limit_validation": { + "last_validated_date": "2026-02-05T18:50:36+00:00", + "durations_in_seconds": { + "setup": 0.1, + "call": 0.07, + "teardown": 0.11, + "total": 0.28 + } + }, + "tests/aws/services/logs/test_logs_filter_events.py::TestFilterLogEvents::test_filter_log_events_pagination": { + "last_validated_date": "2026-02-05T18:50:35+00:00", + "durations_in_seconds": { + "setup": 0.24, + "call": 3.3, + "teardown": 0.24, + "total": 3.78 + } + }, + "tests/aws/services/logs/test_logs_filter_events.py::TestFilterLogEvents::test_filter_log_events_response_header": { + "last_validated_date": "2026-02-05T18:50:24+00:00", + "durations_in_seconds": { + "setup": 0.18, + "call": 0.25, + "teardown": 0.2, + "total": 0.63 + } + }, + "tests/aws/services/logs/test_logs_filter_events.py::TestFilterLogEvents::test_filter_log_events_unknown_token": { + "last_validated_date": "2026-02-05T18:50:36+00:00", + "durations_in_seconds": { + "setup": 0.59, + "call": 0.08, + "teardown": 0.22, + "total": 0.89 + } + }, + "tests/aws/services/logs/test_logs_filter_events.py::TestFilterLogEvents::test_filter_log_events_with_log_stream_names": { + "last_validated_date": "2026-02-05T18:50:27+00:00", + "durations_in_seconds": { + "setup": 0.24, + "call": 3.2, + "teardown": 0.2, + "total": 3.64 + } + }, + "tests/aws/services/logs/test_logs_filter_events.py::TestFilterLogEventsPatterns::test_filter_json_pattern": { + "last_validated_date": "2026-02-05T18:52:08+00:00", + "durations_in_seconds": { + "setup": 0.27, + "call": 3.11, + "teardown": 0.24, + "total": 3.62 + } + }, + "tests/aws/services/logs/test_logs_filter_events.py::TestFilterLogEventsPatterns::test_filter_multiple_words_pattern": { + "last_validated_date": "2026-02-05T18:52:01+00:00", + "durations_in_seconds": { + "setup": 0.28, + "call": 3.11, + "teardown": 0.2, + "total": 3.59 + } + }, + "tests/aws/services/logs/test_logs_filter_events.py::TestFilterLogEventsPatterns::test_filter_quoted_pattern": { + "last_validated_date": "2026-02-05T18:52:05+00:00", + "durations_in_seconds": { + "setup": 0.28, + "call": 3.12, + "teardown": 0.22, + "total": 3.62 + } + }, + "tests/aws/services/logs/test_logs_filter_events.py::TestFilterLogEventsPatterns::test_filter_simple_word_pattern": { + "last_validated_date": "2026-02-05T18:51:57+00:00", + "durations_in_seconds": { + "setup": 0.61, + "call": 3.1, + "teardown": 0.21, + "total": 3.92 + } + } +} diff --git a/tests/aws/services/logs/test_logs_groups.py b/tests/aws/services/logs/test_logs_groups.py new file mode 100644 index 0000000000000..a839b48ba39a0 --- /dev/null +++ b/tests/aws/services/logs/test_logs_groups.py @@ -0,0 +1,344 @@ +"""Tests for CloudWatch Logs - Log Group operations.""" + +import json + +import pytest + +from localstack.testing.pytest import markers +from localstack.utils.common import poll_condition, short_uid + + +def _log_group_exists(log_groups: list, name: str) -> bool: + """Check if a log group with the given name exists in the list.""" + return any(lg["logGroupName"] == name for lg in log_groups) + + +class TestLogsGroups: + """Tests for log group create, delete, describe operations.""" + + @markers.aws.validated + def test_create_and_delete_log_group(self, aws_client): + """Test basic log group creation and deletion.""" + test_name = f"test-log-group-{short_uid()}" + + aws_client.logs.create_log_group(logGroupName=test_name) + + def log_group_created(): + log_groups = aws_client.logs.describe_log_groups(logGroupNamePrefix=test_name).get( + "logGroups", [] + ) + return _log_group_exists(log_groups, test_name) + + assert poll_condition(log_group_created, timeout=5.0, interval=0.5) + + aws_client.logs.delete_log_group(logGroupName=test_name) + + def log_group_deleted(): + log_groups = aws_client.logs.describe_log_groups(logGroupNamePrefix=test_name).get( + "logGroups", [] + ) + return not _log_group_exists(log_groups, test_name) + + assert poll_condition(log_group_deleted, timeout=5.0, interval=0.5) + + @markers.aws.validated + @markers.snapshot.skip_snapshot_verify(paths=["$..logGroups..deletionProtectionEnabled"]) + def test_create_log_group_with_kms_key( + self, aws_client, snapshot, cleanups, kms_create_key, region_name, account_id + ): + """Test log group creation with KMS encryption.""" + snapshot.add_transformer(snapshot.transform.logs_api()) + log_group_name = f"test-log-group-kms-{short_uid()}" + + kms_policy = { + "Version": "2012-10-17", + "Statement": [ + { + "Effect": "Allow", + "Principal": "*", + "Action": "kms:*", + "Resource": "*", + }, + ], + } + + kms_key = kms_create_key(Policy=json.dumps(kms_policy)) + snapshot.add_transformer(snapshot.transform.regex(kms_key["KeyId"], "")) + + aws_client.logs.create_log_group(logGroupName=log_group_name, kmsKeyId=kms_key["Arn"]) + cleanups.append(lambda: aws_client.logs.delete_log_group(logGroupName=log_group_name)) + + response = aws_client.logs.describe_log_groups(logGroupNamePrefix=log_group_name) + snapshot.match("describe-log-groups-with-kms", response) + + assert _log_group_exists(response["logGroups"], log_group_name) + log_group = next(lg for lg in response["logGroups"] if lg["logGroupName"] == log_group_name) + assert "kmsKeyId" in log_group + + @markers.aws.validated + def test_create_log_group_duplicate_error(self, aws_client, snapshot, cleanups): + """Test that creating a duplicate log group raises an error.""" + log_group_name = f"test-log-group-{short_uid()}" + aws_client.logs.create_log_group(logGroupName=log_group_name) + cleanups.append(lambda: aws_client.logs.delete_log_group(logGroupName=log_group_name)) + + with pytest.raises(Exception) as ctx: + aws_client.logs.create_log_group(logGroupName=log_group_name) + snapshot.match("error-duplicate-log-group", ctx.value.response) + + @markers.aws.validated + @markers.snapshot.skip_snapshot_verify(paths=["$..Error.Message"]) + def test_create_log_group_invalid_name_length(self, aws_client, snapshot): + """Test that log group names over 512 characters are rejected.""" + log_group_name = "a" * 513 + + with pytest.raises(Exception) as ctx: + aws_client.logs.create_log_group(logGroupName=log_group_name) + snapshot.match("error-invalid-name-length", ctx.value.response) + + @markers.aws.validated + @markers.snapshot.skip_snapshot_verify(paths=["$..logGroups..deletionProtectionEnabled"]) + def test_describe_log_groups_with_prefix(self, aws_client, snapshot, cleanups): + """Test describing log groups with prefix filter.""" + snapshot.add_transformer(snapshot.transform.logs_api()) + prefix = f"test-prefix-{short_uid()}" + log_group_names = [f"{prefix}-group-{i}" for i in range(3)] + + for name in log_group_names: + aws_client.logs.create_log_group(logGroupName=name) + cleanups.append(lambda n=name: aws_client.logs.delete_log_group(logGroupName=n)) + + response = aws_client.logs.describe_log_groups(logGroupNamePrefix=prefix) + snapshot.match("describe-log-groups-prefix", response) + for name in log_group_names: + assert _log_group_exists(response["logGroups"], name) + + @markers.aws.validated + @markers.snapshot.skip_snapshot_verify( + paths=[ + "$..describe-log-groups-pattern.logGroups..storedBytes", + "$..describe-log-groups-pattern.nextToken", + ] + ) + def test_describe_log_groups_with_pattern(self, aws_client, snapshot, cleanups): + """Test describing log groups with pattern filter.""" + snapshot.add_transformer(snapshot.transform.logs_api()) + unique_id = short_uid() + log_group_name = f"test-pattern-{unique_id}" + + aws_client.logs.create_log_group(logGroupName=log_group_name) + cleanups.append(lambda: aws_client.logs.delete_log_group(logGroupName=log_group_name)) + + # Pattern matching may take time on AWS + def log_group_found_by_pattern(): + log_groups = aws_client.logs.describe_log_groups(logGroupNamePattern=unique_id).get( + "logGroups", [] + ) + return _log_group_exists(log_groups, log_group_name) + + assert poll_condition(log_group_found_by_pattern, timeout=5.0, interval=0.5) + + response = aws_client.logs.describe_log_groups(logGroupNamePattern=unique_id) + snapshot.match("describe-log-groups-pattern", response) + + @markers.aws.validated + def test_describe_log_groups_prefix_and_pattern_error(self, aws_client, snapshot, cleanups): + """Test that using both prefix and pattern raises an error.""" + log_group_name = f"test-log-group-{short_uid()}" + aws_client.logs.create_log_group(logGroupName=log_group_name) + cleanups.append(lambda: aws_client.logs.delete_log_group(logGroupName=log_group_name)) + + with pytest.raises(Exception) as ctx: + aws_client.logs.describe_log_groups( + logGroupNamePattern=log_group_name, logGroupNamePrefix=log_group_name + ) + snapshot.match("error-prefix-and-pattern", ctx.value.response) + + @markers.aws.validated + @markers.snapshot.skip_snapshot_verify(paths=["$..nextToken", "$..storedBytes"]) + def test_list_log_groups_with_pattern(self, aws_client, snapshot, cleanups): + """Test listing log groups with pattern filter.""" + snapshot.add_transformer(snapshot.transform.logs_api()) + unique_id = short_uid() + log_group_name = f"test-list-{unique_id}" + + aws_client.logs.create_log_group(logGroupName=log_group_name) + cleanups.append(lambda: aws_client.logs.delete_log_group(logGroupName=log_group_name)) + + response = aws_client.logs.list_log_groups(logGroupNamePattern="no-such-group") + assert not _log_group_exists(response.get("logGroups", []), log_group_name) + snapshot.match("list-log-groups-no-match", response) + + def log_group_found_by_pattern(): + log_groups = aws_client.logs.describe_log_groups(logGroupNamePattern=unique_id).get( + "logGroups", [] + ) + return _log_group_exists(log_groups, log_group_name) + + assert poll_condition(log_group_found_by_pattern, interval=0.5, timeout=5) + response = aws_client.logs.describe_log_groups(logGroupNamePattern=unique_id).get( + "logGroups", [] + ) + snapshot.match("list-log-groups-match", response) + + +class TestLogsGroupsRetention: + """Tests for log group retention policy operations.""" + + @markers.aws.validated + def test_put_retention_policy(self, aws_client, cleanups): + """Test setting retention policy on a log group.""" + log_group_name = f"test-retention-{short_uid()}" + aws_client.logs.create_log_group(logGroupName=log_group_name) + cleanups.append(lambda: aws_client.logs.delete_log_group(logGroupName=log_group_name)) + + aws_client.logs.put_retention_policy(logGroupName=log_group_name, retentionInDays=7) + + response = aws_client.logs.describe_log_groups(logGroupNamePrefix=log_group_name) + assert response["logGroups"][0].get("retentionInDays") == 7 + + @markers.aws.validated + def test_delete_retention_policy(self, aws_client, cleanups): + """Test deleting retention policy from a log group.""" + log_group_name = f"test-retention-{short_uid()}" + aws_client.logs.create_log_group(logGroupName=log_group_name) + cleanups.append(lambda: aws_client.logs.delete_log_group(logGroupName=log_group_name)) + + # Set retention policy + aws_client.logs.put_retention_policy(logGroupName=log_group_name, retentionInDays=7) + + response = aws_client.logs.describe_log_groups(logGroupNamePrefix=log_group_name) + assert response["logGroups"][0].get("retentionInDays") == 7 + + # Delete retention policy + aws_client.logs.delete_retention_policy(logGroupName=log_group_name) + + response = aws_client.logs.describe_log_groups(logGroupNamePrefix=log_group_name) + assert response["logGroups"][0].get("retentionInDays") is None + + +class TestLogsGroupsTags: + """Tests for log group tagging operations.""" + + @markers.aws.validated + def test_create_log_group_with_tags(self, aws_client, snapshot, cleanups): + """Test creating a log group with initial tags.""" + snapshot.add_transformer(snapshot.transform.logs_api()) + log_group_name = f"test-tags-{short_uid()}" + + aws_client.logs.create_log_group(logGroupName=log_group_name, tags={"env": "testing"}) + cleanups.append(lambda: aws_client.logs.delete_log_group(logGroupName=log_group_name)) + + response = aws_client.logs.list_tags_log_group(logGroupName=log_group_name) + snapshot.match("list-tags-after-create", response) + assert response["tags"] == {"env": "testing"} + + @markers.aws.validated + @pytest.mark.skip(reason="TODO list tags returns empty") + def test_tag_log_group(self, aws_client, snapshot, cleanups): + """Test adding tags to an existing log group using tag_log_group API.""" + snapshot.add_transformer(snapshot.transform.logs_api()) + log_group_name = f"test-tags-{short_uid()}" + + aws_client.logs.create_log_group(logGroupName=log_group_name) + cleanups.append(lambda: aws_client.logs.delete_log_group(logGroupName=log_group_name)) + + # Add tags + aws_client.logs.tag_log_group( + logGroupName=log_group_name, tags={"tag_key_1": "tag_value_1"} + ) + + response = aws_client.logs.list_tags_log_group(logGroupName=log_group_name) + snapshot.match("list-tags-after-tag", response) + assert response["tags"] == {"tag_key_1": "tag_value_1"} + + # Add more tags + aws_client.logs.tag_log_group( + logGroupName=log_group_name, tags={"tag_key_2": "tag_value_2"} + ) + + response = aws_client.logs.list_tags_log_group(logGroupName=log_group_name) + assert response["tags"] == {"tag_key_1": "tag_value_1", "tag_key_2": "tag_value_2"} + + # Update existing tag + aws_client.logs.tag_log_group( + logGroupName=log_group_name, tags={"tag_key_1": "tag_value_XX"} + ) + + response = aws_client.logs.list_tags_log_group(logGroupName=log_group_name) + assert response["tags"] == {"tag_key_1": "tag_value_XX", "tag_key_2": "tag_value_2"} + + @markers.aws.validated + @pytest.mark.skip(reason="TODO list tags returns empty") + def test_untag_log_group(self, aws_client, snapshot, cleanups): + """Test removing tags from a log group using untag_log_group API.""" + snapshot.add_transformer(snapshot.transform.logs_api()) + log_group_name = f"test-tags-{short_uid()}" + + aws_client.logs.create_log_group(logGroupName=log_group_name) + cleanups.append(lambda: aws_client.logs.delete_log_group(logGroupName=log_group_name)) + + # Add tags + tags = {"tag_key_1": "tag_value_1", "tag_key_2": "tag_value_2"} + aws_client.logs.tag_log_group(logGroupName=log_group_name, tags=tags) + + response = aws_client.logs.list_tags_log_group(logGroupName=log_group_name) + assert response["tags"] == tags + + # Remove one tag + aws_client.logs.untag_log_group(logGroupName=log_group_name, tags=["tag_key_1"]) + + response = aws_client.logs.list_tags_log_group(logGroupName=log_group_name) + snapshot.match("list-tags-after-untag", response) + assert response["tags"] == {"tag_key_2": "tag_value_2"} + + @markers.aws.validated + def test_tag_resource_api(self, aws_client, snapshot, cleanups): + """Test tagging log group using the new tag_resource/untag_resource APIs.""" + snapshot.add_transformer(snapshot.transform.logs_api()) + log_group_name = f"test-tags-{short_uid()}" + + aws_client.logs.create_log_group(logGroupName=log_group_name, tags={"env": "testing1"}) + cleanups.append(lambda: aws_client.logs.delete_log_group(logGroupName=log_group_name)) + + response = aws_client.logs.list_tags_log_group(logGroupName=log_group_name) + snapshot.match("list-tags-after-create", response) + + # Get the log group ARN (without trailing :*) + log_group_arn = aws_client.logs.describe_log_groups(logGroupNamePrefix=log_group_name)[ + "logGroups" + ][0]["arn"].rstrip(":*") + + # Add tags using new API + aws_client.logs.tag_resource( + resourceArn=log_group_arn, tags={"test1": "val1", "test2": "val2"} + ) + + response = aws_client.logs.list_tags_log_group(logGroupName=log_group_name) + response_2 = aws_client.logs.list_tags_for_resource(resourceArn=log_group_arn) + + snapshot.match("list-tags-log-group-after-tag-resource", response) + snapshot.match("list-tags-for-resource-after-tag-resource", response_2) + # Values should be the same + assert response["tags"] == response_2["tags"] + + # Add a tag using old API + aws_client.logs.tag_log_group(logGroupName=log_group_name, tags={"test3": "val3"}) + + response = aws_client.logs.list_tags_log_group(logGroupName=log_group_name) + response_2 = aws_client.logs.list_tags_for_resource(resourceArn=log_group_arn) + + snapshot.match("list-tags-log-group-after-tag-log-group", response) + snapshot.match("list-tags-for-resource-after-tag-log-group", response_2) + assert response["tags"] == response_2["tags"] + + # Untag using both APIs + aws_client.logs.untag_log_group(logGroupName=log_group_name, tags=["test3"]) + aws_client.logs.untag_resource(resourceArn=log_group_arn, tagKeys=["env", "test1"]) + + response = aws_client.logs.list_tags_log_group(logGroupName=log_group_name) + response_2 = aws_client.logs.list_tags_for_resource(resourceArn=log_group_arn) + snapshot.match("list-tags-log-group-after-untag", response) + snapshot.match("list-tags-for-resource-after-untag", response_2) + + assert response["tags"] == response_2["tags"] diff --git a/tests/aws/services/logs/test_logs_groups.snapshot.json b/tests/aws/services/logs/test_logs_groups.snapshot.json new file mode 100644 index 0000000000000..a54b3e22915cc --- /dev/null +++ b/tests/aws/services/logs/test_logs_groups.snapshot.json @@ -0,0 +1,278 @@ +{ + "tests/aws/services/logs/test_logs_groups.py::TestLogsGroups::test_create_log_group_with_kms_key": { + "recorded-date": "03-02-2026, 21:00:51", + "recorded-content": { + "describe-log-groups-with-kms": { + "logGroups": [ + { + "arn": "arn::logs::111111111111:log-group::*", + "creationTime": "timestamp", + "deletionProtectionEnabled": false, + "kmsKeyId": "arn::kms::111111111111:key/", + "logGroupArn": "arn::logs::111111111111:log-group:", + "logGroupClass": "STANDARD", + "logGroupName": "", + "metricFilterCount": 0, + "storedBytes": 0 + } + ], + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/logs/test_logs_groups.py::TestLogsGroups::test_create_log_group_duplicate_error": { + "recorded-date": "03-02-2026, 20:57:35", + "recorded-content": { + "error-duplicate-log-group": { + "Error": { + "Code": "ResourceAlreadyExistsException", + "Message": "The specified log group already exists" + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + } + } + }, + "tests/aws/services/logs/test_logs_groups.py::TestLogsGroups::test_create_log_group_invalid_name_length": { + "recorded-date": "03-02-2026, 20:57:35", + "recorded-content": { + "error-invalid-name-length": { + "Error": { + "Code": "InvalidParameterException", + "Message": "Invalid LogGroup or LogStream, both must have length less than or equal to 512." + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + } + } + }, + "tests/aws/services/logs/test_logs_groups.py::TestLogsGroups::test_describe_log_groups_with_prefix": { + "recorded-date": "03-02-2026, 20:57:36", + "recorded-content": { + "describe-log-groups-prefix": { + "logGroups": [ + { + "arn": "arn::logs::111111111111:log-group::*", + "creationTime": "timestamp", + "deletionProtectionEnabled": false, + "logGroupArn": "arn::logs::111111111111:log-group:", + "logGroupClass": "STANDARD", + "logGroupName": "", + "metricFilterCount": 0, + "storedBytes": 0 + }, + { + "arn": "arn::logs::111111111111:log-group::*", + "creationTime": "timestamp", + "deletionProtectionEnabled": false, + "logGroupArn": "arn::logs::111111111111:log-group:", + "logGroupClass": "STANDARD", + "logGroupName": "", + "metricFilterCount": 0, + "storedBytes": 0 + }, + { + "arn": "arn::logs::111111111111:log-group::*", + "creationTime": "timestamp", + "deletionProtectionEnabled": false, + "logGroupArn": "arn::logs::111111111111:log-group:", + "logGroupClass": "STANDARD", + "logGroupName": "", + "metricFilterCount": 0, + "storedBytes": 0 + } + ], + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/logs/test_logs_groups.py::TestLogsGroups::test_describe_log_groups_with_pattern": { + "recorded-date": "03-02-2026, 20:57:37", + "recorded-content": { + "describe-log-groups-pattern": { + "logGroups": [ + { + "arn": "arn::logs::111111111111:log-group::*", + "creationTime": "timestamp", + "logGroupArn": "arn::logs::111111111111:log-group:", + "logGroupClass": "STANDARD", + "logGroupName": "", + "metricFilterCount": 0 + } + ], + "nextToken": "", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/logs/test_logs_groups.py::TestLogsGroups::test_describe_log_groups_prefix_and_pattern_error": { + "recorded-date": "03-02-2026, 20:57:38", + "recorded-content": { + "error-prefix-and-pattern": { + "Error": { + "Code": "InvalidParameterException", + "Message": "LogGroup name prefix and LogGroup name pattern are mutually exclusive parameters." + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + } + } + }, + "tests/aws/services/logs/test_logs_groups.py::TestLogsGroups::test_list_log_groups_with_pattern": { + "recorded-date": "03-02-2026, 20:57:39", + "recorded-content": { + "list-log-groups-no-match": { + "logGroups": [], + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "list-log-groups-match": [ + { + "logGroupName": "", + "creationTime": "timestamp", + "metricFilterCount": 0, + "arn": "arn::logs::111111111111:log-group::*", + "logGroupClass": "STANDARD", + "logGroupArn": "arn::logs::111111111111:log-group:" + } + ] + } + }, + "tests/aws/services/logs/test_logs_groups.py::TestLogsGroupsTags::test_create_log_group_with_tags": { + "recorded-date": "03-02-2026, 21:03:36", + "recorded-content": { + "list-tags-after-create": { + "tags": { + "env": "testing" + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/logs/test_logs_groups.py::TestLogsGroupsTags::test_tag_log_group": { + "recorded-date": "03-02-2026, 21:03:37", + "recorded-content": { + "list-tags-after-tag": { + "tags": { + "tag_key_1": "tag_value_1" + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/logs/test_logs_groups.py::TestLogsGroupsTags::test_untag_log_group": { + "recorded-date": "03-02-2026, 21:03:38", + "recorded-content": { + "list-tags-after-untag": { + "tags": { + "tag_key_2": "tag_value_2" + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/logs/test_logs_groups.py::TestLogsGroupsTags::test_tag_resource_api": { + "recorded-date": "03-02-2026, 21:03:39", + "recorded-content": { + "list-tags-after-create": { + "tags": { + "env": "testing1" + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "list-tags-log-group-after-tag-resource": { + "tags": { + "env": "testing1", + "test1": "val1", + "test2": "val2" + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "list-tags-for-resource-after-tag-resource": { + "tags": { + "env": "testing1", + "test1": "val1", + "test2": "val2" + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "list-tags-log-group-after-tag-log-group": { + "tags": { + "env": "testing1", + "test1": "val1", + "test2": "val2", + "test3": "val3" + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "list-tags-for-resource-after-tag-log-group": { + "tags": { + "env": "testing1", + "test1": "val1", + "test2": "val2", + "test3": "val3" + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "list-tags-log-group-after-untag": { + "tags": { + "test2": "val2" + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "list-tags-for-resource-after-untag": { + "tags": { + "test2": "val2" + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + } +} diff --git a/tests/aws/services/logs/test_logs_groups.validation.json b/tests/aws/services/logs/test_logs_groups.validation.json new file mode 100644 index 0000000000000..3d75b348d5cd0 --- /dev/null +++ b/tests/aws/services/logs/test_logs_groups.validation.json @@ -0,0 +1,128 @@ +{ + "tests/aws/services/logs/test_logs_groups.py::TestLogsGroups::test_create_and_delete_log_group": { + "last_validated_date": "2026-02-03T20:57:33+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.78, + "teardown": 0.0, + "total": 0.78 + } + }, + "tests/aws/services/logs/test_logs_groups.py::TestLogsGroups::test_create_log_group_duplicate_error": { + "last_validated_date": "2026-02-03T20:57:35+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.18, + "teardown": 0.1, + "total": 0.28 + } + }, + "tests/aws/services/logs/test_logs_groups.py::TestLogsGroups::test_create_log_group_invalid_name_length": { + "last_validated_date": "2026-02-03T20:57:35+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.07, + "teardown": 0.0, + "total": 0.07 + } + }, + "tests/aws/services/logs/test_logs_groups.py::TestLogsGroups::test_create_log_group_with_kms_key": { + "last_validated_date": "2026-02-03T21:00:51+00:00", + "durations_in_seconds": { + "setup": 0.39, + "call": 0.94, + "teardown": 0.21, + "total": 1.54 + } + }, + "tests/aws/services/logs/test_logs_groups.py::TestLogsGroups::test_describe_log_groups_prefix_and_pattern_error": { + "last_validated_date": "2026-02-03T20:57:38+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.16, + "teardown": 0.11, + "total": 0.27 + } + }, + "tests/aws/services/logs/test_logs_groups.py::TestLogsGroups::test_describe_log_groups_with_pattern": { + "last_validated_date": "2026-02-03T20:57:37+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 1.46, + "teardown": 0.1, + "total": 1.56 + } + }, + "tests/aws/services/logs/test_logs_groups.py::TestLogsGroups::test_describe_log_groups_with_prefix": { + "last_validated_date": "2026-02-03T20:57:36+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.41, + "teardown": 0.31, + "total": 0.72 + } + }, + "tests/aws/services/logs/test_logs_groups.py::TestLogsGroups::test_list_log_groups_with_pattern": { + "last_validated_date": "2026-02-03T20:57:39+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 1.52, + "teardown": 0.1, + "total": 1.62 + } + }, + "tests/aws/services/logs/test_logs_groups.py::TestLogsGroupsRetention::test_delete_retention_policy": { + "last_validated_date": "2026-02-03T21:02:41+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.43, + "teardown": 0.11, + "total": 0.54 + } + }, + "tests/aws/services/logs/test_logs_groups.py::TestLogsGroupsRetention::test_put_retention_policy": { + "last_validated_date": "2026-02-03T21:02:40+00:00", + "durations_in_seconds": { + "setup": 0.01, + "call": 0.59, + "teardown": 0.13, + "total": 0.73 + } + }, + "tests/aws/services/logs/test_logs_groups.py::TestLogsGroupsTags::test_create_log_group_with_tags": { + "last_validated_date": "2026-02-03T21:03:36+00:00", + "durations_in_seconds": { + "setup": 0.38, + "call": 0.51, + "teardown": 0.18, + "total": 1.07 + } + }, + "tests/aws/services/logs/test_logs_groups.py::TestLogsGroupsTags::test_tag_log_group": { + "last_validated_date": "2026-02-03T21:03:37+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.63, + "teardown": 0.14, + "total": 0.77 + } + }, + "tests/aws/services/logs/test_logs_groups.py::TestLogsGroupsTags::test_tag_resource_api": { + "last_validated_date": "2026-02-03T21:03:39+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 1.17, + "teardown": 0.13, + "total": 1.3 + } + }, + "tests/aws/services/logs/test_logs_groups.py::TestLogsGroupsTags::test_untag_log_group": { + "last_validated_date": "2026-02-03T21:03:38+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.46, + "teardown": 0.13, + "total": 0.59 + } + } +} diff --git a/tests/aws/services/logs/test_logs_metric_filters.py b/tests/aws/services/logs/test_logs_metric_filters.py new file mode 100644 index 0000000000000..d149883b746f9 --- /dev/null +++ b/tests/aws/services/logs/test_logs_metric_filters.py @@ -0,0 +1,460 @@ +"""Tests for CloudWatch Logs - Metric Filter operations.""" + +import pytest +from localstack_snapshot.pytest.snapshot import is_aws + +from localstack.testing.pytest import markers +from localstack.utils.common import now_utc, retry, short_uid + + +class TestMetricFilters: + """Tests for metric filter operations.""" + + @markers.aws.validated + @markers.snapshot.skip_snapshot_verify( + paths=[ + "$..metricFilters..applyOnTransformedLogs", + "$..metricFilters..creationTime", + "$..metricFilters..metricTransformations..defaultValue", + ] + ) + def test_put_metric_filter_basic(self, logs_log_group, aws_client, snapshot, cleanups): + """Test basic metric filter creation.""" + filter_name = f"test-filter-{short_uid()}" + namespace = f"test-namespace-{short_uid()}" + metric_name = f"test-metric-{short_uid()}" + + snapshot.add_transformer(snapshot.transform.logs_api()) + snapshot.add_transformer(snapshot.transform.key_value("filterName")) + snapshot.add_transformer(snapshot.transform.key_value("metricName")) + snapshot.add_transformer(snapshot.transform.key_value("metricNamespace")) + + aws_client.logs.put_metric_filter( + logGroupName=logs_log_group, + filterName=filter_name, + filterPattern=" ", + metricTransformations=[ + { + "metricNamespace": namespace, + "metricName": metric_name, + "metricValue": "1", + "defaultValue": 0, + }, + ], + ) + cleanups.append( + lambda: aws_client.logs.delete_metric_filter( + logGroupName=logs_log_group, filterName=filter_name + ) + ) + + response = aws_client.logs.describe_metric_filters( + logGroupName=logs_log_group, filterNamePrefix=filter_name + ) + snapshot.match("describe-metric-filters", response) + + @markers.aws.validated + @markers.snapshot.skip_snapshot_verify( + paths=[ + "$..metricFilters..applyOnTransformedLogs", + "$..metricFilters..creationTime", + "$..metricFilters..metricTransformations..defaultValue", + ] + ) + def test_put_metric_filter_json_pattern(self, logs_log_group, aws_client, snapshot, cleanups): + """Test metric filter with JSON filter pattern.""" + filter_name = f"test-filter-json-{short_uid()}" + namespace = f"test-namespace-{short_uid()}" + metric_name = f"test-metric-{short_uid()}" + + snapshot.add_transformer(snapshot.transform.logs_api()) + snapshot.add_transformer(snapshot.transform.key_value("filterName")) + snapshot.add_transformer(snapshot.transform.key_value("metricName")) + snapshot.add_transformer(snapshot.transform.key_value("metricNamespace")) + + aws_client.logs.put_metric_filter( + logGroupName=logs_log_group, + filterName=filter_name, + filterPattern='{$.message = "test"}', + metricTransformations=[ + { + "metricNamespace": namespace, + "metricName": metric_name, + "metricValue": "1", + "defaultValue": 0, + }, + ], + ) + cleanups.append( + lambda: aws_client.logs.delete_metric_filter( + logGroupName=logs_log_group, filterName=filter_name + ) + ) + + response = aws_client.logs.describe_metric_filters( + logGroupName=logs_log_group, filterNamePrefix=filter_name + ) + snapshot.match("describe-metric-filters-json", response) + + @markers.aws.validated + @markers.snapshot.skip_snapshot_verify( + paths=["$..metricFilters..applyOnTransformedLogs", "$..metricFilters..creationTime"] + ) + def test_describe_metric_filters_by_prefix(self, aws_client, snapshot, cleanups): + """Test describing metric filters by name prefix.""" + + prefix = f"test-filter-prefix-{short_uid()}" + + snapshot.add_transformer(snapshot.transform.logs_api()) + snapshot.add_transformer(snapshot.transform.key_value("filterName")) + snapshot.add_transformer(snapshot.transform.key_value("metricName")) + snapshot.add_transformer(snapshot.transform.key_value("metricNamespace")) + + log_groups = [] + for i in range(2): + log_group = f"test-log-group-{short_uid()}" + aws_client.logs.create_log_group(logGroupName=log_group) + log_groups.append(log_group) + cleanups.append(lambda lg=log_group: aws_client.logs.delete_log_group(logGroupName=lg)) + + aws_client.logs.put_metric_filter( + logGroupName=log_group, + filterName=f"{prefix}-{i}", + filterPattern=f"filterPattern{i}", + metricTransformations=[ + { + "metricNamespace": f"namespace{i}", + "metricName": f"metric{i}", + "metricValue": str(i), + }, + ], + ) + cleanups.append( + lambda lg=log_group, fn=f"{prefix}-{i}": aws_client.logs.delete_metric_filter( + logGroupName=lg, filterName=fn + ) + ) + + response = aws_client.logs.describe_metric_filters(filterNamePrefix=prefix) + snapshot.match("describe-by-prefix", response) + + @markers.aws.validated + @markers.snapshot.skip_snapshot_verify(paths=["$..applyOnTransformedLogs", "$..creationTime"]) + def test_describe_metric_filters_by_log_group(self, aws_client, snapshot, cleanups): + """Test describing metric filters by log group name.""" + snapshot.add_transformer(snapshot.transform.logs_api()) + snapshot.add_transformer(snapshot.transform.key_value("filterName")) + + log_group1 = f"test-log-group-{short_uid()}" + log_group2 = f"test-log-group-{short_uid()}" + + for log_group in [log_group1, log_group2]: + aws_client.logs.create_log_group(logGroupName=log_group) + cleanups.append(lambda lg=log_group: aws_client.logs.delete_log_group(logGroupName=lg)) + + aws_client.logs.put_metric_filter( + logGroupName=log_group, + filterName=f"filter-{short_uid()}", + filterPattern="pattern", + metricTransformations=[ + { + "metricNamespace": "namespace", + "metricName": "metric", + "metricValue": "1", + }, + ], + ) + + response = aws_client.logs.describe_metric_filters(logGroupName=log_group1) + snapshot.match("describe-by-log-group", response) + + @markers.aws.validated + @markers.snapshot.skip_snapshot_verify(paths=["$..applyOnTransformedLogs", "$..creationTime"]) + def test_describe_metric_filters_by_metric_name( + self, aws_client, snapshot, cleanups, logs_log_group + ): + """Test describing metric filters by metric name and namespace.""" + + snapshot.add_transformer(snapshot.transform.logs_api()) + snapshot.add_transformer(snapshot.transform.key_value("filterName")) + snapshot.add_transformer(snapshot.transform.key_value("metricName")) + snapshot.add_transformer(snapshot.transform.key_value("metricNamespace")) + + log_group = logs_log_group + + metric_name = f"test-metric-{short_uid()}" + namespace = f"test-namespace-{short_uid()}" + + aws_client.logs.put_metric_filter( + logGroupName=log_group, + filterName=f"filter-{short_uid()}", + filterPattern="pattern", + metricTransformations=[ + { + "metricNamespace": namespace, + "metricName": metric_name, + "metricValue": "1", + }, + ], + ) + + response = aws_client.logs.describe_metric_filters( + metricName=metric_name, metricNamespace=namespace + ) + snapshot.match("describe-by-metric-name", response) + + @markers.aws.validated + def test_delete_metric_filter(self, logs_log_group, aws_client): + """Test deleting a metric filter.""" + filter_name = f"test-filter-{short_uid()}" + + aws_client.logs.put_metric_filter( + logGroupName=logs_log_group, + filterName=filter_name, + filterPattern="{ $.val = * }", + metricTransformations=[ + { + "metricNamespace": "namespace", + "metricName": "metric", + "metricValue": "$.value", + }, + ], + ) + + response = aws_client.logs.describe_metric_filters( + logGroupName=logs_log_group, filterNamePrefix=filter_name + ) + assert len(response["metricFilters"]) == 1 + + # Delete the filter + aws_client.logs.delete_metric_filter(logGroupName=logs_log_group, filterName=filter_name) + + response = aws_client.logs.describe_metric_filters( + logGroupName=logs_log_group, filterNamePrefix=filter_name + ) + assert len(response["metricFilters"]) == 0 + + @markers.aws.validated + def test_put_metric_filter_with_special_namespace(self, logs_log_group, aws_client, cleanups): + """Test metric filter with special characters in namespace.""" + filter_name = f"test-filter-{short_uid()}" + namespace = "A.B-c_d/1#2:metricNamespace" # Valid namespace with special chars + + aws_client.logs.put_metric_filter( + logGroupName=logs_log_group, + filterName=filter_name, + filterPattern="filterPattern", + metricTransformations=[ + { + "metricNamespace": namespace, + "metricName": "metricName", + "metricValue": "1", + }, + ], + ) + cleanups.append( + lambda: aws_client.logs.delete_metric_filter( + logGroupName=logs_log_group, filterName=filter_name + ) + ) + + response = aws_client.logs.describe_metric_filters( + metricName="metricName", metricNamespace=namespace + ) + assert len(response["metricFilters"]) == 1 + assert response["metricFilters"][0]["filterName"] == filter_name + + +class TestMetricFiltersValidation: + """Tests for metric filter validation.""" + + @markers.aws.validated + @markers.snapshot.skip_snapshot_verify(paths=["$..Error.Message"]) + def test_put_metric_filter_invalid_filter_name(self, logs_log_group, aws_client, snapshot): + """Test that filter names over 512 characters are rejected.""" + invalid_filter_name = "X" * 513 + + with pytest.raises(Exception) as ctx: + aws_client.logs.put_metric_filter( + logGroupName=logs_log_group, + filterName=invalid_filter_name, + filterPattern="pattern", + metricTransformations=[ + { + "metricNamespace": "namespace", + "metricName": "metric", + "metricValue": "1", + }, + ], + ) + snapshot.match("error-invalid-filter-name", ctx.value.response) + + @markers.aws.validated + @markers.snapshot.skip_snapshot_verify(paths=["$..Error.Message"]) + def test_put_metric_filter_invalid_filter_pattern(self, logs_log_group, aws_client, snapshot): + """Test that filter patterns over 1024 characters are rejected.""" + invalid_filter_pattern = "X" * 1025 + + with pytest.raises(Exception) as ctx: + aws_client.logs.put_metric_filter( + logGroupName=logs_log_group, + filterName="valid-filter", + filterPattern=invalid_filter_pattern, + metricTransformations=[ + { + "metricNamespace": "namespace", + "metricName": "metric", + "metricValue": "1", + }, + ], + ) + snapshot.match("error-invalid-filter-pattern", ctx.value.response) + + @markers.aws.validated + @markers.snapshot.skip_snapshot_verify(paths=["$..Error.Message"]) + def test_put_metric_filter_too_many_transformations(self, logs_log_group, aws_client, snapshot): + """Test that more than 1 metric transformation is rejected.""" + with pytest.raises(Exception) as ctx: + aws_client.logs.put_metric_filter( + logGroupName=logs_log_group, + filterName="valid-filter", + filterPattern="pattern", + metricTransformations=[ + { + "metricNamespace": "namespace1", + "metricName": "metric1", + "metricValue": "1", + }, + { + "metricNamespace": "namespace2", + "metricName": "metric2", + "metricValue": "1", + }, + ], + ) + snapshot.match("error-too-many-transformations", ctx.value.response) + + @markers.aws.validated + @markers.snapshot.skip_snapshot_verify(paths=["$..Error.Message"]) + def test_delete_metric_filter_invalid_filter_name(self, logs_log_group, aws_client, snapshot): + """Test delete metric filter with invalid filter name.""" + invalid_filter_name = "X" * 513 + + with pytest.raises(Exception) as ctx: + aws_client.logs.delete_metric_filter( + logGroupName=logs_log_group, filterName=invalid_filter_name + ) + snapshot.match("error-invalid-filter-name", ctx.value.response) + + @markers.aws.validated + @markers.snapshot.skip_snapshot_verify(paths=["$..Error.Message"]) + def test_delete_metric_filter_invalid_log_group_name(self, aws_client, snapshot): + """Test delete metric filter with invalid log group name.""" + invalid_log_group_name = "X" * 513 + + with pytest.raises(Exception) as ctx: + aws_client.logs.delete_metric_filter( + logGroupName=invalid_log_group_name, filterName="valid-filter" + ) + snapshot.match("error-invalid-log-group-name", ctx.value.response) + + @markers.aws.validated + @markers.snapshot.skip_snapshot_verify(paths=["$..Error.Message"]) + def test_describe_metric_filters_invalid_parameters(self, aws_client, snapshot): + """Test describe metric filters with invalid parameter lengths.""" + # Invalid filter name prefix (over 512 chars) + with pytest.raises(Exception) as ctx: + aws_client.logs.describe_metric_filters(filterNamePrefix="X" * 513) + snapshot.match("error-invalid-filter-prefix", ctx.value.response) + + # Invalid metric name (over 255 chars) + with pytest.raises(Exception) as ctx: + aws_client.logs.describe_metric_filters(metricName="X" * 256, metricNamespace="valid") + snapshot.match("error-invalid-metric-name", ctx.value.response) + + +class TestMetricFiltersCloudWatchIntegration: + """Tests for metric filter integration with CloudWatch metrics.""" + + @markers.aws.validated + @pytest.mark.skip(reason="TODO - Fails against pro") + def test_metric_filters_publish_to_cloudwatch( + self, logs_log_group, logs_log_stream, aws_client + ): + """Test that metric filters publish metrics to CloudWatch.""" + basic_filter_name = f"test-filter-basic-{short_uid()}" + json_filter_name = f"test-filter-json-{short_uid()}" + namespace_name = f"test-metric-namespace-{short_uid()}" + basic_metric_name = f"test-basic-metric-{short_uid()}" + json_metric_name = f"test-json-metric-{short_uid()}" + + basic_transforms = { + "metricNamespace": namespace_name, + "metricName": basic_metric_name, + "metricValue": "1", + "defaultValue": 0, + } + json_transforms = { + "metricNamespace": namespace_name, + "metricName": json_metric_name, + "metricValue": "1", + "defaultValue": 0, + } + + aws_client.logs.put_metric_filter( + logGroupName=logs_log_group, + filterName=basic_filter_name, + filterPattern=" ", + metricTransformations=[basic_transforms], + ) + aws_client.logs.put_metric_filter( + logGroupName=logs_log_group, + filterName=json_filter_name, + filterPattern='{$.message = "test"}', + metricTransformations=[json_transforms], + ) + + response = aws_client.logs.describe_metric_filters( + logGroupName=logs_log_group, filterNamePrefix="test-filter-" + ) + assert response["ResponseMetadata"]["HTTPStatusCode"] == 200 + filter_names = [_filter["filterName"] for _filter in response["metricFilters"]] + assert basic_filter_name in filter_names + assert json_filter_name in filter_names + + # Put log events and assert metrics being published + events = [ + {"timestamp": now_utc(millis=True), "message": "log message 1"}, + {"timestamp": now_utc(millis=True), "message": "log message 2"}, + ] + aws_client.logs.put_log_events( + logGroupName=logs_log_group, logStreamName=logs_log_stream, logEvents=events + ) + + # List metrics + def list_metrics(): + res = aws_client.cloudwatch.list_metrics(Namespace=namespace_name) + assert len(res["Metrics"]) == 2 + + retry( + list_metrics, + retries=20 if is_aws() else 5, + sleep=5 if is_aws() else 1, + sleep_before=3 if is_aws() else 0, + ) + + # Delete filters + aws_client.logs.delete_metric_filter( + logGroupName=logs_log_group, filterName=basic_filter_name + ) + aws_client.logs.delete_metric_filter( + logGroupName=logs_log_group, filterName=json_filter_name + ) + + response = aws_client.logs.describe_metric_filters( + logGroupName=logs_log_group, filterNamePrefix="test-filter-" + ) + assert response["ResponseMetadata"]["HTTPStatusCode"] == 200 + filter_names = [_filter["filterName"] for _filter in response["metricFilters"]] + assert basic_filter_name not in filter_names + assert json_filter_name not in filter_names diff --git a/tests/aws/services/logs/test_logs_metric_filters.snapshot.json b/tests/aws/services/logs/test_logs_metric_filters.snapshot.json new file mode 100644 index 0000000000000..d2b65cb4adfdd --- /dev/null +++ b/tests/aws/services/logs/test_logs_metric_filters.snapshot.json @@ -0,0 +1,253 @@ +{ + "tests/aws/services/logs/test_logs_metric_filters.py::TestMetricFilters::test_put_metric_filter_basic": { + "recorded-date": "05-02-2026, 21:13:19", + "recorded-content": { + "describe-metric-filters": { + "metricFilters": [ + { + "applyOnTransformedLogs": false, + "creationTime": "timestamp", + "filterName": "", + "filterPattern": " ", + "logGroupName": "", + "metricTransformations": [ + { + "defaultValue": 0.0, + "metricName": "", + "metricNamespace": "", + "metricValue": "1" + } + ] + } + ], + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/logs/test_logs_metric_filters.py::TestMetricFilters::test_put_metric_filter_json_pattern": { + "recorded-date": "05-02-2026, 21:15:47", + "recorded-content": { + "describe-metric-filters-json": { + "metricFilters": [ + { + "applyOnTransformedLogs": false, + "creationTime": "timestamp", + "filterName": "", + "filterPattern": "{$.message = \"test\"}", + "logGroupName": "", + "metricTransformations": [ + { + "defaultValue": 0.0, + "metricName": "", + "metricNamespace": "", + "metricValue": "1" + } + ] + } + ], + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/logs/test_logs_metric_filters.py::TestMetricFilters::test_describe_metric_filters_by_prefix": { + "recorded-date": "05-02-2026, 21:17:23", + "recorded-content": { + "describe-by-prefix": { + "metricFilters": [ + { + "applyOnTransformedLogs": false, + "creationTime": "timestamp", + "filterName": "", + "filterPattern": "filterPattern0", + "logGroupName": "", + "metricTransformations": [ + { + "metricName": "", + "metricNamespace": "", + "metricValue": "0" + } + ] + }, + { + "applyOnTransformedLogs": false, + "creationTime": "timestamp", + "filterName": "", + "filterPattern": "filterPattern1", + "logGroupName": "", + "metricTransformations": [ + { + "metricName": "", + "metricNamespace": "", + "metricValue": "1" + } + ] + } + ], + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/logs/test_logs_metric_filters.py::TestMetricFilters::test_describe_metric_filters_by_log_group": { + "recorded-date": "05-02-2026, 21:26:37", + "recorded-content": { + "describe-by-log-group": { + "metricFilters": [ + { + "applyOnTransformedLogs": false, + "creationTime": "timestamp", + "filterName": "", + "filterPattern": "pattern", + "logGroupName": "", + "metricTransformations": [ + { + "metricName": "metric", + "metricNamespace": "namespace", + "metricValue": "1" + } + ] + } + ], + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/logs/test_logs_metric_filters.py::TestMetricFilters::test_describe_metric_filters_by_metric_name": { + "recorded-date": "05-02-2026, 21:28:35", + "recorded-content": { + "describe-by-metric-name": { + "metricFilters": [ + { + "applyOnTransformedLogs": false, + "creationTime": "timestamp", + "filterName": "", + "filterPattern": "pattern", + "logGroupName": "", + "metricTransformations": [ + { + "metricName": "", + "metricNamespace": "", + "metricValue": "1" + } + ] + } + ], + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/logs/test_logs_metric_filters.py::TestMetricFiltersValidation::test_put_metric_filter_invalid_filter_name": { + "recorded-date": "05-02-2026, 21:30:38", + "recorded-content": { + "error-invalid-filter-name": { + "Error": { + "Code": "InvalidParameterException", + "Message": "1 validation error detected: Value 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX' at 'filterName' failed to satisfy constraint: Member must have length less than or equal to 512" + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + } + } + }, + "tests/aws/services/logs/test_logs_metric_filters.py::TestMetricFiltersValidation::test_put_metric_filter_invalid_filter_pattern": { + "recorded-date": "05-02-2026, 21:31:40", + "recorded-content": { + "error-invalid-filter-pattern": { + "Error": { + "Code": "InvalidParameterException", + "Message": "1 validation error detected: Value 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX' at 'filterPattern' failed to satisfy constraint: Member must have length less than or equal to 1024" + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + } + } + }, + "tests/aws/services/logs/test_logs_metric_filters.py::TestMetricFiltersValidation::test_put_metric_filter_too_many_transformations": { + "recorded-date": "05-02-2026, 21:32:47", + "recorded-content": { + "error-too-many-transformations": { + "Error": { + "Code": "InvalidParameterException", + "Message": "1 validation error detected: Value '[MetricTransformation(metricName=metric1, metricNamespace=namespace1, metricValue=1, defaultValue=null, unit=null, dimensions=null), MetricTransformation(metricName=metric2, metricNamespace=namespace2, metricValue=1, defaultValue=null, unit=null, dimensions=null)]' at 'metricTransformations' failed to satisfy constraint: Member must have length less than or equal to 1" + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + } + } + }, + "tests/aws/services/logs/test_logs_metric_filters.py::TestMetricFiltersValidation::test_delete_metric_filter_invalid_filter_name": { + "recorded-date": "05-02-2026, 21:33:33", + "recorded-content": { + "error-invalid-filter-name": { + "Error": { + "Code": "InvalidParameterException", + "Message": "1 validation error detected: Value 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX' at 'filterName' failed to satisfy constraint: Member must have length less than or equal to 512" + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + } + } + }, + "tests/aws/services/logs/test_logs_metric_filters.py::TestMetricFiltersValidation::test_delete_metric_filter_invalid_log_group_name": { + "recorded-date": "05-02-2026, 21:34:19", + "recorded-content": { + "error-invalid-log-group-name": { + "Error": { + "Code": "InvalidParameterException", + "Message": "Invalid LogGroup or LogStream, both must have length less than or equal to 512." + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + } + } + }, + "tests/aws/services/logs/test_logs_metric_filters.py::TestMetricFiltersValidation::test_describe_metric_filters_invalid_parameters": { + "recorded-date": "05-02-2026, 21:34:54", + "recorded-content": { + "error-invalid-filter-prefix": { + "Error": { + "Code": "InvalidParameterException", + "Message": "1 validation error detected: Value 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX' at 'filterNamePrefix' failed to satisfy constraint: Member must have length less than or equal to 512" + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + }, + "error-invalid-metric-name": { + "Error": { + "Code": "InvalidParameterException", + "Message": "1 validation error detected: Value 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX' at 'metricName' failed to satisfy constraint: Member must have length less than or equal to 255" + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + } + } + } +} diff --git a/tests/aws/services/logs/test_logs_metric_filters.validation.json b/tests/aws/services/logs/test_logs_metric_filters.validation.json new file mode 100644 index 0000000000000..8a6222bcada1f --- /dev/null +++ b/tests/aws/services/logs/test_logs_metric_filters.validation.json @@ -0,0 +1,119 @@ +{ + "tests/aws/services/logs/test_logs_metric_filters.py::TestMetricFilters::test_describe_metric_filters_by_log_group": { + "last_validated_date": "2026-02-05T21:26:37+00:00", + "durations_in_seconds": { + "setup": 0.37, + "call": 0.79, + "teardown": 0.28, + "total": 1.44 + } + }, + "tests/aws/services/logs/test_logs_metric_filters.py::TestMetricFilters::test_describe_metric_filters_by_metric_name": { + "last_validated_date": "2026-02-05T21:28:35+00:00", + "durations_in_seconds": { + "setup": 0.76, + "call": 0.23, + "teardown": 0.13, + "total": 1.12 + } + }, + "tests/aws/services/logs/test_logs_metric_filters.py::TestMetricFilters::test_describe_metric_filters_by_prefix": { + "last_validated_date": "2026-02-05T21:17:23+00:00", + "durations_in_seconds": { + "setup": 0.36, + "call": 0.8, + "teardown": 0.44, + "total": 1.6 + } + }, + "tests/aws/services/logs/test_logs_metric_filters.py::TestMetricFilters::test_put_metric_filter_basic": { + "last_validated_date": "2026-02-05T21:13:19+00:00", + "durations_in_seconds": { + "setup": 0.74, + "call": 0.21, + "teardown": 0.24, + "total": 1.19 + } + }, + "tests/aws/services/logs/test_logs_metric_filters.py::TestMetricFilters::test_put_metric_filter_json_pattern": { + "last_validated_date": "2026-02-05T21:15:47+00:00", + "durations_in_seconds": { + "setup": 0.74, + "call": 0.21, + "teardown": 0.24, + "total": 1.19 + } + }, + "tests/aws/services/logs/test_logs_metric_filters.py::TestMetricFilters::test_put_metric_filter_with_special_namespace": { + "last_validated_date": "2026-02-05T21:29:55+00:00", + "durations_in_seconds": { + "setup": 0.43, + "call": 0.29, + "teardown": 0.23, + "total": 0.95 + } + }, + "tests/aws/services/logs/test_logs_metric_filters.py::TestMetricFiltersCloudWatchIntegration::test_metric_filters_publish_to_cloudwatch": { + "last_validated_date": "2026-02-09T19:26:41+00:00", + "durations_in_seconds": { + "setup": 0.49, + "call": 4.09, + "teardown": 0.23, + "total": 4.81 + } + }, + "tests/aws/services/logs/test_logs_metric_filters.py::TestMetricFiltersValidation::test_delete_metric_filter_invalid_filter_name": { + "last_validated_date": "2026-02-05T21:33:33+00:00", + "durations_in_seconds": { + "setup": 0.74, + "call": 0.08, + "teardown": 0.14, + "total": 0.96 + } + }, + "tests/aws/services/logs/test_logs_metric_filters.py::TestMetricFiltersValidation::test_delete_metric_filter_invalid_log_group_name": { + "last_validated_date": "2026-02-05T21:34:19+00:00", + "durations_in_seconds": { + "setup": 0.37, + "call": 0.32, + "teardown": 0.0, + "total": 0.69 + } + }, + "tests/aws/services/logs/test_logs_metric_filters.py::TestMetricFiltersValidation::test_describe_metric_filters_invalid_parameters": { + "last_validated_date": "2026-02-05T21:34:54+00:00", + "durations_in_seconds": { + "setup": 0.35, + "call": 0.43, + "teardown": 0.0, + "total": 0.78 + } + }, + "tests/aws/services/logs/test_logs_metric_filters.py::TestMetricFiltersValidation::test_put_metric_filter_invalid_filter_name": { + "last_validated_date": "2026-02-05T21:30:38+00:00", + "durations_in_seconds": { + "setup": 0.74, + "call": 0.08, + "teardown": 0.12, + "total": 0.94 + } + }, + "tests/aws/services/logs/test_logs_metric_filters.py::TestMetricFiltersValidation::test_put_metric_filter_invalid_filter_pattern": { + "last_validated_date": "2026-02-05T21:31:40+00:00", + "durations_in_seconds": { + "setup": 0.75, + "call": 0.08, + "teardown": 0.14, + "total": 0.97 + } + }, + "tests/aws/services/logs/test_logs_metric_filters.py::TestMetricFiltersValidation::test_put_metric_filter_too_many_transformations": { + "last_validated_date": "2026-02-05T21:32:47+00:00", + "durations_in_seconds": { + "setup": 0.75, + "call": 0.08, + "teardown": 0.27, + "total": 1.1 + } + } +} diff --git a/tests/aws/services/logs/test_logs_queries.py b/tests/aws/services/logs/test_logs_queries.py new file mode 100644 index 0000000000000..5858a21743f2a --- /dev/null +++ b/tests/aws/services/logs/test_logs_queries.py @@ -0,0 +1,215 @@ +"""Tests for CloudWatch Logs - Insights Query operations.""" + +import time + +import pytest +from localstack_snapshot.pytest.snapshot import is_aws + +from localstack.testing.pytest import markers +from localstack.utils.common import now_utc, retry, short_uid + + +def _get_query_results(aws_client, query_id): + def _assert_query_status(): + query_results = aws_client.logs.get_query_results(queryId=query_id) + assert query_results["status"] in ["Complete"] + return query_results + + return retry( + _assert_query_status, + retries=20 if is_aws() else 3, + sleep=5 if is_aws() else 1, + sleep_before=3 if is_aws() else 0, + ) + + +class TestCloudWatchLogsInsightsQueries: + """Tests for CloudWatch Logs Insights query operations.""" + + @markers.aws.validated + def test_start_query_basic(self, logs_log_group, aws_client, snapshot): + """Test starting a basic query.""" + snapshot.add_transformer(snapshot.transform.logs_api()) + + response = aws_client.logs.start_query( + logGroupName=logs_log_group, + startTime=int(time.time()) - 3600, # 1 hour ago + endTime=int(time.time()) + 300, # 5 minutes from now + queryString="fields @message", + ) + snapshot.match("start-query", response) + + @markers.aws.validated + @markers.snapshot.skip_snapshot_verify(paths=["$..Error.Message"]) + def test_start_query_log_group_not_found(self, aws_client, snapshot): + """Test starting a query on a non-existent log group.""" + log_group = f"non-existent-{short_uid()}" + with pytest.raises(Exception) as ctx: + aws_client.logs.start_query( + logGroupName=log_group, + startTime=int(time.time()) - 3600, + endTime=int(time.time()) + 300, + queryString="fields @message", + ) + snapshot.add_transformer(snapshot.transform.regex(log_group, "")) + snapshot.match("error-log-group-not-found", ctx.value.response) + + @markers.aws.validated + @markers.snapshot.skip_snapshot_verify( + paths=[ + "$..queries..createTime", + "$..queries..queryLanguage", + "$..queries..queryString", + "$..queries..status", + ] + ) + def test_describe_queries(self, logs_log_group, aws_client, snapshot): + """Test describing queries for a log group.""" + + start_time = int(time.time()) - 3600 + end_time = int(time.time()) + 300 + + # Start a query + aws_client.logs.start_query( + logGroupName=logs_log_group, + startTime=start_time, + endTime=end_time, + queryString="fields @message", + ) + + # Describe queries + response = aws_client.logs.describe_queries(logGroupName=logs_log_group) + + snapshot.add_transformer(snapshot.transform.key_value("logGroupName")) + snapshot.match("describe-queries", response) + + @markers.aws.validated + @markers.snapshot.skip_snapshot_verify( + paths=["$..queries..queryLanguage", "$..queries..queryString"] + ) + def test_describe_queries_with_status_filter(self, logs_log_group, aws_client, snapshot): + """Test decscribing queries with status filter.""" + + start_time = int(time.time()) - 3600 + end_time = int(time.time()) + 300 + + # Start a query + aws_client.logs.start_query( + logGroupName=logs_log_group, + startTime=start_time, + endTime=end_time, + queryString="fields @message", + ) + + # Describe queries with Complete status + def describe_complete_queries(): + response = aws_client.logs.describe_queries( + logGroupName=logs_log_group, status="Complete" + ) + return response + + response = retry( + describe_complete_queries, + retries=20 if is_aws() else 3, + sleep=5 if is_aws() else 1, + sleep_before=3 if is_aws() else 0, + ) + + snapshot.add_transformer(snapshot.transform.logs_api()) + snapshot.add_transformer( + snapshot.transform.key_value("createTime", reference_replacement=False) + ) + snapshot.add_transformer(snapshot.transform.key_value("status")) + snapshot.add_transformer(snapshot.transform.regex(str(start_time), "")) + snapshot.add_transformer(snapshot.transform.regex(str(end_time), "")) + snapshot.add_transformer(snapshot.transform.regex(logs_log_group, "")) + + snapshot.match("describe-queries-complete", response) + + # Query with Scheduled status should return different results + response = aws_client.logs.describe_queries(logGroupName=logs_log_group, status="Scheduled") + snapshot.match("describe-queries-scheduled", response) + + @markers.aws.validated + def test_describe_queries_empty(self, aws_client, cleanups): + """Test describing queries for a log group with no queries.""" + log_group_name = f"test-log-group-{short_uid()}" + aws_client.logs.create_log_group(logGroupName=log_group_name) + cleanups.append(lambda: aws_client.logs.delete_log_group(logGroupName=log_group_name)) + + response = aws_client.logs.describe_queries(logGroupName=log_group_name) + assert response["queries"] == [] + + +class TestCloudWatchLogsInsightsQueryStrings: + """Tests for various CloudWatch Logs Insights query string patterns.""" + + def _populate_log_group(self, aws_client, log_group_name, log_stream_name): + # Put some log events + timestamp = now_utc(millis=True) + messages = [ + {"timestamp": timestamp - (i * 1000), "message": f"event nr {i}"} for i in range(5) + ] + messages.reverse() + aws_client.logs.put_log_events( + logGroupName=log_group_name, logStreamName=log_stream_name, logEvents=messages + ) + + def _query_results(self, aws_client, log_group_name, query): + # Start a query + start_time = now_utc() - 600 # 10 minutes ago + end_time = start_time + 1200 # 10 minutes from now + + def run_query_and_get_results(): + # Get query results (may need to wait for completion) + query_id = aws_client.logs.start_query( + logGroupName=log_group_name, + startTime=start_time, + endTime=end_time, + queryString=query, + )["queryId"] + results = _get_query_results(aws_client, query_id) + assert len(results["results"]) + return results + + return retry( + run_query_and_get_results, + retries=20 if is_aws() else 3, + sleep=5 if is_aws() else 1, + sleep_before=3 if is_aws() else 0, + ) + + @markers.aws.needs_fixing # The query results are not matching + def test_get_query_results(self, logs_log_group, logs_log_stream, aws_client): + """Test getting query results.""" + + self._populate_log_group(aws_client, logs_log_group, logs_log_stream) + response = self._query_results(aws_client, logs_log_group, "fields @message") + + # TODO FIX issue with Logs returning only one message + assert len(response["results"]) >= 1 + + fields = {row["field"] for result in response["results"] for row in result} + assert "@message" in fields or "@ptr" in fields + + @markers.aws.needs_fixing + def test_query_with_limit(self, logs_log_group, logs_log_stream, aws_client): + """Test query with limit clause.""" + + self._populate_log_group(aws_client, logs_log_group, logs_log_stream) + response = self._query_results(aws_client, logs_log_group, "fields @message | limit 5") + + # TODO FIX issue with Logs returning only one message + assert len(response["results"]) <= 5 + + @markers.aws.needs_fixing + def test_query_with_sort(self, logs_log_group, logs_log_stream, aws_client): + """Test query with sort clause.""" + + self._populate_log_group(aws_client, logs_log_group, logs_log_stream) + response = self._query_results( + aws_client, logs_log_group, "fields @timestamp, @message | sort @timestamp desc" + ) + + # TODO FIX issue with Logs returning only one message + assert len(response["results"]) diff --git a/tests/aws/services/logs/test_logs_queries.snapshot.json b/tests/aws/services/logs/test_logs_queries.snapshot.json new file mode 100644 index 0000000000000..e99acca475917 --- /dev/null +++ b/tests/aws/services/logs/test_logs_queries.snapshot.json @@ -0,0 +1,78 @@ +{ + "tests/aws/services/logs/test_logs_queries.py::TestCloudWatchLogsInsightsQueries::test_start_query_basic": { + "recorded-date": "06-02-2026, 14:49:07", + "recorded-content": { + "start-query": { + "queryId": "", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/logs/test_logs_queries.py::TestCloudWatchLogsInsightsQueries::test_start_query_log_group_not_found": { + "recorded-date": "06-02-2026, 14:51:58", + "recorded-content": { + "error-log-group-not-found": { + "Error": { + "Code": "ResourceNotFoundException", + "Message": "Log group '' does not exist for account ID '111111111111' (Service: AWSLogs; Status Code: 400; Error Code: ResourceNotFoundException; Request ID: b04848e1-f91e-4ed5-8a00-413d7c60de9e; Proxy: null)" + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + } + } + }, + "tests/aws/services/logs/test_logs_queries.py::TestCloudWatchLogsInsightsQueries::test_describe_queries": { + "recorded-date": "06-02-2026, 15:47:17", + "recorded-content": { + "describe-queries": { + "queries": [ + { + "createTime": "create-time", + "logGroupName": "", + "queryId": "", + "queryLanguage": "CWLI", + "queryString": "SOURCE \"\" START=000 END=999 | fields @message", + "status": "" + } + ], + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/logs/test_logs_queries.py::TestCloudWatchLogsInsightsQueries::test_describe_queries_with_status_filter": { + "recorded-date": "06-02-2026, 18:09:24", + "recorded-content": { + "describe-queries-complete": { + "queries": [ + { + "createTime": "create-time", + "logGroupName": "", + "queryId": "", + "queryLanguage": "CWLI", + "queryString": "SOURCE \"\" START=000 END=999 | fields @message", + "status": "" + } + ], + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "describe-queries-scheduled": { + "queries": [], + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + } +} diff --git a/tests/aws/services/logs/test_logs_queries.validation.json b/tests/aws/services/logs/test_logs_queries.validation.json new file mode 100644 index 0000000000000..60b8783165777 --- /dev/null +++ b/tests/aws/services/logs/test_logs_queries.validation.json @@ -0,0 +1,65 @@ +{ + "tests/aws/services/logs/test_logs_queries.py::TestCloudWatchLogsInsightsQueries::test_describe_queries": { + "last_validated_date": "2026-02-06T15:47:17+00:00", + "durations_in_seconds": { + "setup": 0.74, + "call": 0.25, + "teardown": 0.13, + "total": 1.12 + } + }, + "tests/aws/services/logs/test_logs_queries.py::TestCloudWatchLogsInsightsQueries::test_describe_queries_empty": { + "last_validated_date": "2026-02-06T18:09:28+00:00", + "durations_in_seconds": { + "setup": 0.01, + "call": 0.5, + "teardown": 0.12, + "total": 0.63 + } + }, + "tests/aws/services/logs/test_logs_queries.py::TestCloudWatchLogsInsightsQueries::test_describe_queries_with_status_filter": { + "last_validated_date": "2026-02-06T18:09:24+00:00", + "durations_in_seconds": { + "setup": 0.74, + "call": 3.37, + "teardown": 0.13, + "total": 4.24 + } + }, + "tests/aws/services/logs/test_logs_queries.py::TestCloudWatchLogsInsightsQueries::test_start_query_basic": { + "last_validated_date": "2026-02-06T14:49:07+00:00", + "durations_in_seconds": { + "setup": 0.75, + "call": 0.12, + "teardown": 0.12, + "total": 0.99 + } + }, + "tests/aws/services/logs/test_logs_queries.py::TestCloudWatchLogsInsightsQueries::test_start_query_log_group_not_found": { + "last_validated_date": "2026-02-06T14:51:58+00:00", + "durations_in_seconds": { + "setup": 0.63, + "call": 0.43, + "teardown": 0.0, + "total": 1.06 + } + }, + "tests/aws/services/logs/test_logs_queries.py::TestCloudWatchLogsInsightsQueryStrings::test_query_fields_message": { + "last_validated_date": "2026-02-06T18:15:06+00:00", + "durations_in_seconds": { + "setup": 0.5, + "call": 122.55, + "teardown": 0.27, + "total": 123.32 + } + }, + "tests/aws/services/logs/test_logs_queries.py::TestCloudWatchLogsInsightsQueryStrings::test_query_with_sort": { + "last_validated_date": "2026-02-06T18:43:06+00:00", + "durations_in_seconds": { + "setup": 0.49, + "call": 130.93, + "teardown": 0.25, + "total": 131.67 + } + } +} diff --git a/tests/aws/services/logs/test_logs_resource_policies.py b/tests/aws/services/logs/test_logs_resource_policies.py new file mode 100644 index 0000000000000..9444e02f0b2ea --- /dev/null +++ b/tests/aws/services/logs/test_logs_resource_policies.py @@ -0,0 +1,219 @@ +"""Tests for CloudWatch Logs - Resource Policy operations.""" + +import json + +import pytest + +from localstack.testing.pytest import markers +from localstack.utils.common import short_uid + +# Maximum number of resource policies per region (AWS limit) +MAX_RESOURCE_POLICIES_PER_REGION = 10 + +JSON_POLICY_DOC = json.dumps( + { + "Version": "2012-10-17", + "Statement": [ + { + "Sid": "Route53LogsToCloudWatchLogs", + "Effect": "Allow", + "Principal": {"Service": ["route53.amazonaws.com"]}, + "Action": "logs:PutLogEvents", + "Resource": "log_arn", + } + ], + } +) + + +class TestResourcePolicies: + """Tests for resource policy operations.""" + + @markers.aws.validated + @markers.snapshot.skip_snapshot_verify(paths=["$..policyScope"]) + def test_put_resource_policy(self, aws_client, snapshot, cleanups): + """Test creating a resource policy.""" + snapshot.add_transformer(snapshot.transform.logs_api()) + log_group_name = f"test-log-group-{short_uid()}" + policy_name = f"test-policy-{short_uid()}" + + # Create a log group to use its ARN in the policy + aws_client.logs.create_log_group(logGroupName=log_group_name) + cleanups.append(lambda: aws_client.logs.delete_log_group(logGroupName=log_group_name)) + + log_group_info = aws_client.logs.describe_log_groups(logGroupNamePrefix=log_group_name) + log_group_arn = log_group_info["logGroups"][0]["arn"] + + policy_doc = json.dumps( + { + "Version": "2012-10-17", + "Statement": [ + { + "Sid": "Route53LogsToCloudWatchLogs", + "Effect": "Allow", + "Principal": {"Service": ["route53.amazonaws.com"]}, + "Action": "logs:PutLogEvents", + "Resource": log_group_arn, + } + ], + } + ) + + response = aws_client.logs.put_resource_policy( + policyName=policy_name, policyDocument=policy_doc + ) + cleanups.append(lambda: aws_client.logs.delete_resource_policy(policyName=policy_name)) + + snapshot.add_transformer(snapshot.transform.key_value("policyName")) + snapshot.add_transformer( + snapshot.transform.key_value("lastUpdatedTime", reference_replacement=False) + ) + snapshot.add_transformer(snapshot.transform.regex(log_group_arn, "")) + snapshot.match("put-resource-policy", response) + + @markers.aws.validated + @markers.snapshot.skip_snapshot_verify( + paths=[ + "$..policyDocument.Statement..Principal.Service", + "$..policyDocument.Version", + "$..policyScope", + ] + ) + def test_put_resource_policy_update(self, aws_client, snapshot, cleanups): + """Test updating an existing resource policy.""" + policy_name = f"test-policy-{short_uid()}" + + # Create initial policy + aws_client.logs.put_resource_policy(policyName=policy_name, policyDocument=JSON_POLICY_DOC) + cleanups.append(lambda: aws_client.logs.delete_resource_policy(policyName=policy_name)) + + response = aws_client.logs.describe_resource_policies() + policies = [p for p in response["resourcePolicies"] if p["policyName"] == policy_name] + assert len(policies) == 1 + created_time = policies[0]["lastUpdatedTime"] + + # Update the policy with different document + new_document = '{"Statement":[{"Action":"logs:*","Effect":"Allow","Principal":{"Service": ["route53.amazonaws.com"]},"Resource":"*"}]}' + aws_client.logs.put_resource_policy(policyName=policy_name, policyDocument=new_document) + response = aws_client.logs.describe_resource_policies() + policies = [p for p in response["resourcePolicies"] if p["policyName"] == policy_name] + + assert created_time != policies[0]["lastUpdatedTime"] + + snapshot.add_transformer(snapshot.transform.key_value("policyName")) + snapshot.add_transformer( + snapshot.transform.key_value("lastUpdatedTime", reference_replacement=False) + ) + snapshot.match("updated-policy", policies[0]) + + @markers.aws.validated + @markers.snapshot.skip_snapshot_verify( + paths=[ + "$..policyDocument.Statement..Principal.Service", + "$..policyDocument.Version", + "$..policyScope", + ] + ) + def test_describe_resource_policies(self, aws_client, snapshot, cleanups): + """Test describing resource policies.""" + snapshot.add_transformer(snapshot.transform.logs_api()) + prefix = f"test-policy-{short_uid()}" + + # Create multiple policies + for i in range(3): + policy_name = f"{prefix}-{i}" + aws_client.logs.put_resource_policy( + policyName=policy_name, policyDocument=JSON_POLICY_DOC + ) + cleanups.append( + lambda pn=policy_name: aws_client.logs.delete_resource_policy(policyName=pn) + ) + + response = aws_client.logs.describe_resource_policies() + snapshot.match("describe-resource-policies", response) + + # Should contain at least the 3 we created + policies = [p for p in response["resourcePolicies"] if p["policyName"].startswith(prefix)] + snapshot.add_transformer(snapshot.transform.key_value("policyName")) + snapshot.add_transformer( + snapshot.transform.key_value("lastUpdatedTime", reference_replacement=False) + ) + snapshot.match("policies", policies) + + @markers.aws.validated + def test_delete_resource_policy(self, aws_client, cleanups): + """Test deleting a resource policy.""" + policy_name = f"test-policy-{short_uid()}" + + aws_client.logs.put_resource_policy(policyName=policy_name, policyDocument=JSON_POLICY_DOC) + + # Verify it exists + response = aws_client.logs.describe_resource_policies() + policy_names = [p["policyName"] for p in response["resourcePolicies"]] + assert policy_name in policy_names + + # Delete the policy + aws_client.logs.delete_resource_policy(policyName=policy_name) + + # Verify it's deleted + response = aws_client.logs.describe_resource_policies() + policy_names = [p["policyName"] for p in response["resourcePolicies"]] + assert policy_name not in policy_names + + @markers.aws.validated + @markers.snapshot.skip_snapshot_verify(paths=["$..Error.Message"]) + def test_delete_resource_policy_not_found(self, aws_client, snapshot): + """Test deleting a non-existent resource policy.""" + with pytest.raises(Exception) as ctx: + aws_client.logs.delete_resource_policy(policyName="non-existent") + snapshot.match("error-policy-not-found", ctx.value.response) + + +class TestResourcePoliciesLimits: + """Tests for resource policy limit enforcement.""" + + @markers.aws.validated + def test_put_resource_policy_limit_exceeded(self, aws_client, snapshot, cleanups): + """Test that creating more than MAX_RESOURCE_POLICIES_PER_REGION fails.""" + snapshot.add_transformer(snapshot.transform.logs_api()) + prefix = f"test-policy-limit-{short_uid()}" + + # Create the maximum number of resource policies + for idx in range(MAX_RESOURCE_POLICIES_PER_REGION): + policy_name = f"{prefix}-{idx}" + aws_client.logs.put_resource_policy( + policyName=policy_name, policyDocument=JSON_POLICY_DOC + ) + cleanups.append( + lambda pn=policy_name: aws_client.logs.delete_resource_policy(policyName=pn) + ) + + # Try to create one more - should fail + with pytest.raises(Exception) as ctx: + aws_client.logs.put_resource_policy( + policyName=f"{prefix}-too-many", policyDocument=JSON_POLICY_DOC + ) + snapshot.match("error-limit-exceeded", ctx.value.response) + + @markers.aws.validated + def test_put_resource_policy_update_existing_when_at_limit(self, aws_client, cleanups): + """Test that updating existing policy works even when at limit.""" + prefix = f"test-policy-limit-{short_uid()}" + + # Create the maximum number of resource policies + for idx in range(MAX_RESOURCE_POLICIES_PER_REGION): + policy_name = f"{prefix}-{idx}" + aws_client.logs.put_resource_policy( + policyName=policy_name, policyDocument=JSON_POLICY_DOC + ) + cleanups.append( + lambda pn=policy_name: aws_client.logs.delete_resource_policy(policyName=pn) + ) + + # Update an existing policy - should succeed + new_document = '{"Statement":[{"Action":"logs:*","Effect":"Allow","Principal":{"Service":"logs.amazonaws.com"},"Resource":"*"}]}' + response = aws_client.logs.put_resource_policy( + policyName=f"{prefix}-1", policyDocument=new_document + ) + + assert response["resourcePolicy"]["policyDocument"] == new_document diff --git a/tests/aws/services/logs/test_logs_resource_policies.snapshot.json b/tests/aws/services/logs/test_logs_resource_policies.snapshot.json new file mode 100644 index 0000000000000..9118f990627fd --- /dev/null +++ b/tests/aws/services/logs/test_logs_resource_policies.snapshot.json @@ -0,0 +1,216 @@ +{ + "tests/aws/services/logs/test_logs_resource_policies.py::TestResourcePolicies::test_put_resource_policy": { + "recorded-date": "06-02-2026, 19:30:22", + "recorded-content": { + "put-resource-policy": { + "resourcePolicy": { + "lastUpdatedTime": "last-updated-time", + "policyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Sid": "Route53LogsToCloudWatchLogs", + "Effect": "Allow", + "Principal": { + "Service": [ + "route53.amazonaws.com" + ] + }, + "Action": "logs:PutLogEvents", + "Resource": "*" + } + ] + }, + "policyName": "", + "policyScope": "ACCOUNT" + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/logs/test_logs_resource_policies.py::TestResourcePolicies::test_put_resource_policy_update": { + "recorded-date": "06-02-2026, 19:29:16", + "recorded-content": { + "updated-policy": { + "lastUpdatedTime": "last-updated-time", + "policyDocument": { + "Version": "2008-10-17", + "Statement": [ + { + "Effect": "Allow", + "Principal": { + "Service": "route53.amazonaws.com" + }, + "Action": "logs:*", + "Resource": "*" + } + ] + }, + "policyName": "", + "policyScope": "ACCOUNT" + } + } + }, + "tests/aws/services/logs/test_logs_resource_policies.py::TestResourcePolicies::test_describe_resource_policies": { + "recorded-date": "06-02-2026, 19:33:10", + "recorded-content": { + "describe-resource-policies": { + "resourcePolicies": [ + { + "lastUpdatedTime": "last-updated-time", + "policyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Sid": "Route53LogsToCloudWatchLogs", + "Effect": "Allow", + "Principal": { + "Service": "route53.amazonaws.com" + }, + "Action": "logs:PutLogEvents", + "Resource": "log_arn" + } + ] + }, + "policyName": "", + "policyScope": "ACCOUNT" + }, + { + "lastUpdatedTime": "last-updated-time", + "policyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Sid": "Route53LogsToCloudWatchLogs", + "Effect": "Allow", + "Principal": { + "Service": "route53.amazonaws.com" + }, + "Action": "logs:PutLogEvents", + "Resource": "log_arn" + } + ] + }, + "policyName": "", + "policyScope": "ACCOUNT" + }, + { + "lastUpdatedTime": "last-updated-time", + "policyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Sid": "Route53LogsToCloudWatchLogs", + "Effect": "Allow", + "Principal": { + "Service": "route53.amazonaws.com" + }, + "Action": "logs:PutLogEvents", + "Resource": "log_arn" + } + ] + }, + "policyName": "", + "policyScope": "ACCOUNT" + } + ], + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "policies": [ + { + "policyName": "", + "policyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Sid": "Route53LogsToCloudWatchLogs", + "Effect": "Allow", + "Principal": { + "Service": "route53.amazonaws.com" + }, + "Action": "logs:PutLogEvents", + "Resource": "log_arn" + } + ] + }, + "lastUpdatedTime": "last-updated-time", + "policyScope": "ACCOUNT" + }, + { + "policyName": "", + "policyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Sid": "Route53LogsToCloudWatchLogs", + "Effect": "Allow", + "Principal": { + "Service": "route53.amazonaws.com" + }, + "Action": "logs:PutLogEvents", + "Resource": "log_arn" + } + ] + }, + "lastUpdatedTime": "last-updated-time", + "policyScope": "ACCOUNT" + }, + { + "policyName": "", + "policyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Sid": "Route53LogsToCloudWatchLogs", + "Effect": "Allow", + "Principal": { + "Service": "route53.amazonaws.com" + }, + "Action": "logs:PutLogEvents", + "Resource": "log_arn" + } + ] + }, + "lastUpdatedTime": "last-updated-time", + "policyScope": "ACCOUNT" + } + ] + } + }, + "tests/aws/services/logs/test_logs_resource_policies.py::TestResourcePolicies::test_delete_resource_policy_not_found": { + "recorded-date": "06-02-2026, 19:36:10", + "recorded-content": { + "error-policy-not-found": { + "Error": { + "Code": "ResourceNotFoundException", + "Message": "Policy with name [non-existent] does not exist." + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + } + } + }, + "tests/aws/services/logs/test_logs_resource_policies.py::TestResourcePoliciesLimits::test_put_resource_policy_limit_exceeded": { + "recorded-date": "06-02-2026, 19:37:18", + "recorded-content": { + "error-limit-exceeded": { + "Error": { + "Code": "LimitExceededException", + "Message": "Resource limit exceeded." + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + } + } + } +} diff --git a/tests/aws/services/logs/test_logs_resource_policies.validation.json b/tests/aws/services/logs/test_logs_resource_policies.validation.json new file mode 100644 index 0000000000000..b0402a0a7c98a --- /dev/null +++ b/tests/aws/services/logs/test_logs_resource_policies.validation.json @@ -0,0 +1,65 @@ +{ + "tests/aws/services/logs/test_logs_resource_policies.py::TestResourcePolicies::test_delete_resource_policy": { + "last_validated_date": "2026-02-06T19:34:19+00:00", + "durations_in_seconds": { + "setup": 0.01, + "call": 0.65, + "teardown": 0.0, + "total": 0.66 + } + }, + "tests/aws/services/logs/test_logs_resource_policies.py::TestResourcePolicies::test_delete_resource_policy_not_found": { + "last_validated_date": "2026-02-06T19:36:10+00:00", + "durations_in_seconds": { + "setup": 0.37, + "call": 0.36, + "teardown": 0.0, + "total": 0.73 + } + }, + "tests/aws/services/logs/test_logs_resource_policies.py::TestResourcePolicies::test_describe_resource_policies": { + "last_validated_date": "2026-02-06T19:33:10+00:00", + "durations_in_seconds": { + "setup": 0.38, + "call": 0.65, + "teardown": 0.27, + "total": 1.3 + } + }, + "tests/aws/services/logs/test_logs_resource_policies.py::TestResourcePolicies::test_put_resource_policy": { + "last_validated_date": "2026-02-06T19:30:22+00:00", + "durations_in_seconds": { + "setup": 0.38, + "call": 0.57, + "teardown": 0.22, + "total": 1.17 + } + }, + "tests/aws/services/logs/test_logs_resource_policies.py::TestResourcePolicies::test_put_resource_policy_update": { + "last_validated_date": "2026-02-06T19:29:16+00:00", + "durations_in_seconds": { + "setup": 0.38, + "call": 0.67, + "teardown": 0.09, + "total": 1.14 + } + }, + "tests/aws/services/logs/test_logs_resource_policies.py::TestResourcePoliciesLimits::test_put_resource_policy_limit_exceeded": { + "last_validated_date": "2026-02-06T19:37:18+00:00", + "durations_in_seconds": { + "setup": 0.38, + "call": 1.47, + "teardown": 0.92, + "total": 2.77 + } + }, + "tests/aws/services/logs/test_logs_resource_policies.py::TestResourcePoliciesLimits::test_put_resource_policy_update_existing_when_at_limit": { + "last_validated_date": "2026-02-06T19:38:45+00:00", + "durations_in_seconds": { + "setup": 0.01, + "call": 1.34, + "teardown": 0.97, + "total": 2.32 + } + } +} diff --git a/tests/aws/services/logs/test_logs_streams.py b/tests/aws/services/logs/test_logs_streams.py new file mode 100644 index 0000000000000..0ecd63ee44870 --- /dev/null +++ b/tests/aws/services/logs/test_logs_streams.py @@ -0,0 +1,135 @@ +"""Tests for CloudWatch Logs - Log Stream operations.""" + +import pytest + +from localstack.testing.pytest import markers +from localstack.utils.aws import arns +from localstack.utils.common import short_uid + + +def _log_stream_exists(log_streams: list, name: str) -> bool: + """Check if a log stream with the given name exists in the list.""" + return any(ls["logStreamName"] == name for ls in log_streams) + + +class TestLogsStreams: + """Tests for log stream create, delete, describe operations.""" + + @markers.aws.validated + def test_create_and_delete_log_stream(self, logs_log_group, aws_client, snapshot): + """Test basic log stream creation and deletion.""" + snapshot.add_transformer(snapshot.transform.logs_api()) + stream_name = f"test-log-stream-{short_uid()}" + + # Create log stream + aws_client.logs.create_log_stream(logGroupName=logs_log_group, logStreamName=stream_name) + snapshot.add_transformer(snapshot.transform.regex(logs_log_group, "")) + + # Verify stream exists + response = aws_client.logs.describe_log_streams(logGroupName=logs_log_group) + snapshot.match("describe-log-streams-after-create", response) + assert _log_stream_exists(response["logStreams"], stream_name) + + # Delete log stream + aws_client.logs.delete_log_stream(logGroupName=logs_log_group, logStreamName=stream_name) + + # Verify stream is deleted + response = aws_client.logs.describe_log_streams(logGroupName=logs_log_group) + assert not _log_stream_exists(response.get("logStreams", []), stream_name) + + @markers.aws.validated + @markers.snapshot.skip_snapshot_verify(paths=["$..Error.Message"]) + def test_create_log_stream_duplicate_error( + self, logs_log_group, aws_client, snapshot, cleanups + ): + """Test that creating a duplicate log stream raises an error.""" + stream_name = f"test-log-stream-{short_uid()}" + aws_client.logs.create_log_stream(logGroupName=logs_log_group, logStreamName=stream_name) + cleanups.append( + lambda: aws_client.logs.delete_log_stream( + logGroupName=logs_log_group, logStreamName=stream_name + ) + ) + + with pytest.raises(Exception) as ctx: + aws_client.logs.create_log_stream( + logGroupName=logs_log_group, logStreamName=stream_name + ) + snapshot.match("error-duplicate-log-stream", ctx.value.response) + + @markers.aws.validated + def test_describe_log_streams_with_log_group_identifier( + self, logs_log_group, aws_client, region_name, snapshot + ): + """Test describing log streams using logGroupIdentifier parameter.""" + snapshot.add_transformer(snapshot.transform.logs_api()) + snapshot.add_transformer(snapshot.transform.regex(logs_log_group, "")) + stream_name = f"test-log-stream-{short_uid()}" + aws_client.logs.create_log_stream(logGroupName=logs_log_group, logStreamName=stream_name) + + # Using logGroupIdentifier with name + response = aws_client.logs.describe_log_streams(logGroupIdentifier=logs_log_group) + snapshot.match("describe-streams-identifier-name", response) + assert _log_stream_exists(response["logStreams"], stream_name) + + # Using logGroupIdentifier with ARN + account_id = aws_client.sts.get_caller_identity()["Account"] + log_group_arn = arns.log_group_arn( + logs_log_group, + account_id=account_id, + region_name=region_name, + ) + response = aws_client.logs.describe_log_streams(logGroupIdentifier=log_group_arn) + snapshot.match("describe-streams-identifier-arn", response) + assert _log_stream_exists(response["logStreams"], stream_name) + + # Using both logGroupName and logGroupIdentifier should raise error + with pytest.raises(Exception) as ctx: + aws_client.logs.describe_log_streams( + logGroupName=logs_log_group, logGroupIdentifier=logs_log_group + ) + snapshot.match("error-both-name-and-identifier", ctx.value.response) + + @markers.aws.validated + def test_describe_log_streams_with_prefix(self, logs_log_group, aws_client, snapshot, cleanups): + """Test describing log streams with prefix filter.""" + snapshot.add_transformer(snapshot.transform.logs_api()) + snapshot.add_transformer(snapshot.transform.regex(logs_log_group, "")) + prefix = f"test-prefix-{short_uid()}" + stream_names = [f"{prefix}-stream-{i}" for i in range(3)] + + for name in stream_names: + aws_client.logs.create_log_stream(logGroupName=logs_log_group, logStreamName=name) + cleanups.append( + lambda n=name: aws_client.logs.delete_log_stream( + logGroupName=logs_log_group, logStreamName=n + ) + ) + + response = aws_client.logs.describe_log_streams( + logGroupName=logs_log_group, logStreamNamePrefix=prefix + ) + snapshot.match("describe-streams-with-prefix", response) + for name in stream_names: + assert _log_stream_exists(response["logStreams"], name) + + @markers.aws.validated + def test_log_stream_arn_format(self, logs_log_group, aws_client, region_name, snapshot): + """Test that log stream ARN is in the correct format.""" + snapshot.add_transformer(snapshot.transform.logs_api()) + snapshot.add_transformer(snapshot.transform.regex(logs_log_group, "")) + stream_name = f"test-arn-{short_uid()}" + aws_client.logs.create_log_stream(logGroupName=logs_log_group, logStreamName=stream_name) + + response = aws_client.logs.describe_log_streams(logGroupName=logs_log_group) + snapshot.match("describe-log-streams-with-arn", response) + + stream = response["logStreams"][0] + account_id = aws_client.sts.get_caller_identity()["Account"] + + # Verify ARN format + expected_arn = ( + f"arn:aws:logs:{region_name}:{account_id}:" + f"log-group:{logs_log_group}:log-stream:{stream_name}" + ) + assert stream["arn"] == expected_arn diff --git a/tests/aws/services/logs/test_logs_streams.snapshot.json b/tests/aws/services/logs/test_logs_streams.snapshot.json new file mode 100644 index 0000000000000..4305a7837c068 --- /dev/null +++ b/tests/aws/services/logs/test_logs_streams.snapshot.json @@ -0,0 +1,129 @@ +{ + "tests/aws/services/logs/test_logs_streams.py::TestLogsStreams::test_create_and_delete_log_stream": { + "recorded-date": "03-02-2026, 21:22:58", + "recorded-content": { + "describe-log-streams-after-create": { + "logStreams": [ + { + "arn": "arn::logs::111111111111:log-group::log-stream:", + "creationTime": "timestamp", + "logStreamName": "", + "storedBytes": 0 + } + ], + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/logs/test_logs_streams.py::TestLogsStreams::test_create_log_stream_duplicate_error": { + "recorded-date": "03-02-2026, 21:22:58", + "recorded-content": { + "error-duplicate-log-stream": { + "Error": { + "Code": "ResourceAlreadyExistsException", + "Message": "The specified log stream already exists" + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + } + } + }, + "tests/aws/services/logs/test_logs_streams.py::TestLogsStreams::test_describe_log_streams_with_log_group_identifier": { + "recorded-date": "03-02-2026, 21:22:59", + "recorded-content": { + "describe-streams-identifier-name": { + "logStreams": [ + { + "arn": "arn::logs::111111111111:log-group::log-stream:", + "creationTime": "timestamp", + "logStreamName": "", + "storedBytes": 0 + } + ], + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "describe-streams-identifier-arn": { + "logStreams": [ + { + "arn": "arn::logs::111111111111:log-group::log-stream:", + "creationTime": "timestamp", + "logStreamName": "", + "storedBytes": 0 + } + ], + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "error-both-name-and-identifier": { + "Error": { + "Code": "ValidationException", + "Message": "LogGroup name and LogGroup ARN are mutually exclusive parameters." + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + } + } + }, + "tests/aws/services/logs/test_logs_streams.py::TestLogsStreams::test_describe_log_streams_with_prefix": { + "recorded-date": "03-02-2026, 21:23:00", + "recorded-content": { + "describe-streams-with-prefix": { + "logStreams": [ + { + "arn": "arn::logs::111111111111:log-group::log-stream:", + "creationTime": "timestamp", + "logStreamName": "", + "storedBytes": 0 + }, + { + "arn": "arn::logs::111111111111:log-group::log-stream:", + "creationTime": "timestamp", + "logStreamName": "", + "storedBytes": 0 + }, + { + "arn": "arn::logs::111111111111:log-group::log-stream:", + "creationTime": "timestamp", + "logStreamName": "", + "storedBytes": 0 + } + ], + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/logs/test_logs_streams.py::TestLogsStreams::test_log_stream_arn_format": { + "recorded-date": "03-02-2026, 21:23:00", + "recorded-content": { + "describe-log-streams-with-arn": { + "logStreams": [ + { + "arn": "arn::logs::111111111111:log-group::log-stream:", + "creationTime": "timestamp", + "logStreamName": "", + "storedBytes": 0 + } + ], + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + } +} diff --git a/tests/aws/services/logs/test_logs_streams.validation.json b/tests/aws/services/logs/test_logs_streams.validation.json new file mode 100644 index 0000000000000..a624becfdbe44 --- /dev/null +++ b/tests/aws/services/logs/test_logs_streams.validation.json @@ -0,0 +1,47 @@ +{ + "tests/aws/services/logs/test_logs_streams.py::TestLogsStreams::test_create_and_delete_log_stream": { + "last_validated_date": "2026-02-03T21:22:58+00:00", + "durations_in_seconds": { + "setup": 0.76, + "call": 0.38, + "teardown": 0.11, + "total": 1.25 + } + }, + "tests/aws/services/logs/test_logs_streams.py::TestLogsStreams::test_create_log_stream_duplicate_error": { + "last_validated_date": "2026-02-03T21:22:58+00:00", + "durations_in_seconds": { + "setup": 0.1, + "call": 0.16, + "teardown": 0.25, + "total": 0.51 + } + }, + "tests/aws/services/logs/test_logs_streams.py::TestLogsStreams::test_describe_log_streams_with_log_group_identifier": { + "last_validated_date": "2026-02-03T21:22:59+00:00", + "durations_in_seconds": { + "setup": 0.1, + "call": 0.41, + "teardown": 0.11, + "total": 0.62 + } + }, + "tests/aws/services/logs/test_logs_streams.py::TestLogsStreams::test_describe_log_streams_with_prefix": { + "last_validated_date": "2026-02-03T21:23:00+00:00", + "durations_in_seconds": { + "setup": 0.12, + "call": 0.34, + "teardown": 0.42, + "total": 0.88 + } + }, + "tests/aws/services/logs/test_logs_streams.py::TestLogsStreams::test_log_stream_arn_format": { + "last_validated_date": "2026-02-03T21:23:00+00:00", + "durations_in_seconds": { + "setup": 0.1, + "call": 0.25, + "teardown": 0.11, + "total": 0.46 + } + } +} diff --git a/tests/aws/services/logs/test_logs_subscription_filters.py b/tests/aws/services/logs/test_logs_subscription_filters.py new file mode 100644 index 0000000000000..483fda7f2055f --- /dev/null +++ b/tests/aws/services/logs/test_logs_subscription_filters.py @@ -0,0 +1,531 @@ +"""Tests for CloudWatch Logs - Subscription Filter operations.""" + +import base64 +import gzip +import json +import re + +import pytest +from localstack_snapshot.snapshots.transformer import KeyValueBasedTransformer + +from localstack.aws.api.lambda_ import Runtime +from localstack.testing.config import TEST_AWS_REGION_NAME +from localstack.testing.pytest import markers +from localstack.utils import testutil +from localstack.utils.aws.arns import get_partition +from localstack.utils.common import now_utc, retry, short_uid +from tests.aws.services.lambda_.test_lambda import TEST_LAMBDA_PYTHON_ECHO + +# IAM role and policy definitions for cross-service integration +logs_role = { + "Statement": { + "Effect": "Allow", + "Principal": {"Service": f"logs.{TEST_AWS_REGION_NAME}.amazonaws.com"}, + "Action": "sts:AssumeRole", + } +} + +kinesis_permission = { + "Version": "2012-10-17", + "Statement": [{"Effect": "Allow", "Action": "kinesis:PutRecord", "Resource": "*"}], +} + +s3_firehose_role = { + "Statement": { + "Sid": "", + "Effect": "Allow", + "Principal": {"Service": "firehose.amazonaws.com"}, + "Action": "sts:AssumeRole", + } +} + +s3_firehose_permission = { + "Version": "2012-10-17", + "Statement": [{"Effect": "Allow", "Action": ["s3:*", "s3-object-lambda:*"], "Resource": "*"}], +} + +firehose_permission = { + "Version": "2012-10-17", + "Statement": [{"Effect": "Allow", "Action": ["firehose:*"], "Resource": "*"}], +} + + +def _subscription_filter_exists(filters: list, name: str) -> bool: + """Check if a subscription filter with the given name exists in the list.""" + return any(f["filterName"] == name for f in filters) + + +class TestSubscriptionFilters: + """Tests for subscription filter operations.""" + + @markers.aws.validated + def test_describe_subscription_filters_empty(self, logs_log_group, aws_client, snapshot): + """Test describing subscription filters when none exist.""" + snapshot.add_transformer(snapshot.transform.logs_api()) + response = aws_client.logs.describe_subscription_filters(logGroupName=logs_log_group) + snapshot.match("describe-subscription-filters-empty", response) + + @markers.aws.validated + def test_describe_subscription_filters_log_group_not_found(self, aws_client, snapshot): + """Test describing subscription filters for non-existent log group.""" + with pytest.raises(Exception) as ctx: + aws_client.logs.describe_subscription_filters(logGroupName="not-existing-log-group") + snapshot.match("error-log-group-not-found", ctx.value.response) + + @markers.aws.validated + @markers.snapshot.skip_snapshot_verify( + paths=[ + "$..Statement.Condition.StringEquals", + "$..add_permission.ResponseMetadata.HTTPStatusCode", + "$..subscriptionFilters..applyOnTransformedLogs", + ] + ) + def test_put_subscription_filter_lambda( + self, + logs_log_group, + logs_log_stream, + create_lambda_function, + snapshot, + aws_client, + region_name, + ): + """Test putting a subscription filter with Lambda destination.""" + snapshot.add_transformer(snapshot.transform.lambda_api()) + snapshot.add_transformer(snapshot.transform.key_value("logGroupName")) + snapshot.add_transformer(snapshot.transform.key_value("logStreamName")) + snapshot.add_transformer( + KeyValueBasedTransformer( + lambda k, v: ( + v + if k == "id" and (isinstance(v, str) and re.match(re.compile(r"^[0-9]+$"), v)) + else None + ), + replacement="id", + replace_reference=False, + ), + ) + + test_lambda_name = f"test-lambda-function-{short_uid()}" + func_arn = create_lambda_function( + handler_file=TEST_LAMBDA_PYTHON_ECHO, + func_name=test_lambda_name, + runtime=Runtime.python3_12, + )["CreateFunctionResponse"]["FunctionArn"] + + aws_client.lambda_.invoke(FunctionName=test_lambda_name, Payload=b"{}") + + # Get account-id to set the correct policy + account_id = aws_client.sts.get_caller_identity()["Account"] + result = aws_client.lambda_.add_permission( + FunctionName=test_lambda_name, + StatementId=test_lambda_name, + Principal=f"logs.{region_name}.amazonaws.com", + Action="lambda:InvokeFunction", + SourceArn=f"arn:{get_partition(region_name)}:logs:{region_name}:{account_id}:log-group:{logs_log_group}:*", + SourceAccount=account_id, + ) + snapshot.match("add_permission", result) + + result = aws_client.logs.put_subscription_filter( + logGroupName=logs_log_group, + filterName="test", + filterPattern="", + destinationArn=func_arn, + ) + snapshot.match("put_subscription_filter", result) + + aws_client.logs.put_log_events( + logGroupName=logs_log_group, + logStreamName=logs_log_stream, + logEvents=[ + {"timestamp": now_utc(millis=True), "message": "test"}, + {"timestamp": now_utc(millis=True), "message": "test 2"}, + ], + ) + + response = aws_client.logs.describe_subscription_filters(logGroupName=logs_log_group) + assert len(response["subscriptionFilters"]) == 1 + snapshot.match("describe_subscription_filter", response) + + def check_invocation(): + events = testutil.list_all_log_events( + log_group_name=f"/aws/lambda/{test_lambda_name}", logs_client=aws_client.logs + ) + # We only are interested in events that contain "awslogs" + filtered_events = [] + for e in events: + if "awslogs" in e["message"]: + data = json.loads(e["message"])["awslogs"]["data"].encode("utf-8") + decoded_data = gzip.decompress(base64.b64decode(data)).decode("utf-8") + for log_event in json.loads(decoded_data)["logEvents"]: + filtered_events.append(log_event) + assert len(filtered_events) == 2 + + filtered_events.sort(key=lambda k: k.get("message")) + snapshot.match("list_all_log_events", filtered_events) + + retry(check_invocation, retries=6, sleep=3.0) + + @markers.aws.validated + def test_put_subscription_filter_kinesis( + self, logs_log_group, logs_log_stream, create_iam_role_with_policy, aws_client + ): + """Test putting a subscription filter with Kinesis destination.""" + kinesis_name = f"test-kinesis-{short_uid()}" + filter_name = "Destination" + aws_client.kinesis.create_stream(StreamName=kinesis_name, ShardCount=1) + + try: + result = aws_client.kinesis.describe_stream(StreamName=kinesis_name)[ + "StreamDescription" + ] + kinesis_arn = result["StreamARN"] + role = f"test-kinesis-role-{short_uid()}" + policy_name = f"test-kinesis-role-policy-{short_uid()}" + role_arn = create_iam_role_with_policy( + RoleName=role, + PolicyName=policy_name, + RoleDefinition=logs_role, + PolicyDefinition=kinesis_permission, + ) + + # Wait for stream-status "ACTIVE" + status = result["StreamStatus"] + if status != "ACTIVE": + + def check_stream_active(): + state = aws_client.kinesis.describe_stream(StreamName=kinesis_name)[ + "StreamDescription" + ]["StreamStatus"] + if state != "ACTIVE": + raise Exception(f"StreamStatus is {state}") + + retry(check_stream_active, retries=6, sleep=1.0, sleep_before=2.0) + + def put_subscription_filter(): + aws_client.logs.put_subscription_filter( + logGroupName=logs_log_group, + filterName=filter_name, + filterPattern="", + destinationArn=kinesis_arn, + roleArn=role_arn, + ) + + retry(put_subscription_filter, retries=6, sleep=3.0) + + def put_event(): + aws_client.logs.put_log_events( + logGroupName=logs_log_group, + logStreamName=logs_log_stream, + logEvents=[ + {"timestamp": now_utc(millis=True), "message": "test"}, + {"timestamp": now_utc(millis=True), "message": "test 2"}, + ], + ) + + retry(put_event, retries=6, sleep=3.0) + + shard_iterator = aws_client.kinesis.get_shard_iterator( + StreamName=kinesis_name, + ShardId="shardId-000000000000", + ShardIteratorType="TRIM_HORIZON", + )["ShardIterator"] + + response = aws_client.kinesis.get_records(ShardIterator=shard_iterator) + # AWS sends messages as health checks + assert len(response["Records"]) >= 1 + found = False + for record in response["Records"]: + data = record["Data"] + unzipped_data = gzip.decompress(data) + json_data = json.loads(unzipped_data) + if "test" in json.dumps(json_data["logEvents"]): + assert len(json_data["logEvents"]) == 2 + assert json_data["logEvents"][0]["message"] == "test" + assert json_data["logEvents"][1]["message"] == "test 2" + found = True + + assert found + finally: + aws_client.kinesis.delete_stream(StreamName=kinesis_name, EnforceConsumerDeletion=True) + aws_client.logs.delete_subscription_filter( + logGroupName=logs_log_group, filterName=filter_name + ) + + @markers.aws.validated + def test_put_subscription_filter_firehose( + self, logs_log_group, logs_log_stream, s3_bucket, create_iam_role_with_policy, aws_client + ): + """Test putting a subscription filter with Firehose destination.""" + try: + firehose_name = f"test-firehose-{short_uid()}" + s3_bucket_arn = f"arn:aws:s3:::{s3_bucket}" + + role = f"test-firehose-s3-role-{short_uid()}" + policy_name = f"test-firehose-s3-role-policy-{short_uid()}" + role_arn = create_iam_role_with_policy( + RoleName=role, + PolicyName=policy_name, + RoleDefinition=s3_firehose_role, + PolicyDefinition=s3_firehose_permission, + ) + + # AWS has troubles creating the delivery stream the first time + def create_delivery_stream(): + aws_client.firehose.create_delivery_stream( + DeliveryStreamName=firehose_name, + S3DestinationConfiguration={ + "BucketARN": s3_bucket_arn, + "RoleARN": role_arn, + "BufferingHints": {"SizeInMBs": 1, "IntervalInSeconds": 60}, + }, + ) + + retry(create_delivery_stream, retries=5, sleep=10.0) + + response = aws_client.firehose.describe_delivery_stream( + DeliveryStreamName=firehose_name + ) + firehose_arn = response["DeliveryStreamDescription"]["DeliveryStreamARN"] + + role = f"test-firehose-role-{short_uid()}" + policy_name = f"test-firehose-role-policy-{short_uid()}" + role_arn_logs = create_iam_role_with_policy( + RoleName=role, + PolicyName=policy_name, + RoleDefinition=logs_role, + PolicyDefinition=firehose_permission, + ) + + def check_stream_active(): + state = aws_client.firehose.describe_delivery_stream( + DeliveryStreamName=firehose_name + )["DeliveryStreamDescription"]["DeliveryStreamStatus"] + if state != "ACTIVE": + raise Exception(f"DeliveryStreamStatus is {state}") + + retry(check_stream_active, retries=60, sleep=30.0) + + aws_client.logs.put_subscription_filter( + logGroupName=logs_log_group, + filterName="Destination", + filterPattern="", + destinationArn=firehose_arn, + roleArn=role_arn_logs, + ) + + aws_client.logs.put_log_events( + logGroupName=logs_log_group, + logStreamName=logs_log_stream, + logEvents=[ + {"timestamp": now_utc(millis=True), "message": "test"}, + {"timestamp": now_utc(millis=True), "message": "test 2"}, + ], + ) + + def list_objects(): + response = aws_client.s3.list_objects(Bucket=s3_bucket) + assert len(response["Contents"]) >= 1 + + retry(list_objects, retries=60, sleep=30.0) + response = aws_client.s3.list_objects(Bucket=s3_bucket) + key = response["Contents"][-1]["Key"] + response = aws_client.s3.get_object(Bucket=s3_bucket, Key=key) + content = gzip.decompress(response["Body"].read()).decode("utf-8") + assert "DATA_MESSAGE" in content + assert "test" in content + assert "test 2" in content + + finally: + aws_client.firehose.delete_delivery_stream( + DeliveryStreamName=firehose_name, AllowForceDelete=True + ) + + +class TestSubscriptionFilterUpdates: + """Tests for subscription filter update and delete operations.""" + + @markers.aws.validated + @markers.snapshot.skip_snapshot_verify(paths=["$..subscriptionFilters..applyOnTransformedLogs"]) + def test_put_subscription_filter_update( + self, logs_log_group, create_lambda_function, aws_client, region_name, snapshot + ): + """Test updating a subscription filter.""" + test_lambda_name = f"test-lambda-{short_uid()}" + func_arn = create_lambda_function( + handler_file=TEST_LAMBDA_PYTHON_ECHO, + func_name=test_lambda_name, + runtime=Runtime.python3_12, + )["CreateFunctionResponse"]["FunctionArn"] + + account_id = aws_client.sts.get_caller_identity()["Account"] + aws_client.lambda_.add_permission( + FunctionName=test_lambda_name, + StatementId=test_lambda_name, + Principal=f"logs.{region_name}.amazonaws.com", + Action="lambda:InvokeFunction", + SourceArn=f"arn:{get_partition(region_name)}:logs:{region_name}:{account_id}:log-group:{logs_log_group}:*", + SourceAccount=account_id, + ) + + # Create initial subscription filter + aws_client.logs.put_subscription_filter( + logGroupName=logs_log_group, + filterName="test", + filterPattern="", + destinationArn=func_arn, + ) + + response = aws_client.logs.describe_subscription_filters(logGroupName=logs_log_group) + assert len(response["subscriptionFilters"]) == 1 + + # Update subscription filter (same filterName) + aws_client.logs.put_subscription_filter( + logGroupName=logs_log_group, + filterName="test", + filterPattern="[]", + destinationArn=func_arn, + ) + + response = aws_client.logs.describe_subscription_filters(logGroupName=logs_log_group) + snapshot.add_transformer(snapshot.transform.regex(func_arn, "")) + snapshot.add_transformer(snapshot.transform.regex(logs_log_group, "")) + snapshot.match("updated-filter", response) + + @markers.aws.validated + def test_put_subscription_filter_limit_exceeded( + self, logs_log_group, create_lambda_function, aws_client, region_name, snapshot, account_id + ): + """Test that only 2 subscription filters can be associated with a log group.""" + test_lambda_name = f"test-lambda-{short_uid()}" + func_arn = create_lambda_function( + handler_file=TEST_LAMBDA_PYTHON_ECHO, + func_name=test_lambda_name, + runtime=Runtime.python3_12, + )["CreateFunctionResponse"]["FunctionArn"] + + aws_client.lambda_.add_permission( + FunctionName=test_lambda_name, + StatementId=test_lambda_name, + Principal=f"logs.{region_name}.amazonaws.com", + Action="lambda:InvokeFunction", + SourceArn=f"arn:{get_partition(region_name)}:logs:{region_name}:{account_id}:log-group:{logs_log_group}:*", + SourceAccount=account_id, + ) + + # Create first subscription filter + aws_client.logs.put_subscription_filter( + logGroupName=logs_log_group, + filterName="test-1", + filterPattern="", + destinationArn=func_arn, + ) + + # Create second subscription filter + aws_client.logs.put_subscription_filter( + logGroupName=logs_log_group, + filterName="test-2", + filterPattern="[]", + destinationArn=func_arn, + ) + + # Third should fail + with pytest.raises(Exception) as ctx: + aws_client.logs.put_subscription_filter( + logGroupName=logs_log_group, + filterName="test-3", + filterPattern="", + destinationArn=func_arn, + ) + snapshot.match("error-limit-exceeded", ctx.value.response) + + @markers.aws.validated + def test_delete_subscription_filter( + self, logs_log_group, create_lambda_function, aws_client, region_name + ): + """Test deleting a subscription filter.""" + test_lambda_name = f"test-lambda-{short_uid()}" + func_arn = create_lambda_function( + handler_file=TEST_LAMBDA_PYTHON_ECHO, + func_name=test_lambda_name, + runtime=Runtime.python3_12, + )["CreateFunctionResponse"]["FunctionArn"] + + account_id = aws_client.sts.get_caller_identity()["Account"] + aws_client.lambda_.add_permission( + FunctionName=test_lambda_name, + StatementId=test_lambda_name, + Principal=f"logs.{region_name}.amazonaws.com", + Action="lambda:InvokeFunction", + SourceArn=f"arn:{get_partition(region_name)}:logs:{region_name}:{account_id}:log-group:{logs_log_group}:*", + SourceAccount=account_id, + ) + + aws_client.logs.put_subscription_filter( + logGroupName=logs_log_group, + filterName="test", + filterPattern="", + destinationArn=func_arn, + ) + + response = aws_client.logs.describe_subscription_filters(logGroupName=logs_log_group) + assert len(response["subscriptionFilters"]) == 1 + + # Delete subscription filter + aws_client.logs.delete_subscription_filter(logGroupName=logs_log_group, filterName="test") + + response = aws_client.logs.describe_subscription_filters(logGroupName=logs_log_group) + assert len(response["subscriptionFilters"]) == 0 + + @markers.aws.validated + def test_delete_subscription_filter_errors(self, logs_log_group, aws_client, snapshot): + """Test delete subscription filter error handling.""" + # Non-existent log group + with pytest.raises(Exception) as ctx: + aws_client.logs.delete_subscription_filter( + logGroupName="not-existing-log-group", filterName="test" + ) + snapshot.match("error-log-group-not-found", ctx.value.response) + + # Non-existent filter + with pytest.raises(Exception) as ctx: + aws_client.logs.delete_subscription_filter( + logGroupName=logs_log_group, filterName="wrong-filter-name" + ) + snapshot.match("error-filter-not-found", ctx.value.response) + + @markers.aws.validated + @markers.snapshot.skip_snapshot_verify(paths=["$..Error.Code", "$..Error.Message"]) + def test_put_subscription_filter_errors( + self, logs_log_group, create_lambda_function, aws_client, snapshot + ): + """Test put subscription filter error handling.""" + # Non-existent log group + with pytest.raises(Exception) as ctx: + aws_client.logs.put_subscription_filter( + logGroupName="not-existing-log-group", + filterName="test", + filterPattern="", + destinationArn="arn:aws:lambda:us-east-1:123456789012:function:test", + ) + snapshot.match("error-log-group-not-found", ctx.value.response) + + # Non-existent Lambda function + with pytest.raises(Exception) as ctx: + aws_client.logs.put_subscription_filter( + logGroupName=logs_log_group, + filterName="test", + filterPattern="", + destinationArn="arn:aws:lambda:us-east-1:123456789012:function:not-existing", + ) + snapshot.match("error-lambda-not-found", ctx.value.response) + + # Non-existent Kinesis stream + with pytest.raises(Exception) as ctx: + aws_client.logs.put_subscription_filter( + logGroupName=logs_log_group, + filterName="test", + filterPattern="", + destinationArn="arn:aws:kinesis:us-east-1:123456789012:stream/unknown-stream", + ) + snapshot.match("error-kinesis-not-found", ctx.value.response) diff --git a/tests/aws/services/logs/test_logs_subscription_filters.snapshot.json b/tests/aws/services/logs/test_logs_subscription_filters.snapshot.json new file mode 100644 index 0000000000000..39f0dc6df28f2 --- /dev/null +++ b/tests/aws/services/logs/test_logs_subscription_filters.snapshot.json @@ -0,0 +1,189 @@ +{ + "tests/aws/services/logs/test_logs_subscription_filters.py::TestSubscriptionFilters::test_describe_subscription_filters_empty": { + "recorded-date": "06-02-2026, 20:03:19", + "recorded-content": { + "describe-subscription-filters-empty": { + "subscriptionFilters": [], + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/logs/test_logs_subscription_filters.py::TestSubscriptionFilters::test_describe_subscription_filters_log_group_not_found": { + "recorded-date": "06-02-2026, 20:07:39", + "recorded-content": { + "error-log-group-not-found": { + "Error": { + "Code": "ResourceNotFoundException", + "Message": "The specified log group does not exist." + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + } + } + }, + "tests/aws/services/logs/test_logs_subscription_filters.py::TestSubscriptionFilters::test_put_subscription_filter_lambda": { + "recorded-date": "06-02-2026, 20:12:46", + "recorded-content": { + "add_permission": { + "Statement": { + "Sid": "", + "Effect": "Allow", + "Principal": { + "Service": "logs..amazonaws.com" + }, + "Action": "lambda:InvokeFunction", + "Resource": "arn::lambda::111111111111:function:", + "Condition": { + "StringEquals": { + "AWS:SourceAccount": "111111111111" + }, + "ArnLike": { + "AWS:SourceArn": "arn::logs::111111111111:log-group::" + } + } + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 201 + } + }, + "put_subscription_filter": { + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "describe_subscription_filter": { + "subscriptionFilters": [ + { + "applyOnTransformedLogs": false, + "creationTime": "timestamp", + "destinationArn": "arn::lambda::111111111111:function:", + "distribution": "ByLogStream", + "filterName": "test", + "filterPattern": "", + "logGroupName": "" + } + ], + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "list_all_log_events": [ + { + "id": "id", + "timestamp": "timestamp", + "message": "test" + }, + { + "id": "id", + "timestamp": "timestamp", + "message": "test 2" + } + ] + } + }, + "tests/aws/services/logs/test_logs_subscription_filters.py::TestSubscriptionFilterUpdates::test_put_subscription_filter_update": { + "recorded-date": "06-02-2026, 20:46:56", + "recorded-content": { + "updated-filter": { + "subscriptionFilters": [ + { + "applyOnTransformedLogs": false, + "creationTime": "timestamp", + "destinationArn": "", + "distribution": "ByLogStream", + "filterName": "test", + "filterPattern": "[]", + "logGroupName": "" + } + ], + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/logs/test_logs_subscription_filters.py::TestSubscriptionFilterUpdates::test_put_subscription_filter_limit_exceeded": { + "recorded-date": "06-02-2026, 20:49:45", + "recorded-content": { + "error-limit-exceeded": { + "Error": { + "Code": "LimitExceededException", + "Message": "Resource limit exceeded." + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + } + } + }, + "tests/aws/services/logs/test_logs_subscription_filters.py::TestSubscriptionFilterUpdates::test_delete_subscription_filter_errors": { + "recorded-date": "06-02-2026, 20:51:38", + "recorded-content": { + "error-log-group-not-found": { + "Error": { + "Code": "ResourceNotFoundException", + "Message": "The specified log group does not exist." + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + }, + "error-filter-not-found": { + "Error": { + "Code": "ResourceNotFoundException", + "Message": "The specified subscription filter does not exist." + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + } + } + }, + "tests/aws/services/logs/test_logs_subscription_filters.py::TestSubscriptionFilterUpdates::test_put_subscription_filter_errors": { + "recorded-date": "06-02-2026, 20:52:39", + "recorded-content": { + "error-log-group-not-found": { + "Error": { + "Code": "AccessDeniedException", + "Message": "Cross-account lambda invocation passing is not allowed. You must use DestinationPolicies to create cross account lambda triggers." + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + }, + "error-lambda-not-found": { + "Error": { + "Code": "AccessDeniedException", + "Message": "Cross-account lambda invocation passing is not allowed. You must use DestinationPolicies to create cross account lambda triggers." + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + }, + "error-kinesis-not-found": { + "Error": { + "Code": "InvalidParameterException", + "Message": "destinationArn for vendor kinesis cannot be used without roleArn" + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + } + } + } +} diff --git a/tests/aws/services/logs/test_logs_subscription_filters.validation.json b/tests/aws/services/logs/test_logs_subscription_filters.validation.json new file mode 100644 index 0000000000000..d3cf8f0d62fbb --- /dev/null +++ b/tests/aws/services/logs/test_logs_subscription_filters.validation.json @@ -0,0 +1,92 @@ +{ + "tests/aws/services/logs/test_logs_subscription_filters.py::TestSubscriptionFilterUpdates::test_delete_subscription_filter": { + "last_validated_date": "2026-02-06T20:51:25+00:00", + "durations_in_seconds": { + "setup": 11.08, + "call": 2.96, + "teardown": 0.9, + "total": 14.94 + } + }, + "tests/aws/services/logs/test_logs_subscription_filters.py::TestSubscriptionFilterUpdates::test_delete_subscription_filter_errors": { + "last_validated_date": "2026-02-06T20:51:38+00:00", + "durations_in_seconds": { + "setup": 0.73, + "call": 0.19, + "teardown": 0.13, + "total": 1.05 + } + }, + "tests/aws/services/logs/test_logs_subscription_filters.py::TestSubscriptionFilterUpdates::test_put_subscription_filter_errors": { + "last_validated_date": "2026-02-06T20:52:40+00:00", + "durations_in_seconds": { + "setup": 11.39, + "call": 0.22, + "teardown": 0.54, + "total": 12.15 + } + }, + "tests/aws/services/logs/test_logs_subscription_filters.py::TestSubscriptionFilterUpdates::test_put_subscription_filter_limit_exceeded": { + "last_validated_date": "2026-02-06T20:49:46+00:00", + "durations_in_seconds": { + "setup": 11.38, + "call": 2.59, + "teardown": 0.91, + "total": 14.88 + } + }, + "tests/aws/services/logs/test_logs_subscription_filters.py::TestSubscriptionFilterUpdates::test_put_subscription_filter_update": { + "last_validated_date": "2026-02-06T20:46:57+00:00", + "durations_in_seconds": { + "setup": 11.41, + "call": 2.81, + "teardown": 0.92, + "total": 15.14 + } + }, + "tests/aws/services/logs/test_logs_subscription_filters.py::TestSubscriptionFilters::test_describe_subscription_filters_empty": { + "last_validated_date": "2026-02-06T20:03:19+00:00", + "durations_in_seconds": { + "setup": 0.74, + "call": 0.1, + "teardown": 0.13, + "total": 0.97 + } + }, + "tests/aws/services/logs/test_logs_subscription_filters.py::TestSubscriptionFilters::test_describe_subscription_filters_log_group_not_found": { + "last_validated_date": "2026-02-06T20:07:39+00:00", + "durations_in_seconds": { + "setup": 0.37, + "call": 0.34, + "teardown": 0.0, + "total": 0.71 + } + }, + "tests/aws/services/logs/test_logs_subscription_filters.py::TestSubscriptionFilters::test_put_subscription_filter_firehose": { + "last_validated_date": "2026-02-06T20:11:21+00:00", + "durations_in_seconds": { + "setup": 0.97, + "call": 134.54, + "teardown": 2.17, + "total": 137.68 + } + }, + "tests/aws/services/logs/test_logs_subscription_filters.py::TestSubscriptionFilters::test_put_subscription_filter_kinesis": { + "last_validated_date": "2026-02-06T20:08:43+00:00", + "durations_in_seconds": { + "setup": 0.51, + "call": 12.6, + "teardown": 0.5, + "total": 13.61 + } + }, + "tests/aws/services/logs/test_logs_subscription_filters.py::TestSubscriptionFilters::test_put_subscription_filter_lambda": { + "last_validated_date": "2026-02-06T20:12:47+00:00", + "durations_in_seconds": { + "setup": 11.6, + "call": 9.74, + "teardown": 1.04, + "total": 22.38 + } + } +} diff --git a/tests/aws/services/opensearch/test_opensearch.py b/tests/aws/services/opensearch/test_opensearch.py index ebebb8f35a13b..4a378693b08e9 100644 --- a/tests/aws/services/opensearch/test_opensearch.py +++ b/tests/aws/services/opensearch/test_opensearch.py @@ -15,6 +15,8 @@ from localstack import config from localstack.aws.api.opensearch import ( AdvancedSecurityOptionsInput, + AutoTuneDesiredState, + AutoTuneState, ClusterConfig, DomainEndpointOptions, EBSOptions, @@ -40,6 +42,7 @@ OPENSEARCH_PLUGIN_LIST, opensearch_package, ) +from localstack.testing import config as test_config from localstack.testing.aws.util import is_aws_cloud from localstack.testing.pytest import markers from localstack.utils.common import call_safe, poll_condition, retry, short_uid, start_worker_thread @@ -79,11 +82,14 @@ def run_install(*args): @pytest.fixture(autouse=True) def opensearch(): + if is_aws_cloud() or test_config.TEST_SKIP_LOCALSTACK_START: + # we don't install the dependencies if LocalStack is not running in process + return + if not installed.is_set(): install_async() assert installed.wait(timeout=5 * 60), "gave up waiting for opensearch to install" - yield def try_cluster_health(cluster_url: str): @@ -99,6 +105,21 @@ def try_cluster_health(cluster_url: str): ], "expected cluster state to be in a valid state" +@pytest.fixture(autouse=True) +def disable_ssl_validation_for_unsupported_regions(region_name, monkeypatch): + # list of regions supported in our certificate + # prevents SSL verification for regional hostnames not present in the SAN list of the certificate + if region_name not in { + "eu-central-1", + "eu-west-1", + "us-east-1", + "us-east-2", + "us-west-1", + "us-west-2", + }: + monkeypatch.setattr(requests, "verify_ssl", False) + + @markers.skip_offline class TestOpensearchProvider: """ @@ -179,6 +200,7 @@ def test_get_compatible_version_for_domain(self, opensearch_create_domain, aws_c "$..SnapshotOptions.Options.AutomatedSnapshotStartHour", "$..SnapshotOptions.Status.UpdateVersion", "$..SoftwareUpdateOptions", + "$..Status.UpdateVersion", "$..VPCOptions.Status.UpdateVersion", ] ) @@ -259,7 +281,11 @@ def test_domain_lifecycle( plugins_response = http_client.get(plugins_url, headers={"Accept": "application/json"}) else: # TODO fix ssl validation error when using the signed request for the elastic search domain - plugins_response = requests.get(plugins_url, headers={"Accept": "application/json"}) + plugins_response = requests.get( + plugins_url, + headers={"Accept": "application/json"}, + verify=False, + ) installed_plugins = {plugin["component"] for plugin in plugins_response.json()} requested_plugins = set(OPENSEARCH_PLUGIN_LIST) @@ -268,6 +294,59 @@ def test_domain_lifecycle( delete_response = aws_client.opensearch.delete_domain(DomainName=domain_name) snapshot.match("delete-response", delete_response["DomainStatus"]) + @markers.aws.validated + @markers.snapshot.skip_snapshot_verify( + paths=[ + "$..Status.UpdateVersion", + ] + ) + def test_autotune_state_transitions(self, opensearch_create_domain, aws_client, snapshot): + domain_name = opensearch_create_domain( + AutoTuneOptions={"DesiredState": AutoTuneDesiredState.ENABLED}, + ClusterConfig={ + "InstanceType": "m5.large.search", + "InstanceCount": 1, + }, + EBSOptions={ + "EBSEnabled": True, + "VolumeType": "gp2", + "VolumeSize": 10, + }, + ) + + timeout = 25 * 60 if is_aws_cloud() else 2 * 60 + interval = 10 if is_aws_cloud() else 0.5 + + def wait_for_autotune_state(expected_state: AutoTuneState) -> dict: + def _state_matches(): + status = aws_client.opensearch.describe_domain(DomainName=domain_name) + autotune = status["DomainStatus"].get("AutoTuneOptions") or {} + return autotune.get("State") == expected_state + + assert poll_condition(_state_matches, timeout=timeout, interval=interval) + final_status = aws_client.opensearch.describe_domain(DomainName=domain_name) + return final_status["DomainStatus"].get("AutoTuneOptions") or {} + + enabled_status = wait_for_autotune_state(AutoTuneState.ENABLED) + snapshot.match("autotune_enabled_status", enabled_status) + + aws_client.opensearch.update_domain_config( + DomainName=domain_name, AutoTuneOptions={"DesiredState": AutoTuneDesiredState.DISABLED} + ) + + disabled_status = wait_for_autotune_state(AutoTuneState.DISABLED) + snapshot.match("autotune_disabled_status", disabled_status) + + def _config_matches(): + config = aws_client.opensearch.describe_domain_config(DomainName=domain_name) + options = (config["DomainConfig"].get("AutoTuneOptions") or {}).get("Options") or {} + return options.get("DesiredState") == AutoTuneDesiredState.DISABLED + + assert poll_condition(_config_matches, timeout=timeout, interval=interval) + final_config = aws_client.opensearch.describe_domain_config(DomainName=domain_name) + config_autotune = final_config["DomainConfig"].get("AutoTuneOptions") or {} + snapshot.match("autotune_domain_config", config_autotune) + @markers.aws.only_localstack def test_security_plugin(self, opensearch_create_domain, aws_client): master_user_auth = ("master-user", "1[D3&2S)u9[G") @@ -636,6 +715,7 @@ def test_search(self, opensearch_endpoint, opensearch_document_path): f"search unsuccessful({response.status_code}): {response.text}" ) + @markers.requires_in_process @markers.aws.only_localstack def test_endpoint_strategy_path(self, monkeypatch, opensearch_create_domain, aws_client): monkeypatch.setattr(config, "OPENSEARCH_ENDPOINT_STRATEGY", "path") @@ -649,6 +729,7 @@ def test_endpoint_strategy_path(self, monkeypatch, opensearch_create_domain, aws endpoint = status["Endpoint"] assert endpoint.endswith(f"/{domain_name}") + @markers.requires_in_process @markers.aws.only_localstack def test_endpoint_strategy_port(self, monkeypatch, opensearch_create_domain, aws_client): monkeypatch.setattr(config, "OPENSEARCH_ENDPOINT_STRATEGY", "port") @@ -684,6 +765,7 @@ def test_cloudformation_deployment(self, deploy_cfn_template, aws_client): @markers.skip_offline class TestEdgeProxiedOpensearchCluster: + @markers.requires_in_process @markers.aws.only_localstack def test_route_through_edge(self): cluster_id = f"domain-{short_uid()}" @@ -780,6 +862,7 @@ def test_custom_endpoint_disabled( @markers.skip_offline class TestMultiClusterManager: + @markers.requires_in_process @markers.aws.only_localstack def test_multi_cluster(self, account_id, monkeypatch): monkeypatch.setattr(config, "OPENSEARCH_ENDPOINT_STRATEGY", "domain") @@ -828,6 +911,7 @@ def test_multi_cluster(self, account_id, monkeypatch): @markers.skip_offline class TestMultiplexingClusterManager: + @markers.requires_in_process @markers.aws.only_localstack def test_multiplexing_cluster(self, account_id, monkeypatch): monkeypatch.setattr(config, "OPENSEARCH_ENDPOINT_STRATEGY", "domain") @@ -876,6 +960,7 @@ def test_multiplexing_cluster(self, account_id, monkeypatch): @markers.skip_offline class TestSingletonClusterManager: + @markers.requires_in_process @markers.aws.only_localstack def test_endpoint_strategy_port_singleton_cluster(self, account_id, monkeypatch): monkeypatch.setattr(config, "OPENSEARCH_ENDPOINT_STRATEGY", "port") @@ -922,6 +1007,7 @@ def test_endpoint_strategy_port_singleton_cluster(self, account_id, monkeypatch) @markers.skip_offline class TestCustomBackendManager: + @markers.requires_in_process @markers.aws.only_localstack def test_custom_backend(self, account_id, httpserver, monkeypatch): monkeypatch.setattr(config, "OPENSEARCH_ENDPOINT_STRATEGY", "domain") @@ -988,6 +1074,7 @@ def test_custom_backend(self, account_id, httpserver, monkeypatch): httpserver.check() + @markers.requires_in_process @markers.aws.only_localstack def test_custom_backend_with_custom_endpoint( self, diff --git a/tests/aws/services/opensearch/test_opensearch.snapshot.json b/tests/aws/services/opensearch/test_opensearch.snapshot.json index a3445c9f91e4b..3ae43475a36d0 100644 --- a/tests/aws/services/opensearch/test_opensearch.snapshot.json +++ b/tests/aws/services/opensearch/test_opensearch.snapshot.json @@ -1248,5 +1248,33 @@ "UpgradeProcessing": false } } + }, + "tests/aws/services/opensearch/test_opensearch.py::TestOpensearchProvider::test_autotune_state_transitions": { + "recorded-date": "19-11-2025, 13:12:26", + "recorded-content": { + "autotune_enabled_status": { + "State": "ENABLED", + "UseOffPeakWindow": false + }, + "autotune_disabled_status": { + "State": "DISABLED", + "UseOffPeakWindow": false + }, + "autotune_domain_config": { + "Options": { + "DesiredState": "DISABLED", + "MaintenanceSchedules": [], + "RollbackOnDisable": "NO_ROLLBACK", + "UseOffPeakWindow": false + }, + "Status": { + "CreationDate": "", + "PendingDeletion": false, + "State": "DISABLED", + "UpdateDate": "", + "UpdateVersion": 15 + } + } + } } } diff --git a/tests/aws/services/opensearch/test_opensearch.validation.json b/tests/aws/services/opensearch/test_opensearch.validation.json index d9d82f0c8c1ae..5d9a294e9256f 100644 --- a/tests/aws/services/opensearch/test_opensearch.validation.json +++ b/tests/aws/services/opensearch/test_opensearch.validation.json @@ -1,4 +1,13 @@ { + "tests/aws/services/opensearch/test_opensearch.py::TestOpensearchProvider::test_autotune_state_transitions": { + "last_validated_date": "2025-11-19T13:12:26+00:00", + "durations_in_seconds": { + "setup": 0.62, + "call": 1105.63, + "teardown": 0.34, + "total": 1106.59 + } + }, "tests/aws/services/opensearch/test_opensearch.py::TestOpensearchProvider::test_domain_lifecycle": { "last_validated_date": "2025-09-12T08:04:43+00:00", "durations_in_seconds": { diff --git a/tests/aws/services/resourcegroupstaggingapi/test_rgsa.py b/tests/aws/services/resourcegroupstaggingapi/test_rgsa.py index 60e85f094c495..83c5a0b8102c8 100644 --- a/tests/aws/services/resourcegroupstaggingapi/test_rgsa.py +++ b/tests/aws/services/resourcegroupstaggingapi/test_rgsa.py @@ -1,7 +1,12 @@ +import pytest + from localstack.testing.pytest import markers +from localstack.utils.analytics.metadata import is_license_activated class TestRGSAIntegrations: + # TODO: figure out a better way, maybe via marker? e.g. @markers.localstack.ext + @pytest.mark.skipif(condition=not is_license_activated(), reason="integration test with pro") @markers.aws.validated @markers.snapshot.skip_snapshot_verify(paths=["$..PaginationToken"]) def test_get_resources(self, aws_client, cleanups, snapshot): diff --git a/tests/aws/services/route53/resource_providers/test_aws_route53_healthcheck.py b/tests/aws/services/route53/resource_providers/test_aws_route53_healthcheck.py new file mode 100644 index 0000000000000..38a8601781c5c --- /dev/null +++ b/tests/aws/services/route53/resource_providers/test_aws_route53_healthcheck.py @@ -0,0 +1,22 @@ +import os + +from localstack.testing.pytest import markers + + +@markers.aws.validated +@markers.snapshot.skip_snapshot_verify( + paths=["$..HealthCheckConfig.EnableSNI", "$..HealthCheckVersion"] +) +def test_create_health_check(deploy_cfn_template, aws_client, snapshot): + stack = deploy_cfn_template( + template_path=os.path.join( + os.path.dirname(__file__), + "../../../templates/route53_healthcheck.yml", + ), + ) + health_check_id = stack.outputs["HealthCheckId"] + health_check = aws_client.route53.get_health_check(HealthCheckId=health_check_id) + + snapshot.add_transformer(snapshot.transform.key_value("Id", "id")) + snapshot.add_transformer(snapshot.transform.key_value("CallerReference", "caller-reference")) + snapshot.match("HealthCheck", health_check["HealthCheck"]) diff --git a/tests/aws/services/cloudformation/resources/test_route53.snapshot.json b/tests/aws/services/route53/resource_providers/test_aws_route53_healthcheck.snapshot.json similarity index 85% rename from tests/aws/services/cloudformation/resources/test_route53.snapshot.json rename to tests/aws/services/route53/resource_providers/test_aws_route53_healthcheck.snapshot.json index 78372c10e3b32..8c3e241e6575d 100644 --- a/tests/aws/services/cloudformation/resources/test_route53.snapshot.json +++ b/tests/aws/services/route53/resource_providers/test_aws_route53_healthcheck.snapshot.json @@ -1,5 +1,5 @@ { - "tests/aws/services/cloudformation/resources/test_route53.py::test_create_health_check": { + "tests/aws/services/route53/resource_providers/test_aws_route53_healthcheck.py::test_create_health_check": { "recorded-date": "22-09-2023, 13:50:49", "recorded-content": { "HealthCheck": { diff --git a/tests/aws/services/route53/resource_providers/test_aws_route53_healthcheck.validation.json b/tests/aws/services/route53/resource_providers/test_aws_route53_healthcheck.validation.json new file mode 100644 index 0000000000000..1e9af599b11be --- /dev/null +++ b/tests/aws/services/route53/resource_providers/test_aws_route53_healthcheck.validation.json @@ -0,0 +1,5 @@ +{ + "tests/aws/services/route53/resource_providers/test_aws_route53_healthcheck.py::test_create_health_check": { + "last_validated_date": "2023-09-22T11:50:49+00:00" + } +} diff --git a/tests/aws/services/route53/resource_providers/test_aws_route53_recordset.py b/tests/aws/services/route53/resource_providers/test_aws_route53_recordset.py new file mode 100644 index 0000000000000..1da7bd0d8bc50 --- /dev/null +++ b/tests/aws/services/route53/resource_providers/test_aws_route53_recordset.py @@ -0,0 +1,275 @@ +import os +from typing import Literal + +import pytest + +from localstack.config import S3_STATIC_WEBSITE_HOSTNAME +from localstack.constants import AWS_REGION_US_EAST_1 +from localstack.testing.aws.util import is_aws_cloud +from localstack.testing.pytest import markers +from localstack.utils.strings import short_uid +from localstack.utils.urls import localstack_host + + +@pytest.fixture +def record_set_transformers(snapshot): + snapshot.add_transformers_list( + [ + snapshot.transform.jsonpath( + "$..ResourceRecords..Value.[*]", value_replacement="resource-record" + ), + snapshot.transform.jsonpath( + "$..ResourceRecordSets..Name", value_replacement="record-name" + ), + ] + ) + + +@pytest.fixture +def get_s3_website_host_and_hosted_zone_id(aws_client_factory, s3_create_bucket_with_client): + # to be able to deploy an AliasTarget in AWS, we need a valid target. We will use an S3 bucket here + # The HostedZoneId field depends on the region the bucket is deployed in + # See https://docs.aws.amazon.com/general/latest/gr/s3.html#auto-endpoints-website-s3 + + s3_hosted_zone_ids = { + AWS_REGION_US_EAST_1: "Z3AQBSTGFYJSTF", + "us-west-1": "Z2F56UZL2M1ACD", + } + + def _create_s3_website(region_name: Literal["us-east-1", "us-west-1"]): + bucket_name = f"bucket-cfn-{short_uid()}" + hosted_zone_id = s3_hosted_zone_ids[region_name] + + s3_client = aws_client_factory(region_name=region_name).s3 + s3_params = {} + if region_name != AWS_REGION_US_EAST_1: + s3_params["CreateBucketConfiguration"] = {"LocationConstraint": region_name} + s3_create_bucket_with_client(s3_client, Bucket=bucket_name, **s3_params) + s3_client.put_bucket_website( + Bucket=bucket_name, + WebsiteConfiguration={ + "IndexDocument": {"Suffix": "index.html"}, + }, + ) + if is_aws_cloud(): + # beware if adding more regions, it can be `-` or `.` between the `s3-website` and the region name + s3_website_url = f"{bucket_name}.s3-website-{region_name}.amazonaws.com" + else: + s3_website_url = f"{bucket_name}.{S3_STATIC_WEBSITE_HOSTNAME}:{localstack_host().port}" + + return s3_website_url, hosted_zone_id + + yield _create_s3_website + + +@markers.aws.validated +@markers.snapshot.skip_snapshot_verify( + paths=[ + # Moto returns a different value (300 instead of 100) when not provided + "$..MaxItems", + # Different hardcoded value in the SOA record compared to Amazon + "$..ResourceRecordSets.[2].ResourceRecords.[0].Value", + ] +) +def test_create_record_set_via_id( + route53_hosted_zone, aws_client, deploy_cfn_template, snapshot, record_set_transformers +): + create_zone_response = route53_hosted_zone() + hosted_zone_id = create_zone_response["HostedZone"]["Id"] + route53_name = create_zone_response["HostedZone"]["Name"] + parameters = {"HostedZoneId": hosted_zone_id, "Name": route53_name} + deploy_cfn_template( + template_path=os.path.join( + os.path.dirname(__file__), "../../../templates/route53_hostedzoneid_template.yaml" + ), + parameters=parameters, + max_wait=300, + ) + rr_sets = aws_client.route53.list_resource_record_sets(HostedZoneId=hosted_zone_id) + snapshot.match("record-sets", rr_sets) + + +@markers.aws.validated +@markers.snapshot.skip_snapshot_verify( + paths=[ + # Moto returns a different value (300 instead of 100) when not provided + "$..MaxItems", + # Different hardcoded value in the SOA record compared to Amazon + "$..ResourceRecordSets.[2].ResourceRecords.[0].Value", + ] +) +def test_create_record_set_via_name( + deploy_cfn_template, aws_client, route53_hosted_zone, snapshot, record_set_transformers +): + create_zone_response = route53_hosted_zone() + route53_name = create_zone_response["HostedZone"]["Name"] + parameters = {"HostedZoneName": route53_name, "Name": route53_name} + deploy_cfn_template( + template_path=os.path.join( + os.path.dirname(__file__), "../../../templates/route53_hostedzonename_template.yaml" + ), + parameters=parameters, + ) + rr_sets = aws_client.route53.list_resource_record_sets( + HostedZoneId=create_zone_response["HostedZone"]["Id"] + ) + snapshot.match("record-sets", rr_sets) + + +@markers.aws.validated +@markers.snapshot.skip_snapshot_verify( + paths=[ + # Moto returns a different value (300 instead of 100) when not provided + "$..MaxItems", + # Different hardcoded value in the SOA record compared to Amazon + "$..ResourceRecordSets.[2].ResourceRecords.[0].Value", + ] +) +def test_create_record_set_without_resource_record( + deploy_cfn_template, aws_client, route53_hosted_zone, snapshot, record_set_transformers +): + create_zone_response = route53_hosted_zone() + hosted_zone_id = create_zone_response["HostedZone"]["Id"] + route53_name = create_zone_response["HostedZone"]["Name"] + parameters = {"HostedZoneId": hosted_zone_id, "Name": route53_name} + deploy_cfn_template( + template_path=os.path.join( + os.path.dirname(__file__), + "../../../templates/route53_recordset_without_resource_records.yaml", + ), + parameters=parameters, + ) + rr_sets = aws_client.route53.list_resource_record_sets(HostedZoneId=hosted_zone_id) + snapshot.match("record-sets", rr_sets) + + +@markers.aws.validated +@markers.snapshot.skip_snapshot_verify( + paths=[ + # Moto returns a different value (300 instead of 100) when not provided + "$..MaxItems", + # Different hardcoded value in the SOA record compared to Amazon + "$..ResourceRecordSets.[3].ResourceRecords.[0].Value", + ] +) +def test_create_multiple_weighted_alias_target_record_sets( + route53_hosted_zone, + aws_client, + deploy_cfn_template, + snapshot, + record_set_transformers, + get_s3_website_host_and_hosted_zone_id, +): + snapshot.add_transformer(snapshot.transform.key_value("DNSName")) + bucket_1_host, bucket_1_hosted_zone_id = get_s3_website_host_and_hosted_zone_id( + AWS_REGION_US_EAST_1 + ) + bucket_2_host, bucket_2_hosted_zone_id = get_s3_website_host_and_hosted_zone_id("us-west-1") + create_zone_response = route53_hosted_zone() + hosted_zone_id = create_zone_response["HostedZone"]["Id"] + route53_name = create_zone_response["HostedZone"]["Name"] + parameters = { + "HostedZoneId": hosted_zone_id, + "Name": route53_name, + "BucketRegionOneHost": bucket_1_host, + "BucketRegionOneHostedZoneId": bucket_1_hosted_zone_id, + "BucketRegionTwoHost": bucket_2_host, + "BucketRegionTwoHostedZoneId": bucket_2_hosted_zone_id, + } + + deploy_cfn_template( + template_path=os.path.join( + os.path.dirname(__file__), + "../../../templates/route53_hostedzoneid_weighted_template.yaml", + ), + parameters=parameters, + max_wait=300 if is_aws_cloud() else 60, + ) + rr_sets = aws_client.route53.list_resource_record_sets(HostedZoneId=hosted_zone_id) + snapshot.match("record-sets", rr_sets) + + +@markers.aws.validated +@markers.snapshot.skip_snapshot_verify( + paths=[ + # Moto returns a different value (300 instead of 100) when not provided + "$..MaxItems", + # Different hardcoded value in the SOA record compared to Amazon + "$..ResourceRecordSets.[3].ResourceRecords.[0].Value", + ] +) +def test_update_multiple_weighted_alias_target_record_sets( + route53_hosted_zone, + aws_client, + deploy_cfn_template, + snapshot, + record_set_transformers, + get_s3_website_host_and_hosted_zone_id, +): + snapshot.add_transformer(snapshot.transform.key_value("DNSName")) + bucket_1_host, bucket_1_hosted_zone_id = get_s3_website_host_and_hosted_zone_id( + AWS_REGION_US_EAST_1 + ) + bucket_2_host, bucket_2_hosted_zone_id = get_s3_website_host_and_hosted_zone_id("us-west-1") + create_zone_response = route53_hosted_zone() + hosted_zone_id = create_zone_response["HostedZone"]["Id"] + route53_name = create_zone_response["HostedZone"]["Name"] + parameters = { + "HostedZoneId": hosted_zone_id, + "Name": route53_name, + "BucketRegionOneHost": bucket_1_host, + "BucketRegionOneHostedZoneId": bucket_1_hosted_zone_id, + "BucketRegionTwoHost": bucket_2_host, + "BucketRegionTwoHostedZoneId": bucket_2_hosted_zone_id, + } + template_path = os.path.join( + os.path.dirname(__file__), + "../../../templates/route53_hostedzoneid_weighted_template.yaml", + ) + + result = deploy_cfn_template( + template_path=template_path, + parameters=parameters, + max_wait=300 if is_aws_cloud() else 60, + ) + stack_name = result.stack_name + rr_sets = aws_client.route53.list_resource_record_sets(HostedZoneId=hosted_zone_id) + snapshot.match("record-sets", rr_sets) + + parameters["WeightBucketOne"] = "50" + parameters["WeightBucketTwo"] = "100" + + deploy_cfn_template( + template_path=template_path, + parameters=parameters, + max_wait=300 if is_aws_cloud() else 60, + is_update=True, + stack_name=stack_name, + ) + rr_sets = aws_client.route53.list_resource_record_sets(HostedZoneId=hosted_zone_id) + snapshot.match("record-sets-update-weights", rr_sets) + + parameters["BucketRegionTwoHost"] = bucket_1_host + parameters["BucketRegionTwoHostedZoneId"] = bucket_1_hosted_zone_id + + deploy_cfn_template( + template_path=template_path, + parameters=parameters, + max_wait=300 if is_aws_cloud() else 60, + is_update=True, + stack_name=stack_name, + ) + rr_sets = aws_client.route53.list_resource_record_sets(HostedZoneId=hosted_zone_id) + snapshot.match("record-sets-update-alias-target", rr_sets) + + parameters["BucketTwoSetIdentifier"] = "region-3" + + deploy_cfn_template( + template_path=template_path, + parameters=parameters, + max_wait=300 if is_aws_cloud() else 60, + is_update=True, + stack_name=stack_name, + ) + rr_sets = aws_client.route53.list_resource_record_sets(HostedZoneId=hosted_zone_id) + snapshot.match("record-sets-update-set-identifier", rr_sets) diff --git a/tests/aws/services/route53/resource_providers/test_aws_route53_recordset.snapshot.json b/tests/aws/services/route53/resource_providers/test_aws_route53_recordset.snapshot.json new file mode 100644 index 0000000000000..8f67670f39633 --- /dev/null +++ b/tests/aws/services/route53/resource_providers/test_aws_route53_recordset.snapshot.json @@ -0,0 +1,479 @@ +{ + "tests/aws/services/route53/resource_providers/test_aws_route53_recordset.py::test_create_record_set_via_id": { + "recorded-date": "15-01-2026, 17:26:46", + "recorded-content": { + "record-sets": { + "IsTruncated": false, + "MaxItems": "100", + "ResourceRecordSets": [ + { + "Name": "", + "ResourceRecords": [ + { + "Value": "" + } + ], + "TTL": 900, + "Type": "A" + }, + { + "Name": "", + "ResourceRecords": [ + { + "Value": "" + }, + { + "Value": "" + }, + { + "Value": "" + }, + { + "Value": "" + } + ], + "TTL": 172800, + "Type": "NS" + }, + { + "Name": "", + "ResourceRecords": [ + { + "Value": " awsdns-hostmaster.amazon.com. 1 7200 900 1209600 86400" + } + ], + "TTL": 900, + "Type": "SOA" + } + ], + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/route53/resource_providers/test_aws_route53_recordset.py::test_create_record_set_via_name": { + "recorded-date": "15-01-2026, 17:31:53", + "recorded-content": { + "record-sets": { + "IsTruncated": false, + "MaxItems": "100", + "ResourceRecordSets": [ + { + "Name": "", + "ResourceRecords": [ + { + "Value": "" + } + ], + "TTL": 900, + "Type": "A" + }, + { + "Name": "", + "ResourceRecords": [ + { + "Value": "" + }, + { + "Value": "" + }, + { + "Value": "" + }, + { + "Value": "" + } + ], + "TTL": 172800, + "Type": "NS" + }, + { + "Name": "", + "ResourceRecords": [ + { + "Value": " awsdns-hostmaster.amazon.com. 1 7200 900 1209600 86400" + } + ], + "TTL": 900, + "Type": "SOA" + } + ], + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/route53/resource_providers/test_aws_route53_recordset.py::test_create_record_set_without_resource_record": { + "recorded-date": "15-01-2026, 17:36:56", + "recorded-content": { + "record-sets": { + "IsTruncated": false, + "MaxItems": "100", + "ResourceRecordSets": [ + { + "Name": "", + "ResourceRecords": [ + { + "Value": "" + } + ], + "TTL": 900, + "Type": "A" + }, + { + "Name": "", + "ResourceRecords": [ + { + "Value": "" + }, + { + "Value": "" + }, + { + "Value": "" + }, + { + "Value": "" + } + ], + "TTL": 172800, + "Type": "NS" + }, + { + "Name": "", + "ResourceRecords": [ + { + "Value": " awsdns-hostmaster.amazon.com. 1 7200 900 1209600 86400" + } + ], + "TTL": 900, + "Type": "SOA" + } + ], + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/route53/resource_providers/test_aws_route53_recordset.py::test_create_multiple_weighted_alias_target_record_sets": { + "recorded-date": "26-01-2026, 18:57:04", + "recorded-content": { + "record-sets": { + "IsTruncated": false, + "MaxItems": "100", + "ResourceRecordSets": [ + { + "AliasTarget": { + "DNSName": "", + "EvaluateTargetHealth": false, + "HostedZoneId": "Z3AQBSTGFYJSTF" + }, + "Name": "", + "SetIdentifier": "region-1", + "Type": "A", + "Weight": 255 + }, + { + "AliasTarget": { + "DNSName": "", + "EvaluateTargetHealth": false, + "HostedZoneId": "Z2F56UZL2M1ACD" + }, + "Name": "", + "SetIdentifier": "region-2", + "Type": "A", + "Weight": 0 + }, + { + "Name": "", + "ResourceRecords": [ + { + "Value": "" + }, + { + "Value": "" + }, + { + "Value": "" + }, + { + "Value": "" + } + ], + "TTL": 172800, + "Type": "NS" + }, + { + "Name": "", + "ResourceRecords": [ + { + "Value": " awsdns-hostmaster.amazon.com. 1 7200 900 1209600 86400" + } + ], + "TTL": 900, + "Type": "SOA" + } + ], + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/route53/resource_providers/test_aws_route53_recordset.py::test_update_multiple_weighted_alias_target_record_sets": { + "recorded-date": "26-01-2026, 18:51:15", + "recorded-content": { + "record-sets": { + "IsTruncated": false, + "MaxItems": "100", + "ResourceRecordSets": [ + { + "AliasTarget": { + "DNSName": "", + "EvaluateTargetHealth": false, + "HostedZoneId": "Z3AQBSTGFYJSTF" + }, + "Name": "", + "SetIdentifier": "region-1", + "Type": "A", + "Weight": 255 + }, + { + "AliasTarget": { + "DNSName": "", + "EvaluateTargetHealth": false, + "HostedZoneId": "Z2F56UZL2M1ACD" + }, + "Name": "", + "SetIdentifier": "region-2", + "Type": "A", + "Weight": 0 + }, + { + "Name": "", + "ResourceRecords": [ + { + "Value": "" + }, + { + "Value": "" + }, + { + "Value": "" + }, + { + "Value": "" + } + ], + "TTL": 172800, + "Type": "NS" + }, + { + "Name": "", + "ResourceRecords": [ + { + "Value": " awsdns-hostmaster.amazon.com. 1 7200 900 1209600 86400" + } + ], + "TTL": 900, + "Type": "SOA" + } + ], + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "record-sets-update-weights": { + "IsTruncated": false, + "MaxItems": "100", + "ResourceRecordSets": [ + { + "AliasTarget": { + "DNSName": "", + "EvaluateTargetHealth": false, + "HostedZoneId": "Z3AQBSTGFYJSTF" + }, + "Name": "", + "SetIdentifier": "region-1", + "Type": "A", + "Weight": 50 + }, + { + "AliasTarget": { + "DNSName": "", + "EvaluateTargetHealth": false, + "HostedZoneId": "Z2F56UZL2M1ACD" + }, + "Name": "", + "SetIdentifier": "region-2", + "Type": "A", + "Weight": 100 + }, + { + "Name": "", + "ResourceRecords": [ + { + "Value": "" + }, + { + "Value": "" + }, + { + "Value": "" + }, + { + "Value": "" + } + ], + "TTL": 172800, + "Type": "NS" + }, + { + "Name": "", + "ResourceRecords": [ + { + "Value": " awsdns-hostmaster.amazon.com. 1 7200 900 1209600 86400" + } + ], + "TTL": 900, + "Type": "SOA" + } + ], + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "record-sets-update-alias-target": { + "IsTruncated": false, + "MaxItems": "100", + "ResourceRecordSets": [ + { + "AliasTarget": { + "DNSName": "", + "EvaluateTargetHealth": false, + "HostedZoneId": "Z3AQBSTGFYJSTF" + }, + "Name": "", + "SetIdentifier": "region-1", + "Type": "A", + "Weight": 50 + }, + { + "AliasTarget": { + "DNSName": "", + "EvaluateTargetHealth": false, + "HostedZoneId": "Z3AQBSTGFYJSTF" + }, + "Name": "", + "SetIdentifier": "region-2", + "Type": "A", + "Weight": 100 + }, + { + "Name": "", + "ResourceRecords": [ + { + "Value": "" + }, + { + "Value": "" + }, + { + "Value": "" + }, + { + "Value": "" + } + ], + "TTL": 172800, + "Type": "NS" + }, + { + "Name": "", + "ResourceRecords": [ + { + "Value": " awsdns-hostmaster.amazon.com. 1 7200 900 1209600 86400" + } + ], + "TTL": 900, + "Type": "SOA" + } + ], + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "record-sets-update-set-identifier": { + "IsTruncated": false, + "MaxItems": "100", + "ResourceRecordSets": [ + { + "AliasTarget": { + "DNSName": "", + "EvaluateTargetHealth": false, + "HostedZoneId": "Z3AQBSTGFYJSTF" + }, + "Name": "", + "SetIdentifier": "region-1", + "Type": "A", + "Weight": 50 + }, + { + "AliasTarget": { + "DNSName": "", + "EvaluateTargetHealth": false, + "HostedZoneId": "Z3AQBSTGFYJSTF" + }, + "Name": "", + "SetIdentifier": "region-3", + "Type": "A", + "Weight": 100 + }, + { + "Name": "", + "ResourceRecords": [ + { + "Value": "" + }, + { + "Value": "" + }, + { + "Value": "" + }, + { + "Value": "" + } + ], + "TTL": 172800, + "Type": "NS" + }, + { + "Name": "", + "ResourceRecords": [ + { + "Value": " awsdns-hostmaster.amazon.com. 1 7200 900 1209600 86400" + } + ], + "TTL": 900, + "Type": "SOA" + } + ], + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + } +} diff --git a/tests/aws/services/route53/resource_providers/test_aws_route53_recordset.validation.json b/tests/aws/services/route53/resource_providers/test_aws_route53_recordset.validation.json new file mode 100644 index 0000000000000..5674342db3010 --- /dev/null +++ b/tests/aws/services/route53/resource_providers/test_aws_route53_recordset.validation.json @@ -0,0 +1,47 @@ +{ + "tests/aws/services/route53/resource_providers/test_aws_route53_recordset.py::test_create_multiple_weighted_alias_target_record_sets": { + "last_validated_date": "2026-01-26T18:57:39+00:00", + "durations_in_seconds": { + "setup": 0.51, + "call": 44.54, + "teardown": 37.78, + "total": 82.83 + } + }, + "tests/aws/services/route53/resource_providers/test_aws_route53_recordset.py::test_create_record_set_via_id": { + "last_validated_date": "2026-01-15T17:27:21+00:00", + "durations_in_seconds": { + "setup": 0.49, + "call": 43.43, + "teardown": 35.61, + "total": 79.53 + } + }, + "tests/aws/services/route53/resource_providers/test_aws_route53_recordset.py::test_create_record_set_via_name": { + "last_validated_date": "2026-01-15T17:32:28+00:00", + "durations_in_seconds": { + "setup": 0.47, + "call": 40.54, + "teardown": 34.81, + "total": 75.82 + } + }, + "tests/aws/services/route53/resource_providers/test_aws_route53_recordset.py::test_create_record_set_without_resource_record": { + "last_validated_date": "2026-01-15T17:37:31+00:00", + "durations_in_seconds": { + "setup": 0.47, + "call": 42.68, + "teardown": 34.81, + "total": 77.96 + } + }, + "tests/aws/services/route53/resource_providers/test_aws_route53_recordset.py::test_update_multiple_weighted_alias_target_record_sets": { + "last_validated_date": "2026-01-26T18:51:51+00:00", + "durations_in_seconds": { + "setup": 0.49, + "call": 174.99, + "teardown": 38.78, + "total": 214.26 + } + } +} diff --git a/tests/aws/services/route53/test_route53.py b/tests/aws/services/route53/test_route53.py index 93872854ed140..942b5ffe9e063 100644 --- a/tests/aws/services/route53/test_route53.py +++ b/tests/aws/services/route53/test_route53.py @@ -222,3 +222,17 @@ def test_reusable_delegation_sets(self, aws_client): with pytest.raises(Exception) as ctx: client.get_reusable_delegation_set(Id=set_id_1) assert "NoSuchDelegationSet" in str(ctx.value) + + @markers.aws.validated + def test_delete_hosted_zone(self, aws_client, hosted_zone, snapshot): + hosted_zone_response = hosted_zone(Name=f"zone-{short_uid()}.com") + hosted_zone_id = hosted_zone_response["HostedZone"]["Id"].split("/")[-1] + + snapshot.add_transformer(snapshot.transform.regex(hosted_zone_id, "")) + + with pytest.raises(ClientError) as e: + aws_client.route53.delete_hosted_zone(Id=hosted_zone_id + "asdf1234") + snapshot.match("no-such-hosted-zone-error", e.value.response) + + delete_hosted_zone_response = aws_client.route53.delete_hosted_zone(Id=hosted_zone_id) + snapshot.match("delete-hosted-zone-response", delete_hosted_zone_response) diff --git a/tests/aws/services/route53/test_route53.snapshot.json b/tests/aws/services/route53/test_route53.snapshot.json index e82bcf05108b1..4572f18077026 100644 --- a/tests/aws/services/route53/test_route53.snapshot.json +++ b/tests/aws/services/route53/test_route53.snapshot.json @@ -142,5 +142,32 @@ } } } + }, + "tests/aws/services/route53/test_route53.py::TestRoute53::test_delete_hosted_zone": { + "recorded-date": "12-01-2026, 00:07:24", + "recorded-content": { + "no-such-hosted-zone-error": { + "Error": { + "Code": "NoSuchHostedZone", + "Message": "No hosted zone found with ID: asdf1234", + "Type": "Sender" + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 404 + } + }, + "delete-hosted-zone-response": { + "ChangeInfo": { + "Id": "/change/", + "Status": "", + "SubmittedAt": "datetime" + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } } } diff --git a/tests/aws/services/route53/test_route53.validation.json b/tests/aws/services/route53/test_route53.validation.json index 5a7b0037f1b09..731f390ce6725 100644 --- a/tests/aws/services/route53/test_route53.validation.json +++ b/tests/aws/services/route53/test_route53.validation.json @@ -14,6 +14,15 @@ "tests/aws/services/route53/test_route53.py::TestRoute53::test_crud_health_check": { "last_validated_date": "2024-06-13T08:05:47+00:00" }, + "tests/aws/services/route53/test_route53.py::TestRoute53::test_delete_hosted_zone": { + "last_validated_date": "2026-01-12T00:07:24+00:00", + "durations_in_seconds": { + "setup": 0.66, + "call": 0.74, + "teardown": 0.1, + "total": 1.5 + } + }, "tests/aws/services/route53/test_route53.py::TestRoute53::test_reusable_delegation_sets": { "last_validated_date": "2024-06-13T07:43:08+00:00" } diff --git a/tests/aws/services/route53resolver/test_route53resolver.py b/tests/aws/services/route53resolver/test_route53resolver.py index 778e8ec500001..16ccb0b79bfd2 100644 --- a/tests/aws/services/route53resolver/test_route53resolver.py +++ b/tests/aws/services/route53resolver/test_route53resolver.py @@ -808,10 +808,10 @@ def test_list_firewall_rules( Name=firewall_rule_group_name ) cleanups.append( - lambda rule_group_id=rule_group_response["FirewallRuleGroup"][ - "Id" - ]: aws_client.route53resolver.delete_firewall_rule_group( - FirewallRuleGroupId=rule_group_id + lambda rule_group_id=rule_group_response["FirewallRuleGroup"]["Id"]: ( + aws_client.route53resolver.delete_firewall_rule_group( + FirewallRuleGroupId=rule_group_id + ) ) ) # Parameters for creating resources @@ -823,10 +823,10 @@ def test_list_firewall_rules( Name=f"fw-domain-list-{short_uid()}" ) cleanups.append( - lambda domain_list_id=domain_list_response["FirewallDomainList"][ - "Id" - ]: aws_client.route53resolver.delete_firewall_domain_list( - FirewallDomainListId=domain_list_id + lambda domain_list_id=domain_list_response["FirewallDomainList"]["Id"]: ( + aws_client.route53resolver.delete_firewall_domain_list( + FirewallDomainListId=domain_list_id + ) ) ) create_firewall_rule( diff --git a/tests/aws/services/s3/test_s3.py b/tests/aws/services/s3/test_s3.py index e9346ebb1ce5d..a26ef69ce8d5f 100644 --- a/tests/aws/services/s3/test_s3.py +++ b/tests/aws/services/s3/test_s3.py @@ -15,6 +15,7 @@ from importlib.util import find_spec from io import BytesIO from operator import itemgetter +from string import punctuation as ascii_punctuation from typing import TYPE_CHECKING from urllib.parse import SplitResult, parse_qs, quote, urlencode, urlparse, urlunsplit from zoneinfo import ZoneInfo @@ -33,8 +34,7 @@ from localstack_snapshot.snapshots.transformer import RegexTransformer from urllib3 import HTTPHeaderDict -import localstack.config -from localstack import config +from localstack import config, constants from localstack.aws.api.lambda_ import Runtime from localstack.aws.api.s3 import StorageClass, TransitionDefaultMinimumObjectSize from localstack.config import S3_VIRTUAL_HOSTNAME @@ -43,13 +43,15 @@ LOCALHOST_HOSTNAME, ) from localstack.services.s3 import constants as s3_constants +from localstack.services.s3.headers import encode_header_rfc2047 from localstack.services.s3.utils import ( RFC1123, etag_to_base_64_content_md5, + get_bucket_location_xml, parse_expiration_header, rfc_1123_datetime, ) -from localstack.testing.aws.util import in_default_partition, is_aws_cloud +from localstack.testing.aws.util import create_client_with_keys, in_default_partition, is_aws_cloud from localstack.testing.config import ( SECONDARY_TEST_AWS_ACCESS_KEY_ID, SECONDARY_TEST_AWS_SECRET_ACCESS_KEY, @@ -288,6 +290,11 @@ def _simple_bucket_policy(s3_bucket: str) -> dict: } +def get_xml_content(http_response_content: bytes) -> bytes: + # just format a bit the XML, nothing bad parity wise, but allow the test to run against AWS + return http_response_content.replace(b"'", b'"').replace(b"utf", b"UTF") + + class TestS3: @pytest.mark.skipif(condition=TEST_S3_IMAGE, reason="KMS not enabled in S3 image") @markers.aws.validated @@ -433,6 +440,70 @@ def test_put_and_get_object_with_content_language_disposition( snapshot.match("get-object-headers", response["ResponseMetadata"]) assert response["Body"].read() == b"abc123" + @markers.aws.validated + def test_system_metadata_with_unicode(self, s3_bucket, snapshot, aws_client): + snapshot.add_transformer(snapshot.transform.s3_api()) + response = aws_client.s3.put_object( + Bucket=s3_bucket, + Key="test", + ContentLanguage="de", + ContentDisposition='attachment; filename="test_—_file%E2%80%94_é_2.pdf"', + CacheControl="ÄMÄZÕÑ S3", + ) + snapshot.match("put-object", response) + + response = aws_client.s3.get_object(Bucket=s3_bucket, Key="test") + snapshot.match("get-object", response) + + @markers.aws.validated + def test_user_metadata_rfc2047_encoded(self, s3_bucket, snapshot, aws_client): + snapshot.add_transformer(snapshot.transform.s3_api()) + non_ascii = "test_—_file%E2%80%94_é_2?.pdf" + non_ascii_2 = "ÄMÄZÕÑ S3" + utf_metadata = "\x00\x01\x02\x03" + replacement_chars = "�������" + safe_chars = ascii_punctuation + " \t" + response = aws_client.s3.put_object( + Bucket=s3_bucket, + Key="test", + Metadata={ + "non-ascii": encode_header_rfc2047(non_ascii), + "non-ascii-2": encode_header_rfc2047(non_ascii_2), + "non-ascii-binary": encode_header_rfc2047(utf_metadata), + "replacement-chars": encode_header_rfc2047(replacement_chars), + # test if it will decode RFC 2047 looking data and return it decoded + "fake-encoded": "=?UTF-8?Q?actually-ascii?=", + "asciib64-encoded": "=?UTF-8?B?YWJj?=", + "safe-chars": safe_chars, + }, + ) + snapshot.match("put-object", response) + + response = aws_client.s3.get_object(Bucket=s3_bucket, Key="test") + snapshot.match("get-object", response) + + @markers.aws.validated + @markers.snapshot.skip_snapshot_verify( + # AWS returns broken encoded data, so we use replacement chars instead to indicate encoding error, if the + # padding is wrong + paths=["$..Metadata.bad-b64-encoded"], + ) + def test_user_metadata_rfc2047_bad_b64_encoded(self, s3_bucket, snapshot, aws_client): + snapshot.add_transformer(snapshot.transform.s3_api()) + response = aws_client.s3.put_object( + Bucket=s3_bucket, + Key="test", + Metadata={ + # this b64 value has a wrong padding + "bad-b64-encoded": "=?UTF-8?B?=GGG?=" + }, + ) + # AWS does not fail on invalid b64, but it returns gibberish, which we can't really have parity with (not + # worth it, so we return what we received) + snapshot.match("put-object", response) + response = aws_client.s3.get_object(Bucket=s3_bucket, Key="test") + snapshot.match("get-object", response) + @markers.aws.validated @pytest.mark.parametrize( "use_virtual_address", @@ -546,6 +617,44 @@ def test_put_get_object_single_character_trailing_slash(self, s3_bucket, aws_cli resp = aws_client.s3.list_objects_v2(Bucket=s3_bucket) snapshot.match("list-objects-single-char", resp) + @markers.aws.validated + def test_multipart_with_unicode_character_location(self, s3_bucket, aws_client, snapshot): + snapshot.add_transformer( + [ + snapshot.transform.key_value("Bucket", reference_replacement=False), + snapshot.transform.key_value("DisplayName", reference_replacement=False), + snapshot.transform.key_value("UploadId"), + snapshot.transform.key_value( + "ID", value_replacement="owner-id", reference_replacement=False + ), + ] + ) + + key_name = "test-unicode_—_file" + response = aws_client.s3.create_multipart_upload(Bucket=s3_bucket, Key=key_name) + snapshot.match("create-multipart", response) + upload_id = response["UploadId"] + + upload_part = aws_client.s3.upload_part( + Bucket=s3_bucket, + Key=key_name, + Body="upload-part-1", + PartNumber=1, + UploadId=upload_id, + ) + + multipart_upload_parts = [{"ETag": upload_part["ETag"], "PartNumber": 1}] + + response = aws_client.s3.complete_multipart_upload( + Bucket=s3_bucket, + Key=key_name, + MultipartUpload={"Parts": multipart_upload_parts}, + UploadId=upload_id, + ) + snapshot.match("complete-multipart", response) + location_prefix = response["Location"].split("/test-unicode")[0] + snapshot.add_transformer(snapshot.transform.regex(location_prefix, "")) + @markers.aws.validated def test_copy_object_special_character(self, s3_bucket, s3_create_bucket, aws_client, snapshot): snapshot.add_transformer(snapshot.transform.s3_api()) @@ -1000,6 +1109,83 @@ def test_create_bucket_via_host_name(self, s3_vhost_client, aws_client, region_n finally: s3_vhost_client.delete_bucket(Bucket=bucket_name) + @markers.aws.validated + @markers.snapshot.skip_snapshot_verify( + paths=["$..Owner.DisplayName", "$..Buckets..BucketArn"] + ) # Bucket ARN is by AWS in this scenario but not for others. + def test_create_bucket_with_eu_location_constraint( + self, s3_create_bucket_with_client, aws_client_factory, snapshot + ): + snapshot.add_transformer( + [ + snapshot.transform.key_value("ID"), + snapshot.transform.key_value("Name"), + snapshot.transform.key_value("BucketOwner"), + snapshot.transform.key_value("BucketRegion"), + ] + ) + client_eu_west_1 = aws_client_factory(region_name="eu-west-1").s3 + + bucket_name = f"test-eu-region-{short_uid()}" + s3_create_bucket_with_client( + client_eu_west_1, + Bucket=bucket_name, + CreateBucketConfiguration={ + "LocationConstraint": "EU" + }, # EU is just an alias for eu-west-1. + ) + get_bucket_location_response = client_eu_west_1.get_bucket_location(Bucket=bucket_name) + assert get_bucket_location_response["LocationConstraint"] == "EU" + snapshot.match("get-bucket-location", get_bucket_location_response) + + list_buckets_response = client_eu_west_1.list_buckets(Prefix=bucket_name) + assert list_buckets_response["Buckets"][0]["BucketRegion"] == "eu-west-1" + snapshot.match("list-bucket-response", list_buckets_response) + + @markers.aws.validated + def test_create_bucket_with_eu_location_constraint_raises( + self, s3_create_bucket_with_client, aws_client_factory, snapshot + ): + # Should fail for a region that isn't eu-west-1 (not including us-east-1) + client_us_east_2 = aws_client_factory(region_name="us-east-2").s3 + with pytest.raises(ClientError) as e: + s3_create_bucket_with_client( + client_us_east_2, + Bucket=f"test-eu-region-{short_uid()}", + CreateBucketConfiguration={"LocationConstraint": "EU"}, + ) + snapshot.match("eu-location-constraint-error", e.value.response) + + @markers.aws.validated + @pytest.mark.parametrize( + "client_region, location_constraint", + [("us-east-1", "us-east-1"), ("us-east-1", "foo"), ("eu-west-1", "bar")], + ) + def test_create_bucket_with_invalid_location_constraint( + self, + s3_create_bucket_with_client, + aws_client_factory, + snapshot, + client_region, + location_constraint, + ): + # Different error messages are raised for us-east-1. + snapshot.add_transformer( + snapshot.transform.key_value( + "LocationConstraint", value_replacement="location-constraint" + ) + ) + + client = aws_client_factory(region_name=client_region).s3 + with pytest.raises(ClientError) as e: + s3_create_bucket_with_client( + client, + CreateBucketConfiguration={"LocationConstraint": location_constraint}, + ) + snapshot.match( + f"{client_region}-location-constraint-{location_constraint}-error", e.value.response + ) + @markers.aws.validated def test_get_bucket_policy(self, s3_bucket, snapshot, aws_client, allow_bucket_acl, account_id): snapshot.add_transformer(snapshot.transform.key_value("Resource")) @@ -2033,102 +2219,6 @@ def test_s3_copy_object_with_default_checksum(self, s3_bucket, snapshot, aws_cli ) snapshot.match("dest-object-attrs-after-copy", object_attrs) - @markers.aws.validated - def test_s3_copy_object_preconditions(self, s3_bucket, snapshot, aws_client): - snapshot.add_transformer(snapshot.transform.s3_api()) - object_key = "source-object" - dest_key = "dest-object" - # create key with no checksum - put_object = aws_client.s3.put_object( - Bucket=s3_bucket, - Key=object_key, - Body=b"data", - ) - head_obj = aws_client.s3.head_object(Bucket=s3_bucket, Key=object_key) - snapshot.match("head-object", head_obj) - - # wait a bit for the `unmodified_since` value so that it's unvalid. - # S3 compares it the last-modified field, but you can't set the value in the future otherwise it ignores it - # It needs to be now or less, but the object needs to be a bit more recent than that. - time.sleep(3) - - # we're testing the order of validation at the same time by validating all of them at once, by elimination - now = datetime.datetime.now().astimezone(tz=ZoneInfo("GMT")) - wrong_unmodified_since = now - datetime.timedelta(days=1) - - with pytest.raises(ClientError) as e: - aws_client.s3.copy_object( - Bucket=s3_bucket, - CopySource=f"{s3_bucket}/{object_key}", - Key=dest_key, - CopySourceIfModifiedSince=now, - CopySourceIfUnmodifiedSince=wrong_unmodified_since, - CopySourceIfMatch="etag123", - CopySourceIfNoneMatch=put_object["ETag"], - ) - snapshot.match("copy-precondition-if-match", e.value.response) - - with pytest.raises(ClientError) as e: - aws_client.s3.copy_object( - Bucket=s3_bucket, - CopySource=f"{s3_bucket}/{object_key}", - Key=dest_key, - CopySourceIfModifiedSince=now, - CopySourceIfUnmodifiedSince=wrong_unmodified_since, - CopySourceIfNoneMatch=put_object["ETag"], - ) - snapshot.match("copy-precondition-if-unmodified-since", e.value.response) - - with pytest.raises(ClientError) as e: - aws_client.s3.copy_object( - Bucket=s3_bucket, - CopySource=f"{s3_bucket}/{object_key}", - Key=dest_key, - CopySourceIfModifiedSince=now, - CopySourceIfNoneMatch=put_object["ETag"], - ) - snapshot.match("copy-precondition-if-none-match", e.value.response) - - with pytest.raises(ClientError) as e: - aws_client.s3.copy_object( - Bucket=s3_bucket, - CopySource=f"{s3_bucket}/{object_key}", - Key=dest_key, - CopySourceIfModifiedSince=now, - ) - snapshot.match("copy-precondition-if-modified-since", e.value.response) - - # AWS will ignore the value if it's in the future - copy_obj = aws_client.s3.copy_object( - Bucket=s3_bucket, - CopySource=f"{s3_bucket}/{object_key}", - Key=dest_key, - CopySourceIfModifiedSince=now + datetime.timedelta(days=1), - ) - snapshot.match("copy-ignore-future-modified-since", copy_obj) - - # AWS will ignore the missing quotes around the ETag and still reject the request - with pytest.raises(ClientError) as e: - aws_client.s3.copy_object( - Bucket=s3_bucket, - CopySource=f"{s3_bucket}/{object_key}", - Key=dest_key, - CopySourceIfNoneMatch=put_object["ETag"].strip('"'), - ) - snapshot.match("copy-etag-missing-quotes", e.value.response) - - # Positive tests with all conditions checked - copy_obj_all_positive = aws_client.s3.copy_object( - Bucket=s3_bucket, - CopySource=f"{s3_bucket}/{object_key}", - Key=dest_key, - CopySourceIfMatch=put_object["ETag"].strip('"'), - CopySourceIfNoneMatch="etag123", - CopySourceIfModifiedSince=now - datetime.timedelta(days=1), - CopySourceIfUnmodifiedSince=now, - ) - snapshot.match("copy-success", copy_obj_all_positive) - @markers.aws.validated def test_s3_copy_object_wrong_format(self, s3_bucket, snapshot, aws_client): snapshot.add_transformer(snapshot.transform.s3_api()) @@ -2735,9 +2825,18 @@ def test_different_location_constraint( region_us_east_2 = "us-east-2" region_us_west_1 = "us-west-1" + client_us_east_1 = aws_client_factory( + region_name=AWS_REGION_US_EAST_1, config=Config(parameter_validation=False) + ).s3 + client_us_east_2 = aws_client_factory( + region_name=region_us_east_2, config=Config(parameter_validation=False) + ).s3 + client_us_west_1 = aws_client_factory(region_name=region_us_west_1).s3 + snapshot.add_transformer(snapshot.transform.s3_api()) snapshot.add_transformers_list( [ + snapshot.transform.key_value("BucketArn"), snapshot.transform.key_value("Location", "", reference_replacement=False), snapshot.transform.key_value( "LocationConstraint", "", reference_replacement=False @@ -2748,9 +2847,6 @@ def test_different_location_constraint( ] ) bucket_us_east_1 = f"bucket-{short_uid()}" - client_us_east_1 = aws_client_factory( - region_name=AWS_REGION_US_EAST_1, config=Config(parameter_validation=False) - ).s3 s3_create_bucket_with_client( client_us_east_1, Bucket=bucket_us_east_1, @@ -2766,15 +2862,13 @@ def test_different_location_constraint( ) snapshot.match("create-bucket-constraint-us-east-1", exc.value.response) - # assert creation fails with location constraint with the region unset - with pytest.raises(ClientError) as exc: - client_us_east_1.create_bucket( - Bucket=f"bucket-{short_uid()}", - CreateBucketConfiguration={"LocationConstraint": None}, - ) - snapshot.match("create-bucket-constraint-us-east-1-with-None", exc.value.response) + create_bucket_no_location = s3_create_bucket_with_client( + client_us_east_1, + Bucket=f"bucket-{short_uid()}", + CreateBucketConfiguration={"LocationConstraint": None}, + ) + snapshot.match("create-bucket-constraint-us-east-1-with-None", create_bucket_no_location) - client_us_east_2 = aws_client_factory(region_name=region_us_east_2).s3 bucket_us_east_2 = f"bucket-{short_uid()}" s3_create_bucket_with_client( client_us_east_2, @@ -2789,6 +2883,14 @@ def test_different_location_constraint( client_us_east_2.create_bucket(Bucket=f"bucket-{short_uid()}") snapshot.match("create-bucket-us-east-2-no-constraint-exc", exc.value.response) + # assert creation fails without location constraint for us-east-2 region + with pytest.raises(ClientError) as exc: + client_us_east_2.create_bucket( + Bucket=f"bucket-{short_uid()}", + CreateBucketConfiguration={"LocationConstraint": None}, + ) + snapshot.match("create-bucket-constraint-us-east-2-with-None", exc.value.response) + # assert creation fails with wrong location constraint from us-east-2 region to us-west-1 region with pytest.raises(ClientError) as exc: client_us_east_2.create_bucket( @@ -2797,8 +2899,6 @@ def test_different_location_constraint( ) snapshot.match("create-bucket-us-east-2-constraint-to-us-west-1", exc.value.response) - client_us_west_1 = aws_client_factory(region_name=region_us_west_1).s3 - with pytest.raises(ClientError) as exc: client_us_west_1.create_bucket( Bucket=f"bucket-{short_uid()}", @@ -4150,6 +4250,106 @@ def test_access_bucket_different_region(self, s3_create_bucket, s3_vhost_client, assert response.status_code == 200 assert response.history[0].status_code == 307 + @markers.aws.validated + @markers.requires_in_process # we're monkeypatching the handler chain + @markers.snapshot.skip_snapshot_verify( + # missing from `HeadBucket` call + paths=["$..AccessPointAlias"], + ) + def test_create_bucket_aws_global( + self, + aws_client_factory, + cleanups, + aws_client, + snapshot, + aws_http_client_factory, + monkeypatch, + ): + """ + Some tools use the `aws-global` region instead of `us-east-1` when no region are defined. It is considered + a valid region by Botocore too when creating the client, as it is a pseudo-region used for endpoint resolving. + The client is however supposed to then use `us-east-1` to sign the request, not `aws-global`. + Using `aws-global` to sign the request results in an error in AWS. + It seems some tools like the Go SDK used by Terraform might have the wrong logic, and skip the part where + they are supposed to sign with `us-east-1` if you override the endpoint url and skip the endpoint + resolving part, which is how we end up with those kind of requests. + """ + # we need to patch the `DefaultRegionRewriterStrategy` as it wil replace `aws-global` by `us-east-1`, which + # is its default region + from localstack.aws.handlers.region import DefaultRegionRewriterStrategy + + monkeypatch.setattr(DefaultRegionRewriterStrategy, "apply", lambda *_, **__: None) + + global_region = "aws-global" + bucket_prefix = f"global-bucket-{short_uid()}" + bucket_name_1 = f"{bucket_prefix}-{short_uid()}" + headers = {"x-amz-content-sha256": "UNSIGNED-PAYLOAD"} + + snapshot.add_transformers_list( + [ + snapshot.transform.regex(bucket_name_1, ""), + snapshot.transform.regex(bucket_prefix, ""), + snapshot.transform.regex(AWS_REGION_US_EAST_1, ""), + snapshot.transform.key_value("DisplayName"), + snapshot.transform.key_value("ID"), + snapshot.transform.key_value("HostId"), + snapshot.transform.key_value("RequestId"), + ] + ) + http_client = aws_http_client_factory( + service="s3", signer_factory=SigV4Auth, region=global_region + ) + # use the global endpoint with no region + base_endpoint = _endpoint_url(region=AWS_REGION_US_EAST_1) + response = http_client.put(f"{base_endpoint}/{bucket_name_1}", headers=headers) + if response.ok: + # we still clean up even if we expect it to fail, just in case it doesn't fail in AWS + cleanups.append(lambda: aws_client.s3.delete_bucket(Bucket=bucket_name_1)) + + assert response.status_code == 400 + xml_error = xmltodict.parse(response.content) + snapshot.match("xml-error-create-bucket", xml_error) + + # botocore is automatically signing the request with `us-east-1`, so we don't have issues + s3_client = aws_client_factory(region_name=global_region).s3 + create_bucket = s3_client.create_bucket(Bucket=bucket_name_1) + cleanups.append(lambda: aws_client.s3.delete_bucket(Bucket=bucket_name_1)) + snapshot.match("create-bucket-global", create_bucket) + + head_bucket = s3_client.head_bucket(Bucket=bucket_name_1) + snapshot.match("head-bucket-global", head_bucket) + + get_location_1 = aws_client.s3.get_bucket_location(Bucket=bucket_name_1) + # verify that the bucket 1 is created in `us-east-1` + snapshot.match("get-location-1", get_location_1) + + list_buckets_per_region = aws_client.s3.list_buckets( + BucketRegion=AWS_REGION_US_EAST_1, Prefix=bucket_prefix + ) + snapshot.match("list-buckets", list_buckets_per_region) + + # test that HeadBucket also raises an exception + head_response = http_client.head(f"{base_endpoint}/{bucket_name_1}", headers=headers) + + assert head_response.status_code == 400 + assert not head_response.content + + @markers.aws.validated + @pytest.mark.parametrize("client_region", [AWS_REGION_US_EAST_1, "us-west-1"]) + def test_bucket_constraint_aws_global( + self, s3_create_bucket_with_client, snapshot, aws_client_factory, client_region + ): + snapshot.add_transformer(snapshot.transform.s3_api()) + bucket_name = f"bucket-{short_uid()}" + us_east_1_client = aws_client_factory(region_name=client_region).s3 + with pytest.raises(ClientError) as e: + s3_create_bucket_with_client( + us_east_1_client, + Bucket=bucket_name, + CreateBucketConfiguration={"LocationConstraint": "aws-global"}, + ) + snapshot.match("aws-global-constraint", e.value.response) + @markers.aws.validated def test_bucket_does_not_exist(self, s3_vhost_client, snapshot, aws_client): snapshot.add_transformer(snapshot.transform.s3_api()) @@ -4671,6 +4871,7 @@ def test_s3_sse_validate_kms_key( region_us_west_2 = "us-west-2" snapshot.add_transformers_list( [ + snapshot.transform.key_value("CurrentKeyMaterialId"), snapshot.transform.key_value("Description"), snapshot.transform.regex(region_us_east_2, ""), snapshot.transform.regex(region_us_west_2, ""), @@ -4814,7 +5015,12 @@ def test_s3_sse_validate_kms_key( def test_s3_sse_validate_kms_key_state( self, s3_bucket, kms_create_key, monkeypatch, snapshot, aws_client ): - snapshot.add_transformer(snapshot.transform.key_value("Description")) + snapshot.add_transformer( + [ + snapshot.transform.key_value("Description"), + snapshot.transform.key_value("CurrentKeyMaterialId"), + ] + ) data = b"test-sse" # create key in the same region as the bucket @@ -5056,10 +5262,6 @@ def test_response_structure(self, aws_http_client_factory, s3_bucket, aws_client s3_http_client = aws_http_client_factory("s3", signer_factory=SigV4Auth) - def get_xml_content(http_response_content: bytes) -> bytes: - # just format a bit the XML, nothing bad parity wise, but allow the test to run against AWS - return http_response_content.replace(b"'", b'"').replace(b"utf", b"UTF") - # Lists all buckets endpoint_url = _endpoint_url() resp = s3_http_client.get(endpoint_url, headers=headers) @@ -5193,6 +5395,41 @@ def get_xml_content(http_response_content: bytes) -> bytes: assert resp.headers.get("Content-Type") is None assert resp.headers.get("Content-Length") is None + @markers.aws.validated + @pytest.mark.parametrize( + "client_region, location_constraint, expected_result", + [ + ("us-east-1", None, ""), + ("eu-west-1", "EU", "EU"), + ("eu-central-1", "eu-central-1", "eu-central-1"), + ], + ) + def test_response_structure_get_bucket_location( + self, + aws_http_client_factory, + s3_create_bucket_with_client, + aws_client_factory, + client_region, + location_constraint, + expected_result, + ): + s3_http_client = aws_http_client_factory("s3", signer_factory=SigV4Auth) + s3_client = aws_client_factory(region_name=client_region).s3 + bucket_name = f"get-bucket-location-response-test-{short_uid()}" + + bucket_config = ( + {"CreateBucketConfiguration": {"LocationConstraint": location_constraint}} + if location_constraint + else {} + ) + s3_create_bucket_with_client(s3_client, Bucket=bucket_name, **bucket_config) + get_bucket_location_response = s3_http_client.get( + f"{_bucket_url(bucket_name)}?location", + headers={"x-amz-content-sha256": "UNSIGNED-PAYLOAD"}, + ) + xml_content = get_xml_content(get_bucket_location_response.content) + assert get_bucket_location_xml(expected_result).encode() == xml_content + @markers.aws.validated def test_response_structure_get_obj_attrs(self, aws_http_client_factory, s3_bucket, aws_client): """ @@ -5514,9 +5751,6 @@ def test_s3_sse_bucket_key_default( @pytest.mark.skipif(condition=TEST_S3_IMAGE, reason="KMS not enabled in S3 image") @markers.aws.validated - @pytest.mark.skip( - reason="Behaviour not implemented yet: https://github.com/localstack/localstack/issues/6882" - ) # there is currently no server side encryption is place in LS, ETag will be different @markers.snapshot.skip_snapshot_verify(paths=["$..ETag"]) def test_s3_sse_default_kms_key( @@ -6228,6 +6462,7 @@ def add_query_param(request, **kwargs): finally: s3_presigned_client.meta.events.unregister("before-sign.s3.GetObject", add_query_param) + @markers.requires_in_process # Patches skip signature validation @markers.aws.only_localstack def test_presign_check_signature_validation_for_port_permutation( self, s3_bucket, patch_s3_skip_signature_validation_false, aws_client @@ -6270,6 +6505,7 @@ def test_put_object(self, s3_bucket, snapshot, aws_client): assert response["Body"].read() == b"something" snapshot.match("get_object", response) + @markers.requires_in_process # Patches skip signature validation @markers.aws.only_localstack def test_get_request_expires_ignored_if_validation_disabled( self, s3_bucket, monkeypatch, patch_s3_skip_signature_validation_false, aws_client @@ -6481,6 +6717,77 @@ def test_put_url_metadata_with_sig_s3( else: assert "wrong" not in head_object["Metadata"] + @markers.aws.validated + def test_get_response_overrides_unicode_metadata_with_sig_s3( + self, + s3_bucket, + snapshot, + aws_client, + presigned_snapshot_transformers, + ): + snapshot.add_transformer(snapshot.transform.s3_api()) + presigned_client = _s3_client_pre_signed_client( + Config(signature_version="s3"), + endpoint_url=_endpoint_url(), + ) + object_key = "key-non-ascii" + aws_client.s3.put_object(Bucket=s3_bucket, Key=object_key) + + url = presigned_client.generate_presigned_url( + "get_object", + Params={ + "Bucket": s3_bucket, + "Key": object_key, + "ResponseCacheControl": "non-ascii-%E2%80%94_—_é_", + "ResponseContentDisposition": 'filename="test_—_file%E2%80%94_é_2.pdf"', + }, + ) + response = requests.get(url, verify=False) + assert response.status_code == 400 + + response_content = xmltodict.parse(response.content) + snapshot.match("unicode-error", response_content) + + @markers.aws.validated + def test_put_unicode_metadata_with_sig_s3( + self, + s3_bucket, + snapshot, + aws_client, + presigned_snapshot_transformers, + ): + # we need to import the internal handlers of botocore and remove it, because it interferes with testing, and + # other SDKs do not have that validation and will accept non-ascii metadata + from botocore.handlers import validate_ascii_metadata + + snapshot.add_transformer(snapshot.transform.s3_api()) + presigned_client = _s3_client_pre_signed_client( + Config(signature_version="s3"), + endpoint_url=_endpoint_url(), + ) + # remove the builtin handler that validate ascii in the metadata, because AWS actually accepts it if it is in + # pre-signed URLs. + presigned_client.meta.events.unregister( + "before-parameter-build.s3.PutObject", + validate_ascii_metadata, + ) + + object_key = "key-non-ascii" + + metadata = {"foo": "non-ascii-%E2%80%94_—_é_"} + + # put object via presigned URL with metadata + url = presigned_client.generate_presigned_url( + "put_object", + Params={"Bucket": s3_bucket, "Key": object_key, "Metadata": metadata}, + ) + + response = requests.put(url, verify=False) + assert response.ok + + response = aws_client.s3.head_object(Bucket=s3_bucket, Key=object_key) + snapshot.match("head_object", response) + @markers.aws.validated def test_get_object_ignores_request_body(self, s3_bucket, aws_client): key = "foo-key" @@ -6833,6 +7140,7 @@ def test_s3_put_presigned_url_same_header_and_qs_parameter( exception["StatusCode"] = response.status_code snapshot.match("override-signed-qs", exception) + @markers.requires_in_process # Patches skip signature validation @markers.aws.validated @pytest.mark.parametrize("signature_version", ["s3", "s3v4"]) def test_s3_put_presigned_url_missing_sig_param( @@ -6908,6 +7216,7 @@ def test_s3_get_response_content_type_same_as_upload_and_range(self, s3_bucket, @pytest.mark.skipif(condition=TEST_S3_IMAGE, reason="STS not enabled in S3 image") @markers.aws.validated + @markers.requires_in_process # Patches skip signature validation def test_presigned_url_with_session_token( self, s3_create_bucket_with_client, @@ -6947,6 +7256,7 @@ def test_presigned_url_with_session_token( @pytest.mark.skipif(condition=TEST_S3_IMAGE, reason="STS not enabled in S3 image") @markers.aws.validated + @markers.requires_in_process # Patches skip signature validation def test_presigned_url_with_different_user_credentials( self, aws_client, @@ -7018,6 +7328,7 @@ def test_presigned_url_with_different_user_credentials( assert response._content == b"test-value" @markers.aws.validated + @markers.requires_in_process # Patches skip signature validation @pytest.mark.parametrize("signature_version", ["s3", "s3v4"]) def test_s3_get_response_header_overrides( self, s3_bucket, signature_version, patch_s3_skip_signature_validation_false, aws_client @@ -7274,6 +7585,7 @@ def test_presigned_url_signature_authentication( ], ) @markers.aws.validated + @markers.requires_in_process # Patches skip signature validation def test_presigned_url_signature_authentication_multi_part( self, s3_create_bucket, @@ -7538,6 +7850,7 @@ def test_pre_signed_url_forward_slash_bucket( ["s3", "s3v4"], ) @markers.aws.validated + @markers.requires_in_process # Patches skip signature validation def test_s3_presign_url_encoding( self, aws_client, s3_bucket, signature_version, patch_s3_skip_signature_validation_false ): @@ -7721,6 +8034,40 @@ def test_pre_signed_url_if_match(self, s3_bucket, aws_client, aws_session): response = requests.put(req.url) assert response.status_code == 412 + @markers.aws.only_localstack + @markers.requires_in_process # Patches skip signature validation + @pytest.mark.parametrize("signature_version", ["s3", "s3v4"]) + def test_pre_signed_url_validation_works_on_internal_account( + self, + aws_client, + account_id, + s3_create_bucket_with_client, + signature_version, + patch_s3_skip_signature_validation_false, + ): + bucket_name = f"bucket-{short_uid()}" + key_name = "test-key" + credentials = { + "AccessKeyId": config.INTERNAL_RESOURCE_ACCOUNT, + "SecretAccessKey": constants.INTERNAL_AWS_SECRET_ACCESS_KEY, + } + s3_client = create_client_with_keys( + service="s3", + region_name=AWS_REGION_US_EAST_1, + keys=credentials, + client_config=Config(signature_version=signature_version), + ) + + s3_create_bucket_with_client(s3_client=s3_client, Bucket=bucket_name) + s3_client.put_object(Body="test-value", Bucket=bucket_name, Key=key_name) + pre_signed_url = s3_client.generate_presigned_url( + ClientMethod="get_object", + Params={"Bucket": bucket_name, "Key": key_name}, + ExpiresIn=600, + ) + response = requests.get(pre_signed_url) + assert response._content == b"test-value" + class TestS3DeepArchive: """ @@ -10567,6 +10914,7 @@ def test_post_request_expires( "signature_version", ["s3", "s3v4"], ) + @markers.requires_in_process # Patches skip signature validation def test_post_request_malformed_policy( self, s3_bucket, @@ -10609,6 +10957,7 @@ def test_post_request_malformed_policy( assert exception["Error"]["StringToSign"] == presigned_request["fields"]["policy"] @markers.aws.validated + @markers.requires_in_process # Patches skip signature validation @pytest.mark.parametrize( "signature_version", ["s3", "s3v4"], @@ -10650,6 +10999,7 @@ def test_post_request_missing_signature( snapshot.match("exception-missing-signature", exception) @markers.aws.validated + @markers.requires_in_process # Patches skip signature validation @pytest.mark.parametrize( "signature_version", ["s3", "s3v4"], @@ -10901,6 +11251,76 @@ def test_post_object_with_metadata(self, s3_bucket, aws_client, snapshot): head_object = aws_client.s3.head_object(Bucket=s3_bucket, Key=object_key) snapshot.match("head-object", head_object) + @markers.aws.validated + def test_post_object_with_unicode_metadata(self, s3_bucket, aws_client, snapshot): + # https://docs.aws.amazon.com/AmazonS3/latest/userguide/UsingMetadata.html + # To avoid issues related to the presentation of these metadata values, you should conform to using US-ASCII + # characters when using REST and UTF-8 when using SOAP or browser-based uploads through POST. + # When using non-US-ASCII characters in your metadata values, the provided Unicode string is examined for + # non-US-ASCII characters. Values of such headers are character decoded as per RFC 2047 before storing and + # encoded as per RFC 2047 to make them mail-safe before returning. If the string contains only US-ASCII + # characters, it is presented as is. + + snapshot.add_transformer(snapshot.transform.key_value("Bucket"), priority=10) + object_key = "test_unicode—_file.pdf" + content_disposition = 'filename="test_—_file%E2%80%94_é_2-.pdf"' + cache_control = "non-ascii-%E2%80%94_—_é_" + user_metadata = "ÄMÄZÕÑ S3" + user_metadata_2 = "test_—_file%E2%80%94_é_2👑.pdf" + test_safe_chars = "! \"#$%&'()*+,-./0123456789:;<>'?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\t" + utf_8_byte_string = "\x00\x01\x02\x03\x04" + rfc_2047_q_encoded = "=?UTF-8?Q?actually-ascii?=" + rfc_2047_b_encoded = "=?UTF-8?B?YWJj?=" + + presigned_request = aws_client.s3.generate_presigned_post( + Bucket=s3_bucket, + Key=object_key, + ExpiresIn=60, + Fields={ + "Content-Disposition": content_disposition, + "Cache-Control": cache_control, + "x-amz-meta-nonascii": user_metadata, + "x-amz-meta-nonascii-2": user_metadata_2, + "x-amz-meta-safe-chars": test_safe_chars, + "x-amz-meta-utf-8": utf_8_byte_string, + "x-amz-meta-q-encoded": rfc_2047_q_encoded, + "x-amz-meta-b-encoded": rfc_2047_b_encoded, + # we require the 201 status code to get more information from the response + "success_action_status": "201", + }, + Conditions=[ + {"bucket": s3_bucket}, + ["eq", "$Content-Disposition", content_disposition], + ["eq", "$Cache-Control", cache_control], + ["eq", "$x-amz-meta-nonascii", user_metadata], + ["eq", "$x-amz-meta-nonascii-2", user_metadata_2], + ["eq", "$x-amz-meta-safe-chars", test_safe_chars], + ["eq", "$x-amz-meta-utf-8", utf_8_byte_string], + ["eq", "$x-amz-meta-q-encoded", rfc_2047_q_encoded], + ["eq", "$x-amz-meta-b-encoded", rfc_2047_b_encoded], + ["eq", "$success_action_status", "201"], + ], + ) + # PostObject + response = requests.post( + presigned_request["url"], + data=presigned_request["fields"], + files={"file": "test-body-tagging"}, + verify=False, + ) + assert response.status_code == 201 + response_content = xmltodict.parse(response.content) + location_header = response.headers.get("Location") + response_content["LocationHeader"] = location_header + response_content["PostResponse"].pop("@xmlns", None) + snapshot.match("post-object", response_content) + + location_prefix = location_header.split("/test_unicode")[0] + snapshot.add_transformer(snapshot.transform.regex(location_prefix, "")) + + head_object = aws_client.s3.head_object(Bucket=s3_bucket, Key=object_key) + snapshot.match("head-object", head_object) + @markers.aws.validated @markers.snapshot.skip_snapshot_verify( paths=[ @@ -12537,8 +12957,11 @@ def test_s3_checksum_no_automatic_sdk_calculation( class TestS3MultipartUploadChecksum: @markers.aws.validated @markers.snapshot.skip_snapshot_verify( - # it seems the PartNumber might not be deterministic, possibly parallelized on S3 side? - paths=["$.complete-multipart-wrong-parts-checksum.Error.PartNumber"] + # it seems the PartNumber (and ETag by extension) might not be deterministic, possibly parallelized on S3 side? + paths=[ + "$.complete-multipart-wrong-parts-checksum.Error.PartNumber", + "$.complete-multipart-wrong-parts-checksum.Error.ETag", + ] ) @pytest.mark.parametrize("algorithm", ["CRC32", "CRC32C", "SHA1", "SHA256"]) def test_complete_multipart_parts_checksum_composite( @@ -13507,9 +13930,7 @@ def _website_bucket_url(bucket_name: str): if is_aws_cloud(): region = AWS_REGION_US_EAST_1 return f"http://{bucket_name}.s3-website-{region}.amazonaws.com" - return _bucket_url_vhost( - bucket_name, localstack_host=localstack.config.S3_STATIC_WEBSITE_HOSTNAME - ) + return _bucket_url_vhost(bucket_name, localstack_host=config.S3_STATIC_WEBSITE_HOSTNAME) def _bucket_url_vhost(bucket_name: str, region: str = "", localstack_host: str = None) -> str: diff --git a/tests/aws/services/s3/test_s3.snapshot.json b/tests/aws/services/s3/test_s3.snapshot.json index 6738070d038df..e769bde07e748 100644 --- a/tests/aws/services/s3/test_s3.snapshot.json +++ b/tests/aws/services/s3/test_s3.snapshot.json @@ -1,6 +1,6 @@ { "tests/aws/services/s3/test_s3.py::TestS3::test_delete_bucket_with_content": { - "recorded-date": "21-01-2025, 18:26:26", + "recorded-date": "21-02-2026, 00:17:01", "recorded-content": { "list-objects": { "Contents": [ @@ -13,7 +13,6 @@ "Key": "test-key-0", "LastModified": "datetime", "Owner": { - "DisplayName": "", "ID": "" }, "Size": 6, @@ -28,7 +27,6 @@ "Key": "test-key-1", "LastModified": "datetime", "Owner": { - "DisplayName": "", "ID": "" }, "Size": 6, @@ -43,7 +41,6 @@ "Key": "test-key-2", "LastModified": "datetime", "Owner": { - "DisplayName": "", "ID": "" }, "Size": 6, @@ -58,7 +55,6 @@ "Key": "test-key-3", "LastModified": "datetime", "Owner": { - "DisplayName": "", "ID": "" }, "Size": 6, @@ -73,7 +69,6 @@ "Key": "test-key-4", "LastModified": "datetime", "Owner": { - "DisplayName": "", "ID": "" }, "Size": 6, @@ -88,7 +83,6 @@ "Key": "test-key-5", "LastModified": "datetime", "Owner": { - "DisplayName": "", "ID": "" }, "Size": 6, @@ -103,7 +97,6 @@ "Key": "test-key-6", "LastModified": "datetime", "Owner": { - "DisplayName": "", "ID": "" }, "Size": 6, @@ -118,7 +111,6 @@ "Key": "test-key-7", "LastModified": "datetime", "Owner": { - "DisplayName": "", "ID": "" }, "Size": 6, @@ -133,7 +125,6 @@ "Key": "test-key-8", "LastModified": "datetime", "Owner": { - "DisplayName": "", "ID": "" }, "Size": 6, @@ -148,7 +139,6 @@ "Key": "test-key-9", "LastModified": "datetime", "Owner": { - "DisplayName": "", "ID": "" }, "Size": 6, @@ -169,20 +159,12 @@ "list-buckets": { "Buckets": [ { + "BucketArn": "arn::s3:::", "CreationDate": "datetime", "Name": "" - }, - { - "CreationDate": "datetime", - "Name": "" - }, - { - "CreationDate": "datetime", - "Name": "" } ], "Owner": { - "DisplayName": "", "ID": "" }, "ResponseMetadata": { @@ -193,7 +175,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3::test_put_and_get_object_with_utf8_key": { - "recorded-date": "21-01-2025, 18:26:27", + "recorded-date": "21-02-2026, 00:17:02", "recorded-content": { "put-object": { "ChecksumCRC32": "zwK7XA==", @@ -224,7 +206,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3::test_metadata_header_character_decoding": { - "recorded-date": "21-01-2025, 18:26:37", + "recorded-date": "21-02-2026, 00:17:18", "recorded-content": { "head-object": { "AcceptRanges": "bytes", @@ -245,7 +227,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3::test_upload_file_multipart": { - "recorded-date": "21-01-2025, 18:26:40", + "recorded-date": "21-02-2026, 00:17:20", "recorded-content": { "get_object": { "AcceptRanges": "bytes", @@ -266,7 +248,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3::test_get_object_no_such_bucket": { - "recorded-date": "21-01-2025, 18:27:10", + "recorded-date": "21-02-2026, 00:17:57", "recorded-content": { "expected_error": { "Error": { @@ -282,7 +264,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3::test_delete_bucket_no_such_bucket": { - "recorded-date": "21-01-2025, 18:27:11", + "recorded-date": "21-02-2026, 00:17:57", "recorded-content": { "expected_error": { "Error": { @@ -298,7 +280,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3::test_get_bucket_notification_configuration_no_such_bucket": { - "recorded-date": "21-01-2025, 18:27:11", + "recorded-date": "21-02-2026, 00:17:58", "recorded-content": { "expected_error": { "Error": { @@ -314,7 +296,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3::test_get_object_attributes": { - "recorded-date": "17-03-2025, 20:02:49", + "recorded-date": "21-02-2026, 00:18:02", "recorded-content": { "object-attrs": { "Checksum": { @@ -373,7 +355,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3::test_put_and_get_object_with_hash_prefix": { - "recorded-date": "21-01-2025, 18:27:44", + "recorded-date": "21-02-2026, 00:18:18", "recorded-content": { "put-object": { "ChecksumCRC32": "wmkP3w==", @@ -404,7 +386,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3::test_invalid_range_error": { - "recorded-date": "21-01-2025, 18:27:45", + "recorded-date": "21-02-2026, 00:18:20", "recorded-content": { "exc": { "Error": { @@ -421,7 +403,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3::test_range_key_not_exists": { - "recorded-date": "21-01-2025, 18:27:47", + "recorded-date": "21-02-2026, 00:18:22", "recorded-content": { "exc": { "Error": { @@ -437,7 +419,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3::test_put_object_tagging_empty_list": { - "recorded-date": "21-01-2025, 18:28:08", + "recorded-date": "21-02-2026, 00:18:51", "recorded-content": { "created-object-tags": { "TagSet": [], @@ -472,7 +454,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3::test_get_object_after_deleted_in_versioned_bucket": { - "recorded-date": "21-01-2025, 18:28:12", + "recorded-date": "21-02-2026, 00:18:55", "recorded-content": { "get-object": { "AcceptRanges": "bytes", @@ -505,7 +487,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3PutObjectChecksum::test_put_object_checksum[CRC32]": { - "recorded-date": "17-03-2025, 18:27:45", + "recorded-date": "21-02-2026, 00:37:12", "recorded-content": { "put-wrong-checksum-no-b64": { "Error": { @@ -589,7 +571,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3PutObjectChecksum::test_put_object_checksum[CRC32C]": { - "recorded-date": "17-03-2025, 18:27:58", + "recorded-date": "21-02-2026, 00:37:27", "recorded-content": { "put-wrong-checksum-no-b64": { "Error": { @@ -673,7 +655,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3PutObjectChecksum::test_put_object_checksum[SHA1]": { - "recorded-date": "17-03-2025, 18:28:09", + "recorded-date": "21-02-2026, 00:37:34", "recorded-content": { "put-wrong-checksum-no-b64": { "Error": { @@ -757,7 +739,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3PutObjectChecksum::test_put_object_checksum[SHA256]": { - "recorded-date": "17-03-2025, 18:28:24", + "recorded-date": "21-02-2026, 00:37:49", "recorded-content": { "put-wrong-checksum-no-b64": { "Error": { @@ -841,7 +823,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3::test_s3_copy_metadata_replace": { - "recorded-date": "21-01-2025, 18:28:50", + "recorded-date": "21-02-2026, 00:18:57", "recorded-content": { "put_object": { "ChecksumCRC32": "MzVIGw==", @@ -872,6 +854,7 @@ "copy_object": { "CopyObjectResult": { "ChecksumCRC32": "MzVIGw==", + "ChecksumType": "FULL_OBJECT", "ETag": "\"88bac95f31528d13a072c05f2a1cf371\"", "LastModified": "datetime" }, @@ -899,7 +882,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3::test_s3_copy_content_type_and_metadata": { - "recorded-date": "21-01-2025, 18:29:13", + "recorded-date": "21-02-2026, 00:19:21", "recorded-content": { "put_object": { "ChecksumCRC32": "MzVIGw==", @@ -929,6 +912,7 @@ "copy_object": { "CopyObjectResult": { "ChecksumCRC32": "MzVIGw==", + "ChecksumType": "FULL_OBJECT", "ETag": "\"88bac95f31528d13a072c05f2a1cf371\"", "LastModified": "datetime" }, @@ -956,6 +940,7 @@ "copy_object_second": { "CopyObjectResult": { "ChecksumCRC32": "MzVIGw==", + "ChecksumType": "FULL_OBJECT", "ETag": "\"88bac95f31528d13a072c05f2a1cf371\"", "LastModified": "datetime" }, @@ -983,13 +968,12 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3::test_s3_multipart_upload_acls": { - "recorded-date": "21-01-2025, 18:30:13", + "recorded-date": "21-02-2026, 00:20:32", "recorded-content": { "bucket-acl": { "Grants": [ { "Grantee": { - "DisplayName": "", "ID": "", "Type": "CanonicalUser" }, @@ -1004,7 +988,6 @@ } ], "Owner": { - "DisplayName": "", "ID": "" }, "ResponseMetadata": { @@ -1016,7 +999,6 @@ "Grants": [ { "Grantee": { - "DisplayName": "", "ID": "", "Type": "CanonicalUser" }, @@ -1024,7 +1006,6 @@ } ], "Owner": { - "DisplayName": "", "ID": "" }, "ResponseMetadata": { @@ -1036,7 +1017,6 @@ "Grants": [ { "Grantee": { - "DisplayName": "", "ID": "", "Type": "CanonicalUser" }, @@ -1044,7 +1024,6 @@ } ], "Owner": { - "DisplayName": "", "ID": "" }, "ResponseMetadata": { @@ -1056,7 +1035,6 @@ "Grants": [ { "Grantee": { - "DisplayName": "", "ID": "", "Type": "CanonicalUser" }, @@ -1078,7 +1056,6 @@ } ], "Owner": { - "DisplayName": "", "ID": "" }, "ResponseMetadata": { @@ -1089,7 +1066,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3::test_upload_file_with_xml_preamble": { - "recorded-date": "21-01-2025, 18:30:40", + "recorded-date": "21-02-2026, 00:20:56", "recorded-content": { "get_object": { "AcceptRanges": "bytes", @@ -1110,7 +1087,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3::test_bucket_availability": { - "recorded-date": "21-01-2025, 18:30:41", + "recorded-date": "21-02-2026, 00:20:57", "recorded-content": { "bucket-lifecycle": { "Error": { @@ -1137,7 +1114,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3::test_different_location_constraint": { - "recorded-date": "21-01-2025, 18:30:47", + "recorded-date": "23-02-2026, 12:30:37", "recorded-content": { "get-bucket-location-bucket-us-east-1": { "LocationConstraint": null, @@ -1158,13 +1135,11 @@ } }, "create-bucket-constraint-us-east-1-with-None": { - "Error": { - "Code": "MalformedXML", - "Message": "The XML you provided was not well-formed or did not validate against our published schema" - }, + "BucketArn": "", + "Location": "", "ResponseMetadata": { "HTTPHeaders": {}, - "HTTPStatusCode": 400 + "HTTPStatusCode": 200 } }, "get-bucket-location-bucket-us-east-2": { @@ -1184,6 +1159,16 @@ "HTTPStatusCode": 400 } }, + "create-bucket-constraint-us-east-2-with-None": { + "Error": { + "Code": "IllegalLocationConstraintException", + "Message": "The unspecified location constraint is incompatible for the region specific endpoint this request was sent to." + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + }, "create-bucket-us-east-2-constraint-to-us-west-1": { "Error": { "Code": "IllegalLocationConstraintException", @@ -1229,7 +1214,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3::test_get_object_with_anon_credentials": { - "recorded-date": "21-01-2025, 18:30:54", + "recorded-date": "21-02-2026, 00:21:11", "recorded-content": { "get_object": { "AcceptRanges": "bytes", @@ -1250,7 +1235,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3::test_putobject_with_multiple_keys": { - "recorded-date": "21-01-2025, 18:30:56", + "recorded-date": "21-02-2026, 00:21:13", "recorded-content": { "get_object": { "AcceptRanges": "bytes", @@ -1271,7 +1256,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3BucketLifecycle::test_delete_bucket_lifecycle_configuration": { - "recorded-date": "21-01-2025, 18:18:18", + "recorded-date": "21-02-2026, 00:33:15", "recorded-content": { "get-bucket-lifecycle-exc-1": { "Error": { @@ -1323,7 +1308,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3BucketLifecycle::test_delete_lifecycle_configuration_on_bucket_deletion": { - "recorded-date": "21-01-2025, 18:18:20", + "recorded-date": "21-02-2026, 00:33:18", "recorded-content": { "get-bucket-lifecycle-conf": { "Rules": [ @@ -1358,7 +1343,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3BucketLifecycle::test_bucket_lifecycle_configuration_object_expiry": { - "recorded-date": "21-01-2025, 18:18:28", + "recorded-date": "21-02-2026, 00:33:26", "recorded-content": { "get-bucket-lifecycle-conf": { "Rules": [ @@ -1411,7 +1396,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3::test_range_header_body_length": { - "recorded-date": "21-01-2025, 18:30:58", + "recorded-date": "21-02-2026, 00:21:15", "recorded-content": { "get-object": { "AcceptRanges": "bytes", @@ -1446,7 +1431,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3::test_delete_object_tagging": { - "recorded-date": "21-01-2025, 18:31:28", + "recorded-date": "21-02-2026, 00:21:26", "recorded-content": { "get-obj": { "AcceptRanges": "bytes", @@ -1483,7 +1468,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3::test_delete_non_existing_keys": { - "recorded-date": "21-01-2025, 18:31:31", + "recorded-date": "21-02-2026, 00:21:30", "recorded-content": { "deleted-resp": { "Deleted": [ @@ -1505,7 +1490,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3::test_delete_non_existing_keys_in_non_existing_bucket": { - "recorded-date": "21-01-2025, 18:31:36", + "recorded-date": "21-02-2026, 00:21:34", "recorded-content": { "error-non-existent-bucket": { "Error": { @@ -1521,7 +1506,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3::test_s3_request_payer": { - "recorded-date": "21-01-2025, 18:31:42", + "recorded-date": "21-02-2026, 00:21:40", "recorded-content": { "put-bucket-request-payment": { "ResponseMetadata": { @@ -1539,7 +1524,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3::test_s3_request_payer_exceptions": { - "recorded-date": "21-01-2025, 18:31:43", + "recorded-date": "21-02-2026, 00:21:42", "recorded-content": { "wrong-payer-type": { "Error": { @@ -1565,7 +1550,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3::test_bucket_exists": { - "recorded-date": "21-01-2025, 18:31:45", + "recorded-date": "21-02-2026, 00:21:44", "recorded-content": { "get-bucket-cors": { "CORSRules": [ @@ -1590,7 +1575,6 @@ "Grants": [ { "Grantee": { - "DisplayName": "", "ID": "", "Type": "CanonicalUser" }, @@ -1598,7 +1582,6 @@ } ], "Owner": { - "DisplayName": "", "ID": "" }, "ResponseMetadata": { @@ -1620,7 +1603,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3::test_s3_uppercase_key_names": { - "recorded-date": "21-01-2025, 18:31:47", + "recorded-date": "21-02-2026, 00:21:46", "recorded-content": { "response": { "AcceptRanges": "bytes", @@ -1652,7 +1635,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3::test_precondition_failed_error": { - "recorded-date": "21-01-2025, 18:32:22", + "recorded-date": "21-02-2026, 00:22:22", "recorded-content": { "get-object-if-match": { "Error": { @@ -1668,7 +1651,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3::test_s3_invalid_content_md5": { - "recorded-date": "21-01-2025, 18:32:49", + "recorded-date": "21-02-2026, 00:22:47", "recorded-content": { "md5-error-0": { "Error": { @@ -1826,7 +1809,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3::test_s3_upload_download_gzip": { - "recorded-date": "21-01-2025, 18:32:51", + "recorded-date": "21-02-2026, 00:22:49", "recorded-content": { "put-object": { "ChecksumCRC32": "KBARJw==", @@ -1858,7 +1841,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3::test_multipart_copy_object_etag": { - "recorded-date": "17-03-2025, 23:02:42", + "recorded-date": "21-02-2026, 00:22:54", "recorded-content": { "multipart-upload": { "Bucket": "", @@ -1876,6 +1859,7 @@ "copy-object": { "CopyObjectResult": { "ChecksumCRC64NVME": "BsLNlKumA5I=", + "ChecksumType": "FULL_OBJECT", "ETag": "\"eee506dd7ada7ded524c77e359a0e7c6\"", "LastModified": "datetime" }, @@ -1888,6 +1872,7 @@ "copy-object-in-place": { "CopyObjectResult": { "ChecksumCRC64NVME": "BsLNlKumA5I=", + "ChecksumType": "FULL_OBJECT", "ETag": "\"eee506dd7ada7ded524c77e359a0e7c6\"", "LastModified": "datetime" }, @@ -1915,7 +1900,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3::test_set_external_hostname": { - "recorded-date": "17-03-2025, 21:30:10", + "recorded-date": "21-02-2026, 00:23:06", "recorded-content": { "multipart-upload": { "Bucket": "", @@ -1946,7 +1931,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3::test_s3_lambda_integration": { - "recorded-date": "21-01-2025, 18:34:07", + "recorded-date": "21-02-2026, 00:23:21", "recorded-content": { "head_object": { "AcceptRanges": "bytes", @@ -1964,7 +1949,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3::test_s3_uppercase_bucket_name": { - "recorded-date": "21-01-2025, 18:34:09", + "recorded-date": "21-02-2026, 00:23:23", "recorded-content": { "uppercase-bucket": { "Error": { @@ -1980,7 +1965,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3::test_create_bucket_with_existing_name": { - "recorded-date": "21-01-2025, 18:34:10", + "recorded-date": "21-02-2026, 00:23:25", "recorded-content": { "create-bucket-us-west-1": { "Error": { @@ -2007,7 +1992,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3::test_bucket_does_not_exist": { - "recorded-date": "21-01-2025, 18:34:13", + "recorded-date": "21-02-2026, 00:23:31", "recorded-content": { "list_object": { "Error": { @@ -2034,9 +2019,10 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3::test_create_bucket_head_bucket": { - "recorded-date": "21-01-2025, 18:34:17", + "recorded-date": "21-02-2026, 00:23:35", "recorded-content": { "create_bucket": { + "BucketArn": "arn::s3:::", "Location": "/", "ResponseMetadata": { "HTTPHeaders": {}, @@ -2044,6 +2030,7 @@ } }, "create_bucket_location_constraint": { + "BucketArn": "arn::s3:::", "Location": "http://./", "ResponseMetadata": { "HTTPHeaders": {}, @@ -2052,6 +2039,7 @@ }, "head_bucket": { "AccessPointAlias": false, + "BucketArn": "arn::s3:::", "BucketRegion": "", "ResponseMetadata": { "HTTPHeaders": {}, @@ -2061,12 +2049,14 @@ "head_bucket_filtered_header": { "content-type": "application/xml", "x-amz-access-point-alias": "false", + "x-amz-bucket-arn": "arn::s3:::", "x-amz-bucket-region": "", "x-amz-id-2": "x-amz-id-2", "x-amz-request-id": "x-amz-request-id" }, "head_bucket_2": { "AccessPointAlias": false, + "BucketArn": "arn::s3:::", "BucketRegion": "", "ResponseMetadata": { "HTTPHeaders": {}, @@ -2076,6 +2066,7 @@ "head_bucket_2_filtered_header": { "content-type": "application/xml", "x-amz-access-point-alias": "false", + "x-amz-bucket-arn": "arn::s3:::", "x-amz-bucket-region": "", "x-amz-id-2": "x-amz-id-2", "x-amz-request-id": "x-amz-request-id" @@ -2093,7 +2084,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3::test_bucket_name_with_dots": { - "recorded-date": "21-01-2025, 18:34:19", + "recorded-date": "21-02-2026, 00:23:37", "recorded-content": { "list-objects": { "Contents": [ @@ -2106,7 +2097,6 @@ "Key": "my-content", "LastModified": "datetime", "Owner": { - "DisplayName": "", "ID": "" }, "Size": 9, @@ -2165,7 +2155,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3::test_s3_put_more_than_1000_items": { - "recorded-date": "21-01-2025, 18:38:06", + "recorded-date": "21-02-2026, 00:27:23", "recorded-content": { "get_object-1009": { "AcceptRanges": "bytes", @@ -2225,7 +2215,6 @@ "Key": "test-key-990", "LastModified": "datetime", "Owner": { - "DisplayName": "", "ID": "" }, "Size": 8, @@ -2240,7 +2229,6 @@ "Key": "test-key-991", "LastModified": "datetime", "Owner": { - "DisplayName": "", "ID": "" }, "Size": 8, @@ -2255,7 +2243,6 @@ "Key": "test-key-992", "LastModified": "datetime", "Owner": { - "DisplayName": "", "ID": "" }, "Size": 8, @@ -2270,7 +2257,6 @@ "Key": "test-key-993", "LastModified": "datetime", "Owner": { - "DisplayName": "", "ID": "" }, "Size": 8, @@ -2285,7 +2271,6 @@ "Key": "test-key-994", "LastModified": "datetime", "Owner": { - "DisplayName": "", "ID": "" }, "Size": 8, @@ -2300,7 +2285,6 @@ "Key": "test-key-995", "LastModified": "datetime", "Owner": { - "DisplayName": "", "ID": "" }, "Size": 8, @@ -2315,7 +2299,6 @@ "Key": "test-key-996", "LastModified": "datetime", "Owner": { - "DisplayName": "", "ID": "" }, "Size": 8, @@ -2330,7 +2313,6 @@ "Key": "test-key-997", "LastModified": "datetime", "Owner": { - "DisplayName": "", "ID": "" }, "Size": 8, @@ -2345,7 +2327,6 @@ "Key": "test-key-998", "LastModified": "datetime", "Owner": { - "DisplayName": "", "ID": "" }, "Size": 8, @@ -2360,7 +2341,6 @@ "Key": "test-key-999", "LastModified": "datetime", "Owner": { - "DisplayName": "", "ID": "" }, "Size": 8, @@ -2381,7 +2361,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3::test_upload_big_file": { - "recorded-date": "21-01-2025, 18:39:01", + "recorded-date": "21-02-2026, 00:27:29", "recorded-content": { "put_object_key1": { "ChecksumCRC32": "eH3dJA==", @@ -2432,7 +2412,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3::test_get_bucket_versioning_order": { - "recorded-date": "21-01-2025, 18:39:04", + "recorded-date": "21-02-2026, 00:27:32", "recorded-content": { "list_object_versions_before": { "EncodingType": "url", @@ -2479,7 +2459,6 @@ "Key": "test", "LastModified": "datetime", "Owner": { - "DisplayName": "", "ID": "" }, "Size": 4, @@ -2496,7 +2475,6 @@ "Key": "test", "LastModified": "datetime", "Owner": { - "DisplayName": "", "ID": "" }, "Size": 4, @@ -2513,7 +2491,6 @@ "Key": "test2", "LastModified": "datetime", "Owner": { - "DisplayName": "", "ID": "" }, "Size": 4, @@ -2529,7 +2506,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3::test_etag_on_get_object_call": { - "recorded-date": "21-01-2025, 18:39:07", + "recorded-date": "21-02-2026, 00:27:34", "recorded-content": { "get_object": { "AcceptRanges": "bytes", @@ -2565,7 +2542,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3::test_s3_delete_object_with_version_id": { - "recorded-date": "21-01-2025, 18:39:10", + "recorded-date": "21-02-2026, 00:27:38", "recorded-content": { "get_bucket_versioning": { "Status": "Enabled", @@ -2605,7 +2582,6 @@ "Key": "aws/s3/testkey2.txt", "LastModified": "datetime", "Owner": { - "DisplayName": "", "ID": "" }, "Size": 960, @@ -2632,7 +2608,7 @@ "recorded-content": {} }, "tests/aws/services/s3/test_s3.py::TestS3::test_s3_batch_delete_public_objects_using_requests": { - "recorded-date": "21-01-2025, 19:48:17", + "recorded-date": "21-02-2026, 00:27:47", "recorded-content": { "multi-delete-with-requests": { "DeleteResult": { @@ -2662,7 +2638,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3::test_s3_batch_delete_objects": { - "recorded-date": "21-01-2025, 18:39:22", + "recorded-date": "21-02-2026, 00:27:50", "recorded-content": { "batch-delete": { "Deleted": [ @@ -2702,7 +2678,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3PresignedUrl::test_put_object": { - "recorded-date": "17-03-2025, 21:31:27", + "recorded-date": "21-02-2026, 00:29:26", "recorded-content": { "get_object": { "AcceptRanges": "bytes", @@ -2723,11 +2699,12 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3PresignedUrl::test_s3_copy_md5": { - "recorded-date": "21-01-2025, 18:24:04", + "recorded-date": "21-02-2026, 00:30:50", "recorded-content": { "copy-obj": { "CopyObjectResult": { "ChecksumCRC32": "Cdox+w==", + "ChecksumType": "FULL_OBJECT", "ETag": "\"437b930db84b8079c2dd804a71936b5f\"", "LastModified": "datetime" }, @@ -2740,7 +2717,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3DeepArchive::test_s3_get_deep_archive_object_restore": { - "recorded-date": "14-08-2023, 22:35:53", + "recorded-date": "21-02-2026, 00:32:22", "recorded-content": { "get-object-invalid-state": { "Error": { @@ -2775,7 +2752,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3::test_head_object_fields": { - "recorded-date": "21-01-2025, 18:28:10", + "recorded-date": "21-02-2026, 00:18:52", "recorded-content": { "head-object": { "AcceptRanges": "bytes", @@ -2803,13 +2780,12 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3::test_s3_bucket_acl": { - "recorded-date": "21-01-2025, 18:30:17", + "recorded-date": "21-02-2026, 00:20:36", "recorded-content": { "get-bucket-acl": { "Grants": [ { "Grantee": { - "DisplayName": "", "ID": "", "Type": "CanonicalUser" }, @@ -2824,7 +2800,6 @@ } ], "Owner": { - "DisplayName": "", "ID": "" }, "ResponseMetadata": { @@ -2836,7 +2811,6 @@ "Grants": [ { "Grantee": { - "DisplayName": "", "ID": "", "Type": "CanonicalUser" }, @@ -2844,7 +2818,6 @@ } ], "Owner": { - "DisplayName": "", "ID": "" }, "ResponseMetadata": { @@ -2863,7 +2836,6 @@ } ], "Owner": { - "DisplayName": "", "ID": "" }, "ResponseMetadata": { @@ -2875,7 +2847,6 @@ "Grants": [ { "Grantee": { - "DisplayName": "", "ID": "", "Type": "CanonicalUser" }, @@ -2890,7 +2861,6 @@ } ], "Owner": { - "DisplayName": "", "ID": "" }, "ResponseMetadata": { @@ -2901,7 +2871,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3::test_s3_bucket_acl_exceptions": { - "recorded-date": "21-01-2025, 18:30:22", + "recorded-date": "21-02-2026, 00:20:41", "recorded-content": { "put-bucket-canned-acl": { "Error": { @@ -3061,7 +3031,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3::test_s3_get_object_header_overrides": { - "recorded-date": "21-01-2025, 18:39:23", + "recorded-date": "21-02-2026, 00:27:51", "recorded-content": { "get-object": { "AcceptRanges": "bytes", @@ -3088,7 +3058,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3::test_s3_put_object_versioned": { - "recorded-date": "21-01-2025, 18:39:15", + "recorded-date": "21-02-2026, 00:27:43", "recorded-content": { "put-pre-versioned": { "ChecksumCRC32": "uQZ0CQ==", @@ -3135,7 +3105,6 @@ "Key": "non-version-bucket-key", "LastModified": "datetime", "Owner": { - "DisplayName": "", "ID": "" }, "Size": 17, @@ -3223,7 +3192,6 @@ "Key": "non-version-bucket-key", "LastModified": "datetime", "Owner": { - "DisplayName": "", "ID": "" }, "Size": 17, @@ -3240,7 +3208,6 @@ "Key": "versioned-bucket-key", "LastModified": "datetime", "Owner": { - "DisplayName": "", "ID": "" }, "Size": 21, @@ -3257,7 +3224,6 @@ "Key": "versioned-bucket-key", "LastModified": "datetime", "Owner": { - "DisplayName": "", "ID": "" }, "Size": 13, @@ -3289,7 +3255,6 @@ "Key": "non-version-bucket-key", "LastModified": "datetime", "Owner": { - "DisplayName": "", "ID": "" }, "Size": 17, @@ -3306,7 +3271,6 @@ "Key": "versioned-bucket-key", "LastModified": "datetime", "Owner": { - "DisplayName": "", "ID": "" }, "Size": 21, @@ -3323,7 +3287,6 @@ "Key": "versioned-bucket-key", "LastModified": "datetime", "Owner": { - "DisplayName": "", "ID": "" }, "Size": 13, @@ -3400,7 +3363,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3PresignedUrl::test_put_object_with_md5_and_chunk_signature_bad_headers[s3-True]": { - "recorded-date": "21-01-2025, 18:23:05", + "recorded-date": "21-02-2026, 00:29:51", "recorded-content": { "with-decoded-content-length": { "Error": { @@ -3429,11 +3392,11 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3PresignedUrl::test_put_object_with_md5_and_chunk_signature_bad_headers[s3-False]": { - "recorded-date": "21-01-2025, 18:23:07", + "recorded-date": "21-02-2026, 00:29:53", "recorded-content": {} }, "tests/aws/services/s3/test_s3.py::TestS3PresignedUrl::test_put_object_with_md5_and_chunk_signature_bad_headers[s3v4-True]": { - "recorded-date": "21-01-2025, 18:23:09", + "recorded-date": "21-02-2026, 00:29:55", "recorded-content": { "with-decoded-content-length": { "Error": { @@ -3456,11 +3419,11 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3PresignedUrl::test_put_object_with_md5_and_chunk_signature_bad_headers[s3v4-False]": { - "recorded-date": "21-01-2025, 18:23:10", + "recorded-date": "21-02-2026, 00:29:57", "recorded-content": {} }, "tests/aws/services/s3/test_s3.py::TestS3PresignedUrl::test_s3_presigned_url_expired[s3]": { - "recorded-date": "21-01-2025, 18:23:17", + "recorded-date": "21-02-2026, 00:30:04", "recorded-content": { "expired-exception": { "Error": { @@ -3475,7 +3438,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3PresignedUrl::test_s3_presigned_url_expired[s3v4]": { - "recorded-date": "21-01-2025, 18:23:23", + "recorded-date": "21-02-2026, 00:30:09", "recorded-content": { "expired-exception": { "Error": { @@ -3491,7 +3454,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3PresignedUrl::test_presigned_url_signature_authentication_expired[s3-False]": { - "recorded-date": "21-01-2025, 18:24:08", + "recorded-date": "21-02-2026, 00:30:54", "recorded-content": { "expired": { "Error": { @@ -3506,7 +3469,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3PresignedUrl::test_presigned_url_signature_authentication_expired[s3-True]": { - "recorded-date": "21-01-2025, 18:24:12", + "recorded-date": "21-02-2026, 00:30:58", "recorded-content": { "expired": { "Error": { @@ -3521,7 +3484,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3PresignedUrl::test_presigned_url_signature_authentication_expired[s3v4-False]": { - "recorded-date": "21-01-2025, 18:24:16", + "recorded-date": "21-02-2026, 00:31:02", "recorded-content": { "expired": { "Error": { @@ -3537,7 +3500,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3PresignedUrl::test_presigned_url_signature_authentication_expired[s3v4-True]": { - "recorded-date": "21-01-2025, 18:24:20", + "recorded-date": "21-02-2026, 00:31:06", "recorded-content": { "expired": { "Error": { @@ -3553,7 +3516,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3PresignedUrl::test_presigned_url_signature_authentication[s3-False]": { - "recorded-date": "21-01-2025, 18:24:24", + "recorded-date": "21-02-2026, 00:31:10", "recorded-content": { "invalid-get-1": { "Error": { @@ -3582,7 +3545,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3PresignedUrl::test_presigned_url_signature_authentication[s3-True]": { - "recorded-date": "21-01-2025, 18:24:28", + "recorded-date": "21-02-2026, 00:31:14", "recorded-content": { "invalid-get-1": { "Error": { @@ -3611,7 +3574,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3PresignedUrl::test_presigned_url_signature_authentication[s3v4-False]": { - "recorded-date": "21-01-2025, 18:24:31", + "recorded-date": "21-02-2026, 00:31:18", "recorded-content": { "invalid-get-1": { "Error": { @@ -3644,7 +3607,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3PresignedUrl::test_presigned_url_signature_authentication[s3v4-True]": { - "recorded-date": "21-01-2025, 18:24:35", + "recorded-date": "21-02-2026, 00:31:21", "recorded-content": { "invalid-get-1": { "Error": { @@ -3677,7 +3640,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3PresignedUrl::test_s3_put_presigned_url_missing_sig_param[s3]": { - "recorded-date": "21-01-2025, 18:23:35", + "recorded-date": "21-02-2026, 00:30:22", "recorded-content": { "missing-param-exception": { "Error": { @@ -3691,7 +3654,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3PresignedUrl::test_s3_put_presigned_url_missing_sig_param[s3v4]": { - "recorded-date": "21-01-2025, 18:23:37", + "recorded-date": "21-02-2026, 00:30:24", "recorded-content": { "missing-param-exception": { "Error": { @@ -3705,7 +3668,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3PresignedUrl::test_s3_put_presigned_url_with_different_headers[s3]": { - "recorded-date": "21-01-2025, 18:23:27", + "recorded-date": "21-02-2026, 00:30:14", "recorded-content": { "content-type-exception": { "Error": { @@ -3739,7 +3702,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3PresignedUrl::test_s3_put_presigned_url_with_different_headers[s3v4]": { - "recorded-date": "21-01-2025, 18:23:31", + "recorded-date": "21-02-2026, 00:30:17", "recorded-content": { "content-type-exception": { "Error": { @@ -3777,7 +3740,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3PresignedUrl::test_s3_put_presigned_url_same_header_and_qs_parameter": { - "recorded-date": "21-01-2025, 18:23:33", + "recorded-date": "21-02-2026, 00:30:20", "recorded-content": { "double-header-query-string": { "Error": { @@ -3807,7 +3770,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3PresignedPost::test_post_request_expires": { - "recorded-date": "17-03-2025, 20:16:24", + "recorded-date": "21-02-2026, 00:35:25", "recorded-content": { "exception": { "Error": { @@ -3821,7 +3784,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3PresignedPost::test_post_request_malformed_policy[s3]": { - "recorded-date": "17-03-2025, 20:16:26", + "recorded-date": "21-02-2026, 00:35:27", "recorded-content": { "exception-policy": { "Error": { @@ -3839,7 +3802,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3PresignedPost::test_post_request_malformed_policy[s3v4]": { - "recorded-date": "17-03-2025, 20:16:27", + "recorded-date": "21-02-2026, 00:35:28", "recorded-content": { "exception-policy": { "Error": { @@ -3857,7 +3820,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3PresignedPost::test_post_request_missing_signature[s3]": { - "recorded-date": "17-03-2025, 20:16:29", + "recorded-date": "21-02-2026, 00:35:30", "recorded-content": { "exception-missing-signature": { "Error": { @@ -3873,7 +3836,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3PresignedPost::test_post_request_missing_signature[s3v4]": { - "recorded-date": "17-03-2025, 20:16:30", + "recorded-date": "21-02-2026, 00:35:31", "recorded-content": { "exception-missing-signature": { "Error": { @@ -3889,7 +3852,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3PresignedPost::test_post_request_missing_fields[s3]": { - "recorded-date": "17-03-2025, 20:16:32", + "recorded-date": "21-02-2026, 00:35:33", "recorded-content": { "exception-missing-fields": { "Error": { @@ -3914,7 +3877,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3PresignedPost::test_post_request_missing_fields[s3v4]": { - "recorded-date": "17-03-2025, 20:16:34", + "recorded-date": "21-02-2026, 00:35:35", "recorded-content": { "exception-missing-fields": { "Error": { @@ -3939,7 +3902,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3StaticWebsiteHosting::test_validate_website_configuration": { - "recorded-date": "26-08-2023, 00:30:03", + "recorded-date": "21-02-2026, 00:33:06", "recorded-content": { "invalid-website-conf-0": { "Error": { @@ -4032,7 +3995,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3StaticWebsiteHosting::test_crud_website_configuration": { - "recorded-date": "26-08-2023, 00:29:24", + "recorded-date": "21-02-2026, 00:33:08", "recorded-content": { "get-no-such-website-config": { "Error": { @@ -4069,7 +4032,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3StaticWebsiteHosting::test_website_hosting_http_methods": { - "recorded-date": "26-08-2023, 00:30:55", + "recorded-date": "21-02-2026, 00:32:36", "recorded-content": { "not-allowed-post": { "content": "\n405 Method Not Allowed\n\n

405 Method Not Allowed

\n
    \n
  • Code: MethodNotAllowed
  • \n
  • Message: The specified method is not allowed against this resource.
  • \n
  • Method: POST
  • \n
  • ResourceType: OBJECT
  • \n
  • RequestId:
  • \n
  • HostId:
  • \n
\n
\n\n\n" @@ -4080,21 +4043,21 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3StaticWebsiteHosting::test_website_hosting_index_lookup": { - "recorded-date": "26-08-2023, 00:31:15", + "recorded-date": "21-02-2026, 00:32:40", "recorded-content": { "404-no-trailing-slash": "\n404 Not Found\n\n

404 Not Found

\n
    \n
  • Code: NoSuchKey
  • \n
  • Message: The specified key does not exist.
  • \n
  • Key: directory-wrong
  • \n
  • RequestId:
  • \n
  • HostId:
  • \n
\n
\n\n\n", "404-with-trailing-slash": "\n404 Not Found\n\n

404 Not Found

\n
    \n
  • Code: NoSuchKey
  • \n
  • Message: The specified key does not exist.
  • \n
  • Key: directory-wrong/index.html
  • \n
  • RequestId:
  • \n
  • HostId:
  • \n
\n
\n\n\n" } }, "tests/aws/services/s3/test_s3.py::TestS3StaticWebsiteHosting::test_website_hosting_404": { - "recorded-date": "26-08-2023, 00:30:33", + "recorded-date": "21-02-2026, 00:32:43", "recorded-content": { "404-no-such-key": "\n404 Not Found\n\n

404 Not Found

\n
    \n
  • Code: NoSuchKey
  • \n
  • Message: The specified key does not exist.
  • \n
  • Key: index.html
  • \n
  • RequestId:
  • \n
  • HostId:
  • \n
\n
\n\n\n", "404-no-such-key-nor-custom": "\n404 Not Found\n\n

404 Not Found

\n
    \n
  • Code: NoSuchKey
  • \n
  • Message: The specified key does not exist.
  • \n
  • Key: index.html
  • \n
  • RequestId:
  • \n
  • HostId:
  • \n
\n

An Error Occurred While Attempting to Retrieve a Custom Error Document

\n
    \n
  • Code: NoSuchKey
  • \n
  • Message: The specified key does not exist.
  • \n
  • Key: error.html
  • \n
\n
\n\n\n" } }, "tests/aws/services/s3/test_s3.py::TestS3StaticWebsiteHosting::test_website_hosting_no_such_website": { - "recorded-date": "26-08-2023, 00:31:30", + "recorded-date": "21-02-2026, 00:32:33", "recorded-content": { "no-such-bucket": "\n404 Not Found\n\n

404 Not Found

\n
    \n
  • Code: NoSuchBucket
  • \n
  • Message: The specified bucket does not exist
  • \n
  • BucketName:
  • \n
  • RequestId:
  • \n
  • HostId:
  • \n
\n
\n\n\n", "no-such-website-config": "\n404 Not Found\n\n

404 Not Found

\n
    \n
  • Code: NoSuchWebsiteConfiguration
  • \n
  • Message: The specified bucket does not have a website configuration
  • \n
  • BucketName:
  • \n
  • RequestId:
  • \n
  • HostId:
  • \n
\n
\n\n\n", @@ -4102,7 +4065,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3::test_multipart_and_list_parts": { - "recorded-date": "17-03-2025, 21:28:50", + "recorded-date": "21-02-2026, 00:18:10", "recorded-content": { "create-multipart": { "Bucket": "bucket", @@ -4125,7 +4088,6 @@ "MaxParts": 1000, "NextPartNumberMarker": 0, "Owner": { - "DisplayName": "display-name", "ID": "owner-id" }, "PartNumberMarker": 0, @@ -4153,7 +4115,6 @@ }, "Key": "test-list-parts", "Owner": { - "DisplayName": "display-name", "ID": "owner-id" }, "StorageClass": "STANDARD", @@ -4185,7 +4146,6 @@ "MaxParts": 1000, "NextPartNumberMarker": 1, "Owner": { - "DisplayName": "display-name", "ID": "owner-id" }, "PartNumberMarker": 0, @@ -4221,7 +4181,6 @@ }, "Key": "test-list-parts", "Owner": { - "DisplayName": "display-name", "ID": "owner-id" }, "StorageClass": "STANDARD", @@ -4304,7 +4263,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3::test_put_and_get_object_with_content_language_disposition": { - "recorded-date": "21-01-2025, 18:26:29", + "recorded-date": "21-02-2026, 00:17:04", "recorded-content": { "put-object": { "ChecksumCRC32": "zwK7XA==", @@ -4379,7 +4338,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3::test_copy_object_kms": { - "recorded-date": "21-01-2025, 18:26:17", + "recorded-date": "21-02-2026, 00:16:52", "recorded-content": { "get-object": { "AcceptRanges": "bytes", @@ -4401,6 +4360,7 @@ "BucketKeyEnabled": true, "CopyObjectResult": { "ChecksumCRC32": "DUoRhQ==", + "ChecksumType": "FULL_OBJECT", "ETag": "copy-etag", "LastModified": "datetime" }, @@ -4432,7 +4392,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3BucketReplication::test_replication_config": { - "recorded-date": "29-08-2024, 14:09:55", + "recorded-date": "21-02-2026, 00:35:17", "recorded-content": { "expected_error_no_replication_set": { "Error": { @@ -4511,7 +4471,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3::test_delete_non_existing_keys_quiet": { - "recorded-date": "21-01-2025, 18:31:30", + "recorded-date": "21-02-2026, 00:21:28", "recorded-content": { "deleted-resp": { "ResponseMetadata": { @@ -4522,7 +4482,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3BucketReplication::test_replication_config_without_filter": { - "recorded-date": "03-08-2023, 04:13:02", + "recorded-date": "21-02-2026, 00:35:10", "recorded-content": { "expected_error_dest_does_not_exist": { "Error": { @@ -4589,12 +4549,13 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3::test_s3_sse_validate_kms_key": { - "recorded-date": "21-01-2025, 18:39:28", + "recorded-date": "21-02-2026, 00:27:56", "recorded-content": { "create-kms-key": { "AWSAccountId": "111111111111", "Arn": "arn::kms::111111111111:key/", "CreationDate": "datetime", + "CurrentKeyMaterialId": "", "CustomerMasterKeySpec": "SYMMETRIC_DEFAULT", "Description": "", "Enabled": true, @@ -4682,7 +4643,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3::test_complete_multipart_parts_order": { - "recorded-date": "17-03-2025, 21:30:44", + "recorded-date": "21-02-2026, 00:28:13", "recorded-content": { "upload-part-negative-part-number": { "Error": { @@ -4736,7 +4697,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3::test_put_object_storage_class[STANDARD-True]": { - "recorded-date": "21-01-2025, 18:41:18", + "recorded-date": "21-02-2026, 00:28:15", "recorded-content": { "get-object-storage-class": { "LastModified": "datetime", @@ -4765,7 +4726,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3::test_put_object_storage_class[STANDARD_IA-True]": { - "recorded-date": "21-01-2025, 18:41:20", + "recorded-date": "21-02-2026, 00:28:17", "recorded-content": { "get-object-storage-class": { "LastModified": "datetime", @@ -4795,7 +4756,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3::test_put_object_storage_class[GLACIER-False]": { - "recorded-date": "21-01-2025, 18:41:22", + "recorded-date": "21-02-2026, 00:28:19", "recorded-content": { "get-object-storage-class": { "LastModified": "datetime", @@ -4820,7 +4781,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3::test_put_object_storage_class[GLACIER_IR-True]": { - "recorded-date": "21-01-2025, 18:41:24", + "recorded-date": "21-02-2026, 00:28:21", "recorded-content": { "get-object-storage-class": { "LastModified": "datetime", @@ -4850,7 +4811,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3::test_put_object_storage_class[ONEZONE_IA-True]": { - "recorded-date": "21-01-2025, 18:41:28", + "recorded-date": "21-02-2026, 00:28:25", "recorded-content": { "get-object-storage-class": { "LastModified": "datetime", @@ -4880,7 +4841,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3::test_put_object_storage_class[INTELLIGENT_TIERING-True]": { - "recorded-date": "21-01-2025, 18:41:30", + "recorded-date": "21-02-2026, 00:28:27", "recorded-content": { "get-object-storage-class": { "LastModified": "datetime", @@ -4910,7 +4871,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3::test_put_object_storage_class[DEEP_ARCHIVE-False]": { - "recorded-date": "21-01-2025, 18:41:32", + "recorded-date": "21-02-2026, 00:28:29", "recorded-content": { "get-object-storage-class": { "LastModified": "datetime", @@ -4935,7 +4896,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3::test_put_object_storage_class[REDUCED_REDUNDANCY-True]": { - "recorded-date": "21-01-2025, 18:41:26", + "recorded-date": "21-02-2026, 00:28:23", "recorded-content": { "get-object-storage-class": { "LastModified": "datetime", @@ -4965,7 +4926,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3::test_put_object_storage_class_outposts": { - "recorded-date": "21-01-2025, 18:41:34", + "recorded-date": "21-02-2026, 00:28:31", "recorded-content": { "put-object-outposts": { "Error": { @@ -4992,7 +4953,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3PutObjectChecksum::test_s3_get_object_checksum[SHA256]": { - "recorded-date": "17-03-2025, 18:28:54", + "recorded-date": "21-02-2026, 00:38:16", "recorded-content": { "put-object": { "ChecksumSHA256": "1YQo81vx2VFUl0q5ccWISq8AkSBQQ0WO80S82TmfdIQ=", @@ -5066,7 +5027,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3PutObjectChecksum::test_s3_get_object_checksum[None]": { - "recorded-date": "17-03-2025, 18:29:00", + "recorded-date": "21-02-2026, 00:38:22", "recorded-content": { "put-object": { "ChecksumCRC32": "lVk/nw==", @@ -5140,7 +5101,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3PutObjectChecksum::test_s3_checksum_with_content_encoding": { - "recorded-date": "17-03-2025, 18:29:02", + "recorded-date": "21-02-2026, 00:38:24", "recorded-content": { "put-object": { "ChecksumSHA256": "WO7lLNG8Mn/d4GkX4DqZXqeaVHJCN+BxvMNJXLOhukg=", @@ -5200,12 +5161,12 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3MultipartUploadChecksum::test_multipart_parts_checksum_exceptions_composite": { - "recorded-date": "15-06-2025, 17:11:24", + "recorded-date": "21-02-2026, 00:40:43", "recorded-content": { "create-mpu-wrong-checksum-algo": { "Error": { "Code": "InvalidRequest", - "Message": "Checksum algorithm provided is unsupported. Please try again with any of the valid types: [CRC32, CRC32C, SHA1, SHA256]" + "Message": "Checksum algorithm provided is unsupported. Please try again with any of the valid types: [CRC32, CRC32C, CRC64NVME, SHA1, SHA256]" }, "ResponseMetadata": { "HTTPHeaders": {}, @@ -5253,7 +5214,6 @@ }, "Key": "test-multipart-checksum-exc", "Owner": { - "DisplayName": "display-name", "ID": "i-d" }, "StorageClass": "STANDARD", @@ -5319,12 +5279,13 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3::test_s3_sse_validate_kms_key_state": { - "recorded-date": "21-01-2025, 18:39:38", + "recorded-date": "21-02-2026, 00:28:06", "recorded-content": { "create-kms-key": { "AWSAccountId": "111111111111", "Arn": "arn::kms::111111111111:key/", "CreationDate": "datetime", + "CurrentKeyMaterialId": "", "CustomerMasterKeySpec": "SYMMETRIC_DEFAULT", "Description": "", "Enabled": true, @@ -5342,7 +5303,7 @@ "success-put-object-sse": { "ChecksumCRC32": "KHcEKQ==", "ChecksumType": "FULL_OBJECT", - "ETag": "\"e1ae6a8d27c2b77e7dcd9b4c8a3b579d\"", + "ETag": "\"82d933006b334fd100179a6307217cce\"", "SSEKMSKeyId": "arn::kms::111111111111:key/", "ServerSideEncryption": "aws:kms", "ResponseMetadata": { @@ -5357,7 +5318,7 @@ "ChecksumType": "FULL_OBJECT", "ContentLength": 8, "ContentType": "binary/octet-stream", - "ETag": "\"e1ae6a8d27c2b77e7dcd9b4c8a3b579d\"", + "ETag": "\"82d933006b334fd100179a6307217cce\"", "LastModified": "datetime", "Metadata": {}, "SSEKMSKeyId": "arn::kms::111111111111:key/", @@ -5400,7 +5361,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3::test_delete_keys_in_versioned_bucket": { - "recorded-date": "21-01-2025, 18:31:34", + "recorded-date": "21-02-2026, 00:21:33", "recorded-content": { "list-objects-v2": { "Contents": [ @@ -5447,7 +5408,6 @@ "Key": "test-key-versioned", "LastModified": "datetime", "Owner": { - "DisplayName": "", "ID": "" }, "VersionId": "" @@ -5471,7 +5431,6 @@ "Key": "test-key-versioned", "LastModified": "datetime", "Owner": { - "DisplayName": "", "ID": "" }, "Size": 12, @@ -5488,7 +5447,6 @@ "Key": "test-key-versioned", "LastModified": "datetime", "Owner": { - "DisplayName": "", "ID": "" }, "Size": 9, @@ -5505,11 +5463,11 @@ "Deleted": [ { "Key": "test-key-versioned", - "VersionId": "" + "VersionId": "" }, { "Key": "test-key-versioned", - "VersionId": "" + "VersionId": "" } ], "ResponseMetadata": { @@ -5536,7 +5494,6 @@ "Key": "test-key-versioned", "LastModified": "datetime", "Owner": { - "DisplayName": "", "ID": "" }, "VersionId": "" @@ -5571,7 +5528,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3::test_put_object_acl_on_delete_marker": { - "recorded-date": "21-01-2025, 18:31:40", + "recorded-date": "21-02-2026, 00:21:38", "recorded-content": { "put-obj-1": { "ChecksumCRC32": "Cdox+w==", @@ -5653,7 +5610,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3::test_get_object_attributes_versioned": { - "recorded-date": "21-01-2025, 18:27:33", + "recorded-date": "21-02-2026, 00:18:07", "recorded-content": { "put-obj-v1": { "ChecksumCRC32": "WC+ANw==", @@ -5846,7 +5803,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3::test_s3_multipart_upload_sse": { - "recorded-date": "17-03-2025, 21:31:09", + "recorded-date": "21-02-2026, 00:28:49", "recorded-content": { "multi-sse-create-multipart": { "Bucket": "", @@ -5863,7 +5820,7 @@ "multi-sse-upload-part": { "BucketKeyEnabled": true, "ChecksumCRC32": "KHcEKQ==", - "ETag": "\"f14c3faa9237b95312866412ecf80f93\"", + "ETag": "\"1a9f0234d9c670a8c2f8b1ceda267641\"", "SSEKMSKeyId": "arn::kms::111111111111:key/", "ServerSideEncryption": "aws:kms", "ResponseMetadata": { @@ -5874,7 +5831,7 @@ "multi-sse-compete-multipart": { "Bucket": "", "BucketKeyEnabled": true, - "ETag": "\"a35f284c9ce41d60640bd70f8069a276-1\"", + "ETag": "\"93a0cb8ec20934211e19adabef9a6407-1\"", "Key": "test-sse-field-multipart", "Location": "", "SSEKMSKeyId": "arn::kms::111111111111:key/", @@ -5892,7 +5849,7 @@ "ChecksumType": "FULL_OBJECT", "ContentLength": 8, "ContentType": "binary/octet-stream", - "ETag": "\"a35f284c9ce41d60640bd70f8069a276-1\"", + "ETag": "\"93a0cb8ec20934211e19adabef9a6407-1\"", "LastModified": "datetime", "Metadata": {}, "SSEKMSKeyId": "arn::kms::111111111111:key/", @@ -5905,7 +5862,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3::test_s3_sse_bucket_key_default": { - "recorded-date": "21-01-2025, 18:42:37", + "recorded-date": "21-02-2026, 00:28:53", "recorded-content": { "put-obj-default-before-setting": { "ChecksumCRC32": "KHcEKQ==", @@ -5976,7 +5933,7 @@ "BucketKeyEnabled": true, "ChecksumCRC32": "KHcEKQ==", "ChecksumType": "FULL_OBJECT", - "ETag": "\"7ebdc638d81c4fcc1479f682db3c21d3\"", + "ETag": "\"69a4214580de172e3b6dbfaf0b1aaf4a\"", "SSEKMSKeyId": "arn::kms::111111111111:key/", "ServerSideEncryption": "aws:kms", "ResponseMetadata": { @@ -5992,7 +5949,7 @@ "ChecksumType": "FULL_OBJECT", "ContentLength": 8, "ContentType": "binary/octet-stream", - "ETag": "\"7ebdc638d81c4fcc1479f682db3c21d3\"", + "ETag": "\"69a4214580de172e3b6dbfaf0b1aaf4a\"", "LastModified": "datetime", "Metadata": {}, "SSEKMSKeyId": "arn::kms::111111111111:key/", @@ -6005,10 +5962,12 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3::test_s3_sse_default_kms_key": { - "recorded-date": "03-04-2023, 22:16:19", + "recorded-date": "21-02-2026, 00:43:37", "recorded-content": { "put-obj-default-kms-s3-key": { - "ETag": "\"dbcc38f7b88c4c92ee5f9484d181ff51\"", + "ChecksumCRC32": "KHcEKQ==", + "ChecksumType": "FULL_OBJECT", + "ETag": "\"8c4f00a5f79a9d26aaf8462d148bd5bf\"", "SSEKMSKeyId": "arn::kms::111111111111:key/", "ServerSideEncryption": "aws:kms", "ResponseMetadata": { @@ -6019,9 +5978,11 @@ "get-obj-default-kms-s3-key": { "AcceptRanges": "bytes", "Body": "test-sse", + "ChecksumCRC32": "KHcEKQ==", + "ChecksumType": "FULL_OBJECT", "ContentLength": 8, "ContentType": "binary/octet-stream", - "ETag": "\"dbcc38f7b88c4c92ee5f9484d181ff51\"", + "ETag": "\"8c4f00a5f79a9d26aaf8462d148bd5bf\"", "LastModified": "datetime", "Metadata": {}, "SSEKMSKeyId": "arn::kms::111111111111:key/", @@ -6032,7 +5993,9 @@ } }, "put-obj-default-kms-s3-key-bucket-2": { - "ETag": "\"9c8f3cc18cd06e60966725b1c5996554\"", + "ChecksumCRC32": "KHcEKQ==", + "ChecksumType": "FULL_OBJECT", + "ETag": "\"59252a09a794c20170ced454936d6299\"", "SSEKMSKeyId": "arn::kms::111111111111:key/", "ServerSideEncryption": "aws:kms", "ResponseMetadata": { @@ -6043,9 +6006,11 @@ "get-obj-default-kms-s3-key-bucket-2": { "AcceptRanges": "bytes", "Body": "test-sse", + "ChecksumCRC32": "KHcEKQ==", + "ChecksumType": "FULL_OBJECT", "ContentLength": 8, "ContentType": "binary/octet-stream", - "ETag": "\"9c8f3cc18cd06e60966725b1c5996554\"", + "ETag": "\"59252a09a794c20170ced454936d6299\"", "LastModified": "datetime", "Metadata": {}, "SSEKMSKeyId": "arn::kms::111111111111:key/", @@ -6079,7 +6044,9 @@ }, "put-obj-default-kms-s3-key-from-bucket": { "BucketKeyEnabled": true, - "ETag": "\"671ef6aeba0f69c2391cf0a1b094d0aa\"", + "ChecksumCRC32": "KHcEKQ==", + "ChecksumType": "FULL_OBJECT", + "ETag": "\"8a33ac88b9e72b00c035aac8388183f5\"", "SSEKMSKeyId": "arn::kms::111111111111:key/", "ServerSideEncryption": "aws:kms", "ResponseMetadata": { @@ -6091,9 +6058,11 @@ "AcceptRanges": "bytes", "Body": "test-sse", "BucketKeyEnabled": true, + "ChecksumCRC32": "KHcEKQ==", + "ChecksumType": "FULL_OBJECT", "ContentLength": 8, "ContentType": "binary/octet-stream", - "ETag": "\"671ef6aeba0f69c2391cf0a1b094d0aa\"", + "ETag": "\"8a33ac88b9e72b00c035aac8388183f5\"", "LastModified": "datetime", "Metadata": {}, "SSEKMSKeyId": "arn::kms::111111111111:key/", @@ -6106,7 +6075,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3::test_s3_copy_object_in_place": { - "recorded-date": "21-01-2025, 18:29:17", + "recorded-date": "21-02-2026, 00:19:24", "recorded-content": { "put_object": { "ChecksumCRC32": "MzVIGw==", @@ -6154,6 +6123,7 @@ "copy-object-in-place-with-storage-class": { "CopyObjectResult": { "ChecksumSHA256": "lyTB4g5uPk1/V+0l+dTvsAblCFkNUoyQ2ll/andcE+U=", + "ChecksumType": "FULL_OBJECT", "ETag": "\"88bac95f31528d13a072c05f2a1cf371\"", "LastModified": "datetime" }, @@ -6175,7 +6145,6 @@ "Grants": [ { "Grantee": { - "DisplayName": "", "ID": "", "Type": "CanonicalUser" }, @@ -6183,7 +6152,6 @@ } ], "Owner": { - "DisplayName": "", "ID": "" }, "ResponseMetadata": { @@ -6204,7 +6172,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3::test_s3_copy_object_in_place_metadata_directive": { - "recorded-date": "21-01-2025, 18:29:37", + "recorded-date": "21-02-2026, 00:19:45", "recorded-content": { "put_object": { "ChecksumCRC32": "MzVIGw==", @@ -6244,6 +6212,7 @@ "copy-replace-directive": { "CopyObjectResult": { "ChecksumCRC32": "MzVIGw==", + "ChecksumType": "FULL_OBJECT", "ETag": "\"88bac95f31528d13a072c05f2a1cf371\"", "LastModified": "datetime" }, @@ -6271,6 +6240,7 @@ "copy-copy-directive": { "CopyObjectResult": { "ChecksumCRC32": "MzVIGw==", + "ChecksumType": "FULL_OBJECT", "ETag": "\"88bac95f31528d13a072c05f2a1cf371\"", "LastModified": "datetime" }, @@ -6298,6 +6268,7 @@ "copy-copy-directive-ignore": { "CopyObjectResult": { "ChecksumCRC32": "MzVIGw==", + "ChecksumType": "FULL_OBJECT", "ETag": "\"88bac95f31528d13a072c05f2a1cf371\"", "LastModified": "datetime" }, @@ -6325,6 +6296,7 @@ "copy-replace-directive-empty": { "CopyObjectResult": { "ChecksumCRC32": "MzVIGw==", + "ChecksumType": "FULL_OBJECT", "ETag": "\"88bac95f31528d13a072c05f2a1cf371\"", "LastModified": "datetime" }, @@ -6350,7 +6322,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3::test_s3_copy_object_in_place_storage_class": { - "recorded-date": "21-01-2025, 18:29:28", + "recorded-date": "21-02-2026, 00:19:36", "recorded-content": { "put-object": { "ChecksumCRC32": "2H9+DA==", @@ -6386,6 +6358,7 @@ "copy-object-in-place-with-storage-class": { "CopyObjectResult": { "ChecksumCRC32": "2H9+DA==", + "ChecksumType": "FULL_OBJECT", "ETag": "\"098f6bcd4621d373cade4e832627b4f6\"", "LastModified": "datetime" }, @@ -6406,13 +6379,13 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3::test_s3_copy_object_in_place_with_encryption": { - "recorded-date": "21-01-2025, 18:29:32", + "recorded-date": "21-02-2026, 00:19:40", "recorded-content": { "put-object-with-kms-encryption": { "BucketKeyEnabled": true, "ChecksumCRC32": "2H9+DA==", "ChecksumType": "FULL_OBJECT", - "ETag": "\"526373ef70063d48e68f588bbdfec7ef\"", + "ETag": "\"b00b3bfc95beb7094e6a43eaa2ca08ab\"", "SSEKMSKeyId": "", "ServerSideEncryption": "aws:kms", "ResponseMetadata": { @@ -6425,7 +6398,7 @@ "BucketKeyEnabled": true, "ContentLength": 4, "ContentType": "binary/octet-stream", - "ETag": "\"526373ef70063d48e68f588bbdfec7ef\"", + "ETag": "\"b00b3bfc95beb7094e6a43eaa2ca08ab\"", "LastModified": "datetime", "Metadata": {}, "SSEKMSKeyId": "", @@ -6438,7 +6411,8 @@ "copy-object-in-place-with-sse": { "CopyObjectResult": { "ChecksumCRC32": "2H9+DA==", - "ETag": "\"d83cbdabd3c2ff281f17810fd677232c\"", + "ChecksumType": "FULL_OBJECT", + "ETag": "\"a92b4ea5fde51dc81ab84292dfee0367\"", "LastModified": "datetime" }, "SSEKMSKeyId": "", @@ -6452,7 +6426,7 @@ "AcceptRanges": "bytes", "ContentLength": 4, "ContentType": "binary/octet-stream", - "ETag": "\"d83cbdabd3c2ff281f17810fd677232c\"", + "ETag": "\"a92b4ea5fde51dc81ab84292dfee0367\"", "LastModified": "datetime", "Metadata": {}, "SSEKMSKeyId": "", @@ -6465,6 +6439,7 @@ "copy-object-in-place-without-kms-sse": { "CopyObjectResult": { "ChecksumCRC32": "2H9+DA==", + "ChecksumType": "FULL_OBJECT", "ETag": "\"098f6bcd4621d373cade4e832627b4f6\"", "LastModified": "datetime" }, @@ -6490,6 +6465,7 @@ "copy-object-in-place-with-aes": { "CopyObjectResult": { "ChecksumCRC32": "2H9+DA==", + "ChecksumType": "FULL_OBJECT", "ETag": "\"098f6bcd4621d373cade4e832627b4f6\"", "LastModified": "datetime" }, @@ -6515,7 +6491,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3::test_s3_copy_object_storage_class": { - "recorded-date": "21-01-2025, 18:29:41", + "recorded-date": "21-02-2026, 00:19:50", "recorded-content": { "put-object": { "ChecksumCRC32": "2H9+DA==", @@ -6552,6 +6528,7 @@ "copy-object-in-place-with-storage-class": { "CopyObjectResult": { "ChecksumCRC32": "2H9+DA==", + "ChecksumType": "FULL_OBJECT", "ETag": "\"098f6bcd4621d373cade4e832627b4f6\"", "LastModified": "datetime" }, @@ -6582,7 +6559,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3::test_s3_copy_metadata_directive_copy": { - "recorded-date": "21-01-2025, 18:28:52", + "recorded-date": "21-02-2026, 00:18:59", "recorded-content": { "put-object": { "ChecksumCRC32": "2H9+DA==", @@ -6613,6 +6590,7 @@ "copy-object": { "CopyObjectResult": { "ChecksumCRC32": "2H9+DA==", + "ChecksumType": "FULL_OBJECT", "ETag": "\"098f6bcd4621d373cade4e832627b4f6\"", "LastModified": "datetime" }, @@ -6641,7 +6619,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3::test_s3_copy_object_in_place_website_redirect_location": { - "recorded-date": "21-01-2025, 18:29:39", + "recorded-date": "21-02-2026, 00:19:47", "recorded-content": { "put-object": { "ChecksumCRC32": "2H9+DA==", @@ -6670,6 +6648,7 @@ "copy-object-in-place-with-website-redirection": { "CopyObjectResult": { "ChecksumCRC32": "2H9+DA==", + "ChecksumType": "FULL_OBJECT", "ETag": "\"098f6bcd4621d373cade4e832627b4f6\"", "LastModified": "datetime" }, @@ -6696,7 +6675,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3::test_copy_in_place_with_bucket_encryption": { - "recorded-date": "21-01-2025, 18:29:34", + "recorded-date": "21-02-2026, 00:19:42", "recorded-content": { "put-bucket-encryption": { "ResponseMetadata": { @@ -6717,6 +6696,7 @@ "copy-obj": { "CopyObjectResult": { "ChecksumCRC32": "AAAAAA==", + "ChecksumType": "FULL_OBJECT", "ETag": "\"d41d8cd98f00b204e9800998ecf8427e\"", "LastModified": "datetime" }, @@ -6729,7 +6709,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3PutObjectChecksum::test_s3_get_object_checksum[CRC32]": { - "recorded-date": "17-03-2025, 18:28:46", + "recorded-date": "21-02-2026, 00:38:07", "recorded-content": { "put-object": { "ChecksumCRC32": "lVk/nw==", @@ -6803,7 +6783,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3PutObjectChecksum::test_s3_get_object_checksum[CRC32C]": { - "recorded-date": "17-03-2025, 18:28:48", + "recorded-date": "21-02-2026, 00:38:10", "recorded-content": { "put-object": { "ChecksumCRC32C": "Fz3epA==", @@ -6877,7 +6857,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3PutObjectChecksum::test_s3_get_object_checksum[SHA1]": { - "recorded-date": "17-03-2025, 18:28:51", + "recorded-date": "21-02-2026, 00:38:13", "recorded-content": { "put-object": { "ChecksumSHA1": "jbXkHAsXUrubtL3dqDQ4w+7WXc0=", @@ -6951,7 +6931,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3::test_s3_analytics_configurations": { - "recorded-date": "21-01-2025, 18:42:41", + "recorded-date": "21-02-2026, 00:28:57", "recorded-content": { "put_config_with_storage_analysis_err": { "Error": { @@ -7136,7 +7116,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3::test_s3_intelligent_tier_config": { - "recorded-date": "21-01-2025, 19:48:46", + "recorded-date": "21-02-2026, 00:29:00", "recorded-content": { "put_bucket_intelligent_tiering_configuration_err_1`": { "Error": { @@ -7289,7 +7269,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3::test_multipart_no_such_upload": { - "recorded-date": "21-01-2025, 18:27:38", + "recorded-date": "21-02-2026, 00:18:12", "recorded-content": { "upload-exc": { "Error": { @@ -7327,7 +7307,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3::test_s3_copy_object_with_checksum[CRC32]": { - "recorded-date": "24-01-2025, 19:06:29", + "recorded-date": "21-02-2026, 00:19:52", "recorded-content": { "put-object-no-checksum": { "ChecksumCRC32": "MzVIGw==", @@ -7353,6 +7333,7 @@ "copy-object-in-place-with-checksum": { "CopyObjectResult": { "ChecksumCRC32": "MzVIGw==", + "ChecksumType": "FULL_OBJECT", "ETag": "\"88bac95f31528d13a072c05f2a1cf371\"", "LastModified": "datetime" }, @@ -7376,6 +7357,7 @@ "copy-object-to-dest-keep-checksum": { "CopyObjectResult": { "ChecksumCRC32": "MzVIGw==", + "ChecksumType": "FULL_OBJECT", "ETag": "\"88bac95f31528d13a072c05f2a1cf371\"", "LastModified": "datetime" }, @@ -7388,7 +7370,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3::test_s3_copy_object_with_checksum[CRC32C]": { - "recorded-date": "24-01-2025, 19:06:31", + "recorded-date": "21-02-2026, 00:19:55", "recorded-content": { "put-object-no-checksum": { "ChecksumCRC32": "MzVIGw==", @@ -7414,6 +7396,7 @@ "copy-object-in-place-with-checksum": { "CopyObjectResult": { "ChecksumCRC32C": "078Ilw==", + "ChecksumType": "FULL_OBJECT", "ETag": "\"88bac95f31528d13a072c05f2a1cf371\"", "LastModified": "datetime" }, @@ -7437,6 +7420,7 @@ "copy-object-to-dest-keep-checksum": { "CopyObjectResult": { "ChecksumCRC32C": "078Ilw==", + "ChecksumType": "FULL_OBJECT", "ETag": "\"88bac95f31528d13a072c05f2a1cf371\"", "LastModified": "datetime" }, @@ -7449,7 +7433,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3::test_s3_copy_object_with_checksum[SHA1]": { - "recorded-date": "24-01-2025, 19:06:34", + "recorded-date": "21-02-2026, 00:19:57", "recorded-content": { "put-object-no-checksum": { "ChecksumCRC32": "MzVIGw==", @@ -7475,6 +7459,7 @@ "copy-object-in-place-with-checksum": { "CopyObjectResult": { "ChecksumSHA1": "5zXdjmjYk4EJ8Cw4PMnQVslCpRQ=", + "ChecksumType": "FULL_OBJECT", "ETag": "\"88bac95f31528d13a072c05f2a1cf371\"", "LastModified": "datetime" }, @@ -7498,6 +7483,7 @@ "copy-object-to-dest-keep-checksum": { "CopyObjectResult": { "ChecksumSHA1": "5zXdjmjYk4EJ8Cw4PMnQVslCpRQ=", + "ChecksumType": "FULL_OBJECT", "ETag": "\"88bac95f31528d13a072c05f2a1cf371\"", "LastModified": "datetime" }, @@ -7510,7 +7496,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3::test_s3_copy_object_with_checksum[SHA256]": { - "recorded-date": "24-01-2025, 19:06:36", + "recorded-date": "21-02-2026, 00:19:59", "recorded-content": { "put-object-no-checksum": { "ChecksumCRC32": "MzVIGw==", @@ -7536,6 +7522,7 @@ "copy-object-in-place-with-checksum": { "CopyObjectResult": { "ChecksumSHA256": "lyTB4g5uPk1/V+0l+dTvsAblCFkNUoyQ2ll/andcE+U=", + "ChecksumType": "FULL_OBJECT", "ETag": "\"88bac95f31528d13a072c05f2a1cf371\"", "LastModified": "datetime" }, @@ -7559,6 +7546,7 @@ "copy-object-to-dest-keep-checksum": { "CopyObjectResult": { "ChecksumSHA256": "lyTB4g5uPk1/V+0l+dTvsAblCFkNUoyQ2ll/andcE+U=", + "ChecksumType": "FULL_OBJECT", "ETag": "\"88bac95f31528d13a072c05f2a1cf371\"", "LastModified": "datetime" }, @@ -7571,7 +7559,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3::test_put_get_object_special_character[file%2Fname]": { - "recorded-date": "21-01-2025, 18:26:42", + "recorded-date": "21-02-2026, 00:17:23", "recorded-content": { "put-object-special-char": { "ChecksumCRC32": "2H9+DA==", @@ -7633,7 +7621,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3::test_put_get_object_special_character[test@key/]": { - "recorded-date": "21-01-2025, 18:26:44", + "recorded-date": "21-02-2026, 00:17:25", "recorded-content": { "put-object-special-char": { "ChecksumCRC32": "2H9+DA==", @@ -7695,7 +7683,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3::test_put_get_object_special_character[test%123]": { - "recorded-date": "21-01-2025, 18:26:46", + "recorded-date": "21-02-2026, 00:17:27", "recorded-content": { "put-object-special-char": { "ChecksumCRC32": "2H9+DA==", @@ -7757,7 +7745,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3::test_put_get_object_special_character[test%percent]": { - "recorded-date": "21-01-2025, 18:26:48", + "recorded-date": "21-02-2026, 00:17:29", "recorded-content": { "put-object-special-char": { "ChecksumCRC32": "2H9+DA==", @@ -7819,7 +7807,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3::test_put_get_object_special_character[test key/]": { - "recorded-date": "21-01-2025, 18:26:50", + "recorded-date": "21-02-2026, 00:17:31", "recorded-content": { "put-object-special-char": { "ChecksumCRC32": "2H9+DA==", @@ -7881,7 +7869,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3::test_put_get_object_special_character[test key//]": { - "recorded-date": "21-01-2025, 18:26:52", + "recorded-date": "21-02-2026, 00:17:33", "recorded-content": { "put-object-special-char": { "ChecksumCRC32": "2H9+DA==", @@ -7943,7 +7931,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3::test_put_get_object_special_character[test%123/]": { - "recorded-date": "21-01-2025, 18:26:54", + "recorded-date": "21-02-2026, 00:17:35", "recorded-content": { "put-object-special-char": { "ChecksumCRC32": "2H9+DA==", @@ -8005,7 +7993,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3::test_put_get_object_special_character[a/%F0%9F%98%80/]": { - "recorded-date": "21-01-2025, 18:26:56", + "recorded-date": "21-02-2026, 00:17:37", "recorded-content": { "put-object-special-char": { "ChecksumCRC32": "2H9+DA==", @@ -8067,7 +8055,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3::test_s3_get_object_headers": { - "recorded-date": "21-01-2025, 18:42:49", + "recorded-date": "21-02-2026, 00:29:04", "recorded-content": { "if_none_match_err_1": { "Code": "304", @@ -8087,105 +8075,8 @@ } } }, - "tests/aws/services/s3/test_s3.py::TestS3::test_s3_copy_object_preconditions": { - "recorded-date": "21-01-2025, 18:29:56", - "recorded-content": { - "head-object": { - "AcceptRanges": "bytes", - "ContentLength": 4, - "ContentType": "binary/octet-stream", - "ETag": "\"8d777f385d3dfec8815d20f7496026dc\"", - "LastModified": "datetime", - "Metadata": {}, - "ServerSideEncryption": "AES256", - "ResponseMetadata": { - "HTTPHeaders": {}, - "HTTPStatusCode": 200 - } - }, - "copy-precondition-if-match": { - "Error": { - "Code": "PreconditionFailed", - "Condition": "x-amz-copy-source-If-Match", - "Message": "At least one of the pre-conditions you specified did not hold" - }, - "ResponseMetadata": { - "HTTPHeaders": {}, - "HTTPStatusCode": 412 - } - }, - "copy-precondition-if-unmodified-since": { - "Error": { - "Code": "PreconditionFailed", - "Condition": "x-amz-copy-source-If-Unmodified-Since", - "Message": "At least one of the pre-conditions you specified did not hold" - }, - "ResponseMetadata": { - "HTTPHeaders": {}, - "HTTPStatusCode": 412 - } - }, - "copy-precondition-if-none-match": { - "Error": { - "Code": "PreconditionFailed", - "Condition": "x-amz-copy-source-If-None-Match", - "Message": "At least one of the pre-conditions you specified did not hold" - }, - "ResponseMetadata": { - "HTTPHeaders": {}, - "HTTPStatusCode": 412 - } - }, - "copy-precondition-if-modified-since": { - "Error": { - "Code": "PreconditionFailed", - "Condition": "x-amz-copy-source-If-Modified-Since", - "Message": "At least one of the pre-conditions you specified did not hold" - }, - "ResponseMetadata": { - "HTTPHeaders": {}, - "HTTPStatusCode": 412 - } - }, - "copy-ignore-future-modified-since": { - "CopyObjectResult": { - "ChecksumCRC32": "rfPzYw==", - "ETag": "\"8d777f385d3dfec8815d20f7496026dc\"", - "LastModified": "datetime" - }, - "ServerSideEncryption": "AES256", - "ResponseMetadata": { - "HTTPHeaders": {}, - "HTTPStatusCode": 200 - } - }, - "copy-etag-missing-quotes": { - "Error": { - "Code": "PreconditionFailed", - "Condition": "x-amz-copy-source-If-None-Match", - "Message": "At least one of the pre-conditions you specified did not hold" - }, - "ResponseMetadata": { - "HTTPHeaders": {}, - "HTTPStatusCode": 412 - } - }, - "copy-success": { - "CopyObjectResult": { - "ChecksumCRC32": "rfPzYw==", - "ETag": "\"8d777f385d3dfec8815d20f7496026dc\"", - "LastModified": "datetime" - }, - "ServerSideEncryption": "AES256", - "ResponseMetadata": { - "HTTPHeaders": {}, - "HTTPStatusCode": 200 - } - } - } - }, "tests/aws/services/s3/test_s3.py::TestS3BucketLogging::test_put_bucket_logging": { - "recorded-date": "12-08-2023, 19:54:07", + "recorded-date": "21-02-2026, 00:34:53", "recorded-content": { "get-bucket-logging-default": { "ResponseMetadata": { @@ -8197,7 +8088,6 @@ "Grants": [ { "Grantee": { - "DisplayName": "display-name", "ID": "owner-id", "Type": "CanonicalUser" }, @@ -8205,7 +8095,6 @@ } ], "Owner": { - "DisplayName": "display-name", "ID": "owner-id" }, "ResponseMetadata": { @@ -8238,7 +8127,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3BucketLogging::test_put_bucket_logging_accept_wrong_grants": { - "recorded-date": "03-08-2023, 04:26:11", + "recorded-date": "21-02-2026, 00:34:57", "recorded-content": { "put-bucket-logging": { "ResponseMetadata": { @@ -8275,7 +8164,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3BucketLogging::test_put_bucket_logging_wrong_target": { - "recorded-date": "30-08-2024, 11:31:48", + "recorded-date": "21-02-2026, 00:35:00", "recorded-content": { "put-bucket-logging-different-regions": { "Error": { @@ -8302,7 +8191,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3BucketLifecycle::test_bucket_lifecycle_configuration_object_expiry_versioned": { - "recorded-date": "21-01-2025, 18:18:31", + "recorded-date": "21-02-2026, 00:33:29", "recorded-content": { "get-bucket-lifecycle-conf": { "Rules": [ @@ -8447,7 +8336,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3BucketLifecycle::test_bucket_lifecycle_multiple_rules": { - "recorded-date": "21-01-2025, 18:18:36", + "recorded-date": "21-02-2026, 00:33:34", "recorded-content": { "get-bucket-lifecycle-conf": { "Rules": [ @@ -8517,7 +8406,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3BucketLifecycle::test_put_bucket_lifecycle_conf_exc": { - "recorded-date": "21-01-2025, 18:18:24", + "recorded-date": "21-02-2026, 00:33:22", "recorded-content": { "missing-id": { "Error": { @@ -8604,7 +8493,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3BucketLifecycle::test_bucket_lifecycle_configuration_date": { - "recorded-date": "21-01-2025, 18:18:26", + "recorded-date": "21-02-2026, 00:33:24", "recorded-content": { "get-bucket-lifecycle-conf": { "Rules": [ @@ -8626,7 +8515,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3BucketLifecycle::test_bucket_lifecycle_object_size_rules": { - "recorded-date": "21-01-2025, 18:18:38", + "recorded-date": "21-02-2026, 00:33:37", "recorded-content": { "get-bucket-lifecycle-conf": { "Rules": [ @@ -8688,7 +8577,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3BucketLifecycle::test_bucket_lifecycle_tag_rules": { - "recorded-date": "21-01-2025, 18:18:42", + "recorded-date": "21-02-2026, 00:33:41", "recorded-content": { "get-bucket-lifecycle-conf": { "Rules": [ @@ -8843,7 +8732,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3BucketLifecycle::test_object_expiry_after_bucket_lifecycle_configuration": { - "recorded-date": "21-01-2025, 18:18:33", + "recorded-date": "21-02-2026, 00:33:32", "recorded-content": { "put-object-before": { "ChecksumCRC32": "2H9+DA==", @@ -8912,7 +8801,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3::test_s3_inventory_report_crud": { - "recorded-date": "21-01-2025, 18:42:52", + "recorded-date": "21-02-2026, 00:29:07", "recorded-content": { "put-inventory-config": { "ResponseMetadata": { @@ -8997,7 +8886,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3::test_s3_put_inventory_report_exceptions": { - "recorded-date": "21-01-2025, 18:42:57", + "recorded-date": "21-02-2026, 00:29:11", "recorded-content": { "wrong-id": { "Error": { @@ -9062,7 +8951,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3::test_put_bucket_inventory_config_order": { - "recorded-date": "21-01-2025, 18:43:00", + "recorded-date": "21-02-2026, 00:29:15", "recorded-content": { "list-inventory-config": { "InventoryConfigurationList": [ @@ -9161,7 +9050,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3BucketLifecycle::test_lifecycle_expired_object_delete_marker": { - "recorded-date": "21-01-2025, 18:18:44", + "recorded-date": "21-02-2026, 00:33:43", "recorded-content": { "get-bucket-lifecycle-conf": { "Rules": [ @@ -9204,7 +9093,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3::test_multipart_complete_multipart_too_small": { - "recorded-date": "21-01-2025, 18:27:40", + "recorded-date": "21-02-2026, 00:18:14", "recorded-content": { "upload-part1": { "ChecksumCRC32": "rfPzYw==", @@ -9251,7 +9140,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3::test_multipart_complete_multipart_wrong_part": { - "recorded-date": "21-01-2025, 18:27:42", + "recorded-date": "21-02-2026, 00:18:17", "recorded-content": { "complete-exc-wrong-part-number": { "Error": { @@ -9282,7 +9171,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3::test_s3_copy_tagging_directive[COPY]": { - "recorded-date": "21-01-2025, 18:28:54", + "recorded-date": "21-02-2026, 00:19:02", "recorded-content": { "put-object": { "ChecksumCRC32": "2H9+DA==", @@ -9309,6 +9198,7 @@ "copy-object": { "CopyObjectResult": { "ChecksumCRC32": "2H9+DA==", + "ChecksumType": "FULL_OBJECT", "ETag": "\"098f6bcd4621d373cade4e832627b4f6\"", "LastModified": "datetime" }, @@ -9333,6 +9223,7 @@ "copy-object-tag-empty": { "CopyObjectResult": { "ChecksumCRC32": "2H9+DA==", + "ChecksumType": "FULL_OBJECT", "ETag": "\"098f6bcd4621d373cade4e832627b4f6\"", "LastModified": "datetime" }, @@ -9357,7 +9248,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3::test_s3_copy_tagging_directive[REPLACE]": { - "recorded-date": "21-01-2025, 18:28:57", + "recorded-date": "21-02-2026, 00:19:04", "recorded-content": { "put-object": { "ChecksumCRC32": "2H9+DA==", @@ -9384,6 +9275,7 @@ "copy-object": { "CopyObjectResult": { "ChecksumCRC32": "2H9+DA==", + "ChecksumType": "FULL_OBJECT", "ETag": "\"098f6bcd4621d373cade4e832627b4f6\"", "LastModified": "datetime" }, @@ -9408,6 +9300,7 @@ "copy-object-tag-empty": { "CopyObjectResult": { "ChecksumCRC32": "2H9+DA==", + "ChecksumType": "FULL_OBJECT", "ETag": "\"098f6bcd4621d373cade4e832627b4f6\"", "LastModified": "datetime" }, @@ -9427,7 +9320,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3::test_s3_copy_tagging_directive[None]": { - "recorded-date": "21-01-2025, 18:28:59", + "recorded-date": "21-02-2026, 00:19:06", "recorded-content": { "put-object": { "ChecksumCRC32": "2H9+DA==", @@ -9454,6 +9347,7 @@ "copy-object": { "CopyObjectResult": { "ChecksumCRC32": "2H9+DA==", + "ChecksumType": "FULL_OBJECT", "ETag": "\"098f6bcd4621d373cade4e832627b4f6\"", "LastModified": "datetime" }, @@ -9478,6 +9372,7 @@ "copy-object-tag-empty": { "CopyObjectResult": { "ChecksumCRC32": "2H9+DA==", + "ChecksumType": "FULL_OBJECT", "ETag": "\"098f6bcd4621d373cade4e832627b4f6\"", "LastModified": "datetime" }, @@ -9502,7 +9397,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3::test_get_object_content_length_with_virtual_host[True]": { - "recorded-date": "21-01-2025, 18:43:02", + "recorded-date": "21-02-2026, 00:29:17", "recorded-content": { "get-obj-content-len-headers": { "accept-ranges": "bytes", @@ -9519,7 +9414,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3::test_get_object_content_length_with_virtual_host[False]": { - "recorded-date": "21-01-2025, 18:43:04", + "recorded-date": "21-02-2026, 00:29:19", "recorded-content": { "get-obj-content-len-headers": { "accept-ranges": "bytes", @@ -9536,7 +9431,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3ObjectLockRetention::test_s3_object_retention_exc": { - "recorded-date": "20-06-2025, 16:29:06", + "recorded-date": "21-02-2026, 00:33:51", "recorded-content": { "put-object-retention-no-bucket": { "Error": { @@ -9635,7 +9530,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3ObjectLockRetention::test_s3_copy_object_retention_lock": { - "recorded-date": "21-01-2025, 18:18:00", + "recorded-date": "21-02-2026, 00:34:08", "recorded-content": { "put-source-object": { "ChecksumCRC32": "MzVIGw==", @@ -9667,6 +9562,7 @@ "copy-lock": { "CopyObjectResult": { "ChecksumCRC32": "MzVIGw==", + "ChecksumType": "FULL_OBJECT", "ETag": "\"88bac95f31528d13a072c05f2a1cf371\"", "LastModified": "datetime" }, @@ -9695,7 +9591,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3ObjectLockRetention::test_s3_object_retention": { - "recorded-date": "20-06-2025, 17:02:01", + "recorded-date": "21-02-2026, 00:34:06", "recorded-content": { "put-obj-locked-1": { "ChecksumCRC32": "2H9+DA==", @@ -9793,7 +9689,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3ObjectLockRetention::test_bucket_config_default_retention": { - "recorded-date": "20-06-2025, 17:35:52", + "recorded-date": "21-02-2026, 00:34:11", "recorded-content": { "put-lock-config": { "ResponseMetadata": { @@ -9869,7 +9765,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3ObjectLockRetention::test_object_lock_delete_markers": { - "recorded-date": "21-01-2025, 18:18:05", + "recorded-date": "21-02-2026, 00:34:13", "recorded-content": { "put-object-with-lock": { "ChecksumCRC32": "l5fLBg==", @@ -9943,7 +9839,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3ObjectLockRetention::test_object_lock_extend_duration": { - "recorded-date": "21-01-2025, 18:18:07", + "recorded-date": "21-02-2026, 00:34:15", "recorded-content": { "put-object-with-lock": { "ChecksumCRC32": "l5fLBg==", @@ -10007,7 +9903,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3ObjectLockLegalHold::test_put_get_object_legal_hold": { - "recorded-date": "21-01-2025, 18:17:06", + "recorded-date": "21-02-2026, 00:34:34", "recorded-content": { "put-obj": { "ChecksumCRC32": "2H9+DA==", @@ -10069,7 +9965,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3ObjectLockLegalHold::test_put_object_legal_hold_exc": { - "recorded-date": "21-01-2025, 18:17:12", + "recorded-date": "21-02-2026, 00:34:40", "recorded-content": { "put-object-legal-hold-no-bucket": { "Error": { @@ -10126,7 +10022,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3ObjectLockLegalHold::test_delete_locked_object": { - "recorded-date": "21-01-2025, 18:17:15", + "recorded-date": "21-02-2026, 00:34:43", "recorded-content": { "put-obj": { "ChecksumCRC32": "2H9+DA==", @@ -10178,7 +10074,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3ObjectLockLegalHold::test_s3_legal_hold_lock_versioned": { - "recorded-date": "21-01-2025, 18:17:18", + "recorded-date": "21-02-2026, 00:34:47", "recorded-content": { "put-object": { "ChecksumCRC32": "2H9+DA==", @@ -10275,7 +10171,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3ObjectLockLegalHold::test_s3_copy_object_legal_hold": { - "recorded-date": "21-01-2025, 18:17:21", + "recorded-date": "21-02-2026, 00:34:50", "recorded-content": { "put-object": { "ChecksumCRC32": "MzVIGw==", @@ -10306,6 +10202,7 @@ "copy-legal-hold": { "CopyObjectResult": { "ChecksumCRC32": "MzVIGw==", + "ChecksumType": "FULL_OBJECT", "ETag": "\"88bac95f31528d13a072c05f2a1cf371\"", "LastModified": "datetime" }, @@ -10334,7 +10231,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3ObjectLockLegalHold::test_put_object_with_legal_hold": { - "recorded-date": "21-01-2025, 18:17:08", + "recorded-date": "21-02-2026, 00:34:36", "recorded-content": { "put-obj": { "ChecksumCRC32": "2H9+DA==", @@ -10371,7 +10268,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3::test_s3_get_object_preconditions[get_object]": { - "recorded-date": "21-01-2025, 18:30:04", + "recorded-date": "21-02-2026, 00:20:22", "recorded-content": { "precondition-if-match": { "Error": { @@ -10486,7 +10383,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3::test_s3_get_object_preconditions[head_object]": { - "recorded-date": "21-01-2025, 18:30:10", + "recorded-date": "21-02-2026, 00:20:28", "recorded-content": { "precondition-if-match": { "Error": { @@ -10590,7 +10487,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3::test_get_object_part": { - "recorded-date": "07-07-2025, 17:56:14", + "recorded-date": "21-02-2026, 00:22:58", "recorded-content": { "multipart-upload": { "Bucket": "", @@ -10706,7 +10603,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3PresignedPost::test_post_object_with_tags[single]": { - "recorded-date": "17-03-2025, 20:16:38", + "recorded-date": "21-02-2026, 00:35:40", "recorded-content": { "get-tagging": { "TagSet": [ @@ -10723,7 +10620,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3PresignedPost::test_post_object_with_tags[list]": { - "recorded-date": "17-03-2025, 20:16:39", + "recorded-date": "21-02-2026, 00:35:43", "recorded-content": { "get-tagging": { "TagSet": [ @@ -10744,7 +10641,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3PresignedPost::test_post_object_with_tags[invalid]": { - "recorded-date": "17-03-2025, 20:16:41", + "recorded-date": "21-02-2026, 00:35:44", "recorded-content": { "get-tagging": { "TagSet": [], @@ -10756,7 +10653,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3PresignedPost::test_post_object_with_tags[notxml]": { - "recorded-date": "17-03-2025, 20:16:43", + "recorded-date": "21-02-2026, 00:35:46", "recorded-content": { "tagging-error": { "Error": { @@ -10769,7 +10666,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3PresignedPost::test_post_object_with_metadata": { - "recorded-date": "17-03-2025, 21:56:03", + "recorded-date": "21-02-2026, 00:35:48", "recorded-content": { "head-object": { "AcceptRanges": "bytes", @@ -10792,7 +10689,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3PresignedPost::test_post_object_with_storage_class": { - "recorded-date": "17-03-2025, 20:16:47", + "recorded-date": "21-02-2026, 00:35:52", "recorded-content": { "head-object": { "AcceptRanges": "bytes", @@ -10820,7 +10717,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3::test_s3_object_acl": { - "recorded-date": "21-01-2025, 18:30:26", + "recorded-date": "21-02-2026, 00:20:45", "recorded-content": { "put-object-default-acl": { "ChecksumCRC32": "AAAAAA==", @@ -10836,7 +10733,6 @@ "Grants": [ { "Grantee": { - "DisplayName": "", "ID": "", "Type": "CanonicalUser" }, @@ -10844,7 +10740,6 @@ } ], "Owner": { - "DisplayName": "", "ID": "" }, "ResponseMetadata": { @@ -10862,7 +10757,6 @@ "Grants": [ { "Grantee": { - "DisplayName": "", "ID": "", "Type": "CanonicalUser" }, @@ -10877,7 +10771,6 @@ } ], "Owner": { - "DisplayName": "", "ID": "" }, "ResponseMetadata": { @@ -10896,7 +10789,6 @@ } ], "Owner": { - "DisplayName": "", "ID": "" }, "ResponseMetadata": { @@ -10908,7 +10800,6 @@ "Grants": [ { "Grantee": { - "DisplayName": "", "ID": "", "Type": "CanonicalUser" }, @@ -10923,7 +10814,6 @@ } ], "Owner": { - "DisplayName": "", "ID": "" }, "ResponseMetadata": { @@ -10934,7 +10824,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3::test_s3_object_acl_exceptions": { - "recorded-date": "21-01-2025, 18:30:32", + "recorded-date": "21-02-2026, 00:20:51", "recorded-content": { "put-object-canned-acl": { "Error": { @@ -11106,7 +10996,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3::test_empty_bucket_fixture": { - "recorded-date": "21-01-2025, 18:43:07", + "recorded-date": "21-02-2026, 00:29:22", "recorded-content": { "list-obj": { "Contents": [ @@ -11170,7 +11060,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3::test_bucket_operation_between_regions": { - "recorded-date": "21-01-2025, 18:30:52", + "recorded-date": "21-02-2026, 00:21:08", "recorded-content": { "put-website-config-region-1": { "ResponseMetadata": { @@ -11212,7 +11102,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3::test_multipart_overwrite_key": { - "recorded-date": "17-03-2025, 21:29:05", + "recorded-date": "21-02-2026, 00:22:51", "recorded-content": { "put-object": { "ChecksumCRC32": "B18g1g==", @@ -11240,7 +11130,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3::test_delete_objects_encoding": { - "recorded-date": "21-01-2025, 18:31:37", + "recorded-date": "21-02-2026, 00:21:36", "recorded-content": { "list-objects-before-delete": { "Contents": [ @@ -11434,7 +11324,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3::test_url_encoded_key[True]": { - "recorded-date": "21-01-2025, 18:27:06", + "recorded-date": "21-02-2026, 00:17:52", "recorded-content": { "list-object-encoded-char": { "Contents": [ @@ -11486,7 +11376,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3::test_url_encoded_key[False]": { - "recorded-date": "21-01-2025, 18:27:09", + "recorded-date": "21-02-2026, 00:17:56", "recorded-content": { "list-object-encoded-char": { "Contents": [ @@ -11603,7 +11493,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3PresignedUrl::test_put_url_metadata_with_sig_s3v4[True]": { - "recorded-date": "21-01-2025, 18:22:52", + "recorded-date": "21-02-2026, 00:29:33", "recorded-content": { "no-meta-headers": { "Error": { @@ -11646,7 +11536,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3PresignedUrl::test_put_url_metadata_with_sig_s3v4[False]": { - "recorded-date": "21-01-2025, 18:22:55", + "recorded-date": "21-02-2026, 00:29:36", "recorded-content": { "no-meta-headers": { "Error": { @@ -11689,7 +11579,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3PresignedUrl::test_put_url_metadata_with_sig_s3[True]": { - "recorded-date": "21-01-2025, 18:22:57", + "recorded-date": "21-02-2026, 00:29:39", "recorded-content": { "head_object": { "AcceptRanges": "bytes", @@ -11721,7 +11611,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3PresignedUrl::test_put_url_metadata_with_sig_s3[False]": { - "recorded-date": "21-01-2025, 18:22:59", + "recorded-date": "21-02-2026, 00:29:41", "recorded-content": { "head_object": { "AcceptRanges": "bytes", @@ -11753,7 +11643,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3PresignedUrl::test_presigned_url_v4_x_amz_in_qs": { - "recorded-date": "17-03-2025, 21:32:11", + "recorded-date": "21-02-2026, 00:31:46", "recorded-content": { "head-object": { "AcceptRanges": "bytes", @@ -11775,7 +11665,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3::test_object_with_slashes_in_key[True]": { - "recorded-date": "21-01-2025, 18:26:32", + "recorded-date": "21-02-2026, 00:17:13", "recorded-content": { "list-objects-slashes": { "Contents": [ @@ -11827,7 +11717,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3::test_object_with_slashes_in_key[False]": { - "recorded-date": "21-01-2025, 18:26:36", + "recorded-date": "21-02-2026, 00:17:16", "recorded-content": { "list-objects-slashes": { "Contents": [ @@ -11879,7 +11769,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3BucketLogging::test_put_bucket_logging_cross_locations": { - "recorded-date": "29-08-2024, 15:58:14", + "recorded-date": "21-02-2026, 00:35:04", "recorded-content": { "put-bucket-logging-cross-us-east-1": { "Error": { @@ -11907,7 +11797,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3::test_copy_object_special_character": { - "recorded-date": "21-01-2025, 18:27:00", + "recorded-date": "21-02-2026, 00:17:46", "recorded-content": { "put-object-src-special-char-file%2Fname": { "ChecksumCRC32": "2H9+DA==", @@ -11922,6 +11812,7 @@ "copy-object-special-char-file%2Fname": { "CopyObjectResult": { "ChecksumCRC32": "2H9+DA==", + "ChecksumType": "FULL_OBJECT", "ETag": "\"098f6bcd4621d373cade4e832627b4f6\"", "LastModified": "datetime" }, @@ -11944,6 +11835,7 @@ "copy-object-special-char-test@key/": { "CopyObjectResult": { "ChecksumCRC32": "2H9+DA==", + "ChecksumType": "FULL_OBJECT", "ETag": "\"098f6bcd4621d373cade4e832627b4f6\"", "LastModified": "datetime" }, @@ -11966,6 +11858,7 @@ "copy-object-special-char-test key/": { "CopyObjectResult": { "ChecksumCRC32": "2H9+DA==", + "ChecksumType": "FULL_OBJECT", "ETag": "\"098f6bcd4621d373cade4e832627b4f6\"", "LastModified": "datetime" }, @@ -11988,6 +11881,7 @@ "copy-object-special-char-test key//": { "CopyObjectResult": { "ChecksumCRC32": "2H9+DA==", + "ChecksumType": "FULL_OBJECT", "ETag": "\"098f6bcd4621d373cade4e832627b4f6\"", "LastModified": "datetime" }, @@ -12010,6 +11904,7 @@ "copy-object-special-char-a/%F0%9F%98%80/": { "CopyObjectResult": { "ChecksumCRC32": "2H9+DA==", + "ChecksumType": "FULL_OBJECT", "ETag": "\"098f6bcd4621d373cade4e832627b4f6\"", "LastModified": "datetime" }, @@ -12032,6 +11927,7 @@ "copy-object-special-char-test+key": { "CopyObjectResult": { "ChecksumCRC32": "2H9+DA==", + "ChecksumType": "FULL_OBJECT", "ETag": "\"098f6bcd4621d373cade4e832627b4f6\"", "LastModified": "datetime" }, @@ -12124,7 +12020,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3PresignedPost::test_post_object_with_wrong_content_type": { - "recorded-date": "17-03-2025, 20:16:49", + "recorded-date": "21-02-2026, 00:35:54", "recorded-content": { "invalid-content-type-error": { "Error": { @@ -12138,7 +12034,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3PresignedPost::test_post_object_with_file_as_string": { - "recorded-date": "17-03-2025, 20:16:51", + "recorded-date": "21-02-2026, 00:35:58", "recorded-content": { "head-object": { "AcceptRanges": "bytes", @@ -12192,7 +12088,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3::test_s3_copy_object_wrong_format": { - "recorded-date": "21-01-2025, 18:29:58", + "recorded-date": "21-02-2026, 00:20:16", "recorded-content": { "copy-object-wrong-copy-source": { "Error": { @@ -12209,7 +12105,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3::test_s3_copy_object_in_place_versioned": { - "recorded-date": "21-01-2025, 18:29:22", + "recorded-date": "21-02-2026, 00:19:29", "recorded-content": { "put_object": { "ChecksumCRC32": "MzVIGw==", @@ -12260,6 +12156,7 @@ "copy-in-place-versioned": { "CopyObjectResult": { "ChecksumCRC32": "MzVIGw==", + "ChecksumType": "FULL_OBJECT", "ETag": "\"88bac95f31528d13a072c05f2a1cf371\"", "LastModified": "datetime" }, @@ -12307,6 +12204,7 @@ "copy-in-place-versioned-suspended": { "CopyObjectResult": { "ChecksumCRC32": "MzVIGw==", + "ChecksumType": "FULL_OBJECT", "ETag": "\"88bac95f31528d13a072c05f2a1cf371\"", "LastModified": "datetime" }, @@ -12368,6 +12266,7 @@ "copy-in-place-versioned-re-enabled": { "CopyObjectResult": { "ChecksumCRC32": "MzVIGw==", + "ChecksumType": "FULL_OBJECT", "ETag": "\"88bac95f31528d13a072c05f2a1cf371\"", "LastModified": "datetime" }, @@ -12381,7 +12280,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3PresignedPost::test_post_object_policy_validation_size": { - "recorded-date": "17-03-2025, 20:17:02", + "recorded-date": "21-02-2026, 00:36:08", "recorded-content": { "invalid-content-length-too-big": { "Error": { @@ -12430,7 +12329,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3PresignedPost::test_post_object_policy_conditions_validation_eq": { - "recorded-date": "17-03-2025, 20:16:55", + "recorded-date": "21-02-2026, 00:36:02", "recorded-content": { "invalid-condition-eq": { "Error": { @@ -12501,7 +12400,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3PresignedPost::test_post_object_policy_conditions_validation_starts_with": { - "recorded-date": "17-03-2025, 20:16:58", + "recorded-date": "21-02-2026, 00:36:05", "recorded-content": { "invalid-condition-starts-with": { "Error": { @@ -12554,7 +12453,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3PresignedPost::test_presigned_post_with_different_user_credentials": { - "recorded-date": "17-03-2025, 20:17:16", + "recorded-date": "21-02-2026, 00:36:22", "recorded-content": { "get-obj": { "AcceptRanges": "bytes", @@ -12575,7 +12474,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3PresignedUrl::test_presigned_double_encoded_credentials": { - "recorded-date": "21-01-2025, 18:23:03", + "recorded-date": "21-02-2026, 00:29:49", "recorded-content": { "error-malformed": { "Error": { @@ -12588,7 +12487,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3::test_s3_copy_object_in_place_suspended_only": { - "recorded-date": "21-01-2025, 18:29:26", + "recorded-date": "21-02-2026, 00:19:34", "recorded-content": { "put_object": { "ChecksumCRC32": "MzVIGw==", @@ -12618,6 +12517,7 @@ "copy-in-place-non-versioned": { "CopyObjectResult": { "ChecksumCRC32": "MzVIGw==", + "ChecksumType": "FULL_OBJECT", "ETag": "\"88bac95f31528d13a072c05f2a1cf371\"", "LastModified": "datetime" }, @@ -12661,6 +12561,7 @@ "copy-in-place-versioned-suspended": { "CopyObjectResult": { "ChecksumCRC32": "MzVIGw==", + "ChecksumType": "FULL_OBJECT", "ETag": "\"88bac95f31528d13a072c05f2a1cf371\"", "LastModified": "datetime" }, @@ -12707,6 +12608,7 @@ "copy-in-place-versioned-suspended-twice": { "CopyObjectResult": { "ChecksumCRC32": "MzVIGw==", + "ChecksumType": "FULL_OBJECT", "ETag": "\"88bac95f31528d13a072c05f2a1cf371\"", "LastModified": "datetime" }, @@ -12720,7 +12622,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3::test_get_object_attributes_with_space": { - "recorded-date": "21-01-2025, 18:27:30", + "recorded-date": "21-02-2026, 00:18:04", "recorded-content": { "get-attrs-with-whitespace": { "GetObjectAttributesResponse": { @@ -12749,7 +12651,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3PutObjectChecksum::test_s3_checksum_no_algorithm": { - "recorded-date": "17-03-2025, 18:29:05", + "recorded-date": "21-02-2026, 00:38:27", "recorded-content": { "put-wrong-checksum": { "Error": { @@ -12799,7 +12701,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3SSECEncryption::test_put_object_validation_sse_c": { - "recorded-date": "21-01-2025, 18:16:18", + "recorded-date": "21-02-2026, 00:36:33", "recorded-content": { "put-obj-sse-c-both-encryption": { "Error": { @@ -12828,7 +12730,6 @@ "put-obj-sse-c-no-algo": { "Error": { "ArgumentName": "x-amz-server-side-encryption", - "ArgumentValue": "null", "Code": "InvalidArgument", "Message": "Requests specifying Server Side Encryption with Customer provided keys must provide a valid encryption algorithm." }, @@ -12840,7 +12741,6 @@ "put-obj-sse-c-no-key": { "Error": { "ArgumentName": "x-amz-server-side-encryption", - "ArgumentValue": "null", "Code": "InvalidArgument", "Message": "Requests specifying Server Side Encryption with Customer provided keys must provide an appropriate secret key." }, @@ -12852,7 +12752,6 @@ "put-obj-sse-c-no-md5": { "Error": { "ArgumentName": "x-amz-server-side-encryption", - "ArgumentValue": "null", "Code": "InvalidArgument", "Message": "The secret key was invalid for the specified algorithm." }, @@ -12864,7 +12763,6 @@ "put-obj-sse-c-wrong-key-size": { "Error": { "ArgumentName": "x-amz-server-side-encryption", - "ArgumentValue": "null", "Code": "InvalidArgument", "Message": "The secret key was invalid for the specified algorithm." }, @@ -12876,7 +12774,6 @@ "put-obj-sse-c-bad-md5": { "Error": { "ArgumentName": "x-amz-server-side-encryption", - "ArgumentValue": "null", "Code": "InvalidArgument", "Message": "The calculated MD5 hash of the key did not match the hash that was provided." }, @@ -12888,12 +12785,12 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3SSECEncryption::test_object_retrieval_sse_c": { - "recorded-date": "22-01-2025, 14:21:49", + "recorded-date": "21-02-2026, 00:36:37", "recorded-content": { "put-obj-sse-c": { "ChecksumCRC32": "qIrZrA==", "ChecksumType": "FULL_OBJECT", - "ETag": "\"7f021303b8ca8e5af2c5ee7bf1e96a18\"", + "ETag": "\"b68bda5295f8e709f07a0ab89d752f16\"", "SSECustomerAlgorithm": "AES256", "SSECustomerKeyMD5": "JMwgiexXqwuPqIPjYFmIZQ==", "ResponseMetadata": { @@ -12978,7 +12875,6 @@ "get-obj-sse-c-wrong-key-size": { "Error": { "ArgumentName": "x-amz-server-side-encryption", - "ArgumentValue": "null", "Code": "InvalidArgument", "Message": "The secret key was invalid for the specified algorithm." }, @@ -12990,7 +12886,6 @@ "get-obj-sse-c-bad-md5": { "Error": { "ArgumentName": "x-amz-server-side-encryption", - "ArgumentValue": "null", "Code": "InvalidArgument", "Message": "The calculated MD5 hash of the key did not match the hash that was provided." }, @@ -13002,12 +12897,12 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3SSECEncryption::test_copy_object_with_sse_c": { - "recorded-date": "21-01-2025, 18:16:26", + "recorded-date": "21-02-2026, 00:36:41", "recorded-content": { "put-obj-sse-c": { "ChecksumCRC32": "qIrZrA==", "ChecksumType": "FULL_OBJECT", - "ETag": "\"9e12596cb25a080bf57d9655b61cce93\"", + "ETag": "\"b876fdc9f53c719dd2a6130ba9715a69\"", "SSECustomerAlgorithm": "AES256", "SSECustomerKeyMD5": "JMwgiexXqwuPqIPjYFmIZQ==", "ResponseMetadata": { @@ -13018,6 +12913,7 @@ "copy-obj-sse-c-target-no-sse-c": { "CopyObjectResult": { "ChecksumCRC32": "qIrZrA==", + "ChecksumType": "FULL_OBJECT", "ETag": "\"6af8307c2460f2d208ad254f04be4b0d\"", "LastModified": "datetime" }, @@ -13030,7 +12926,8 @@ "copy-obj-sse-c": { "CopyObjectResult": { "ChecksumCRC32": "qIrZrA==", - "ETag": "\"f8c18b77e4724f2b67755eb07ca0d417\"", + "ChecksumType": "FULL_OBJECT", + "ETag": "\"5e04d65f8c04ad2392df8d14c98443a5\"", "LastModified": "datetime" }, "SSECustomerAlgorithm": "AES256", @@ -13099,7 +12996,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3SSECEncryption::test_multipart_upload_sse_c": { - "recorded-date": "17-03-2025, 22:55:35", + "recorded-date": "21-02-2026, 00:36:47", "recorded-content": { "create-mpu-sse-c": { "Bucket": "bucket", @@ -13114,7 +13011,7 @@ }, "upload-part-0": { "ChecksumCRC32": "NRU+Sw==", - "ETag": "\"55725a011e3346d563c0704e1619e91c\"", + "ETag": "\"cf96b8ba9d9e9e6349399eb3fc08a3f7\"", "SSECustomerAlgorithm": "AES256", "SSECustomerKeyMD5": "JMwgiexXqwuPqIPjYFmIZQ==", "ResponseMetadata": { @@ -13124,7 +13021,7 @@ }, "upload-part-1": { "ChecksumCRC32": "NRU+Sw==", - "ETag": "\"5a89fb15ffa5db577508d72fe9d5b61d\"", + "ETag": "\"baa1d9ab47364489d4954efe66a37864\"", "SSECustomerAlgorithm": "AES256", "SSECustomerKeyMD5": "JMwgiexXqwuPqIPjYFmIZQ==", "ResponseMetadata": { @@ -13134,7 +13031,7 @@ }, "upload-part-2": { "ChecksumCRC32": "NRU+Sw==", - "ETag": "\"000a293bf05bdb2787a36ffe787ba40e\"", + "ETag": "\"6e7021813aee13e435eeaff924b9160c\"", "SSECustomerAlgorithm": "AES256", "SSECustomerKeyMD5": "JMwgiexXqwuPqIPjYFmIZQ==", "ResponseMetadata": { @@ -13153,25 +13050,24 @@ "MaxParts": 1000, "NextPartNumberMarker": 3, "Owner": { - "DisplayName": "display-name", "ID": "i-d" }, "PartNumberMarker": 0, "Parts": [ { - "ETag": "\"55725a011e3346d563c0704e1619e91c\"", + "ETag": "\"cf96b8ba9d9e9e6349399eb3fc08a3f7\"", "LastModified": "datetime", "PartNumber": 1, "Size": 5242881 }, { - "ETag": "\"5a89fb15ffa5db577508d72fe9d5b61d\"", + "ETag": "\"baa1d9ab47364489d4954efe66a37864\"", "LastModified": "datetime", "PartNumber": 2, "Size": 5242881 }, { - "ETag": "\"000a293bf05bdb2787a36ffe787ba40e\"", + "ETag": "\"6e7021813aee13e435eeaff924b9160c\"", "LastModified": "datetime", "PartNumber": 3, "Size": 5242881 @@ -13186,7 +13082,7 @@ }, "complete-multipart-checksum": { "Bucket": "bucket", - "ETag": "\"8d8dff3df79d195957f14d81d054538e-3\"", + "ETag": "\"2d296eb6540ecd21430c385336c5dc9c-3\"", "Key": "test-sse-c-multipart", "Location": "", "ResponseMetadata": { @@ -13209,7 +13105,7 @@ "Body": "", "ContentLength": 15728643, "ContentType": "binary/octet-stream", - "ETag": "\"8d8dff3df79d195957f14d81d054538e-3\"", + "ETag": "\"2d296eb6540ecd21430c385336c5dc9c-3\"", "LastModified": "datetime", "Metadata": {}, "SSECustomerAlgorithm": "AES256", @@ -13222,7 +13118,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3SSECEncryption::test_multipart_upload_sse_c_validation": { - "recorded-date": "21-01-2025, 18:16:43", + "recorded-date": "21-02-2026, 00:36:50", "recorded-content": { "create-mpu-no-sse-c": { "Bucket": "bucket", @@ -13278,12 +13174,12 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3SSECEncryption::test_put_object_lifecycle_with_sse_c": { - "recorded-date": "21-01-2025, 18:16:15", + "recorded-date": "21-02-2026, 00:36:30", "recorded-content": { "put-obj-sse-c": { "ChecksumCRC32": "qIrZrA==", "ChecksumType": "FULL_OBJECT", - "ETag": "\"1339c8b8d4cf4416490531cabb5b5963\"", + "ETag": "\"b84c1aee7b2787381547d4277d117b01\"", "SSECustomerAlgorithm": "AES256", "SSECustomerKeyMD5": "JMwgiexXqwuPqIPjYFmIZQ==", "ResponseMetadata": { @@ -13295,7 +13191,7 @@ "AcceptRanges": "bytes", "ContentLength": 9, "ContentType": "binary/octet-stream", - "ETag": "\"1339c8b8d4cf4416490531cabb5b5963\"", + "ETag": "\"b84c1aee7b2787381547d4277d117b01\"", "LastModified": "datetime", "Metadata": {}, "SSECustomerAlgorithm": "AES256", @@ -13312,7 +13208,7 @@ "ChecksumType": "FULL_OBJECT", "ContentLength": 9, "ContentType": "binary/octet-stream", - "ETag": "\"1339c8b8d4cf4416490531cabb5b5963\"", + "ETag": "\"b84c1aee7b2787381547d4277d117b01\"", "LastModified": "datetime", "Metadata": {}, "SSECustomerAlgorithm": "AES256", @@ -13323,7 +13219,7 @@ } }, "get-obj-attrs-sse-c": { - "ETag": "1339c8b8d4cf4416490531cabb5b5963", + "ETag": "b84c1aee7b2787381547d4277d117b01", "LastModified": "datetime", "ObjectSize": 9, "ResponseMetadata": { @@ -13340,12 +13236,12 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3SSECEncryption::test_sse_c_with_versioning": { - "recorded-date": "21-01-2025, 18:16:46", + "recorded-date": "21-02-2026, 00:36:53", "recorded-content": { "put-obj-sse-c-version-1": { "ChecksumCRC32": "gQ5gbg==", "ChecksumType": "FULL_OBJECT", - "ETag": "\"2e00061193ff6efbafd20ee93b0898f2\"", + "ETag": "\"5e8209fe441f4c01aa50431ca1dbbc59\"", "SSECustomerAlgorithm": "AES256", "SSECustomerKeyMD5": "JMwgiexXqwuPqIPjYFmIZQ==", "VersionId": "", @@ -13357,7 +13253,7 @@ "put-obj-sse-c-version-2": { "ChecksumCRC32": "GAcx1A==", "ChecksumType": "FULL_OBJECT", - "ETag": "\"5e5d63b0148e2c6dc33e7d3316be8581\"", + "ETag": "\"715fb6e9472d58a780ca13f8b0ac891e\"", "SSECustomerAlgorithm": "AES256", "SSECustomerKeyMD5": "KoitZ78ZSAQHz4+gxDpJqQ==", "VersionId": "", @@ -13373,7 +13269,7 @@ "ChecksumType": "FULL_OBJECT", "ContentLength": 8, "ContentType": "binary/octet-stream", - "ETag": "\"5e5d63b0148e2c6dc33e7d3316be8581\"", + "ETag": "\"715fb6e9472d58a780ca13f8b0ac891e\"", "LastModified": "datetime", "Metadata": {}, "SSECustomerAlgorithm": "AES256", @@ -13391,7 +13287,7 @@ "ChecksumType": "FULL_OBJECT", "ContentLength": 8, "ContentType": "binary/octet-stream", - "ETag": "\"5e5d63b0148e2c6dc33e7d3316be8581\"", + "ETag": "\"715fb6e9472d58a780ca13f8b0ac891e\"", "LastModified": "datetime", "Metadata": {}, "SSECustomerAlgorithm": "AES256", @@ -13419,7 +13315,7 @@ "ChecksumType": "FULL_OBJECT", "ContentLength": 8, "ContentType": "binary/octet-stream", - "ETag": "\"2e00061193ff6efbafd20ee93b0898f2\"", + "ETag": "\"5e8209fe441f4c01aa50431ca1dbbc59\"", "LastModified": "datetime", "Metadata": {}, "SSECustomerAlgorithm": "AES256", @@ -13433,7 +13329,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3::test_s3_copy_tagging_directive_versioned[COPY]": { - "recorded-date": "21-01-2025, 18:29:02", + "recorded-date": "21-02-2026, 00:19:10", "recorded-content": { "put-object": { "ChecksumCRC32": "2H9+DA==", @@ -13486,6 +13382,7 @@ "copy-object": { "CopyObjectResult": { "ChecksumCRC32": "BnpCOA==", + "ChecksumType": "FULL_OBJECT", "ETag": "\"c814444dd0b31747f0a59e12a5351daa\"", "LastModified": "datetime" }, @@ -13513,6 +13410,7 @@ "copy-object-tag-empty": { "CopyObjectResult": { "ChecksumCRC32": "BnpCOA==", + "ChecksumType": "FULL_OBJECT", "ETag": "\"c814444dd0b31747f0a59e12a5351daa\"", "LastModified": "datetime" }, @@ -13540,6 +13438,7 @@ "copy-object-v1": { "CopyObjectResult": { "ChecksumCRC32": "2H9+DA==", + "ChecksumType": "FULL_OBJECT", "ETag": "\"098f6bcd4621d373cade4e832627b4f6\"", "LastModified": "datetime" }, @@ -13567,6 +13466,7 @@ "copy-object-tag-empty-v1": { "CopyObjectResult": { "ChecksumCRC32": "2H9+DA==", + "ChecksumType": "FULL_OBJECT", "ETag": "\"098f6bcd4621d373cade4e832627b4f6\"", "LastModified": "datetime" }, @@ -13594,7 +13494,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3::test_s3_copy_tagging_directive_versioned[REPLACE]": { - "recorded-date": "21-01-2025, 18:29:06", + "recorded-date": "21-02-2026, 00:19:14", "recorded-content": { "put-object": { "ChecksumCRC32": "2H9+DA==", @@ -13647,6 +13547,7 @@ "copy-object": { "CopyObjectResult": { "ChecksumCRC32": "BnpCOA==", + "ChecksumType": "FULL_OBJECT", "ETag": "\"c814444dd0b31747f0a59e12a5351daa\"", "LastModified": "datetime" }, @@ -13674,6 +13575,7 @@ "copy-object-tag-empty": { "CopyObjectResult": { "ChecksumCRC32": "BnpCOA==", + "ChecksumType": "FULL_OBJECT", "ETag": "\"c814444dd0b31747f0a59e12a5351daa\"", "LastModified": "datetime" }, @@ -13696,6 +13598,7 @@ "copy-object-v1": { "CopyObjectResult": { "ChecksumCRC32": "2H9+DA==", + "ChecksumType": "FULL_OBJECT", "ETag": "\"098f6bcd4621d373cade4e832627b4f6\"", "LastModified": "datetime" }, @@ -13723,6 +13626,7 @@ "copy-object-tag-empty-v1": { "CopyObjectResult": { "ChecksumCRC32": "2H9+DA==", + "ChecksumType": "FULL_OBJECT", "ETag": "\"098f6bcd4621d373cade4e832627b4f6\"", "LastModified": "datetime" }, @@ -13745,7 +13649,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3::test_s3_copy_tagging_directive_versioned[None]": { - "recorded-date": "21-01-2025, 18:29:10", + "recorded-date": "21-02-2026, 00:19:18", "recorded-content": { "put-object": { "ChecksumCRC32": "2H9+DA==", @@ -13798,6 +13702,7 @@ "copy-object": { "CopyObjectResult": { "ChecksumCRC32": "BnpCOA==", + "ChecksumType": "FULL_OBJECT", "ETag": "\"c814444dd0b31747f0a59e12a5351daa\"", "LastModified": "datetime" }, @@ -13825,6 +13730,7 @@ "copy-object-tag-empty": { "CopyObjectResult": { "ChecksumCRC32": "BnpCOA==", + "ChecksumType": "FULL_OBJECT", "ETag": "\"c814444dd0b31747f0a59e12a5351daa\"", "LastModified": "datetime" }, @@ -13852,6 +13758,7 @@ "copy-object-v1": { "CopyObjectResult": { "ChecksumCRC32": "2H9+DA==", + "ChecksumType": "FULL_OBJECT", "ETag": "\"098f6bcd4621d373cade4e832627b4f6\"", "LastModified": "datetime" }, @@ -13879,6 +13786,7 @@ "copy-object-tag-empty-v1": { "CopyObjectResult": { "ChecksumCRC32": "2H9+DA==", + "ChecksumType": "FULL_OBJECT", "ETag": "\"098f6bcd4621d373cade4e832627b4f6\"", "LastModified": "datetime" }, @@ -13906,10 +13814,11 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3::test_region_header_exists_outside_us_east_1": { - "recorded-date": "21-01-2025, 18:26:20", + "recorded-date": "21-02-2026, 00:16:55", "recorded-content": { "head_bucket": { "AccessPointAlias": false, + "BucketArn": "arn::s3:::", "BucketRegion": "", "ResponseMetadata": { "HTTPHeaders": {}, @@ -13931,7 +13840,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3::test_get_bucket_policy": { - "recorded-date": "21-01-2025, 18:27:51", + "recorded-date": "21-02-2026, 00:18:28", "recorded-content": { "get-bucket-policy-no-such-bucket-policy": { "Error": { @@ -13995,7 +13904,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3::test_delete_bucket_policy": { - "recorded-date": "21-01-2025, 18:28:06", + "recorded-date": "21-02-2026, 00:18:46", "recorded-content": { "delete-bucket-policy": { "ResponseMetadata": { @@ -14017,7 +13926,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3::test_put_bucket_policy": { - "recorded-date": "21-01-2025, 18:27:58", + "recorded-date": "21-02-2026, 00:18:36", "recorded-content": { "put-bucket-policy": { "ResponseMetadata": { @@ -14047,7 +13956,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3::test_delete_bucket_policy_expected_bucket_owner": { - "recorded-date": "21-01-2025, 18:50:24", + "recorded-date": "21-02-2026, 00:18:49", "recorded-content": { "delete-bucket-policy-with-expected-bucket-owner-error": { "Error": { @@ -14078,7 +13987,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3::test_put_bucket_policy_expected_bucket_owner": { - "recorded-date": "21-01-2025, 18:50:21", + "recorded-date": "21-02-2026, 00:18:39", "recorded-content": { "put-bucket-policy-with-expected-bucket-owner-error": { "Error": { @@ -14099,7 +14008,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3::test_get_bucket_policy_invalid_account_id[0000]": { - "recorded-date": "21-01-2025, 18:27:52", + "recorded-date": "21-02-2026, 00:18:30", "recorded-content": { "get-bucket-policy-invalid-bucket-owner": { "Error": { @@ -14114,7 +14023,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3::test_get_bucket_policy_invalid_account_id[0000000000020]": { - "recorded-date": "21-01-2025, 18:27:53", + "recorded-date": "21-02-2026, 00:18:31", "recorded-content": { "get-bucket-policy-invalid-bucket-owner": { "Error": { @@ -14129,7 +14038,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3::test_get_bucket_policy_invalid_account_id[abcd]": { - "recorded-date": "21-01-2025, 18:27:55", + "recorded-date": "21-02-2026, 00:18:33", "recorded-content": { "get-bucket-policy-invalid-bucket-owner": { "Error": { @@ -14144,7 +14053,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3::test_get_bucket_policy_invalid_account_id[aa000000000$]": { - "recorded-date": "21-01-2025, 18:27:56", + "recorded-date": "21-02-2026, 00:18:34", "recorded-content": { "get-bucket-policy-invalid-bucket-owner": { "Error": { @@ -14159,7 +14068,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3::test_put_bucket_policy_invalid_account_id[0000]": { - "recorded-date": "21-01-2025, 18:28:00", + "recorded-date": "21-02-2026, 00:18:40", "recorded-content": { "put-bucket-policy-invalid-bucket-owner": { "Error": { @@ -14174,7 +14083,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3::test_put_bucket_policy_invalid_account_id[0000000000020]": { - "recorded-date": "21-01-2025, 18:28:01", + "recorded-date": "21-02-2026, 00:18:41", "recorded-content": { "put-bucket-policy-invalid-bucket-owner": { "Error": { @@ -14189,7 +14098,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3::test_put_bucket_policy_invalid_account_id[abcd]": { - "recorded-date": "21-01-2025, 18:28:03", + "recorded-date": "21-02-2026, 00:18:43", "recorded-content": { "put-bucket-policy-invalid-bucket-owner": { "Error": { @@ -14204,7 +14113,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3::test_put_bucket_policy_invalid_account_id[aa000000000$]": { - "recorded-date": "21-01-2025, 18:28:04", + "recorded-date": "21-02-2026, 00:18:44", "recorded-content": { "put-bucket-policy-invalid-bucket-owner": { "Error": { @@ -14219,7 +14128,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3PutObjectChecksum::test_s3_get_object_checksum[CRC64NVME]": { - "recorded-date": "17-03-2025, 18:28:57", + "recorded-date": "21-02-2026, 00:38:19", "recorded-content": { "put-object": { "ChecksumCRC64NVME": "1f2xscCCZCU=", @@ -14293,7 +14202,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3::test_put_get_object_single_character_trailing_slash": { - "recorded-date": "22-01-2025, 19:05:31", + "recorded-date": "21-02-2026, 00:17:40", "recorded-content": { "put-object-single-char-a/": { "ChecksumCRC32": "2H9+DA==", @@ -14423,7 +14332,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3::test_s3_copy_object_with_checksum[CRC64NVME]": { - "recorded-date": "24-01-2025, 19:06:38", + "recorded-date": "21-02-2026, 00:20:02", "recorded-content": { "put-object-no-checksum": { "ChecksumCRC32": "MzVIGw==", @@ -14449,6 +14358,7 @@ "copy-object-in-place-with-checksum": { "CopyObjectResult": { "ChecksumCRC64NVME": "pX30eiUx5C0=", + "ChecksumType": "FULL_OBJECT", "ETag": "\"88bac95f31528d13a072c05f2a1cf371\"", "LastModified": "datetime" }, @@ -14472,6 +14382,7 @@ "copy-object-to-dest-keep-checksum": { "CopyObjectResult": { "ChecksumCRC64NVME": "pX30eiUx5C0=", + "ChecksumType": "FULL_OBJECT", "ETag": "\"88bac95f31528d13a072c05f2a1cf371\"", "LastModified": "datetime" }, @@ -14484,7 +14395,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3PutObjectChecksum::test_put_object_checksum[CRC64NVME]": { - "recorded-date": "17-03-2025, 18:28:43", + "recorded-date": "21-02-2026, 00:38:04", "recorded-content": { "put-wrong-checksum-no-b64": { "Error": { @@ -14568,7 +14479,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3PutObjectChecksum::test_s3_checksum_no_automatic_sdk_calculation": { - "recorded-date": "17-03-2025, 22:25:43", + "recorded-date": "21-02-2026, 00:38:31", "recorded-content": { "wrong-checksum": { "Error": { @@ -14652,6 +14563,7 @@ "copy-obj-default-checksum": { "CopyObjectResult": { "ChecksumCRC64NVME": "qUVrWYOrIAM=", + "ChecksumType": "FULL_OBJECT", "ETag": "\"e6d9226c2a86b7232933663c13467527\"", "LastModified": "datetime" }, @@ -14675,7 +14587,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3MultipartUploadChecksum::test_complete_multipart_parts_checksum_composite[CRC32]": { - "recorded-date": "07-07-2025, 17:39:49", + "recorded-date": "21-02-2026, 00:38:39", "recorded-content": { "create-mpu-checksum": { "Bucket": "bucket", @@ -14729,7 +14641,6 @@ "MaxParts": 1000, "NextPartNumberMarker": 3, "Owner": { - "DisplayName": "display-name", "ID": "i-d" }, "PartNumberMarker": 0, @@ -14768,7 +14679,7 @@ "Code": "InvalidPart", "ETag": "c4c753e69bb853187f5854c46cf801c6", "Message": "One or more of the specified parts could not be found. The part may not have been uploaded, or the specified entity tag may not match the part's entity tag.", - "PartNumber": "2", + "PartNumber": "1", "UploadId": "" }, "ResponseMetadata": { @@ -14869,6 +14780,7 @@ "copy-obj-checksum": { "CopyObjectResult": { "ChecksumCRC32": "qSEQSA==", + "ChecksumType": "FULL_OBJECT", "ETag": "\"a0397ee2df08832642af5d7e57c5760c\"", "LastModified": "datetime" }, @@ -14911,7 +14823,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3MultipartUploadChecksum::test_complete_multipart_parts_checksum_composite[CRC32C]": { - "recorded-date": "07-07-2025, 17:40:10", + "recorded-date": "21-02-2026, 00:38:48", "recorded-content": { "create-mpu-checksum": { "Bucket": "bucket", @@ -14965,7 +14877,6 @@ "MaxParts": 1000, "NextPartNumberMarker": 3, "Owner": { - "DisplayName": "display-name", "ID": "i-d" }, "PartNumberMarker": 0, @@ -15004,7 +14915,7 @@ "Code": "InvalidPart", "ETag": "c4c753e69bb853187f5854c46cf801c6", "Message": "One or more of the specified parts could not be found. The part may not have been uploaded, or the specified entity tag may not match the part's entity tag.", - "PartNumber": "1", + "PartNumber": "2", "UploadId": "" }, "ResponseMetadata": { @@ -15105,6 +15016,7 @@ "copy-obj-checksum": { "CopyObjectResult": { "ChecksumCRC32C": "eTdAQA==", + "ChecksumType": "FULL_OBJECT", "ETag": "\"a0397ee2df08832642af5d7e57c5760c\"", "LastModified": "datetime" }, @@ -15147,7 +15059,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3MultipartUploadChecksum::test_complete_multipart_parts_checksum_composite[SHA1]": { - "recorded-date": "07-07-2025, 17:40:50", + "recorded-date": "21-02-2026, 00:38:55", "recorded-content": { "create-mpu-checksum": { "Bucket": "bucket", @@ -15201,7 +15113,6 @@ "MaxParts": 1000, "NextPartNumberMarker": 3, "Owner": { - "DisplayName": "display-name", "ID": "i-d" }, "PartNumberMarker": 0, @@ -15238,9 +15149,9 @@ "complete-multipart-wrong-parts-checksum": { "Error": { "Code": "InvalidPart", - "ETag": "c4c753e69bb853187f5854c46cf801c6", + "ETag": "e09c80c42fda55f9d992e59ca6b3307d", "Message": "One or more of the specified parts could not be found. The part may not have been uploaded, or the specified entity tag may not match the part's entity tag.", - "PartNumber": "2", + "PartNumber": "3", "UploadId": "" }, "ResponseMetadata": { @@ -15341,6 +15252,7 @@ "copy-obj-checksum": { "CopyObjectResult": { "ChecksumSHA1": "eIC+AqBqApUmeqCBQ+9n8OVTP+8=", + "ChecksumType": "FULL_OBJECT", "ETag": "\"a0397ee2df08832642af5d7e57c5760c\"", "LastModified": "datetime" }, @@ -15383,7 +15295,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3MultipartUploadChecksum::test_complete_multipart_parts_checksum_composite[SHA256]": { - "recorded-date": "07-07-2025, 17:41:10", + "recorded-date": "21-02-2026, 00:39:02", "recorded-content": { "create-mpu-checksum": { "Bucket": "bucket", @@ -15437,7 +15349,6 @@ "MaxParts": 1000, "NextPartNumberMarker": 3, "Owner": { - "DisplayName": "display-name", "ID": "i-d" }, "PartNumberMarker": 0, @@ -15474,9 +15385,9 @@ "complete-multipart-wrong-parts-checksum": { "Error": { "Code": "InvalidPart", - "ETag": "c4c753e69bb853187f5854c46cf801c6", + "ETag": "e09c80c42fda55f9d992e59ca6b3307d", "Message": "One or more of the specified parts could not be found. The part may not have been uploaded, or the specified entity tag may not match the part's entity tag.", - "PartNumber": "1", + "PartNumber": "3", "UploadId": "" }, "ResponseMetadata": { @@ -15577,6 +15488,7 @@ "copy-obj-checksum": { "CopyObjectResult": { "ChecksumSHA256": "0+991zqhqOQ5J2EdwChmHIeC1dXXuJzaCritTzqVGDw=", + "ChecksumType": "FULL_OBJECT", "ETag": "\"a0397ee2df08832642af5d7e57c5760c\"", "LastModified": "datetime" }, @@ -15619,7 +15531,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3MultipartUploadChecksum::test_multipart_checksum_type_compatibility[COMPOSITE-CRC32]": { - "recorded-date": "15-06-2025, 17:09:49", + "recorded-date": "21-02-2026, 00:39:03", "recorded-content": { "create-mpu-checksum": { "Bucket": "bucket", @@ -15636,7 +15548,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3MultipartUploadChecksum::test_multipart_checksum_type_compatibility[COMPOSITE-CRC32C]": { - "recorded-date": "15-06-2025, 17:09:50", + "recorded-date": "21-02-2026, 00:39:05", "recorded-content": { "create-mpu-checksum": { "Bucket": "bucket", @@ -15653,7 +15565,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3MultipartUploadChecksum::test_multipart_checksum_type_compatibility[COMPOSITE-SHA1]": { - "recorded-date": "15-06-2025, 17:09:52", + "recorded-date": "21-02-2026, 00:39:06", "recorded-content": { "create-mpu-checksum": { "Bucket": "bucket", @@ -15670,7 +15582,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3MultipartUploadChecksum::test_multipart_checksum_type_compatibility[COMPOSITE-SHA256]": { - "recorded-date": "15-06-2025, 17:09:53", + "recorded-date": "21-02-2026, 00:39:07", "recorded-content": { "create-mpu-checksum": { "Bucket": "bucket", @@ -15687,7 +15599,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3MultipartUploadChecksum::test_multipart_checksum_type_compatibility[COMPOSITE-CRC64NVME]": { - "recorded-date": "15-06-2025, 17:09:54", + "recorded-date": "21-02-2026, 00:39:08", "recorded-content": { "create-mpu-checksum-exc": { "Error": { @@ -15702,7 +15614,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3MultipartUploadChecksum::test_multipart_checksum_type_compatibility[FULL_OBJECT-CRC32]": { - "recorded-date": "15-06-2025, 17:09:56", + "recorded-date": "21-02-2026, 00:39:10", "recorded-content": { "create-mpu-checksum": { "Bucket": "bucket", @@ -15719,7 +15631,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3MultipartUploadChecksum::test_multipart_checksum_type_compatibility[FULL_OBJECT-CRC32C]": { - "recorded-date": "15-06-2025, 17:09:57", + "recorded-date": "21-02-2026, 00:39:11", "recorded-content": { "create-mpu-checksum": { "Bucket": "bucket", @@ -15736,7 +15648,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3MultipartUploadChecksum::test_multipart_checksum_type_compatibility[FULL_OBJECT-SHA1]": { - "recorded-date": "15-06-2025, 17:09:58", + "recorded-date": "21-02-2026, 00:39:12", "recorded-content": { "create-mpu-checksum-exc": { "Error": { @@ -15751,7 +15663,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3MultipartUploadChecksum::test_multipart_checksum_type_compatibility[FULL_OBJECT-SHA256]": { - "recorded-date": "15-06-2025, 17:10:00", + "recorded-date": "21-02-2026, 00:39:14", "recorded-content": { "create-mpu-checksum-exc": { "Error": { @@ -15766,7 +15678,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3MultipartUploadChecksum::test_multipart_checksum_type_compatibility[FULL_OBJECT-CRC64NVME]": { - "recorded-date": "15-06-2025, 17:10:01", + "recorded-date": "21-02-2026, 00:39:16", "recorded-content": { "create-mpu-checksum": { "Bucket": "bucket", @@ -15783,7 +15695,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3MultipartUploadChecksum::test_multipart_checksum_type_default_for_checksum[CRC32]": { - "recorded-date": "15-06-2025, 17:10:03", + "recorded-date": "21-02-2026, 00:39:17", "recorded-content": { "create-mpu-default-checksum-type": { "Bucket": "bucket", @@ -15800,7 +15712,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3MultipartUploadChecksum::test_multipart_checksum_type_default_for_checksum[CRC32C]": { - "recorded-date": "15-06-2025, 17:10:04", + "recorded-date": "21-02-2026, 00:39:18", "recorded-content": { "create-mpu-default-checksum-type": { "Bucket": "bucket", @@ -15817,7 +15729,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3MultipartUploadChecksum::test_multipart_checksum_type_default_for_checksum[SHA1]": { - "recorded-date": "15-06-2025, 17:10:05", + "recorded-date": "21-02-2026, 00:39:19", "recorded-content": { "create-mpu-default-checksum-type": { "Bucket": "bucket", @@ -15834,7 +15746,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3MultipartUploadChecksum::test_multipart_checksum_type_default_for_checksum[SHA256]": { - "recorded-date": "15-06-2025, 17:10:07", + "recorded-date": "21-02-2026, 00:39:21", "recorded-content": { "create-mpu-default-checksum-type": { "Bucket": "bucket", @@ -15851,7 +15763,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3MultipartUploadChecksum::test_multipart_checksum_type_default_for_checksum[CRC64NVME]": { - "recorded-date": "15-06-2025, 17:10:08", + "recorded-date": "21-02-2026, 00:39:22", "recorded-content": { "create-mpu-default-checksum-type": { "Bucket": "bucket", @@ -15868,7 +15780,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3MultipartUploadChecksum::test_complete_multipart_parts_checksum_full_object[CRC32]": { - "recorded-date": "07-07-2025, 17:41:34", + "recorded-date": "21-02-2026, 00:40:50", "recorded-content": { "create-mpu-checksum": { "Bucket": "bucket", @@ -15922,7 +15834,6 @@ "MaxParts": 1000, "NextPartNumberMarker": 3, "Owner": { - "DisplayName": "display-name", "ID": "i-d" }, "PartNumberMarker": 0, @@ -16031,6 +15942,7 @@ "copy-obj-checksum": { "CopyObjectResult": { "ChecksumCRC32": "qSEQSA==", + "ChecksumType": "FULL_OBJECT", "ETag": "\"a0397ee2df08832642af5d7e57c5760c\"", "LastModified": "datetime" }, @@ -16071,7 +15983,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3MultipartUploadChecksum::test_complete_multipart_parts_checksum_full_object[CRC32C]": { - "recorded-date": "07-07-2025, 17:41:53", + "recorded-date": "21-02-2026, 00:40:57", "recorded-content": { "create-mpu-checksum": { "Bucket": "bucket", @@ -16125,7 +16037,6 @@ "MaxParts": 1000, "NextPartNumberMarker": 3, "Owner": { - "DisplayName": "display-name", "ID": "i-d" }, "PartNumberMarker": 0, @@ -16164,7 +16075,7 @@ "Code": "InvalidPart", "ETag": "c4c753e69bb853187f5854c46cf801c6", "Message": "One or more of the specified parts could not be found. The part may not have been uploaded, or the specified entity tag may not match the part's entity tag.", - "PartNumber": "2", + "PartNumber": "1", "UploadId": "" }, "ResponseMetadata": { @@ -16234,6 +16145,7 @@ "copy-obj-checksum": { "CopyObjectResult": { "ChecksumCRC32C": "eTdAQA==", + "ChecksumType": "FULL_OBJECT", "ETag": "\"a0397ee2df08832642af5d7e57c5760c\"", "LastModified": "datetime" }, @@ -16274,7 +16186,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3MultipartUploadChecksum::test_complete_multipart_parts_checksum_full_object[CRC64NVME]": { - "recorded-date": "07-07-2025, 17:42:04", + "recorded-date": "21-02-2026, 00:41:04", "recorded-content": { "create-mpu-checksum": { "Bucket": "bucket", @@ -16328,7 +16240,6 @@ "MaxParts": 1000, "NextPartNumberMarker": 3, "Owner": { - "DisplayName": "display-name", "ID": "i-d" }, "PartNumberMarker": 0, @@ -16437,6 +16348,7 @@ "copy-obj-checksum": { "CopyObjectResult": { "ChecksumCRC64NVME": "ZMNX55lZurA=", + "ChecksumType": "FULL_OBJECT", "ETag": "\"a0397ee2df08832642af5d7e57c5760c\"", "LastModified": "datetime" }, @@ -16477,7 +16389,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3MultipartUploadChecksum::test_multipart_parts_checksum_exceptions_full_object": { - "recorded-date": "15-06-2025, 17:12:51", + "recorded-date": "21-02-2026, 00:42:04", "recorded-content": { "create-mpu-no-checksum-algo-with-type": { "Error": { @@ -16520,7 +16432,6 @@ }, "Key": "test-multipart-checksum-exc", "Owner": { - "DisplayName": "display-name", "ID": "i-d" }, "StorageClass": "STANDARD", @@ -16639,7 +16550,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3MultipartUploadChecksum::test_complete_multipart_parts_checksum_default": { - "recorded-date": "15-06-2025, 17:12:56", + "recorded-date": "21-02-2026, 00:42:09", "recorded-content": { "create-mpu-no-checksum": { "Bucket": "bucket", @@ -16668,7 +16579,6 @@ }, "Key": "test-multipart-checksum", "Owner": { - "DisplayName": "display-name", "ID": "i-d" }, "StorageClass": "STANDARD", @@ -16700,7 +16610,6 @@ "MaxParts": 1000, "NextPartNumberMarker": 1, "Owner": { - "DisplayName": "display-name", "ID": "i-d" }, "PartNumberMarker": 0, @@ -16827,6 +16736,7 @@ "copy-obj-checksum": { "CopyObjectResult": { "ChecksumCRC64NVME": "Rnr2/5P7Gsk=", + "ChecksumType": "FULL_OBJECT", "ETag": "\"47bce5c74f589f4867dbd57e9ca9f808\"", "LastModified": "datetime" }, @@ -16851,7 +16761,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3MultipartUploadChecksum::test_multipart_size_validation": { - "recorded-date": "15-06-2025, 17:13:01", + "recorded-date": "21-02-2026, 00:42:14", "recorded-content": { "create-mpu": { "Bucket": "bucket", @@ -16910,7 +16820,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3MultipartUploadChecksum::test_multipart_upload_part_checksum_exception[CRC32]": { - "recorded-date": "15-06-2025, 17:10:17", + "recorded-date": "21-02-2026, 00:39:37", "recorded-content": { "put-wrong-checksum-no-b64": { "Error": { @@ -16935,7 +16845,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3MultipartUploadChecksum::test_multipart_upload_part_checksum_exception[CRC32C]": { - "recorded-date": "15-06-2025, 17:10:27", + "recorded-date": "21-02-2026, 00:39:48", "recorded-content": { "put-wrong-checksum-no-b64": { "Error": { @@ -16960,7 +16870,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3MultipartUploadChecksum::test_multipart_upload_part_checksum_exception[SHA1]": { - "recorded-date": "15-06-2025, 17:10:44", + "recorded-date": "21-02-2026, 00:40:02", "recorded-content": { "put-wrong-checksum-no-b64": { "Error": { @@ -16985,7 +16895,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3MultipartUploadChecksum::test_multipart_upload_part_checksum_exception[SHA256]": { - "recorded-date": "15-06-2025, 17:10:59", + "recorded-date": "21-02-2026, 00:40:15", "recorded-content": { "put-wrong-checksum-no-b64": { "Error": { @@ -17010,7 +16920,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3MultipartUploadChecksum::test_multipart_upload_part_checksum_exception[CRC64NVME]": { - "recorded-date": "15-06-2025, 17:11:10", + "recorded-date": "21-02-2026, 00:40:29", "recorded-content": { "put-wrong-checksum-no-b64": { "Error": { @@ -17035,7 +16945,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3BucketLifecycle::test_s3_transition_default_minimum_object_size": { - "recorded-date": "03-02-2025, 10:15:23", + "recorded-date": "21-02-2026, 00:33:46", "recorded-content": { "varies-by-storage": { "TransitionDefaultMinimumObjectSize": "varies_by_storage_class", @@ -17128,7 +17038,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3MultipartUploadChecksum::test_complete_multipart_parts_checksum_full_object_default": { - "recorded-date": "15-06-2025, 17:12:58", + "recorded-date": "21-02-2026, 00:42:11", "recorded-content": { "create-mpu-checksum-crc64": { "Bucket": "bucket", @@ -17213,7 +17123,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3PresignedPost::test_post_object_default_checksum": { - "recorded-date": "17-03-2025, 21:46:24", + "recorded-date": "21-02-2026, 00:35:55", "recorded-content": { "head-object": { "AcceptRanges": "bytes", @@ -17233,7 +17143,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3::test_s3_copy_object_with_default_checksum[CRC32]": { - "recorded-date": "17-03-2025, 22:17:03", + "recorded-date": "21-02-2026, 00:20:04", "recorded-content": { "put-object-no-checksum": { "ChecksumCRC32": "MzVIGw==", @@ -17259,6 +17169,7 @@ "copy-object-in-place-with-no-checksum": { "CopyObjectResult": { "ChecksumCRC32": "MzVIGw==", + "ChecksumType": "FULL_OBJECT", "ETag": "\"88bac95f31528d13a072c05f2a1cf371\"", "LastModified": "datetime" }, @@ -17282,6 +17193,7 @@ "copy-object-to-dest-keep-checksum": { "CopyObjectResult": { "ChecksumCRC32": "MzVIGw==", + "ChecksumType": "FULL_OBJECT", "ETag": "\"88bac95f31528d13a072c05f2a1cf371\"", "LastModified": "datetime" }, @@ -17305,7 +17217,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3::test_s3_copy_object_with_default_checksum[CRC32C]": { - "recorded-date": "17-03-2025, 22:17:06", + "recorded-date": "21-02-2026, 00:20:07", "recorded-content": { "put-object-no-checksum": { "ChecksumCRC32C": "078Ilw==", @@ -17331,6 +17243,7 @@ "copy-object-in-place-with-no-checksum": { "CopyObjectResult": { "ChecksumCRC32C": "078Ilw==", + "ChecksumType": "FULL_OBJECT", "ETag": "\"88bac95f31528d13a072c05f2a1cf371\"", "LastModified": "datetime" }, @@ -17354,6 +17267,7 @@ "copy-object-to-dest-keep-checksum": { "CopyObjectResult": { "ChecksumCRC32C": "078Ilw==", + "ChecksumType": "FULL_OBJECT", "ETag": "\"88bac95f31528d13a072c05f2a1cf371\"", "LastModified": "datetime" }, @@ -17377,7 +17291,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3::test_s3_copy_object_with_default_checksum[SHA1]": { - "recorded-date": "17-03-2025, 22:17:08", + "recorded-date": "21-02-2026, 00:20:09", "recorded-content": { "put-object-no-checksum": { "ChecksumSHA1": "5zXdjmjYk4EJ8Cw4PMnQVslCpRQ=", @@ -17403,6 +17317,7 @@ "copy-object-in-place-with-no-checksum": { "CopyObjectResult": { "ChecksumSHA1": "5zXdjmjYk4EJ8Cw4PMnQVslCpRQ=", + "ChecksumType": "FULL_OBJECT", "ETag": "\"88bac95f31528d13a072c05f2a1cf371\"", "LastModified": "datetime" }, @@ -17426,6 +17341,7 @@ "copy-object-to-dest-keep-checksum": { "CopyObjectResult": { "ChecksumSHA1": "5zXdjmjYk4EJ8Cw4PMnQVslCpRQ=", + "ChecksumType": "FULL_OBJECT", "ETag": "\"88bac95f31528d13a072c05f2a1cf371\"", "LastModified": "datetime" }, @@ -17449,7 +17365,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3::test_s3_copy_object_with_default_checksum[SHA256]": { - "recorded-date": "17-03-2025, 22:17:11", + "recorded-date": "21-02-2026, 00:20:12", "recorded-content": { "put-object-no-checksum": { "ChecksumSHA256": "lyTB4g5uPk1/V+0l+dTvsAblCFkNUoyQ2ll/andcE+U=", @@ -17475,6 +17391,7 @@ "copy-object-in-place-with-no-checksum": { "CopyObjectResult": { "ChecksumSHA256": "lyTB4g5uPk1/V+0l+dTvsAblCFkNUoyQ2ll/andcE+U=", + "ChecksumType": "FULL_OBJECT", "ETag": "\"88bac95f31528d13a072c05f2a1cf371\"", "LastModified": "datetime" }, @@ -17498,6 +17415,7 @@ "copy-object-to-dest-keep-checksum": { "CopyObjectResult": { "ChecksumSHA256": "lyTB4g5uPk1/V+0l+dTvsAblCFkNUoyQ2ll/andcE+U=", + "ChecksumType": "FULL_OBJECT", "ETag": "\"88bac95f31528d13a072c05f2a1cf371\"", "LastModified": "datetime" }, @@ -17521,7 +17439,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3::test_s3_copy_object_with_default_checksum[CRC64NVME]": { - "recorded-date": "17-03-2025, 22:17:13", + "recorded-date": "21-02-2026, 00:20:14", "recorded-content": { "put-object-no-checksum": { "ChecksumCRC64NVME": "pX30eiUx5C0=", @@ -17547,6 +17465,7 @@ "copy-object-in-place-with-no-checksum": { "CopyObjectResult": { "ChecksumCRC64NVME": "pX30eiUx5C0=", + "ChecksumType": "FULL_OBJECT", "ETag": "\"88bac95f31528d13a072c05f2a1cf371\"", "LastModified": "datetime" }, @@ -17570,6 +17489,7 @@ "copy-object-to-dest-keep-checksum": { "CopyObjectResult": { "ChecksumCRC64NVME": "pX30eiUx5C0=", + "ChecksumType": "FULL_OBJECT", "ETag": "\"88bac95f31528d13a072c05f2a1cf371\"", "LastModified": "datetime" }, @@ -17593,7 +17513,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3SSECEncryption::test_put_object_default_checksum_with_sse_c": { - "recorded-date": "17-03-2025, 23:22:53", + "recorded-date": "21-02-2026, 00:36:56", "recorded-content": { "head-obj-sse-c": { "AcceptRanges": "bytes", @@ -17601,7 +17521,7 @@ "ChecksumType": "FULL_OBJECT", "ContentLength": 11, "ContentType": "binary/octet-stream", - "ETag": "\"14838aba23aac65c8befbb53acf51014\"", + "ETag": "\"a5d8837e2a881c286b90c0586f2869de\"", "LastModified": "datetime", "Metadata": {}, "SSECustomerAlgorithm": "AES256", @@ -17618,7 +17538,7 @@ "ChecksumType": "FULL_OBJECT", "ContentLength": 11, "ContentType": "binary/octet-stream", - "ETag": "\"14838aba23aac65c8befbb53acf51014\"", + "ETag": "\"a5d8837e2a881c286b90c0586f2869de\"", "LastModified": "datetime", "Metadata": {}, "SSECustomerAlgorithm": "AES256", @@ -17633,7 +17553,7 @@ "ChecksumCRC64NVME": "qUVrWYOrIAM=", "ChecksumType": "FULL_OBJECT" }, - "ETag": "14838aba23aac65c8befbb53acf51014", + "ETag": "a5d8837e2a881c286b90c0586f2869de", "LastModified": "datetime", "ResponseMetadata": { "HTTPHeaders": {}, @@ -17643,7 +17563,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3MultipartUploadChecksum::test_multipart_upload_part_copy_checksum[COMPOSITE]": { - "recorded-date": "16-06-2025, 10:53:39", + "recorded-date": "21-02-2026, 00:42:17", "recorded-content": { "put-object": { "ChecksumCRC32": "nG7pIA==", @@ -17692,7 +17612,6 @@ "MaxParts": 1000, "NextPartNumberMarker": 1, "Owner": { - "DisplayName": "display-name", "ID": "i-d" }, "PartNumberMarker": 0, @@ -17785,7 +17704,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3MultipartUploadChecksum::test_multipart_upload_part_copy_checksum[FULL_OBJECT]": { - "recorded-date": "16-06-2025, 10:53:42", + "recorded-date": "21-02-2026, 00:42:20", "recorded-content": { "put-object": { "ChecksumCRC32": "nG7pIA==", @@ -17834,7 +17753,6 @@ "MaxParts": 1000, "NextPartNumberMarker": 1, "Owner": { - "DisplayName": "display-name", "ID": "i-d" }, "PartNumberMarker": 0, @@ -17916,7 +17834,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3ObjectLockRetention::test_s3_object_retention_compliance_mode": { - "recorded-date": "20-06-2025, 17:19:56", + "recorded-date": "21-02-2026, 00:34:29", "recorded-content": { "put-obj-locked-1": { "ChecksumCRC32": "2H9+DA==", @@ -17993,7 +17911,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3ObjectLockRetention::test_s3_object_lock_mode_validation": { - "recorded-date": "20-06-2025, 17:33:40", + "recorded-date": "21-02-2026, 00:34:32", "recorded-content": { "put-obj-locked-error-no-retain-date": { "Error": { @@ -18044,7 +17962,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3::test_get_object_part_checksum[COMPOSITE]": { - "recorded-date": "07-07-2025, 18:23:54", + "recorded-date": "21-02-2026, 00:23:01", "recorded-content": { "create-mpu-checksum": { "Bucket": "", @@ -18118,7 +18036,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3::test_get_object_part_checksum[FULL_OBJECT]": { - "recorded-date": "07-07-2025, 18:23:57", + "recorded-date": "21-02-2026, 00:23:03", "recorded-content": { "create-mpu-checksum": { "Bucket": "", @@ -18192,7 +18110,7 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3::test_s3_object_expires": { - "recorded-date": "22-07-2025, 14:00:54", + "recorded-date": "21-02-2026, 00:20:54", "recorded-content": { "put-object-expires-future": { "ChecksumCRC32": "jHNlIQ==", @@ -18281,5 +18199,389 @@ } } } + }, + "tests/aws/services/s3/test_s3.py::TestS3::test_create_bucket_aws_global": { + "recorded-date": "21-02-2026, 00:23:28", + "recorded-content": { + "xml-error-create-bucket": { + "Error": { + "Code": "AuthorizationHeaderMalformed", + "HostId": "", + "Message": "The authorization header is malformed; the region 'aws-global' is wrong; expecting ''", + "Region": "", + "RequestId": "" + } + }, + "create-bucket-global": { + "BucketArn": "arn::s3:::", + "Location": "/", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "head-bucket-global": { + "AccessPointAlias": false, + "BucketArn": "arn::s3:::", + "BucketRegion": "", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "get-location-1": { + "LocationConstraint": null, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "list-buckets": { + "Buckets": [ + { + "BucketArn": "arn::s3:::", + "BucketRegion": "", + "CreationDate": "datetime", + "Name": "" + } + ], + "Owner": { + "ID": "" + }, + "Prefix": "", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/s3/test_s3.py::TestS3::test_bucket_constraint_aws_global[us-east-1]": { + "recorded-date": "21-02-2026, 00:23:29", + "recorded-content": { + "aws-global-constraint": { + "Error": { + "Code": "InvalidLocationConstraint", + "LocationConstraint": "aws-global", + "Message": "The specified location-constraint is not valid" + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + } + } + }, + "tests/aws/services/s3/test_s3.py::TestS3::test_bucket_constraint_aws_global[us-west-1]": { + "recorded-date": "21-02-2026, 00:23:30", + "recorded-content": { + "aws-global-constraint": { + "Error": { + "Code": "IllegalLocationConstraintException", + "Message": "The aws-global location constraint is incompatible for the region specific endpoint this request was sent to." + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + } + } + }, + "tests/aws/services/s3/test_s3.py::TestS3::test_create_bucket_with_eu_location_constraint": { + "recorded-date": "21-02-2026, 00:18:25", + "recorded-content": { + "get-bucket-location": { + "LocationConstraint": "EU", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "list-bucket-response": { + "Buckets": [ + { + "BucketArn": "arn::s3:::", + "BucketRegion": "", + "CreationDate": "datetime", + "Name": "" + } + ], + "Owner": { + "ID": "" + }, + "Prefix": "", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/s3/test_s3.py::TestS3::test_create_bucket_with_eu_location_constraint_raises": { + "recorded-date": "21-02-2026, 00:18:26", + "recorded-content": { + "eu-location-constraint-error": { + "Error": { + "Code": "IllegalLocationConstraintException", + "Message": "The EU location constraint is incompatible for the region specific endpoint this request was sent to." + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + } + } + }, + "tests/aws/services/s3/test_s3.py::TestS3::test_create_bucket_with_invalid_location_constraint[us-east-1-us-east-1]": { + "recorded-date": "21-02-2026, 00:18:26", + "recorded-content": { + "us-east-1-location-constraint-us-east-1-error": { + "Error": { + "Code": "InvalidLocationConstraint", + "LocationConstraint": "", + "Message": "The specified location-constraint is not valid" + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + } + } + }, + "tests/aws/services/s3/test_s3.py::TestS3::test_create_bucket_with_invalid_location_constraint[us-east-1-foo]": { + "recorded-date": "21-02-2026, 00:18:27", + "recorded-content": { + "us-east-1-location-constraint-foo-error": { + "Error": { + "Code": "InvalidLocationConstraint", + "LocationConstraint": "", + "Message": "The specified location-constraint is not valid" + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + } + } + }, + "tests/aws/services/s3/test_s3.py::TestS3::test_create_bucket_with_invalid_location_constraint[eu-west-1-bar]": { + "recorded-date": "21-02-2026, 00:18:27", + "recorded-content": { + "eu-west-1-location-constraint-bar-error": { + "Error": { + "Code": "IllegalLocationConstraintException", + "Message": "The bar location constraint is incompatible for the region specific endpoint this request was sent to." + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + } + } + }, + "tests/aws/services/s3/test_s3.py::TestS3PresignedPost::test_post_object_with_unicode_metadata": { + "recorded-date": "21-02-2026, 00:35:50", + "recorded-content": { + "post-object": { + "LocationHeader": "/test_unicode%E2%80%94_file.pdf", + "PostResponse": { + "Bucket": "", + "ETag": "\"a7d8531d918474360de3e2eaeb110cda\"", + "Key": "test_unicode\u2014_file.pdf", + "Location": "/test_unicode%E2%80%94_file.pdf" + } + }, + "head-object": { + "AcceptRanges": "bytes", + "CacheControl": "non-ascii-%E2%80%94_ _\u00e9_", + "ContentDisposition": "filename=\"test_ _file%E2%80%94_\u00e9_2-.pdf\"", + "ContentLength": 17, + "ContentType": "binary/octet-stream", + "ETag": "\"a7d8531d918474360de3e2eaeb110cda\"", + "LastModified": "datetime", + "Metadata": { + "b-encoded": "=?UTF-8?B?YWJj?=", + "nonascii": "=?UTF-8?Q?=C3=84M=C3=84Z=C3=95=C3=91_S3?=", + "nonascii-2": "=?UTF-8?Q?test=5F=E2=80=94=5Ffile%E2%80%94=5F=C3=A9=5F2=F0=9F=91=91.pdf?=", + "q-encoded": "=?UTF-8?Q?actually-ascii?=", + "safe-chars": "! \"#$%&'()*+,-./0123456789:;<>'?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\t", + "utf-8": "=?UTF-8?B?AAECAwQ=?=" + }, + "ServerSideEncryption": "AES256", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/s3/test_s3.py::TestS3::test_system_metadata_with_unicode": { + "recorded-date": "21-02-2026, 00:17:06", + "recorded-content": { + "put-object": { + "ChecksumCRC32": "AAAAAA==", + "ChecksumType": "FULL_OBJECT", + "ETag": "\"d41d8cd98f00b204e9800998ecf8427e\"", + "ServerSideEncryption": "AES256", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "get-object": { + "AcceptRanges": "bytes", + "Body": "", + "CacheControl": "\u00c3\u0084M\u00c3\u0084Z\u00c3\u0095\u00c3\u0091 S3", + "ChecksumCRC32": "AAAAAA==", + "ChecksumType": "FULL_OBJECT", + "ContentDisposition": "attachment; filename=\"test_\u00e2\u0080\u0094_file%E2%80%94_\u00c3\u00a9_2.pdf\"", + "ContentLanguage": "de", + "ContentLength": 0, + "ContentType": "binary/octet-stream", + "ETag": "\"d41d8cd98f00b204e9800998ecf8427e\"", + "LastModified": "datetime", + "Metadata": {}, + "ServerSideEncryption": "AES256", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/s3/test_s3.py::TestS3PresignedUrl::test_get_response_overrides_unicode_metadata_with_sig_s3": { + "recorded-date": "21-02-2026, 00:29:43", + "recorded-content": { + "unicode-error": { + "Error": { + "ArgumentName": "response-cache-control", + "ArgumentValue": "non-ascii-%E2%80%94_\u2014_\u00e9_", + "Code": "InvalidArgument", + "HostId": "host-id", + "Message": "Header value cannot be represented using ISO-8859-1.", + "RequestId": "" + } + } + } + }, + "tests/aws/services/s3/test_s3.py::TestS3PresignedUrl::test_put_unicode_metadata_with_sig_s3": { + "recorded-date": "21-02-2026, 00:29:45", + "recorded-content": { + "head_object": { + "AcceptRanges": "bytes", + "ContentLength": 0, + "ContentType": "binary/octet-stream", + "ETag": "\"d41d8cd98f00b204e9800998ecf8427e\"", + "LastModified": "datetime", + "Metadata": { + "foo": "=?UTF-8?Q?non-ascii-%E2%80%94=5F=E2=80=94=5F=C3=A9=5F?=" + }, + "ServerSideEncryption": "AES256", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/s3/test_s3.py::TestS3::test_multipart_with_unicode_character_location": { + "recorded-date": "21-02-2026, 00:17:42", + "recorded-content": { + "create-multipart": { + "Bucket": "bucket", + "Key": "test-unicode_\u2014_file", + "ServerSideEncryption": "AES256", + "UploadId": "", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "complete-multipart": { + "Bucket": "bucket", + "ChecksumCRC64NVME": "LPvyvt6AWlQ=", + "ChecksumType": "FULL_OBJECT", + "ETag": "\"209b3f7345bfc0220995968302e3e9a8-1\"", + "Key": "test-unicode_\u2014_file", + "Location": "/test-unicode_%E2%80%94_file", + "ServerSideEncryption": "AES256", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/s3/test_s3.py::TestS3::test_user_metadata_rfc2047_encoded": { + "recorded-date": "21-02-2026, 00:17:08", + "recorded-content": { + "put-object": { + "ChecksumCRC32": "AAAAAA==", + "ChecksumType": "FULL_OBJECT", + "ETag": "\"d41d8cd98f00b204e9800998ecf8427e\"", + "ServerSideEncryption": "AES256", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "get-object": { + "AcceptRanges": "bytes", + "Body": "", + "ChecksumCRC32": "AAAAAA==", + "ChecksumType": "FULL_OBJECT", + "ContentLength": 0, + "ContentType": "binary/octet-stream", + "ETag": "\"d41d8cd98f00b204e9800998ecf8427e\"", + "LastModified": "datetime", + "Metadata": { + "asciib64-encoded": "abc", + "fake-encoded": "actually-ascii", + "non-ascii": "=?UTF-8?Q?test=5F=E2=80=94=5Ffile%E2%80%94=5F=C3=A9=5F2=3F.pdf?=", + "non-ascii-2": "=?UTF-8?Q?=C3=84M=C3=84Z=C3=95=C3=91_S3?=", + "non-ascii-binary": "=?UTF-8?B?AAECAw==?=", + "replacement-chars": "=?UTF-8?B?77+977+977+977+977+977+977+9?=", + "safe-chars": "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~" + }, + "ServerSideEncryption": "AES256", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/s3/test_s3.py::TestS3::test_user_metadata_rfc2047_bad_b64_encoded": { + "recorded-date": "21-02-2026, 00:17:10", + "recorded-content": { + "put-object": { + "ChecksumCRC32": "AAAAAA==", + "ChecksumType": "FULL_OBJECT", + "ETag": "\"d41d8cd98f00b204e9800998ecf8427e\"", + "ServerSideEncryption": "AES256", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "get-object": { + "AcceptRanges": "bytes", + "Body": "", + "ChecksumCRC32": "AAAAAA==", + "ChecksumType": "FULL_OBJECT", + "ContentLength": 0, + "ContentType": "binary/octet-stream", + "ETag": "\"d41d8cd98f00b204e9800998ecf8427e\"", + "LastModified": "datetime", + "Metadata": { + "bad-b64-encoded": "=?UTF-8?B?77+9Ye+/vQ==?=" + }, + "ServerSideEncryption": "AES256", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } } } diff --git a/tests/aws/services/s3/test_s3.validation.json b/tests/aws/services/s3/test_s3.validation.json index 2515de0643734..b2a80621e1be5 100644 --- a/tests/aws/services/s3/test_s3.validation.json +++ b/tests/aws/services/s3/test_s3.validation.json @@ -1,152 +1,470 @@ { "tests/aws/services/s3/test_s3.py::TestS3::test_bucket_availability": { - "last_validated_date": "2025-01-21T18:30:41+00:00" + "last_validated_date": "2026-02-21T00:20:57+00:00", + "durations_in_seconds": { + "setup": 0.01, + "call": 0.44, + "teardown": 0.01, + "total": 0.46 + } + }, + "tests/aws/services/s3/test_s3.py::TestS3::test_bucket_constraint_aws_global[us-east-1]": { + "last_validated_date": "2026-02-21T00:23:29+00:00", + "durations_in_seconds": { + "setup": 0.01, + "call": 0.46, + "teardown": 0.0, + "total": 0.47 + } + }, + "tests/aws/services/s3/test_s3.py::TestS3::test_bucket_constraint_aws_global[us-west-1]": { + "last_validated_date": "2026-02-21T00:23:30+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.63, + "teardown": 0.01, + "total": 0.64 + } }, "tests/aws/services/s3/test_s3.py::TestS3::test_bucket_does_not_exist": { - "last_validated_date": "2025-01-21T18:34:13+00:00" + "last_validated_date": "2026-02-21T00:23:31+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 1.54, + "teardown": 0.0, + "total": 1.54 + } }, "tests/aws/services/s3/test_s3.py::TestS3::test_bucket_exists": { - "last_validated_date": "2025-01-21T18:31:45+00:00" + "last_validated_date": "2026-02-21T00:21:44+00:00", + "durations_in_seconds": { + "setup": 0.53, + "call": 0.85, + "teardown": 0.65, + "total": 2.03 + } }, "tests/aws/services/s3/test_s3.py::TestS3::test_bucket_name_with_dots": { - "last_validated_date": "2025-01-21T18:34:19+00:00" + "last_validated_date": "2026-02-21T00:23:38+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 1.94, + "teardown": 0.94, + "total": 2.88 + } }, "tests/aws/services/s3/test_s3.py::TestS3::test_bucket_operation_between_regions": { - "last_validated_date": "2025-01-21T18:30:52+00:00" + "last_validated_date": "2026-02-21T00:21:09+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 2.78, + "teardown": 0.98, + "total": 3.76 + } }, "tests/aws/services/s3/test_s3.py::TestS3::test_complete_multipart_parts_order": { - "last_validated_date": "2025-03-17T21:30:44+00:00" + "last_validated_date": "2026-02-21T00:28:14+00:00", + "durations_in_seconds": { + "setup": 0.54, + "call": 5.25, + "teardown": 0.99, + "total": 6.78 + } }, "tests/aws/services/s3/test_s3.py::TestS3::test_copy_in_place_with_bucket_encryption": { - "last_validated_date": "2025-01-21T18:29:34+00:00" + "last_validated_date": "2026-02-21T00:19:43+00:00", + "durations_in_seconds": { + "setup": 0.52, + "call": 0.61, + "teardown": 0.95, + "total": 2.08 + } }, "tests/aws/services/s3/test_s3.py::TestS3::test_copy_object_kms": { - "last_validated_date": "2025-01-21T18:26:17+00:00" + "last_validated_date": "2026-02-21T00:16:53+00:00", + "durations_in_seconds": { + "setup": 1.09, + "call": 1.4, + "teardown": 1.07, + "total": 3.56 + } }, "tests/aws/services/s3/test_s3.py::TestS3::test_copy_object_special_character": { - "last_validated_date": "2025-01-21T18:27:00+00:00" + "last_validated_date": "2026-02-21T00:17:48+00:00", + "durations_in_seconds": { + "setup": 0.5, + "call": 2.8, + "teardown": 2.11, + "total": 5.41 + } }, "tests/aws/services/s3/test_s3.py::TestS3::test_copy_object_special_character_plus_for_space": { - "last_validated_date": "2025-01-21T18:27:03+00:00" + "last_validated_date": "2026-02-21T00:17:51+00:00", + "durations_in_seconds": { + "setup": 0.51, + "call": 0.8, + "teardown": 1.02, + "total": 2.33 + } + }, + "tests/aws/services/s3/test_s3.py::TestS3::test_create_bucket_aws_global": { + "last_validated_date": "2026-02-21T00:23:28+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 1.79, + "teardown": 0.54, + "total": 2.33 + } }, "tests/aws/services/s3/test_s3.py::TestS3::test_create_bucket_head_bucket": { - "last_validated_date": "2025-01-21T18:34:17+00:00" + "last_validated_date": "2026-02-21T00:23:35+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 3.8, + "teardown": 0.01, + "total": 3.81 + } }, "tests/aws/services/s3/test_s3.py::TestS3::test_create_bucket_via_host_name": { - "last_validated_date": "2025-01-21T18:27:49+00:00" + "last_validated_date": "2026-02-21T00:18:24+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 1.64, + "teardown": 0.0, + "total": 1.64 + } + }, + "tests/aws/services/s3/test_s3.py::TestS3::test_create_bucket_with_eu_location_constraint": { + "last_validated_date": "2026-02-21T00:18:26+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.83, + "teardown": 0.79, + "total": 1.62 + } + }, + "tests/aws/services/s3/test_s3.py::TestS3::test_create_bucket_with_eu_location_constraint_raises": { + "last_validated_date": "2026-02-21T00:18:26+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.42, + "teardown": 0.01, + "total": 0.43 + } }, "tests/aws/services/s3/test_s3.py::TestS3::test_create_bucket_with_existing_name": { - "last_validated_date": "2025-01-21T18:34:10+00:00" + "last_validated_date": "2026-02-21T00:23:26+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 1.36, + "teardown": 1.47, + "total": 2.83 + } + }, + "tests/aws/services/s3/test_s3.py::TestS3::test_create_bucket_with_invalid_location_constraint[eu-west-1-bar]": { + "last_validated_date": "2026-02-21T00:18:27+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.13, + "teardown": 0.01, + "total": 0.14 + } + }, + "tests/aws/services/s3/test_s3.py::TestS3::test_create_bucket_with_invalid_location_constraint[us-east-1-foo]": { + "last_validated_date": "2026-02-21T00:18:27+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.33, + "teardown": 0.01, + "total": 0.34 + } + }, + "tests/aws/services/s3/test_s3.py::TestS3::test_create_bucket_with_invalid_location_constraint[us-east-1-us-east-1]": { + "last_validated_date": "2026-02-21T00:18:26+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.36, + "teardown": 0.01, + "total": 0.37 + } }, "tests/aws/services/s3/test_s3.py::TestS3::test_delete_bucket_no_such_bucket": { - "last_validated_date": "2025-01-21T18:27:11+00:00" + "last_validated_date": "2026-02-21T00:17:57+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.33, + "teardown": 0.01, + "total": 0.34 + } }, "tests/aws/services/s3/test_s3.py::TestS3::test_delete_bucket_policy": { - "last_validated_date": "2025-01-21T18:28:06+00:00" + "last_validated_date": "2026-02-21T00:18:47+00:00", + "durations_in_seconds": { + "setup": 0.91, + "call": 0.51, + "teardown": 0.56, + "total": 1.98 + } }, "tests/aws/services/s3/test_s3.py::TestS3::test_delete_bucket_policy_expected_bucket_owner": { - "last_validated_date": "2025-01-21T18:50:24+00:00" + "last_validated_date": "2026-02-21T00:18:49+00:00", + "durations_in_seconds": { + "setup": 0.87, + "call": 0.9, + "teardown": 0.62, + "total": 2.39 + } }, "tests/aws/services/s3/test_s3.py::TestS3::test_delete_bucket_with_content": { - "last_validated_date": "2025-01-21T18:26:26+00:00" + "last_validated_date": "2026-02-21T00:17:01+00:00", + "durations_in_seconds": { + "setup": 0.49, + "call": 3.65, + "teardown": 0.23, + "total": 4.37 + } }, "tests/aws/services/s3/test_s3.py::TestS3::test_delete_keys_in_versioned_bucket": { - "last_validated_date": "2025-01-21T18:31:34+00:00" + "last_validated_date": "2026-02-21T00:21:34+00:00", + "durations_in_seconds": { + "setup": 0.5, + "call": 2.04, + "teardown": 0.58, + "total": 3.12 + } }, "tests/aws/services/s3/test_s3.py::TestS3::test_delete_non_existing_keys": { - "last_validated_date": "2025-01-21T18:31:31+00:00" + "last_validated_date": "2026-02-21T00:21:31+00:00", + "durations_in_seconds": { + "setup": 0.53, + "call": 0.37, + "teardown": 0.81, + "total": 1.71 + } }, "tests/aws/services/s3/test_s3.py::TestS3::test_delete_non_existing_keys_in_non_existing_bucket": { - "last_validated_date": "2025-01-21T18:31:36+00:00" + "last_validated_date": "2026-02-21T00:21:34+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.33, + "teardown": 0.01, + "total": 0.34 + } }, "tests/aws/services/s3/test_s3.py::TestS3::test_delete_non_existing_keys_quiet": { - "last_validated_date": "2025-01-21T18:31:30+00:00" + "last_validated_date": "2026-02-21T00:21:29+00:00", + "durations_in_seconds": { + "setup": 0.53, + "call": 0.43, + "teardown": 0.85, + "total": 1.81 + } }, "tests/aws/services/s3/test_s3.py::TestS3::test_delete_object_tagging": { - "last_validated_date": "2025-01-21T18:31:28+00:00" + "last_validated_date": "2026-02-21T00:21:27+00:00", + "durations_in_seconds": { + "setup": 0.48, + "call": 0.78, + "teardown": 0.95, + "total": 2.21 + } }, "tests/aws/services/s3/test_s3.py::TestS3::test_delete_objects_encoding": { - "last_validated_date": "2025-01-21T18:31:37+00:00" + "last_validated_date": "2026-02-21T00:21:36+00:00", + "durations_in_seconds": { + "setup": 0.49, + "call": 1.0, + "teardown": 0.59, + "total": 2.08 + } }, "tests/aws/services/s3/test_s3.py::TestS3::test_different_location_constraint": { - "last_validated_date": "2025-01-21T18:30:47+00:00" + "last_validated_date": "2026-02-23T12:30:40+00:00", + "durations_in_seconds": { + "setup": 0.49, + "call": 5.45, + "teardown": 2.88, + "total": 8.82 + } }, "tests/aws/services/s3/test_s3.py::TestS3::test_download_fileobj_multiple_range_requests": { - "last_validated_date": "2025-01-21T18:31:23+00:00" + "last_validated_date": "2026-02-21T00:21:23+00:00", + "durations_in_seconds": { + "setup": 0.52, + "call": 5.16, + "teardown": 0.98, + "total": 6.66 + } }, "tests/aws/services/s3/test_s3.py::TestS3::test_empty_bucket_fixture": { - "last_validated_date": "2025-01-21T18:43:07+00:00" + "last_validated_date": "2026-02-21T00:29:23+00:00", + "durations_in_seconds": { + "setup": 0.49, + "call": 1.6, + "teardown": 0.59, + "total": 2.68 + } }, "tests/aws/services/s3/test_s3.py::TestS3::test_etag_on_get_object_call": { - "last_validated_date": "2025-01-21T18:39:07+00:00" + "last_validated_date": "2026-02-21T00:27:35+00:00", + "durations_in_seconds": { + "setup": 0.53, + "call": 0.8, + "teardown": 0.97, + "total": 2.3 + } }, "tests/aws/services/s3/test_s3.py::TestS3::test_get_bucket_notification_configuration_no_such_bucket": { - "last_validated_date": "2025-01-21T18:27:11+00:00" + "last_validated_date": "2026-02-21T00:17:58+00:00", + "durations_in_seconds": { + "setup": 0.01, + "call": 0.33, + "teardown": 0.01, + "total": 0.35 + } }, "tests/aws/services/s3/test_s3.py::TestS3::test_get_bucket_policy": { - "last_validated_date": "2025-01-21T18:27:51+00:00" + "last_validated_date": "2026-02-21T00:18:29+00:00", + "durations_in_seconds": { + "setup": 0.86, + "call": 0.72, + "teardown": 0.59, + "total": 2.17 + } }, "tests/aws/services/s3/test_s3.py::TestS3::test_get_bucket_policy_invalid_account_id[0000000000020]": { - "last_validated_date": "2025-01-21T18:27:53+00:00" + "last_validated_date": "2026-02-21T00:18:32+00:00", + "durations_in_seconds": { + "setup": 0.53, + "call": 0.1, + "teardown": 0.89, + "total": 1.52 + } }, "tests/aws/services/s3/test_s3.py::TestS3::test_get_bucket_policy_invalid_account_id[0000]": { - "last_validated_date": "2025-01-21T18:27:52+00:00" + "last_validated_date": "2026-02-21T00:18:30+00:00", + "durations_in_seconds": { + "setup": 0.5, + "call": 0.11, + "teardown": 0.8, + "total": 1.41 + } }, "tests/aws/services/s3/test_s3.py::TestS3::test_get_bucket_policy_invalid_account_id[aa000000000$]": { - "last_validated_date": "2025-01-21T18:27:56+00:00" + "last_validated_date": "2026-02-21T00:18:35+00:00", + "durations_in_seconds": { + "setup": 0.52, + "call": 0.1, + "teardown": 0.8, + "total": 1.42 + } }, "tests/aws/services/s3/test_s3.py::TestS3::test_get_bucket_policy_invalid_account_id[abcd]": { - "last_validated_date": "2025-01-21T18:27:55+00:00" + "last_validated_date": "2026-02-21T00:18:33+00:00", + "durations_in_seconds": { + "setup": 0.51, + "call": 0.1, + "teardown": 0.83, + "total": 1.44 + } }, "tests/aws/services/s3/test_s3.py::TestS3::test_get_bucket_versioning_order": { - "last_validated_date": "2025-01-21T18:39:04+00:00" + "last_validated_date": "2026-02-21T00:27:33+00:00", + "durations_in_seconds": { + "setup": 0.55, + "call": 1.3, + "teardown": 1.16, + "total": 3.01 + } }, "tests/aws/services/s3/test_s3.py::TestS3::test_get_object_after_deleted_in_versioned_bucket": { - "last_validated_date": "2025-01-21T18:28:12+00:00" + "last_validated_date": "2026-02-21T00:18:56+00:00", + "durations_in_seconds": { + "setup": 0.5, + "call": 1.04, + "teardown": 0.76, + "total": 2.3 + } }, "tests/aws/services/s3/test_s3.py::TestS3::test_get_object_attributes": { - "last_validated_date": "2025-03-17T20:02:49+00:00" + "last_validated_date": "2026-02-21T00:18:03+00:00", + "durations_in_seconds": { + "setup": 0.52, + "call": 3.92, + "teardown": 1.03, + "total": 5.47 + } }, "tests/aws/services/s3/test_s3.py::TestS3::test_get_object_attributes_versioned": { - "last_validated_date": "2025-01-21T18:27:33+00:00" + "last_validated_date": "2026-02-21T00:18:08+00:00", + "durations_in_seconds": { + "setup": 0.52, + "call": 1.5, + "teardown": 1.03, + "total": 3.05 + } }, "tests/aws/services/s3/test_s3.py::TestS3::test_get_object_attributes_with_space": { - "last_validated_date": "2025-01-21T18:27:30+00:00" + "last_validated_date": "2026-02-21T00:18:05+00:00", + "durations_in_seconds": { + "setup": 0.51, + "call": 0.69, + "teardown": 1.0, + "total": 2.2 + } }, "tests/aws/services/s3/test_s3.py::TestS3::test_get_object_content_length_with_virtual_host[False]": { - "last_validated_date": "2025-01-21T18:43:04+00:00" + "last_validated_date": "2026-02-21T00:29:20+00:00", + "durations_in_seconds": { + "setup": 0.54, + "call": 0.58, + "teardown": 1.0, + "total": 2.12 + } }, "tests/aws/services/s3/test_s3.py::TestS3::test_get_object_content_length_with_virtual_host[True]": { - "last_validated_date": "2025-01-21T18:43:02+00:00" + "last_validated_date": "2026-02-21T00:29:18+00:00", + "durations_in_seconds": { + "setup": 0.53, + "call": 0.55, + "teardown": 0.95, + "total": 2.03 + } }, "tests/aws/services/s3/test_s3.py::TestS3::test_get_object_no_such_bucket": { - "last_validated_date": "2025-01-21T18:27:10+00:00" + "last_validated_date": "2026-02-21T00:17:57+00:00", + "durations_in_seconds": { + "setup": 0.01, + "call": 0.33, + "teardown": 0.01, + "total": 0.35 + } }, "tests/aws/services/s3/test_s3.py::TestS3::test_get_object_part": { - "last_validated_date": "2025-07-07T17:56:15+00:00", + "last_validated_date": "2026-02-21T00:22:59+00:00", "durations_in_seconds": { - "setup": 1.4, - "call": 10.69, - "teardown": 1.07, - "total": 13.16 + "setup": 0.52, + "call": 3.36, + "teardown": 0.97, + "total": 4.85 } }, "tests/aws/services/s3/test_s3.py::TestS3::test_get_object_part_checksum[COMPOSITE]": { - "last_validated_date": "2025-07-07T18:23:55+00:00", + "last_validated_date": "2026-02-21T00:23:02+00:00", "durations_in_seconds": { - "setup": 1.05, - "call": 0.85, - "teardown": 1.02, - "total": 2.92 + "setup": 0.51, + "call": 0.75, + "teardown": 0.93, + "total": 2.19 } }, "tests/aws/services/s3/test_s3.py::TestS3::test_get_object_part_checksum[FULL_OBJECT]": { - "last_validated_date": "2025-07-07T18:23:58+00:00", + "last_validated_date": "2026-02-21T00:23:04+00:00", "durations_in_seconds": { - "setup": 0.6, - "call": 0.85, - "teardown": 1.17, - "total": 2.62 + "setup": 0.61, + "call": 0.82, + "teardown": 0.95, + "total": 2.38 } }, "tests/aws/services/s3/test_s3.py::TestS3::test_get_object_part_checksum_composite": { @@ -159,106 +477,328 @@ } }, "tests/aws/services/s3/test_s3.py::TestS3::test_get_object_with_anon_credentials": { - "last_validated_date": "2025-01-21T18:30:54+00:00" + "last_validated_date": "2026-02-21T00:21:12+00:00", + "durations_in_seconds": { + "setup": 0.92, + "call": 0.87, + "teardown": 1.03, + "total": 2.82 + } }, "tests/aws/services/s3/test_s3.py::TestS3::test_get_range_object_headers": { - "last_validated_date": "2025-01-21T18:31:25+00:00" + "last_validated_date": "2026-02-21T00:21:25+00:00", + "durations_in_seconds": { + "setup": 0.49, + "call": 0.33, + "teardown": 1.21, + "total": 2.03 + } }, "tests/aws/services/s3/test_s3.py::TestS3::test_head_object_fields": { - "last_validated_date": "2025-01-21T18:28:10+00:00" + "last_validated_date": "2026-02-21T00:18:53+00:00", + "durations_in_seconds": { + "setup": 0.52, + "call": 0.43, + "teardown": 0.97, + "total": 1.92 + } }, "tests/aws/services/s3/test_s3.py::TestS3::test_invalid_range_error": { - "last_validated_date": "2025-01-21T18:27:45+00:00" + "last_validated_date": "2026-02-21T00:18:21+00:00", + "durations_in_seconds": { + "setup": 0.5, + "call": 0.32, + "teardown": 0.99, + "total": 1.81 + } }, "tests/aws/services/s3/test_s3.py::TestS3::test_metadata_header_character_decoding": { - "last_validated_date": "2025-01-21T18:26:37+00:00" + "last_validated_date": "2026-02-21T00:17:19+00:00", + "durations_in_seconds": { + "setup": 0.5, + "call": 0.43, + "teardown": 0.95, + "total": 1.88 + } + }, + "tests/aws/services/s3/test_s3.py::TestS3::test_metadata_header_character_unicode_encoding": { + "last_validated_date": "2026-01-28T17:21:11+00:00", + "durations_in_seconds": { + "setup": 1.08, + "call": 0.32, + "teardown": 0.96, + "total": 2.36 + } }, "tests/aws/services/s3/test_s3.py::TestS3::test_multipart_and_list_parts": { - "last_validated_date": "2025-03-17T21:28:50+00:00" + "last_validated_date": "2026-02-21T00:18:11+00:00", + "durations_in_seconds": { + "setup": 0.52, + "call": 1.51, + "teardown": 0.74, + "total": 2.77 + } }, "tests/aws/services/s3/test_s3.py::TestS3::test_multipart_complete_multipart_too_small": { - "last_validated_date": "2025-01-21T18:27:40+00:00" + "last_validated_date": "2026-02-21T00:18:15+00:00", + "durations_in_seconds": { + "setup": 0.52, + "call": 1.05, + "teardown": 0.83, + "total": 2.4 + } }, "tests/aws/services/s3/test_s3.py::TestS3::test_multipart_complete_multipart_wrong_part": { - "last_validated_date": "2025-01-21T18:27:42+00:00" + "last_validated_date": "2026-02-21T00:18:17+00:00", + "durations_in_seconds": { + "setup": 0.51, + "call": 0.82, + "teardown": 0.8, + "total": 2.13 + } }, "tests/aws/services/s3/test_s3.py::TestS3::test_multipart_copy_object_etag": { - "last_validated_date": "2025-03-17T23:02:42+00:00" + "last_validated_date": "2026-02-21T00:22:55+00:00", + "durations_in_seconds": { + "setup": 0.54, + "call": 1.04, + "teardown": 1.01, + "total": 2.59 + } }, "tests/aws/services/s3/test_s3.py::TestS3::test_multipart_no_such_upload": { - "last_validated_date": "2025-01-21T18:27:38+00:00" + "last_validated_date": "2026-02-21T00:18:13+00:00", + "durations_in_seconds": { + "setup": 0.54, + "call": 0.54, + "teardown": 0.61, + "total": 1.69 + } }, "tests/aws/services/s3/test_s3.py::TestS3::test_multipart_overwrite_key": { - "last_validated_date": "2025-03-17T21:29:05+00:00" + "last_validated_date": "2026-02-21T00:22:52+00:00", + "durations_in_seconds": { + "setup": 0.52, + "call": 0.91, + "teardown": 0.97, + "total": 2.4 + } + }, + "tests/aws/services/s3/test_s3.py::TestS3::test_multipart_with_unicode_character_location": { + "last_validated_date": "2026-02-21T00:17:43+00:00", + "durations_in_seconds": { + "setup": 0.53, + "call": 0.56, + "teardown": 0.74, + "total": 1.83 + } }, "tests/aws/services/s3/test_s3.py::TestS3::test_object_with_slashes_in_key[False]": { - "last_validated_date": "2025-01-21T18:26:36+00:00" + "last_validated_date": "2026-02-21T00:17:17+00:00", + "durations_in_seconds": { + "setup": 0.5, + "call": 1.67, + "teardown": 0.97, + "total": 3.14 + } }, "tests/aws/services/s3/test_s3.py::TestS3::test_object_with_slashes_in_key[True]": { - "last_validated_date": "2025-01-21T18:26:32+00:00" + "last_validated_date": "2026-02-21T00:17:14+00:00", + "durations_in_seconds": { + "setup": 0.56, + "call": 1.64, + "teardown": 0.96, + "total": 3.16 + } }, "tests/aws/services/s3/test_s3.py::TestS3::test_precondition_failed_error": { - "last_validated_date": "2025-01-21T18:32:22+00:00" + "last_validated_date": "2026-02-21T00:22:23+00:00", + "durations_in_seconds": { + "setup": 0.52, + "call": 0.33, + "teardown": 0.96, + "total": 1.81 + } }, "tests/aws/services/s3/test_s3.py::TestS3::test_put_and_get_object_with_content_language_disposition": { - "last_validated_date": "2025-01-21T18:26:29+00:00" + "last_validated_date": "2026-02-21T00:17:05+00:00", + "durations_in_seconds": { + "setup": 0.55, + "call": 0.47, + "teardown": 0.95, + "total": 1.97 + } }, "tests/aws/services/s3/test_s3.py::TestS3::test_put_and_get_object_with_hash_prefix": { - "last_validated_date": "2025-01-21T18:27:44+00:00" + "last_validated_date": "2026-02-21T00:18:19+00:00", + "durations_in_seconds": { + "setup": 0.52, + "call": 0.49, + "teardown": 0.92, + "total": 1.93 + } }, "tests/aws/services/s3/test_s3.py::TestS3::test_put_and_get_object_with_utf8_key": { - "last_validated_date": "2025-01-21T18:26:27+00:00" + "last_validated_date": "2026-02-21T00:17:03+00:00", + "durations_in_seconds": { + "setup": 0.51, + "call": 0.44, + "teardown": 0.98, + "total": 1.93 + } }, "tests/aws/services/s3/test_s3.py::TestS3::test_put_bucket_inventory_config_order": { - "last_validated_date": "2025-01-21T18:43:00+00:00" + "last_validated_date": "2026-02-21T00:29:16+00:00", + "durations_in_seconds": { + "setup": 0.01, + "call": 1.86, + "teardown": 1.23, + "total": 3.1 + } }, "tests/aws/services/s3/test_s3.py::TestS3::test_put_bucket_policy": { - "last_validated_date": "2025-01-21T18:27:58+00:00" + "last_validated_date": "2026-02-21T00:18:37+00:00", + "durations_in_seconds": { + "setup": 0.87, + "call": 0.35, + "teardown": 0.6, + "total": 1.82 + } }, "tests/aws/services/s3/test_s3.py::TestS3::test_put_bucket_policy_expected_bucket_owner": { - "last_validated_date": "2025-01-21T18:50:21+00:00" + "last_validated_date": "2026-02-21T00:18:39+00:00", + "durations_in_seconds": { + "setup": 1.34, + "call": 0.54, + "teardown": 0.56, + "total": 2.44 + } }, "tests/aws/services/s3/test_s3.py::TestS3::test_put_bucket_policy_invalid_account_id[0000000000020]": { - "last_validated_date": "2025-01-21T18:28:01+00:00" + "last_validated_date": "2026-02-21T00:18:42+00:00", + "durations_in_seconds": { + "setup": 0.48, + "call": 0.1, + "teardown": 0.8, + "total": 1.38 + } }, "tests/aws/services/s3/test_s3.py::TestS3::test_put_bucket_policy_invalid_account_id[0000]": { - "last_validated_date": "2025-01-21T18:28:00+00:00" + "last_validated_date": "2026-02-21T00:18:41+00:00", + "durations_in_seconds": { + "setup": 0.49, + "call": 0.1, + "teardown": 0.78, + "total": 1.37 + } }, "tests/aws/services/s3/test_s3.py::TestS3::test_put_bucket_policy_invalid_account_id[aa000000000$]": { - "last_validated_date": "2025-01-21T18:28:04+00:00" + "last_validated_date": "2026-02-21T00:18:45+00:00", + "durations_in_seconds": { + "setup": 0.52, + "call": 0.1, + "teardown": 0.8, + "total": 1.42 + } }, "tests/aws/services/s3/test_s3.py::TestS3::test_put_bucket_policy_invalid_account_id[abcd]": { - "last_validated_date": "2025-01-21T18:28:03+00:00" + "last_validated_date": "2026-02-21T00:18:43+00:00", + "durations_in_seconds": { + "setup": 0.5, + "call": 0.1, + "teardown": 0.8, + "total": 1.4 + } }, "tests/aws/services/s3/test_s3.py::TestS3::test_put_get_object_single_character_trailing_slash": { - "last_validated_date": "2025-01-22T19:05:31+00:00" + "last_validated_date": "2026-02-21T00:17:41+00:00", + "durations_in_seconds": { + "setup": 0.51, + "call": 1.83, + "teardown": 1.0, + "total": 3.34 + } }, "tests/aws/services/s3/test_s3.py::TestS3::test_put_get_object_special_character[a/%F0%9F%98%80/]": { - "last_validated_date": "2025-01-21T18:26:56+00:00" + "last_validated_date": "2026-02-21T00:17:38+00:00", + "durations_in_seconds": { + "setup": 0.51, + "call": 0.9, + "teardown": 0.59, + "total": 2.0 + } }, "tests/aws/services/s3/test_s3.py::TestS3::test_put_get_object_special_character[file%2Fname]": { - "last_validated_date": "2025-01-21T18:26:42+00:00" + "last_validated_date": "2026-02-21T00:17:23+00:00", + "durations_in_seconds": { + "setup": 0.5, + "call": 0.93, + "teardown": 0.56, + "total": 1.99 + } }, "tests/aws/services/s3/test_s3.py::TestS3::test_put_get_object_special_character[test key//]": { - "last_validated_date": "2025-01-21T18:26:52+00:00" + "last_validated_date": "2026-02-21T00:17:34+00:00", + "durations_in_seconds": { + "setup": 0.53, + "call": 0.9, + "teardown": 0.63, + "total": 2.06 + } }, "tests/aws/services/s3/test_s3.py::TestS3::test_put_get_object_special_character[test key/]": { - "last_validated_date": "2025-01-21T18:26:50+00:00" - }, + "last_validated_date": "2026-02-21T00:17:32+00:00", + "durations_in_seconds": { + "setup": 0.51, + "call": 0.9, + "teardown": 0.61, + "total": 2.02 + } + }, "tests/aws/services/s3/test_s3.py::TestS3::test_put_get_object_special_character[test%123/]": { - "last_validated_date": "2025-01-21T18:26:54+00:00" + "last_validated_date": "2026-02-21T00:17:36+00:00", + "durations_in_seconds": { + "setup": 0.52, + "call": 0.89, + "teardown": 0.6, + "total": 2.01 + } }, "tests/aws/services/s3/test_s3.py::TestS3::test_put_get_object_special_character[test%123]": { - "last_validated_date": "2025-01-21T18:26:46+00:00" + "last_validated_date": "2026-02-21T00:17:28+00:00", + "durations_in_seconds": { + "setup": 0.53, + "call": 0.97, + "teardown": 0.59, + "total": 2.09 + } }, "tests/aws/services/s3/test_s3.py::TestS3::test_put_get_object_special_character[test%percent]": { - "last_validated_date": "2025-01-21T18:26:48+00:00" + "last_validated_date": "2026-02-21T00:17:30+00:00", + "durations_in_seconds": { + "setup": 0.54, + "call": 0.89, + "teardown": 0.61, + "total": 2.04 + } }, "tests/aws/services/s3/test_s3.py::TestS3::test_put_get_object_special_character[test@key/]": { - "last_validated_date": "2025-01-21T18:26:44+00:00" + "last_validated_date": "2026-02-21T00:17:25+00:00", + "durations_in_seconds": { + "setup": 0.52, + "call": 0.87, + "teardown": 0.62, + "total": 2.01 + } }, "tests/aws/services/s3/test_s3.py::TestS3::test_put_object_acl_on_delete_marker": { - "last_validated_date": "2025-01-21T18:31:40+00:00" + "last_validated_date": "2026-02-21T00:21:39+00:00", + "durations_in_seconds": { + "setup": 0.86, + "call": 1.31, + "teardown": 0.97, + "total": 3.14 + } }, "tests/aws/services/s3/test_s3.py::TestS3::test_put_object_checksum[CRC32C]": { "last_validated_date": "2025-01-21T18:28:18+00:00" @@ -273,76 +813,223 @@ "last_validated_date": "2025-01-21T18:28:23+00:00" }, "tests/aws/services/s3/test_s3.py::TestS3::test_put_object_storage_class[DEEP_ARCHIVE-False]": { - "last_validated_date": "2025-01-21T18:41:32+00:00" + "last_validated_date": "2026-02-21T00:28:30+00:00", + "durations_in_seconds": { + "setup": 0.53, + "call": 0.46, + "teardown": 0.97, + "total": 1.96 + } }, "tests/aws/services/s3/test_s3.py::TestS3::test_put_object_storage_class[GLACIER-False]": { - "last_validated_date": "2025-01-21T18:41:22+00:00" + "last_validated_date": "2026-02-21T00:28:20+00:00", + "durations_in_seconds": { + "setup": 0.54, + "call": 0.47, + "teardown": 1.0, + "total": 2.01 + } }, "tests/aws/services/s3/test_s3.py::TestS3::test_put_object_storage_class[GLACIER_IR-True]": { - "last_validated_date": "2025-01-21T18:41:24+00:00" + "last_validated_date": "2026-02-21T00:28:22+00:00", + "durations_in_seconds": { + "setup": 0.53, + "call": 0.48, + "teardown": 0.75, + "total": 1.76 + } }, "tests/aws/services/s3/test_s3.py::TestS3::test_put_object_storage_class[INTELLIGENT_TIERING-True]": { - "last_validated_date": "2025-01-21T18:41:30+00:00" + "last_validated_date": "2026-02-21T00:28:28+00:00", + "durations_in_seconds": { + "setup": 0.51, + "call": 0.52, + "teardown": 0.99, + "total": 2.02 + } }, "tests/aws/services/s3/test_s3.py::TestS3::test_put_object_storage_class[ONEZONE_IA-True]": { - "last_validated_date": "2025-01-21T18:41:28+00:00" + "last_validated_date": "2026-02-21T00:28:26+00:00", + "durations_in_seconds": { + "setup": 0.58, + "call": 0.52, + "teardown": 0.99, + "total": 2.09 + } }, "tests/aws/services/s3/test_s3.py::TestS3::test_put_object_storage_class[REDUCED_REDUNDANCY-True]": { - "last_validated_date": "2025-01-21T18:41:26+00:00" + "last_validated_date": "2026-02-21T00:28:24+00:00", + "durations_in_seconds": { + "setup": 0.51, + "call": 0.55, + "teardown": 1.06, + "total": 2.12 + } }, "tests/aws/services/s3/test_s3.py::TestS3::test_put_object_storage_class[STANDARD-True]": { - "last_validated_date": "2025-01-21T18:41:18+00:00" + "last_validated_date": "2026-02-21T00:28:16+00:00", + "durations_in_seconds": { + "setup": 0.52, + "call": 0.49, + "teardown": 0.97, + "total": 1.98 + } }, "tests/aws/services/s3/test_s3.py::TestS3::test_put_object_storage_class[STANDARD_IA-True]": { - "last_validated_date": "2025-01-21T18:41:20+00:00" + "last_validated_date": "2026-02-21T00:28:18+00:00", + "durations_in_seconds": { + "setup": 0.53, + "call": 0.47, + "teardown": 0.97, + "total": 1.97 + } }, "tests/aws/services/s3/test_s3.py::TestS3::test_put_object_storage_class_outposts": { - "last_validated_date": "2025-01-21T18:41:34+00:00" + "last_validated_date": "2026-02-21T00:28:32+00:00", + "durations_in_seconds": { + "setup": 0.54, + "call": 0.45, + "teardown": 0.84, + "total": 1.83 + } }, "tests/aws/services/s3/test_s3.py::TestS3::test_put_object_tagging_empty_list": { - "last_validated_date": "2025-01-21T18:28:08+00:00" + "last_validated_date": "2026-02-21T00:18:52+00:00", + "durations_in_seconds": { + "setup": 0.52, + "call": 0.88, + "teardown": 0.99, + "total": 2.39 + } }, "tests/aws/services/s3/test_s3.py::TestS3::test_putobject_with_multiple_keys": { - "last_validated_date": "2025-01-21T18:30:56+00:00" + "last_validated_date": "2026-02-21T00:21:14+00:00", + "durations_in_seconds": { + "setup": 0.53, + "call": 0.45, + "teardown": 1.0, + "total": 1.98 + } }, "tests/aws/services/s3/test_s3.py::TestS3::test_range_header_body_length": { - "last_validated_date": "2025-01-21T18:30:58+00:00" + "last_validated_date": "2026-02-21T00:21:16+00:00", + "durations_in_seconds": { + "setup": 0.51, + "call": 0.47, + "teardown": 0.94, + "total": 1.92 + } }, "tests/aws/services/s3/test_s3.py::TestS3::test_range_key_not_exists": { - "last_validated_date": "2025-01-21T18:27:47+00:00" + "last_validated_date": "2026-02-21T00:18:22+00:00", + "durations_in_seconds": { + "setup": 0.5, + "call": 0.11, + "teardown": 0.58, + "total": 1.19 + } }, "tests/aws/services/s3/test_s3.py::TestS3::test_region_header_exists_outside_us_east_1": { - "last_validated_date": "2025-01-21T18:26:20+00:00" + "last_validated_date": "2026-02-21T00:16:57+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 2.27, + "teardown": 1.59, + "total": 3.86 + } }, "tests/aws/services/s3/test_s3.py::TestS3::test_response_structure": { - "last_validated_date": "2025-01-21T18:41:38+00:00" + "last_validated_date": "2026-02-21T00:28:36+00:00", + "durations_in_seconds": { + "setup": 0.52, + "call": 2.36, + "teardown": 1.03, + "total": 3.91 + } + }, + "tests/aws/services/s3/test_s3.py::TestS3::test_response_structure_get_bucket_location[eu-central-1-eu-central-1-eu-central-1]": { + "last_validated_date": "2026-02-21T00:28:42+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 1.12, + "teardown": 0.85, + "total": 1.97 + } + }, + "tests/aws/services/s3/test_s3.py::TestS3::test_response_structure_get_bucket_location[eu-west-1-EU-EU]": { + "last_validated_date": "2026-02-21T00:28:40+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 1.01, + "teardown": 0.86, + "total": 1.87 + } + }, + "tests/aws/services/s3/test_s3.py::TestS3::test_response_structure_get_bucket_location[us-east-1-None-]": { + "last_validated_date": "2026-02-21T00:28:38+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.89, + "teardown": 0.61, + "total": 1.5 + } }, "tests/aws/services/s3/test_s3.py::TestS3::test_response_structure_get_obj_attrs": { - "last_validated_date": "2025-08-18T16:12:31+00:00", + "last_validated_date": "2026-02-21T00:28:45+00:00", "durations_in_seconds": { - "setup": 0.71, - "call": 1.55, - "teardown": 1.3, - "total": 3.56 + "setup": 0.52, + "call": 1.6, + "teardown": 1.08, + "total": 3.2 } }, "tests/aws/services/s3/test_s3.py::TestS3::test_s3_analytics_configurations": { - "last_validated_date": "2025-01-21T18:42:41+00:00" + "last_validated_date": "2026-02-21T00:28:58+00:00", + "durations_in_seconds": { + "setup": 0.01, + "call": 2.73, + "teardown": 1.23, + "total": 3.97 + } }, "tests/aws/services/s3/test_s3.py::TestS3::test_s3_batch_delete_objects": { - "last_validated_date": "2025-01-21T18:39:22+00:00" + "last_validated_date": "2026-02-21T00:27:50+00:00", + "durations_in_seconds": { + "setup": 0.5, + "call": 1.74, + "teardown": 0.61, + "total": 2.85 + } }, "tests/aws/services/s3/test_s3.py::TestS3::test_s3_batch_delete_objects_using_requests_with_acl": { "last_validated_date": "2023-08-03T02:23:41+00:00" }, "tests/aws/services/s3/test_s3.py::TestS3::test_s3_batch_delete_public_objects_using_requests": { - "last_validated_date": "2025-01-21T19:48:17+00:00" + "last_validated_date": "2026-02-21T00:27:48+00:00", + "durations_in_seconds": { + "setup": 0.95, + "call": 1.41, + "teardown": 0.57, + "total": 2.93 + } }, "tests/aws/services/s3/test_s3.py::TestS3::test_s3_bucket_acl": { - "last_validated_date": "2025-01-21T18:30:17+00:00" + "last_validated_date": "2026-02-21T00:20:36+00:00", + "durations_in_seconds": { + "setup": 0.91, + "call": 1.38, + "teardown": 0.57, + "total": 2.86 + } }, "tests/aws/services/s3/test_s3.py::TestS3::test_s3_bucket_acl_exceptions": { - "last_validated_date": "2025-01-21T18:30:22+00:00" + "last_validated_date": "2026-02-21T00:20:42+00:00", + "durations_in_seconds": { + "setup": 0.49, + "call": 4.33, + "teardown": 0.81, + "total": 5.63 + } }, "tests/aws/services/s3/test_s3.py::TestS3::test_s3_checksum_no_algorithm": { "last_validated_date": "2025-01-21T18:28:45+00:00" @@ -354,97 +1041,274 @@ "last_validated_date": "2025-01-21T18:28:42+00:00" }, "tests/aws/services/s3/test_s3.py::TestS3::test_s3_copy_content_type_and_metadata": { - "last_validated_date": "2025-01-21T18:29:13+00:00" + "last_validated_date": "2026-02-21T00:19:22+00:00", + "durations_in_seconds": { + "setup": 0.5, + "call": 1.2, + "teardown": 0.96, + "total": 2.66 + } }, "tests/aws/services/s3/test_s3.py::TestS3::test_s3_copy_metadata_directive_copy": { - "last_validated_date": "2025-01-21T18:28:52+00:00" + "last_validated_date": "2026-02-21T00:19:00+00:00", + "durations_in_seconds": { + "setup": 0.5, + "call": 0.64, + "teardown": 0.97, + "total": 2.11 + } }, "tests/aws/services/s3/test_s3.py::TestS3::test_s3_copy_metadata_replace": { - "last_validated_date": "2025-01-21T18:28:50+00:00" + "last_validated_date": "2026-02-21T00:18:58+00:00", + "durations_in_seconds": { + "setup": 0.52, + "call": 0.71, + "teardown": 0.97, + "total": 2.2 + } }, "tests/aws/services/s3/test_s3.py::TestS3::test_s3_copy_object_in_place": { - "last_validated_date": "2025-01-21T18:29:17+00:00" + "last_validated_date": "2026-02-21T00:19:25+00:00", + "durations_in_seconds": { + "setup": 0.91, + "call": 1.42, + "teardown": 1.16, + "total": 3.49 + } }, "tests/aws/services/s3/test_s3.py::TestS3::test_s3_copy_object_in_place_metadata_directive": { - "last_validated_date": "2025-01-21T18:29:37+00:00" + "last_validated_date": "2026-02-21T00:19:46+00:00", + "durations_in_seconds": { + "setup": 0.49, + "call": 1.74, + "teardown": 0.95, + "total": 3.18 + } }, "tests/aws/services/s3/test_s3.py::TestS3::test_s3_copy_object_in_place_storage_class": { - "last_validated_date": "2025-01-21T18:29:28+00:00" + "last_validated_date": "2026-02-21T00:19:37+00:00", + "durations_in_seconds": { + "setup": 0.49, + "call": 0.83, + "teardown": 0.92, + "total": 2.24 + } }, "tests/aws/services/s3/test_s3.py::TestS3::test_s3_copy_object_in_place_suspended_only": { - "last_validated_date": "2025-01-21T18:29:26+00:00" + "last_validated_date": "2026-02-21T00:19:35+00:00", + "durations_in_seconds": { + "setup": 0.92, + "call": 1.95, + "teardown": 1.28, + "total": 4.15 + } }, "tests/aws/services/s3/test_s3.py::TestS3::test_s3_copy_object_in_place_versioned": { - "last_validated_date": "2025-01-21T18:29:22+00:00" + "last_validated_date": "2026-02-21T00:19:31+00:00", + "durations_in_seconds": { + "setup": 0.93, + "call": 3.03, + "teardown": 1.33, + "total": 5.29 + } }, "tests/aws/services/s3/test_s3.py::TestS3::test_s3_copy_object_in_place_website_redirect_location": { - "last_validated_date": "2025-01-21T18:29:39+00:00" + "last_validated_date": "2026-02-21T00:19:48+00:00", + "durations_in_seconds": { + "setup": 0.49, + "call": 0.65, + "teardown": 0.97, + "total": 2.11 + } }, "tests/aws/services/s3/test_s3.py::TestS3::test_s3_copy_object_in_place_with_encryption": { - "last_validated_date": "2025-01-21T18:29:31+00:00" - }, - "tests/aws/services/s3/test_s3.py::TestS3::test_s3_copy_object_preconditions": { - "last_validated_date": "2025-01-21T18:29:56+00:00" + "last_validated_date": "2026-02-21T00:19:41+00:00", + "durations_in_seconds": { + "setup": 0.5, + "call": 1.82, + "teardown": 1.12, + "total": 3.44 + } }, "tests/aws/services/s3/test_s3.py::TestS3::test_s3_copy_object_storage_class": { - "last_validated_date": "2025-01-21T18:29:41+00:00" + "last_validated_date": "2026-02-21T00:19:51+00:00", + "durations_in_seconds": { + "setup": 0.49, + "call": 1.04, + "teardown": 1.16, + "total": 2.69 + } }, "tests/aws/services/s3/test_s3.py::TestS3::test_s3_copy_object_with_checksum[CRC32C]": { - "last_validated_date": "2025-01-24T19:06:31+00:00" + "last_validated_date": "2026-02-21T00:19:56+00:00", + "durations_in_seconds": { + "setup": 0.5, + "call": 0.99, + "teardown": 0.98, + "total": 2.47 + } }, "tests/aws/services/s3/test_s3.py::TestS3::test_s3_copy_object_with_checksum[CRC32]": { - "last_validated_date": "2025-01-24T19:06:29+00:00" + "last_validated_date": "2026-02-21T00:19:53+00:00", + "durations_in_seconds": { + "setup": 0.51, + "call": 0.94, + "teardown": 0.95, + "total": 2.4 + } }, "tests/aws/services/s3/test_s3.py::TestS3::test_s3_copy_object_with_checksum[CRC64NVME]": { - "last_validated_date": "2025-01-24T19:06:38+00:00" + "last_validated_date": "2026-02-21T00:20:03+00:00", + "durations_in_seconds": { + "setup": 0.49, + "call": 0.83, + "teardown": 0.93, + "total": 2.25 + } }, "tests/aws/services/s3/test_s3.py::TestS3::test_s3_copy_object_with_checksum[SHA1]": { - "last_validated_date": "2025-01-24T19:06:34+00:00" + "last_validated_date": "2026-02-21T00:19:58+00:00", + "durations_in_seconds": { + "setup": 0.53, + "call": 0.95, + "teardown": 0.97, + "total": 2.45 + } }, "tests/aws/services/s3/test_s3.py::TestS3::test_s3_copy_object_with_checksum[SHA256]": { - "last_validated_date": "2025-01-24T19:06:36+00:00" + "last_validated_date": "2026-02-21T00:20:00+00:00", + "durations_in_seconds": { + "setup": 0.51, + "call": 0.84, + "teardown": 0.94, + "total": 2.29 + } }, "tests/aws/services/s3/test_s3.py::TestS3::test_s3_copy_object_with_default_checksum[CRC32C]": { - "last_validated_date": "2025-03-17T22:17:06+00:00" + "last_validated_date": "2026-02-21T00:20:08+00:00", + "durations_in_seconds": { + "setup": 0.52, + "call": 0.95, + "teardown": 0.92, + "total": 2.39 + } }, "tests/aws/services/s3/test_s3.py::TestS3::test_s3_copy_object_with_default_checksum[CRC32]": { - "last_validated_date": "2025-03-17T22:17:03+00:00" + "last_validated_date": "2026-02-21T00:20:05+00:00", + "durations_in_seconds": { + "setup": 0.53, + "call": 1.19, + "teardown": 0.94, + "total": 2.66 + } }, "tests/aws/services/s3/test_s3.py::TestS3::test_s3_copy_object_with_default_checksum[CRC64NVME]": { - "last_validated_date": "2025-03-17T22:17:13+00:00" + "last_validated_date": "2026-02-21T00:20:15+00:00", + "durations_in_seconds": { + "setup": 0.49, + "call": 0.97, + "teardown": 0.96, + "total": 2.42 + } }, "tests/aws/services/s3/test_s3.py::TestS3::test_s3_copy_object_with_default_checksum[SHA1]": { - "last_validated_date": "2025-03-17T22:17:08+00:00" + "last_validated_date": "2026-02-21T00:20:10+00:00", + "durations_in_seconds": { + "setup": 0.5, + "call": 1.13, + "teardown": 0.93, + "total": 2.56 + } }, "tests/aws/services/s3/test_s3.py::TestS3::test_s3_copy_object_with_default_checksum[SHA256]": { - "last_validated_date": "2025-03-17T22:17:11+00:00" + "last_validated_date": "2026-02-21T00:20:13+00:00", + "durations_in_seconds": { + "setup": 0.49, + "call": 1.13, + "teardown": 0.96, + "total": 2.58 + } }, "tests/aws/services/s3/test_s3.py::TestS3::test_s3_copy_object_wrong_format": { - "last_validated_date": "2025-01-21T18:29:58+00:00" + "last_validated_date": "2026-02-21T00:20:17+00:00", + "durations_in_seconds": { + "setup": 0.53, + "call": 0.22, + "teardown": 0.82, + "total": 1.57 + } }, "tests/aws/services/s3/test_s3.py::TestS3::test_s3_copy_tagging_directive[COPY]": { - "last_validated_date": "2025-01-21T18:28:54+00:00" + "last_validated_date": "2026-02-21T00:19:03+00:00", + "durations_in_seconds": { + "setup": 0.49, + "call": 0.97, + "teardown": 0.97, + "total": 2.43 + } }, "tests/aws/services/s3/test_s3.py::TestS3::test_s3_copy_tagging_directive[None]": { - "last_validated_date": "2025-01-21T18:28:59+00:00" + "last_validated_date": "2026-02-21T00:19:07+00:00", + "durations_in_seconds": { + "setup": 0.48, + "call": 0.87, + "teardown": 1.01, + "total": 2.36 + } }, "tests/aws/services/s3/test_s3.py::TestS3::test_s3_copy_tagging_directive[REPLACE]": { - "last_validated_date": "2025-01-21T18:28:57+00:00" + "last_validated_date": "2026-02-21T00:19:05+00:00", + "durations_in_seconds": { + "setup": 0.51, + "call": 0.91, + "teardown": 0.97, + "total": 2.39 + } }, "tests/aws/services/s3/test_s3.py::TestS3::test_s3_copy_tagging_directive_versioned[COPY]": { - "last_validated_date": "2025-01-21T18:29:02+00:00" + "last_validated_date": "2026-02-21T00:19:11+00:00", + "durations_in_seconds": { + "setup": 0.49, + "call": 1.91, + "teardown": 1.58, + "total": 3.98 + } }, "tests/aws/services/s3/test_s3.py::TestS3::test_s3_copy_tagging_directive_versioned[None]": { - "last_validated_date": "2025-01-21T18:29:10+00:00" + "last_validated_date": "2026-02-21T00:19:19+00:00", + "durations_in_seconds": { + "setup": 0.5, + "call": 2.16, + "teardown": 1.45, + "total": 4.11 + } }, "tests/aws/services/s3/test_s3.py::TestS3::test_s3_copy_tagging_directive_versioned[REPLACE]": { - "last_validated_date": "2025-01-21T18:29:06+00:00" + "last_validated_date": "2026-02-21T00:19:15+00:00", + "durations_in_seconds": { + "setup": 0.53, + "call": 1.88, + "teardown": 1.52, + "total": 3.93 + } }, "tests/aws/services/s3/test_s3.py::TestS3::test_s3_delete_object_with_version_id": { - "last_validated_date": "2025-01-21T18:39:10+00:00" + "last_validated_date": "2026-02-21T00:27:39+00:00", + "durations_in_seconds": { + "setup": 0.74, + "call": 1.72, + "teardown": 1.31, + "total": 3.77 + } }, "tests/aws/services/s3/test_s3.py::TestS3::test_s3_download_object_with_lambda": { - "last_validated_date": "2025-01-21T18:32:19+00:00" + "last_validated_date": "2026-02-21T00:22:21+00:00", + "durations_in_seconds": { + "setup": 11.31, + "call": 21.61, + "teardown": 1.89, + "total": 34.81 + } }, "tests/aws/services/s3/test_s3.py::TestS3::test_s3_get_object_checksum[CRC32C]": { "last_validated_date": "2025-01-21T18:28:29+00:00" @@ -465,837 +1329,1938 @@ "last_validated_date": "2025-01-21T18:28:35+00:00" }, "tests/aws/services/s3/test_s3.py::TestS3::test_s3_get_object_header_overrides": { - "last_validated_date": "2025-01-21T18:39:23+00:00" + "last_validated_date": "2026-02-21T00:27:52+00:00", + "durations_in_seconds": { + "setup": 0.53, + "call": 0.34, + "teardown": 0.99, + "total": 1.86 + } }, "tests/aws/services/s3/test_s3.py::TestS3::test_s3_get_object_headers": { - "last_validated_date": "2025-01-21T18:42:49+00:00" + "last_validated_date": "2026-02-21T00:29:05+00:00", + "durations_in_seconds": { + "setup": 0.55, + "call": 2.33, + "teardown": 1.08, + "total": 3.96 + } }, "tests/aws/services/s3/test_s3.py::TestS3::test_s3_get_object_preconditions[get_object]": { - "last_validated_date": "2025-01-21T18:30:04+00:00" + "last_validated_date": "2026-02-21T00:20:23+00:00", + "durations_in_seconds": { + "setup": 0.61, + "call": 4.99, + "teardown": 0.97, + "total": 6.57 + } }, "tests/aws/services/s3/test_s3.py::TestS3::test_s3_get_object_preconditions[head_object]": { - "last_validated_date": "2025-01-21T18:30:10+00:00" + "last_validated_date": "2026-02-21T00:20:29+00:00", + "durations_in_seconds": { + "setup": 0.52, + "call": 4.53, + "teardown": 0.94, + "total": 5.99 + } }, "tests/aws/services/s3/test_s3.py::TestS3::test_s3_intelligent_tier_config": { - "last_validated_date": "2025-01-21T19:48:46+00:00" + "last_validated_date": "2026-02-21T00:29:01+00:00", + "durations_in_seconds": { + "setup": 0.53, + "call": 1.95, + "teardown": 0.62, + "total": 3.1 + } }, "tests/aws/services/s3/test_s3.py::TestS3::test_s3_invalid_content_md5": { - "last_validated_date": "2025-01-21T18:32:49+00:00" + "last_validated_date": "2026-02-21T00:22:48+00:00", + "durations_in_seconds": { + "setup": 0.53, + "call": 22.94, + "teardown": 0.99, + "total": 24.46 + } }, "tests/aws/services/s3/test_s3.py::TestS3::test_s3_inventory_report_crud": { - "last_validated_date": "2025-01-21T18:42:52+00:00" + "last_validated_date": "2026-02-21T00:29:08+00:00", + "durations_in_seconds": { + "setup": 0.01, + "call": 2.07, + "teardown": 1.19, + "total": 3.27 + } }, "tests/aws/services/s3/test_s3.py::TestS3::test_s3_lambda_integration": { - "last_validated_date": "2025-01-21T18:34:07+00:00" + "last_validated_date": "2026-02-21T00:23:23+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 14.0, + "teardown": 1.95, + "total": 15.95 + } }, "tests/aws/services/s3/test_s3.py::TestS3::test_s3_multipart_upload_acls": { - "last_validated_date": "2025-01-21T18:30:13+00:00" + "last_validated_date": "2026-02-21T00:20:33+00:00", + "durations_in_seconds": { + "setup": 0.94, + "call": 1.97, + "teardown": 0.97, + "total": 3.88 + } }, "tests/aws/services/s3/test_s3.py::TestS3::test_s3_multipart_upload_sse": { - "last_validated_date": "2025-03-17T21:31:09+00:00" + "last_validated_date": "2026-02-21T00:28:50+00:00", + "durations_in_seconds": { + "setup": 0.53, + "call": 1.27, + "teardown": 1.11, + "total": 2.91 + } }, "tests/aws/services/s3/test_s3.py::TestS3::test_s3_object_acl": { - "last_validated_date": "2025-01-21T18:30:26+00:00" + "last_validated_date": "2026-02-21T00:20:46+00:00", + "durations_in_seconds": { + "setup": 0.92, + "call": 2.26, + "teardown": 0.93, + "total": 4.11 + } }, "tests/aws/services/s3/test_s3.py::TestS3::test_s3_object_acl_exceptions": { - "last_validated_date": "2025-01-21T18:30:32+00:00" + "last_validated_date": "2026-02-21T00:20:52+00:00", + "durations_in_seconds": { + "setup": 0.5, + "call": 4.84, + "teardown": 1.13, + "total": 6.47 + } }, "tests/aws/services/s3/test_s3.py::TestS3::test_s3_object_expires": { - "last_validated_date": "2025-07-22T15:02:15+00:00", + "last_validated_date": "2026-02-21T00:20:55+00:00", "durations_in_seconds": { - "setup": 1.19, - "call": 1.34, - "teardown": 1.24, - "total": 3.77 + "setup": 0.5, + "call": 1.19, + "teardown": 0.94, + "total": 2.63 } }, "tests/aws/services/s3/test_s3.py::TestS3::test_s3_put_inventory_report_exceptions": { - "last_validated_date": "2025-01-21T18:42:57+00:00" + "last_validated_date": "2026-02-21T00:29:13+00:00", + "durations_in_seconds": { + "setup": 0.01, + "call": 3.11, + "teardown": 1.44, + "total": 4.56 + } }, "tests/aws/services/s3/test_s3.py::TestS3::test_s3_put_more_than_1000_items": { - "last_validated_date": "2025-01-21T18:38:06+00:00" + "last_validated_date": "2026-02-21T00:27:26+00:00", + "durations_in_seconds": { + "setup": 0.52, + "call": 224.74, + "teardown": 3.2, + "total": 228.46 + } }, "tests/aws/services/s3/test_s3.py::TestS3::test_s3_put_object_versioned": { - "last_validated_date": "2025-01-21T18:39:15+00:00" + "last_validated_date": "2026-02-21T00:27:45+00:00", + "durations_in_seconds": { + "setup": 0.53, + "call": 3.69, + "teardown": 1.47, + "total": 5.69 + } }, "tests/aws/services/s3/test_s3.py::TestS3::test_s3_request_payer": { - "last_validated_date": "2025-01-21T18:31:42+00:00" + "last_validated_date": "2026-02-21T00:21:41+00:00", + "durations_in_seconds": { + "setup": 0.51, + "call": 0.29, + "teardown": 0.6, + "total": 1.4 + } }, "tests/aws/services/s3/test_s3.py::TestS3::test_s3_request_payer_exceptions": { - "last_validated_date": "2025-01-21T18:31:43+00:00" + "last_validated_date": "2026-02-21T00:21:42+00:00", + "durations_in_seconds": { + "setup": 0.49, + "call": 0.44, + "teardown": 0.8, + "total": 1.73 + } }, "tests/aws/services/s3/test_s3.py::TestS3::test_s3_sse_bucket_key_default": { - "last_validated_date": "2025-01-21T18:42:37+00:00" + "last_validated_date": "2026-02-21T00:28:54+00:00", + "durations_in_seconds": { + "setup": 0.51, + "call": 1.92, + "teardown": 1.1, + "total": 3.53 + } }, "tests/aws/services/s3/test_s3.py::TestS3::test_s3_sse_default_kms_key": { - "last_validated_date": "2023-04-03T20:16:19+00:00" + "last_validated_date": "2026-02-21T00:43:39+00:00", + "durations_in_seconds": { + "setup": 0.48, + "call": 2.77, + "teardown": 1.97, + "total": 5.22 + } }, "tests/aws/services/s3/test_s3.py::TestS3::test_s3_sse_validate_kms_key": { - "last_validated_date": "2025-01-21T18:39:28+00:00" + "last_validated_date": "2026-02-21T00:27:58+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 4.01, + "teardown": 1.81, + "total": 5.82 + } }, "tests/aws/services/s3/test_s3.py::TestS3::test_s3_sse_validate_kms_key_state": { - "last_validated_date": "2025-01-21T18:39:38+00:00" + "last_validated_date": "2026-02-21T00:28:08+00:00", + "durations_in_seconds": { + "setup": 0.53, + "call": 7.57, + "teardown": 1.35, + "total": 9.45 + } }, "tests/aws/services/s3/test_s3.py::TestS3::test_s3_timestamp_precision": { - "last_validated_date": "2025-01-21T18:41:40+00:00" + "last_validated_date": "2026-02-21T00:28:47+00:00", + "durations_in_seconds": { + "setup": 0.53, + "call": 1.06, + "teardown": 1.0, + "total": 2.59 + } }, "tests/aws/services/s3/test_s3.py::TestS3::test_s3_upload_download_gzip": { - "last_validated_date": "2025-01-21T18:32:51+00:00" + "last_validated_date": "2026-02-21T00:22:50+00:00", + "durations_in_seconds": { + "setup": 0.52, + "call": 0.34, + "teardown": 0.96, + "total": 1.82 + } }, "tests/aws/services/s3/test_s3.py::TestS3::test_s3_uppercase_bucket_name": { - "last_validated_date": "2025-01-21T18:34:09+00:00" + "last_validated_date": "2026-02-21T00:23:23+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.41, + "teardown": 0.01, + "total": 0.42 + } }, "tests/aws/services/s3/test_s3.py::TestS3::test_s3_uppercase_key_names": { - "last_validated_date": "2025-01-21T18:31:47+00:00" + "last_validated_date": "2026-02-21T00:21:47+00:00", + "durations_in_seconds": { + "setup": 0.01, + "call": 1.18, + "teardown": 0.96, + "total": 2.15 + } }, "tests/aws/services/s3/test_s3.py::TestS3::test_set_external_hostname": { - "last_validated_date": "2025-03-17T21:30:10+00:00" + "last_validated_date": "2026-02-21T00:23:07+00:00", + "durations_in_seconds": { + "setup": 0.93, + "call": 1.05, + "teardown": 0.92, + "total": 2.9 + } + }, + "tests/aws/services/s3/test_s3.py::TestS3::test_system_metadata_with_unicode": { + "last_validated_date": "2026-02-21T00:17:07+00:00", + "durations_in_seconds": { + "setup": 0.58, + "call": 0.42, + "teardown": 0.99, + "total": 1.99 + } }, "tests/aws/services/s3/test_s3.py::TestS3::test_upload_big_file": { - "last_validated_date": "2025-01-21T18:39:01+00:00" + "last_validated_date": "2026-02-21T00:27:30+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 2.52, + "teardown": 0.97, + "total": 3.49 + } }, "tests/aws/services/s3/test_s3.py::TestS3::test_upload_file_multipart": { - "last_validated_date": "2025-01-21T18:26:40+00:00" + "last_validated_date": "2026-02-21T00:17:21+00:00", + "durations_in_seconds": { + "setup": 0.5, + "call": 0.81, + "teardown": 0.94, + "total": 2.25 + } }, "tests/aws/services/s3/test_s3.py::TestS3::test_upload_file_with_xml_preamble": { - "last_validated_date": "2025-01-21T18:30:40+00:00" + "last_validated_date": "2026-02-21T00:20:57+00:00", + "durations_in_seconds": { + "setup": 0.53, + "call": 0.42, + "teardown": 0.99, + "total": 1.94 + } }, "tests/aws/services/s3/test_s3.py::TestS3::test_url_encoded_key[False]": { - "last_validated_date": "2025-01-21T18:27:09+00:00" + "last_validated_date": "2026-02-21T00:17:57+00:00", + "durations_in_seconds": { + "setup": 0.52, + "call": 1.43, + "teardown": 1.01, + "total": 2.96 + } }, "tests/aws/services/s3/test_s3.py::TestS3::test_url_encoded_key[True]": { - "last_validated_date": "2025-01-21T18:27:06+00:00" + "last_validated_date": "2026-02-21T00:17:54+00:00", + "durations_in_seconds": { + "setup": 0.51, + "call": 1.35, + "teardown": 1.17, + "total": 3.03 + } + }, + "tests/aws/services/s3/test_s3.py::TestS3::test_user_metadata_rfc2047_bad_b64_encoded": { + "last_validated_date": "2026-02-21T00:17:11+00:00", + "durations_in_seconds": { + "setup": 0.72, + "call": 0.33, + "teardown": 0.75, + "total": 1.8 + } + }, + "tests/aws/services/s3/test_s3.py::TestS3::test_user_metadata_rfc2047_encoded": { + "last_validated_date": "2026-02-21T00:17:09+00:00", + "durations_in_seconds": { + "setup": 0.51, + "call": 0.34, + "teardown": 0.98, + "total": 1.83 + } }, "tests/aws/services/s3/test_s3.py::TestS3BucketLifecycle::test_bucket_lifecycle_configuration_date": { - "last_validated_date": "2025-01-21T18:18:26+00:00" + "last_validated_date": "2026-02-21T00:33:24+00:00", + "durations_in_seconds": { + "setup": 0.52, + "call": 0.39, + "teardown": 0.63, + "total": 1.54 + } }, "tests/aws/services/s3/test_s3.py::TestS3BucketLifecycle::test_bucket_lifecycle_configuration_object_expiry": { - "last_validated_date": "2025-01-21T18:18:28+00:00" + "last_validated_date": "2026-02-21T00:33:27+00:00", + "durations_in_seconds": { + "setup": 0.52, + "call": 0.84, + "teardown": 1.02, + "total": 2.38 + } }, "tests/aws/services/s3/test_s3.py::TestS3BucketLifecycle::test_bucket_lifecycle_configuration_object_expiry_versioned": { - "last_validated_date": "2025-01-21T18:18:31+00:00" + "last_validated_date": "2026-02-21T00:33:30+00:00", + "durations_in_seconds": { + "setup": 0.5, + "call": 1.54, + "teardown": 1.45, + "total": 3.49 + } }, "tests/aws/services/s3/test_s3.py::TestS3BucketLifecycle::test_bucket_lifecycle_multiple_rules": { - "last_validated_date": "2025-01-21T18:18:36+00:00" + "last_validated_date": "2026-02-21T00:33:35+00:00", + "durations_in_seconds": { + "setup": 0.52, + "call": 1.09, + "teardown": 1.08, + "total": 2.69 + } }, "tests/aws/services/s3/test_s3.py::TestS3BucketLifecycle::test_bucket_lifecycle_object_size_rules": { - "last_validated_date": "2025-01-21T18:18:38+00:00" + "last_validated_date": "2026-02-21T00:33:38+00:00", + "durations_in_seconds": { + "setup": 0.52, + "call": 1.08, + "teardown": 1.04, + "total": 2.64 + } }, "tests/aws/services/s3/test_s3.py::TestS3BucketLifecycle::test_bucket_lifecycle_tag_rules": { - "last_validated_date": "2025-01-21T18:18:42+00:00" + "last_validated_date": "2026-02-21T00:33:42+00:00", + "durations_in_seconds": { + "setup": 0.53, + "call": 2.53, + "teardown": 1.08, + "total": 4.14 + } }, "tests/aws/services/s3/test_s3.py::TestS3BucketLifecycle::test_delete_bucket_lifecycle_configuration": { - "last_validated_date": "2025-01-21T18:18:18+00:00" + "last_validated_date": "2026-02-21T00:33:16+00:00", + "durations_in_seconds": { + "setup": 0.5, + "call": 1.01, + "teardown": 0.6, + "total": 2.11 + } }, "tests/aws/services/s3/test_s3.py::TestS3BucketLifecycle::test_delete_lifecycle_configuration_on_bucket_deletion": { - "last_validated_date": "2025-01-21T18:18:20+00:00" + "last_validated_date": "2026-02-21T00:33:18+00:00", + "durations_in_seconds": { + "setup": 0.01, + "call": 1.68, + "teardown": 0.86, + "total": 2.55 + } }, "tests/aws/services/s3/test_s3.py::TestS3BucketLifecycle::test_lifecycle_expired_object_delete_marker": { - "last_validated_date": "2025-01-21T18:18:44+00:00" + "last_validated_date": "2026-02-21T00:33:44+00:00", + "durations_in_seconds": { + "setup": 0.52, + "call": 0.72, + "teardown": 1.0, + "total": 2.24 + } }, "tests/aws/services/s3/test_s3.py::TestS3BucketLifecycle::test_object_expiry_after_bucket_lifecycle_configuration": { - "last_validated_date": "2025-01-21T18:18:33+00:00" + "last_validated_date": "2026-02-21T00:33:33+00:00", + "durations_in_seconds": { + "setup": 0.51, + "call": 1.06, + "teardown": 1.03, + "total": 2.6 + } }, "tests/aws/services/s3/test_s3.py::TestS3BucketLifecycle::test_put_bucket_lifecycle_conf_exc": { - "last_validated_date": "2025-01-21T18:18:24+00:00" + "last_validated_date": "2026-02-21T00:33:23+00:00", + "durations_in_seconds": { + "setup": 0.52, + "call": 2.83, + "teardown": 0.84, + "total": 4.19 + } }, "tests/aws/services/s3/test_s3.py::TestS3BucketLifecycle::test_s3_transition_default_minimum_object_size": { - "last_validated_date": "2025-02-03T10:15:22+00:00" + "last_validated_date": "2026-02-21T00:33:47+00:00", + "durations_in_seconds": { + "setup": 0.52, + "call": 1.35, + "teardown": 0.84, + "total": 2.71 + } }, "tests/aws/services/s3/test_s3.py::TestS3BucketLogging::test_put_bucket_logging": { - "last_validated_date": "2023-08-12T17:54:07+00:00" + "last_validated_date": "2026-02-21T00:34:55+00:00", + "durations_in_seconds": { + "setup": 0.01, + "call": 1.77, + "teardown": 2.27, + "total": 4.05 + } }, "tests/aws/services/s3/test_s3.py::TestS3BucketLogging::test_put_bucket_logging_accept_wrong_grants": { - "last_validated_date": "2023-08-03T02:26:11+00:00" + "last_validated_date": "2026-02-21T00:34:58+00:00", + "durations_in_seconds": { + "setup": 0.01, + "call": 1.63, + "teardown": 1.2, + "total": 2.84 + } }, "tests/aws/services/s3/test_s3.py::TestS3BucketLogging::test_put_bucket_logging_cross_locations": { - "last_validated_date": "2024-08-29T15:58:14+00:00" + "last_validated_date": "2026-02-21T00:35:07+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 2.52, + "teardown": 2.68, + "total": 5.2 + } }, "tests/aws/services/s3/test_s3.py::TestS3BucketLogging::test_put_bucket_logging_wrong_target": { - "last_validated_date": "2024-08-30T11:31:48+00:00" + "last_validated_date": "2026-02-21T00:35:02+00:00", + "durations_in_seconds": { + "setup": 0.01, + "call": 1.54, + "teardown": 2.27, + "total": 3.82 + } }, "tests/aws/services/s3/test_s3.py::TestS3BucketReplication::test_replication_config": { - "last_validated_date": "2024-08-29T14:09:55+00:00" + "last_validated_date": "2026-02-21T00:35:19+00:00", + "durations_in_seconds": { + "setup": 0.01, + "call": 4.93, + "teardown": 1.95, + "total": 6.89 + } }, "tests/aws/services/s3/test_s3.py::TestS3BucketReplication::test_replication_config_without_filter": { - "last_validated_date": "2023-08-03T02:13:02+00:00" + "last_validated_date": "2026-02-21T00:35:12+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 3.21, + "teardown": 1.59, + "total": 4.8 + } }, "tests/aws/services/s3/test_s3.py::TestS3DeepArchive::test_s3_get_deep_archive_object_restore": { - "last_validated_date": "2023-08-14T20:35:53+00:00" + "last_validated_date": "2026-02-21T00:32:23+00:00", + "durations_in_seconds": { + "setup": 0.01, + "call": 1.43, + "teardown": 0.95, + "total": 2.39 + } + }, + "tests/aws/services/s3/test_s3.py::TestS3DeepArchive::test_storage_class_deep_archive": { + "last_validated_date": "2026-02-21T00:32:21+00:00", + "durations_in_seconds": { + "setup": 0.51, + "call": 1.48, + "teardown": 0.96, + "total": 2.95 + } }, "tests/aws/services/s3/test_s3.py::TestS3MultipartUploadChecksum::test_complete_multipart_parts_checksum_composite[CRC32C]": { - "last_validated_date": "2025-07-07T17:40:11+00:00", + "last_validated_date": "2026-02-21T00:38:48+00:00", "durations_in_seconds": { - "setup": 0.63, - "call": 18.57, - "teardown": 1.06, - "total": 20.26 + "setup": 0.5, + "call": 7.11, + "teardown": 0.77, + "total": 8.38 } }, "tests/aws/services/s3/test_s3.py::TestS3MultipartUploadChecksum::test_complete_multipart_parts_checksum_composite[CRC32]": { - "last_validated_date": "2025-07-07T17:39:51+00:00", + "last_validated_date": "2026-02-21T00:38:40+00:00", "durations_in_seconds": { - "setup": 0.99, - "call": 17.13, - "teardown": 1.18, - "total": 19.3 + "setup": 0.57, + "call": 6.55, + "teardown": 1.01, + "total": 8.13 } }, "tests/aws/services/s3/test_s3.py::TestS3MultipartUploadChecksum::test_complete_multipart_parts_checksum_composite[SHA1]": { - "last_validated_date": "2025-07-07T17:40:51+00:00", + "last_validated_date": "2026-02-21T00:38:55+00:00", "durations_in_seconds": { "setup": 0.56, - "call": 38.2, - "teardown": 1.57, - "total": 40.33 + "call": 5.85, + "teardown": 0.76, + "total": 7.17 } }, "tests/aws/services/s3/test_s3.py::TestS3MultipartUploadChecksum::test_complete_multipart_parts_checksum_composite[SHA256]": { - "last_validated_date": "2025-07-07T17:41:11+00:00", + "last_validated_date": "2026-02-21T00:39:03+00:00", "durations_in_seconds": { - "setup": 0.67, - "call": 17.67, - "teardown": 1.12, - "total": 19.46 + "setup": 0.51, + "call": 5.75, + "teardown": 1.0, + "total": 7.26 } }, "tests/aws/services/s3/test_s3.py::TestS3MultipartUploadChecksum::test_complete_multipart_parts_checksum_default": { - "last_validated_date": "2025-06-15T17:12:57+00:00", + "last_validated_date": "2026-02-21T00:42:10+00:00", "durations_in_seconds": { - "setup": 0.59, - "call": 2.92, - "teardown": 0.99, - "total": 4.5 + "setup": 0.55, + "call": 2.97, + "teardown": 0.97, + "total": 4.49 } }, "tests/aws/services/s3/test_s3.py::TestS3MultipartUploadChecksum::test_complete_multipart_parts_checksum_full_object[CRC32C]": { - "last_validated_date": "2025-07-07T17:41:54+00:00", + "last_validated_date": "2026-02-21T00:40:58+00:00", "durations_in_seconds": { - "setup": 0.74, - "call": 17.12, - "teardown": 1.01, - "total": 18.87 + "setup": 0.54, + "call": 5.34, + "teardown": 1.04, + "total": 6.92 } }, "tests/aws/services/s3/test_s3.py::TestS3MultipartUploadChecksum::test_complete_multipart_parts_checksum_full_object[CRC32]": { - "last_validated_date": "2025-07-07T17:41:35+00:00", + "last_validated_date": "2026-02-21T00:40:51+00:00", "durations_in_seconds": { - "setup": 1.26, - "call": 16.39, - "teardown": 1.06, - "total": 18.71 + "setup": 0.53, + "call": 5.27, + "teardown": 1.01, + "total": 6.81 } }, "tests/aws/services/s3/test_s3.py::TestS3MultipartUploadChecksum::test_complete_multipart_parts_checksum_full_object[CRC64NVME]": { - "last_validated_date": "2025-07-07T17:42:05+00:00", + "last_validated_date": "2026-02-21T00:41:05+00:00", "durations_in_seconds": { - "setup": 0.66, - "call": 9.59, - "teardown": 1.14, - "total": 11.39 + "setup": 0.54, + "call": 5.8, + "teardown": 1.0, + "total": 7.34 } }, "tests/aws/services/s3/test_s3.py::TestS3MultipartUploadChecksum::test_complete_multipart_parts_checksum_full_object_default": { - "last_validated_date": "2025-06-15T17:12:59+00:00", + "last_validated_date": "2026-02-21T00:42:12+00:00", "durations_in_seconds": { - "setup": 0.5, - "call": 0.92, - "teardown": 1.0, - "total": 2.42 + "setup": 0.51, + "call": 0.94, + "teardown": 0.95, + "total": 2.4 } }, "tests/aws/services/s3/test_s3.py::TestS3MultipartUploadChecksum::test_multipart_checksum_type_compatibility[COMPOSITE-CRC32C]": { - "last_validated_date": "2025-06-15T17:09:51+00:00", + "last_validated_date": "2026-02-21T00:39:05+00:00", "durations_in_seconds": { - "setup": 0.5, + "setup": 0.51, "call": 0.12, - "teardown": 0.61, + "teardown": 0.6, "total": 1.23 } }, "tests/aws/services/s3/test_s3.py::TestS3MultipartUploadChecksum::test_multipart_checksum_type_compatibility[COMPOSITE-CRC32]": { - "last_validated_date": "2025-06-15T17:09:50+00:00", + "last_validated_date": "2026-02-21T00:39:04+00:00", "durations_in_seconds": { - "setup": 0.48, + "setup": 0.54, "call": 0.12, - "teardown": 0.56, - "total": 1.16 + "teardown": 0.59, + "total": 1.25 } }, "tests/aws/services/s3/test_s3.py::TestS3MultipartUploadChecksum::test_multipart_checksum_type_compatibility[COMPOSITE-CRC64NVME]": { - "last_validated_date": "2025-06-15T17:09:55+00:00", + "last_validated_date": "2026-02-21T00:39:09+00:00", "durations_in_seconds": { - "setup": 0.56, + "setup": 0.52, "call": 0.11, - "teardown": 0.77, - "total": 1.44 + "teardown": 0.82, + "total": 1.45 } }, "tests/aws/services/s3/test_s3.py::TestS3MultipartUploadChecksum::test_multipart_checksum_type_compatibility[COMPOSITE-SHA1]": { - "last_validated_date": "2025-06-15T17:09:52+00:00", + "last_validated_date": "2026-02-21T00:39:07+00:00", "durations_in_seconds": { - "setup": 0.57, + "setup": 0.51, "call": 0.14, - "teardown": 0.58, - "total": 1.29 + "teardown": 0.62, + "total": 1.27 } }, "tests/aws/services/s3/test_s3.py::TestS3MultipartUploadChecksum::test_multipart_checksum_type_compatibility[COMPOSITE-SHA256]": { - "last_validated_date": "2025-06-15T17:09:54+00:00", + "last_validated_date": "2026-02-21T00:39:08+00:00", "durations_in_seconds": { - "setup": 0.48, - "call": 0.14, - "teardown": 0.57, - "total": 1.19 + "setup": 0.58, + "call": 0.13, + "teardown": 0.59, + "total": 1.3 } }, "tests/aws/services/s3/test_s3.py::TestS3MultipartUploadChecksum::test_multipart_checksum_type_compatibility[FULL_OBJECT-CRC32C]": { - "last_validated_date": "2025-06-15T17:09:58+00:00", + "last_validated_date": "2026-02-21T00:39:12+00:00", "durations_in_seconds": { - "setup": 0.64, + "setup": 0.5, "call": 0.13, - "teardown": 0.64, - "total": 1.41 + "teardown": 0.63, + "total": 1.26 } }, "tests/aws/services/s3/test_s3.py::TestS3MultipartUploadChecksum::test_multipart_checksum_type_compatibility[FULL_OBJECT-CRC32]": { - "last_validated_date": "2025-06-15T17:09:56+00:00", + "last_validated_date": "2026-02-21T00:39:11+00:00", "durations_in_seconds": { "setup": 0.51, - "call": 0.13, - "teardown": 0.64, - "total": 1.28 + "call": 0.14, + "teardown": 0.6, + "total": 1.25 } }, "tests/aws/services/s3/test_s3.py::TestS3MultipartUploadChecksum::test_multipart_checksum_type_compatibility[FULL_OBJECT-CRC64NVME]": { - "last_validated_date": "2025-06-15T17:10:02+00:00", + "last_validated_date": "2026-02-21T00:39:16+00:00", "durations_in_seconds": { - "setup": 0.51, - "call": 0.15, - "teardown": 0.64, - "total": 1.3 + "setup": 0.53, + "call": 0.13, + "teardown": 0.65, + "total": 1.31 } }, "tests/aws/services/s3/test_s3.py::TestS3MultipartUploadChecksum::test_multipart_checksum_type_compatibility[FULL_OBJECT-SHA1]": { - "last_validated_date": "2025-06-15T17:09:59+00:00", + "last_validated_date": "2026-02-21T00:39:13+00:00", "durations_in_seconds": { - "setup": 0.51, - "call": 0.11, - "teardown": 0.91, - "total": 1.53 + "setup": 0.5, + "call": 0.12, + "teardown": 0.94, + "total": 1.56 } }, "tests/aws/services/s3/test_s3.py::TestS3MultipartUploadChecksum::test_multipart_checksum_type_compatibility[FULL_OBJECT-SHA256]": { - "last_validated_date": "2025-06-15T17:10:01+00:00", + "last_validated_date": "2026-02-21T00:39:15+00:00", "durations_in_seconds": { "setup": 0.51, - "call": 0.12, + "call": 0.14, "teardown": 0.83, - "total": 1.46 + "total": 1.48 } }, "tests/aws/services/s3/test_s3.py::TestS3MultipartUploadChecksum::test_multipart_checksum_type_default_for_checksum[CRC32C]": { - "last_validated_date": "2025-06-15T17:10:05+00:00", + "last_validated_date": "2026-02-21T00:39:19+00:00", "durations_in_seconds": { - "setup": 0.57, - "call": 0.13, + "setup": 0.53, + "call": 0.14, "teardown": 0.63, - "total": 1.33 + "total": 1.3 } }, "tests/aws/services/s3/test_s3.py::TestS3MultipartUploadChecksum::test_multipart_checksum_type_default_for_checksum[CRC32]": { - "last_validated_date": "2025-06-15T17:10:03+00:00", + "last_validated_date": "2026-02-21T00:39:17+00:00", "durations_in_seconds": { - "setup": 0.49, - "call": 0.12, - "teardown": 0.6, - "total": 1.21 + "setup": 0.54, + "call": 0.13, + "teardown": 0.65, + "total": 1.32 } }, "tests/aws/services/s3/test_s3.py::TestS3MultipartUploadChecksum::test_multipart_checksum_type_default_for_checksum[CRC64NVME]": { - "last_validated_date": "2025-06-15T17:10:08+00:00", + "last_validated_date": "2026-02-21T00:39:23+00:00", "durations_in_seconds": { - "setup": 0.47, - "call": 0.11, - "teardown": 0.57, - "total": 1.15 + "setup": 0.58, + "call": 0.14, + "teardown": 0.72, + "total": 1.44 } }, "tests/aws/services/s3/test_s3.py::TestS3MultipartUploadChecksum::test_multipart_checksum_type_default_for_checksum[SHA1]": { - "last_validated_date": "2025-06-15T17:10:06+00:00", + "last_validated_date": "2026-02-21T00:39:20+00:00", "durations_in_seconds": { - "setup": 0.59, - "call": 0.14, - "teardown": 0.6, - "total": 1.33 + "setup": 0.53, + "call": 0.12, + "teardown": 0.59, + "total": 1.24 } }, "tests/aws/services/s3/test_s3.py::TestS3MultipartUploadChecksum::test_multipart_checksum_type_default_for_checksum[SHA256]": { - "last_validated_date": "2025-06-15T17:10:07+00:00", + "last_validated_date": "2026-02-21T00:39:21+00:00", "durations_in_seconds": { - "setup": 0.5, - "call": 0.11, - "teardown": 0.57, - "total": 1.18 + "setup": 0.51, + "call": 0.13, + "teardown": 0.61, + "total": 1.25 } }, "tests/aws/services/s3/test_s3.py::TestS3MultipartUploadChecksum::test_multipart_parts_checksum_exceptions_composite": { - "last_validated_date": "2025-06-15T17:11:25+00:00", + "last_validated_date": "2026-02-21T00:40:44+00:00", "durations_in_seconds": { - "setup": 0.52, - "call": 12.45, - "teardown": 0.89, - "total": 13.86 + "setup": 0.55, + "call": 13.23, + "teardown": 0.86, + "total": 14.64 } }, "tests/aws/services/s3/test_s3.py::TestS3MultipartUploadChecksum::test_multipart_parts_checksum_exceptions_full_object": { - "last_validated_date": "2025-06-15T17:12:52+00:00", + "last_validated_date": "2026-02-21T00:42:06+00:00", "durations_in_seconds": { - "setup": 0.49, - "call": 42.48, - "teardown": 1.16, - "total": 44.13 + "setup": 0.52, + "call": 58.81, + "teardown": 1.05, + "total": 60.38 } }, "tests/aws/services/s3/test_s3.py::TestS3MultipartUploadChecksum::test_multipart_size_validation": { - "last_validated_date": "2025-06-15T17:13:02+00:00", + "last_validated_date": "2026-02-21T00:42:15+00:00", "durations_in_seconds": { - "setup": 0.53, - "call": 1.14, - "teardown": 1.03, - "total": 2.7 + "setup": 0.51, + "call": 1.15, + "teardown": 0.95, + "total": 2.61 } }, "tests/aws/services/s3/test_s3.py::TestS3MultipartUploadChecksum::test_multipart_upload_part_checksum_exception[CRC32C]": { - "last_validated_date": "2025-06-15T17:10:28+00:00", + "last_validated_date": "2026-02-21T00:39:49+00:00", "durations_in_seconds": { - "setup": 0.47, - "call": 9.47, - "teardown": 0.9, - "total": 10.84 + "setup": 0.53, + "call": 9.99, + "teardown": 0.85, + "total": 11.37 } }, "tests/aws/services/s3/test_s3.py::TestS3MultipartUploadChecksum::test_multipart_upload_part_checksum_exception[CRC32]": { - "last_validated_date": "2025-06-15T17:10:18+00:00", + "last_validated_date": "2026-02-21T00:39:38+00:00", "durations_in_seconds": { - "setup": 0.46, - "call": 8.02, - "teardown": 0.84, - "total": 9.32 + "setup": 0.55, + "call": 13.52, + "teardown": 0.85, + "total": 14.92 } }, "tests/aws/services/s3/test_s3.py::TestS3MultipartUploadChecksum::test_multipart_upload_part_checksum_exception[CRC64NVME]": { - "last_validated_date": "2025-06-15T17:11:11+00:00", + "last_validated_date": "2026-02-21T00:40:29+00:00", "durations_in_seconds": { - "setup": 0.52, - "call": 9.39, - "teardown": 0.81, - "total": 10.72 + "setup": 0.54, + "call": 11.7, + "teardown": 0.86, + "total": 13.1 } }, "tests/aws/services/s3/test_s3.py::TestS3MultipartUploadChecksum::test_multipart_upload_part_checksum_exception[SHA1]": { - "last_validated_date": "2025-06-15T17:10:44+00:00", + "last_validated_date": "2026-02-21T00:40:03+00:00", "durations_in_seconds": { - "setup": 0.52, - "call": 14.71, - "teardown": 0.86, - "total": 16.09 + "setup": 0.53, + "call": 12.43, + "teardown": 0.9, + "total": 13.86 } }, "tests/aws/services/s3/test_s3.py::TestS3MultipartUploadChecksum::test_multipart_upload_part_checksum_exception[SHA256]": { - "last_validated_date": "2025-06-15T17:11:00+00:00", + "last_validated_date": "2026-02-21T00:40:16+00:00", "durations_in_seconds": { - "setup": 0.62, - "call": 14.22, - "teardown": 0.81, - "total": 15.65 + "setup": 0.55, + "call": 11.88, + "teardown": 0.86, + "total": 13.29 } }, "tests/aws/services/s3/test_s3.py::TestS3MultipartUploadChecksum::test_multipart_upload_part_copy_checksum[COMPOSITE]": { - "last_validated_date": "2025-06-16T10:53:40+00:00", + "last_validated_date": "2026-02-21T00:42:18+00:00", "durations_in_seconds": { - "setup": 0.97, - "call": 1.5, - "teardown": 1.06, - "total": 3.53 + "setup": 0.52, + "call": 1.46, + "teardown": 0.98, + "total": 2.96 } }, "tests/aws/services/s3/test_s3.py::TestS3MultipartUploadChecksum::test_multipart_upload_part_copy_checksum[FULL_OBJECT]": { - "last_validated_date": "2025-06-16T10:53:43+00:00", + "last_validated_date": "2026-02-21T00:42:22+00:00", "durations_in_seconds": { - "setup": 0.52, - "call": 1.4, - "teardown": 0.94, - "total": 2.86 + "setup": 0.55, + "call": 1.55, + "teardown": 1.98, + "total": 4.08 } }, "tests/aws/services/s3/test_s3.py::TestS3ObjectLockLegalHold::test_delete_locked_object": { - "last_validated_date": "2025-01-21T18:17:15+00:00" + "last_validated_date": "2026-02-21T00:34:45+00:00", + "durations_in_seconds": { + "setup": 0.01, + "call": 1.49, + "teardown": 1.34, + "total": 2.84 + } }, "tests/aws/services/s3/test_s3.py::TestS3ObjectLockLegalHold::test_put_get_object_legal_hold": { - "last_validated_date": "2025-01-21T18:17:06+00:00" + "last_validated_date": "2026-02-21T00:34:35+00:00", + "durations_in_seconds": { + "setup": 0.01, + "call": 1.33, + "teardown": 1.22, + "total": 2.56 + } }, "tests/aws/services/s3/test_s3.py::TestS3ObjectLockLegalHold::test_put_object_legal_hold_exc": { - "last_validated_date": "2025-01-21T18:17:12+00:00" + "last_validated_date": "2026-02-21T00:34:42+00:00", + "durations_in_seconds": { + "setup": 0.01, + "call": 2.56, + "teardown": 1.83, + "total": 4.4 + } }, "tests/aws/services/s3/test_s3.py::TestS3ObjectLockLegalHold::test_put_object_with_legal_hold": { - "last_validated_date": "2025-01-21T18:17:08+00:00" + "last_validated_date": "2026-02-21T00:34:38+00:00", + "durations_in_seconds": { + "setup": 0.01, + "call": 1.01, + "teardown": 1.39, + "total": 2.41 + } }, "tests/aws/services/s3/test_s3.py::TestS3ObjectLockLegalHold::test_s3_copy_object_legal_hold": { - "last_validated_date": "2025-01-21T18:17:21+00:00" + "last_validated_date": "2026-02-21T00:34:51+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 1.46, + "teardown": 1.49, + "total": 2.95 + } }, "tests/aws/services/s3/test_s3.py::TestS3ObjectLockLegalHold::test_s3_legal_hold_lock_versioned": { - "last_validated_date": "2025-01-21T18:17:18+00:00" + "last_validated_date": "2026-02-21T00:34:48+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 2.03, + "teardown": 1.42, + "total": 3.45 + } }, "tests/aws/services/s3/test_s3.py::TestS3ObjectLockRetention::test_bucket_config_default_retention": { - "last_validated_date": "2025-06-20T17:35:53+00:00", + "last_validated_date": "2026-02-21T00:34:12+00:00", "durations_in_seconds": { - "setup": 0.48, - "call": 1.55, - "teardown": 1.78, - "total": 3.81 + "setup": 0.0, + "call": 1.47, + "teardown": 1.55, + "total": 3.02 } }, "tests/aws/services/s3/test_s3.py::TestS3ObjectLockRetention::test_object_lock_delete_markers": { - "last_validated_date": "2025-01-21T18:18:05+00:00" + "last_validated_date": "2026-02-21T00:34:14+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 1.26, + "teardown": 0.98, + "total": 2.24 + } }, "tests/aws/services/s3/test_s3.py::TestS3ObjectLockRetention::test_object_lock_extend_duration": { - "last_validated_date": "2025-01-21T18:18:07+00:00" + "last_validated_date": "2026-02-21T00:34:17+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 1.16, + "teardown": 1.28, + "total": 2.44 + } }, "tests/aws/services/s3/test_s3.py::TestS3ObjectLockRetention::test_s3_copy_object_retention_lock": { - "last_validated_date": "2025-01-21T18:18:00+00:00" + "last_validated_date": "2026-02-21T00:34:09+00:00", + "durations_in_seconds": { + "setup": 0.01, + "call": 1.18, + "teardown": 1.49, + "total": 2.68 + } }, "tests/aws/services/s3/test_s3.py::TestS3ObjectLockRetention::test_s3_object_lock_mode_validation": { - "last_validated_date": "2025-06-20T17:33:41+00:00", + "last_validated_date": "2026-02-21T00:34:33+00:00", "durations_in_seconds": { - "setup": 0.43, - "call": 1.68, - "teardown": 0.86, - "total": 2.97 + "setup": 0.01, + "call": 2.11, + "teardown": 0.87, + "total": 2.99 } }, "tests/aws/services/s3/test_s3.py::TestS3ObjectLockRetention::test_s3_object_retention": { - "last_validated_date": "2025-06-20T17:02:02+00:00", + "last_validated_date": "2026-02-21T00:34:06+00:00", "durations_in_seconds": { - "setup": 0.47, - "call": 12.42, + "setup": 0.0, + "call": 12.36, "teardown": 0.62, - "total": 13.51 + "total": 12.98 } }, "tests/aws/services/s3/test_s3.py::TestS3ObjectLockRetention::test_s3_object_retention_compliance_mode": { - "last_validated_date": "2025-06-20T17:19:57+00:00", + "last_validated_date": "2026-02-21T00:34:30+00:00", "durations_in_seconds": { - "setup": 0.44, - "call": 11.7, - "teardown": 1.29, - "total": 13.43 + "setup": 0.0, + "call": 11.75, + "teardown": 1.02, + "total": 12.77 } }, "tests/aws/services/s3/test_s3.py::TestS3ObjectLockRetention::test_s3_object_retention_exc": { - "last_validated_date": "2025-06-20T16:29:08+00:00", + "last_validated_date": "2026-02-21T00:33:53+00:00", "durations_in_seconds": { - "setup": 0.5, - "call": 3.38, - "teardown": 2.69, - "total": 6.57 + "setup": 0.0, + "call": 3.57, + "teardown": 2.64, + "total": 6.21 } }, "tests/aws/services/s3/test_s3.py::TestS3PresignedPost::test_post_object_default_checksum": { - "last_validated_date": "2025-03-17T21:46:24+00:00" + "last_validated_date": "2026-02-21T00:35:56+00:00", + "durations_in_seconds": { + "setup": 0.51, + "call": 0.45, + "teardown": 0.95, + "total": 1.91 + } }, "tests/aws/services/s3/test_s3.py::TestS3PresignedPost::test_post_object_policy_casing[s3]": { - "last_validated_date": "2025-03-28T19:11:34+00:00" + "last_validated_date": "2026-02-21T00:36:26+00:00", + "durations_in_seconds": { + "setup": 0.51, + "call": 0.71, + "teardown": 0.95, + "total": 2.17 + } }, "tests/aws/services/s3/test_s3.py::TestS3PresignedPost::test_post_object_policy_casing[s3v4]": { - "last_validated_date": "2025-03-28T19:11:36+00:00" + "last_validated_date": "2026-02-21T00:36:28+00:00", + "durations_in_seconds": { + "setup": 0.74, + "call": 0.72, + "teardown": 0.96, + "total": 2.42 + } }, "tests/aws/services/s3/test_s3.py::TestS3PresignedPost::test_post_object_policy_conditions_validation_eq": { - "last_validated_date": "2025-03-17T20:16:55+00:00" + "last_validated_date": "2026-02-21T00:36:03+00:00", + "durations_in_seconds": { + "setup": 0.5, + "call": 2.5, + "teardown": 0.93, + "total": 3.93 + } }, "tests/aws/services/s3/test_s3.py::TestS3PresignedPost::test_post_object_policy_conditions_validation_starts_with": { - "last_validated_date": "2025-03-17T20:16:58+00:00" + "last_validated_date": "2026-02-21T00:36:06+00:00", + "durations_in_seconds": { + "setup": 0.5, + "call": 1.77, + "teardown": 0.92, + "total": 3.19 + } }, "tests/aws/services/s3/test_s3.py::TestS3PresignedPost::test_post_object_policy_validation_size": { - "last_validated_date": "2025-03-17T20:17:02+00:00" + "last_validated_date": "2026-02-21T00:36:09+00:00", + "durations_in_seconds": { + "setup": 0.49, + "call": 2.07, + "teardown": 0.91, + "total": 3.47 + } }, "tests/aws/services/s3/test_s3.py::TestS3PresignedPost::test_post_object_with_file_as_string": { - "last_validated_date": "2025-03-17T20:16:51+00:00" + "last_validated_date": "2026-02-21T00:35:59+00:00", + "durations_in_seconds": { + "setup": 0.5, + "call": 0.89, + "teardown": 0.93, + "total": 2.32 + } + }, + "tests/aws/services/s3/test_s3.py::TestS3PresignedPost::test_post_object_with_files": { + "last_validated_date": "2026-02-21T00:35:21+00:00", + "durations_in_seconds": { + "setup": 0.84, + "call": 0.72, + "teardown": 0.91, + "total": 2.47 + } }, "tests/aws/services/s3/test_s3.py::TestS3PresignedPost::test_post_object_with_metadata": { - "last_validated_date": "2025-03-17T21:56:03+00:00" + "last_validated_date": "2026-02-21T00:35:49+00:00", + "durations_in_seconds": { + "setup": 0.51, + "call": 0.44, + "teardown": 0.93, + "total": 1.88 + } }, "tests/aws/services/s3/test_s3.py::TestS3PresignedPost::test_post_object_with_storage_class": { - "last_validated_date": "2025-03-17T20:16:47+00:00" + "last_validated_date": "2026-02-21T00:35:53+00:00", + "durations_in_seconds": { + "setup": 0.5, + "call": 0.78, + "teardown": 0.94, + "total": 2.22 + } }, "tests/aws/services/s3/test_s3.py::TestS3PresignedPost::test_post_object_with_tags[invalid]": { - "last_validated_date": "2025-03-17T20:16:41+00:00" + "last_validated_date": "2026-02-21T00:35:45+00:00", + "durations_in_seconds": { + "setup": 0.53, + "call": 0.47, + "teardown": 0.95, + "total": 1.95 + } }, "tests/aws/services/s3/test_s3.py::TestS3PresignedPost::test_post_object_with_tags[list]": { - "last_validated_date": "2025-03-17T20:16:39+00:00" + "last_validated_date": "2026-02-21T00:35:43+00:00", + "durations_in_seconds": { + "setup": 0.51, + "call": 0.48, + "teardown": 0.97, + "total": 1.96 + } }, "tests/aws/services/s3/test_s3.py::TestS3PresignedPost::test_post_object_with_tags[notxml]": { - "last_validated_date": "2025-03-17T20:16:43+00:00" + "last_validated_date": "2026-02-21T00:35:47+00:00", + "durations_in_seconds": { + "setup": 0.52, + "call": 0.44, + "teardown": 0.58, + "total": 1.54 + } }, "tests/aws/services/s3/test_s3.py::TestS3PresignedPost::test_post_object_with_tags[single]": { - "last_validated_date": "2025-03-17T20:16:38+00:00" + "last_validated_date": "2026-02-21T00:35:42+00:00", + "durations_in_seconds": { + "setup": 0.5, + "call": 0.49, + "teardown": 1.07, + "total": 2.06 + } + }, + "tests/aws/services/s3/test_s3.py::TestS3PresignedPost::test_post_object_with_unicode_metadata": { + "last_validated_date": "2026-02-21T00:35:51+00:00", + "durations_in_seconds": { + "setup": 0.49, + "call": 0.51, + "teardown": 0.92, + "total": 1.92 + } }, "tests/aws/services/s3/test_s3.py::TestS3PresignedPost::test_post_object_with_wrong_content_type": { - "last_validated_date": "2025-03-17T20:16:49+00:00" + "last_validated_date": "2026-02-21T00:35:54+00:00", + "durations_in_seconds": { + "setup": 0.51, + "call": 0.3, + "teardown": 0.58, + "total": 1.39 + } }, "tests/aws/services/s3/test_s3.py::TestS3PresignedPost::test_post_request_expires": { - "last_validated_date": "2025-03-17T20:16:24+00:00" + "last_validated_date": "2026-02-21T00:35:26+00:00", + "durations_in_seconds": { + "setup": 0.48, + "call": 3.33, + "teardown": 0.6, + "total": 4.41 + } }, "tests/aws/services/s3/test_s3.py::TestS3PresignedPost::test_post_request_malformed_policy[s3]": { - "last_validated_date": "2025-03-17T20:16:26+00:00" + "last_validated_date": "2026-02-21T00:35:27+00:00", + "durations_in_seconds": { + "setup": 0.52, + "call": 0.37, + "teardown": 0.59, + "total": 1.48 + } }, "tests/aws/services/s3/test_s3.py::TestS3PresignedPost::test_post_request_malformed_policy[s3v4]": { - "last_validated_date": "2025-03-17T20:16:27+00:00" + "last_validated_date": "2026-02-21T00:35:29+00:00", + "durations_in_seconds": { + "setup": 0.51, + "call": 0.36, + "teardown": 0.59, + "total": 1.46 + } }, "tests/aws/services/s3/test_s3.py::TestS3PresignedPost::test_post_request_missing_fields[s3]": { - "last_validated_date": "2025-03-17T20:16:32+00:00" + "last_validated_date": "2026-02-21T00:35:34+00:00", + "durations_in_seconds": { + "setup": 0.89, + "call": 0.61, + "teardown": 0.61, + "total": 2.11 + } }, "tests/aws/services/s3/test_s3.py::TestS3PresignedPost::test_post_request_missing_fields[s3v4]": { - "last_validated_date": "2025-03-17T20:16:34+00:00" + "last_validated_date": "2026-02-21T00:35:36+00:00", + "durations_in_seconds": { + "setup": 0.5, + "call": 0.74, + "teardown": 0.57, + "total": 1.81 + } }, "tests/aws/services/s3/test_s3.py::TestS3PresignedPost::test_post_request_missing_signature[s3]": { - "last_validated_date": "2025-03-17T20:16:29+00:00" + "last_validated_date": "2026-02-21T00:35:30+00:00", + "durations_in_seconds": { + "setup": 0.51, + "call": 0.33, + "teardown": 0.59, + "total": 1.43 + } }, "tests/aws/services/s3/test_s3.py::TestS3PresignedPost::test_post_request_missing_signature[s3v4]": { - "last_validated_date": "2025-03-17T20:16:30+00:00" + "last_validated_date": "2026-02-21T00:35:32+00:00", + "durations_in_seconds": { + "setup": 0.53, + "call": 0.35, + "teardown": 0.59, + "total": 1.47 + } }, "tests/aws/services/s3/test_s3.py::TestS3PresignedPost::test_presigned_post_with_different_user_credentials": { - "last_validated_date": "2025-03-17T20:17:16+00:00" + "last_validated_date": "2026-02-21T00:36:24+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 12.48, + "teardown": 1.9, + "total": 14.38 + } }, "tests/aws/services/s3/test_s3.py::TestS3PresignedPost::test_s3_presigned_post_success_action_redirect": { - "last_validated_date": "2025-03-17T20:16:36+00:00" + "last_validated_date": "2026-02-21T00:35:39+00:00", + "durations_in_seconds": { + "setup": 0.49, + "call": 0.67, + "teardown": 0.93, + "total": 2.09 + } + }, + "tests/aws/services/s3/test_s3.py::TestS3PresignedPost::test_s3_presigned_post_success_action_status_201_response": { + "last_validated_date": "2026-02-21T00:35:37+00:00", + "durations_in_seconds": { + "setup": 0.49, + "call": 0.34, + "teardown": 0.97, + "total": 1.8 + } }, "tests/aws/services/s3/test_s3.py::TestS3PresignedUrl::test_delete_has_empty_content_length_header": { - "last_validated_date": "2025-01-21T18:22:48+00:00" + "last_validated_date": "2026-02-21T00:29:29+00:00", + "durations_in_seconds": { + "setup": 0.55, + "call": 1.13, + "teardown": 0.58, + "total": 2.26 + } }, "tests/aws/services/s3/test_s3.py::TestS3PresignedUrl::test_get_object_ignores_request_body": { - "last_validated_date": "2025-01-21T18:23:01+00:00" + "last_validated_date": "2026-02-21T00:29:48+00:00", + "durations_in_seconds": { + "setup": 0.5, + "call": 0.54, + "teardown": 0.93, + "total": 1.97 + } + }, + "tests/aws/services/s3/test_s3.py::TestS3PresignedUrl::test_get_response_overrides_unicode_metadata_with_sig_s3": { + "last_validated_date": "2026-02-21T00:29:44+00:00", + "durations_in_seconds": { + "setup": 0.51, + "call": 0.55, + "teardown": 0.96, + "total": 2.02 + } }, "tests/aws/services/s3/test_s3.py::TestS3PresignedUrl::test_head_has_correct_content_length_header": { - "last_validated_date": "2025-01-21T18:22:49+00:00" + "last_validated_date": "2026-02-21T00:29:31+00:00", + "durations_in_seconds": { + "setup": 0.52, + "call": 0.56, + "teardown": 1.0, + "total": 2.08 + } }, "tests/aws/services/s3/test_s3.py::TestS3PresignedUrl::test_pre_signed_url_forward_slash_bucket": { - "last_validated_date": "2025-01-21T18:25:38+00:00" + "last_validated_date": "2026-02-21T00:32:06+00:00", + "durations_in_seconds": { + "setup": 0.5, + "call": 0.54, + "teardown": 0.97, + "total": 2.01 + } }, "tests/aws/services/s3/test_s3.py::TestS3PresignedUrl::test_pre_signed_url_if_match": { - "last_validated_date": "2025-05-15T13:08:44+00:00" + "last_validated_date": "2026-02-21T00:32:18+00:00", + "durations_in_seconds": { + "setup": 0.53, + "call": 0.57, + "teardown": 0.97, + "total": 2.07 + } }, "tests/aws/services/s3/test_s3.py::TestS3PresignedUrl::test_pre_signed_url_if_none_match": { - "last_validated_date": "2025-05-15T12:51:09+00:00" + "last_validated_date": "2026-02-21T00:32:16+00:00", + "durations_in_seconds": { + "setup": 0.54, + "call": 0.71, + "teardown": 0.99, + "total": 2.24 + } }, "tests/aws/services/s3/test_s3.py::TestS3PresignedUrl::test_presign_with_additional_query_params": { - "last_validated_date": "2025-01-21T18:22:43+00:00" + "last_validated_date": "2026-02-21T00:29:25+00:00", + "durations_in_seconds": { + "setup": 0.51, + "call": 0.71, + "teardown": 0.94, + "total": 2.16 + } }, "tests/aws/services/s3/test_s3.py::TestS3PresignedUrl::test_presigned_double_encoded_credentials": { - "last_validated_date": "2025-01-21T18:23:03+00:00" + "last_validated_date": "2026-02-21T00:29:50+00:00", + "durations_in_seconds": { + "setup": 0.51, + "call": 0.54, + "teardown": 0.95, + "total": 2.0 + } }, "tests/aws/services/s3/test_s3.py::TestS3PresignedUrl::test_presigned_url_signature_authentication[s3-False]": { - "last_validated_date": "2025-01-21T18:24:24+00:00" + "last_validated_date": "2026-02-21T00:31:11+00:00", + "durations_in_seconds": { + "setup": 0.01, + "call": 3.26, + "teardown": 0.59, + "total": 3.86 + } }, "tests/aws/services/s3/test_s3.py::TestS3PresignedUrl::test_presigned_url_signature_authentication[s3-True]": { - "last_validated_date": "2025-01-21T18:24:28+00:00" + "last_validated_date": "2026-02-21T00:31:15+00:00", + "durations_in_seconds": { + "setup": 0.01, + "call": 3.19, + "teardown": 0.57, + "total": 3.77 + } }, "tests/aws/services/s3/test_s3.py::TestS3PresignedUrl::test_presigned_url_signature_authentication[s3v4-False]": { - "last_validated_date": "2025-01-21T18:24:31+00:00" + "last_validated_date": "2026-02-21T00:31:18+00:00", + "durations_in_seconds": { + "setup": 0.01, + "call": 3.09, + "teardown": 0.58, + "total": 3.68 + } }, "tests/aws/services/s3/test_s3.py::TestS3PresignedUrl::test_presigned_url_signature_authentication[s3v4-True]": { - "last_validated_date": "2025-01-21T18:24:35+00:00" + "last_validated_date": "2026-02-21T00:31:22+00:00", + "durations_in_seconds": { + "setup": 0.01, + "call": 3.02, + "teardown": 0.58, + "total": 3.61 + } }, "tests/aws/services/s3/test_s3.py::TestS3PresignedUrl::test_presigned_url_signature_authentication_expired[s3-False]": { - "last_validated_date": "2025-01-21T18:24:08+00:00" + "last_validated_date": "2026-02-21T00:30:55+00:00", + "durations_in_seconds": { + "setup": 0.01, + "call": 3.11, + "teardown": 0.97, + "total": 4.09 + } }, "tests/aws/services/s3/test_s3.py::TestS3PresignedUrl::test_presigned_url_signature_authentication_expired[s3-True]": { - "last_validated_date": "2025-01-21T18:24:12+00:00" + "last_validated_date": "2026-02-21T00:30:59+00:00", + "durations_in_seconds": { + "setup": 0.01, + "call": 3.1, + "teardown": 0.98, + "total": 4.09 + } }, "tests/aws/services/s3/test_s3.py::TestS3PresignedUrl::test_presigned_url_signature_authentication_expired[s3v4-False]": { - "last_validated_date": "2025-01-21T18:24:16+00:00" + "last_validated_date": "2026-02-21T00:31:03+00:00", + "durations_in_seconds": { + "setup": 0.01, + "call": 3.13, + "teardown": 0.96, + "total": 4.1 + } }, "tests/aws/services/s3/test_s3.py::TestS3PresignedUrl::test_presigned_url_signature_authentication_expired[s3v4-True]": { - "last_validated_date": "2025-01-21T18:24:20+00:00" + "last_validated_date": "2026-02-21T00:31:07+00:00", + "durations_in_seconds": { + "setup": 0.01, + "call": 3.08, + "teardown": 0.72, + "total": 3.81 + } }, "tests/aws/services/s3/test_s3.py::TestS3PresignedUrl::test_presigned_url_signature_authentication_multi_part[s3-False]": { - "last_validated_date": "2025-01-21T18:24:37+00:00" + "last_validated_date": "2026-02-21T00:31:25+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 1.74, + "teardown": 0.96, + "total": 2.7 + } }, "tests/aws/services/s3/test_s3.py::TestS3PresignedUrl::test_presigned_url_signature_authentication_multi_part[s3-True]": { - "last_validated_date": "2025-01-21T18:24:40+00:00" + "last_validated_date": "2026-02-21T00:31:27+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 1.8, + "teardown": 0.94, + "total": 2.74 + } }, "tests/aws/services/s3/test_s3.py::TestS3PresignedUrl::test_presigned_url_signature_authentication_multi_part[s3v4-False]": { - "last_validated_date": "2025-01-21T18:24:43+00:00" + "last_validated_date": "2026-02-21T00:31:30+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 1.79, + "teardown": 1.04, + "total": 2.83 + } }, "tests/aws/services/s3/test_s3.py::TestS3PresignedUrl::test_presigned_url_signature_authentication_multi_part[s3v4-True]": { - "last_validated_date": "2025-01-21T18:24:45+00:00" + "last_validated_date": "2026-02-21T00:31:33+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 1.87, + "teardown": 0.93, + "total": 2.8 + } }, "tests/aws/services/s3/test_s3.py::TestS3PresignedUrl::test_presigned_url_v4_signed_headers_in_qs": { - "last_validated_date": "2025-01-21T18:25:34+00:00" + "last_validated_date": "2026-02-21T00:32:04+00:00", + "durations_in_seconds": { + "setup": 0.5, + "call": 11.74, + "teardown": 2.82, + "total": 15.06 + } }, "tests/aws/services/s3/test_s3.py::TestS3PresignedUrl::test_presigned_url_v4_x_amz_in_qs": { - "last_validated_date": "2025-03-17T21:32:11+00:00" + "last_validated_date": "2026-02-21T00:31:49+00:00", + "durations_in_seconds": { + "setup": 0.49, + "call": 12.4, + "teardown": 2.76, + "total": 15.65 + } }, "tests/aws/services/s3/test_s3.py::TestS3PresignedUrl::test_presigned_url_with_different_user_credentials": { - "last_validated_date": "2025-01-21T18:23:55+00:00" + "last_validated_date": "2026-02-21T00:30:44+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 12.33, + "teardown": 2.06, + "total": 14.39 + } }, "tests/aws/services/s3/test_s3.py::TestS3PresignedUrl::test_presigned_url_with_session_token": { - "last_validated_date": "2025-01-21T18:23:42+00:00" + "last_validated_date": "2026-02-21T00:30:30+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 1.47, + "teardown": 1.22, + "total": 2.69 + } }, "tests/aws/services/s3/test_s3.py::TestS3PresignedUrl::test_put_object": { - "last_validated_date": "2025-03-17T21:31:27+00:00" + "last_validated_date": "2026-02-21T00:29:27+00:00", + "durations_in_seconds": { + "setup": 0.51, + "call": 0.61, + "teardown": 1.01, + "total": 2.13 + } }, "tests/aws/services/s3/test_s3.py::TestS3PresignedUrl::test_put_object_with_md5_and_chunk_signature_bad_headers[s3-False]": { - "last_validated_date": "2025-01-21T18:23:07+00:00" + "last_validated_date": "2026-02-21T00:29:54+00:00", + "durations_in_seconds": { + "setup": 0.5, + "call": 0.62, + "teardown": 0.59, + "total": 1.71 + } }, "tests/aws/services/s3/test_s3.py::TestS3PresignedUrl::test_put_object_with_md5_and_chunk_signature_bad_headers[s3-True]": { - "last_validated_date": "2025-01-21T18:23:05+00:00" + "last_validated_date": "2026-02-21T00:29:52+00:00", + "durations_in_seconds": { + "setup": 0.5, + "call": 0.63, + "teardown": 0.61, + "total": 1.74 + } }, "tests/aws/services/s3/test_s3.py::TestS3PresignedUrl::test_put_object_with_md5_and_chunk_signature_bad_headers[s3v4-False]": { - "last_validated_date": "2025-01-21T18:23:10+00:00" + "last_validated_date": "2026-02-21T00:29:57+00:00", + "durations_in_seconds": { + "setup": 0.49, + "call": 0.73, + "teardown": 0.57, + "total": 1.79 + } }, "tests/aws/services/s3/test_s3.py::TestS3PresignedUrl::test_put_object_with_md5_and_chunk_signature_bad_headers[s3v4-True]": { - "last_validated_date": "2025-01-21T18:23:09+00:00" + "last_validated_date": "2026-02-21T00:29:55+00:00", + "durations_in_seconds": { + "setup": 0.49, + "call": 0.62, + "teardown": 0.59, + "total": 1.7 + } + }, + "tests/aws/services/s3/test_s3.py::TestS3PresignedUrl::test_put_unicode_metadata_with_sig_s3": { + "last_validated_date": "2026-02-21T00:29:46+00:00", + "durations_in_seconds": { + "setup": 0.51, + "call": 0.56, + "teardown": 0.93, + "total": 2.0 + } }, "tests/aws/services/s3/test_s3.py::TestS3PresignedUrl::test_put_url_metadata_with_sig_s3[False]": { - "last_validated_date": "2025-01-21T18:22:59+00:00" + "last_validated_date": "2026-02-21T00:29:42+00:00", + "durations_in_seconds": { + "setup": 0.53, + "call": 1.02, + "teardown": 0.94, + "total": 2.49 + } }, "tests/aws/services/s3/test_s3.py::TestS3PresignedUrl::test_put_url_metadata_with_sig_s3[True]": { - "last_validated_date": "2025-01-21T18:22:57+00:00" + "last_validated_date": "2026-02-21T00:29:40+00:00", + "durations_in_seconds": { + "setup": 0.5, + "call": 1.01, + "teardown": 0.95, + "total": 2.46 + } }, "tests/aws/services/s3/test_s3.py::TestS3PresignedUrl::test_put_url_metadata_with_sig_s3v4[False]": { - "last_validated_date": "2025-01-21T18:22:55+00:00" + "last_validated_date": "2026-02-21T00:29:37+00:00", + "durations_in_seconds": { + "setup": 0.77, + "call": 1.33, + "teardown": 0.94, + "total": 3.04 + } }, "tests/aws/services/s3/test_s3.py::TestS3PresignedUrl::test_put_url_metadata_with_sig_s3v4[True]": { - "last_validated_date": "2025-01-21T18:22:52+00:00" + "last_validated_date": "2026-02-21T00:29:34+00:00", + "durations_in_seconds": { + "setup": 0.51, + "call": 1.31, + "teardown": 0.97, + "total": 2.79 + } }, "tests/aws/services/s3/test_s3.py::TestS3PresignedUrl::test_s3_copy_md5": { - "last_validated_date": "2025-01-21T18:24:04+00:00" + "last_validated_date": "2026-02-21T00:30:51+00:00", + "durations_in_seconds": { + "setup": 0.52, + "call": 0.72, + "teardown": 1.02, + "total": 2.26 + } }, "tests/aws/services/s3/test_s3.py::TestS3PresignedUrl::test_s3_get_response_content_type_same_as_upload_and_range": { - "last_validated_date": "2025-01-21T18:23:40+00:00" + "last_validated_date": "2026-02-21T00:30:27+00:00", + "durations_in_seconds": { + "setup": 0.52, + "call": 0.94, + "teardown": 0.97, + "total": 2.43 + } }, "tests/aws/services/s3/test_s3.py::TestS3PresignedUrl::test_s3_get_response_default_content_type": { - "last_validated_date": "2025-01-21T18:23:12+00:00" + "last_validated_date": "2026-02-21T00:29:59+00:00", + "durations_in_seconds": { + "setup": 0.52, + "call": 0.54, + "teardown": 0.9, + "total": 1.96 + } }, "tests/aws/services/s3/test_s3.py::TestS3PresignedUrl::test_s3_get_response_header_overrides[s3]": { - "last_validated_date": "2025-01-21T18:23:58+00:00" + "last_validated_date": "2026-02-21T00:30:46+00:00", + "durations_in_seconds": { + "setup": 0.5, + "call": 0.56, + "teardown": 1.05, + "total": 2.11 + } }, "tests/aws/services/s3/test_s3.py::TestS3PresignedUrl::test_s3_get_response_header_overrides[s3v4]": { - "last_validated_date": "2025-01-21T18:24:00+00:00" + "last_validated_date": "2026-02-21T00:30:49+00:00", + "durations_in_seconds": { + "setup": 0.53, + "call": 0.6, + "teardown": 1.03, + "total": 2.16 + } }, "tests/aws/services/s3/test_s3.py::TestS3PresignedUrl::test_s3_ignored_special_headers": { - "last_validated_date": "2025-01-21T18:25:45+00:00" + "last_validated_date": "2026-02-21T00:32:13+00:00", + "durations_in_seconds": { + "setup": 0.53, + "call": 1.66, + "teardown": 0.97, + "total": 3.16 + } }, "tests/aws/services/s3/test_s3.py::TestS3PresignedUrl::test_s3_presign_url_encoding[s3]": { - "last_validated_date": "2025-01-21T18:25:40+00:00" + "last_validated_date": "2026-02-21T00:32:08+00:00", + "durations_in_seconds": { + "setup": 0.6, + "call": 0.56, + "teardown": 1.05, + "total": 2.21 + } }, "tests/aws/services/s3/test_s3.py::TestS3PresignedUrl::test_s3_presign_url_encoding[s3v4]": { - "last_validated_date": "2025-01-21T18:25:42+00:00" + "last_validated_date": "2026-02-21T00:32:10+00:00", + "durations_in_seconds": { + "setup": 0.52, + "call": 0.59, + "teardown": 0.97, + "total": 2.08 + } }, "tests/aws/services/s3/test_s3.py::TestS3PresignedUrl::test_s3_presigned_url_expired[s3]": { - "last_validated_date": "2025-01-21T18:23:17+00:00" + "last_validated_date": "2026-02-21T00:30:05+00:00", + "durations_in_seconds": { + "setup": 0.49, + "call": 4.2, + "teardown": 0.93, + "total": 5.62 + } }, "tests/aws/services/s3/test_s3.py::TestS3PresignedUrl::test_s3_presigned_url_expired[s3v4]": { - "last_validated_date": "2025-01-21T18:23:23+00:00" + "last_validated_date": "2026-02-21T00:30:10+00:00", + "durations_in_seconds": { + "setup": 0.49, + "call": 4.28, + "teardown": 0.92, + "total": 5.69 + } }, "tests/aws/services/s3/test_s3.py::TestS3PresignedUrl::test_s3_put_presigned_url_missing_sig_param[s3]": { - "last_validated_date": "2025-01-21T18:23:35+00:00" + "last_validated_date": "2026-02-21T00:30:23+00:00", + "durations_in_seconds": { + "setup": 0.53, + "call": 0.55, + "teardown": 0.95, + "total": 2.03 + } }, "tests/aws/services/s3/test_s3.py::TestS3PresignedUrl::test_s3_put_presigned_url_missing_sig_param[s3v4]": { - "last_validated_date": "2025-01-21T18:23:37+00:00" + "last_validated_date": "2026-02-21T00:30:25+00:00", + "durations_in_seconds": { + "setup": 0.5, + "call": 0.55, + "teardown": 1.0, + "total": 2.05 + } }, "tests/aws/services/s3/test_s3.py::TestS3PresignedUrl::test_s3_put_presigned_url_same_header_and_qs_parameter": { - "last_validated_date": "2025-01-21T18:23:33+00:00" + "last_validated_date": "2026-02-21T00:30:21+00:00", + "durations_in_seconds": { + "setup": 0.52, + "call": 0.87, + "teardown": 0.98, + "total": 2.37 + } }, "tests/aws/services/s3/test_s3.py::TestS3PresignedUrl::test_s3_put_presigned_url_with_different_headers[s3]": { - "last_validated_date": "2025-01-21T18:23:27+00:00" + "last_validated_date": "2026-02-21T00:30:15+00:00", + "durations_in_seconds": { + "setup": 0.52, + "call": 2.98, + "teardown": 0.95, + "total": 4.45 + } }, "tests/aws/services/s3/test_s3.py::TestS3PresignedUrl::test_s3_put_presigned_url_with_different_headers[s3v4]": { - "last_validated_date": "2025-01-21T18:23:31+00:00" + "last_validated_date": "2026-02-21T00:30:18+00:00", + "durations_in_seconds": { + "setup": 0.54, + "call": 2.02, + "teardown": 0.96, + "total": 3.52 + } }, "tests/aws/services/s3/test_s3.py::TestS3PutObjectChecksum::test_put_object_checksum[CRC32C]": { - "last_validated_date": "2025-03-17T18:27:58+00:00" + "last_validated_date": "2026-02-21T00:37:28+00:00", + "durations_in_seconds": { + "setup": 0.54, + "call": 13.51, + "teardown": 0.99, + "total": 15.04 + } }, "tests/aws/services/s3/test_s3.py::TestS3PutObjectChecksum::test_put_object_checksum[CRC32]": { - "last_validated_date": "2025-03-17T18:27:45+00:00" + "last_validated_date": "2026-02-21T00:37:13+00:00", + "durations_in_seconds": { + "setup": 0.53, + "call": 14.48, + "teardown": 0.98, + "total": 15.99 + } }, "tests/aws/services/s3/test_s3.py::TestS3PutObjectChecksum::test_put_object_checksum[CRC64NVME]": { - "last_validated_date": "2025-03-17T18:28:43+00:00" + "last_validated_date": "2026-02-21T00:38:05+00:00", + "durations_in_seconds": { + "setup": 0.52, + "call": 13.04, + "teardown": 1.04, + "total": 14.6 + } }, "tests/aws/services/s3/test_s3.py::TestS3PutObjectChecksum::test_put_object_checksum[SHA1]": { - "last_validated_date": "2025-03-17T18:28:09+00:00" + "last_validated_date": "2026-02-21T00:37:35+00:00", + "durations_in_seconds": { + "setup": 0.52, + "call": 5.99, + "teardown": 0.97, + "total": 7.48 + } }, "tests/aws/services/s3/test_s3.py::TestS3PutObjectChecksum::test_put_object_checksum[SHA256]": { - "last_validated_date": "2025-03-17T18:28:24+00:00" + "last_validated_date": "2026-02-21T00:37:50+00:00", + "durations_in_seconds": { + "setup": 0.51, + "call": 13.58, + "teardown": 0.76, + "total": 14.85 + } }, "tests/aws/services/s3/test_s3.py::TestS3PutObjectChecksum::test_s3_checksum_no_algorithm": { - "last_validated_date": "2025-03-17T18:29:05+00:00" + "last_validated_date": "2026-02-21T00:38:28+00:00", + "durations_in_seconds": { + "setup": 0.52, + "call": 1.01, + "teardown": 0.98, + "total": 2.51 + } }, "tests/aws/services/s3/test_s3.py::TestS3PutObjectChecksum::test_s3_checksum_no_automatic_sdk_calculation": { - "last_validated_date": "2025-03-17T22:25:43+00:00" + "last_validated_date": "2026-02-21T00:38:32+00:00", + "durations_in_seconds": { + "setup": 0.53, + "call": 2.05, + "teardown": 1.03, + "total": 3.61 + } }, "tests/aws/services/s3/test_s3.py::TestS3PutObjectChecksum::test_s3_checksum_with_content_encoding": { - "last_validated_date": "2025-03-17T18:29:02+00:00" + "last_validated_date": "2026-02-21T00:38:26+00:00", + "durations_in_seconds": { + "setup": 0.54, + "call": 0.59, + "teardown": 1.11, + "total": 2.24 + } }, "tests/aws/services/s3/test_s3.py::TestS3PutObjectChecksum::test_s3_get_object_checksum[CRC32C]": { - "last_validated_date": "2025-03-17T18:28:48+00:00" + "last_validated_date": "2026-02-21T00:38:11+00:00", + "durations_in_seconds": { + "setup": 0.53, + "call": 1.46, + "teardown": 0.98, + "total": 2.97 + } }, "tests/aws/services/s3/test_s3.py::TestS3PutObjectChecksum::test_s3_get_object_checksum[CRC32]": { - "last_validated_date": "2025-03-17T18:28:46+00:00" + "last_validated_date": "2026-02-21T00:38:08+00:00", + "durations_in_seconds": { + "setup": 0.9, + "call": 1.42, + "teardown": 0.98, + "total": 3.3 + } }, "tests/aws/services/s3/test_s3.py::TestS3PutObjectChecksum::test_s3_get_object_checksum[CRC64NVME]": { - "last_validated_date": "2025-03-17T18:28:57+00:00" + "last_validated_date": "2026-02-21T00:38:20+00:00", + "durations_in_seconds": { + "setup": 0.52, + "call": 1.4, + "teardown": 1.3, + "total": 3.22 + } }, "tests/aws/services/s3/test_s3.py::TestS3PutObjectChecksum::test_s3_get_object_checksum[None]": { - "last_validated_date": "2025-03-17T18:29:00+00:00" + "last_validated_date": "2026-02-21T00:38:23+00:00", + "durations_in_seconds": { + "setup": 0.55, + "call": 1.5, + "teardown": 0.97, + "total": 3.02 + } }, "tests/aws/services/s3/test_s3.py::TestS3PutObjectChecksum::test_s3_get_object_checksum[SHA1]": { - "last_validated_date": "2025-03-17T18:28:51+00:00" + "last_validated_date": "2026-02-21T00:38:14+00:00", + "durations_in_seconds": { + "setup": 0.54, + "call": 1.42, + "teardown": 0.98, + "total": 2.94 + } }, "tests/aws/services/s3/test_s3.py::TestS3PutObjectChecksum::test_s3_get_object_checksum[SHA256]": { - "last_validated_date": "2025-03-17T18:28:54+00:00" + "last_validated_date": "2026-02-21T00:38:17+00:00", + "durations_in_seconds": { + "setup": 0.53, + "call": 1.48, + "teardown": 0.97, + "total": 2.98 + } }, "tests/aws/services/s3/test_s3.py::TestS3SSECEncryption::test_copy_object_with_sse_c": { - "last_validated_date": "2025-01-21T18:16:26+00:00" + "last_validated_date": "2026-02-21T00:36:42+00:00", + "durations_in_seconds": { + "setup": 0.52, + "call": 1.94, + "teardown": 1.22, + "total": 3.68 + } }, "tests/aws/services/s3/test_s3.py::TestS3SSECEncryption::test_multipart_upload_sse_c": { - "last_validated_date": "2025-03-17T22:55:35+00:00" + "last_validated_date": "2026-02-21T00:36:48+00:00", + "durations_in_seconds": { + "setup": 0.51, + "call": 4.37, + "teardown": 0.97, + "total": 5.85 + } }, "tests/aws/services/s3/test_s3.py::TestS3SSECEncryption::test_multipart_upload_sse_c_validation": { - "last_validated_date": "2025-01-21T18:16:43+00:00" + "last_validated_date": "2026-02-21T00:36:51+00:00", + "durations_in_seconds": { + "setup": 0.51, + "call": 1.2, + "teardown": 0.85, + "total": 2.56 + } }, "tests/aws/services/s3/test_s3.py::TestS3SSECEncryption::test_object_retrieval_sse_c": { - "last_validated_date": "2025-01-22T14:21:48+00:00" + "last_validated_date": "2026-02-21T00:36:39+00:00", + "durations_in_seconds": { + "setup": 0.53, + "call": 2.92, + "teardown": 1.2, + "total": 4.65 + } }, "tests/aws/services/s3/test_s3.py::TestS3SSECEncryption::test_put_object_default_checksum_with_sse_c": { - "last_validated_date": "2025-03-17T23:22:52+00:00" + "last_validated_date": "2026-02-21T00:36:57+00:00", + "durations_in_seconds": { + "setup": 0.53, + "call": 1.0, + "teardown": 0.99, + "total": 2.52 + } }, "tests/aws/services/s3/test_s3.py::TestS3SSECEncryption::test_put_object_lifecycle_with_sse_c": { - "last_validated_date": "2025-01-21T18:16:15+00:00" + "last_validated_date": "2026-02-21T00:36:30+00:00", + "durations_in_seconds": { + "setup": 0.51, + "call": 1.02, + "teardown": 0.61, + "total": 2.14 + } }, "tests/aws/services/s3/test_s3.py::TestS3SSECEncryption::test_put_object_validation_sse_c": { - "last_validated_date": "2025-01-21T18:16:18+00:00" + "last_validated_date": "2026-02-21T00:36:34+00:00", + "durations_in_seconds": { + "setup": 0.53, + "call": 2.14, + "teardown": 0.86, + "total": 3.53 + } }, "tests/aws/services/s3/test_s3.py::TestS3SSECEncryption::test_sse_c_with_versioning": { - "last_validated_date": "2025-01-21T18:16:46+00:00" + "last_validated_date": "2026-02-21T00:36:54+00:00", + "durations_in_seconds": { + "setup": 0.52, + "call": 1.64, + "teardown": 1.38, + "total": 3.54 + } }, "tests/aws/services/s3/test_s3.py::TestS3StaticWebsiteHosting::test_crud_website_configuration": { - "last_validated_date": "2023-08-25T22:29:24+00:00" + "last_validated_date": "2026-02-21T00:33:08+00:00", + "durations_in_seconds": { + "setup": 0.52, + "call": 0.71, + "teardown": 0.59, + "total": 1.82 + } + }, + "tests/aws/services/s3/test_s3.py::TestS3StaticWebsiteHosting::test_object_website_redirect_location": { + "last_validated_date": "2026-02-21T00:32:47+00:00", + "durations_in_seconds": { + "setup": 0.94, + "call": 1.42, + "teardown": 1.05, + "total": 3.41 + } + }, + "tests/aws/services/s3/test_s3.py::TestS3StaticWebsiteHosting::test_routing_rules_conditions": { + "last_validated_date": "2026-02-21T00:32:52+00:00", + "durations_in_seconds": { + "setup": 0.88, + "call": 2.78, + "teardown": 0.96, + "total": 4.62 + } + }, + "tests/aws/services/s3/test_s3.py::TestS3StaticWebsiteHosting::test_routing_rules_empty_replace_prefix": { + "last_validated_date": "2026-02-21T00:32:59+00:00", + "durations_in_seconds": { + "setup": 0.89, + "call": 2.42, + "teardown": 0.97, + "total": 4.28 + } + }, + "tests/aws/services/s3/test_s3.py::TestS3StaticWebsiteHosting::test_routing_rules_order": { + "last_validated_date": "2026-02-21T00:33:03+00:00", + "durations_in_seconds": { + "setup": 0.88, + "call": 1.75, + "teardown": 0.96, + "total": 3.59 + } + }, + "tests/aws/services/s3/test_s3.py::TestS3StaticWebsiteHosting::test_routing_rules_redirects": { + "last_validated_date": "2026-02-21T00:32:55+00:00", + "durations_in_seconds": { + "setup": 0.88, + "call": 1.18, + "teardown": 0.63, + "total": 2.69 + } + }, + "tests/aws/services/s3/test_s3.py::TestS3StaticWebsiteHosting::test_s3_static_website_hosting": { + "last_validated_date": "2026-02-21T00:32:31+00:00", + "durations_in_seconds": { + "setup": 0.96, + "call": 3.35, + "teardown": 1.01, + "total": 5.32 + } + }, + "tests/aws/services/s3/test_s3.py::TestS3StaticWebsiteHosting::test_s3_static_website_index": { + "last_validated_date": "2026-02-21T00:32:26+00:00", + "durations_in_seconds": { + "setup": 0.95, + "call": 0.8, + "teardown": 0.95, + "total": 2.7 + } }, "tests/aws/services/s3/test_s3.py::TestS3StaticWebsiteHosting::test_validate_website_configuration": { - "last_validated_date": "2023-08-25T22:30:03+00:00" + "last_validated_date": "2026-02-21T00:33:06+00:00", + "durations_in_seconds": { + "setup": 0.52, + "call": 2.38, + "teardown": 0.83, + "total": 3.73 + } }, "tests/aws/services/s3/test_s3.py::TestS3StaticWebsiteHosting::test_website_hosting_404": { - "last_validated_date": "2023-08-25T22:30:33+00:00" + "last_validated_date": "2026-02-21T00:32:44+00:00", + "durations_in_seconds": { + "setup": 0.94, + "call": 1.39, + "teardown": 1.04, + "total": 3.37 + } }, "tests/aws/services/s3/test_s3.py::TestS3StaticWebsiteHosting::test_website_hosting_http_methods": { - "last_validated_date": "2023-08-25T22:30:55+00:00" + "last_validated_date": "2026-02-21T00:32:37+00:00", + "durations_in_seconds": { + "setup": 0.95, + "call": 1.34, + "teardown": 1.06, + "total": 3.35 + } }, "tests/aws/services/s3/test_s3.py::TestS3StaticWebsiteHosting::test_website_hosting_index_lookup": { - "last_validated_date": "2023-08-25T22:31:15+00:00" + "last_validated_date": "2026-02-21T00:32:41+00:00", + "durations_in_seconds": { + "setup": 0.93, + "call": 1.88, + "teardown": 0.98, + "total": 3.79 + } }, "tests/aws/services/s3/test_s3.py::TestS3StaticWebsiteHosting::test_website_hosting_no_such_website": { - "last_validated_date": "2023-08-25T22:31:30+00:00" + "last_validated_date": "2026-02-21T00:32:33+00:00", + "durations_in_seconds": { + "setup": 0.94, + "call": 0.8, + "teardown": 0.61, + "total": 2.35 + } + }, + "tests/aws/services/s3/test_s3.py::TestS3StaticWebsiteHosting::test_website_hosting_redirect_all": { + "last_validated_date": "2026-02-21T00:33:14+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 4.07, + "teardown": 1.54, + "total": 5.61 + } } } diff --git a/tests/aws/services/s3/test_s3_api.py b/tests/aws/services/s3/test_s3_api.py index cfab12711471b..0d33b6b02eea3 100644 --- a/tests/aws/services/s3/test_s3_api.py +++ b/tests/aws/services/s3/test_s3_api.py @@ -9,7 +9,9 @@ from botocore.config import Config from botocore.exceptions import ClientError from localstack_snapshot.snapshots.transformer import SortingTransformer +from moto.wafv2.models import US_EAST_1_REGION +from localstack.aws.api.s3 import StorageClass from localstack.testing.pytest import markers from localstack.utils.strings import long_uid, short_uid from tests.aws.services.s3.conftest import TEST_S3_IMAGE @@ -492,8 +494,6 @@ def test_get_object_range(self, aws_client, s3_bucket, snapshot): class TestS3Multipart: - # TODO: write a validated test for UploadPartCopy preconditions - @markers.aws.validated @markers.snapshot.skip_snapshot_verify(paths=["$..PartNumberMarker"]) # TODO: investigate this def test_upload_part_copy_range(self, aws_client, s3_bucket, snapshot): @@ -812,7 +812,8 @@ def test_upload_part_copy_with_copy_source_if_modified_since_in_future_success( self, aws_client, s3_bucket, snapshot ): """ - Providing CopyIfModifiedSince with a datetime which is in the future will always pass (even though it evaluates to false). This is AWS defined behaviour. + Providing CopyIfModifiedSince with a datetime which is in the future will always pass (even though it + evaluates to false). This is AWS defined behaviour. """ snapshot.add_transformer( [ @@ -943,7 +944,8 @@ def test_upload_part_copy_with_copy_source_if_unmodified_since_match_failed( self, aws_client, s3_bucket, snapshot ): """ - Providing CopySourceIfUnmodifiedSince with a datetime where the object has been modified since this datetime should fail. + Providing CopySourceIfUnmodifiedSince with a datetime where the object has been modified since + this datetime should fail. """ snapshot.add_transformer( [ @@ -989,7 +991,8 @@ def test_upload_part_copy_with_copy_source_if_match_and_if_unmodified_since_matc self, aws_client, s3_bucket, snapshot ): """ - If CopySourceIfMatch is provided with CopySourceIfUnmodifiedSince it should proceed even if the latter evaluates to false. + If CopySourceIfMatch is provided with CopySourceIfUnmodifiedSince it should proceed even if the latter + evaluates to false. See documentation: https://docs.aws.amazon.com/AmazonS3/latest/API/API_UploadPartCopy.html """ snapshot.add_transformer( @@ -1104,7 +1107,8 @@ def test_upload_part_copy_with_if_modified_since_failed(self, aws_client, s3_buc ) upload_id = create_multipart_upload["UploadId"] - # Don't do this, but required for behaviour with CopySourceIfModifiedSince which will pass if a future time is provided. + # Don't do this, but required for behaviour with CopySourceIfModifiedSince which will pass + # if a future time is provided. sleep(1) with pytest.raises(ClientError) as error: @@ -1370,6 +1374,7 @@ def test_s3_bucket_encryption_sse_kms(self, s3_bucket, kms_key, aws_client, snap ] ) def test_s3_bucket_encryption_sse_kms_aws_managed_key(self, s3_bucket, aws_client, snapshot): + snapshot.add_transformer(snapshot.transform.key_value("CurrentKeyMaterialId")) # if you don't provide a KMS key, AWS will use an AWS managed one. put_bucket_enc = aws_client.s3.put_bucket_encryption( Bucket=s3_bucket, @@ -1450,6 +1455,130 @@ def test_bucket_tagging_crud(self, s3_bucket, aws_client, snapshot): aws_client.s3.get_bucket_tagging(Bucket=s3_bucket) e.match("NoSuchTagSet") + @markers.aws.validated + def test_create_bucket_with_tags( + self, s3_create_bucket_with_client, region_name, aws_client, snapshot + ): + snapshot.add_transformers_list( + [ + snapshot.transform.key_value("BucketArn"), + snapshot.transform.key_value("Location"), + ] + ) + additional_config = {} + if region_name != US_EAST_1_REGION: + additional_config["LocationConstraint"] = region_name + + bucket_name = f"test-bucket-tag-{short_uid()}" + create_bucket = s3_create_bucket_with_client( + aws_client.s3, + Bucket=bucket_name, + CreateBucketConfiguration={ + "Tags": [{"Key": "tag1", "Value": "value1"}], + **additional_config, + }, + ) + snapshot.match("create-bucket-with-tags", create_bucket) + + get_bucket_tags = aws_client.s3.get_bucket_tagging(Bucket=bucket_name) + snapshot.match("get-bucket-tags", get_bucket_tags) + + @markers.aws.validated + def test_create_bucket_with_empty_tags( + self, s3_create_bucket_with_client, aws_client_factory, snapshot + ): + snapshot.add_transformers_list( + [ + snapshot.transform.key_value("BucketName"), + snapshot.transform.key_value("Location"), + snapshot.transform.key_value("BucketArn"), + ] + ) + + s3_client = aws_client_factory( + region_name=US_EAST_1_REGION, config=Config(parameter_validation=False) + ).s3 + + bucket_name = f"test-bucket-tag-{short_uid()}" + create_bucket = s3_create_bucket_with_client( + s3_client, + Bucket=bucket_name, + CreateBucketConfiguration={"Tags": []}, + ) + snapshot.match("create-bucket-with-empty-tags", create_bucket) + + with pytest.raises(ClientError) as e: + s3_client.get_bucket_tagging(Bucket=bucket_name) + snapshot.match("get-bucket-tags", e.value.response) + + create_bucket_none = s3_create_bucket_with_client( + s3_client, + Bucket=bucket_name, + CreateBucketConfiguration={"Tags": None}, + ) + snapshot.match("create-bucket-with-none-tags", create_bucket_none) + + @markers.aws.validated + def test_create_bucket_with_tags_us_east_1_idempotency( + self, s3_create_bucket_with_client, aws_client_factory, snapshot + ): + snapshot.add_transformers_list( + [ + snapshot.transform.key_value("BucketName"), + snapshot.transform.key_value("Location"), + snapshot.transform.key_value("BucketArn"), + ] + ) + us_east_1_s3_client = aws_client_factory( + region_name=US_EAST_1_REGION, config=Config(parameter_validation=False) + ).s3 + + bucket_name = f"test-bucket-tag-{short_uid()}" + create_bucket = s3_create_bucket_with_client( + us_east_1_s3_client, + Bucket=bucket_name, + CreateBucketConfiguration={"Tags": [{"Key": "tag1", "Value": "value1"}]}, + ) + snapshot.match("create-bucket-with-tags", create_bucket) + + get_bucket_tags = us_east_1_s3_client.get_bucket_tagging(Bucket=bucket_name) + snapshot.match("get-bucket-tags", get_bucket_tags) + + with pytest.raises(ClientError) as e: + s3_create_bucket_with_client( + us_east_1_s3_client, + Bucket=bucket_name, + CreateBucketConfiguration={"Tags": [{"Key": "tag2", "Value": "value2"}]}, + ) + snapshot.match("create-bucket-different-tags", e.value.response) + + create_bucket = s3_create_bucket_with_client( + us_east_1_s3_client, + Bucket=bucket_name, + ) + snapshot.match("create-bucket-with-no-tags", create_bucket) + + get_bucket_tags = us_east_1_s3_client.get_bucket_tagging(Bucket=bucket_name) + snapshot.match("get-bucket-tags-after-re-create", get_bucket_tags) + + with pytest.raises(ClientError) as e: + s3_create_bucket_with_client( + us_east_1_s3_client, + Bucket=bucket_name, + CreateBucketConfiguration={"Tags": [{"Key": "tag1", "Value": "value1"}]}, + ) + snapshot.match("create-bucket-with-same-tags", e.value.response) + + create_bucket_empty_tags = s3_create_bucket_with_client( + us_east_1_s3_client, + Bucket=bucket_name, + CreateBucketConfiguration={"Tags": []}, + ) + snapshot.match("create-bucket-with-empty-tags", create_bucket_empty_tags) + + get_bucket_tags = us_east_1_s3_client.get_bucket_tagging(Bucket=bucket_name) + snapshot.match("get-bucket-tags-after-create-empty", get_bucket_tags) + @markers.aws.validated def test_bucket_tagging_exc(self, s3_bucket, aws_client, snapshot): snapshot.add_transformer(snapshot.transform.key_value("BucketName")) @@ -1466,6 +1595,82 @@ def test_bucket_tagging_exc(self, s3_bucket, aws_client, snapshot): aws_client.s3.put_bucket_tagging(Bucket=fake_bucket, Tagging={"TagSet": []}) snapshot.match("put-no-bucket-tags", e.value.response) + @markers.aws.validated + @markers.snapshot.skip_snapshot_verify( + paths=[ + # FIXME: regenerate snapshot when AWS is not raising a 500 error anymore + "$.tags-key-aws-duplicated-key.*" + ] + ) + def test_create_bucket_with_tags_exc( + self, s3_create_bucket_with_client, aws_client_factory, snapshot + ): + snapshot.add_transformers_list( + [ + snapshot.transform.key_value("BucketName"), + snapshot.transform.key_value("Location"), + ] + ) + s3_client = aws_client_factory( + region_name=US_EAST_1_REGION, config=Config(parameter_validation=False) + ).s3 + + bucket_name = f"test-bucket-tag-{short_uid()}" + + with pytest.raises(ClientError) as e: + s3_create_bucket_with_client( + s3_client, + Bucket=bucket_name, + CreateBucketConfiguration={"Tags": [{"Key": None, "Value": "value1"}]}, + ) + snapshot.match("tags-key-none", e.value.response) + + with pytest.raises(ClientError) as e: + s3_create_bucket_with_client( + s3_client, + Bucket=bucket_name, + CreateBucketConfiguration={"Tags": [{"Key": "key1", "Value": None}]}, + ) + snapshot.match("tags-value-none", e.value.response) + + with pytest.raises(ClientError) as e: + s3_create_bucket_with_client( + s3_client, + Bucket=bucket_name, + CreateBucketConfiguration={"Tags": [{"Key": "aws:test", "Value": "value1"}]}, + ) + snapshot.match("tags-key-aws-prefix", e.value.response) + + # FIXME: re-generate the snapshot later, AWS is returning a 500 error as of now (27 Nov 2025) + with pytest.raises(ClientError) as e: + s3_create_bucket_with_client( + s3_client, + Bucket=bucket_name, + CreateBucketConfiguration={ + "Tags": [ + {"Key": "key1", "Value": "value1"}, + {"Key": "key1", "Value": "value1"}, + ] + }, + ) + snapshot.match("tags-key-aws-duplicated-key", e.value.response) + + with pytest.raises(ClientError) as e: + s3_create_bucket_with_client( + s3_client, + Bucket=bucket_name, + CreateBucketConfiguration={"Tags": [{"Key": "test", "Value": "value1,value2"}]}, + ) + snapshot.match("tags-key-aws-bad-value", e.value.response) + + with pytest.raises(ClientError) as e: + s3_create_bucket_with_client( + s3_client, + Bucket=bucket_name, + CreateBucketConfiguration={"Tags": [{"Key": "test,test2", "Value": "value1"}]}, + ) + snapshot.match("tags-key-aws-bad-key", e.value.response) + @markers.aws.validated def test_put_bucket_tagging_none_value( self, s3_bucket, aws_client_factory, snapshot, region_name @@ -1742,6 +1947,44 @@ def test_put_object_with_tags(self, s3_bucket, aws_client, snapshot): get_object_tags = aws_client.s3.get_object_tagging(Bucket=s3_bucket, Key=object_key) snapshot.match("get-object-tags-wrong-format-qs-2", get_object_tags) + @markers.aws.validated + def test_head_object_with_tags(self, s3_bucket, aws_client, snapshot): + object_key = "test-put-object-tagging" + # tagging must be a URL encoded string directly + tag_set = "tag1=tag1&tag2=tag2&tag=" + put_object = aws_client.s3.put_object( + Bucket=s3_bucket, Key=object_key, Body="test-tagging", Tagging=tag_set + ) + snapshot.match("put-object", put_object) + + head_object = aws_client.s3.head_object(Bucket=s3_bucket, Key=object_key) + snapshot.match("head-obj-after-create", head_object) + + tag_set_2 = {"TagSet": [{"Key": "tag3", "Value": "tag3"}]} + put_bucket_tags = aws_client.s3.put_object_tagging( + Bucket=s3_bucket, Key=object_key, Tagging=tag_set_2 + ) + snapshot.match("put-object-tags", put_bucket_tags) + + head_object = aws_client.s3.head_object(Bucket=s3_bucket, Key=object_key) + snapshot.match("head-obj-after-tagging", head_object) + + tag_set_2 = { + "TagSet": [ + {"Key": "tag3", "Value": "tag3"}, + {"Key": "tag4", "Value": "tag4"}, + {"Key": "tag5", "Value": "tag5"}, + ] + } + aws_client.s3.put_object_tagging(Bucket=s3_bucket, Key=object_key, Tagging=tag_set_2) + head_object = aws_client.s3.head_object(Bucket=s3_bucket, Key=object_key) + snapshot.match("head-obj-after-overwrite", head_object) + + aws_client.s3.put_object_tagging(Bucket=s3_bucket, Key=object_key, Tagging={"TagSet": []}) + + head_object = aws_client.s3.head_object(Bucket=s3_bucket, Key=object_key) + snapshot.match("head-obj-after-removal", head_object) + @markers.aws.validated def test_object_tags_delete_or_overwrite_object(self, s3_bucket, aws_client, snapshot): # verify that tags aren't kept after object deletion @@ -1769,12 +2012,17 @@ def test_object_tags_delete_or_overwrite_object(self, s3_bucket, aws_client, sna snapshot.match("get-object-after-recreation", get_bucket_tags) @markers.aws.validated - def test_tagging_validation(self, s3_bucket, aws_client, snapshot): + def test_tagging_validation( + self, s3_bucket, aws_client, aws_client_factory, region_name, snapshot + ): object_key = "tagging-validation" aws_client.s3.put_object(Bucket=s3_bucket, Key=object_key, Body=b"") + s3_client = aws_client_factory( + region_name=region_name, config=Config(parameter_validation=False) + ).s3 with pytest.raises(ClientError) as e: - aws_client.s3.put_bucket_tagging( + s3_client.put_bucket_tagging( Bucket=s3_bucket, Tagging={ "TagSet": [ @@ -1786,7 +2034,7 @@ def test_tagging_validation(self, s3_bucket, aws_client, snapshot): snapshot.match("put-bucket-tags-duplicate-keys", e.value.response) with pytest.raises(ClientError) as e: - aws_client.s3.put_bucket_tagging( + s3_client.put_bucket_tagging( Bucket=s3_bucket, Tagging={ "TagSet": [ @@ -1797,7 +2045,18 @@ def test_tagging_validation(self, s3_bucket, aws_client, snapshot): snapshot.match("put-bucket-tags-invalid-key", e.value.response) with pytest.raises(ClientError) as e: - aws_client.s3.put_bucket_tagging( + s3_client.put_bucket_tagging( + Bucket=s3_bucket, + Tagging={ + "TagSet": [ + {"Key": None, "Value": "Val1"}, + ] + }, + ) + snapshot.match("put-bucket-tags-none-key", e.value.response) + + with pytest.raises(ClientError) as e: + s3_client.put_bucket_tagging( Bucket=s3_bucket, Tagging={ "TagSet": [ @@ -1808,7 +2067,18 @@ def test_tagging_validation(self, s3_bucket, aws_client, snapshot): snapshot.match("put-bucket-tags-invalid-value", e.value.response) with pytest.raises(ClientError) as e: - aws_client.s3.put_bucket_tagging( + s3_client.put_bucket_tagging( + Bucket=s3_bucket, + Tagging={ + "TagSet": [ + {"Key": "key1", "Value": None}, + ] + }, + ) + snapshot.match("put-bucket-tags-none-value", e.value.response) + + with pytest.raises(ClientError) as e: + s3_client.put_bucket_tagging( Bucket=s3_bucket, Tagging={ "TagSet": [ @@ -1819,7 +2089,7 @@ def test_tagging_validation(self, s3_bucket, aws_client, snapshot): snapshot.match("put-bucket-tags-aws-prefixed", e.value.response) with pytest.raises(ClientError) as e: - aws_client.s3.put_object_tagging( + s3_client.put_object_tagging( Bucket=s3_bucket, Key=object_key, Tagging={ @@ -1833,7 +2103,7 @@ def test_tagging_validation(self, s3_bucket, aws_client, snapshot): snapshot.match("put-object-tags-duplicate-keys", e.value.response) with pytest.raises(ClientError) as e: - aws_client.s3.put_object_tagging( + s3_client.put_object_tagging( Bucket=s3_bucket, Key=object_key, Tagging={"TagSet": [{"Key": "Key1,Key2", "Value": "Val1"}]}, @@ -1842,13 +2112,29 @@ def test_tagging_validation(self, s3_bucket, aws_client, snapshot): snapshot.match("put-object-tags-invalid-field", e.value.response) with pytest.raises(ClientError) as e: - aws_client.s3.put_object_tagging( + s3_client.put_object_tagging( Bucket=s3_bucket, Key=object_key, Tagging={"TagSet": [{"Key": "aws:prefixed", "Value": "Val1"}]}, ) snapshot.match("put-object-tags-aws-prefixed", e.value.response) + with pytest.raises(ClientError) as e: + s3_client.put_object_tagging( + Bucket=s3_bucket, + Key=object_key, + Tagging={"TagSet": [{"Key": None, "Value": "Val1"}]}, + ) + snapshot.match("put-object-tags-none-key", e.value.response) + + with pytest.raises(ClientError) as e: + s3_client.put_object_tagging( + Bucket=s3_bucket, + Key=object_key, + Tagging={"TagSet": [{"Key": "key1", "Value": None}]}, + ) + snapshot.match("put-object-tags-none-value", e.value.response) + class TestS3ObjectLock: @markers.aws.validated @@ -1906,13 +2192,13 @@ def test_put_object_lock_configuration_on_existing_bucket( @markers.aws.validated def test_get_put_object_lock_configuration(self, s3_create_bucket, aws_client, snapshot): - s3_bucket = s3_create_bucket(ObjectLockEnabledForBucket=True) + bucket_name = s3_create_bucket(ObjectLockEnabledForBucket=True) - get_lock_config = aws_client.s3.get_object_lock_configuration(Bucket=s3_bucket) + get_lock_config = aws_client.s3.get_object_lock_configuration(Bucket=bucket_name) snapshot.match("get-lock-config-start", get_lock_config) put_lock_config = aws_client.s3.put_object_lock_configuration( - Bucket=s3_bucket, + Bucket=bucket_name, ObjectLockConfiguration={ "ObjectLockEnabled": "Enabled", "Rule": { @@ -1925,26 +2211,26 @@ def test_get_put_object_lock_configuration(self, s3_create_bucket, aws_client, s ) snapshot.match("put-lock-config", put_lock_config) - get_lock_config = aws_client.s3.get_object_lock_configuration(Bucket=s3_bucket) + get_lock_config = aws_client.s3.get_object_lock_configuration(Bucket=bucket_name) snapshot.match("get-lock-config", get_lock_config) put_lock_config_enabled = aws_client.s3.put_object_lock_configuration( - Bucket=s3_bucket, + Bucket=bucket_name, ObjectLockConfiguration={ "ObjectLockEnabled": "Enabled", }, ) snapshot.match("put-lock-config-enabled", put_lock_config_enabled) - get_lock_config = aws_client.s3.get_object_lock_configuration(Bucket=s3_bucket) + get_lock_config = aws_client.s3.get_object_lock_configuration(Bucket=bucket_name) snapshot.match("get-lock-config-only-enabled", get_lock_config) @markers.aws.validated def test_put_object_lock_configuration_exc(self, s3_create_bucket, aws_client, snapshot): - s3_bucket = s3_create_bucket(ObjectLockEnabledForBucket=True) + bucket_name = s3_create_bucket(ObjectLockEnabledForBucket=True) with pytest.raises(ClientError) as e: aws_client.s3.put_object_lock_configuration( - Bucket=s3_bucket, + Bucket=bucket_name, ObjectLockConfiguration={ "Rule": { "DefaultRetention": { @@ -1958,20 +2244,20 @@ def test_put_object_lock_configuration_exc(self, s3_create_bucket, aws_client, s with pytest.raises(ClientError) as e: aws_client.s3.put_object_lock_configuration( - Bucket=s3_bucket, ObjectLockConfiguration={} + Bucket=bucket_name, ObjectLockConfiguration={} ) snapshot.match("put-lock-config-empty", e.value.response) with pytest.raises(ClientError) as e: aws_client.s3.put_object_lock_configuration( - Bucket=s3_bucket, + Bucket=bucket_name, ObjectLockConfiguration={"ObjectLockEnabled": "Enabled", "Rule": {}}, ) snapshot.match("put-lock-config-empty-rule", e.value.response) with pytest.raises(ClientError) as e: aws_client.s3.put_object_lock_configuration( - Bucket=s3_bucket, + Bucket=bucket_name, ObjectLockConfiguration={ "ObjectLockEnabled": "Enabled", "Rule": {"DefaultRetention": {}}, @@ -1981,7 +2267,7 @@ def test_put_object_lock_configuration_exc(self, s3_create_bucket, aws_client, s with pytest.raises(ClientError) as e: aws_client.s3.put_object_lock_configuration( - Bucket=s3_bucket, + Bucket=bucket_name, ObjectLockConfiguration={ "ObjectLockEnabled": "Enabled", "Rule": { @@ -1995,7 +2281,7 @@ def test_put_object_lock_configuration_exc(self, s3_create_bucket, aws_client, s with pytest.raises(ClientError) as e: aws_client.s3.put_object_lock_configuration( - Bucket=s3_bucket, + Bucket=bucket_name, ObjectLockConfiguration={ "ObjectLockEnabled": "Enabled", "Rule": { @@ -2010,7 +2296,7 @@ def test_put_object_lock_configuration_exc(self, s3_create_bucket, aws_client, s with pytest.raises(ClientError) as e: aws_client.s3.put_object_lock_configuration( - Bucket=s3_bucket, + Bucket=bucket_name, ObjectLockConfiguration={ "ObjectLockEnabled": "Enabled", "Rule": { @@ -2104,8 +2390,8 @@ def test_crud_bucket_ownership_controls(self, s3_create_bucket, aws_client, snap delete_idempotent = aws_client.s3.delete_bucket_ownership_controls(Bucket=default_s3_bucket) snapshot.match("delete-ownership-after-delete", delete_idempotent) - s3_bucket = s3_create_bucket(ObjectOwnership="BucketOwnerPreferred") - get_ownership_at_creation = aws_client.s3.get_bucket_ownership_controls(Bucket=s3_bucket) + bucket_name = s3_create_bucket(ObjectOwnership="BucketOwnerPreferred") + get_ownership_at_creation = aws_client.s3.get_bucket_ownership_controls(Bucket=bucket_name) snapshot.match("get-ownership-at-creation", get_ownership_at_creation) @markers.aws.validated @@ -2758,6 +3044,294 @@ def test_multipart_if_match_etag(self, s3_bucket, aws_client, snapshot): ) snapshot.match("complete-multipart-if-match-overwrite-multipart", complete_multipart_1) + @markers.aws.validated + def test_copy_object_if_none_match(self, s3_bucket, aws_client, snapshot): + """Test CopyObject with If-None-Match header (destination conditional)""" + src_key = "source-object" + dest_key = "dest-object" + + # Create source object + aws_client.s3.put_object(Bucket=s3_bucket, Key=src_key, Body="source content") + + # Copy should succeed when destination doesn't exist + copy_result = aws_client.s3.copy_object( + Bucket=s3_bucket, + CopySource=f"{s3_bucket}/{src_key}", + Key=dest_key, + IfNoneMatch="*", + ) + snapshot.match("copy-obj", copy_result) + + # Copy should fail when destination already exists + with pytest.raises(ClientError) as e: + aws_client.s3.copy_object( + Bucket=s3_bucket, + CopySource=f"{s3_bucket}/{src_key}", + Key=dest_key, + IfNoneMatch="*", + ) + snapshot.match("copy-obj-if-none-match-fail", e.value.response) + + @markers.aws.validated + def test_copy_object_if_match(self, s3_bucket, aws_client, snapshot): + """Test CopyObject with If-Match header (destination conditional)""" + src_key = "source-object" + dest_key = "dest-object" + + # Create source object + aws_client.s3.put_object(Bucket=s3_bucket, Key=src_key, Body="source content") + + # Create initial destination object + put_result = aws_client.s3.put_object( + Bucket=s3_bucket, Key=dest_key, Body="initial content" + ) + dest_etag = put_result["ETag"] + + # Copy should succeed when destination ETag matches + copy_result = aws_client.s3.copy_object( + Bucket=s3_bucket, + CopySource=f"{s3_bucket}/{src_key}", + Key=dest_key, + IfMatch=dest_etag, + ) + snapshot.match("copy-obj-if-match", copy_result) + + # Copy should fail when destination ETag doesn't match (wrong ETag) + with pytest.raises(ClientError) as e: + aws_client.s3.copy_object( + Bucket=s3_bucket, + CopySource=f"{s3_bucket}/{src_key}", + Key=dest_key, + IfMatch='"wrong-etag"', + ) + snapshot.match("copy-obj-if-match-fail-wrong-etag", e.value.response) + + # Copy should fail when destination doesn't exist + with pytest.raises(ClientError) as e: + aws_client.s3.copy_object( + Bucket=s3_bucket, + CopySource=f"{s3_bucket}/{src_key}", + Key="non-existent-key", + IfMatch=dest_etag, + ) + snapshot.match("copy-obj-if-match-fail-no-object", e.value.response) + + @markers.aws.validated + @markers.snapshot.skip_snapshot_verify( + paths=[ + # TODO: AWS started added ChecksumType to CopyObjectResult + "$..CopyObjectResult.ChecksumType", + # TODO: AWS stopped returning DisplayName (finally) + "$..Owner.DisplayName", + ] + ) + def test_copy_object_if_none_match_versioned_bucket(self, s3_bucket, aws_client, snapshot): + """Test CopyObject with If-None-Match header in a versioned bucket. + + For buckets with versioning enabled, S3 checks for the presence of a current object version. + If the current object version is a delete marker, the copy should succeed with If-None-Match. + """ + aws_client.s3.put_bucket_versioning( + Bucket=s3_bucket, VersioningConfiguration={"Status": "Enabled"} + ) + + src_key = "source-object" + dest_key = "dest-object" + + # Create source object + aws_client.s3.put_object(Bucket=s3_bucket, Key=src_key, Body="source content") + + # Copy should succeed when destination doesn't exist + copy_result = aws_client.s3.copy_object( + Bucket=s3_bucket, + CopySource=f"{s3_bucket}/{src_key}", + Key=dest_key, + IfNoneMatch="*", + ) + snapshot.match("copy-obj", copy_result) + + # Copy should fail when destination already exists + with pytest.raises(ClientError) as e: + aws_client.s3.copy_object( + Bucket=s3_bucket, + CopySource=f"{s3_bucket}/{src_key}", + Key=dest_key, + IfNoneMatch="*", + ) + snapshot.match("copy-obj-if-none-match-fail", e.value.response) + + # Delete the destination object (creates a delete marker in versioned bucket) + del_obj = aws_client.s3.delete_object(Bucket=s3_bucket, Key=dest_key) + snapshot.match("del-obj", del_obj) + + # Copy should succeed when current version is a delete marker + copy_after_del = aws_client.s3.copy_object( + Bucket=s3_bucket, + CopySource=f"{s3_bucket}/{src_key}", + Key=dest_key, + IfNoneMatch="*", + ) + snapshot.match("copy-obj-after-del", copy_after_del) + + list_object_versions = aws_client.s3.list_object_versions(Bucket=s3_bucket) + snapshot.match("list-object-versions", list_object_versions) + + @markers.aws.validated + @markers.snapshot.skip_snapshot_verify( + paths=[ + # TODO: AWS started added ChecksumType to CopyObjectResult + "$..CopyObjectResult.ChecksumType", + # TODO: AWS stopped returning DisplayName (finally) + "$..Owner.DisplayName", + ] + ) + def test_copy_object_if_match_versioned_bucket(self, s3_bucket, aws_client, snapshot): + """Test CopyObject with If-Match header in a versioned bucket. + + For versioned buckets, If-Match checks against the current object version's ETag. + If the current version is a delete marker, the copy should fail. + """ + aws_client.s3.put_bucket_versioning( + Bucket=s3_bucket, VersioningConfiguration={"Status": "Enabled"} + ) + + src_key = "source-object" + dest_key = "dest-object" + + # Create source object + aws_client.s3.put_object(Bucket=s3_bucket, Key=src_key, Body="source content") + + # Create initial destination object + put_result = aws_client.s3.put_object( + Bucket=s3_bucket, Key=dest_key, Body="initial content" + ) + snapshot.match("put-obj", put_result) + dest_etag_1 = put_result["ETag"] + + # Copy should fail with wrong ETag + with pytest.raises(ClientError) as e: + aws_client.s3.copy_object( + Bucket=s3_bucket, + CopySource=f"{s3_bucket}/{src_key}", + Key=dest_key, + IfMatch='"wrong-etag"', + ) + snapshot.match("copy-obj-if-match-wrong-etag", e.value.response) + + # Delete the destination object (creates a delete marker) + del_obj = aws_client.s3.delete_object(Bucket=s3_bucket, Key=dest_key) + snapshot.match("del-obj", del_obj) + + # Copy should fail when current version is a delete marker (even with correct old ETag) + with pytest.raises(ClientError) as e: + aws_client.s3.copy_object( + Bucket=s3_bucket, + CopySource=f"{s3_bucket}/{src_key}", + Key=dest_key, + IfMatch=dest_etag_1, + ) + snapshot.match("copy-obj-after-del-exc", e.value.response) + + # Create a new destination object + put_result_2 = aws_client.s3.put_object( + Bucket=s3_bucket, Key=dest_key, Body="new content after delete" + ) + snapshot.match("put-obj-after-del", put_result_2) + dest_etag_2 = put_result_2["ETag"] + + # Copy should succeed with correct current ETag + copy_result = aws_client.s3.copy_object( + Bucket=s3_bucket, + CopySource=f"{s3_bucket}/{src_key}", + Key=dest_key, + IfMatch=dest_etag_2, + ) + snapshot.match("copy-obj-if-match", copy_result) + + list_object_versions = aws_client.s3.list_object_versions(Bucket=s3_bucket) + snapshot.match("list-object-versions", list_object_versions) + + @markers.aws.validated + def test_copy_object_precondition_write_validation(self, s3_bucket, aws_client, snapshot): + src_key = "source-object" + dest_key = "dest-object" + + # Create source object + put_obj = aws_client.s3.put_object(Bucket=s3_bucket, Key=src_key, Body="source content") + + # assert that IfNoneMatch only accept '*' + with pytest.raises(ClientError) as e: + aws_client.s3.copy_object( + Bucket=s3_bucket, + CopySource=f"{s3_bucket}/{src_key}", + Key=dest_key, + IfNoneMatch=put_obj["ETag"], + ) + snapshot.match("copy-obj-none-match-etag", e.value.response) + + with pytest.raises(ClientError) as e: + aws_client.s3.copy_object( + Bucket=s3_bucket, + CopySource=f"{s3_bucket}/{src_key}", + Key=dest_key, + IfMatch="*", + ) + snapshot.match("copy-obj-if-match-star", e.value.response) + + with pytest.raises(ClientError) as e: + aws_client.s3.copy_object( + Bucket=s3_bucket, + CopySource=f"{s3_bucket}/{src_key}", + Key=dest_key, + IfMatch="*", + IfNoneMatch=put_obj["ETag"], + ) + snapshot.match("copy-obj-both", e.value.response) + + @markers.aws.validated + def test_copy_object_if_none_match_in_place(self, s3_bucket, aws_client, snapshot): + """Test CopyObject with If-None-Match header (destination conditional)""" + src_key = "source-object" + + # Create source object + aws_client.s3.put_object(Bucket=s3_bucket, Key=src_key, Body="source content") + + # Copy should fail when destination already exists (in place) + with pytest.raises(ClientError) as e: + aws_client.s3.copy_object( + Bucket=s3_bucket, + CopySource=f"{s3_bucket}/{src_key}", + Key=src_key, + IfNoneMatch="*", + StorageClass=StorageClass.STANDARD, + ) + snapshot.match("copy-obj-if-none-match-fail", e.value.response) + + @markers.aws.validated + @markers.snapshot.skip_snapshot_verify( + paths=[ + # TODO: AWS started added ChecksumType to CopyObjectResult + "$..CopyObjectResult.ChecksumType", + ] + ) + def test_copy_object_if_match_in_place(self, s3_bucket, aws_client, snapshot): + """Test CopyObject with If-None-Match header (destination conditional)""" + src_key = "source-object" + + # Create source object + put_obj = aws_client.s3.put_object(Bucket=s3_bucket, Key=src_key, Body="source content") + + # Copy should fail when destination already exists (in place) + # with pytest.raises(ClientError) as e: + copy_obj = aws_client.s3.copy_object( + Bucket=s3_bucket, + CopySource=f"{s3_bucket}/{src_key}", + Key=src_key, + IfMatch=put_obj["ETag"], + StorageClass=StorageClass.STANDARD, + ) + snapshot.match("copy-obj-if-match-in-place", copy_obj) + class TestS3MetricsConfiguration: @markers.aws.validated @@ -2920,6 +3494,9 @@ def test_delete_metrics_configuration_twice(self, s3_bucket, aws_client, snapsho snapshot.match("delete_bucket_metrics_configuration_2", delete_err.value.response) +@pytest.mark.skip( + reason="Behavior is not in line anymore with AWS: implement IfMatch in DeleteObject" +) class TestS3DeletePrecondition: @markers.aws.validated def test_delete_object_if_match_non_express(self, s3_bucket, aws_client, snapshot): diff --git a/tests/aws/services/s3/test_s3_api.snapshot.json b/tests/aws/services/s3/test_s3_api.snapshot.json index 710c164da10ad..b6326b0383f03 100644 --- a/tests/aws/services/s3/test_s3_api.snapshot.json +++ b/tests/aws/services/s3/test_s3_api.snapshot.json @@ -1,6 +1,6 @@ { "tests/aws/services/s3/test_s3_api.py::TestS3ObjectCRUD::test_delete_object_versioned": { - "recorded-date": "21-01-2025, 18:09:37", + "recorded-date": "21-02-2026, 01:01:45", "recorded-content": { "put-object": { "ChecksumCRC32": "1jy6qw==", @@ -76,7 +76,6 @@ "Key": "test-delete", "LastModified": "datetime", "Owner": { - "DisplayName": "", "ID": "" }, "VersionId": "" @@ -86,7 +85,6 @@ "Key": "test-delete", "LastModified": "datetime", "Owner": { - "DisplayName": "", "ID": "" }, "VersionId": "" @@ -110,7 +108,6 @@ "Key": "test-delete", "LastModified": "datetime", "Owner": { - "DisplayName": "", "ID": "" }, "Size": 11, @@ -173,7 +170,7 @@ } }, "tests/aws/services/s3/test_s3_api.py::TestS3ObjectCRUD::test_delete_object": { - "recorded-date": "21-01-2025, 18:09:31", + "recorded-date": "21-02-2026, 01:01:39", "recorded-content": { "put-object": { "ChecksumCRC32": "1jy6qw==", @@ -212,7 +209,7 @@ } }, "tests/aws/services/s3/test_s3_api.py::TestS3BucketCRUD::test_delete_versioned_bucket_with_objects": { - "recorded-date": "01-08-2023, 16:54:38", + "recorded-date": "21-02-2026, 01:01:38", "recorded-content": { "delete-with-obj-and-delete-marker": { "Error": { @@ -260,7 +257,7 @@ } }, "tests/aws/services/s3/test_s3_api.py::TestS3ObjectCRUD::test_get_object_with_version_unversioned_bucket": { - "recorded-date": "21-01-2025, 18:09:42", + "recorded-date": "21-02-2026, 01:01:51", "recorded-content": { "put-object": { "ChecksumCRC32": "jSiR5g==", @@ -303,7 +300,7 @@ } }, "tests/aws/services/s3/test_s3_api.py::TestS3ObjectCRUD::test_list_object_versions_order_unversioned": { - "recorded-date": "21-01-2025, 18:09:52", + "recorded-date": "21-02-2026, 01:02:01", "recorded-content": { "list-empty": { "EncodingType": "url", @@ -367,7 +364,6 @@ "Key": "a-test-object-1", "LastModified": "datetime", "Owner": { - "DisplayName": "", "ID": "" }, "Size": 13, @@ -384,7 +380,6 @@ "Key": "b-test-object-2", "LastModified": "datetime", "Owner": { - "DisplayName": "", "ID": "" }, "Size": 13, @@ -401,7 +396,6 @@ "Key": "c-test-object-3", "LastModified": "datetime", "Owner": { - "DisplayName": "", "ID": "" }, "Size": 13, @@ -417,7 +411,7 @@ } }, "tests/aws/services/s3/test_s3_api.py::TestS3BucketCRUD::test_delete_bucket_with_objects": { - "recorded-date": "27-07-2023, 00:25:16", + "recorded-date": "21-02-2026, 01:01:36", "recorded-content": { "delete-with-obj": { "Error": { @@ -445,7 +439,7 @@ } }, "tests/aws/services/s3/test_s3_api.py::TestS3ObjectCRUD::test_delete_objects": { - "recorded-date": "21-01-2025, 18:09:33", + "recorded-date": "21-02-2026, 01:01:42", "recorded-content": { "put-object": { "ChecksumCRC32": "1jy6qw==", @@ -491,7 +485,7 @@ } }, "tests/aws/services/s3/test_s3_api.py::TestS3ObjectCRUD::test_delete_objects_versioned": { - "recorded-date": "21-01-2025, 18:09:40", + "recorded-date": "23-02-2026, 11:04:21", "recorded-content": { "put-object": { "ChecksumCRC32": "1jy6qw==", @@ -576,7 +570,7 @@ } }, "tests/aws/services/s3/test_s3_api.py::TestS3BucketVersioning::test_bucket_versioning_crud": { - "recorded-date": "21-01-2025, 18:10:29", + "recorded-date": "21-02-2026, 01:02:46", "recorded-content": { "get-versioning-before": { "ResponseMetadata": { @@ -671,7 +665,7 @@ } }, "tests/aws/services/s3/test_s3_api.py::TestS3ObjectCRUD::test_put_object_on_suspended_bucket": { - "recorded-date": "21-01-2025, 18:09:46", + "recorded-date": "21-02-2026, 01:01:55", "recorded-content": { "put-object-0": { "ChecksumCRC32": "yAYCLA==", @@ -725,7 +719,6 @@ "Key": "test-version", "LastModified": "datetime", "Owner": { - "DisplayName": "", "ID": "" }, "Size": 14, @@ -742,7 +735,6 @@ "Key": "test-version", "LastModified": "datetime", "Owner": { - "DisplayName": "", "ID": "" }, "Size": 14, @@ -759,7 +751,6 @@ "Key": "test-version", "LastModified": "datetime", "Owner": { - "DisplayName": "", "ID": "" }, "Size": 14, @@ -791,7 +782,6 @@ "Key": "test-version", "LastModified": "datetime", "Owner": { - "DisplayName": "", "ID": "" }, "Size": 14, @@ -808,7 +798,6 @@ "Key": "test-version", "LastModified": "datetime", "Owner": { - "DisplayName": "", "ID": "" }, "Size": 14, @@ -825,7 +814,6 @@ "Key": "test-version", "LastModified": "datetime", "Owner": { - "DisplayName": "", "ID": "" }, "Size": 14, @@ -867,7 +855,6 @@ "Key": "test-version", "LastModified": "datetime", "Owner": { - "DisplayName": "", "ID": "" }, "Size": 22, @@ -884,7 +871,6 @@ "Key": "test-version", "LastModified": "datetime", "Owner": { - "DisplayName": "", "ID": "" }, "Size": 14, @@ -901,7 +887,6 @@ "Key": "test-version", "LastModified": "datetime", "Owner": { - "DisplayName": "", "ID": "" }, "Size": 14, @@ -918,7 +903,6 @@ "Key": "test-version", "LastModified": "datetime", "Owner": { - "DisplayName": "", "ID": "" }, "Size": 14, @@ -960,7 +944,6 @@ "Key": "test-version", "LastModified": "datetime", "Owner": { - "DisplayName": "", "ID": "" }, "Size": 22, @@ -977,7 +960,6 @@ "Key": "test-version", "LastModified": "datetime", "Owner": { - "DisplayName": "", "ID": "" }, "Size": 14, @@ -994,7 +976,6 @@ "Key": "test-version", "LastModified": "datetime", "Owner": { - "DisplayName": "", "ID": "" }, "Size": 14, @@ -1011,7 +992,6 @@ "Key": "test-version", "LastModified": "datetime", "Owner": { - "DisplayName": "", "ID": "" }, "Size": 14, @@ -1044,7 +1024,7 @@ } }, "tests/aws/services/s3/test_s3_api.py::TestS3ObjectCRUD::test_delete_object_on_suspended_bucket": { - "recorded-date": "21-01-2025, 18:09:50", + "recorded-date": "21-02-2026, 01:01:59", "recorded-content": { "put-object-0": { "ChecksumCRC32": "yAYCLA==", @@ -1087,7 +1067,6 @@ "Key": "test-delete-suspended", "LastModified": "datetime", "Owner": { - "DisplayName": "", "ID": "" }, "Size": 14, @@ -1104,7 +1083,6 @@ "Key": "test-delete-suspended", "LastModified": "datetime", "Owner": { - "DisplayName": "", "ID": "" }, "Size": 14, @@ -1132,7 +1110,6 @@ "Key": "test-delete-suspended", "LastModified": "datetime", "Owner": { - "DisplayName": "", "ID": "" }, "VersionId": "" @@ -1156,7 +1133,6 @@ "Key": "test-delete-suspended", "LastModified": "datetime", "Owner": { - "DisplayName": "", "ID": "" }, "Size": 14, @@ -1173,7 +1149,6 @@ "Key": "test-delete-suspended", "LastModified": "datetime", "Owner": { - "DisplayName": "", "ID": "" }, "Size": 14, @@ -1215,7 +1190,6 @@ "Key": "test-delete-suspended", "LastModified": "datetime", "Owner": { - "DisplayName": "", "ID": "" }, "Size": 35, @@ -1232,7 +1206,6 @@ "Key": "test-delete-suspended", "LastModified": "datetime", "Owner": { - "DisplayName": "", "ID": "" }, "Size": 14, @@ -1249,7 +1222,6 @@ "Key": "test-delete-suspended", "LastModified": "datetime", "Owner": { - "DisplayName": "", "ID": "" }, "Size": 14, @@ -1277,7 +1249,6 @@ "Key": "test-delete-suspended", "LastModified": "datetime", "Owner": { - "DisplayName": "", "ID": "" }, "VersionId": "" @@ -1301,7 +1272,6 @@ "Key": "test-delete-suspended", "LastModified": "datetime", "Owner": { - "DisplayName": "", "ID": "" }, "Size": 14, @@ -1318,7 +1288,6 @@ "Key": "test-delete-suspended", "LastModified": "datetime", "Owner": { - "DisplayName": "", "ID": "" }, "Size": 14, @@ -1334,7 +1303,7 @@ } }, "tests/aws/services/s3/test_s3_api.py::TestS3BucketEncryption::test_s3_default_bucket_encryption": { - "recorded-date": "21-01-2025, 18:10:45", + "recorded-date": "21-02-2026, 01:02:50", "recorded-content": { "default-bucket-encryption": { "ServerSideEncryptionConfiguration": { @@ -1373,7 +1342,7 @@ } }, "tests/aws/services/s3/test_s3_api.py::TestS3BucketEncryption::test_s3_default_bucket_encryption_exc": { - "recorded-date": "21-01-2025, 18:10:47", + "recorded-date": "21-02-2026, 01:02:53", "recorded-content": { "get-bucket-enc-no-bucket": { "Error": { @@ -1442,7 +1411,7 @@ } }, "tests/aws/services/s3/test_s3_api.py::TestS3BucketEncryption::test_s3_bucket_encryption_sse_s3": { - "recorded-date": "21-01-2025, 18:10:49", + "recorded-date": "21-02-2026, 01:02:55", "recorded-content": { "put-bucket-enc": { "ResponseMetadata": { @@ -1492,7 +1461,7 @@ } }, "tests/aws/services/s3/test_s3_api.py::TestS3BucketEncryption::test_s3_bucket_encryption_sse_kms_aws_managed_key": { - "recorded-date": "21-01-2025, 18:10:55", + "recorded-date": "21-02-2026, 01:03:01", "recorded-content": { "put-bucket-enc": { "ResponseMetadata": { @@ -1520,7 +1489,7 @@ "BucketKeyEnabled": true, "ChecksumCRC32": "J1mCHA==", "ChecksumType": "FULL_OBJECT", - "ETag": "\"08d16e16e9b2006587e811c5d81ea74f\"", + "ETag": "\"ec9f92ff18167a8c0cbff69597b6abf1\"", "SSEKMSKeyId": "arn::kms::111111111111:key/", "ServerSideEncryption": "aws:kms", "ResponseMetadata": { @@ -1533,6 +1502,7 @@ "AWSAccountId": "111111111111", "Arn": "arn::kms::111111111111:key/", "CreationDate": "datetime", + "CurrentKeyMaterialId": "", "CustomerMasterKeySpec": "SYMMETRIC_DEFAULT", "Description": "Default key that protects my S3 objects when no other key is defined", "Enabled": true, @@ -1557,7 +1527,7 @@ "BucketKeyEnabled": true, "ContentLength": 14, "ContentType": "binary/octet-stream", - "ETag": "\"08d16e16e9b2006587e811c5d81ea74f\"", + "ETag": "\"ec9f92ff18167a8c0cbff69597b6abf1\"", "LastModified": "datetime", "Metadata": {}, "SSEKMSKeyId": "arn::kms::111111111111:key/", @@ -1575,7 +1545,7 @@ "ChecksumType": "FULL_OBJECT", "ContentLength": 14, "ContentType": "binary/octet-stream", - "ETag": "\"08d16e16e9b2006587e811c5d81ea74f\"", + "ETag": "\"ec9f92ff18167a8c0cbff69597b6abf1\"", "LastModified": "datetime", "Metadata": {}, "SSEKMSKeyId": "arn::kms::111111111111:key/", @@ -1588,7 +1558,7 @@ } }, "tests/aws/services/s3/test_s3_api.py::TestS3BucketEncryption::test_s3_bucket_encryption_sse_kms": { - "recorded-date": "21-01-2025, 18:10:53", + "recorded-date": "21-02-2026, 01:02:58", "recorded-content": { "put-bucket-enc": { "ResponseMetadata": { @@ -1617,7 +1587,7 @@ "BucketKeyEnabled": true, "ChecksumCRC32": "J1mCHA==", "ChecksumType": "FULL_OBJECT", - "ETag": "\"ed93a03fee21ae796b5619dfb8afbe13\"", + "ETag": "\"88206b4eb968f907bf407d28fb04ceff\"", "SSEKMSKeyId": "arn::kms::111111111111:key/", "ServerSideEncryption": "aws:kms", "ResponseMetadata": { @@ -1630,7 +1600,7 @@ "BucketKeyEnabled": true, "ContentLength": 14, "ContentType": "binary/octet-stream", - "ETag": "\"ed93a03fee21ae796b5619dfb8afbe13\"", + "ETag": "\"88206b4eb968f907bf407d28fb04ceff\"", "LastModified": "datetime", "Metadata": {}, "SSEKMSKeyId": "arn::kms::111111111111:key/", @@ -1648,7 +1618,7 @@ "ChecksumType": "FULL_OBJECT", "ContentLength": 14, "ContentType": "binary/octet-stream", - "ETag": "\"ed93a03fee21ae796b5619dfb8afbe13\"", + "ETag": "\"88206b4eb968f907bf407d28fb04ceff\"", "LastModified": "datetime", "Metadata": {}, "SSEKMSKeyId": "arn::kms::111111111111:key/", @@ -1667,7 +1637,7 @@ "put-object-encrypted-bucket-key-disabled": { "ChecksumCRC32": "J1mCHA==", "ChecksumType": "FULL_OBJECT", - "ETag": "\"0b507d4ef8c3b14da00a61984206ca0d\"", + "ETag": "\"7dfb290d8f2cc85b35a86adf9bceb32a\"", "SSEKMSKeyId": "arn::kms::111111111111:key/", "ServerSideEncryption": "aws:kms", "ResponseMetadata": { @@ -1678,7 +1648,7 @@ } }, "tests/aws/services/s3/test_s3_api.py::TestS3BucketObjectTagging::test_bucket_tagging_crud": { - "recorded-date": "21-01-2025, 18:11:06", + "recorded-date": "23-02-2026, 11:08:45", "recorded-content": { "get-bucket-tags-empty": { "Error": { @@ -1746,7 +1716,7 @@ } }, "tests/aws/services/s3/test_s3_api.py::TestS3BucketObjectTagging::test_object_tagging_crud": { - "recorded-date": "21-01-2025, 18:11:10", + "recorded-date": "23-02-2026, 11:09:07", "recorded-content": { "put-object": { "ChecksumCRC32": "lpqTBg==", @@ -1854,7 +1824,7 @@ } }, "tests/aws/services/s3/test_s3_api.py::TestS3BucketObjectTagging::test_put_object_with_tags": { - "recorded-date": "21-01-2025, 18:11:19", + "recorded-date": "23-02-2026, 11:09:19", "recorded-content": { "put-object": { "ChecksumCRC32": "lpqTBg==", @@ -1912,6 +1882,7 @@ "LastModified": "datetime", "Metadata": {}, "ServerSideEncryption": "AES256", + "TagCount": 1, "ResponseMetadata": { "HTTPHeaders": {}, "HTTPStatusCode": 200 @@ -1969,7 +1940,7 @@ } }, "tests/aws/services/s3/test_s3_api.py::TestS3BucketObjectTagging::test_bucket_tagging_exc": { - "recorded-date": "21-01-2025, 18:11:07", + "recorded-date": "23-02-2026, 11:08:53", "recorded-content": { "get-no-bucket-tags": { "Error": { @@ -2007,7 +1978,7 @@ } }, "tests/aws/services/s3/test_s3_api.py::TestS3BucketObjectTagging::test_object_tagging_versioned": { - "recorded-date": "19-09-2025, 23:28:45", + "recorded-date": "23-02-2026, 11:09:16", "recorded-content": { "put-obj-0": { "ChecksumCRC32": "XCKz9A==", @@ -2183,7 +2154,7 @@ } }, "tests/aws/services/s3/test_s3_api.py::TestS3BucketObjectTagging::test_object_tagging_exc": { - "recorded-date": "02-09-2025, 22:43:24", + "recorded-date": "23-02-2026, 11:09:10", "recorded-content": { "get-no-bucket-tags": { "Error": { @@ -2278,7 +2249,7 @@ } }, "tests/aws/services/s3/test_s3_api.py::TestS3BucketObjectTagging::test_object_tags_delete_or_overwrite_object": { - "recorded-date": "21-01-2025, 18:11:22", + "recorded-date": "23-02-2026, 11:09:25", "recorded-content": { "get-object-after-creation": { "TagSet": [ @@ -2309,7 +2280,7 @@ } }, "tests/aws/services/s3/test_s3_api.py::TestS3BucketObjectTagging::test_tagging_validation": { - "recorded-date": "21-01-2025, 18:11:25", + "recorded-date": "23-02-2026, 11:09:30", "recorded-content": { "put-bucket-tags-duplicate-keys": { "Error": { @@ -2333,6 +2304,16 @@ "HTTPStatusCode": 400 } }, + "put-bucket-tags-none-key": { + "Error": { + "Code": "MalformedXML", + "Message": "The XML you provided was not well-formed or did not validate against our published schema" + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + }, "put-bucket-tags-invalid-value": { "Error": { "Code": "InvalidTag", @@ -2345,6 +2326,16 @@ "HTTPStatusCode": 400 } }, + "put-bucket-tags-none-value": { + "Error": { + "Code": "MalformedXML", + "Message": "The XML you provided was not well-formed or did not validate against our published schema" + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + }, "put-bucket-tags-aws-prefixed": { "Error": { "Code": "InvalidTag", @@ -2388,11 +2379,31 @@ "HTTPHeaders": {}, "HTTPStatusCode": 400 } + }, + "put-object-tags-none-key": { + "Error": { + "Code": "MalformedXML", + "Message": "The XML you provided was not well-formed or did not validate against our published schema" + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + }, + "put-object-tags-none-value": { + "Error": { + "Code": "MalformedXML", + "Message": "The XML you provided was not well-formed or did not validate against our published schema" + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } } } }, "tests/aws/services/s3/test_s3_api.py::TestS3ObjectLock::test_put_object_lock_configuration_on_existing_bucket": { - "recorded-date": "21-01-2025, 18:11:36", + "recorded-date": "21-02-2026, 01:03:59", "recorded-content": { "get-object-lock-existing-bucket-no-config": { "Error": { @@ -2455,7 +2466,7 @@ } }, "tests/aws/services/s3/test_s3_api.py::TestS3ObjectLock::test_get_put_object_lock_configuration": { - "recorded-date": "21-01-2025, 18:11:37", + "recorded-date": "21-02-2026, 01:04:00", "recorded-content": { "get-lock-config-start": { "ObjectLockConfiguration": { @@ -2505,7 +2516,7 @@ } }, "tests/aws/services/s3/test_s3_api.py::TestS3ObjectLock::test_put_object_lock_configuration_exc": { - "recorded-date": "20-06-2025, 17:03:24", + "recorded-date": "21-02-2026, 01:04:04", "recorded-content": { "put-lock-config-no-enabled": { "Error": { @@ -2580,7 +2591,7 @@ } }, "tests/aws/services/s3/test_s3_api.py::TestS3ObjectLock::test_get_object_lock_configuration_exc": { - "recorded-date": "21-01-2025, 18:11:42", + "recorded-date": "21-02-2026, 01:04:06", "recorded-content": { "get-lock-config-no-enabled": { "Error": { @@ -2607,7 +2618,7 @@ } }, "tests/aws/services/s3/test_s3_api.py::TestS3ObjectLock::test_disable_versioning_on_locked_bucket": { - "recorded-date": "21-01-2025, 18:11:43", + "recorded-date": "21-02-2026, 01:04:07", "recorded-content": { "disable-versioning-on-locked-bucket": { "Error": { @@ -2628,7 +2639,7 @@ } }, "tests/aws/services/s3/test_s3_api.py::TestS3BucketOwnershipControls::test_crud_bucket_ownership_controls": { - "recorded-date": "10-08-2023, 02:57:08", + "recorded-date": "21-02-2026, 01:04:13", "recorded-content": { "default-ownership": { "OwnershipControls": { @@ -2701,7 +2712,7 @@ } }, "tests/aws/services/s3/test_s3_api.py::TestS3BucketOwnershipControls::test_bucket_ownership_controls_exc": { - "recorded-date": "10-08-2023, 03:08:54", + "recorded-date": "21-02-2026, 01:04:17", "recorded-content": { "default-ownership": { "OwnershipControls": { @@ -2771,7 +2782,7 @@ } }, "tests/aws/services/s3/test_s3_api.py::TestS3PublicAccessBlock::test_crud_public_access_block": { - "recorded-date": "10-08-2023, 03:29:18", + "recorded-date": "21-02-2026, 01:04:19", "recorded-content": { "get-default-public-access-block": { "PublicAccessBlockConfiguration": { @@ -2833,7 +2844,7 @@ "recorded-content": {} }, "tests/aws/services/s3/test_s3_api.py::TestS3BucketPolicy::test_bucket_policy_crud": { - "recorded-date": "20-10-2023, 17:31:38", + "recorded-date": "21-02-2026, 01:04:22", "recorded-content": { "get-bucket-default-policy": { "Error": { @@ -2897,7 +2908,7 @@ } }, "tests/aws/services/s3/test_s3_api.py::TestS3BucketPolicy::test_bucket_policy_exc": { - "recorded-date": "10-08-2023, 17:35:26", + "recorded-date": "21-02-2026, 01:04:24", "recorded-content": { "put-empty-bucket-policy": { "Error": { @@ -2932,7 +2943,7 @@ } }, "tests/aws/services/s3/test_s3_api.py::TestS3BucketAccelerateConfiguration::test_bucket_acceleration_configuration_crud": { - "recorded-date": "10-08-2023, 18:26:06", + "recorded-date": "21-02-2026, 01:04:28", "recorded-content": { "get-bucket-default-accelerate-config": { "ResponseMetadata": { @@ -2969,7 +2980,7 @@ } }, "tests/aws/services/s3/test_s3_api.py::TestS3BucketAccelerateConfiguration::test_bucket_acceleration_configuration_exc": { - "recorded-date": "10-08-2023, 18:01:50", + "recorded-date": "21-02-2026, 01:04:30", "recorded-content": { "put-bucket-accelerate-config-lowercase": { "Error": { @@ -3004,7 +3015,7 @@ } }, "tests/aws/services/s3/test_s3_api.py::TestS3ObjectCRUD::test_get_object_range": { - "recorded-date": "07-07-2025, 17:50:03", + "recorded-date": "21-02-2026, 01:02:09", "recorded-content": { "get-0-8": { "AcceptRanges": "bytes", @@ -3278,7 +3289,7 @@ } }, "tests/aws/services/s3/test_s3_api.py::TestS3Multipart::test_upload_part_copy_range": { - "recorded-date": "13-06-2025, 12:42:54", + "recorded-date": "21-02-2026, 01:02:15", "recorded-content": { "put-src-object": { "ChecksumCRC32": "poTHxg==", @@ -3344,7 +3355,6 @@ "MaxParts": 1000, "NextPartNumberMarker": 3, "Owner": { - "DisplayName": "display-name", "ID": "i-d" }, "PartNumberMarker": 0, @@ -3520,7 +3530,7 @@ } }, "tests/aws/services/s3/test_s3_api.py::TestS3ObjectLock::test_delete_object_with_no_locking": { - "recorded-date": "21-01-2025, 18:11:45", + "recorded-date": "21-02-2026, 01:04:09", "recorded-content": { "delete-object-bypass-no-lock": { "Error": { @@ -3558,7 +3568,7 @@ } }, "tests/aws/services/s3/test_s3_api.py::TestS3Multipart::test_upload_part_copy_no_copy_source_range": { - "recorded-date": "13-06-2025, 12:42:57", + "recorded-date": "21-02-2026, 01:02:18", "recorded-content": { "put-src-object": { "ChecksumCRC32": "poTHxg==", @@ -3602,7 +3612,6 @@ "MaxParts": 1000, "NextPartNumberMarker": 1, "Owner": { - "DisplayName": "display-name", "ID": "i-d" }, "PartNumberMarker": 0, @@ -3624,7 +3633,7 @@ } }, "tests/aws/services/s3/test_s3_api.py::TestS3ObjectWritePrecondition::test_put_object_if_none_match": { - "recorded-date": "17-03-2025, 20:15:37", + "recorded-date": "21-02-2026, 01:04:34", "recorded-content": { "put-obj": { "ChecksumCRC32": "AAAAAA==", @@ -3666,7 +3675,7 @@ } }, "tests/aws/services/s3/test_s3_api.py::TestS3ObjectWritePrecondition::test_put_object_if_none_match_validation": { - "recorded-date": "17-03-2025, 20:15:39", + "recorded-date": "21-02-2026, 01:04:36", "recorded-content": { "put-obj": { "ChecksumCRC32": "AAAAAA==", @@ -3693,7 +3702,7 @@ } }, "tests/aws/services/s3/test_s3_api.py::TestS3ObjectWritePrecondition::test_put_object_if_none_match_versioned_bucket": { - "recorded-date": "17-03-2025, 20:15:48", + "recorded-date": "21-02-2026, 01:04:44", "recorded-content": { "put-obj": { "ChecksumCRC32": "AAAAAA==", @@ -3743,7 +3752,6 @@ "Key": "test-precondition", "LastModified": "datetime", "Owner": { - "DisplayName": "", "ID": "" }, "VersionId": "" @@ -3767,7 +3775,6 @@ "Key": "test-precondition", "LastModified": "datetime", "Owner": { - "DisplayName": "", "ID": "" }, "Size": 0, @@ -3784,7 +3791,6 @@ "Key": "test-precondition", "LastModified": "datetime", "Owner": { - "DisplayName": "", "ID": "" }, "Size": 0, @@ -3800,7 +3806,7 @@ } }, "tests/aws/services/s3/test_s3_api.py::TestS3ObjectWritePrecondition::test_multipart_if_none_match_with_delete": { - "recorded-date": "17-03-2025, 20:15:42", + "recorded-date": "21-02-2026, 01:04:39", "recorded-content": { "put-obj": { "ChecksumCRC32": "AAAAAA==", @@ -3867,7 +3873,7 @@ } }, "tests/aws/services/s3/test_s3_api.py::TestS3ObjectWritePrecondition::test_multipart_if_none_match_with_put": { - "recorded-date": "17-03-2025, 20:15:45", + "recorded-date": "21-02-2026, 01:04:41", "recorded-content": { "create-multipart": { "Bucket": "", @@ -3903,7 +3909,7 @@ } }, "tests/aws/services/s3/test_s3_api.py::TestS3BucketVersioning::test_object_version_id_format": { - "recorded-date": "21-01-2025, 18:10:31", + "recorded-date": "21-02-2026, 01:02:47", "recorded-content": { "put-object": { "ChecksumCRC32": "AAAAAA==", @@ -3919,7 +3925,7 @@ } }, "tests/aws/services/s3/test_s3_api.py::TestS3ObjectWritePrecondition::test_put_object_if_match": { - "recorded-date": "17-03-2025, 20:15:51", + "recorded-date": "21-02-2026, 01:04:47", "recorded-content": { "put-obj": { "ChecksumCRC32": "2H9+DA==", @@ -3982,7 +3988,7 @@ } }, "tests/aws/services/s3/test_s3_api.py::TestS3ObjectWritePrecondition::test_put_object_if_match_validation": { - "recorded-date": "17-03-2025, 20:15:53", + "recorded-date": "21-02-2026, 01:04:49", "recorded-content": { "put-obj-if-match-star-value": { "Error": { @@ -4021,7 +4027,7 @@ } }, "tests/aws/services/s3/test_s3_api.py::TestS3ObjectWritePrecondition::test_multipart_if_match_with_put": { - "recorded-date": "17-03-2025, 20:15:56", + "recorded-date": "21-02-2026, 01:04:52", "recorded-content": { "put-obj": { "ChecksumCRC32": "2H9+DA==", @@ -4102,7 +4108,7 @@ } }, "tests/aws/services/s3/test_s3_api.py::TestS3ObjectWritePrecondition::test_multipart_if_match_with_put_identical": { - "recorded-date": "17-03-2025, 20:15:59", + "recorded-date": "21-02-2026, 01:04:56", "recorded-content": { "put-obj": { "ChecksumCRC32": "2H9+DA==", @@ -4172,7 +4178,7 @@ } }, "tests/aws/services/s3/test_s3_api.py::TestS3ObjectWritePrecondition::test_multipart_if_match_with_delete": { - "recorded-date": "17-03-2025, 20:16:02", + "recorded-date": "21-02-2026, 01:04:59", "recorded-content": { "put-obj": { "ChecksumCRC32": "2H9+DA==", @@ -4236,7 +4242,7 @@ } }, "tests/aws/services/s3/test_s3_api.py::TestS3ObjectWritePrecondition::test_put_object_if_match_versioned_bucket": { - "recorded-date": "17-03-2025, 20:16:06", + "recorded-date": "21-02-2026, 01:05:02", "recorded-content": { "put-obj": { "ChecksumCRC32": "2H9+DA==", @@ -4308,7 +4314,6 @@ "Key": "test-precondition", "LastModified": "datetime", "Owner": { - "DisplayName": "", "ID": "" }, "VersionId": "" @@ -4332,7 +4337,6 @@ "Key": "test-precondition", "LastModified": "datetime", "Owner": { - "DisplayName": "", "ID": "" }, "Size": 13, @@ -4349,7 +4353,6 @@ "Key": "test-precondition", "LastModified": "datetime", "Owner": { - "DisplayName": "", "ID": "" }, "Size": 14, @@ -4366,7 +4369,6 @@ "Key": "test-precondition", "LastModified": "datetime", "Owner": { - "DisplayName": "", "ID": "" }, "Size": 4, @@ -4382,7 +4384,7 @@ } }, "tests/aws/services/s3/test_s3_api.py::TestS3ObjectWritePrecondition::test_put_object_if_match_and_if_none_match_validation": { - "recorded-date": "17-03-2025, 20:16:07", + "recorded-date": "21-02-2026, 01:05:04", "recorded-content": { "put-obj-both-precondition": { "Error": { @@ -4399,7 +4401,7 @@ } }, "tests/aws/services/s3/test_s3_api.py::TestS3ObjectWritePrecondition::test_multipart_if_match_etag": { - "recorded-date": "17-03-2025, 20:16:10", + "recorded-date": "21-02-2026, 01:05:07", "recorded-content": { "put-obj": { "ChecksumCRC32": "2H9+DA==", @@ -4471,7 +4473,7 @@ } }, "tests/aws/services/s3/test_s3_api.py::TestS3MetricsConfiguration::test_put_bucket_metrics_configuration": { - "recorded-date": "13-06-2025, 08:33:02", + "recorded-date": "21-02-2026, 01:05:25", "recorded-content": { "put_bucket_metrics_configuration": { "ResponseMetadata": { @@ -4494,7 +4496,7 @@ } }, "tests/aws/services/s3/test_s3_api.py::TestS3MetricsConfiguration::test_overwrite_bucket_metrics_configuration": { - "recorded-date": "13-06-2025, 08:33:03", + "recorded-date": "21-02-2026, 01:05:27", "recorded-content": { "overwrite_bucket_metrics_configuration": { "ResponseMetadata": { @@ -4517,7 +4519,7 @@ } }, "tests/aws/services/s3/test_s3_api.py::TestS3MetricsConfiguration::test_list_bucket_metrics_configurations": { - "recorded-date": "13-06-2025, 08:33:04", + "recorded-date": "21-02-2026, 01:05:28", "recorded-content": { "list_bucket_metrics_configurations": { "IsTruncated": false, @@ -4543,7 +4545,7 @@ } }, "tests/aws/services/s3/test_s3_api.py::TestS3MetricsConfiguration::test_get_bucket_metrics_configuration": { - "recorded-date": "13-06-2025, 08:33:17", + "recorded-date": "21-02-2026, 01:05:44", "recorded-content": { "get_bucket_metrics_configuration": { "MetricsConfiguration": { @@ -4560,7 +4562,7 @@ } }, "tests/aws/services/s3/test_s3_api.py::TestS3MetricsConfiguration::test_get_bucket_metrics_configuration_not_exist": { - "recorded-date": "13-06-2025, 08:33:18", + "recorded-date": "21-02-2026, 01:05:45", "recorded-content": { "get_bucket_metrics_configuration": { "Error": { @@ -4575,7 +4577,7 @@ } }, "tests/aws/services/s3/test_s3_api.py::TestS3MetricsConfiguration::test_delete_metrics_configuration": { - "recorded-date": "13-06-2025, 08:33:19", + "recorded-date": "21-02-2026, 01:05:47", "recorded-content": { "delete_bucket_metrics_configuration": { "ResponseMetadata": { @@ -4596,7 +4598,7 @@ } }, "tests/aws/services/s3/test_s3_api.py::TestS3MetricsConfiguration::test_list_bucket_metrics_configurations_paginated": { - "recorded-date": "13-06-2025, 08:33:16", + "recorded-date": "21-02-2026, 01:05:43", "recorded-content": { "list_bucket_metrics_configurations_page_2": { "ContinuationToken": "", @@ -4623,7 +4625,7 @@ } }, "tests/aws/services/s3/test_s3_api.py::TestS3MetricsConfiguration::test_delete_metrics_configuration_twice": { - "recorded-date": "13-06-2025, 08:33:20", + "recorded-date": "21-02-2026, 01:05:48", "recorded-content": { "delete_bucket_metrics_configuration_1": { "ResponseMetadata": { @@ -4644,23 +4646,23 @@ } }, "tests/aws/services/s3/test_s3_api.py::TestS3DeletePrecondition::test_delete_object_if_match_non_express": { - "recorded-date": "23-06-2025, 08:53:20", + "recorded-date": "21-02-2026, 01:05:50", "recorded-content": { "delete-obj-if-match": { "Error": { - "Code": "NotImplemented", - "Header": "If-Match", - "Message": "A header you provided implies functionality that is not implemented" + "Code": "PreconditionFailed", + "Condition": "If-Match", + "Message": "At least one of the pre-conditions you specified did not hold" }, "ResponseMetadata": { "HTTPHeaders": {}, - "HTTPStatusCode": 501 + "HTTPStatusCode": 412 } } } }, "tests/aws/services/s3/test_s3_api.py::TestS3DeletePrecondition::test_delete_object_if_match_modified_non_express": { - "recorded-date": "23-06-2025, 09:05:52", + "recorded-date": "21-02-2026, 01:05:52", "recorded-content": { "delete-obj-if-match-last-modified": { "Error": { @@ -4676,7 +4678,7 @@ } }, "tests/aws/services/s3/test_s3_api.py::TestS3DeletePrecondition::test_delete_object_if_match_size_non_express": { - "recorded-date": "23-06-2025, 09:05:59", + "recorded-date": "21-02-2026, 01:05:54", "recorded-content": { "delete-obj-if-match-size": { "Error": { @@ -4692,7 +4694,7 @@ } }, "tests/aws/services/s3/test_s3_api.py::TestS3DeletePrecondition::test_delete_object_if_match_all_non_express": { - "recorded-date": "23-06-2025, 09:06:41", + "recorded-date": "21-02-2026, 01:05:56", "recorded-content": { "delete-obj-if-match-all": { "Error": { @@ -4708,7 +4710,7 @@ } }, "tests/aws/services/s3/test_s3_api.py::TestS3BucketNotificationConfiguration::test_bucket_notification_with_missing_values_in_rule": { - "recorded-date": "02-09-2025, 21:38:48", + "recorded-date": "21-02-2026, 01:05:59", "recorded-content": { "invalid-rule-no-values": { "Error": { @@ -4743,7 +4745,7 @@ } }, "tests/aws/services/s3/test_s3_api.py::TestS3BucketNotificationConfiguration::test_bucket_notification_with_invalid_filter_rules": { - "recorded-date": "02-09-2025, 21:37:07", + "recorded-date": "21-02-2026, 01:06:01", "recorded-content": { "invalid_filter_name": { "Error": { @@ -4760,7 +4762,7 @@ } }, "tests/aws/services/s3/test_s3_api.py::TestS3BucketObjectTagging::test_put_object_tagging_none_value": { - "recorded-date": "02-09-2025, 22:43:06", + "recorded-date": "23-02-2026, 11:09:12", "recorded-content": { "put-none-tag-set": { "ResponseMetadata": { @@ -4778,7 +4780,7 @@ } }, "tests/aws/services/s3/test_s3_api.py::TestS3BucketObjectTagging::test_put_bucket_tagging_none_value": { - "recorded-date": "05-09-2025, 11:35:52", + "recorded-date": "23-02-2026, 11:09:04", "recorded-content": { "put-bucket-tags-origin": { "ResponseMetadata": { @@ -4806,7 +4808,7 @@ } }, "tests/aws/services/s3/test_s3_api.py::TestS3Multipart::test_upload_part_copy_with_copy_source_if_match_and_if_unmodified_since_match": { - "recorded-date": "06-09-2025, 09:23:25", + "recorded-date": "21-02-2026, 01:02:36", "recorded-content": { "upload-part-copy": { "CopyPartResult": { @@ -4851,7 +4853,7 @@ } }, "tests/aws/services/s3/test_s3_api.py::TestS3Multipart::test_upload_part_copy_with_copy_source_if_none_match_and_if_unmodified_since_match_failed": { - "recorded-date": "06-09-2025, 09:24:36", + "recorded-date": "21-02-2026, 01:02:38", "recorded-content": { "upload-part-copy-source-unmodified-since-and-if-none-match": { "Error": { @@ -4867,7 +4869,7 @@ } }, "tests/aws/services/s3/test_s3_api.py::TestS3Multipart::test_upload_part_copy_with_if_modified_since_failed": { - "recorded-date": "06-09-2025, 09:24:51", + "recorded-date": "21-02-2026, 01:02:42", "recorded-content": { "upload-part-copy-source-modified-since-match": { "Error": { @@ -4883,7 +4885,7 @@ } }, "tests/aws/services/s3/test_s3_api.py::TestS3Multipart::test_upload_part_copy_with_copy_source_if_match_failed": { - "recorded-date": "06-09-2025, 09:22:26", + "recorded-date": "21-02-2026, 01:02:30", "recorded-content": { "upload-part-copy-source-if-match": { "Error": { @@ -4899,7 +4901,7 @@ } }, "tests/aws/services/s3/test_s3_api.py::TestS3Multipart::test_upload_part_copy_with_copy_source_if_none_match_failed": { - "recorded-date": "06-09-2025, 09:22:50", + "recorded-date": "21-02-2026, 01:02:32", "recorded-content": { "upload-part-copy-source-if-none-match": { "Error": { @@ -4915,7 +4917,7 @@ } }, "tests/aws/services/s3/test_s3_api.py::TestS3Multipart::test_upload_part_copy_with_copy_source_if_unmodified_since_match_failed": { - "recorded-date": "06-09-2025, 09:23:12", + "recorded-date": "21-02-2026, 01:02:34", "recorded-content": { "upload-part-copy-source-unmodified-since-match": { "Error": { @@ -4931,7 +4933,7 @@ } }, "tests/aws/services/s3/test_s3_api.py::TestS3Multipart::test_upload_part_copy_with_copy_source_if_match_success": { - "recorded-date": "06-09-2025, 09:36:51", + "recorded-date": "21-02-2026, 01:02:20", "recorded-content": { "upload-part-copy-if-match": { "CopyPartResult": { @@ -4976,7 +4978,7 @@ } }, "tests/aws/services/s3/test_s3_api.py::TestS3Multipart::test_upload_part_copy_with_copy_source_if_match_none_success": { - "recorded-date": "06-09-2025, 09:39:55", + "recorded-date": "21-02-2026, 01:02:22", "recorded-content": { "upload-part-copy-if-none-match": { "CopyPartResult": { @@ -5021,7 +5023,7 @@ } }, "tests/aws/services/s3/test_s3_api.py::TestS3Multipart::test_upload_part_copy_with_copy_source_if_unmodified_since_success": { - "recorded-date": "06-09-2025, 09:47:30", + "recorded-date": "21-02-2026, 01:02:24", "recorded-content": { "upload-part-copy-if-unmodified-since": { "CopyPartResult": { @@ -5066,7 +5068,7 @@ } }, "tests/aws/services/s3/test_s3_api.py::TestS3Multipart::test_upload_part_copy_with_copy_source_if_modified_since_success": { - "recorded-date": "06-09-2025, 10:07:29", + "recorded-date": "21-02-2026, 01:02:26", "recorded-content": { "upload-part-copy-if-modified-since": { "CopyPartResult": { @@ -5111,7 +5113,7 @@ } }, "tests/aws/services/s3/test_s3_api.py::TestS3Multipart::test_upload_part_copy_with_copy_source_if_modified_since_in_future_success": { - "recorded-date": "06-09-2025, 10:20:23", + "recorded-date": "21-02-2026, 01:02:28", "recorded-content": { "upload-part-copy-if-modified-since-in-future": { "CopyPartResult": { @@ -5154,5 +5156,727 @@ } } } + }, + "tests/aws/services/s3/test_s3_api.py::TestS3BucketObjectTagging::test_create_bucket_with_tags": { + "recorded-date": "23-02-2026, 11:08:46", + "recorded-content": { + "create-bucket-with-tags": { + "BucketArn": "", + "Location": "", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "get-bucket-tags": { + "TagSet": [ + { + "Key": "tag1", + "Value": "value1" + } + ], + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/s3/test_s3_api.py::TestS3BucketObjectTagging::test_create_bucket_with_tags_us_east_1_idempotency": { + "recorded-date": "23-02-2026, 11:12:03", + "recorded-content": { + "create-bucket-with-tags": { + "BucketArn": "arn::s3:::", + "Location": "/", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "get-bucket-tags": { + "TagSet": [ + { + "Key": "tag1", + "Value": "value1" + } + ], + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "create-bucket-different-tags": { + "Error": { + "BucketName": "", + "Code": "BucketAlreadyOwnedByYou", + "Message": "Your previous request to create the named bucket succeeded and you already own it." + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 409 + } + }, + "create-bucket-with-no-tags": { + "BucketArn": "arn::s3:::", + "Location": "/", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "get-bucket-tags-after-re-create": { + "TagSet": [ + { + "Key": "tag1", + "Value": "value1" + } + ], + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "create-bucket-with-same-tags": { + "Error": { + "BucketName": "", + "Code": "BucketAlreadyOwnedByYou", + "Message": "Your previous request to create the named bucket succeeded and you already own it." + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 409 + } + }, + "create-bucket-with-empty-tags": { + "BucketArn": "arn::s3:::", + "Location": "/", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "get-bucket-tags-after-create-empty": { + "TagSet": [ + { + "Key": "tag1", + "Value": "value1" + } + ], + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/s3/test_s3_api.py::TestS3BucketObjectTagging::test_create_bucket_with_tags_exc": { + "recorded-date": "23-02-2026, 11:09:02", + "recorded-content": { + "tags-key-none": { + "Error": { + "Code": "MalformedXML", + "Message": "The XML you provided was not well-formed or did not validate against our published schema" + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + }, + "tags-value-none": { + "Error": { + "Code": "MalformedXML", + "Message": "The XML you provided was not well-formed or did not validate against our published schema" + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + }, + "tags-key-aws-prefix": { + "Error": { + "Code": "InvalidTag", + "Message": "User-defined tag keys can't start with \"aws:\". This prefix is reserved for system tags. Remove \"aws:\" from your tag keys and try again." + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + }, + "tags-key-aws-duplicated-key": { + "Error": { + "Code": "InternalError", + "Message": "We encountered an internal error. Please try again." + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 500 + } + }, + "tags-key-aws-bad-value": { + "Error": { + "Code": "InvalidTag", + "Message": "The TagValue you have provided is invalid", + "TagKey": "test", + "TagValue": "value1,value2" + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + }, + "tags-key-aws-bad-key": { + "Error": { + "Code": "InvalidTag", + "Message": "The TagKey you have provided is invalid", + "TagKey": "test,test2" + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + } + } + }, + "tests/aws/services/s3/test_s3_api.py::TestS3BucketObjectTagging::test_create_bucket_with_empty_tags": { + "recorded-date": "23-02-2026, 11:11:49", + "recorded-content": { + "create-bucket-with-empty-tags": { + "BucketArn": "arn::s3:::", + "Location": "/", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "get-bucket-tags": { + "Error": { + "BucketName": "", + "Code": "NoSuchTagSet", + "Message": "The TagSet does not exist" + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 404 + } + }, + "create-bucket-with-none-tags": { + "BucketArn": "arn::s3:::", + "Location": "/", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/s3/test_s3_api.py::TestS3BucketObjectTagging::test_head_object_with_tags": { + "recorded-date": "23-02-2026, 11:09:22", + "recorded-content": { + "put-object": { + "ChecksumCRC32": "lpqTBg==", + "ChecksumType": "FULL_OBJECT", + "ETag": "\"b635a7fc30aa9091e0d236bee77e6844\"", + "ServerSideEncryption": "AES256", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "head-obj-after-create": { + "AcceptRanges": "bytes", + "ContentLength": 12, + "ContentType": "binary/octet-stream", + "ETag": "\"b635a7fc30aa9091e0d236bee77e6844\"", + "LastModified": "datetime", + "Metadata": {}, + "ServerSideEncryption": "AES256", + "TagCount": 3, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "put-object-tags": { + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "head-obj-after-tagging": { + "AcceptRanges": "bytes", + "ContentLength": 12, + "ContentType": "binary/octet-stream", + "ETag": "\"b635a7fc30aa9091e0d236bee77e6844\"", + "LastModified": "datetime", + "Metadata": {}, + "ServerSideEncryption": "AES256", + "TagCount": 1, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "head-obj-after-overwrite": { + "AcceptRanges": "bytes", + "ContentLength": 12, + "ContentType": "binary/octet-stream", + "ETag": "\"b635a7fc30aa9091e0d236bee77e6844\"", + "LastModified": "datetime", + "Metadata": {}, + "ServerSideEncryption": "AES256", + "TagCount": 3, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "head-obj-after-removal": { + "AcceptRanges": "bytes", + "ContentLength": 12, + "ContentType": "binary/octet-stream", + "ETag": "\"b635a7fc30aa9091e0d236bee77e6844\"", + "LastModified": "datetime", + "Metadata": {}, + "ServerSideEncryption": "AES256", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/s3/test_s3_api.py::TestS3ObjectWritePrecondition::test_copy_object_if_none_match": { + "recorded-date": "21-02-2026, 01:05:09", + "recorded-content": { + "copy-obj": { + "CopyObjectResult": { + "ChecksumCRC32": "wmoL/Q==", + "ChecksumType": "FULL_OBJECT", + "ETag": "\"4d96fd1280dd67fe2eac895339a0a8e3\"", + "LastModified": "datetime" + }, + "ServerSideEncryption": "AES256", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "copy-obj-if-none-match-fail": { + "Error": { + "Code": "PreconditionFailed", + "Condition": "If-None-Match", + "Message": "At least one of the pre-conditions you specified did not hold" + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 412 + } + } + } + }, + "tests/aws/services/s3/test_s3_api.py::TestS3ObjectWritePrecondition::test_copy_object_if_match": { + "recorded-date": "21-02-2026, 01:05:11", + "recorded-content": { + "copy-obj-if-match": { + "CopyObjectResult": { + "ChecksumCRC32": "wmoL/Q==", + "ChecksumType": "FULL_OBJECT", + "ETag": "\"4d96fd1280dd67fe2eac895339a0a8e3\"", + "LastModified": "datetime" + }, + "ServerSideEncryption": "AES256", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "copy-obj-if-match-fail-wrong-etag": { + "Error": { + "Code": "PreconditionFailed", + "Condition": "If-Match", + "Message": "At least one of the pre-conditions you specified did not hold" + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 412 + } + }, + "copy-obj-if-match-fail-no-object": { + "Error": { + "Code": "NoSuchKey", + "Key": "non-existent-key", + "Message": "The specified key does not exist." + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 404 + } + } + } + }, + "tests/aws/services/s3/test_s3_api.py::TestS3ObjectWritePrecondition::test_copy_object_if_none_match_versioned_bucket": { + "recorded-date": "21-02-2026, 01:05:14", + "recorded-content": { + "copy-obj": { + "CopyObjectResult": { + "ChecksumCRC32": "wmoL/Q==", + "ChecksumType": "FULL_OBJECT", + "ETag": "\"4d96fd1280dd67fe2eac895339a0a8e3\"", + "LastModified": "datetime" + }, + "CopySourceVersionId": "", + "ServerSideEncryption": "AES256", + "VersionId": "", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "copy-obj-if-none-match-fail": { + "Error": { + "Code": "PreconditionFailed", + "Condition": "If-None-Match", + "Message": "At least one of the pre-conditions you specified did not hold" + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 412 + } + }, + "del-obj": { + "DeleteMarker": true, + "VersionId": "", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 204 + } + }, + "copy-obj-after-del": { + "CopyObjectResult": { + "ChecksumCRC32": "wmoL/Q==", + "ChecksumType": "FULL_OBJECT", + "ETag": "\"4d96fd1280dd67fe2eac895339a0a8e3\"", + "LastModified": "datetime" + }, + "CopySourceVersionId": "", + "ServerSideEncryption": "AES256", + "VersionId": "", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "list-object-versions": { + "DeleteMarkers": [ + { + "IsLatest": false, + "Key": "dest-object", + "LastModified": "datetime", + "Owner": { + "ID": "" + }, + "VersionId": "" + } + ], + "EncodingType": "url", + "IsTruncated": false, + "KeyMarker": "", + "MaxKeys": 1000, + "Name": "", + "Prefix": "", + "VersionIdMarker": "", + "Versions": [ + { + "ChecksumAlgorithm": [ + "CRC32" + ], + "ChecksumType": "FULL_OBJECT", + "ETag": "\"4d96fd1280dd67fe2eac895339a0a8e3\"", + "IsLatest": true, + "Key": "dest-object", + "LastModified": "datetime", + "Owner": { + "ID": "" + }, + "Size": 14, + "StorageClass": "STANDARD", + "VersionId": "" + }, + { + "ChecksumAlgorithm": [ + "CRC32" + ], + "ChecksumType": "FULL_OBJECT", + "ETag": "\"4d96fd1280dd67fe2eac895339a0a8e3\"", + "IsLatest": false, + "Key": "dest-object", + "LastModified": "datetime", + "Owner": { + "ID": "" + }, + "Size": 14, + "StorageClass": "STANDARD", + "VersionId": "" + }, + { + "ChecksumAlgorithm": [ + "CRC32" + ], + "ChecksumType": "FULL_OBJECT", + "ETag": "\"4d96fd1280dd67fe2eac895339a0a8e3\"", + "IsLatest": true, + "Key": "source-object", + "LastModified": "datetime", + "Owner": { + "ID": "" + }, + "Size": 14, + "StorageClass": "STANDARD", + "VersionId": "" + } + ], + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/s3/test_s3_api.py::TestS3ObjectWritePrecondition::test_copy_object_if_match_versioned_bucket": { + "recorded-date": "21-02-2026, 01:05:18", + "recorded-content": { + "put-obj": { + "ChecksumCRC32": "P8fZPQ==", + "ChecksumType": "FULL_OBJECT", + "ETag": "\"38370d56e3e114d73ebedd6ac7b19028\"", + "ServerSideEncryption": "AES256", + "VersionId": "", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "copy-obj-if-match-wrong-etag": { + "Error": { + "Code": "PreconditionFailed", + "Condition": "If-Match", + "Message": "At least one of the pre-conditions you specified did not hold" + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 412 + } + }, + "del-obj": { + "DeleteMarker": true, + "VersionId": "", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 204 + } + }, + "copy-obj-after-del-exc": { + "Error": { + "Code": "NoSuchKey", + "Key": "dest-object", + "Message": "The specified key does not exist." + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 404 + } + }, + "put-obj-after-del": { + "ChecksumCRC32": "ORgJnw==", + "ChecksumType": "FULL_OBJECT", + "ETag": "\"06becddd7457b4bad77f1d3bca3a3ad1\"", + "ServerSideEncryption": "AES256", + "VersionId": "", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "copy-obj-if-match": { + "CopyObjectResult": { + "ChecksumCRC32": "wmoL/Q==", + "ChecksumType": "FULL_OBJECT", + "ETag": "\"4d96fd1280dd67fe2eac895339a0a8e3\"", + "LastModified": "datetime" + }, + "CopySourceVersionId": "", + "ServerSideEncryption": "AES256", + "VersionId": "", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "list-object-versions": { + "DeleteMarkers": [ + { + "IsLatest": false, + "Key": "dest-object", + "LastModified": "datetime", + "Owner": { + "ID": "" + }, + "VersionId": "" + } + ], + "EncodingType": "url", + "IsTruncated": false, + "KeyMarker": "", + "MaxKeys": 1000, + "Name": "", + "Prefix": "", + "VersionIdMarker": "", + "Versions": [ + { + "ChecksumAlgorithm": [ + "CRC32" + ], + "ChecksumType": "FULL_OBJECT", + "ETag": "\"4d96fd1280dd67fe2eac895339a0a8e3\"", + "IsLatest": true, + "Key": "dest-object", + "LastModified": "datetime", + "Owner": { + "ID": "" + }, + "Size": 14, + "StorageClass": "STANDARD", + "VersionId": "" + }, + { + "ChecksumAlgorithm": [ + "CRC32" + ], + "ChecksumType": "FULL_OBJECT", + "ETag": "\"06becddd7457b4bad77f1d3bca3a3ad1\"", + "IsLatest": false, + "Key": "dest-object", + "LastModified": "datetime", + "Owner": { + "ID": "" + }, + "Size": 24, + "StorageClass": "STANDARD", + "VersionId": "" + }, + { + "ChecksumAlgorithm": [ + "CRC32" + ], + "ChecksumType": "FULL_OBJECT", + "ETag": "\"38370d56e3e114d73ebedd6ac7b19028\"", + "IsLatest": false, + "Key": "dest-object", + "LastModified": "datetime", + "Owner": { + "ID": "" + }, + "Size": 15, + "StorageClass": "STANDARD", + "VersionId": "" + }, + { + "ChecksumAlgorithm": [ + "CRC32" + ], + "ChecksumType": "FULL_OBJECT", + "ETag": "\"4d96fd1280dd67fe2eac895339a0a8e3\"", + "IsLatest": true, + "Key": "source-object", + "LastModified": "datetime", + "Owner": { + "ID": "" + }, + "Size": 14, + "StorageClass": "STANDARD", + "VersionId": "" + } + ], + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/s3/test_s3_api.py::TestS3ObjectWritePrecondition::test_copy_object_precondition_write_validation": { + "recorded-date": "21-02-2026, 01:05:21", + "recorded-content": { + "copy-obj-none-match-etag": { + "Error": { + "Code": "NotImplemented", + "Header": "If-None-Match", + "Message": "A header you provided implies functionality that is not implemented", + "additionalMessage": "We don't accept the provided value of If-None-Match header for this API" + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 501 + } + }, + "copy-obj-if-match-star": { + "Error": { + "Code": "NotImplemented", + "Header": "If-Match", + "Message": "A header you provided implies functionality that is not implemented", + "additionalMessage": "We don't accept the provided value of If-Match header for this API" + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 501 + } + }, + "copy-obj-both": { + "Error": { + "Code": "NotImplemented", + "Header": "If-Match,If-None-Match", + "Message": "A header you provided implies functionality that is not implemented", + "additionalMessage": "Multiple conditional request headers present in the request" + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 501 + } + } + } + }, + "tests/aws/services/s3/test_s3_api.py::TestS3ObjectWritePrecondition::test_copy_object_if_none_match_in_place": { + "recorded-date": "21-02-2026, 01:05:22", + "recorded-content": { + "copy-obj-if-none-match-fail": { + "Error": { + "Code": "PreconditionFailed", + "Condition": "If-None-Match", + "Message": "At least one of the pre-conditions you specified did not hold" + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 412 + } + } + } + }, + "tests/aws/services/s3/test_s3_api.py::TestS3ObjectWritePrecondition::test_copy_object_if_match_in_place": { + "recorded-date": "21-02-2026, 01:05:24", + "recorded-content": { + "copy-obj-if-match-in-place": { + "CopyObjectResult": { + "ChecksumCRC32": "wmoL/Q==", + "ChecksumType": "FULL_OBJECT", + "ETag": "\"4d96fd1280dd67fe2eac895339a0a8e3\"", + "LastModified": "datetime" + }, + "ServerSideEncryption": "AES256", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } } } diff --git a/tests/aws/services/s3/test_s3_api.validation.json b/tests/aws/services/s3/test_s3_api.validation.json index 2dbd3e8427102..551ab03f95da0 100644 --- a/tests/aws/services/s3/test_s3_api.validation.json +++ b/tests/aws/services/s3/test_s3_api.validation.json @@ -1,395 +1,839 @@ { "tests/aws/services/s3/test_s3_api.py::TestS3BucketAccelerateConfiguration::test_bucket_acceleration_configuration_crud": { - "last_validated_date": "2023-08-10T16:26:06+00:00" + "last_validated_date": "2026-02-21T01:04:28+00:00", + "durations_in_seconds": { + "setup": 0.52, + "call": 2.41, + "teardown": 0.6, + "total": 3.53 + } }, "tests/aws/services/s3/test_s3_api.py::TestS3BucketAccelerateConfiguration::test_bucket_acceleration_configuration_exc": { - "last_validated_date": "2023-08-10T16:01:50+00:00" + "last_validated_date": "2026-02-21T01:04:32+00:00", + "durations_in_seconds": { + "setup": 0.51, + "call": 1.07, + "teardown": 1.68, + "total": 3.26 + } }, "tests/aws/services/s3/test_s3_api.py::TestS3BucketCRUD::test_delete_bucket_with_objects": { - "last_validated_date": "2023-07-26T22:25:16+00:00" + "last_validated_date": "2026-02-21T01:01:36+00:00", + "durations_in_seconds": { + "setup": 1.07, + "call": 0.91, + "teardown": 0.21, + "total": 2.19 + } }, "tests/aws/services/s3/test_s3_api.py::TestS3BucketCRUD::test_delete_versioned_bucket_with_objects": { - "last_validated_date": "2024-08-29T13:20:49+00:00" + "last_validated_date": "2026-02-21T01:01:38+00:00", + "durations_in_seconds": { + "setup": 0.54, + "call": 1.42, + "teardown": 0.21, + "total": 2.17 + } }, "tests/aws/services/s3/test_s3_api.py::TestS3BucketEncryption::test_s3_bucket_encryption_sse_kms": { - "last_validated_date": "2025-01-21T18:10:53+00:00" + "last_validated_date": "2026-02-21T01:03:00+00:00", + "durations_in_seconds": { + "setup": 1.07, + "call": 1.58, + "teardown": 1.14, + "total": 3.79 + } }, "tests/aws/services/s3/test_s3_api.py::TestS3BucketEncryption::test_s3_bucket_encryption_sse_kms_aws_managed_key": { - "last_validated_date": "2025-01-21T18:10:55+00:00" + "last_validated_date": "2026-02-21T01:03:02+00:00", + "durations_in_seconds": { + "setup": 0.52, + "call": 1.03, + "teardown": 1.01, + "total": 2.56 + } }, "tests/aws/services/s3/test_s3_api.py::TestS3BucketEncryption::test_s3_bucket_encryption_sse_s3": { - "last_validated_date": "2025-01-21T18:10:49+00:00" + "last_validated_date": "2026-02-21T01:02:56+00:00", + "durations_in_seconds": { + "setup": 0.53, + "call": 0.7, + "teardown": 0.99, + "total": 2.22 + } }, "tests/aws/services/s3/test_s3_api.py::TestS3BucketEncryption::test_s3_default_bucket_encryption": { - "last_validated_date": "2025-01-21T18:10:45+00:00" + "last_validated_date": "2026-02-21T01:02:51+00:00", + "durations_in_seconds": { + "setup": 0.53, + "call": 0.62, + "teardown": 0.62, + "total": 1.77 + } }, "tests/aws/services/s3/test_s3_api.py::TestS3BucketEncryption::test_s3_default_bucket_encryption_exc": { - "last_validated_date": "2025-01-21T18:10:47+00:00" + "last_validated_date": "2026-02-21T01:02:53+00:00", + "durations_in_seconds": { + "setup": 0.52, + "call": 1.48, + "teardown": 0.97, + "total": 2.97 + } }, "tests/aws/services/s3/test_s3_api.py::TestS3BucketNotificationConfiguration::test_bucket_notification_with_invalid_filter_rules": { - "last_validated_date": "2025-09-02T21:37:08+00:00", + "last_validated_date": "2026-02-21T01:06:02+00:00", "durations_in_seconds": { - "setup": 1.07, - "call": 0.74, - "teardown": 1.04, - "total": 2.85 + "setup": 0.6, + "call": 0.37, + "teardown": 1.0, + "total": 1.97 } }, "tests/aws/services/s3/test_s3_api.py::TestS3BucketNotificationConfiguration::test_bucket_notification_with_missing_values_in_rule": { - "last_validated_date": "2025-09-02T21:38:48+00:00", + "last_validated_date": "2026-02-21T01:06:00+00:00", "durations_in_seconds": { - "setup": 1.04, - "call": 1.57, - "teardown": 0.81, - "total": 3.42 + "setup": 0.5, + "call": 1.6, + "teardown": 0.82, + "total": 2.92 } }, "tests/aws/services/s3/test_s3_api.py::TestS3BucketObjectTagging::test_bucket_tagging_crud": { - "last_validated_date": "2025-01-21T18:11:06+00:00" + "last_validated_date": "2026-02-23T11:08:45+00:00", + "durations_in_seconds": { + "setup": 1.03, + "call": 1.67, + "teardown": 0.62, + "total": 3.32 + } }, "tests/aws/services/s3/test_s3_api.py::TestS3BucketObjectTagging::test_bucket_tagging_exc": { - "last_validated_date": "2025-06-12T23:32:16+00:00" + "last_validated_date": "2026-02-23T11:08:54+00:00", + "durations_in_seconds": { + "setup": 0.55, + "call": 0.56, + "teardown": 0.71, + "total": 1.82 + } + }, + "tests/aws/services/s3/test_s3_api.py::TestS3BucketObjectTagging::test_create_bucket_with_empty_tags": { + "last_validated_date": "2026-02-23T11:11:50+00:00", + "durations_in_seconds": { + "setup": 0.48, + "call": 0.99, + "teardown": 1.08, + "total": 2.55 + } + }, + "tests/aws/services/s3/test_s3_api.py::TestS3BucketObjectTagging::test_create_bucket_with_tags": { + "last_validated_date": "2026-02-23T11:08:47+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.78, + "teardown": 0.62, + "total": 1.4 + } + }, + "tests/aws/services/s3/test_s3_api.py::TestS3BucketObjectTagging::test_create_bucket_with_tags_exc": { + "last_validated_date": "2026-02-23T11:09:02+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 8.66, + "teardown": 0.01, + "total": 8.67 + } + }, + "tests/aws/services/s3/test_s3_api.py::TestS3BucketObjectTagging::test_create_bucket_with_tags_us_east_1_idempotency": { + "last_validated_date": "2026-02-23T11:12:04+00:00", + "durations_in_seconds": { + "setup": 0.47, + "call": 1.71, + "teardown": 1.24, + "total": 3.42 + } + }, + "tests/aws/services/s3/test_s3_api.py::TestS3BucketObjectTagging::test_head_object_with_tags": { + "last_validated_date": "2026-02-23T11:09:23+00:00", + "durations_in_seconds": { + "setup": 0.53, + "call": 1.13, + "teardown": 1.02, + "total": 2.68 + } }, "tests/aws/services/s3/test_s3_api.py::TestS3BucketObjectTagging::test_object_tagging_crud": { - "last_validated_date": "2025-01-21T18:11:10+00:00" + "last_validated_date": "2026-02-23T11:09:08+00:00", + "durations_in_seconds": { + "setup": 0.6, + "call": 1.73, + "teardown": 0.99, + "total": 3.32 + } }, "tests/aws/services/s3/test_s3_api.py::TestS3BucketObjectTagging::test_object_tagging_exc": { - "last_validated_date": "2025-09-02T22:43:25+00:00", + "last_validated_date": "2026-02-23T11:09:10+00:00", "durations_in_seconds": { - "setup": 1.07, - "call": 1.36, - "teardown": 0.87, - "total": 3.3 + "setup": 0.52, + "call": 1.31, + "teardown": 0.86, + "total": 2.69 } }, "tests/aws/services/s3/test_s3_api.py::TestS3BucketObjectTagging::test_object_tagging_versioned": { - "last_validated_date": "2025-09-19T23:28:46+00:00", + "last_validated_date": "2026-02-23T11:09:17+00:00", "durations_in_seconds": { - "setup": 1.08, - "call": 2.55, - "teardown": 1.07, - "total": 4.7 + "setup": 0.59, + "call": 2.59, + "teardown": 1.01, + "total": 4.19 } }, "tests/aws/services/s3/test_s3_api.py::TestS3BucketObjectTagging::test_object_tags_delete_or_overwrite_object": { - "last_validated_date": "2025-01-21T18:11:22+00:00" + "last_validated_date": "2026-02-23T11:09:26+00:00", + "durations_in_seconds": { + "setup": 0.52, + "call": 1.25, + "teardown": 0.98, + "total": 2.75 + } }, "tests/aws/services/s3/test_s3_api.py::TestS3BucketObjectTagging::test_put_bucket_tagging_none_value": { - "last_validated_date": "2025-09-05T11:35:52+00:00", + "last_validated_date": "2026-02-23T11:09:04+00:00", "durations_in_seconds": { - "setup": 0.96, - "call": 0.77, - "teardown": 0.56, - "total": 2.29 + "setup": 0.58, + "call": 0.82, + "teardown": 0.61, + "total": 2.01 } }, "tests/aws/services/s3/test_s3_api.py::TestS3BucketObjectTagging::test_put_object_tagging_none_value": { - "last_validated_date": "2025-09-02T22:43:07+00:00", + "last_validated_date": "2026-02-23T11:09:13+00:00", "durations_in_seconds": { - "setup": 1.05, - "call": 0.68, - "teardown": 0.96, - "total": 2.69 + "setup": 0.55, + "call": 0.73, + "teardown": 1.06, + "total": 2.34 } }, "tests/aws/services/s3/test_s3_api.py::TestS3BucketObjectTagging::test_put_object_with_tags": { - "last_validated_date": "2025-01-21T18:11:19+00:00" + "last_validated_date": "2026-02-23T11:09:20+00:00", + "durations_in_seconds": { + "setup": 0.53, + "call": 1.73, + "teardown": 0.96, + "total": 3.22 + } }, "tests/aws/services/s3/test_s3_api.py::TestS3BucketObjectTagging::test_tagging_validation": { - "last_validated_date": "2025-01-21T18:11:25+00:00" + "last_validated_date": "2026-02-23T11:09:31+00:00", + "durations_in_seconds": { + "setup": 0.53, + "call": 4.09, + "teardown": 1.01, + "total": 5.63 + } }, "tests/aws/services/s3/test_s3_api.py::TestS3BucketOwnershipControls::test_bucket_ownership_controls_exc": { - "last_validated_date": "2023-08-10T01:08:54+00:00" + "last_validated_date": "2026-02-21T01:04:18+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 2.38, + "teardown": 0.85, + "total": 3.23 + } }, "tests/aws/services/s3/test_s3_api.py::TestS3BucketOwnershipControls::test_crud_bucket_ownership_controls": { - "last_validated_date": "2023-08-10T00:57:08+00:00" + "last_validated_date": "2026-02-21T01:04:14+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 2.44, + "teardown": 1.19, + "total": 3.63 + } }, "tests/aws/services/s3/test_s3_api.py::TestS3BucketPolicy::test_bucket_policy_crud": { - "last_validated_date": "2023-10-20T15:31:38+00:00" + "last_validated_date": "2026-02-21T01:04:22+00:00", + "durations_in_seconds": { + "setup": 0.53, + "call": 1.44, + "teardown": 0.62, + "total": 2.59 + } }, "tests/aws/services/s3/test_s3_api.py::TestS3BucketPolicy::test_bucket_policy_exc": { - "last_validated_date": "2023-08-10T15:35:26+00:00" + "last_validated_date": "2026-02-21T01:04:25+00:00", + "durations_in_seconds": { + "setup": 0.53, + "call": 1.35, + "teardown": 0.86, + "total": 2.74 + } }, "tests/aws/services/s3/test_s3_api.py::TestS3BucketVersioning::test_bucket_versioning_crud": { - "last_validated_date": "2025-01-21T18:10:29+00:00" + "last_validated_date": "2026-02-21T01:02:47+00:00", + "durations_in_seconds": { + "setup": 0.52, + "call": 2.55, + "teardown": 0.84, + "total": 3.91 + } }, "tests/aws/services/s3/test_s3_api.py::TestS3BucketVersioning::test_object_version_id_format": { - "last_validated_date": "2025-01-21T18:10:31+00:00" + "last_validated_date": "2026-02-21T01:02:49+00:00", + "durations_in_seconds": { + "setup": 0.52, + "call": 0.34, + "teardown": 1.37, + "total": 2.23 + } }, "tests/aws/services/s3/test_s3_api.py::TestS3DeletePrecondition::test_delete_object_if_match_all_non_express": { - "last_validated_date": "2025-06-23T09:06:43+00:00", + "last_validated_date": "2026-02-21T01:05:57+00:00", "durations_in_seconds": { - "setup": 0.96, - "call": 0.24, - "teardown": 1.13, - "total": 2.33 + "setup": 0.55, + "call": 0.22, + "teardown": 1.18, + "total": 1.95 } }, "tests/aws/services/s3/test_s3_api.py::TestS3DeletePrecondition::test_delete_object_if_match_modified_non_express": { - "last_validated_date": "2025-06-23T09:05:53+00:00", + "last_validated_date": "2026-02-21T01:05:53+00:00", "durations_in_seconds": { - "setup": 1.05, - "call": 0.23, - "teardown": 1.16, - "total": 2.44 + "setup": 0.52, + "call": 0.25, + "teardown": 1.23, + "total": 2.0 } }, "tests/aws/services/s3/test_s3_api.py::TestS3DeletePrecondition::test_delete_object_if_match_non_express": { - "last_validated_date": "2025-06-23T08:53:21+00:00", + "last_validated_date": "2026-02-21T01:05:51+00:00", "durations_in_seconds": { - "setup": 1.05, - "call": 0.24, - "teardown": 1.1, - "total": 2.39 + "setup": 0.56, + "call": 0.25, + "teardown": 0.97, + "total": 1.78 } }, "tests/aws/services/s3/test_s3_api.py::TestS3DeletePrecondition::test_delete_object_if_match_size_non_express": { - "last_validated_date": "2025-06-23T09:06:00+00:00", + "last_validated_date": "2026-02-21T01:05:55+00:00", "durations_in_seconds": { - "setup": 0.98, - "call": 0.22, - "teardown": 1.17, - "total": 2.37 + "setup": 0.53, + "call": 0.24, + "teardown": 1.24, + "total": 2.01 } }, "tests/aws/services/s3/test_s3_api.py::TestS3MetricsConfiguration::test_delete_metrics_configuration": { - "last_validated_date": "2025-06-13T08:33:19+00:00" + "last_validated_date": "2026-02-21T01:05:47+00:00", + "durations_in_seconds": { + "setup": 0.52, + "call": 0.37, + "teardown": 0.6, + "total": 1.49 + } }, "tests/aws/services/s3/test_s3_api.py::TestS3MetricsConfiguration::test_delete_metrics_configuration_twice": { - "last_validated_date": "2025-06-13T08:33:20+00:00" + "last_validated_date": "2026-02-21T01:05:49+00:00", + "durations_in_seconds": { + "setup": 0.63, + "call": 0.36, + "teardown": 0.61, + "total": 1.6 + } }, "tests/aws/services/s3/test_s3_api.py::TestS3MetricsConfiguration::test_get_bucket_metrics_configuration": { - "last_validated_date": "2025-06-13T08:33:17+00:00" + "last_validated_date": "2026-02-21T01:05:45+00:00", + "durations_in_seconds": { + "setup": 0.51, + "call": 0.24, + "teardown": 0.67, + "total": 1.42 + } }, "tests/aws/services/s3/test_s3_api.py::TestS3MetricsConfiguration::test_get_bucket_metrics_configuration_not_exist": { - "last_validated_date": "2025-06-13T08:33:18+00:00" + "last_validated_date": "2026-02-21T01:05:46+00:00", + "durations_in_seconds": { + "setup": 0.53, + "call": 0.12, + "teardown": 0.61, + "total": 1.26 + } }, "tests/aws/services/s3/test_s3_api.py::TestS3MetricsConfiguration::test_list_bucket_metrics_configurations": { - "last_validated_date": "2025-06-13T08:33:04+00:00" + "last_validated_date": "2026-02-21T01:05:29+00:00", + "durations_in_seconds": { + "setup": 0.54, + "call": 0.41, + "teardown": 0.63, + "total": 1.58 + } }, "tests/aws/services/s3/test_s3_api.py::TestS3MetricsConfiguration::test_list_bucket_metrics_configurations_paginated": { - "last_validated_date": "2025-06-13T08:33:16+00:00" + "last_validated_date": "2026-02-21T01:05:43+00:00", + "durations_in_seconds": { + "setup": 0.51, + "call": 13.27, + "teardown": 0.57, + "total": 14.35 + } }, "tests/aws/services/s3/test_s3_api.py::TestS3MetricsConfiguration::test_overwrite_bucket_metrics_configuration": { - "last_validated_date": "2025-06-13T08:33:03+00:00" + "last_validated_date": "2026-02-21T01:05:27+00:00", + "durations_in_seconds": { + "setup": 0.53, + "call": 0.37, + "teardown": 0.61, + "total": 1.51 + } }, "tests/aws/services/s3/test_s3_api.py::TestS3MetricsConfiguration::test_put_bucket_metrics_configuration": { - "last_validated_date": "2025-06-13T08:33:02+00:00" + "last_validated_date": "2026-02-21T01:05:26+00:00", + "durations_in_seconds": { + "setup": 0.52, + "call": 0.25, + "teardown": 0.59, + "total": 1.36 + } }, "tests/aws/services/s3/test_s3_api.py::TestS3Multipart::test_upload_part_copy_no_copy_source_range": { - "last_validated_date": "2025-06-13T12:42:58+00:00", + "last_validated_date": "2026-02-21T01:02:19+00:00", "durations_in_seconds": { - "setup": 0.55, - "call": 0.66, - "teardown": 1.07, - "total": 2.28 + "setup": 0.51, + "call": 0.64, + "teardown": 1.02, + "total": 2.17 } }, "tests/aws/services/s3/test_s3_api.py::TestS3Multipart::test_upload_part_copy_range": { - "last_validated_date": "2025-06-13T12:42:55+00:00", + "last_validated_date": "2026-02-21T01:02:17+00:00", "durations_in_seconds": { - "setup": 1.02, - "call": 5.28, - "teardown": 1.54, - "total": 7.84 + "setup": 0.5, + "call": 4.83, + "teardown": 1.19, + "total": 6.52 } }, "tests/aws/services/s3/test_s3_api.py::TestS3Multipart::test_upload_part_copy_with_copy_source_if_match_and_if_unmodified_since_match": { - "last_validated_date": "2025-09-06T09:23:26+00:00", + "last_validated_date": "2026-02-21T01:02:37+00:00", "durations_in_seconds": { - "setup": 0.88, - "call": 0.21, - "teardown": 0.66, - "total": 1.75 + "setup": 0.53, + "call": 0.64, + "teardown": 1.0, + "total": 2.17 } }, "tests/aws/services/s3/test_s3_api.py::TestS3Multipart::test_upload_part_copy_with_copy_source_if_match_failed": { - "last_validated_date": "2025-09-06T09:22:26+00:00", + "last_validated_date": "2026-02-21T01:02:31+00:00", "durations_in_seconds": { - "setup": 1.06, - "call": 0.16, - "teardown": 0.54, - "total": 1.76 + "setup": 0.5, + "call": 0.46, + "teardown": 0.98, + "total": 1.94 } }, "tests/aws/services/s3/test_s3_api.py::TestS3Multipart::test_upload_part_copy_with_copy_source_if_match_none_success": { - "last_validated_date": "2025-09-06T09:39:55+00:00", + "last_validated_date": "2026-02-21T01:02:23+00:00", "durations_in_seconds": { - "setup": 0.95, - "call": 0.2, - "teardown": 0.62, - "total": 1.77 + "setup": 0.52, + "call": 0.63, + "teardown": 1.02, + "total": 2.17 } }, "tests/aws/services/s3/test_s3_api.py::TestS3Multipart::test_upload_part_copy_with_copy_source_if_match_success": { - "last_validated_date": "2025-09-06T09:36:51+00:00", + "last_validated_date": "2026-02-21T01:02:21+00:00", "durations_in_seconds": { - "setup": 0.96, - "call": 0.21, - "teardown": 0.68, - "total": 1.85 + "setup": 0.51, + "call": 0.61, + "teardown": 0.99, + "total": 2.11 } }, "tests/aws/services/s3/test_s3_api.py::TestS3Multipart::test_upload_part_copy_with_copy_source_if_modified_since_in_future_success": { - "last_validated_date": "2025-09-06T10:20:24+00:00", + "last_validated_date": "2026-02-21T01:02:29+00:00", "durations_in_seconds": { - "setup": 0.97, - "call": 0.27, - "teardown": 0.74, - "total": 1.98 + "setup": 0.5, + "call": 0.61, + "teardown": 0.97, + "total": 2.08 } }, "tests/aws/services/s3/test_s3_api.py::TestS3Multipart::test_upload_part_copy_with_copy_source_if_modified_since_success": { - "last_validated_date": "2025-09-06T10:07:29+00:00", + "last_validated_date": "2026-02-21T01:02:27+00:00", "durations_in_seconds": { - "setup": 0.92, - "call": 0.29, - "teardown": 0.72, - "total": 1.93 + "setup": 0.5, + "call": 0.62, + "teardown": 0.95, + "total": 2.07 } }, "tests/aws/services/s3/test_s3_api.py::TestS3Multipart::test_upload_part_copy_with_copy_source_if_none_match_and_if_unmodified_since_match_failed": { - "last_validated_date": "2025-09-06T09:24:37+00:00", + "last_validated_date": "2026-02-21T01:02:40+00:00", "durations_in_seconds": { - "setup": 0.95, - "call": 0.15, - "teardown": 0.56, - "total": 1.66 + "setup": 0.53, + "call": 0.51, + "teardown": 1.12, + "total": 2.16 } }, "tests/aws/services/s3/test_s3_api.py::TestS3Multipart::test_upload_part_copy_with_copy_source_if_none_match_failed": { - "last_validated_date": "2025-09-06T09:22:51+00:00", + "last_validated_date": "2026-02-21T01:02:33+00:00", "durations_in_seconds": { - "setup": 0.87, - "call": 0.14, - "teardown": 0.51, - "total": 1.52 + "setup": 0.53, + "call": 0.48, + "teardown": 0.98, + "total": 1.99 } }, "tests/aws/services/s3/test_s3_api.py::TestS3Multipart::test_upload_part_copy_with_copy_source_if_unmodified_since_match_failed": { - "last_validated_date": "2025-09-06T09:23:12+00:00", + "last_validated_date": "2026-02-21T01:02:35+00:00", "durations_in_seconds": { - "setup": 1.0, - "call": 0.15, - "teardown": 0.57, - "total": 1.72 + "setup": 0.51, + "call": 0.47, + "teardown": 0.98, + "total": 1.96 } }, "tests/aws/services/s3/test_s3_api.py::TestS3Multipart::test_upload_part_copy_with_copy_source_if_unmodified_since_success": { - "last_validated_date": "2025-09-06T09:47:31+00:00", + "last_validated_date": "2026-02-21T01:02:25+00:00", "durations_in_seconds": { - "setup": 1.09, - "call": 0.2, - "teardown": 0.61, - "total": 1.9 + "setup": 0.52, + "call": 0.61, + "teardown": 1.08, + "total": 2.21 } }, "tests/aws/services/s3/test_s3_api.py::TestS3Multipart::test_upload_part_copy_with_if_modified_since_failed": { - "last_validated_date": "2025-09-06T09:24:52+00:00", + "last_validated_date": "2026-02-21T01:02:43+00:00", "durations_in_seconds": { - "setup": 0.96, - "call": 1.16, - "teardown": 0.68, - "total": 2.8 + "setup": 0.52, + "call": 1.48, + "teardown": 0.98, + "total": 2.98 } }, "tests/aws/services/s3/test_s3_api.py::TestS3ObjectCRUD::test_delete_object": { - "last_validated_date": "2025-01-21T18:09:31+00:00" + "last_validated_date": "2026-02-21T01:01:40+00:00", + "durations_in_seconds": { + "setup": 0.55, + "call": 0.58, + "teardown": 0.8, + "total": 1.93 + } }, "tests/aws/services/s3/test_s3_api.py::TestS3ObjectCRUD::test_delete_object_on_suspended_bucket": { - "last_validated_date": "2025-01-21T18:09:50+00:00" + "last_validated_date": "2026-02-21T01:02:00+00:00", + "durations_in_seconds": { + "setup": 0.54, + "call": 1.9, + "teardown": 0.98, + "total": 3.42 + } }, "tests/aws/services/s3/test_s3_api.py::TestS3ObjectCRUD::test_delete_object_versioned": { - "last_validated_date": "2025-01-21T18:09:37+00:00" + "last_validated_date": "2026-02-21T01:01:46+00:00", + "durations_in_seconds": { + "setup": 0.53, + "call": 2.32, + "teardown": 1.18, + "total": 4.03 + } }, "tests/aws/services/s3/test_s3_api.py::TestS3ObjectCRUD::test_delete_objects": { - "last_validated_date": "2025-01-21T18:09:33+00:00" + "last_validated_date": "2026-02-21T01:01:42+00:00", + "durations_in_seconds": { + "setup": 0.51, + "call": 0.74, + "teardown": 0.9, + "total": 2.15 + } }, "tests/aws/services/s3/test_s3_api.py::TestS3ObjectCRUD::test_delete_objects_versioned": { - "last_validated_date": "2025-01-21T18:09:40+00:00" + "last_validated_date": "2026-02-23T11:04:22+00:00", + "durations_in_seconds": { + "setup": 1.03, + "call": 1.95, + "teardown": 1.23, + "total": 4.21 + } }, "tests/aws/services/s3/test_s3_api.py::TestS3ObjectCRUD::test_get_object_range": { - "last_validated_date": "2025-07-07T17:50:04+00:00", + "last_validated_date": "2026-02-21T01:02:10+00:00", "durations_in_seconds": { - "setup": 1.13, - "call": 6.21, - "teardown": 0.99, - "total": 8.33 + "setup": 0.51, + "call": 6.12, + "teardown": 0.96, + "total": 7.59 } }, "tests/aws/services/s3/test_s3_api.py::TestS3ObjectCRUD::test_get_object_with_version_unversioned_bucket": { - "last_validated_date": "2025-01-21T18:09:42+00:00" + "last_validated_date": "2026-02-21T01:01:52+00:00", + "durations_in_seconds": { + "setup": 0.53, + "call": 0.79, + "teardown": 0.76, + "total": 2.08 + } }, "tests/aws/services/s3/test_s3_api.py::TestS3ObjectCRUD::test_list_object_versions_order_unversioned": { - "last_validated_date": "2025-01-21T18:09:52+00:00" + "last_validated_date": "2026-02-21T01:02:02+00:00", + "durations_in_seconds": { + "setup": 0.51, + "call": 0.96, + "teardown": 0.96, + "total": 2.43 + } }, "tests/aws/services/s3/test_s3_api.py::TestS3ObjectCRUD::test_put_object_on_suspended_bucket": { - "last_validated_date": "2025-01-21T18:09:46+00:00" + "last_validated_date": "2026-02-21T01:01:57+00:00", + "durations_in_seconds": { + "setup": 0.53, + "call": 2.45, + "teardown": 1.43, + "total": 4.41 + } }, "tests/aws/services/s3/test_s3_api.py::TestS3ObjectLock::test_delete_object_with_no_locking": { - "last_validated_date": "2025-01-21T18:11:45+00:00" + "last_validated_date": "2026-02-21T01:04:11+00:00", + "durations_in_seconds": { + "setup": 0.54, + "call": 1.02, + "teardown": 1.35, + "total": 2.91 + } }, "tests/aws/services/s3/test_s3_api.py::TestS3ObjectLock::test_disable_versioning_on_locked_bucket": { - "last_validated_date": "2025-01-21T18:11:43+00:00" + "last_validated_date": "2026-02-21T01:04:08+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.87, + "teardown": 0.61, + "total": 1.48 + } }, "tests/aws/services/s3/test_s3_api.py::TestS3ObjectLock::test_get_object_lock_configuration_exc": { - "last_validated_date": "2025-01-21T18:11:42+00:00" + "last_validated_date": "2026-02-21T01:04:06+00:00", + "durations_in_seconds": { + "setup": 0.53, + "call": 0.47, + "teardown": 0.61, + "total": 1.61 + } }, "tests/aws/services/s3/test_s3_api.py::TestS3ObjectLock::test_get_put_object_lock_configuration": { - "last_validated_date": "2025-01-21T18:11:37+00:00" + "last_validated_date": "2026-02-21T01:04:01+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 1.25, + "teardown": 0.6, + "total": 1.85 + } }, "tests/aws/services/s3/test_s3_api.py::TestS3ObjectLock::test_put_object_lock_configuration_exc": { - "last_validated_date": "2025-06-20T17:03:25+00:00", + "last_validated_date": "2026-02-21T01:04:05+00:00", "durations_in_seconds": { - "setup": 0.55, - "call": 2.64, - "teardown": 0.83, - "total": 4.02 + "setup": 0.0, + "call": 2.79, + "teardown": 0.88, + "total": 3.67 } }, "tests/aws/services/s3/test_s3_api.py::TestS3ObjectLock::test_put_object_lock_configuration_on_existing_bucket": { - "last_validated_date": "2025-01-21T18:11:36+00:00" + "last_validated_date": "2026-02-21T01:03:59+00:00", + "durations_in_seconds": { + "setup": 0.52, + "call": 1.49, + "teardown": 0.64, + "total": 2.65 + } + }, + "tests/aws/services/s3/test_s3_api.py::TestS3ObjectWritePrecondition::test_copy_object_if_match": { + "last_validated_date": "2026-02-21T01:05:11+00:00", + "durations_in_seconds": { + "setup": 0.53, + "call": 0.81, + "teardown": 1.02, + "total": 2.36 + } + }, + "tests/aws/services/s3/test_s3_api.py::TestS3ObjectWritePrecondition::test_copy_object_if_match_in_place": { + "last_validated_date": "2026-02-21T01:05:24+00:00", + "durations_in_seconds": { + "setup": 0.53, + "call": 0.37, + "teardown": 0.97, + "total": 1.87 + } + }, + "tests/aws/services/s3/test_s3_api.py::TestS3ObjectWritePrecondition::test_copy_object_if_match_versioned_bucket": { + "last_validated_date": "2026-02-21T01:05:18+00:00", + "durations_in_seconds": { + "setup": 0.51, + "call": 1.49, + "teardown": 1.51, + "total": 3.51 + } + }, + "tests/aws/services/s3/test_s3_api.py::TestS3ObjectWritePrecondition::test_copy_object_if_none_match": { + "last_validated_date": "2026-02-21T01:05:09+00:00", + "durations_in_seconds": { + "setup": 0.52, + "call": 0.48, + "teardown": 1.04, + "total": 2.04 + } + }, + "tests/aws/services/s3/test_s3_api.py::TestS3ObjectWritePrecondition::test_copy_object_if_none_match_in_place": { + "last_validated_date": "2026-02-21T01:05:22+00:00", + "durations_in_seconds": { + "setup": 0.51, + "call": 0.33, + "teardown": 1.02, + "total": 1.86 + } + }, + "tests/aws/services/s3/test_s3_api.py::TestS3ObjectWritePrecondition::test_copy_object_if_none_match_versioned_bucket": { + "last_validated_date": "2026-02-21T01:05:14+00:00", + "durations_in_seconds": { + "setup": 0.52, + "call": 1.11, + "teardown": 1.39, + "total": 3.02 + } + }, + "tests/aws/services/s3/test_s3_api.py::TestS3ObjectWritePrecondition::test_copy_object_precondition_write_validation": { + "last_validated_date": "2026-02-21T01:05:21+00:00", + "durations_in_seconds": { + "setup": 0.52, + "call": 1.0, + "teardown": 1.28, + "total": 2.8 + } }, "tests/aws/services/s3/test_s3_api.py::TestS3ObjectWritePrecondition::test_multipart_if_match_etag": { - "last_validated_date": "2025-03-17T20:16:09+00:00" + "last_validated_date": "2026-02-21T01:05:07+00:00", + "durations_in_seconds": { + "setup": 0.54, + "call": 1.49, + "teardown": 1.01, + "total": 3.04 + } }, "tests/aws/services/s3/test_s3_api.py::TestS3ObjectWritePrecondition::test_multipart_if_match_with_delete": { - "last_validated_date": "2025-03-17T20:16:01+00:00" + "last_validated_date": "2026-02-21T01:04:59+00:00", + "durations_in_seconds": { + "setup": 0.58, + "call": 1.37, + "teardown": 1.03, + "total": 2.98 + } }, "tests/aws/services/s3/test_s3_api.py::TestS3ObjectWritePrecondition::test_multipart_if_match_with_put": { - "last_validated_date": "2025-03-17T20:15:55+00:00" + "last_validated_date": "2026-02-21T01:04:52+00:00", + "durations_in_seconds": { + "setup": 0.52, + "call": 1.7, + "teardown": 1.01, + "total": 3.23 + } }, "tests/aws/services/s3/test_s3_api.py::TestS3ObjectWritePrecondition::test_multipart_if_match_with_put_identical": { - "last_validated_date": "2025-03-17T20:15:58+00:00" + "last_validated_date": "2026-02-21T01:04:56+00:00", + "durations_in_seconds": { + "setup": 0.53, + "call": 1.59, + "teardown": 1.02, + "total": 3.14 + } }, "tests/aws/services/s3/test_s3_api.py::TestS3ObjectWritePrecondition::test_multipart_if_none_match_with_delete": { - "last_validated_date": "2025-03-17T20:15:41+00:00" + "last_validated_date": "2026-02-21T01:04:39+00:00", + "durations_in_seconds": { + "setup": 0.5, + "call": 1.49, + "teardown": 0.98, + "total": 2.97 + } }, "tests/aws/services/s3/test_s3_api.py::TestS3ObjectWritePrecondition::test_multipart_if_none_match_with_put": { - "last_validated_date": "2025-03-17T20:15:44+00:00" + "last_validated_date": "2026-02-21T01:04:41+00:00", + "durations_in_seconds": { + "setup": 0.52, + "call": 0.63, + "teardown": 0.99, + "total": 2.14 + } }, "tests/aws/services/s3/test_s3_api.py::TestS3ObjectWritePrecondition::test_put_object_if_match": { - "last_validated_date": "2025-03-17T20:15:50+00:00" + "last_validated_date": "2026-02-21T01:04:47+00:00", + "durations_in_seconds": { + "setup": 0.5, + "call": 1.25, + "teardown": 1.03, + "total": 2.78 + } }, "tests/aws/services/s3/test_s3_api.py::TestS3ObjectWritePrecondition::test_put_object_if_match_and_if_none_match_validation": { - "last_validated_date": "2025-06-12T23:32:49+00:00" + "last_validated_date": "2026-02-21T01:05:04+00:00", + "durations_in_seconds": { + "setup": 0.52, + "call": 0.11, + "teardown": 0.83, + "total": 1.46 + } }, "tests/aws/services/s3/test_s3_api.py::TestS3ObjectWritePrecondition::test_put_object_if_match_validation": { - "last_validated_date": "2025-03-17T20:15:52+00:00" + "last_validated_date": "2026-02-21T01:04:49+00:00", + "durations_in_seconds": { + "setup": 0.52, + "call": 0.89, + "teardown": 0.87, + "total": 2.28 + } }, "tests/aws/services/s3/test_s3_api.py::TestS3ObjectWritePrecondition::test_put_object_if_match_versioned_bucket": { - "last_validated_date": "2025-03-17T20:16:04+00:00" + "last_validated_date": "2026-02-21T01:05:02+00:00", + "durations_in_seconds": { + "setup": 0.55, + "call": 1.76, + "teardown": 1.44, + "total": 3.75 + } }, "tests/aws/services/s3/test_s3_api.py::TestS3ObjectWritePrecondition::test_put_object_if_none_match": { - "last_validated_date": "2025-03-17T20:15:36+00:00" + "last_validated_date": "2026-02-21T01:04:34+00:00", + "durations_in_seconds": { + "setup": 0.53, + "call": 0.72, + "teardown": 1.01, + "total": 2.26 + } }, "tests/aws/services/s3/test_s3_api.py::TestS3ObjectWritePrecondition::test_put_object_if_none_match_validation": { - "last_validated_date": "2025-03-17T20:15:38+00:00" + "last_validated_date": "2026-02-21T01:04:36+00:00", + "durations_in_seconds": { + "setup": 0.53, + "call": 0.24, + "teardown": 1.22, + "total": 1.99 + } }, "tests/aws/services/s3/test_s3_api.py::TestS3ObjectWritePrecondition::test_put_object_if_none_match_versioned_bucket": { - "last_validated_date": "2025-03-17T20:15:46+00:00" + "last_validated_date": "2026-02-21T01:04:44+00:00", + "durations_in_seconds": { + "setup": 0.54, + "call": 1.11, + "teardown": 1.48, + "total": 3.13 + } }, "tests/aws/services/s3/test_s3_api.py::TestS3PublicAccessBlock::test_crud_public_access_block": { - "last_validated_date": "2023-08-10T01:29:18+00:00" + "last_validated_date": "2026-02-21T01:04:20+00:00", + "durations_in_seconds": { + "setup": 0.52, + "call": 0.88, + "teardown": 0.6, + "total": 2.0 + } } } diff --git a/tests/aws/services/s3/test_s3_list_operations.py b/tests/aws/services/s3/test_s3_list_operations.py index f081782c0ecb3..e8f9a27c5e411 100644 --- a/tests/aws/services/s3/test_s3_list_operations.py +++ b/tests/aws/services/s3/test_s3_list_operations.py @@ -5,6 +5,7 @@ import datetime from io import BytesIO +from urllib.parse import quote import pytest import xmltodict @@ -160,6 +161,53 @@ def test_list_buckets_with_continuation_token(self, s3_create_bucket, aws_client snapshot.match("list-objects-with-continuation", response) + @markers.aws.validated + def test_list_buckets_region_validation(self, aws_client, snapshot): + with pytest.raises(ClientError) as e: + aws_client.s3.list_buckets(BucketRegion="eu-east-1") + snapshot.match("bad-region", e.value.response) + + @markers.aws.only_localstack + @markers.requires_in_process + def test_region_validation_non_standard_regions_enabled( + self, snapshot, monkeypatch, aws_client_factory, s3_create_bucket_with_client + ): + monkeypatch.setattr(config, "ALLOW_NONSTANDARD_REGIONS", True) + # we need to patch the `DefaultRegionRewriterStrategy` as it wil replace `eu-east-1` by `us-east-1`, which + # is its default region + from localstack.aws.handlers.region import DefaultRegionRewriterStrategy + + monkeypatch.setattr(DefaultRegionRewriterStrategy, "apply", lambda *_, **__: None) + + bad_region = "eu-east-1" + + # A client created with us-east-1 can create buckets in any region, including the bad region. + client_us_east_1 = aws_client_factory(region_name=AWS_REGION_US_EAST_1).s3 + s3_create_bucket_with_client( + client_us_east_1, + CreateBucketConfiguration={"LocationConstraint": bad_region}, + ) + + # A client created in the bad region should can only create buckets in this region. + client_bad_region = aws_client_factory(region_name=bad_region).s3 + s3_create_bucket_with_client( + client_bad_region, + CreateBucketConfiguration={"LocationConstraint": bad_region}, + ) + with pytest.raises(ClientError) as e: + s3_create_bucket_with_client( + client_bad_region, + CreateBucketConfiguration={"LocationConstraint": AWS_REGION_US_EAST_1}, + ) + assert ( + e.value.response["Error"]["Message"] + == "The us-east-1 location constraint is incompatible for the region specific endpoint this request was sent to." + ) + + list_buckets = client_us_east_1.list_buckets(BucketRegion=bad_region) + for bucket in list_buckets["Buckets"]: + assert bucket["BucketRegion"] == bad_region + class TestS3ListObjects: @markers.aws.validated @@ -430,6 +478,114 @@ def test_list_objects_v2_continuation_common_prefixes(self, s3_bucket, snapshot, snapshot.match("list-objects-v2-end", response) assert "NextContinuationToken" not in response + @markers.aws.validated + def test_list_objects_v2_continuation_token_safe_chars( + self, s3_bucket, snapshot, aws_client_factory + ): + snapshot.add_transformer(snapshot.transform.s3_api()) + # S3 does not have a consistent ContinuationToken, must be based on a paginator + snapshot.add_transformer( + snapshot.transform.key_value("NextContinuationToken", reference_replacement=False) + ) + snapshot.add_transformer( + snapshot.transform.key_value("ContinuationToken", reference_replacement=False) + ) + # we disable validation on the client to be able to set EncodingType to None (only valid value is `url`) + s3_client = aws_client_factory(config=Config(parameter_validation=False)).s3 + keys = [ + "file%2Fname", + "test@key/", + "test%123", + "test%percent", + "test key/", + "test key//", + "test%123/", + "a/%F0%9F%98%80/", + "date=2026-01-01/", + "date=2026-02-01/", + "date=2026-03-01/", + "date=2026-05-01/", + ] + for key in keys: + s3_client.put_object(Bucket=s3_bucket, Key=key) + + response = s3_client.list_objects_v2(Bucket=s3_bucket, MaxKeys=5) + snapshot.match("list-objects-v2-max-5", response) + + continuation_token = response["NextContinuationToken"] + + response = s3_client.list_objects_v2(Bucket=s3_bucket, ContinuationToken=continuation_token) + snapshot.match("list-objects-v2-rest", response) + + start_after = keys[-3] + # forcing the EncodingType to be `None` to verify behavior + response = s3_client.list_objects_v2( + Bucket=s3_bucket, + StartAfter=start_after, + MaxKeys=2, + EncodingType=None, + ) + snapshot.match("list-objects-start-after", response) + + response = s3_client.list_objects_v2( + Bucket=s3_bucket, + StartAfter=start_after, + MaxKeys=2, + EncodingType="url", + ) + snapshot.match("list-objects-start-after-url-type", response) + + url_safe_key = quote(start_after) + response = s3_client.list_objects_v2(Bucket=s3_bucket, StartAfter=url_safe_key, MaxKeys=2) + snapshot.match("list-objects-start-after-encoded", response) + continuation_token_2 = response["NextContinuationToken"] + + response = s3_client.list_objects_v2( + Bucket=s3_bucket, + StartAfter=start_after, + ContinuationToken=continuation_token_2, + MaxKeys=2, + ) + snapshot.match("list-objects-start-after-token", response) + + response = s3_client.list_objects_v2( + Bucket=s3_bucket, + ContinuationToken=continuation_token_2, + MaxKeys=2, + ) + snapshot.match("list-objects-continuation-token-2", response) + + @markers.aws.validated + @pytest.mark.parametrize( + "s3_operation", + ( + "list_objects_v2", + "list_objects", + "list_object_versions", + "list_multipart_uploads", + ), + ) + def test_list_ops_encoding_type_validation( + self, s3_bucket, snapshot, aws_client_factory, s3_operation + ): + # we disable validation on the client to be able to set EncodingType to None (only valid value is `url`) + s3_client = aws_client_factory(config=Config(parameter_validation=False)).s3 + if s3_operation == "list_object_versions": + # to test list_object_versions, we need the bucket to be versioned + s3_client.put_bucket_versioning( + Bucket=s3_bucket, VersioningConfiguration={"Status": "Enabled"} + ) + + client_method = getattr(s3_client, s3_operation) + + with pytest.raises(ClientError) as e: + client_method(Bucket=s3_bucket, EncodingType="value") + snapshot.match(f"{s3_operation}-error-wrong-value", e.value.response) + + with pytest.raises(ClientError) as e: + client_method(Bucket=s3_bucket, EncodingType="") + snapshot.match(f"{s3_operation}-error-empty-value", e.value.response) + class TestS3ListObjectVersions: @markers.aws.validated diff --git a/tests/aws/services/s3/test_s3_list_operations.snapshot.json b/tests/aws/services/s3/test_s3_list_operations.snapshot.json index ab827dee03cff..aebc0f6e7f64e 100644 --- a/tests/aws/services/s3/test_s3_list_operations.snapshot.json +++ b/tests/aws/services/s3/test_s3_list_operations.snapshot.json @@ -1,6 +1,6 @@ { "tests/aws/services/s3/test_s3_list_operations.py::TestS3ListObjects::test_list_objects_with_prefix[]": { - "recorded-date": "21-01-2025, 18:14:22", + "recorded-date": "21-02-2026, 00:05:13", "recorded-content": { "list-objects": { "Contents": [ @@ -13,7 +13,6 @@ "Key": "test/foo/bar/123", "LastModified": "datetime", "Owner": { - "DisplayName": "", "ID": "" }, "Size": 11, @@ -34,7 +33,7 @@ } }, "tests/aws/services/s3/test_s3_list_operations.py::TestS3ListObjects::test_list_objects_with_prefix[/]": { - "recorded-date": "21-01-2025, 18:14:24", + "recorded-date": "21-02-2026, 00:05:14", "recorded-content": { "list-objects": { "CommonPrefixes": [ @@ -57,7 +56,7 @@ } }, "tests/aws/services/s3/test_s3_list_operations.py::TestS3ListObjects::test_list_objects_with_prefix[%2F]": { - "recorded-date": "21-01-2025, 18:14:26", + "recorded-date": "21-02-2026, 00:05:17", "recorded-content": { "list-objects": { "Contents": [ @@ -70,7 +69,6 @@ "Key": "test/foo/bar/123", "LastModified": "datetime", "Owner": { - "DisplayName": "", "ID": "" }, "Size": 11, @@ -105,7 +103,7 @@ } }, "tests/aws/services/s3/test_s3_list_operations.py::TestS3ListObjects::test_list_objects_next_marker": { - "recorded-date": "21-01-2025, 18:14:29", + "recorded-date": "21-02-2026, 00:05:19", "recorded-content": { "list-objects-all": { "Contents": [ @@ -118,7 +116,6 @@ "Key": "", "LastModified": "datetime", "Owner": { - "DisplayName": "", "ID": "" }, "Size": 11, @@ -133,7 +130,6 @@ "Key": "", "LastModified": "datetime", "Owner": { - "DisplayName": "", "ID": "" }, "Size": 11, @@ -148,7 +144,6 @@ "Key": "", "LastModified": "datetime", "Owner": { - "DisplayName": "", "ID": "" }, "Size": 11, @@ -177,7 +172,6 @@ "Key": "", "LastModified": "datetime", "Owner": { - "DisplayName": "", "ID": "" }, "Size": 11, @@ -208,7 +202,6 @@ "Key": "", "LastModified": "datetime", "Owner": { - "DisplayName": "", "ID": "" }, "Size": 11, @@ -237,7 +230,6 @@ "Key": "", "LastModified": "datetime", "Owner": { - "DisplayName": "", "ID": "" }, "Size": 11, @@ -258,7 +250,7 @@ } }, "tests/aws/services/s3/test_s3_list_operations.py::TestS3ListObjects::test_s3_list_objects_empty_marker": { - "recorded-date": "21-01-2025, 18:14:31", + "recorded-date": "21-02-2026, 00:05:21", "recorded-content": { "list-objects": { "EncodingType": "url", @@ -275,7 +267,7 @@ } }, "tests/aws/services/s3/test_s3_list_operations.py::TestS3ListObjectsV2::test_list_objects_v2_with_prefix": { - "recorded-date": "21-01-2025, 18:14:40", + "recorded-date": "21-02-2026, 00:05:31", "recorded-content": { "list-objects-v2-1": { "Contents": [ @@ -428,7 +420,7 @@ } }, "tests/aws/services/s3/test_s3_list_operations.py::TestS3ListObjectsV2::test_list_objects_v2_with_prefix_and_delimiter": { - "recorded-date": "21-01-2025, 18:14:43", + "recorded-date": "21-02-2026, 00:05:33", "recorded-content": { "list-objects-v2-1": { "CommonPrefixes": [ @@ -509,7 +501,7 @@ } }, "tests/aws/services/s3/test_s3_list_operations.py::TestS3ListObjectsV2::test_list_objects_v2_continuation_start_after": { - "recorded-date": "21-01-2025, 18:14:48", + "recorded-date": "21-02-2026, 00:05:38", "recorded-content": { "list-objects-v2-max-5": { "Contents": [ @@ -816,7 +808,7 @@ } }, "tests/aws/services/s3/test_s3_list_operations.py::TestS3ListObjectsV2::test_list_objects_v2_continuation_common_prefixes": { - "recorded-date": "21-01-2025, 18:14:51", + "recorded-date": "21-02-2026, 00:05:41", "recorded-content": { "list-objects-v2-all-keys": { "Contents": [ @@ -953,7 +945,7 @@ } }, "tests/aws/services/s3/test_s3_list_operations.py::TestS3ListObjectVersions::test_list_objects_versions_markers": { - "recorded-date": "21-01-2025, 18:14:56", + "recorded-date": "21-02-2026, 00:05:57", "recorded-content": { "version-order": { "Versions": [ @@ -993,7 +985,6 @@ "Key": "test_0", "LastModified": "datetime", "Owner": { - "DisplayName": "", "ID": "" }, "VersionId": "" @@ -1003,7 +994,6 @@ "Key": "test_1", "LastModified": "datetime", "Owner": { - "DisplayName": "", "ID": "" }, "VersionId": "" @@ -1013,7 +1003,6 @@ "Key": "test_2", "LastModified": "datetime", "Owner": { - "DisplayName": "", "ID": "" }, "VersionId": "" @@ -1037,7 +1026,6 @@ "Key": "test_0", "LastModified": "datetime", "Owner": { - "DisplayName": "", "ID": "" }, "Size": 9, @@ -1054,7 +1042,6 @@ "Key": "test_0", "LastModified": "datetime", "Owner": { - "DisplayName": "", "ID": "" }, "Size": 9, @@ -1071,7 +1058,6 @@ "Key": "test_1", "LastModified": "datetime", "Owner": { - "DisplayName": "", "ID": "" }, "Size": 9, @@ -1088,7 +1074,6 @@ "Key": "test_1", "LastModified": "datetime", "Owner": { - "DisplayName": "", "ID": "" }, "Size": 9, @@ -1105,7 +1090,6 @@ "Key": "test_2", "LastModified": "datetime", "Owner": { - "DisplayName": "", "ID": "" }, "Size": 9, @@ -1122,7 +1106,6 @@ "Key": "test_2", "LastModified": "datetime", "Owner": { - "DisplayName": "", "ID": "" }, "Size": 9, @@ -1142,7 +1125,6 @@ "Key": "test_0", "LastModified": "datetime", "Owner": { - "DisplayName": "", "ID": "" }, "VersionId": "" @@ -1152,7 +1134,6 @@ "Key": "test_1", "LastModified": "datetime", "Owner": { - "DisplayName": "", "ID": "" }, "VersionId": "" @@ -1178,7 +1159,6 @@ "Key": "test_0", "LastModified": "datetime", "Owner": { - "DisplayName": "", "ID": "" }, "Size": 9, @@ -1195,7 +1175,6 @@ "Key": "test_0", "LastModified": "datetime", "Owner": { - "DisplayName": "", "ID": "" }, "Size": 9, @@ -1212,7 +1191,6 @@ "Key": "test_1", "LastModified": "datetime", "Owner": { - "DisplayName": "", "ID": "" }, "Size": 9, @@ -1232,7 +1210,6 @@ "Key": "test_2", "LastModified": "datetime", "Owner": { - "DisplayName": "", "ID": "" }, "VersionId": "" @@ -1298,7 +1275,6 @@ "Key": "test_1", "LastModified": "datetime", "Owner": { - "DisplayName": "", "ID": "" }, "Size": 9, @@ -1330,7 +1306,6 @@ "Key": "test_2", "LastModified": "datetime", "Owner": { - "DisplayName": "", "ID": "" }, "Size": 9, @@ -1364,7 +1339,6 @@ "Key": "test_0", "LastModified": "datetime", "Owner": { - "DisplayName": "", "ID": "" }, "Size": 9, @@ -1380,7 +1354,7 @@ } }, "tests/aws/services/s3/test_s3_list_operations.py::TestS3ListObjectVersions::test_list_object_versions_pagination_common_prefixes": { - "recorded-date": "21-01-2025, 18:14:59", + "recorded-date": "21-02-2026, 00:06:01", "recorded-content": { "list-object-versions-all-keys": { "EncodingType": "url", @@ -1401,7 +1375,6 @@ "Key": "folder/aSubfolder/subFile1", "LastModified": "datetime", "Owner": { - "DisplayName": "", "ID": "" }, "Size": 11, @@ -1418,7 +1391,6 @@ "Key": "folder/aSubfolder/subFile2", "LastModified": "datetime", "Owner": { - "DisplayName": "", "ID": "" }, "Size": 11, @@ -1435,7 +1407,6 @@ "Key": "folder/file1", "LastModified": "datetime", "Owner": { - "DisplayName": "", "ID": "" }, "Size": 11, @@ -1452,7 +1423,6 @@ "Key": "folder/file2", "LastModified": "datetime", "Owner": { - "DisplayName": "", "ID": "" }, "Size": 11, @@ -1507,7 +1477,6 @@ "Key": "folder/file1", "LastModified": "datetime", "Owner": { - "DisplayName": "", "ID": "" }, "Size": 11, @@ -1540,7 +1509,6 @@ "Key": "folder/file2", "LastModified": "datetime", "Owner": { - "DisplayName": "", "ID": "" }, "Size": 11, @@ -1575,7 +1543,6 @@ "Key": "folder/file1", "LastModified": "datetime", "Owner": { - "DisplayName": "", "ID": "" }, "Size": 11, @@ -1591,7 +1558,7 @@ } }, "tests/aws/services/s3/test_s3_list_operations.py::TestS3ListObjectVersions::test_list_objects_versions_with_prefix": { - "recorded-date": "21-01-2025, 18:15:03", + "recorded-date": "21-02-2026, 00:06:05", "recorded-content": { "list-object-version-1": { "CommonPrefixes": [ @@ -1618,7 +1585,6 @@ "Key": "dir/test", "LastModified": "datetime", "Owner": { - "DisplayName": "", "ID": "" }, "Size": 15, @@ -1635,7 +1601,6 @@ "Key": "dir/test", "LastModified": "datetime", "Owner": { - "DisplayName": "", "ID": "" }, "Size": 15, @@ -1687,7 +1652,6 @@ "Key": "dir/test", "LastModified": "datetime", "Owner": { - "DisplayName": "", "ID": "" }, "Size": 15, @@ -1704,7 +1668,6 @@ "Key": "dir/test", "LastModified": "datetime", "Owner": { - "DisplayName": "", "ID": "" }, "Size": 15, @@ -1756,7 +1719,6 @@ "Key": "dir/subdir/test2", "LastModified": "datetime", "Owner": { - "DisplayName": "", "ID": "" }, "Size": 15, @@ -1773,7 +1735,6 @@ "Key": "dir/subdir/test2", "LastModified": "datetime", "Owner": { - "DisplayName": "", "ID": "" }, "Size": 15, @@ -1806,7 +1767,6 @@ "Key": "dir/subdir/test2", "LastModified": "datetime", "Owner": { - "DisplayName": "", "ID": "" }, "Size": 15, @@ -1823,7 +1783,6 @@ "Key": "dir/subdir/test2", "LastModified": "datetime", "Owner": { - "DisplayName": "", "ID": "" }, "Size": 15, @@ -1853,7 +1812,7 @@ } }, "tests/aws/services/s3/test_s3_list_operations.py::TestS3ListMultipartUploads::test_list_multiparts_next_marker": { - "recorded-date": "21-01-2025, 18:15:10", + "recorded-date": "21-02-2026, 00:06:32", "recorded-content": { "list-multiparts-empty": { "Bucket": "", @@ -1904,7 +1863,6 @@ }, "Key": "", "Owner": { - "DisplayName": "display-name", "ID": "owner-id" }, "StorageClass": "STANDARD", @@ -1918,7 +1876,6 @@ }, "Key": "", "Owner": { - "DisplayName": "display-name", "ID": "owner-id" }, "StorageClass": "STANDARD", @@ -1932,7 +1889,6 @@ }, "Key": "", "Owner": { - "DisplayName": "display-name", "ID": "owner-id" }, "StorageClass": "STANDARD", @@ -1946,7 +1902,6 @@ }, "Key": "", "Owner": { - "DisplayName": "display-name", "ID": "owner-id" }, "StorageClass": "STANDARD", @@ -1960,7 +1915,6 @@ }, "Key": "", "Owner": { - "DisplayName": "display-name", "ID": "owner-id" }, "StorageClass": "STANDARD", @@ -1989,7 +1943,6 @@ }, "Key": "", "Owner": { - "DisplayName": "display-name", "ID": "owner-id" }, "StorageClass": "STANDARD", @@ -2018,7 +1971,6 @@ }, "Key": "", "Owner": { - "DisplayName": "display-name", "ID": "owner-id" }, "StorageClass": "STANDARD", @@ -2060,7 +2012,6 @@ }, "Key": "", "Owner": { - "DisplayName": "display-name", "ID": "owner-id" }, "StorageClass": "STANDARD", @@ -2089,7 +2040,6 @@ }, "Key": "", "Owner": { - "DisplayName": "display-name", "ID": "owner-id" }, "StorageClass": "STANDARD", @@ -2118,7 +2068,6 @@ }, "Key": "", "Owner": { - "DisplayName": "display-name", "ID": "owner-id" }, "StorageClass": "STANDARD", @@ -2147,7 +2096,6 @@ }, "Key": "", "Owner": { - "DisplayName": "display-name", "ID": "owner-id" }, "StorageClass": "STANDARD", @@ -2188,7 +2136,6 @@ }, "Key": "", "Owner": { - "DisplayName": "display-name", "ID": "owner-id" }, "StorageClass": "STANDARD", @@ -2203,7 +2150,7 @@ } }, "tests/aws/services/s3/test_s3_list_operations.py::TestS3ListMultipartUploads::test_list_multiparts_with_prefix_and_delimiter": { - "recorded-date": "21-01-2025, 18:15:12", + "recorded-date": "21-02-2026, 00:06:34", "recorded-content": { "list-multiparts-1": { "Bucket": "", @@ -2289,7 +2236,6 @@ }, "Key": "", "Owner": { - "DisplayName": "display-name", "ID": "owner-id" }, "StorageClass": "STANDARD", @@ -2303,7 +2249,6 @@ }, "Key": "", "Owner": { - "DisplayName": "display-name", "ID": "owner-id" }, "StorageClass": "STANDARD", @@ -2316,7 +2261,7 @@ } }, "tests/aws/services/s3/test_s3_list_operations.py::TestS3ListParts::test_list_parts_pagination": { - "recorded-date": "21-01-2025, 18:15:18", + "recorded-date": "21-02-2026, 00:06:40", "recorded-content": { "list-parts-empty": { "Bucket": "bucket", @@ -2329,7 +2274,6 @@ "MaxParts": 1000, "NextPartNumberMarker": 0, "Owner": { - "DisplayName": "display-name", "ID": "i-d" }, "PartNumberMarker": 0, @@ -2351,7 +2295,6 @@ "MaxParts": 1000, "NextPartNumberMarker": 2, "Owner": { - "DisplayName": "display-name", "ID": "i-d" }, "PartNumberMarker": 0, @@ -2387,7 +2330,6 @@ "MaxParts": 1, "NextPartNumberMarker": 1, "Owner": { - "DisplayName": "display-name", "ID": "i-d" }, "PartNumberMarker": 0, @@ -2417,7 +2359,6 @@ "MaxParts": 1, "NextPartNumberMarker": 2, "Owner": { - "DisplayName": "display-name", "ID": "i-d" }, "PartNumberMarker": 1, @@ -2447,7 +2388,6 @@ "MaxParts": 1, "NextPartNumberMarker": 0, "Owner": { - "DisplayName": "display-name", "ID": "i-d" }, "PartNumberMarker": 10, @@ -2461,7 +2401,7 @@ } }, "tests/aws/services/s3/test_s3_list_operations.py::TestS3ListObjects::test_list_objects_marker_common_prefixes": { - "recorded-date": "21-01-2025, 18:14:33", + "recorded-date": "21-02-2026, 00:05:24", "recorded-content": { "list-objects-all-keys": { "Contents": [ @@ -2474,7 +2414,6 @@ "Key": "folder/aSubfolder/subFile1", "LastModified": "datetime", "Owner": { - "DisplayName": "", "ID": "" }, "Size": 11, @@ -2489,7 +2428,6 @@ "Key": "folder/aSubfolder/subFile2", "LastModified": "datetime", "Owner": { - "DisplayName": "", "ID": "" }, "Size": 11, @@ -2504,7 +2442,6 @@ "Key": "folder/file1", "LastModified": "datetime", "Owner": { - "DisplayName": "", "ID": "" }, "Size": 11, @@ -2519,7 +2456,6 @@ "Key": "folder/file2", "LastModified": "datetime", "Owner": { - "DisplayName": "", "ID": "" }, "Size": 11, @@ -2567,7 +2503,6 @@ "Key": "folder/file1", "LastModified": "datetime", "Owner": { - "DisplayName": "", "ID": "" }, "Size": 11, @@ -2598,7 +2533,6 @@ "Key": "folder/file2", "LastModified": "datetime", "Owner": { - "DisplayName": "", "ID": "" }, "Size": 11, @@ -2628,7 +2562,6 @@ "Key": "folder/file1", "LastModified": "datetime", "Owner": { - "DisplayName": "", "ID": "" }, "Size": 11, @@ -2651,7 +2584,7 @@ } }, "tests/aws/services/s3/test_s3_list_operations.py::TestS3ListMultipartUploads::test_list_multipart_uploads_marker_common_prefixes": { - "recorded-date": "21-01-2025, 18:15:14", + "recorded-date": "21-02-2026, 00:06:36", "recorded-content": { "list-multiparts-start": { "Bucket": "", @@ -2692,7 +2625,6 @@ }, "Key": "folder/file1", "Owner": { - "DisplayName": "display-name", "ID": "owner-id" }, "StorageClass": "STANDARD", @@ -2723,7 +2655,6 @@ }, "Key": "folder/file1", "Owner": { - "DisplayName": "display-name", "ID": "owner-id" }, "StorageClass": "STANDARD", @@ -2738,7 +2669,7 @@ } }, "tests/aws/services/s3/test_s3_list_operations.py::TestS3ListParts::test_list_parts_empty_part_number_marker": { - "recorded-date": "21-01-2025, 18:15:20", + "recorded-date": "21-02-2026, 00:06:42", "recorded-content": { "list-parts-empty-marker": { "Bucket": "bucket", @@ -2751,7 +2682,6 @@ "MaxParts": 1000, "NextPartNumberMarker": 1, "Owner": { - "DisplayName": "display-name", "ID": "i-d" }, "PartNumberMarker": 0, @@ -2781,7 +2711,6 @@ "MaxParts": 1000, "NextPartNumberMarker": 1, "Owner": { - "DisplayName": "display-name", "ID": "i-d" }, "PartNumberMarker": 0, @@ -2803,7 +2732,7 @@ } }, "tests/aws/services/s3/test_s3_list_operations.py::TestS3ListObjectVersions::test_list_objects_versions_with_prefix_only_and_pagination": { - "recorded-date": "13-02-2025, 03:52:21", + "recorded-date": "21-02-2026, 00:06:10", "recorded-content": { "list-object-version-prefix-full": { "EncodingType": "url", @@ -2824,7 +2753,6 @@ "Key": "prefixed_key", "LastModified": "datetime", "Owner": { - "DisplayName": "", "ID": "" }, "Size": 0, @@ -2841,7 +2769,6 @@ "Key": "prefixed_key", "LastModified": "datetime", "Owner": { - "DisplayName": "", "ID": "" }, "Size": 0, @@ -2858,7 +2785,6 @@ "Key": "prefixed_key", "LastModified": "datetime", "Owner": { - "DisplayName": "", "ID": "" }, "Size": 0, @@ -2875,7 +2801,6 @@ "Key": "prefixed_key", "LastModified": "datetime", "Owner": { - "DisplayName": "", "ID": "" }, "Size": 0, @@ -2892,7 +2817,6 @@ "Key": "prefixed_key", "LastModified": "datetime", "Owner": { - "DisplayName": "", "ID": "" }, "Size": 0, @@ -2926,7 +2850,6 @@ "Key": "prefixed_key", "LastModified": "datetime", "Owner": { - "DisplayName": "", "ID": "" }, "Size": 0, @@ -2943,7 +2866,6 @@ "Key": "prefixed_key", "LastModified": "datetime", "Owner": { - "DisplayName": "", "ID": "" }, "Size": 0, @@ -2960,7 +2882,6 @@ "Key": "prefixed_key", "LastModified": "datetime", "Owner": { - "DisplayName": "", "ID": "" }, "Size": 0, @@ -3005,7 +2926,6 @@ "Key": "prefixed_key", "LastModified": "datetime", "Owner": { - "DisplayName": "", "ID": "" }, "Size": 0, @@ -3022,7 +2942,6 @@ "Key": "prefixed_key", "LastModified": "datetime", "Owner": { - "DisplayName": "", "ID": "" }, "Size": 0, @@ -3054,7 +2973,6 @@ "Key": "prefixed_key", "LastModified": "datetime", "Owner": { - "DisplayName": "", "ID": "" }, "Size": 0, @@ -3071,7 +2989,6 @@ "Key": "prefixed_key", "LastModified": "datetime", "Owner": { - "DisplayName": "", "ID": "" }, "Size": 0, @@ -3087,11 +3004,12 @@ } }, "tests/aws/services/s3/test_s3_list_operations.py::TestS3ListBuckets::test_list_buckets_with_max_buckets": { - "recorded-date": "14-05-2025, 09:10:49", + "recorded-date": "21-02-2026, 00:04:59", "recorded-content": { "list-objects-with-max-buckets": { "Buckets": [ { + "BucketArn": "arn::s3:::", "BucketRegion": "", "CreationDate": "datetime", "Name": "" @@ -3099,7 +3017,6 @@ ], "ContinuationToken": "", "Owner": { - "DisplayName": "", "ID": "" }, "ResponseMetadata": { @@ -3110,11 +3027,12 @@ } }, "tests/aws/services/s3/test_s3_list_operations.py::TestS3ListBuckets::test_list_buckets_with_continuation_token": { - "recorded-date": "14-05-2025, 09:10:59", + "recorded-date": "21-02-2026, 00:05:10", "recorded-content": { "list-objects-with-continuation": { "Buckets": [ { + "BucketArn": "arn::s3:::", "BucketRegion": "", "CreationDate": "datetime", "Name": "" @@ -3122,7 +3040,6 @@ ], "ContinuationToken": "", "Owner": { - "DisplayName": "", "ID": "" }, "ResponseMetadata": { @@ -3133,11 +3050,12 @@ } }, "tests/aws/services/s3/test_s3_list_operations.py::TestS3ListBuckets::test_list_buckets_when_continuation_token_is_empty": { - "recorded-date": "14-05-2025, 09:10:50", + "recorded-date": "21-02-2026, 00:05:02", "recorded-content": { "list-objects-with-empty-continuation-token": { "Buckets": [ { + "BucketArn": "arn::s3:::", "BucketRegion": "", "CreationDate": "datetime", "Name": "" @@ -3145,7 +3063,6 @@ ], "ContinuationToken": "", "Owner": { - "DisplayName": "", "ID": "" }, "ResponseMetadata": { @@ -3156,12 +3073,11 @@ } }, "tests/aws/services/s3/test_s3_list_operations.py::TestS3ListBuckets::test_list_buckets_by_prefix_with_case_sensitivity": { - "recorded-date": "14-05-2025, 09:10:46", + "recorded-date": "21-02-2026, 00:04:57", "recorded-content": { "list-objects-by-prefix-empty": { "Buckets": [], "Owner": { - "DisplayName": "", "ID": "" }, "Prefix": "", @@ -3173,13 +3089,13 @@ "list-objects-by-prefix-not-empty": { "Buckets": [ { + "BucketArn": "arn::s3:::", "BucketRegion": "", "CreationDate": "datetime", "Name": "" } ], "Owner": { - "DisplayName": "", "ID": "" }, "Prefix": "", @@ -3191,7 +3107,7 @@ } }, "tests/aws/services/s3/test_s3_list_operations.py::TestS3ListBuckets::test_list_buckets_by_bucket_region": { - "recorded-date": "14-05-2025, 09:10:54", + "recorded-date": "21-02-2026, 00:05:05", "recorded-content": { "list-objects-by-bucket-region-empty": { "Buckets": [], @@ -3207,13 +3123,13 @@ "list-objects-by-bucket-region-not-empty": { "Buckets": [ { + "BucketArn": "arn::s3:::", "BucketRegion": "", "CreationDate": "datetime", "Name": "" } ], "Owner": { - "DisplayName": "", "ID": "" }, "Prefix": "", @@ -3225,7 +3141,7 @@ } }, "tests/aws/services/s3/test_s3_list_operations.py::TestS3ListParts::test_list_parts_via_object_attrs_pagination": { - "recorded-date": "16-06-2025, 13:47:27", + "recorded-date": "21-02-2026, 00:06:47", "recorded-content": { "list-parts": { "Bucket": "bucket", @@ -3240,7 +3156,6 @@ "MaxParts": 1000, "NextPartNumberMarker": 2, "Owner": { - "DisplayName": "display-name", "ID": "i-d" }, "PartNumberMarker": 0, @@ -3368,5 +3283,493 @@ } } } + }, + "tests/aws/services/s3/test_s3_list_operations.py::TestS3ListBuckets::test_list_buckets_region_validation": { + "recorded-date": "21-02-2026, 00:05:12", + "recorded-content": { + "bad-region": { + "Error": { + "ArgumentName": "bucket-region", + "Code": "InvalidArgument", + "Message": "Argument value eu-east-1 is not a valid AWS Region" + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + } + } + }, + "tests/aws/services/s3/test_s3_list_operations.py::TestS3ListObjectsV2::test_list_objects_v2_continuation_token_safe_chars": { + "recorded-date": "21-02-2026, 00:05:45", + "recorded-content": { + "list-objects-v2-max-5": { + "Contents": [ + { + "ChecksumAlgorithm": [ + "CRC32" + ], + "ChecksumType": "FULL_OBJECT", + "ETag": "\"d41d8cd98f00b204e9800998ecf8427e\"", + "Key": "a/%F0%9F%98%80/", + "LastModified": "datetime", + "Size": 0, + "StorageClass": "STANDARD" + }, + { + "ChecksumAlgorithm": [ + "CRC32" + ], + "ChecksumType": "FULL_OBJECT", + "ETag": "\"d41d8cd98f00b204e9800998ecf8427e\"", + "Key": "date=2026-01-01/", + "LastModified": "datetime", + "Size": 0, + "StorageClass": "STANDARD" + }, + { + "ChecksumAlgorithm": [ + "CRC32" + ], + "ChecksumType": "FULL_OBJECT", + "ETag": "\"d41d8cd98f00b204e9800998ecf8427e\"", + "Key": "date=2026-02-01/", + "LastModified": "datetime", + "Size": 0, + "StorageClass": "STANDARD" + }, + { + "ChecksumAlgorithm": [ + "CRC32" + ], + "ChecksumType": "FULL_OBJECT", + "ETag": "\"d41d8cd98f00b204e9800998ecf8427e\"", + "Key": "date=2026-03-01/", + "LastModified": "datetime", + "Size": 0, + "StorageClass": "STANDARD" + }, + { + "ChecksumAlgorithm": [ + "CRC32" + ], + "ChecksumType": "FULL_OBJECT", + "ETag": "\"d41d8cd98f00b204e9800998ecf8427e\"", + "Key": "date=2026-05-01/", + "LastModified": "datetime", + "Size": 0, + "StorageClass": "STANDARD" + } + ], + "EncodingType": "url", + "IsTruncated": true, + "KeyCount": 5, + "MaxKeys": 5, + "Name": "", + "NextContinuationToken": "next-continuation-token", + "Prefix": "", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "list-objects-v2-rest": { + "Contents": [ + { + "ChecksumAlgorithm": [ + "CRC32" + ], + "ChecksumType": "FULL_OBJECT", + "ETag": "\"d41d8cd98f00b204e9800998ecf8427e\"", + "Key": "file%2Fname", + "LastModified": "datetime", + "Size": 0, + "StorageClass": "STANDARD" + }, + { + "ChecksumAlgorithm": [ + "CRC32" + ], + "ChecksumType": "FULL_OBJECT", + "ETag": "\"d41d8cd98f00b204e9800998ecf8427e\"", + "Key": "test key/", + "LastModified": "datetime", + "Size": 0, + "StorageClass": "STANDARD" + }, + { + "ChecksumAlgorithm": [ + "CRC32" + ], + "ChecksumType": "FULL_OBJECT", + "ETag": "\"d41d8cd98f00b204e9800998ecf8427e\"", + "Key": "test key//", + "LastModified": "datetime", + "Size": 0, + "StorageClass": "STANDARD" + }, + { + "ChecksumAlgorithm": [ + "CRC32" + ], + "ChecksumType": "FULL_OBJECT", + "ETag": "\"d41d8cd98f00b204e9800998ecf8427e\"", + "Key": "test%123", + "LastModified": "datetime", + "Size": 0, + "StorageClass": "STANDARD" + }, + { + "ChecksumAlgorithm": [ + "CRC32" + ], + "ChecksumType": "FULL_OBJECT", + "ETag": "\"d41d8cd98f00b204e9800998ecf8427e\"", + "Key": "test%123/", + "LastModified": "datetime", + "Size": 0, + "StorageClass": "STANDARD" + }, + { + "ChecksumAlgorithm": [ + "CRC32" + ], + "ChecksumType": "FULL_OBJECT", + "ETag": "\"d41d8cd98f00b204e9800998ecf8427e\"", + "Key": "test%percent", + "LastModified": "datetime", + "Size": 0, + "StorageClass": "STANDARD" + }, + { + "ChecksumAlgorithm": [ + "CRC32" + ], + "ChecksumType": "FULL_OBJECT", + "ETag": "\"d41d8cd98f00b204e9800998ecf8427e\"", + "Key": "test@key/", + "LastModified": "datetime", + "Size": 0, + "StorageClass": "STANDARD" + } + ], + "ContinuationToken": "continuation-token", + "EncodingType": "url", + "IsTruncated": false, + "KeyCount": 7, + "MaxKeys": 1000, + "Name": "", + "Prefix": "", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "list-objects-start-after": { + "Contents": [ + { + "ChecksumAlgorithm": [ + "CRC32" + ], + "ChecksumType": "FULL_OBJECT", + "ETag": "\"d41d8cd98f00b204e9800998ecf8427e\"", + "Key": "date=2026-03-01/", + "LastModified": "datetime", + "Size": 0, + "StorageClass": "STANDARD" + }, + { + "ChecksumAlgorithm": [ + "CRC32" + ], + "ChecksumType": "FULL_OBJECT", + "ETag": "\"d41d8cd98f00b204e9800998ecf8427e\"", + "Key": "date=2026-05-01/", + "LastModified": "datetime", + "Size": 0, + "StorageClass": "STANDARD" + } + ], + "IsTruncated": true, + "KeyCount": 2, + "MaxKeys": 2, + "Name": "", + "NextContinuationToken": "next-continuation-token", + "Prefix": "", + "StartAfter": "date=2026-02-01/", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "list-objects-start-after-url-type": { + "Contents": [ + { + "ChecksumAlgorithm": [ + "CRC32" + ], + "ChecksumType": "FULL_OBJECT", + "ETag": "\"d41d8cd98f00b204e9800998ecf8427e\"", + "Key": "date%3D2026-03-01/", + "LastModified": "datetime", + "Size": 0, + "StorageClass": "STANDARD" + }, + { + "ChecksumAlgorithm": [ + "CRC32" + ], + "ChecksumType": "FULL_OBJECT", + "ETag": "\"d41d8cd98f00b204e9800998ecf8427e\"", + "Key": "date%3D2026-05-01/", + "LastModified": "datetime", + "Size": 0, + "StorageClass": "STANDARD" + } + ], + "EncodingType": "url", + "IsTruncated": true, + "KeyCount": 2, + "MaxKeys": 2, + "Name": "", + "NextContinuationToken": "next-continuation-token", + "Prefix": "", + "StartAfter": "date%3D2026-02-01/", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "list-objects-start-after-encoded": { + "Contents": [ + { + "ChecksumAlgorithm": [ + "CRC32" + ], + "ChecksumType": "FULL_OBJECT", + "ETag": "\"d41d8cd98f00b204e9800998ecf8427e\"", + "Key": "date=2026-01-01/", + "LastModified": "datetime", + "Size": 0, + "StorageClass": "STANDARD" + }, + { + "ChecksumAlgorithm": [ + "CRC32" + ], + "ChecksumType": "FULL_OBJECT", + "ETag": "\"d41d8cd98f00b204e9800998ecf8427e\"", + "Key": "date=2026-02-01/", + "LastModified": "datetime", + "Size": 0, + "StorageClass": "STANDARD" + } + ], + "EncodingType": "url", + "IsTruncated": true, + "KeyCount": 2, + "MaxKeys": 2, + "Name": "", + "NextContinuationToken": "next-continuation-token", + "Prefix": "", + "StartAfter": "date%3D2026-02-01/", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "list-objects-start-after-token": { + "Contents": [ + { + "ChecksumAlgorithm": [ + "CRC32" + ], + "ChecksumType": "FULL_OBJECT", + "ETag": "\"d41d8cd98f00b204e9800998ecf8427e\"", + "Key": "date=2026-03-01/", + "LastModified": "datetime", + "Size": 0, + "StorageClass": "STANDARD" + }, + { + "ChecksumAlgorithm": [ + "CRC32" + ], + "ChecksumType": "FULL_OBJECT", + "ETag": "\"d41d8cd98f00b204e9800998ecf8427e\"", + "Key": "date=2026-05-01/", + "LastModified": "datetime", + "Size": 0, + "StorageClass": "STANDARD" + } + ], + "ContinuationToken": "continuation-token", + "EncodingType": "url", + "IsTruncated": true, + "KeyCount": 2, + "MaxKeys": 2, + "Name": "", + "NextContinuationToken": "next-continuation-token", + "Prefix": "", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "list-objects-continuation-token-2": { + "Contents": [ + { + "ChecksumAlgorithm": [ + "CRC32" + ], + "ChecksumType": "FULL_OBJECT", + "ETag": "\"d41d8cd98f00b204e9800998ecf8427e\"", + "Key": "date=2026-03-01/", + "LastModified": "datetime", + "Size": 0, + "StorageClass": "STANDARD" + }, + { + "ChecksumAlgorithm": [ + "CRC32" + ], + "ChecksumType": "FULL_OBJECT", + "ETag": "\"d41d8cd98f00b204e9800998ecf8427e\"", + "Key": "date=2026-05-01/", + "LastModified": "datetime", + "Size": 0, + "StorageClass": "STANDARD" + } + ], + "ContinuationToken": "continuation-token", + "EncodingType": "url", + "IsTruncated": true, + "KeyCount": 2, + "MaxKeys": 2, + "Name": "", + "NextContinuationToken": "next-continuation-token", + "Prefix": "", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/s3/test_s3_list_operations.py::TestS3ListObjectsV2::test_list_ops_encoding_type_validation[list_objects_v2]": { + "recorded-date": "21-02-2026, 00:05:47", + "recorded-content": { + "list_objects_v2-error-wrong-value": { + "Error": { + "ArgumentName": "encoding-type", + "ArgumentValue": "value", + "Code": "InvalidArgument", + "Message": "Invalid Encoding Method specified in Request" + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + }, + "list_objects_v2-error-empty-value": { + "Error": { + "ArgumentName": "encoding-type", + "ArgumentValue": null, + "Code": "InvalidArgument", + "Message": "Invalid Encoding Method specified in Request" + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + } + } + }, + "tests/aws/services/s3/test_s3_list_operations.py::TestS3ListObjectsV2::test_list_ops_encoding_type_validation[list_objects]": { + "recorded-date": "21-02-2026, 00:05:49", + "recorded-content": { + "list_objects-error-wrong-value": { + "Error": { + "ArgumentName": "encoding-type", + "ArgumentValue": "value", + "Code": "InvalidArgument", + "Message": "Invalid Encoding Method specified in Request" + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + }, + "list_objects-error-empty-value": { + "Error": { + "ArgumentName": "encoding-type", + "ArgumentValue": null, + "Code": "InvalidArgument", + "Message": "Invalid Encoding Method specified in Request" + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + } + } + }, + "tests/aws/services/s3/test_s3_list_operations.py::TestS3ListObjectsV2::test_list_ops_encoding_type_validation[list_object_versions]": { + "recorded-date": "21-02-2026, 00:05:51", + "recorded-content": { + "list_object_versions-error-wrong-value": { + "Error": { + "ArgumentName": "encoding-type", + "ArgumentValue": "value", + "Code": "InvalidArgument", + "Message": "Invalid Encoding Method specified in Request" + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + }, + "list_object_versions-error-empty-value": { + "Error": { + "ArgumentName": "encoding-type", + "ArgumentValue": null, + "Code": "InvalidArgument", + "Message": "Invalid Encoding Method specified in Request" + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + } + } + }, + "tests/aws/services/s3/test_s3_list_operations.py::TestS3ListObjectsV2::test_list_ops_encoding_type_validation[list_multipart_uploads]": { + "recorded-date": "21-02-2026, 00:05:53", + "recorded-content": { + "list_multipart_uploads-error-wrong-value": { + "Error": { + "ArgumentName": "encoding-type", + "ArgumentValue": "value", + "Code": "InvalidArgument", + "Message": "Invalid Encoding Method specified in Request" + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + }, + "list_multipart_uploads-error-empty-value": { + "Error": { + "ArgumentName": "encoding-type", + "ArgumentValue": null, + "Code": "InvalidArgument", + "Message": "Invalid Encoding Method specified in Request" + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + } + } } } diff --git a/tests/aws/services/s3/test_s3_list_operations.validation.json b/tests/aws/services/s3/test_s3_list_operations.validation.json index 127660f3efd56..4805d1aed2925 100644 --- a/tests/aws/services/s3/test_s3_list_operations.validation.json +++ b/tests/aws/services/s3/test_s3_list_operations.validation.json @@ -1,101 +1,335 @@ { "tests/aws/services/s3/test_s3_list_operations.py::TestS3ListBuckets::test_list_buckets_by_bucket_region": { - "last_validated_date": "2025-05-14T09:11:19+00:00" + "last_validated_date": "2026-02-21T00:05:08+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 2.53, + "teardown": 2.28, + "total": 4.81 + } }, "tests/aws/services/s3/test_s3_list_operations.py::TestS3ListBuckets::test_list_buckets_by_prefix_with_case_sensitivity": { - "last_validated_date": "2025-05-14T09:11:11+00:00" + "last_validated_date": "2026-02-21T00:04:58+00:00", + "durations_in_seconds": { + "setup": 0.49, + "call": 1.65, + "teardown": 1.18, + "total": 3.32 + } + }, + "tests/aws/services/s3/test_s3_list_operations.py::TestS3ListBuckets::test_list_buckets_region_validation": { + "last_validated_date": "2026-02-21T00:05:12+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.1, + "teardown": 0.0, + "total": 0.1 + } }, "tests/aws/services/s3/test_s3_list_operations.py::TestS3ListBuckets::test_list_buckets_when_continuation_token_is_empty": { - "last_validated_date": "2025-05-14T09:11:17+00:00" + "last_validated_date": "2026-02-21T00:05:03+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 1.24, + "teardown": 1.17, + "total": 2.41 + } }, "tests/aws/services/s3/test_s3_list_operations.py::TestS3ListBuckets::test_list_buckets_with_continuation_token": { - "last_validated_date": "2025-05-14T09:11:24+00:00" + "last_validated_date": "2026-02-21T00:05:11+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 2.1, + "teardown": 1.74, + "total": 3.84 + } }, "tests/aws/services/s3/test_s3_list_operations.py::TestS3ListBuckets::test_list_buckets_with_max_buckets": { - "last_validated_date": "2025-05-14T09:11:14+00:00" + "last_validated_date": "2026-02-21T00:05:00+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 1.31, + "teardown": 1.16, + "total": 2.47 + } }, "tests/aws/services/s3/test_s3_list_operations.py::TestS3ListMultipartUploads::test_list_multipart_uploads_marker_common_prefixes": { - "last_validated_date": "2025-01-21T18:15:14+00:00" + "last_validated_date": "2026-02-21T00:06:37+00:00", + "durations_in_seconds": { + "setup": 0.5, + "call": 0.93, + "teardown": 0.59, + "total": 2.02 + } }, "tests/aws/services/s3/test_s3_list_operations.py::TestS3ListMultipartUploads::test_list_multiparts_next_marker": { - "last_validated_date": "2025-01-21T18:15:10+00:00" + "last_validated_date": "2026-02-21T00:06:32+00:00", + "durations_in_seconds": { + "setup": 0.51, + "call": 2.19, + "teardown": 0.59, + "total": 3.29 + } }, "tests/aws/services/s3/test_s3_list_operations.py::TestS3ListMultipartUploads::test_list_multiparts_with_prefix_and_delimiter": { - "last_validated_date": "2025-01-21T18:15:12+00:00" + "last_validated_date": "2026-02-21T00:06:35+00:00", + "durations_in_seconds": { + "setup": 0.5, + "call": 1.24, + "teardown": 0.6, + "total": 2.34 + } }, "tests/aws/services/s3/test_s3_list_operations.py::TestS3ListMultipartUploads::test_s3_list_multiparts_timestamp_precision": { - "last_validated_date": "2025-01-21T18:15:16+00:00" + "last_validated_date": "2026-02-21T00:06:38+00:00", + "durations_in_seconds": { + "setup": 0.51, + "call": 0.47, + "teardown": 0.58, + "total": 1.56 + } }, "tests/aws/services/s3/test_s3_list_operations.py::TestS3ListObjectVersions::test_list_object_versions_pagination_common_prefixes": { - "last_validated_date": "2025-01-21T18:14:59+00:00" + "last_validated_date": "2026-02-21T00:06:02+00:00", + "durations_in_seconds": { + "setup": 0.51, + "call": 1.73, + "teardown": 1.42, + "total": 3.66 + } }, "tests/aws/services/s3/test_s3_list_operations.py::TestS3ListObjectVersions::test_list_objects_versions_markers": { - "last_validated_date": "2025-01-21T18:14:56+00:00" + "last_validated_date": "2026-02-21T00:05:59+00:00", + "durations_in_seconds": { + "setup": 0.51, + "call": 3.36, + "teardown": 1.51, + "total": 5.38 + } }, "tests/aws/services/s3/test_s3_list_operations.py::TestS3ListObjectVersions::test_list_objects_versions_with_prefix": { - "last_validated_date": "2025-01-21T18:15:03+00:00" + "last_validated_date": "2026-02-21T00:06:07+00:00", + "durations_in_seconds": { + "setup": 0.52, + "call": 2.28, + "teardown": 1.53, + "total": 4.33 + } }, "tests/aws/services/s3/test_s3_list_operations.py::TestS3ListObjectVersions::test_list_objects_versions_with_prefix_only_and_pagination": { - "last_validated_date": "2025-02-13T03:52:21+00:00" + "last_validated_date": "2026-02-21T00:06:11+00:00", + "durations_in_seconds": { + "setup": 0.5, + "call": 2.35, + "teardown": 1.39, + "total": 4.24 + } }, "tests/aws/services/s3/test_s3_list_operations.py::TestS3ListObjectVersions::test_list_objects_versions_with_prefix_only_and_pagination_many_versions": { - "last_validated_date": "2025-02-13T20:24:26+00:00" + "last_validated_date": "2026-02-21T00:06:27+00:00", + "durations_in_seconds": { + "setup": 0.52, + "call": 12.94, + "teardown": 2.22, + "total": 15.68 + } }, "tests/aws/services/s3/test_s3_list_operations.py::TestS3ListObjectVersions::test_s3_list_object_versions_timestamp_precision": { - "last_validated_date": "2025-01-21T18:15:06+00:00" + "last_validated_date": "2026-02-21T00:06:29+00:00", + "durations_in_seconds": { + "setup": 0.51, + "call": 0.9, + "teardown": 0.97, + "total": 2.38 + } }, "tests/aws/services/s3/test_s3_list_operations.py::TestS3ListObjects::test_list_objects_marker_common_prefixes": { - "last_validated_date": "2025-01-21T18:14:33+00:00" + "last_validated_date": "2026-02-21T00:05:25+00:00", + "durations_in_seconds": { + "setup": 0.54, + "call": 1.49, + "teardown": 0.99, + "total": 3.02 + } }, "tests/aws/services/s3/test_s3_list_operations.py::TestS3ListObjects::test_list_objects_next_marker": { - "last_validated_date": "2025-01-21T18:14:29+00:00" + "last_validated_date": "2026-02-21T00:05:20+00:00", + "durations_in_seconds": { + "setup": 0.52, + "call": 1.19, + "teardown": 1.02, + "total": 2.73 + } }, "tests/aws/services/s3/test_s3_list_operations.py::TestS3ListObjects::test_list_objects_with_prefix[%2F]": { - "last_validated_date": "2025-01-21T18:14:26+00:00" + "last_validated_date": "2026-02-21T00:05:18+00:00", + "durations_in_seconds": { + "setup": 0.5, + "call": 0.75, + "teardown": 0.93, + "total": 2.18 + } }, "tests/aws/services/s3/test_s3_list_operations.py::TestS3ListObjects::test_list_objects_with_prefix[/]": { - "last_validated_date": "2025-01-21T18:14:24+00:00" + "last_validated_date": "2026-02-21T00:05:15+00:00", + "durations_in_seconds": { + "setup": 0.5, + "call": 0.45, + "teardown": 0.91, + "total": 1.86 + } }, "tests/aws/services/s3/test_s3_list_operations.py::TestS3ListObjects::test_list_objects_with_prefix[]": { - "last_validated_date": "2025-01-21T18:14:22+00:00" + "last_validated_date": "2026-02-21T00:05:13+00:00", + "durations_in_seconds": { + "setup": 0.51, + "call": 0.42, + "teardown": 0.93, + "total": 1.86 + } }, "tests/aws/services/s3/test_s3_list_operations.py::TestS3ListObjects::test_s3_list_objects_empty_marker": { - "last_validated_date": "2025-01-21T18:14:31+00:00" + "last_validated_date": "2026-02-21T00:05:22+00:00", + "durations_in_seconds": { + "setup": 0.52, + "call": 0.21, + "teardown": 0.6, + "total": 1.33 + } }, "tests/aws/services/s3/test_s3_list_operations.py::TestS3ListObjects::test_s3_list_objects_timestamp_precision[ListObjectsV2]": { - "last_validated_date": "2025-01-21T18:14:37+00:00" + "last_validated_date": "2026-02-21T00:05:29+00:00", + "durations_in_seconds": { + "setup": 0.51, + "call": 0.55, + "teardown": 0.95, + "total": 2.01 + } }, "tests/aws/services/s3/test_s3_list_operations.py::TestS3ListObjects::test_s3_list_objects_timestamp_precision[ListObjects]": { - "last_validated_date": "2025-01-21T18:14:35+00:00" + "last_validated_date": "2026-02-21T00:05:27+00:00", + "durations_in_seconds": { + "setup": 0.52, + "call": 0.54, + "teardown": 0.94, + "total": 2.0 + } }, "tests/aws/services/s3/test_s3_list_operations.py::TestS3ListObjectsV2::test_list_objects_v2_continuation_common_prefixes": { - "last_validated_date": "2025-01-21T18:14:51+00:00" + "last_validated_date": "2026-02-21T00:05:42+00:00", + "durations_in_seconds": { + "setup": 0.51, + "call": 1.36, + "teardown": 0.99, + "total": 2.86 + } }, "tests/aws/services/s3/test_s3_list_operations.py::TestS3ListObjectsV2::test_list_objects_v2_continuation_start_after": { - "last_validated_date": "2025-01-21T18:14:48+00:00" + "last_validated_date": "2026-02-21T00:05:39+00:00", + "durations_in_seconds": { + "setup": 0.49, + "call": 3.17, + "teardown": 1.31, + "total": 4.97 + } + }, + "tests/aws/services/s3/test_s3_list_operations.py::TestS3ListObjectsV2::test_list_objects_v2_continuation_token_safe_chars": { + "last_validated_date": "2026-02-21T00:05:46+00:00", + "durations_in_seconds": { + "setup": 0.52, + "call": 2.63, + "teardown": 1.15, + "total": 4.3 + } }, "tests/aws/services/s3/test_s3_list_operations.py::TestS3ListObjectsV2::test_list_objects_v2_with_prefix": { - "last_validated_date": "2025-01-21T18:14:40+00:00" + "last_validated_date": "2026-02-21T00:05:31+00:00", + "durations_in_seconds": { + "setup": 0.49, + "call": 1.41, + "teardown": 0.95, + "total": 2.85 + } }, "tests/aws/services/s3/test_s3_list_operations.py::TestS3ListObjectsV2::test_list_objects_v2_with_prefix_and_delimiter": { - "last_validated_date": "2025-01-21T18:14:43+00:00" + "last_validated_date": "2026-02-21T00:05:34+00:00", + "durations_in_seconds": { + "setup": 0.5, + "call": 1.2, + "teardown": 0.76, + "total": 2.46 + } + }, + "tests/aws/services/s3/test_s3_list_operations.py::TestS3ListObjectsV2::test_list_ops_encoding_type_validation[list_multipart_uploads]": { + "last_validated_date": "2026-02-21T00:05:53+00:00", + "durations_in_seconds": { + "setup": 0.51, + "call": 0.64, + "teardown": 0.59, + "total": 1.74 + } + }, + "tests/aws/services/s3/test_s3_list_operations.py::TestS3ListObjectsV2::test_list_ops_encoding_type_validation[list_object_versions]": { + "last_validated_date": "2026-02-21T00:05:52+00:00", + "durations_in_seconds": { + "setup": 0.51, + "call": 0.94, + "teardown": 0.59, + "total": 2.04 + } + }, + "tests/aws/services/s3/test_s3_list_operations.py::TestS3ListObjectsV2::test_list_ops_encoding_type_validation[list_objects]": { + "last_validated_date": "2026-02-21T00:05:50+00:00", + "durations_in_seconds": { + "setup": 0.51, + "call": 0.64, + "teardown": 0.59, + "total": 1.74 + } + }, + "tests/aws/services/s3/test_s3_list_operations.py::TestS3ListObjectsV2::test_list_ops_encoding_type_validation[list_objects_v2]": { + "last_validated_date": "2026-02-21T00:05:48+00:00", + "durations_in_seconds": { + "setup": 0.5, + "call": 0.64, + "teardown": 0.59, + "total": 1.73 + } }, "tests/aws/services/s3/test_s3_list_operations.py::TestS3ListParts::test_list_parts_empty_part_number_marker": { - "last_validated_date": "2025-01-21T18:15:20+00:00" + "last_validated_date": "2026-02-21T00:06:43+00:00", + "durations_in_seconds": { + "setup": 0.52, + "call": 0.82, + "teardown": 0.6, + "total": 1.94 + } }, "tests/aws/services/s3/test_s3_list_operations.py::TestS3ListParts::test_list_parts_pagination": { - "last_validated_date": "2025-01-21T18:15:18+00:00" + "last_validated_date": "2026-02-21T00:06:41+00:00", + "durations_in_seconds": { + "setup": 0.52, + "call": 1.21, + "teardown": 0.59, + "total": 2.32 + } }, "tests/aws/services/s3/test_s3_list_operations.py::TestS3ListParts::test_list_parts_via_object_attrs_pagination": { - "last_validated_date": "2025-06-16T13:47:28+00:00", + "last_validated_date": "2026-02-21T00:06:48+00:00", "durations_in_seconds": { - "setup": 0.97, - "call": 10.45, + "setup": 0.53, + "call": 2.56, "teardown": 0.97, - "total": 12.39 + "total": 4.06 } }, "tests/aws/services/s3/test_s3_list_operations.py::TestS3ListParts::test_s3_list_parts_timestamp_precision": { - "last_validated_date": "2025-01-21T18:15:22+00:00" + "last_validated_date": "2026-02-21T00:06:44+00:00", + "durations_in_seconds": { + "setup": 0.51, + "call": 0.72, + "teardown": 0.58, + "total": 1.81 + } } } diff --git a/tests/aws/services/s3/test_s3_preconditions.py b/tests/aws/services/s3/test_s3_preconditions.py new file mode 100644 index 0000000000000..0ba685631b95c --- /dev/null +++ b/tests/aws/services/s3/test_s3_preconditions.py @@ -0,0 +1,185 @@ +import datetime +import time +from zoneinfo import ZoneInfo + +import pytest +from botocore.exceptions import ClientError + +from localstack.testing.pytest import markers + + +class TestS3CopySourcePreconditions: + @markers.aws.validated + def test_s3_copy_object_preconditions(self, s3_bucket, snapshot, aws_client): + snapshot.add_transformer(snapshot.transform.s3_api()) + object_key = "source-object" + dest_key = "dest-object" + # create key with no checksum + put_object = aws_client.s3.put_object( + Bucket=s3_bucket, + Key=object_key, + Body=b"data", + ) + head_obj = aws_client.s3.head_object(Bucket=s3_bucket, Key=object_key) + snapshot.match("head-object", head_obj) + + # wait a bit for the `modified_since` value so that it's invalid. + # S3 compares it the last-modified field, but you can't set the value in the future otherwise it ignores it. + # It needs to be now or less, but the object needs to be a bit more recent than that. + time.sleep(3) + + # we're testing the order of validation at the same time by validating all of them at once, by elimination + now = datetime.datetime.now().astimezone(tz=ZoneInfo("GMT")) + wrong_unmodified_since = now - datetime.timedelta(days=1) + + with pytest.raises(ClientError) as e: + aws_client.s3.copy_object( + Bucket=s3_bucket, + CopySource=f"{s3_bucket}/{object_key}", + Key=dest_key, + CopySourceIfModifiedSince=now, + CopySourceIfUnmodifiedSince=wrong_unmodified_since, + CopySourceIfMatch="etag123", + CopySourceIfNoneMatch=put_object["ETag"], + ) + snapshot.match("copy-precondition-if-match", e.value.response) + + with pytest.raises(ClientError) as e: + aws_client.s3.copy_object( + Bucket=s3_bucket, + CopySource=f"{s3_bucket}/{object_key}", + Key=dest_key, + CopySourceIfModifiedSince=now, + CopySourceIfUnmodifiedSince=wrong_unmodified_since, + CopySourceIfNoneMatch=put_object["ETag"], + ) + snapshot.match("copy-precondition-if-unmodified-since", e.value.response) + + with pytest.raises(ClientError) as e: + aws_client.s3.copy_object( + Bucket=s3_bucket, + CopySource=f"{s3_bucket}/{object_key}", + Key=dest_key, + CopySourceIfModifiedSince=now, + CopySourceIfNoneMatch=put_object["ETag"], + ) + snapshot.match("copy-precondition-if-none-match", e.value.response) + + with pytest.raises(ClientError) as e: + aws_client.s3.copy_object( + Bucket=s3_bucket, + CopySource=f"{s3_bucket}/{object_key}", + Key=dest_key, + CopySourceIfModifiedSince=now, + ) + snapshot.match("copy-precondition-if-modified-since", e.value.response) + + # AWS will ignore the value if it's in the future + copy_obj = aws_client.s3.copy_object( + Bucket=s3_bucket, + CopySource=f"{s3_bucket}/{object_key}", + Key=dest_key, + CopySourceIfModifiedSince=now + datetime.timedelta(days=1), + ) + snapshot.match("copy-ignore-future-modified-since", copy_obj) + + # AWS will ignore the missing quotes around the ETag and still reject the request + with pytest.raises(ClientError) as e: + aws_client.s3.copy_object( + Bucket=s3_bucket, + CopySource=f"{s3_bucket}/{object_key}", + Key=dest_key, + CopySourceIfNoneMatch=put_object["ETag"].strip('"'), + ) + snapshot.match("copy-etag-missing-quotes", e.value.response) + + # Positive tests with all conditions checked + copy_obj_all_positive = aws_client.s3.copy_object( + Bucket=s3_bucket, + CopySource=f"{s3_bucket}/{object_key}", + Key=dest_key, + CopySourceIfMatch=put_object["ETag"].strip('"'), + CopySourceIfNoneMatch="etag123", + CopySourceIfModifiedSince=now - datetime.timedelta(days=1), + CopySourceIfUnmodifiedSince=now, + ) + snapshot.match("copy-success", copy_obj_all_positive) + + @markers.aws.validated + def test_s3_copy_object_if_source_modified_since_versioned( + self, s3_bucket, snapshot, aws_client + ): + snapshot.add_transformer(snapshot.transform.s3_api()) + aws_client.s3.put_bucket_versioning( + Bucket=s3_bucket, VersioningConfiguration={"Status": "Enabled"} + ) + object_key = "source-object" + dest_key = "dest-object" + # create key with no checksum + aws_client.s3.put_object( + Bucket=s3_bucket, + Key=object_key, + Body=b"data", + ) + head_obj = aws_client.s3.head_object(Bucket=s3_bucket, Key=object_key) + snapshot.match("head-object", head_obj) + object_last_modified = head_obj["LastModified"] + + if_modified_since = object_last_modified - datetime.timedelta(minutes=1) + + copy_object = aws_client.s3.copy_object( + Bucket=s3_bucket, + CopySource=f"{s3_bucket}/{object_key}", + Key=dest_key, + CopySourceIfModifiedSince=if_modified_since, + ) + snapshot.match("copy-if-modified-since", copy_object) + + with pytest.raises(ClientError) as e: + aws_client.s3.copy_object( + Bucket=s3_bucket, + CopySource=f"{s3_bucket}/{object_key}", + Key=dest_key, + CopySourceIfModifiedSince=object_last_modified, + ) + snapshot.match("copy-if-modified-since-last-modified", e.value.response) + + @markers.aws.validated + def test_s3_copy_object_if_source_unmodified_since_versioned( + self, s3_bucket, snapshot, aws_client + ): + snapshot.add_transformer(snapshot.transform.s3_api()) + aws_client.s3.put_bucket_versioning( + Bucket=s3_bucket, VersioningConfiguration={"Status": "Enabled"} + ) + object_key = "source-object" + dest_key = "dest-object" + # create key with no checksum + aws_client.s3.put_object( + Bucket=s3_bucket, + Key=object_key, + Body=b"data", + ) + head_obj = aws_client.s3.head_object(Bucket=s3_bucket, Key=object_key) + snapshot.match("head-object", head_obj) + last_modified = head_obj["LastModified"] + + copy_object = aws_client.s3.copy_object( + Bucket=s3_bucket, + CopySource=f"{s3_bucket}/{object_key}", + Key=dest_key, + CopySourceIfUnmodifiedSince=last_modified, + ) + snapshot.match("copy-if-unmodified-since", copy_object) + + now = datetime.datetime.now().astimezone(tz=ZoneInfo("GMT")) + wrong_unmodified_since = now - datetime.timedelta(days=1) + + with pytest.raises(ClientError) as e: + aws_client.s3.copy_object( + Bucket=s3_bucket, + CopySource=f"{s3_bucket}/{object_key}", + Key=dest_key, + CopySourceIfUnmodifiedSince=wrong_unmodified_since, + ) + snapshot.match("copy-past-if-unmodified-since", e.value.response) diff --git a/tests/aws/services/s3/test_s3_preconditions.snapshot.json b/tests/aws/services/s3/test_s3_preconditions.snapshot.json new file mode 100644 index 0000000000000..1ac51a6d116ab --- /dev/null +++ b/tests/aws/services/s3/test_s3_preconditions.snapshot.json @@ -0,0 +1,191 @@ +{ + "tests/aws/services/s3/test_s3_preconditions.py::TestS3CopySourcePreconditions::test_s3_copy_object_preconditions": { + "recorded-date": "23-02-2026, 11:37:02", + "recorded-content": { + "head-object": { + "AcceptRanges": "bytes", + "ContentLength": 4, + "ContentType": "binary/octet-stream", + "ETag": "\"8d777f385d3dfec8815d20f7496026dc\"", + "LastModified": "datetime", + "Metadata": {}, + "ServerSideEncryption": "AES256", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "copy-precondition-if-match": { + "Error": { + "Code": "PreconditionFailed", + "Condition": "x-amz-copy-source-If-Match", + "Message": "At least one of the pre-conditions you specified did not hold" + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 412 + } + }, + "copy-precondition-if-unmodified-since": { + "Error": { + "Code": "PreconditionFailed", + "Condition": "x-amz-copy-source-If-Unmodified-Since", + "Message": "At least one of the pre-conditions you specified did not hold" + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 412 + } + }, + "copy-precondition-if-none-match": { + "Error": { + "Code": "PreconditionFailed", + "Condition": "x-amz-copy-source-If-None-Match", + "Message": "At least one of the pre-conditions you specified did not hold" + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 412 + } + }, + "copy-precondition-if-modified-since": { + "Error": { + "Code": "PreconditionFailed", + "Condition": "x-amz-copy-source-If-Modified-Since", + "Message": "At least one of the pre-conditions you specified did not hold" + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 412 + } + }, + "copy-ignore-future-modified-since": { + "CopyObjectResult": { + "ChecksumCRC32": "rfPzYw==", + "ChecksumType": "FULL_OBJECT", + "ETag": "\"8d777f385d3dfec8815d20f7496026dc\"", + "LastModified": "datetime" + }, + "ServerSideEncryption": "AES256", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "copy-etag-missing-quotes": { + "Error": { + "Code": "PreconditionFailed", + "Condition": "x-amz-copy-source-If-None-Match", + "Message": "At least one of the pre-conditions you specified did not hold" + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 412 + } + }, + "copy-success": { + "CopyObjectResult": { + "ChecksumCRC32": "rfPzYw==", + "ChecksumType": "FULL_OBJECT", + "ETag": "\"8d777f385d3dfec8815d20f7496026dc\"", + "LastModified": "datetime" + }, + "ServerSideEncryption": "AES256", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/s3/test_s3_preconditions.py::TestS3CopySourcePreconditions::test_s3_copy_object_if_source_modified_since_versioned": { + "recorded-date": "23-02-2026, 11:37:05", + "recorded-content": { + "head-object": { + "AcceptRanges": "bytes", + "ContentLength": 4, + "ContentType": "binary/octet-stream", + "ETag": "\"8d777f385d3dfec8815d20f7496026dc\"", + "LastModified": "datetime", + "Metadata": {}, + "ServerSideEncryption": "AES256", + "VersionId": "", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "copy-if-modified-since": { + "CopyObjectResult": { + "ChecksumCRC32": "rfPzYw==", + "ChecksumType": "FULL_OBJECT", + "ETag": "\"8d777f385d3dfec8815d20f7496026dc\"", + "LastModified": "datetime" + }, + "CopySourceVersionId": "", + "ServerSideEncryption": "AES256", + "VersionId": "", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "copy-if-modified-since-last-modified": { + "Error": { + "Code": "PreconditionFailed", + "Condition": "x-amz-copy-source-If-Modified-Since", + "Message": "At least one of the pre-conditions you specified did not hold" + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 412 + } + } + } + }, + "tests/aws/services/s3/test_s3_preconditions.py::TestS3CopySourcePreconditions::test_s3_copy_object_if_source_unmodified_since_versioned": { + "recorded-date": "23-02-2026, 11:37:08", + "recorded-content": { + "head-object": { + "AcceptRanges": "bytes", + "ContentLength": 4, + "ContentType": "binary/octet-stream", + "ETag": "\"8d777f385d3dfec8815d20f7496026dc\"", + "LastModified": "datetime", + "Metadata": {}, + "ServerSideEncryption": "AES256", + "VersionId": "", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "copy-if-unmodified-since": { + "CopyObjectResult": { + "ChecksumCRC32": "rfPzYw==", + "ChecksumType": "FULL_OBJECT", + "ETag": "\"8d777f385d3dfec8815d20f7496026dc\"", + "LastModified": "datetime" + }, + "CopySourceVersionId": "", + "ServerSideEncryption": "AES256", + "VersionId": "", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "copy-past-if-unmodified-since": { + "Error": { + "Code": "PreconditionFailed", + "Condition": "x-amz-copy-source-If-Unmodified-Since", + "Message": "At least one of the pre-conditions you specified did not hold" + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 412 + } + } + } + } +} diff --git a/tests/aws/services/s3/test_s3_preconditions.validation.json b/tests/aws/services/s3/test_s3_preconditions.validation.json new file mode 100644 index 0000000000000..245cd73fb59bf --- /dev/null +++ b/tests/aws/services/s3/test_s3_preconditions.validation.json @@ -0,0 +1,29 @@ +{ + "tests/aws/services/s3/test_s3_preconditions.py::TestS3CopySourcePreconditions::test_s3_copy_object_if_source_modified_since_versioned": { + "last_validated_date": "2026-02-23T11:37:06+00:00", + "durations_in_seconds": { + "setup": 0.53, + "call": 1.02, + "teardown": 1.51, + "total": 3.06 + } + }, + "tests/aws/services/s3/test_s3_preconditions.py::TestS3CopySourcePreconditions::test_s3_copy_object_if_source_unmodified_since_versioned": { + "last_validated_date": "2026-02-23T11:37:09+00:00", + "durations_in_seconds": { + "setup": 0.53, + "call": 0.93, + "teardown": 1.48, + "total": 2.94 + } + }, + "tests/aws/services/s3/test_s3_preconditions.py::TestS3CopySourcePreconditions::test_s3_copy_object_preconditions": { + "last_validated_date": "2026-02-23T11:37:03+00:00", + "durations_in_seconds": { + "setup": 1.1, + "call": 4.4, + "teardown": 1.02, + "total": 6.52 + } + } +} diff --git a/tests/aws/services/s3control/test_s3control.py b/tests/aws/services/s3control/test_s3control.py index c7daf08fad70d..8132ef3b5ff6a 100644 --- a/tests/aws/services/s3control/test_s3control.py +++ b/tests/aws/services/s3control/test_s3control.py @@ -10,8 +10,6 @@ from localstack.utils.strings import short_uid from localstack.utils.urls import localstack_host -# TODO: this fails in CI, not sure why yet -# s3_control_endpoint = f"http://s3-control.{localstack_host()}" s3_control_endpoint = f"https://{localstack_host().host_and_port()}" @@ -421,3 +419,152 @@ def test_access_point_pagination( list_by_bucket = s3control_client.list_access_points(AccountId=account_id, Bucket=bucket_1) snapshot.match("list-by-bucket", list_by_bucket) + + +@markers.snapshot.skip_snapshot_verify( + paths=[ + # FIXME: this needs to be updated in the serializer, see https://github.com/localstack/localstack/pull/9730 + "$..HostId", + ] +) +class TestS3ControlTagging: + @markers.aws.validated + def test_tag_lifecycle( + self, s3_bucket, s3control_client, snapshot, account_id, s3control_snapshot + ): + bucket_arn = f"arn:aws:s3:::{s3_bucket}" + + list_tags_before = s3control_client.list_tags_for_resource( + AccountId=account_id, + ResourceArn=bucket_arn, + ) + snapshot.match("list-tags-before", list_tags_before) + + tag_resource = s3control_client.tag_resource( + AccountId=account_id, + ResourceArn=bucket_arn, + Tags=[ + {"Key": "key1", "Value": "value1"}, + {"Key": "key2", "Value": "value2"}, + ], + ) + snapshot.match("tag-resource", tag_resource) + + list_tags_1 = s3control_client.list_tags_for_resource( + AccountId=account_id, + ResourceArn=bucket_arn, + ) + snapshot.match("list-tags-1", list_tags_1) + + tag_resource_after_update = s3control_client.tag_resource( + AccountId=account_id, ResourceArn=bucket_arn, Tags=[{"Key": "key3", "Value": "value3"}] + ) + snapshot.match("tag-resource-after-update", tag_resource_after_update) + + list_tags_after_update = s3control_client.list_tags_for_resource( + AccountId=account_id, + ResourceArn=bucket_arn, + ) + snapshot.match("list-tags-after-update", list_tags_after_update) + + untag_resource = s3control_client.untag_resource( + AccountId=account_id, ResourceArn=bucket_arn, TagKeys=["key3"] + ) + snapshot.match("untag-resource", untag_resource) + + list_tags_after_untag = s3control_client.list_tags_for_resource( + AccountId=account_id, + ResourceArn=bucket_arn, + ) + snapshot.match("list-tags-after-untag", list_tags_after_untag) + + untag_resource_idempotent = s3control_client.untag_resource( + AccountId=account_id, ResourceArn=bucket_arn, TagKeys=["key3"] + ) + snapshot.match("untag-resource-idempotent", untag_resource_idempotent) + + @markers.aws.validated + def test_tag_resource_validation( + self, s3_bucket, s3control_client_no_validation, account_id, snapshot, s3control_snapshot + ): + bucket_arn = f"arn:aws:s3:::{s3_bucket}" + + with pytest.raises(ClientError) as e: + s3control_client_no_validation.tag_resource( + AccountId=account_id, + ResourceArn=bucket_arn, + Tags=[{"Key": None, "Value": "value1"}], + ) + snapshot.match("tags-key-none", e.value.response) + + with pytest.raises(ClientError) as e: + s3control_client_no_validation.tag_resource( + AccountId=account_id, + ResourceArn=bucket_arn, + Tags=[{"Key": "key1", "Value": None}], + ) + snapshot.match("tags-value-none", e.value.response) + + with pytest.raises(ClientError) as e: + s3control_client_no_validation.tag_resource( + AccountId=account_id, + ResourceArn=bucket_arn, + Tags=[{"Key": "aws:test", "Value": "value1"}], + ) + snapshot.match("tags-key-aws-prefix", e.value.response) + + with pytest.raises(ClientError) as e: + s3control_client_no_validation.tag_resource( + AccountId=account_id, + ResourceArn=bucket_arn, + Tags=[ + {"Key": "key1", "Value": "value1"}, + {"Key": "key1", "Value": "value1"}, + ], + ) + snapshot.match("tags-key-aws-duplicated-key", e.value.response) + + with pytest.raises(ClientError) as e: + s3control_client_no_validation.tag_resource( + AccountId=account_id, + ResourceArn=bucket_arn, + Tags=[{"Key": "test", "Value": "value1,value2"}], + ) + snapshot.match("tags-key-aws-bad-value", e.value.response) + + with pytest.raises(ClientError) as e: + s3control_client_no_validation.tag_resource( + AccountId=account_id, + ResourceArn=bucket_arn, + Tags=[{"Key": "test,test2", "Value": "value1"}], + ) + snapshot.match("tags-key-aws-bad-key", e.value.response) + + @markers.aws.validated + def test_tag_operation_no_bucket( + self, s3_bucket, s3control_client, account_id, snapshot, s3control_snapshot + ): + bucket_arn = f"arn:aws:s3:::{short_uid()}-{short_uid()}" + + with pytest.raises(ClientError) as e: + s3control_client.tag_resource( + AccountId=account_id, + ResourceArn=bucket_arn, + Tags=[{"Key": "key1", "Value": "value1"}], + ) + snapshot.match("tag-resource-no-exist", e.value.response) + + with pytest.raises(ClientError) as e: + s3control_client.untag_resource( + AccountId=account_id, + ResourceArn=bucket_arn, + TagKeys=["key1"], + ) + snapshot.match("untag-resource-no-exist", e.value.response) + + with pytest.raises(ClientError) as e: + s3control_client.list_tags_for_resource( + AccountId=account_id, + ResourceArn=bucket_arn, + ) + snapshot.match("list-resource-tags-no-exist", e.value.response) diff --git a/tests/aws/services/s3control/test_s3control.snapshot.json b/tests/aws/services/s3control/test_s3control.snapshot.json index 3165e12ab6836..32c81a9b892f3 100644 --- a/tests/aws/services/s3control/test_s3control.snapshot.json +++ b/tests/aws/services/s3control/test_s3control.snapshot.json @@ -589,5 +589,202 @@ } } } + }, + "tests/aws/services/s3control/test_s3control.py::TestS3ControlTagging::test_tag_lifecycle": { + "recorded-date": "28-11-2025, 11:45:27", + "recorded-content": { + "list-tags-before": { + "Tags": [], + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "tag-resource": { + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 204 + } + }, + "list-tags-1": { + "Tags": [ + { + "Key": "key1", + "Value": "value1" + }, + { + "Key": "key2", + "Value": "value2" + } + ], + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "tag-resource-after-update": { + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 204 + } + }, + "list-tags-after-update": { + "Tags": [ + { + "Key": "key1", + "Value": "value1" + }, + { + "Key": "key2", + "Value": "value2" + }, + { + "Key": "key3", + "Value": "value3" + } + ], + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "untag-resource": { + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 204 + } + }, + "list-tags-after-untag": { + "Tags": [ + { + "Key": "key1", + "Value": "value1" + }, + { + "Key": "key2", + "Value": "value2" + } + ], + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "untag-resource-idempotent": { + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 204 + } + } + } + }, + "tests/aws/services/s3control/test_s3control.py::TestS3ControlTagging::test_tag_resource_validation": { + "recorded-date": "28-11-2025, 12:06:32", + "recorded-content": { + "tags-key-none": { + "Error": { + "Code": "MalformedXML", + "Message": "The XML you provided was not well-formed or did not validate against our published schema" + }, + "HostId": "host-id", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + }, + "tags-value-none": { + "Error": { + "Code": "MalformedXML", + "Message": "The XML you provided was not well-formed or did not validate against our published schema" + }, + "HostId": "host-id", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + }, + "tags-key-aws-prefix": { + "Error": { + "Code": "InvalidTag", + "Message": "User-defined tag keys can't start with \"aws:\". This prefix is reserved for system tags. Remove \"aws:\" from your tag keys and try again." + }, + "HostId": "host-id", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + }, + "tags-key-aws-duplicated-key": { + "Error": { + "Code": "InvalidTag", + "Message": "There are duplicate tag keys in your request. Remove the duplicate tag keys and try again." + }, + "HostId": "host-id", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + }, + "tags-key-aws-bad-value": { + "Error": { + "Code": "InvalidTag", + "Message": "This request contains a tag key or value that isn't valid. Valid characters include the following: [a-zA-Z+-=._:/]. Tag keys can contain up to 128 characters. Tag values can contain up to 256 characters." + }, + "HostId": "host-id", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + }, + "tags-key-aws-bad-key": { + "Error": { + "Code": "InvalidTag", + "Message": "This request contains a tag key or value that isn't valid. Valid characters include the following: [a-zA-Z+-=._:/]. Tag keys can contain up to 128 characters. Tag values can contain up to 256 characters." + }, + "HostId": "host-id", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + } + } + }, + "tests/aws/services/s3control/test_s3control.py::TestS3ControlTagging::test_tag_operation_no_bucket": { + "recorded-date": "28-11-2025, 11:45:32", + "recorded-content": { + "tag-resource-no-exist": { + "Error": { + "Code": "NoSuchResource", + "Message": "The specified resource doesn't exist." + }, + "HostId": "host-id", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 404 + } + }, + "untag-resource-no-exist": { + "Error": { + "Code": "NoSuchResource", + "Message": "The specified resource doesn't exist." + }, + "HostId": "host-id", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 404 + } + }, + "list-resource-tags-no-exist": { + "Error": { + "Code": "NoSuchResource", + "Message": "The specified resource doesn't exist." + }, + "HostId": "host-id", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 404 + } + } + } } } diff --git a/tests/aws/services/s3control/test_s3control.validation.json b/tests/aws/services/s3control/test_s3control.validation.json index 4fcb430b372e8..1d846d89a642c 100644 --- a/tests/aws/services/s3control/test_s3control.validation.json +++ b/tests/aws/services/s3control/test_s3control.validation.json @@ -25,5 +25,32 @@ }, "tests/aws/services/s3control/test_s3control.py::TestS3ControlPublicAccessBlock::test_empty_public_access_block": { "last_validated_date": "2024-05-30T17:32:59+00:00" + }, + "tests/aws/services/s3control/test_s3control.py::TestS3ControlTagging::test_tag_lifecycle": { + "last_validated_date": "2025-11-28T11:45:28+00:00", + "durations_in_seconds": { + "setup": 1.07, + "call": 1.41, + "teardown": 0.64, + "total": 3.12 + } + }, + "tests/aws/services/s3control/test_s3control.py::TestS3ControlTagging::test_tag_operation_no_bucket": { + "last_validated_date": "2025-11-28T11:45:33+00:00", + "durations_in_seconds": { + "setup": 0.54, + "call": 0.56, + "teardown": 0.6, + "total": 1.7 + } + }, + "tests/aws/services/s3control/test_s3control.py::TestS3ControlTagging::test_tag_resource_validation": { + "last_validated_date": "2025-11-28T12:06:32+00:00", + "durations_in_seconds": { + "setup": 1.18, + "call": 2.18, + "teardown": 0.61, + "total": 3.97 + } } } diff --git a/tests/aws/services/scheduler/conftest.py b/tests/aws/services/scheduler/conftest.py index 3591951039e6b..21f54ebcc612c 100644 --- a/tests/aws/services/scheduler/conftest.py +++ b/tests/aws/services/scheduler/conftest.py @@ -1,7 +1,10 @@ +import json import logging +import time import pytest +from localstack.testing.aws.util import is_aws_cloud from localstack.utils.strings import short_uid LOG = logging.getLogger(__name__) @@ -27,3 +30,34 @@ def _events_scheduler_create_schedule_group(name, **kwargs): aws_client.scheduler.delete_schedule_group(ScheduleGroupArn=schedule_group_arn) except Exception: LOG.info("Failed to delete schedule group %s", schedule_group_arn) + + +@pytest.fixture(scope="module") +def scheduler_role(aws_client): + role_name = f"test-scheduler-role-{short_uid()}" + trust_policy = { + "Version": "2012-10-17", + "Statement": [ + { + "Effect": "Allow", + "Principal": {"Service": "scheduler.amazonaws.com"}, + "Action": "sts:AssumeRole", + } + ], + } + + role = aws_client.iam.create_role( + RoleName=role_name, + AssumeRolePolicyDocument=json.dumps(trust_policy), + ) + role_arn = role["Role"]["Arn"] + + if is_aws_cloud(): + time.sleep(10) + + yield role_arn + + try: + aws_client.iam.delete_role(RoleName=role_name) + except Exception: + LOG.debug("Failed to delete role %s", role_name) diff --git a/tests/aws/services/scheduler/test_scheduler.py b/tests/aws/services/scheduler/test_scheduler.py index 2a0b9ec8f1584..29503c27a2ac0 100644 --- a/tests/aws/services/scheduler/test_scheduler.py +++ b/tests/aws/services/scheduler/test_scheduler.py @@ -109,6 +109,40 @@ def tests_create_schedule_with_invalid_schedule_expression( snapshot.match("invalid-schedule-expression", e.value.response) +@markers.aws.validated +@pytest.mark.parametrize( + "schedule_expression", + [ + "cron(0-15/1 8-8 ? * 2,3,4,5,6,7 *)", + "cron(30-30 13-13 ? * 2,4,6 *)", + "cron(1-31/30 1-1 ? * 1,7 *)", + "cron(0 18 ? * MON-FRI *)", + "cron(*/15 * * * ? *)", + "cron(0-59/10 0-23/2 ? * * *)", + ], +) +def test_create_schedule_with_valid_cron_expressions( + schedule_expression, aws_client, region_name, account_id, cleanups, snapshot, scheduler_role +): + # regression test for https://github.com/localstack/localstack/issues/13572 + snapshot.add_transformer(snapshot.transform.key_value("ScheduleArn")) + scheduler_name = f"test-scheduler-{short_uid()}" + + response = aws_client.scheduler.create_schedule( + Name=scheduler_name, + ScheduleExpression=schedule_expression, + FlexibleTimeWindow={"Mode": "OFF"}, + Target={ + "Arn": f"arn:aws:lambda:{region_name}:{account_id}:function:dummy", + "RoleArn": scheduler_role, + }, + ) + + cleanups.append(lambda: aws_client.scheduler.delete_schedule(Name=scheduler_name)) + + snapshot.match("create-schedule", response) + + @markers.aws.validated def tests_create_schedule_with_valid_schedule_expression( create_role, aws_client, region_name, account_id, cleanups, snapshot diff --git a/tests/aws/services/scheduler/test_scheduler.snapshot.json b/tests/aws/services/scheduler/test_scheduler.snapshot.json index 9000ad747a3a0..900f1d8f832fc 100644 --- a/tests/aws/services/scheduler/test_scheduler.snapshot.json +++ b/tests/aws/services/scheduler/test_scheduler.snapshot.json @@ -311,5 +311,77 @@ } } } + }, + "tests/aws/services/scheduler/test_scheduler.py::test_create_schedule_with_valid_cron_expressions[cron(0-15/1 8-8 ? * 2,3,4,5,6,7 *)]": { + "recorded-date": "17-01-2026, 18:20:57", + "recorded-content": { + "create-schedule": { + "ScheduleArn": "", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/scheduler/test_scheduler.py::test_create_schedule_with_valid_cron_expressions[cron(30-30 13-13 ? * 2,4,6 *)]": { + "recorded-date": "17-01-2026, 18:21:07", + "recorded-content": { + "create-schedule": { + "ScheduleArn": "", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/scheduler/test_scheduler.py::test_create_schedule_with_valid_cron_expressions[cron(1-31/30 1-1 ? * 1,7 *)]": { + "recorded-date": "17-01-2026, 18:21:18", + "recorded-content": { + "create-schedule": { + "ScheduleArn": "", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/scheduler/test_scheduler.py::test_create_schedule_with_valid_cron_expressions[cron(0 18 ? * MON-FRI *)]": { + "recorded-date": "17-01-2026, 18:21:28", + "recorded-content": { + "create-schedule": { + "ScheduleArn": "", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/scheduler/test_scheduler.py::test_create_schedule_with_valid_cron_expressions[cron(*/15 * * * ? *)]": { + "recorded-date": "17-01-2026, 18:21:39", + "recorded-content": { + "create-schedule": { + "ScheduleArn": "", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/scheduler/test_scheduler.py::test_create_schedule_with_valid_cron_expressions[cron(0-59/10 0-23/2 ? * * *)]": { + "recorded-date": "17-01-2026, 18:21:50", + "recorded-content": { + "create-schedule": { + "ScheduleArn": "", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } } } diff --git a/tests/aws/services/scheduler/test_scheduler.validation.json b/tests/aws/services/scheduler/test_scheduler.validation.json index 7f9a09fc8febe..66d8e53c4f394 100644 --- a/tests/aws/services/scheduler/test_scheduler.validation.json +++ b/tests/aws/services/scheduler/test_scheduler.validation.json @@ -1,4 +1,58 @@ { + "tests/aws/services/scheduler/test_scheduler.py::test_create_schedule_with_valid_cron_expressions[cron(*/15 * * * ? *)]": { + "last_validated_date": "2026-01-17T18:21:39+00:00", + "durations_in_seconds": { + "setup": 10.17, + "call": 0.22, + "teardown": 0.28, + "total": 10.67 + } + }, + "tests/aws/services/scheduler/test_scheduler.py::test_create_schedule_with_valid_cron_expressions[cron(0 18 ? * MON-FRI *)]": { + "last_validated_date": "2026-01-17T18:21:29+00:00", + "durations_in_seconds": { + "setup": 10.17, + "call": 0.16, + "teardown": 0.23, + "total": 10.56 + } + }, + "tests/aws/services/scheduler/test_scheduler.py::test_create_schedule_with_valid_cron_expressions[cron(0-15/1 8-8 ? * 2,3,4,5,6,7 *)]": { + "last_validated_date": "2026-01-17T18:20:57+00:00", + "durations_in_seconds": { + "setup": 10.9, + "call": 0.24, + "teardown": 0.25, + "total": 11.39 + } + }, + "tests/aws/services/scheduler/test_scheduler.py::test_create_schedule_with_valid_cron_expressions[cron(0-59/10 0-23/2 ? * * *)]": { + "last_validated_date": "2026-01-17T18:21:50+00:00", + "durations_in_seconds": { + "setup": 10.19, + "call": 0.17, + "teardown": 0.24, + "total": 10.6 + } + }, + "tests/aws/services/scheduler/test_scheduler.py::test_create_schedule_with_valid_cron_expressions[cron(1-31/30 1-1 ? * 1,7 *)]": { + "last_validated_date": "2026-01-17T18:21:18+00:00", + "durations_in_seconds": { + "setup": 10.17, + "call": 0.2, + "teardown": 0.25, + "total": 10.62 + } + }, + "tests/aws/services/scheduler/test_scheduler.py::test_create_schedule_with_valid_cron_expressions[cron(30-30 13-13 ? * 2,4,6 *)]": { + "last_validated_date": "2026-01-17T18:21:07+00:00", + "durations_in_seconds": { + "setup": 10.18, + "call": 0.22, + "teardown": 0.29, + "total": 10.69 + } + }, "tests/aws/services/scheduler/test_scheduler.py::test_list_schedules": { "last_validated_date": "2024-06-11T22:50:50+00:00" }, diff --git a/tests/aws/services/secretsmanager/test_secretsmanager.py b/tests/aws/services/secretsmanager/test_secretsmanager.py index 1c83093002c2d..996dd16ef1206 100644 --- a/tests/aws/services/secretsmanager/test_secretsmanager.py +++ b/tests/aws/services/secretsmanager/test_secretsmanager.py @@ -2458,6 +2458,39 @@ def test_secret_tags(self, aws_client, create_secret, sm_snapshot, cleanups): describe_secret_6 = aws_client.secretsmanager.describe_secret(SecretId=secret_arn) sm_snapshot.match("describe_secret_6", describe_secret_6) + @markers.aws.validated + def test_tag_untag_resource_on_deleted_secret(self, aws_client, create_secret, sm_snapshot): + """Test that tagging/untagging a secret marked for deletion raises InvalidRequestException.""" + secret_name = short_uid() + response = create_secret( + Name=secret_name, + SecretString="test-secret-value", + Tags=[{"Key": "initial-tag", "Value": "initial-value"}], + ) + + sm_snapshot.add_transformers_list( + sm_snapshot.transform.secretsmanager_secret_id_arn(response, 0) + ) + sm_snapshot.match("create_secret", response) + + secret_arn = response["ARN"] + + # Delete the secret (marks for deletion with recovery window) + delete_response = aws_client.secretsmanager.delete_secret(SecretId=secret_arn) + sm_snapshot.match("delete_secret", delete_response) + + # Attempting to tag a deleted secret should raise InvalidRequestException + with pytest.raises(ClientError) as exc_tag: + aws_client.secretsmanager.tag_resource( + SecretId=secret_arn, Tags=[{"Key": "new-tag", "Value": "new-value"}] + ) + sm_snapshot.match("tag_deleted_secret_error", exc_tag.value.response) + + # Attempting to untag a deleted secret should raise InvalidRequestException + with pytest.raises(ClientError) as exc_untag: + aws_client.secretsmanager.untag_resource(SecretId=secret_arn, TagKeys=["initial-tag"]) + sm_snapshot.match("untag_deleted_secret_error", exc_untag.value.response) + @markers.aws.validated def test_get_secret_value_errors(self, aws_client, create_secret, sm_snapshot): secret_name = short_uid() @@ -2535,6 +2568,7 @@ def test_get_secret_value( ) sm_snapshot.match("secret_value_http_response", json_response) + @markers.requires_in_process @markers.aws.only_localstack def test_create_secret_with_custom_id( self, account_id, region_name, create_secret, set_resource_custom_id @@ -2578,6 +2612,49 @@ def test_force_delete_deleted_secret(self, sm_snapshot, secret_name, aws_client) self._wait_force_deletion_completed(aws_client.secretsmanager, secret_id) + @pytest.mark.parametrize( + "put_secret_binary, update_secret_binary", + [ + (b"footest", b"updated1"), + (b"tops3cret", b"updated2"), + (b"\x00\x01\x02\xff", b"\xfe\xfd"), + ], + ) + @markers.aws.validated + def test_change_secret_value_after_creation( + self, + sm_snapshot, + create_secret, + aws_client, + put_secret_binary, + update_secret_binary, + ): + secret_name = f"test-secret-{short_uid()}" + response = create_secret(Name=secret_name, SecretBinary=b"initial") + sm_snapshot.add_transformers_list( + sm_snapshot.transform.secretsmanager_secret_id_arn(response, 0) + ) + + secret_value_response = aws_client.secretsmanager.get_secret_value(SecretId=secret_name) + sm_snapshot.match("put_secret_value_secret_response", secret_value_response) + + aws_client.secretsmanager.put_secret_value( + SecretId=secret_name, SecretBinary=put_secret_binary + ) + + secret_value_response_updated = aws_client.secretsmanager.get_secret_value( + SecretId=secret_name + ) + sm_snapshot.match("put_secret_binary_response_updated", secret_value_response_updated) + + aws_client.secretsmanager.update_secret( + SecretId=secret_name, SecretBinary=update_secret_binary + ) + secret_value_response_updated2 = aws_client.secretsmanager.get_secret_value( + SecretId=secret_name + ) + sm_snapshot.match("update_secret_binary_response_updated", secret_value_response_updated2) + class TestSecretsManagerMultiAccounts: @markers.aws.validated @@ -2668,8 +2745,9 @@ def test_cross_account_access(self, aws_client, secondary_aws_client, cleanups): # Note: when removing tags, the response will be empty list in case of AWS, # but it will be None in Localstack. To avoid failing the test, we will use the default value as list assert poll_condition( - lambda: aws_client.secretsmanager.describe_secret(SecretId=secret_arn).get("Tags", []) - == [], + lambda: ( + aws_client.secretsmanager.describe_secret(SecretId=secret_arn).get("Tags", []) == [] + ), timeout=5.0, interval=0.5, ) @@ -2775,10 +2853,10 @@ def test_cross_account_access_non_default_key(self, aws_client, secondary_aws_cl ) assert poll_condition( - lambda: aws_client.secretsmanager.describe_secret(SecretId=secret_arn).get( - "DeletedDate" - ) - is not None, + lambda: ( + aws_client.secretsmanager.describe_secret(SecretId=secret_arn).get("DeletedDate") + is not None + ), timeout=5.0, interval=0.5, ) @@ -2786,10 +2864,10 @@ def test_cross_account_access_non_default_key(self, aws_client, secondary_aws_cl secondary_aws_client.secretsmanager.restore_secret(SecretId=secret_arn) assert poll_condition( - lambda: aws_client.secretsmanager.describe_secret(SecretId=secret_arn).get( - "DeletedDate" - ) - is None, + lambda: ( + aws_client.secretsmanager.describe_secret(SecretId=secret_arn).get("DeletedDate") + is None + ), timeout=5.0, interval=0.5, ) diff --git a/tests/aws/services/secretsmanager/test_secretsmanager.snapshot.json b/tests/aws/services/secretsmanager/test_secretsmanager.snapshot.json index 8e52ed68a419c..11ba9f73dfc8e 100644 --- a/tests/aws/services/secretsmanager/test_secretsmanager.snapshot.json +++ b/tests/aws/services/secretsmanager/test_secretsmanager.snapshot.json @@ -4761,5 +4761,191 @@ } } } + }, + "tests/aws/services/secretsmanager/test_secretsmanager.py::TestSecretsManager::test_tag_untag_resource_on_deleted_secret": { + "recorded-date": "29-01-2026, 22:02:37", + "recorded-content": { + "create_secret": { + "ARN": "arn::secretsmanager::111111111111:secret:", + "Name": "", + "VersionId": "", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "delete_secret": { + "ARN": "arn::secretsmanager::111111111111:secret:", + "DeletionDate": "datetime", + "Name": "", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "tag_deleted_secret_error": { + "Error": { + "Code": "InvalidRequestException", + "Message": "You can't perform this operation on the secret because it was marked for deletion." + }, + "Message": "You can't perform this operation on the secret because it was marked for deletion.", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + }, + "untag_deleted_secret_error": { + "Error": { + "Code": "InvalidRequestException", + "Message": "You can't perform this operation on the secret because it was marked for deletion." + }, + "Message": "You can't perform this operation on the secret because it was marked for deletion.", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + } + } + }, + "tests/aws/services/secretsmanager/test_secretsmanager.py::TestSecretsManager::test_change_secret_value_after_creation[footest-updated1]": { + "recorded-date": "07-02-2026, 13:37:49", + "recorded-content": { + "put_secret_value_secret_response": { + "ARN": "arn::secretsmanager::111111111111:secret:", + "CreatedDate": "datetime", + "Name": "", + "SecretBinary": "b'initial'", + "VersionId": "", + "VersionStages": [ + "AWSCURRENT" + ], + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "put_secret_binary_response_updated": { + "ARN": "arn::secretsmanager::111111111111:secret:", + "CreatedDate": "datetime", + "Name": "", + "SecretBinary": "b'footest'", + "VersionId": "", + "VersionStages": [ + "AWSCURRENT" + ], + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "update_secret_binary_response_updated": { + "ARN": "arn::secretsmanager::111111111111:secret:", + "CreatedDate": "datetime", + "Name": "", + "SecretBinary": "b'updated1'", + "VersionId": "", + "VersionStages": [ + "AWSCURRENT" + ], + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/secretsmanager/test_secretsmanager.py::TestSecretsManager::test_change_secret_value_after_creation[tops3cret-updated2]": { + "recorded-date": "07-02-2026, 13:37:49", + "recorded-content": { + "put_secret_value_secret_response": { + "ARN": "arn::secretsmanager::111111111111:secret:", + "CreatedDate": "datetime", + "Name": "", + "SecretBinary": "b'initial'", + "VersionId": "", + "VersionStages": [ + "AWSCURRENT" + ], + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "put_secret_binary_response_updated": { + "ARN": "arn::secretsmanager::111111111111:secret:", + "CreatedDate": "datetime", + "Name": "", + "SecretBinary": "b'tops3cret'", + "VersionId": "", + "VersionStages": [ + "AWSCURRENT" + ], + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "update_secret_binary_response_updated": { + "ARN": "arn::secretsmanager::111111111111:secret:", + "CreatedDate": "datetime", + "Name": "", + "SecretBinary": "b'updated2'", + "VersionId": "", + "VersionStages": [ + "AWSCURRENT" + ], + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/secretsmanager/test_secretsmanager.py::TestSecretsManager::test_change_secret_value_after_creation[\\x00\\x01\\x02\\xff-\\xfe\\xfd]": { + "recorded-date": "07-02-2026, 13:37:49", + "recorded-content": { + "put_secret_value_secret_response": { + "ARN": "arn::secretsmanager::111111111111:secret:", + "CreatedDate": "datetime", + "Name": "", + "SecretBinary": "b'initial'", + "VersionId": "", + "VersionStages": [ + "AWSCURRENT" + ], + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "put_secret_binary_response_updated": { + "ARN": "arn::secretsmanager::111111111111:secret:", + "CreatedDate": "datetime", + "Name": "", + "SecretBinary": "b'\\x00\\x01\\x02\\xff'", + "VersionId": "", + "VersionStages": [ + "AWSCURRENT" + ], + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "update_secret_binary_response_updated": { + "ARN": "arn::secretsmanager::111111111111:secret:", + "CreatedDate": "datetime", + "Name": "", + "SecretBinary": "b'\\xfe\\xfd'", + "VersionId": "", + "VersionStages": [ + "AWSCURRENT" + ], + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } } } diff --git a/tests/aws/services/secretsmanager/test_secretsmanager.validation.json b/tests/aws/services/secretsmanager/test_secretsmanager.validation.json index d44fb5cb56bc5..7b193475585ab 100644 --- a/tests/aws/services/secretsmanager/test_secretsmanager.validation.json +++ b/tests/aws/services/secretsmanager/test_secretsmanager.validation.json @@ -134,6 +134,15 @@ "tests/aws/services/secretsmanager/test_secretsmanager.py::TestSecretsManager::test_secret_version_not_found": { "last_validated_date": "2024-06-13T08:04:35+00:00" }, + "tests/aws/services/secretsmanager/test_secretsmanager.py::TestSecretsManager::test_tag_untag_resource_on_deleted_secret": { + "last_validated_date": "2026-01-29T22:02:38+00:00", + "durations_in_seconds": { + "setup": 0.79, + "call": 1.51, + "teardown": 0.23, + "total": 2.53 + } + }, "tests/aws/services/secretsmanager/test_secretsmanager.py::TestSecretsManager::test_update_secret_description": { "last_validated_date": "2024-03-15T08:12:49+00:00" }, diff --git a/tests/aws/services/ses/test_ses.py b/tests/aws/services/ses/test_ses.py index c6fd53dd13df4..32abe2630b1af 100644 --- a/tests/aws/services/ses/test_ses.py +++ b/tests/aws/services/ses/test_ses.py @@ -1036,6 +1036,7 @@ def _get_emails(): @pytest.mark.usefixtures("openapi_validate") class TestSESRetrospection: + @markers.requires_in_process @markers.aws.only_localstack def test_send_email_can_retrospect(self, aws_client): # Test that sent emails can be retrospected through saved file and API access @@ -1116,6 +1117,7 @@ def _read_message_from_filesystem(message_id: str) -> dict: assert requests.delete(emails_url + f"?id={message2_id}").status_code == 204 assert requests.get(emails_url).json() == {"messages": []} + @markers.requires_in_process @markers.aws.only_localstack def test_send_templated_email_can_retrospect(self, create_template, aws_client): # Test that sent emails can be retrospected through saved file and API access diff --git a/tests/aws/services/sns/conftest.py b/tests/aws/services/sns/conftest.py index fa653ff8e75d7..290a292828b51 100644 --- a/tests/aws/services/sns/conftest.py +++ b/tests/aws/services/sns/conftest.py @@ -1,8 +1,5 @@ -import os - import pytest -from localstack.testing.aws.util import is_aws_cloud from localstack.utils.strings import short_uid LAMBDA_FN_SNS_ENDPOINT = """ @@ -20,16 +17,6 @@ def handler(event, *args): """ -def is_sns_v2_provider(): - return os.environ.get("PROVIDER_OVERRIDE_SNS") == "v2" and not is_aws_cloud() - - -skip_if_sns_v2 = pytest.mark.skipif( - is_sns_v2_provider(), - reason="Skipping test for v2 provider as it contains operations not yet supported", -) - - @pytest.fixture def create_sns_http_endpoint_and_queue( aws_client, account_id, create_lambda_function, sqs_create_queue diff --git a/tests/aws/services/sns/test_sns.py b/tests/aws/services/sns/test_sns.py index c67f2af681f30..e6ac138b7346d 100644 --- a/tests/aws/services/sns/test_sns.py +++ b/tests/aws/services/sns/test_sns.py @@ -5,6 +5,7 @@ import queue import random import time +import uuid from io import BytesIO from operator import itemgetter @@ -17,6 +18,7 @@ from cryptography import x509 from cryptography.hazmat.primitives import hashes from cryptography.hazmat.primitives.asymmetric import padding +from localstack_snapshot.snapshots.transformer import RegexTransformer from pytest_httpserver import HTTPServer from werkzeug import Response @@ -29,12 +31,14 @@ from localstack.services.sns.constants import ( PLATFORM_ENDPOINT_MSGS_ENDPOINT, SMS_MSGS_ENDPOINT, + SMS_PHONE_NUMBER_OPT_OUT_ENDPOINT, SUBSCRIPTION_TOKENS_ENDPOINT, ) from localstack.services.sns.provider import SnsProvider from localstack.testing.aws.util import is_aws_cloud from localstack.testing.config import TEST_AWS_ACCESS_KEY_ID, TEST_AWS_SECRET_ACCESS_KEY from localstack.testing.pytest import markers +from localstack.testing.snapshots.transformer_utility import TransformerUtility from localstack.utils import testutil from localstack.utils.aws.arns import get_partition, parse_arn, sqs_queue_arn from localstack.utils.net import wait_for_port_closed, wait_for_port_open @@ -43,7 +47,6 @@ from localstack.utils.testutil import check_expected_lambda_log_events_length from tests.aws.services.lambda_.functions import lambda_integration from tests.aws.services.lambda_.test_lambda import TEST_LAMBDA_PYTHON, TEST_LAMBDA_PYTHON_ECHO -from tests.aws.services.sns.conftest import skip_if_sns_v2 LOG = logging.getLogger(__name__) @@ -70,9 +73,17 @@ def factory(**kwargs): yield factory for platform_application in platform_applications: - endpoints = aws_client.sns.list_endpoints_by_platform_application( - PlatformApplicationArn=platform_application - ) + try: + endpoints = aws_client.sns.list_endpoints_by_platform_application( + PlatformApplicationArn=platform_application + ) + except Exception as e: + LOG.debug( + "Error cleaning up platform app '%s': %s", + platform_application, + e, + ) + return for endpoint in endpoints["Endpoints"]: try: aws_client.sns.delete_endpoint(EndpointArn=endpoint["EndpointArn"]) @@ -89,16 +100,32 @@ def factory(**kwargs): LOG.debug("Error cleaning up platform application '%s': %s", platform_application, e) +@pytest.fixture +def sns_create_platform_endpoint(aws_client): + platform_endpoints = [] + + def factory(platform_application_arn: str, token: str, **kwargs): + response = aws_client.sns.create_platform_endpoint( + PlatformApplicationArn=platform_application_arn, Token=token, **kwargs + ) + platform_endpoints.append(response["EndpointArn"]) + return response + + yield factory + + for endpoint in platform_endpoints: + try: + aws_client.sns.delete_endpoint(EndpointArn=endpoint["EndpointArn"]) + except Exception as e: + LOG.debug( + "Error cleaning up platform endpoint '%s': %s", + endpoint, + e, + ) + + class TestSNSTopicCrud: @markers.aws.validated - @markers.snapshot.skip_snapshot_verify( - paths=[ - "$.get-topic-attrs.Attributes.DeliveryPolicy", - "$.get-topic-attrs.Attributes.EffectiveDeliveryPolicy", - "$.get-topic-attrs.Attributes.Policy.Statement..Action", # SNS:Receive is added by moto but not returned in AWS - ] - ) - @skip_if_sns_v2 def test_create_topic_with_attributes(self, sns_create_topic, snapshot, aws_client): create_topic = sns_create_topic( Name="topictest.fifo", @@ -127,7 +154,6 @@ def test_create_topic_with_attributes(self, sns_create_topic, snapshot, aws_clie snapshot.match("get-attrs-malformed-topic", e.value.response) @markers.aws.validated - @skip_if_sns_v2 def test_tags(self, sns_create_topic, snapshot, aws_client): topic_arn = sns_create_topic()["TopicArn"] with pytest.raises(ClientError) as exc: @@ -164,15 +190,30 @@ def test_tags(self, sns_create_topic, snapshot, aws_client): snapshot.match("list-after-update-tags", tags) @markers.aws.validated - @markers.snapshot.skip_snapshot_verify( - paths=[ - "$.get-topic-attrs.Attributes.DeliveryPolicy", - "$.get-topic-attrs.Attributes.EffectiveDeliveryPolicy", - "$.get-topic-attrs.Attributes.Policy.Statement..Action", - # SNS:Receive is added by moto but not returned in AWS - ] - ) - @skip_if_sns_v2 + def test_tags_removed_after_deletion(self, aws_client, sns_create_topic, snapshot): + topic_name = f"topic-{short_uid()}" + topic = sns_create_topic(Name=topic_name) + topic_arn = topic["TopicArn"] + aws_client.sns.tag_resource( + ResourceArn=topic_arn, + Tags=[ + {"Key": "k1", "Value": "v1"}, + {"Key": "k2", "Value": "v2"}, + ], + ) + tags = aws_client.sns.list_tags_for_resource(ResourceArn=topic_arn) + tags["Tags"].sort(key=itemgetter("Key")) + snapshot.match("list-created-tags", tags) + + # delete the topic and recreate the same topic to ensure the tags no longer exist + aws_client.sns.delete_topic(TopicArn=topic_arn) + sns_create_topic(Name=topic_name) + + tags_response = aws_client.sns.list_tags_for_resource(ResourceArn=topic_arn) + assert len(tags_response["Tags"]) == 0 + snapshot.match("list-empty-tags", tags_response) + + @markers.aws.validated def test_create_topic_test_arn(self, sns_create_topic, snapshot, aws_client, account_id): topic_name = "topic-test-create" response = sns_create_topic(Name=topic_name) @@ -197,7 +238,6 @@ def test_create_topic_test_arn(self, sns_create_topic, snapshot, aws_client, acc snapshot.match("topic-not-exists", e.value.response) @markers.aws.validated - @skip_if_sns_v2 def test_delete_topic_idempotency(self, sns_create_topic, aws_client, snapshot): topic_arn = sns_create_topic()["TopicArn"] @@ -211,7 +251,6 @@ def test_delete_topic_idempotency(self, sns_create_topic, aws_client, snapshot): snapshot.match("delete-topic-again", delete_topic) @markers.aws.validated - @skip_if_sns_v2 def test_create_duplicate_topic_with_more_tags(self, sns_create_topic, snapshot, aws_client): topic_name = "test-duplicated-topic-more-tags" sns_create_topic(Name=topic_name) @@ -222,7 +261,6 @@ def test_create_duplicate_topic_with_more_tags(self, sns_create_topic, snapshot, snapshot.match("exception-duplicate", e.value.response) @markers.aws.validated - @skip_if_sns_v2 def test_create_duplicate_topic_check_idempotency(self, sns_create_topic, snapshot): topic_name = f"test-{short_uid()}" tags = [{"Key": "a", "Value": "1"}, {"Key": "b", "Value": "2"}] @@ -242,7 +280,6 @@ def test_create_duplicate_topic_check_idempotency(self, sns_create_topic, snapsh snapshot.match(f"response-same-arn-{index}", response) @markers.aws.validated - @skip_if_sns_v2 def test_create_topic_after_delete_with_new_tags(self, sns_create_topic, snapshot, aws_client): topic_name = f"test-{short_uid()}" topic = sns_create_topic(Name=topic_name, Tags=[{"Key": "Name", "Value": "pqr"}]) @@ -254,7 +291,6 @@ def test_create_topic_after_delete_with_new_tags(self, sns_create_topic, snapsho @markers.aws.validated @pytest.mark.skip(reason="Not properly implemented in Moto, only mocked") - @skip_if_sns_v2 def test_topic_delivery_policy_crud(self, sns_create_topic, snapshot, aws_client): # https://docs.aws.amazon.com/sns/latest/dg/sns-message-delivery-retries.html create_topic = sns_create_topic( @@ -330,13 +366,307 @@ def test_topic_delivery_policy_crud(self, sns_create_topic, snapshot, aws_client snapshot.match("get-topic-attrs-after-delete", get_attrs_updated) +class TestSNSTopicCrudV2: + @markers.aws.validated + def test_delete_non_existent_topic(self, snapshot, aws_client, account_id, region_name): + response = aws_client.sns.delete_topic( + TopicArn=f"arn:aws:sns:{region_name}:{account_id}:non-existent-{short_uid()}" + ) + + snapshot.match("delete-non-existent-topic", response) + + @markers.aws.validated + def test_create_topic_should_be_idempotent(self, snapshot, sns_create_topic, aws_client): + topic_name = f"test-idempotent-{short_uid()}" + + resp1 = sns_create_topic(Name=topic_name) + aws_client.sns.set_topic_attributes( + TopicArn=resp1["TopicArn"], AttributeName="DisplayName", AttributeValue="AlreadySet" + ) + attrs = aws_client.sns.get_topic_attributes(TopicArn=resp1["TopicArn"]) + snapshot.match("topic-attrs-idempotent-1", attrs) + + resp2 = sns_create_topic(Name=topic_name) + attrs = aws_client.sns.get_topic_attributes(TopicArn=resp2["TopicArn"]) + snapshot.match("topic-attrs-idempotent-2", attrs) + + @markers.aws.validated + def test_create_topic_different_attrs(self, snapshot, sns_create_topic, aws_client): + topic_name = f"test-idempotent-{short_uid()}" + + create_topic_1 = sns_create_topic(Name=topic_name, Attributes={"DisplayName": "Value1"}) + snapshot.match("create-topic", create_topic_1) + + create_topic_no_attr = sns_create_topic(Name=topic_name) + snapshot.match("create-topic-no-attrs", create_topic_no_attr) + + attrs = aws_client.sns.get_topic_attributes(TopicArn=create_topic_1["TopicArn"]) + snapshot.match("topic-attrs", attrs) + + sns_create_topic(Name=topic_name, Attributes={"DisplayName": "Value1"}) + + # FifoTopic = False is a special case, seems to be stored internally + sns_create_topic(Name=topic_name, Attributes={"FifoTopic": "false"}) + + with pytest.raises(ClientError) as exc: + sns_create_topic(Name=topic_name, Attributes={"DisplayName": "Value2"}) + snapshot.match("create-topic-diff-attrs", exc.value.response) + + with pytest.raises(ClientError) as exc: + sns_create_topic(Name=topic_name, Attributes={"FifoTopic": "true"}) + snapshot.match("create-topic-new-attrs-fifo", exc.value.response) + + with pytest.raises(ClientError) as exc: + sns_create_topic(Name=topic_name, Attributes={"SignatureVersion": "2"}) + snapshot.match("create-topic-new-attrs", exc.value.response) + + with pytest.raises(ClientError) as exc: + sns_create_topic( + Name=topic_name, Attributes={"SignatureVersion": "2", "DisplayName": "Value1"} + ) + snapshot.match("create-topic-new-and-same-attrs", exc.value.response) + + @markers.aws.validated + def test_create_topic_name_constraints(self, snapshot, sns_create_topic): + # Valid names within length constraints + valid_name = "a" * 256 + resp = sns_create_topic(Name=valid_name) + snapshot.match("valid-name-max-length", resp) + + # Invalid names: too short / too long + with pytest.raises(ClientError) as e: + sns_create_topic(Name="") + snapshot.match("name-too-short", e.value.response) + + with pytest.raises(ClientError) as e: + sns_create_topic(Name="a" * 257) + snapshot.match("name-too-long", e.value.response) + + with pytest.raises(ClientError) as e: + sns_create_topic(Name="test.fifo") + snapshot.match("name-contains-fifo", e.value.response) + + with pytest.raises(ClientError) as e: + sns_create_topic(Name="test", Attributes={"FifoTopic": "true"}) + snapshot.match("fifo-name-not-contains-fifo", e.value.response) + + # Invalid chars + # TODO: the index is used because using special characters in the matched name doesn't work for all chars + # -> we should write a snapshot test to investigate further + for index, c in enumerate([":", ";", "!", "@", "|", "^", "%", " "]): + with pytest.raises(ClientError) as e: + sns_create_topic(Name=f"bad{c}name") + snapshot.match(f"name-invalid-char-{index}", e.value.response) + + @markers.aws.validated + def test_create_topic_in_multiple_regions( + self, aws_client, aws_client_factory, snapshot, region_name, secondary_region_name + ): + topic_name = f"multiregion-{short_uid()}" + snapshot.add_transformer(RegexTransformer(region_name, "")) + snapshot.add_transformer(RegexTransformer(secondary_region_name, "")) + + sns_primary_region = aws_client_factory(region_name=region_name).sns + topic_arn_primary_region = sns_primary_region.create_topic(Name=topic_name)["TopicArn"] + + sns_secondary_region = aws_client_factory(region_name=secondary_region_name).sns + topic_arn_secondary_region = sns_secondary_region.create_topic(Name=topic_name)["TopicArn"] + + list_topics_primary = sns_primary_region.list_topics() + snapshot.match("list-primary", list_topics_primary) + list_topics_secondary = sns_secondary_region.list_topics() + snapshot.match("list-secondary", list_topics_secondary) + + snapshot.match( + "topic-east", sns_primary_region.get_topic_attributes(TopicArn=topic_arn_primary_region) + ) + snapshot.match( + "topic-west", + sns_secondary_region.get_topic_attributes(TopicArn=topic_arn_secondary_region), + ) + + @markers.aws.validated + def test_list_topic_paging(self, aws_client, sns_create_topic): + topic_arns = [] + page_size = 100 + for i in range(page_size + 20): # > default page size + resp = sns_create_topic(Name=f"paging-{i}-{short_uid()}") + topic_arns.append(resp["TopicArn"]) + + resp = aws_client.sns.list_topics() + assert len(resp["Topics"]) == page_size + + assert "NextToken" in resp + token = resp["NextToken"] + + resp2 = aws_client.sns.list_topics(NextToken=token) + + # Collect all returned ARNs to ensure no duplicates / missing + all_returned_arns = [t["TopicArn"] for t in resp["Topics"]] + [ + t["TopicArn"] for t in resp2["Topics"] + ] + assert set(topic_arns).issubset(set(all_returned_arns)) + + @markers.aws.validated + def test_topic_get_attributes_with_fifo_false(self, sns_create_topic, aws_client, snapshot): + resp = sns_create_topic( + Name=f"standard-topic-{short_uid()}", Attributes={"FifoTopic": "false"} + ) + topic_arn = resp["TopicArn"] + + attrs = aws_client.sns.get_topic_attributes(TopicArn=topic_arn) + snapshot.match("get-attrs-standard-topic", attrs) + + with pytest.raises(ClientError) as e: + aws_client.sns.set_topic_attributes( + TopicArn=topic_arn, AttributeName="FifoTopic", AttributeValue="false" + ) + snapshot.match("set-fifo-false-after-creation", e.value.response) + + @markers.aws.validated + def test_topic_add_permission(self, sns_create_topic, aws_client, snapshot, account_id): + topic_arn = sns_create_topic()["TopicArn"] + resp = aws_client.sns.add_permission( + TopicArn=topic_arn, Label="test", AWSAccountId=[account_id], ActionName=["Publish"] + ) + snapshot.match("add-permission-response", resp) + + attributes_resp = aws_client.sns.get_topic_attributes(TopicArn=topic_arn) + policy_str = attributes_resp["Attributes"]["Policy"] + policy_json = json.loads(policy_str) + snapshot.match("topic-policy-after-permission", policy_json) + + @markers.aws.validated + def test_topic_add_multiple_permissions( + self, sns_create_topic, aws_client, snapshot, account_id + ): + topic_arn = sns_create_topic()["TopicArn"] + resp = aws_client.sns.add_permission( + TopicArn=topic_arn, + Label="test", + AWSAccountId=[account_id], + ActionName=["Publish", "Subscribe"], + ) + snapshot.match("add-permission-response", resp) + + attributes_resp = aws_client.sns.get_topic_attributes(TopicArn=topic_arn) + policy_str = attributes_resp["Attributes"]["Policy"] + policy_json = json.loads(policy_str) + snapshot.match("topic-policy-after-permission", policy_json) + + @markers.aws.validated + def test_topic_remove_permission(self, sns_create_topic, aws_client, snapshot, account_id): + topic_arn = sns_create_topic()["TopicArn"] + label = "test" + aws_client.sns.add_permission( + TopicArn=topic_arn, Label=label, AWSAccountId=[account_id], ActionName=["Publish"] + ) + + aws_client.sns.remove_permission(TopicArn=topic_arn, Label=label) + attributes_resp = aws_client.sns.get_topic_attributes(TopicArn=topic_arn) + policy_str = attributes_resp["Attributes"]["Policy"] + policy_json = json.loads(policy_str) + snapshot.match("topic-policy", policy_json) + + @markers.aws.validated + def test_add_permission_errors(self, snapshot, aws_client, account_id): + topic_name = f"topic-{short_uid()}" + topic_arn = aws_client.sns.create_topic(Name=topic_name)["TopicArn"] + + aws_client.sns.add_permission( + TopicArn=topic_arn, + Label="test", + AWSAccountId=[account_id], + ActionName=["Publish"], + ) + + with pytest.raises(ClientError) as e: + aws_client.sns.add_permission( + TopicArn=topic_arn, + Label="test", + AWSAccountId=[account_id], + ActionName=["AddPermission"], + ) + snapshot.match("duplicate-label", e.value.response) + + with pytest.raises(ClientError) as e: + aws_client.sns.add_permission( + TopicArn=f"{topic_arn}-not-existing", + Label="test-2", + AWSAccountId=[account_id], + ActionName=["AddPermission"], + ) + snapshot.match("topic-not-found", e.value.response) + + with pytest.raises(ClientError) as e: + aws_client.sns.add_permission( + TopicArn=topic_arn, + Label="test-2", + AWSAccountId=[account_id], + ActionName=["InvalidAction"], + ) + snapshot.match("invalid-action", e.value.response) + + @markers.aws.validated + def test_remove_permission_errors(self, snapshot, aws_client, account_id): + topic_name = f"topic-{short_uid()}" + topic_arn = aws_client.sns.create_topic(Name=topic_name)["TopicArn"] + aws_client.sns.add_permission( + TopicArn=topic_arn, + Label="test", + AWSAccountId=[account_id], + ActionName=["Publish"], + ) + + with pytest.raises(ClientError) as e: + aws_client.sns.remove_permission(TopicArn=f"{topic_arn}-not-existing", Label="test") + + snapshot.match("topic-not-found", e.value.response) + + @markers.aws.validated + def test_data_protection_policy_crud(self, snapshot, aws_client, region_name): + topic_name = f"topic-{short_uid()}" + topic_arn = aws_client.sns.create_topic(Name=topic_name)["TopicArn"] + + policy_doc = { + "Name": "data_protection_policy", + "Description": "Test Policy", + "Version": "2021-06-01", + "Statement": [ + { + "Sid": "test-statement", + "DataDirection": "Inbound", + "Principal": ["*"], + "DataIdentifier": [ + f"arn:aws:dataprotection:{region_name}::data-identifier/EmailAddress" + ], + "Operation": {"Deny": {}}, + } + ], + } + + response = aws_client.sns.get_topic_attributes(TopicArn=topic_arn) + snapshot.match("get-topic-attributes-before-policy", response) + + response = aws_client.sns.put_data_protection_policy( + ResourceArn=topic_arn, DataProtectionPolicy=json.dumps(policy_doc) + ) + snapshot.match("put-data-protection-policy", response) + + response = aws_client.sns.get_data_protection_policy(ResourceArn=topic_arn) + snapshot.match("get-data-protection-policy", response) + + # check if policy shows up in the attributes + response = aws_client.sns.get_topic_attributes(TopicArn=topic_arn) + snapshot.match("get-topic-attributes-after-policy", response) + + class TestSNSPublishCrud: """ This class contains tests related to the global `Publish` validation, not tied to a particular kind of subscription """ @markers.aws.validated - @skip_if_sns_v2 def test_publish_by_path_parameters( self, sns_create_topic, @@ -395,7 +725,6 @@ def test_publish_by_path_parameters( assert msg_body["Message"] == message @markers.aws.validated - @skip_if_sns_v2 def test_publish_wrong_arn_format(self, snapshot, aws_client): message = "Good news everyone!" with pytest.raises(ClientError) as e: @@ -414,7 +743,6 @@ def test_publish_wrong_arn_format(self, snapshot, aws_client): snapshot.match("empty-topic", e.value.response) @markers.aws.validated - @skip_if_sns_v2 def test_publish_message_by_target_arn( self, sns_create_topic, sqs_create_queue, sns_create_sqs_subscription, snapshot, aws_client ): @@ -449,7 +777,6 @@ def test_publish_message_by_target_arn( snapshot.match("receive-target-arn", response) @markers.aws.validated - @skip_if_sns_v2 def test_publish_message_before_subscribe_topic( self, sns_create_topic, sqs_create_queue, sns_create_sqs_subscription, snapshot, aws_client ): @@ -478,7 +805,6 @@ def test_publish_message_before_subscribe_topic( snapshot.match("receive-messages", response) @markers.aws.validated - @skip_if_sns_v2 def test_unknown_topic_publish(self, sns_create_topic, snapshot, aws_client): # create topic to get the basic arn structure # otherwise you get InvalidClientTokenId exception because of account id @@ -498,7 +824,6 @@ def test_unknown_topic_publish(self, sns_create_topic, snapshot, aws_client): snapshot.match("error", e.value.response) @markers.aws.validated - @skip_if_sns_v2 def test_topic_publish_another_region( self, sns_create_topic, snapshot, aws_client, aws_client_factory, secondary_region_name ): @@ -538,7 +863,21 @@ def test_topic_publish_another_region( snapshot.match("error-batch", e.value.response) @markers.aws.validated - @skip_if_sns_v2 + def test_publish_no_confirm_subscription( + self, sns_create_topic, snapshot, sns_subscription, aws_client, e_mail_address + ): + topic_arn = sns_create_topic()["TopicArn"] + sns_subscription(TopicArn=topic_arn, Protocol="email", Endpoint=e_mail_address) + + # We are not confirming the subscription + def _assert_subscription(): + subscriptions = aws_client.sns.list_subscriptions()["Subscriptions"] + sub = [s for s in subscriptions if s["TopicArn"] == topic_arn][0] + assert sub["SubscriptionArn"] == "PendingConfirmation" + + retry(_assert_subscription, retries=15, sleep=2) + + @markers.aws.validated def test_publish_non_existent_target(self, sns_create_topic, snapshot, aws_client, region_name): topic_arn = sns_create_topic()["TopicArn"] account_id = parse_arn(topic_arn)["account"] @@ -550,7 +889,6 @@ def test_publish_non_existent_target(self, sns_create_topic, snapshot, aws_clien snapshot.match("non-existent-endpoint", ex.value.response) @markers.aws.validated - @skip_if_sns_v2 def test_publish_with_empty_subject(self, sns_create_topic, snapshot, aws_client): topic_arn = sns_create_topic()["TopicArn"] @@ -571,7 +909,6 @@ def test_publish_with_empty_subject(self, sns_create_topic, snapshot, aws_client snapshot.match("response-with-empty-subject", e.value.response) @markers.aws.validated - @skip_if_sns_v2 def test_empty_sns_message( self, sns_create_topic, sqs_create_queue, sns_create_sqs_subscription, snapshot, aws_client ): @@ -590,7 +927,6 @@ def test_empty_sns_message( snapshot.match("queue-attrs", queue_attrs) @markers.aws.validated - @skip_if_sns_v2 def test_publish_too_long_message(self, sns_create_topic, snapshot, aws_client): topic_arn = sns_create_topic()["TopicArn"] # simulate payload over 256kb @@ -622,7 +958,6 @@ def test_publish_too_long_message(self, sns_create_topic, snapshot, aws_client): assert publish["ResponseMetadata"]["HTTPStatusCode"] == 200 @markers.aws.validated - @skip_if_sns_v2 def test_publish_batch_too_long_message(self, sns_create_topic, snapshot, aws_client): topic_arn = sns_create_topic()["TopicArn"] # simulate payload over 256kb @@ -687,7 +1022,92 @@ def test_publish_batch_too_long_message(self, sns_create_topic, snapshot, aws_cl assert publish_batch["ResponseMetadata"]["HTTPStatusCode"] == 200 @markers.aws.validated - @skip_if_sns_v2 + def test_publish_batch_invalid_entry_id(self, sns_create_topic, snapshot, aws_client): + """Test validation of batch entry ID according to AWS specifications. + + Entry IDs must: + - Only contain alphanumeric characters, hyphens, and underscores + - Be at most 80 characters long + """ + topic_arn = sns_create_topic()["TopicArn"] + + # Test 1: ID with invalid character (dot) + with pytest.raises(ClientError) as e: + aws_client.sns.publish_batch( + TopicArn=topic_arn, + PublishBatchRequestEntries=[ + { + "Id": "message.id", + "Message": "test message", + } + ], + ) + snapshot.match("invalid-char-dot", e.value.response) + + # Test 2: ID with multiple invalid characters + with pytest.raises(ClientError) as e: + aws_client.sns.publish_batch( + TopicArn=topic_arn, + PublishBatchRequestEntries=[ + { + "Id": "msg@123#test", + "Message": "test message", + } + ], + ) + snapshot.match("invalid-char-special", e.value.response) + + # Test 3: ID that is too long (81 characters) + with pytest.raises(ClientError) as e: + aws_client.sns.publish_batch( + TopicArn=topic_arn, + PublishBatchRequestEntries=[ + { + "Id": "a" * 81, + "Message": "test message", + } + ], + ) + snapshot.match("id-too-long-81", e.value.response) + + # Test 4: ID that is way too long (91 characters) + with pytest.raises(ClientError) as e: + aws_client.sns.publish_batch( + TopicArn=topic_arn, + PublishBatchRequestEntries=[ + { + "Id": "myreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallylongid", + "Message": "test message", + } + ], + ) + snapshot.match("id-too-long-91", e.value.response) + + # Test 5: Valid ID with exactly 80 characters (should succeed) + publish_batch_response = aws_client.sns.publish_batch( + TopicArn=topic_arn, + PublishBatchRequestEntries=[ + { + "Id": "a" * 80, + "Message": "test message", + } + ], + ) + snapshot.match("valid-id-80-chars", publish_batch_response) + + # Test 6: Valid ID with allowed characters (should succeed) + publish_batch_response = aws_client.sns.publish_batch( + TopicArn=topic_arn, + PublishBatchRequestEntries=[ + { + "Id": "valid-message_123", + "Message": "test message", + } + ], + ) + snapshot.match("valid-id-with-hyphen-underscore", publish_batch_response) + + @markers.aws.validated def test_message_structure_json_exc(self, sns_create_topic, snapshot, aws_client): topic_arn = sns_create_topic()["TopicArn"] # TODO: add batch @@ -735,7 +1155,6 @@ def test_message_structure_json_exc(self, sns_create_topic, snapshot, aws_client class TestSNSSubscriptionCrud: @markers.aws.validated - @skip_if_sns_v2 def test_subscribe_with_invalid_protocol(self, sns_create_topic, sns_subscription, snapshot): topic_arn = sns_create_topic()["TopicArn"] @@ -747,7 +1166,6 @@ def test_subscribe_with_invalid_protocol(self, sns_create_topic, sns_subscriptio snapshot.match("exception", e.value.response) @markers.aws.validated - @skip_if_sns_v2 def test_unsubscribe_from_non_existing_subscription( self, sns_create_topic, sqs_create_queue, sns_create_sqs_subscription, snapshot, aws_client ): @@ -760,7 +1178,6 @@ def test_unsubscribe_from_non_existing_subscription( snapshot.match("empty-unsubscribe", response) @markers.aws.validated - @skip_if_sns_v2 def test_create_subscriptions_with_attributes( self, sns_create_topic, @@ -813,7 +1230,6 @@ def test_create_subscriptions_with_attributes( snapshot.match("get-attrs-nonexistent-sub", e.value.response) @markers.aws.validated - @skip_if_sns_v2 def test_not_found_error_on_set_subscription_attributes( self, sns_create_topic, @@ -868,7 +1284,6 @@ def check_subscription_deleted(): "$.invalid-json-filter-policy.Error.Message", # message contains java trace in AWS, assert instead ] ) - @skip_if_sns_v2 def test_validate_set_sub_attributes( self, sns_create_topic, @@ -942,7 +1357,6 @@ def test_validate_set_sub_attributes( @markers.snapshot.skip_snapshot_verify( paths=["$.invalid-token.Error.Message"] # validate the token shape ) - @skip_if_sns_v2 def test_sns_confirm_subscription_wrong_token(self, sns_create_topic, snapshot, aws_client): topic_arn = sns_create_topic()["TopicArn"] @@ -969,42 +1383,29 @@ def test_sns_confirm_subscription_wrong_token(self, sns_create_topic, snapshot, snapshot.match("token-not-exists", e.value.response) @markers.aws.validated - @markers.snapshot.skip_snapshot_verify( - paths=["$.list-subscriptions.Subscriptions"], - # there could be cleanup issues and don't want to flake, manually assert - ) - @skip_if_sns_v2 def test_list_subscriptions( self, sns_create_topic, sqs_create_queue, sqs_get_queue_arn, sns_subscription, - snapshot, aws_client, ): - snapshot.add_transformer(snapshot.transform.key_value("NextToken")) topic = sns_create_topic() topic_arn = topic["TopicArn"] - snapshot.match("create-topic-1", topic) topic_2 = sns_create_topic() topic_arn_2 = topic_2["TopicArn"] - snapshot.match("create-topic-2", topic_2) - sorting_list = [] + created_subscriptions = [] for i in range(3): queue_url = sqs_create_queue() queue_arn = sqs_get_queue_arn(queue_url) - subscription = sns_subscription(TopicArn=topic_arn, Protocol="sqs", Endpoint=queue_arn) - snapshot.match(f"sub-topic-1-{i}", subscription) - sorting_list.append((topic_arn, queue_arn)) + sns_subscription(TopicArn=topic_arn, Protocol="sqs", Endpoint=queue_arn) + created_subscriptions.append((topic_arn, queue_arn)) for i in range(3): queue_url = sqs_create_queue() queue_arn = sqs_get_queue_arn(queue_url) - subscription = sns_subscription( - TopicArn=topic_arn_2, Protocol="sqs", Endpoint=queue_arn - ) - snapshot.match(f"sub-topic-2-{i}", subscription) - sorting_list.append((topic_arn_2, queue_arn)) + sns_subscription(TopicArn=topic_arn_2, Protocol="sqs", Endpoint=queue_arn) + created_subscriptions.append((topic_arn_2, queue_arn)) list_subs = aws_client.sns.list_subscriptions() all_subs = list_subs["Subscriptions"] @@ -1013,14 +1414,10 @@ def test_list_subscriptions( list_subs = aws_client.sns.list_subscriptions(NextToken=next_token) all_subs.extend(list_subs["Subscriptions"]) - all_subs.sort(key=lambda x: sorting_list.index((x["TopicArn"], x["Endpoint"]))) - list_subs["Subscriptions"] = all_subs - snapshot.match("list-subscriptions-aggregated", list_subs) - - assert all((sub["TopicArn"], sub["Endpoint"]) in sorting_list for sub in all_subs) + all_sub_tuples = [(sub["TopicArn"], sub["Endpoint"]) for sub in all_subs] + assert all(sub in all_sub_tuples for sub in created_subscriptions) @markers.aws.validated - @skip_if_sns_v2 def test_list_subscriptions_by_topic_pagination( self, sns_create_topic, sns_subscription, snapshot, aws_client ): @@ -1062,7 +1459,6 @@ def test_list_subscriptions_by_topic_pagination( assert len(response["Subscriptions"]) <= 100 @markers.aws.validated - @skip_if_sns_v2 def test_subscribe_idempotency( self, aws_client, sns_create_topic, sqs_create_queue, sqs_get_queue_arn, snapshot ): @@ -1134,7 +1530,6 @@ def subscribe_queue_to_topic(attributes: dict = None) -> dict: snapshot.match("subscribe-diff-attributes", e.value.response) @markers.aws.validated - @skip_if_sns_v2 def test_unsubscribe_idempotency( self, sns_create_topic, sqs_create_queue, sns_create_sqs_subscription, snapshot, aws_client ): @@ -1151,7 +1546,6 @@ def test_unsubscribe_idempotency( snapshot.match("unsubscribe-2", unsubscribe_2) @markers.aws.validated - @skip_if_sns_v2 def test_unsubscribe_wrong_arn_format(self, snapshot, aws_client_factory, region_name): sns_client = aws_client_factory( region_name=region_name, config=Config(parameter_validation=False) @@ -1178,7 +1572,6 @@ def test_unsubscribe_wrong_arn_format(self, snapshot, aws_client_factory, region snapshot.match("invalid-unsubscribe-arn-4", e.value.response) @markers.aws.validated - @skip_if_sns_v2 def test_subscribe_with_invalid_topic(self, sns_create_topic, sns_subscription, snapshot): with pytest.raises(ClientError) as e: sns_subscription( @@ -1206,25 +1599,331 @@ def test_subscribe_with_invalid_topic(self, sns_create_topic, sns_subscription, snapshot.match("non-existent-topic", e.value.response) -class TestSNSSubscriptionLambda: +class TestSNSSubscriptionCrudV2: @markers.aws.validated - @skip_if_sns_v2 - def test_python_lambda_subscribe_sns_topic( - self, - sns_create_topic, - sns_subscription, - lambda_su_role, - create_lambda_function, - snapshot, - aws_client, - ): - function_name = f"lambda-function-{short_uid()}" - permission_id = f"test-statement-{short_uid()}" - subject = "[Subject] Test subject" - message = "Hello world." - topic_arn = sns_create_topic()["TopicArn"] + def test_subscribe_sms(self, sns_create_topic, aws_client, snapshot): + topic_name = f"test-topic-{short_uid()}" + snapshot.add_transformer(snapshot.transform.regex(topic_name, "")) + topic_arn = sns_create_topic(Name=topic_name)["TopicArn"] - lambda_creation_response = create_lambda_function( + resp = aws_client.sns.subscribe( + TopicArn=topic_arn, + Protocol="sms", + Endpoint="+1234567890", + ) + snapshot.match("subscribe-sms-1", resp) + + # FIXME + @pytest.mark.skipif(not is_aws_cloud(), reason="not accepting valid sms endpoint") + @markers.aws.validated + def test_subscribe_sms_obscure_phone_number(self, sns_create_topic, aws_client, snapshot): + topic_name = f"test-topic-{short_uid()}" + snapshot.add_transformer(snapshot.transform.regex(topic_name, "")) + topic_arn = sns_create_topic(Name=topic_name)["TopicArn"] + resp = aws_client.sns.subscribe( + TopicArn=topic_arn, + Protocol="sms", + Endpoint="+12/34-567.890", + ) + snapshot.match("subscribe-sms-2", resp) + + @markers.aws.validated + def test_subscribe_unknown_topic(self, aws_client, snapshot, account_id, region_name): + with pytest.raises(ClientError) as e: + aws_client.sns.subscribe( + TopicArn=f"arn:aws:sns:{region_name}:{account_id}:unknown-{short_uid()}", + Protocol="sms", + Endpoint="+1234567890", + ) + snapshot.match("subscribe-unknown-topic", e.value.response) + + @markers.aws.validated + def test_subscribe_unknown_sqs_queue( + self, sns_create_topic, aws_client, snapshot, account_id, region_name + ): + topic_name = f"test-topic-{short_uid()}" + snapshot.add_transformer(snapshot.transform.regex(topic_name, "")) + topic_arn = sns_create_topic(Name=topic_name)["TopicArn"] + resp = aws_client.sns.subscribe( + TopicArn=topic_arn, + Protocol="sqs", + Endpoint=f"arn:aws:sqs:{region_name}:{account_id}:unknown-{short_uid()}", + ) + snapshot.match("subscribe-unknown-sqs", resp) + + with pytest.raises(ClientError) as e: + aws_client.sns.subscribe( + TopicArn=topic_arn, + Protocol="sqs", + Endpoint="unknown", + ) + snapshot.match("subscribe-unknown-sqs-invalid_arn", e.value.response) + + @markers.aws.validated + def test_subscribe_sqs_queue_url( + self, sns_create_topic, sqs_create_queue, aws_client, snapshot + ): + topic_arn = sns_create_topic(Name=f"sqs-topic-{short_uid()}")["TopicArn"] + queue_url = sqs_create_queue(QueueName=f"queue-{short_uid()}") + + with pytest.raises(ClientError) as e: + aws_client.sns.subscribe( + TopicArn=topic_arn, + Protocol="sqs", + Endpoint=queue_url, + ) + + snapshot.match("subscribe-sqs-via-url-error", e.value.response) + + @markers.aws.validated + def test_subscribe_invalid_sms(self, sns_create_topic, aws_client, snapshot): + topic_arn = sns_create_topic(Name=f"bad-sms-{short_uid()}")["TopicArn"] + + invalid_numbers = ["+15--551234567", "NAA+15551234567", "+15551234567.", "/+15551234567"] + + for number in invalid_numbers: + with pytest.raises(ClientError) as e: + aws_client.sns.subscribe( + TopicArn=topic_arn, + Protocol="sms", + Endpoint=number, + ) + snapshot.match(f"subscribe-bad-sms-{number}", e.value.response) + + # TODO: Parametrize for email protocol as well + @markers.aws.validated + def test_creating_subscription(self, sns_create_topic, aws_client, snapshot): + topic_arn = sns_create_topic(Name=f"create-sub-{short_uid()}")["TopicArn"] + + resp = aws_client.sns.subscribe( + TopicArn=topic_arn, Protocol="http", Endpoint="http://example.com/" + ) + # TODO: investigate why it leaves the subscription in `SNS.ListSubscriptions`, we maybe need to clean up + # after deleting topics, not fully in parity as AWS cleans up instantly + snapshot.match("create-subscription", resp) + + # TODO: parametrize for email protocol + @markers.aws.validated + def test_unsubscribe_from_deleted_topic(self, sns_create_topic, aws_client, snapshot): + topic_arn = sns_create_topic(Name=f"del-topic-sub-{short_uid()}")["TopicArn"] + + sub_arn = aws_client.sns.subscribe( + TopicArn=topic_arn, + Protocol="http", + Endpoint="http://example.com/", + )["SubscriptionArn"] + + aws_client.sns.delete_topic(TopicArn=topic_arn) + + with pytest.raises(ClientError) as e: + aws_client.sns.unsubscribe(SubscriptionArn=sub_arn) + snapshot.match("unsubscribe-deleted-topic", e.value.response) + + # TODO: parametrize for http and email protocol + @markers.aws.validated + def test_getting_subscriptions_by_topic( + self, sns_create_topic, sqs_create_queue, sqs_get_queue_arn, aws_client, snapshot + ): + topic_arn = sns_create_topic(Name=f"get-subs-{short_uid()}")["TopicArn"] + queue_url = sqs_create_queue(QueueName=f"queue-{short_uid()}") + + aws_client.sns.subscribe( + TopicArn=topic_arn, + Protocol="sqs", + Endpoint=sqs_get_queue_arn(queue_url), + ) + + resp = aws_client.sns.list_subscriptions_by_topic(TopicArn=topic_arn) + snapshot.match("list-subscriptions-by-topic", resp) + + @markers.aws.validated + def test_subscription_paging(self, sns_create_topic, aws_client, snapshot, sns_subscription): + topic_arn = sns_create_topic(Name=f"paging-sub-{short_uid()}")["TopicArn"] + + sub_arns = [] + for i in range(120): + sub_arns.append( + sns_subscription( + TopicArn=topic_arn, + Protocol="email", + Endpoint=f"user{i}@example.com", + )["SubscriptionArn"] + ) + + resp = aws_client.sns.list_subscriptions_by_topic(TopicArn=topic_arn) + assert "NextToken" in resp + + # TODO: parametrize for http and email protocol + @markers.aws.validated + def test_subscribe_attributes( + self, + sns_create_topic, + aws_client, + snapshot, + sqs_create_queue, + sqs_get_queue_arn, + sns_subscription, + ): + topic_arn = sns_create_topic(Name=f"get-subs-{short_uid()}")["TopicArn"] + queue_url = sqs_create_queue(QueueName=f"queue-{short_uid()}") + + subscribe_response = sns_subscription( + TopicArn=topic_arn, + Protocol="sqs", + Endpoint=sqs_get_queue_arn(queue_url), + ) + sub_arn = subscribe_response["SubscriptionArn"] + + resp = aws_client.sns.get_subscription_attributes(SubscriptionArn=sub_arn) + snapshot.match("get-subscription-attributes", resp) + + # TODO: parametrize for http and email protocol + @markers.aws.validated + def test_creating_subscription_with_attributes( + self, + sns_create_topic, + aws_client, + snapshot, + sqs_create_queue, + sqs_get_queue_arn, + sns_subscription, + ): + topic_arn = sns_create_topic(Name=f"get-subs-{short_uid()}")["TopicArn"] + queue_url = sqs_create_queue(QueueName=f"queue-{short_uid()}") + + sub_arn = sns_subscription( + TopicArn=topic_arn, + Protocol="sqs", + Endpoint=sqs_get_queue_arn(queue_url), + Attributes={"RawMessageDelivery": "true"}, + )["SubscriptionArn"] + + attrs = aws_client.sns.get_subscription_attributes(SubscriptionArn=sub_arn) + snapshot.match("subscription-with-attributes", attrs) + + # TODO: parametrize for http and email protocol + @markers.aws.validated + def test_set_subscription_attributes( + self, + sns_create_topic, + aws_client, + snapshot, + sqs_create_queue, + sqs_get_queue_arn, + sns_subscription, + ): + topic_arn = sns_create_topic(Name=f"get-subs-{short_uid()}")["TopicArn"] + queue_url = sqs_create_queue(QueueName=f"queue-{short_uid()}") + + sub_arn = sns_subscription( + TopicArn=topic_arn, + Protocol="sqs", + Endpoint=sqs_get_queue_arn(queue_url), + )["SubscriptionArn"] + + aws_client.sns.set_subscription_attributes( + SubscriptionArn=sub_arn, + AttributeName="RawMessageDelivery", + AttributeValue="true", + ) + + attrs = aws_client.sns.get_subscription_attributes(SubscriptionArn=sub_arn) + snapshot.match("set-subscription-attributes", attrs) + + @markers.snapshot.skip_snapshot_verify( + paths=["$..Error.Message"], + # AWS adds a strange stacktrace that contains REDACTED at the end. The "regular" error message matches + ) + @markers.aws.validated + def test_subscribe_invalid_filter_policy(self, sns_create_topic, aws_client, snapshot): + topic_arn = sns_create_topic(Name=f"filter-policy-{short_uid()}")["TopicArn"] + + with pytest.raises(ClientError) as e: + aws_client.sns.subscribe( + TopicArn=topic_arn, + Protocol="email", + Endpoint="test@example.com", + Attributes={"FilterPolicy": "invalid-json"}, + ) + snapshot.match("subscribe-invalid-filter-policy", e.value.response) + + # FIXME + @pytest.mark.skip( + reason="Https for aws lambda URL required but not implemented in localstack lambda" + ) + @markers.aws.validated + def test_confirm_subscription( + self, sns_create_topic, aws_client, snapshot, create_lambda_function + ): + snapshot.add_transformer(TransformerUtility.key_value("SubscriptionArn")) + topic_arn = sns_create_topic(Name=f"confirm-sub-{short_uid()}")["TopicArn"] + function_name = f"lambda-{short_uid()}" + create_lambda_function( + handler_file=TEST_LAMBDA_PYTHON_ECHO, + func_name=function_name, + runtime=Runtime.python3_12, + ) + + url_config = aws_client.lambda_.create_function_url_config( + FunctionName=function_name, AuthType="NONE" + ) + aws_client.lambda_.add_permission( + FunctionName=function_name, + Action="lambda:InvokeFunctionUrl", + StatementId="AllowSNSInvoke", + Principal="*", + FunctionUrlAuthType="NONE", + ) + + aws_client.sns.subscribe( + TopicArn=topic_arn, + Protocol="https", + Endpoint=url_config["FunctionUrl"], + ) + + def _get_token(): + token_message = aws_client.logs.filter_log_events( + logGroupName=f"/aws/lambda/{function_name}", filterPattern="Token=" + )["events"][0]["message"] + confirmation_url = json.loads(json.loads(token_message)["body"])["SubscribeURL"] + token = confirmation_url.split("Token=")[1] + return token + + token = retry(_get_token, retries=5, sleep=2) + resp = aws_client.sns.confirm_subscription( + TopicArn=topic_arn, Token=token, AuthenticateOnUnsubscribe="true" + ) + snapshot.match("confirm-subscription", resp) + + @markers.aws.validated + def test_get_subscription_attributes_error_not_exists( + self, aws_client, snapshot, account_id, region_name + ): + with pytest.raises(ClientError) as e: + aws_client.sns.get_subscription_attributes( + SubscriptionArn=f"arn:aws:sns:{region_name}:{account_id}:nonexistent:{uuid.uuid4()}" + ) + snapshot.match("get-sub-attrs-nonexistent", e.value.response) + + +class TestSNSSubscriptionLambda: + @markers.aws.validated + def test_python_lambda_subscribe_sns_topic( + self, + sns_create_topic, + sns_subscription, + lambda_su_role, + create_lambda_function, + snapshot, + aws_client, + ): + function_name = f"lambda-function-{short_uid()}" + permission_id = f"test-statement-{short_uid()}" + subject = "[Subject] Test subject" + message = "Hello world." + topic_arn = sns_create_topic()["TopicArn"] + + lambda_creation_response = create_lambda_function( func_name=function_name, handler_file=TEST_LAMBDA_PYTHON_ECHO, runtime=Runtime.python3_12, @@ -1270,7 +1969,6 @@ def check_subscription(): snapshot.match("notification", notification) @markers.aws.validated - @skip_if_sns_v2 def test_sns_topic_as_lambda_dead_letter_queue( self, lambda_su_role, @@ -1363,7 +2061,6 @@ def receive_dlq(): snapshot.match("messages", messages) @markers.aws.validated - @skip_if_sns_v2 def test_redrive_policy_lambda_subscription( self, sns_create_topic, @@ -1419,7 +2116,6 @@ def test_redrive_policy_lambda_subscription( @markers.aws.validated @pytest.mark.parametrize("signature_version", ["1", "2"]) - @skip_if_sns_v2 def test_publish_lambda_verify_signature( self, aws_client, @@ -1524,7 +2220,6 @@ def check_subscription(): class TestSNSSubscriptionSQS: @markers.aws.validated - @skip_if_sns_v2 def test_subscribe_sqs_queue( self, sqs_create_queue, sns_create_topic, sns_create_sqs_subscription, snapshot, aws_client ): @@ -1565,7 +2260,6 @@ def test_subscribe_sqs_queue( snapshot.match("messages", response) @markers.aws.validated - @skip_if_sns_v2 def test_publish_unicode_chars( self, sns_create_topic, sqs_create_queue, sns_create_sqs_subscription, snapshot, aws_client ): @@ -1584,7 +2278,6 @@ def test_publish_unicode_chars( snapshot.match("received-message", response) @markers.aws.validated - @skip_if_sns_v2 def test_attribute_raw_subscribe( self, sns_create_topic, sqs_create_queue, sns_create_sqs_subscription, snapshot, aws_client ): @@ -1628,7 +2321,6 @@ def test_attribute_raw_subscribe( snapshot.match("messages-response", response) @markers.aws.validated - @skip_if_sns_v2 def test_sqs_topic_subscription_confirmation( self, sns_create_topic, sqs_create_queue, sns_create_sqs_subscription, snapshot, aws_client ): @@ -1652,7 +2344,6 @@ def check_subscription(): assert poll_condition(check_subscription, timeout=5) @markers.aws.validated - @skip_if_sns_v2 def test_publish_sqs_from_sns( self, sns_create_topic, sqs_create_queue, sns_create_sqs_subscription, snapshot, aws_client ): @@ -1720,7 +2411,6 @@ def test_publish_sqs_from_sns( } @markers.aws.validated - @skip_if_sns_v2 def test_publish_batch_messages_from_sns_to_sqs( self, sns_create_topic, sqs_create_queue, sns_create_sqs_subscription, snapshot, aws_client ): @@ -1798,7 +2488,6 @@ def get_messages(): snapshot.match("messages", {"Messages": messages}) @markers.aws.validated - @skip_if_sns_v2 def test_publish_batch_messages_without_topic(self, sns_create_topic, snapshot, aws_client): topic_arn = sns_create_topic()["TopicArn"] fake_topic_arn = topic_arn + "fake-topic" @@ -1817,7 +2506,6 @@ def test_publish_batch_messages_without_topic(self, sns_create_topic, snapshot, snapshot.match("publish-batch-no-topic", e.value.response) @markers.aws.validated - @skip_if_sns_v2 def test_publish_batch_exceptions( self, sns_create_topic, sqs_create_queue, sns_create_sqs_subscription, snapshot, aws_client ): @@ -1883,7 +2571,6 @@ def test_publish_batch_exceptions( snapshot.match("no-default-key-json", e.value.response) @markers.aws.validated - @skip_if_sns_v2 def test_subscribe_to_sqs_with_queue_url( self, sns_create_topic, sqs_create_queue, sns_subscription, snapshot ): @@ -1895,7 +2582,6 @@ def test_subscribe_to_sqs_with_queue_url( snapshot.match("sub-queue-url", e.value.response) @markers.aws.validated - @skip_if_sns_v2 def test_publish_sqs_from_sns_with_xray_propagation( self, sns_create_topic, sqs_create_queue, sns_create_sqs_subscription, snapshot, aws_client ): @@ -1934,7 +2620,6 @@ def add_xray_header(request, **_kwargs): @pytest.mark.parametrize("raw_message_delivery", [True, False]) @markers.aws.validated - @skip_if_sns_v2 def test_redrive_policy_sqs_queue_subscription( self, sns_create_topic, @@ -2009,7 +2694,6 @@ def test_redrive_policy_sqs_queue_subscription( snapshot.match("messages", response) @markers.aws.validated - @skip_if_sns_v2 def test_message_attributes_not_missing( self, sns_create_sqs_subscription, sns_create_topic, sqs_create_queue, snapshot, aws_client ): @@ -2081,7 +2765,6 @@ def test_message_attributes_not_missing( # https://docs.aws.amazon.com/sns/latest/api/API_MessageAttributeValue.html @markers.aws.validated - @skip_if_sns_v2 def test_subscription_after_failure_to_deliver( self, sns_create_topic, @@ -2180,7 +2863,6 @@ def test_subscription_after_failure_to_deliver( snapshot.match(f"message-{i}-after-delete", response) @markers.aws.validated - @skip_if_sns_v2 def test_empty_or_wrong_message_attributes( self, sns_create_sqs_subscription, @@ -2245,7 +2927,6 @@ def test_empty_or_wrong_message_attributes( snapshot.match(f"batch-{error_type}", e.value.response) @markers.aws.validated - @skip_if_sns_v2 def test_message_attributes_prefixes( self, sns_create_sqs_subscription, sns_create_topic, sqs_create_queue, snapshot, aws_client ): @@ -2291,7 +2972,6 @@ def test_message_attributes_prefixes( snapshot.match("publish-ok-2", response) @markers.aws.validated - @skip_if_sns_v2 def test_message_structure_json_to_sqs( self, aws_client, sns_create_topic, sqs_create_queue, snapshot, sns_create_sqs_subscription ): @@ -2328,7 +3008,6 @@ def test_message_structure_json_to_sqs( @markers.aws.validated @pytest.mark.parametrize("signature_version", ["1", "2"]) - @skip_if_sns_v2 def test_publish_sqs_verify_signature( self, aws_client, @@ -2393,7 +3072,6 @@ def test_publish_sqs_verify_signature( assert is_valid is None @markers.aws.validated - @skip_if_sns_v2 def test_publish_message_group_id( self, aws_client, @@ -2424,7 +3102,6 @@ def test_publish_message_group_id( class TestSNSSubscriptionSQSFifo: @markers.aws.validated @pytest.mark.parametrize("content_based_deduplication", [True, False]) - @skip_if_sns_v2 def test_message_to_fifo_sqs( self, sns_create_topic, @@ -2486,7 +3163,6 @@ def test_message_to_fifo_sqs( "$.dedup-messages.Messages" ], # FIXME: introduce deduplication at Topic level, not only SQS ) - @skip_if_sns_v2 def test_fifo_topic_to_regular_sqs( self, sns_create_topic, @@ -2545,7 +3221,6 @@ def test_fifo_topic_to_regular_sqs( snapshot.match("dedup-messages", response) @markers.aws.validated - @skip_if_sns_v2 def test_validations_for_fifo( self, sns_create_topic, @@ -2629,15 +3304,7 @@ def test_validations_for_fifo( snapshot.match("no-msg-dedup-regular-topic", e.value.response) @markers.aws.validated - @markers.snapshot.skip_snapshot_verify( - paths=[ - "$.topic-attrs.Attributes.DeliveryPolicy", - "$.topic-attrs.Attributes.EffectiveDeliveryPolicy", - "$.topic-attrs.Attributes.Policy.Statement..Action", # SNS:Receive is added by moto but not returned in AWS - ] - ) @pytest.mark.parametrize("raw_message_delivery", [True, False]) - @skip_if_sns_v2 def test_publish_fifo_messages_to_dlq( self, sns_create_topic, @@ -2794,15 +3461,11 @@ def get_messages_from_dlq(amount_msg: int): @markers.aws.validated @markers.snapshot.skip_snapshot_verify( paths=[ - "$.topic-attrs.Attributes.DeliveryPolicy", - "$.topic-attrs.Attributes.EffectiveDeliveryPolicy", - "$.topic-attrs.Attributes.Policy.Statement..Action", # SNS:Receive is added by moto but not returned in AWS "$.republish-batch-response-fifo.Successful..MessageId", # TODO: SNS doesnt keep track of duplicate "$.republish-batch-response-fifo.Successful..SequenceNumber", # TODO: SNS doesnt keep track of duplicate - ] + ], ) @pytest.mark.parametrize("content_based_deduplication", [True, False]) - @skip_if_sns_v2 def test_publish_batch_messages_from_fifo_topic_to_fifo_queue( self, sns_create_topic, @@ -2939,7 +3602,6 @@ def get_messages(): @markers.aws.validated @pytest.mark.parametrize("raw_message_delivery", [True, False]) - @skip_if_sns_v2 def test_publish_to_fifo_topic_to_sqs_queue_no_content_dedup( self, sns_create_topic, @@ -3021,7 +3683,6 @@ def get_messages(): snapshot.match("messages", {"Messages": messages}) @markers.aws.validated - @skip_if_sns_v2 def test_publish_to_fifo_topic_deduplication_on_topic_level( self, sns_create_topic, @@ -3082,7 +3743,6 @@ def test_publish_to_fifo_topic_deduplication_on_topic_level( snapshot.match("dedup-messages", response) @markers.aws.validated - @skip_if_sns_v2 def test_publish_to_fifo_with_target_arn(self, sns_create_topic, aws_client): topic_name = f"topic-{short_uid()}.fifo" topic_attributes = { @@ -3105,7 +3765,6 @@ def test_publish_to_fifo_with_target_arn(self, sns_create_topic, aws_client): assert "MessageId" in response @markers.aws.validated - @skip_if_sns_v2 def test_message_to_fifo_sqs_ordering( self, sns_create_topic, @@ -3122,126 +3781,762 @@ def test_message_to_fifo_sqs_ordering( Attributes=topic_attributes, )["TopicArn"] - queue_attributes = {"FifoQueue": "true", "ContentBasedDeduplication": "true"} - queues = [] - queue_amount = 5 - message_amount = 10 + queue_attributes = {"FifoQueue": "true", "ContentBasedDeduplication": "true"} + queues = [] + queue_amount = 5 + message_amount = 10 + + for _ in range(queue_amount): + queue_name = f"queue-{short_uid()}.fifo" + queue_url = sqs_create_queue( + QueueName=queue_name, + Attributes=queue_attributes, + ) + sns_create_sqs_subscription( + topic_arn=topic_arn, queue_url=queue_url, Attributes={"RawMessageDelivery": "true"} + ) + queues.append(queue_url) + + for i in range(message_amount): + aws_client.sns.publish( + TopicArn=topic_arn, Message=str(i), MessageGroupId="message-group-id-1" + ) + + all_messages = [] + for queue_url in queues: + messages = sqs_collect_messages( + queue_url, + expected=message_amount, + timeout=10, + max_number_of_messages=message_amount, + ) + contents = [message["Body"] for message in messages] + all_messages.append(contents) + + # we're expecting the order to be the same across all queues + reference_order = all_messages[0] + for received_content in all_messages[1:]: + assert received_content == reference_order + + +class TestSNSSubscriptionSES: + @markers.requires_in_process + @markers.aws.only_localstack + def test_topic_email_subscription_confirmation( + self, sns_create_topic, sns_subscription, aws_client + ): + # FIXME: we do not send the token to the email endpoint, so they cannot validate it + # create AWS validated test for format + # for now, access internals + topic_arn = sns_create_topic()["TopicArn"] + subscription = sns_subscription( + TopicArn=topic_arn, + Protocol="email", + Endpoint="localstack@yopmail.com", + ) + subscription_arn = subscription["SubscriptionArn"] + parsed_arn = parse_arn(subscription_arn) + store = SnsProvider.get_store(parsed_arn["account"], parsed_arn["region"]) + + sub_attr = aws_client.sns.get_subscription_attributes(SubscriptionArn=subscription_arn) + assert sub_attr["Attributes"]["PendingConfirmation"] == "true" + + def check_subscription(): + for token, sub_arn in store.subscription_tokens.items(): + if sub_arn == subscription_arn: + aws_client.sns.confirm_subscription(TopicArn=topic_arn, Token=token) + + sub_attributes = aws_client.sns.get_subscription_attributes( + SubscriptionArn=subscription_arn + ) + assert sub_attributes["Attributes"]["PendingConfirmation"] == "false" + + retry(check_subscription, retries=PUBLICATION_RETRIES, sleep=PUBLICATION_TIMEOUT) + + @markers.requires_in_process + @markers.aws.only_localstack + def test_email_sender( + self, + sns_create_topic, + sns_subscription, + aws_client, + monkeypatch, + ): + # make sure to reset all received emails in SES + requests.delete("http://localhost:4566/_aws/ses") + + topic_arn = sns_create_topic()["TopicArn"] + sns_subscription( + TopicArn=topic_arn, + Protocol="email", + Endpoint="localstack@yopmail.com", + ) + + aws_client.sns.publish( + Message="Test message", + TopicArn=topic_arn, + ) + + def _get_messages(amount: int) -> list[dict]: + response = requests.get("http://localhost:4566/_aws/ses").json() + assert len(response["messages"]) == amount + return response["messages"] + + messages = retry(lambda: _get_messages(1), retries=PUBLICATION_RETRIES, sleep=1) + # legacy default value, should be replaced at some point + assert messages[0]["Source"] == "admin@localstack.com" + requests.delete("http://localhost:4566/_aws/ses") + + sender_address = "no-reply@sns.localstack.cloud" + monkeypatch.setattr(config, "SNS_SES_SENDER_ADDRESS", sender_address) + + aws_client.sns.publish( + Message="Test message", + TopicArn=topic_arn, + ) + messages = retry(lambda: _get_messages(1), retries=PUBLICATION_RETRIES, sleep=1) + assert messages[0]["Source"] == sender_address + + +@pytest.fixture(scope="class") +def platform_credentials() -> tuple[str, str]: + # these values need to be extracted from a real amazon developer account if tested against AWS + # https://developer.amazon.com/settings/console/securityprofile/overview.html + client_id = "dummy" + client_secret = "dummy" + return client_id, client_secret + + +@pytest.fixture(scope="class") +def e_mail_address() -> str: + # this address must be real and accessible if you want to test email subscriptions + e_mail = "test@example.com" + return e_mail + + +@pytest.fixture(scope="class") +def phone_number() -> str: + # if you want to test phone number operations against AWS and a real phone number, replace this value + # and use this fixture. + # note: you might need to verify that number first in your AWS account due to the sms sandbox + phone_number = "+430000000000" + return phone_number + + +class TestSNSPlatformApplicationCrud: + @markers.aws.manual_setup_required + def test_create_platform_application( + self, aws_client, snapshot, sns_create_platform_application, platform_credentials + ): + platform = "ADM" + # if tested against AWS, the fixture needs to contain real credentials + client_id, client_secret = platform_credentials + attributes = {"PlatformPrincipal": client_id, "PlatformCredential": client_secret} + response = sns_create_platform_application(Platform=platform, Attributes=attributes) + snapshot.match("create-platform-application", response) + + @markers.aws.manual_setup_required + def test_list_platform_applications( + self, aws_client, snapshot, sns_create_platform_application, platform_credentials + ): + name = f"platform-application-{short_uid()}" + platform = "ADM" + # if tested against AWS, the fixture needs to contain real credentials + client_id, client_secret = platform_credentials + attributes = {"PlatformPrincipal": client_id, "PlatformCredential": client_secret} + sns_create_platform_application(Name=name, Platform=platform, Attributes=attributes) + + response = aws_client.sns.list_platform_applications() + snapshot.match("list-platform-applications", response) + + @pytest.mark.parametrize( + "attributes", + [ + {}, + {"PlatformPrincipal": "dummy"}, + {"PlatformCredential": "dummy"}, + ], + ids=["no-args", "missing-credential", "missing-principal"], + ) + @markers.aws.validated + def test_create_platform_application_invalid_attributes(self, aws_client, snapshot, attributes): + # We cannot actually verify the validity of the passed credentials, which is why it is not part of this test + name = f"platform-application-{short_uid()}" + platform = "ADM" + with pytest.raises(ClientError) as e: + aws_client.sns.create_platform_application( + Name=name, Platform=platform, Attributes=attributes + ) + snapshot.match("platform-application-no-attributes", e.value.response) + + @pytest.mark.parametrize( + "name", [f"{'a' * 257}", "", "@name"], ids=["too-long", "empty", "invalid-char"] + ) + @markers.aws.validated + def test_create_platform_application_invalid_name(self, aws_client, snapshot, name): + attributes = {"PlatformPrincipal": "dummy", "PlatformCredential": "dummy"} + platform = "ADM" + with pytest.raises(ClientError) as e: + aws_client.sns.create_platform_application( + Name=name, Platform=platform, Attributes=attributes + ) + snapshot.match("invalid-application-name", e.value.response) + + @markers.aws.validated + def test_create_platform_application_invalid_platform(self, aws_client, snapshot): + attributes = {"PlatformPrincipal": "dummy", "PlatformCredential": "dummy"} + + name = f"platform-application-{short_uid()}" + invalid_platform = "AAA" + with pytest.raises(ClientError) as e: + aws_client.sns.create_platform_application( + Name=name, Platform=invalid_platform, Attributes=attributes + ) + snapshot.match("invalid-platform", e.value.response) + + @markers.aws.manual_setup_required + def test_get_platform_application_attributes( + self, aws_client, snapshot, sns_create_platform_application, platform_credentials + ): + name = f"platform-application-{short_uid()}" + platform = "ADM" + # if tested against AWS, the fixture needs to contain real credentials + client_id, client_secret = platform_credentials + attributes = {"PlatformPrincipal": client_id, "PlatformCredential": client_secret} + platform_application_arn = sns_create_platform_application( + Name=name, Platform=platform, Attributes=attributes + )["PlatformApplicationArn"] + response = aws_client.sns.get_platform_application_attributes( + PlatformApplicationArn=platform_application_arn + ) + snapshot.match("get-application-attributes", response) + + @markers.aws.validated + def test_get_platform_application_attributes_invalid_arn(self, aws_client, snapshot): + with pytest.raises(ClientError) as e: + aws_client.sns.get_platform_application_attributes(PlatformApplicationArn="invalid-arn") + snapshot.match("invalid-application-arn", e.value.response) + + @markers.aws.validated + def test_get_platform_application_attributes_non_existing_app( + self, aws_client, snapshot, account_id, region_name + ): + with pytest.raises(ClientError) as e: + aws_client.sns.get_platform_application_attributes( + PlatformApplicationArn=f"arn:aws:sns:{region_name}:{account_id}:app/ADM/NonExistingApp" + ) + snapshot.match("non_existing-application-arn", e.value.response) + + @markers.aws.manual_setup_required + def test_set_platform_application_attributes( + self, aws_client, snapshot, sns_create_platform_application, platform_credentials + ): + name = f"platform-application-{short_uid()}" + platform = "ADM" + # if tested against AWS, the fixture needs to contain real credentials + client_id, client_secret = platform_credentials + attributes = {"PlatformPrincipal": client_id, "PlatformCredential": client_secret} + platform_application_arn = sns_create_platform_application( + Name=name, Platform=platform, Attributes=attributes + )["PlatformApplicationArn"] + + attributes = {"SuccessFeedbackSampleRate": "50"} + aws_client.sns.set_platform_application_attributes( + Attributes=attributes, PlatformApplicationArn=platform_application_arn + ) + # give the attributes time to propagate + if is_aws_cloud(): + time.sleep(30) + response = aws_client.sns.get_platform_application_attributes( + PlatformApplicationArn=platform_application_arn + ) + snapshot.match("set-get-application-attributes", response) + + @markers.aws.validated + def test_set_platform_application_attributes_invalid_arn(self, aws_client, snapshot): + with pytest.raises(ClientError) as e: + aws_client.sns.set_platform_application_attributes( + PlatformApplicationArn="invalid-arn", Attributes={} + ) + snapshot.match("invalid-application-arn", e.value.response) + + @pytest.mark.parametrize( + "attributes", + [ + {}, + {"PlatformPrincipal": "dummy"}, + ], + ids=["no-args", "dummy-args"], + ) + @markers.aws.validated + def test_set_platform_application_attributes_non_existing_app( + self, aws_client, snapshot, account_id, region_name, attributes + ): + with pytest.raises(ClientError) as e: + aws_client.sns.set_platform_application_attributes( + PlatformApplicationArn=f"arn:aws:sns:{region_name}:{account_id}:app/ADM/NonExistingApp", + Attributes=attributes, + ) + snapshot.match("non_existing-application-arn", e.value.response) + + +class TestSNSPlatformEndpointCrud: + @markers.aws.manual_setup_required + def test_create_platform_endpoint( + self, + sns_create_platform_application, + sns_create_platform_endpoint, + aws_client, + account_id, + region_name, + platform_credentials, + snapshot, + ): + # if tested against AWS, the fixture needs to contain real credentials + app_name = f"platform-application-{short_uid()}" + snapshot.add_transformer(RegexTransformer(app_name, "")) + principal, credential = platform_credentials + attributes = {"PlatformPrincipal": principal, "PlatformCredential": credential} + app_arn = sns_create_platform_application( + Name=app_name, Platform="ADM", Attributes=attributes + )["PlatformApplicationArn"] + response = sns_create_platform_endpoint(platform_application_arn=app_arn, token="token_1") + snapshot.match("create-platform-endpoint", response) + + @markers.aws.manual_setup_required + def test_create_platform_endpoint_idempotency( + self, + sns_create_platform_application, + aws_client, + account_id, + region_name, + platform_credentials, + sns_create_platform_endpoint, + snapshot, + ): + # if tested against AWS, the fixture needs to contain real credentials + principal, credential = platform_credentials + attributes = {"PlatformPrincipal": principal, "PlatformCredential": credential} + app_name = f"platform-application-{short_uid()}" + snapshot.add_transformer(RegexTransformer(app_name, "")) + app_arn = sns_create_platform_application( + Name=app_name, Platform="ADM", Attributes=attributes + )["PlatformApplicationArn"] + response = sns_create_platform_endpoint(platform_application_arn=app_arn, token="token_1") + snapshot.match("create-platform-endpoint", response) + + # create again with the same attributes and token + response = sns_create_platform_endpoint(platform_application_arn=app_arn, token="token_1") + snapshot.match("create-platform-endpoint-idempotent", response) + + # create again with different attributes + with pytest.raises(ClientError) as e: + sns_create_platform_endpoint( + platform_application_arn=app_arn, token="token_1", Attributes={"Enabled": "false"} + ) + snapshot.match("create-platform-endpoint-different-token", e.value.response) + + @markers.aws.validated + def test_create_platform_endpoint_non_existent_app( + self, + sns_create_platform_application, + aws_client, + account_id, + region_name, + snapshot, + ): + platform_application_arn = "arn:aws:sns:%s:%s:app/ADM/non_existent_app" + with pytest.raises(ClientError) as e: + aws_client.sns.create_platform_endpoint( + PlatformApplicationArn=platform_application_arn % (region_name, account_id), + Token="token_1", + ) + snapshot.match("create-platform-endpoint", e.value.response) + + @markers.aws.manual_setup_required + def test_list_platform_endpoints( + self, + sns_create_platform_application, + aws_client, + account_id, + region_name, + platform_credentials, + sns_create_platform_endpoint, + snapshot, + ): + app_name = f"platform-application-{short_uid()}" + snapshot.add_transformer(RegexTransformer(app_name, "")) + # if tested against AWS, the fixture needs to contain real credentials + principal, credential = platform_credentials + attributes = {"PlatformPrincipal": principal, "PlatformCredential": credential} + app_arn = sns_create_platform_application( + Name=app_name, Platform="ADM", Attributes=attributes + )["PlatformApplicationArn"] + sns_create_platform_endpoint(platform_application_arn=app_arn, token="token_1") + response = aws_client.sns.list_endpoints_by_platform_application( + PlatformApplicationArn=app_arn + ) + + snapshot.match("list-endpoints-by-app", response) + + @markers.aws.manual_setup_required + def test_delete_platform_endpoint( + self, + sns_create_platform_application, + aws_client, + account_id, + region_name, + platform_credentials, + sns_create_platform_endpoint, + snapshot, + ): + app_name = f"platform-application-{short_uid()}" + snapshot.add_transformer(RegexTransformer(app_name, "")) + # if tested against AWS, the fixture needs to contain real credentials + principal, credential = platform_credentials + attributes = {"PlatformPrincipal": principal, "PlatformCredential": credential} + app_arn = sns_create_platform_application( + Name=app_name, Platform="ADM", Attributes=attributes + )["PlatformApplicationArn"] + endpoint_arn = sns_create_platform_endpoint( + platform_application_arn=app_arn, token="token_1" + )["EndpointArn"] + response = aws_client.sns.list_endpoints_by_platform_application( + PlatformApplicationArn=app_arn + ) + snapshot.match("list-endpoints-by-app-pre-delete", response) + + response = aws_client.sns.delete_endpoint(EndpointArn=endpoint_arn) + snapshot.match("delete-endpoint", response) + if is_aws_cloud(): + time.sleep(10) + response = aws_client.sns.list_endpoints_by_platform_application( + PlatformApplicationArn=app_arn + ) + snapshot.match("list-endpoints-by-app-post-delete", response) + + @markers.snapshot.skip_snapshot_verify( + paths=[ + "$..NextToken" + ], # FIXME: investigate why AWS is not deterministic here, NextToken is sometimes present, sometimes not + ) + @markers.aws.manual_setup_required + def test_delete_platform_endpoint_with_subscription( + self, + sns_create_platform_application, + sns_create_topic, + sns_subscription, + aws_client, + account_id, + region_name, + platform_credentials, + sns_create_platform_endpoint, + snapshot, + ): + # from the docs https://docs.aws.amazon.com/cli/latest/reference/sns/delete-endpoint.html + # "When you delete an endpoint that is also subscribed to a topic, then + # you must also unsubscribe the endpoint from the topic." + # This test validates this particular case + + app_name = f"platform-application-{short_uid()}" + snapshot.add_transformer(RegexTransformer(app_name, "")) + snapshot.add_transformer(snapshot.transform.key_value("NextToken")) + # if tested against AWS, the fixture needs to contain real credentials + principal, credential = platform_credentials + attributes = {"PlatformPrincipal": principal, "PlatformCredential": credential} + app_arn = sns_create_platform_application( + Name=app_name, Platform="ADM", Attributes=attributes + )["PlatformApplicationArn"] + endpoint_arn = sns_create_platform_endpoint( + platform_application_arn=app_arn, token="token_1" + )["EndpointArn"] + topic_arn = sns_create_topic()["TopicArn"] + sns_subscription(TopicArn=topic_arn, Protocol="application", Endpoint=endpoint_arn) + + # time to let the changes propagate + if is_aws_cloud(): + time.sleep(20) + + # we list subscriptions by topic, as some tests are not cleaning up properly + response = aws_client.sns.list_subscriptions_by_topic(TopicArn=topic_arn) + snapshot.match("list-subscriptions-pre-delete", response) + + response = aws_client.sns.delete_endpoint(EndpointArn=endpoint_arn) + snapshot.match("delete-endpoint", response) + + # time to let the changes propagate + if is_aws_cloud(): + time.sleep(20) + + response = aws_client.sns.list_subscriptions_by_topic(TopicArn=topic_arn) + snapshot.match("list-subscriptions-post-delete", response) - for _ in range(queue_amount): - queue_name = f"queue-{short_uid()}.fifo" - queue_url = sqs_create_queue( - QueueName=queue_name, - Attributes=queue_attributes, - ) - sns_create_sqs_subscription( - topic_arn=topic_arn, queue_url=queue_url, Attributes={"RawMessageDelivery": "true"} - ) - queues.append(queue_url) + @markers.aws.manual_setup_required + def test_delete_endpoints_of_deleted_app( + self, + sns_create_platform_application, + sns_create_topic, + sns_subscription, + aws_client, + account_id, + region_name, + platform_credentials, + sns_create_platform_endpoint, + snapshot, + ): + app_name = f"platform-application-{short_uid()}" + snapshot.add_transformer(RegexTransformer(app_name, "")) + # if tested against AWS, the fixture needs to contain real credentials + principal, credential = platform_credentials + attributes = {"PlatformPrincipal": principal, "PlatformCredential": credential} + app_arn = sns_create_platform_application( + Name=app_name, Platform="ADM", Attributes=attributes + )["PlatformApplicationArn"] + endpoint_arn = sns_create_platform_endpoint( + platform_application_arn=app_arn, token="token_1" + )["EndpointArn"] - for i in range(message_amount): - aws_client.sns.publish( - TopicArn=topic_arn, Message=str(i), MessageGroupId="message-group-id-1" - ) + response = aws_client.sns.delete_platform_application(PlatformApplicationArn=app_arn) + snapshot.match("delete-application", response) + if is_aws_cloud(): + time.sleep(10) + with pytest.raises(ClientError) as e: + aws_client.sns.list_endpoints_by_platform_application(PlatformApplicationArn=app_arn) + snapshot.match("list-endpoints-after-app-delete", e.value.response) - all_messages = [] - for queue_url in queues: - messages = sqs_collect_messages( - queue_url, - expected=message_amount, - timeout=10, - max_number_of_messages=message_amount, - ) - contents = [message["Body"] for message in messages] - all_messages.append(contents) + aws_client.sns.delete_endpoint(EndpointArn=endpoint_arn) - # we're expecting the order to be the same across all queues - reference_order = all_messages[0] - for received_content in all_messages[1:]: - assert received_content == reference_order + @markers.aws.manual_setup_required + def test_get_platform_endpoint_attributes( + self, + aws_client, + snapshot, + platform_credentials, + sns_create_platform_endpoint, + sns_create_platform_application, + ): + app_name = f"platform-application-{short_uid()}" + snapshot.add_transformer(RegexTransformer(app_name, "")) + # if tested against AWS, the fixture needs to contain real credentials + principal, credential = platform_credentials + attributes = {"PlatformPrincipal": principal, "PlatformCredential": credential} + app_arn = sns_create_platform_application( + Name=app_name, Platform="ADM", Attributes=attributes + )["PlatformApplicationArn"] + endpoint_arn = sns_create_platform_endpoint( + platform_application_arn=app_arn, token="token_1" + )["EndpointArn"] + response = aws_client.sns.get_endpoint_attributes(EndpointArn=endpoint_arn) + snapshot.match("get-platform-endpoint-attributes", response) -class TestSNSSubscriptionSES: - @markers.aws.only_localstack - @skip_if_sns_v2 - def test_topic_email_subscription_confirmation( - self, sns_create_topic, sns_subscription, aws_client + @markers.aws.manual_setup_required + def test_set_platform_endpoint_attributes( + self, + snapshot, + platform_credentials, + sns_create_platform_endpoint, + sns_create_platform_application, + aws_client, ): - # FIXME: we do not send the token to the email endpoint, so they cannot validate it - # create AWS validated test for format - # for now, access internals - topic_arn = sns_create_topic()["TopicArn"] - subscription = sns_subscription( - TopicArn=topic_arn, - Protocol="email", - Endpoint="localstack@yopmail.com", + app_name = f"platform-application-{short_uid()}" + snapshot.add_transformer(RegexTransformer(app_name, "")) + # if tested against AWS, the fixture needs to contain real credentials + principal, credential = platform_credentials + attributes = {"PlatformPrincipal": principal, "PlatformCredential": credential} + app_arn = sns_create_platform_application( + Name=app_name, Platform="ADM", Attributes=attributes + )["PlatformApplicationArn"] + endpoint_arn = sns_create_platform_endpoint( + platform_application_arn=app_arn, token="token_1" + )["EndpointArn"] + + new_attributes = {"Enabled": "false"} + response = aws_client.sns.set_endpoint_attributes( + EndpointArn=endpoint_arn, Attributes=new_attributes ) - subscription_arn = subscription["SubscriptionArn"] - parsed_arn = parse_arn(subscription_arn) - store = SnsProvider.get_store(parsed_arn["account"], parsed_arn["region"]) + snapshot.match("set-platform-endpoint-attributes", response) - sub_attr = aws_client.sns.get_subscription_attributes(SubscriptionArn=subscription_arn) - assert sub_attr["Attributes"]["PendingConfirmation"] == "true" + response = aws_client.sns.get_endpoint_attributes(EndpointArn=endpoint_arn) + snapshot.match("get-platform-endpoint-attributes", response) - def check_subscription(): - for token, sub_arn in store.subscription_tokens.items(): - if sub_arn == subscription_arn: - aws_client.sns.confirm_subscription(TopicArn=topic_arn, Token=token) + @markers.aws.validated + def test_get_platform_endpoint_attributes_non_existent_endpoint( + self, + snapshot, + platform_credentials, + sns_create_platform_endpoint, + sns_create_platform_application, + aws_client, + account_id, + region_name, + ): + endpoint_arn = f"arn:aws:sns:{region_name}:{account_id}:endpoint/ADM/fakeapp/{uuid.uuid4()}" + with pytest.raises(ClientError) as e: + aws_client.sns.get_endpoint_attributes(EndpointArn=endpoint_arn) + snapshot.match("set-platform-endpoint-attributes-non-existent-app", e.value.response) - sub_attributes = aws_client.sns.get_subscription_attributes( - SubscriptionArn=subscription_arn - ) - assert sub_attributes["Attributes"]["PendingConfirmation"] == "false" + @markers.aws.validated + def test_set_platform_endpoint_attributes_non_existent_endpoint( + self, + snapshot, + platform_credentials, + sns_create_platform_endpoint, + sns_create_platform_application, + aws_client, + account_id, + region_name, + ): + endpoint_arn = f"arn:aws:sns:{region_name}:{account_id}:endpoint/ADM/fakeapp/{uuid.uuid4()}" + attributes = {"Enabled": "false"} + with pytest.raises(ClientError) as e: + aws_client.sns.set_endpoint_attributes(EndpointArn=endpoint_arn, Attributes=attributes) + snapshot.match("set-platform-endpoint-attributes-non-existent-app", e.value.response) + + @pytest.mark.parametrize( + "attributes", + [ + {}, + {"PlatformPrincipal": "Principal"}, + {"PlatformCredential": "Credential"}, + {"InvalidKey": "Value"}, + {"CustomUserData": "A" * 2050}, + ], + ids=[ + "Empty", + "Invalid_Name_Principal", + "Invalid_Name_Credential", + "Invalid_Name_Generic", + "Data_Too_Long", + ], + ) + @markers.aws.manual_setup_required + def test_set_platform_endpoint_attributes_invalid_attributes( + self, + snapshot, + platform_credentials, + sns_create_platform_endpoint, + sns_create_platform_application, + aws_client, + attributes, + ): + app_name = f"platform-application-{short_uid()}" + snapshot.add_transformer(RegexTransformer(app_name, "")) + # if tested against AWS, the fixture needs to contain real credentials + principal, credential = platform_credentials + initial_attributes = {"PlatformPrincipal": principal, "PlatformCredential": credential} + app_arn = sns_create_platform_application( + Name=app_name, Platform="ADM", Attributes=initial_attributes + )["PlatformApplicationArn"] + endpoint_arn = sns_create_platform_endpoint( + platform_application_arn=app_arn, token="token_1" + )["EndpointArn"] - retry(check_subscription, retries=PUBLICATION_RETRIES, sleep=PUBLICATION_TIMEOUT) + with pytest.raises(ClientError) as e: + aws_client.sns.set_endpoint_attributes(EndpointArn=endpoint_arn, Attributes=attributes) + snapshot.match("set-platform-endpoint-invalid-attributes", e.value.response) + + @pytest.mark.parametrize( + "attributes", + [ + {"PlatformPrincipal": "Principal"}, + {"PlatformCredential": "Credential"}, + {"InvalidKey": "Value"}, + {"CustomUserData": "A" * 2050}, + ], + ids=[ + "Invalid_Name_Principal", + "Invalid_Name_Credential", + "Invalid_Name_Generic", + "Data_Too_Long", + ], + ) + @markers.aws.manual_setup_required + def test_create_platform_endpoint_with_invalid_attributes( + self, + snapshot, + platform_credentials, + sns_create_platform_endpoint, + sns_create_platform_application, + aws_client, + attributes, + ): + app_name = f"platform-application-{short_uid()}" + snapshot.add_transformer(RegexTransformer(app_name, "")) + # if tested against AWS, the fixture needs to contain real credentials + principal, credential = platform_credentials + platform_attributes = {"PlatformPrincipal": principal, "PlatformCredential": credential} + app_arn = sns_create_platform_application( + Name=app_name, Platform="ADM", Attributes=platform_attributes + )["PlatformApplicationArn"] + with pytest.raises(ClientError) as e: + sns_create_platform_endpoint( + platform_application_arn=app_arn, token="token_1", Attributes=attributes + ) + snapshot.match("create-platform-endpoint-invalid-attr", e.value.response) - @markers.aws.only_localstack - @skip_if_sns_v2 - def test_email_sender( + @markers.aws.manual_setup_required + def test_create_platform_endpoint_custom_data( self, - sns_create_topic, - sns_subscription, + snapshot, + platform_credentials, + sns_create_platform_endpoint, + sns_create_platform_application, aws_client, - monkeypatch, ): - # make sure to reset all received emails in SES - requests.delete("http://localhost:4566/_aws/ses") + app_name = f"platform-application-{short_uid()}" + snapshot.add_transformer(RegexTransformer(app_name, "")) + # if tested against AWS, the fixture needs to contain real credentials + principal, credential = platform_credentials + platform_attributes = {"PlatformPrincipal": principal, "PlatformCredential": credential} + app_arn = sns_create_platform_application( + Name=app_name, Platform="ADM", Attributes=platform_attributes + )["PlatformApplicationArn"] - topic_arn = sns_create_topic()["TopicArn"] - sns_subscription( - TopicArn=topic_arn, - Protocol="email", - Endpoint="localstack@yopmail.com", - ) + custom_user_data = "bar" + endpoint_arn = sns_create_platform_endpoint( + platform_application_arn=app_arn, token="token_1", CustomUserData=custom_user_data + )["EndpointArn"] - aws_client.sns.publish( - Message="Test message", - TopicArn=topic_arn, - ) + response = aws_client.sns.get_endpoint_attributes(EndpointArn=endpoint_arn) + snapshot.match("create-endpoint-double-custom-data", response) - def _get_messages(amount: int) -> list[dict]: - response = requests.get("http://localhost:4566/_aws/ses").json() - assert len(response["messages"]) == amount - return response["messages"] + @markers.aws.manual_setup_required + def test_create_platform_endpoint_double_custom_data( + self, + snapshot, + platform_credentials, + sns_create_platform_endpoint, + sns_create_platform_application, + aws_client, + ): + # For some reason, CustomUserData can be specified both as parameter directly and inside attributes. - messages = retry(lambda: _get_messages(1), retries=PUBLICATION_RETRIES, sleep=1) - # legacy default value, should be replaced at some point - assert messages[0]["Source"] == "admin@localstack.com" - requests.delete("http://localhost:4566/_aws/ses") + app_name = f"platform-application-{short_uid()}" + snapshot.add_transformer(RegexTransformer(app_name, "")) + # if tested against AWS, the fixture needs to contain real credentials + principal, credential = platform_credentials + platform_attributes = {"PlatformPrincipal": principal, "PlatformCredential": credential} + app_arn = sns_create_platform_application( + Name=app_name, Platform="ADM", Attributes=platform_attributes + )["PlatformApplicationArn"] - sender_address = "no-reply@sns.localstack.cloud" - monkeypatch.setattr(config, "SNS_SES_SENDER_ADDRESS", sender_address) + attributes = {"CustomUserData": "foo"} + custom_user_data = "bar" + endpoint_arn = sns_create_platform_endpoint( + platform_application_arn=app_arn, + token="token_1", + Attributes=attributes, + CustomUserData=custom_user_data, + )["EndpointArn"] - aws_client.sns.publish( - Message="Test message", - TopicArn=topic_arn, - ) - messages = retry(lambda: _get_messages(1), retries=PUBLICATION_RETRIES, sleep=1) - assert messages[0]["Source"] == sender_address + response = aws_client.sns.get_endpoint_attributes(EndpointArn=endpoint_arn) + snapshot.match("create-endpoint-double-custom-data", response) class TestSNSPlatformEndpoint: + @markers.requires_in_process @markers.aws.only_localstack - @skip_if_sns_v2 def test_subscribe_platform_endpoint( self, sns_create_topic, @@ -3250,13 +4545,17 @@ def test_subscribe_platform_endpoint( aws_client, account_id, region_name, + platform_credentials, ): sns_backend = SnsProvider.get_store(account_id, region_name) topic_arn = sns_create_topic()["TopicArn"] - app_arn = sns_create_platform_application(Name="app1", Platform="p1", Attributes={})[ - "PlatformApplicationArn" - ] + platform = "ADM" + client_id, client_secret = platform_credentials + attributes = {"PlatformPrincipal": client_id, "PlatformCredential": client_secret} + app_arn = sns_create_platform_application( + Name="app1", Platform=platform, Attributes=attributes + )["PlatformApplicationArn"] platform_arn = aws_client.sns.create_platform_endpoint( PlatformApplicationArn=app_arn, Token="token_1" )["EndpointArn"] @@ -3288,7 +4587,6 @@ def check_message(): # AWS validating this is hard because we need real credentials for a GCM/Apple mobile app # TODO: AWS validate this test # See https://github.com/getmoto/moto/pull/6953 where Moto updated errors. - @skip_if_sns_v2 def test_create_platform_endpoint_check_idempotency( self, sns_create_platform_application, aws_client ): @@ -3334,12 +4632,16 @@ def test_create_platform_endpoint_check_idempotency( @markers.aws.needs_fixing # AWS validating this is hard because we need real credentials for a GCM/Apple mobile app - @skip_if_sns_v2 - def test_publish_disabled_endpoint(self, sns_create_platform_application, aws_client): + def test_publish_disabled_endpoint( + self, sns_create_platform_application, aws_client, platform_credentials + ): + platform = "ADM" + client_id, client_secret = platform_credentials + attributes = {"PlatformPrincipal": client_id, "PlatformCredential": client_secret} response = sns_create_platform_application( Name=f"test-{short_uid()}", - Platform="GCM", - Attributes={"PlatformCredential": "123"}, + Platform=platform, + Attributes=attributes, ) platform_arn = response["PlatformApplicationArn"] response = aws_client.sns.create_platform_endpoint( @@ -3355,12 +4657,20 @@ def test_publish_disabled_endpoint(self, sns_create_platform_application, aws_cl EndpointArn=endpoint_arn, Attributes={"Enabled": "false"} ) - get_attrs = aws_client.sns.get_endpoint_attributes(EndpointArn=endpoint_arn) - assert get_attrs["Attributes"]["Enabled"] == "false" + retries = 3 + sleep = 1 + if is_aws_cloud(): + retries = 30 + sleep = 2 + def _assert_endpoint_disabled(): + get_attrs = aws_client.sns.get_endpoint_attributes(EndpointArn=endpoint_arn) + assert get_attrs["Attributes"]["Enabled"] == "false" + + retry(_assert_endpoint_disabled, retries=retries, sleep=sleep) with pytest.raises(ClientError) as e: message = { - "GCM": '{ "notification": {"title": "Title of notification", "body": "It works" } }' + platform: '{ "notification": {"title": "Title of notification", "body": "It works" } }' } aws_client.sns.publish( TargetArn=endpoint_arn, MessageStructure="json", Message=json.dumps(message) @@ -3371,7 +4681,6 @@ def test_publish_disabled_endpoint(self, sns_create_platform_application, aws_cl @markers.aws.only_localstack # needs real credentials for GCM/FCM @pytest.mark.skip(reason="Need to implement credentials validation when creating platform") - @skip_if_sns_v2 def test_publish_to_gcm(self, sns_create_platform_application, aws_client): key = "mock_server_key" token = "mock_token" @@ -3398,8 +4707,8 @@ def test_publish_to_gcm(self, sns_create_platform_application, aws_client): ) assert ex.value.response["Error"]["Code"] == "InvalidParameter" + @markers.requires_in_process @markers.aws.only_localstack - @skip_if_sns_v2 def test_publish_to_platform_endpoint_is_dispatched( self, sns_create_topic, @@ -3408,7 +4717,10 @@ def test_publish_to_platform_endpoint_is_dispatched( aws_client, account_id, region_name, + platform_credentials, ): + client_id, client_secret = platform_credentials + attributes = {"PlatformPrincipal": client_id, "PlatformCredential": client_secret} topic_arn = sns_create_topic()["TopicArn"] endpoints_arn = {} for platform_type in ["APNS", "GCM"]: @@ -3416,7 +4728,7 @@ def test_publish_to_platform_endpoint_is_dispatched( # Create an Apple platform application app_arn = sns_create_platform_application( - Name=application_platform_name, Platform=platform_type, Attributes={} + Name=application_platform_name, Platform=platform_type, Attributes=attributes )["PlatformApplicationArn"] endpoint_arn = aws_client.sns.create_platform_endpoint( @@ -3446,13 +4758,13 @@ def test_publish_to_platform_endpoint_is_dispatched( Message=json.dumps(message), MessageStructure="json", ) - sns_backend = SnsProvider.get_store(account_id, region_name) platform_endpoint_msgs = sns_backend.platform_endpoint_messages # assert that message has been received def check_message(): - assert len(platform_endpoint_msgs[endpoint_arn]) > 0 + for arn in endpoints_arn.values(): + assert len(platform_endpoint_msgs[arn]) > 0 retry(check_message, retries=PUBLICATION_RETRIES, sleep=PUBLICATION_TIMEOUT) @@ -3462,8 +4774,8 @@ def check_message(): class TestSNSSMS: + @markers.requires_in_process @markers.aws.only_localstack - @skip_if_sns_v2 def test_publish_sms(self, aws_client, account_id, region_name): phone_number = "+33000000000" response = aws_client.sns.publish(PhoneNumber=phone_number, Message="This is a SMS") @@ -3471,8 +4783,8 @@ def test_publish_sms(self, aws_client, account_id, region_name): assert response["ResponseMetadata"]["HTTPStatusCode"] == 200 sns_backend = SnsProvider.get_store( - account_id=account_id, - region_name=region_name, + account_id, + region_name, ) def check_messages(): @@ -3487,7 +4799,6 @@ def check_messages(): retry(check_messages, sleep=0.5) @markers.aws.validated - @skip_if_sns_v2 def test_subscribe_sms_endpoint(self, sns_create_topic, sns_subscription, snapshot, aws_client): phone_number = "+123123123" topic_arn = sns_create_topic()["TopicArn"] @@ -3499,8 +4810,8 @@ def test_subscribe_sms_endpoint(self, sns_create_topic, sns_subscription, snapsh ) snapshot.match("subscribe-sms-attrs", sub_attrs) + @markers.requires_in_process @markers.aws.only_localstack - @skip_if_sns_v2 def test_publish_sms_endpoint( self, sns_create_topic, sns_subscription, aws_client, account_id, region_name ): @@ -3532,7 +4843,6 @@ def check_messages(): retry(check_messages, sleep=0.5) @markers.aws.validated - @skip_if_sns_v2 def test_publish_wrong_phone_format( self, sns_create_topic, sns_subscription, snapshot, aws_client ): @@ -3552,10 +4862,168 @@ def test_publish_wrong_phone_format( sns_subscription(TopicArn=topic_arn, Protocol="sms", Endpoint="NAA+15551234567") snapshot.match("wrong-endpoint", e.value.response) + @markers.aws.manual_setup_required + def test_set_get_sms_attributes(self, aws_client, account_id, snapshot): + if is_aws_cloud(): + LOG.warning( + "Warning: this test will permanently set values for sms attributes in this region. \n Removing is not possible, only overwriting.\n Remove the exception if you wish to proceed" + ) + raise Exception("Check logs to enable this test against AWS") + + aws_client.sns.set_sms_attributes( + attributes={ + "DeliveryStatusSuccessSamplingRate": "100", + "DefaultSenderID": "LSTest", + "DefaultSMSType": "Promotional", + } + ) + + response = aws_client.sns.get_sms_attributes() + snapshot.match("get-sms-all-attributes", response) + + response = aws_client.sns.get_sms_attributes( + attributes=["DefaultSenderID", "DefaultSMSType"] + ) + snapshot.match("get-sms-some-attributes", response) + + @markers.aws.manual_setup_required + def test_get_sms_attributes_from_unmodified_region( + self, aws_client_factory, secondary_region_name, snapshot + ): + # if the secondary region is already modified, you can use SECONDARY_TEST_AWS_PROFILE and similar + # variables to change it + + default_spend_limit = "1" + + sns_unmodified_region = aws_client_factory(region_name=secondary_region_name).sns + response = sns_unmodified_region.get_sms_attributes() + assert response["attributes"]["MonthlySpendLimit"] == default_spend_limit + snapshot.match("get-sms-attributes_unmodified_region", response) + + @pytest.mark.parametrize( + "attribute_key_value", + [ + ("InvalidAttribute", "invalid"), + ("DefaultSendID", "a" * 12), + ("DefaultSendID", "123456789"), + ("DefaultSMSType", "invalid"), + ], + ids=["InvalidAttributeName", "TooLongID", "NoLetterID", "InvalidSMSType"], + ) + @markers.aws.validated + def test_set_invalid_sms_attributes(self, aws_client, snapshot, attribute_key_value): + with pytest.raises(ClientError) as e: + aws_client.sns.set_sms_attributes( + attributes={ + attribute_key_value[0]: attribute_key_value[1], + } + ) + snapshot.match("invalid-attribute", e.value.response) + + @markers.aws.manual_setup_required + @markers.requires_in_process + def test_is_phone_number_opted_out( + self, phone_number, aws_client, snapshot, account_id, region_name, cleanups + ): + # this test expects the fixture-provided phone number to be opted out + # if you want to test against AWS, you need to manually opt out a number + # https://us-east-1.console.aws.amazon.com/sms-voice/home?region=us-east-1#/opt-out-lists?name=Default&tab=opt-out-list-opted-out-numbers + sns_store = SnsProvider.get_store(account_id, region_name) + + def cleanup_store(): + sns_store.PHONE_NUMBERS_OPTED_OUT.remove(phone_number) + + if not is_aws_cloud(): + sns_store.PHONE_NUMBERS_OPTED_OUT.add(phone_number) + cleanups.append(cleanup_store) + + response = aws_client.sns.check_if_phone_number_is_opted_out(phoneNumber=phone_number) + snapshot.match("phone-number-opted-out", response) + + @markers.aws.manual_setup_required + @markers.requires_in_process + def test_list_phone_numbers_opted_out( + self, phone_number, aws_client, snapshot, account_id, region_name, cleanups + ): + # this test expects exactly one phone number opted out + # if you want to test against AWS, you need to manually opt out a number + # https://us-east-1.console.aws.amazon.com/sms-voice/home?region=us-east-1#/opt-out-lists?name=Default&tab=opt-out-list-opted-out-numbers + sns_store = SnsProvider.get_store(account_id, region_name) + + def cleanup_store(): + sns_store.PHONE_NUMBERS_OPTED_OUT.remove(phone_number) + + if not is_aws_cloud(): + sns_store.PHONE_NUMBERS_OPTED_OUT.add(phone_number) + cleanups.append(cleanup_store) + + snapshot.add_transformer( + TransformerUtility.jsonpath( + jsonpath="$..phoneNumbers[*]", + value_replacement="phone-number", + ) + ) + response = aws_client.sns.list_phone_numbers_opted_out() + snapshot.match("list-phone-numbers-opted-out", response) + + @markers.aws.manual_setup_required + @markers.requires_in_process + def test_opt_in_phone_number( + self, phone_number, aws_client, snapshot, account_id, region_name, cleanups + ): + # this test expects exactly one phone number opted out + # if you want to test against AWS, you need to manually opt out a number + # https://us-east-1.console.aws.amazon.com/sms-voice/home?region=us-east-1#/opt-out-lists?name=Default&tab=opt-out-list-opted-out-numbers + # IMPORTANT: a phone number can only be opted in once every 30 days on AWS. + # Make sure everything else is set up and taken care of properly before trying to validate this. + sns_store = SnsProvider.get_store(account_id, region_name) + + def cleanup_store(): + sns_store.PHONE_NUMBERS_OPTED_OUT.remove(phone_number) + + if not is_aws_cloud(): + sns_store.PHONE_NUMBERS_OPTED_OUT.add(phone_number) + cleanups.append(cleanup_store) + response = aws_client.sns.check_if_phone_number_is_opted_out(phoneNumber=phone_number) + assert response["isOptedOut"] + + response = aws_client.sns.opt_in_phone_number(phoneNumber=phone_number) + snapshot.match("opt-in-phone-number", response) + + @markers.aws.only_localstack + @markers.requires_in_process + def test_opt_out_phone_number_via_endpoint( + self, phone_number, aws_client, snapshot, account_id, cleanups + ): + response = aws_client.sns.check_if_phone_number_is_opted_out(phoneNumber=phone_number) + assert not response["isOptedOut"] + data = {"phoneNumber": phone_number, "accountId": account_id} + phone_url = config.external_service_url() + SMS_PHONE_NUMBER_OPT_OUT_ENDPOINT + requests.post(phone_url, data=json.dumps(data)) + + response = aws_client.sns.check_if_phone_number_is_opted_out(phoneNumber=phone_number) + assert response["isOptedOut"] + + @markers.aws.validated + def test_opt_in_non_existing_phone_number( + self, phone_number, aws_client, snapshot, account_id, region_name + ): + non_existing_number = "+4411111111" + response = aws_client.sns.opt_in_phone_number(phoneNumber=non_existing_number) + + snapshot.match("opt-in-non-existing-number", response) + + @markers.aws.validated + def test_opt_in_invalid_number(self, phone_number, aws_client, snapshot): + invalid_number = "invalid" + with pytest.raises(ClientError) as e: + aws_client.sns.opt_in_phone_number(phoneNumber=invalid_number) + + snapshot.match("opt-in-non-existing-number", e.value.response) + class TestSNSSubscriptionHttp: @markers.aws.validated - @skip_if_sns_v2 def test_http_subscription_response( self, sns_create_topic, @@ -3584,8 +5052,8 @@ def test_http_subscription_response( ) snapshot.match("subscription-with-arn", subscription_with_arn) + @markers.requires_in_process # uses pytest httpserver @markers.aws.manual_setup_required - @skip_if_sns_v2 def test_redrive_policy_http_subscription( self, sns_create_topic, sqs_create_queue, sqs_get_queue_arn, sns_subscription, aws_client ): @@ -3633,8 +5101,8 @@ def test_redrive_policy_http_subscription( assert message["Type"] == "Notification" assert json.loads(message["Message"])["message"] == "test_redrive_policy" + @markers.requires_in_process # uses pytest httpserver @markers.aws.manual_setup_required - @skip_if_sns_v2 def test_multiple_subscriptions_http_endpoint( self, sns_create_topic, sns_subscription, aws_client ): @@ -3719,6 +5187,7 @@ def handler(_request): for server in servers: server.stop() + @markers.requires_in_process # uses pytest httpserver @markers.aws.manual_setup_required @pytest.mark.parametrize("raw_message_delivery", [True, False]) @markers.snapshot.skip_snapshot_verify( @@ -3728,7 +5197,6 @@ def handler(_request): "$.http-confirm-sub-headers.Accept", ] ) - @skip_if_sns_v2 def test_subscribe_external_http_endpoint( self, sns_create_http_endpoint, raw_message_delivery, aws_client, snapshot ): @@ -3902,9 +5370,9 @@ def _clean_headers(response_headers: dict): ) snapshot.match("unsubscribe-request", payload) + @markers.requires_in_process # uses pytest httpserver @markers.aws.manual_setup_required @pytest.mark.parametrize("raw_message_delivery", [True, False]) - @skip_if_sns_v2 def test_dlq_external_http_endpoint( self, sqs_create_queue, @@ -3989,6 +5457,7 @@ def test_dlq_external_http_endpoint( # AWS doesn't send to the DLQ if the UnsubscribeConfirmation fails to be delivered assert "Messages" not in response or response["Messages"] == [] + @markers.requires_in_process # uses pytest httpserver @markers.aws.manual_setup_required @pytest.mark.parametrize("raw_message_delivery", [True, False]) @markers.snapshot.skip_snapshot_verify( @@ -4005,7 +5474,6 @@ def test_dlq_external_http_endpoint( "$.topic-attrs.Attributes.Policy.Statement..Action", ] ) - @skip_if_sns_v2 def test_subscribe_external_http_endpoint_content_type( self, sns_create_http_endpoint, @@ -4101,7 +5569,6 @@ def _clean_headers(response_headers: dict): snapshot.match("http-message-headers", _clean_headers(notification_request.headers)) @markers.aws.validated - @skip_if_sns_v2 def test_subscribe_external_http_endpoint_lambda_url_sig_validation( self, create_sns_http_endpoint_and_queue, @@ -4271,7 +5738,6 @@ def validate_message_signature(msg_event: dict, msg_type: str): class TestSNSSubscriptionFirehose: @markers.aws.validated - @skip_if_sns_v2 def test_publish_to_firehose_with_s3( self, create_role, @@ -4397,7 +5863,6 @@ def sqs_secondary_client(self, secondary_aws_client): return secondary_aws_client.sqs @markers.aws.only_localstack - @skip_if_sns_v2 def test_cross_account_access(self, sns_primary_client, sns_secondary_client, sns_create_topic): # Cross-account access is supported for below operations. # This list is taken from ActionName param of the AddPermissions operation @@ -4452,7 +5917,6 @@ def test_cross_account_access(self, sns_primary_client, sns_secondary_client, sn assert sns_secondary_client.delete_topic(TopicArn=topic_arn) @markers.aws.only_localstack - @skip_if_sns_v2 def test_cross_account_publish_to_sqs( self, sns_create_topic, @@ -4576,7 +6040,6 @@ def sqs_region2_client(self, aws_client_factory, secondary_region_name): return aws_client_factory(region_name=secondary_region_name).sqs @markers.aws.validated - @skip_if_sns_v2 def test_cross_region_access(self, sns_region1_client, sns_region2_client, snapshot, cleanups): # We do not have a list of supported Cross-region access for operations. # This test is validating that Cross-account does not mean Cross-region most of the time @@ -4614,7 +6077,6 @@ def test_cross_region_access(self, sns_region1_client, sns_region2_client, snaps snapshot.match("delete-topic", e.value.response) @markers.aws.validated - @skip_if_sns_v2 def test_cross_region_delivery_sqs( self, sns_region1_client, @@ -4687,14 +6149,6 @@ def test_cross_region_delivery_sqs( class TestSNSPublishDelivery: @markers.aws.validated - @markers.snapshot.skip_snapshot_verify( - paths=[ - "$..Attributes.DeliveryPolicy", - "$..Attributes.EffectiveDeliveryPolicy", - "$..Attributes.Policy.Statement..Action", # SNS:Receive is added by moto but not returned in AWS - ] - ) - @skip_if_sns_v2 def test_delivery_lambda( self, sns_create_topic, @@ -4861,9 +6315,9 @@ def get_log_events(): class TestSNSCertEndpoint: + @markers.requires_in_process @markers.aws.only_localstack @pytest.mark.parametrize("cert_host", ["", "sns.us-east-1.amazonaws.com"]) - @skip_if_sns_v2 def test_cert_endpoint_host( self, aws_client, @@ -4908,8 +6362,8 @@ def test_cert_endpoint_host( @pytest.mark.usefixtures("openapi_validate") class TestSNSRetrospectionEndpoints: + @markers.requires_in_process @markers.aws.only_localstack - @skip_if_sns_v2 def test_publish_to_platform_endpoint_can_retrospect( self, sns_create_topic, @@ -4919,7 +6373,11 @@ def test_publish_to_platform_endpoint_can_retrospect( account_id, region_name, secondary_region_name, + platform_credentials, ): + platform = "APNS" + client_id, client_secret = platform_credentials + attributes = {"PlatformPrincipal": client_id, "PlatformCredential": client_secret} sns_backend = SnsProvider.get_store(account_id, region_name) # clean up the saved messages sns_backend_endpoint_arns = list(sns_backend.platform_endpoint_messages.keys()) @@ -4930,7 +6388,7 @@ def test_publish_to_platform_endpoint_can_retrospect( application_platform_name = f"app-platform-{short_uid()}" app_arn = sns_create_platform_application( - Name=application_platform_name, Platform="APNS", Attributes={} + Name=application_platform_name, Platform=platform, Attributes=attributes )["PlatformApplicationArn"] endpoint_arn = aws_client.sns.create_platform_endpoint( @@ -5065,8 +6523,8 @@ def check_message(): ).json() assert not msg_with_region["platform_endpoint_messages"] + @markers.requires_in_process @markers.aws.only_localstack - @skip_if_sns_v2 def test_publish_sms_can_retrospect( self, sns_create_topic, @@ -5169,8 +6627,8 @@ def check_message(): msg_with_region = requests.get(msgs_url, params={"region": region_name}).json() assert not msg_with_region["sms_messages"] + @markers.requires_in_process @markers.aws.only_localstack - @skip_if_sns_v2 def test_subscription_tokens_can_retrospect( self, sns_create_topic, diff --git a/tests/aws/services/sns/test_sns.snapshot.json b/tests/aws/services/sns/test_sns.snapshot.json index 33687119db961..86884fc34df67 100644 --- a/tests/aws/services/sns/test_sns.snapshot.json +++ b/tests/aws/services/sns/test_sns.snapshot.json @@ -90,7 +90,7 @@ } }, "tests/aws/services/sns/test_sns.py::TestSNSTopicCrud::test_tags": { - "recorded-date": "24-08-2023, 22:30:44", + "recorded-date": "13-10-2025, 06:50:09", "recorded-content": { "duplicate-key-error": { "Error": { @@ -146,7 +146,7 @@ } }, "tests/aws/services/sns/test_sns.py::TestSNSTopicCrud::test_create_topic_test_arn": { - "recorded-date": "24-08-2023, 22:30:45", + "recorded-date": "29-09-2025, 09:32:56", "recorded-content": { "create-topic": { "TopicArn": "arn::sns::111111111111:", @@ -235,7 +235,7 @@ } }, "tests/aws/services/sns/test_sns.py::TestSNSTopicCrud::test_create_duplicate_topic_with_more_tags": { - "recorded-date": "24-08-2023, 22:30:46", + "recorded-date": "13-10-2025, 06:53:55", "recorded-content": { "exception-duplicate": { "Error": { @@ -251,7 +251,7 @@ } }, "tests/aws/services/sns/test_sns.py::TestSNSTopicCrud::test_create_duplicate_topic_check_idempotency": { - "recorded-date": "24-08-2023, 22:30:47", + "recorded-date": "13-10-2025, 07:07:09", "recorded-content": { "response-created": { "TopicArn": "arn::sns::111111111111:", @@ -284,7 +284,7 @@ } }, "tests/aws/services/sns/test_sns.py::TestSNSTopicCrud::test_create_topic_after_delete_with_new_tags": { - "recorded-date": "24-08-2023, 22:30:48", + "recorded-date": "13-10-2025, 07:59:08", "recorded-content": { "topic-0": { "TopicArn": "arn::sns::111111111111:", @@ -637,7 +637,7 @@ } }, "tests/aws/services/sns/test_sns.py::TestSNSSubscriptionCrud::test_subscribe_with_invalid_protocol": { - "recorded-date": "24-08-2023, 23:27:50", + "recorded-date": "06-10-2025, 10:25:11", "recorded-content": { "exception": { "Error": { @@ -653,7 +653,7 @@ } }, "tests/aws/services/sns/test_sns.py::TestSNSSubscriptionCrud::test_unsubscribe_from_non_existing_subscription": { - "recorded-date": "24-08-2023, 23:27:52", + "recorded-date": "06-10-2025, 10:25:16", "recorded-content": { "empty-unsubscribe": { "ResponseMetadata": { @@ -664,7 +664,7 @@ } }, "tests/aws/services/sns/test_sns.py::TestSNSSubscriptionCrud::test_create_subscriptions_with_attributes": { - "recorded-date": "29-03-2024, 19:44:43", + "recorded-date": "06-10-2025, 10:25:19", "recorded-content": { "subscribe-wrong-attr": { "Error": { @@ -715,7 +715,7 @@ } }, "tests/aws/services/sns/test_sns.py::TestSNSSubscriptionCrud::test_not_found_error_on_set_subscription_attributes": { - "recorded-date": "24-08-2023, 23:27:55", + "recorded-date": "06-10-2025, 10:25:23", "recorded-content": { "sub": { "SubscriptionArn": "arn::sns::111111111111::", @@ -777,7 +777,7 @@ } }, "tests/aws/services/sns/test_sns.py::TestSNSSubscriptionCrud::test_validate_set_sub_attributes": { - "recorded-date": "29-03-2024, 19:30:24", + "recorded-date": "06-10-2025, 10:25:27", "recorded-content": { "fake-attribute": { "Error": { @@ -826,7 +826,7 @@ "invalid-json-redrive-policy": { "Error": { "Code": "InvalidParameter", - "Message": "Invalid parameter: RedrivePolicy: failed to parse JSON. Unexpected character ('i' (code 105)): was expecting double-quote to start field name\n at [Source: java.io.StringReader@469cc9aa; line: 1, column: 3]", + "Message": "Invalid parameter: RedrivePolicy: failed to parse JSON. Unexpected character ('i' (code 105)): was expecting double-quote to start field name\n at [Source: REDACTED (`StreamReadFeature.INCLUDE_SOURCE_IN_LOCATION` disabled); line: 1, column: 2]", "Type": "Sender" }, "ResponseMetadata": { @@ -837,7 +837,7 @@ "invalid-json-filter-policy": { "Error": { "Code": "InvalidParameter", - "Message": "Invalid parameter: FilterPolicy: failed to parse JSON. Unexpected character ('i' (code 105)): was expecting double-quote to start field name\n at [Source: (String)\"{invalidjson}\"; line: 1, column: 3]", + "Message": "Invalid parameter: FilterPolicy: failed to parse JSON. Unexpected character ('i' (code 105)): was expecting double-quote to start field name\n at [Source: REDACTED (`StreamReadFeature.INCLUDE_SOURCE_IN_LOCATION` disabled); line: 1, column: 2]", "Type": "Sender" }, "ResponseMetadata": { @@ -848,7 +848,7 @@ } }, "tests/aws/services/sns/test_sns.py::TestSNSSubscriptionCrud::test_sns_confirm_subscription_wrong_token": { - "recorded-date": "24-08-2023, 23:27:58", + "recorded-date": "06-10-2025, 10:25:28", "recorded-content": { "topic-not-exists": { "Error": { @@ -886,7 +886,7 @@ } }, "tests/aws/services/sns/test_sns.py::TestSNSSubscriptionLambda::test_python_lambda_subscribe_sns_topic": { - "recorded-date": "24-08-2023, 23:28:59", + "recorded-date": "06-10-2025, 11:08:48", "recorded-content": { "notification": { "Message": "Hello world.", @@ -2764,7 +2764,7 @@ } }, "tests/aws/services/sns/test_sns.py::TestSNSSubscriptionSQSFifo::test_publish_batch_messages_from_fifo_topic_to_fifo_queue[True]": { - "recorded-date": "07-12-2023, 10:10:22", + "recorded-date": "17-12-2025, 13:21:07", "recorded-content": { "topic-attrs": { "Attributes": { @@ -2969,7 +2969,7 @@ } }, "tests/aws/services/sns/test_sns.py::TestSNSSubscriptionSQSFifo::test_publish_batch_messages_from_fifo_topic_to_fifo_queue[False]": { - "recorded-date": "07-12-2023, 10:10:29", + "recorded-date": "17-12-2025, 13:21:15", "recorded-content": { "topic-attrs": { "Attributes": { @@ -3599,118 +3599,11 @@ } }, "tests/aws/services/sns/test_sns.py::TestSNSSubscriptionCrud::test_list_subscriptions": { - "recorded-date": "25-08-2023, 16:23:53", - "recorded-content": { - "create-topic-1": { - "TopicArn": "arn::sns::111111111111:", - "ResponseMetadata": { - "HTTPHeaders": {}, - "HTTPStatusCode": 200 - } - }, - "create-topic-2": { - "TopicArn": "arn::sns::111111111111:", - "ResponseMetadata": { - "HTTPHeaders": {}, - "HTTPStatusCode": 200 - } - }, - "sub-topic-1-0": { - "SubscriptionArn": "arn::sns::111111111111::", - "ResponseMetadata": { - "HTTPHeaders": {}, - "HTTPStatusCode": 200 - } - }, - "sub-topic-1-1": { - "SubscriptionArn": "arn::sns::111111111111::", - "ResponseMetadata": { - "HTTPHeaders": {}, - "HTTPStatusCode": 200 - } - }, - "sub-topic-1-2": { - "SubscriptionArn": "arn::sns::111111111111::", - "ResponseMetadata": { - "HTTPHeaders": {}, - "HTTPStatusCode": 200 - } - }, - "sub-topic-2-0": { - "SubscriptionArn": "arn::sns::111111111111::", - "ResponseMetadata": { - "HTTPHeaders": {}, - "HTTPStatusCode": 200 - } - }, - "sub-topic-2-1": { - "SubscriptionArn": "arn::sns::111111111111::", - "ResponseMetadata": { - "HTTPHeaders": {}, - "HTTPStatusCode": 200 - } - }, - "sub-topic-2-2": { - "SubscriptionArn": "arn::sns::111111111111::", - "ResponseMetadata": { - "HTTPHeaders": {}, - "HTTPStatusCode": 200 - } - }, - "list-subscriptions-aggregated": { - "Subscriptions": [ - { - "Endpoint": "arn::sqs::111111111111:", - "Owner": "111111111111", - "Protocol": "sqs", - "SubscriptionArn": "arn::sns::111111111111::", - "TopicArn": "arn::sns::111111111111:" - }, - { - "Endpoint": "arn::sqs::111111111111:", - "Owner": "111111111111", - "Protocol": "sqs", - "SubscriptionArn": "arn::sns::111111111111::", - "TopicArn": "arn::sns::111111111111:" - }, - { - "Endpoint": "arn::sqs::111111111111:", - "Owner": "111111111111", - "Protocol": "sqs", - "SubscriptionArn": "arn::sns::111111111111::", - "TopicArn": "arn::sns::111111111111:" - }, - { - "Endpoint": "arn::sqs::111111111111:", - "Owner": "111111111111", - "Protocol": "sqs", - "SubscriptionArn": "arn::sns::111111111111::", - "TopicArn": "arn::sns::111111111111:" - }, - { - "Endpoint": "arn::sqs::111111111111:", - "Owner": "111111111111", - "Protocol": "sqs", - "SubscriptionArn": "arn::sns::111111111111::", - "TopicArn": "arn::sns::111111111111:" - }, - { - "Endpoint": "arn::sqs::111111111111:", - "Owner": "111111111111", - "Protocol": "sqs", - "SubscriptionArn": "arn::sns::111111111111::", - "TopicArn": "arn::sns::111111111111:" - } - ], - "ResponseMetadata": { - "HTTPHeaders": {}, - "HTTPStatusCode": 200 - } - } - } + "recorded-date": "07-10-2025, 10:07:36", + "recorded-content": {} }, "tests/aws/services/sns/test_sns.py::TestSNSSubscriptionCrud::test_subscribe_idempotency": { - "recorded-date": "20-03-2025, 17:16:39", + "recorded-date": "06-10-2025, 10:26:46", "recorded-content": { "subscribe": { "SubscriptionArn": "arn::sns::111111111111::", @@ -4021,7 +3914,7 @@ } }, "tests/aws/services/sns/test_sns.py::TestSNSSubscriptionCrud::test_unsubscribe_wrong_arn_format": { - "recorded-date": "02-09-2025, 20:17:36", + "recorded-date": "06-10-2025, 10:26:51", "recorded-content": { "invalid-unsubscribe-arn-1": { "Error": { @@ -4070,7 +3963,7 @@ } }, "tests/aws/services/sns/test_sns.py::TestSNSSubscriptionCrud::test_unsubscribe_idempotency": { - "recorded-date": "07-11-2023, 00:36:06", + "recorded-date": "06-10-2025, 10:26:49", "recorded-content": { "unsubscribe-1": { "ResponseMetadata": { @@ -4239,7 +4132,7 @@ } }, "tests/aws/services/sns/test_sns.py::TestSNSSubscriptionCrud::test_list_subscriptions_by_topic_pagination": { - "recorded-date": "16-05-2024, 10:32:16", + "recorded-date": "06-10-2025, 10:26:42", "recorded-content": { "list-sub-per-topic-page-2": { "Subscriptions": [ @@ -4951,7 +4844,7 @@ } }, "tests/aws/services/sns/test_sns.py::TestSNSSubscriptionCrud::test_subscribe_with_invalid_topic": { - "recorded-date": "23-01-2025, 22:38:17", + "recorded-date": "06-10-2025, 10:26:53", "recorded-content": { "invalid-subscribe-arn-1": { "Error": { @@ -5208,7 +5101,7 @@ } }, "tests/aws/services/sns/test_sns.py::TestSNSTopicCrud::test_delete_topic_idempotency": { - "recorded-date": "28-05-2025, 10:08:38", + "recorded-date": "29-09-2025, 09:46:20", "recorded-content": { "delete-topic": { "ResponseMetadata": { @@ -5265,5 +5158,2364 @@ } } } + }, + "tests/aws/services/sns/test_sns.py::TestSNSTopicCrudV2::test_delete_non_existent_topic": { + "recorded-date": "29-09-2025, 10:10:56", + "recorded-content": { + "delete-non-existent-topic": { + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/sns/test_sns.py::TestSNSTopicCrudV2::test_create_topic_should_be_idempotent": { + "recorded-date": "29-09-2025, 10:23:24", + "recorded-content": { + "topic-attrs-idempotent-1": { + "Attributes": { + "DisplayName": "AlreadySet", + "EffectiveDeliveryPolicy": { + "http": { + "defaultHealthyRetryPolicy": { + "minDelayTarget": 20, + "maxDelayTarget": 20, + "numRetries": 3, + "numMaxDelayRetries": 0, + "numNoDelayRetries": 0, + "numMinDelayRetries": 0, + "backoffFunction": "linear" + }, + "disableSubscriptionOverrides": false, + "defaultRequestPolicy": { + "headerContentType": "text/plain; charset=UTF-8" + } + } + }, + "Owner": "111111111111", + "Policy": { + "Version": "2008-10-17", + "Id": "__default_policy_ID", + "Statement": [ + { + "Sid": "__default_statement_ID", + "Effect": "Allow", + "Principal": { + "AWS": "*" + }, + "Action": [ + "SNS:GetTopicAttributes", + "SNS:SetTopicAttributes", + "SNS:AddPermission", + "SNS:RemovePermission", + "SNS:DeleteTopic", + "SNS:Subscribe", + "SNS:ListSubscriptionsByTopic", + "SNS:Publish" + ], + "Resource": "arn::sns::111111111111:", + "Condition": { + "StringEquals": { + "AWS:SourceOwner": "111111111111" + } + } + } + ] + }, + "SubscriptionsConfirmed": "0", + "SubscriptionsDeleted": "0", + "SubscriptionsPending": "0", + "TopicArn": "arn::sns::111111111111:" + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "topic-attrs-idempotent-2": { + "Attributes": { + "DisplayName": "AlreadySet", + "EffectiveDeliveryPolicy": { + "http": { + "defaultHealthyRetryPolicy": { + "minDelayTarget": 20, + "maxDelayTarget": 20, + "numRetries": 3, + "numMaxDelayRetries": 0, + "numNoDelayRetries": 0, + "numMinDelayRetries": 0, + "backoffFunction": "linear" + }, + "disableSubscriptionOverrides": false, + "defaultRequestPolicy": { + "headerContentType": "text/plain; charset=UTF-8" + } + } + }, + "Owner": "111111111111", + "Policy": { + "Version": "2008-10-17", + "Id": "__default_policy_ID", + "Statement": [ + { + "Sid": "__default_statement_ID", + "Effect": "Allow", + "Principal": { + "AWS": "*" + }, + "Action": [ + "SNS:GetTopicAttributes", + "SNS:SetTopicAttributes", + "SNS:AddPermission", + "SNS:RemovePermission", + "SNS:DeleteTopic", + "SNS:Subscribe", + "SNS:ListSubscriptionsByTopic", + "SNS:Publish" + ], + "Resource": "arn::sns::111111111111:", + "Condition": { + "StringEquals": { + "AWS:SourceOwner": "111111111111" + } + } + } + ] + }, + "SubscriptionsConfirmed": "0", + "SubscriptionsDeleted": "0", + "SubscriptionsPending": "0", + "TopicArn": "arn::sns::111111111111:" + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/sns/test_sns.py::TestSNSTopicCrudV2::test_create_topic_name_constraints": { + "recorded-date": "06-02-2026, 19:15:23", + "recorded-content": { + "valid-name-max-length": { + "TopicArn": "arn::sns::111111111111:", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "name-too-short": { + "Error": { + "Code": "InvalidParameter", + "Message": "Invalid parameter: Topic Name", + "Type": "Sender" + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + }, + "name-too-long": { + "Error": { + "Code": "InvalidParameter", + "Message": "Invalid parameter: Topic Name", + "Type": "Sender" + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + }, + "name-contains-fifo": { + "Error": { + "Code": "InvalidParameter", + "Message": "Invalid parameter: Topic Name", + "Type": "Sender" + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + }, + "fifo-name-not-contains-fifo": { + "Error": { + "Code": "InvalidParameter", + "Message": "Invalid parameter: Topic Name", + "Type": "Sender" + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + }, + "name-invalid-char-0": { + "Error": { + "Code": "InvalidParameter", + "Message": "Invalid parameter: Topic Name", + "Type": "Sender" + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + }, + "name-invalid-char-1": { + "Error": { + "Code": "InvalidParameter", + "Message": "Invalid parameter: Topic Name", + "Type": "Sender" + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + }, + "name-invalid-char-2": { + "Error": { + "Code": "InvalidParameter", + "Message": "Invalid parameter: Topic Name", + "Type": "Sender" + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + }, + "name-invalid-char-3": { + "Error": { + "Code": "InvalidParameter", + "Message": "Invalid parameter: Topic Name", + "Type": "Sender" + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + }, + "name-invalid-char-4": { + "Error": { + "Code": "InvalidParameter", + "Message": "Invalid parameter: Topic Name", + "Type": "Sender" + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + }, + "name-invalid-char-5": { + "Error": { + "Code": "InvalidParameter", + "Message": "Invalid parameter: Topic Name", + "Type": "Sender" + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + }, + "name-invalid-char-6": { + "Error": { + "Code": "InvalidParameter", + "Message": "Invalid parameter: Topic Name", + "Type": "Sender" + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + }, + "name-invalid-char-7": { + "Error": { + "Code": "InvalidParameter", + "Message": "Invalid parameter: Topic Name", + "Type": "Sender" + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + } + } + }, + "tests/aws/services/sns/test_sns.py::TestSNSTopicCrudV2::test_topic_get_attributes_with_fifo_false": { + "recorded-date": "29-09-2025, 11:10:41", + "recorded-content": { + "get-attrs-standard-topic": { + "Attributes": { + "DisplayName": "", + "EffectiveDeliveryPolicy": { + "http": { + "defaultHealthyRetryPolicy": { + "minDelayTarget": 20, + "maxDelayTarget": 20, + "numRetries": 3, + "numMaxDelayRetries": 0, + "numNoDelayRetries": 0, + "numMinDelayRetries": 0, + "backoffFunction": "linear" + }, + "disableSubscriptionOverrides": false, + "defaultRequestPolicy": { + "headerContentType": "text/plain; charset=UTF-8" + } + } + }, + "Owner": "111111111111", + "Policy": { + "Version": "2008-10-17", + "Id": "__default_policy_ID", + "Statement": [ + { + "Sid": "__default_statement_ID", + "Effect": "Allow", + "Principal": { + "AWS": "*" + }, + "Action": [ + "SNS:GetTopicAttributes", + "SNS:SetTopicAttributes", + "SNS:AddPermission", + "SNS:RemovePermission", + "SNS:DeleteTopic", + "SNS:Subscribe", + "SNS:ListSubscriptionsByTopic", + "SNS:Publish" + ], + "Resource": "arn::sns::111111111111:", + "Condition": { + "StringEquals": { + "AWS:SourceOwner": "111111111111" + } + } + } + ] + }, + "SubscriptionsConfirmed": "0", + "SubscriptionsDeleted": "0", + "SubscriptionsPending": "0", + "TopicArn": "arn::sns::111111111111:" + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "set-fifo-false-after-creation": { + "Error": { + "Code": "InvalidParameter", + "Message": "Invalid parameter: AttributeName", + "Type": "Sender" + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + } + } + }, + "tests/aws/services/sns/test_sns.py::TestSNSTopicCrudV2::test_create_topic_in_multiple_regions": { + "recorded-date": "08-10-2025, 08:54:10", + "recorded-content": { + "list-primary": { + "Topics": [ + { + "TopicArn": "arn::sns::111111111111:" + } + ], + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "list-secondary": { + "Topics": [ + { + "TopicArn": "arn::sns::111111111111:" + } + ], + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "topic-east": { + "Attributes": { + "DisplayName": "", + "EffectiveDeliveryPolicy": { + "http": { + "defaultHealthyRetryPolicy": { + "minDelayTarget": 20, + "maxDelayTarget": 20, + "numRetries": 3, + "numMaxDelayRetries": 0, + "numNoDelayRetries": 0, + "numMinDelayRetries": 0, + "backoffFunction": "linear" + }, + "disableSubscriptionOverrides": false, + "defaultRequestPolicy": { + "headerContentType": "text/plain; charset=UTF-8" + } + } + }, + "Owner": "111111111111", + "Policy": { + "Version": "2008-10-17", + "Id": "__default_policy_ID", + "Statement": [ + { + "Sid": "__default_statement_ID", + "Effect": "Allow", + "Principal": { + "AWS": "*" + }, + "Action": [ + "SNS:GetTopicAttributes", + "SNS:SetTopicAttributes", + "SNS:AddPermission", + "SNS:RemovePermission", + "SNS:DeleteTopic", + "SNS:Subscribe", + "SNS:ListSubscriptionsByTopic", + "SNS:Publish" + ], + "Resource": "arn::sns::111111111111:", + "Condition": { + "StringEquals": { + "AWS:SourceOwner": "111111111111" + } + } + } + ] + }, + "SubscriptionsConfirmed": "0", + "SubscriptionsDeleted": "0", + "SubscriptionsPending": "0", + "TopicArn": "arn::sns::111111111111:" + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "topic-west": { + "Attributes": { + "DisplayName": "", + "EffectiveDeliveryPolicy": { + "http": { + "defaultHealthyRetryPolicy": { + "minDelayTarget": 20, + "maxDelayTarget": 20, + "numRetries": 3, + "numMaxDelayRetries": 0, + "numNoDelayRetries": 0, + "numMinDelayRetries": 0, + "backoffFunction": "linear" + }, + "disableSubscriptionOverrides": false, + "defaultRequestPolicy": { + "headerContentType": "text/plain; charset=UTF-8" + } + } + }, + "Owner": "111111111111", + "Policy": { + "Version": "2008-10-17", + "Id": "__default_policy_ID", + "Statement": [ + { + "Sid": "__default_statement_ID", + "Effect": "Allow", + "Principal": { + "AWS": "*" + }, + "Action": [ + "SNS:GetTopicAttributes", + "SNS:SetTopicAttributes", + "SNS:AddPermission", + "SNS:RemovePermission", + "SNS:DeleteTopic", + "SNS:Subscribe", + "SNS:ListSubscriptionsByTopic", + "SNS:Publish" + ], + "Resource": "arn::sns::111111111111:", + "Condition": { + "StringEquals": { + "AWS:SourceOwner": "111111111111" + } + } + } + ] + }, + "SubscriptionsConfirmed": "0", + "SubscriptionsDeleted": "0", + "SubscriptionsPending": "0", + "TopicArn": "arn::sns::111111111111:" + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/sns/test_sns.py::TestSNSSubscriptionCrudV2::test_subscribe_sms": { + "recorded-date": "06-10-2025, 11:39:50", + "recorded-content": { + "subscribe-sms-1": { + "SubscriptionArn": "arn::sns::111111111111::", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/sns/test_sns.py::TestSNSSubscriptionCrudV2::test_subscribe_unknown_topic": { + "recorded-date": "06-10-2025, 11:43:45", + "recorded-content": { + "subscribe-unknown-topic": { + "Error": { + "Code": "NotFound", + "Message": "Topic does not exist", + "Type": "Sender" + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 404 + } + } + } + }, + "tests/aws/services/sns/test_sns.py::TestSNSSubscriptionCrudV2::test_subscribe_unknown_sqs_queue": { + "recorded-date": "06-10-2025, 12:03:29", + "recorded-content": { + "subscribe-unknown-sqs": { + "SubscriptionArn": "arn::sns::111111111111::", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "subscribe-unknown-sqs-invalid_arn": { + "Error": { + "Code": "InvalidParameter", + "Message": "Invalid parameter: SQS endpoint ARN", + "Type": "Sender" + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + } + } + }, + "tests/aws/services/sns/test_sns.py::TestSNSSubscriptionCrudV2::test_subscribe_sqs_queue_url": { + "recorded-date": "06-10-2025, 11:56:36", + "recorded-content": { + "subscribe-sqs-via-url-error": { + "Error": { + "Code": "InvalidParameter", + "Message": "Invalid parameter: SQS endpoint ARN", + "Type": "Sender" + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + } + } + }, + "tests/aws/services/sns/test_sns.py::TestSNSSubscriptionCrudV2::test_double_subscription": { + "recorded-date": "06-10-2025, 11:39:56", + "recorded-content": { + "double-subscription-first": { + "SubscriptionArn": "arn::sns::111111111111:double-sub-befdfdff:", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "double-subscription-second": { + "SubscriptionArn": "arn::sns::111111111111:double-sub-befdfdff:", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/sns/test_sns.py::TestSNSSubscriptionCrudV2::test_subscribe_bad_sms": { + "recorded-date": "06-10-2025, 11:39:57", + "recorded-content": { + "subscribe-bad-sms": { + "Error": { + "Code": "InvalidParameter", + "Message": "Invalid SMS endpoint: invalid-number", + "Type": "Sender" + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + } + } + }, + "tests/aws/services/sns/test_sns.py::TestSNSSubscriptionCrudV2::test_creating_subscription": { + "recorded-date": "07-10-2025, 07:40:45", + "recorded-content": { + "create-subscription": { + "SubscriptionArn": "pending confirmation", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/sns/test_sns.py::TestSNSSubscriptionCrudV2::test_unsubscribe_from_deleted_topic": { + "recorded-date": "07-10-2025, 07:46:56", + "recorded-content": { + "unsubscribe-deleted-topic": { + "Error": { + "Code": "InvalidParameter", + "Message": "Invalid parameter: SubscriptionArn Reason: An ARN must have at least 6 elements, not 1", + "Type": "Sender" + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + } + } + }, + "tests/aws/services/sns/test_sns.py::TestSNSSubscriptionCrudV2::test_getting_subscriptions_by_topic": { + "recorded-date": "07-10-2025, 08:29:43", + "recorded-content": { + "list-subscriptions-by-topic": { + "Subscriptions": [ + { + "Endpoint": "arn::sqs::111111111111:", + "Owner": "111111111111", + "Protocol": "sqs", + "SubscriptionArn": "arn::sns::111111111111::", + "TopicArn": "arn::sns::111111111111:" + } + ], + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/sns/test_sns.py::TestSNSSubscriptionCrudV2::test_subscribe_sms_obscure_phone_number": { + "recorded-date": "06-10-2025, 11:39:51", + "recorded-content": { + "subscribe-sms-2": { + "SubscriptionArn": "arn::sns::111111111111::", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/sns/test_sns.py::TestSNSSubscriptionCrudV2::test_subscribe_attributes": { + "recorded-date": "12-01-2026, 13:03:28", + "recorded-content": { + "get-subscription-attributes": { + "Attributes": { + "ConfirmationWasAuthenticated": "true", + "Endpoint": "arn::sqs::111111111111:", + "Owner": "111111111111", + "PendingConfirmation": "false", + "Protocol": "sqs", + "RawMessageDelivery": "false", + "SubscriptionArn": "arn::sns::111111111111::", + "SubscriptionPrincipal": "arn::iam::111111111111:user/", + "TopicArn": "arn::sns::111111111111:" + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/sns/test_sns.py::TestSNSSubscriptionCrudV2::test_creating_subscription_with_attributes": { + "recorded-date": "12-01-2026, 13:08:24", + "recorded-content": { + "subscription-with-attributes": { + "Attributes": { + "ConfirmationWasAuthenticated": "true", + "Endpoint": "arn::sqs::111111111111:", + "Owner": "111111111111", + "PendingConfirmation": "false", + "Protocol": "sqs", + "RawMessageDelivery": "true", + "SubscriptionArn": "arn::sns::111111111111::", + "SubscriptionPrincipal": "arn::iam::111111111111:user/", + "TopicArn": "arn::sns::111111111111:" + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/sns/test_sns.py::TestSNSSubscriptionCrudV2::test_delete_subscriptions_on_delete_topic": { + "recorded-date": "12-01-2026, 13:09:31", + "recorded-content": { + "get-sub-after-topic-delete": { + "Attributes": { + "ConfirmationWasAuthenticated": "true", + "Endpoint": "arn::sqs::111111111111:", + "Owner": "111111111111", + "PendingConfirmation": "false", + "Protocol": "sqs", + "RawMessageDelivery": "true", + "SubscriptionArn": "arn::sns::111111111111::", + "SubscriptionPrincipal": "arn::iam::111111111111:user/", + "TopicArn": "arn::sns::111111111111:" + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/sns/test_sns.py::TestSNSSubscriptionCrudV2::test_set_subscription_attributes": { + "recorded-date": "13-01-2026, 09:21:16", + "recorded-content": { + "set-subscription-attributes": { + "Attributes": { + "ConfirmationWasAuthenticated": "true", + "Endpoint": "arn::sqs::111111111111:", + "Owner": "111111111111", + "PendingConfirmation": "false", + "Protocol": "sqs", + "RawMessageDelivery": "true", + "SubscriptionArn": "arn::sns::111111111111::", + "SubscriptionPrincipal": "arn::iam::111111111111:user/", + "TopicArn": "arn::sns::111111111111:" + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/sns/test_sns.py::TestSNSSubscriptionCrudV2::test_subscribe_invalid_filter_policy": { + "recorded-date": "13-01-2026, 09:26:43", + "recorded-content": { + "subscribe-invalid-filter-policy": { + "Error": { + "Code": "InvalidParameter", + "Message": "Invalid parameter: Attributes Reason: FilterPolicy: failed to parse JSON. Unrecognized token 'invalid': was expecting (JSON String, Number, Array, Object or token 'null', 'true' or 'false')\n at [Source: REDACTED (`StreamReadFeature.INCLUDE_SOURCE_IN_LOCATION` disabled); line: 1, column: 8]", + "Type": "Sender" + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + } + } + }, + "tests/aws/services/sns/test_sns.py::TestSNSSubscriptionCrudV2::test_check_not_opted_out": { + "recorded-date": "06-10-2025, 11:40:48", + "recorded-content": {} + }, + "tests/aws/services/sns/test_sns.py::TestSNSSubscriptionCrudV2::test_check_opted_out": { + "recorded-date": "06-10-2025, 11:40:49", + "recorded-content": {} + }, + "tests/aws/services/sns/test_sns.py::TestSNSSubscriptionCrudV2::test_check_opted_out_invalid": { + "recorded-date": "06-10-2025, 11:40:49", + "recorded-content": {} + }, + "tests/aws/services/sns/test_sns.py::TestSNSSubscriptionCrudV2::test_list_opted_out": { + "recorded-date": "06-10-2025, 11:40:50", + "recorded-content": { + "list-opted-out": { + "phoneNumbers": [], + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/sns/test_sns.py::TestSNSSubscriptionCrudV2::test_opt_in": { + "recorded-date": "06-10-2025, 11:40:50", + "recorded-content": {} + }, + "tests/aws/services/sns/test_sns.py::TestSNSSubscriptionCrudV2::test_confirm_subscription": { + "recorded-date": "14-01-2026, 09:45:12", + "recorded-content": { + "confirm-subscription": { + "SubscriptionArn": "arn::sns::111111111111:confirm-sub-e46f689a:", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/sns/test_sns.py::TestSNSSubscriptionCrudV2::test_get_subscription_attributes_error_not_exists": { + "recorded-date": "14-01-2026, 10:27:15", + "recorded-content": { + "get-sub-attrs-nonexistent": { + "Error": { + "Code": "NotFound", + "Message": "Subscription does not exist", + "Type": "Sender" + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 404 + } + } + } + }, + "tests/aws/services/sns/test_sns.py::TestSNSSubscriptionCrudV2::test_subscribe_invalid_sms": { + "recorded-date": "06-10-2025, 12:09:25", + "recorded-content": { + "subscribe-bad-sms-+15--551234567": { + "Error": { + "Code": "InvalidParameter", + "Message": "Invalid SMS endpoint: +15--551234567", + "Type": "Sender" + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + }, + "subscribe-bad-sms-NAA+15551234567": { + "Error": { + "Code": "InvalidParameter", + "Message": "Invalid SMS endpoint: NAA+15551234567", + "Type": "Sender" + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + }, + "subscribe-bad-sms-+15551234567.": { + "Error": { + "Code": "InvalidParameter", + "Message": "Invalid SMS endpoint: +15551234567.", + "Type": "Sender" + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + }, + "subscribe-bad-sms-/+15551234567": { + "Error": { + "Code": "InvalidParameter", + "Message": "Invalid SMS endpoint: /+15551234567", + "Type": "Sender" + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + } + } + }, + "tests/aws/services/sns/test_sns.py::TestSNSSMS::test_set_get_sms_attributes": { + "recorded-date": "13-10-2025, 10:30:42", + "recorded-content": { + "get-sms-all-attributes": { + "attributes": { + "DefaultSMSType": "Promotional", + "DefaultSenderID": "LSTest", + "DeliveryStatusSuccessSamplingRate": "100", + "MonthlySpendLimit": "1" + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "get-sms-some-attributes": { + "attributes": { + "DefaultSMSType": "Promotional", + "DefaultSenderID": "LSTest" + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/sns/test_sns.py::TestSNSSMS::test_set_invalid_sms_attributes[InvalidAttributeName]": { + "recorded-date": "13-10-2025, 10:43:41", + "recorded-content": { + "invalid-attribute": { + "Error": { + "Code": "InvalidParameter", + "Message": "InvalidAttribute is not a valid attribute", + "Type": "Sender" + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + } + } + }, + "tests/aws/services/sns/test_sns.py::TestSNSSMS::test_set_invalid_sms_attributes[TooLongID]": { + "recorded-date": "13-10-2025, 10:43:45", + "recorded-content": { + "invalid-attribute": { + "Error": { + "Code": "InvalidParameter", + "Message": "DefaultSendID is not a valid attribute", + "Type": "Sender" + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + } + } + }, + "tests/aws/services/sns/test_sns.py::TestSNSSMS::test_set_invalid_sms_attributes[NoLetterID]": { + "recorded-date": "13-10-2025, 10:43:52", + "recorded-content": { + "invalid-attribute": { + "Error": { + "Code": "InvalidParameter", + "Message": "DefaultSendID is not a valid attribute", + "Type": "Sender" + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + } + } + }, + "tests/aws/services/sns/test_sns.py::TestSNSSMS::test_set_invalid_sms_attributes[InvalidSMSType]": { + "recorded-date": "13-10-2025, 10:43:57", + "recorded-content": { + "invalid-attribute": { + "Error": { + "Code": "InvalidParameter", + "Message": "DefaultSMSType is invalid", + "Type": "Sender" + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + } + } + }, + "tests/aws/services/sns/test_sns.py::TestSNSSMS::test_get_sms_attributes_from_unmodified_region": { + "recorded-date": "13-10-2025, 11:12:33", + "recorded-content": { + "get-sms-attributes_unmodified_region": { + "attributes": { + "MonthlySpendLimit": "1" + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/sns/test_sns.py::TestSNSPlatformApplicationCrud::test_create_platform_application": { + "recorded-date": "29-10-2025, 09:14:55", + "recorded-content": { + "create-platform-application": { + "PlatformApplicationArn": "arn::sns::111111111111:app/ADM/", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/sns/test_sns.py::TestSNSPlatformApplicationCrud::test_list_platform_applications": { + "recorded-date": "29-10-2025, 09:20:15", + "recorded-content": { + "list-platform-applications": { + "PlatformApplications": [ + { + "Attributes": { + "Enabled": "true" + }, + "PlatformApplicationArn": "arn::sns::111111111111:app/ADM/" + } + ], + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/sns/test_sns.py::TestSNSPlatformApplicationCrud::test_create_platform_application_invalid_attributes[no-args]": { + "recorded-date": "28-10-2025, 09:29:33", + "recorded-content": { + "platform-application-no-attributes": { + "Error": { + "Code": "ValidationError", + "Message": "1 validation error detected: Value null at 'attributes' failed to satisfy constraint: Member must not be null", + "Type": "Sender" + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + } + } + }, + "tests/aws/services/sns/test_sns.py::TestSNSPlatformApplicationCrud::test_create_platform_application_invalid_attributes[missing-credential]": { + "recorded-date": "28-10-2025, 09:29:33", + "recorded-content": { + "platform-application-no-attributes": { + "Error": { + "Code": "InvalidParameter", + "Message": "Invalid parameter: Attributes Reason: PlatformPrincipal attribute provided without PlatformCredential", + "Type": "Sender" + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + } + } + }, + "tests/aws/services/sns/test_sns.py::TestSNSPlatformApplicationCrud::test_create_platform_application_invalid_attributes[missing-principal]": { + "recorded-date": "28-10-2025, 09:29:34", + "recorded-content": { + "platform-application-no-attributes": { + "Error": { + "Code": "InvalidParameter", + "Message": "Invalid parameter: Attributes Reason: PlatformCredential attribute provided without PlatformPrincipal", + "Type": "Sender" + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + } + } + }, + "tests/aws/services/sns/test_sns.py::TestSNSPlatformApplicationCrud::test_create_platform_application_invalid_name[too-long]": { + "recorded-date": "28-10-2025, 09:29:34", + "recorded-content": { + "invalid-application-name": { + "Error": { + "Code": "InvalidParameter", + "Message": "Invalid parameter: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa Reason: must be at most 256 characters long", + "Type": "Sender" + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + } + } + }, + "tests/aws/services/sns/test_sns.py::TestSNSPlatformApplicationCrud::test_create_platform_application_invalid_name[empty]": { + "recorded-date": "28-10-2025, 09:29:34", + "recorded-content": { + "invalid-application-name": { + "Error": { + "Code": "InvalidParameter", + "Message": "Invalid parameter: Reason: cannot be empty", + "Type": "Sender" + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + } + } + }, + "tests/aws/services/sns/test_sns.py::TestSNSPlatformApplicationCrud::test_create_platform_application_invalid_name[invalid-char]": { + "recorded-date": "28-10-2025, 09:29:35", + "recorded-content": { + "invalid-application-name": { + "Error": { + "Code": "InvalidParameter", + "Message": "Invalid parameter: @name Reason: must contain only characters 'a'-'z', 'A'-'Z', '0'-'9', '_', '-', and '.'", + "Type": "Sender" + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + } + } + }, + "tests/aws/services/sns/test_sns.py::TestSNSPlatformApplicationCrud::test_create_platform_application_invalid_platform": { + "recorded-date": "28-10-2025, 09:29:35", + "recorded-content": { + "invalid-platform": { + "Error": { + "Code": "InvalidParameter", + "Message": "Invalid parameter: Platform Reason: AAA is not supported", + "Type": "Sender" + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + } + } + }, + "tests/aws/services/sns/test_sns.py::TestSNSPlatformApplicationCrud::test_get_platform_application_attributes_invalid_arn": { + "recorded-date": "28-10-2025, 09:29:37", + "recorded-content": { + "invalid-application-arn": { + "Error": { + "Code": "InvalidParameter", + "Message": "Invalid parameter: PlatformApplicationArn Reason: An ARN must have at least 6 elements, not 1", + "Type": "Sender" + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + } + } + }, + "tests/aws/services/sns/test_sns.py::TestSNSPlatformApplicationCrud::test_get_platform_application_attributes": { + "recorded-date": "28-10-2025, 09:29:36", + "recorded-content": { + "get-application-attributes": { + "Attributes": { + "Enabled": "true" + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/sns/test_sns.py::TestSNSPlatformApplicationCrud::test_set_platform_application_attributes": { + "recorded-date": "28-10-2025, 09:30:09", + "recorded-content": { + "set-get-application-attributes": { + "Attributes": { + "Enabled": "true", + "SuccessFeedbackSampleRate": "50" + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/sns/test_sns.py::TestSNSPlatformApplicationCrud::test_get_platform_application_attributes_non_existing_app": { + "recorded-date": "28-10-2025, 09:29:37", + "recorded-content": { + "non_existing-application-arn": { + "Error": { + "Code": "NotFound", + "Message": "PlatformApplication does not exist", + "Type": "Sender" + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 404 + } + } + } + }, + "tests/aws/services/sns/test_sns.py::TestSNSPlatformApplicationCrud::test_set_platform_application_attributes_invalid_arn": { + "recorded-date": "28-10-2025, 09:30:09", + "recorded-content": { + "invalid-application-arn": { + "Error": { + "Code": "InvalidParameter", + "Message": "Invalid parameter: PlatformApplicationArn Reason: An ARN must have at least 6 elements, not 1", + "Type": "Sender" + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + } + } + }, + "tests/aws/services/sns/test_sns.py::TestSNSPlatformApplicationCrud::test_set_platform_application_attributes_non_existing_app": { + "recorded-date": "28-10-2025, 09:17:14", + "recorded-content": { + "non_existing-application-arn": { + "Error": { + "Code": "ValidationError", + "Message": "1 validation error detected: Value null at 'attributes' failed to satisfy constraint: Member must not be null", + "Type": "Sender" + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + } + } + }, + "tests/aws/services/sns/test_sns.py::TestSNSPlatformApplicationCrud::test_set_platform_application_attributes_non_existing_app[no-args]": { + "recorded-date": "28-10-2025, 09:30:09", + "recorded-content": { + "non_existing-application-arn": { + "Error": { + "Code": "ValidationError", + "Message": "1 validation error detected: Value null at 'attributes' failed to satisfy constraint: Member must not be null", + "Type": "Sender" + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + } + } + }, + "tests/aws/services/sns/test_sns.py::TestSNSPlatformApplicationCrud::test_set_platform_application_attributes_non_existing_app[missing-credential]": { + "recorded-date": "28-10-2025, 09:23:04", + "recorded-content": { + "non_existing-application-arn": { + "Error": { + "Code": "NotFound", + "Message": "PlatformApplication does not exist", + "Type": "Sender" + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 404 + } + } + } + }, + "tests/aws/services/sns/test_sns.py::TestSNSPlatformApplicationCrud::test_set_platform_application_attributes_non_existing_app[missing-principal]": { + "recorded-date": "28-10-2025, 09:23:04", + "recorded-content": { + "non_existing-application-arn": { + "Error": { + "Code": "NotFound", + "Message": "PlatformApplication does not exist", + "Type": "Sender" + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 404 + } + } + } + }, + "tests/aws/services/sns/test_sns.py::TestSNSPlatformApplicationCrud::test_set_platform_application_attributes_non_existing_app[dummy-args]": { + "recorded-date": "28-10-2025, 09:30:09", + "recorded-content": { + "non_existing-application-arn": { + "Error": { + "Code": "NotFound", + "Message": "PlatformApplication does not exist", + "Type": "Sender" + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 404 + } + } + } + }, + "tests/aws/services/sns/test_sns.py::TestSNSPlatformEndpointCrud::test_create_platform_endpoint": { + "recorded-date": "31-10-2025, 21:26:47", + "recorded-content": { + "create-platform-endpoint": { + "EndpointArn": "arn::sns::111111111111:endpoint/ADM//", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/sns/test_sns.py::TestSNSPlatformEndpointCrud::test_create_platform_endpoint_idempotency": { + "recorded-date": "31-10-2025, 21:26:49", + "recorded-content": { + "create-platform-endpoint": { + "EndpointArn": "arn::sns::111111111111:endpoint/ADM//", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "create-platform-endpoint-idempotent": { + "EndpointArn": "arn::sns::111111111111:endpoint/ADM//", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "create-platform-endpoint-different-token": { + "Error": { + "Code": "InvalidParameter", + "Message": "Invalid parameter: Token Reason: Endpoint arn::sns::111111111111:endpoint/ADM// already exists with the same Token, but different attributes.", + "Type": "Sender" + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + } + } + }, + "tests/aws/services/sns/test_sns.py::TestSNSPlatformEndpointCrud::test_create_platform_endpoint_non_existent_app": { + "recorded-date": "31-10-2025, 21:26:50", + "recorded-content": { + "create-platform-endpoint": { + "Error": { + "Code": "NotFound", + "Message": "PlatformApplication does not exist", + "Type": "Sender" + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 404 + } + } + } + }, + "tests/aws/services/sns/test_sns.py::TestSNSPlatformEndpointCrud::test_list_platform_endpoints": { + "recorded-date": "31-10-2025, 21:26:51", + "recorded-content": { + "list-endpoints-by-app": { + "Endpoints": [ + { + "Attributes": { + "Enabled": "true", + "Token": "token_1" + }, + "EndpointArn": "arn::sns::111111111111:endpoint/ADM//" + } + ], + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/sns/test_sns.py::TestSNSPlatformEndpointCrud::test_delete_platform_endpoint": { + "recorded-date": "31-10-2025, 21:27:05", + "recorded-content": { + "list-endpoints-by-app-pre-delete": { + "Endpoints": [ + { + "Attributes": { + "Enabled": "true", + "Token": "token_1" + }, + "EndpointArn": "arn::sns::111111111111:endpoint/ADM//" + } + ], + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "delete-endpoint": { + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "list-endpoints-by-app-post-delete": { + "Endpoints": [], + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/sns/test_sns.py::TestSNSPlatformEndpointCrud::test_delete_platform_endpoint_with_subscription": { + "recorded-date": "04-11-2025, 19:18:31", + "recorded-content": { + "list-subscriptions-pre-delete": { + "NextToken": "", + "Subscriptions": [ + { + "Endpoint": "arn::sns::111111111111:endpoint/ADM//", + "Owner": "111111111111", + "Protocol": "application", + "SubscriptionArn": "arn::sns::111111111111::", + "TopicArn": "arn::sns::111111111111:" + } + ], + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "delete-endpoint": { + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "list-subscriptions-post-delete": { + "NextToken": "", + "Subscriptions": [ + { + "Endpoint": "arn::sns::111111111111:endpoint/ADM//", + "Owner": "111111111111", + "Protocol": "application", + "SubscriptionArn": "arn::sns::111111111111::", + "TopicArn": "arn::sns::111111111111:" + } + ], + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/sns/test_sns.py::TestSNSPlatformEndpointCrud::test_delete_endpoints_of_deleted_app": { + "recorded-date": "31-10-2025, 21:28:02", + "recorded-content": { + "delete-application": { + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "list-endpoints-after-app-delete": { + "Error": { + "Code": "NotFound", + "Message": "PlatformApplication does not exist", + "Type": "Sender" + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 404 + } + } + } + }, + "tests/aws/services/sns/test_sns.py::TestSNSPlatformEndpointCrud::test_get_platform_endpoint_attributes": { + "recorded-date": "31-10-2025, 21:28:04", + "recorded-content": { + "get-platform-endpoint-attributes": { + "Attributes": { + "Enabled": "true", + "Token": "token_1" + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/sns/test_sns.py::TestSNSPlatformEndpointCrud::test_set_platform_endpoint_attributes": { + "recorded-date": "31-10-2025, 21:28:06", + "recorded-content": { + "set-platform-endpoint-attributes": { + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "get-platform-endpoint-attributes": { + "Attributes": { + "Enabled": "false", + "Token": "token_1" + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/sns/test_sns.py::TestSNSPlatformEndpointCrud::test_set_platform_endpoint_attributes_invalid_arn": { + "recorded-date": "31-10-2025, 20:20:11", + "recorded-content": { + "set-platform-endpoint-attributes-non-existent-app": { + "Error": { + "Code": "InvalidParameter", + "Message": "Invalid parameter: EndpointArn Reason: Wrong number of slashes in relative portion of the ARN.", + "Type": "Sender" + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + } + } + }, + "tests/aws/services/sns/test_sns.py::TestSNSPlatformEndpointCrud::test_set_platform_endpoint_attributes_non_existent_endpoint": { + "recorded-date": "31-10-2025, 21:28:06", + "recorded-content": { + "set-platform-endpoint-attributes-non-existent-app": { + "Error": { + "Code": "NotFound", + "Message": "Endpoint does not exist", + "Type": "Sender" + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 404 + } + } + } + }, + "tests/aws/services/sns/test_sns.py::TestSNSPlatformEndpointCrud::test_set_platform_endpoint_attributes_invalid_attributes[Invalid_Name_Principal]": { + "recorded-date": "31-10-2025, 21:31:04", + "recorded-content": { + "set-platform-endpoint-invalid-attributes": { + "Error": { + "Code": "InvalidParameter", + "Message": "Invalid parameter: Attributes Reason: Invalid attribute name: PlatformPrincipal", + "Type": "Sender" + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + } + } + }, + "tests/aws/services/sns/test_sns.py::TestSNSPlatformEndpointCrud::test_set_platform_endpoint_attributes_invalid_attributes[Invalid_Name_Credential]": { + "recorded-date": "31-10-2025, 21:31:06", + "recorded-content": { + "set-platform-endpoint-invalid-attributes": { + "Error": { + "Code": "InvalidParameter", + "Message": "Invalid parameter: Attributes Reason: Invalid attribute name: PlatformCredential", + "Type": "Sender" + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + } + } + }, + "tests/aws/services/sns/test_sns.py::TestSNSPlatformEndpointCrud::test_set_platform_endpoint_attributes_invalid_attributes[Invalid_Name_Generic]": { + "recorded-date": "31-10-2025, 21:31:07", + "recorded-content": { + "set-platform-endpoint-invalid-attributes": { + "Error": { + "Code": "InvalidParameter", + "Message": "Invalid parameter: Attributes Reason: Invalid attribute name: InvalidKey", + "Type": "Sender" + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + } + } + }, + "tests/aws/services/sns/test_sns.py::TestSNSPlatformEndpointCrud::test_set_platform_endpoint_attributes_invalid_attributes[Data_Too_Long]": { + "recorded-date": "31-10-2025, 21:31:10", + "recorded-content": { + "set-platform-endpoint-invalid-attributes": { + "Error": { + "Code": "InvalidParameter", + "Message": "Invalid parameter: Attributes Reason: Invalid value for attribute: CustomUserData: must be at most 2048 bytes long in UTF-8 encoding", + "Type": "Sender" + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + } + } + }, + "tests/aws/services/sns/test_sns.py::TestSNSPlatformEndpointCrud::test_get_platform_endpoint_attributes_non_existent_endpoint": { + "recorded-date": "31-10-2025, 21:28:06", + "recorded-content": { + "set-platform-endpoint-attributes-non-existent-app": { + "Error": { + "Code": "NotFound", + "Message": "Endpoint does not exist", + "Type": "Sender" + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 404 + } + } + } + }, + "tests/aws/services/sns/test_sns.py::TestSNSPlatformEndpointCrud::test_set_platform_endpoint_attributes_invalid_attributes[Empty]": { + "recorded-date": "31-10-2025, 21:31:03", + "recorded-content": { + "set-platform-endpoint-invalid-attributes": { + "Error": { + "Code": "ValidationError", + "Message": "1 validation error detected: Value null at 'attributes' failed to satisfy constraint: Member must not be null", + "Type": "Sender" + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + } + } + }, + "tests/aws/services/sns/test_sns.py::TestSNSPlatformEndpointCrud::test_create_platform_endpoint_with_invalid_attributes[Empty]": { + "recorded-date": "31-10-2025, 21:25:17", + "recorded-content": {} + }, + "tests/aws/services/sns/test_sns.py::TestSNSPlatformEndpointCrud::test_create_platform_endpoint_with_invalid_attributes[Invalid_Name_Principal]": { + "recorded-date": "31-10-2025, 21:28:15", + "recorded-content": { + "create-platform-endpoint-invalid-attr": { + "Error": { + "Code": "InvalidParameter", + "Message": "Invalid parameter: Attributes Reason: Invalid attribute name: PlatformPrincipal", + "Type": "Sender" + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + } + } + }, + "tests/aws/services/sns/test_sns.py::TestSNSPlatformEndpointCrud::test_create_platform_endpoint_with_invalid_attributes[Invalid_Name_Credential]": { + "recorded-date": "31-10-2025, 21:28:16", + "recorded-content": { + "create-platform-endpoint-invalid-attr": { + "Error": { + "Code": "InvalidParameter", + "Message": "Invalid parameter: Attributes Reason: Invalid attribute name: PlatformCredential", + "Type": "Sender" + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + } + } + }, + "tests/aws/services/sns/test_sns.py::TestSNSPlatformEndpointCrud::test_create_platform_endpoint_with_invalid_attributes[Invalid_Name_Generic]": { + "recorded-date": "31-10-2025, 21:28:17", + "recorded-content": { + "create-platform-endpoint-invalid-attr": { + "Error": { + "Code": "InvalidParameter", + "Message": "Invalid parameter: Attributes Reason: Invalid attribute name: InvalidKey", + "Type": "Sender" + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + } + } + }, + "tests/aws/services/sns/test_sns.py::TestSNSPlatformEndpointCrud::test_create_platform_endpoint_with_invalid_attributes[Data_Too_Long]": { + "recorded-date": "31-10-2025, 21:28:18", + "recorded-content": { + "create-platform-endpoint-invalid-attr": { + "Error": { + "Code": "InvalidParameter", + "Message": "Invalid parameter: Attributes Reason: Invalid value for attribute: CustomUserData: must be at most 2048 bytes long in UTF-8 encoding", + "Type": "Sender" + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + } + } + }, + "tests/aws/services/sns/test_sns.py::TestSNSPlatformEndpointCrud::test_create_platform_endpoint_double_custom_data": { + "recorded-date": "31-10-2025, 21:41:35", + "recorded-content": { + "create-endpoint-double-custom-data": { + "Attributes": { + "CustomUserData": "foo", + "Enabled": "true", + "Token": "token_1" + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/sns/test_sns.py::TestSNSPlatformEndpointCrud::test_create_platform_endpoint_custom_data": { + "recorded-date": "31-10-2025, 21:45:15", + "recorded-content": { + "create-endpoint-double-custom-data": { + "Attributes": { + "CustomUserData": "bar", + "Enabled": "true", + "Token": "token_1" + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/sns/test_sns.py::TestSNSSMS::test_is_phone_number_opted_out": { + "recorded-date": "01-12-2025, 19:33:36", + "recorded-content": { + "phone-number-opted-out": { + "isOptedOut": true, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/sns/test_sns.py::TestSNSSMS::test_list_phone_numbers_opted_out": { + "recorded-date": "01-12-2025, 19:37:44", + "recorded-content": { + "list-phone-numbers-opted-out": { + "phoneNumbers": [ + "" + ], + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/sns/test_sns.py::TestSNSSMS::test_opt_in_phone_number": { + "recorded-date": "01-12-2025, 19:44:54", + "recorded-content": { + "opt-in-phone-number": { + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/sns/test_sns.py::TestSNSSMS::test_opt_in_non_existing_phone_number": { + "recorded-date": "01-12-2025, 19:53:23", + "recorded-content": { + "opt-in-non-existing-number": { + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/sns/test_sns.py::TestSNSTopicCrudV2::test_topic_add_permission": { + "recorded-date": "11-12-2025, 11:43:04", + "recorded-content": { + "add-permission-response": { + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "topic-policy-after-permission": { + "Id": "__default_policy_ID", + "Statement": [ + { + "Action": [ + "SNS:GetTopicAttributes", + "SNS:SetTopicAttributes", + "SNS:AddPermission", + "SNS:RemovePermission", + "SNS:DeleteTopic", + "SNS:Subscribe", + "SNS:ListSubscriptionsByTopic", + "SNS:Publish" + ], + "Condition": { + "StringEquals": { + "AWS:SourceOwner": "111111111111" + } + }, + "Effect": "Allow", + "Principal": { + "AWS": "*" + }, + "Resource": "arn::sns::111111111111:", + "Sid": "__default_statement_ID" + }, + { + "Action": "SNS:Publish", + "Effect": "Allow", + "Principal": { + "AWS": "arn::iam::111111111111:" + }, + "Resource": "arn::sns::111111111111:", + "Sid": "test" + } + ], + "Version": "2008-10-17" + } + } + }, + "tests/aws/services/sns/test_sns.py::TestSNSTopicCrudV2::test_topic_remove_permission": { + "recorded-date": "11-12-2025, 12:02:07", + "recorded-content": { + "topic-policy": { + "Id": "__default_policy_ID", + "Statement": [ + { + "Action": [ + "SNS:GetTopicAttributes", + "SNS:SetTopicAttributes", + "SNS:AddPermission", + "SNS:RemovePermission", + "SNS:DeleteTopic", + "SNS:Subscribe", + "SNS:ListSubscriptionsByTopic", + "SNS:Publish" + ], + "Condition": { + "StringEquals": { + "AWS:SourceOwner": "111111111111" + } + }, + "Effect": "Allow", + "Principal": { + "AWS": "*" + }, + "Resource": "arn::sns::111111111111:", + "Sid": "__default_statement_ID" + } + ], + "Version": "2008-10-17" + } + } + }, + "tests/aws/services/sns/test_sns.py::TestSNSTopicCrudV2::test_topic_policy_overwrite_lifecycle": { + "recorded-date": "11-12-2025, 12:39:06", + "recorded-content": {} + }, + "tests/aws/services/sns/test_sns.py::TestSNSTopicCrudV2::test_topic_add_multiple_permissions": { + "recorded-date": "11-12-2025, 12:53:37", + "recorded-content": { + "add-permission-response": { + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "topic-policy-after-permission": { + "Id": "__default_policy_ID", + "Statement": [ + { + "Action": [ + "SNS:GetTopicAttributes", + "SNS:SetTopicAttributes", + "SNS:AddPermission", + "SNS:RemovePermission", + "SNS:DeleteTopic", + "SNS:Subscribe", + "SNS:ListSubscriptionsByTopic", + "SNS:Publish" + ], + "Condition": { + "StringEquals": { + "AWS:SourceOwner": "111111111111" + } + }, + "Effect": "Allow", + "Principal": { + "AWS": "*" + }, + "Resource": "arn::sns::111111111111:", + "Sid": "__default_statement_ID" + }, + { + "Action": [ + "SNS:Publish", + "SNS:Subscribe" + ], + "Effect": "Allow", + "Principal": { + "AWS": "arn::iam::111111111111:" + }, + "Resource": "arn::sns::111111111111:", + "Sid": "test" + } + ], + "Version": "2008-10-17" + } + } + }, + "tests/aws/services/sns/test_sns.py::TestSNSTopicCrudV2::test_add_permission_errors": { + "recorded-date": "11-12-2025, 13:00:18", + "recorded-content": { + "duplicate-label": { + "Error": { + "Code": "InvalidParameter", + "Message": "Invalid parameter: Statement already exists", + "Type": "Sender" + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + }, + "topic-not-found": { + "Error": { + "Code": "NotFound", + "Message": "Topic does not exist", + "Type": "Sender" + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 404 + } + }, + "invalid-action": { + "Error": { + "Code": "InvalidParameter", + "Message": "Invalid parameter: Policy statement action out of service scope!", + "Type": "Sender" + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + } + } + }, + "tests/aws/services/sns/test_sns.py::TestSNSTopicCrudV2::test_remove_permission_errors": { + "recorded-date": "11-12-2025, 13:05:40", + "recorded-content": { + "topic-not-found": { + "Error": { + "Code": "NotFound", + "Message": "Topic does not exist", + "Type": "Sender" + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 404 + } + } + } + }, + "tests/aws/services/sns/test_sns.py::TestSNSTopicCrudV2::test_data_protection_policy_crud": { + "recorded-date": "18-12-2025, 07:54:08", + "recorded-content": { + "get-topic-attributes-before-policy": { + "Attributes": { + "DisplayName": "", + "EffectiveDeliveryPolicy": { + "http": { + "defaultHealthyRetryPolicy": { + "minDelayTarget": 20, + "maxDelayTarget": 20, + "numRetries": 3, + "numMaxDelayRetries": 0, + "numNoDelayRetries": 0, + "numMinDelayRetries": 0, + "backoffFunction": "linear" + }, + "disableSubscriptionOverrides": false, + "defaultRequestPolicy": { + "headerContentType": "text/plain; charset=UTF-8" + } + } + }, + "Owner": "111111111111", + "Policy": { + "Version": "2008-10-17", + "Id": "__default_policy_ID", + "Statement": [ + { + "Sid": "__default_statement_ID", + "Effect": "Allow", + "Principal": { + "AWS": "*" + }, + "Action": [ + "SNS:GetTopicAttributes", + "SNS:SetTopicAttributes", + "SNS:AddPermission", + "SNS:RemovePermission", + "SNS:DeleteTopic", + "SNS:Subscribe", + "SNS:ListSubscriptionsByTopic", + "SNS:Publish" + ], + "Resource": "arn::sns::111111111111:", + "Condition": { + "StringEquals": { + "AWS:SourceOwner": "111111111111" + } + } + } + ] + }, + "SubscriptionsConfirmed": "0", + "SubscriptionsDeleted": "0", + "SubscriptionsPending": "0", + "TopicArn": "arn::sns::111111111111:" + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "put-data-protection-policy": { + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "get-data-protection-policy": { + "DataProtectionPolicy": { + "Name": "data_protection_policy", + "Description": "Test Policy", + "Version": "2021-06-01", + "Statement": [ + { + "Sid": "test-statement", + "DataDirection": "Inbound", + "Principal": [ + "*" + ], + "DataIdentifier": [ + "arn::dataprotection:::data-identifier/EmailAddress" + ], + "Operation": { + "Deny": {} + } + } + ] + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "get-topic-attributes-after-policy": { + "Attributes": { + "DisplayName": "", + "EffectiveDeliveryPolicy": { + "http": { + "defaultHealthyRetryPolicy": { + "minDelayTarget": 20, + "maxDelayTarget": 20, + "numRetries": 3, + "numMaxDelayRetries": 0, + "numNoDelayRetries": 0, + "numMinDelayRetries": 0, + "backoffFunction": "linear" + }, + "disableSubscriptionOverrides": false, + "defaultRequestPolicy": { + "headerContentType": "text/plain; charset=UTF-8" + } + } + }, + "Owner": "111111111111", + "Policy": { + "Version": "2008-10-17", + "Id": "__default_policy_ID", + "Statement": [ + { + "Sid": "__default_statement_ID", + "Effect": "Allow", + "Principal": { + "AWS": "*" + }, + "Action": [ + "SNS:GetTopicAttributes", + "SNS:SetTopicAttributes", + "SNS:AddPermission", + "SNS:RemovePermission", + "SNS:DeleteTopic", + "SNS:Subscribe", + "SNS:ListSubscriptionsByTopic", + "SNS:Publish" + ], + "Resource": "arn::sns::111111111111:", + "Condition": { + "StringEquals": { + "AWS:SourceOwner": "111111111111" + } + } + } + ] + }, + "SubscriptionsConfirmed": "0", + "SubscriptionsDeleted": "0", + "SubscriptionsPending": "0", + "TopicArn": "arn::sns::111111111111:" + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/sns/test_sns.py::TestSNSPublishCrud::test_publish_batch_invalid_entry_id": { + "recorded-date": "23-12-2025, 17:39:15", + "recorded-content": { + "invalid-char-dot": { + "Error": { + "Code": "InvalidBatchEntryId", + "Message": "The Id of a batch entry in the batch request contains an impermissible character: message.id", + "Type": "Sender" + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + }, + "invalid-char-special": { + "Error": { + "Code": "InvalidBatchEntryId", + "Message": "The Id of a batch entry in the batch request contains an impermissible character: msg@123#test", + "Type": "Sender" + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + }, + "id-too-long-81": { + "Error": { + "Code": "InvalidBatchEntryId", + "Message": "The Id of a batch entry in the batch request is too long: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + "Type": "Sender" + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + }, + "id-too-long-91": { + "Error": { + "Code": "InvalidBatchEntryId", + "Message": "The Id of a batch entry in the batch request is too long: myreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallylongid", + "Type": "Sender" + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + }, + "valid-id-80-chars": { + "Failed": [], + "Successful": [ + { + "Id": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + "MessageId": "" + } + ], + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "valid-id-with-hyphen-underscore": { + "Failed": [], + "Successful": [ + { + "Id": "valid-message_123", + "MessageId": "" + } + ], + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/sns/test_sns.py::TestSNSSMS::test_opt_in_invalid_number": { + "recorded-date": "13-01-2026, 09:38:15", + "recorded-content": { + "opt-in-non-existing-number": { + "Error": { + "Code": "InvalidParameter", + "Message": "Invalid parameter: PhoneNumber Reason: input incorrectly formatted", + "Type": "Sender" + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + } + } + }, + "tests/aws/services/sns/test_sns.py::TestSNSTopicCrudV2::test_create_topic_different_attrs": { + "recorded-date": "06-02-2026, 19:09:15", + "recorded-content": { + "create-topic": { + "TopicArn": "arn::sns::111111111111:", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "create-topic-no-attrs": { + "TopicArn": "arn::sns::111111111111:", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "topic-attrs": { + "Attributes": { + "DisplayName": "Value1", + "EffectiveDeliveryPolicy": { + "http": { + "defaultHealthyRetryPolicy": { + "minDelayTarget": 20, + "maxDelayTarget": 20, + "numRetries": 3, + "numMaxDelayRetries": 0, + "numNoDelayRetries": 0, + "numMinDelayRetries": 0, + "backoffFunction": "linear" + }, + "disableSubscriptionOverrides": false, + "defaultRequestPolicy": { + "headerContentType": "text/plain; charset=UTF-8" + } + } + }, + "Owner": "111111111111", + "Policy": { + "Version": "2008-10-17", + "Id": "__default_policy_ID", + "Statement": [ + { + "Sid": "__default_statement_ID", + "Effect": "Allow", + "Principal": { + "AWS": "*" + }, + "Action": [ + "SNS:GetTopicAttributes", + "SNS:SetTopicAttributes", + "SNS:AddPermission", + "SNS:RemovePermission", + "SNS:DeleteTopic", + "SNS:Subscribe", + "SNS:ListSubscriptionsByTopic", + "SNS:Publish" + ], + "Resource": "arn::sns::111111111111:", + "Condition": { + "StringEquals": { + "AWS:SourceOwner": "111111111111" + } + } + } + ] + }, + "SubscriptionsConfirmed": "0", + "SubscriptionsDeleted": "0", + "SubscriptionsPending": "0", + "TopicArn": "arn::sns::111111111111:" + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "create-topic-diff-attrs": { + "Error": { + "Code": "InvalidParameter", + "Message": "Invalid parameter: Attributes Reason: Topic already exists with different attributes", + "Type": "Sender" + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + }, + "create-topic-new-attrs-fifo": { + "Error": { + "Code": "InvalidParameter", + "Message": "Invalid parameter: Topic Name", + "Type": "Sender" + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + }, + "create-topic-new-attrs": { + "Error": { + "Code": "InvalidParameter", + "Message": "Invalid parameter: Attributes Reason: Topic already exists with different attributes", + "Type": "Sender" + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + }, + "create-topic-new-and-same-attrs": { + "Error": { + "Code": "InvalidParameter", + "Message": "Invalid parameter: Attributes Reason: Topic already exists with different attributes", + "Type": "Sender" + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + } + } + }, + "tests/aws/services/sns/test_sns.py::TestSNSTopicCrud::test_tags_removed_after_deletion": { + "recorded-date": "16-02-2026, 05:26:44", + "recorded-content": { + "list-created-tags": { + "Tags": [ + { + "Key": "k1", + "Value": "v1" + }, + { + "Key": "k2", + "Value": "v2" + } + ], + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "list-empty-tags": { + "Tags": [], + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } } } diff --git a/tests/aws/services/sns/test_sns.validation.json b/tests/aws/services/sns/test_sns.validation.json index 757998bdd060f..04b9e6c2cf56e 100644 --- a/tests/aws/services/sns/test_sns.validation.json +++ b/tests/aws/services/sns/test_sns.validation.json @@ -5,29 +5,626 @@ "tests/aws/services/sns/test_sns.py::TestSNSMultiRegions::test_cross_region_delivery_sqs": { "last_validated_date": "2025-05-28T09:55:16+00:00" }, + "tests/aws/services/sns/test_sns.py::TestSNSPlatformApplicationCrud::test_create_platform_application": { + "last_validated_date": "2025-10-29T09:20:54+00:00", + "durations_in_seconds": { + "setup": 0.93, + "call": 1.05, + "teardown": 0.46, + "total": 2.44 + } + }, + "tests/aws/services/sns/test_sns.py::TestSNSPlatformApplicationCrud::test_create_platform_application_invalid_attributes[invalid-cred-first0]": { + "last_validated_date": "2025-10-27T11:10:12+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.18, + "teardown": 0.01, + "total": 0.19 + } + }, + "tests/aws/services/sns/test_sns.py::TestSNSPlatformApplicationCrud::test_create_platform_application_invalid_attributes[invalid-cred-first1]": { + "last_validated_date": "2025-10-27T11:10:12+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.17, + "teardown": 0.0, + "total": 0.17 + } + }, + "tests/aws/services/sns/test_sns.py::TestSNSPlatformApplicationCrud::test_create_platform_application_invalid_attributes[missing-credential]": { + "last_validated_date": "2025-10-29T09:20:56+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.3, + "teardown": 0.0, + "total": 0.3 + } + }, + "tests/aws/services/sns/test_sns.py::TestSNSPlatformApplicationCrud::test_create_platform_application_invalid_attributes[missing-principal]": { + "last_validated_date": "2025-10-29T09:20:56+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.14, + "teardown": 0.0, + "total": 0.14 + } + }, + "tests/aws/services/sns/test_sns.py::TestSNSPlatformApplicationCrud::test_create_platform_application_invalid_attributes[no-args]": { + "last_validated_date": "2025-10-29T09:20:55+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.34, + "teardown": 0.0, + "total": 0.34 + } + }, + "tests/aws/services/sns/test_sns.py::TestSNSPlatformApplicationCrud::test_create_platform_application_invalid_name[empty]": { + "last_validated_date": "2025-10-29T09:20:56+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.13, + "teardown": 0.0, + "total": 0.13 + } + }, + "tests/aws/services/sns/test_sns.py::TestSNSPlatformApplicationCrud::test_create_platform_application_invalid_name[invalid-char]": { + "last_validated_date": "2025-10-29T09:20:56+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.21, + "teardown": 0.0, + "total": 0.21 + } + }, + "tests/aws/services/sns/test_sns.py::TestSNSPlatformApplicationCrud::test_create_platform_application_invalid_name[too-long]": { + "last_validated_date": "2025-10-29T09:20:56+00:00", + "durations_in_seconds": { + "setup": 0.01, + "call": 0.25, + "teardown": 0.0, + "total": 0.26 + } + }, + "tests/aws/services/sns/test_sns.py::TestSNSPlatformApplicationCrud::test_create_platform_application_invalid_platform": { + "last_validated_date": "2025-10-29T09:20:57+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.25, + "teardown": 0.0, + "total": 0.25 + } + }, + "tests/aws/services/sns/test_sns.py::TestSNSPlatformApplicationCrud::test_create_platform_invalid_values": { + "last_validated_date": "2025-10-27T11:36:17+00:00", + "durations_in_seconds": { + "setup": 1.03, + "call": 1.57, + "teardown": 0.01, + "total": 2.61 + } + }, + "tests/aws/services/sns/test_sns.py::TestSNSPlatformApplicationCrud::test_get_missing_platform_application_attributes": { + "last_validated_date": "2025-10-27T12:48:51+00:00", + "durations_in_seconds": { + "setup": 1.05, + "call": 0.91, + "teardown": 0.0, + "total": 1.96 + } + }, + "tests/aws/services/sns/test_sns.py::TestSNSPlatformApplicationCrud::test_get_platform_application_attributes": { + "last_validated_date": "2025-10-29T09:20:58+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.62, + "teardown": 0.62, + "total": 1.24 + } + }, + "tests/aws/services/sns/test_sns.py::TestSNSPlatformApplicationCrud::test_get_platform_application_attributes_invalid_arn": { + "last_validated_date": "2025-10-29T09:20:58+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.31, + "teardown": 0.0, + "total": 0.31 + } + }, + "tests/aws/services/sns/test_sns.py::TestSNSPlatformApplicationCrud::test_get_platform_application_attributes_non_existing_app": { + "last_validated_date": "2025-10-29T09:20:58+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.3, + "teardown": 0.0, + "total": 0.3 + } + }, + "tests/aws/services/sns/test_sns.py::TestSNSPlatformApplicationCrud::test_list_platform_applications": { + "last_validated_date": "2025-10-29T09:20:55+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.46, + "teardown": 0.44, + "total": 0.9 + } + }, + "tests/aws/services/sns/test_sns.py::TestSNSPlatformApplicationCrud::test_set_platform_application_attributes": { + "last_validated_date": "2025-10-29T09:21:31+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 31.68, + "teardown": 0.37, + "total": 32.05 + } + }, + "tests/aws/services/sns/test_sns.py::TestSNSPlatformApplicationCrud::test_set_platform_application_attributes_invalid_arn": { + "last_validated_date": "2025-10-29T09:21:31+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.3, + "teardown": 0.0, + "total": 0.3 + } + }, + "tests/aws/services/sns/test_sns.py::TestSNSPlatformApplicationCrud::test_set_platform_application_attributes_non_existing_app": { + "last_validated_date": "2025-10-28T09:17:14+00:00", + "durations_in_seconds": { + "setup": 0.98, + "call": 1.27, + "teardown": 0.0, + "total": 2.25 + } + }, + "tests/aws/services/sns/test_sns.py::TestSNSPlatformApplicationCrud::test_set_platform_application_attributes_non_existing_app[dummy-args]": { + "last_validated_date": "2025-10-29T09:21:31+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.3, + "teardown": 0.0, + "total": 0.3 + } + }, + "tests/aws/services/sns/test_sns.py::TestSNSPlatformApplicationCrud::test_set_platform_application_attributes_non_existing_app[missing-credential]": { + "last_validated_date": "2025-10-28T09:23:04+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.3, + "teardown": 0.0, + "total": 0.3 + } + }, + "tests/aws/services/sns/test_sns.py::TestSNSPlatformApplicationCrud::test_set_platform_application_attributes_non_existing_app[missing-principal]": { + "last_validated_date": "2025-10-28T09:23:04+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.3, + "teardown": 0.0, + "total": 0.3 + } + }, + "tests/aws/services/sns/test_sns.py::TestSNSPlatformApplicationCrud::test_set_platform_application_attributes_non_existing_app[no-args]": { + "last_validated_date": "2025-10-29T09:21:31+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.3, + "teardown": 0.0, + "total": 0.3 + } + }, + "tests/aws/services/sns/test_sns.py::TestSNSPlatformEndpoint::test_publish_disabled_endpoint": { + "last_validated_date": "2025-11-27T08:34:37+00:00", + "durations_in_seconds": { + "setup": 1.83, + "call": 48.48, + "teardown": 1.6, + "total": 51.91 + } + }, + "tests/aws/services/sns/test_sns.py::TestSNSPlatformEndpointCrud::test_create_platform_endpoint": { + "last_validated_date": "2025-10-31T21:26:47+00:00", + "durations_in_seconds": { + "setup": 0.9, + "call": 1.63, + "teardown": 0.93, + "total": 3.46 + } + }, + "tests/aws/services/sns/test_sns.py::TestSNSPlatformEndpointCrud::test_create_platform_endpoint_custom_data": { + "last_validated_date": "2025-10-31T21:45:15+00:00", + "durations_in_seconds": { + "setup": 1.1, + "call": 1.44, + "teardown": 0.61, + "total": 3.15 + } + }, + "tests/aws/services/sns/test_sns.py::TestSNSPlatformEndpointCrud::test_create_platform_endpoint_double_custom_data": { + "last_validated_date": "2025-10-31T21:41:35+00:00", + "durations_in_seconds": { + "setup": 1.26, + "call": 1.82, + "teardown": 0.62, + "total": 3.7 + } + }, + "tests/aws/services/sns/test_sns.py::TestSNSPlatformEndpointCrud::test_create_platform_endpoint_idempotency": { + "last_validated_date": "2025-10-31T21:26:49+00:00", + "durations_in_seconds": { + "setup": 0.01, + "call": 1.19, + "teardown": 0.92, + "total": 2.12 + } + }, + "tests/aws/services/sns/test_sns.py::TestSNSPlatformEndpointCrud::test_create_platform_endpoint_non_existent_app": { + "last_validated_date": "2025-10-31T21:26:50+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.3, + "teardown": 0.01, + "total": 0.31 + } + }, + "tests/aws/services/sns/test_sns.py::TestSNSPlatformEndpointCrud::test_create_platform_endpoint_with_invalid_attributes[Data_Too_Long]": { + "last_validated_date": "2025-10-31T21:28:18+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.6, + "teardown": 0.62, + "total": 1.22 + } + }, + "tests/aws/services/sns/test_sns.py::TestSNSPlatformEndpointCrud::test_create_platform_endpoint_with_invalid_attributes[Invalid_Name_Credential]": { + "last_validated_date": "2025-10-31T21:28:16+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.61, + "teardown": 0.47, + "total": 1.08 + } + }, + "tests/aws/services/sns/test_sns.py::TestSNSPlatformEndpointCrud::test_create_platform_endpoint_with_invalid_attributes[Invalid_Name_Generic]": { + "last_validated_date": "2025-10-31T21:28:17+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.3, + "teardown": 0.57, + "total": 0.87 + } + }, + "tests/aws/services/sns/test_sns.py::TestSNSPlatformEndpointCrud::test_create_platform_endpoint_with_invalid_attributes[Invalid_Name_Principal]": { + "last_validated_date": "2025-10-31T21:28:15+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.36, + "teardown": 0.56, + "total": 0.92 + } + }, + "tests/aws/services/sns/test_sns.py::TestSNSPlatformEndpointCrud::test_delete_endpoints_of_deleted_app": { + "last_validated_date": "2025-10-31T21:28:02+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 12.49, + "teardown": 0.14, + "total": 12.63 + } + }, + "tests/aws/services/sns/test_sns.py::TestSNSPlatformEndpointCrud::test_delete_platform_endpoint": { + "last_validated_date": "2025-10-31T21:27:05+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 12.61, + "teardown": 0.6, + "total": 13.21 + } + }, + "tests/aws/services/sns/test_sns.py::TestSNSPlatformEndpointCrud::test_delete_platform_endpoint_with_subscription": { + "last_validated_date": "2025-11-04T19:18:31+00:00", + "durations_in_seconds": { + "setup": 0.01, + "call": 44.2, + "teardown": 1.07, + "total": 45.28 + } + }, + "tests/aws/services/sns/test_sns.py::TestSNSPlatformEndpointCrud::test_get_platform_endpoint_attributes": { + "last_validated_date": "2025-10-31T21:28:04+00:00", + "durations_in_seconds": { + "setup": 0.01, + "call": 0.86, + "teardown": 0.92, + "total": 1.79 + } + }, + "tests/aws/services/sns/test_sns.py::TestSNSPlatformEndpointCrud::test_get_platform_endpoint_attributes_non_existent_endpoint": { + "last_validated_date": "2025-10-31T21:28:06+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.14, + "teardown": 0.0, + "total": 0.14 + } + }, + "tests/aws/services/sns/test_sns.py::TestSNSPlatformEndpointCrud::test_list_platform_endpoint": { + "last_validated_date": "2025-10-31T18:07:43+00:00", + "durations_in_seconds": { + "setup": 1.01, + "call": 1.9, + "teardown": 0.89, + "total": 3.8 + } + }, + "tests/aws/services/sns/test_sns.py::TestSNSPlatformEndpointCrud::test_list_platform_endpoints": { + "last_validated_date": "2025-10-31T21:26:51+00:00", + "durations_in_seconds": { + "setup": 0.01, + "call": 0.89, + "teardown": 0.92, + "total": 1.82 + } + }, + "tests/aws/services/sns/test_sns.py::TestSNSPlatformEndpointCrud::test_set_platform_endpoint_attributes": { + "last_validated_date": "2025-10-31T21:28:06+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 1.02, + "teardown": 0.92, + "total": 1.94 + } + }, + "tests/aws/services/sns/test_sns.py::TestSNSPlatformEndpointCrud::test_set_platform_endpoint_attributes_invalid_arn": { + "last_validated_date": "2025-10-31T20:20:11+00:00", + "durations_in_seconds": { + "setup": 1.05, + "call": 0.9, + "teardown": 0.01, + "total": 1.96 + } + }, + "tests/aws/services/sns/test_sns.py::TestSNSPlatformEndpointCrud::test_set_platform_endpoint_attributes_invalid_attributes[Data_Too_Long]": { + "last_validated_date": "2025-10-31T21:31:10+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.91, + "teardown": 1.33, + "total": 2.24 + } + }, + "tests/aws/services/sns/test_sns.py::TestSNSPlatformEndpointCrud::test_set_platform_endpoint_attributes_invalid_attributes[Empty]": { + "last_validated_date": "2025-10-31T21:31:03+00:00", + "durations_in_seconds": { + "setup": 1.41, + "call": 1.81, + "teardown": 0.92, + "total": 4.14 + } + }, + "tests/aws/services/sns/test_sns.py::TestSNSPlatformEndpointCrud::test_set_platform_endpoint_attributes_invalid_attributes[Invalid_Name_Credential]": { + "last_validated_date": "2025-10-31T21:31:06+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.86, + "teardown": 0.6, + "total": 1.46 + } + }, + "tests/aws/services/sns/test_sns.py::TestSNSPlatformEndpointCrud::test_set_platform_endpoint_attributes_invalid_attributes[Invalid_Name_Generic]": { + "last_validated_date": "2025-10-31T21:31:07+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.62, + "teardown": 0.93, + "total": 1.55 + } + }, + "tests/aws/services/sns/test_sns.py::TestSNSPlatformEndpointCrud::test_set_platform_endpoint_attributes_invalid_attributes[Invalid_Name_Principal]": { + "last_validated_date": "2025-10-31T21:31:04+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.92, + "teardown": 0.78, + "total": 1.7 + } + }, + "tests/aws/services/sns/test_sns.py::TestSNSPlatformEndpointCrud::test_set_platform_endpoint_attributes_invalid_attributes[attributes0]": { + "last_validated_date": "2025-10-31T20:48:00+00:00", + "durations_in_seconds": { + "setup": 1.11, + "call": 1.64, + "teardown": 0.9, + "total": 3.65 + } + }, + "tests/aws/services/sns/test_sns.py::TestSNSPlatformEndpointCrud::test_set_platform_endpoint_attributes_invalid_attributes[attributes1]": { + "last_validated_date": "2025-10-31T20:48:01+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.9, + "teardown": 0.79, + "total": 1.69 + } + }, + "tests/aws/services/sns/test_sns.py::TestSNSPlatformEndpointCrud::test_set_platform_endpoint_attributes_invalid_attributes[attributes2]": { + "last_validated_date": "2025-10-31T20:48:03+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.74, + "teardown": 0.84, + "total": 1.58 + } + }, + "tests/aws/services/sns/test_sns.py::TestSNSPlatformEndpointCrud::test_set_platform_endpoint_attributes_invalid_attributes[attributes3]": { + "last_validated_date": "2025-10-31T20:48:04+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.9, + "teardown": 0.63, + "total": 1.53 + } + }, + "tests/aws/services/sns/test_sns.py::TestSNSPlatformEndpointCrud::test_set_platform_endpoint_attributes_invalid_attributes[attributes4]": { + "last_validated_date": "2025-10-31T20:48:06+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.9, + "teardown": 0.7, + "total": 1.6 + } + }, + "tests/aws/services/sns/test_sns.py::TestSNSPlatformEndpointCrud::test_set_platform_endpoint_attributes_non_existent_app": { + "last_validated_date": "2025-10-31T20:29:24+00:00", + "durations_in_seconds": { + "setup": 0.8, + "call": 0.93, + "teardown": 0.01, + "total": 1.74 + } + }, + "tests/aws/services/sns/test_sns.py::TestSNSPlatformEndpointCrud::test_set_platform_endpoint_attributes_non_existent_endpoint": { + "last_validated_date": "2025-10-31T21:28:06+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.26, + "teardown": 0.0, + "total": 0.26 + } + }, + "tests/aws/services/sns/test_sns.py::TestSNSPlatformEndpointCrud::test_subscribe_platform_endpoint": { + "last_validated_date": "2025-10-31T17:43:57+00:00", + "durations_in_seconds": { + "setup": 0.82, + "call": 1.43, + "teardown": 0.92, + "total": 3.17 + } + }, + "tests/aws/services/sns/test_sns.py::TestSNSPlatformEndpointCrud::test_subscribe_platform_endpoint_idempotency": { + "last_validated_date": "2025-10-31T16:53:41+00:00", + "durations_in_seconds": { + "setup": 1.05, + "call": 2.22, + "teardown": 0.92, + "total": 4.19 + } + }, + "tests/aws/services/sns/test_sns.py::TestSNSPlatformEndpointCrud::test_subscribe_platform_endpoint_non_existent_app": { + "last_validated_date": "2025-10-31T17:44:08+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 1.24, + "teardown": 0.0, + "total": 1.24 + } + }, + "tests/aws/services/sns/test_sns.py::TestSNSPlatformEndpointCrud::test_subscribe_platform_endpoint_wrong_application_arn[invalid_appname_arn]": { + "last_validated_date": "2025-10-31T17:29:23+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.29, + "teardown": 0.0, + "total": 0.29 + } + }, + "tests/aws/services/sns/test_sns.py::TestSNSPlatformEndpointCrud::test_subscribe_platform_endpoint_wrong_application_arn[invalid_format_arn]": { + "last_validated_date": "2025-10-31T17:29:22+00:00", + "durations_in_seconds": { + "setup": 1.14, + "call": 0.73, + "teardown": 0.01, + "total": 1.88 + } + }, "tests/aws/services/sns/test_sns.py::TestSNSPublishCrud::test_empty_sns_message": { - "last_validated_date": "2023-08-24T20:31:48+00:00" + "last_validated_date": "2025-11-19T12:41:02+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 1.65, + "teardown": 0.59, + "total": 2.24 + } }, "tests/aws/services/sns/test_sns.py::TestSNSPublishCrud::test_message_structure_json_exc": { - "last_validated_date": "2023-08-24T20:31:50+00:00" + "last_validated_date": "2025-11-19T12:41:06+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.91, + "teardown": 0.22, + "total": 1.13 + } + }, + "tests/aws/services/sns/test_sns.py::TestSNSPublishCrud::test_publish_batch_invalid_entry_id": { + "last_validated_date": "2025-12-23T17:39:15+00:00", + "durations_in_seconds": { + "setup": 5.45, + "call": 1.98, + "teardown": 0.16, + "total": 7.59 + } }, "tests/aws/services/sns/test_sns.py::TestSNSPublishCrud::test_publish_batch_too_long_message": { - "last_validated_date": "2024-09-04T00:48:01+00:00" + "last_validated_date": "2025-11-19T12:41:05+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.81, + "teardown": 0.21, + "total": 1.02 + } }, "tests/aws/services/sns/test_sns.py::TestSNSPublishCrud::test_publish_by_path_parameters": { - "last_validated_date": "2023-08-24T20:31:40+00:00" + "last_validated_date": "2025-11-19T12:39:58+00:00", + "durations_in_seconds": { + "setup": 0.85, + "call": 3.38, + "teardown": 0.61, + "total": 4.84 + } }, "tests/aws/services/sns/test_sns.py::TestSNSPublishCrud::test_publish_message_before_subscribe_topic": { - "last_validated_date": "2023-08-24T20:31:44+00:00" + "last_validated_date": "2025-11-19T12:40:47+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 1.9, + "teardown": 0.61, + "total": 2.51 + } }, "tests/aws/services/sns/test_sns.py::TestSNSPublishCrud::test_publish_message_by_target_arn": { - "last_validated_date": "2023-08-24T20:31:42+00:00" + "last_validated_date": "2025-11-19T12:40:44+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 2.04, + "teardown": 0.65, + "total": 2.69 + } + }, + "tests/aws/services/sns/test_sns.py::TestSNSPublishCrud::test_publish_no_confirm_subscription": { + "last_validated_date": "2026-01-30T08:41:34+00:00", + "durations_in_seconds": { + "setup": 1.18, + "call": 1.63, + "teardown": 0.61, + "total": 3.42 + } }, "tests/aws/services/sns/test_sns.py::TestSNSPublishCrud::test_publish_non_existent_target": { - "last_validated_date": "2023-08-24T20:31:46+00:00" + "last_validated_date": "2025-11-19T12:40:59+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.37, + "teardown": 0.21, + "total": 0.58 + } }, "tests/aws/services/sns/test_sns.py::TestSNSPublishCrud::test_publish_too_long_message": { - "last_validated_date": "2024-09-04T00:38:06+00:00" + "last_validated_date": "2025-11-19T12:41:04+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 1.29, + "teardown": 0.22, + "total": 1.51 + } }, "tests/aws/services/sns/test_sns.py::TestSNSPublishCrud::test_publish_verify_signature": { "last_validated_date": "2024-01-04T17:22:57+00:00" @@ -39,67 +636,478 @@ "last_validated_date": "2024-01-04T17:39:19+00:00" }, "tests/aws/services/sns/test_sns.py::TestSNSPublishCrud::test_publish_with_empty_subject": { - "last_validated_date": "2023-08-24T20:31:46+00:00" + "last_validated_date": "2025-11-19T12:41:00+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.61, + "teardown": 0.23, + "total": 0.84 + } }, "tests/aws/services/sns/test_sns.py::TestSNSPublishCrud::test_publish_wrong_arn_format": { - "last_validated_date": "2024-03-11T10:36:34+00:00" + "last_validated_date": "2025-11-19T12:40:42+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.5, + "teardown": 0.0, + "total": 0.5 + } }, "tests/aws/services/sns/test_sns.py::TestSNSPublishCrud::test_topic_publish_another_region": { - "last_validated_date": "2023-11-17T17:14:28+00:00" + "last_validated_date": "2025-11-19T12:40:58+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 9.79, + "teardown": 0.85, + "total": 10.64 + } }, "tests/aws/services/sns/test_sns.py::TestSNSPublishCrud::test_unknown_topic_publish": { - "last_validated_date": "2023-08-24T20:31:45+00:00" + "last_validated_date": "2025-11-19T12:40:48+00:00", + "durations_in_seconds": { + "setup": 0.01, + "call": 0.61, + "teardown": 0.23, + "total": 0.85 + } }, "tests/aws/services/sns/test_sns.py::TestSNSPublishDelivery::test_delivery_lambda": { "last_validated_date": "2023-11-07T10:11:37+00:00" }, + "tests/aws/services/sns/test_sns.py::TestSNSSMS::test_get_sms_attributes_from_unmodified_region": { + "last_validated_date": "2025-12-02T12:58:44+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 2.64, + "teardown": 0.0, + "total": 2.64 + } + }, + "tests/aws/services/sns/test_sns.py::TestSNSSMS::test_is_phone_number_opted_out": { + "last_validated_date": "2025-12-01T19:33:36+00:00", + "durations_in_seconds": { + "setup": 0.74, + "call": 0.63, + "teardown": 0.0, + "total": 1.37 + } + }, + "tests/aws/services/sns/test_sns.py::TestSNSSMS::test_list_phone_numbers_opted_out": { + "last_validated_date": "2025-12-02T12:58:54+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.16, + "teardown": 0.0, + "total": 0.16 + } + }, + "tests/aws/services/sns/test_sns.py::TestSNSSMS::test_opt_in_invalid_number": { + "last_validated_date": "2026-01-13T09:38:15+00:00", + "durations_in_seconds": { + "setup": 1.02, + "call": 0.79, + "teardown": 0.03, + "total": 1.84 + } + }, + "tests/aws/services/sns/test_sns.py::TestSNSSMS::test_opt_in_non_existing_phone_number": { + "last_validated_date": "2025-12-02T12:58:54+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.14, + "teardown": 0.0, + "total": 0.14 + } + }, + "tests/aws/services/sns/test_sns.py::TestSNSSMS::test_opt_in_phone_number": { + "last_validated_date": "2025-12-01T19:44:54+00:00", + "durations_in_seconds": { + "setup": 0.94, + "call": 1.02, + "teardown": 0.0, + "total": 1.96 + } + }, "tests/aws/services/sns/test_sns.py::TestSNSSMS::test_publish_wrong_phone_format": { - "last_validated_date": "2023-08-24T22:20:12+00:00" + "last_validated_date": "2025-12-02T12:58:42+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.87, + "teardown": 0.25, + "total": 1.12 + } + }, + "tests/aws/services/sns/test_sns.py::TestSNSSMS::test_set_get_sms_attributes": { + "last_validated_date": "2025-10-13T10:30:42+00:00", + "durations_in_seconds": { + "setup": 0.69, + "call": 1.27, + "teardown": 0.01, + "total": 1.97 + } + }, + "tests/aws/services/sns/test_sns.py::TestSNSSMS::test_set_invalid_sms_attributes[InvalidAttributeName]": { + "last_validated_date": "2025-12-02T12:58:45+00:00", + "durations_in_seconds": { + "setup": 0.01, + "call": 0.3, + "teardown": 0.0, + "total": 0.31 + } + }, + "tests/aws/services/sns/test_sns.py::TestSNSSMS::test_set_invalid_sms_attributes[InvalidSMSType]": { + "last_validated_date": "2025-12-02T12:58:53+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 2.16, + "teardown": 0.0, + "total": 2.16 + } + }, + "tests/aws/services/sns/test_sns.py::TestSNSSMS::test_set_invalid_sms_attributes[NoLetterID]": { + "last_validated_date": "2025-12-02T12:58:51+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 3.38, + "teardown": 0.0, + "total": 3.38 + } + }, + "tests/aws/services/sns/test_sns.py::TestSNSSMS::test_set_invalid_sms_attributes[TooLongID]": { + "last_validated_date": "2025-12-02T12:58:48+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 3.04, + "teardown": 0.0, + "total": 3.04 + } + }, + "tests/aws/services/sns/test_sns.py::TestSNSSMS::test_set_invalid_sms_attributes[attribute_key_value0]": { + "last_validated_date": "2025-10-13T10:41:10+00:00", + "durations_in_seconds": { + "setup": 0.84, + "call": 1.05, + "teardown": 0.06, + "total": 1.95 + } + }, + "tests/aws/services/sns/test_sns.py::TestSNSSMS::test_set_invalid_sms_attributes[attribute_key_value1]": { + "last_validated_date": "2025-10-13T10:41:12+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 2.69, + "teardown": 0.01, + "total": 2.7 + } + }, + "tests/aws/services/sns/test_sns.py::TestSNSSMS::test_set_invalid_sms_attributes[attribute_key_value2]": { + "last_validated_date": "2025-10-13T10:41:15+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 2.86, + "teardown": 0.01, + "total": 2.87 + } + }, + "tests/aws/services/sns/test_sns.py::TestSNSSMS::test_set_invalid_sms_attributes[attribute_key_value3]": { + "last_validated_date": "2025-10-13T10:41:18+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 2.55, + "teardown": 0.01, + "total": 2.56 + } }, "tests/aws/services/sns/test_sns.py::TestSNSSMS::test_subscribe_sms_endpoint": { - "last_validated_date": "2024-05-14T19:34:11+00:00" + "last_validated_date": "2025-12-02T12:58:41+00:00", + "durations_in_seconds": { + "setup": 0.81, + "call": 2.06, + "teardown": 0.61, + "total": 3.48 + } }, "tests/aws/services/sns/test_sns.py::TestSNSSubscriptionCrud::test_create_subscriptions_with_attributes": { - "last_validated_date": "2024-03-29T19:44:42+00:00" + "last_validated_date": "2025-10-06T10:25:19+00:00", + "durations_in_seconds": { + "setup": 0.01, + "call": 2.64, + "teardown": 0.82, + "total": 3.47 + } }, "tests/aws/services/sns/test_sns.py::TestSNSSubscriptionCrud::test_list_subscriptions": { "last_validated_date": "2023-08-25T14:23:53+00:00" }, "tests/aws/services/sns/test_sns.py::TestSNSSubscriptionCrud::test_list_subscriptions_by_topic_pagination": { - "last_validated_date": "2024-05-16T10:31:56+00:00" + "last_validated_date": "2025-10-06T10:26:42+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 33.24, + "teardown": 31.21, + "total": 64.45 + } }, "tests/aws/services/sns/test_sns.py::TestSNSSubscriptionCrud::test_not_found_error_on_set_subscription_attributes": { - "last_validated_date": "2023-08-24T21:27:55+00:00" + "last_validated_date": "2025-10-06T10:25:23+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 2.99, + "teardown": 0.8, + "total": 3.79 + } }, "tests/aws/services/sns/test_sns.py::TestSNSSubscriptionCrud::test_sns_confirm_subscription_wrong_token": { - "last_validated_date": "2023-08-24T21:27:58+00:00" + "last_validated_date": "2025-10-06T10:25:28+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 1.19, + "teardown": 0.32, + "total": 1.51 + } }, "tests/aws/services/sns/test_sns.py::TestSNSSubscriptionCrud::test_subscribe_idempotency": { - "last_validated_date": "2025-03-20T17:16:39+00:00" + "last_validated_date": "2025-10-06T10:26:46+00:00", + "durations_in_seconds": { + "setup": 0.01, + "call": 3.54, + "teardown": 0.41, + "total": 3.96 + } }, "tests/aws/services/sns/test_sns.py::TestSNSSubscriptionCrud::test_subscribe_with_invalid_protocol": { - "last_validated_date": "2023-08-24T21:27:50+00:00" + "last_validated_date": "2025-10-06T10:25:11+00:00", + "durations_in_seconds": { + "setup": 1.15, + "call": 1.16, + "teardown": 0.38, + "total": 2.69 + } }, "tests/aws/services/sns/test_sns.py::TestSNSSubscriptionCrud::test_subscribe_with_invalid_topic": { - "last_validated_date": "2025-01-23T22:38:16+00:00" + "last_validated_date": "2025-10-06T10:26:53+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 1.06, + "teardown": 0.32, + "total": 1.38 + } }, "tests/aws/services/sns/test_sns.py::TestSNSSubscriptionCrud::test_unsubscribe_from_non_existing_subscription": { - "last_validated_date": "2023-08-24T21:27:52+00:00" + "last_validated_date": "2025-10-06T10:25:16+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 3.15, + "teardown": 0.94, + "total": 4.09 + } }, "tests/aws/services/sns/test_sns.py::TestSNSSubscriptionCrud::test_unsubscribe_idempotency": { - "last_validated_date": "2023-11-06T23:36:06+00:00" + "last_validated_date": "2025-10-06T10:26:49+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 2.03, + "teardown": 0.93, + "total": 2.96 + } }, "tests/aws/services/sns/test_sns.py::TestSNSSubscriptionCrud::test_unsubscribe_wrong_arn_format": { - "last_validated_date": "2025-09-02T20:17:36+00:00", + "last_validated_date": "2025-10-06T10:26:51+00:00", "durations_in_seconds": { - "setup": 0.45, - "call": 0.73, - "teardown": 0.0, - "total": 1.18 + "setup": 0.0, + "call": 1.77, + "teardown": 0.02, + "total": 1.79 } }, "tests/aws/services/sns/test_sns.py::TestSNSSubscriptionCrud::test_validate_set_sub_attributes": { - "last_validated_date": "2024-03-29T19:30:23+00:00" + "last_validated_date": "2025-10-06T10:25:27+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 2.92, + "teardown": 0.88, + "total": 3.8 + } + }, + "tests/aws/services/sns/test_sns.py::TestSNSSubscriptionCrudV2::test_confirm_subscription": { + "last_validated_date": "2026-01-14T09:45:12+00:00", + "durations_in_seconds": { + "setup": 49.43, + "call": 9.88, + "teardown": 1.51, + "total": 60.82 + } + }, + "tests/aws/services/sns/test_sns.py::TestSNSSubscriptionCrudV2::test_creating_subscription": { + "last_validated_date": "2025-10-07T07:40:45+00:00", + "durations_in_seconds": { + "setup": 1.23, + "call": 1.41, + "teardown": 0.23, + "total": 2.87 + } + }, + "tests/aws/services/sns/test_sns.py::TestSNSSubscriptionCrudV2::test_creating_subscription_with_attributes": { + "last_validated_date": "2026-01-12T13:08:24+00:00", + "durations_in_seconds": { + "setup": 1.2, + "call": 2.79, + "teardown": 0.72, + "total": 4.71 + } + }, + "tests/aws/services/sns/test_sns.py::TestSNSSubscriptionCrudV2::test_delete_subscriptions_on_delete_topic": { + "last_validated_date": "2026-01-12T13:09:31+00:00", + "durations_in_seconds": { + "setup": 0.8, + "call": 3.09, + "teardown": 0.8, + "total": 4.69 + } + }, + "tests/aws/services/sns/test_sns.py::TestSNSSubscriptionCrudV2::test_double_subscription": { + "last_validated_date": "2025-10-06T11:39:56+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 1.1, + "teardown": 0.4, + "total": 1.5 + } + }, + "tests/aws/services/sns/test_sns.py::TestSNSSubscriptionCrudV2::test_get_subscription_attributes_error_not_exists": { + "last_validated_date": "2026-01-14T10:27:15+00:00", + "durations_in_seconds": { + "setup": 1.65, + "call": 25.2, + "teardown": 0.0, + "total": 26.85 + } + }, + "tests/aws/services/sns/test_sns.py::TestSNSSubscriptionCrudV2::test_getting_subscriptions_by_topic": { + "last_validated_date": "2025-10-07T08:29:43+00:00", + "durations_in_seconds": { + "setup": 1.07, + "call": 3.6, + "teardown": 0.53, + "total": 5.2 + } + }, + "tests/aws/services/sns/test_sns.py::TestSNSSubscriptionCrudV2::test_list_opted_out": { + "last_validated_date": "2025-10-06T11:40:50+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.27, + "teardown": 0.02, + "total": 0.29 + } + }, + "tests/aws/services/sns/test_sns.py::TestSNSSubscriptionCrudV2::test_set_subscription_attributes": { + "last_validated_date": "2026-01-13T09:21:16+00:00", + "durations_in_seconds": { + "setup": 1.07, + "call": 2.51, + "teardown": 0.63, + "total": 4.21 + } + }, + "tests/aws/services/sns/test_sns.py::TestSNSSubscriptionCrudV2::test_subscribe_attributes": { + "last_validated_date": "2026-01-12T13:03:28+00:00", + "durations_in_seconds": { + "setup": 1.02, + "call": 2.72, + "teardown": 0.85, + "total": 4.59 + } + }, + "tests/aws/services/sns/test_sns.py::TestSNSSubscriptionCrudV2::test_subscribe_bad_sms": { + "last_validated_date": "2025-10-06T11:39:57+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.61, + "teardown": 0.32, + "total": 0.93 + } + }, + "tests/aws/services/sns/test_sns.py::TestSNSSubscriptionCrudV2::test_subscribe_invalid_filter_policy": { + "last_validated_date": "2026-01-13T09:26:43+00:00", + "durations_in_seconds": { + "setup": 0.96, + "call": 1.06, + "teardown": 0.27, + "total": 2.29 + } + }, + "tests/aws/services/sns/test_sns.py::TestSNSSubscriptionCrudV2::test_subscribe_invalid_sms": { + "last_validated_date": "2025-10-06T12:09:25+00:00", + "durations_in_seconds": { + "setup": 1.35, + "call": 2.17, + "teardown": 0.39, + "total": 3.91 + } + }, + "tests/aws/services/sns/test_sns.py::TestSNSSubscriptionCrudV2::test_subscribe_sms": { + "last_validated_date": "2025-10-06T11:39:50+00:00", + "durations_in_seconds": { + "setup": 1.17, + "call": 1.41, + "teardown": 0.3, + "total": 2.88 + } + }, + "tests/aws/services/sns/test_sns.py::TestSNSSubscriptionCrudV2::test_subscribe_sms_obscure_phone_number": { + "last_validated_date": "2025-10-06T11:39:51+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.6, + "teardown": 0.22, + "total": 0.82 + } + }, + "tests/aws/services/sns/test_sns.py::TestSNSSubscriptionCrudV2::test_subscribe_sqs_queue_url": { + "last_validated_date": "2025-10-06T11:56:36+00:00", + "durations_in_seconds": { + "setup": 0.99, + "call": 2.53, + "teardown": 0.44, + "total": 3.96 + } + }, + "tests/aws/services/sns/test_sns.py::TestSNSSubscriptionCrudV2::test_subscribe_unknown_sqs_queue": { + "last_validated_date": "2025-10-06T12:03:29+00:00", + "durations_in_seconds": { + "setup": 1.09, + "call": 1.85, + "teardown": 0.45, + "total": 3.39 + } + }, + "tests/aws/services/sns/test_sns.py::TestSNSSubscriptionCrudV2::test_subscribe_unknown_topic": { + "last_validated_date": "2025-10-06T11:43:45+00:00", + "durations_in_seconds": { + "setup": 0.97, + "call": 1.32, + "teardown": 0.04, + "total": 2.33 + } + }, + "tests/aws/services/sns/test_sns.py::TestSNSSubscriptionCrudV2::test_subscription_paging": { + "last_validated_date": "2025-10-07T14:33:46+00:00", + "durations_in_seconds": { + "setup": 0.78, + "call": 39.01, + "teardown": 0.2, + "total": 39.99 + } + }, + "tests/aws/services/sns/test_sns.py::TestSNSSubscriptionCrudV2::test_unsubscribe_from_deleted_topic": { + "last_validated_date": "2025-10-07T07:46:56+00:00", + "durations_in_seconds": { + "setup": 0.96, + "call": 2.59, + "teardown": 0.23, + "total": 3.78 + } }, "tests/aws/services/sns/test_sns.py::TestSNSSubscriptionHttp::test_http_subscription_response": { "last_validated_date": "2024-05-13T21:28:15+00:00" @@ -120,13 +1128,31 @@ "last_validated_date": "2025-01-24T18:51:32+00:00" }, "tests/aws/services/sns/test_sns.py::TestSNSSubscriptionLambda::test_publish_lambda_verify_signature[1]": { - "last_validated_date": "2024-01-04T18:31:41+00:00" + "last_validated_date": "2025-11-25T08:38:27+00:00", + "durations_in_seconds": { + "setup": 13.07, + "call": 16.84, + "teardown": 2.04, + "total": 31.95 + } }, "tests/aws/services/sns/test_sns.py::TestSNSSubscriptionLambda::test_publish_lambda_verify_signature[2]": { - "last_validated_date": "2024-01-04T18:33:46+00:00" + "last_validated_date": "2025-11-25T08:38:46+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 15.87, + "teardown": 2.97, + "total": 18.84 + } }, "tests/aws/services/sns/test_sns.py::TestSNSSubscriptionLambda::test_python_lambda_subscribe_sns_topic": { - "last_validated_date": "2023-08-24T21:28:59+00:00" + "last_validated_date": "2025-10-06T11:08:49+00:00", + "durations_in_seconds": { + "setup": 13.12, + "call": 15.88, + "teardown": 3.04, + "total": 32.04 + } }, "tests/aws/services/sns/test_sns.py::TestSNSSubscriptionLambda::test_redrive_policy_lambda_subscription": { "last_validated_date": "2023-08-24T21:33:01+00:00" @@ -234,16 +1260,40 @@ "last_validated_date": "2025-02-19T01:29:14+00:00" }, "tests/aws/services/sns/test_sns.py::TestSNSSubscriptionSQSFifo::test_publish_batch_messages_from_fifo_topic_to_fifo_queue[False]": { - "last_validated_date": "2023-11-09T20:10:33+00:00" + "last_validated_date": "2025-12-17T14:14:22+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 7.37, + "teardown": 0.92, + "total": 8.29 + } }, "tests/aws/services/sns/test_sns.py::TestSNSSubscriptionSQSFifo::test_publish_batch_messages_from_fifo_topic_to_fifo_queue[True]": { - "last_validated_date": "2023-11-09T20:10:27+00:00" + "last_validated_date": "2025-12-17T14:14:14+00:00", + "durations_in_seconds": { + "setup": 0.93, + "call": 8.94, + "teardown": 0.91, + "total": 10.78 + } }, "tests/aws/services/sns/test_sns.py::TestSNSSubscriptionSQSFifo::test_publish_fifo_messages_to_dlq[False]": { - "last_validated_date": "2023-08-24T21:37:59+00:00" + "last_validated_date": "2025-11-24T12:29:56+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 5.28, + "teardown": 1.03, + "total": 6.31 + } }, "tests/aws/services/sns/test_sns.py::TestSNSSubscriptionSQSFifo::test_publish_fifo_messages_to_dlq[True]": { - "last_validated_date": "2023-08-24T21:37:54+00:00" + "last_validated_date": "2025-11-24T12:29:49+00:00", + "durations_in_seconds": { + "setup": 1.07, + "call": 7.89, + "teardown": 1.13, + "total": 10.09 + } }, "tests/aws/services/sns/test_sns.py::TestSNSSubscriptionSQSFifo::test_publish_to_fifo_topic_deduplication_on_topic_level": { "last_validated_date": "2023-11-09T20:07:36+00:00" @@ -264,27 +1314,195 @@ } }, "tests/aws/services/sns/test_sns.py::TestSNSTopicCrud::test_create_duplicate_topic_check_idempotency": { - "last_validated_date": "2023-08-24T20:30:47+00:00" + "last_validated_date": "2025-10-13T07:07:09+00:00", + "durations_in_seconds": { + "setup": 1.26, + "call": 2.02, + "teardown": 1.08, + "total": 4.36 + } }, "tests/aws/services/sns/test_sns.py::TestSNSTopicCrud::test_create_duplicate_topic_with_more_tags": { - "last_validated_date": "2023-08-24T20:30:46+00:00" + "last_validated_date": "2025-10-13T06:53:55+00:00", + "durations_in_seconds": { + "setup": 1.09, + "call": 1.57, + "teardown": 0.31, + "total": 2.97 + } }, "tests/aws/services/sns/test_sns.py::TestSNSTopicCrud::test_create_topic_after_delete_with_new_tags": { - "last_validated_date": "2023-08-24T20:30:48+00:00" + "last_validated_date": "2025-10-13T07:59:08+00:00", + "durations_in_seconds": { + "setup": 0.88, + "call": 1.32, + "teardown": 0.58, + "total": 2.78 + } }, "tests/aws/services/sns/test_sns.py::TestSNSTopicCrud::test_create_topic_test_arn": { - "last_validated_date": "2023-08-24T20:30:45+00:00" + "last_validated_date": "2025-09-29T09:32:56+00:00", + "durations_in_seconds": { + "setup": 1.07, + "call": 2.33, + "teardown": 0.2, + "total": 3.6 + } }, "tests/aws/services/sns/test_sns.py::TestSNSTopicCrud::test_create_topic_with_attributes": { - "last_validated_date": "2023-10-06T18:11:02+00:00" + "last_validated_date": "2025-09-25T07:41:34+00:00", + "durations_in_seconds": { + "setup": 0.87, + "call": 2.31, + "teardown": 0.3, + "total": 3.48 + } }, "tests/aws/services/sns/test_sns.py::TestSNSTopicCrud::test_delete_topic_idempotency": { - "last_validated_date": "2025-05-28T10:08:38+00:00" + "last_validated_date": "2025-09-29T09:46:20+00:00", + "durations_in_seconds": { + "setup": 0.95, + "call": 1.72, + "teardown": 0.15, + "total": 2.82 + } }, "tests/aws/services/sns/test_sns.py::TestSNSTopicCrud::test_tags": { - "last_validated_date": "2023-08-24T20:30:44+00:00" + "last_validated_date": "2025-10-13T06:50:09+00:00", + "durations_in_seconds": { + "setup": 0.86, + "call": 2.28, + "teardown": 0.34, + "total": 3.48 + } + }, + "tests/aws/services/sns/test_sns.py::TestSNSTopicCrud::test_tags_removed_after_deletion": { + "last_validated_date": "2026-02-16T05:26:44+00:00", + "durations_in_seconds": { + "setup": 4.17, + "call": 2.64, + "teardown": 0.72, + "total": 7.53 + } }, "tests/aws/services/sns/test_sns.py::TestSNSTopicCrud::test_topic_delivery_policy_crud": { "last_validated_date": "2024-10-03T21:46:17+00:00" + }, + "tests/aws/services/sns/test_sns.py::TestSNSTopicCrudV2::test_add_permission_errors": { + "last_validated_date": "2025-12-11T13:00:18+00:00", + "durations_in_seconds": { + "setup": 1.16, + "call": 2.15, + "teardown": 0.0, + "total": 3.31 + } + }, + "tests/aws/services/sns/test_sns.py::TestSNSTopicCrudV2::test_create_topic_different_attrs": { + "last_validated_date": "2026-02-06T19:09:15+00:00", + "durations_in_seconds": { + "setup": 0.45, + "call": 1.36, + "teardown": 0.5, + "total": 2.31 + } + }, + "tests/aws/services/sns/test_sns.py::TestSNSTopicCrudV2::test_create_topic_in_multiple_regions": { + "last_validated_date": "2025-10-08T08:54:10+00:00", + "durations_in_seconds": { + "setup": 1.29, + "call": 5.7, + "teardown": 0.01, + "total": 7.0 + } + }, + "tests/aws/services/sns/test_sns.py::TestSNSTopicCrudV2::test_create_topic_name_constraints": { + "last_validated_date": "2026-02-06T19:15:23+00:00", + "durations_in_seconds": { + "setup": 0.46, + "call": 1.71, + "teardown": 0.21, + "total": 2.38 + } + }, + "tests/aws/services/sns/test_sns.py::TestSNSTopicCrudV2::test_create_topic_should_be_idempotent": { + "last_validated_date": "2025-09-29T10:40:50+00:00", + "durations_in_seconds": { + "setup": 1.14, + "call": 1.89, + "teardown": 0.47, + "total": 3.5 + } + }, + "tests/aws/services/sns/test_sns.py::TestSNSTopicCrudV2::test_data_protection_policy_crud": { + "last_validated_date": "2025-12-18T07:54:08+00:00", + "durations_in_seconds": { + "setup": 0.84, + "call": 1.82, + "teardown": 0.04, + "total": 2.7 + } + }, + "tests/aws/services/sns/test_sns.py::TestSNSTopicCrudV2::test_delete_non_existent_topic": { + "last_validated_date": "2025-09-29T10:10:56+00:00", + "durations_in_seconds": { + "setup": 1.16, + "call": 1.4, + "teardown": 0.02, + "total": 2.58 + } + }, + "tests/aws/services/sns/test_sns.py::TestSNSTopicCrudV2::test_list_topic_paging": { + "last_validated_date": "2025-09-29T11:39:42+00:00", + "durations_in_seconds": { + "setup": 1.14, + "call": 38.91, + "teardown": 37.48, + "total": 77.53 + } + }, + "tests/aws/services/sns/test_sns.py::TestSNSTopicCrudV2::test_remove_permission_errors": { + "last_validated_date": "2025-12-11T13:05:40+00:00", + "durations_in_seconds": { + "setup": 0.94, + "call": 1.36, + "teardown": 0.01, + "total": 2.31 + } + }, + "tests/aws/services/sns/test_sns.py::TestSNSTopicCrudV2::test_topic_add_multiple_permissions": { + "last_validated_date": "2025-12-11T12:53:37+00:00", + "durations_in_seconds": { + "setup": 1.03, + "call": 1.84, + "teardown": 0.3, + "total": 3.17 + } + }, + "tests/aws/services/sns/test_sns.py::TestSNSTopicCrudV2::test_topic_add_permission": { + "last_validated_date": "2025-12-11T11:43:04+00:00", + "durations_in_seconds": { + "setup": 0.91, + "call": 1.51, + "teardown": 0.3, + "total": 2.72 + } + }, + "tests/aws/services/sns/test_sns.py::TestSNSTopicCrudV2::test_topic_get_attributes_with_fifo_false": { + "last_validated_date": "2025-09-29T11:10:41+00:00", + "durations_in_seconds": { + "setup": 0.94, + "call": 1.77, + "teardown": 0.31, + "total": 3.02 + } + }, + "tests/aws/services/sns/test_sns.py::TestSNSTopicCrudV2::test_topic_remove_permission": { + "last_validated_date": "2025-12-11T12:02:07+00:00", + "durations_in_seconds": { + "setup": 1.15, + "call": 2.22, + "teardown": 0.3, + "total": 3.67 + } } } diff --git a/tests/aws/services/sns/test_sns_filter_policy.py b/tests/aws/services/sns/test_sns_filter_policy.py index 15ea761fb791d..18fc17eaec215 100644 --- a/tests/aws/services/sns/test_sns_filter_policy.py +++ b/tests/aws/services/sns/test_sns_filter_policy.py @@ -11,7 +11,6 @@ from localstack.utils.aws.arns import get_partition from localstack.utils.files import load_file from localstack.utils.sync import poll_condition, retry -from tests.aws.services.sns.conftest import skip_if_sns_v2 THIS_FOLDER: str = os.path.dirname(os.path.realpath(__file__)) TEST_PAYLOAD_DIR = os.path.join(THIS_FOLDER, "test_payloads") @@ -52,7 +51,6 @@ def _inner(topic_arn: str, queue_url: str, filter_scope: str, filter_policy: dic class TestSNSFilterPolicyCrud: @markers.aws.validated - @skip_if_sns_v2 def test_set_subscription_filter_policy_scope( self, sqs_create_queue, sns_create_topic, sns_create_sqs_subscription, snapshot, aws_client ): @@ -104,7 +102,6 @@ def test_set_subscription_filter_policy_scope( snapshot.match("sub-attrs-after-setting-policy", subscription_attrs) @markers.aws.validated - @skip_if_sns_v2 def test_sub_filter_policy_nested_property( self, sqs_create_queue, sns_create_topic, sns_create_sqs_subscription, snapshot, aws_client ): @@ -147,7 +144,6 @@ def test_sub_filter_policy_nested_property( "$.sub-filter-policy-rule-no-list.Error.Message", # message contains java trace in AWS, assert instead ] ) - @skip_if_sns_v2 def test_sub_filter_policy_nested_property_constraints( self, sqs_create_queue, sns_create_topic, sns_create_sqs_subscription, snapshot, aws_client ): @@ -214,7 +210,6 @@ def test_sub_filter_policy_nested_property_constraints( class TestSNSFilterPolicyAttributes: @markers.aws.validated - @skip_if_sns_v2 def test_filter_policy( self, sqs_create_queue, sns_create_topic, sns_create_sqs_subscription, snapshot, aws_client ): @@ -340,7 +335,6 @@ def check_no_filter_policy(): snapshot.match("messages-4", response_4) @markers.aws.validated - @skip_if_sns_v2 def test_exists_filter_policy( self, sqs_create_queue, sns_create_topic, sns_create_sqs_subscription, snapshot, aws_client ): @@ -458,7 +452,6 @@ def get_filter_policy(): assert num_msgs_4 == num_msgs_3 @markers.aws.validated - @skip_if_sns_v2 def test_exists_filter_policy_attributes_array( self, sqs_create_queue, @@ -561,7 +554,6 @@ def get_messages(aws_client, _queue_url: str, _msg_list: list, expected: int): @markers.aws.validated @pytest.mark.parametrize("raw_message_delivery", [True, False]) - @skip_if_sns_v2 def test_filter_policy_on_message_body( self, sqs_create_queue, @@ -668,7 +660,6 @@ def test_filter_policy_on_message_body( assert "Messages" not in response or response["Messages"] == [] @markers.aws.validated - @skip_if_sns_v2 def test_filter_policy_for_batch( self, sqs_create_queue, sns_create_topic, sns_create_sqs_subscription, snapshot, aws_client ): @@ -772,7 +763,6 @@ def test_filter_policy_for_batch( snapshot.match("messages-with-filter-after-publish-filtered", response_after_publish_filter) @markers.aws.validated - @skip_if_sns_v2 def test_filter_policy_on_message_body_dot_attribute( self, sqs_create_queue, @@ -898,7 +888,6 @@ def _verify_and_snapshot_sqs_messages(msg_to_send: list[dict], snapshot_prefix: assert "Messages" not in response or response["Messages"] == [] @markers.aws.validated - @skip_if_sns_v2 def test_filter_policy_on_message_body_array_attributes( self, sqs_create_queue, @@ -958,7 +947,6 @@ def test_filter_policy_on_message_body_array_attributes( snapshot.match(f"messages-queue-{i}", {"Messages": recv_messages}) @markers.aws.validated - @skip_if_sns_v2 def test_filter_policy_on_message_body_array_of_object_attributes( self, sqs_create_queue, @@ -1074,7 +1062,6 @@ def test_filter_policy_on_message_body_array_of_object_attributes( snapshot.match("messages", {"Messages": received_messages}) @markers.aws.validated - @skip_if_sns_v2 def test_filter_policy_on_message_body_or_attribute( self, sqs_create_queue, @@ -1172,7 +1159,6 @@ def test_filter_policy_on_message_body_or_attribute( snapshot.match("messages-queue", {"Messages": recv_messages}) @markers.aws.validated - @skip_if_sns_v2 def test_filter_policy_empty_array_payload( self, sqs_create_queue, @@ -1226,7 +1212,6 @@ def test_filter_policy_empty_array_payload( snapshot.match("messages-queue", {"Messages": recv_messages}) @markers.aws.validated - @skip_if_sns_v2 def test_filter_policy_large_complex_payload( self, sqs_create_queue, @@ -1265,7 +1250,6 @@ def test_filter_policy_large_complex_payload( assert len(recv_messages) == 1 @markers.aws.validated - @skip_if_sns_v2 def test_filter_policy_ip_address_condition( self, sqs_create_queue, @@ -1359,7 +1343,6 @@ def _add_normalized_field_to_snapshot(error_dict): # AWS adds JSON position error: `\n at [Source: (String)"{"key":[["value"]]}"; line: 1, column: 10]` paths=["$..Error.Message"] ) - @skip_if_sns_v2 def test_validate_policy( self, sns_create_topic, @@ -1398,7 +1381,6 @@ def _subscribe(policy: dict): @markers.aws.validated @markers.snapshot.skip_snapshot_verify(paths=["$..Error.Message"]) - @skip_if_sns_v2 def test_validate_policy_string_operators( self, sns_create_topic, @@ -1503,7 +1485,6 @@ def _subscribe(policy: dict): @markers.aws.validated @markers.snapshot.skip_snapshot_verify(paths=["$..Error.Message"]) - @skip_if_sns_v2 def test_validate_policy_numeric_operator( self, sns_create_topic, @@ -1609,7 +1590,6 @@ def _subscribe(policy: dict): @markers.aws.validated @markers.snapshot.skip_snapshot_verify(paths=["$..Error.Message"]) - @skip_if_sns_v2 def test_validate_policy_exists_operator( self, sns_create_topic, @@ -1642,7 +1622,6 @@ def _subscribe(policy: dict): @markers.aws.validated @markers.snapshot.skip_snapshot_verify(paths=["$..Error.Message"]) - @skip_if_sns_v2 def test_validate_policy_nested_anything_but_operator( self, sns_create_topic, @@ -1708,7 +1687,6 @@ def _subscribe(policy: dict): assert response["ResponseMetadata"]["HTTPStatusCode"] == 200 @markers.aws.validated - @skip_if_sns_v2 def test_policy_complexity( self, sns_create_topic, @@ -1753,7 +1731,6 @@ def _subscribe(policy: dict): snapshot.match("error-complexity-too-many-fields", e.value.response) @markers.aws.validated - @skip_if_sns_v2 def test_policy_complexity_with_or( self, sns_create_topic, diff --git a/tests/aws/services/sqs/resource_providers/templates/sqs_fifo_queue_all_properties.yml b/tests/aws/services/sqs/resource_providers/templates/sqs_fifo_queue_all_properties.yml new file mode 100644 index 0000000000000..53b2962a185d1 --- /dev/null +++ b/tests/aws/services/sqs/resource_providers/templates/sqs_fifo_queue_all_properties.yml @@ -0,0 +1,49 @@ +# +# Define an SQS FIFO Queue with all possible properties set to valid values. +# +Resources: + FifoQueue: + Type: 'AWS::SQS::Queue' + Properties: + QueueName: 'MyFifoQueue.fifo' + FifoQueue: true + ContentBasedDeduplication: true + DeduplicationScope: 'messageGroup' + FifoThroughputLimit: 'perMessageGroupId' + DelaySeconds: 13 + MaximumMessageSize: 3232 + MessageRetentionPeriod: 13425 + ReceiveMessageWaitTimeSeconds: 15 + VisibilityTimeout: 42 + RedrivePolicy: + deadLetterTargetArn: !GetAtt DeadLetterQueue.Arn + maxReceiveCount: 7 + SqsManagedSseEnabled: false + KmsMasterKeyId: 'alias/aws/sqs' + KmsDataKeyReusePeriodSeconds: 200 + Tags: + - Key: 'Environment' + Value: 'Production' + - Key: 'Department' + Value: 'Finance' + + DeadLetterQueue: + Type: 'AWS::SQS::Queue' + Properties: + FifoQueue: true + RedriveAllowPolicy: + redrivePermission: 'allowAll' + +Outputs: + QueueUrl: + Description: 'URL of the SQS Fifo Queue' + Value: !Ref FifoQueue + QueueArn: + Description: 'ARN of the SQS Fifo Queue' + Value: !GetAtt FifoQueue.Arn + DeadLetterQueueUrl: + Description: 'URL of the Dead Letter Queue' + Value: !Ref DeadLetterQueue + DeadLetterQueueArn: + Description: 'ARN of the Dead Letter Queue' + Value: !GetAtt DeadLetterQueue.Arn diff --git a/tests/aws/services/sqs/resource_providers/templates/sqs_fifo_queue_required_properties.yml b/tests/aws/services/sqs/resource_providers/templates/sqs_fifo_queue_required_properties.yml new file mode 100644 index 0000000000000..c60e20a744287 --- /dev/null +++ b/tests/aws/services/sqs/resource_providers/templates/sqs_fifo_queue_required_properties.yml @@ -0,0 +1,17 @@ +# +# Define an SQS FIFO Queue with only the required properties set. All other properties will +# take their default values. +# +Resources: + FifoQueue: + Type: 'AWS::SQS::Queue' + Properties: + FifoQueue: true + +Outputs: + QueueUrl: + Description: 'URL of the SQS Fifo Queue' + Value: !Ref FifoQueue + QueueArn: + Description: 'ARN of the SQS Fifo Queue' + Value: !GetAtt FifoQueue.Arn diff --git a/tests/aws/services/sqs/resource_providers/templates/sqs_fifo_queue_with_name_only.yml b/tests/aws/services/sqs/resource_providers/templates/sqs_fifo_queue_with_name_only.yml new file mode 100644 index 0000000000000..5551da2f3e834 --- /dev/null +++ b/tests/aws/services/sqs/resource_providers/templates/sqs_fifo_queue_with_name_only.yml @@ -0,0 +1,17 @@ +# +# Define an SQS FIFO Queue with only the QueueName attribute set. +# +Resources: + FifoQueue: + Type: 'AWS::SQS::Queue' + Properties: + QueueName: 'MyFifoQueue.fifo' + FifoQueue: true + +Outputs: + QueueUrl: + Description: 'URL of the SQS Fifo Queue' + Value: !Ref FifoQueue + QueueArn: + Description: 'ARN of the SQS Fifo Queue' + Value: !GetAtt FifoQueue.Arn diff --git a/tests/aws/services/sqs/resource_providers/templates/sqs_standard_queue_all_properties.yml b/tests/aws/services/sqs/resource_providers/templates/sqs_standard_queue_all_properties.yml new file mode 100644 index 0000000000000..2e23499ba1746 --- /dev/null +++ b/tests/aws/services/sqs/resource_providers/templates/sqs_standard_queue_all_properties.yml @@ -0,0 +1,44 @@ +# +# A standard SQS queue with all properties set, including a dead-letter queue. All properties are set to valid values. +# +Resources: + StandardQueue: + Type: 'AWS::SQS::Queue' + Properties: + QueueName: 'MyStandardQueueWithAllProperties' + DelaySeconds: 17 + MaximumMessageSize: 1234 + MessageRetentionPeriod: 13579 + ReceiveMessageWaitTimeSeconds: 18 + VisibilityTimeout: 45 + RedrivePolicy: + deadLetterTargetArn: !GetAtt DeadLetterQueue.Arn + maxReceiveCount: 7 + SqsManagedSseEnabled: false + KmsMasterKeyId: 'alias/aws/sqs' + KmsDataKeyReusePeriodSeconds: 297 + Tags: + - Key: 'Environment' + Value: 'Production' + - Key: 'Department' + Value: 'Finance' + + DeadLetterQueue: + Type: 'AWS::SQS::Queue' + Properties: + RedriveAllowPolicy: + redrivePermission: 'allowAll' + +Outputs: + QueueUrl: + Description: 'URL of the SQS Standard Queue' + Value: !Ref StandardQueue + QueueArn: + Description: 'ARN of the SQS Standard Queue' + Value: !GetAtt StandardQueue.Arn + DeadLetterQueueUrl: + Description: 'URL of the Dead Letter Queue' + Value: !Ref DeadLetterQueue + DeadLetterQueueArn: + Description: 'ARN of the Dead Letter Queue' + Value: !GetAtt DeadLetterQueue.Arn diff --git a/tests/aws/services/sqs/resource_providers/templates/sqs_standard_queue_all_properties_variant_1.yml b/tests/aws/services/sqs/resource_providers/templates/sqs_standard_queue_all_properties_variant_1.yml new file mode 100644 index 0000000000000..e42ffa651e223 --- /dev/null +++ b/tests/aws/services/sqs/resource_providers/templates/sqs_standard_queue_all_properties_variant_1.yml @@ -0,0 +1,43 @@ +# +# Similar to sqs_standard_queue_all_properties.yml in that it defines a standard SQS queue with all properties set, +# however, the property values are different. +# +Resources: + StandardQueue: + Type: 'AWS::SQS::Queue' + Properties: + QueueName: 'MyStandardQueueWithAllProperties' + DelaySeconds: 16 + MaximumMessageSize: 4321 + MessageRetentionPeriod: 17539 + ReceiveMessageWaitTimeSeconds: 17 + VisibilityTimeout: 40 + RedrivePolicy: + deadLetterTargetArn: !GetAtt DeadLetterQueue.Arn + maxReceiveCount: 3 + SqsManagedSseEnabled: true + Tags: + - Key: 'Environment' + Value: 'Staging' + - Key: 'Department' + Value: 'Sales' + + DeadLetterQueue: + Type: 'AWS::SQS::Queue' + Properties: + RedriveAllowPolicy: + redrivePermission: 'allowAll' + +Outputs: + QueueUrl: + Description: 'URL of the SQS Standard Queue' + Value: !Ref StandardQueue + QueueArn: + Description: 'ARN of the SQS Standard Queue' + Value: !GetAtt StandardQueue.Arn + DeadLetterQueueUrl: + Description: 'URL of the Dead Letter Queue' + Value: !Ref DeadLetterQueue + DeadLetterQueueArn: + Description: 'ARN of the Dead Letter Queue' + Value: !GetAtt DeadLetterQueue.Arn diff --git a/tests/aws/services/sqs/resource_providers/templates/sqs_standard_queue_all_properties_variant_2.yml b/tests/aws/services/sqs/resource_providers/templates/sqs_standard_queue_all_properties_variant_2.yml new file mode 100644 index 0000000000000..6c1da7b64661d --- /dev/null +++ b/tests/aws/services/sqs/resource_providers/templates/sqs_standard_queue_all_properties_variant_2.yml @@ -0,0 +1,43 @@ +# +# Similar to sqs_standard_queue_all_properties.yml in that it defines a standard SQS queue with all properties set, +# however, the property values are different, including the Queue name. +# +Resources: + StandardQueue: + Type: 'AWS::SQS::Queue' + Properties: + QueueName: 'MyStandardQueueWithADifferentName' + DelaySeconds: 15 + MaximumMessageSize: 4444 + MessageRetentionPeriod: 17777 + ReceiveMessageWaitTimeSeconds: 14 + VisibilityTimeout: 35 + RedrivePolicy: + deadLetterTargetArn: !GetAtt DeadLetterQueue.Arn + maxReceiveCount: 4 + SqsManagedSseEnabled: true + Tags: + - Key: 'Environment' + Value: 'Pre-Test' + - Key: 'Department' + Value: 'Marketing' + + DeadLetterQueue: + Type: 'AWS::SQS::Queue' + Properties: + RedriveAllowPolicy: + redrivePermission: 'allowAll' + +Outputs: + QueueUrl: + Description: 'URL of the SQS Standard Queue' + Value: !Ref StandardQueue + QueueArn: + Description: 'ARN of the SQS Standard Queue' + Value: !GetAtt StandardQueue.Arn + DeadLetterQueueUrl: + Description: 'URL of the Dead Letter Queue' + Value: !Ref DeadLetterQueue + DeadLetterQueueArn: + Description: 'ARN of the Dead Letter Queue' + Value: !GetAtt DeadLetterQueue.Arn diff --git a/tests/aws/services/sqs/resource_providers/templates/sqs_standard_queue_all_properties_with_error.yml b/tests/aws/services/sqs/resource_providers/templates/sqs_standard_queue_all_properties_with_error.yml new file mode 100644 index 0000000000000..6b60a7bd16c3d --- /dev/null +++ b/tests/aws/services/sqs/resource_providers/templates/sqs_standard_queue_all_properties_with_error.yml @@ -0,0 +1,45 @@ +# +# A standard SQS queue with all properties set, including a dead-letter queue. The ReceiveMessageWaitTimeSeconds +# property is set to an invalid value (21) to simulate an error scenario. +# +Resources: + StandardQueue: + Type: 'AWS::SQS::Queue' + Properties: + QueueName: 'MyStandardQueueWithAllProperties' + DelaySeconds: 31 + MaximumMessageSize: 1048576 + MessageRetentionPeriod: 13579 + ReceiveMessageWaitTimeSeconds: 21 + VisibilityTimeout: 45 + RedrivePolicy: + deadLetterTargetArn: !GetAtt DeadLetterQueue.Arn + maxReceiveCount: 7 + SqsManagedSseEnabled: false + KmsMasterKeyId: 'alias/aws/sqs' + KmsDataKeyReusePeriodSeconds: 297 + Tags: + - Key: 'Environment' + Value: 'Production' + - Key: 'Department' + Value: 'Finance' + + DeadLetterQueue: + Type: 'AWS::SQS::Queue' + Properties: + RedriveAllowPolicy: + redrivePermission: 'allowAll' + +Outputs: + QueueUrl: + Description: 'URL of the SQS Standard Queue' + Value: !Ref StandardQueue + QueueArn: + Description: 'ARN of the SQS Standard Queue' + Value: !GetAtt StandardQueue.Arn + DeadLetterQueueUrl: + Description: 'URL of the Dead Letter Queue' + Value: !Ref DeadLetterQueue + DeadLetterQueueArn: + Description: 'ARN of the Dead Letter Queue' + Value: !GetAtt DeadLetterQueue.Arn diff --git a/tests/aws/services/sqs/resource_providers/templates/sqs_standard_queue_no_resource.yml b/tests/aws/services/sqs/resource_providers/templates/sqs_standard_queue_no_resource.yml new file mode 100644 index 0000000000000..c9a18dc5f149a --- /dev/null +++ b/tests/aws/services/sqs/resource_providers/templates/sqs_standard_queue_no_resource.yml @@ -0,0 +1,18 @@ +# +# A template defining only a dead-letter SQS queue without any additional properties. This template does not +# contain the main queue, so applying this template should remove any existing main queue. +# +Resources: + DeadLetterQueue: + Type: 'AWS::SQS::Queue' + Properties: + RedriveAllowPolicy: + redrivePermission: 'allowAll' + +Outputs: + DeadLetterQueueUrl: + Description: 'URL of the Dead Letter Queue' + Value: !Ref DeadLetterQueue + DeadLetterQueueArn: + Description: 'ARN of the Dead Letter Queue' + Value: !GetAtt DeadLetterQueue.Arn diff --git a/tests/aws/services/sqs/resource_providers/templates/sqs_standard_queue_required_properties.yml b/tests/aws/services/sqs/resource_providers/templates/sqs_standard_queue_required_properties.yml new file mode 100644 index 0000000000000..f5f8ee5c1798e --- /dev/null +++ b/tests/aws/services/sqs/resource_providers/templates/sqs_standard_queue_required_properties.yml @@ -0,0 +1,14 @@ +# +# A standard SQS queue with no properties set, including the name which will be auto-generated. +# +Resources: + StandardQueue: + Type: 'AWS::SQS::Queue' + +Outputs: + QueueUrl: + Description: 'URL of the SQS Standard Queue' + Value: !Ref StandardQueue + QueueArn: + Description: 'ARN of the SQS Standard Queue' + Value: !GetAtt StandardQueue.Arn diff --git a/tests/aws/services/sqs/resource_providers/templates/sqs_standard_queue_some_properties.yml b/tests/aws/services/sqs/resource_providers/templates/sqs_standard_queue_some_properties.yml new file mode 100644 index 0000000000000..f8be1c306d625 --- /dev/null +++ b/tests/aws/services/sqs/resource_providers/templates/sqs_standard_queue_some_properties.yml @@ -0,0 +1,38 @@ +# +# A standard SQS queue with some properties set, but not all. The properties set have valid values, and the unset +# properties will take their default values. +# +Resources: + StandardQueue: + Type: 'AWS::SQS::Queue' + Properties: + QueueName: 'MyStandardQueueWithAllProperties' + DelaySeconds: 17 + VisibilityTimeout: 43 + RedrivePolicy: + deadLetterTargetArn: !GetAtt DeadLetterQueue.Arn + maxReceiveCount: 7 + SqsManagedSseEnabled: false + Tags: + - Key: 'Environment' + Value: 'Pre-Production' + + DeadLetterQueue: + Type: 'AWS::SQS::Queue' + Properties: + RedriveAllowPolicy: + redrivePermission: 'allowAll' + +Outputs: + QueueUrl: + Description: 'URL of the SQS Standard Queue' + Value: !Ref StandardQueue + QueueArn: + Description: 'ARN of the SQS Standard Queue' + Value: !GetAtt StandardQueue.Arn + DeadLetterQueueUrl: + Description: 'URL of the Dead Letter Queue' + Value: !Ref DeadLetterQueue + DeadLetterQueueArn: + Description: 'ARN of the Dead Letter Queue' + Value: !GetAtt DeadLetterQueue.Arn diff --git a/tests/aws/services/sqs/resource_providers/templates/sqs_standard_queue_some_properties_without_name.yml b/tests/aws/services/sqs/resource_providers/templates/sqs_standard_queue_some_properties_without_name.yml new file mode 100644 index 0000000000000..bba8bd1bed745 --- /dev/null +++ b/tests/aws/services/sqs/resource_providers/templates/sqs_standard_queue_some_properties_without_name.yml @@ -0,0 +1,21 @@ +# +# A standard SQS queue with some properties set, but not all. The properties set have valid values, and the unset +# properties will take their default values. This is similar to sqs_standard_queue_some_properties.yml, but without +# specifying a name for the queue, so it'll be auto-generated. +# +Resources: + StandardQueue: + Type: 'AWS::SQS::Queue' + Properties: + VisibilityTimeout: 30 + MaximumMessageSize: 4321 + MessageRetentionPeriod: 17539 + ReceiveMessageWaitTimeSeconds: 17 + +Outputs: + QueueUrl: + Description: 'URL of the SQS Standard Queue' + Value: !Ref StandardQueue + QueueArn: + Description: 'ARN of the SQS Standard Queue' + Value: !GetAtt StandardQueue.Arn diff --git a/tests/aws/services/sqs/resource_providers/templates/sqs_with_queueinlinepolicy.yml b/tests/aws/services/sqs/resource_providers/templates/sqs_with_queueinlinepolicy.yml new file mode 100644 index 0000000000000..0cac63290c300 --- /dev/null +++ b/tests/aws/services/sqs/resource_providers/templates/sqs_with_queueinlinepolicy.yml @@ -0,0 +1,27 @@ +# +# A standard SQS queue with an associated queue inline policy allowing a few actions. +# + +Resources: + MyQueue: + Type: AWS::SQS::Queue + + Policy: + Type: AWS::SQS::QueueInlinePolicy + Properties: + PolicyDocument: + Version: "2012-10-17" + Statement: + - Effect: Allow + Principal: "*" + Action: + - sqs:SendMessage + - sqs:GetQueueAttributes + - sqs:GetQueueUrl + Resource: !GetAtt MyQueue.Arn + Queue: !Ref MyQueue + +Outputs: + QueueUrl: + Value: + Ref: MyQueue diff --git a/tests/aws/services/sqs/resource_providers/templates/sqs_with_queueinlinepolicy_variant_1.yml b/tests/aws/services/sqs/resource_providers/templates/sqs_with_queueinlinepolicy_variant_1.yml new file mode 100644 index 0000000000000..2b2d438d4c900 --- /dev/null +++ b/tests/aws/services/sqs/resource_providers/templates/sqs_with_queueinlinepolicy_variant_1.yml @@ -0,0 +1,29 @@ +# +# A standard SQS queue with an associated queue inline policy allowing a few actions. +# + +Resources: + MyQueue: + Type: AWS::SQS::Queue + + Policy: + Type: AWS::SQS::QueueInlinePolicy + Properties: + PolicyDocument: + Version: "2012-10-17" + Statement: + - Effect: Allow + Principal: "*" + Action: + - sqs:SendMessage + - sqs:GetQueueAttributes + - sqs:GetQueueUrl + - sqs:DeleteMessage + - sqs:ReceiveMessage + Resource: !GetAtt MyQueue.Arn + Queue: !Ref MyQueue + +Outputs: + QueueUrl: + Value: + Ref: MyQueue diff --git a/tests/aws/templates/sqs_with_queuepolicy.yaml b/tests/aws/services/sqs/resource_providers/templates/sqs_with_queuepolicy.yml similarity index 58% rename from tests/aws/templates/sqs_with_queuepolicy.yaml rename to tests/aws/services/sqs/resource_providers/templates/sqs_with_queuepolicy.yml index 0fabf18902847..2d0f49423fcaa 100644 --- a/tests/aws/templates/sqs_with_queuepolicy.yaml +++ b/tests/aws/services/sqs/resource_providers/templates/sqs_with_queuepolicy.yml @@ -1,6 +1,14 @@ +# +# A standard SQS queue with an associated queue policy allowing a few actions. +# Resources: - Queue4A7E3555: + Queue1: Type: AWS::SQS::Queue + Queue2: + Type: AWS::SQS::Queue + Queue3: + Type: AWS::SQS::Queue + QueuePolicy25439813: Type: AWS::SQS::QueuePolicy Properties: @@ -14,12 +22,18 @@ Resources: Principal: "*" Resource: Fn::GetAtt: - - Queue4A7E3555 + - Queue1 - Arn Version: "2012-10-17" Queues: - - Ref: Queue4A7E3555 + - Ref: Queue1 Outputs: - QueueUrlOutput: + Queue1Url: + Value: + Ref: Queue1 + Queue2Url: + Value: + Ref: Queue2 + Queue3Url: Value: - Ref: Queue4A7E3555 + Ref: Queue3 diff --git a/tests/aws/services/sqs/resource_providers/templates/sqs_with_queuepolicy_for_3_queues.yml b/tests/aws/services/sqs/resource_providers/templates/sqs_with_queuepolicy_for_3_queues.yml new file mode 100644 index 0000000000000..5092a307037a4 --- /dev/null +++ b/tests/aws/services/sqs/resource_providers/templates/sqs_with_queuepolicy_for_3_queues.yml @@ -0,0 +1,43 @@ +# +# A standard SQS queue with an associated queue policy allowing a few actions. +# +Resources: + Queue1: + Type: AWS::SQS::Queue + Queue2: + Type: AWS::SQS::Queue + Queue3: + Type: AWS::SQS::Queue + + QueuePolicy25439813: + Type: AWS::SQS::QueuePolicy + Properties: + PolicyDocument: + Statement: + - Action: + - sqs:SendMessage + - sqs:GetQueueAttributes + - sqs:GetQueueUrl + - sqs:ChangeMessageVisibility + Effect: Allow + Principal: "*" + Resource: + Fn::GetAtt: + - Queue1 + - Arn + Version: "2012-10-17" + Queues: + - Ref: Queue1 + - Ref: Queue2 + - Ref: Queue3 + +Outputs: + Queue1Url: + Value: + Ref: Queue1 + Queue2Url: + Value: + Ref: Queue2 + Queue3Url: + Value: + Ref: Queue3 diff --git a/tests/aws/services/sqs/resource_providers/templates/sqs_with_queuepolicy_updated.yml b/tests/aws/services/sqs/resource_providers/templates/sqs_with_queuepolicy_updated.yml new file mode 100644 index 0000000000000..f6b05ab1d72bb --- /dev/null +++ b/tests/aws/services/sqs/resource_providers/templates/sqs_with_queuepolicy_updated.yml @@ -0,0 +1,41 @@ +# +# A standard SQS queue with an associated queue policy allowing a slightly different set of actions compared +# to sqs_with_queuepolicy.yml. +# +Resources: + Queue1: + Type: AWS::SQS::Queue + Queue2: + Type: AWS::SQS::Queue + Queue3: + Type: AWS::SQS::Queue + + QueuePolicy25439813: + Type: AWS::SQS::QueuePolicy + Properties: + PolicyDocument: + Statement: + - Action: + - sqs:SendMessage + - sqs:GetQueueAttributes + - sqs:GetQueueUrl + - sqs:DeleteMessage + Effect: Allow + Principal: "*" + Resource: + Fn::GetAtt: + - Queue1 + - Arn + Version: "2012-10-17" + Queues: + - Ref: Queue1 +Outputs: + Queue1Url: + Value: + Ref: Queue1 + Queue2Url: + Value: + Ref: Queue2 + Queue3Url: + Value: + Ref: Queue3 diff --git a/tests/aws/services/sqs/resource_providers/templates/sqs_without_queueinlinepolicy.yml b/tests/aws/services/sqs/resource_providers/templates/sqs_without_queueinlinepolicy.yml new file mode 100644 index 0000000000000..b9a7dba45edd9 --- /dev/null +++ b/tests/aws/services/sqs/resource_providers/templates/sqs_without_queueinlinepolicy.yml @@ -0,0 +1,12 @@ +# +# A standard SQS queue without an associated queue (inline) policy. +# + +Resources: + MyQueue: + Type: AWS::SQS::Queue + +Outputs: + QueueUrl: + Value: + Ref: MyQueue diff --git a/tests/aws/services/sqs/resource_providers/templates/sqs_without_queuepolicy.yml b/tests/aws/services/sqs/resource_providers/templates/sqs_without_queuepolicy.yml new file mode 100644 index 0000000000000..0c2661333ec77 --- /dev/null +++ b/tests/aws/services/sqs/resource_providers/templates/sqs_without_queuepolicy.yml @@ -0,0 +1,21 @@ +# +# A set of three standard SQS queues without any associated queue policies. +# +Resources: + Queue1: + Type: AWS::SQS::Queue + Queue2: + Type: AWS::SQS::Queue + Queue3: + Type: AWS::SQS::Queue + +Outputs: + Queue1Url: + Value: + Ref: Queue1 + Queue2Url: + Value: + Ref: Queue2 + Queue3Url: + Value: + Ref: Queue3 diff --git a/tests/aws/services/sqs/resource_providers/test_aws_sqs_queue.py b/tests/aws/services/sqs/resource_providers/test_aws_sqs_queue.py new file mode 100644 index 0000000000000..a9d63fc6efbc7 --- /dev/null +++ b/tests/aws/services/sqs/resource_providers/test_aws_sqs_queue.py @@ -0,0 +1,293 @@ +import os + +import pytest +from botocore.exceptions import ClientError + +from localstack.testing.pytest import markers +from localstack.testing.pytest.fixtures import StackDeployError + + +def deploy_stack(deploy_cfn_template, template_filename, **kwargs): + """ + Helper function to deploy a CloudFormation stack using a template file. This exists to reduce + boilerplate in the test cases. + """ + template_path = os.path.join(os.path.dirname(__file__), "templates", template_filename) + return deploy_cfn_template(template_path=template_path, **kwargs) + + +@markers.aws.validated +def test_create_standard_queue_with_required_properties(deploy_cfn_template, aws_client, snapshot): + stack = deploy_stack(deploy_cfn_template, "sqs_standard_queue_required_properties.yml") + (queue_url, queue_arn) = (stack.outputs["QueueUrl"], stack.outputs["QueueArn"]) + + snapshot.match( + "attributes", + aws_client.sqs.get_queue_attributes(QueueUrl=queue_url, AttributeNames=["All"]), + ) + snapshot.add_transformer(snapshot.transform.regex(queue_arn, "")) + + # auto-generated name check + assert "StandardQueue" in queue_url + assert not queue_url.endswith(".fifo") + + +@markers.aws.validated +def test_create_standard_queue_with_all_properties(deploy_cfn_template, aws_client, snapshot): + stack = deploy_stack(deploy_cfn_template, "sqs_standard_queue_all_properties.yml") + (queue_url, queue_arn, dlq_queue_url, dlq_queue_arn) = ( + stack.outputs["QueueUrl"], + stack.outputs["QueueArn"], + stack.outputs["DeadLetterQueueUrl"], + stack.outputs["DeadLetterQueueArn"], + ) + + snapshot.match( + "attributes", + aws_client.sqs.get_queue_attributes(QueueUrl=queue_url, AttributeNames=["All"]), + ) + snapshot.match("tags", aws_client.sqs.list_queue_tags(QueueUrl=queue_url)) + snapshot.match( + "dlq_attributes", + aws_client.sqs.get_queue_attributes( + QueueUrl=dlq_queue_url, AttributeNames=["RedriveAllowPolicy"] + ), + ) + snapshot.add_transformer(snapshot.transform.regex(queue_arn, "")) + snapshot.add_transformer(snapshot.transform.regex(dlq_queue_arn, "")) + + +@markers.aws.validated +def test_create_fifo_queue_with_required_properties(deploy_cfn_template, aws_client, snapshot): + stack = deploy_stack(deploy_cfn_template, "sqs_fifo_queue_required_properties.yml") + (queue_url, queue_arn) = (stack.outputs["QueueUrl"], stack.outputs["QueueArn"]) + + snapshot.match( + "attributes", + aws_client.sqs.get_queue_attributes(QueueUrl=queue_url, AttributeNames=["All"]), + ) + snapshot.add_transformer(snapshot.transform.regex(queue_arn, "")) + + # auto-generated name check + assert "FifoQueue" in queue_url + assert queue_url.endswith(".fifo") + + +@markers.aws.validated +def test_create_fifo_queue_with_all_properties(deploy_cfn_template, aws_client, snapshot): + stack = deploy_stack(deploy_cfn_template, "sqs_fifo_queue_all_properties.yml") + (queue_url, queue_arn, dlq_queue_url, dlq_queue_arn) = ( + stack.outputs["QueueUrl"], + stack.outputs["QueueArn"], + stack.outputs["DeadLetterQueueUrl"], + stack.outputs["DeadLetterQueueArn"], + ) + + snapshot.match( + "attributes", + aws_client.sqs.get_queue_attributes(QueueUrl=queue_url, AttributeNames=["All"]), + ) + snapshot.match("tags", aws_client.sqs.list_queue_tags(QueueUrl=queue_url)) + snapshot.match( + "dlq_attributes", + aws_client.sqs.get_queue_attributes( + QueueUrl=dlq_queue_url, AttributeNames=["RedriveAllowPolicy"] + ), + ) + snapshot.add_transformer(snapshot.transform.regex(queue_arn, "")) + snapshot.add_transformer(snapshot.transform.regex(dlq_queue_arn, "")) + + +@markers.aws.validated +def test_update_standard_queue_modify_properties_in_place( + deploy_cfn_template, aws_client, snapshot +): + stack = deploy_stack(deploy_cfn_template, "sqs_standard_queue_all_properties.yml") + queue_url = stack.outputs["QueueUrl"] + + # Update the stack to add optional properties + updated_stack = deploy_stack( + deploy_cfn_template, + "sqs_standard_queue_all_properties_variant_1.yml", + is_update=True, + stack_name=stack.stack_name, + ) + updated_queue_url = updated_stack.outputs["QueueUrl"] + assert queue_url == updated_queue_url + + snapshot.match( + "updated_attributes", + aws_client.sqs.get_queue_attributes(QueueUrl=updated_queue_url, AttributeNames=["All"]), + ) + snapshot.match("updated_tags", aws_client.sqs.list_queue_tags(QueueUrl=updated_queue_url)) + snapshot.add_transformer(snapshot.transform.regex(stack.outputs["QueueArn"], "")) + snapshot.add_transformer( + snapshot.transform.regex(stack.outputs["DeadLetterQueueArn"], "") + ) + + +@markers.aws.validated +def test_update_standard_queue_add_properties_with_replacement( + deploy_cfn_template, aws_client, snapshot +): + stack = deploy_stack(deploy_cfn_template, "sqs_standard_queue_all_properties.yml") + (queue_url, dlq_queue_url) = (stack.outputs["QueueUrl"], stack.outputs["DeadLetterQueueUrl"]) + + # Update the stack to rename the queue - this will cause the resource to be replaced, rather than + # updating the existing queue in place + updated_stack = deploy_stack( + deploy_cfn_template, + "sqs_standard_queue_all_properties_variant_2.yml", + is_update=True, + stack_name=stack.stack_name, + ) + (updated_queue_url, updated_dlq_queue_url) = ( + updated_stack.outputs["QueueUrl"], + updated_stack.outputs["DeadLetterQueueUrl"], + ) + assert queue_url != updated_queue_url + assert dlq_queue_url == updated_dlq_queue_url + + snapshot.match( + "updated_attributes", + aws_client.sqs.get_queue_attributes(QueueUrl=updated_queue_url, AttributeNames=["All"]), + ) + snapshot.match("updated_tags", aws_client.sqs.list_queue_tags(QueueUrl=updated_queue_url)) + snapshot.add_transformer(snapshot.transform.key_value("deadLetterTargetArn", "")) + + # confirm that the original queue has been deleted + with pytest.raises(ClientError) as exc: + aws_client.sqs.get_queue_attributes(QueueUrl=queue_url, AttributeNames=["All"]) + snapshot.match("error", exc.value.response) + + +@markers.aws.validated +def test_update_standard_queue_remove_some_properties(deploy_cfn_template, aws_client, snapshot): + stack = deploy_stack(deploy_cfn_template, "sqs_standard_queue_all_properties.yml") + queue_url = stack.outputs["QueueUrl"] + + # Update the stack with modified properties + updated_stack = deploy_stack( + deploy_cfn_template, + "sqs_standard_queue_some_properties.yml", + is_update=True, + stack_name=stack.stack_name, + ) + updated_queue_url = updated_stack.outputs["QueueUrl"] + assert queue_url == updated_queue_url + + snapshot.match( + "updated_attributes", + aws_client.sqs.get_queue_attributes(QueueUrl=updated_queue_url, AttributeNames=["All"]), + ) + snapshot.match("updated_tags", aws_client.sqs.list_queue_tags(QueueUrl=updated_queue_url)) + snapshot.add_transformer(snapshot.transform.regex(stack.outputs["QueueArn"], "")) + snapshot.add_transformer(snapshot.transform.key_value("deadLetterTargetArn", "")) + + +@markers.aws.validated +def test_update_fifo_queue_remove_all_properties(deploy_cfn_template, aws_client, snapshot): + stack = deploy_stack(deploy_cfn_template, "sqs_fifo_queue_all_properties.yml") + queue_url = stack.outputs["QueueUrl"] + + # Update the stack to remove optional properties, reverting to only the required properties + updated_stack = deploy_stack( + deploy_cfn_template, + "sqs_fifo_queue_required_properties.yml", + is_update=True, + stack_name=stack.stack_name, + ) + + # URL will change, because queue name is auto-generated when QueueName is not specified + updated_queue_url = updated_stack.outputs["QueueUrl"] + assert queue_url != updated_queue_url + + snapshot.match( + "updated_attributes", + aws_client.sqs.get_queue_attributes(QueueUrl=updated_queue_url, AttributeNames=["All"]), + ) + snapshot.match("updated_tags", aws_client.sqs.list_queue_tags(QueueUrl=updated_queue_url)) + snapshot.add_transformer( + snapshot.transform.regex(updated_stack.outputs["QueueArn"], "") + ) + + +@markers.aws.validated +def test_update_fifo_queue_remove_all_properties_except_queuename( + deploy_cfn_template, aws_client, snapshot +): + stack = deploy_stack(deploy_cfn_template, "sqs_fifo_queue_all_properties.yml") + queue_url = stack.outputs["QueueUrl"] + + # Update the stack to remove optional properties, reverting to only providing the QueueName property + updated_stack = deploy_stack( + deploy_cfn_template, + "sqs_fifo_queue_with_name_only.yml", + is_update=True, + stack_name=stack.stack_name, + ) + + # URL will remain the same, because queue name is explicitly specified + updated_queue_url = updated_stack.outputs["QueueUrl"] + assert queue_url == updated_queue_url + + snapshot.match( + "updated_attributes", + aws_client.sqs.get_queue_attributes(QueueUrl=updated_queue_url, AttributeNames=["All"]), + ) + snapshot.match("updated_tags", aws_client.sqs.list_queue_tags(QueueUrl=updated_queue_url)) + snapshot.add_transformer( + snapshot.transform.regex(updated_stack.outputs["QueueArn"], "") + ) + + +@markers.aws.validated +def test_update_completely_remove_resource(deploy_cfn_template, aws_client, snapshot): + stack = deploy_stack(deploy_cfn_template, "sqs_standard_queue_all_properties.yml") + queue_url = stack.outputs["QueueUrl"] + + # Delete the queue by updating the stack to remove the resource + deploy_stack( + deploy_cfn_template, + "sqs_standard_queue_no_resource.yml", + is_update=True, + stack_name=stack.stack_name, + ) + + # expect an exception to be thrown because the resource is deleted + with pytest.raises(ClientError) as exc: + aws_client.sqs.get_queue_attributes(QueueUrl=queue_url, AttributeNames=["All"]) + snapshot.match("error", exc.value.response) + + +@markers.aws.validated +def test_update_standard_queue_without_explicit_name(deploy_cfn_template, aws_client, snapshot): + stack = deploy_stack(deploy_cfn_template, "sqs_standard_queue_required_properties.yml") + queue_url = stack.outputs["QueueUrl"] + + # Update the stack to add optional properties, but expect the same queue name to be used. + updated_stack = deploy_stack( + deploy_cfn_template, + "sqs_standard_queue_some_properties_without_name.yml", + is_update=True, + stack_name=stack.stack_name, + ) + updated_queue_url = updated_stack.outputs["QueueUrl"] + assert queue_url == updated_queue_url + + snapshot.match( + "updated_attributes", + aws_client.sqs.get_queue_attributes(QueueUrl=updated_queue_url, AttributeNames=["All"]), + ) + snapshot.add_transformer(snapshot.transform.regex(stack.outputs["QueueArn"], "")) + + +@pytest.mark.skip(reason="SQS service in LocalStack does not correctly fail on invalid parameters") +@markers.aws.needs_fixing +def test_error_invalid_parameter(deploy_cfn_template, aws_client, snapshot): + with pytest.raises(StackDeployError) as exc: + deploy_stack( + deploy_cfn_template, + "sqs_standard_queue_all_properties_with_error.yml", + ) + snapshot.match("error", exc.value) diff --git a/tests/aws/services/sqs/resource_providers/test_aws_sqs_queue.snapshot.json b/tests/aws/services/sqs/resource_providers/test_aws_sqs_queue.snapshot.json new file mode 100644 index 0000000000000..9a5a413c13211 --- /dev/null +++ b/tests/aws/services/sqs/resource_providers/test_aws_sqs_queue.snapshot.json @@ -0,0 +1,404 @@ +{ + "tests/aws/services/sqs/resource_providers/test_aws_sqs_queue.py::test_create_standard_queue_with_required_properties": { + "recorded-date": "18-12-2025, 22:04:55", + "recorded-content": { + "attributes": { + "Attributes": { + "ApproximateNumberOfMessages": "0", + "ApproximateNumberOfMessagesDelayed": "0", + "ApproximateNumberOfMessagesNotVisible": "0", + "CreatedTimestamp": "timestamp", + "DelaySeconds": "0", + "LastModifiedTimestamp": "timestamp", + "MaximumMessageSize": "1048576", + "MessageRetentionPeriod": "345600", + "QueueArn": "", + "ReceiveMessageWaitTimeSeconds": "0", + "SqsManagedSseEnabled": "true", + "VisibilityTimeout": "30" + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/sqs/resource_providers/test_aws_sqs_queue.py::test_create_standard_queue_with_all_properties": { + "recorded-date": "18-12-2025, 22:06:15", + "recorded-content": { + "attributes": { + "Attributes": { + "ApproximateNumberOfMessages": "0", + "ApproximateNumberOfMessagesDelayed": "0", + "ApproximateNumberOfMessagesNotVisible": "0", + "CreatedTimestamp": "timestamp", + "DelaySeconds": "17", + "KmsDataKeyReusePeriodSeconds": "297", + "KmsMasterKeyId": "alias/aws/sqs", + "LastModifiedTimestamp": "timestamp", + "MaximumMessageSize": "1234", + "MessageRetentionPeriod": "13579", + "QueueArn": "", + "ReceiveMessageWaitTimeSeconds": "18", + "RedrivePolicy": { + "deadLetterTargetArn": "", + "maxReceiveCount": 7 + }, + "SqsManagedSseEnabled": "false", + "VisibilityTimeout": "45" + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "tags": { + "Tags": { + "Department": "Finance", + "Environment": "Production" + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "dlq_attributes": { + "Attributes": { + "RedriveAllowPolicy": { + "redrivePermission": "allowAll" + } + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/sqs/resource_providers/test_aws_sqs_queue.py::test_create_fifo_queue_with_required_properties": { + "recorded-date": "18-12-2025, 22:08:03", + "recorded-content": { + "attributes": { + "Attributes": { + "ApproximateNumberOfMessages": "0", + "ApproximateNumberOfMessagesDelayed": "0", + "ApproximateNumberOfMessagesNotVisible": "0", + "ContentBasedDeduplication": "false", + "CreatedTimestamp": "timestamp", + "DeduplicationScope": "queue", + "DelaySeconds": "0", + "FifoQueue": "true", + "FifoThroughputLimit": "perQueue", + "LastModifiedTimestamp": "timestamp", + "MaximumMessageSize": "1048576", + "MessageRetentionPeriod": "345600", + "QueueArn": "", + "ReceiveMessageWaitTimeSeconds": "0", + "SqsManagedSseEnabled": "true", + "VisibilityTimeout": "30" + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/sqs/resource_providers/test_aws_sqs_queue.py::test_create_fifo_queue_with_all_properties": { + "recorded-date": "18-12-2025, 22:09:23", + "recorded-content": { + "attributes": { + "Attributes": { + "ApproximateNumberOfMessages": "0", + "ApproximateNumberOfMessagesDelayed": "0", + "ApproximateNumberOfMessagesNotVisible": "0", + "ContentBasedDeduplication": "true", + "CreatedTimestamp": "timestamp", + "DeduplicationScope": "messageGroup", + "DelaySeconds": "13", + "FifoQueue": "true", + "FifoThroughputLimit": "perMessageGroupId", + "KmsDataKeyReusePeriodSeconds": "200", + "KmsMasterKeyId": "alias/aws/sqs", + "LastModifiedTimestamp": "timestamp", + "MaximumMessageSize": "3232", + "MessageRetentionPeriod": "13425", + "QueueArn": "", + "ReceiveMessageWaitTimeSeconds": "15", + "RedrivePolicy": { + "deadLetterTargetArn": "", + "maxReceiveCount": 7 + }, + "SqsManagedSseEnabled": "false", + "VisibilityTimeout": "42" + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "tags": { + "Tags": { + "Department": "Finance", + "Environment": "Production" + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "dlq_attributes": { + "Attributes": { + "RedriveAllowPolicy": { + "redrivePermission": "allowAll" + } + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/sqs/resource_providers/test_aws_sqs_queue.py::test_update_standard_queue_modify_properties_in_place": { + "recorded-date": "18-12-2025, 22:12:01", + "recorded-content": { + "updated_attributes": { + "Attributes": { + "ApproximateNumberOfMessages": "0", + "ApproximateNumberOfMessagesDelayed": "0", + "ApproximateNumberOfMessagesNotVisible": "0", + "CreatedTimestamp": "timestamp", + "DelaySeconds": "16", + "LastModifiedTimestamp": "timestamp", + "MaximumMessageSize": "4321", + "MessageRetentionPeriod": "17539", + "QueueArn": "", + "ReceiveMessageWaitTimeSeconds": "17", + "RedrivePolicy": { + "deadLetterTargetArn": "", + "maxReceiveCount": 3 + }, + "SqsManagedSseEnabled": "true", + "VisibilityTimeout": "40" + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "updated_tags": { + "Tags": { + "Department": "Sales", + "Environment": "Staging" + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/sqs/resource_providers/test_aws_sqs_queue.py::test_update_standard_queue_add_properties_with_replacement": { + "recorded-date": "18-12-2025, 22:15:10", + "recorded-content": { + "updated_attributes": { + "Attributes": { + "ApproximateNumberOfMessages": "0", + "ApproximateNumberOfMessagesDelayed": "0", + "ApproximateNumberOfMessagesNotVisible": "0", + "CreatedTimestamp": "timestamp", + "DelaySeconds": "15", + "LastModifiedTimestamp": "timestamp", + "MaximumMessageSize": "4444", + "MessageRetentionPeriod": "17777", + "QueueArn": "arn::sqs::111111111111:MyStandardQueueWithADifferentName", + "ReceiveMessageWaitTimeSeconds": "14", + "RedrivePolicy": { + "deadLetterTargetArn": "<:1>", + "maxReceiveCount": 4 + }, + "SqsManagedSseEnabled": "true", + "VisibilityTimeout": "35" + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "updated_tags": { + "Tags": { + "Department": "Marketing", + "Environment": "Pre-Test" + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "error": { + "Error": { + "Code": "AWS.SimpleQueueService.NonExistentQueue", + "Message": "The specified queue does not exist.", + "QueryErrorCode": "QueueDoesNotExist", + "Type": "Sender" + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + } + } + }, + "tests/aws/services/sqs/resource_providers/test_aws_sqs_queue.py::test_update_standard_queue_remove_some_properties": { + "recorded-date": "18-12-2025, 22:17:47", + "recorded-content": { + "updated_attributes": { + "Attributes": { + "ApproximateNumberOfMessages": "0", + "ApproximateNumberOfMessagesDelayed": "0", + "ApproximateNumberOfMessagesNotVisible": "0", + "CreatedTimestamp": "timestamp", + "DelaySeconds": "17", + "LastModifiedTimestamp": "timestamp", + "MaximumMessageSize": "262144", + "MessageRetentionPeriod": "345600", + "QueueArn": "", + "ReceiveMessageWaitTimeSeconds": "0", + "RedrivePolicy": { + "deadLetterTargetArn": "<:1>", + "maxReceiveCount": 7 + }, + "SqsManagedSseEnabled": "false", + "VisibilityTimeout": "43" + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "updated_tags": { + "Tags": { + "Environment": "Pre-Production" + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/sqs/resource_providers/test_aws_sqs_queue.py::test_update_completely_remove_resource": { + "recorded-date": "18-12-2025, 22:20:21", + "recorded-content": { + "error": { + "Error": { + "Code": "AWS.SimpleQueueService.NonExistentQueue", + "Message": "The specified queue does not exist.", + "QueryErrorCode": "QueueDoesNotExist", + "Type": "Sender" + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + } + } + }, + "tests/aws/services/sqs/resource_providers/test_aws_sqs_queue.py::test_update_standard_queue_without_explicit_name": { + "recorded-date": "18-12-2025, 22:22:23", + "recorded-content": { + "updated_attributes": { + "Attributes": { + "ApproximateNumberOfMessages": "0", + "ApproximateNumberOfMessagesDelayed": "0", + "ApproximateNumberOfMessagesNotVisible": "0", + "CreatedTimestamp": "timestamp", + "DelaySeconds": "0", + "LastModifiedTimestamp": "timestamp", + "MaximumMessageSize": "4321", + "MessageRetentionPeriod": "17539", + "QueueArn": "", + "ReceiveMessageWaitTimeSeconds": "17", + "SqsManagedSseEnabled": "true", + "VisibilityTimeout": "30" + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/sqs/resource_providers/test_aws_sqs_queue.py::test_update_fifo_queue_remove_all_properties": { + "recorded-date": "14-01-2026, 16:34:50", + "recorded-content": { + "updated_attributes": { + "Attributes": { + "ApproximateNumberOfMessages": "0", + "ApproximateNumberOfMessagesDelayed": "0", + "ApproximateNumberOfMessagesNotVisible": "0", + "ContentBasedDeduplication": "false", + "CreatedTimestamp": "timestamp", + "DeduplicationScope": "queue", + "DelaySeconds": "0", + "FifoQueue": "true", + "FifoThroughputLimit": "perQueue", + "LastModifiedTimestamp": "timestamp", + "MaximumMessageSize": "1048576", + "MessageRetentionPeriod": "345600", + "QueueArn": "", + "ReceiveMessageWaitTimeSeconds": "0", + "SqsManagedSseEnabled": "true", + "VisibilityTimeout": "30" + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "updated_tags": { + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/sqs/resource_providers/test_aws_sqs_queue.py::test_update_fifo_queue_remove_all_properties_except_queuename": { + "recorded-date": "14-01-2026, 16:37:34", + "recorded-content": { + "updated_attributes": { + "Attributes": { + "ApproximateNumberOfMessages": "0", + "ApproximateNumberOfMessagesDelayed": "0", + "ApproximateNumberOfMessagesNotVisible": "0", + "ContentBasedDeduplication": "false", + "CreatedTimestamp": "timestamp", + "DeduplicationScope": "messageGroup", + "DelaySeconds": "0", + "FifoQueue": "true", + "FifoThroughputLimit": "perMessageGroupId", + "LastModifiedTimestamp": "timestamp", + "MaximumMessageSize": "262144", + "MessageRetentionPeriod": "345600", + "QueueArn": "", + "ReceiveMessageWaitTimeSeconds": "0", + "SqsManagedSseEnabled": "false", + "VisibilityTimeout": "30" + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "updated_tags": { + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + } +} diff --git a/tests/aws/services/sqs/resource_providers/test_aws_sqs_queue.validation.json b/tests/aws/services/sqs/resource_providers/test_aws_sqs_queue.validation.json new file mode 100644 index 0000000000000..aababcc20195c --- /dev/null +++ b/tests/aws/services/sqs/resource_providers/test_aws_sqs_queue.validation.json @@ -0,0 +1,101 @@ +{ + "tests/aws/services/sqs/resource_providers/test_aws_sqs_queue.py::test_create_fifo_queue_with_all_properties": { + "last_validated_date": "2025-12-18T22:10:29+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 45.37, + "teardown": 66.13, + "total": 111.5 + } + }, + "tests/aws/services/sqs/resource_providers/test_aws_sqs_queue.py::test_create_fifo_queue_with_required_properties": { + "last_validated_date": "2025-12-18T22:08:38+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 42.49, + "teardown": 34.51, + "total": 77.0 + } + }, + "tests/aws/services/sqs/resource_providers/test_aws_sqs_queue.py::test_create_standard_queue_with_all_properties": { + "last_validated_date": "2025-12-18T22:07:21+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 45.72, + "teardown": 66.09, + "total": 111.81 + } + }, + "tests/aws/services/sqs/resource_providers/test_aws_sqs_queue.py::test_create_standard_queue_with_required_properties": { + "last_validated_date": "2025-12-18T22:05:29+00:00", + "durations_in_seconds": { + "setup": 1.03, + "call": 43.56, + "teardown": 34.51, + "total": 79.1 + } + }, + "tests/aws/services/sqs/resource_providers/test_aws_sqs_queue.py::test_update_completely_remove_resource": { + "last_validated_date": "2025-12-18T22:20:56+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 87.4, + "teardown": 34.94, + "total": 122.34 + } + }, + "tests/aws/services/sqs/resource_providers/test_aws_sqs_queue.py::test_update_fifo_queue_remove_all_properties": { + "last_validated_date": "2026-01-14T16:35:25+00:00", + "durations_in_seconds": { + "setup": 0.97, + "call": 153.78, + "teardown": 35.22, + "total": 189.97 + } + }, + "tests/aws/services/sqs/resource_providers/test_aws_sqs_queue.py::test_update_fifo_queue_remove_all_properties_except_queuename": { + "last_validated_date": "2026-01-14T16:38:10+00:00", + "durations_in_seconds": { + "setup": 1.11, + "call": 122.59, + "teardown": 35.1, + "total": 158.8 + } + }, + "tests/aws/services/sqs/resource_providers/test_aws_sqs_queue.py::test_update_standard_queue_add_properties_with_replacement": { + "last_validated_date": "2025-12-18T22:16:16+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 122.66, + "teardown": 66.53, + "total": 189.19 + } + }, + "tests/aws/services/sqs/resource_providers/test_aws_sqs_queue.py::test_update_standard_queue_modify_properties_in_place": { + "last_validated_date": "2025-12-18T22:13:07+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 91.09, + "teardown": 66.39, + "total": 157.48 + } + }, + "tests/aws/services/sqs/resource_providers/test_aws_sqs_queue.py::test_update_standard_queue_remove_some_properties": { + "last_validated_date": "2025-12-18T22:18:54+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 91.05, + "teardown": 66.57, + "total": 157.62 + } + }, + "tests/aws/services/sqs/resource_providers/test_aws_sqs_queue.py::test_update_standard_queue_without_explicit_name": { + "last_validated_date": "2025-12-18T22:22:58+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 86.74, + "teardown": 35.07, + "total": 121.81 + } + } +} diff --git a/tests/aws/services/sqs/resource_providers/test_aws_sqs_queueinlinepolicy.py b/tests/aws/services/sqs/resource_providers/test_aws_sqs_queueinlinepolicy.py new file mode 100644 index 0000000000000..2a2b8f778bf3a --- /dev/null +++ b/tests/aws/services/sqs/resource_providers/test_aws_sqs_queueinlinepolicy.py @@ -0,0 +1,70 @@ +import os + +from localstack.testing.pytest import markers + + +def deploy_stack(deploy_cfn_template, template_filename, **kwargs): + """ + Helper function to deploy a CloudFormation stack using a template file. This exists to reduce + boilerplate in the test cases. + """ + template_path = os.path.join(os.path.dirname(__file__), "templates", template_filename) + return deploy_cfn_template(template_path=template_path, **kwargs) + + +@markers.aws.validated +def test_create_sqs_with_inlinepolicy(deploy_cfn_template, aws_client, snapshot): + stack = deploy_stack(deploy_cfn_template, "sqs_with_queueinlinepolicy.yml") + queue_url = stack.outputs["QueueUrl"] + + snapshot.match( + "policy", aws_client.sqs.get_queue_attributes(QueueUrl=queue_url, AttributeNames=["Policy"]) + ) + snapshot.add_transformer(snapshot.transform.key_value("Resource")) + + +@markers.aws.validated +def test_update_sqs_with_inlinepolicy(deploy_cfn_template, aws_client, snapshot): + stack = deploy_stack(deploy_cfn_template, "sqs_with_queueinlinepolicy.yml") + queue_url = stack.outputs["QueueUrl"] + + snapshot.match( + "policy_before", + aws_client.sqs.get_queue_attributes(QueueUrl=queue_url, AttributeNames=["Policy"]), + ) + + deploy_stack( + deploy_cfn_template, + "sqs_with_queueinlinepolicy_variant_1.yml", + is_update=True, + stack_name=stack.stack_name, + ) + snapshot.match( + "policy_after", + aws_client.sqs.get_queue_attributes(QueueUrl=queue_url, AttributeNames=["Policy"]), + ) + snapshot.add_transformer(snapshot.transform.key_value("Resource")) + + +@markers.aws.validated +def test_update_sqs_remove_inlinepolicy(deploy_cfn_template, aws_client, snapshot): + stack = deploy_stack(deploy_cfn_template, "sqs_with_queueinlinepolicy.yml") + queue_url = stack.outputs["QueueUrl"] + + snapshot.match( + "policy_before", + aws_client.sqs.get_queue_attributes(QueueUrl=queue_url, AttributeNames=["Policy"]), + ) + + deploy_stack( + deploy_cfn_template, + "sqs_without_queueinlinepolicy.yml", + is_update=True, + stack_name=stack.stack_name, + ) + + snapshot.match( + "policy_after", + aws_client.sqs.get_queue_attributes(QueueUrl=queue_url, AttributeNames=["Policy"]), + ) + snapshot.add_transformer(snapshot.transform.key_value("Resource")) diff --git a/tests/aws/services/sqs/resource_providers/test_aws_sqs_queueinlinepolicy.snapshot.json b/tests/aws/services/sqs/resource_providers/test_aws_sqs_queueinlinepolicy.snapshot.json new file mode 100644 index 0000000000000..c2d2b26eb96ea --- /dev/null +++ b/tests/aws/services/sqs/resource_providers/test_aws_sqs_queueinlinepolicy.snapshot.json @@ -0,0 +1,117 @@ +{ + "tests/aws/services/sqs/resource_providers/test_aws_sqs_queueinlinepolicy.py::test_create_sqs_with_inlinepolicy": { + "recorded-date": "18-12-2025, 22:24:13", + "recorded-content": { + "policy": { + "Attributes": { + "Policy": { + "Version": "2012-10-17", + "Statement": [ + { + "Effect": "Allow", + "Principal": "*", + "Action": [ + "sqs:SendMessage", + "sqs:GetQueueAttributes", + "sqs:GetQueueUrl" + ], + "Resource": "" + } + ] + } + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/sqs/resource_providers/test_aws_sqs_queueinlinepolicy.py::test_update_sqs_with_inlinepolicy": { + "recorded-date": "18-12-2025, 22:28:18", + "recorded-content": { + "policy_before": { + "Attributes": { + "Policy": { + "Version": "2012-10-17", + "Statement": [ + { + "Effect": "Allow", + "Principal": "*", + "Action": [ + "sqs:SendMessage", + "sqs:GetQueueAttributes", + "sqs:GetQueueUrl" + ], + "Resource": "" + } + ] + } + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "policy_after": { + "Attributes": { + "Policy": { + "Version": "2012-10-17", + "Statement": [ + { + "Effect": "Allow", + "Principal": "*", + "Action": [ + "sqs:SendMessage", + "sqs:GetQueueAttributes", + "sqs:GetQueueUrl", + "sqs:DeleteMessage", + "sqs:ReceiveMessage" + ], + "Resource": "" + } + ] + } + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/sqs/resource_providers/test_aws_sqs_queueinlinepolicy.py::test_update_sqs_remove_inlinepolicy": { + "recorded-date": "18-12-2025, 22:32:22", + "recorded-content": { + "policy_before": { + "Attributes": { + "Policy": { + "Version": "2012-10-17", + "Statement": [ + { + "Effect": "Allow", + "Principal": "*", + "Action": [ + "sqs:SendMessage", + "sqs:GetQueueAttributes", + "sqs:GetQueueUrl" + ], + "Resource": "" + } + ] + } + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "policy_after": { + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + } +} diff --git a/tests/aws/services/sqs/resource_providers/test_aws_sqs_queueinlinepolicy.validation.json b/tests/aws/services/sqs/resource_providers/test_aws_sqs_queueinlinepolicy.validation.json new file mode 100644 index 0000000000000..c5edb3324071d --- /dev/null +++ b/tests/aws/services/sqs/resource_providers/test_aws_sqs_queueinlinepolicy.validation.json @@ -0,0 +1,29 @@ +{ + "tests/aws/services/sqs/resource_providers/test_aws_sqs_queueinlinepolicy.py::test_create_sqs_with_inlinepolicy": { + "last_validated_date": "2025-12-18T22:25:49+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 75.28, + "teardown": 95.53, + "total": 170.81 + } + }, + "tests/aws/services/sqs/resource_providers/test_aws_sqs_queueinlinepolicy.py::test_update_sqs_remove_inlinepolicy": { + "last_validated_date": "2025-12-18T22:32:57+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 148.04, + "teardown": 35.02, + "total": 183.06 + } + }, + "tests/aws/services/sqs/resource_providers/test_aws_sqs_queueinlinepolicy.py::test_update_sqs_with_inlinepolicy": { + "last_validated_date": "2025-12-18T22:29:54+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 149.31, + "teardown": 95.73, + "total": 245.04 + } + } +} diff --git a/tests/aws/services/sqs/resource_providers/test_aws_sqs_queuepolicy.py b/tests/aws/services/sqs/resource_providers/test_aws_sqs_queuepolicy.py new file mode 100644 index 0000000000000..d89c274872123 --- /dev/null +++ b/tests/aws/services/sqs/resource_providers/test_aws_sqs_queuepolicy.py @@ -0,0 +1,149 @@ +import os + +from localstack.testing.pytest import markers + + +def deploy_stack(deploy_cfn_template, template_filename, **kwargs): + """ + Helper function to deploy a CloudFormation stack using a template file. This exists to reduce + boilerplate in the test cases. + """ + template_path = os.path.join(os.path.dirname(__file__), "templates", template_filename) + return deploy_cfn_template(template_path=template_path, **kwargs) + + +@markers.aws.validated +def test_sqs_queue_policy(deploy_cfn_template, aws_client, snapshot): + result = deploy_stack(deploy_cfn_template, "sqs_with_queuepolicy.yml") + queue_url = result.outputs["Queue1Url"] + + snapshot.match( + "policy", aws_client.sqs.get_queue_attributes(QueueUrl=queue_url, AttributeNames=["Policy"]) + ) + snapshot.add_transformer(snapshot.transform.key_value("Resource")) + + +@markers.aws.validated +def test_update_sqs_queuepolicy(deploy_cfn_template, aws_client, snapshot): + stack = deploy_stack(deploy_cfn_template, "sqs_with_queuepolicy.yml") + policy = aws_client.sqs.get_queue_attributes( + QueueUrl=stack.outputs["Queue1Url"], AttributeNames=["Policy"] + ) + snapshot.match("policy1", policy["Attributes"]["Policy"]) + + updated_stack = deploy_stack( + deploy_cfn_template, + "sqs_with_queuepolicy_updated.yml", + is_update=True, + stack_name=stack.stack_name, + ) + + policy = aws_client.sqs.get_queue_attributes( + QueueUrl=updated_stack.outputs["Queue1Url"], AttributeNames=["Policy"] + ) + + snapshot.match("policy2", policy["Attributes"]["Policy"]) + snapshot.add_transformer(snapshot.transform.cloudformation_api()) + + +@markers.aws.validated +def test_update_add_two_additional_queues_to_policy(deploy_cfn_template, aws_client, snapshot): + stack = deploy_stack(deploy_cfn_template, "sqs_with_queuepolicy.yml") + queue_1_url = stack.outputs["Queue1Url"] + queue_2_url = stack.outputs["Queue2Url"] + queue_3_url = stack.outputs["Queue3Url"] + snapshot.match( + "queue_1_before", + aws_client.sqs.get_queue_attributes(QueueUrl=queue_1_url, AttributeNames=["Policy"]), + ) + snapshot.match( + "queue_2_before", + aws_client.sqs.get_queue_attributes(QueueUrl=queue_2_url, AttributeNames=["Policy"]), + ) + snapshot.match( + "queue_3_before", + aws_client.sqs.get_queue_attributes(QueueUrl=queue_3_url, AttributeNames=["Policy"]), + ) + + deploy_stack( + deploy_cfn_template, + "sqs_with_queuepolicy_for_3_queues.yml", + is_update=True, + stack_name=stack.stack_name, + ) + snapshot.match( + "queue_1_after", + aws_client.sqs.get_queue_attributes(QueueUrl=queue_1_url, AttributeNames=["Policy"]), + ) + snapshot.match( + "queue_2_after", + aws_client.sqs.get_queue_attributes(QueueUrl=queue_2_url, AttributeNames=["Policy"]), + ) + snapshot.match( + "queue_3_after", + aws_client.sqs.get_queue_attributes(QueueUrl=queue_3_url, AttributeNames=["Policy"]), + ) + snapshot.add_transformer(snapshot.transform.key_value("Resource")) + + +@markers.aws.validated +def test_update_remove_two_queues_from_policy(deploy_cfn_template, aws_client, snapshot): + stack = deploy_stack(deploy_cfn_template, "sqs_with_queuepolicy_for_3_queues.yml") + queue_1_url = stack.outputs["Queue1Url"] + queue_2_url = stack.outputs["Queue2Url"] + queue_3_url = stack.outputs["Queue3Url"] + snapshot.match( + "queue_1_before", + aws_client.sqs.get_queue_attributes(QueueUrl=queue_1_url, AttributeNames=["Policy"]), + ) + snapshot.match( + "queue_2_before", + aws_client.sqs.get_queue_attributes(QueueUrl=queue_2_url, AttributeNames=["Policy"]), + ) + snapshot.match( + "queue_3_before", + aws_client.sqs.get_queue_attributes(QueueUrl=queue_3_url, AttributeNames=["Policy"]), + ) + + deploy_stack( + deploy_cfn_template, + "sqs_with_queuepolicy.yml", + is_update=True, + stack_name=stack.stack_name, + ) + snapshot.match( + "queue_1_after", + aws_client.sqs.get_queue_attributes(QueueUrl=queue_1_url, AttributeNames=["Policy"]), + ) + snapshot.match( + "queue_2_after", + aws_client.sqs.get_queue_attributes(QueueUrl=queue_2_url, AttributeNames=["Policy"]), + ) + snapshot.match( + "queue_3_after", + aws_client.sqs.get_queue_attributes(QueueUrl=queue_3_url, AttributeNames=["Policy"]), + ) + snapshot.add_transformer(snapshot.transform.key_value("Resource")) + + +@markers.aws.validated +def test_update_to_remove_queuepolicy_from_template(deploy_cfn_template, aws_client, snapshot): + stack = deploy_stack(deploy_cfn_template, "sqs_with_queuepolicy.yml") + queue_url = stack.outputs["Queue1Url"] + snapshot.match( + "policy_before", + aws_client.sqs.get_queue_attributes(QueueUrl=queue_url, AttributeNames=["Policy"]), + ) + + deploy_stack( + deploy_cfn_template, + "sqs_without_queuepolicy.yml", + is_update=True, + stack_name=stack.stack_name, + ) + + snapshot.match( + "policy_after", + aws_client.sqs.get_queue_attributes(QueueUrl=queue_url, AttributeNames=["Policy"]), + ) + snapshot.add_transformer(snapshot.transform.key_value("Resource")) diff --git a/tests/aws/services/sqs/resource_providers/test_aws_sqs_queuepolicy.snapshot.json b/tests/aws/services/sqs/resource_providers/test_aws_sqs_queuepolicy.snapshot.json new file mode 100644 index 0000000000000..8d625e2742349 --- /dev/null +++ b/tests/aws/services/sqs/resource_providers/test_aws_sqs_queuepolicy.snapshot.json @@ -0,0 +1,324 @@ +{ + "tests/aws/services/sqs/resource_providers/test_aws_sqs_queuepolicy.py::test_sqs_queue_policy": { + "recorded-date": "18-12-2025, 22:33:40", + "recorded-content": { + "policy": { + "Attributes": { + "Policy": { + "Version": "2012-10-17", + "Statement": [ + { + "Effect": "Allow", + "Principal": "*", + "Action": [ + "sqs:SendMessage", + "sqs:GetQueueAttributes", + "sqs:GetQueueUrl" + ], + "Resource": "" + } + ] + } + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/sqs/resource_providers/test_aws_sqs_queuepolicy.py::test_update_sqs_queuepolicy": { + "recorded-date": "18-12-2025, 22:36:17", + "recorded-content": { + "policy1": { + "Version": "2012-10-17", + "Statement": [ + { + "Effect": "Allow", + "Principal": "*", + "Action": [ + "sqs:SendMessage", + "sqs:GetQueueAttributes", + "sqs:GetQueueUrl" + ], + "Resource": "arn::sqs::111111111111:" + } + ] + }, + "policy2": { + "Version": "2012-10-17", + "Statement": [ + { + "Effect": "Allow", + "Principal": "*", + "Action": [ + "sqs:SendMessage", + "sqs:GetQueueAttributes", + "sqs:GetQueueUrl", + "sqs:DeleteMessage" + ], + "Resource": "arn::sqs::111111111111:" + } + ] + } + } + }, + "tests/aws/services/sqs/resource_providers/test_aws_sqs_queuepolicy.py::test_update_add_two_additional_queues_to_policy": { + "recorded-date": "18-12-2025, 22:38:51", + "recorded-content": { + "queue_1_before": { + "Attributes": { + "Policy": { + "Version": "2012-10-17", + "Statement": [ + { + "Effect": "Allow", + "Principal": "*", + "Action": [ + "sqs:SendMessage", + "sqs:GetQueueAttributes", + "sqs:GetQueueUrl" + ], + "Resource": "" + } + ] + } + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "queue_2_before": { + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "queue_3_before": { + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "queue_1_after": { + "Attributes": { + "Policy": { + "Version": "2012-10-17", + "Statement": [ + { + "Effect": "Allow", + "Principal": "*", + "Action": [ + "sqs:SendMessage", + "sqs:GetQueueAttributes", + "sqs:GetQueueUrl", + "sqs:ChangeMessageVisibility" + ], + "Resource": "" + } + ] + } + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "queue_2_after": { + "Attributes": { + "Policy": { + "Version": "2012-10-17", + "Statement": [ + { + "Effect": "Allow", + "Principal": "*", + "Action": [ + "sqs:SendMessage", + "sqs:GetQueueAttributes", + "sqs:GetQueueUrl", + "sqs:ChangeMessageVisibility" + ], + "Resource": "" + } + ] + } + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "queue_3_after": { + "Attributes": { + "Policy": { + "Version": "2012-10-17", + "Statement": [ + { + "Effect": "Allow", + "Principal": "*", + "Action": [ + "sqs:SendMessage", + "sqs:GetQueueAttributes", + "sqs:GetQueueUrl", + "sqs:ChangeMessageVisibility" + ], + "Resource": "" + } + ] + } + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/sqs/resource_providers/test_aws_sqs_queuepolicy.py::test_update_remove_two_queues_from_policy": { + "recorded-date": "18-12-2025, 22:41:27", + "recorded-content": { + "queue_1_before": { + "Attributes": { + "Policy": { + "Version": "2012-10-17", + "Statement": [ + { + "Effect": "Allow", + "Principal": "*", + "Action": [ + "sqs:SendMessage", + "sqs:GetQueueAttributes", + "sqs:GetQueueUrl", + "sqs:ChangeMessageVisibility" + ], + "Resource": "" + } + ] + } + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "queue_2_before": { + "Attributes": { + "Policy": { + "Version": "2012-10-17", + "Statement": [ + { + "Effect": "Allow", + "Principal": "*", + "Action": [ + "sqs:SendMessage", + "sqs:GetQueueAttributes", + "sqs:GetQueueUrl", + "sqs:ChangeMessageVisibility" + ], + "Resource": "" + } + ] + } + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "queue_3_before": { + "Attributes": { + "Policy": { + "Version": "2012-10-17", + "Statement": [ + { + "Effect": "Allow", + "Principal": "*", + "Action": [ + "sqs:SendMessage", + "sqs:GetQueueAttributes", + "sqs:GetQueueUrl", + "sqs:ChangeMessageVisibility" + ], + "Resource": "" + } + ] + } + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "queue_1_after": { + "Attributes": { + "Policy": { + "Version": "2012-10-17", + "Statement": [ + { + "Effect": "Allow", + "Principal": "*", + "Action": [ + "sqs:SendMessage", + "sqs:GetQueueAttributes", + "sqs:GetQueueUrl" + ], + "Resource": "" + } + ] + } + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "queue_2_after": { + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "queue_3_after": { + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/sqs/resource_providers/test_aws_sqs_queuepolicy.py::test_update_to_remove_queuepolicy_from_template": { + "recorded-date": "18-12-2025, 22:43:59", + "recorded-content": { + "policy_before": { + "Attributes": { + "Policy": { + "Version": "2012-10-17", + "Statement": [ + { + "Effect": "Allow", + "Principal": "*", + "Action": [ + "sqs:SendMessage", + "sqs:GetQueueAttributes", + "sqs:GetQueueUrl" + ], + "Resource": "" + } + ] + } + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "policy_after": { + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + } +} diff --git a/tests/aws/services/sqs/resource_providers/test_aws_sqs_queuepolicy.validation.json b/tests/aws/services/sqs/resource_providers/test_aws_sqs_queuepolicy.validation.json new file mode 100644 index 0000000000000..1c2e7d317b5a1 --- /dev/null +++ b/tests/aws/services/sqs/resource_providers/test_aws_sqs_queuepolicy.validation.json @@ -0,0 +1,38 @@ +{ + "tests/aws/services/sqs/resource_providers/test_aws_sqs_queuepolicy.py::test_sqs_queue_policy": { + "last_validated_date": "2025-12-18T22:34:49+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 43.41, + "teardown": 68.6, + "total": 112.01 + } + }, + "tests/aws/services/sqs/resource_providers/test_aws_sqs_queuepolicy.py::test_update_add_two_additional_queues_to_policy": { + "last_validated_date": "2025-12-18T22:39:59+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 87.32, + "teardown": 67.71, + "total": 155.03 + } + }, + "tests/aws/services/sqs/resource_providers/test_aws_sqs_queuepolicy.py::test_update_remove_two_queues_from_policy": { + "last_validated_date": "2025-12-18T22:42:34+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 87.92, + "teardown": 66.76, + "total": 154.68 + } + }, + "tests/aws/services/sqs/resource_providers/test_aws_sqs_queuepolicy.py::test_update_sqs_queuepolicy": { + "last_validated_date": "2025-12-18T22:37:24+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 87.64, + "teardown": 67.44, + "total": 155.08 + } + } +} diff --git a/tests/aws/services/sqs/test_sqs.py b/tests/aws/services/sqs/test_sqs.py index 3550246595946..1d97b003db4d0 100644 --- a/tests/aws/services/sqs/test_sqs.py +++ b/tests/aws/services/sqs/test_sqs.py @@ -82,6 +82,7 @@ def aws_sqs_client(aws_client, request: str) -> "SQSClient": class TestSqsProvider: + @markers.requires_in_process @markers.aws.only_localstack def test_get_queue_url_contains_localstack_host( self, @@ -228,6 +229,7 @@ def test_create_queue_recently_deleted(self, sqs_create_queue, monkeypatch, aws_ "You must wait 60 seconds after deleting a queue before you can create another with the same name." ) + @markers.requires_in_process @markers.aws.only_localstack def test_create_queue_recently_deleted_cache( self, @@ -1276,6 +1278,40 @@ def test_fifo_delete_after_visibility_timeout(self, sqs_create_queue, aws_sqs_cl aws_sqs_client.delete_message(QueueUrl=queue_url, ReceiptHandle=receipt_handle) snapshot.match("delete_after_timeout_fifo", e.value.response) + @markers.aws.validated + def test_fifo_delete_after_visibility_timeout_extended( + self, sqs_create_queue, aws_sqs_client, snapshot + ): + timeout = 1 + queue_url = sqs_create_queue( + QueueName=f"test-{short_uid()}.fifo", + Attributes={ + "VisibilityTimeout": f"{timeout}", + "FifoQueue": "True", + "ContentBasedDeduplication": "True", + }, + ) + + aws_sqs_client.send_message(QueueUrl=queue_url, MessageBody="foobar", MessageGroupId="1") + # receive the message + initial_receive = aws_sqs_client.receive_message(QueueUrl=queue_url, WaitTimeSeconds=5) + snapshot.match("received_sqs_message", initial_receive) + receipt_handle = initial_receive["Messages"][0]["ReceiptHandle"] + + # extend the visibility timeout window + aws_sqs_client.change_message_visibility( + QueueUrl=queue_url, ReceiptHandle=receipt_handle, VisibilityTimeout=5 + ) + + # exceed the original visibility timeout window but not the extended one + time.sleep(timeout + 0.5) + aws_sqs_client.delete_message(QueueUrl=queue_url, ReceiptHandle=receipt_handle) + + snapshot.match( + "delete_after_timeout_fifo_extended", + aws_sqs_client.receive_message(QueueUrl=queue_url), + ) + @markers.aws.validated def test_receive_terminate_visibility_timeout(self, sqs_queue, aws_sqs_client): queue_url = sqs_queue @@ -1608,6 +1644,7 @@ def collect_messages(): bodies = {message["Body"] for message in messages} assert bodies == {"0", "1", "2", "3", "4", "5", "6", "7", "8"} + @markers.requires_in_process @markers.aws.only_localstack def test_external_endpoint(self, monkeypatch, sqs_create_queue, aws_sqs_client): external_host = "external-host" @@ -1628,6 +1665,7 @@ def test_external_endpoint(self, monkeypatch, sqs_create_queue, aws_sqs_client): receive_result = aws_sqs_client.receive_message(QueueUrl=queue_url) assert receive_result["Messages"][0]["Body"] == message_body + @markers.requires_in_process @markers.aws.only_localstack def test_external_hostname_via_host_header(self, monkeypatch, sqs_create_queue, region_name): """test making a request with a different external hostname/port being returned""" @@ -2071,6 +2109,69 @@ def test_fifo_message_group_visibility_after_change_message_visibility( assert response["Messages"][1]["Body"] == "g1-m1" assert len(response["Messages"]) == 2 + @pytest.mark.parametrize( + "message_position", [0, 1, 2], ids=["0-visible", "1-visible", "2-visible"] + ) + @markers.aws.validated + def test_fifo_group_visibility_extends_with_change_message_visibility( + self, sqs_create_queue, aws_sqs_client, snapshot, message_position + ): + initial_visibility_timeout = 1 + extended_visibility_timeout = 4 + queue_name = f"test-queue-{short_uid()}.fifo" + queue_url = sqs_create_queue( + QueueName=queue_name, + Attributes={ + "FifoQueue": "true", + "VisibilityTimeout": f"{initial_visibility_timeout}", + }, + ) + + # Send 3 messages + aws_sqs_client.send_message( + QueueUrl=queue_url, + MessageBody="foo", + MessageGroupId="1", + MessageDeduplicationId="foo", + ) + aws_sqs_client.send_message( + QueueUrl=queue_url, + MessageBody="bar", + MessageGroupId="1", + MessageDeduplicationId="bar", + ) + aws_sqs_client.send_message( + QueueUrl=queue_url, + MessageBody="baz", + MessageGroupId="1", + MessageDeduplicationId="baz", + ) + + # Receive all messages + response = aws_sqs_client.receive_message(QueueUrl=queue_url, MaxNumberOfMessages=5) + + # We should have received all 3 messages from the group + snapshot.match("receive_all_messages", response) + + receipt_handle = response["Messages"][message_position]["ReceiptHandle"] + # extend visibility timeout of one message + aws_sqs_client.change_message_visibility( + QueueUrl=queue_url, + ReceiptHandle=receipt_handle, + VisibilityTimeout=extended_visibility_timeout, + ) + + # Wait until the other 2 message become visible again, but the extended message is still invisible + time.sleep( + initial_visibility_timeout + + (extended_visibility_timeout - initial_visibility_timeout) / 2 + ) + + response = aws_sqs_client.receive_message(QueueUrl=queue_url, MaxNumberOfMessages=5) + + # The extended message and all messages within the same group that come after it are invisible. + snapshot.match("some-messages-invisible", response) + @markers.aws.validated def test_fifo_message_group_visibility_after_delete(self, sqs_create_queue, aws_sqs_client): queue_url = sqs_create_queue( @@ -3935,8 +4036,10 @@ def test_dead_letter_queue_execution_lambda_mapping_preserves_id( else: timeout = 15.0 assert poll_condition( - lambda: "Messages" - in aws_sqs_client.receive_message(QueueUrl=dl_queue_url, VisibilityTimeout=0), + lambda: ( + "Messages" + in aws_sqs_client.receive_message(QueueUrl=dl_queue_url, VisibilityTimeout=0) + ), timeout, 1.0, ) @@ -4088,6 +4191,7 @@ def test_remove_message_with_old_receipt_handle(self, sqs_create_queue, aws_sqs_ ) assert int(approx_nr_of_messages["Attributes"]["ApproximateNumberOfMessages"]) == 0 + @markers.requires_in_process @markers.aws.only_localstack def test_list_queues_multi_region_without_endpoint_strategy( self, aws_client_factory, cleanups, monkeypatch @@ -4546,6 +4650,29 @@ def test_sse_queue_attributes(self, sqs_create_queue, snapshot, aws_sqs_client): ) snapshot.match("sse_sqs_attributes", response) + @markers.aws.validated + @markers.snapshot.skip_snapshot_verify(paths=["$..Attributes.SqsManagedSseEnabled"]) + def test_set_queue_attributes_default_values(self, sqs_create_queue, snapshot, aws_sqs_client): + queue_url = sqs_create_queue() + response = aws_sqs_client.get_queue_attributes(QueueUrl=queue_url, AttributeNames=["All"]) + snapshot.match("get-queue-attributes-initial-values", response) + + updated_attributes = { + "KmsMasterKeyId": "testKeyId", + "KmsDataKeyReusePeriodSeconds": "6000", + } + aws_sqs_client.set_queue_attributes(QueueUrl=queue_url, Attributes=updated_attributes) + response = aws_sqs_client.get_queue_attributes(QueueUrl=queue_url, AttributeNames=["All"]) + snapshot.match("get-queue-attributes-after-update", response) + + default_attributes = { + "KmsMasterKeyId": "", + "KmsDataKeyReusePeriodSeconds": "300", + } + aws_sqs_client.set_queue_attributes(QueueUrl=queue_url, Attributes=default_attributes) + response = aws_sqs_client.get_queue_attributes(QueueUrl=queue_url, AttributeNames=["All"]) + snapshot.match("get-queue-attributes-after-set-to-defaults", response) + @pytest.mark.skip(reason="validation currently not implemented in localstack") @markers.aws.validated def test_sse_kms_and_sqs_are_mutually_exclusive( @@ -5291,6 +5418,7 @@ def test_endpoint_strategy_with_multi_region( assert response.ok assert "foobar" in response.text + @markers.requires_in_process @markers.aws.only_localstack def test_queue_url_format_path_strategy( self, sqs_create_queue, account_id, region_name, monkeypatch diff --git a/tests/aws/services/sqs/test_sqs.snapshot.json b/tests/aws/services/sqs/test_sqs.snapshot.json index 59b4b256f7276..cbf0839eaf311 100644 --- a/tests/aws/services/sqs/test_sqs.snapshot.json +++ b/tests/aws/services/sqs/test_sqs.snapshot.json @@ -4219,5 +4219,721 @@ "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_fifo_approximate_number_of_messages_not_visible[sqs_query]": { "recorded-date": "25-09-2025, 21:54:43", "recorded-content": {} + }, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_fifo_delete_after_visibility_timeout_extended[sqs]": { + "recorded-date": "05-10-2025, 14:42:35", + "recorded-content": { + "received_sqs_message": { + "Messages": [ + { + "Body": "foobar", + "MD5OfBody": "3858f62230ac3c915f300c664312c63f", + "MessageId": "", + "ReceiptHandle": "" + } + ], + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "delete_after_timeout_fifo_extended": { + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_fifo_delete_after_visibility_timeout_extended[sqs_query]": { + "recorded-date": "05-10-2025, 14:42:37", + "recorded-content": { + "received_sqs_message": { + "Messages": [ + { + "Body": "foobar", + "MD5OfBody": "3858f62230ac3c915f300c664312c63f", + "MessageId": "", + "ReceiptHandle": "" + } + ], + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "delete_after_timeout_fifo_extended": { + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_fifo_group_visibility_extends_with_change_message_visibility[sqs-all-invisible]": { + "recorded-date": "19-11-2025, 10:45:24", + "recorded-content": { + "receive_all_messages": { + "Messages": [ + { + "Body": "foo", + "MD5OfBody": "acbd18db4cc2f85cedef654fccc4a4d8", + "MessageId": "", + "ReceiptHandle": "" + }, + { + "Body": "bar", + "MD5OfBody": "37b51d194a7513e45b56f6524f2d51f2", + "MessageId": "", + "ReceiptHandle": "" + }, + { + "Body": "baz", + "MD5OfBody": "73feffa4b7f6bb68e44cf984c85f6e88", + "MessageId": "", + "ReceiptHandle": "" + } + ], + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "some-messages-invisible": { + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_fifo_group_visibility_extends_with_change_message_visibility[sqs-1-invisible]": { + "recorded-date": "19-11-2025, 10:45:27", + "recorded-content": { + "receive_all_messages": { + "Messages": [ + { + "Body": "foo", + "MD5OfBody": "acbd18db4cc2f85cedef654fccc4a4d8", + "MessageId": "", + "ReceiptHandle": "" + }, + { + "Body": "bar", + "MD5OfBody": "37b51d194a7513e45b56f6524f2d51f2", + "MessageId": "", + "ReceiptHandle": "" + }, + { + "Body": "baz", + "MD5OfBody": "73feffa4b7f6bb68e44cf984c85f6e88", + "MessageId": "", + "ReceiptHandle": "" + } + ], + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "some-messages-invisible": { + "Messages": [ + { + "Body": "foo", + "MD5OfBody": "acbd18db4cc2f85cedef654fccc4a4d8", + "MessageId": "", + "ReceiptHandle": "" + } + ], + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_fifo_group_visibility_extends_with_change_message_visibility[sqs-no-invisible]": { + "recorded-date": "19-11-2025, 10:45:30", + "recorded-content": { + "receive_all_messages": { + "Messages": [ + { + "Body": "foo", + "MD5OfBody": "acbd18db4cc2f85cedef654fccc4a4d8", + "MessageId": "", + "ReceiptHandle": "" + }, + { + "Body": "bar", + "MD5OfBody": "37b51d194a7513e45b56f6524f2d51f2", + "MessageId": "", + "ReceiptHandle": "" + }, + { + "Body": "baz", + "MD5OfBody": "73feffa4b7f6bb68e44cf984c85f6e88", + "MessageId": "", + "ReceiptHandle": "" + } + ], + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "some-messages-invisible": { + "Messages": [ + { + "Body": "foo", + "MD5OfBody": "acbd18db4cc2f85cedef654fccc4a4d8", + "MessageId": "", + "ReceiptHandle": "" + }, + { + "Body": "bar", + "MD5OfBody": "37b51d194a7513e45b56f6524f2d51f2", + "MessageId": "", + "ReceiptHandle": "" + } + ], + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_fifo_group_visibility_extends_with_change_message_visibility[sqs_query-all-invisible]": { + "recorded-date": "19-11-2025, 10:45:34", + "recorded-content": { + "receive_all_messages": { + "Messages": [ + { + "Body": "foo", + "MD5OfBody": "acbd18db4cc2f85cedef654fccc4a4d8", + "MessageId": "", + "ReceiptHandle": "" + }, + { + "Body": "bar", + "MD5OfBody": "37b51d194a7513e45b56f6524f2d51f2", + "MessageId": "", + "ReceiptHandle": "" + }, + { + "Body": "baz", + "MD5OfBody": "73feffa4b7f6bb68e44cf984c85f6e88", + "MessageId": "", + "ReceiptHandle": "" + } + ], + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "some-messages-invisible": { + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_fifo_group_visibility_extends_with_change_message_visibility[sqs_query-1-invisible]": { + "recorded-date": "19-11-2025, 10:45:37", + "recorded-content": { + "receive_all_messages": { + "Messages": [ + { + "Body": "foo", + "MD5OfBody": "acbd18db4cc2f85cedef654fccc4a4d8", + "MessageId": "", + "ReceiptHandle": "" + }, + { + "Body": "bar", + "MD5OfBody": "37b51d194a7513e45b56f6524f2d51f2", + "MessageId": "", + "ReceiptHandle": "" + }, + { + "Body": "baz", + "MD5OfBody": "73feffa4b7f6bb68e44cf984c85f6e88", + "MessageId": "", + "ReceiptHandle": "" + } + ], + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "some-messages-invisible": { + "Messages": [ + { + "Body": "foo", + "MD5OfBody": "acbd18db4cc2f85cedef654fccc4a4d8", + "MessageId": "", + "ReceiptHandle": "" + } + ], + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_fifo_group_visibility_extends_with_change_message_visibility[sqs_query-no-invisible]": { + "recorded-date": "19-11-2025, 10:45:40", + "recorded-content": { + "receive_all_messages": { + "Messages": [ + { + "Body": "foo", + "MD5OfBody": "acbd18db4cc2f85cedef654fccc4a4d8", + "MessageId": "", + "ReceiptHandle": "" + }, + { + "Body": "bar", + "MD5OfBody": "37b51d194a7513e45b56f6524f2d51f2", + "MessageId": "", + "ReceiptHandle": "" + }, + { + "Body": "baz", + "MD5OfBody": "73feffa4b7f6bb68e44cf984c85f6e88", + "MessageId": "", + "ReceiptHandle": "" + } + ], + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "some-messages-invisible": { + "Messages": [ + { + "Body": "foo", + "MD5OfBody": "acbd18db4cc2f85cedef654fccc4a4d8", + "MessageId": "", + "ReceiptHandle": "" + }, + { + "Body": "bar", + "MD5OfBody": "37b51d194a7513e45b56f6524f2d51f2", + "MessageId": "", + "ReceiptHandle": "" + } + ], + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_fifo_group_visibility_extends_with_change_message_visibility[sqs-0-visible]": { + "recorded-date": "19-11-2025, 10:47:45", + "recorded-content": { + "receive_all_messages": { + "Messages": [ + { + "Body": "foo", + "MD5OfBody": "acbd18db4cc2f85cedef654fccc4a4d8", + "MessageId": "", + "ReceiptHandle": "" + }, + { + "Body": "bar", + "MD5OfBody": "37b51d194a7513e45b56f6524f2d51f2", + "MessageId": "", + "ReceiptHandle": "" + }, + { + "Body": "baz", + "MD5OfBody": "73feffa4b7f6bb68e44cf984c85f6e88", + "MessageId": "", + "ReceiptHandle": "" + } + ], + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "some-messages-invisible": { + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_fifo_group_visibility_extends_with_change_message_visibility[sqs-1-visible]": { + "recorded-date": "19-11-2025, 10:47:48", + "recorded-content": { + "receive_all_messages": { + "Messages": [ + { + "Body": "foo", + "MD5OfBody": "acbd18db4cc2f85cedef654fccc4a4d8", + "MessageId": "", + "ReceiptHandle": "" + }, + { + "Body": "bar", + "MD5OfBody": "37b51d194a7513e45b56f6524f2d51f2", + "MessageId": "", + "ReceiptHandle": "" + }, + { + "Body": "baz", + "MD5OfBody": "73feffa4b7f6bb68e44cf984c85f6e88", + "MessageId": "", + "ReceiptHandle": "" + } + ], + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "some-messages-invisible": { + "Messages": [ + { + "Body": "foo", + "MD5OfBody": "acbd18db4cc2f85cedef654fccc4a4d8", + "MessageId": "", + "ReceiptHandle": "" + } + ], + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_fifo_group_visibility_extends_with_change_message_visibility[sqs-2-visible]": { + "recorded-date": "19-11-2025, 10:47:51", + "recorded-content": { + "receive_all_messages": { + "Messages": [ + { + "Body": "foo", + "MD5OfBody": "acbd18db4cc2f85cedef654fccc4a4d8", + "MessageId": "", + "ReceiptHandle": "" + }, + { + "Body": "bar", + "MD5OfBody": "37b51d194a7513e45b56f6524f2d51f2", + "MessageId": "", + "ReceiptHandle": "" + }, + { + "Body": "baz", + "MD5OfBody": "73feffa4b7f6bb68e44cf984c85f6e88", + "MessageId": "", + "ReceiptHandle": "" + } + ], + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "some-messages-invisible": { + "Messages": [ + { + "Body": "foo", + "MD5OfBody": "acbd18db4cc2f85cedef654fccc4a4d8", + "MessageId": "", + "ReceiptHandle": "" + }, + { + "Body": "bar", + "MD5OfBody": "37b51d194a7513e45b56f6524f2d51f2", + "MessageId": "", + "ReceiptHandle": "" + } + ], + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_fifo_group_visibility_extends_with_change_message_visibility[sqs_query-0-visible]": { + "recorded-date": "19-11-2025, 10:47:55", + "recorded-content": { + "receive_all_messages": { + "Messages": [ + { + "Body": "foo", + "MD5OfBody": "acbd18db4cc2f85cedef654fccc4a4d8", + "MessageId": "", + "ReceiptHandle": "" + }, + { + "Body": "bar", + "MD5OfBody": "37b51d194a7513e45b56f6524f2d51f2", + "MessageId": "", + "ReceiptHandle": "" + }, + { + "Body": "baz", + "MD5OfBody": "73feffa4b7f6bb68e44cf984c85f6e88", + "MessageId": "", + "ReceiptHandle": "" + } + ], + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "some-messages-invisible": { + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_fifo_group_visibility_extends_with_change_message_visibility[sqs_query-1-visible]": { + "recorded-date": "19-11-2025, 10:47:58", + "recorded-content": { + "receive_all_messages": { + "Messages": [ + { + "Body": "foo", + "MD5OfBody": "acbd18db4cc2f85cedef654fccc4a4d8", + "MessageId": "", + "ReceiptHandle": "" + }, + { + "Body": "bar", + "MD5OfBody": "37b51d194a7513e45b56f6524f2d51f2", + "MessageId": "", + "ReceiptHandle": "" + }, + { + "Body": "baz", + "MD5OfBody": "73feffa4b7f6bb68e44cf984c85f6e88", + "MessageId": "", + "ReceiptHandle": "" + } + ], + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "some-messages-invisible": { + "Messages": [ + { + "Body": "foo", + "MD5OfBody": "acbd18db4cc2f85cedef654fccc4a4d8", + "MessageId": "", + "ReceiptHandle": "" + } + ], + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_fifo_group_visibility_extends_with_change_message_visibility[sqs_query-2-visible]": { + "recorded-date": "19-11-2025, 10:48:01", + "recorded-content": { + "receive_all_messages": { + "Messages": [ + { + "Body": "foo", + "MD5OfBody": "acbd18db4cc2f85cedef654fccc4a4d8", + "MessageId": "", + "ReceiptHandle": "" + }, + { + "Body": "bar", + "MD5OfBody": "37b51d194a7513e45b56f6524f2d51f2", + "MessageId": "", + "ReceiptHandle": "" + }, + { + "Body": "baz", + "MD5OfBody": "73feffa4b7f6bb68e44cf984c85f6e88", + "MessageId": "", + "ReceiptHandle": "" + } + ], + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "some-messages-invisible": { + "Messages": [ + { + "Body": "foo", + "MD5OfBody": "acbd18db4cc2f85cedef654fccc4a4d8", + "MessageId": "", + "ReceiptHandle": "" + }, + { + "Body": "bar", + "MD5OfBody": "37b51d194a7513e45b56f6524f2d51f2", + "MessageId": "", + "ReceiptHandle": "" + } + ], + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_set_queue_attributes_default_values[sqs]": { + "recorded-date": "10-12-2025, 18:38:55", + "recorded-content": { + "get-queue-attributes-initial-values": { + "Attributes": { + "ApproximateNumberOfMessages": "0", + "ApproximateNumberOfMessagesDelayed": "0", + "ApproximateNumberOfMessagesNotVisible": "0", + "CreatedTimestamp": "timestamp", + "DelaySeconds": "0", + "LastModifiedTimestamp": "timestamp", + "MaximumMessageSize": "1048576", + "MessageRetentionPeriod": "345600", + "QueueArn": "arn::sqs::111111111111:", + "ReceiveMessageWaitTimeSeconds": "0", + "SqsManagedSseEnabled": "true", + "VisibilityTimeout": "30" + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "get-queue-attributes-after-update": { + "Attributes": { + "ApproximateNumberOfMessages": "0", + "ApproximateNumberOfMessagesDelayed": "0", + "ApproximateNumberOfMessagesNotVisible": "0", + "CreatedTimestamp": "timestamp", + "DelaySeconds": "0", + "KmsDataKeyReusePeriodSeconds": "6000", + "KmsMasterKeyId": "testKeyId", + "LastModifiedTimestamp": "timestamp", + "MaximumMessageSize": "1048576", + "MessageRetentionPeriod": "345600", + "QueueArn": "arn::sqs::111111111111:", + "ReceiveMessageWaitTimeSeconds": "0", + "SqsManagedSseEnabled": "false", + "VisibilityTimeout": "30" + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "get-queue-attributes-after-set-to-defaults": { + "Attributes": { + "ApproximateNumberOfMessages": "0", + "ApproximateNumberOfMessagesDelayed": "0", + "ApproximateNumberOfMessagesNotVisible": "0", + "CreatedTimestamp": "timestamp", + "DelaySeconds": "0", + "LastModifiedTimestamp": "timestamp", + "MaximumMessageSize": "1048576", + "MessageRetentionPeriod": "345600", + "QueueArn": "arn::sqs::111111111111:", + "ReceiveMessageWaitTimeSeconds": "0", + "SqsManagedSseEnabled": "false", + "VisibilityTimeout": "30" + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_set_queue_attributes_default_values[sqs_query]": { + "recorded-date": "10-12-2025, 18:38:57", + "recorded-content": { + "get-queue-attributes-initial-values": { + "Attributes": { + "ApproximateNumberOfMessages": "0", + "ApproximateNumberOfMessagesDelayed": "0", + "ApproximateNumberOfMessagesNotVisible": "0", + "CreatedTimestamp": "timestamp", + "DelaySeconds": "0", + "LastModifiedTimestamp": "timestamp", + "MaximumMessageSize": "1048576", + "MessageRetentionPeriod": "345600", + "QueueArn": "arn::sqs::111111111111:", + "ReceiveMessageWaitTimeSeconds": "0", + "SqsManagedSseEnabled": "true", + "VisibilityTimeout": "30" + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "get-queue-attributes-after-update": { + "Attributes": { + "ApproximateNumberOfMessages": "0", + "ApproximateNumberOfMessagesDelayed": "0", + "ApproximateNumberOfMessagesNotVisible": "0", + "CreatedTimestamp": "timestamp", + "DelaySeconds": "0", + "KmsDataKeyReusePeriodSeconds": "6000", + "KmsMasterKeyId": "testKeyId", + "LastModifiedTimestamp": "timestamp", + "MaximumMessageSize": "1048576", + "MessageRetentionPeriod": "345600", + "QueueArn": "arn::sqs::111111111111:", + "ReceiveMessageWaitTimeSeconds": "0", + "SqsManagedSseEnabled": "false", + "VisibilityTimeout": "30" + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "get-queue-attributes-after-set-to-defaults": { + "Attributes": { + "ApproximateNumberOfMessages": "0", + "ApproximateNumberOfMessagesDelayed": "0", + "ApproximateNumberOfMessagesNotVisible": "0", + "CreatedTimestamp": "timestamp", + "DelaySeconds": "0", + "LastModifiedTimestamp": "timestamp", + "MaximumMessageSize": "1048576", + "MessageRetentionPeriod": "345600", + "QueueArn": "arn::sqs::111111111111:", + "ReceiveMessageWaitTimeSeconds": "0", + "SqsManagedSseEnabled": "false", + "VisibilityTimeout": "30" + }, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } } } diff --git a/tests/aws/services/sqs/test_sqs.validation.json b/tests/aws/services/sqs/test_sqs.validation.json index 3b62f59b54ae3..c86ed337b2b42 100644 --- a/tests/aws/services/sqs/test_sqs.validation.json +++ b/tests/aws/services/sqs/test_sqs.validation.json @@ -248,12 +248,156 @@ "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_fifo_delete_after_visibility_timeout[sqs_query]": { "last_validated_date": "2025-03-28T13:37:13+00:00" }, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_fifo_delete_after_visibility_timeout_extended[sqs]": { + "last_validated_date": "2025-10-05T14:42:35+00:00", + "durations_in_seconds": { + "setup": 0.23, + "call": 2.01, + "teardown": 0.09, + "total": 2.33 + } + }, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_fifo_delete_after_visibility_timeout_extended[sqs_query]": { + "last_validated_date": "2025-10-05T14:42:37+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 2.0, + "teardown": 0.1, + "total": 2.1 + } + }, "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_fifo_empty_message_groups_added_back_to_queue[sqs]": { "last_validated_date": "2024-04-30T13:46:32+00:00" }, "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_fifo_empty_message_groups_added_back_to_queue[sqs_query]": { "last_validated_date": "2024-04-30T13:46:34+00:00" }, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_fifo_group_visibility_extends_with_change_message_visibility[sqs-0-visible]": { + "last_validated_date": "2025-11-19T10:47:45+00:00", + "durations_in_seconds": { + "setup": 1.24, + "call": 3.6, + "teardown": 0.24, + "total": 5.08 + } + }, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_fifo_group_visibility_extends_with_change_message_visibility[sqs-1-invisible]": { + "last_validated_date": "2025-11-19T10:45:27+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 2.76, + "teardown": 0.2, + "total": 2.96 + } + }, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_fifo_group_visibility_extends_with_change_message_visibility[sqs-1-visible]": { + "last_validated_date": "2025-11-19T10:47:48+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 2.87, + "teardown": 0.19, + "total": 3.06 + } + }, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_fifo_group_visibility_extends_with_change_message_visibility[sqs-2-visible]": { + "last_validated_date": "2025-11-19T10:47:51+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 2.77, + "teardown": 0.19, + "total": 2.96 + } + }, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_fifo_group_visibility_extends_with_change_message_visibility[sqs-all-invisible]": { + "last_validated_date": "2025-11-19T10:45:24+00:00", + "durations_in_seconds": { + "setup": 0.69, + "call": 3.4, + "teardown": 0.19, + "total": 4.28 + } + }, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_fifo_group_visibility_extends_with_change_message_visibility[sqs-no-invisible]": { + "last_validated_date": "2025-11-19T10:45:30+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 2.97, + "teardown": 0.19, + "total": 3.16 + } + }, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_fifo_group_visibility_extends_with_change_message_visibility[sqs]": { + "last_validated_date": "2025-11-18T13:34:41+00:00", + "durations_in_seconds": { + "setup": 0.9, + "call": 14.49, + "teardown": 0.28, + "total": 15.67 + } + }, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_fifo_group_visibility_extends_with_change_message_visibility[sqs_query-0-visible]": { + "last_validated_date": "2025-11-19T10:47:55+00:00", + "durations_in_seconds": { + "setup": 0.01, + "call": 3.34, + "teardown": 0.24, + "total": 3.59 + } + }, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_fifo_group_visibility_extends_with_change_message_visibility[sqs_query-1-invisible]": { + "last_validated_date": "2025-11-19T10:45:37+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 2.68, + "teardown": 0.18, + "total": 2.86 + } + }, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_fifo_group_visibility_extends_with_change_message_visibility[sqs_query-1-visible]": { + "last_validated_date": "2025-11-19T10:47:58+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 2.88, + "teardown": 0.19, + "total": 3.07 + } + }, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_fifo_group_visibility_extends_with_change_message_visibility[sqs_query-2-visible]": { + "last_validated_date": "2025-11-19T10:48:01+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 2.88, + "teardown": 0.19, + "total": 3.07 + } + }, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_fifo_group_visibility_extends_with_change_message_visibility[sqs_query-all-invisible]": { + "last_validated_date": "2025-11-19T10:45:34+00:00", + "durations_in_seconds": { + "setup": 0.01, + "call": 3.1, + "teardown": 0.18, + "total": 3.29 + } + }, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_fifo_group_visibility_extends_with_change_message_visibility[sqs_query-no-invisible]": { + "last_validated_date": "2025-11-19T10:45:40+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 2.87, + "teardown": 0.19, + "total": 3.06 + } + }, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_fifo_group_visibility_extends_with_change_message_visibility[sqs_query]": { + "last_validated_date": "2025-11-18T13:34:56+00:00", + "durations_in_seconds": { + "setup": 0.01, + "call": 14.52, + "teardown": 0.2, + "total": 14.73 + } + }, "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_fifo_high_throughput_ordering[sqs]": { "last_validated_date": "2024-04-30T13:34:27+00:00" }, @@ -266,6 +410,24 @@ "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_fifo_message_attributes[sqs_query]": { "last_validated_date": "2024-04-30T13:36:57+00:00" }, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_fifo_message_group_visibility_after_change_message_visibility[sqs]": { + "last_validated_date": "2025-11-17T08:55:04+00:00", + "durations_in_seconds": { + "setup": 1.26, + "call": 4.38, + "teardown": 0.3, + "total": 5.94 + } + }, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_fifo_message_group_visibility_after_change_message_visibility[sqs_query]": { + "last_validated_date": "2025-11-17T08:55:09+00:00", + "durations_in_seconds": { + "setup": 0.02, + "call": 4.77, + "teardown": 0.3, + "total": 5.09 + } + }, "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_fifo_queue_send_message_with_delay_seconds_fails[sqs]": { "last_validated_date": "2024-04-30T13:33:33+00:00" }, @@ -593,6 +755,24 @@ "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_set_empty_redrive_policy[sqs_query]": { "last_validated_date": "2024-08-20T14:14:11+00:00" }, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_set_queue_attributes_default_values[sqs]": { + "last_validated_date": "2025-12-10T18:38:55+00:00", + "durations_in_seconds": { + "setup": 2.41, + "call": 2.34, + "teardown": 0.29, + "total": 5.04 + } + }, + "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_set_queue_attributes_default_values[sqs_query]": { + "last_validated_date": "2025-12-10T18:38:57+00:00", + "durations_in_seconds": { + "setup": 0.01, + "call": 2.21, + "teardown": 0.3, + "total": 2.52 + } + }, "tests/aws/services/sqs/test_sqs.py::TestSqsProvider::test_set_unsupported_attribute_fifo[sqs]": { "last_validated_date": "2024-05-14T22:23:46+00:00" }, diff --git a/tests/aws/services/stepfunctions/mocked_service_integrations/mock_config_files/__init__.py b/tests/aws/services/stepfunctions/local_mocked_service_integrations/__init__.py similarity index 100% rename from tests/aws/services/stepfunctions/mocked_service_integrations/mock_config_files/__init__.py rename to tests/aws/services/stepfunctions/local_mocked_service_integrations/__init__.py diff --git a/tests/aws/services/stepfunctions/mocked_service_integrations/mocked_responses/__init__.py b/tests/aws/services/stepfunctions/local_mocked_service_integrations/mock_config_files/__init__.py similarity index 100% rename from tests/aws/services/stepfunctions/mocked_service_integrations/mocked_responses/__init__.py rename to tests/aws/services/stepfunctions/local_mocked_service_integrations/mock_config_files/__init__.py diff --git a/tests/aws/services/stepfunctions/mocked_service_integrations/mock_config_files/lambda_sqs_integration.json5 b/tests/aws/services/stepfunctions/local_mocked_service_integrations/mock_config_files/lambda_sqs_integration.json5 similarity index 100% rename from tests/aws/services/stepfunctions/mocked_service_integrations/mock_config_files/lambda_sqs_integration.json5 rename to tests/aws/services/stepfunctions/local_mocked_service_integrations/mock_config_files/lambda_sqs_integration.json5 diff --git a/tests/aws/services/stepfunctions/mocked_service_integrations/mocked_responses/callback/__init__.py b/tests/aws/services/stepfunctions/local_mocked_service_integrations/mocked_responses/__init__.py similarity index 100% rename from tests/aws/services/stepfunctions/mocked_service_integrations/mocked_responses/callback/__init__.py rename to tests/aws/services/stepfunctions/local_mocked_service_integrations/mocked_responses/__init__.py diff --git a/tests/aws/services/stepfunctions/mocked_service_integrations/mocked_responses/dynamodb/__init__.py b/tests/aws/services/stepfunctions/local_mocked_service_integrations/mocked_responses/callback/__init__.py similarity index 100% rename from tests/aws/services/stepfunctions/mocked_service_integrations/mocked_responses/dynamodb/__init__.py rename to tests/aws/services/stepfunctions/local_mocked_service_integrations/mocked_responses/callback/__init__.py diff --git a/tests/aws/services/stepfunctions/mocked_service_integrations/mocked_responses/callback/task_failure.json5 b/tests/aws/services/stepfunctions/local_mocked_service_integrations/mocked_responses/callback/task_failure.json5 similarity index 100% rename from tests/aws/services/stepfunctions/mocked_service_integrations/mocked_responses/callback/task_failure.json5 rename to tests/aws/services/stepfunctions/local_mocked_service_integrations/mocked_responses/callback/task_failure.json5 diff --git a/tests/aws/services/stepfunctions/mocked_service_integrations/mocked_responses/callback/task_success_string_literal.json5 b/tests/aws/services/stepfunctions/local_mocked_service_integrations/mocked_responses/callback/task_success_string_literal.json5 similarity index 100% rename from tests/aws/services/stepfunctions/mocked_service_integrations/mocked_responses/callback/task_success_string_literal.json5 rename to tests/aws/services/stepfunctions/local_mocked_service_integrations/mocked_responses/callback/task_success_string_literal.json5 diff --git a/tests/aws/services/stepfunctions/mocked_service_integrations/mocked_responses/dynamodb/200_get_item.json5 b/tests/aws/services/stepfunctions/local_mocked_service_integrations/mocked_responses/dynamodb/200_get_item.json5 similarity index 100% rename from tests/aws/services/stepfunctions/mocked_service_integrations/mocked_responses/dynamodb/200_get_item.json5 rename to tests/aws/services/stepfunctions/local_mocked_service_integrations/mocked_responses/dynamodb/200_get_item.json5 diff --git a/tests/aws/services/stepfunctions/mocked_service_integrations/mocked_responses/dynamodb/200_put_item.json5 b/tests/aws/services/stepfunctions/local_mocked_service_integrations/mocked_responses/dynamodb/200_put_item.json5 similarity index 100% rename from tests/aws/services/stepfunctions/mocked_service_integrations/mocked_responses/dynamodb/200_put_item.json5 rename to tests/aws/services/stepfunctions/local_mocked_service_integrations/mocked_responses/dynamodb/200_put_item.json5 diff --git a/tests/aws/services/stepfunctions/mocked_service_integrations/mocked_responses/events/__init__.py b/tests/aws/services/stepfunctions/local_mocked_service_integrations/mocked_responses/dynamodb/__init__.py similarity index 100% rename from tests/aws/services/stepfunctions/mocked_service_integrations/mocked_responses/events/__init__.py rename to tests/aws/services/stepfunctions/local_mocked_service_integrations/mocked_responses/dynamodb/__init__.py diff --git a/tests/aws/services/stepfunctions/mocked_service_integrations/mocked_responses/events/200_put_events.json5 b/tests/aws/services/stepfunctions/local_mocked_service_integrations/mocked_responses/events/200_put_events.json5 similarity index 100% rename from tests/aws/services/stepfunctions/mocked_service_integrations/mocked_responses/events/200_put_events.json5 rename to tests/aws/services/stepfunctions/local_mocked_service_integrations/mocked_responses/events/200_put_events.json5 diff --git a/tests/aws/services/stepfunctions/mocked_service_integrations/mocked_responses/lambda/__init__.py b/tests/aws/services/stepfunctions/local_mocked_service_integrations/mocked_responses/events/__init__.py similarity index 100% rename from tests/aws/services/stepfunctions/mocked_service_integrations/mocked_responses/lambda/__init__.py rename to tests/aws/services/stepfunctions/local_mocked_service_integrations/mocked_responses/events/__init__.py diff --git a/tests/aws/services/stepfunctions/local_mocked_service_integrations/mocked_responses/lambda/200_status_change_between_invocations.json5 b/tests/aws/services/stepfunctions/local_mocked_service_integrations/mocked_responses/lambda/200_status_change_between_invocations.json5 new file mode 100644 index 0000000000000..c80c826e3a995 --- /dev/null +++ b/tests/aws/services/stepfunctions/local_mocked_service_integrations/mocked_responses/lambda/200_status_change_between_invocations.json5 @@ -0,0 +1,18 @@ +{ + "0": { + "Return": { + "StatusCode": 200, + "Payload": { + "status": "running", + } + } + }, + "1": { + "Return": { + "StatusCode": 200, + "Payload": { + "status": "completed" + } + } + } +} diff --git a/tests/aws/services/stepfunctions/mocked_service_integrations/mocked_responses/lambda/200_string_body.json5 b/tests/aws/services/stepfunctions/local_mocked_service_integrations/mocked_responses/lambda/200_string_body.json5 similarity index 100% rename from tests/aws/services/stepfunctions/mocked_service_integrations/mocked_responses/lambda/200_string_body.json5 rename to tests/aws/services/stepfunctions/local_mocked_service_integrations/mocked_responses/lambda/200_string_body.json5 diff --git a/tests/aws/services/stepfunctions/local_mocked_service_integrations/mocked_responses/lambda/200_string_body_two_invocations.json5 b/tests/aws/services/stepfunctions/local_mocked_service_integrations/mocked_responses/lambda/200_string_body_two_invocations.json5 new file mode 100644 index 0000000000000..03b86e74ccc60 --- /dev/null +++ b/tests/aws/services/stepfunctions/local_mocked_service_integrations/mocked_responses/lambda/200_string_body_two_invocations.json5 @@ -0,0 +1,10 @@ +{ + "0-1": { + "Return": { + "StatusCode": 200, + "Payload": { + "body": "string body" + } + } + } +} diff --git a/tests/aws/services/stepfunctions/mocked_service_integrations/mocked_responses/sns/__init__.py b/tests/aws/services/stepfunctions/local_mocked_service_integrations/mocked_responses/lambda/__init__.py similarity index 100% rename from tests/aws/services/stepfunctions/mocked_service_integrations/mocked_responses/sns/__init__.py rename to tests/aws/services/stepfunctions/local_mocked_service_integrations/mocked_responses/lambda/__init__.py diff --git a/tests/aws/services/stepfunctions/mocked_service_integrations/mocked_responses/lambda/not_ready_timeout_200_string_body.json5 b/tests/aws/services/stepfunctions/local_mocked_service_integrations/mocked_responses/lambda/not_ready_timeout_200_string_body.json5 similarity index 100% rename from tests/aws/services/stepfunctions/mocked_service_integrations/mocked_responses/lambda/not_ready_timeout_200_string_body.json5 rename to tests/aws/services/stepfunctions/local_mocked_service_integrations/mocked_responses/lambda/not_ready_timeout_200_string_body.json5 diff --git a/tests/aws/services/stepfunctions/mocked_service_integrations/mocked_responses/sns/200_publish.json5 b/tests/aws/services/stepfunctions/local_mocked_service_integrations/mocked_responses/sns/200_publish.json5 similarity index 100% rename from tests/aws/services/stepfunctions/mocked_service_integrations/mocked_responses/sns/200_publish.json5 rename to tests/aws/services/stepfunctions/local_mocked_service_integrations/mocked_responses/sns/200_publish.json5 diff --git a/tests/aws/services/stepfunctions/mocked_service_integrations/mocked_responses/sqs/__init__.py b/tests/aws/services/stepfunctions/local_mocked_service_integrations/mocked_responses/sns/__init__.py similarity index 100% rename from tests/aws/services/stepfunctions/mocked_service_integrations/mocked_responses/sqs/__init__.py rename to tests/aws/services/stepfunctions/local_mocked_service_integrations/mocked_responses/sns/__init__.py diff --git a/tests/aws/services/stepfunctions/mocked_service_integrations/mocked_responses/sqs/200_send_message.json5 b/tests/aws/services/stepfunctions/local_mocked_service_integrations/mocked_responses/sqs/200_send_message.json5 similarity index 100% rename from tests/aws/services/stepfunctions/mocked_service_integrations/mocked_responses/sqs/200_send_message.json5 rename to tests/aws/services/stepfunctions/local_mocked_service_integrations/mocked_responses/sqs/200_send_message.json5 diff --git a/tests/aws/services/stepfunctions/mocked_service_integrations/mocked_responses/states/__init__.py b/tests/aws/services/stepfunctions/local_mocked_service_integrations/mocked_responses/sqs/__init__.py similarity index 100% rename from tests/aws/services/stepfunctions/mocked_service_integrations/mocked_responses/states/__init__.py rename to tests/aws/services/stepfunctions/local_mocked_service_integrations/mocked_responses/sqs/__init__.py diff --git a/tests/aws/services/stepfunctions/mocked_service_integrations/mocked_responses/states/200_start_execution_sync.json5 b/tests/aws/services/stepfunctions/local_mocked_service_integrations/mocked_responses/states/200_start_execution_sync.json5 similarity index 100% rename from tests/aws/services/stepfunctions/mocked_service_integrations/mocked_responses/states/200_start_execution_sync.json5 rename to tests/aws/services/stepfunctions/local_mocked_service_integrations/mocked_responses/states/200_start_execution_sync.json5 diff --git a/tests/aws/services/stepfunctions/mocked_service_integrations/mocked_responses/states/200_start_execution_sync2.json5 b/tests/aws/services/stepfunctions/local_mocked_service_integrations/mocked_responses/states/200_start_execution_sync2.json5 similarity index 100% rename from tests/aws/services/stepfunctions/mocked_service_integrations/mocked_responses/states/200_start_execution_sync2.json5 rename to tests/aws/services/stepfunctions/local_mocked_service_integrations/mocked_responses/states/200_start_execution_sync2.json5 diff --git a/tests/aws/services/stepfunctions/templates/mocked/__init__.py b/tests/aws/services/stepfunctions/local_mocked_service_integrations/mocked_responses/states/__init__.py similarity index 100% rename from tests/aws/services/stepfunctions/templates/mocked/__init__.py rename to tests/aws/services/stepfunctions/local_mocked_service_integrations/mocked_responses/states/__init__.py diff --git a/tests/aws/services/stepfunctions/mocked_service_integrations/mocked_service_integrations.py b/tests/aws/services/stepfunctions/local_mocked_service_integrations/mocked_service_integrations.py similarity index 86% rename from tests/aws/services/stepfunctions/mocked_service_integrations/mocked_service_integrations.py rename to tests/aws/services/stepfunctions/local_mocked_service_integrations/mocked_service_integrations.py index ec97e7119e3fb..72756acdd1970 100644 --- a/tests/aws/services/stepfunctions/mocked_service_integrations/mocked_service_integrations.py +++ b/tests/aws/services/stepfunctions/local_mocked_service_integrations/mocked_service_integrations.py @@ -10,9 +10,15 @@ class MockedServiceIntegrationsLoader(abc.ABC): + MOCKED_RESPONSE_LAMBDA_200_STRING_BODY_TWO_INVOCATIONS: Final[str] = os.path.join( + _THIS_FOLDER, "mocked_responses/lambda/200_string_body_two_invocations.json5" + ) MOCKED_RESPONSE_LAMBDA_200_STRING_BODY: Final[str] = os.path.join( _THIS_FOLDER, "mocked_responses/lambda/200_string_body.json5" ) + MOCKED_RESPONSE_LAMBDA_200_STATUS_CHANGE_BETWEEN_INVOCATIONS: Final[str] = os.path.join( + _THIS_FOLDER, "mocked_responses/lambda/200_status_change_between_invocations.json5" + ) MOCKED_RESPONSE_LAMBDA_NOT_READY_TIMEOUT_200_STRING_BODY: Final[str] = os.path.join( _THIS_FOLDER, "mocked_responses/lambda/not_ready_timeout_200_string_body.json5" ) diff --git a/tests/aws/services/stepfunctions/templates/mocked/statemachines/__init__.py b/tests/aws/services/stepfunctions/templates/local_mocked/__init__.py similarity index 100% rename from tests/aws/services/stepfunctions/templates/mocked/statemachines/__init__.py rename to tests/aws/services/stepfunctions/templates/local_mocked/__init__.py diff --git a/tests/aws/services/stepfunctions/templates/mocked/mocked_templates.py b/tests/aws/services/stepfunctions/templates/local_mocked/mocked_templates.py similarity index 100% rename from tests/aws/services/stepfunctions/templates/mocked/mocked_templates.py rename to tests/aws/services/stepfunctions/templates/local_mocked/mocked_templates.py diff --git a/tests/aws/services/stepfunctions/v2/mocking/__init__.py b/tests/aws/services/stepfunctions/templates/local_mocked/statemachines/__init__.py similarity index 100% rename from tests/aws/services/stepfunctions/v2/mocking/__init__.py rename to tests/aws/services/stepfunctions/templates/local_mocked/statemachines/__init__.py diff --git a/tests/aws/services/stepfunctions/templates/mocked/statemachines/lambda_sqs_integration.json5 b/tests/aws/services/stepfunctions/templates/local_mocked/statemachines/lambda_sqs_integration.json5 similarity index 100% rename from tests/aws/services/stepfunctions/templates/mocked/statemachines/lambda_sqs_integration.json5 rename to tests/aws/services/stepfunctions/templates/local_mocked/statemachines/lambda_sqs_integration.json5 diff --git a/tests/aws/services/stepfunctions/templates/scenarios/scenarios_templates.py b/tests/aws/services/stepfunctions/templates/scenarios/scenarios_templates.py index 29a4a77473035..86328836114d4 100644 --- a/tests/aws/services/stepfunctions/templates/scenarios/scenarios_templates.py +++ b/tests/aws/services/stepfunctions/templates/scenarios/scenarios_templates.py @@ -227,6 +227,10 @@ class ScenariosTemplate(TemplateLoader): LAMBDA_EMPTY_RETRY: Final[str] = os.path.join( _THIS_FOLDER, "statemachines/lambda_empty_retry.json5" ) + LAMBDA_REPEAT_UNTIL_LOOP: Final[str] = os.path.join( + _THIS_FOLDER, "statemachines/lambda_repeat_until_loop.json5" + ) + LAMBDA_INVOKE_WITH_RETRY_BASE: Final[str] = os.path.join( _THIS_FOLDER, "statemachines/lambda_invoke_with_retry_base.json5" ) diff --git a/tests/aws/services/stepfunctions/templates/scenarios/statemachines/lambda_repeat_until_loop.json5 b/tests/aws/services/stepfunctions/templates/scenarios/statemachines/lambda_repeat_until_loop.json5 new file mode 100644 index 0000000000000..6a1110c4b86da --- /dev/null +++ b/tests/aws/services/stepfunctions/templates/scenarios/statemachines/lambda_repeat_until_loop.json5 @@ -0,0 +1,31 @@ +{ + "QueryLanguage": "JSONata", + "StartAt": "LambdaState", + "States": { + "LambdaState": { + "Type": "Task", + "Resource": "arn:aws:states:::lambda:invoke", + "Arguments": { + "FunctionName": "__tbd__", + "Payload": "__tbd__" + }, + "Assign": { + "status": "{% $states.result.Payload.status %}", + }, + "Next": "CheckCompleted" + }, + "CheckCompleted": { + "Type": "Choice", + "Choices": [ + { + "Condition": "{% $status = 'completed' %}", + "Next": "Finish" + } + ], + "Default": "LambdaState" + }, + "Finish": { + "Type": "Succeed" + } + } +} diff --git a/tests/aws/services/stepfunctions/templates/test_state/statemachines/base_aws_api_kms_encrypt.json5 b/tests/aws/services/stepfunctions/templates/test_state/statemachines/base_aws_api_kms_encrypt.json5 new file mode 100644 index 0000000000000..1cc3b11be8c1f --- /dev/null +++ b/tests/aws/services/stepfunctions/templates/test_state/statemachines/base_aws_api_kms_encrypt.json5 @@ -0,0 +1,9 @@ +{ + "Type": "Task", + "Resource": "arn:aws:states:::aws-sdk:kms:encrypt", + "Parameters": { + "KeyId.$": "$.KeyId", + "Plaintext.$": "$.Plaintext" + }, + "End": true +} diff --git a/tests/aws/services/stepfunctions/templates/test_state/statemachines/base_aws_api_lambda_get_function.json5 b/tests/aws/services/stepfunctions/templates/test_state/statemachines/base_aws_api_lambda_get_function.json5 new file mode 100644 index 0000000000000..71f6c13f85b03 --- /dev/null +++ b/tests/aws/services/stepfunctions/templates/test_state/statemachines/base_aws_api_lambda_get_function.json5 @@ -0,0 +1,8 @@ +{ + "Type": "Task", + "Resource": "arn:aws:states:::aws-sdk:lambda:getFunction", + "Parameters": { + "FunctionName.$": "$.FunctionName", + }, + "End": true +} diff --git a/tests/aws/services/stepfunctions/templates/test_state/statemachines/base_aws_api_s3_get_object.json5 b/tests/aws/services/stepfunctions/templates/test_state/statemachines/base_aws_api_s3_get_object.json5 new file mode 100644 index 0000000000000..8ff30e643a1d9 --- /dev/null +++ b/tests/aws/services/stepfunctions/templates/test_state/statemachines/base_aws_api_s3_get_object.json5 @@ -0,0 +1,9 @@ +{ + "Type": "Task", + "Resource": "arn:aws:states:::aws-sdk:s3:getObject", + "Parameters": { + "Bucket.$": "$.Bucket", + "Key.$": "$.Key" + }, + "End": true +} diff --git a/tests/aws/services/stepfunctions/templates/test_state/statemachines/base_dynamodb_service_task_state.json5 b/tests/aws/services/stepfunctions/templates/test_state/statemachines/base_dynamodb_service_task_state.json5 new file mode 100644 index 0000000000000..ee6ade074ceea --- /dev/null +++ b/tests/aws/services/stepfunctions/templates/test_state/statemachines/base_dynamodb_service_task_state.json5 @@ -0,0 +1,9 @@ +{ + "Type": "Task", + "Resource": "arn:aws:states:::dynamodb:putItem", + "Parameters": { + "TableName.$": "$.TableName", + "Item.$": "$.Item" + }, + "End": true +} diff --git a/tests/aws/services/stepfunctions/templates/test_state/statemachines/base_events_put_events.json5 b/tests/aws/services/stepfunctions/templates/test_state/statemachines/base_events_put_events.json5 new file mode 100644 index 0000000000000..bea87edf439f7 --- /dev/null +++ b/tests/aws/services/stepfunctions/templates/test_state/statemachines/base_events_put_events.json5 @@ -0,0 +1,8 @@ +{ + "Type": "Task", + "Resource": "arn:aws:states:::events:putEvents", + "Parameters": { + "Entries.$": "$.Entries" + }, + "End": true +} diff --git a/tests/aws/services/stepfunctions/templates/test_state/statemachines/base_fail_state_machine.json5 b/tests/aws/services/stepfunctions/templates/test_state/statemachines/base_fail_state_machine.json5 new file mode 100644 index 0000000000000..d4ab7bd29df21 --- /dev/null +++ b/tests/aws/services/stepfunctions/templates/test_state/statemachines/base_fail_state_machine.json5 @@ -0,0 +1,12 @@ +{ + "Comment": "BASE_FAIL_STATE_MACHINE", + "QueryLanguage": "JSONata", + "StartAt": "State0", + "States": { + "State0": { + "Type": "Fail", + "Error": "SomeFailure", + "Cause": "This state machines raises a 'SomeFailure' failure.", + }, + } +} \ No newline at end of file diff --git a/tests/aws/services/stepfunctions/templates/test_state/statemachines/base_invalid_state_definition.json5 b/tests/aws/services/stepfunctions/templates/test_state/statemachines/base_invalid_state_definition.json5 new file mode 100644 index 0000000000000..0e1557ed50d6e --- /dev/null +++ b/tests/aws/services/stepfunctions/templates/test_state/statemachines/base_invalid_state_definition.json5 @@ -0,0 +1,10 @@ +{ + "Comment": "Base state machine with a state that is not a valid state definition.", + "StartAt": "ExistingButInvalidState", + "States": { + "ExistingButInvalidState": { + "Type": "TypeThatDoesNotExist", + "End": true + } + } +} diff --git a/tests/aws/services/stepfunctions/templates/test_state/statemachines/base_lambda_service_task_state.json5 b/tests/aws/services/stepfunctions/templates/test_state/statemachines/base_lambda_service_task_state.json5 index ca37fca1a5f41..a0b97ce13e8f1 100644 --- a/tests/aws/services/stepfunctions/templates/test_state/statemachines/base_lambda_service_task_state.json5 +++ b/tests/aws/services/stepfunctions/templates/test_state/statemachines/base_lambda_service_task_state.json5 @@ -1,4 +1,5 @@ { + "Comment": "BASE_LAMBDA_SERVICE_TASK_STATE", "Type": "Task", "Resource": "arn:aws:states:::lambda:invoke", "Parameters": { diff --git a/tests/aws/services/stepfunctions/templates/test_state/statemachines/base_map_state.json5 b/tests/aws/services/stepfunctions/templates/test_state/statemachines/base_map_state.json5 new file mode 100644 index 0000000000000..9b254bbfed0de --- /dev/null +++ b/tests/aws/services/stepfunctions/templates/test_state/statemachines/base_map_state.json5 @@ -0,0 +1,27 @@ +{ + "Comment": "BASE_MAP_STATE", + "Type": "Map", + "QueryLanguage": "JSONata", + "Items": "{% $states.input.Values %}", + "ItemProcessor": { + "ProcessorConfig": { + "Mode": "DISTRIBUTED", + "ExecutionType": "STANDARD" + }, + "StartAt": "TestState", + "States": { + "TestState": { + "Type": "Task", + "QueryLanguage": "JSONata", + "Resource": "arn:aws:states:::lambda:invoke", + "Arguments": { + "FunctionName": "foo", + "Payload": "bar" + }, + "End": true + } + } + }, + "Output": "{% $states %}", + "End": true +} diff --git a/tests/aws/services/stepfunctions/templates/test_state/statemachines/base_map_state_catch.json5 b/tests/aws/services/stepfunctions/templates/test_state/statemachines/base_map_state_catch.json5 new file mode 100644 index 0000000000000..5797a349c8b37 --- /dev/null +++ b/tests/aws/services/stepfunctions/templates/test_state/statemachines/base_map_state_catch.json5 @@ -0,0 +1,34 @@ +{ + "Comment": "BASE_MAP_STATE_CATCH", + "Type": "Map", + "QueryLanguage": "JSONata", + "Items": "{% $states.input.Values %}", + "ItemProcessor": { + "ProcessorConfig": { + "Mode": "DISTRIBUTED", + "ExecutionType": "STANDARD" + }, + "StartAt": "TestState", + "States": { + "TestState": { + "Type": "Task", + "Resource": "arn:aws:lambda:your-region:your-account-id:function:yourHelloWorldFunction", + "End": true + } + } + }, + "Catch": [ + { + "ErrorEquals": ["MockException"], + "Output": "{% $states %}", + "Next": "HandleMockError" + }, + { + "ErrorEquals": ["States.ExceedToleratedFailureThreshold"], + "Output": "{% $states %}", + "Next": "HandleThreshold" + } + ], + "ToleratedFailureCount": 1, + "End": true +} \ No newline at end of file diff --git a/tests/aws/services/stepfunctions/templates/test_state/statemachines/base_map_state_machine.json5 b/tests/aws/services/stepfunctions/templates/test_state/statemachines/base_map_state_machine.json5 new file mode 100644 index 0000000000000..d43d32f7fe622 --- /dev/null +++ b/tests/aws/services/stepfunctions/templates/test_state/statemachines/base_map_state_machine.json5 @@ -0,0 +1,25 @@ +{ + "Comment": "BASE_MAP_STATE_MACHINE", + "StartAt": "State0", + "States": { + "State0": { + "Type": "Map", + "ItemsPath": "$.Values", + "ItemProcessor": { + "ProcessorConfig": { + "Mode": "DISTRIBUTED", + "ExecutionType": "STANDARD" + }, + "StartAt": "HandleItem", + "States": { + "HandleItem": { + "Type": "Pass", + "End": true + } + } + }, + "ToleratedFailureCount": 2, + "End": true + } + } +} \ No newline at end of file diff --git a/tests/aws/services/stepfunctions/templates/test_state/statemachines/base_map_state_machine_choice_fail.json5 b/tests/aws/services/stepfunctions/templates/test_state/statemachines/base_map_state_machine_choice_fail.json5 new file mode 100644 index 0000000000000..4ffd4020899f9 --- /dev/null +++ b/tests/aws/services/stepfunctions/templates/test_state/statemachines/base_map_state_machine_choice_fail.json5 @@ -0,0 +1,40 @@ +{ + "Comment": "BASE_MAP_STATE_MACHINE_CHOICE_FAIL", + "StartAt": "MapState", + "States": { + "State0": { + "Type": "Map", + "ItemsPath": "$.Values", + "ItemProcessor": { + "ProcessorConfig": { + "Mode": "INLINE" + }, + "StartAt": "HandleItem", + "States": { + "RouteItem": { + "QueryLanguage": "JSONata", + "Type": "Choice", + "Comment": "The first item should always fail.", + "Choices": [ + { + "Next": "FailureHandler", + "Condition": "{% $$.Map.Item.Index = 0 %}", + }, + ], + "Default": "SucceessHandler" + }, + "FailureHandler": { + "Type": "Fail", + "Error": "SomeFailure", + "Cause": "This state machines raises a 'SomeFailure' failure." + }, + "SucceessHandler": { + "Type": "Pass", + "End": true + } + } + }, + "End": true + } + } +} \ No newline at end of file diff --git a/tests/aws/services/stepfunctions/templates/test_state/statemachines/base_map_state_machine_fail.json5 b/tests/aws/services/stepfunctions/templates/test_state/statemachines/base_map_state_machine_fail.json5 new file mode 100644 index 0000000000000..697e550a6c6d7 --- /dev/null +++ b/tests/aws/services/stepfunctions/templates/test_state/statemachines/base_map_state_machine_fail.json5 @@ -0,0 +1,24 @@ +{ + "Comment": "BASE_MAP_STATE_MACHINE_FAIL", + "StartAt": "State0", + "States": { + "State0": { + "Type": "Map", + "ItemsPath": "$.Values", + "ItemProcessor": { + "ProcessorConfig": { + "Mode": "INLINE" + }, + "StartAt": "HandleItem", + "States": { + "HandleItem": { + "Type": "Fail", + "Error": "SomeFailure", + "Cause": "This state machines raises a 'SomeFailure' failure." + } + } + }, + "End": true + } + } +} diff --git a/tests/aws/services/stepfunctions/templates/test_state/statemachines/base_map_state_result_writer.json5 b/tests/aws/services/stepfunctions/templates/test_state/statemachines/base_map_state_result_writer.json5 new file mode 100644 index 0000000000000..3d62ea97cca7c --- /dev/null +++ b/tests/aws/services/stepfunctions/templates/test_state/statemachines/base_map_state_result_writer.json5 @@ -0,0 +1,32 @@ +{ + "Comment": "BASE_MAP_STATE", + "Type": "Map", + "ItemsPath": "$.Values", + "ItemProcessor": { + "ProcessorConfig": { + "Mode": "DISTRIBUTED", + "ExecutionType": "STANDARD" + }, + "StartAt": "TestState", + "States": { + "TestState": { + "Type": "Task", + "Resource": "arn:aws:states:::lambda:invoke", + "Parameters": { + "FunctionName": "foo", + "Payload": "bar" + }, + "End": true + } + } + }, + "ResultWriter": { + "Resource": "arn:aws:states:::s3:putObject", + "Parameters": { + "Bucket": "result-bucket", + "Prefix": "mapJobs" + } + }, + "Label": "TestMap", + "End": true +} diff --git a/tests/aws/services/stepfunctions/templates/test_state/statemachines/base_map_state_retry.json5 b/tests/aws/services/stepfunctions/templates/test_state/statemachines/base_map_state_retry.json5 new file mode 100644 index 0000000000000..777468d6f1d19 --- /dev/null +++ b/tests/aws/services/stepfunctions/templates/test_state/statemachines/base_map_state_retry.json5 @@ -0,0 +1,32 @@ +{ + "Comment": "BASE_MAP_STATE_RETRY", + "Type": "Map", + "QueryLanguage": "JSONata", + "Items": "{% $states.input.Values %}", + "ItemProcessor": { + "ProcessorConfig": { + "Mode": "DISTRIBUTED", + "ExecutionType": "STANDARD" + }, + "StartAt": "TestState", + "States": { + "TestState": { + "Type": "Task", + "Resource": "arn:aws:lambda:your-region:your-account-id:function:yourHelloWorldFunction", + "End": true + } + } + }, + "Retry": [ + { + "ErrorEquals": ["MockException"], + "MaxAttempts": 3 + }, + { + "ErrorEquals": ["States.ExceedToleratedFailureThreshold"], + "MaxAttempts": 2 + } + ], + "ToleratedFailureCount": 1, + "End": true +} \ No newline at end of file diff --git a/tests/aws/services/stepfunctions/templates/test_state/statemachines/base_multi_state_machine.json5 b/tests/aws/services/stepfunctions/templates/test_state/statemachines/base_multi_state_machine.json5 new file mode 100644 index 0000000000000..e6ea7816cc408 --- /dev/null +++ b/tests/aws/services/stepfunctions/templates/test_state/statemachines/base_multi_state_machine.json5 @@ -0,0 +1,16 @@ +{ + "Comment": "BASE_MULTI_STATE_MACHINE", + "QueryLanguage": "JSONata", + "StartAt": "State0", + "States": { + "State0": { + "Type": "Pass", + "Next": "State1" + }, + "State1": { + "Type": "Fail", + "Error": "SomeFailure", + "Cause": "This state machines raises a 'SomeFailure' failure.", + }, + } +} \ No newline at end of file diff --git a/tests/aws/services/stepfunctions/templates/test_state/statemachines/base_parallel_state.json5 b/tests/aws/services/stepfunctions/templates/test_state/statemachines/base_parallel_state.json5 new file mode 100644 index 0000000000000..adc0ad0afc803 --- /dev/null +++ b/tests/aws/services/stepfunctions/templates/test_state/statemachines/base_parallel_state.json5 @@ -0,0 +1,24 @@ +{ + "Type": "Parallel", + "Branches": [ + { + "StartAt": "B1", + "States": { + "B1": { + "Type": "Pass", + "End": true + } + } + }, + { + "StartAt": "B2", + "States": { + "B2": { + "Type": "Pass", + "End": true + } + } + } + ], + "End": true +} diff --git a/tests/aws/services/stepfunctions/templates/test_state/statemachines/base_pass_state_machine.json5 b/tests/aws/services/stepfunctions/templates/test_state/statemachines/base_pass_state_machine.json5 new file mode 100644 index 0000000000000..869593a6ea2a5 --- /dev/null +++ b/tests/aws/services/stepfunctions/templates/test_state/statemachines/base_pass_state_machine.json5 @@ -0,0 +1,10 @@ +{ + "Comment": "BASE_PASS_STATE_MACHINE", + "StartAt": "State0", + "States": { + "State0": { + "Type": "Pass", + "End": true + } + } +} \ No newline at end of file diff --git a/tests/aws/services/stepfunctions/templates/test_state/statemachines/base_sfn_start_execution.json5 b/tests/aws/services/stepfunctions/templates/test_state/statemachines/base_sfn_start_execution.json5 new file mode 100644 index 0000000000000..5f90af204e34c --- /dev/null +++ b/tests/aws/services/stepfunctions/templates/test_state/statemachines/base_sfn_start_execution.json5 @@ -0,0 +1,14 @@ +{ + "Type": "Task", + "QueryLanguage": "JSONata", + "Resource": "arn:aws:states:::states:startExecution", + "Arguments": { + "Input": "{% $states.input.targetInput %}", + "StateMachineArn": "{% $states.input.stateMachineArn %}", + "Name": "{% $states.input.name %}" + }, + "Output": { + "targetExecutionResult": "{% $states.result %}" + }, + "End": true, +} diff --git a/tests/aws/services/stepfunctions/templates/test_state/statemachines/base_sqs_send_message.json5 b/tests/aws/services/stepfunctions/templates/test_state/statemachines/base_sqs_send_message.json5 new file mode 100644 index 0000000000000..dd7b6254e0368 --- /dev/null +++ b/tests/aws/services/stepfunctions/templates/test_state/statemachines/base_sqs_send_message.json5 @@ -0,0 +1,9 @@ +{ + "Type": "Task", + "Resource": "arn:aws:states:::sqs:sendMessage", + "Parameters": { + "QueueUrl.$": "$.QueueUrl", + "MessageBody.$": "$.MessageBody" + }, + "End": true +} diff --git a/tests/aws/services/stepfunctions/templates/test_state/statemachines/base_task_state_catch.json5 b/tests/aws/services/stepfunctions/templates/test_state/statemachines/base_task_state_catch.json5 new file mode 100644 index 0000000000000..51d12e7cec9b7 --- /dev/null +++ b/tests/aws/services/stepfunctions/templates/test_state/statemachines/base_task_state_catch.json5 @@ -0,0 +1,23 @@ +{ + "Comment": "BASE_TASK_STATE_CATCH", + "QueryLanguage": "JSONata", + "Type": "Task", + "Resource": "arn:aws:states:::lambda:invoke", + "Arguments": { + "FunctionName": "foo", + "Payload": "bar" + }, + "Catch": [ + { + "ErrorEquals": ["MockException"], + "Output": "{% $states %}", + "Next": "HandleMockError" + }, + { + "ErrorEquals": ["States.TaskFailed"], + "Output": "{% $states %}", + "Next": "HandleThreshold" + } + ], + "End": true +} \ No newline at end of file diff --git a/tests/aws/services/stepfunctions/templates/test_state/statemachines/base_task_state_retry.json5 b/tests/aws/services/stepfunctions/templates/test_state/statemachines/base_task_state_retry.json5 new file mode 100644 index 0000000000000..d8fb2fb20dc8b --- /dev/null +++ b/tests/aws/services/stepfunctions/templates/test_state/statemachines/base_task_state_retry.json5 @@ -0,0 +1,19 @@ +{ + "Comment": "BASE_TASK_STATE_RETRY", + "QueryLanguage": "JSONata", + "Type": "Task", + "Resource": "arn:aws:states:::lambda:invoke", + "Arguments": { + "FunctionName": "foo", + "Payload": "bar" + }, + "Retry": [ + { + "ErrorEquals": ["MockException"], + "IntervalSeconds": 1, + "MaxAttempts": 5, + "BackoffRate": 2.0 + }, + ], + "End": true +} \ No newline at end of file diff --git a/tests/aws/services/stepfunctions/templates/test_state/statemachines/io_dynamodb_service_task_state.json5 b/tests/aws/services/stepfunctions/templates/test_state/statemachines/io_dynamodb_service_task_state.json5 new file mode 100644 index 0000000000000..6adee18d1b35f --- /dev/null +++ b/tests/aws/services/stepfunctions/templates/test_state/statemachines/io_dynamodb_service_task_state.json5 @@ -0,0 +1,10 @@ +{ + "Type": "Task", + "Resource": "arn:aws:states:::dynamodb:putItem", + "Parameters": { + "TableName.$": "$.TableName", + "Item.$": "$.Item" + }, + "ResultPath": "$.putItemOutput", + "End": true +} diff --git a/tests/aws/services/stepfunctions/templates/test_state/statemachines/io_jsonata_parallel_state.json5 b/tests/aws/services/stepfunctions/templates/test_state/statemachines/io_jsonata_parallel_state.json5 new file mode 100644 index 0000000000000..419fb7b0415a3 --- /dev/null +++ b/tests/aws/services/stepfunctions/templates/test_state/statemachines/io_jsonata_parallel_state.json5 @@ -0,0 +1,30 @@ +{ + "Type": "Parallel", + "QueryLanguage": "JSONata", + "Arguments": "{% $states.input.parallelInput %}", + "Output": { + "parallelInput": "{% $states.input.parallelInput %}", + "parallelResult": "{% $states.result %}" + }, + "Branches": [ + { + "StartAt": "B1", + "States": { + "B1": { + "Type": "Pass", + "End": true + } + } + }, + { + "StartAt": "B2", + "States": { + "B2": { + "Type": "Pass", + "End": true + } + } + } + ], + "End": true +} diff --git a/tests/aws/services/stepfunctions/templates/test_state/statemachines/io_output_path_dynamodb_service_task_state.json5 b/tests/aws/services/stepfunctions/templates/test_state/statemachines/io_output_path_dynamodb_service_task_state.json5 new file mode 100644 index 0000000000000..1c0a72d3c9aed --- /dev/null +++ b/tests/aws/services/stepfunctions/templates/test_state/statemachines/io_output_path_dynamodb_service_task_state.json5 @@ -0,0 +1,11 @@ +{ + "Type": "Task", + "Resource": "arn:aws:states:::dynamodb:putItem", + "Parameters": { + "TableName.$": "$.TableName", + "Item.$": "$.Item" + }, + "ResultPath": "$.putItemOutput", + "OutputPath": "$.putItemOutput", + "End": true +} diff --git a/tests/aws/services/stepfunctions/templates/test_state/statemachines/io_parallel_state.json5 b/tests/aws/services/stepfunctions/templates/test_state/statemachines/io_parallel_state.json5 new file mode 100644 index 0000000000000..6817565bfeb60 --- /dev/null +++ b/tests/aws/services/stepfunctions/templates/test_state/statemachines/io_parallel_state.json5 @@ -0,0 +1,27 @@ +{ + "Type": "Parallel", + "InputPath": "$.parallelInput", + "ResultPath": "$.parallelResult", + "OutputPath": "$", + "Branches": [ + { + "StartAt": "B1", + "States": { + "B1": { + "Type": "Pass", + "End": true + } + } + }, + { + "StartAt": "B2", + "States": { + "B2": { + "Type": "Pass", + "End": true + } + } + } + ], + "End": true +} diff --git a/tests/aws/services/stepfunctions/templates/test_state/statemachines/io_sqs_service_task_wait.json5 b/tests/aws/services/stepfunctions/templates/test_state/statemachines/io_sqs_service_task_wait.json5 new file mode 100644 index 0000000000000..ac1e3fdbe0ac2 --- /dev/null +++ b/tests/aws/services/stepfunctions/templates/test_state/statemachines/io_sqs_service_task_wait.json5 @@ -0,0 +1,14 @@ +{ + "Comment": "IO_SQS_SERVICE_TASK_WAIT", + "Type": "Task", + "Resource": "arn:aws:states:::sqs:sendMessage.waitForTaskToken", + "Parameters": { + "QueueUrl": "__QUEUE_URL__", + "MessageBody": { + "Message": "Hello from Step Functions!", + "TaskToken.$": "$$.Task.Token" + } + }, + "ResultPath": "$.SQS", + "Next": "NEXT_STATE" +} diff --git a/tests/aws/services/stepfunctions/templates/test_state/statemachines/localstack_blogpost_scenario_state_machine.json5 b/tests/aws/services/stepfunctions/templates/test_state/statemachines/localstack_blogpost_scenario_state_machine.json5 new file mode 100644 index 0000000000000..882ca205f4368 --- /dev/null +++ b/tests/aws/services/stepfunctions/templates/test_state/statemachines/localstack_blogpost_scenario_state_machine.json5 @@ -0,0 +1,63 @@ +{ + "Comment": "Cost approval workflow", + "QueryLanguage": "JSONata", + "StartAt": "Approval Required", + "States": { + "Approval Required": { + "Type": "Choice", + "Choices": [ + { + "Condition": "{% $states.input.cost < 10 %}", + "Next": "Purchase Approved" + } + ], + "Default": "Ask for Approval" + }, + "Purchase Approved": { + "Type": "Succeed" + }, + "Ask for Approval": { + "Type": "Task", + "Resource": "arn:aws:states:::apigateway:invoke", + "Arguments": { + "Method": "POST", + "ApiEndpoint": "__api_gateway_endpoint__", + "Path": "/approval", + "RequestBody": { + "cost": "{% $states.input.cost %}", + "dept_id": "12345678" + }, + "AuthType": "NO_AUTH" + }, + "Retry": [ + { + "ErrorEquals": [ + "States.ALL" + ], + "BackoffRate": 2, + "IntervalSeconds": 1, + "MaxAttempts": 3, + } + ], + "Next": "Check Approval", + "Output": { + "approval": "{% $states.result.approval %}", + "approval_code": "2387462", + "approved_by": "Mary" + } + }, + "Check Approval": { + "Type": "Choice", + "Choices": [ + { + "Next": "Purchase Approved", + "Condition": "{% $states.input.approval %}" + } + ], + "Default": "Not Approved" + }, + "Not Approved": { + "Type": "Fail" + } + }, +} diff --git a/tests/aws/services/stepfunctions/templates/test_state/statemachines/map_item_reader_state_machine.json5 b/tests/aws/services/stepfunctions/templates/test_state/statemachines/map_item_reader_state_machine.json5 new file mode 100644 index 0000000000000..c2ebe9d770f8f --- /dev/null +++ b/tests/aws/services/stepfunctions/templates/test_state/statemachines/map_item_reader_state_machine.json5 @@ -0,0 +1,35 @@ +{ + "Comment": "MAP_ITEM_READER_STATE_MACHINE", + "QueryLanguage": "JSONata", + "StartAt": "State0", + "States": { + "State0": { + "Type": "Map", + "MaxConcurrency": 1, + "ItemReader": { + "ReaderConfig": { + "InputType": "JSON", + }, + "Resource": "arn:aws:states:::s3:getObject", + "Arguments": { + "Bucket": "{% $states.input.Bucket %}", + "Key":"{% $states.input.Key %}" + }, + }, + "ItemProcessor": { + "ProcessorConfig": { + "Mode": "DISTRIBUTED", + "ExecutionType": "STANDARD" + }, + "StartAt": "HandleItem", + "States": { + "HandleItem": { + "Type": "Pass", + "End": true + } + }, + }, + "End": true + } + } +} diff --git a/tests/aws/services/stepfunctions/templates/test_state/statemachines/map_task_state.json5 b/tests/aws/services/stepfunctions/templates/test_state/statemachines/map_task_state.json5 new file mode 100644 index 0000000000000..bbe91f3404209 --- /dev/null +++ b/tests/aws/services/stepfunctions/templates/test_state/statemachines/map_task_state.json5 @@ -0,0 +1,55 @@ +{ + "Comment": "MAP_TASK_STATE", + "Type": "Map", + "QueryLanguage": "JSONata", + "Items": "{% $states.input.Values %}", + "ItemProcessor": { + "ProcessorConfig": { + "Mode": "DISTRIBUTED", + "ExecutionType": "STANDARD" + }, + "StartAt": "TestState", + "States": { + "TestState": { + "Type": "Task", + "QueryLanguage": "JSONata", + "Resource": "arn:aws:states:::lambda:invoke", + "Arguments": { + "FunctionName": "foo", + "Payload": "bar" + }, + "End": true + } + } + }, + "Output": { + "result": "{% $map($states.result, function($v) { $v = 1 ? 'pass' : 'failed' }) %}", + "successCount": "{% $count($states.result[$ = 1]) %}", + "failedCount": "{% $count($states.result[$ = 0]) %}" + }, + "ToleratedFailureCount": 1, + "Retry": [ + { + "ErrorEquals": ["MockException"], + "MaxAttempts": 3 + }, + { + "ErrorEquals": ["States.ExceedToleratedFailureThreshold"], + "MaxAttempts": 2 + } + ], + "Catch": [ + { + "ErrorEquals": ["States.ExceedToleratedFailureThreshold"], + "Output": "{% $states %}", + "Next": "HandleThresholdExceeded" + }, + { + "ErrorEquals": ["MockException"], + "Output": "{% $states %}", + "Next": "HandleMockException" + + } + ], + "End": true +} \ No newline at end of file diff --git a/tests/aws/services/stepfunctions/templates/test_state/statemachines/map_task_state_machine.json5 b/tests/aws/services/stepfunctions/templates/test_state/statemachines/map_task_state_machine.json5 new file mode 100644 index 0000000000000..bf317718b4ff6 --- /dev/null +++ b/tests/aws/services/stepfunctions/templates/test_state/statemachines/map_task_state_machine.json5 @@ -0,0 +1,31 @@ +{ + "Comment": "MAP_TASK_STATE_MACHINE", + "QueryLanguage": "JSONata", + "StartAt": "State0", + "States": { + "State0": { + "Type": "Map", + "Items": "{% $states.input.Values %}", + "ItemProcessor": { + "ProcessorConfig": { + "Mode": "DISTRIBUTED", + "ExecutionType": "STANDARD" + }, + "StartAt": "HandleItem", + "States": { + "HandleItem": { + "Type": "Task", + "Resource": "arn:aws:states:::lambda:invoke", + "Arguments": { + "FunctionName": "function-arn", + "Payload": "{% $states.input %}", + }, + "End": true + } + } + }, + "ToleratedFailureCount": 1, + "End": true + } + } +} diff --git a/tests/aws/services/stepfunctions/templates/test_state/test_state_templates.py b/tests/aws/services/stepfunctions/templates/test_state/test_state_templates.py index 18b5aa888ffd2..37b540e1d9e16 100644 --- a/tests/aws/services/stepfunctions/templates/test_state/test_state_templates.py +++ b/tests/aws/services/stepfunctions/templates/test_state/test_state_templates.py @@ -19,6 +19,34 @@ class TestStateTemplate(TemplateLoader): BASE_RESULT_PASS_STATE: Final[str] = os.path.join( _THIS_FOLDER, "statemachines/base_result_pass_state.json5" ) + BASE_DYNAMODB_SERVICE_TASK_STATE: Final[str] = os.path.join( + _THIS_FOLDER, "statemachines/base_dynamodb_service_task_state.json5" + ) + BASE_DYNAMODB_SERVICE_TASK_STATE: Final[str] = os.path.join( + _THIS_FOLDER, "statemachines/base_dynamodb_service_task_state.json5" + ) + IO_DYNAMODB_SERVICE_TASK_STATE: Final[str] = os.path.join( + _THIS_FOLDER, "statemachines/io_dynamodb_service_task_state.json5" + ) + IO_OUTPUT_PATH_DYNAMODB_SERVICE_TASK_STATE: Final[str] = os.path.join( + _THIS_FOLDER, "statemachines/io_output_path_dynamodb_service_task_state.json5" + ) + + IO_SQS_SERVICE_TASK_WAIT: Final[str] = os.path.join( + _THIS_FOLDER, "statemachines/io_sqs_service_task_wait.json5" + ) + + BASE_MAP_STATE: Final[str] = os.path.join(_THIS_FOLDER, "statemachines/base_map_state.json5") + BASE_MAP_STATE_WITH_RESULT_WRITER: Final[str] = os.path.join( + _THIS_FOLDER, "statemachines/base_map_state_result_writer.json5" + ) + BASE_MAP_STATE_CATCH: Final[str] = os.path.join( + _THIS_FOLDER, "statemachines/base_map_state_catch.json5" + ) + BASE_MAP_STATE_RETRY: Final[str] = os.path.join( + _THIS_FOLDER, "statemachines/base_map_state_retry.json5" + ) + IO_PASS_STATE: Final[str] = os.path.join(_THIS_FOLDER, "statemachines/io_pass_state.json5") IO_RESULT_PASS_STATE: Final[str] = os.path.join( _THIS_FOLDER, "statemachines/io_result_pass_state.json5" @@ -33,3 +61,83 @@ class TestStateTemplate(TemplateLoader): IO_LAMBDA_SERVICE_TASK_STATE: Final[str] = os.path.join( _THIS_FOLDER, "statemachines/io_lambda_service_task_state.json5" ) + BASE_EVENTS_PUT_EVENTS_TASK_STATE: Final[str] = os.path.join( + _THIS_FOLDER, "statemachines/base_events_put_events.json5" + ) + BASE_SQS_SEND_MESSAGE_TASK_STATE: Final[str] = os.path.join( + _THIS_FOLDER, "statemachines/base_sqs_send_message.json5" + ) + BASE_SFN_START_EXECUTION_TASK_STATE: Final[str] = os.path.join( + _THIS_FOLDER, "statemachines/base_sfn_start_execution.json5" + ) + BASE_AWS_SDK_S3_GET_OBJECT_TASK_STATE: Final[str] = os.path.join( + _THIS_FOLDER, "statemachines/base_aws_api_s3_get_object.json5" + ) + BASE_AWS_SDK_KMS_ENCRYPT_TASK_STATE: Final[str] = os.path.join( + _THIS_FOLDER, "statemachines/base_aws_api_kms_encrypt.json5" + ) + BASE_AWS_SDK_LAMBDA_GET_FUNCTION: Final[str] = os.path.join( + _THIS_FOLDER, "statemachines/base_aws_api_lambda_get_function.json5" + ) + + BASE_TASK_STATE_RETRY: Final[str] = os.path.join( + _THIS_FOLDER, "statemachines/base_task_state_retry.json5" + ) + BASE_TASK_STATE_CATCH: Final[str] = os.path.join( + _THIS_FOLDER, "statemachines/base_task_state_catch.json5" + ) + + MAP_TASK_STATE: Final[str] = os.path.join(_THIS_FOLDER, "statemachines/map_task_state.json5") + + BASE_PARALLEL_STATE: Final[str] = os.path.join( + _THIS_FOLDER, "statemachines/base_parallel_state.json5" + ) + IO_PARALLEL_STATE: Final[str] = os.path.join( + _THIS_FOLDER, "statemachines/io_parallel_state.json5" + ) + IO_JSONATA_PARALLEL_STATE: Final[str] = os.path.join( + _THIS_FOLDER, "statemachines/io_jsonata_parallel_state.json5" + ) + + +class TestStateMachineTemplate(TemplateLoader): + BASE_MULTI_STATE_MACHINE: Final[str] = os.path.join( + _THIS_FOLDER, "statemachines/base_multi_state_machine.json5" + ) + + BASE_PASS_STATE_MACHINE: Final[str] = os.path.join( + _THIS_FOLDER, "statemachines/base_pass_state_machine.json5" + ) + + BASE_FAIL_STATE_MACHINE: Final[str] = os.path.join( + _THIS_FOLDER, "statemachines/base_fail_state_machine.json5" + ) + + BASE_MAP_STATE_MACHINE: Final[str] = os.path.join( + _THIS_FOLDER, "statemachines/base_map_state_machine.json5" + ) + + MAP_TASK_STATE_MACHINE: Final[str] = os.path.join( + _THIS_FOLDER, "statemachines/map_task_state_machine.json5" + ) + + MAP_ITEM_READER_STATE_MACHINE: Final[str] = os.path.join( + _THIS_FOLDER, "statemachines/map_item_reader_state_machine.json5" + ) + + # TODO The below state machines need to be snapshot and included in parity tests + BASE_MAP_STATE_MACHINE_FAIL: Final[str] = os.path.join( + _THIS_FOLDER, "statemachines/base_map_state_machine_fail.json5" + ) + + BASE_MAP_STATE_MACHINE_CHOICE_FAIL: Final[str] = os.path.join( + _THIS_FOLDER, "statemachines/base_map_state_machine_choice_fail.json5" + ) + + LOCALSTACK_BLOGPOST_SCENARIO_STATE_MACHINE: Final[str] = os.path.join( + _THIS_FOLDER, "statemachines/localstack_blogpost_scenario_state_machine.json5" + ) + + BASE_INVALID_STATE_DEFINITION: Final[str] = os.path.join( + _THIS_FOLDER, "statemachines/base_invalid_state_definition.json5" + ) diff --git a/tests/aws/services/stepfunctions/templates/validation/statemachines/invalid_downgrade_query_language.json5 b/tests/aws/services/stepfunctions/templates/validation/statemachines/invalid_downgrade_query_language.json5 new file mode 100644 index 0000000000000..d79d8a9e085ea --- /dev/null +++ b/tests/aws/services/stepfunctions/templates/validation/statemachines/invalid_downgrade_query_language.json5 @@ -0,0 +1,11 @@ +{ + "StartAt": "Pass", + "States": { + "Pass": { + "Type": "Pass", + "End": true, + "QueryLanguage": "JSONPath" + } + }, + "QueryLanguage": "JSONata" +} diff --git a/tests/aws/services/stepfunctions/templates/validation/statemachines/valid_query_language_pass.json5 b/tests/aws/services/stepfunctions/templates/validation/statemachines/valid_query_language_pass.json5 new file mode 100644 index 0000000000000..9ceb6bbd32400 --- /dev/null +++ b/tests/aws/services/stepfunctions/templates/validation/statemachines/valid_query_language_pass.json5 @@ -0,0 +1,24 @@ +{ + "StartAt": "Map", + "QueryLanguage": "JSONPath", + "States": { + "Map": { + "Type": "Map", + "QueryLanguage": "JSONata", + "ItemProcessor": { + "ProcessorConfig": { + "Mode": "INLINE" + }, + "StartAt": "Pass", + "States": { + "Pass": { + "QueryLanguage": "JSONPath", + "Type": "Pass", + "End": true + } + } + }, + "End": true + } + } +} diff --git a/tests/aws/services/stepfunctions/templates/validation/validation_templates.py b/tests/aws/services/stepfunctions/templates/validation/validation_templates.py index ec4243c08e07c..3250675942f86 100644 --- a/tests/aws/services/stepfunctions/templates/validation/validation_templates.py +++ b/tests/aws/services/stepfunctions/templates/validation/validation_templates.py @@ -10,4 +10,10 @@ class ValidationTemplate(TemplateLoader): INVALID_BASE_NO_STARTAT: Final[str] = os.path.join( _THIS_FOLDER, "statemachines/invalid_base_no_startat.json5" ) + INVALID_DOWNGRADE_QUERY_LANGUAGE: Final[str] = os.path.join( + _THIS_FOLDER, "statemachines/invalid_downgrade_query_language.json5" + ) VALID_BASE_PASS: Final[str] = os.path.join(_THIS_FOLDER, "statemachines/valid_base_pass.json5") + VALID_QUERY_LANGUAGE_PASS: Final[str] = os.path.join( + _THIS_FOLDER, "statemachines/valid_query_language_pass.json5" + ) diff --git a/tests/aws/services/stepfunctions/v2/error_handling/test_task_service_lambda.snapshot.json b/tests/aws/services/stepfunctions/v2/error_handling/test_task_service_lambda.snapshot.json index 33131f7120100..34cb33686ceef 100644 --- a/tests/aws/services/stepfunctions/v2/error_handling/test_task_service_lambda.snapshot.json +++ b/tests/aws/services/stepfunctions/v2/error_handling/test_task_service_lambda.snapshot.json @@ -904,7 +904,7 @@ } }, "tests/aws/services/stepfunctions/v2/error_handling/test_task_service_lambda.py::TestTaskServiceLambda::test_no_such_function": { - "recorded-date": "28-11-2024, 13:05:16", + "recorded-date": "25-11-2025, 15:29:42", "recorded-content": { "get_execution_history": { "events": [ @@ -969,7 +969,7 @@ "id": 5, "previousEventId": 4, "taskFailedEventDetails": { - "cause": "Function not found: arn::lambda::111111111111:function:no_such_ (Service: AWSLambda; Status Code: 404; Error Code: ResourceNotFoundException; Request ID: ; Proxy: null)", + "cause": "Function not found: arn::lambda::111111111111:function:no_such_:$LATEST (Service: AWSLambda; Status Code: 404; Error Code: ResourceNotFoundException; Request ID: ; Proxy: null)", "error": "Lambda.ResourceNotFoundException", "resource": "invoke", "resourceType": "lambda" @@ -979,7 +979,7 @@ }, { "executionFailedEventDetails": { - "cause": "Function not found: arn::lambda::111111111111:function:no_such_ (Service: AWSLambda; Status Code: 404; Error Code: ResourceNotFoundException; Request ID: ; Proxy: null)", + "cause": "Function not found: arn::lambda::111111111111:function:no_such_:$LATEST (Service: AWSLambda; Status Code: 404; Error Code: ResourceNotFoundException; Request ID: ; Proxy: null)", "error": "Lambda.ResourceNotFoundException" }, "id": 6, @@ -996,7 +996,7 @@ } }, "tests/aws/services/stepfunctions/v2/error_handling/test_task_service_lambda.py::TestTaskServiceLambda::test_no_such_function_catch": { - "recorded-date": "28-11-2024, 13:05:33", + "recorded-date": "25-11-2025, 21:15:38", "recorded-content": { "get_execution_history": { "events": [ @@ -1061,7 +1061,7 @@ "id": 5, "previousEventId": 4, "taskFailedEventDetails": { - "cause": "Function not found: arn::lambda::111111111111:function:no_such_ (Service: AWSLambda; Status Code: 404; Error Code: ResourceNotFoundException; Request ID: ; Proxy: null)", + "cause": "Function not found: arn::lambda::111111111111:function:no_such_:$LATEST (Service: AWSLambda; Status Code: 404; Error Code: ResourceNotFoundException; Request ID: ; Proxy: null)", "error": "Lambda.ResourceNotFoundException", "resource": "invoke", "resourceType": "lambda" @@ -1076,7 +1076,7 @@ "name": "Start", "output": { "Error": "Lambda.ResourceNotFoundException", - "Cause": "Function not found: arn::lambda::111111111111:function:no_such_ (Service: AWSLambda; Status Code: 404; Error Code: ResourceNotFoundException; Request ID: ; Proxy: null)" + "Cause": "Function not found: arn::lambda::111111111111:function:no_such_:$LATEST (Service: AWSLambda; Status Code: 404; Error Code: ResourceNotFoundException; Request ID: ; Proxy: null)" }, "outputDetails": { "truncated": false @@ -1091,7 +1091,7 @@ "stateEnteredEventDetails": { "input": { "Error": "Lambda.ResourceNotFoundException", - "Cause": "Function not found: arn::lambda::111111111111:function:no_such_ (Service: AWSLambda; Status Code: 404; Error Code: ResourceNotFoundException; Request ID: ; Proxy: null)" + "Cause": "Function not found: arn::lambda::111111111111:function:no_such_:$LATEST (Service: AWSLambda; Status Code: 404; Error Code: ResourceNotFoundException; Request ID: ; Proxy: null)" }, "inputDetails": { "truncated": false @@ -1108,10 +1108,10 @@ "name": "EndWithStateTaskFailedHandler", "output": { "Error": "Lambda.ResourceNotFoundException", - "Cause": "Function not found: arn::lambda::111111111111:function:no_such_ (Service: AWSLambda; Status Code: 404; Error Code: ResourceNotFoundException; Request ID: ; Proxy: null)", + "Cause": "Function not found: arn::lambda::111111111111:function:no_such_:$LATEST (Service: AWSLambda; Status Code: 404; Error Code: ResourceNotFoundException; Request ID: ; Proxy: null)", "task_failed_error": { "Error": "Lambda.ResourceNotFoundException", - "Cause": "Function not found: arn::lambda::111111111111:function:no_such_ (Service: AWSLambda; Status Code: 404; Error Code: ResourceNotFoundException; Request ID: ; Proxy: null)" + "Cause": "Function not found: arn::lambda::111111111111:function:no_such_:$LATEST (Service: AWSLambda; Status Code: 404; Error Code: ResourceNotFoundException; Request ID: ; Proxy: null)" } }, "outputDetails": { @@ -1125,10 +1125,10 @@ "executionSucceededEventDetails": { "output": { "Error": "Lambda.ResourceNotFoundException", - "Cause": "Function not found: arn::lambda::111111111111:function:no_such_ (Service: AWSLambda; Status Code: 404; Error Code: ResourceNotFoundException; Request ID: ; Proxy: null)", + "Cause": "Function not found: arn::lambda::111111111111:function:no_such_:$LATEST (Service: AWSLambda; Status Code: 404; Error Code: ResourceNotFoundException; Request ID: ; Proxy: null)", "task_failed_error": { "Error": "Lambda.ResourceNotFoundException", - "Cause": "Function not found: arn::lambda::111111111111:function:no_such_ (Service: AWSLambda; Status Code: 404; Error Code: ResourceNotFoundException; Request ID: ; Proxy: null)" + "Cause": "Function not found: arn::lambda::111111111111:function:no_such_:$LATEST (Service: AWSLambda; Status Code: 404; Error Code: ResourceNotFoundException; Request ID: ; Proxy: null)" } }, "outputDetails": { diff --git a/tests/aws/services/stepfunctions/v2/error_handling/test_task_service_lambda.validation.json b/tests/aws/services/stepfunctions/v2/error_handling/test_task_service_lambda.validation.json index 8d7be471fc48c..26ee197775553 100644 --- a/tests/aws/services/stepfunctions/v2/error_handling/test_task_service_lambda.validation.json +++ b/tests/aws/services/stepfunctions/v2/error_handling/test_task_service_lambda.validation.json @@ -3,10 +3,22 @@ "last_validated_date": "2024-11-28T13:05:54+00:00" }, "tests/aws/services/stepfunctions/v2/error_handling/test_task_service_lambda.py::TestTaskServiceLambda::test_no_such_function": { - "last_validated_date": "2024-11-28T13:05:16+00:00" + "last_validated_date": "2025-11-25T15:29:44+00:00", + "durations_in_seconds": { + "setup": 11.48, + "call": 16.85, + "teardown": 2.53, + "total": 30.86 + } }, "tests/aws/services/stepfunctions/v2/error_handling/test_task_service_lambda.py::TestTaskServiceLambda::test_no_such_function_catch": { - "last_validated_date": "2024-11-28T13:05:33+00:00" + "last_validated_date": "2025-11-25T21:15:40+00:00", + "durations_in_seconds": { + "setup": 11.11, + "call": 14.27, + "teardown": 1.84, + "total": 27.22 + } }, "tests/aws/services/stepfunctions/v2/error_handling/test_task_service_lambda.py::TestTaskServiceLambda::test_raise_custom_exception": { "last_validated_date": "2024-11-28T13:03:53+00:00" diff --git a/tests/aws/services/stepfunctions/v2/evaluate_jsonata/test_base_evaluate_expressions.py b/tests/aws/services/stepfunctions/v2/evaluate_jsonata/test_base_evaluate_expressions.py index 88fd4cd980971..6b9cf3885bc79 100644 --- a/tests/aws/services/stepfunctions/v2/evaluate_jsonata/test_base_evaluate_expressions.py +++ b/tests/aws/services/stepfunctions/v2/evaluate_jsonata/test_base_evaluate_expressions.py @@ -164,6 +164,30 @@ def test_base_jsonata_regular_expressions( execution_input=exec_input, ) + @markers.aws.validated + def test_merge_with_dynamic_args( + self, + aws_client, + create_state_machine_iam_role, + create_state_machine, + sfn_snapshot, + ): + """Regression test for #13579: $merge with dynamic variable references in array literals.""" + template = EJT.load_sfn_template(EJT.BASE_PASS) + template["States"]["Start"]["Output"] = ( + "{% $merge([$states.input.part1, $states.input.part2]) %}" + ) + definition = json.dumps(template) + exec_input = json.dumps({"part1": {"hello": "world"}, "part2": {"foo": "bar"}}) + create_and_record_execution( + aws_client, + create_state_machine_iam_role=create_state_machine_iam_role, + create_state_machine=create_state_machine, + sfn_snapshot=sfn_snapshot, + definition=definition, + execution_input=exec_input, + ) + @markers.aws.validated @pytest.mark.parametrize( "field,input_value", diff --git a/tests/aws/services/stepfunctions/v2/evaluate_jsonata/test_base_evaluate_expressions.snapshot.json b/tests/aws/services/stepfunctions/v2/evaluate_jsonata/test_base_evaluate_expressions.snapshot.json index e38998ae7801a..9f29e7d7c5a26 100644 --- a/tests/aws/services/stepfunctions/v2/evaluate_jsonata/test_base_evaluate_expressions.snapshot.json +++ b/tests/aws/services/stepfunctions/v2/evaluate_jsonata/test_base_evaluate_expressions.snapshot.json @@ -2355,5 +2355,89 @@ } } } + }, + "tests/aws/services/stepfunctions/v2/evaluate_jsonata/test_base_evaluate_expressions.py::TestBaseEvaluateJsonata::test_merge_with_dynamic_args": { + "recorded-date": "11-02-2026, 07:16:48", + "recorded-content": { + "get_execution_history": { + "events": [ + { + "executionStartedEventDetails": { + "input": { + "part1": { + "hello": "world" + }, + "part2": { + "foo": "bar" + } + }, + "inputDetails": { + "truncated": false + }, + "roleArn": "snf_role_arn" + }, + "id": 1, + "previousEventId": 0, + "timestamp": "timestamp", + "type": "ExecutionStarted" + }, + { + "id": 2, + "previousEventId": 0, + "stateEnteredEventDetails": { + "input": { + "part1": { + "hello": "world" + }, + "part2": { + "foo": "bar" + } + }, + "inputDetails": { + "truncated": false + }, + "name": "Start" + }, + "timestamp": "timestamp", + "type": "PassStateEntered" + }, + { + "id": 3, + "previousEventId": 2, + "stateExitedEventDetails": { + "name": "Start", + "output": { + "hello": "world", + "foo": "bar" + }, + "outputDetails": { + "truncated": false + } + }, + "timestamp": "timestamp", + "type": "PassStateExited" + }, + { + "executionSucceededEventDetails": { + "output": { + "hello": "world", + "foo": "bar" + }, + "outputDetails": { + "truncated": false + } + }, + "id": 4, + "previousEventId": 3, + "timestamp": "timestamp", + "type": "ExecutionSucceeded" + } + ], + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } } } diff --git a/tests/aws/services/stepfunctions/v2/evaluate_jsonata/test_base_evaluate_expressions.validation.json b/tests/aws/services/stepfunctions/v2/evaluate_jsonata/test_base_evaluate_expressions.validation.json index 3f52ee8c28602..a9a71a763e816 100644 --- a/tests/aws/services/stepfunctions/v2/evaluate_jsonata/test_base_evaluate_expressions.validation.json +++ b/tests/aws/services/stepfunctions/v2/evaluate_jsonata/test_base_evaluate_expressions.validation.json @@ -142,5 +142,14 @@ "teardown": 2.73, "total": 19.85 } + }, + "tests/aws/services/stepfunctions/v2/evaluate_jsonata/test_base_evaluate_expressions.py::TestBaseEvaluateJsonata::test_merge_with_dynamic_args": { + "last_validated_date": "2026-02-11T07:16:51+00:00", + "durations_in_seconds": { + "setup": 0.59, + "call": 35.92, + "teardown": 2.58, + "total": 39.09 + } } } diff --git a/localstack-core/localstack/services/sns/v2/models.py b/tests/aws/services/stepfunctions/v2/local_mocking/__init__.py similarity index 100% rename from localstack-core/localstack/services/sns/v2/models.py rename to tests/aws/services/stepfunctions/v2/local_mocking/__init__.py diff --git a/tests/aws/services/stepfunctions/v2/mocking/test_aws_scenarios.py b/tests/aws/services/stepfunctions/v2/local_mocking/test_aws_scenarios.py similarity index 94% rename from tests/aws/services/stepfunctions/v2/mocking/test_aws_scenarios.py rename to tests/aws/services/stepfunctions/v2/local_mocking/test_aws_scenarios.py index 0ced66200e798..94c13de0b7e31 100644 --- a/tests/aws/services/stepfunctions/v2/mocking/test_aws_scenarios.py +++ b/tests/aws/services/stepfunctions/v2/local_mocking/test_aws_scenarios.py @@ -3,13 +3,14 @@ from localstack.testing.pytest import markers from localstack.testing.pytest.stepfunctions.utils import create_and_run_mock from localstack.utils.strings import short_uid -from tests.aws.services.stepfunctions.mocked_service_integrations.mocked_service_integrations import ( +from tests.aws.services.stepfunctions.local_mocked_service_integrations.mocked_service_integrations import ( MockedServiceIntegrationsLoader, ) -from tests.aws.services.stepfunctions.templates.mocked.mocked_templates import MockedTemplates +from tests.aws.services.stepfunctions.templates.local_mocked.mocked_templates import MockedTemplates class TestBaseScenarios: + @markers.requires_in_process @markers.aws.only_localstack def test_lambda_sqs_integration_happy_path( self, @@ -46,6 +47,7 @@ def test_lambda_sqs_integration_happy_path( event_last = events[-1] assert event_last["type"] == "ExecutionSucceeded" + @markers.requires_in_process @markers.aws.only_localstack def test_lambda_sqs_integration_retry_path( self, @@ -103,6 +105,7 @@ def test_lambda_sqs_integration_retry_path( event_last = events[-1] assert event_last["type"] == "ExecutionSucceeded" + @markers.requires_in_process @markers.aws.only_localstack def test_lambda_sqs_integration_hybrid_path( self, diff --git a/tests/aws/services/stepfunctions/v2/mocking/test_base_callbacks.py b/tests/aws/services/stepfunctions/v2/local_mocking/test_base_callbacks.py similarity index 99% rename from tests/aws/services/stepfunctions/v2/mocking/test_base_callbacks.py rename to tests/aws/services/stepfunctions/v2/local_mocking/test_base_callbacks.py index 78ab730b6363a..571766f06e484 100644 --- a/tests/aws/services/stepfunctions/v2/mocking/test_base_callbacks.py +++ b/tests/aws/services/stepfunctions/v2/local_mocking/test_base_callbacks.py @@ -12,7 +12,7 @@ create_state_machine_with_iam_role, ) from localstack.utils.strings import short_uid -from tests.aws.services.stepfunctions.mocked_service_integrations.mocked_service_integrations import ( +from tests.aws.services.stepfunctions.local_mocked_service_integrations.mocked_service_integrations import ( MockedServiceIntegrationsLoader, ) from tests.aws.services.stepfunctions.templates.base.base_templates import BaseTemplate diff --git a/tests/aws/services/stepfunctions/v2/mocking/test_base_callbacks.snapshot.json b/tests/aws/services/stepfunctions/v2/local_mocking/test_base_callbacks.snapshot.json similarity index 96% rename from tests/aws/services/stepfunctions/v2/mocking/test_base_callbacks.snapshot.json rename to tests/aws/services/stepfunctions/v2/local_mocking/test_base_callbacks.snapshot.json index 4628554c854af..e99f063aefd21 100644 --- a/tests/aws/services/stepfunctions/v2/mocking/test_base_callbacks.snapshot.json +++ b/tests/aws/services/stepfunctions/v2/local_mocking/test_base_callbacks.snapshot.json @@ -1,6 +1,6 @@ { - "tests/aws/services/stepfunctions/v2/mocking/test_base_callbacks.py::TestBaseScenarios::test_sfn_start_execution_sync[SFN_SYNC]": { - "recorded-date": "24-04-2025, 10:05:48", + "tests/aws/services/stepfunctions/v2/local_mocking/test_base_callbacks.py::TestBaseScenarios::test_sfn_start_execution_sync[SFN_SYNC]": { + "recorded-date": "28-10-2025, 09:41:39", "recorded-content": { "get_execution_history": { "events": [ @@ -77,7 +77,7 @@ "keep-alive" ], "Content-Length": [ - "164" + "161" ], "Date": "date", "Content-Type": [ @@ -86,7 +86,7 @@ }, "HttpHeaders": { "connection": "keep-alive", - "Content-Length": "164", + "Content-Length": "161", "Content-Type": "application/x-amz-json-1.0", "Date": "date", "x-amzn-RequestId": "x-amzn-RequestId" @@ -208,8 +208,8 @@ } } }, - "tests/aws/services/stepfunctions/v2/mocking/test_base_callbacks.py::TestBaseScenarios::test_sfn_start_execution_sync[SFN_SYNC2]": { - "recorded-date": "24-04-2025, 10:06:22", + "tests/aws/services/stepfunctions/v2/local_mocking/test_base_callbacks.py::TestBaseScenarios::test_sfn_start_execution_sync[SFN_SYNC2]": { + "recorded-date": "28-10-2025, 09:42:11", "recorded-content": { "get_execution_history": { "events": [ @@ -286,7 +286,7 @@ "keep-alive" ], "Content-Length": [ - "164" + "161" ], "Date": "date", "Content-Type": [ @@ -295,7 +295,7 @@ }, "HttpHeaders": { "connection": "keep-alive", - "Content-Length": "164", + "Content-Length": "161", "Content-Type": "application/x-amz-json-1.0", "Date": "date", "x-amzn-RequestId": "x-amzn-RequestId" @@ -423,8 +423,8 @@ } } }, - "tests/aws/services/stepfunctions/v2/mocking/test_base_callbacks.py::TestBaseScenarios::test_sqs_wait_for_task_token": { - "recorded-date": "29-04-2025, 10:17:01", + "tests/aws/services/stepfunctions/v2/local_mocking/test_base_callbacks.py::TestBaseScenarios::test_sqs_wait_for_task_token": { + "recorded-date": "28-10-2025, 09:42:41", "recorded-content": { "get_execution_history": { "events": [ @@ -578,8 +578,8 @@ } } }, - "tests/aws/services/stepfunctions/v2/mocking/test_base_callbacks.py::TestBaseScenarios::test_sqs_wait_for_task_token_task_failure": { - "recorded-date": "29-04-2025, 11:15:14", + "tests/aws/services/stepfunctions/v2/local_mocking/test_base_callbacks.py::TestBaseScenarios::test_sqs_wait_for_task_token_task_failure": { + "recorded-date": "28-10-2025, 09:43:11", "recorded-content": { "get_execution_history": { "events": [ diff --git a/tests/aws/services/stepfunctions/v2/local_mocking/test_base_callbacks.validation.json b/tests/aws/services/stepfunctions/v2/local_mocking/test_base_callbacks.validation.json new file mode 100644 index 0000000000000..6ab28e711db38 --- /dev/null +++ b/tests/aws/services/stepfunctions/v2/local_mocking/test_base_callbacks.validation.json @@ -0,0 +1,38 @@ +{ + "tests/aws/services/stepfunctions/v2/local_mocking/test_base_callbacks.py::TestBaseScenarios::test_sfn_start_execution_sync[SFN_SYNC2]": { + "last_validated_date": "2025-10-28T09:42:14+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 28.55, + "teardown": 2.78, + "total": 31.33 + } + }, + "tests/aws/services/stepfunctions/v2/local_mocking/test_base_callbacks.py::TestBaseScenarios::test_sfn_start_execution_sync[SFN_SYNC]": { + "last_validated_date": "2025-10-28T09:41:42+00:00", + "durations_in_seconds": { + "setup": 0.51, + "call": 29.71, + "teardown": 3.07, + "total": 33.29 + } + }, + "tests/aws/services/stepfunctions/v2/local_mocking/test_base_callbacks.py::TestBaseScenarios::test_sqs_wait_for_task_token": { + "last_validated_date": "2025-10-28T09:42:43+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 27.0, + "teardown": 2.67, + "total": 29.67 + } + }, + "tests/aws/services/stepfunctions/v2/local_mocking/test_base_callbacks.py::TestBaseScenarios::test_sqs_wait_for_task_token_task_failure": { + "last_validated_date": "2025-10-28T09:43:14+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 27.62, + "teardown": 2.66, + "total": 30.28 + } + } +} diff --git a/tests/aws/services/stepfunctions/v2/mocking/test_base_scenarios.py b/tests/aws/services/stepfunctions/v2/local_mocking/test_base_scenarios.py similarity index 87% rename from tests/aws/services/stepfunctions/v2/mocking/test_base_scenarios.py rename to tests/aws/services/stepfunctions/v2/local_mocking/test_base_scenarios.py index cfaccf6623702..93cc95063edfe 100644 --- a/tests/aws/services/stepfunctions/v2/mocking/test_base_scenarios.py +++ b/tests/aws/services/stepfunctions/v2/local_mocking/test_base_scenarios.py @@ -16,8 +16,9 @@ create_and_record_mocked_execution, create_and_record_mocked_sync_execution, ) +from localstack.utils.aws import arns from localstack.utils.strings import short_uid -from tests.aws.services.stepfunctions.mocked_service_integrations.mocked_service_integrations import ( +from tests.aws.services.stepfunctions.local_mocked_service_integrations.mocked_service_integrations import ( MockedServiceIntegrationsLoader, ) from tests.aws.services.stepfunctions.templates.scenarios.scenarios_templates import ( @@ -323,8 +324,8 @@ def test_sqs_send_message( if is_aws_cloud(): queue_name = f"queue-{short_uid()}" queue_url = sqs_create_queue(QueueName=queue_name) - sfn_snapshot.add_transformer(RegexTransformer(queue_name, "sqs-queue-name")) sfn_snapshot.add_transformer(RegexTransformer(queue_url, "sqs-queue-url")) + sfn_snapshot.add_transformer(RegexTransformer(queue_name, "sqs-queue-name")) exec_input = json.dumps({"QueueUrl": queue_url, "MessageBody": message_body}) create_and_record_execution( @@ -605,7 +606,7 @@ def test_map_state_lambda( state_machine_name = f"mocked_state_machine_{short_uid()}" test_name = "TestCaseName" lambda_200_string_body = MockedServiceIntegrationsLoader.load( - MockedServiceIntegrationsLoader.MOCKED_RESPONSE_LAMBDA_200_STRING_BODY + MockedServiceIntegrationsLoader.MOCKED_RESPONSE_LAMBDA_200_STRING_BODY_TWO_INVOCATIONS ) mock_config = { "StateMachines": { @@ -659,6 +660,20 @@ def test_parallel_state_lambda( sfn_snapshot.add_transformer( RegexTransformer(function_name_branch2, "function_name_branch2") ) + sfn_snapshot.add_transformer( + JsonpathTransformer( + "$..stateExitedEventDetails.output", + "stateExitedEventDetails.output", + replace_reference=False, + ) + ) + sfn_snapshot.add_transformer( + JsonpathTransformer( + "$..executionSucceededEventDetails.output", + "executionSucceededEventDetails.output", + replace_reference=False, + ) + ) exec_input = json.dumps( { @@ -727,3 +742,86 @@ def test_parallel_state_lambda( state_machine_name, test_name, ) + + @markers.aws.validated + def test_numbered_mock_responses_multiple_success_invocations( + self, + aws_client, + create_state_machine_iam_role, + create_state_machine, + create_lambda_function, + account_id, + region_name, + sfn_snapshot, + monkeypatch, + mock_config_file, + ): + """ + Test that numbered mock responses ("0", "1", etc.) iterate correctly + through multiple successful invocations of the same state, + e.g. in a repeat-until loop implemented using a choice state. + """ + template = ScenariosTemplate.load_sfn_template(ScenariosTemplate.LAMBDA_REPEAT_UNTIL_LOOP) + template["States"]["LambdaState"]["Arguments"]["Payload"] = { + "status": "{% $exists($status) ? 'completed' : 'running' %}" + } + + exec_input = json.dumps({}) + function_name = f"lambda_{short_uid()}" + sfn_snapshot.add_transformer(RegexTransformer(function_name, "lambda_function_name")) + + if is_aws_cloud(): + lambda_creation_response = create_lambda_function( + func_name=function_name, + handler_file=ServicesTemplates.LAMBDA_ID_FUNCTION, + runtime=Runtime.python3_12, + ) + lambda_arn = lambda_creation_response["CreateFunctionResponse"]["FunctionArn"] + template["States"]["LambdaState"]["Arguments"]["FunctionName"] = lambda_arn + definition = json.dumps(template) + create_and_record_execution( + aws_client, + create_state_machine_iam_role, + create_state_machine, + sfn_snapshot, + definition, + exec_input, + ) + else: + state_machine_name = f"mock_cycling_test_{short_uid()}" + test_name = "NumberedResponseCyclingTest" + + sfn_snapshot.add_transformer(RegexTransformer(state_machine_name, "state_machine_name")) + + lambda_200_loop_status = MockedServiceIntegrationsLoader.load( + MockedServiceIntegrationsLoader.MOCKED_RESPONSE_LAMBDA_200_STATUS_CHANGE_BETWEEN_INVOCATIONS + ) + mock_config = { + "StateMachines": { + state_machine_name: { + "TestCases": {test_name: {"LambdaState": "lambda_200_loop_status"}} + } + }, + "MockedResponses": {"lambda_200_loop_status": lambda_200_loop_status}, + } + + mock_config_file_path = mock_config_file(mock_config) + monkeypatch.setattr(config, "SFN_MOCK_CONFIG", mock_config_file_path) + + template["States"]["LambdaState"]["Arguments"]["FunctionName"] = ( + arns.lambda_function_arn( + function_name=function_name, account_id=account_id, region_name=region_name + ) + ) + definition = json.dumps(template) + + create_and_record_mocked_execution( + aws_client, + create_state_machine_iam_role, + create_state_machine, + sfn_snapshot, + definition, + exec_input, + state_machine_name, + test_name, + ) diff --git a/tests/aws/services/stepfunctions/v2/mocking/test_base_scenarios.snapshot.json b/tests/aws/services/stepfunctions/v2/local_mocking/test_base_scenarios.snapshot.json similarity index 75% rename from tests/aws/services/stepfunctions/v2/mocking/test_base_scenarios.snapshot.json rename to tests/aws/services/stepfunctions/v2/local_mocking/test_base_scenarios.snapshot.json index 739ec3945461f..0d50c20c34f70 100644 --- a/tests/aws/services/stepfunctions/v2/mocking/test_base_scenarios.snapshot.json +++ b/tests/aws/services/stepfunctions/v2/local_mocking/test_base_scenarios.snapshot.json @@ -1,6 +1,6 @@ { - "tests/aws/services/stepfunctions/v2/mocking/test_base_scenarios.py::TestBaseScenarios::test_lambda_service_invoke": { - "recorded-date": "14-04-2025, 18:51:50", + "tests/aws/services/stepfunctions/v2/local_mocking/test_base_scenarios.py::TestBaseScenarios::test_lambda_service_invoke": { + "recorded-date": "28-10-2025, 09:44:00", "recorded-content": { "get_execution_history": { "events": [ @@ -436,8 +436,8 @@ } } }, - "tests/aws/services/stepfunctions/v2/mocking/test_base_scenarios.py::TestBaseScenarios::test_lambda_invoke": { - "recorded-date": "22-04-2025, 10:30:21", + "tests/aws/services/stepfunctions/v2/local_mocking/test_base_scenarios.py::TestBaseScenarios::test_lambda_invoke": { + "recorded-date": "28-10-2025, 09:43:41", "recorded-content": { "get_execution_history": { "events": [ @@ -543,8 +543,8 @@ } } }, - "tests/aws/services/stepfunctions/v2/mocking/test_base_scenarios.py::TestBaseScenarios::test_sqs_send_message": { - "recorded-date": "22-04-2025, 19:39:14", + "tests/aws/services/stepfunctions/v2/local_mocking/test_base_scenarios.py::TestBaseScenarios::test_sqs_send_message": { + "recorded-date": "28-10-2025, 10:04:26", "recorded-content": { "get_execution_history": { "events": [ @@ -739,8 +739,8 @@ } } }, - "tests/aws/services/stepfunctions/v2/mocking/test_base_scenarios.py::TestBaseScenarios::test_sns_publish_base": { - "recorded-date": "23-04-2025, 13:52:23", + "tests/aws/services/stepfunctions/v2/local_mocking/test_base_scenarios.py::TestBaseScenarios::test_sns_publish_base": { + "recorded-date": "28-10-2025, 09:44:52", "recorded-content": { "get_execution_history": { "events": [ @@ -938,8 +938,8 @@ } } }, - "tests/aws/services/stepfunctions/v2/mocking/test_base_scenarios.py::TestBaseScenarios::test_events_put_events": { - "recorded-date": "23-04-2025, 14:28:24", + "tests/aws/services/stepfunctions/v2/local_mocking/test_base_scenarios.py::TestBaseScenarios::test_events_put_events": { + "recorded-date": "28-10-2025, 09:45:08", "recorded-content": { "get_execution_history": { "events": [ @@ -1083,8 +1083,8 @@ } } }, - "tests/aws/services/stepfunctions/v2/mocking/test_base_scenarios.py::TestBaseScenarios::test_dynamodb_put_get_item": { - "recorded-date": "23-04-2025, 15:32:30", + "tests/aws/services/stepfunctions/v2/local_mocking/test_base_scenarios.py::TestBaseScenarios::test_dynamodb_put_get_item": { + "recorded-date": "28-10-2025, 09:45:33", "recorded-content": { "get_execution_history": { "events": [ @@ -1646,8 +1646,8 @@ } } }, - "tests/aws/services/stepfunctions/v2/mocking/test_base_scenarios.py::TestBaseScenarios::test_map_state_lambda": { - "recorded-date": "24-04-2025, 11:11:05", + "tests/aws/services/stepfunctions/v2/local_mocking/test_base_scenarios.py::TestBaseScenarios::test_map_state_lambda": { + "recorded-date": "28-10-2025, 09:45:56", "recorded-content": { "get_execution_history": { "events": [ @@ -2064,8 +2064,8 @@ } } }, - "tests/aws/services/stepfunctions/v2/mocking/test_base_scenarios.py::TestBaseScenarios::test_parallel_state_lambda": { - "recorded-date": "28-04-2025, 12:36:06", + "tests/aws/services/stepfunctions/v2/local_mocking/test_base_scenarios.py::TestBaseScenarios::test_parallel_state_lambda": { + "recorded-date": "28-10-2025, 10:19:56", "recorded-content": { "get_execution_history": { "events": [ @@ -2162,49 +2162,7 @@ "previousEventId": 0, "stateExitedEventDetails": { "name": "Branch1", - "output": { - "ExecutedVersion": "$LATEST", - "Payload": [ - "string-literal" - ], - "SdkHttpMetadata": { - "AllHttpHeaders": { - "X-Amz-Executed-Version": [ - "$LATEST" - ], - "x-amzn-Remapped-Content-Length": [ - "0" - ], - "Connection": [ - "keep-alive" - ], - "x-amzn-RequestId": "x-amzn-RequestId", - "Content-Length": [ - "18" - ], - "Date": "date", - "X-Amzn-Trace-Id": "X-Amzn-Trace-Id", - "Content-Type": [ - "application/json" - ] - }, - "HttpHeaders": { - "Connection": "keep-alive", - "Content-Length": "18", - "Content-Type": "application/json", - "Date": "date", - "X-Amz-Executed-Version": "$LATEST", - "x-amzn-Remapped-Content-Length": "0", - "x-amzn-RequestId": "x-amzn-RequestId", - "X-Amzn-Trace-Id": "X-Amzn-Trace-Id" - }, - "HttpStatusCode": 200 - }, - "SdkResponseMetadata": { - "RequestId": "RequestId" - }, - "StatusCode": 200 - }, + "output": "stateExitedEventDetails.output", "outputDetails": { "truncated": false } @@ -2219,47 +2177,7 @@ "previousEventId": 0, "stateExitedEventDetails": { "name": "Branch2", - "output": { - "ExecutedVersion": "$LATEST", - "Payload": "input-event-['string-literal']", - "SdkHttpMetadata": { - "AllHttpHeaders": { - "X-Amz-Executed-Version": [ - "$LATEST" - ], - "x-amzn-Remapped-Content-Length": [ - "0" - ], - "Connection": [ - "keep-alive" - ], - "x-amzn-RequestId": "x-amzn-RequestId", - "Content-Length": [ - "32" - ], - "Date": "date", - "X-Amzn-Trace-Id": "X-Amzn-Trace-Id", - "Content-Type": [ - "application/json" - ] - }, - "HttpHeaders": { - "Connection": "keep-alive", - "Content-Length": "32", - "Content-Type": "application/json", - "Date": "date", - "X-Amz-Executed-Version": "$LATEST", - "x-amzn-Remapped-Content-Length": "0", - "x-amzn-RequestId": "x-amzn-RequestId", - "X-Amzn-Trace-Id": "X-Amzn-Trace-Id" - }, - "HttpStatusCode": 200 - }, - "SdkResponseMetadata": { - "RequestId": "RequestId" - }, - "StatusCode": 200 - }, + "output": "stateExitedEventDetails.output", "outputDetails": { "truncated": false } @@ -2448,7 +2366,7 @@ "previousEventId": 13, "stateExitedEventDetails": { "name": "ParallelState", - "output": "[{\"ExecutedVersion\":\"$LATEST\",\"Payload\":[\"string-literal\"],\"SdkHttpMetadata\":{\"AllHttpHeaders\":{\"X-Amz-Executed-Version\":[\"$LATEST\"],\"x-amzn-Remapped-Content-Length\":[\"0\"],\"Connection\":[\"keep-alive\"],\"x-amzn-RequestId\":[\"c455c86f-6cb5-4d5d-8a71-4f0a98b33059\"],\"Content-Length\":[\"18\"],\"Date\":[\"Mon, 28 Apr 2025 12:36:05 GMT\"],\"X-Amzn-Trace-Id\":[\"Root=1-680f7635-0182b6d14f9778376d202e25;Parent=7880c132e0e2009b;Sampled=0;Lineage=1:816810b0:0\"],\"Content-Type\":[\"application/json\"]},\"HttpHeaders\":{\"Connection\":\"keep-alive\",\"Content-Length\":\"18\",\"Content-Type\":\"application/json\",\"Date\":\"Mon, 28 Apr 2025 12:36:05 GMT\",\"X-Amz-Executed-Version\":\"$LATEST\",\"x-amzn-Remapped-Content-Length\":\"0\",\"x-amzn-RequestId\":\"c455c86f-6cb5-4d5d-8a71-4f0a98b33059\",\"X-Amzn-Trace-Id\":\"Root=1-680f7635-0182b6d14f9778376d202e25;Parent=7880c132e0e2009b;Sampled=0;Lineage=1:816810b0:0\"},\"HttpStatusCode\":200},\"SdkResponseMetadata\":{\"RequestId\":\"c455c86f-6cb5-4d5d-8a71-4f0a98b33059\"},\"StatusCode\":200},{\"ExecutedVersion\":\"$LATEST\",\"Payload\":\"input-event-['string-literal']\",\"SdkHttpMetadata\":{\"AllHttpHeaders\":{\"X-Amz-Executed-Version\":[\"$LATEST\"],\"x-amzn-Remapped-Content-Length\":[\"0\"],\"Connection\":[\"keep-alive\"],\"x-amzn-RequestId\":[\"bee07bb2-41e2-4c9f-9f6f-1a70696cc112\"],\"Content-Length\":[\"32\"],\"Date\":[\"Mon, 28 Apr 2025 12:36:05 GMT\"],\"X-Amzn-Trace-Id\":[\"Root=1-680f7635-5bd01853792e73951459090c;Parent=56aa9955dca169e9;Sampled=0;Lineage=1:786b2a01:0\"],\"Content-Type\":[\"application/json\"]},\"HttpHeaders\":{\"Connection\":\"keep-alive\",\"Content-Length\":\"32\",\"Content-Type\":\"application/json\",\"Date\":\"Mon, 28 Apr 2025 12:36:05 GMT\",\"X-Amz-Executed-Version\":\"$LATEST\",\"x-amzn-Remapped-Content-Length\":\"0\",\"x-amzn-RequestId\":\"bee07bb2-41e2-4c9f-9f6f-1a70696cc112\",\"X-Amzn-Trace-Id\":\"Root=1-680f7635-5bd01853792e73951459090c;Parent=56aa9955dca169e9;Sampled=0;Lineage=1:786b2a01:0\"},\"HttpStatusCode\":200},\"SdkResponseMetadata\":{\"RequestId\":\"bee07bb2-41e2-4c9f-9f6f-1a70696cc112\"},\"StatusCode\":200}]", + "output": "stateExitedEventDetails.output", "outputDetails": { "truncated": false } @@ -2458,7 +2376,7 @@ }, { "executionSucceededEventDetails": { - "output": "[{\"ExecutedVersion\":\"$LATEST\",\"Payload\":[\"string-literal\"],\"SdkHttpMetadata\":{\"AllHttpHeaders\":{\"X-Amz-Executed-Version\":[\"$LATEST\"],\"x-amzn-Remapped-Content-Length\":[\"0\"],\"Connection\":[\"keep-alive\"],\"x-amzn-RequestId\":[\"c455c86f-6cb5-4d5d-8a71-4f0a98b33059\"],\"Content-Length\":[\"18\"],\"Date\":[\"Mon, 28 Apr 2025 12:36:05 GMT\"],\"X-Amzn-Trace-Id\":[\"Root=1-680f7635-0182b6d14f9778376d202e25;Parent=7880c132e0e2009b;Sampled=0;Lineage=1:816810b0:0\"],\"Content-Type\":[\"application/json\"]},\"HttpHeaders\":{\"Connection\":\"keep-alive\",\"Content-Length\":\"18\",\"Content-Type\":\"application/json\",\"Date\":\"Mon, 28 Apr 2025 12:36:05 GMT\",\"X-Amz-Executed-Version\":\"$LATEST\",\"x-amzn-Remapped-Content-Length\":\"0\",\"x-amzn-RequestId\":\"c455c86f-6cb5-4d5d-8a71-4f0a98b33059\",\"X-Amzn-Trace-Id\":\"Root=1-680f7635-0182b6d14f9778376d202e25;Parent=7880c132e0e2009b;Sampled=0;Lineage=1:816810b0:0\"},\"HttpStatusCode\":200},\"SdkResponseMetadata\":{\"RequestId\":\"c455c86f-6cb5-4d5d-8a71-4f0a98b33059\"},\"StatusCode\":200},{\"ExecutedVersion\":\"$LATEST\",\"Payload\":\"input-event-['string-literal']\",\"SdkHttpMetadata\":{\"AllHttpHeaders\":{\"X-Amz-Executed-Version\":[\"$LATEST\"],\"x-amzn-Remapped-Content-Length\":[\"0\"],\"Connection\":[\"keep-alive\"],\"x-amzn-RequestId\":[\"bee07bb2-41e2-4c9f-9f6f-1a70696cc112\"],\"Content-Length\":[\"32\"],\"Date\":[\"Mon, 28 Apr 2025 12:36:05 GMT\"],\"X-Amzn-Trace-Id\":[\"Root=1-680f7635-5bd01853792e73951459090c;Parent=56aa9955dca169e9;Sampled=0;Lineage=1:786b2a01:0\"],\"Content-Type\":[\"application/json\"]},\"HttpHeaders\":{\"Connection\":\"keep-alive\",\"Content-Length\":\"32\",\"Content-Type\":\"application/json\",\"Date\":\"Mon, 28 Apr 2025 12:36:05 GMT\",\"X-Amz-Executed-Version\":\"$LATEST\",\"x-amzn-Remapped-Content-Length\":\"0\",\"x-amzn-RequestId\":\"bee07bb2-41e2-4c9f-9f6f-1a70696cc112\",\"X-Amzn-Trace-Id\":\"Root=1-680f7635-5bd01853792e73951459090c;Parent=56aa9955dca169e9;Sampled=0;Lineage=1:786b2a01:0\"},\"HttpStatusCode\":200},\"SdkResponseMetadata\":{\"RequestId\":\"bee07bb2-41e2-4c9f-9f6f-1a70696cc112\"},\"StatusCode\":200}]", + "output": "executionSucceededEventDetails.output", "outputDetails": { "truncated": false } @@ -2476,8 +2394,8 @@ } } }, - "tests/aws/services/stepfunctions/v2/mocking/test_base_scenarios.py::TestBaseScenarios::test_lambda_service_invoke_sync_execution": { - "recorded-date": "03-06-2025, 18:47:04", + "tests/aws/services/stepfunctions/v2/local_mocking/test_base_scenarios.py::TestBaseScenarios::test_lambda_service_invoke_sync_execution": { + "recorded-date": "28-10-2025, 09:44:18", "recorded-content": { "creation_response": { "creationDate": "datetime", @@ -2489,7 +2407,7 @@ }, "start_execution_sync_response": { "billingDetails": { - "billedDurationInMilliseconds": 300, + "billedDurationInMilliseconds": 400, "billedMemoryUsedInMB": 64 }, "executionArn": "arn::states::111111111111:express:::", @@ -2602,5 +2520,771 @@ } } } + }, + "tests/aws/services/stepfunctions/v2/local_mocking/test_base_scenarios.py::TestBaseScenarios::test_numbered_mock_responses_multiple_success_invocations": { + "recorded-date": "04-02-2026, 08:37:50", + "recorded-content": { + "get_execution_history": { + "events": [ + { + "executionStartedEventDetails": { + "input": {}, + "inputDetails": { + "truncated": false + }, + "roleArn": "snf_role_arn" + }, + "id": 1, + "previousEventId": 0, + "timestamp": "timestamp", + "type": "ExecutionStarted" + }, + { + "id": 2, + "previousEventId": 0, + "stateEnteredEventDetails": { + "input": {}, + "inputDetails": { + "truncated": false + }, + "name": "LambdaState" + }, + "timestamp": "timestamp", + "type": "TaskStateEntered" + }, + { + "id": 3, + "previousEventId": 2, + "taskScheduledEventDetails": { + "parameters": { + "FunctionName": "arn::lambda::111111111111:function:lambda_function_name", + "Payload": { + "status": "running" + } + }, + "region": "", + "resource": "invoke", + "resourceType": "lambda" + }, + "timestamp": "timestamp", + "type": "TaskScheduled" + }, + { + "id": 4, + "previousEventId": 3, + "taskStartedEventDetails": { + "resource": "invoke", + "resourceType": "lambda" + }, + "timestamp": "timestamp", + "type": "TaskStarted" + }, + { + "id": 5, + "previousEventId": 4, + "taskSucceededEventDetails": { + "output": { + "ExecutedVersion": "$LATEST", + "Payload": { + "status": "running" + }, + "SdkHttpMetadata": { + "AllHttpHeaders": { + "X-Amz-Executed-Version": [ + "$LATEST" + ], + "x-amzn-Remapped-Content-Length": [ + "0" + ], + "Connection": [ + "keep-alive" + ], + "x-amzn-RequestId": "x-amzn-RequestId", + "Content-Length": [ + "21" + ], + "Date": "date", + "X-Amzn-Trace-Id": "X-Amzn-Trace-Id", + "Content-Type": [ + "application/json" + ] + }, + "HttpHeaders": { + "Connection": "keep-alive", + "Content-Length": "21", + "Content-Type": "application/json", + "Date": "date", + "X-Amz-Executed-Version": "$LATEST", + "x-amzn-Remapped-Content-Length": "0", + "x-amzn-RequestId": "x-amzn-RequestId", + "X-Amzn-Trace-Id": "X-Amzn-Trace-Id" + }, + "HttpStatusCode": 200 + }, + "SdkResponseMetadata": { + "RequestId": "RequestId" + }, + "StatusCode": 200 + }, + "outputDetails": { + "truncated": false + }, + "resource": "invoke", + "resourceType": "lambda" + }, + "timestamp": "timestamp", + "type": "TaskSucceeded" + }, + { + "id": 6, + "previousEventId": 5, + "stateExitedEventDetails": { + "assignedVariables": { + "status": "\"running\"" + }, + "assignedVariablesDetails": { + "truncated": false + }, + "name": "LambdaState", + "output": { + "ExecutedVersion": "$LATEST", + "Payload": { + "status": "running" + }, + "SdkHttpMetadata": { + "AllHttpHeaders": { + "X-Amz-Executed-Version": [ + "$LATEST" + ], + "x-amzn-Remapped-Content-Length": [ + "0" + ], + "Connection": [ + "keep-alive" + ], + "x-amzn-RequestId": "x-amzn-RequestId", + "Content-Length": [ + "21" + ], + "Date": "date", + "X-Amzn-Trace-Id": "X-Amzn-Trace-Id", + "Content-Type": [ + "application/json" + ] + }, + "HttpHeaders": { + "Connection": "keep-alive", + "Content-Length": "21", + "Content-Type": "application/json", + "Date": "date", + "X-Amz-Executed-Version": "$LATEST", + "x-amzn-Remapped-Content-Length": "0", + "x-amzn-RequestId": "x-amzn-RequestId", + "X-Amzn-Trace-Id": "X-Amzn-Trace-Id" + }, + "HttpStatusCode": 200 + }, + "SdkResponseMetadata": { + "RequestId": "RequestId" + }, + "StatusCode": 200 + }, + "outputDetails": { + "truncated": false + } + }, + "timestamp": "timestamp", + "type": "TaskStateExited" + }, + { + "id": 7, + "previousEventId": 6, + "stateEnteredEventDetails": { + "input": { + "ExecutedVersion": "$LATEST", + "Payload": { + "status": "running" + }, + "SdkHttpMetadata": { + "AllHttpHeaders": { + "X-Amz-Executed-Version": [ + "$LATEST" + ], + "x-amzn-Remapped-Content-Length": [ + "0" + ], + "Connection": [ + "keep-alive" + ], + "x-amzn-RequestId": "x-amzn-RequestId", + "Content-Length": [ + "21" + ], + "Date": "date", + "X-Amzn-Trace-Id": "X-Amzn-Trace-Id", + "Content-Type": [ + "application/json" + ] + }, + "HttpHeaders": { + "Connection": "keep-alive", + "Content-Length": "21", + "Content-Type": "application/json", + "Date": "date", + "X-Amz-Executed-Version": "$LATEST", + "x-amzn-Remapped-Content-Length": "0", + "x-amzn-RequestId": "x-amzn-RequestId", + "X-Amzn-Trace-Id": "X-Amzn-Trace-Id" + }, + "HttpStatusCode": 200 + }, + "SdkResponseMetadata": { + "RequestId": "RequestId" + }, + "StatusCode": 200 + }, + "inputDetails": { + "truncated": false + }, + "name": "CheckCompleted" + }, + "timestamp": "timestamp", + "type": "ChoiceStateEntered" + }, + { + "id": 8, + "previousEventId": 7, + "stateExitedEventDetails": { + "name": "CheckCompleted", + "output": { + "ExecutedVersion": "$LATEST", + "Payload": { + "status": "running" + }, + "SdkHttpMetadata": { + "AllHttpHeaders": { + "X-Amz-Executed-Version": [ + "$LATEST" + ], + "x-amzn-Remapped-Content-Length": [ + "0" + ], + "Connection": [ + "keep-alive" + ], + "x-amzn-RequestId": "x-amzn-RequestId", + "Content-Length": [ + "21" + ], + "Date": "date", + "X-Amzn-Trace-Id": "X-Amzn-Trace-Id", + "Content-Type": [ + "application/json" + ] + }, + "HttpHeaders": { + "Connection": "keep-alive", + "Content-Length": "21", + "Content-Type": "application/json", + "Date": "date", + "X-Amz-Executed-Version": "$LATEST", + "x-amzn-Remapped-Content-Length": "0", + "x-amzn-RequestId": "x-amzn-RequestId", + "X-Amzn-Trace-Id": "X-Amzn-Trace-Id" + }, + "HttpStatusCode": 200 + }, + "SdkResponseMetadata": { + "RequestId": "RequestId" + }, + "StatusCode": 200 + }, + "outputDetails": { + "truncated": false + } + }, + "timestamp": "timestamp", + "type": "ChoiceStateExited" + }, + { + "id": 9, + "previousEventId": 8, + "stateEnteredEventDetails": { + "input": { + "ExecutedVersion": "$LATEST", + "Payload": { + "status": "running" + }, + "SdkHttpMetadata": { + "AllHttpHeaders": { + "X-Amz-Executed-Version": [ + "$LATEST" + ], + "x-amzn-Remapped-Content-Length": [ + "0" + ], + "Connection": [ + "keep-alive" + ], + "x-amzn-RequestId": "x-amzn-RequestId", + "Content-Length": [ + "21" + ], + "Date": "date", + "X-Amzn-Trace-Id": "X-Amzn-Trace-Id", + "Content-Type": [ + "application/json" + ] + }, + "HttpHeaders": { + "Connection": "keep-alive", + "Content-Length": "21", + "Content-Type": "application/json", + "Date": "date", + "X-Amz-Executed-Version": "$LATEST", + "x-amzn-Remapped-Content-Length": "0", + "x-amzn-RequestId": "x-amzn-RequestId", + "X-Amzn-Trace-Id": "X-Amzn-Trace-Id" + }, + "HttpStatusCode": 200 + }, + "SdkResponseMetadata": { + "RequestId": "RequestId" + }, + "StatusCode": 200 + }, + "inputDetails": { + "truncated": false + }, + "name": "LambdaState" + }, + "timestamp": "timestamp", + "type": "TaskStateEntered" + }, + { + "id": 10, + "previousEventId": 9, + "taskScheduledEventDetails": { + "parameters": { + "FunctionName": "arn::lambda::111111111111:function:lambda_function_name", + "Payload": { + "status": "completed" + } + }, + "region": "", + "resource": "invoke", + "resourceType": "lambda" + }, + "timestamp": "timestamp", + "type": "TaskScheduled" + }, + { + "id": 11, + "previousEventId": 10, + "taskStartedEventDetails": { + "resource": "invoke", + "resourceType": "lambda" + }, + "timestamp": "timestamp", + "type": "TaskStarted" + }, + { + "id": 12, + "previousEventId": 11, + "taskSucceededEventDetails": { + "output": { + "ExecutedVersion": "$LATEST", + "Payload": { + "status": "completed" + }, + "SdkHttpMetadata": { + "AllHttpHeaders": { + "X-Amz-Executed-Version": [ + "$LATEST" + ], + "x-amzn-Remapped-Content-Length": [ + "0" + ], + "Connection": [ + "keep-alive" + ], + "x-amzn-RequestId": "x-amzn-RequestId", + "Content-Length": [ + "23" + ], + "Date": "date", + "X-Amzn-Trace-Id": "X-Amzn-Trace-Id", + "Content-Type": [ + "application/json" + ] + }, + "HttpHeaders": { + "Connection": "keep-alive", + "Content-Length": "23", + "Content-Type": "application/json", + "Date": "date", + "X-Amz-Executed-Version": "$LATEST", + "x-amzn-Remapped-Content-Length": "0", + "x-amzn-RequestId": "x-amzn-RequestId", + "X-Amzn-Trace-Id": "X-Amzn-Trace-Id" + }, + "HttpStatusCode": 200 + }, + "SdkResponseMetadata": { + "RequestId": "RequestId" + }, + "StatusCode": 200 + }, + "outputDetails": { + "truncated": false + }, + "resource": "invoke", + "resourceType": "lambda" + }, + "timestamp": "timestamp", + "type": "TaskSucceeded" + }, + { + "id": 13, + "previousEventId": 12, + "stateExitedEventDetails": { + "assignedVariables": { + "status": "\"completed\"" + }, + "assignedVariablesDetails": { + "truncated": false + }, + "name": "LambdaState", + "output": { + "ExecutedVersion": "$LATEST", + "Payload": { + "status": "completed" + }, + "SdkHttpMetadata": { + "AllHttpHeaders": { + "X-Amz-Executed-Version": [ + "$LATEST" + ], + "x-amzn-Remapped-Content-Length": [ + "0" + ], + "Connection": [ + "keep-alive" + ], + "x-amzn-RequestId": "x-amzn-RequestId", + "Content-Length": [ + "23" + ], + "Date": "date", + "X-Amzn-Trace-Id": "X-Amzn-Trace-Id", + "Content-Type": [ + "application/json" + ] + }, + "HttpHeaders": { + "Connection": "keep-alive", + "Content-Length": "23", + "Content-Type": "application/json", + "Date": "date", + "X-Amz-Executed-Version": "$LATEST", + "x-amzn-Remapped-Content-Length": "0", + "x-amzn-RequestId": "x-amzn-RequestId", + "X-Amzn-Trace-Id": "X-Amzn-Trace-Id" + }, + "HttpStatusCode": 200 + }, + "SdkResponseMetadata": { + "RequestId": "RequestId" + }, + "StatusCode": 200 + }, + "outputDetails": { + "truncated": false + } + }, + "timestamp": "timestamp", + "type": "TaskStateExited" + }, + { + "id": 14, + "previousEventId": 13, + "stateEnteredEventDetails": { + "input": { + "ExecutedVersion": "$LATEST", + "Payload": { + "status": "completed" + }, + "SdkHttpMetadata": { + "AllHttpHeaders": { + "X-Amz-Executed-Version": [ + "$LATEST" + ], + "x-amzn-Remapped-Content-Length": [ + "0" + ], + "Connection": [ + "keep-alive" + ], + "x-amzn-RequestId": "x-amzn-RequestId", + "Content-Length": [ + "23" + ], + "Date": "date", + "X-Amzn-Trace-Id": "X-Amzn-Trace-Id", + "Content-Type": [ + "application/json" + ] + }, + "HttpHeaders": { + "Connection": "keep-alive", + "Content-Length": "23", + "Content-Type": "application/json", + "Date": "date", + "X-Amz-Executed-Version": "$LATEST", + "x-amzn-Remapped-Content-Length": "0", + "x-amzn-RequestId": "x-amzn-RequestId", + "X-Amzn-Trace-Id": "X-Amzn-Trace-Id" + }, + "HttpStatusCode": 200 + }, + "SdkResponseMetadata": { + "RequestId": "RequestId" + }, + "StatusCode": 200 + }, + "inputDetails": { + "truncated": false + }, + "name": "CheckCompleted" + }, + "timestamp": "timestamp", + "type": "ChoiceStateEntered" + }, + { + "id": 15, + "previousEventId": 14, + "stateExitedEventDetails": { + "name": "CheckCompleted", + "output": { + "ExecutedVersion": "$LATEST", + "Payload": { + "status": "completed" + }, + "SdkHttpMetadata": { + "AllHttpHeaders": { + "X-Amz-Executed-Version": [ + "$LATEST" + ], + "x-amzn-Remapped-Content-Length": [ + "0" + ], + "Connection": [ + "keep-alive" + ], + "x-amzn-RequestId": "x-amzn-RequestId", + "Content-Length": [ + "23" + ], + "Date": "date", + "X-Amzn-Trace-Id": "X-Amzn-Trace-Id", + "Content-Type": [ + "application/json" + ] + }, + "HttpHeaders": { + "Connection": "keep-alive", + "Content-Length": "23", + "Content-Type": "application/json", + "Date": "date", + "X-Amz-Executed-Version": "$LATEST", + "x-amzn-Remapped-Content-Length": "0", + "x-amzn-RequestId": "x-amzn-RequestId", + "X-Amzn-Trace-Id": "X-Amzn-Trace-Id" + }, + "HttpStatusCode": 200 + }, + "SdkResponseMetadata": { + "RequestId": "RequestId" + }, + "StatusCode": 200 + }, + "outputDetails": { + "truncated": false + } + }, + "timestamp": "timestamp", + "type": "ChoiceStateExited" + }, + { + "id": 16, + "previousEventId": 15, + "stateEnteredEventDetails": { + "input": { + "ExecutedVersion": "$LATEST", + "Payload": { + "status": "completed" + }, + "SdkHttpMetadata": { + "AllHttpHeaders": { + "X-Amz-Executed-Version": [ + "$LATEST" + ], + "x-amzn-Remapped-Content-Length": [ + "0" + ], + "Connection": [ + "keep-alive" + ], + "x-amzn-RequestId": "x-amzn-RequestId", + "Content-Length": [ + "23" + ], + "Date": "date", + "X-Amzn-Trace-Id": "X-Amzn-Trace-Id", + "Content-Type": [ + "application/json" + ] + }, + "HttpHeaders": { + "Connection": "keep-alive", + "Content-Length": "23", + "Content-Type": "application/json", + "Date": "date", + "X-Amz-Executed-Version": "$LATEST", + "x-amzn-Remapped-Content-Length": "0", + "x-amzn-RequestId": "x-amzn-RequestId", + "X-Amzn-Trace-Id": "X-Amzn-Trace-Id" + }, + "HttpStatusCode": 200 + }, + "SdkResponseMetadata": { + "RequestId": "RequestId" + }, + "StatusCode": 200 + }, + "inputDetails": { + "truncated": false + }, + "name": "Finish" + }, + "timestamp": "timestamp", + "type": "SucceedStateEntered" + }, + { + "id": 17, + "previousEventId": 16, + "stateExitedEventDetails": { + "name": "Finish", + "output": { + "ExecutedVersion": "$LATEST", + "Payload": { + "status": "completed" + }, + "SdkHttpMetadata": { + "AllHttpHeaders": { + "X-Amz-Executed-Version": [ + "$LATEST" + ], + "x-amzn-Remapped-Content-Length": [ + "0" + ], + "Connection": [ + "keep-alive" + ], + "x-amzn-RequestId": "x-amzn-RequestId", + "Content-Length": [ + "23" + ], + "Date": "date", + "X-Amzn-Trace-Id": "X-Amzn-Trace-Id", + "Content-Type": [ + "application/json" + ] + }, + "HttpHeaders": { + "Connection": "keep-alive", + "Content-Length": "23", + "Content-Type": "application/json", + "Date": "date", + "X-Amz-Executed-Version": "$LATEST", + "x-amzn-Remapped-Content-Length": "0", + "x-amzn-RequestId": "x-amzn-RequestId", + "X-Amzn-Trace-Id": "X-Amzn-Trace-Id" + }, + "HttpStatusCode": 200 + }, + "SdkResponseMetadata": { + "RequestId": "RequestId" + }, + "StatusCode": 200 + }, + "outputDetails": { + "truncated": false + } + }, + "timestamp": "timestamp", + "type": "SucceedStateExited" + }, + { + "executionSucceededEventDetails": { + "output": { + "ExecutedVersion": "$LATEST", + "Payload": { + "status": "completed" + }, + "SdkHttpMetadata": { + "AllHttpHeaders": { + "X-Amz-Executed-Version": [ + "$LATEST" + ], + "x-amzn-Remapped-Content-Length": [ + "0" + ], + "Connection": [ + "keep-alive" + ], + "x-amzn-RequestId": "x-amzn-RequestId", + "Content-Length": [ + "23" + ], + "Date": "date", + "X-Amzn-Trace-Id": "X-Amzn-Trace-Id", + "Content-Type": [ + "application/json" + ] + }, + "HttpHeaders": { + "Connection": "keep-alive", + "Content-Length": "23", + "Content-Type": "application/json", + "Date": "date", + "X-Amz-Executed-Version": "$LATEST", + "x-amzn-Remapped-Content-Length": "0", + "x-amzn-RequestId": "x-amzn-RequestId", + "X-Amzn-Trace-Id": "X-Amzn-Trace-Id" + }, + "HttpStatusCode": 200 + }, + "SdkResponseMetadata": { + "RequestId": "RequestId" + }, + "StatusCode": 200 + }, + "outputDetails": { + "truncated": false + } + }, + "id": 18, + "previousEventId": 17, + "timestamp": "timestamp", + "type": "ExecutionSucceeded" + } + ], + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } } } diff --git a/tests/aws/services/stepfunctions/v2/local_mocking/test_base_scenarios.validation.json b/tests/aws/services/stepfunctions/v2/local_mocking/test_base_scenarios.validation.json new file mode 100644 index 0000000000000..62b2dc32ff1e4 --- /dev/null +++ b/tests/aws/services/stepfunctions/v2/local_mocking/test_base_scenarios.validation.json @@ -0,0 +1,92 @@ +{ + "tests/aws/services/stepfunctions/v2/local_mocking/test_base_scenarios.py::TestBaseScenarios::test_dynamodb_put_get_item": { + "last_validated_date": "2025-10-28T09:45:35+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 23.19, + "teardown": 1.78, + "total": 24.97 + } + }, + "tests/aws/services/stepfunctions/v2/local_mocking/test_base_scenarios.py::TestBaseScenarios::test_events_put_events": { + "last_validated_date": "2025-10-28T09:45:10+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 13.95, + "teardown": 2.44, + "total": 16.39 + } + }, + "tests/aws/services/stepfunctions/v2/local_mocking/test_base_scenarios.py::TestBaseScenarios::test_lambda_invoke": { + "last_validated_date": "2025-10-28T09:43:43+00:00", + "durations_in_seconds": { + "setup": 10.55, + "call": 16.82, + "teardown": 2.19, + "total": 29.56 + } + }, + "tests/aws/services/stepfunctions/v2/local_mocking/test_base_scenarios.py::TestBaseScenarios::test_lambda_service_invoke": { + "last_validated_date": "2025-10-28T09:44:02+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 16.4, + "teardown": 2.25, + "total": 18.65 + } + }, + "tests/aws/services/stepfunctions/v2/local_mocking/test_base_scenarios.py::TestBaseScenarios::test_lambda_service_invoke_sync_execution": { + "last_validated_date": "2025-10-28T09:44:20+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 15.81, + "teardown": 1.95, + "total": 17.76 + } + }, + "tests/aws/services/stepfunctions/v2/local_mocking/test_base_scenarios.py::TestBaseScenarios::test_map_state_lambda": { + "last_validated_date": "2025-10-28T09:45:58+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 20.99, + "teardown": 2.51, + "total": 23.5 + } + }, + "tests/aws/services/stepfunctions/v2/local_mocking/test_base_scenarios.py::TestBaseScenarios::test_numbered_mock_responses_multiple_success_invocations": { + "last_validated_date": "2026-02-04T08:37:53+00:00", + "durations_in_seconds": { + "setup": 11.76, + "call": 17.42, + "teardown": 3.35, + "total": 32.53 + } + }, + "tests/aws/services/stepfunctions/v2/local_mocking/test_base_scenarios.py::TestBaseScenarios::test_parallel_state_lambda": { + "last_validated_date": "2025-10-28T10:20:00+00:00", + "durations_in_seconds": { + "setup": 11.86, + "call": 19.2, + "teardown": 3.44, + "total": 34.5 + } + }, + "tests/aws/services/stepfunctions/v2/local_mocking/test_base_scenarios.py::TestBaseScenarios::test_sns_publish_base": { + "last_validated_date": "2025-10-28T09:44:54+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 15.03, + "teardown": 1.98, + "total": 17.01 + } + }, + "tests/aws/services/stepfunctions/v2/local_mocking/test_base_scenarios.py::TestBaseScenarios::test_sqs_send_message": { + "last_validated_date": "2025-10-28T10:04:28+00:00", + "durations_in_seconds": { + "setup": 11.84, + "call": 15.44, + "teardown": 2.01, + "total": 29.29 + } + } +} diff --git a/tests/aws/services/stepfunctions/v2/mocking/test_mock_config_file.py b/tests/aws/services/stepfunctions/v2/local_mocking/test_mock_config_file.py similarity index 77% rename from tests/aws/services/stepfunctions/v2/mocking/test_mock_config_file.py rename to tests/aws/services/stepfunctions/v2/local_mocking/test_mock_config_file.py index 931d66512936e..e193ffd062382 100644 --- a/tests/aws/services/stepfunctions/v2/mocking/test_mock_config_file.py +++ b/tests/aws/services/stepfunctions/v2/local_mocking/test_mock_config_file.py @@ -1,10 +1,10 @@ from localstack import config -from localstack.services.stepfunctions.mocking.mock_config import ( - MockTestCase, - load_mock_test_case_for, +from localstack.services.stepfunctions.local_mocking.mock_config import ( + LocalMockTestCase, + load_local_mock_test_case_for, ) from localstack.testing.pytest import markers -from tests.aws.services.stepfunctions.mocked_service_integrations.mocked_service_integrations import ( +from tests.aws.services.stepfunctions.local_mocked_service_integrations.mocked_service_integrations import ( MockedServiceIntegrationsLoader, ) @@ -12,7 +12,7 @@ class TestMockConfigFile: @markers.aws.only_localstack def test_is_mock_config_flag_detected_unset(self, mock_config_file): - mock_test_case = load_mock_test_case_for( + mock_test_case = load_local_mock_test_case_for( state_machine_name="state_machine_name", test_case_name="test_case_name" ) assert mock_test_case is None @@ -31,7 +31,7 @@ def test_is_mock_config_flag_detected_set(self, mock_config_file, monkeypatch): } mock_config_file_path = mock_config_file(mock_config) monkeypatch.setattr(config, "SFN_MOCK_CONFIG", mock_config_file_path) - mock_test_case: MockTestCase = load_mock_test_case_for( + mock_test_case: LocalMockTestCase = load_local_mock_test_case_for( state_machine_name="S0", test_case_name="BaseTestCase" ) assert mock_test_case is not None diff --git a/tests/aws/services/stepfunctions/v2/mocking/test_base_callbacks.validation.json b/tests/aws/services/stepfunctions/v2/mocking/test_base_callbacks.validation.json deleted file mode 100644 index 1151f58cdcd1e..0000000000000 --- a/tests/aws/services/stepfunctions/v2/mocking/test_base_callbacks.validation.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "tests/aws/services/stepfunctions/v2/mocking/test_base_callbacks.py::TestBaseScenarios::test_sfn_start_execution_sync[SFN_SYNC2]": { - "last_validated_date": "2025-04-24T10:06:22+00:00" - }, - "tests/aws/services/stepfunctions/v2/mocking/test_base_callbacks.py::TestBaseScenarios::test_sfn_start_execution_sync[SFN_SYNC]": { - "last_validated_date": "2025-04-24T10:05:48+00:00" - }, - "tests/aws/services/stepfunctions/v2/mocking/test_base_callbacks.py::TestBaseScenarios::test_sqs_wait_for_task_token": { - "last_validated_date": "2025-04-29T10:17:01+00:00" - }, - "tests/aws/services/stepfunctions/v2/mocking/test_base_callbacks.py::TestBaseScenarios::test_sqs_wait_for_task_token_task_failure": { - "last_validated_date": "2025-04-29T11:15:14+00:00" - } -} diff --git a/tests/aws/services/stepfunctions/v2/mocking/test_base_scenarios.validation.json b/tests/aws/services/stepfunctions/v2/mocking/test_base_scenarios.validation.json deleted file mode 100644 index 5836f11a2ed34..0000000000000 --- a/tests/aws/services/stepfunctions/v2/mocking/test_base_scenarios.validation.json +++ /dev/null @@ -1,29 +0,0 @@ -{ - "tests/aws/services/stepfunctions/v2/mocking/test_base_scenarios.py::TestBaseScenarios::test_dynamodb_put_get_item": { - "last_validated_date": "2025-04-23T15:32:30+00:00" - }, - "tests/aws/services/stepfunctions/v2/mocking/test_base_scenarios.py::TestBaseScenarios::test_events_put_events": { - "last_validated_date": "2025-04-23T14:28:24+00:00" - }, - "tests/aws/services/stepfunctions/v2/mocking/test_base_scenarios.py::TestBaseScenarios::test_lambda_invoke": { - "last_validated_date": "2025-04-22T10:30:21+00:00" - }, - "tests/aws/services/stepfunctions/v2/mocking/test_base_scenarios.py::TestBaseScenarios::test_lambda_service_invoke": { - "last_validated_date": "2025-04-14T18:51:50+00:00" - }, - "tests/aws/services/stepfunctions/v2/mocking/test_base_scenarios.py::TestBaseScenarios::test_lambda_service_invoke_sync_execution": { - "last_validated_date": "2025-06-03T18:47:04+00:00" - }, - "tests/aws/services/stepfunctions/v2/mocking/test_base_scenarios.py::TestBaseScenarios::test_map_state_lambda": { - "last_validated_date": "2025-04-24T11:11:05+00:00" - }, - "tests/aws/services/stepfunctions/v2/mocking/test_base_scenarios.py::TestBaseScenarios::test_parallel_state_lambda": { - "last_validated_date": "2025-04-28T12:36:06+00:00" - }, - "tests/aws/services/stepfunctions/v2/mocking/test_base_scenarios.py::TestBaseScenarios::test_sns_publish_base": { - "last_validated_date": "2025-04-23T13:52:23+00:00" - }, - "tests/aws/services/stepfunctions/v2/mocking/test_base_scenarios.py::TestBaseScenarios::test_sqs_send_message": { - "last_validated_date": "2025-04-22T19:39:14+00:00" - } -} diff --git a/tests/aws/services/stepfunctions/v2/outputdecl/test_output.snapshot.json b/tests/aws/services/stepfunctions/v2/outputdecl/test_output.snapshot.json index 3e3b4ce45dc52..fb014dc780f7a 100644 --- a/tests/aws/services/stepfunctions/v2/outputdecl/test_output.snapshot.json +++ b/tests/aws/services/stepfunctions/v2/outputdecl/test_output.snapshot.json @@ -1,6 +1,6 @@ { "tests/aws/services/stepfunctions/v2/outputdecl/test_output.py::TestArgumentsBase::test_base_cases[BASE_EMPTY]": { - "recorded-date": "04-11-2024, 13:15:46", + "recorded-date": "19-02-2026, 14:47:34", "recorded-content": { "get_execution_history": { "events": [ @@ -78,7 +78,7 @@ } }, "tests/aws/services/stepfunctions/v2/outputdecl/test_output.py::TestArgumentsBase::test_base_cases[BASE_LITERALS]": { - "recorded-date": "04-11-2024, 13:16:06", + "recorded-date": "19-02-2026, 14:47:49", "recorded-content": { "get_execution_history": { "events": [ @@ -266,7 +266,7 @@ } }, "tests/aws/services/stepfunctions/v2/outputdecl/test_output.py::TestArgumentsBase::test_base_cases[BASE_EXPR]": { - "recorded-date": "04-11-2024, 13:16:22", + "recorded-date": "19-02-2026, 14:48:04", "recorded-content": { "get_execution_history": { "events": [ @@ -463,7 +463,7 @@ } }, "tests/aws/services/stepfunctions/v2/outputdecl/test_output.py::TestArgumentsBase::test_base_cases[BASE_DIRECT_EXPR]": { - "recorded-date": "04-11-2024, 13:16:38", + "recorded-date": "19-02-2026, 14:48:17", "recorded-content": { "get_execution_history": { "events": [ @@ -587,7 +587,7 @@ } }, "tests/aws/services/stepfunctions/v2/outputdecl/test_output.py::TestArgumentsBase::test_base_lambda[BASE_LAMBDA]": { - "recorded-date": "04-11-2024, 14:01:00", + "recorded-date": "19-02-2026, 14:48:36", "recorded-content": { "get_execution_history": { "events": [ @@ -813,7 +813,7 @@ } }, "tests/aws/services/stepfunctions/v2/outputdecl/test_output.py::TestArgumentsBase::test_base_task_lambda[BASE_TASK_LAMBDA]": { - "recorded-date": "04-11-2024, 14:15:19", + "recorded-date": "19-02-2026, 14:48:54", "recorded-content": { "get_execution_history": { "events": [ @@ -920,9 +920,7 @@ "Connection": [ "keep-alive" ], - "x-amzn-RequestId": [ - "" - ], + "x-amzn-RequestId": "x-amzn-RequestId", "Content-Length": [ "60" ], @@ -939,13 +937,13 @@ "Date": "date", "X-Amz-Executed-Version": "$LATEST", "x-amzn-Remapped-Content-Length": "0", - "x-amzn-RequestId": "", + "x-amzn-RequestId": "x-amzn-RequestId", "X-Amzn-Trace-Id": "X-Amzn-Trace-Id" }, "HttpStatusCode": 200 }, "SdkResponseMetadata": { - "RequestId": "" + "RequestId": "RequestId" }, "StatusCode": 200 }, @@ -996,9 +994,7 @@ "Connection": [ "keep-alive" ], - "x-amzn-RequestId": [ - "" - ], + "x-amzn-RequestId": "x-amzn-RequestId", "Content-Length": [ "60" ], @@ -1015,13 +1011,13 @@ "Date": "date", "X-Amz-Executed-Version": "$LATEST", "x-amzn-Remapped-Content-Length": "0", - "x-amzn-RequestId": "", + "x-amzn-RequestId": "x-amzn-RequestId", "X-Amzn-Trace-Id": "X-Amzn-Trace-Id" }, "HttpStatusCode": 200 }, "SdkResponseMetadata": { - "RequestId": "" + "RequestId": "RequestId" }, "StatusCode": 200 } @@ -1068,9 +1064,7 @@ "Connection": [ "keep-alive" ], - "x-amzn-RequestId": [ - "" - ], + "x-amzn-RequestId": "x-amzn-RequestId", "Content-Length": [ "60" ], @@ -1087,13 +1081,13 @@ "Date": "date", "X-Amz-Executed-Version": "$LATEST", "x-amzn-Remapped-Content-Length": "0", - "x-amzn-RequestId": "", + "x-amzn-RequestId": "x-amzn-RequestId", "X-Amzn-Trace-Id": "X-Amzn-Trace-Id" }, "HttpStatusCode": 200 }, "SdkResponseMetadata": { - "RequestId": "" + "RequestId": "RequestId" }, "StatusCode": 200 } @@ -1116,7 +1110,7 @@ } }, "tests/aws/services/stepfunctions/v2/outputdecl/test_output.py::TestArgumentsBase::test_base_output_any_non_dict[NULL]": { - "recorded-date": "20-11-2024, 18:24:00", + "recorded-date": "19-02-2026, 14:49:08", "recorded-content": { "get_execution_history": { "events": [ @@ -1184,7 +1178,7 @@ } }, "tests/aws/services/stepfunctions/v2/outputdecl/test_output.py::TestArgumentsBase::test_base_output_any_non_dict[INT]": { - "recorded-date": "20-11-2024, 18:24:15", + "recorded-date": "19-02-2026, 14:49:23", "recorded-content": { "get_execution_history": { "events": [ @@ -1252,7 +1246,7 @@ } }, "tests/aws/services/stepfunctions/v2/outputdecl/test_output.py::TestArgumentsBase::test_base_output_any_non_dict[FLOAT]": { - "recorded-date": "20-11-2024, 18:24:31", + "recorded-date": "19-02-2026, 14:49:37", "recorded-content": { "get_execution_history": { "events": [ @@ -1320,7 +1314,7 @@ } }, "tests/aws/services/stepfunctions/v2/outputdecl/test_output.py::TestArgumentsBase::test_base_output_any_non_dict[BOOL]": { - "recorded-date": "20-11-2024, 18:24:46", + "recorded-date": "19-02-2026, 14:49:51", "recorded-content": { "get_execution_history": { "events": [ @@ -1388,7 +1382,7 @@ } }, "tests/aws/services/stepfunctions/v2/outputdecl/test_output.py::TestArgumentsBase::test_base_output_any_non_dict[STR_LIT]": { - "recorded-date": "20-11-2024, 18:25:01", + "recorded-date": "19-02-2026, 14:50:05", "recorded-content": { "get_execution_history": { "events": [ @@ -1456,7 +1450,7 @@ } }, "tests/aws/services/stepfunctions/v2/outputdecl/test_output.py::TestArgumentsBase::test_base_output_any_non_dict[JSONATA_EXPR]": { - "recorded-date": "20-11-2024, 18:25:16", + "recorded-date": "19-02-2026, 14:50:20", "recorded-content": { "get_execution_history": { "events": [ @@ -1528,7 +1522,7 @@ } }, "tests/aws/services/stepfunctions/v2/outputdecl/test_output.py::TestArgumentsBase::test_base_output_any_non_dict[LIST_EMPY]": { - "recorded-date": "20-11-2024, 18:25:31", + "recorded-date": "19-02-2026, 14:50:35", "recorded-content": { "get_execution_history": { "events": [ @@ -1596,7 +1590,7 @@ } }, "tests/aws/services/stepfunctions/v2/outputdecl/test_output.py::TestArgumentsBase::test_base_output_any_non_dict[LIST_RICH]": { - "recorded-date": "20-11-2024, 18:25:47", + "recorded-date": "19-02-2026, 14:50:49", "recorded-content": { "get_execution_history": { "events": [ @@ -1664,7 +1658,7 @@ } }, "tests/aws/services/stepfunctions/v2/outputdecl/test_output.py::TestArgumentsBase::test_output_in_choice[CONDITION_TRUE]": { - "recorded-date": "27-12-2024, 14:50:09", + "recorded-date": "19-02-2026, 14:51:09", "recorded-content": { "get_execution_history": { "events": [ @@ -1758,7 +1752,7 @@ } }, "tests/aws/services/stepfunctions/v2/outputdecl/test_output.py::TestArgumentsBase::test_output_in_choice[CONDITION_FALSE]": { - "recorded-date": "27-12-2024, 14:50:24", + "recorded-date": "19-02-2026, 14:51:23", "recorded-content": { "get_execution_history": { "events": [ diff --git a/tests/aws/services/stepfunctions/v2/outputdecl/test_output.validation.json b/tests/aws/services/stepfunctions/v2/outputdecl/test_output.validation.json index 42c2f4701dbb8..90978192ba431 100644 --- a/tests/aws/services/stepfunctions/v2/outputdecl/test_output.validation.json +++ b/tests/aws/services/stepfunctions/v2/outputdecl/test_output.validation.json @@ -1,50 +1,146 @@ { "tests/aws/services/stepfunctions/v2/outputdecl/test_output.py::TestArgumentsBase::test_base_cases[BASE_DIRECT_EXPR]": { - "last_validated_date": "2024-11-04T13:16:37+00:00" + "last_validated_date": "2026-02-19T14:48:17+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 12.29, + "teardown": 1.44, + "total": 13.73 + } }, "tests/aws/services/stepfunctions/v2/outputdecl/test_output.py::TestArgumentsBase::test_base_cases[BASE_EMPTY]": { - "last_validated_date": "2024-11-04T13:15:44+00:00" + "last_validated_date": "2026-02-19T14:47:34+00:00", + "durations_in_seconds": { + "setup": 11.5, + "call": 12.74, + "teardown": 1.36, + "total": 25.6 + } }, "tests/aws/services/stepfunctions/v2/outputdecl/test_output.py::TestArgumentsBase::test_base_cases[BASE_EXPR]": { - "last_validated_date": "2024-11-04T13:16:20+00:00" + "last_validated_date": "2026-02-19T14:48:04+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 13.43, + "teardown": 1.41, + "total": 14.84 + } }, "tests/aws/services/stepfunctions/v2/outputdecl/test_output.py::TestArgumentsBase::test_base_cases[BASE_LITERALS]": { - "last_validated_date": "2024-11-04T13:16:04+00:00" + "last_validated_date": "2026-02-19T14:47:49+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 13.3, + "teardown": 1.35, + "total": 14.65 + } }, "tests/aws/services/stepfunctions/v2/outputdecl/test_output.py::TestArgumentsBase::test_base_lambda[BASE_LAMBDA]": { - "last_validated_date": "2024-11-04T14:00:57+00:00" + "last_validated_date": "2026-02-19T14:48:36+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 16.91, + "teardown": 2.27, + "total": 19.18 + } }, "tests/aws/services/stepfunctions/v2/outputdecl/test_output.py::TestArgumentsBase::test_base_output_any_non_dict[BOOL]": { - "last_validated_date": "2024-11-20T18:24:44+00:00" + "last_validated_date": "2026-02-19T14:49:51+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 12.32, + "teardown": 1.42, + "total": 13.74 + } }, "tests/aws/services/stepfunctions/v2/outputdecl/test_output.py::TestArgumentsBase::test_base_output_any_non_dict[FLOAT]": { - "last_validated_date": "2024-11-20T18:24:29+00:00" + "last_validated_date": "2026-02-19T14:49:37+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 13.44, + "teardown": 1.4, + "total": 14.84 + } }, "tests/aws/services/stepfunctions/v2/outputdecl/test_output.py::TestArgumentsBase::test_base_output_any_non_dict[INT]": { - "last_validated_date": "2024-11-20T18:24:13+00:00" + "last_validated_date": "2026-02-19T14:49:23+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 13.38, + "teardown": 1.44, + "total": 14.82 + } }, "tests/aws/services/stepfunctions/v2/outputdecl/test_output.py::TestArgumentsBase::test_base_output_any_non_dict[JSONATA_EXPR]": { - "last_validated_date": "2024-11-20T18:25:14+00:00" + "last_validated_date": "2026-02-19T14:50:20+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 13.41, + "teardown": 1.43, + "total": 14.84 + } }, "tests/aws/services/stepfunctions/v2/outputdecl/test_output.py::TestArgumentsBase::test_base_output_any_non_dict[LIST_EMPY]": { - "last_validated_date": "2024-11-20T18:25:29+00:00" + "last_validated_date": "2026-02-19T14:50:35+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 13.39, + "teardown": 1.4, + "total": 14.79 + } }, "tests/aws/services/stepfunctions/v2/outputdecl/test_output.py::TestArgumentsBase::test_base_output_any_non_dict[LIST_RICH]": { - "last_validated_date": "2024-11-20T18:25:45+00:00" + "last_validated_date": "2026-02-19T14:50:49+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 13.37, + "teardown": 1.45, + "total": 14.82 + } }, "tests/aws/services/stepfunctions/v2/outputdecl/test_output.py::TestArgumentsBase::test_base_output_any_non_dict[NULL]": { - "last_validated_date": "2024-11-20T18:23:58+00:00" + "last_validated_date": "2026-02-19T14:49:08+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 12.34, + "teardown": 1.39, + "total": 13.73 + } }, "tests/aws/services/stepfunctions/v2/outputdecl/test_output.py::TestArgumentsBase::test_base_output_any_non_dict[STR_LIT]": { - "last_validated_date": "2024-11-20T18:24:59+00:00" + "last_validated_date": "2026-02-19T14:50:05+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 12.31, + "teardown": 1.41, + "total": 13.72 + } }, "tests/aws/services/stepfunctions/v2/outputdecl/test_output.py::TestArgumentsBase::test_base_task_lambda[BASE_TASK_LAMBDA]": { - "last_validated_date": "2024-11-04T14:15:16+00:00" + "last_validated_date": "2026-02-19T14:48:54+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 15.3, + "teardown": 2.36, + "total": 17.66 + } }, "tests/aws/services/stepfunctions/v2/outputdecl/test_output.py::TestArgumentsBase::test_output_in_choice[CONDITION_FALSE]": { - "last_validated_date": "2024-12-27T14:50:22+00:00" + "last_validated_date": "2026-02-19T14:51:24+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 12.74, + "teardown": 2.4, + "total": 15.14 + } }, "tests/aws/services/stepfunctions/v2/outputdecl/test_output.py::TestArgumentsBase::test_output_in_choice[CONDITION_TRUE]": { - "last_validated_date": "2024-12-27T14:50:08+00:00" + "last_validated_date": "2026-02-19T14:51:09+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 18.03, + "teardown": 1.43, + "total": 19.46 + } } } diff --git a/tests/aws/services/stepfunctions/v2/services/test_apigetway_task_service.snapshot.json b/tests/aws/services/stepfunctions/v2/services/test_apigetway_task_service.snapshot.json index ee88f11d33538..2f39639bcf9af 100644 --- a/tests/aws/services/stepfunctions/v2/services/test_apigetway_task_service.snapshot.json +++ b/tests/aws/services/stepfunctions/v2/services/test_apigetway_task_service.snapshot.json @@ -1,6 +1,6 @@ { "tests/aws/services/stepfunctions/v2/services/test_apigetway_task_service.py::TestTaskApiGateway::test_invoke_with_query_parameters": { - "recorded-date": "20-08-2023, 15:18:59", + "recorded-date": "06-11-2025, 12:16:28", "recorded-content": { "get_execution_history": { "events": [ @@ -259,7 +259,7 @@ } }, "tests/aws/services/stepfunctions/v2/services/test_apigetway_task_service.py::TestTaskApiGateway::test_invoke_base": { - "recorded-date": "20-08-2023, 15:26:20", + "recorded-date": "06-11-2025, 12:12:42", "recorded-content": { "get_execution_history": { "events": [ @@ -449,7 +449,7 @@ } }, "tests/aws/services/stepfunctions/v2/services/test_apigetway_task_service.py::TestTaskApiGateway::test_invoke_with_body_post[None]": { - "recorded-date": "25-08-2023, 12:40:49", + "recorded-date": "06-11-2025, 12:13:06", "recorded-content": { "get_execution_history": { "events": [ @@ -642,7 +642,7 @@ } }, "tests/aws/services/stepfunctions/v2/services/test_apigetway_task_service.py::TestTaskApiGateway::test_invoke_with_body_post[]": { - "recorded-date": "25-08-2023, 12:41:13", + "recorded-date": "06-11-2025, 12:13:47", "recorded-content": { "get_execution_history": { "events": [ @@ -835,7 +835,7 @@ } }, "tests/aws/services/stepfunctions/v2/services/test_apigetway_task_service.py::TestTaskApiGateway::test_invoke_with_body_post[HelloWorld]": { - "recorded-date": "25-08-2023, 12:41:49", + "recorded-date": "06-11-2025, 12:14:17", "recorded-content": { "get_execution_history": { "events": [ @@ -1800,7 +1800,7 @@ } }, "tests/aws/services/stepfunctions/v2/services/test_apigetway_task_service.py::TestTaskApiGateway::test_invoke_error": { - "recorded-date": "20-08-2023, 16:15:34", + "recorded-date": "06-11-2025, 12:16:53", "recorded-content": { "get_execution_history": { "events": [ @@ -1905,7 +1905,7 @@ } }, "tests/aws/services/stepfunctions/v2/services/test_apigetway_task_service.py::TestTaskApiGateway::test_invoke_with_body_post[request_body3]": { - "recorded-date": "25-08-2023, 12:42:12", + "recorded-date": "06-11-2025, 12:14:54", "recorded-content": { "get_execution_history": { "events": [ @@ -2181,7 +2181,7 @@ } }, "tests/aws/services/stepfunctions/v2/services/test_apigetway_task_service.py::TestTaskApiGateway::test_invoke_with_headers[custom_header1]": { - "recorded-date": "06-10-2024, 14:50:48", + "recorded-date": "06-11-2025, 12:15:22", "recorded-content": { "get_execution_history": { "events": [ @@ -2401,7 +2401,7 @@ } }, "tests/aws/services/stepfunctions/v2/services/test_apigetway_task_service.py::TestTaskApiGateway::test_invoke_with_headers[custom_header2]": { - "recorded-date": "06-10-2024, 14:51:07", + "recorded-date": "06-11-2025, 12:16:00", "recorded-content": { "get_execution_history": { "events": [ diff --git a/tests/aws/services/stepfunctions/v2/services/test_apigetway_task_service.validation.json b/tests/aws/services/stepfunctions/v2/services/test_apigetway_task_service.validation.json index 22773c1a8de00..266e15481a172 100644 --- a/tests/aws/services/stepfunctions/v2/services/test_apigetway_task_service.validation.json +++ b/tests/aws/services/stepfunctions/v2/services/test_apigetway_task_service.validation.json @@ -1,32 +1,86 @@ { "tests/aws/services/stepfunctions/v2/services/test_apigetway_task_service.py::TestTaskApiGateway::test_invoke_base": { - "last_validated_date": "2023-08-20T13:26:20+00:00" + "last_validated_date": "2025-11-06T12:12:46+00:00", + "durations_in_seconds": { + "setup": 12.84, + "call": 21.85, + "teardown": 4.98, + "total": 39.67 + } }, "tests/aws/services/stepfunctions/v2/services/test_apigetway_task_service.py::TestTaskApiGateway::test_invoke_error": { - "last_validated_date": "2023-08-20T14:15:34+00:00" + "last_validated_date": "2025-11-06T12:17:34+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 18.14, + "teardown": 41.19, + "total": 59.33 + } }, "tests/aws/services/stepfunctions/v2/services/test_apigetway_task_service.py::TestTaskApiGateway::test_invoke_with_body_post[HelloWorld]": { - "last_validated_date": "2023-08-25T10:41:49+00:00" + "last_validated_date": "2025-11-06T12:14:35+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 19.32, + "teardown": 17.83, + "total": 37.15 + } }, "tests/aws/services/stepfunctions/v2/services/test_apigetway_task_service.py::TestTaskApiGateway::test_invoke_with_body_post[None]": { - "last_validated_date": "2023-08-25T10:40:49+00:00" + "last_validated_date": "2025-11-06T12:13:28+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 19.38, + "teardown": 22.02, + "total": 41.4 + } }, "tests/aws/services/stepfunctions/v2/services/test_apigetway_task_service.py::TestTaskApiGateway::test_invoke_with_body_post[]": { - "last_validated_date": "2023-08-25T10:41:13+00:00" + "last_validated_date": "2025-11-06T12:13:58+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 19.41, + "teardown": 10.31, + "total": 29.72 + } }, "tests/aws/services/stepfunctions/v2/services/test_apigetway_task_service.py::TestTaskApiGateway::test_invoke_with_body_post[request_body3]": { - "last_validated_date": "2023-08-25T10:42:12+00:00" + "last_validated_date": "2025-11-06T12:15:03+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 19.36, + "teardown": 8.46, + "total": 27.82 + } }, "tests/aws/services/stepfunctions/v2/services/test_apigetway_task_service.py::TestTaskApiGateway::test_invoke_with_headers[custom_header1]": { - "last_validated_date": "2024-10-06T14:50:48+00:00" + "last_validated_date": "2025-11-06T12:15:41+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 19.48, + "teardown": 18.67, + "total": 38.15 + } }, "tests/aws/services/stepfunctions/v2/services/test_apigetway_task_service.py::TestTaskApiGateway::test_invoke_with_headers[custom_header2]": { - "last_validated_date": "2024-10-06T14:51:07+00:00" + "last_validated_date": "2025-11-06T12:16:08+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 19.23, + "teardown": 8.24, + "total": 27.47 + } }, "tests/aws/services/stepfunctions/v2/services/test_apigetway_task_service.py::TestTaskApiGateway::test_invoke_with_headers[singleStringHeader]": { "last_validated_date": "2024-10-06T14:50:24+00:00" }, "tests/aws/services/stepfunctions/v2/services/test_apigetway_task_service.py::TestTaskApiGateway::test_invoke_with_query_parameters": { - "last_validated_date": "2023-08-20T13:18:59+00:00" + "last_validated_date": "2025-11-06T12:16:35+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 20.2, + "teardown": 6.06, + "total": 26.26 + } } } diff --git a/tests/aws/services/stepfunctions/v2/services/test_aws_sdk_task_service.snapshot.json b/tests/aws/services/stepfunctions/v2/services/test_aws_sdk_task_service.snapshot.json index 7fd6cff9f6673..18f8adf6f654b 100644 --- a/tests/aws/services/stepfunctions/v2/services/test_aws_sdk_task_service.snapshot.json +++ b/tests/aws/services/stepfunctions/v2/services/test_aws_sdk_task_service.snapshot.json @@ -1,6 +1,6 @@ { "tests/aws/services/stepfunctions/v2/services/test_aws_sdk_task_service.py::TestTaskServiceAwsSdk::test_list_secrets": { - "recorded-date": "22-06-2023, 13:59:49", + "recorded-date": "06-11-2025, 12:17:53", "recorded-content": { "get_execution_history": { "events": [ @@ -142,7 +142,7 @@ } }, "tests/aws/services/stepfunctions/v2/services/test_aws_sdk_task_service.py::TestTaskServiceAwsSdk::test_dynamodb_put_get_item": { - "recorded-date": "16-05-2023, 22:27:38", + "recorded-date": "06-11-2025, 12:18:15", "recorded-content": { "get_execution_history": { "events": [ @@ -341,11 +341,11 @@ "taskSucceededEventDetails": { "output": { "Item": { - "data": { - "S": "HelloWorld" - }, "id": { "S": "id1" + }, + "data": { + "S": "HelloWorld" } } }, @@ -381,11 +381,11 @@ "putItemOutput": {}, "getItemOutput": { "Item": { - "data": { - "S": "HelloWorld" - }, "id": { "S": "id1" + }, + "data": { + "S": "HelloWorld" } } } @@ -417,11 +417,11 @@ "putItemOutput": {}, "getItemOutput": { "Item": { - "data": { - "S": "HelloWorld" - }, "id": { "S": "id1" + }, + "data": { + "S": "HelloWorld" } } } @@ -444,7 +444,7 @@ } }, "tests/aws/services/stepfunctions/v2/services/test_aws_sdk_task_service.py::TestTaskServiceAwsSdk::test_dynamodb_put_delete_item": { - "recorded-date": "16-05-2023, 22:28:05", + "recorded-date": "06-11-2025, 12:18:39", "recorded-content": { "get_execution_history": { "events": [ @@ -719,7 +719,7 @@ } }, "tests/aws/services/stepfunctions/v2/services/test_aws_sdk_task_service.py::TestTaskServiceAwsSdk::test_dynamodb_put_update_get_item": { - "recorded-date": "16-05-2023, 22:28:28", + "recorded-date": "06-11-2025, 12:19:01", "recorded-content": { "get_execution_history": { "events": [ @@ -1220,7 +1220,7 @@ } }, "tests/aws/services/stepfunctions/v2/services/test_aws_sdk_task_service.py::TestTaskServiceAwsSdk::test_sfn_start_execution": { - "recorded-date": "18-12-2023, 14:22:59", + "recorded-date": "06-11-2025, 12:20:01", "recorded-content": { "get_execution_history": { "events": [ @@ -1341,7 +1341,7 @@ } }, "tests/aws/services/stepfunctions/v2/services/test_aws_sdk_task_service.py::TestTaskServiceAwsSdk::test_sfn_start_execution_implicit_json_serialisation": { - "recorded-date": "05-02-2024, 11:29:16", + "recorded-date": "06-11-2025, 12:20:37", "recorded-content": { "get_execution_history": { "events": [ @@ -1489,7 +1489,7 @@ } }, "tests/aws/services/stepfunctions/v2/services/test_aws_sdk_task_service.py::TestTaskServiceAwsSdk::test_sfn_send_task_outcome_with_no_such_token[state_machine_template0]": { - "recorded-date": "10-04-2024, 18:55:26", + "recorded-date": "06-11-2025, 12:19:18", "recorded-content": { "get_execution_history": { "events": [ @@ -1552,7 +1552,7 @@ "id": 5, "previousEventId": 4, "taskFailedEventDetails": { - "cause": "Invalid Token: 'Invalid token' (Service: Sfn, Status Code: 400, Request ID: )", + "cause": "Invalid Token: 'Invalid token' (Service: Sfn, Status Code: 400, Request ID: ) (SDK Attempt Count: 1)", "error": "Sfn.InvalidTokenException", "resource": "sendTaskSuccess", "resourceType": "aws-sdk:sfn" @@ -1562,7 +1562,7 @@ }, { "executionFailedEventDetails": { - "cause": "Invalid Token: 'Invalid token' (Service: Sfn, Status Code: 400, Request ID: )", + "cause": "Invalid Token: 'Invalid token' (Service: Sfn, Status Code: 400, Request ID: ) (SDK Attempt Count: 1)", "error": "Sfn.InvalidTokenException" }, "id": 6, @@ -1579,7 +1579,7 @@ } }, "tests/aws/services/stepfunctions/v2/services/test_aws_sdk_task_service.py::TestTaskServiceAwsSdk::test_sfn_send_task_outcome_with_no_such_token[state_machine_template1]": { - "recorded-date": "10-04-2024, 18:55:40", + "recorded-date": "06-11-2025, 12:19:33", "recorded-content": { "get_execution_history": { "events": [ @@ -1641,7 +1641,7 @@ "id": 5, "previousEventId": 4, "taskFailedEventDetails": { - "cause": "Invalid Token: 'Invalid token' (Service: Sfn, Status Code: 400, Request ID: )", + "cause": "Invalid Token: 'Invalid token' (Service: Sfn, Status Code: 400, Request ID: ) (SDK Attempt Count: 1)", "error": "Sfn.InvalidTokenException", "resource": "sendTaskFailure", "resourceType": "aws-sdk:sfn" @@ -1651,7 +1651,7 @@ }, { "executionFailedEventDetails": { - "cause": "Invalid Token: 'Invalid token' (Service: Sfn, Status Code: 400, Request ID: )", + "cause": "Invalid Token: 'Invalid token' (Service: Sfn, Status Code: 400, Request ID: ) (SDK Attempt Count: 1)", "error": "Sfn.InvalidTokenException" }, "id": 6, @@ -1668,7 +1668,7 @@ } }, "tests/aws/services/stepfunctions/v2/services/test_aws_sdk_task_service.py::TestTaskServiceAwsSdk::test_s3_get_object[empty_str]": { - "recorded-date": "27-01-2025, 10:17:44", + "recorded-date": "06-11-2025, 12:21:01", "recorded-content": { "get_execution_history": { "events": [ @@ -1804,7 +1804,7 @@ } }, "tests/aws/services/stepfunctions/v2/services/test_aws_sdk_task_service.py::TestTaskServiceAwsSdk::test_s3_get_object[str]": { - "recorded-date": "27-01-2025, 10:18:02", + "recorded-date": "06-11-2025, 12:21:21", "recorded-content": { "get_execution_history": { "events": [ @@ -1940,7 +1940,7 @@ } }, "tests/aws/services/stepfunctions/v2/services/test_aws_sdk_task_service.py::TestTaskServiceAwsSdk::test_s3_get_object[empty_binary]": { - "recorded-date": "27-01-2025, 10:18:18", + "recorded-date": "06-11-2025, 12:21:40", "recorded-content": { "get_execution_history": { "events": [ @@ -2076,7 +2076,7 @@ } }, "tests/aws/services/stepfunctions/v2/services/test_aws_sdk_task_service.py::TestTaskServiceAwsSdk::test_s3_get_object[binary]": { - "recorded-date": "27-01-2025, 10:18:40", + "recorded-date": "06-11-2025, 12:22:00", "recorded-content": { "get_execution_history": { "events": [ @@ -2212,7 +2212,7 @@ } }, "tests/aws/services/stepfunctions/v2/services/test_aws_sdk_task_service.py::TestTaskServiceAwsSdk::test_s3_get_object[bytearray]": { - "recorded-date": "27-01-2025, 10:18:56", + "recorded-date": "06-11-2025, 12:22:19", "recorded-content": { "get_execution_history": { "events": [ @@ -2348,7 +2348,7 @@ } }, "tests/aws/services/stepfunctions/v2/services/test_aws_sdk_task_service.py::TestTaskServiceAwsSdk::test_s3_put_object[str]": { - "recorded-date": "27-01-2025, 10:29:12", + "recorded-date": "06-11-2025, 12:22:38", "recorded-content": { "get_execution_history": { "events": [ @@ -2491,7 +2491,7 @@ } }, "tests/aws/services/stepfunctions/v2/services/test_aws_sdk_task_service.py::TestTaskServiceAwsSdk::test_s3_put_object[dict]": { - "recorded-date": "27-01-2025, 10:29:28", + "recorded-date": "06-11-2025, 12:22:57", "recorded-content": { "get_execution_history": { "events": [ @@ -2642,7 +2642,7 @@ } }, "tests/aws/services/stepfunctions/v2/services/test_aws_sdk_task_service.py::TestTaskServiceAwsSdk::test_s3_put_object[list]": { - "recorded-date": "27-01-2025, 10:29:44", + "recorded-date": "06-11-2025, 12:23:16", "recorded-content": { "get_execution_history": { "events": [ @@ -2794,7 +2794,7 @@ } }, "tests/aws/services/stepfunctions/v2/services/test_aws_sdk_task_service.py::TestTaskServiceAwsSdk::test_s3_put_object[bool]": { - "recorded-date": "27-01-2025, 10:30:01", + "recorded-date": "06-11-2025, 12:23:35", "recorded-content": { "get_execution_history": { "events": [ @@ -2937,7 +2937,7 @@ } }, "tests/aws/services/stepfunctions/v2/services/test_aws_sdk_task_service.py::TestTaskServiceAwsSdk::test_s3_put_object[num]": { - "recorded-date": "27-01-2025, 10:30:17", + "recorded-date": "06-11-2025, 12:23:54", "recorded-content": { "get_execution_history": { "events": [ diff --git a/tests/aws/services/stepfunctions/v2/services/test_aws_sdk_task_service.validation.json b/tests/aws/services/stepfunctions/v2/services/test_aws_sdk_task_service.validation.json index 53dcdf9b58d8d..8a64e4f5f1459 100644 --- a/tests/aws/services/stepfunctions/v2/services/test_aws_sdk_task_service.validation.json +++ b/tests/aws/services/stepfunctions/v2/services/test_aws_sdk_task_service.validation.json @@ -1,53 +1,164 @@ { "tests/aws/services/stepfunctions/v2/services/test_aws_sdk_task_service.py::TestTaskServiceAwsSdk::test_dynamodb_put_delete_item": { - "last_validated_date": "2023-05-16T20:28:05+00:00" + "last_validated_date": "2025-11-06T12:18:41+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 21.28, + "teardown": 2.13, + "total": 23.41 + } }, "tests/aws/services/stepfunctions/v2/services/test_aws_sdk_task_service.py::TestTaskServiceAwsSdk::test_dynamodb_put_get_item": { - "last_validated_date": "2023-05-16T20:27:38+00:00" + "last_validated_date": "2025-11-06T12:18:18+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 20.9, + "teardown": 2.12, + "total": 23.02 + } }, "tests/aws/services/stepfunctions/v2/services/test_aws_sdk_task_service.py::TestTaskServiceAwsSdk::test_dynamodb_put_update_get_item": { - "last_validated_date": "2023-05-16T20:28:28+00:00" + "last_validated_date": "2025-11-06T12:19:04+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 20.52, + "teardown": 2.44, + "total": 22.96 + } }, "tests/aws/services/stepfunctions/v2/services/test_aws_sdk_task_service.py::TestTaskServiceAwsSdk::test_list_secrets": { - "last_validated_date": "2023-06-22T11:59:49+00:00" + "last_validated_date": "2025-11-06T12:17:55+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 18.96, + "teardown": 1.7, + "total": 20.66 + } }, "tests/aws/services/stepfunctions/v2/services/test_aws_sdk_task_service.py::TestTaskServiceAwsSdk::test_s3_get_object[binary]": { - "last_validated_date": "2025-01-27T10:18:40+00:00" + "last_validated_date": "2025-11-06T12:22:04+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 15.72, + "teardown": 3.57, + "total": 19.29 + } }, "tests/aws/services/stepfunctions/v2/services/test_aws_sdk_task_service.py::TestTaskServiceAwsSdk::test_s3_get_object[bytearray]": { - "last_validated_date": "2025-01-27T10:18:56+00:00" + "last_validated_date": "2025-11-06T12:22:22+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 15.37, + "teardown": 3.55, + "total": 18.92 + } }, "tests/aws/services/stepfunctions/v2/services/test_aws_sdk_task_service.py::TestTaskServiceAwsSdk::test_s3_get_object[empty_binary]": { - "last_validated_date": "2025-01-27T10:18:18+00:00" + "last_validated_date": "2025-11-06T12:21:44+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 16.17, + "teardown": 3.74, + "total": 19.91 + } }, "tests/aws/services/stepfunctions/v2/services/test_aws_sdk_task_service.py::TestTaskServiceAwsSdk::test_s3_get_object[empty_str]": { - "last_validated_date": "2025-01-27T10:17:44+00:00" + "last_validated_date": "2025-11-06T12:21:05+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 20.53, + "teardown": 3.77, + "total": 24.3 + } }, "tests/aws/services/stepfunctions/v2/services/test_aws_sdk_task_service.py::TestTaskServiceAwsSdk::test_s3_get_object[str]": { - "last_validated_date": "2025-01-27T10:18:02+00:00" + "last_validated_date": "2025-11-06T12:21:24+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 15.75, + "teardown": 3.73, + "total": 19.48 + } }, "tests/aws/services/stepfunctions/v2/services/test_aws_sdk_task_service.py::TestTaskServiceAwsSdk::test_s3_put_object[bool]": { - "last_validated_date": "2025-01-27T10:30:01+00:00" + "last_validated_date": "2025-11-06T12:23:38+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 15.98, + "teardown": 3.22, + "total": 19.2 + } }, "tests/aws/services/stepfunctions/v2/services/test_aws_sdk_task_service.py::TestTaskServiceAwsSdk::test_s3_put_object[dict]": { - "last_validated_date": "2025-01-27T10:29:28+00:00" + "last_validated_date": "2025-11-06T12:23:00+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 15.81, + "teardown": 3.25, + "total": 19.06 + } }, "tests/aws/services/stepfunctions/v2/services/test_aws_sdk_task_service.py::TestTaskServiceAwsSdk::test_s3_put_object[list]": { - "last_validated_date": "2025-01-27T10:29:44+00:00" + "last_validated_date": "2025-11-06T12:23:19+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 15.87, + "teardown": 3.25, + "total": 19.12 + } }, "tests/aws/services/stepfunctions/v2/services/test_aws_sdk_task_service.py::TestTaskServiceAwsSdk::test_s3_put_object[num]": { - "last_validated_date": "2025-01-27T10:30:17+00:00" + "last_validated_date": "2025-11-06T12:23:57+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 15.76, + "teardown": 3.33, + "total": 19.09 + } }, "tests/aws/services/stepfunctions/v2/services/test_aws_sdk_task_service.py::TestTaskServiceAwsSdk::test_s3_put_object[str]": { - "last_validated_date": "2025-01-27T10:29:12+00:00" + "last_validated_date": "2025-11-06T12:22:41+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 15.06, + "teardown": 3.18, + "total": 18.24 + } }, "tests/aws/services/stepfunctions/v2/services/test_aws_sdk_task_service.py::TestTaskServiceAwsSdk::test_sfn_send_task_outcome_with_no_such_token[state_machine_template0]": { - "last_validated_date": "2024-04-10T18:55:26+00:00" + "last_validated_date": "2025-11-06T12:19:20+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 14.23, + "teardown": 1.69, + "total": 15.92 + } }, "tests/aws/services/stepfunctions/v2/services/test_aws_sdk_task_service.py::TestTaskServiceAwsSdk::test_sfn_send_task_outcome_with_no_such_token[state_machine_template1]": { - "last_validated_date": "2024-04-10T18:55:40+00:00" + "last_validated_date": "2025-11-06T12:19:35+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 13.14, + "teardown": 1.73, + "total": 14.87 + } + }, + "tests/aws/services/stepfunctions/v2/services/test_aws_sdk_task_service.py::TestTaskServiceAwsSdk::test_sfn_start_execution": { + "last_validated_date": "2025-11-06T12:20:05+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 26.45, + "teardown": 4.09, + "total": 30.54 + } }, "tests/aws/services/stepfunctions/v2/services/test_aws_sdk_task_service.py::TestTaskServiceAwsSdk::test_sfn_start_execution_implicit_json_serialisation": { - "last_validated_date": "2024-02-05T11:29:16+00:00" + "last_validated_date": "2025-11-06T12:20:41+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 31.74, + "teardown": 3.5, + "total": 35.24 + } } } diff --git a/tests/aws/services/stepfunctions/v2/services/test_dynamodb_task_service.py b/tests/aws/services/stepfunctions/v2/services/test_dynamodb_task_service.py index b198625b0f1b4..3d04c929dc7a4 100644 --- a/tests/aws/services/stepfunctions/v2/services/test_dynamodb_task_service.py +++ b/tests/aws/services/stepfunctions/v2/services/test_dynamodb_task_service.py @@ -1,7 +1,9 @@ import json import pytest -from localstack_snapshot.snapshots.transformer import RegexTransformer +from localstack_snapshot.snapshots.transformer import ( + RegexTransformer, +) from localstack.testing.pytest import markers from localstack.testing.pytest.stepfunctions.utils import ( diff --git a/tests/aws/services/stepfunctions/v2/services/test_dynamodb_task_service.snapshot.json b/tests/aws/services/stepfunctions/v2/services/test_dynamodb_task_service.snapshot.json index a3014785e3f0e..ffcc09e68dc75 100644 --- a/tests/aws/services/stepfunctions/v2/services/test_dynamodb_task_service.snapshot.json +++ b/tests/aws/services/stepfunctions/v2/services/test_dynamodb_task_service.snapshot.json @@ -1,6 +1,6 @@ { "tests/aws/services/stepfunctions/v2/services/test_dynamodb_task_service.py::TestTaskServiceDynamoDB::test_base_integrations[DYNAMODB_PUT_GET_ITEM]": { - "recorded-date": "03-02-2025, 16:31:26", + "recorded-date": "06-11-2025, 23:10:57", "recorded-content": { "get_execution_history": { "events": [ @@ -334,10 +334,10 @@ "Server": [ "Server" ], + "x-amzn-requestid": "x-amzn-requestid", "Connection": [ "keep-alive" ], - "x-amzn-RequestId": "x-amzn-RequestId", "x-amz-crc32": "x-amz-crc32", "Content-Length": [ "53" @@ -354,7 +354,7 @@ "Date": "date", "Server": "Server", "x-amz-crc32": "x-amz-crc32", - "x-amzn-RequestId": "x-amzn-RequestId" + "x-amzn-requestid": "x-amzn-requestid" }, "HttpStatusCode": 200 }, @@ -445,10 +445,10 @@ "Server": [ "Server" ], + "x-amzn-requestid": "x-amzn-requestid", "Connection": [ "keep-alive" ], - "x-amzn-RequestId": "x-amzn-RequestId", "x-amz-crc32": "x-amz-crc32", "Content-Length": [ "53" @@ -465,7 +465,7 @@ "Date": "date", "Server": "Server", "x-amz-crc32": "x-amz-crc32", - "x-amzn-RequestId": "x-amzn-RequestId" + "x-amzn-requestid": "x-amzn-requestid" }, "HttpStatusCode": 200 }, @@ -552,10 +552,10 @@ "Server": [ "Server" ], + "x-amzn-requestid": "x-amzn-requestid", "Connection": [ "keep-alive" ], - "x-amzn-RequestId": "x-amzn-RequestId", "x-amz-crc32": "x-amz-crc32", "Content-Length": [ "53" @@ -572,7 +572,7 @@ "Date": "date", "Server": "Server", "x-amz-crc32": "x-amz-crc32", - "x-amzn-RequestId": "x-amzn-RequestId" + "x-amzn-requestid": "x-amzn-requestid" }, "HttpStatusCode": 200 }, @@ -599,7 +599,7 @@ } }, "tests/aws/services/stepfunctions/v2/services/test_dynamodb_task_service.py::TestTaskServiceDynamoDB::test_base_integrations[DYNAMODB_PUT_DELETE_ITEM]": { - "recorded-date": "03-02-2025, 16:31:51", + "recorded-date": "06-11-2025, 23:11:20", "recorded-content": { "get_execution_history": { "events": [ @@ -1174,7 +1174,7 @@ } }, "tests/aws/services/stepfunctions/v2/services/test_dynamodb_task_service.py::TestTaskServiceDynamoDB::test_base_integrations[DYNAMODB_PUT_UPDATE_GET_ITEM]": { - "recorded-date": "03-02-2025, 16:34:47", + "recorded-date": "06-11-2025, 23:11:42", "recorded-content": { "get_execution_history": { "events": [ @@ -1813,10 +1813,10 @@ "Server": [ "Server" ], + "x-amzn-requestid": "x-amzn-requestid", "Connection": [ "keep-alive" ], - "x-amzn-RequestId": "x-amzn-RequestId", "x-amz-crc32": "x-amz-crc32", "Content-Length": [ "83" @@ -1833,7 +1833,7 @@ "Date": "date", "Server": "Server", "x-amz-crc32": "x-amz-crc32", - "x-amzn-RequestId": "x-amzn-RequestId" + "x-amzn-requestid": "x-amzn-requestid" }, "HttpStatusCode": 200 }, @@ -1966,10 +1966,10 @@ "Server": [ "Server" ], + "x-amzn-requestid": "x-amzn-requestid", "Connection": [ "keep-alive" ], - "x-amzn-RequestId": "x-amzn-RequestId", "x-amz-crc32": "x-amz-crc32", "Content-Length": [ "83" @@ -1986,7 +1986,7 @@ "Date": "date", "Server": "Server", "x-amz-crc32": "x-amz-crc32", - "x-amzn-RequestId": "x-amzn-RequestId" + "x-amzn-requestid": "x-amzn-requestid" }, "HttpStatusCode": 200 }, @@ -2115,10 +2115,10 @@ "Server": [ "Server" ], + "x-amzn-requestid": "x-amzn-requestid", "Connection": [ "keep-alive" ], - "x-amzn-RequestId": "x-amzn-RequestId", "x-amz-crc32": "x-amz-crc32", "Content-Length": [ "83" @@ -2135,7 +2135,7 @@ "Date": "date", "Server": "Server", "x-amz-crc32": "x-amz-crc32", - "x-amzn-RequestId": "x-amzn-RequestId" + "x-amzn-requestid": "x-amzn-requestid" }, "HttpStatusCode": 200 }, @@ -2162,7 +2162,7 @@ } }, "tests/aws/services/stepfunctions/v2/services/test_dynamodb_task_service.py::TestTaskServiceDynamoDB::test_invalid_integration": { - "recorded-date": "03-02-2025, 16:35:03", + "recorded-date": "06-11-2025, 23:12:21", "recorded-content": { "exception": { "exception_typename": "InvalidDefinition", @@ -2171,7 +2171,7 @@ } }, "tests/aws/services/stepfunctions/v2/services/test_dynamodb_task_service.py::TestTaskServiceDynamoDB::test_base_integrations[DYNAMODB_PUT_QUERY]": { - "recorded-date": "05-02-2025, 09:50:00", + "recorded-date": "06-11-2025, 23:12:05", "recorded-content": { "get_execution_history": { "events": [ @@ -2496,11 +2496,11 @@ "Count": 1, "Items": [ { - "data": { - "S": "HelloWorld" - }, "id": { "S": "id1" + }, + "data": { + "S": "HelloWorld" } } ], @@ -2579,11 +2579,11 @@ "Count": 1, "Items": [ { - "data": { - "S": "HelloWorld" - }, "id": { "S": "id1" + }, + "data": { + "S": "HelloWorld" } } ], @@ -2658,11 +2658,11 @@ "Count": 1, "Items": [ { - "data": { - "S": "HelloWorld" - }, "id": { "S": "id1" + }, + "data": { + "S": "HelloWorld" } } ], diff --git a/tests/aws/services/stepfunctions/v2/services/test_dynamodb_task_service.validation.json b/tests/aws/services/stepfunctions/v2/services/test_dynamodb_task_service.validation.json index 690385c45fd30..b4c669758ae13 100644 --- a/tests/aws/services/stepfunctions/v2/services/test_dynamodb_task_service.validation.json +++ b/tests/aws/services/stepfunctions/v2/services/test_dynamodb_task_service.validation.json @@ -1,17 +1,47 @@ { "tests/aws/services/stepfunctions/v2/services/test_dynamodb_task_service.py::TestTaskServiceDynamoDB::test_base_integrations[DYNAMODB_PUT_DELETE_ITEM]": { - "last_validated_date": "2025-02-03T16:31:51+00:00" + "last_validated_date": "2025-11-06T23:11:22+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 21.02, + "teardown": 2.18, + "total": 23.2 + } }, "tests/aws/services/stepfunctions/v2/services/test_dynamodb_task_service.py::TestTaskServiceDynamoDB::test_base_integrations[DYNAMODB_PUT_GET_ITEM]": { - "last_validated_date": "2025-02-03T16:31:26+00:00" + "last_validated_date": "2025-11-06T23:10:59+00:00", + "durations_in_seconds": { + "setup": 0.78, + "call": 19.92, + "teardown": 2.12, + "total": 22.82 + } }, "tests/aws/services/stepfunctions/v2/services/test_dynamodb_task_service.py::TestTaskServiceDynamoDB::test_base_integrations[DYNAMODB_PUT_QUERY]": { - "last_validated_date": "2025-02-05T09:50:00+00:00" + "last_validated_date": "2025-11-06T23:12:07+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 20.5, + "teardown": 2.29, + "total": 22.79 + } }, "tests/aws/services/stepfunctions/v2/services/test_dynamodb_task_service.py::TestTaskServiceDynamoDB::test_base_integrations[DYNAMODB_PUT_UPDATE_GET_ITEM]": { - "last_validated_date": "2025-02-03T16:34:47+00:00" + "last_validated_date": "2025-11-06T23:11:44+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 20.04, + "teardown": 2.16, + "total": 22.2 + } }, "tests/aws/services/stepfunctions/v2/services/test_dynamodb_task_service.py::TestTaskServiceDynamoDB::test_invalid_integration": { - "last_validated_date": "2025-02-03T16:35:03+00:00" + "last_validated_date": "2025-11-06T23:12:22+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 13.66, + "teardown": 1.23, + "total": 14.89 + } } } diff --git a/tests/aws/services/stepfunctions/v2/services/test_events_task_service.snapshot.json b/tests/aws/services/stepfunctions/v2/services/test_events_task_service.snapshot.json index 70c23a96ec4fb..4aa039fff1af8 100644 --- a/tests/aws/services/stepfunctions/v2/services/test_events_task_service.snapshot.json +++ b/tests/aws/services/stepfunctions/v2/services/test_events_task_service.snapshot.json @@ -1,6 +1,6 @@ { "tests/aws/services/stepfunctions/v2/services/test_events_task_service.py::TestTaskServiceEvents::test_put_events_base": { - "recorded-date": "12-09-2023, 10:45:20", + "recorded-date": "06-11-2025, 13:30:27", "recorded-content": { "get_execution_history": { "events": [ @@ -265,7 +265,7 @@ } }, "tests/aws/services/stepfunctions/v2/services/test_events_task_service.py::TestTaskServiceEvents::test_put_events_malformed_detail": { - "recorded-date": "12-09-2023, 10:51:57", + "recorded-date": "06-11-2025, 12:26:47", "recorded-content": { "get_execution_history": { "events": [ @@ -384,12 +384,11 @@ "HTTPHeaders": {}, "HTTPStatusCode": 200 } - }, - "stepfunctions_events": [] + } } }, "tests/aws/services/stepfunctions/v2/services/test_events_task_service.py::TestTaskServiceEvents::test_put_events_no_source": { - "recorded-date": "12-09-2023, 13:17:16", + "recorded-date": "06-11-2025, 12:27:36", "recorded-content": { "get_execution_history": { "events": [ @@ -576,7 +575,7 @@ } }, "tests/aws/services/stepfunctions/v2/services/test_events_task_service.py::TestTaskServiceEvents::test_put_events_mixed_malformed_detail": { - "recorded-date": "05-12-2024, 13:56:38", + "recorded-date": "06-11-2025, 12:27:54", "recorded-content": { "get_execution_history": { "events": [ diff --git a/tests/aws/services/stepfunctions/v2/services/test_events_task_service.validation.json b/tests/aws/services/stepfunctions/v2/services/test_events_task_service.validation.json index c3a3a74b82377..5c4ff19bc7be8 100644 --- a/tests/aws/services/stepfunctions/v2/services/test_events_task_service.validation.json +++ b/tests/aws/services/stepfunctions/v2/services/test_events_task_service.validation.json @@ -1,14 +1,38 @@ { "tests/aws/services/stepfunctions/v2/services/test_events_task_service.py::TestTaskServiceEvents::test_put_events_base": { - "last_validated_date": "2023-09-12T08:45:20+00:00" + "last_validated_date": "2025-11-06T13:30:30+00:00", + "durations_in_seconds": { + "setup": 0.68, + "call": 18.5, + "teardown": 3.05, + "total": 22.23 + } }, "tests/aws/services/stepfunctions/v2/services/test_events_task_service.py::TestTaskServiceEvents::test_put_events_malformed_detail": { - "last_validated_date": "2024-12-05T11:30:19+00:00" + "last_validated_date": "2025-11-06T12:26:50+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 13.84, + "teardown": 2.94, + "total": 16.78 + } }, "tests/aws/services/stepfunctions/v2/services/test_events_task_service.py::TestTaskServiceEvents::test_put_events_mixed_malformed_detail": { - "last_validated_date": "2024-12-05T13:56:38+00:00" + "last_validated_date": "2025-11-06T12:27:57+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 15.32, + "teardown": 3.56, + "total": 18.88 + } }, "tests/aws/services/stepfunctions/v2/services/test_events_task_service.py::TestTaskServiceEvents::test_put_events_no_source": { - "last_validated_date": "2023-09-12T11:17:16+00:00" + "last_validated_date": "2025-11-06T12:27:38+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 45.87, + "teardown": 2.61, + "total": 48.48 + } } } diff --git a/tests/aws/services/stepfunctions/v2/services/test_lambda_task.snapshot.json b/tests/aws/services/stepfunctions/v2/services/test_lambda_task.snapshot.json index 807a6c562aab1..677371488477a 100644 --- a/tests/aws/services/stepfunctions/v2/services/test_lambda_task.snapshot.json +++ b/tests/aws/services/stepfunctions/v2/services/test_lambda_task.snapshot.json @@ -1,6 +1,6 @@ { "tests/aws/services/stepfunctions/v2/services/test_lambda_task.py::TestTaskLambda::test_invoke_pipe": { - "recorded-date": "22-06-2023, 13:34:18", + "recorded-date": "06-11-2025, 12:31:08", "recorded-content": { "get_execution_history": { "events": [ @@ -170,7 +170,7 @@ } }, "tests/aws/services/stepfunctions/v2/services/test_lambda_task.py::TestTaskLambda::test_invoke_bytes_payload": { - "recorded-date": "04-08-2023, 10:45:41", + "recorded-date": "06-11-2025, 12:28:14", "recorded-content": { "get_execution_history": { "events": [ @@ -360,7 +360,7 @@ } }, "tests/aws/services/stepfunctions/v2/services/test_lambda_task.py::TestTaskLambda::test_invoke_json_values[HelloWorld]": { - "recorded-date": "04-08-2023, 16:13:17", + "recorded-date": "06-11-2025, 12:28:52", "recorded-content": { "get_execution_history": { "events": [ @@ -455,7 +455,7 @@ } }, "tests/aws/services/stepfunctions/v2/services/test_lambda_task.py::TestTaskLambda::test_invoke_json_values[0.0]": { - "recorded-date": "04-08-2023, 16:13:35", + "recorded-date": "06-11-2025, 12:29:11", "recorded-content": { "get_execution_history": { "events": [ @@ -550,7 +550,7 @@ } }, "tests/aws/services/stepfunctions/v2/services/test_lambda_task.py::TestTaskLambda::test_invoke_json_values[0_0]": { - "recorded-date": "04-08-2023, 16:13:53", + "recorded-date": "06-11-2025, 12:29:30", "recorded-content": { "get_execution_history": { "events": [ @@ -645,7 +645,7 @@ } }, "tests/aws/services/stepfunctions/v2/services/test_lambda_task.py::TestTaskLambda::test_invoke_json_values[0_1]": { - "recorded-date": "04-08-2023, 16:14:12", + "recorded-date": "06-11-2025, 12:29:49", "recorded-content": { "get_execution_history": { "events": [ @@ -740,7 +740,7 @@ } }, "tests/aws/services/stepfunctions/v2/services/test_lambda_task.py::TestTaskLambda::test_invoke_json_values[True]": { - "recorded-date": "04-08-2023, 16:14:30", + "recorded-date": "06-11-2025, 12:30:09", "recorded-content": { "get_execution_history": { "events": [ @@ -835,7 +835,7 @@ } }, "tests/aws/services/stepfunctions/v2/services/test_lambda_task.py::TestTaskLambda::test_invoke_json_values[json_value6]": { - "recorded-date": "04-08-2023, 16:15:06", + "recorded-date": "06-11-2025, 12:30:47", "recorded-content": { "get_execution_history": { "events": [ @@ -1025,7 +1025,7 @@ } }, "tests/aws/services/stepfunctions/v2/services/test_lambda_task.py::TestTaskLambda::test_invoke_json_values[json_value5]": { - "recorded-date": "04-08-2023, 16:14:48", + "recorded-date": "06-11-2025, 12:30:28", "recorded-content": { "get_execution_history": { "events": [ @@ -1120,7 +1120,7 @@ } }, "tests/aws/services/stepfunctions/v2/services/test_lambda_task.py::TestTaskLambda::test_lambda_task_filter_parameters_input": { - "recorded-date": "22-09-2023, 22:36:51", + "recorded-date": "06-11-2025, 12:31:27", "recorded-content": { "get_execution_history": { "events": [ @@ -1275,7 +1275,7 @@ } }, "tests/aws/services/stepfunctions/v2/services/test_lambda_task.py::TestTaskLambda::test_invoke_string_payload": { - "recorded-date": "25-03-2024, 22:25:45", + "recorded-date": "06-11-2025, 12:28:33", "recorded-content": { "get_execution_history": { "events": [ diff --git a/tests/aws/services/stepfunctions/v2/services/test_lambda_task.validation.json b/tests/aws/services/stepfunctions/v2/services/test_lambda_task.validation.json index 72dad53a757ec..3886cc534292c 100644 --- a/tests/aws/services/stepfunctions/v2/services/test_lambda_task.validation.json +++ b/tests/aws/services/stepfunctions/v2/services/test_lambda_task.validation.json @@ -1,35 +1,101 @@ { "tests/aws/services/stepfunctions/v2/services/test_lambda_task.py::TestTaskLambda::test_invoke_bytes_payload": { - "last_validated_date": "2023-08-04T08:45:41+00:00" + "last_validated_date": "2025-11-06T12:28:16+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 16.29, + "teardown": 2.83, + "total": 19.12 + } }, "tests/aws/services/stepfunctions/v2/services/test_lambda_task.py::TestTaskLambda::test_invoke_json_values[0.0]": { - "last_validated_date": "2023-08-04T14:13:35+00:00" + "last_validated_date": "2025-11-06T12:29:14+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 16.31, + "teardown": 2.76, + "total": 19.07 + } }, "tests/aws/services/stepfunctions/v2/services/test_lambda_task.py::TestTaskLambda::test_invoke_json_values[0_0]": { - "last_validated_date": "2023-08-04T14:13:53+00:00" + "last_validated_date": "2025-11-06T12:29:33+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 16.43, + "teardown": 2.9, + "total": 19.33 + } }, "tests/aws/services/stepfunctions/v2/services/test_lambda_task.py::TestTaskLambda::test_invoke_json_values[0_1]": { - "last_validated_date": "2023-08-04T14:14:12+00:00" + "last_validated_date": "2025-11-06T12:29:52+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 16.12, + "teardown": 2.75, + "total": 18.87 + } }, "tests/aws/services/stepfunctions/v2/services/test_lambda_task.py::TestTaskLambda::test_invoke_json_values[HelloWorld]": { - "last_validated_date": "2023-08-04T14:13:17+00:00" + "last_validated_date": "2025-11-06T12:28:55+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 16.33, + "teardown": 2.86, + "total": 19.19 + } }, "tests/aws/services/stepfunctions/v2/services/test_lambda_task.py::TestTaskLambda::test_invoke_json_values[True]": { - "last_validated_date": "2023-08-04T14:14:30+00:00" + "last_validated_date": "2025-11-06T12:30:11+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 16.36, + "teardown": 2.79, + "total": 19.15 + } }, "tests/aws/services/stepfunctions/v2/services/test_lambda_task.py::TestTaskLambda::test_invoke_json_values[json_value5]": { - "last_validated_date": "2023-08-04T14:14:48+00:00" + "last_validated_date": "2025-11-06T12:30:30+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 16.22, + "teardown": 2.91, + "total": 19.13 + } }, "tests/aws/services/stepfunctions/v2/services/test_lambda_task.py::TestTaskLambda::test_invoke_json_values[json_value6]": { - "last_validated_date": "2023-08-04T14:15:06+00:00" + "last_validated_date": "2025-11-06T12:30:49+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 16.3, + "teardown": 2.45, + "total": 18.75 + } }, "tests/aws/services/stepfunctions/v2/services/test_lambda_task.py::TestTaskLambda::test_invoke_pipe": { - "last_validated_date": "2023-06-22T11:34:18+00:00" + "last_validated_date": "2025-11-06T12:31:11+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 18.67, + "teardown": 3.32, + "total": 21.99 + } }, "tests/aws/services/stepfunctions/v2/services/test_lambda_task.py::TestTaskLambda::test_invoke_string_payload": { - "last_validated_date": "2024-03-25T22:25:45+00:00" + "last_validated_date": "2025-11-06T12:28:36+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 16.36, + "teardown": 2.79, + "total": 19.15 + } }, "tests/aws/services/stepfunctions/v2/services/test_lambda_task.py::TestTaskLambda::test_lambda_task_filter_parameters_input": { - "last_validated_date": "2023-09-22T20:36:51+00:00" + "last_validated_date": "2025-11-06T12:31:30+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 16.31, + "teardown": 2.94, + "total": 19.25 + } } } diff --git a/tests/aws/services/stepfunctions/v2/services/test_lambda_task_service.snapshot.json b/tests/aws/services/stepfunctions/v2/services/test_lambda_task_service.snapshot.json index 3bb44279ebb34..528aab071322c 100644 --- a/tests/aws/services/stepfunctions/v2/services/test_lambda_task_service.snapshot.json +++ b/tests/aws/services/stepfunctions/v2/services/test_lambda_task_service.snapshot.json @@ -1,6 +1,6 @@ { "tests/aws/services/stepfunctions/v2/services/test_lambda_task_service.py::TestTaskServiceLambda::test_invoke": { - "recorded-date": "22-06-2023, 13:39:30", + "recorded-date": "06-11-2025, 12:31:47", "recorded-content": { "get_execution_history": { "events": [ @@ -79,9 +79,7 @@ "Connection": [ "keep-alive" ], - "x-amzn-RequestId": [ - "" - ], + "x-amzn-RequestId": "x-amzn-RequestId", "Content-Length": [ "2" ], @@ -98,13 +96,13 @@ "Date": "date", "X-Amz-Executed-Version": "$LATEST", "x-amzn-Remapped-Content-Length": "0", - "x-amzn-RequestId": "", + "x-amzn-RequestId": "x-amzn-RequestId", "X-Amzn-Trace-Id": "X-Amzn-Trace-Id" }, "HttpStatusCode": 200 }, "SdkResponseMetadata": { - "RequestId": "" + "RequestId": "RequestId" }, "StatusCode": 200 }, @@ -136,9 +134,7 @@ "Connection": [ "keep-alive" ], - "x-amzn-RequestId": [ - "" - ], + "x-amzn-RequestId": "x-amzn-RequestId", "Content-Length": [ "2" ], @@ -155,13 +151,13 @@ "Date": "date", "X-Amz-Executed-Version": "$LATEST", "x-amzn-Remapped-Content-Length": "0", - "x-amzn-RequestId": "", + "x-amzn-RequestId": "x-amzn-RequestId", "X-Amzn-Trace-Id": "X-Amzn-Trace-Id" }, "HttpStatusCode": 200 }, "SdkResponseMetadata": { - "RequestId": "" + "RequestId": "RequestId" }, "StatusCode": 200 }, @@ -190,9 +186,7 @@ "Connection": [ "keep-alive" ], - "x-amzn-RequestId": [ - "" - ], + "x-amzn-RequestId": "x-amzn-RequestId", "Content-Length": [ "2" ], @@ -209,13 +203,13 @@ "Date": "date", "X-Amz-Executed-Version": "$LATEST", "x-amzn-Remapped-Content-Length": "0", - "x-amzn-RequestId": "", + "x-amzn-RequestId": "x-amzn-RequestId", "X-Amzn-Trace-Id": "X-Amzn-Trace-Id" }, "HttpStatusCode": 200 }, "SdkResponseMetadata": { - "RequestId": "" + "RequestId": "RequestId" }, "StatusCode": 200 }, @@ -246,9 +240,7 @@ "Connection": [ "keep-alive" ], - "x-amzn-RequestId": [ - "" - ], + "x-amzn-RequestId": "x-amzn-RequestId", "Content-Length": [ "2" ], @@ -265,13 +257,13 @@ "Date": "date", "X-Amz-Executed-Version": "$LATEST", "x-amzn-Remapped-Content-Length": "0", - "x-amzn-RequestId": "", + "x-amzn-RequestId": "x-amzn-RequestId", "X-Amzn-Trace-Id": "X-Amzn-Trace-Id" }, "HttpStatusCode": 200 }, "SdkResponseMetadata": { - "RequestId": "" + "RequestId": "RequestId" }, "StatusCode": 200, "final": { @@ -288,9 +280,7 @@ "Connection": [ "keep-alive" ], - "x-amzn-RequestId": [ - "" - ], + "x-amzn-RequestId": "x-amzn-RequestId", "Content-Length": [ "2" ], @@ -307,13 +297,13 @@ "Date": "date", "X-Amz-Executed-Version": "$LATEST", "x-amzn-Remapped-Content-Length": "0", - "x-amzn-RequestId": "", + "x-amzn-RequestId": "x-amzn-RequestId", "X-Amzn-Trace-Id": "X-Amzn-Trace-Id" }, "HttpStatusCode": 200 }, "SdkResponseMetadata": { - "RequestId": "" + "RequestId": "RequestId" }, "StatusCode": 200 } @@ -341,9 +331,7 @@ "Connection": [ "keep-alive" ], - "x-amzn-RequestId": [ - "" - ], + "x-amzn-RequestId": "x-amzn-RequestId", "Content-Length": [ "2" ], @@ -360,13 +348,13 @@ "Date": "date", "X-Amz-Executed-Version": "$LATEST", "x-amzn-Remapped-Content-Length": "0", - "x-amzn-RequestId": "", + "x-amzn-RequestId": "x-amzn-RequestId", "X-Amzn-Trace-Id": "X-Amzn-Trace-Id" }, "HttpStatusCode": 200 }, "SdkResponseMetadata": { - "RequestId": "" + "RequestId": "RequestId" }, "StatusCode": 200, "final": { @@ -383,9 +371,7 @@ "Connection": [ "keep-alive" ], - "x-amzn-RequestId": [ - "" - ], + "x-amzn-RequestId": "x-amzn-RequestId", "Content-Length": [ "2" ], @@ -402,13 +388,13 @@ "Date": "date", "X-Amz-Executed-Version": "$LATEST", "x-amzn-Remapped-Content-Length": "0", - "x-amzn-RequestId": "", + "x-amzn-RequestId": "x-amzn-RequestId", "X-Amzn-Trace-Id": "X-Amzn-Trace-Id" }, "HttpStatusCode": 200 }, "SdkResponseMetadata": { - "RequestId": "" + "RequestId": "RequestId" }, "StatusCode": 200 } @@ -431,7 +417,7 @@ } }, "tests/aws/services/stepfunctions/v2/services/test_lambda_task_service.py::TestTaskServiceLambda::test_invoke_unsupported_param": { - "recorded-date": "22-06-2023, 14:15:28", + "recorded-date": "06-11-2025, 12:32:26", "recorded-content": { "get_execution_history": { "events": [ @@ -517,9 +503,7 @@ "Connection": [ "keep-alive" ], - "x-amzn-RequestId": [ - "" - ], + "x-amzn-RequestId": "x-amzn-RequestId", "Content-Length": [ "2" ], @@ -537,13 +521,13 @@ "X-Amz-Executed-Version": "$LATEST", "X-Amz-Log-Result": "", "x-amzn-Remapped-Content-Length": "0", - "x-amzn-RequestId": "", + "x-amzn-RequestId": "x-amzn-RequestId", "X-Amzn-Trace-Id": "X-Amzn-Trace-Id" }, "HttpStatusCode": 200 }, "SdkResponseMetadata": { - "RequestId": "" + "RequestId": "RequestId" }, "StatusCode": 200 }, @@ -579,9 +563,7 @@ "Connection": [ "keep-alive" ], - "x-amzn-RequestId": [ - "" - ], + "x-amzn-RequestId": "x-amzn-RequestId", "Content-Length": [ "2" ], @@ -599,13 +581,13 @@ "X-Amz-Executed-Version": "$LATEST", "X-Amz-Log-Result": "", "x-amzn-Remapped-Content-Length": "0", - "x-amzn-RequestId": "", + "x-amzn-RequestId": "x-amzn-RequestId", "X-Amzn-Trace-Id": "X-Amzn-Trace-Id" }, "HttpStatusCode": 200 }, "SdkResponseMetadata": { - "RequestId": "" + "RequestId": "RequestId" }, "StatusCode": 200 }, @@ -638,9 +620,7 @@ "Connection": [ "keep-alive" ], - "x-amzn-RequestId": [ - "" - ], + "x-amzn-RequestId": "x-amzn-RequestId", "Content-Length": [ "2" ], @@ -658,13 +638,13 @@ "X-Amz-Executed-Version": "$LATEST", "X-Amz-Log-Result": "", "x-amzn-Remapped-Content-Length": "0", - "x-amzn-RequestId": "", + "x-amzn-RequestId": "x-amzn-RequestId", "X-Amzn-Trace-Id": "X-Amzn-Trace-Id" }, "HttpStatusCode": 200 }, "SdkResponseMetadata": { - "RequestId": "" + "RequestId": "RequestId" }, "StatusCode": 200 }, @@ -699,9 +679,7 @@ "Connection": [ "keep-alive" ], - "x-amzn-RequestId": [ - "" - ], + "x-amzn-RequestId": "x-amzn-RequestId", "Content-Length": [ "2" ], @@ -719,13 +697,13 @@ "X-Amz-Executed-Version": "$LATEST", "X-Amz-Log-Result": "", "x-amzn-Remapped-Content-Length": "0", - "x-amzn-RequestId": "", + "x-amzn-RequestId": "x-amzn-RequestId", "X-Amzn-Trace-Id": "X-Amzn-Trace-Id" }, "HttpStatusCode": 200 }, "SdkResponseMetadata": { - "RequestId": "" + "RequestId": "RequestId" }, "StatusCode": 200, "final": { @@ -746,9 +724,7 @@ "Connection": [ "keep-alive" ], - "x-amzn-RequestId": [ - "" - ], + "x-amzn-RequestId": "x-amzn-RequestId", "Content-Length": [ "2" ], @@ -766,13 +742,13 @@ "X-Amz-Executed-Version": "$LATEST", "X-Amz-Log-Result": "", "x-amzn-Remapped-Content-Length": "0", - "x-amzn-RequestId": "", + "x-amzn-RequestId": "x-amzn-RequestId", "X-Amzn-Trace-Id": "X-Amzn-Trace-Id" }, "HttpStatusCode": 200 }, "SdkResponseMetadata": { - "RequestId": "" + "RequestId": "RequestId" }, "StatusCode": 200 } @@ -804,9 +780,7 @@ "Connection": [ "keep-alive" ], - "x-amzn-RequestId": [ - "" - ], + "x-amzn-RequestId": "x-amzn-RequestId", "Content-Length": [ "2" ], @@ -824,13 +798,13 @@ "X-Amz-Executed-Version": "$LATEST", "X-Amz-Log-Result": "", "x-amzn-Remapped-Content-Length": "0", - "x-amzn-RequestId": "", + "x-amzn-RequestId": "x-amzn-RequestId", "X-Amzn-Trace-Id": "X-Amzn-Trace-Id" }, "HttpStatusCode": 200 }, "SdkResponseMetadata": { - "RequestId": "" + "RequestId": "RequestId" }, "StatusCode": 200, "final": { @@ -851,9 +825,7 @@ "Connection": [ "keep-alive" ], - "x-amzn-RequestId": [ - "" - ], + "x-amzn-RequestId": "x-amzn-RequestId", "Content-Length": [ "2" ], @@ -871,13 +843,13 @@ "X-Amz-Executed-Version": "$LATEST", "X-Amz-Log-Result": "", "x-amzn-Remapped-Content-Length": "0", - "x-amzn-RequestId": "", + "x-amzn-RequestId": "x-amzn-RequestId", "X-Amzn-Trace-Id": "X-Amzn-Trace-Id" }, "HttpStatusCode": 200 }, "SdkResponseMetadata": { - "RequestId": "" + "RequestId": "RequestId" }, "StatusCode": 200 } @@ -900,11 +872,11 @@ } }, "tests/aws/services/stepfunctions/v2/services/test_lambda_task_service.py::TestTaskServiceLambda::test_list_functions": { - "recorded-date": "11-05-2023, 11:29:56", + "recorded-date": "06-11-2025, 12:34:55", "recorded-content": {} }, "tests/aws/services/stepfunctions/v2/services/test_lambda_task_service.py::TestTaskServiceLambda::test_invoke_bytes_payload": { - "recorded-date": "04-08-2023, 10:48:27", + "recorded-date": "06-11-2025, 12:32:06", "recorded-content": { "get_execution_history": { "events": [ @@ -983,9 +955,7 @@ "Connection": [ "keep-alive" ], - "x-amzn-RequestId": [ - "" - ], + "x-amzn-RequestId": "x-amzn-RequestId", "Content-Length": [ "13" ], @@ -1002,13 +972,13 @@ "Date": "date", "X-Amz-Executed-Version": "$LATEST", "x-amzn-Remapped-Content-Length": "0", - "x-amzn-RequestId": "", + "x-amzn-RequestId": "x-amzn-RequestId", "X-Amzn-Trace-Id": "X-Amzn-Trace-Id" }, "HttpStatusCode": 200 }, "SdkResponseMetadata": { - "RequestId": "" + "RequestId": "RequestId" }, "StatusCode": 200 }, @@ -1040,9 +1010,7 @@ "Connection": [ "keep-alive" ], - "x-amzn-RequestId": [ - "" - ], + "x-amzn-RequestId": "x-amzn-RequestId", "Content-Length": [ "13" ], @@ -1059,13 +1027,13 @@ "Date": "date", "X-Amz-Executed-Version": "$LATEST", "x-amzn-Remapped-Content-Length": "0", - "x-amzn-RequestId": "", + "x-amzn-RequestId": "x-amzn-RequestId", "X-Amzn-Trace-Id": "X-Amzn-Trace-Id" }, "HttpStatusCode": 200 }, "SdkResponseMetadata": { - "RequestId": "" + "RequestId": "RequestId" }, "StatusCode": 200 }, @@ -1094,9 +1062,7 @@ "Connection": [ "keep-alive" ], - "x-amzn-RequestId": [ - "" - ], + "x-amzn-RequestId": "x-amzn-RequestId", "Content-Length": [ "13" ], @@ -1113,13 +1079,13 @@ "Date": "date", "X-Amz-Executed-Version": "$LATEST", "x-amzn-Remapped-Content-Length": "0", - "x-amzn-RequestId": "", + "x-amzn-RequestId": "x-amzn-RequestId", "X-Amzn-Trace-Id": "X-Amzn-Trace-Id" }, "HttpStatusCode": 200 }, "SdkResponseMetadata": { - "RequestId": "" + "RequestId": "RequestId" }, "StatusCode": 200 }, @@ -1150,9 +1116,7 @@ "Connection": [ "keep-alive" ], - "x-amzn-RequestId": [ - "" - ], + "x-amzn-RequestId": "x-amzn-RequestId", "Content-Length": [ "13" ], @@ -1169,13 +1133,13 @@ "Date": "date", "X-Amz-Executed-Version": "$LATEST", "x-amzn-Remapped-Content-Length": "0", - "x-amzn-RequestId": "", + "x-amzn-RequestId": "x-amzn-RequestId", "X-Amzn-Trace-Id": "X-Amzn-Trace-Id" }, "HttpStatusCode": 200 }, "SdkResponseMetadata": { - "RequestId": "" + "RequestId": "RequestId" }, "StatusCode": 200, "final": { @@ -1192,9 +1156,7 @@ "Connection": [ "keep-alive" ], - "x-amzn-RequestId": [ - "" - ], + "x-amzn-RequestId": "x-amzn-RequestId", "Content-Length": [ "13" ], @@ -1211,13 +1173,13 @@ "Date": "date", "X-Amz-Executed-Version": "$LATEST", "x-amzn-Remapped-Content-Length": "0", - "x-amzn-RequestId": "", + "x-amzn-RequestId": "x-amzn-RequestId", "X-Amzn-Trace-Id": "X-Amzn-Trace-Id" }, "HttpStatusCode": 200 }, "SdkResponseMetadata": { - "RequestId": "" + "RequestId": "RequestId" }, "StatusCode": 200 } @@ -1245,9 +1207,7 @@ "Connection": [ "keep-alive" ], - "x-amzn-RequestId": [ - "" - ], + "x-amzn-RequestId": "x-amzn-RequestId", "Content-Length": [ "13" ], @@ -1264,13 +1224,13 @@ "Date": "date", "X-Amz-Executed-Version": "$LATEST", "x-amzn-Remapped-Content-Length": "0", - "x-amzn-RequestId": "", + "x-amzn-RequestId": "x-amzn-RequestId", "X-Amzn-Trace-Id": "X-Amzn-Trace-Id" }, "HttpStatusCode": 200 }, "SdkResponseMetadata": { - "RequestId": "" + "RequestId": "RequestId" }, "StatusCode": 200, "final": { @@ -1287,9 +1247,7 @@ "Connection": [ "keep-alive" ], - "x-amzn-RequestId": [ - "" - ], + "x-amzn-RequestId": "x-amzn-RequestId", "Content-Length": [ "13" ], @@ -1306,13 +1264,13 @@ "Date": "date", "X-Amz-Executed-Version": "$LATEST", "x-amzn-Remapped-Content-Length": "0", - "x-amzn-RequestId": "", + "x-amzn-RequestId": "x-amzn-RequestId", "X-Amzn-Trace-Id": "X-Amzn-Trace-Id" }, "HttpStatusCode": 200 }, "SdkResponseMetadata": { - "RequestId": "" + "RequestId": "RequestId" }, "StatusCode": 200 } @@ -1766,7 +1724,7 @@ } }, "tests/aws/services/stepfunctions/v2/services/test_lambda_task_service.py::TestTaskServiceLambda::test_invoke_json_values[HelloWorld]": { - "recorded-date": "04-08-2023, 16:04:28", + "recorded-date": "06-11-2025, 12:32:44", "recorded-content": { "get_execution_history": { "events": [ @@ -1845,9 +1803,7 @@ "Connection": [ "keep-alive" ], - "x-amzn-RequestId": [ - "" - ], + "x-amzn-RequestId": "x-amzn-RequestId", "Content-Length": [ "12" ], @@ -1864,13 +1820,13 @@ "Date": "date", "X-Amz-Executed-Version": "$LATEST", "x-amzn-Remapped-Content-Length": "0", - "x-amzn-RequestId": "", + "x-amzn-RequestId": "x-amzn-RequestId", "X-Amzn-Trace-Id": "X-Amzn-Trace-Id" }, "HttpStatusCode": 200 }, "SdkResponseMetadata": { - "RequestId": "" + "RequestId": "RequestId" }, "StatusCode": 200 }, @@ -1902,9 +1858,7 @@ "Connection": [ "keep-alive" ], - "x-amzn-RequestId": [ - "" - ], + "x-amzn-RequestId": "x-amzn-RequestId", "Content-Length": [ "12" ], @@ -1921,13 +1875,13 @@ "Date": "date", "X-Amz-Executed-Version": "$LATEST", "x-amzn-Remapped-Content-Length": "0", - "x-amzn-RequestId": "", + "x-amzn-RequestId": "x-amzn-RequestId", "X-Amzn-Trace-Id": "X-Amzn-Trace-Id" }, "HttpStatusCode": 200 }, "SdkResponseMetadata": { - "RequestId": "" + "RequestId": "RequestId" }, "StatusCode": 200 }, @@ -1956,9 +1910,7 @@ "Connection": [ "keep-alive" ], - "x-amzn-RequestId": [ - "" - ], + "x-amzn-RequestId": "x-amzn-RequestId", "Content-Length": [ "12" ], @@ -1975,13 +1927,13 @@ "Date": "date", "X-Amz-Executed-Version": "$LATEST", "x-amzn-Remapped-Content-Length": "0", - "x-amzn-RequestId": "", + "x-amzn-RequestId": "x-amzn-RequestId", "X-Amzn-Trace-Id": "X-Amzn-Trace-Id" }, "HttpStatusCode": 200 }, "SdkResponseMetadata": { - "RequestId": "" + "RequestId": "RequestId" }, "StatusCode": 200 }, @@ -2012,9 +1964,7 @@ "Connection": [ "keep-alive" ], - "x-amzn-RequestId": [ - "" - ], + "x-amzn-RequestId": "x-amzn-RequestId", "Content-Length": [ "12" ], @@ -2031,13 +1981,13 @@ "Date": "date", "X-Amz-Executed-Version": "$LATEST", "x-amzn-Remapped-Content-Length": "0", - "x-amzn-RequestId": "", + "x-amzn-RequestId": "x-amzn-RequestId", "X-Amzn-Trace-Id": "X-Amzn-Trace-Id" }, "HttpStatusCode": 200 }, "SdkResponseMetadata": { - "RequestId": "" + "RequestId": "RequestId" }, "StatusCode": 200, "final": { @@ -2054,9 +2004,7 @@ "Connection": [ "keep-alive" ], - "x-amzn-RequestId": [ - "" - ], + "x-amzn-RequestId": "x-amzn-RequestId", "Content-Length": [ "12" ], @@ -2073,13 +2021,13 @@ "Date": "date", "X-Amz-Executed-Version": "$LATEST", "x-amzn-Remapped-Content-Length": "0", - "x-amzn-RequestId": "", + "x-amzn-RequestId": "x-amzn-RequestId", "X-Amzn-Trace-Id": "X-Amzn-Trace-Id" }, "HttpStatusCode": 200 }, "SdkResponseMetadata": { - "RequestId": "" + "RequestId": "RequestId" }, "StatusCode": 200 } @@ -2107,9 +2055,7 @@ "Connection": [ "keep-alive" ], - "x-amzn-RequestId": [ - "" - ], + "x-amzn-RequestId": "x-amzn-RequestId", "Content-Length": [ "12" ], @@ -2126,13 +2072,13 @@ "Date": "date", "X-Amz-Executed-Version": "$LATEST", "x-amzn-Remapped-Content-Length": "0", - "x-amzn-RequestId": "", + "x-amzn-RequestId": "x-amzn-RequestId", "X-Amzn-Trace-Id": "X-Amzn-Trace-Id" }, "HttpStatusCode": 200 }, "SdkResponseMetadata": { - "RequestId": "" + "RequestId": "RequestId" }, "StatusCode": 200, "final": { @@ -2149,9 +2095,7 @@ "Connection": [ "keep-alive" ], - "x-amzn-RequestId": [ - "" - ], + "x-amzn-RequestId": "x-amzn-RequestId", "Content-Length": [ "12" ], @@ -2168,13 +2112,13 @@ "Date": "date", "X-Amz-Executed-Version": "$LATEST", "x-amzn-Remapped-Content-Length": "0", - "x-amzn-RequestId": "", + "x-amzn-RequestId": "x-amzn-RequestId", "X-Amzn-Trace-Id": "X-Amzn-Trace-Id" }, "HttpStatusCode": 200 }, "SdkResponseMetadata": { - "RequestId": "" + "RequestId": "RequestId" }, "StatusCode": 200 } @@ -2197,7 +2141,7 @@ } }, "tests/aws/services/stepfunctions/v2/services/test_lambda_task_service.py::TestTaskServiceLambda::test_invoke_json_values[0.0]": { - "recorded-date": "04-08-2023, 16:04:46", + "recorded-date": "06-11-2025, 12:33:04", "recorded-content": { "get_execution_history": { "events": [ @@ -2276,9 +2220,7 @@ "Connection": [ "keep-alive" ], - "x-amzn-RequestId": [ - "" - ], + "x-amzn-RequestId": "x-amzn-RequestId", "Content-Length": [ "3" ], @@ -2295,13 +2237,13 @@ "Date": "date", "X-Amz-Executed-Version": "$LATEST", "x-amzn-Remapped-Content-Length": "0", - "x-amzn-RequestId": "", + "x-amzn-RequestId": "x-amzn-RequestId", "X-Amzn-Trace-Id": "X-Amzn-Trace-Id" }, "HttpStatusCode": 200 }, "SdkResponseMetadata": { - "RequestId": "" + "RequestId": "RequestId" }, "StatusCode": 200 }, @@ -2333,9 +2275,7 @@ "Connection": [ "keep-alive" ], - "x-amzn-RequestId": [ - "" - ], + "x-amzn-RequestId": "x-amzn-RequestId", "Content-Length": [ "3" ], @@ -2352,13 +2292,13 @@ "Date": "date", "X-Amz-Executed-Version": "$LATEST", "x-amzn-Remapped-Content-Length": "0", - "x-amzn-RequestId": "", + "x-amzn-RequestId": "x-amzn-RequestId", "X-Amzn-Trace-Id": "X-Amzn-Trace-Id" }, "HttpStatusCode": 200 }, "SdkResponseMetadata": { - "RequestId": "" + "RequestId": "RequestId" }, "StatusCode": 200 }, @@ -2387,9 +2327,7 @@ "Connection": [ "keep-alive" ], - "x-amzn-RequestId": [ - "" - ], + "x-amzn-RequestId": "x-amzn-RequestId", "Content-Length": [ "3" ], @@ -2406,13 +2344,13 @@ "Date": "date", "X-Amz-Executed-Version": "$LATEST", "x-amzn-Remapped-Content-Length": "0", - "x-amzn-RequestId": "", + "x-amzn-RequestId": "x-amzn-RequestId", "X-Amzn-Trace-Id": "X-Amzn-Trace-Id" }, "HttpStatusCode": 200 }, "SdkResponseMetadata": { - "RequestId": "" + "RequestId": "RequestId" }, "StatusCode": 200 }, @@ -2443,9 +2381,7 @@ "Connection": [ "keep-alive" ], - "x-amzn-RequestId": [ - "" - ], + "x-amzn-RequestId": "x-amzn-RequestId", "Content-Length": [ "3" ], @@ -2462,13 +2398,13 @@ "Date": "date", "X-Amz-Executed-Version": "$LATEST", "x-amzn-Remapped-Content-Length": "0", - "x-amzn-RequestId": "", + "x-amzn-RequestId": "x-amzn-RequestId", "X-Amzn-Trace-Id": "X-Amzn-Trace-Id" }, "HttpStatusCode": 200 }, "SdkResponseMetadata": { - "RequestId": "" + "RequestId": "RequestId" }, "StatusCode": 200, "final": { @@ -2485,9 +2421,7 @@ "Connection": [ "keep-alive" ], - "x-amzn-RequestId": [ - "" - ], + "x-amzn-RequestId": "x-amzn-RequestId", "Content-Length": [ "3" ], @@ -2504,13 +2438,13 @@ "Date": "date", "X-Amz-Executed-Version": "$LATEST", "x-amzn-Remapped-Content-Length": "0", - "x-amzn-RequestId": "", + "x-amzn-RequestId": "x-amzn-RequestId", "X-Amzn-Trace-Id": "X-Amzn-Trace-Id" }, "HttpStatusCode": 200 }, "SdkResponseMetadata": { - "RequestId": "" + "RequestId": "RequestId" }, "StatusCode": 200 } @@ -2538,9 +2472,7 @@ "Connection": [ "keep-alive" ], - "x-amzn-RequestId": [ - "" - ], + "x-amzn-RequestId": "x-amzn-RequestId", "Content-Length": [ "3" ], @@ -2557,13 +2489,13 @@ "Date": "date", "X-Amz-Executed-Version": "$LATEST", "x-amzn-Remapped-Content-Length": "0", - "x-amzn-RequestId": "", + "x-amzn-RequestId": "x-amzn-RequestId", "X-Amzn-Trace-Id": "X-Amzn-Trace-Id" }, "HttpStatusCode": 200 }, "SdkResponseMetadata": { - "RequestId": "" + "RequestId": "RequestId" }, "StatusCode": 200, "final": { @@ -2580,9 +2512,7 @@ "Connection": [ "keep-alive" ], - "x-amzn-RequestId": [ - "" - ], + "x-amzn-RequestId": "x-amzn-RequestId", "Content-Length": [ "3" ], @@ -2599,13 +2529,13 @@ "Date": "date", "X-Amz-Executed-Version": "$LATEST", "x-amzn-Remapped-Content-Length": "0", - "x-amzn-RequestId": "", + "x-amzn-RequestId": "x-amzn-RequestId", "X-Amzn-Trace-Id": "X-Amzn-Trace-Id" }, "HttpStatusCode": 200 }, "SdkResponseMetadata": { - "RequestId": "" + "RequestId": "RequestId" }, "StatusCode": 200 } @@ -2628,7 +2558,7 @@ } }, "tests/aws/services/stepfunctions/v2/services/test_lambda_task_service.py::TestTaskServiceLambda::test_invoke_json_values[0_0]": { - "recorded-date": "04-08-2023, 16:05:04", + "recorded-date": "06-11-2025, 12:33:23", "recorded-content": { "get_execution_history": { "events": [ @@ -2707,9 +2637,7 @@ "Connection": [ "keep-alive" ], - "x-amzn-RequestId": [ - "" - ], + "x-amzn-RequestId": "x-amzn-RequestId", "Content-Length": [ "1" ], @@ -2726,13 +2654,13 @@ "Date": "date", "X-Amz-Executed-Version": "$LATEST", "x-amzn-Remapped-Content-Length": "0", - "x-amzn-RequestId": "", + "x-amzn-RequestId": "x-amzn-RequestId", "X-Amzn-Trace-Id": "X-Amzn-Trace-Id" }, "HttpStatusCode": 200 }, "SdkResponseMetadata": { - "RequestId": "" + "RequestId": "RequestId" }, "StatusCode": 200 }, @@ -2764,9 +2692,7 @@ "Connection": [ "keep-alive" ], - "x-amzn-RequestId": [ - "" - ], + "x-amzn-RequestId": "x-amzn-RequestId", "Content-Length": [ "1" ], @@ -2783,13 +2709,13 @@ "Date": "date", "X-Amz-Executed-Version": "$LATEST", "x-amzn-Remapped-Content-Length": "0", - "x-amzn-RequestId": "", + "x-amzn-RequestId": "x-amzn-RequestId", "X-Amzn-Trace-Id": "X-Amzn-Trace-Id" }, "HttpStatusCode": 200 }, "SdkResponseMetadata": { - "RequestId": "" + "RequestId": "RequestId" }, "StatusCode": 200 }, @@ -2818,9 +2744,7 @@ "Connection": [ "keep-alive" ], - "x-amzn-RequestId": [ - "" - ], + "x-amzn-RequestId": "x-amzn-RequestId", "Content-Length": [ "1" ], @@ -2837,13 +2761,13 @@ "Date": "date", "X-Amz-Executed-Version": "$LATEST", "x-amzn-Remapped-Content-Length": "0", - "x-amzn-RequestId": "", + "x-amzn-RequestId": "x-amzn-RequestId", "X-Amzn-Trace-Id": "X-Amzn-Trace-Id" }, "HttpStatusCode": 200 }, "SdkResponseMetadata": { - "RequestId": "" + "RequestId": "RequestId" }, "StatusCode": 200 }, @@ -2874,9 +2798,7 @@ "Connection": [ "keep-alive" ], - "x-amzn-RequestId": [ - "" - ], + "x-amzn-RequestId": "x-amzn-RequestId", "Content-Length": [ "1" ], @@ -2893,13 +2815,13 @@ "Date": "date", "X-Amz-Executed-Version": "$LATEST", "x-amzn-Remapped-Content-Length": "0", - "x-amzn-RequestId": "", + "x-amzn-RequestId": "x-amzn-RequestId", "X-Amzn-Trace-Id": "X-Amzn-Trace-Id" }, "HttpStatusCode": 200 }, "SdkResponseMetadata": { - "RequestId": "" + "RequestId": "RequestId" }, "StatusCode": 200, "final": { @@ -2916,9 +2838,7 @@ "Connection": [ "keep-alive" ], - "x-amzn-RequestId": [ - "" - ], + "x-amzn-RequestId": "x-amzn-RequestId", "Content-Length": [ "1" ], @@ -2935,13 +2855,13 @@ "Date": "date", "X-Amz-Executed-Version": "$LATEST", "x-amzn-Remapped-Content-Length": "0", - "x-amzn-RequestId": "", + "x-amzn-RequestId": "x-amzn-RequestId", "X-Amzn-Trace-Id": "X-Amzn-Trace-Id" }, "HttpStatusCode": 200 }, "SdkResponseMetadata": { - "RequestId": "" + "RequestId": "RequestId" }, "StatusCode": 200 } @@ -2969,9 +2889,7 @@ "Connection": [ "keep-alive" ], - "x-amzn-RequestId": [ - "" - ], + "x-amzn-RequestId": "x-amzn-RequestId", "Content-Length": [ "1" ], @@ -2988,13 +2906,13 @@ "Date": "date", "X-Amz-Executed-Version": "$LATEST", "x-amzn-Remapped-Content-Length": "0", - "x-amzn-RequestId": "", + "x-amzn-RequestId": "x-amzn-RequestId", "X-Amzn-Trace-Id": "X-Amzn-Trace-Id" }, "HttpStatusCode": 200 }, "SdkResponseMetadata": { - "RequestId": "" + "RequestId": "RequestId" }, "StatusCode": 200, "final": { @@ -3011,9 +2929,7 @@ "Connection": [ "keep-alive" ], - "x-amzn-RequestId": [ - "" - ], + "x-amzn-RequestId": "x-amzn-RequestId", "Content-Length": [ "1" ], @@ -3030,13 +2946,13 @@ "Date": "date", "X-Amz-Executed-Version": "$LATEST", "x-amzn-Remapped-Content-Length": "0", - "x-amzn-RequestId": "", + "x-amzn-RequestId": "x-amzn-RequestId", "X-Amzn-Trace-Id": "X-Amzn-Trace-Id" }, "HttpStatusCode": 200 }, "SdkResponseMetadata": { - "RequestId": "" + "RequestId": "RequestId" }, "StatusCode": 200 } @@ -3059,7 +2975,7 @@ } }, "tests/aws/services/stepfunctions/v2/services/test_lambda_task_service.py::TestTaskServiceLambda::test_invoke_json_values[0_1]": { - "recorded-date": "04-08-2023, 16:05:23", + "recorded-date": "06-11-2025, 12:33:42", "recorded-content": { "get_execution_history": { "events": [ @@ -3138,9 +3054,7 @@ "Connection": [ "keep-alive" ], - "x-amzn-RequestId": [ - "" - ], + "x-amzn-RequestId": "x-amzn-RequestId", "Content-Length": [ "1" ], @@ -3157,13 +3071,13 @@ "Date": "date", "X-Amz-Executed-Version": "$LATEST", "x-amzn-Remapped-Content-Length": "0", - "x-amzn-RequestId": "", + "x-amzn-RequestId": "x-amzn-RequestId", "X-Amzn-Trace-Id": "X-Amzn-Trace-Id" }, "HttpStatusCode": 200 }, "SdkResponseMetadata": { - "RequestId": "" + "RequestId": "RequestId" }, "StatusCode": 200 }, @@ -3195,9 +3109,7 @@ "Connection": [ "keep-alive" ], - "x-amzn-RequestId": [ - "" - ], + "x-amzn-RequestId": "x-amzn-RequestId", "Content-Length": [ "1" ], @@ -3214,13 +3126,13 @@ "Date": "date", "X-Amz-Executed-Version": "$LATEST", "x-amzn-Remapped-Content-Length": "0", - "x-amzn-RequestId": "", + "x-amzn-RequestId": "x-amzn-RequestId", "X-Amzn-Trace-Id": "X-Amzn-Trace-Id" }, "HttpStatusCode": 200 }, "SdkResponseMetadata": { - "RequestId": "" + "RequestId": "RequestId" }, "StatusCode": 200 }, @@ -3249,9 +3161,7 @@ "Connection": [ "keep-alive" ], - "x-amzn-RequestId": [ - "" - ], + "x-amzn-RequestId": "x-amzn-RequestId", "Content-Length": [ "1" ], @@ -3268,13 +3178,13 @@ "Date": "date", "X-Amz-Executed-Version": "$LATEST", "x-amzn-Remapped-Content-Length": "0", - "x-amzn-RequestId": "", + "x-amzn-RequestId": "x-amzn-RequestId", "X-Amzn-Trace-Id": "X-Amzn-Trace-Id" }, "HttpStatusCode": 200 }, "SdkResponseMetadata": { - "RequestId": "" + "RequestId": "RequestId" }, "StatusCode": 200 }, @@ -3305,9 +3215,7 @@ "Connection": [ "keep-alive" ], - "x-amzn-RequestId": [ - "" - ], + "x-amzn-RequestId": "x-amzn-RequestId", "Content-Length": [ "1" ], @@ -3324,13 +3232,13 @@ "Date": "date", "X-Amz-Executed-Version": "$LATEST", "x-amzn-Remapped-Content-Length": "0", - "x-amzn-RequestId": "", + "x-amzn-RequestId": "x-amzn-RequestId", "X-Amzn-Trace-Id": "X-Amzn-Trace-Id" }, "HttpStatusCode": 200 }, "SdkResponseMetadata": { - "RequestId": "" + "RequestId": "RequestId" }, "StatusCode": 200, "final": { @@ -3347,9 +3255,7 @@ "Connection": [ "keep-alive" ], - "x-amzn-RequestId": [ - "" - ], + "x-amzn-RequestId": "x-amzn-RequestId", "Content-Length": [ "1" ], @@ -3366,13 +3272,13 @@ "Date": "date", "X-Amz-Executed-Version": "$LATEST", "x-amzn-Remapped-Content-Length": "0", - "x-amzn-RequestId": "", + "x-amzn-RequestId": "x-amzn-RequestId", "X-Amzn-Trace-Id": "X-Amzn-Trace-Id" }, "HttpStatusCode": 200 }, "SdkResponseMetadata": { - "RequestId": "" + "RequestId": "RequestId" }, "StatusCode": 200 } @@ -3400,9 +3306,7 @@ "Connection": [ "keep-alive" ], - "x-amzn-RequestId": [ - "" - ], + "x-amzn-RequestId": "x-amzn-RequestId", "Content-Length": [ "1" ], @@ -3419,13 +3323,13 @@ "Date": "date", "X-Amz-Executed-Version": "$LATEST", "x-amzn-Remapped-Content-Length": "0", - "x-amzn-RequestId": "", + "x-amzn-RequestId": "x-amzn-RequestId", "X-Amzn-Trace-Id": "X-Amzn-Trace-Id" }, "HttpStatusCode": 200 }, "SdkResponseMetadata": { - "RequestId": "" + "RequestId": "RequestId" }, "StatusCode": 200, "final": { @@ -3442,9 +3346,7 @@ "Connection": [ "keep-alive" ], - "x-amzn-RequestId": [ - "" - ], + "x-amzn-RequestId": "x-amzn-RequestId", "Content-Length": [ "1" ], @@ -3461,13 +3363,13 @@ "Date": "date", "X-Amz-Executed-Version": "$LATEST", "x-amzn-Remapped-Content-Length": "0", - "x-amzn-RequestId": "", + "x-amzn-RequestId": "x-amzn-RequestId", "X-Amzn-Trace-Id": "X-Amzn-Trace-Id" }, "HttpStatusCode": 200 }, "SdkResponseMetadata": { - "RequestId": "" + "RequestId": "RequestId" }, "StatusCode": 200 } @@ -3490,7 +3392,7 @@ } }, "tests/aws/services/stepfunctions/v2/services/test_lambda_task_service.py::TestTaskServiceLambda::test_invoke_json_values[True]": { - "recorded-date": "04-08-2023, 16:05:41", + "recorded-date": "06-11-2025, 12:34:01", "recorded-content": { "get_execution_history": { "events": [ @@ -3569,9 +3471,7 @@ "Connection": [ "keep-alive" ], - "x-amzn-RequestId": [ - "" - ], + "x-amzn-RequestId": "x-amzn-RequestId", "Content-Length": [ "4" ], @@ -3588,13 +3488,13 @@ "Date": "date", "X-Amz-Executed-Version": "$LATEST", "x-amzn-Remapped-Content-Length": "0", - "x-amzn-RequestId": "", + "x-amzn-RequestId": "x-amzn-RequestId", "X-Amzn-Trace-Id": "X-Amzn-Trace-Id" }, "HttpStatusCode": 200 }, "SdkResponseMetadata": { - "RequestId": "" + "RequestId": "RequestId" }, "StatusCode": 200 }, @@ -3626,9 +3526,7 @@ "Connection": [ "keep-alive" ], - "x-amzn-RequestId": [ - "" - ], + "x-amzn-RequestId": "x-amzn-RequestId", "Content-Length": [ "4" ], @@ -3645,13 +3543,13 @@ "Date": "date", "X-Amz-Executed-Version": "$LATEST", "x-amzn-Remapped-Content-Length": "0", - "x-amzn-RequestId": "", + "x-amzn-RequestId": "x-amzn-RequestId", "X-Amzn-Trace-Id": "X-Amzn-Trace-Id" }, "HttpStatusCode": 200 }, "SdkResponseMetadata": { - "RequestId": "" + "RequestId": "RequestId" }, "StatusCode": 200 }, @@ -3680,9 +3578,7 @@ "Connection": [ "keep-alive" ], - "x-amzn-RequestId": [ - "" - ], + "x-amzn-RequestId": "x-amzn-RequestId", "Content-Length": [ "4" ], @@ -3699,13 +3595,13 @@ "Date": "date", "X-Amz-Executed-Version": "$LATEST", "x-amzn-Remapped-Content-Length": "0", - "x-amzn-RequestId": "", + "x-amzn-RequestId": "x-amzn-RequestId", "X-Amzn-Trace-Id": "X-Amzn-Trace-Id" }, "HttpStatusCode": 200 }, "SdkResponseMetadata": { - "RequestId": "" + "RequestId": "RequestId" }, "StatusCode": 200 }, @@ -3736,9 +3632,7 @@ "Connection": [ "keep-alive" ], - "x-amzn-RequestId": [ - "" - ], + "x-amzn-RequestId": "x-amzn-RequestId", "Content-Length": [ "4" ], @@ -3755,13 +3649,13 @@ "Date": "date", "X-Amz-Executed-Version": "$LATEST", "x-amzn-Remapped-Content-Length": "0", - "x-amzn-RequestId": "", + "x-amzn-RequestId": "x-amzn-RequestId", "X-Amzn-Trace-Id": "X-Amzn-Trace-Id" }, "HttpStatusCode": 200 }, "SdkResponseMetadata": { - "RequestId": "" + "RequestId": "RequestId" }, "StatusCode": 200, "final": { @@ -3778,9 +3672,7 @@ "Connection": [ "keep-alive" ], - "x-amzn-RequestId": [ - "" - ], + "x-amzn-RequestId": "x-amzn-RequestId", "Content-Length": [ "4" ], @@ -3797,13 +3689,13 @@ "Date": "date", "X-Amz-Executed-Version": "$LATEST", "x-amzn-Remapped-Content-Length": "0", - "x-amzn-RequestId": "", + "x-amzn-RequestId": "x-amzn-RequestId", "X-Amzn-Trace-Id": "X-Amzn-Trace-Id" }, "HttpStatusCode": 200 }, "SdkResponseMetadata": { - "RequestId": "" + "RequestId": "RequestId" }, "StatusCode": 200 } @@ -3831,9 +3723,7 @@ "Connection": [ "keep-alive" ], - "x-amzn-RequestId": [ - "" - ], + "x-amzn-RequestId": "x-amzn-RequestId", "Content-Length": [ "4" ], @@ -3850,13 +3740,13 @@ "Date": "date", "X-Amz-Executed-Version": "$LATEST", "x-amzn-Remapped-Content-Length": "0", - "x-amzn-RequestId": "", + "x-amzn-RequestId": "x-amzn-RequestId", "X-Amzn-Trace-Id": "X-Amzn-Trace-Id" }, "HttpStatusCode": 200 }, "SdkResponseMetadata": { - "RequestId": "" + "RequestId": "RequestId" }, "StatusCode": 200, "final": { @@ -3873,9 +3763,7 @@ "Connection": [ "keep-alive" ], - "x-amzn-RequestId": [ - "" - ], + "x-amzn-RequestId": "x-amzn-RequestId", "Content-Length": [ "4" ], @@ -3892,13 +3780,13 @@ "Date": "date", "X-Amz-Executed-Version": "$LATEST", "x-amzn-Remapped-Content-Length": "0", - "x-amzn-RequestId": "", + "x-amzn-RequestId": "x-amzn-RequestId", "X-Amzn-Trace-Id": "X-Amzn-Trace-Id" }, "HttpStatusCode": 200 }, "SdkResponseMetadata": { - "RequestId": "" + "RequestId": "RequestId" }, "StatusCode": 200 } @@ -3921,7 +3809,7 @@ } }, "tests/aws/services/stepfunctions/v2/services/test_lambda_task_service.py::TestTaskServiceLambda::test_invoke_json_values[json_value6]": { - "recorded-date": "04-08-2023, 16:06:16", + "recorded-date": "06-11-2025, 12:34:40", "recorded-content": { "get_execution_history": { "events": [ @@ -4000,9 +3888,7 @@ "Connection": [ "keep-alive" ], - "x-amzn-RequestId": [ - "" - ], + "x-amzn-RequestId": "x-amzn-RequestId", "Content-Length": [ "2" ], @@ -4019,13 +3905,13 @@ "Date": "date", "X-Amz-Executed-Version": "$LATEST", "x-amzn-Remapped-Content-Length": "0", - "x-amzn-RequestId": "", + "x-amzn-RequestId": "x-amzn-RequestId", "X-Amzn-Trace-Id": "X-Amzn-Trace-Id" }, "HttpStatusCode": 200 }, "SdkResponseMetadata": { - "RequestId": "" + "RequestId": "RequestId" }, "StatusCode": 200 }, @@ -4057,9 +3943,7 @@ "Connection": [ "keep-alive" ], - "x-amzn-RequestId": [ - "" - ], + "x-amzn-RequestId": "x-amzn-RequestId", "Content-Length": [ "2" ], @@ -4076,13 +3960,13 @@ "Date": "date", "X-Amz-Executed-Version": "$LATEST", "x-amzn-Remapped-Content-Length": "0", - "x-amzn-RequestId": "", + "x-amzn-RequestId": "x-amzn-RequestId", "X-Amzn-Trace-Id": "X-Amzn-Trace-Id" }, "HttpStatusCode": 200 }, "SdkResponseMetadata": { - "RequestId": "" + "RequestId": "RequestId" }, "StatusCode": 200 }, @@ -4111,9 +3995,7 @@ "Connection": [ "keep-alive" ], - "x-amzn-RequestId": [ - "" - ], + "x-amzn-RequestId": "x-amzn-RequestId", "Content-Length": [ "2" ], @@ -4130,13 +4012,13 @@ "Date": "date", "X-Amz-Executed-Version": "$LATEST", "x-amzn-Remapped-Content-Length": "0", - "x-amzn-RequestId": "", + "x-amzn-RequestId": "x-amzn-RequestId", "X-Amzn-Trace-Id": "X-Amzn-Trace-Id" }, "HttpStatusCode": 200 }, "SdkResponseMetadata": { - "RequestId": "" + "RequestId": "RequestId" }, "StatusCode": 200 }, @@ -4167,9 +4049,7 @@ "Connection": [ "keep-alive" ], - "x-amzn-RequestId": [ - "" - ], + "x-amzn-RequestId": "x-amzn-RequestId", "Content-Length": [ "2" ], @@ -4186,13 +4066,13 @@ "Date": "date", "X-Amz-Executed-Version": "$LATEST", "x-amzn-Remapped-Content-Length": "0", - "x-amzn-RequestId": "", + "x-amzn-RequestId": "x-amzn-RequestId", "X-Amzn-Trace-Id": "X-Amzn-Trace-Id" }, "HttpStatusCode": 200 }, "SdkResponseMetadata": { - "RequestId": "" + "RequestId": "RequestId" }, "StatusCode": 200, "final": { @@ -4209,9 +4089,7 @@ "Connection": [ "keep-alive" ], - "x-amzn-RequestId": [ - "" - ], + "x-amzn-RequestId": "x-amzn-RequestId", "Content-Length": [ "2" ], @@ -4228,13 +4106,13 @@ "Date": "date", "X-Amz-Executed-Version": "$LATEST", "x-amzn-Remapped-Content-Length": "0", - "x-amzn-RequestId": "", + "x-amzn-RequestId": "x-amzn-RequestId", "X-Amzn-Trace-Id": "X-Amzn-Trace-Id" }, "HttpStatusCode": 200 }, "SdkResponseMetadata": { - "RequestId": "" + "RequestId": "RequestId" }, "StatusCode": 200 } @@ -4262,9 +4140,7 @@ "Connection": [ "keep-alive" ], - "x-amzn-RequestId": [ - "" - ], + "x-amzn-RequestId": "x-amzn-RequestId", "Content-Length": [ "2" ], @@ -4281,13 +4157,13 @@ "Date": "date", "X-Amz-Executed-Version": "$LATEST", "x-amzn-Remapped-Content-Length": "0", - "x-amzn-RequestId": "", + "x-amzn-RequestId": "x-amzn-RequestId", "X-Amzn-Trace-Id": "X-Amzn-Trace-Id" }, "HttpStatusCode": 200 }, "SdkResponseMetadata": { - "RequestId": "" + "RequestId": "RequestId" }, "StatusCode": 200, "final": { @@ -4304,9 +4180,7 @@ "Connection": [ "keep-alive" ], - "x-amzn-RequestId": [ - "" - ], + "x-amzn-RequestId": "x-amzn-RequestId", "Content-Length": [ "2" ], @@ -4323,13 +4197,13 @@ "Date": "date", "X-Amz-Executed-Version": "$LATEST", "x-amzn-Remapped-Content-Length": "0", - "x-amzn-RequestId": "", + "x-amzn-RequestId": "x-amzn-RequestId", "X-Amzn-Trace-Id": "X-Amzn-Trace-Id" }, "HttpStatusCode": 200 }, "SdkResponseMetadata": { - "RequestId": "" + "RequestId": "RequestId" }, "StatusCode": 200 } @@ -4783,7 +4657,7 @@ } }, "tests/aws/services/stepfunctions/v2/services/test_lambda_task_service.py::TestTaskServiceLambda::test_invoke_json_values[json_value5]": { - "recorded-date": "04-08-2023, 16:05:59", + "recorded-date": "06-11-2025, 12:34:21", "recorded-content": { "get_execution_history": { "events": [ @@ -4862,9 +4736,7 @@ "Connection": [ "keep-alive" ], - "x-amzn-RequestId": [ - "" - ], + "x-amzn-RequestId": "x-amzn-RequestId", "Content-Length": [ "2" ], @@ -4881,13 +4753,13 @@ "Date": "date", "X-Amz-Executed-Version": "$LATEST", "x-amzn-Remapped-Content-Length": "0", - "x-amzn-RequestId": "", + "x-amzn-RequestId": "x-amzn-RequestId", "X-Amzn-Trace-Id": "X-Amzn-Trace-Id" }, "HttpStatusCode": 200 }, "SdkResponseMetadata": { - "RequestId": "" + "RequestId": "RequestId" }, "StatusCode": 200 }, @@ -4919,9 +4791,7 @@ "Connection": [ "keep-alive" ], - "x-amzn-RequestId": [ - "" - ], + "x-amzn-RequestId": "x-amzn-RequestId", "Content-Length": [ "2" ], @@ -4938,13 +4808,13 @@ "Date": "date", "X-Amz-Executed-Version": "$LATEST", "x-amzn-Remapped-Content-Length": "0", - "x-amzn-RequestId": "", + "x-amzn-RequestId": "x-amzn-RequestId", "X-Amzn-Trace-Id": "X-Amzn-Trace-Id" }, "HttpStatusCode": 200 }, "SdkResponseMetadata": { - "RequestId": "" + "RequestId": "RequestId" }, "StatusCode": 200 }, @@ -4973,9 +4843,7 @@ "Connection": [ "keep-alive" ], - "x-amzn-RequestId": [ - "" - ], + "x-amzn-RequestId": "x-amzn-RequestId", "Content-Length": [ "2" ], @@ -4992,13 +4860,13 @@ "Date": "date", "X-Amz-Executed-Version": "$LATEST", "x-amzn-Remapped-Content-Length": "0", - "x-amzn-RequestId": "", + "x-amzn-RequestId": "x-amzn-RequestId", "X-Amzn-Trace-Id": "X-Amzn-Trace-Id" }, "HttpStatusCode": 200 }, "SdkResponseMetadata": { - "RequestId": "" + "RequestId": "RequestId" }, "StatusCode": 200 }, @@ -5029,9 +4897,7 @@ "Connection": [ "keep-alive" ], - "x-amzn-RequestId": [ - "" - ], + "x-amzn-RequestId": "x-amzn-RequestId", "Content-Length": [ "2" ], @@ -5048,13 +4914,13 @@ "Date": "date", "X-Amz-Executed-Version": "$LATEST", "x-amzn-Remapped-Content-Length": "0", - "x-amzn-RequestId": "", + "x-amzn-RequestId": "x-amzn-RequestId", "X-Amzn-Trace-Id": "X-Amzn-Trace-Id" }, "HttpStatusCode": 200 }, "SdkResponseMetadata": { - "RequestId": "" + "RequestId": "RequestId" }, "StatusCode": 200, "final": { @@ -5071,9 +4937,7 @@ "Connection": [ "keep-alive" ], - "x-amzn-RequestId": [ - "" - ], + "x-amzn-RequestId": "x-amzn-RequestId", "Content-Length": [ "2" ], @@ -5090,13 +4954,13 @@ "Date": "date", "X-Amz-Executed-Version": "$LATEST", "x-amzn-Remapped-Content-Length": "0", - "x-amzn-RequestId": "", + "x-amzn-RequestId": "x-amzn-RequestId", "X-Amzn-Trace-Id": "X-Amzn-Trace-Id" }, "HttpStatusCode": 200 }, "SdkResponseMetadata": { - "RequestId": "" + "RequestId": "RequestId" }, "StatusCode": 200 } @@ -5124,9 +4988,7 @@ "Connection": [ "keep-alive" ], - "x-amzn-RequestId": [ - "" - ], + "x-amzn-RequestId": "x-amzn-RequestId", "Content-Length": [ "2" ], @@ -5143,13 +5005,13 @@ "Date": "date", "X-Amz-Executed-Version": "$LATEST", "x-amzn-Remapped-Content-Length": "0", - "x-amzn-RequestId": "", + "x-amzn-RequestId": "x-amzn-RequestId", "X-Amzn-Trace-Id": "X-Amzn-Trace-Id" }, "HttpStatusCode": 200 }, "SdkResponseMetadata": { - "RequestId": "" + "RequestId": "RequestId" }, "StatusCode": 200, "final": { @@ -5166,9 +5028,7 @@ "Connection": [ "keep-alive" ], - "x-amzn-RequestId": [ - "" - ], + "x-amzn-RequestId": "x-amzn-RequestId", "Content-Length": [ "2" ], @@ -5185,13 +5045,13 @@ "Date": "date", "X-Amz-Executed-Version": "$LATEST", "x-amzn-Remapped-Content-Length": "0", - "x-amzn-RequestId": "", + "x-amzn-RequestId": "x-amzn-RequestId", "X-Amzn-Trace-Id": "X-Amzn-Trace-Id" }, "HttpStatusCode": 200 }, "SdkResponseMetadata": { - "RequestId": "" + "RequestId": "RequestId" }, "StatusCode": 200 } diff --git a/tests/aws/services/stepfunctions/v2/services/test_lambda_task_service.validation.json b/tests/aws/services/stepfunctions/v2/services/test_lambda_task_service.validation.json index b35e29ce0760f..0574ae9f68a30 100644 --- a/tests/aws/services/stepfunctions/v2/services/test_lambda_task_service.validation.json +++ b/tests/aws/services/stepfunctions/v2/services/test_lambda_task_service.validation.json @@ -1,33 +1,93 @@ { "tests/aws/services/stepfunctions/v2/services/test_lambda_task_service.py::TestTaskServiceLambda::test_invoke": { - "last_validated_date": "2023-06-22T11:39:30+00:00" + "last_validated_date": "2025-11-06T12:31:50+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 16.88, + "teardown": 2.88, + "total": 19.76 + } }, "tests/aws/services/stepfunctions/v2/services/test_lambda_task_service.py::TestTaskServiceLambda::test_invoke_bytes_payload": { - "last_validated_date": "2023-08-04T08:48:27+00:00" + "last_validated_date": "2025-11-06T12:32:09+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 16.23, + "teardown": 2.73, + "total": 18.96 + } }, "tests/aws/services/stepfunctions/v2/services/test_lambda_task_service.py::TestTaskServiceLambda::test_invoke_json_values[0.0]": { - "last_validated_date": "2023-08-04T14:04:46+00:00" + "last_validated_date": "2025-11-06T12:33:06+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 16.33, + "teardown": 2.8, + "total": 19.13 + } }, "tests/aws/services/stepfunctions/v2/services/test_lambda_task_service.py::TestTaskServiceLambda::test_invoke_json_values[0_0]": { - "last_validated_date": "2023-08-04T14:05:04+00:00" + "last_validated_date": "2025-11-06T12:33:25+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 16.29, + "teardown": 2.79, + "total": 19.08 + } }, "tests/aws/services/stepfunctions/v2/services/test_lambda_task_service.py::TestTaskServiceLambda::test_invoke_json_values[0_1]": { - "last_validated_date": "2023-08-04T14:05:23+00:00" + "last_validated_date": "2025-11-06T12:33:45+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 16.7, + "teardown": 2.84, + "total": 19.54 + } }, "tests/aws/services/stepfunctions/v2/services/test_lambda_task_service.py::TestTaskServiceLambda::test_invoke_json_values[HelloWorld]": { - "last_validated_date": "2023-08-04T14:04:28+00:00" + "last_validated_date": "2025-11-06T12:32:47+00:00", + "durations_in_seconds": { + "setup": 0.01, + "call": 16.35, + "teardown": 2.87, + "total": 19.23 + } }, "tests/aws/services/stepfunctions/v2/services/test_lambda_task_service.py::TestTaskServiceLambda::test_invoke_json_values[True]": { - "last_validated_date": "2023-08-04T14:05:41+00:00" + "last_validated_date": "2025-11-06T12:34:04+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 16.45, + "teardown": 3.0, + "total": 19.45 + } }, "tests/aws/services/stepfunctions/v2/services/test_lambda_task_service.py::TestTaskServiceLambda::test_invoke_json_values[json_value5]": { - "last_validated_date": "2023-08-04T14:05:59+00:00" + "last_validated_date": "2025-11-06T12:34:24+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 16.33, + "teardown": 2.85, + "total": 19.18 + } }, "tests/aws/services/stepfunctions/v2/services/test_lambda_task_service.py::TestTaskServiceLambda::test_invoke_json_values[json_value6]": { - "last_validated_date": "2023-08-04T14:06:16+00:00" + "last_validated_date": "2025-11-06T12:34:43+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 16.16, + "teardown": 2.83, + "total": 18.99 + } }, "tests/aws/services/stepfunctions/v2/services/test_lambda_task_service.py::TestTaskServiceLambda::test_invoke_unsupported_param": { - "last_validated_date": "2023-06-22T12:15:28+00:00" + "last_validated_date": "2025-11-06T12:32:28+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 16.45, + "teardown": 2.34, + "total": 18.79 + } }, "tests/aws/services/stepfunctions/v2/services/test_lambda_task_service.py::TestTaskServiceLambda::test_list_functions": { "last_validated_date": "2023-05-11T09:29:56+00:00" diff --git a/tests/aws/services/stepfunctions/v2/services/test_sfn_task_service.snapshot.json b/tests/aws/services/stepfunctions/v2/services/test_sfn_task_service.snapshot.json index 6bdef2214ab02..7f81bba580e9c 100644 --- a/tests/aws/services/stepfunctions/v2/services/test_sfn_task_service.snapshot.json +++ b/tests/aws/services/stepfunctions/v2/services/test_sfn_task_service.snapshot.json @@ -1,6 +1,6 @@ { "tests/aws/services/stepfunctions/v2/services/test_sfn_task_service.py::TestTaskServiceSfn::test_start_execution": { - "recorded-date": "28-06-2023, 11:07:54", + "recorded-date": "06-11-2025, 12:35:23", "recorded-content": { "get_execution_history": { "events": [ @@ -72,14 +72,12 @@ "ExecutionArn": "arn::states::111111111111:execution::TestStartTarget", "SdkHttpMetadata": { "AllHttpHeaders": { - "x-amzn-RequestId": [ - "" - ], + "x-amzn-RequestId": "x-amzn-RequestId", "connection": [ "keep-alive" ], "Content-Length": [ - "160" + "164" ], "Date": "date", "Content-Type": [ @@ -88,15 +86,15 @@ }, "HttpHeaders": { "connection": "keep-alive", - "Content-Length": "160", + "Content-Length": "164", "Content-Type": "application/x-amz-json-1.0", "Date": "date", - "x-amzn-RequestId": "" + "x-amzn-RequestId": "x-amzn-RequestId" }, "HttpStatusCode": 200 }, "SdkResponseMetadata": { - "RequestId": "" + "RequestId": "RequestId" }, "StartDate": "start-date" }, @@ -118,14 +116,12 @@ "ExecutionArn": "arn::states::111111111111:execution::TestStartTarget", "SdkHttpMetadata": { "AllHttpHeaders": { - "x-amzn-RequestId": [ - "" - ], + "x-amzn-RequestId": "x-amzn-RequestId", "connection": [ "keep-alive" ], "Content-Length": [ - "160" + "164" ], "Date": "date", "Content-Type": [ @@ -134,15 +130,15 @@ }, "HttpHeaders": { "connection": "keep-alive", - "Content-Length": "160", + "Content-Length": "164", "Content-Type": "application/x-amz-json-1.0", "Date": "date", - "x-amzn-RequestId": "" + "x-amzn-RequestId": "x-amzn-RequestId" }, "HttpStatusCode": 200 }, "SdkResponseMetadata": { - "RequestId": "" + "RequestId": "RequestId" }, "StartDate": "start-date" }, @@ -159,14 +155,12 @@ "ExecutionArn": "arn::states::111111111111:execution::TestStartTarget", "SdkHttpMetadata": { "AllHttpHeaders": { - "x-amzn-RequestId": [ - "" - ], + "x-amzn-RequestId": "x-amzn-RequestId", "connection": [ "keep-alive" ], "Content-Length": [ - "160" + "164" ], "Date": "date", "Content-Type": [ @@ -175,15 +169,15 @@ }, "HttpHeaders": { "connection": "keep-alive", - "Content-Length": "160", + "Content-Length": "164", "Content-Type": "application/x-amz-json-1.0", "Date": "date", - "x-amzn-RequestId": "" + "x-amzn-RequestId": "x-amzn-RequestId" }, "HttpStatusCode": 200 }, "SdkResponseMetadata": { - "RequestId": "" + "RequestId": "RequestId" }, "StartDate": "start-date" }, @@ -205,7 +199,7 @@ } }, "tests/aws/services/stepfunctions/v2/services/test_sfn_task_service.py::TestTaskServiceSfn::test_start_execution_input_json": { - "recorded-date": "28-06-2023, 11:12:13", + "recorded-date": "06-11-2025, 12:35:53", "recorded-content": { "get_execution_history": { "events": [ @@ -283,14 +277,12 @@ "ExecutionArn": "arn::states::111111111111:execution::TestStartTarget", "SdkHttpMetadata": { "AllHttpHeaders": { - "x-amzn-RequestId": [ - "" - ], + "x-amzn-RequestId": "x-amzn-RequestId", "connection": [ "keep-alive" ], "Content-Length": [ - "161" + "163" ], "Date": "date", "Content-Type": [ @@ -299,15 +291,15 @@ }, "HttpHeaders": { "connection": "keep-alive", - "Content-Length": "161", + "Content-Length": "163", "Content-Type": "application/x-amz-json-1.0", "Date": "date", - "x-amzn-RequestId": "" + "x-amzn-RequestId": "x-amzn-RequestId" }, "HttpStatusCode": 200 }, "SdkResponseMetadata": { - "RequestId": "" + "RequestId": "RequestId" }, "StartDate": "start-date" }, @@ -329,14 +321,12 @@ "ExecutionArn": "arn::states::111111111111:execution::TestStartTarget", "SdkHttpMetadata": { "AllHttpHeaders": { - "x-amzn-RequestId": [ - "" - ], + "x-amzn-RequestId": "x-amzn-RequestId", "connection": [ "keep-alive" ], "Content-Length": [ - "161" + "163" ], "Date": "date", "Content-Type": [ @@ -345,15 +335,15 @@ }, "HttpHeaders": { "connection": "keep-alive", - "Content-Length": "161", + "Content-Length": "163", "Content-Type": "application/x-amz-json-1.0", "Date": "date", - "x-amzn-RequestId": "" + "x-amzn-RequestId": "x-amzn-RequestId" }, "HttpStatusCode": 200 }, "SdkResponseMetadata": { - "RequestId": "" + "RequestId": "RequestId" }, "StartDate": "start-date" }, @@ -370,14 +360,12 @@ "ExecutionArn": "arn::states::111111111111:execution::TestStartTarget", "SdkHttpMetadata": { "AllHttpHeaders": { - "x-amzn-RequestId": [ - "" - ], + "x-amzn-RequestId": "x-amzn-RequestId", "connection": [ "keep-alive" ], "Content-Length": [ - "161" + "163" ], "Date": "date", "Content-Type": [ @@ -386,15 +374,15 @@ }, "HttpHeaders": { "connection": "keep-alive", - "Content-Length": "161", + "Content-Length": "163", "Content-Type": "application/x-amz-json-1.0", "Date": "date", - "x-amzn-RequestId": "" + "x-amzn-RequestId": "x-amzn-RequestId" }, "HttpStatusCode": 200 }, "SdkResponseMetadata": { - "RequestId": "" + "RequestId": "RequestId" }, "StartDate": "start-date" }, diff --git a/tests/aws/services/stepfunctions/v2/services/test_sfn_task_service.validation.json b/tests/aws/services/stepfunctions/v2/services/test_sfn_task_service.validation.json index 523e1dd819bc6..e9e1d958d873f 100644 --- a/tests/aws/services/stepfunctions/v2/services/test_sfn_task_service.validation.json +++ b/tests/aws/services/stepfunctions/v2/services/test_sfn_task_service.validation.json @@ -1,8 +1,20 @@ { "tests/aws/services/stepfunctions/v2/services/test_sfn_task_service.py::TestTaskServiceSfn::test_start_execution": { - "last_validated_date": "2023-06-28T09:07:54+00:00" + "last_validated_date": "2025-11-06T12:35:26+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 26.43, + "teardown": 3.49, + "total": 29.92 + } }, "tests/aws/services/stepfunctions/v2/services/test_sfn_task_service.py::TestTaskServiceSfn::test_start_execution_input_json": { - "last_validated_date": "2023-06-28T09:12:13+00:00" + "last_validated_date": "2025-11-06T12:35:56+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 26.93, + "teardown": 3.38, + "total": 30.31 + } } } diff --git a/tests/aws/services/stepfunctions/v2/services/test_sns_task_service.snapshot.json b/tests/aws/services/stepfunctions/v2/services/test_sns_task_service.snapshot.json index 37813b499bd00..2eb900d45cb18 100644 --- a/tests/aws/services/stepfunctions/v2/services/test_sns_task_service.snapshot.json +++ b/tests/aws/services/stepfunctions/v2/services/test_sns_task_service.snapshot.json @@ -1,6 +1,6 @@ { "tests/aws/services/stepfunctions/v2/services/test_sns_task_service.py::TestTaskServiceSns::test_publish_base[HelloWorld]": { - "recorded-date": "03-09-2023, 13:33:23", + "recorded-date": "06-11-2025, 12:36:44", "recorded-content": { "get_execution_history": { "events": [ @@ -75,8 +75,9 @@ "MessageId": "", "SdkHttpMetadata": { "AllHttpHeaders": { - "x-amzn-RequestId": [ - "" + "x-amzn-RequestId": "x-amzn-RequestId", + "connection": [ + "keep-alive" ], "Content-Length": [ "294" @@ -87,15 +88,16 @@ ] }, "HttpHeaders": { + "connection": "keep-alive", "Content-Length": "294", "Content-Type": "text/xml", "Date": "date", - "x-amzn-RequestId": "" + "x-amzn-RequestId": "x-amzn-RequestId" }, "HttpStatusCode": 200 }, "SdkResponseMetadata": { - "RequestId": "" + "RequestId": "RequestId" } }, "outputDetails": { @@ -116,8 +118,9 @@ "MessageId": "", "SdkHttpMetadata": { "AllHttpHeaders": { - "x-amzn-RequestId": [ - "" + "x-amzn-RequestId": "x-amzn-RequestId", + "connection": [ + "keep-alive" ], "Content-Length": [ "294" @@ -128,15 +131,16 @@ ] }, "HttpHeaders": { + "connection": "keep-alive", "Content-Length": "294", "Content-Type": "text/xml", "Date": "date", - "x-amzn-RequestId": "" + "x-amzn-RequestId": "x-amzn-RequestId" }, "HttpStatusCode": 200 }, "SdkResponseMetadata": { - "RequestId": "" + "RequestId": "RequestId" } }, "outputDetails": { @@ -152,8 +156,9 @@ "MessageId": "", "SdkHttpMetadata": { "AllHttpHeaders": { - "x-amzn-RequestId": [ - "" + "x-amzn-RequestId": "x-amzn-RequestId", + "connection": [ + "keep-alive" ], "Content-Length": [ "294" @@ -164,15 +169,16 @@ ] }, "HttpHeaders": { + "connection": "keep-alive", "Content-Length": "294", "Content-Type": "text/xml", "Date": "date", - "x-amzn-RequestId": "" + "x-amzn-RequestId": "x-amzn-RequestId" }, "HttpStatusCode": 200 }, "SdkResponseMetadata": { - "RequestId": "" + "RequestId": "RequestId" } }, "outputDetails": { @@ -193,7 +199,7 @@ } }, "tests/aws/services/stepfunctions/v2/services/test_sns_task_service.py::TestTaskServiceSns::test_publish_base[message1]": { - "recorded-date": "03-09-2023, 13:33:39", + "recorded-date": "06-11-2025, 12:37:01", "recorded-content": { "get_execution_history": { "events": [ @@ -268,8 +274,9 @@ "MessageId": "", "SdkHttpMetadata": { "AllHttpHeaders": { - "x-amzn-RequestId": [ - "" + "x-amzn-RequestId": "x-amzn-RequestId", + "connection": [ + "keep-alive" ], "Content-Length": [ "294" @@ -280,15 +287,16 @@ ] }, "HttpHeaders": { + "connection": "keep-alive", "Content-Length": "294", "Content-Type": "text/xml", "Date": "date", - "x-amzn-RequestId": "" + "x-amzn-RequestId": "x-amzn-RequestId" }, "HttpStatusCode": 200 }, "SdkResponseMetadata": { - "RequestId": "" + "RequestId": "RequestId" } }, "outputDetails": { @@ -309,8 +317,9 @@ "MessageId": "", "SdkHttpMetadata": { "AllHttpHeaders": { - "x-amzn-RequestId": [ - "" + "x-amzn-RequestId": "x-amzn-RequestId", + "connection": [ + "keep-alive" ], "Content-Length": [ "294" @@ -321,15 +330,16 @@ ] }, "HttpHeaders": { + "connection": "keep-alive", "Content-Length": "294", "Content-Type": "text/xml", "Date": "date", - "x-amzn-RequestId": "" + "x-amzn-RequestId": "x-amzn-RequestId" }, "HttpStatusCode": 200 }, "SdkResponseMetadata": { - "RequestId": "" + "RequestId": "RequestId" } }, "outputDetails": { @@ -345,8 +355,9 @@ "MessageId": "", "SdkHttpMetadata": { "AllHttpHeaders": { - "x-amzn-RequestId": [ - "" + "x-amzn-RequestId": "x-amzn-RequestId", + "connection": [ + "keep-alive" ], "Content-Length": [ "294" @@ -357,15 +368,16 @@ ] }, "HttpHeaders": { + "connection": "keep-alive", "Content-Length": "294", "Content-Type": "text/xml", "Date": "date", - "x-amzn-RequestId": "" + "x-amzn-RequestId": "x-amzn-RequestId" }, "HttpStatusCode": 200 }, "SdkResponseMetadata": { - "RequestId": "" + "RequestId": "RequestId" } }, "outputDetails": { @@ -386,7 +398,7 @@ } }, "tests/aws/services/stepfunctions/v2/services/test_sns_task_service.py::TestTaskServiceSns::test_publish_base[1]": { - "recorded-date": "03-09-2023, 13:33:55", + "recorded-date": "06-11-2025, 12:37:17", "recorded-content": { "get_execution_history": { "events": [ @@ -461,8 +473,9 @@ "MessageId": "", "SdkHttpMetadata": { "AllHttpHeaders": { - "x-amzn-RequestId": [ - "" + "x-amzn-RequestId": "x-amzn-RequestId", + "connection": [ + "keep-alive" ], "Content-Length": [ "294" @@ -473,15 +486,16 @@ ] }, "HttpHeaders": { + "connection": "keep-alive", "Content-Length": "294", "Content-Type": "text/xml", "Date": "date", - "x-amzn-RequestId": "" + "x-amzn-RequestId": "x-amzn-RequestId" }, "HttpStatusCode": 200 }, "SdkResponseMetadata": { - "RequestId": "" + "RequestId": "RequestId" } }, "outputDetails": { @@ -502,8 +516,9 @@ "MessageId": "", "SdkHttpMetadata": { "AllHttpHeaders": { - "x-amzn-RequestId": [ - "" + "x-amzn-RequestId": "x-amzn-RequestId", + "connection": [ + "keep-alive" ], "Content-Length": [ "294" @@ -514,15 +529,16 @@ ] }, "HttpHeaders": { + "connection": "keep-alive", "Content-Length": "294", "Content-Type": "text/xml", "Date": "date", - "x-amzn-RequestId": "" + "x-amzn-RequestId": "x-amzn-RequestId" }, "HttpStatusCode": 200 }, "SdkResponseMetadata": { - "RequestId": "" + "RequestId": "RequestId" } }, "outputDetails": { @@ -538,8 +554,9 @@ "MessageId": "", "SdkHttpMetadata": { "AllHttpHeaders": { - "x-amzn-RequestId": [ - "" + "x-amzn-RequestId": "x-amzn-RequestId", + "connection": [ + "keep-alive" ], "Content-Length": [ "294" @@ -550,15 +567,16 @@ ] }, "HttpHeaders": { + "connection": "keep-alive", "Content-Length": "294", "Content-Type": "text/xml", "Date": "date", - "x-amzn-RequestId": "" + "x-amzn-RequestId": "x-amzn-RequestId" }, "HttpStatusCode": 200 }, "SdkResponseMetadata": { - "RequestId": "" + "RequestId": "RequestId" } }, "outputDetails": { @@ -579,7 +597,7 @@ } }, "tests/aws/services/stepfunctions/v2/services/test_sns_task_service.py::TestTaskServiceSns::test_publish_base[True]": { - "recorded-date": "03-09-2023, 13:34:10", + "recorded-date": "06-11-2025, 12:37:34", "recorded-content": { "get_execution_history": { "events": [ @@ -654,8 +672,9 @@ "MessageId": "", "SdkHttpMetadata": { "AllHttpHeaders": { - "x-amzn-RequestId": [ - "" + "x-amzn-RequestId": "x-amzn-RequestId", + "connection": [ + "keep-alive" ], "Content-Length": [ "294" @@ -666,15 +685,16 @@ ] }, "HttpHeaders": { + "connection": "keep-alive", "Content-Length": "294", "Content-Type": "text/xml", "Date": "date", - "x-amzn-RequestId": "" + "x-amzn-RequestId": "x-amzn-RequestId" }, "HttpStatusCode": 200 }, "SdkResponseMetadata": { - "RequestId": "" + "RequestId": "RequestId" } }, "outputDetails": { @@ -695,8 +715,9 @@ "MessageId": "", "SdkHttpMetadata": { "AllHttpHeaders": { - "x-amzn-RequestId": [ - "" + "x-amzn-RequestId": "x-amzn-RequestId", + "connection": [ + "keep-alive" ], "Content-Length": [ "294" @@ -707,15 +728,16 @@ ] }, "HttpHeaders": { + "connection": "keep-alive", "Content-Length": "294", "Content-Type": "text/xml", "Date": "date", - "x-amzn-RequestId": "" + "x-amzn-RequestId": "x-amzn-RequestId" }, "HttpStatusCode": 200 }, "SdkResponseMetadata": { - "RequestId": "" + "RequestId": "RequestId" } }, "outputDetails": { @@ -731,8 +753,9 @@ "MessageId": "", "SdkHttpMetadata": { "AllHttpHeaders": { - "x-amzn-RequestId": [ - "" + "x-amzn-RequestId": "x-amzn-RequestId", + "connection": [ + "keep-alive" ], "Content-Length": [ "294" @@ -743,15 +766,16 @@ ] }, "HttpHeaders": { + "connection": "keep-alive", "Content-Length": "294", "Content-Type": "text/xml", "Date": "date", - "x-amzn-RequestId": "" + "x-amzn-RequestId": "x-amzn-RequestId" }, "HttpStatusCode": 200 }, "SdkResponseMetadata": { - "RequestId": "" + "RequestId": "RequestId" } }, "outputDetails": { @@ -772,7 +796,7 @@ } }, "tests/aws/services/stepfunctions/v2/services/test_sns_task_service.py::TestTaskServiceSns::test_publish_base[None]": { - "recorded-date": "03-09-2023, 13:34:25", + "recorded-date": "06-11-2025, 12:37:50", "recorded-content": { "get_execution_history": { "events": [ @@ -847,8 +871,9 @@ "MessageId": "", "SdkHttpMetadata": { "AllHttpHeaders": { - "x-amzn-RequestId": [ - "" + "x-amzn-RequestId": "x-amzn-RequestId", + "connection": [ + "keep-alive" ], "Content-Length": [ "294" @@ -859,15 +884,16 @@ ] }, "HttpHeaders": { + "connection": "keep-alive", "Content-Length": "294", "Content-Type": "text/xml", "Date": "date", - "x-amzn-RequestId": "" + "x-amzn-RequestId": "x-amzn-RequestId" }, "HttpStatusCode": 200 }, "SdkResponseMetadata": { - "RequestId": "" + "RequestId": "RequestId" } }, "outputDetails": { @@ -888,8 +914,9 @@ "MessageId": "", "SdkHttpMetadata": { "AllHttpHeaders": { - "x-amzn-RequestId": [ - "" + "x-amzn-RequestId": "x-amzn-RequestId", + "connection": [ + "keep-alive" ], "Content-Length": [ "294" @@ -900,15 +927,16 @@ ] }, "HttpHeaders": { + "connection": "keep-alive", "Content-Length": "294", "Content-Type": "text/xml", "Date": "date", - "x-amzn-RequestId": "" + "x-amzn-RequestId": "x-amzn-RequestId" }, "HttpStatusCode": 200 }, "SdkResponseMetadata": { - "RequestId": "" + "RequestId": "RequestId" } }, "outputDetails": { @@ -924,8 +952,9 @@ "MessageId": "", "SdkHttpMetadata": { "AllHttpHeaders": { - "x-amzn-RequestId": [ - "" + "x-amzn-RequestId": "x-amzn-RequestId", + "connection": [ + "keep-alive" ], "Content-Length": [ "294" @@ -936,15 +965,16 @@ ] }, "HttpHeaders": { + "connection": "keep-alive", "Content-Length": "294", "Content-Type": "text/xml", "Date": "date", - "x-amzn-RequestId": "" + "x-amzn-RequestId": "x-amzn-RequestId" }, "HttpStatusCode": 200 }, "SdkResponseMetadata": { - "RequestId": "" + "RequestId": "RequestId" } }, "outputDetails": { @@ -965,7 +995,7 @@ } }, "tests/aws/services/stepfunctions/v2/services/test_sns_task_service.py::TestTaskServiceSns::test_publish_base[]": { - "recorded-date": "03-09-2023, 13:34:40", + "recorded-date": "06-11-2025, 12:38:06", "recorded-content": { "get_execution_history": { "events": [ @@ -1040,8 +1070,9 @@ "MessageId": "", "SdkHttpMetadata": { "AllHttpHeaders": { - "x-amzn-RequestId": [ - "" + "x-amzn-RequestId": "x-amzn-RequestId", + "connection": [ + "keep-alive" ], "Content-Length": [ "294" @@ -1052,15 +1083,16 @@ ] }, "HttpHeaders": { + "connection": "keep-alive", "Content-Length": "294", "Content-Type": "text/xml", "Date": "date", - "x-amzn-RequestId": "" + "x-amzn-RequestId": "x-amzn-RequestId" }, "HttpStatusCode": 200 }, "SdkResponseMetadata": { - "RequestId": "" + "RequestId": "RequestId" } }, "outputDetails": { @@ -1081,8 +1113,9 @@ "MessageId": "", "SdkHttpMetadata": { "AllHttpHeaders": { - "x-amzn-RequestId": [ - "" + "x-amzn-RequestId": "x-amzn-RequestId", + "connection": [ + "keep-alive" ], "Content-Length": [ "294" @@ -1093,15 +1126,16 @@ ] }, "HttpHeaders": { + "connection": "keep-alive", "Content-Length": "294", "Content-Type": "text/xml", "Date": "date", - "x-amzn-RequestId": "" + "x-amzn-RequestId": "x-amzn-RequestId" }, "HttpStatusCode": 200 }, "SdkResponseMetadata": { - "RequestId": "" + "RequestId": "RequestId" } }, "outputDetails": { @@ -1117,8 +1151,9 @@ "MessageId": "", "SdkHttpMetadata": { "AllHttpHeaders": { - "x-amzn-RequestId": [ - "" + "x-amzn-RequestId": "x-amzn-RequestId", + "connection": [ + "keep-alive" ], "Content-Length": [ "294" @@ -1129,15 +1164,16 @@ ] }, "HttpHeaders": { + "connection": "keep-alive", "Content-Length": "294", "Content-Type": "text/xml", "Date": "date", - "x-amzn-RequestId": "" + "x-amzn-RequestId": "x-amzn-RequestId" }, "HttpStatusCode": 200 }, "SdkResponseMetadata": { - "RequestId": "" + "RequestId": "RequestId" } }, "outputDetails": { @@ -1359,7 +1395,7 @@ } }, "tests/aws/services/stepfunctions/v2/services/test_sns_task_service.py::TestTaskServiceSns::test_publish_base_error_topic_arn": { - "recorded-date": "03-09-2023, 13:35:10", + "recorded-date": "06-11-2025, 12:39:31", "recorded-content": { "get_execution_history": { "events": [ @@ -1457,7 +1493,7 @@ } }, "tests/aws/services/stepfunctions/v2/services/test_sns_task_service.py::TestTaskServiceSns::test_publish_message_attributes[HelloWorld]": { - "recorded-date": "27-01-2025, 07:07:04", + "recorded-date": "06-11-2025, 12:38:22", "recorded-content": { "get_execution_history": { "events": [ @@ -1544,9 +1580,7 @@ "MessageId": "", "SdkHttpMetadata": { "AllHttpHeaders": { - "x-amzn-RequestId": [ - "" - ], + "x-amzn-RequestId": "x-amzn-RequestId", "connection": [ "keep-alive" ], @@ -1563,12 +1597,12 @@ "Content-Length": "294", "Content-Type": "text/xml", "Date": "date", - "x-amzn-RequestId": "" + "x-amzn-RequestId": "x-amzn-RequestId" }, "HttpStatusCode": 200 }, "SdkResponseMetadata": { - "RequestId": "" + "RequestId": "RequestId" } }, "outputDetails": { @@ -1589,9 +1623,7 @@ "MessageId": "", "SdkHttpMetadata": { "AllHttpHeaders": { - "x-amzn-RequestId": [ - "" - ], + "x-amzn-RequestId": "x-amzn-RequestId", "connection": [ "keep-alive" ], @@ -1608,12 +1640,12 @@ "Content-Length": "294", "Content-Type": "text/xml", "Date": "date", - "x-amzn-RequestId": "" + "x-amzn-RequestId": "x-amzn-RequestId" }, "HttpStatusCode": 200 }, "SdkResponseMetadata": { - "RequestId": "" + "RequestId": "RequestId" } }, "outputDetails": { @@ -1629,9 +1661,7 @@ "MessageId": "", "SdkHttpMetadata": { "AllHttpHeaders": { - "x-amzn-RequestId": [ - "" - ], + "x-amzn-RequestId": "x-amzn-RequestId", "connection": [ "keep-alive" ], @@ -1648,12 +1678,12 @@ "Content-Length": "294", "Content-Type": "text/xml", "Date": "date", - "x-amzn-RequestId": "" + "x-amzn-RequestId": "x-amzn-RequestId" }, "HttpStatusCode": 200 }, "SdkResponseMetadata": { - "RequestId": "" + "RequestId": "RequestId" } }, "outputDetails": { @@ -1701,7 +1731,7 @@ } }, "tests/aws/services/stepfunctions/v2/services/test_sns_task_service.py::TestTaskServiceSns::test_publish_message_attributes[\"HelloWorld\"]": { - "recorded-date": "27-01-2025, 07:07:20", + "recorded-date": "06-11-2025, 12:38:40", "recorded-content": { "get_execution_history": { "events": [ @@ -1788,9 +1818,7 @@ "MessageId": "", "SdkHttpMetadata": { "AllHttpHeaders": { - "x-amzn-RequestId": [ - "" - ], + "x-amzn-RequestId": "x-amzn-RequestId", "connection": [ "keep-alive" ], @@ -1807,12 +1835,12 @@ "Content-Length": "294", "Content-Type": "text/xml", "Date": "date", - "x-amzn-RequestId": "" + "x-amzn-RequestId": "x-amzn-RequestId" }, "HttpStatusCode": 200 }, "SdkResponseMetadata": { - "RequestId": "" + "RequestId": "RequestId" } }, "outputDetails": { @@ -1833,9 +1861,7 @@ "MessageId": "", "SdkHttpMetadata": { "AllHttpHeaders": { - "x-amzn-RequestId": [ - "" - ], + "x-amzn-RequestId": "x-amzn-RequestId", "connection": [ "keep-alive" ], @@ -1852,12 +1878,12 @@ "Content-Length": "294", "Content-Type": "text/xml", "Date": "date", - "x-amzn-RequestId": "" + "x-amzn-RequestId": "x-amzn-RequestId" }, "HttpStatusCode": 200 }, "SdkResponseMetadata": { - "RequestId": "" + "RequestId": "RequestId" } }, "outputDetails": { @@ -1873,9 +1899,7 @@ "MessageId": "", "SdkHttpMetadata": { "AllHttpHeaders": { - "x-amzn-RequestId": [ - "" - ], + "x-amzn-RequestId": "x-amzn-RequestId", "connection": [ "keep-alive" ], @@ -1892,12 +1916,12 @@ "Content-Length": "294", "Content-Type": "text/xml", "Date": "date", - "x-amzn-RequestId": "" + "x-amzn-RequestId": "x-amzn-RequestId" }, "HttpStatusCode": 200 }, "SdkResponseMetadata": { - "RequestId": "" + "RequestId": "RequestId" } }, "outputDetails": { @@ -1945,7 +1969,7 @@ } }, "tests/aws/services/stepfunctions/v2/services/test_sns_task_service.py::TestTaskServiceSns::test_publish_message_attributes[{}]": { - "recorded-date": "27-01-2025, 07:07:36", + "recorded-date": "06-11-2025, 12:38:58", "recorded-content": { "get_execution_history": { "events": [ @@ -2032,9 +2056,7 @@ "MessageId": "", "SdkHttpMetadata": { "AllHttpHeaders": { - "x-amzn-RequestId": [ - "" - ], + "x-amzn-RequestId": "x-amzn-RequestId", "connection": [ "keep-alive" ], @@ -2051,12 +2073,12 @@ "Content-Length": "294", "Content-Type": "text/xml", "Date": "date", - "x-amzn-RequestId": "" + "x-amzn-RequestId": "x-amzn-RequestId" }, "HttpStatusCode": 200 }, "SdkResponseMetadata": { - "RequestId": "" + "RequestId": "RequestId" } }, "outputDetails": { @@ -2077,9 +2099,7 @@ "MessageId": "", "SdkHttpMetadata": { "AllHttpHeaders": { - "x-amzn-RequestId": [ - "" - ], + "x-amzn-RequestId": "x-amzn-RequestId", "connection": [ "keep-alive" ], @@ -2096,12 +2116,12 @@ "Content-Length": "294", "Content-Type": "text/xml", "Date": "date", - "x-amzn-RequestId": "" + "x-amzn-RequestId": "x-amzn-RequestId" }, "HttpStatusCode": 200 }, "SdkResponseMetadata": { - "RequestId": "" + "RequestId": "RequestId" } }, "outputDetails": { @@ -2117,9 +2137,7 @@ "MessageId": "", "SdkHttpMetadata": { "AllHttpHeaders": { - "x-amzn-RequestId": [ - "" - ], + "x-amzn-RequestId": "x-amzn-RequestId", "connection": [ "keep-alive" ], @@ -2136,12 +2154,12 @@ "Content-Length": "294", "Content-Type": "text/xml", "Date": "date", - "x-amzn-RequestId": "" + "x-amzn-RequestId": "x-amzn-RequestId" }, "HttpStatusCode": 200 }, "SdkResponseMetadata": { - "RequestId": "" + "RequestId": "RequestId" } }, "outputDetails": { @@ -2189,7 +2207,7 @@ } }, "tests/aws/services/stepfunctions/v2/services/test_sns_task_service.py::TestTaskServiceSns::test_publish_message_attributes[message_value3]": { - "recorded-date": "27-01-2025, 07:07:54", + "recorded-date": "06-11-2025, 12:39:15", "recorded-content": { "get_execution_history": { "events": [ @@ -2276,9 +2294,7 @@ "MessageId": "", "SdkHttpMetadata": { "AllHttpHeaders": { - "x-amzn-RequestId": [ - "" - ], + "x-amzn-RequestId": "x-amzn-RequestId", "connection": [ "keep-alive" ], @@ -2295,12 +2311,12 @@ "Content-Length": "294", "Content-Type": "text/xml", "Date": "date", - "x-amzn-RequestId": "" + "x-amzn-RequestId": "x-amzn-RequestId" }, "HttpStatusCode": 200 }, "SdkResponseMetadata": { - "RequestId": "" + "RequestId": "RequestId" } }, "outputDetails": { @@ -2321,9 +2337,7 @@ "MessageId": "", "SdkHttpMetadata": { "AllHttpHeaders": { - "x-amzn-RequestId": [ - "" - ], + "x-amzn-RequestId": "x-amzn-RequestId", "connection": [ "keep-alive" ], @@ -2340,12 +2354,12 @@ "Content-Length": "294", "Content-Type": "text/xml", "Date": "date", - "x-amzn-RequestId": "" + "x-amzn-RequestId": "x-amzn-RequestId" }, "HttpStatusCode": 200 }, "SdkResponseMetadata": { - "RequestId": "" + "RequestId": "RequestId" } }, "outputDetails": { @@ -2361,9 +2375,7 @@ "MessageId": "", "SdkHttpMetadata": { "AllHttpHeaders": { - "x-amzn-RequestId": [ - "" - ], + "x-amzn-RequestId": "x-amzn-RequestId", "connection": [ "keep-alive" ], @@ -2380,12 +2392,12 @@ "Content-Length": "294", "Content-Type": "text/xml", "Date": "date", - "x-amzn-RequestId": "" + "x-amzn-RequestId": "x-amzn-RequestId" }, "HttpStatusCode": 200 }, "SdkResponseMetadata": { - "RequestId": "" + "RequestId": "RequestId" } }, "outputDetails": { @@ -2433,7 +2445,7 @@ } }, "tests/aws/services/stepfunctions/v2/services/test_sns_task_service.py::TestTaskServiceSns::test_fifo_message_attribute[input_params0-True]": { - "recorded-date": "08-02-2024, 10:06:30", + "recorded-date": "06-11-2025, 12:36:11", "recorded-content": { "get_execution_history": { "events": [ @@ -2531,7 +2543,7 @@ } }, "tests/aws/services/stepfunctions/v2/services/test_sns_task_service.py::TestTaskServiceSns::test_fifo_message_attribute[input_params1-False]": { - "recorded-date": "08-02-2024, 10:06:49", + "recorded-date": "06-11-2025, 12:36:27", "recorded-content": { "get_execution_history": { "events": [ @@ -2612,9 +2624,7 @@ "MessageId": "", "SdkHttpMetadata": { "AllHttpHeaders": { - "x-amzn-RequestId": [ - "" - ], + "x-amzn-RequestId": "x-amzn-RequestId", "connection": [ "keep-alive" ], @@ -2631,12 +2641,12 @@ "Content-Length": "352", "Content-Type": "text/xml", "Date": "date", - "x-amzn-RequestId": "" + "x-amzn-RequestId": "x-amzn-RequestId" }, "HttpStatusCode": 200 }, "SdkResponseMetadata": { - "RequestId": "" + "RequestId": "RequestId" }, "SequenceNumber": "" }, @@ -2658,9 +2668,7 @@ "MessageId": "", "SdkHttpMetadata": { "AllHttpHeaders": { - "x-amzn-RequestId": [ - "" - ], + "x-amzn-RequestId": "x-amzn-RequestId", "connection": [ "keep-alive" ], @@ -2677,12 +2685,12 @@ "Content-Length": "352", "Content-Type": "text/xml", "Date": "date", - "x-amzn-RequestId": "" + "x-amzn-RequestId": "x-amzn-RequestId" }, "HttpStatusCode": 200 }, "SdkResponseMetadata": { - "RequestId": "" + "RequestId": "RequestId" }, "SequenceNumber": "" }, @@ -2699,9 +2707,7 @@ "MessageId": "", "SdkHttpMetadata": { "AllHttpHeaders": { - "x-amzn-RequestId": [ - "" - ], + "x-amzn-RequestId": "x-amzn-RequestId", "connection": [ "keep-alive" ], @@ -2718,12 +2724,12 @@ "Content-Length": "352", "Content-Type": "text/xml", "Date": "date", - "x-amzn-RequestId": "" + "x-amzn-RequestId": "x-amzn-RequestId" }, "HttpStatusCode": 200 }, "SdkResponseMetadata": { - "RequestId": "" + "RequestId": "RequestId" }, "SequenceNumber": "" }, diff --git a/tests/aws/services/stepfunctions/v2/services/test_sns_task_service.validation.json b/tests/aws/services/stepfunctions/v2/services/test_sns_task_service.validation.json index a53bb3fba34a7..b09febda41f1d 100644 --- a/tests/aws/services/stepfunctions/v2/services/test_sns_task_service.validation.json +++ b/tests/aws/services/stepfunctions/v2/services/test_sns_task_service.validation.json @@ -1,44 +1,122 @@ { "tests/aws/services/stepfunctions/v2/services/test_sns_task_service.py::TestTaskServiceSns::test_fifo_message_attribute[input_params0-True]": { - "last_validated_date": "2024-02-08T10:06:30+00:00" + "last_validated_date": "2025-11-06T12:36:13+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 14.22, + "teardown": 2.48, + "total": 16.7 + } }, "tests/aws/services/stepfunctions/v2/services/test_sns_task_service.py::TestTaskServiceSns::test_fifo_message_attribute[input_params1-False]": { - "last_validated_date": "2024-02-08T10:06:49+00:00" + "last_validated_date": "2025-11-06T12:36:30+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 14.29, + "teardown": 2.44, + "total": 16.73 + } }, "tests/aws/services/stepfunctions/v2/services/test_sns_task_service.py::TestTaskServiceSns::test_publish_base[1]": { - "last_validated_date": "2023-09-03T11:33:55+00:00" + "last_validated_date": "2025-11-06T12:37:20+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 14.59, + "teardown": 2.46, + "total": 17.05 + } }, "tests/aws/services/stepfunctions/v2/services/test_sns_task_service.py::TestTaskServiceSns::test_publish_base[HelloWorld]": { - "last_validated_date": "2023-09-03T11:33:23+00:00" + "last_validated_date": "2025-11-06T12:36:47+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 14.28, + "teardown": 2.35, + "total": 16.63 + } }, "tests/aws/services/stepfunctions/v2/services/test_sns_task_service.py::TestTaskServiceSns::test_publish_base[None]": { - "last_validated_date": "2023-09-03T11:34:25+00:00" + "last_validated_date": "2025-11-06T12:37:52+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 13.16, + "teardown": 2.37, + "total": 15.53 + } }, "tests/aws/services/stepfunctions/v2/services/test_sns_task_service.py::TestTaskServiceSns::test_publish_base[True]": { - "last_validated_date": "2023-09-03T11:34:10+00:00" + "last_validated_date": "2025-11-06T12:37:37+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 14.4, + "teardown": 2.47, + "total": 16.87 + } }, "tests/aws/services/stepfunctions/v2/services/test_sns_task_service.py::TestTaskServiceSns::test_publish_base[]": { - "last_validated_date": "2023-09-03T11:34:40+00:00" + "last_validated_date": "2025-11-06T12:38:08+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 13.17, + "teardown": 2.33, + "total": 15.5 + } }, "tests/aws/services/stepfunctions/v2/services/test_sns_task_service.py::TestTaskServiceSns::test_publish_base[message1]": { - "last_validated_date": "2023-09-03T11:33:39+00:00" + "last_validated_date": "2025-11-06T12:37:03+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 14.23, + "teardown": 2.13, + "total": 16.36 + } }, "tests/aws/services/stepfunctions/v2/services/test_sns_task_service.py::TestTaskServiceSns::test_publish_base_error_topic_arn": { - "last_validated_date": "2023-09-03T11:35:10+00:00" + "last_validated_date": "2025-11-06T12:39:34+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 13.84, + "teardown": 2.38, + "total": 16.22 + } }, "tests/aws/services/stepfunctions/v2/services/test_sns_task_service.py::TestTaskServiceSns::test_publish_message_attributes": { "last_validated_date": "2023-09-03T11:34:55+00:00" }, "tests/aws/services/stepfunctions/v2/services/test_sns_task_service.py::TestTaskServiceSns::test_publish_message_attributes[\"HelloWorld\"]": { - "last_validated_date": "2025-01-27T07:07:20+00:00" + "last_validated_date": "2025-11-06T12:38:43+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 15.15, + "teardown": 2.7, + "total": 17.85 + } }, "tests/aws/services/stepfunctions/v2/services/test_sns_task_service.py::TestTaskServiceSns::test_publish_message_attributes[HelloWorld]": { - "last_validated_date": "2025-01-27T07:07:04+00:00" + "last_validated_date": "2025-11-06T12:38:25+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 14.49, + "teardown": 2.56, + "total": 17.05 + } }, "tests/aws/services/stepfunctions/v2/services/test_sns_task_service.py::TestTaskServiceSns::test_publish_message_attributes[message_value3]": { - "last_validated_date": "2025-01-27T07:07:54+00:00" + "last_validated_date": "2025-11-06T12:39:17+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 14.07, + "teardown": 2.67, + "total": 16.74 + } }, "tests/aws/services/stepfunctions/v2/services/test_sns_task_service.py::TestTaskServiceSns::test_publish_message_attributes[{}]": { - "last_validated_date": "2025-01-27T07:07:36+00:00" + "last_validated_date": "2025-11-06T12:39:01+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 15.14, + "teardown": 2.61, + "total": 17.75 + } } } diff --git a/tests/aws/services/stepfunctions/v2/services/test_sqs_task_service.snapshot.json b/tests/aws/services/stepfunctions/v2/services/test_sqs_task_service.snapshot.json index 6fb95be414ef4..d1cd8af6569ec 100644 --- a/tests/aws/services/stepfunctions/v2/services/test_sqs_task_service.snapshot.json +++ b/tests/aws/services/stepfunctions/v2/services/test_sqs_task_service.snapshot.json @@ -1,6 +1,6 @@ { "tests/aws/services/stepfunctions/v2/services/test_sqs_task_service.py::TestTaskServiceSqs::test_send_message": { - "recorded-date": "18-04-2024, 06:37:09", + "recorded-date": "06-11-2025, 12:39:48", "recorded-content": { "get_execution_history": { "events": [ @@ -70,9 +70,7 @@ "MessageId": "", "SdkHttpMetadata": { "AllHttpHeaders": { - "x-amzn-RequestId": [ - "" - ], + "x-amzn-RequestId": "x-amzn-RequestId", "connection": [ "keep-alive" ], @@ -89,12 +87,12 @@ "Content-Length": "106", "Content-Type": "application/x-amz-json-1.0", "Date": "date", - "x-amzn-RequestId": "" + "x-amzn-RequestId": "x-amzn-RequestId" }, "HttpStatusCode": 200 }, "SdkResponseMetadata": { - "RequestId": "" + "RequestId": "RequestId" } }, "outputDetails": { @@ -116,9 +114,7 @@ "MessageId": "", "SdkHttpMetadata": { "AllHttpHeaders": { - "x-amzn-RequestId": [ - "" - ], + "x-amzn-RequestId": "x-amzn-RequestId", "connection": [ "keep-alive" ], @@ -135,12 +131,12 @@ "Content-Length": "106", "Content-Type": "application/x-amz-json-1.0", "Date": "date", - "x-amzn-RequestId": "" + "x-amzn-RequestId": "x-amzn-RequestId" }, "HttpStatusCode": 200 }, "SdkResponseMetadata": { - "RequestId": "" + "RequestId": "RequestId" } }, "outputDetails": { @@ -157,9 +153,7 @@ "MessageId": "", "SdkHttpMetadata": { "AllHttpHeaders": { - "x-amzn-RequestId": [ - "" - ], + "x-amzn-RequestId": "x-amzn-RequestId", "connection": [ "keep-alive" ], @@ -176,12 +170,12 @@ "Content-Length": "106", "Content-Type": "application/x-amz-json-1.0", "Date": "date", - "x-amzn-RequestId": "" + "x-amzn-RequestId": "x-amzn-RequestId" }, "HttpStatusCode": 200 }, "SdkResponseMetadata": { - "RequestId": "" + "RequestId": "RequestId" } }, "outputDetails": { @@ -202,7 +196,7 @@ } }, "tests/aws/services/stepfunctions/v2/services/test_sqs_task_service.py::TestTaskServiceSqs::test_send_message_unsupported_parameters": { - "recorded-date": "18-04-2024, 06:37:24", + "recorded-date": "06-11-2025, 12:40:04", "recorded-content": { "get_execution_history": { "events": [ @@ -278,9 +272,7 @@ "MessageId": "", "SdkHttpMetadata": { "AllHttpHeaders": { - "x-amzn-RequestId": [ - "" - ], + "x-amzn-RequestId": "x-amzn-RequestId", "connection": [ "keep-alive" ], @@ -297,12 +289,12 @@ "Content-Length": "106", "Content-Type": "application/x-amz-json-1.0", "Date": "date", - "x-amzn-RequestId": "" + "x-amzn-RequestId": "x-amzn-RequestId" }, "HttpStatusCode": 200 }, "SdkResponseMetadata": { - "RequestId": "" + "RequestId": "RequestId" } }, "outputDetails": { @@ -324,9 +316,7 @@ "MessageId": "", "SdkHttpMetadata": { "AllHttpHeaders": { - "x-amzn-RequestId": [ - "" - ], + "x-amzn-RequestId": "x-amzn-RequestId", "connection": [ "keep-alive" ], @@ -343,12 +333,12 @@ "Content-Length": "106", "Content-Type": "application/x-amz-json-1.0", "Date": "date", - "x-amzn-RequestId": "" + "x-amzn-RequestId": "x-amzn-RequestId" }, "HttpStatusCode": 200 }, "SdkResponseMetadata": { - "RequestId": "" + "RequestId": "RequestId" } }, "outputDetails": { @@ -365,9 +355,7 @@ "MessageId": "", "SdkHttpMetadata": { "AllHttpHeaders": { - "x-amzn-RequestId": [ - "" - ], + "x-amzn-RequestId": "x-amzn-RequestId", "connection": [ "keep-alive" ], @@ -384,12 +372,12 @@ "Content-Length": "106", "Content-Type": "application/x-amz-json-1.0", "Date": "date", - "x-amzn-RequestId": "" + "x-amzn-RequestId": "x-amzn-RequestId" }, "HttpStatusCode": 200 }, "SdkResponseMetadata": { - "RequestId": "" + "RequestId": "RequestId" } }, "outputDetails": { @@ -410,7 +398,7 @@ } }, "tests/aws/services/stepfunctions/v2/services/test_sqs_task_service.py::TestTaskServiceSqs::test_send_message_attributes": { - "recorded-date": "22-08-2024, 10:04:56", + "recorded-date": "06-11-2025, 12:40:20", "recorded-content": { "get_execution_history": { "events": [ @@ -495,9 +483,7 @@ "MessageId": "", "SdkHttpMetadata": { "AllHttpHeaders": { - "x-amzn-RequestId": [ - "" - ], + "x-amzn-RequestId": "x-amzn-RequestId", "connection": [ "keep-alive" ], @@ -514,12 +500,12 @@ "Content-Length": "166", "Content-Type": "application/x-amz-json-1.0", "Date": "date", - "x-amzn-RequestId": "" + "x-amzn-RequestId": "x-amzn-RequestId" }, "HttpStatusCode": 200 }, "SdkResponseMetadata": { - "RequestId": "" + "RequestId": "RequestId" } }, "outputDetails": { @@ -542,9 +528,7 @@ "MessageId": "", "SdkHttpMetadata": { "AllHttpHeaders": { - "x-amzn-RequestId": [ - "" - ], + "x-amzn-RequestId": "x-amzn-RequestId", "connection": [ "keep-alive" ], @@ -561,12 +545,12 @@ "Content-Length": "166", "Content-Type": "application/x-amz-json-1.0", "Date": "date", - "x-amzn-RequestId": "" + "x-amzn-RequestId": "x-amzn-RequestId" }, "HttpStatusCode": 200 }, "SdkResponseMetadata": { - "RequestId": "" + "RequestId": "RequestId" } }, "outputDetails": { @@ -584,9 +568,7 @@ "MessageId": "", "SdkHttpMetadata": { "AllHttpHeaders": { - "x-amzn-RequestId": [ - "" - ], + "x-amzn-RequestId": "x-amzn-RequestId", "connection": [ "keep-alive" ], @@ -603,12 +585,12 @@ "Content-Length": "166", "Content-Type": "application/x-amz-json-1.0", "Date": "date", - "x-amzn-RequestId": "" + "x-amzn-RequestId": "x-amzn-RequestId" }, "HttpStatusCode": 200 }, "SdkResponseMetadata": { - "RequestId": "" + "RequestId": "RequestId" } }, "outputDetails": { diff --git a/tests/aws/services/stepfunctions/v2/services/test_sqs_task_service.validation.json b/tests/aws/services/stepfunctions/v2/services/test_sqs_task_service.validation.json index 24c2546956eb3..1dee24dc90729 100644 --- a/tests/aws/services/stepfunctions/v2/services/test_sqs_task_service.validation.json +++ b/tests/aws/services/stepfunctions/v2/services/test_sqs_task_service.validation.json @@ -1,11 +1,29 @@ { "tests/aws/services/stepfunctions/v2/services/test_sqs_task_service.py::TestTaskServiceSqs::test_send_message": { - "last_validated_date": "2024-08-21T15:47:00+00:00" + "last_validated_date": "2025-11-06T12:39:50+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 14.54, + "teardown": 1.92, + "total": 16.46 + } }, "tests/aws/services/stepfunctions/v2/services/test_sqs_task_service.py::TestTaskServiceSqs::test_send_message_attributes": { - "last_validated_date": "2024-08-22T10:04:56+00:00" + "last_validated_date": "2025-11-06T12:40:23+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 14.51, + "teardown": 2.57, + "total": 17.08 + } }, "tests/aws/services/stepfunctions/v2/services/test_sqs_task_service.py::TestTaskServiceSqs::test_send_message_unsupported_parameters": { - "last_validated_date": "2024-04-18T06:37:24+00:00" + "last_validated_date": "2025-11-06T12:40:06+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 14.29, + "teardown": 1.62, + "total": 15.91 + } } } diff --git a/tests/aws/services/stepfunctions/v2/test_sfn_api_validation.py b/tests/aws/services/stepfunctions/v2/test_sfn_api_validation.py index 01bbd45143709..c13bafeea3988 100644 --- a/tests/aws/services/stepfunctions/v2/test_sfn_api_validation.py +++ b/tests/aws/services/stepfunctions/v2/test_sfn_api_validation.py @@ -34,8 +34,18 @@ def test_validate_state_machine_definition_not_a_definition( @pytest.mark.parametrize( "validation_template", - [ValidationTemplate.VALID_BASE_PASS, ValidationTemplate.INVALID_BASE_NO_STARTAT], - ids=["VALID_BASE_PASS", "INVALID_BASE_NO_STARTAT"], + [ + ValidationTemplate.VALID_BASE_PASS, + ValidationTemplate.INVALID_DOWNGRADE_QUERY_LANGUAGE, + ValidationTemplate.VALID_QUERY_LANGUAGE_PASS, + ValidationTemplate.INVALID_BASE_NO_STARTAT, + ], + ids=[ + "VALID_BASE_PASS", + "INVALID_DOWNGRADE_QUERY_LANGUAGE", + "VALID_QUERY_LANGUAGE_PASS", + "INVALID_BASE_NO_STARTAT", + ], ) @markers.aws.validated def test_validate_state_machine_definition_type_standard( @@ -53,9 +63,17 @@ def test_validate_state_machine_definition_type_standard( [ ValidationTemplate.VALID_BASE_PASS, ValidationTemplate.INVALID_BASE_NO_STARTAT, + ValidationTemplate.INVALID_DOWNGRADE_QUERY_LANGUAGE, + ValidationTemplate.VALID_QUERY_LANGUAGE_PASS, CallbackTemplates.SQS_WAIT_FOR_TASK_TOKEN, ], - ids=["VALID_BASE_PASS", "INVALID_BASE_NO_STARTAT", "ILLEGAL_WFTT"], + ids=[ + "VALID_BASE_PASS", + "INVALID_BASE_NO_STARTAT", + "INVALID_DOWNGRADE_QUERY_LANGUAGE", + "VALID_QUERY_LANGUAGE_PASS", + "ILLEGAL_WFTT", + ], ) @markers.aws.validated def test_validate_state_machine_definition_type_express( diff --git a/tests/aws/services/stepfunctions/v2/test_sfn_api_validation.snapshot.json b/tests/aws/services/stepfunctions/v2/test_sfn_api_validation.snapshot.json index 1a66526efd53b..4c5acae6bb169 100644 --- a/tests/aws/services/stepfunctions/v2/test_sfn_api_validation.snapshot.json +++ b/tests/aws/services/stepfunctions/v2/test_sfn_api_validation.snapshot.json @@ -1,6 +1,6 @@ { "tests/aws/services/stepfunctions/v2/test_sfn_api_validation.py::TestSfnApiValidation::test_validate_state_machine_definition_not_a_definition[EMPTY_STRING]": { - "recorded-date": "09-10-2024, 08:51:57", + "recorded-date": "19-10-2025, 02:38:10", "recorded-content": { "validation_response": { "diagnostics": [ @@ -20,7 +20,7 @@ } }, "tests/aws/services/stepfunctions/v2/test_sfn_api_validation.py::TestSfnApiValidation::test_validate_state_machine_definition_not_a_definition[NOT_A_DEF]": { - "recorded-date": "09-10-2024, 08:51:58", + "recorded-date": "19-10-2025, 02:38:10", "recorded-content": { "validation_response": { "diagnostics": [ @@ -41,7 +41,7 @@ } }, "tests/aws/services/stepfunctions/v2/test_sfn_api_validation.py::TestSfnApiValidation::test_validate_state_machine_definition_not_a_definition[EMPTY_DICT]": { - "recorded-date": "09-10-2024, 08:51:58", + "recorded-date": "19-10-2025, 02:38:10", "recorded-content": { "validation_response": { "diagnostics": [ @@ -62,7 +62,7 @@ } }, "tests/aws/services/stepfunctions/v2/test_sfn_api_validation.py::TestSfnApiValidation::test_validate_state_machine_definition_type_standard[VALID_BASE_PASS]": { - "recorded-date": "09-10-2024, 08:51:58", + "recorded-date": "19-10-2025, 02:38:11", "recorded-content": { "validation_response": { "diagnostics": [], @@ -76,7 +76,7 @@ } }, "tests/aws/services/stepfunctions/v2/test_sfn_api_validation.py::TestSfnApiValidation::test_validate_state_machine_definition_type_standard[INVALID_BASE_NO_STARTAT]": { - "recorded-date": "09-10-2024, 08:51:58", + "recorded-date": "19-10-2025, 02:38:11", "recorded-content": { "validation_response": { "diagnostics": [ @@ -97,7 +97,7 @@ } }, "tests/aws/services/stepfunctions/v2/test_sfn_api_validation.py::TestSfnApiValidation::test_validate_state_machine_definition_type_express[VALID_BASE_PASS]": { - "recorded-date": "09-10-2024, 08:51:58", + "recorded-date": "19-10-2025, 02:38:11", "recorded-content": { "validation_response": { "diagnostics": [], @@ -111,7 +111,7 @@ } }, "tests/aws/services/stepfunctions/v2/test_sfn_api_validation.py::TestSfnApiValidation::test_validate_state_machine_definition_type_express[INVALID_BASE_NO_STARTAT]": { - "recorded-date": "09-10-2024, 08:51:58", + "recorded-date": "19-10-2025, 02:38:11", "recorded-content": { "validation_response": { "diagnostics": [ @@ -132,7 +132,7 @@ } }, "tests/aws/services/stepfunctions/v2/test_sfn_api_validation.py::TestSfnApiValidation::test_validate_state_machine_definition_type_express[ILLEGAL_WFTT]": { - "recorded-date": "09-10-2024, 08:51:58", + "recorded-date": "19-10-2025, 02:38:12", "recorded-content": { "validation_response": { "diagnostics": [ @@ -151,5 +151,75 @@ } } } + }, + "tests/aws/services/stepfunctions/v2/test_sfn_api_validation.py::TestSfnApiValidation::test_validate_state_machine_definition_type_standard[VALID_QUERY_LANGUAGE_PASS]": { + "recorded-date": "19-10-2025, 02:38:11", + "recorded-content": { + "validation_response": { + "diagnostics": [], + "result": "OK", + "truncated": false, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/stepfunctions/v2/test_sfn_api_validation.py::TestSfnApiValidation::test_validate_state_machine_definition_type_standard[INVALID_DOWNGRADE_QUERY_LANGUAGE]": { + "recorded-date": "19-10-2025, 02:38:11", + "recorded-content": { + "validation_response": { + "diagnostics": [ + { + "code": "SCHEMA_VALIDATION_FAILED", + "location": "/States/Pass", + "message": "'QueryLanguage' can not be 'JSONPath' if set to 'JSONata' for whole state machine", + "severity": "ERROR" + } + ], + "result": "FAIL", + "truncated": false, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/stepfunctions/v2/test_sfn_api_validation.py::TestSfnApiValidation::test_validate_state_machine_definition_type_express[INVALID_DOWNGRADE_QUERY_LANGUAGE]": { + "recorded-date": "19-10-2025, 02:38:11", + "recorded-content": { + "validation_response": { + "diagnostics": [ + { + "code": "SCHEMA_VALIDATION_FAILED", + "location": "/States/Pass", + "message": "'QueryLanguage' can not be 'JSONPath' if set to 'JSONata' for whole state machine", + "severity": "ERROR" + } + ], + "result": "FAIL", + "truncated": false, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/stepfunctions/v2/test_sfn_api_validation.py::TestSfnApiValidation::test_validate_state_machine_definition_type_express[VALID_QUERY_LANGUAGE_PASS]": { + "recorded-date": "19-10-2025, 02:38:11", + "recorded-content": { + "validation_response": { + "diagnostics": [], + "result": "OK", + "truncated": false, + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } } } diff --git a/tests/aws/services/stepfunctions/v2/test_sfn_api_validation.validation.json b/tests/aws/services/stepfunctions/v2/test_sfn_api_validation.validation.json index 5e40a3ce68487..5142bb49a8533 100644 --- a/tests/aws/services/stepfunctions/v2/test_sfn_api_validation.validation.json +++ b/tests/aws/services/stepfunctions/v2/test_sfn_api_validation.validation.json @@ -1,26 +1,110 @@ { "tests/aws/services/stepfunctions/v2/test_sfn_api_validation.py::TestSfnApiValidation::test_validate_state_machine_definition_not_a_definition[EMPTY_DICT]": { - "last_validated_date": "2024-10-09T08:51:58+00:00" + "last_validated_date": "2025-10-19T02:38:10+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.11, + "teardown": 0.0, + "total": 0.11 + } }, "tests/aws/services/stepfunctions/v2/test_sfn_api_validation.py::TestSfnApiValidation::test_validate_state_machine_definition_not_a_definition[EMPTY_STRING]": { - "last_validated_date": "2024-10-09T08:51:57+00:00" + "last_validated_date": "2025-10-19T02:38:10+00:00", + "durations_in_seconds": { + "setup": 1.14, + "call": 0.58, + "teardown": 0.0, + "total": 1.72 + } }, "tests/aws/services/stepfunctions/v2/test_sfn_api_validation.py::TestSfnApiValidation::test_validate_state_machine_definition_not_a_definition[NOT_A_DEF]": { - "last_validated_date": "2024-10-09T08:51:58+00:00" + "last_validated_date": "2025-10-19T02:38:10+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.13, + "teardown": 0.0, + "total": 0.13 + } }, "tests/aws/services/stepfunctions/v2/test_sfn_api_validation.py::TestSfnApiValidation::test_validate_state_machine_definition_type_express[ILLEGAL_WFTT]": { - "last_validated_date": "2024-10-09T08:51:58+00:00" + "last_validated_date": "2025-10-19T02:38:12+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.11, + "teardown": 0.0, + "total": 0.11 + } }, "tests/aws/services/stepfunctions/v2/test_sfn_api_validation.py::TestSfnApiValidation::test_validate_state_machine_definition_type_express[INVALID_BASE_NO_STARTAT]": { - "last_validated_date": "2024-10-09T08:51:58+00:00" + "last_validated_date": "2025-10-19T02:38:11+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.13, + "teardown": 0.0, + "total": 0.13 + } + }, + "tests/aws/services/stepfunctions/v2/test_sfn_api_validation.py::TestSfnApiValidation::test_validate_state_machine_definition_type_express[INVALID_DOWNGRADE_QUERY_LANGUAGE]": { + "last_validated_date": "2025-10-19T02:38:11+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.1, + "teardown": 0.0, + "total": 0.1 + } }, "tests/aws/services/stepfunctions/v2/test_sfn_api_validation.py::TestSfnApiValidation::test_validate_state_machine_definition_type_express[VALID_BASE_PASS]": { - "last_validated_date": "2024-10-09T08:51:58+00:00" + "last_validated_date": "2025-10-19T02:38:11+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.1, + "teardown": 0.0, + "total": 0.1 + } + }, + "tests/aws/services/stepfunctions/v2/test_sfn_api_validation.py::TestSfnApiValidation::test_validate_state_machine_definition_type_express[VALID_QUERY_LANGUAGE_PASS]": { + "last_validated_date": "2025-10-19T02:38:11+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.1, + "teardown": 0.0, + "total": 0.1 + } }, "tests/aws/services/stepfunctions/v2/test_sfn_api_validation.py::TestSfnApiValidation::test_validate_state_machine_definition_type_standard[INVALID_BASE_NO_STARTAT]": { - "last_validated_date": "2024-10-09T08:51:58+00:00" + "last_validated_date": "2025-10-19T02:38:11+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.12, + "teardown": 0.0, + "total": 0.12 + } + }, + "tests/aws/services/stepfunctions/v2/test_sfn_api_validation.py::TestSfnApiValidation::test_validate_state_machine_definition_type_standard[INVALID_DOWNGRADE_QUERY_LANGUAGE]": { + "last_validated_date": "2025-10-19T02:38:11+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.1, + "teardown": 0.0, + "total": 0.1 + } }, "tests/aws/services/stepfunctions/v2/test_sfn_api_validation.py::TestSfnApiValidation::test_validate_state_machine_definition_type_standard[VALID_BASE_PASS]": { - "last_validated_date": "2024-10-09T08:51:58+00:00" + "last_validated_date": "2025-10-19T02:38:11+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.11, + "teardown": 0.0, + "total": 0.11 + } + }, + "tests/aws/services/stepfunctions/v2/test_sfn_api_validation.py::TestSfnApiValidation::test_validate_state_machine_definition_type_standard[VALID_QUERY_LANGUAGE_PASS]": { + "last_validated_date": "2025-10-19T02:38:11+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.11, + "teardown": 0.0, + "total": 0.11 + } } } diff --git a/tests/aws/services/stepfunctions/v2/test_state/test_field_validation_mode.py b/tests/aws/services/stepfunctions/v2/test_state/test_field_validation_mode.py new file mode 100644 index 0000000000000..d01ce521dbc2a --- /dev/null +++ b/tests/aws/services/stepfunctions/v2/test_state/test_field_validation_mode.py @@ -0,0 +1,355 @@ +import json + +import pytest + +from localstack.aws.api.stepfunctions import InspectionLevel +from localstack.testing.aws.util import is_aws_cloud +from localstack.testing.pytest import markers +from localstack.utils.aws import arns +from tests.aws.services.stepfunctions.templates.test_state.test_state_templates import ( + TestStateTemplate as TST, +) + + +class TestFieldValidationMode: + """ + + TODO test cases and edge cases found out in the wild that are good candidates for tests + - lambda response payload is not a string but a JSON - results in a validation error against the API spec + - somehow in SQS SendMessage response the following mock {"MD5OfMessageBody": {"unexpected": ["object"]}} while the API spec requires {"MD5OfMessageBody": "string"}. + At the same time, MessageId is validated to be a string. Both fields are in the API spec and both are strings there. + """ + + EVENTBRIDGE_VALIDATION_PASS_FIELDS_NOT_IN_SPEC = [ + pytest.param({"random": "json"}, id="field_not_part_of_api_spec"), + pytest.param({}, id="empty_json"), + # pytest.param("Hello World", id="simple_string"), TODO validate these general failure modes in a validation parity test + # pytest.param(42, id="simple_number"), + # pytest.param(["a", "b", "c"], id="simple_list"), + ] + + @markers.aws.validated + @pytest.mark.parametrize("result", EVENTBRIDGE_VALIDATION_PASS_FIELDS_NOT_IN_SPEC) + def test_strict_mode_mock_result_field_not_in_api_spec( + self, + aws_client_no_sync_prefix, + sfn_snapshot, + result, + ): + """ + Only fields from the API spec are validated + """ + template = TST.load_sfn_template(TST.BASE_EVENTS_PUT_EVENTS_TASK_STATE) + definition = json.dumps(template) + + entries = [ + { + "Detail": "detail", + "DetailType": "detail_type", + "Source": "source", + }, + ] + exec_input = json.dumps({"Entries": entries}) + + mock = {"result": json.dumps(result)} + + test_case_response = aws_client_no_sync_prefix.stepfunctions.test_state( + definition=definition, + input=exec_input, + inspectionLevel=InspectionLevel.INFO, + mock=mock, + ) + sfn_snapshot.match("test_case_response", test_case_response) + + EVENTBRIDGE_VAlIDATION_ERRORS = [ + pytest.param( + {"Entries": "Entries value should have been a list of entry objects"}, + id="wrong_type_top_level_field", + ), + pytest.param( + { + "Entries": [ + {"EventId": ["EventId value should have been a string not a list of strings"]} + ] + }, + id="wrong_type_nested_field", + ), + pytest.param( + { + "Entries": [ + {"EventId": "First eventId has correct type: string"}, + {"EventId": ["Second eventId has incorrect type: array"]}, + ] + }, + id="wrong_type_2nd_array_element", + ), + ] + + @markers.aws.validated + @pytest.mark.parametrize("result", EVENTBRIDGE_VAlIDATION_ERRORS) + def test_strict_mode_eventbridge_task( + self, + aws_client, + aws_client_no_sync_prefix, + sfn_snapshot, + result, + ): + template = TST.load_sfn_template(TST.BASE_EVENTS_PUT_EVENTS_TASK_STATE) + definition = json.dumps(template) + + entries = [ + { + "Detail": "detail", + "DetailType": "detail_type", + "Source": "source", + }, + ] + exec_input = json.dumps({"Entries": entries}) + + mock = {"result": json.dumps(result)} + + with pytest.raises(aws_client.stepfunctions.exceptions.ValidationException) as e: + aws_client_no_sync_prefix.stepfunctions.test_state( + definition=definition, + input=exec_input, + inspectionLevel=InspectionLevel.INFO, + mock=mock, + ) + sfn_snapshot.match("validation-exception", e.value.response) + + SFN_VALIDATION_ERRORS = [ + pytest.param( + {}, + id="missing_required_fields", + ), + pytest.param( + {"executionArn": "stringValueExecutionArn", "startDate": "stringValueStartDate"}, + id="field_name_not_in_sfn_case", + ), + pytest.param( + {"ExecutionArn": "stringValueExecutionArn", "StartDate": True}, + id="wrong_timestamp_type_bool", + ), + pytest.param( + {"ExecutionArn": "stringValueExecutionArn", "StartDate": 1764103483}, + id="wrong_timestamp_type_number", + ), + ] + + @markers.aws.validated + @pytest.mark.parametrize("result", SFN_VALIDATION_ERRORS) + def test_strict_mode_sfn_task( + self, + aws_client, + aws_client_no_sync_prefix, + account_id, + region_name, + sfn_snapshot, + result, + ): + template = TST.load_sfn_template(TST.BASE_SFN_START_EXECUTION_TASK_STATE) + definition = json.dumps(template) + + target_state_machine_arn = arns.stepfunctions_state_machine_arn( + name="TargetStateMachine", account_id=account_id, region_name=region_name + ) + + target_execution_name = "TestStartTarget" + + exec_input = json.dumps( + { + "stateMachineArn": target_state_machine_arn, + "targetInput": None, + "name": target_execution_name, + } + ) + + mock = {"result": json.dumps(result)} + + with pytest.raises(aws_client.stepfunctions.exceptions.ValidationException) as e: + aws_client_no_sync_prefix.stepfunctions.test_state( + definition=definition, + input=exec_input, + inspectionLevel=InspectionLevel.INFO, + mock=mock, + ) + sfn_snapshot.match("validation-exception", e.value.response) + + LAMBDA_VALIDATION_ERRORS = [ + pytest.param( + {"StatusCode": "200"}, + id="wrong_integer_type_string", + ), + ] + + @markers.aws.validated + @pytest.mark.parametrize("result", LAMBDA_VALIDATION_ERRORS) + def test_strict_mode_lambda_task( + self, + aws_client, + aws_client_no_sync_prefix, + sfn_snapshot, + result, + ): + template = TST.load_sfn_template(TST.BASE_LAMBDA_SERVICE_TASK_STATE) + definition = json.dumps(template) + exec_input = json.dumps({"FunctionName": "function_name", "Payload": None}) + + mock = {"result": json.dumps(result)} + + with pytest.raises(aws_client.stepfunctions.exceptions.ValidationException) as e: + aws_client_no_sync_prefix.stepfunctions.test_state( + definition=definition, + input=exec_input, + inspectionLevel=InspectionLevel.INFO, + mock=mock, + ) + sfn_snapshot.match("validation-exception", e.value.response) + + DYNAMODB_VALIDATION_ERRORS = [ + pytest.param( + {"ConsumedCapacity": {"CapacityUnits": "123.45"}}, + id="wrong_float_type_string", + ), + ] + + @markers.aws.validated + @pytest.mark.parametrize("result", DYNAMODB_VALIDATION_ERRORS) + def test_strict_mode_dynamodb_task( + self, + aws_client, + aws_client_no_sync_prefix, + sfn_snapshot, + result, + ): + template = TST.load_sfn_template(TST.BASE_DYNAMODB_SERVICE_TASK_STATE) + definition = json.dumps(template) + exec_input = json.dumps( + { + "TableName": "table_name", + "Item": {"data": {"S": "HelloWorld"}, "id": {"S": "id1"}}, + } + ) + + mock = {"result": json.dumps(result)} + + with pytest.raises(aws_client.stepfunctions.exceptions.ValidationException) as e: + aws_client_no_sync_prefix.stepfunctions.test_state( + definition=definition, + input=exec_input, + inspectionLevel=InspectionLevel.INFO, + mock=mock, + ) + sfn_snapshot.match("validation-exception", e.value.response) + + AWS_SDK_S3_VALIDATION_ERRORS = [ + pytest.param( + {"ContentLength": "9000"}, + id="wrong_long_type_string", + ), + pytest.param( + {"StorageClass": "Papyrus"}, + id="non_existent_enum_value", + ), + ] + + @markers.aws.validated + @pytest.mark.parametrize("result", AWS_SDK_S3_VALIDATION_ERRORS) + def test_strict_mode_aws_sdk_s3_task( + self, + aws_client, + aws_client_no_sync_prefix, + sfn_snapshot, + result, + ): + template = TST.load_sfn_template(TST.BASE_AWS_SDK_S3_GET_OBJECT_TASK_STATE) + definition = json.dumps(template) + exec_input = json.dumps({"Bucket": "bucket_name", "Key": "file_key"}) + + mock = {"result": json.dumps(result)} + + with pytest.raises(aws_client.stepfunctions.exceptions.ValidationException) as e: + aws_client_no_sync_prefix.stepfunctions.test_state( + definition=definition, + input=exec_input, + inspectionLevel=InspectionLevel.INFO, + mock=mock, + ) + sfn_snapshot.match("validation-exception", e.value.response) + + AWS_SDK_KMS_VALIDATION_ERRORS = [ + pytest.param( + {"CiphertextBlob": 123}, + id="wrong_blob_type_number", + ), + pytest.param( + {"CiphertextBlob": ""}, + id="wrong_blob_length_less_than_minimum", + marks=pytest.mark.skipif( + condition=not is_aws_cloud(), + reason="string value length validation is not implemented yet", + ), # TODO implement value length validation + ), + ] + + @markers.aws.validated + @pytest.mark.parametrize("result", AWS_SDK_KMS_VALIDATION_ERRORS) + def test_strict_mode_aws_sdk_kms_task( + self, + aws_client, + aws_client_no_sync_prefix, + sfn_snapshot, + result, + ): + template = TST.load_sfn_template(TST.BASE_AWS_SDK_KMS_ENCRYPT_TASK_STATE) + definition = json.dumps(template) + exec_input = json.dumps({"KeyId": "key_id", "Plaintext": "plain_text"}) + + mock = {"result": json.dumps(result)} + + with pytest.raises(aws_client.stepfunctions.exceptions.ValidationException) as e: + aws_client_no_sync_prefix.stepfunctions.test_state( + definition=definition, + input=exec_input, + inspectionLevel=InspectionLevel.INFO, + mock=mock, + ) + sfn_snapshot.match("validation-exception", e.value.response) + + AWS_SDK_LAMBDA_GET_FUNCTION_VALIDATION_ERRORS = [ + pytest.param( + {"Configuration": {"MemorySize": 127}}, + id="integer_less_than_minimum_allowed", + ), + pytest.param( + {"Configuration": {"MemorySize": 10241}}, + id="integer_more_than_maximum_allowed", + ), + ] + + @pytest.mark.skipif( + condition=not is_aws_cloud(), reason="number value range validation is not implemented yet" + ) # TODO implement number value range validation + @markers.aws.validated + @pytest.mark.parametrize("result", AWS_SDK_LAMBDA_GET_FUNCTION_VALIDATION_ERRORS) + def test_strict_mode_aws_sdk_lambda_get_function_task( + self, + aws_client, + aws_client_no_sync_prefix, + sfn_snapshot, + result, + ): + template = TST.load_sfn_template(TST.BASE_AWS_SDK_LAMBDA_GET_FUNCTION) + definition = json.dumps(template) + exec_input = json.dumps({"FunctionName": "function_name"}) + + mock = {"result": json.dumps(result)} + + with pytest.raises(aws_client.stepfunctions.exceptions.ValidationException) as e: + aws_client_no_sync_prefix.stepfunctions.test_state( + definition=definition, + input=exec_input, + inspectionLevel=InspectionLevel.INFO, + mock=mock, + ) + sfn_snapshot.match("validation-exception", e.value.response) diff --git a/tests/aws/services/stepfunctions/v2/test_state/test_field_validation_mode.snapshot.json b/tests/aws/services/stepfunctions/v2/test_state/test_field_validation_mode.snapshot.json new file mode 100644 index 0000000000000..9cfb658b6091c --- /dev/null +++ b/tests/aws/services/stepfunctions/v2/test_state/test_field_validation_mode.snapshot.json @@ -0,0 +1,270 @@ +{ + "tests/aws/services/stepfunctions/v2/test_state/test_field_validation_mode.py::TestFieldValidationMode::test_strict_mode_mock_result_field_not_in_api_spec[field_not_part_of_api_spec]": { + "recorded-date": "03-12-2025, 01:10:10", + "recorded-content": { + "test_case_response": { + "output": { + "random": "json" + }, + "status": "SUCCEEDED", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_field_validation_mode.py::TestFieldValidationMode::test_strict_mode_mock_result_field_not_in_api_spec[empty_json]": { + "recorded-date": "03-12-2025, 01:10:10", + "recorded-content": { + "test_case_response": { + "output": {}, + "status": "SUCCEEDED", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_field_validation_mode.py::TestFieldValidationMode::test_strict_mode_eventbridge_task[wrong_type_top_level_field]": { + "recorded-date": "03-12-2025, 01:10:10", + "recorded-content": { + "validation-exception": { + "Error": { + "Code": "ValidationException", + "Message": "Mock result schema validation error: Field 'Entries' must be an array" + }, + "message": "Mock result schema validation error: Field 'Entries' must be an array", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + } + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_field_validation_mode.py::TestFieldValidationMode::test_strict_mode_eventbridge_task[wrong_type_nested_field]": { + "recorded-date": "03-12-2025, 01:10:10", + "recorded-content": { + "validation-exception": { + "Error": { + "Code": "ValidationException", + "Message": "Mock result schema validation error: Field 'EventId' must be a string" + }, + "message": "Mock result schema validation error: Field 'EventId' must be a string", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + } + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_field_validation_mode.py::TestFieldValidationMode::test_strict_mode_eventbridge_task[wrong_type_2nd_array_element]": { + "recorded-date": "03-12-2025, 01:10:10", + "recorded-content": { + "validation-exception": { + "Error": { + "Code": "ValidationException", + "Message": "Mock result schema validation error: Field 'EventId' must be a string" + }, + "message": "Mock result schema validation error: Field 'EventId' must be a string", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + } + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_field_validation_mode.py::TestFieldValidationMode::test_strict_mode_sfn_task[missing_required_fields]": { + "recorded-date": "03-12-2025, 01:10:11", + "recorded-content": { + "validation-exception": { + "Error": { + "Code": "ValidationException", + "Message": "Mock result schema validation error: Required field 'ExecutionArn' is missing" + }, + "message": "Mock result schema validation error: Required field 'ExecutionArn' is missing", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + } + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_field_validation_mode.py::TestFieldValidationMode::test_strict_mode_sfn_task[field_name_not_in_sfn_case]": { + "recorded-date": "03-12-2025, 01:10:11", + "recorded-content": { + "validation-exception": { + "Error": { + "Code": "ValidationException", + "Message": "Mock result schema validation error: Required field 'ExecutionArn' is missing" + }, + "message": "Mock result schema validation error: Required field 'ExecutionArn' is missing", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + } + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_field_validation_mode.py::TestFieldValidationMode::test_strict_mode_sfn_task[wrong_timestamp_type_bool]": { + "recorded-date": "03-12-2025, 01:10:11", + "recorded-content": { + "validation-exception": { + "Error": { + "Code": "ValidationException", + "Message": "Mock result schema validation error: Field 'StartDate' must be a string" + }, + "message": "Mock result schema validation error: Field 'StartDate' must be a string", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + } + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_field_validation_mode.py::TestFieldValidationMode::test_strict_mode_sfn_task[wrong_timestamp_type_number]": { + "recorded-date": "03-12-2025, 01:10:11", + "recorded-content": { + "validation-exception": { + "Error": { + "Code": "ValidationException", + "Message": "Mock result schema validation error: Field 'StartDate' must be a string" + }, + "message": "Mock result schema validation error: Field 'StartDate' must be a string", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + } + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_field_validation_mode.py::TestFieldValidationMode::test_strict_mode_lambda_task[wrong_integer_type_string]": { + "recorded-date": "03-12-2025, 01:10:11", + "recorded-content": { + "validation-exception": { + "Error": { + "Code": "ValidationException", + "Message": "Mock result schema validation error: Field 'StatusCode' must be a number" + }, + "message": "Mock result schema validation error: Field 'StatusCode' must be a number", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + } + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_field_validation_mode.py::TestFieldValidationMode::test_strict_mode_dynamodb_task[wrong_float_type_string]": { + "recorded-date": "03-12-2025, 01:10:12", + "recorded-content": { + "validation-exception": { + "Error": { + "Code": "ValidationException", + "Message": "Mock result schema validation error: Field 'CapacityUnits' must be a number" + }, + "message": "Mock result schema validation error: Field 'CapacityUnits' must be a number", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + } + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_field_validation_mode.py::TestFieldValidationMode::test_strict_mode_aws_sdk_s3_task[wrong_long_type_string]": { + "recorded-date": "03-12-2025, 01:10:12", + "recorded-content": { + "validation-exception": { + "Error": { + "Code": "ValidationException", + "Message": "Mock result schema validation error: Field 'ContentLength' must be a number" + }, + "message": "Mock result schema validation error: Field 'ContentLength' must be a number", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + } + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_field_validation_mode.py::TestFieldValidationMode::test_strict_mode_aws_sdk_s3_task[non_existent_enum_value]": { + "recorded-date": "03-12-2025, 01:10:12", + "recorded-content": { + "validation-exception": { + "Error": { + "Code": "ValidationException", + "Message": "Mock result schema validation error: Field 'StorageClass' is not an expected value" + }, + "message": "Mock result schema validation error: Field 'StorageClass' is not an expected value", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + } + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_field_validation_mode.py::TestFieldValidationMode::test_strict_mode_aws_sdk_kms_task[wrong_blob_type_number]": { + "recorded-date": "03-12-2025, 01:10:12", + "recorded-content": { + "validation-exception": { + "Error": { + "Code": "ValidationException", + "Message": "Mock result schema validation error: Field 'CiphertextBlob' must be a string" + }, + "message": "Mock result schema validation error: Field 'CiphertextBlob' must be a string", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + } + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_field_validation_mode.py::TestFieldValidationMode::test_strict_mode_aws_sdk_kms_task[wrong_blob_length_less_than_minimum]": { + "recorded-date": "03-12-2025, 01:10:13", + "recorded-content": { + "validation-exception": { + "Error": { + "Code": "ValidationException", + "Message": "Mock result schema validation error: Field 'CiphertextBlob' is smaller than the minimum length" + }, + "message": "Mock result schema validation error: Field 'CiphertextBlob' is smaller than the minimum length", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + } + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_field_validation_mode.py::TestFieldValidationMode::test_strict_mode_aws_sdk_lambda_get_function_task[integer_less_than_minimum_allowed]": { + "recorded-date": "03-12-2025, 01:10:13", + "recorded-content": { + "validation-exception": { + "Error": { + "Code": "ValidationException", + "Message": "Mock result schema validation error: Field 'MemorySize' is less than the minimum value" + }, + "message": "Mock result schema validation error: Field 'MemorySize' is less than the minimum value", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + } + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_field_validation_mode.py::TestFieldValidationMode::test_strict_mode_aws_sdk_lambda_get_function_task[integer_more_than_maximum_allowed]": { + "recorded-date": "03-12-2025, 01:10:13", + "recorded-content": { + "validation-exception": { + "Error": { + "Code": "ValidationException", + "Message": "Mock result schema validation error: Field 'MemorySize' exceeds the maximum value" + }, + "message": "Mock result schema validation error: Field 'MemorySize' exceeds the maximum value", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + } + } + } +} diff --git a/tests/aws/services/stepfunctions/v2/test_state/test_field_validation_mode.validation.json b/tests/aws/services/stepfunctions/v2/test_state/test_field_validation_mode.validation.json new file mode 100644 index 0000000000000..8175803528190 --- /dev/null +++ b/tests/aws/services/stepfunctions/v2/test_state/test_field_validation_mode.validation.json @@ -0,0 +1,155 @@ +{ + "tests/aws/services/stepfunctions/v2/test_state/test_field_validation_mode.py::TestFieldValidationMode::test_strict_mode_aws_sdk_kms_task[wrong_blob_length_less_than_minimum]": { + "last_validated_date": "2025-12-03T01:10:13+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.24, + "teardown": 0.0, + "total": 0.24 + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_field_validation_mode.py::TestFieldValidationMode::test_strict_mode_aws_sdk_kms_task[wrong_blob_type_number]": { + "last_validated_date": "2025-12-03T01:10:12+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.2, + "teardown": 0.0, + "total": 0.2 + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_field_validation_mode.py::TestFieldValidationMode::test_strict_mode_aws_sdk_lambda_get_function_task[integer_less_than_minimum_allowed]": { + "last_validated_date": "2025-12-03T01:10:13+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.21, + "teardown": 0.0, + "total": 0.21 + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_field_validation_mode.py::TestFieldValidationMode::test_strict_mode_aws_sdk_lambda_get_function_task[integer_more_than_maximum_allowed]": { + "last_validated_date": "2025-12-03T01:10:13+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.2, + "teardown": 0.0, + "total": 0.2 + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_field_validation_mode.py::TestFieldValidationMode::test_strict_mode_aws_sdk_s3_task[non_existent_enum_value]": { + "last_validated_date": "2025-12-03T01:10:12+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.28, + "teardown": 0.0, + "total": 0.28 + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_field_validation_mode.py::TestFieldValidationMode::test_strict_mode_aws_sdk_s3_task[wrong_long_type_string]": { + "last_validated_date": "2025-12-03T01:10:12+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.2, + "teardown": 0.0, + "total": 0.2 + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_field_validation_mode.py::TestFieldValidationMode::test_strict_mode_dynamodb_task[wrong_float_type_string]": { + "last_validated_date": "2025-12-03T01:10:12+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.22, + "teardown": 0.0, + "total": 0.22 + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_field_validation_mode.py::TestFieldValidationMode::test_strict_mode_eventbridge_task[wrong_type_2nd_array_element]": { + "last_validated_date": "2025-12-03T01:10:10+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.2, + "teardown": 0.0, + "total": 0.2 + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_field_validation_mode.py::TestFieldValidationMode::test_strict_mode_eventbridge_task[wrong_type_nested_field]": { + "last_validated_date": "2025-12-03T01:10:10+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.2, + "teardown": 0.0, + "total": 0.2 + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_field_validation_mode.py::TestFieldValidationMode::test_strict_mode_eventbridge_task[wrong_type_top_level_field]": { + "last_validated_date": "2025-12-03T01:10:10+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.21, + "teardown": 0.0, + "total": 0.21 + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_field_validation_mode.py::TestFieldValidationMode::test_strict_mode_lambda_task[wrong_integer_type_string]": { + "last_validated_date": "2025-12-03T01:10:11+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.22, + "teardown": 0.0, + "total": 0.22 + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_field_validation_mode.py::TestFieldValidationMode::test_strict_mode_mock_result_field_not_in_api_spec[empty_json]": { + "last_validated_date": "2025-12-03T01:10:10+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.2, + "teardown": 0.0, + "total": 0.2 + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_field_validation_mode.py::TestFieldValidationMode::test_strict_mode_mock_result_field_not_in_api_spec[field_not_part_of_api_spec]": { + "last_validated_date": "2025-12-03T01:10:10+00:00", + "durations_in_seconds": { + "setup": 0.52, + "call": 0.65, + "teardown": 0.0, + "total": 1.17 + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_field_validation_mode.py::TestFieldValidationMode::test_strict_mode_sfn_task[field_name_not_in_sfn_case]": { + "last_validated_date": "2025-12-03T01:10:11+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.21, + "teardown": 0.0, + "total": 0.21 + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_field_validation_mode.py::TestFieldValidationMode::test_strict_mode_sfn_task[missing_required_fields]": { + "last_validated_date": "2025-12-03T01:10:11+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.26, + "teardown": 0.0, + "total": 0.26 + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_field_validation_mode.py::TestFieldValidationMode::test_strict_mode_sfn_task[wrong_timestamp_type_bool]": { + "last_validated_date": "2025-12-03T01:10:11+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.2, + "teardown": 0.0, + "total": 0.2 + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_field_validation_mode.py::TestFieldValidationMode::test_strict_mode_sfn_task[wrong_timestamp_type_number]": { + "last_validated_date": "2025-12-03T01:10:11+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.2, + "teardown": 0.0, + "total": 0.2 + } + } +} diff --git a/tests/aws/services/stepfunctions/v2/test_state/test_field_validation_mode_none.py b/tests/aws/services/stepfunctions/v2/test_state/test_field_validation_mode_none.py new file mode 100644 index 0000000000000..f6e7e9fec3976 --- /dev/null +++ b/tests/aws/services/stepfunctions/v2/test_state/test_field_validation_mode_none.py @@ -0,0 +1,60 @@ +import json + +import pytest + +from localstack.aws.api.stepfunctions import InspectionLevel +from localstack.testing.pytest import markers +from localstack.utils.aws import arns +from tests.aws.services.stepfunctions.templates.test_state.test_state_templates import ( + TestStateTemplate as TST, +) + + +class TestFieldValidationModeNone: + SFN_VALIDATION_ERRORS = [ + pytest.param( + {}, + id="missing_required_fields", + ), + pytest.param( + {"ExecutionArn": "stringValueExecutionArn", "StartDate": True}, + id="wrong_timestamp_type_bool", + ), + ] + + @markers.aws.validated + @pytest.mark.parametrize("result", SFN_VALIDATION_ERRORS) + def test_none_mode_sfn_task( + self, + aws_client_no_sync_prefix, + account_id, + region_name, + sfn_snapshot, + result, + ): + template = TST.load_sfn_template(TST.BASE_SFN_START_EXECUTION_TASK_STATE) + definition = json.dumps(template) + + target_state_machine_arn = arns.stepfunctions_state_machine_arn( + name="TargetStateMachine", account_id=account_id, region_name=region_name + ) + + target_execution_name = "TestStartTarget" + + exec_input = json.dumps( + { + "stateMachineArn": target_state_machine_arn, + "targetInput": None, + "name": target_execution_name, + } + ) + + mock = {"result": json.dumps(result), "fieldValidationMode": "NONE"} + + test_state_response = aws_client_no_sync_prefix.stepfunctions.test_state( + definition=definition, + input=exec_input, + inspectionLevel=InspectionLevel.INFO, + mock=mock, + ) + sfn_snapshot.match("test_state_response", test_state_response) diff --git a/tests/aws/services/stepfunctions/v2/test_state/test_field_validation_mode_none.snapshot.json b/tests/aws/services/stepfunctions/v2/test_state/test_field_validation_mode_none.snapshot.json new file mode 100644 index 0000000000000..1814ca1c64915 --- /dev/null +++ b/tests/aws/services/stepfunctions/v2/test_state/test_field_validation_mode_none.snapshot.json @@ -0,0 +1,35 @@ +{ + "tests/aws/services/stepfunctions/v2/test_state/test_field_validation_mode_none.py::TestFieldValidationModeNone::test_none_mode_sfn_task[missing_required_fields]": { + "recorded-date": "03-12-2025, 01:12:35", + "recorded-content": { + "test_state_response": { + "output": { + "targetExecutionResult": {} + }, + "status": "SUCCEEDED", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_field_validation_mode_none.py::TestFieldValidationModeNone::test_none_mode_sfn_task[wrong_timestamp_type_bool]": { + "recorded-date": "03-12-2025, 01:12:35", + "recorded-content": { + "test_state_response": { + "output": { + "targetExecutionResult": { + "ExecutionArn": "stringValueExecutionArn", + "StartDate": true + } + }, + "status": "SUCCEEDED", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + } +} diff --git a/tests/aws/services/stepfunctions/v2/test_state/test_field_validation_mode_none.validation.json b/tests/aws/services/stepfunctions/v2/test_state/test_field_validation_mode_none.validation.json new file mode 100644 index 0000000000000..4610684b4aa39 --- /dev/null +++ b/tests/aws/services/stepfunctions/v2/test_state/test_field_validation_mode_none.validation.json @@ -0,0 +1,20 @@ +{ + "tests/aws/services/stepfunctions/v2/test_state/test_field_validation_mode_none.py::TestFieldValidationModeNone::test_none_mode_sfn_task[missing_required_fields]": { + "last_validated_date": "2025-12-03T01:12:35+00:00", + "durations_in_seconds": { + "setup": 0.49, + "call": 0.62, + "teardown": 0.0, + "total": 1.11 + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_field_validation_mode_none.py::TestFieldValidationModeNone::test_none_mode_sfn_task[wrong_timestamp_type_bool]": { + "last_validated_date": "2025-12-03T01:12:35+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.2, + "teardown": 0.0, + "total": 0.2 + } + } +} diff --git a/tests/aws/services/stepfunctions/v2/test_state/test_field_validation_mode_present.py b/tests/aws/services/stepfunctions/v2/test_state/test_field_validation_mode_present.py new file mode 100644 index 0000000000000..f29dabbbfde1f --- /dev/null +++ b/tests/aws/services/stepfunctions/v2/test_state/test_field_validation_mode_present.py @@ -0,0 +1,398 @@ +import json + +import pytest + +from localstack.aws.api.stepfunctions import InspectionLevel +from localstack.testing.aws.util import is_aws_cloud +from localstack.testing.pytest import markers +from localstack.utils.aws import arns +from tests.aws.services.stepfunctions.templates.test_state.test_state_templates import ( + TestStateTemplate as TST, +) + + +class TestFieldValidationModePresent: + EVENTBRIDGE_VALIDATION_PASS_FIELDS_NOT_IN_SPEC = [ + pytest.param({"random": "json"}, id="field_not_part_of_api_spec"), + pytest.param({}, id="empty_json"), + ] + + @markers.aws.validated + @pytest.mark.parametrize("result", EVENTBRIDGE_VALIDATION_PASS_FIELDS_NOT_IN_SPEC) + def test_present_mode_mock_result_field_not_in_api_spec( + self, + aws_client_no_sync_prefix, + sfn_snapshot, + result, + ): + """ + Only fields from the API spec are validated + """ + template = TST.load_sfn_template(TST.BASE_EVENTS_PUT_EVENTS_TASK_STATE) + definition = json.dumps(template) + + entries = [ + { + "Detail": "detail", + "DetailType": "detail_type", + "Source": "source", + }, + ] + exec_input = json.dumps({"Entries": entries}) + + mock = {"result": json.dumps(result), "fieldValidationMode": "PRESENT"} + + test_case_response = aws_client_no_sync_prefix.stepfunctions.test_state( + definition=definition, + input=exec_input, + inspectionLevel=InspectionLevel.INFO, + mock=mock, + ) + sfn_snapshot.match("test_case_response", test_case_response) + + EVENTBRIDGE_VAlIDATION_ERRORS = [ + pytest.param( + {"Entries": "Entries value should have been a list of entry objects"}, + id="wrong_type_top_level_field", + ), + pytest.param( + { + "Entries": [ + {"EventId": ["EventId value should have been a string not a list of strings"]} + ] + }, + id="wrong_type_nested_field", + ), + pytest.param( + { + "Entries": [ + {"EventId": "First eventId has correct type: string"}, + {"EventId": ["Second eventId has incorrect type: array"]}, + ] + }, + id="wrong_type_2nd_array_element", + ), + ] + + @markers.aws.validated + @pytest.mark.parametrize("result", EVENTBRIDGE_VAlIDATION_ERRORS) + def test_present_mode_eventbridge_task( + self, + aws_client, + aws_client_no_sync_prefix, + sfn_snapshot, + result, + ): + template = TST.load_sfn_template(TST.BASE_EVENTS_PUT_EVENTS_TASK_STATE) + definition = json.dumps(template) + + entries = [ + { + "Detail": "detail", + "DetailType": "detail_type", + "Source": "source", + }, + ] + exec_input = json.dumps({"Entries": entries}) + + mock = {"result": json.dumps(result), "fieldValidationMode": "PRESENT"} + + with pytest.raises(aws_client.stepfunctions.exceptions.ValidationException) as e: + aws_client_no_sync_prefix.stepfunctions.test_state( + definition=definition, + input=exec_input, + inspectionLevel=InspectionLevel.INFO, + mock=mock, + ) + sfn_snapshot.match("validation-exception", e.value.response) + + SFN_MALFORMED_RESULTS_ALLOWED_IN_PRESENT_MODE = [ + pytest.param( + {}, + id="missing_required_fields", # not validated in PRESENT mode + ), + pytest.param( + {"executionArn": "stringValueExecutionArn", "startDate": "stringValueStartDate"}, + id="field_name_not_in_sfn_case", # should be treated as unknown field + marks=pytest.mark.skipif( + condition=not is_aws_cloud(), + reason="in LocalStack mock field names are normalized whereas in AWS they are not", + # TODO analyse if this normalization can be reasonable fixed - mock is only applied to StateTaskService._eval_service_task, all before_ and after_ methods are still executed, maybe it is not needed + ), + ), + ] + + @markers.aws.validated + @pytest.mark.parametrize("result", SFN_MALFORMED_RESULTS_ALLOWED_IN_PRESENT_MODE) + def test_present_mode_sfn_task_validation_pass( + self, + aws_client_no_sync_prefix, + account_id, + region_name, + sfn_snapshot, + result, + ): + """ + This test is not throwing validation error but rather checks that the edge case where validation passes in PRESENT mode. + """ + template = TST.load_sfn_template(TST.BASE_SFN_START_EXECUTION_TASK_STATE) + definition = json.dumps(template) + + target_state_machine_arn = arns.stepfunctions_state_machine_arn( + name="TargetStateMachine", account_id=account_id, region_name=region_name + ) + + target_execution_name = "TestStartTarget" + + exec_input = json.dumps( + { + "stateMachineArn": target_state_machine_arn, + "targetInput": None, + "name": target_execution_name, + } + ) + + mock = {"result": json.dumps(result), "fieldValidationMode": "PRESENT"} + + test_state_response = aws_client_no_sync_prefix.stepfunctions.test_state( + definition=definition, + input=exec_input, + inspectionLevel=InspectionLevel.INFO, + mock=mock, + ) + sfn_snapshot.match("test_state_response", test_state_response) + + SFN_MALFORMED_RESULTS_NOT_ALLOWED_IN_PRESENT_MODE = [ + pytest.param( + { + "StartDate": True + }, # ExecutionArn required field is not present but that won't be an error in PRESENT mode, the format of the present field will be though + id="wrong_timestamp_type_bool", + ), + pytest.param( + { + "ExecutionArn": 1764103483 + }, # StartDate required field is not present but that won't be an error in PRESENT mode, the format of the present field will be though + id="wrong_string_type_number", + ), + ] + + @markers.aws.validated + @pytest.mark.parametrize("result", SFN_MALFORMED_RESULTS_NOT_ALLOWED_IN_PRESENT_MODE) + def test_present_mode_sfn_task_validation_fail( + self, + aws_client, + aws_client_no_sync_prefix, + account_id, + region_name, + sfn_snapshot, + result, + ): + template = TST.load_sfn_template(TST.BASE_SFN_START_EXECUTION_TASK_STATE) + definition = json.dumps(template) + + target_state_machine_arn = arns.stepfunctions_state_machine_arn( + name="TargetStateMachine", account_id=account_id, region_name=region_name + ) + + target_execution_name = "TestStartTarget" + + exec_input = json.dumps( + { + "stateMachineArn": target_state_machine_arn, + "targetInput": None, + "name": target_execution_name, + } + ) + + mock = {"result": json.dumps(result), "fieldValidationMode": "PRESENT"} + + with pytest.raises(aws_client.stepfunctions.exceptions.ValidationException) as e: + aws_client_no_sync_prefix.stepfunctions.test_state( + definition=definition, + input=exec_input, + inspectionLevel=InspectionLevel.INFO, + mock=mock, + ) + sfn_snapshot.match("validation-exception", e.value.response) + + LAMBDA_VALIDATION_ERRORS = [ + pytest.param( + { + "StatusCode": "200" + }, # StatusCode is not a required field but is validated because it is present + id="wrong_integer_type_string", + ), + ] + + @markers.aws.validated + @pytest.mark.parametrize("result", LAMBDA_VALIDATION_ERRORS) + def test_present_mode_lambda_task( + self, + aws_client, + aws_client_no_sync_prefix, + sfn_snapshot, + result, + ): + template = TST.load_sfn_template(TST.BASE_LAMBDA_SERVICE_TASK_STATE) + definition = json.dumps(template) + exec_input = json.dumps({"FunctionName": "function_name", "Payload": None}) + + mock = {"result": json.dumps(result), "fieldValidationMode": "PRESENT"} + + with pytest.raises(aws_client.stepfunctions.exceptions.ValidationException) as e: + aws_client_no_sync_prefix.stepfunctions.test_state( + definition=definition, + input=exec_input, + inspectionLevel=InspectionLevel.INFO, + mock=mock, + ) + sfn_snapshot.match("validation-exception", e.value.response) + + DYNAMODB_VALIDATION_ERRORS = [ + pytest.param( + {"ConsumedCapacity": {"CapacityUnits": "123.45"}}, + id="wrong_float_type_string", + ), + ] + + @markers.aws.validated + @pytest.mark.parametrize("result", DYNAMODB_VALIDATION_ERRORS) + def test_present_mode_dynamodb_task( + self, + aws_client, + aws_client_no_sync_prefix, + sfn_snapshot, + result, + ): + template = TST.load_sfn_template(TST.BASE_DYNAMODB_SERVICE_TASK_STATE) + definition = json.dumps(template) + exec_input = json.dumps( + { + "TableName": "table_name", + "Item": {"data": {"S": "HelloWorld"}, "id": {"S": "id1"}}, + } + ) + + mock = {"result": json.dumps(result), "fieldValidationMode": "PRESENT"} + + with pytest.raises(aws_client.stepfunctions.exceptions.ValidationException) as e: + aws_client_no_sync_prefix.stepfunctions.test_state( + definition=definition, + input=exec_input, + inspectionLevel=InspectionLevel.INFO, + mock=mock, + ) + sfn_snapshot.match("validation-exception", e.value.response) + + AWS_SDK_S3_VALIDATION_ERRORS = [ + pytest.param( + {"ContentLength": "9000"}, + id="wrong_long_type_string", + ), + pytest.param( + {"StorageClass": "Papyrus"}, + id="non_existent_enum_value", + ), + ] + + @markers.aws.validated + @pytest.mark.parametrize("result", AWS_SDK_S3_VALIDATION_ERRORS) + def test_present_mode_aws_sdk_s3_task( + self, + aws_client, + aws_client_no_sync_prefix, + sfn_snapshot, + result, + ): + template = TST.load_sfn_template(TST.BASE_AWS_SDK_S3_GET_OBJECT_TASK_STATE) + definition = json.dumps(template) + exec_input = json.dumps({"Bucket": "bucket_name", "Key": "file_key"}) + + mock = {"result": json.dumps(result), "fieldValidationMode": "PRESENT"} + + with pytest.raises(aws_client.stepfunctions.exceptions.ValidationException) as e: + aws_client_no_sync_prefix.stepfunctions.test_state( + definition=definition, + input=exec_input, + inspectionLevel=InspectionLevel.INFO, + mock=mock, + ) + sfn_snapshot.match("validation-exception", e.value.response) + + AWS_SDK_KMS_VALIDATION_ERRORS = [ + pytest.param( + {"CiphertextBlob": 123}, + id="wrong_blob_type_number", + ), + pytest.param( + {"CiphertextBlob": ""}, + id="wrong_blob_length_less_than_minimum", + marks=pytest.mark.skipif( + condition=not is_aws_cloud(), + reason="string value length validation is not implemented yet", + ), + ), + ] + + @markers.aws.validated + @pytest.mark.parametrize("result", AWS_SDK_KMS_VALIDATION_ERRORS) + def test_present_mode_aws_sdk_kms_task( + self, + aws_client, + aws_client_no_sync_prefix, + sfn_snapshot, + result, + ): + template = TST.load_sfn_template(TST.BASE_AWS_SDK_KMS_ENCRYPT_TASK_STATE) + definition = json.dumps(template) + exec_input = json.dumps({"KeyId": "key_id", "Plaintext": "plain_text"}) + + mock = {"result": json.dumps(result), "fieldValidationMode": "PRESENT"} + + with pytest.raises(aws_client.stepfunctions.exceptions.ValidationException) as e: + aws_client_no_sync_prefix.stepfunctions.test_state( + definition=definition, + input=exec_input, + inspectionLevel=InspectionLevel.INFO, + mock=mock, + ) + sfn_snapshot.match("validation-exception", e.value.response) + + AWS_SDK_LAMBDA_GET_FUNCTION_VALIDATION_ERRORS = [ + pytest.param( + {"Configuration": {"MemorySize": 127}}, + id="integer_less_than_minimum_allowed", + ), + pytest.param( + {"Configuration": {"MemorySize": 10241}}, + id="integer_more_than_maximum_allowed", + ), + ] + + @pytest.mark.skipif( + condition=not is_aws_cloud(), reason="number value range validation is not implemented yet" + ) # TODO implement number value range validation + @markers.aws.validated + @pytest.mark.parametrize("result", AWS_SDK_LAMBDA_GET_FUNCTION_VALIDATION_ERRORS) + def test_present_mode_aws_sdk_lambda_get_function_task( + self, + aws_client, + aws_client_no_sync_prefix, + sfn_snapshot, + result, + ): + template = TST.load_sfn_template(TST.BASE_AWS_SDK_LAMBDA_GET_FUNCTION) + definition = json.dumps(template) + exec_input = json.dumps({"FunctionName": "function_name"}) + + mock = {"result": json.dumps(result), "fieldValidationMode": "PRESENT"} + + with pytest.raises(aws_client.stepfunctions.exceptions.ValidationException) as e: + aws_client_no_sync_prefix.stepfunctions.test_state( + definition=definition, + input=exec_input, + inspectionLevel=InspectionLevel.INFO, + mock=mock, + ) + sfn_snapshot.match("validation-exception", e.value.response) diff --git a/tests/aws/services/stepfunctions/v2/test_state/test_field_validation_mode_present.snapshot.json b/tests/aws/services/stepfunctions/v2/test_state/test_field_validation_mode_present.snapshot.json new file mode 100644 index 0000000000000..2fd232e07d1e7 --- /dev/null +++ b/tests/aws/services/stepfunctions/v2/test_state/test_field_validation_mode_present.snapshot.json @@ -0,0 +1,271 @@ +{ + "tests/aws/services/stepfunctions/v2/test_state/test_field_validation_mode_present.py::TestFieldValidationModePresent::test_present_mode_mock_result_field_not_in_api_spec[field_not_part_of_api_spec]": { + "recorded-date": "03-12-2025, 01:16:43", + "recorded-content": { + "test_case_response": { + "output": { + "random": "json" + }, + "status": "SUCCEEDED", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_field_validation_mode_present.py::TestFieldValidationModePresent::test_present_mode_mock_result_field_not_in_api_spec[empty_json]": { + "recorded-date": "03-12-2025, 01:16:43", + "recorded-content": { + "test_case_response": { + "output": {}, + "status": "SUCCEEDED", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_field_validation_mode_present.py::TestFieldValidationModePresent::test_present_mode_eventbridge_task[wrong_type_top_level_field]": { + "recorded-date": "03-12-2025, 01:16:44", + "recorded-content": { + "validation-exception": { + "Error": { + "Code": "ValidationException", + "Message": "Mock result schema validation error: Field 'Entries' must be an array" + }, + "message": "Mock result schema validation error: Field 'Entries' must be an array", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + } + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_field_validation_mode_present.py::TestFieldValidationModePresent::test_present_mode_eventbridge_task[wrong_type_nested_field]": { + "recorded-date": "03-12-2025, 01:16:44", + "recorded-content": { + "validation-exception": { + "Error": { + "Code": "ValidationException", + "Message": "Mock result schema validation error: Field 'EventId' must be a string" + }, + "message": "Mock result schema validation error: Field 'EventId' must be a string", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + } + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_field_validation_mode_present.py::TestFieldValidationModePresent::test_present_mode_eventbridge_task[wrong_type_2nd_array_element]": { + "recorded-date": "03-12-2025, 01:16:44", + "recorded-content": { + "validation-exception": { + "Error": { + "Code": "ValidationException", + "Message": "Mock result schema validation error: Field 'EventId' must be a string" + }, + "message": "Mock result schema validation error: Field 'EventId' must be a string", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + } + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_field_validation_mode_present.py::TestFieldValidationModePresent::test_present_mode_sfn_task_validation_pass[missing_required_fields]": { + "recorded-date": "03-12-2025, 01:16:44", + "recorded-content": { + "test_state_response": { + "output": { + "targetExecutionResult": {} + }, + "status": "SUCCEEDED", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_field_validation_mode_present.py::TestFieldValidationModePresent::test_present_mode_sfn_task_validation_pass[field_name_not_in_sfn_case]": { + "recorded-date": "03-12-2025, 01:16:44", + "recorded-content": { + "test_state_response": { + "output": { + "targetExecutionResult": { + "executionArn": "stringValueExecutionArn", + "startDate": "stringValueStartDate" + } + }, + "status": "SUCCEEDED", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_field_validation_mode_present.py::TestFieldValidationModePresent::test_present_mode_sfn_task_validation_fail[wrong_timestamp_type_bool]": { + "recorded-date": "03-12-2025, 01:16:45", + "recorded-content": { + "validation-exception": { + "Error": { + "Code": "ValidationException", + "Message": "Mock result schema validation error: Field 'StartDate' must be a string" + }, + "message": "Mock result schema validation error: Field 'StartDate' must be a string", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + } + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_field_validation_mode_present.py::TestFieldValidationModePresent::test_present_mode_sfn_task_validation_fail[wrong_string_type_number]": { + "recorded-date": "03-12-2025, 01:16:45", + "recorded-content": { + "validation-exception": { + "Error": { + "Code": "ValidationException", + "Message": "Mock result schema validation error: Field 'ExecutionArn' must be a string" + }, + "message": "Mock result schema validation error: Field 'ExecutionArn' must be a string", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + } + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_field_validation_mode_present.py::TestFieldValidationModePresent::test_present_mode_lambda_task[wrong_integer_type_string]": { + "recorded-date": "03-12-2025, 01:16:45", + "recorded-content": { + "validation-exception": { + "Error": { + "Code": "ValidationException", + "Message": "Mock result schema validation error: Field 'StatusCode' must be a number" + }, + "message": "Mock result schema validation error: Field 'StatusCode' must be a number", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + } + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_field_validation_mode_present.py::TestFieldValidationModePresent::test_present_mode_dynamodb_task[wrong_float_type_string]": { + "recorded-date": "03-12-2025, 01:16:45", + "recorded-content": { + "validation-exception": { + "Error": { + "Code": "ValidationException", + "Message": "Mock result schema validation error: Field 'CapacityUnits' must be a number" + }, + "message": "Mock result schema validation error: Field 'CapacityUnits' must be a number", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + } + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_field_validation_mode_present.py::TestFieldValidationModePresent::test_present_mode_aws_sdk_s3_task[wrong_long_type_string]": { + "recorded-date": "03-12-2025, 01:16:46", + "recorded-content": { + "validation-exception": { + "Error": { + "Code": "ValidationException", + "Message": "Mock result schema validation error: Field 'ContentLength' must be a number" + }, + "message": "Mock result schema validation error: Field 'ContentLength' must be a number", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + } + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_field_validation_mode_present.py::TestFieldValidationModePresent::test_present_mode_aws_sdk_s3_task[non_existent_enum_value]": { + "recorded-date": "03-12-2025, 01:16:46", + "recorded-content": { + "validation-exception": { + "Error": { + "Code": "ValidationException", + "Message": "Mock result schema validation error: Field 'StorageClass' is not an expected value" + }, + "message": "Mock result schema validation error: Field 'StorageClass' is not an expected value", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + } + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_field_validation_mode_present.py::TestFieldValidationModePresent::test_present_mode_aws_sdk_kms_task[wrong_blob_type_number]": { + "recorded-date": "03-12-2025, 01:16:46", + "recorded-content": { + "validation-exception": { + "Error": { + "Code": "ValidationException", + "Message": "Mock result schema validation error: Field 'CiphertextBlob' must be a string" + }, + "message": "Mock result schema validation error: Field 'CiphertextBlob' must be a string", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + } + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_field_validation_mode_present.py::TestFieldValidationModePresent::test_present_mode_aws_sdk_kms_task[wrong_blob_length_less_than_minimum]": { + "recorded-date": "03-12-2025, 01:16:46", + "recorded-content": { + "validation-exception": { + "Error": { + "Code": "ValidationException", + "Message": "Mock result schema validation error: Field 'CiphertextBlob' is smaller than the minimum length" + }, + "message": "Mock result schema validation error: Field 'CiphertextBlob' is smaller than the minimum length", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + } + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_field_validation_mode_present.py::TestFieldValidationModePresent::test_present_mode_aws_sdk_lambda_get_function_task[integer_less_than_minimum_allowed]": { + "recorded-date": "03-12-2025, 01:16:46", + "recorded-content": { + "validation-exception": { + "Error": { + "Code": "ValidationException", + "Message": "Mock result schema validation error: Field 'MemorySize' is less than the minimum value" + }, + "message": "Mock result schema validation error: Field 'MemorySize' is less than the minimum value", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + } + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_field_validation_mode_present.py::TestFieldValidationModePresent::test_present_mode_aws_sdk_lambda_get_function_task[integer_more_than_maximum_allowed]": { + "recorded-date": "03-12-2025, 01:16:47", + "recorded-content": { + "validation-exception": { + "Error": { + "Code": "ValidationException", + "Message": "Mock result schema validation error: Field 'MemorySize' exceeds the maximum value" + }, + "message": "Mock result schema validation error: Field 'MemorySize' exceeds the maximum value", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + } + } + } +} diff --git a/tests/aws/services/stepfunctions/v2/test_state/test_field_validation_mode_present.validation.json b/tests/aws/services/stepfunctions/v2/test_state/test_field_validation_mode_present.validation.json new file mode 100644 index 0000000000000..869bb7efbd54e --- /dev/null +++ b/tests/aws/services/stepfunctions/v2/test_state/test_field_validation_mode_present.validation.json @@ -0,0 +1,155 @@ +{ + "tests/aws/services/stepfunctions/v2/test_state/test_field_validation_mode_present.py::TestFieldValidationModePresent::test_present_mode_aws_sdk_kms_task[wrong_blob_length_less_than_minimum]": { + "last_validated_date": "2025-12-03T01:16:46+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.21, + "teardown": 0.0, + "total": 0.21 + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_field_validation_mode_present.py::TestFieldValidationModePresent::test_present_mode_aws_sdk_kms_task[wrong_blob_type_number]": { + "last_validated_date": "2025-12-03T01:16:46+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.22, + "teardown": 0.0, + "total": 0.22 + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_field_validation_mode_present.py::TestFieldValidationModePresent::test_present_mode_aws_sdk_lambda_get_function_task[integer_less_than_minimum_allowed]": { + "last_validated_date": "2025-12-03T01:16:46+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.2, + "teardown": 0.0, + "total": 0.2 + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_field_validation_mode_present.py::TestFieldValidationModePresent::test_present_mode_aws_sdk_lambda_get_function_task[integer_more_than_maximum_allowed]": { + "last_validated_date": "2025-12-03T01:16:47+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.2, + "teardown": 0.0, + "total": 0.2 + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_field_validation_mode_present.py::TestFieldValidationModePresent::test_present_mode_aws_sdk_s3_task[non_existent_enum_value]": { + "last_validated_date": "2025-12-03T01:16:46+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.26, + "teardown": 0.0, + "total": 0.26 + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_field_validation_mode_present.py::TestFieldValidationModePresent::test_present_mode_aws_sdk_s3_task[wrong_long_type_string]": { + "last_validated_date": "2025-12-03T01:16:46+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.2, + "teardown": 0.0, + "total": 0.2 + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_field_validation_mode_present.py::TestFieldValidationModePresent::test_present_mode_dynamodb_task[wrong_float_type_string]": { + "last_validated_date": "2025-12-03T01:16:45+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.18, + "teardown": 0.0, + "total": 0.18 + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_field_validation_mode_present.py::TestFieldValidationModePresent::test_present_mode_eventbridge_task[wrong_type_2nd_array_element]": { + "last_validated_date": "2025-12-03T01:16:44+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.21, + "teardown": 0.0, + "total": 0.21 + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_field_validation_mode_present.py::TestFieldValidationModePresent::test_present_mode_eventbridge_task[wrong_type_nested_field]": { + "last_validated_date": "2025-12-03T01:16:44+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.2, + "teardown": 0.0, + "total": 0.2 + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_field_validation_mode_present.py::TestFieldValidationModePresent::test_present_mode_eventbridge_task[wrong_type_top_level_field]": { + "last_validated_date": "2025-12-03T01:16:44+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.21, + "teardown": 0.0, + "total": 0.21 + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_field_validation_mode_present.py::TestFieldValidationModePresent::test_present_mode_lambda_task[wrong_integer_type_string]": { + "last_validated_date": "2025-12-03T01:16:45+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.21, + "teardown": 0.0, + "total": 0.21 + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_field_validation_mode_present.py::TestFieldValidationModePresent::test_present_mode_mock_result_field_not_in_api_spec[empty_json]": { + "last_validated_date": "2025-12-03T01:16:43+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.2, + "teardown": 0.0, + "total": 0.2 + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_field_validation_mode_present.py::TestFieldValidationModePresent::test_present_mode_mock_result_field_not_in_api_spec[field_not_part_of_api_spec]": { + "last_validated_date": "2025-12-03T01:16:43+00:00", + "durations_in_seconds": { + "setup": 0.51, + "call": 0.68, + "teardown": 0.0, + "total": 1.19 + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_field_validation_mode_present.py::TestFieldValidationModePresent::test_present_mode_sfn_task_validation_fail[wrong_string_type_number]": { + "last_validated_date": "2025-12-03T01:16:45+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.21, + "teardown": 0.0, + "total": 0.21 + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_field_validation_mode_present.py::TestFieldValidationModePresent::test_present_mode_sfn_task_validation_fail[wrong_timestamp_type_bool]": { + "last_validated_date": "2025-12-03T01:16:45+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.21, + "teardown": 0.0, + "total": 0.21 + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_field_validation_mode_present.py::TestFieldValidationModePresent::test_present_mode_sfn_task_validation_pass[field_name_not_in_sfn_case]": { + "last_validated_date": "2025-12-03T01:16:44+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.22, + "teardown": 0.0, + "total": 0.22 + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_field_validation_mode_present.py::TestFieldValidationModePresent::test_present_mode_sfn_task_validation_pass[missing_required_fields]": { + "last_validated_date": "2025-12-03T01:16:44+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.21, + "teardown": 0.0, + "total": 0.21 + } + } +} diff --git a/tests/aws/services/stepfunctions/v2/test_state/test_state_configuration.py b/tests/aws/services/stepfunctions/v2/test_state/test_state_configuration.py new file mode 100644 index 0000000000000..aea596a208161 --- /dev/null +++ b/tests/aws/services/stepfunctions/v2/test_state/test_state_configuration.py @@ -0,0 +1,322 @@ +import json +from typing import Final + +import pytest + +from localstack.aws.api.stepfunctions import InspectionLevel +from localstack.testing.pytest import markers +from tests.aws.services.stepfunctions.templates.test_state.test_state_templates import ( + TestStateMachineTemplate as TSMT, +) +from tests.aws.services.stepfunctions.templates.test_state.test_state_templates import ( + TestStateTemplate as TST, +) + +TEST_STATE_NAME: Final[str] = "TestState" + +DEFAULT_INPUT = json.dumps({"Values": ["first", "second", "third"]}) + +BASE_TEMPLATE_BINDINGS: list[str] = [ + TST.BASE_MAP_STATE, + TST.BASE_MAP_STATE_CATCH, + TST.BASE_MAP_STATE_RETRY, + TST.MAP_TASK_STATE, +] + +IDS_BASE_TEMPLATE_BINDINGS: list[str] = [ + "BASE_MAP_STATE", + "BASE_MAP_STATE_CATCH", + "BASE_MAP_STATE_RETRY", + "MAP_TASK_STATE", +] + + +class TestStateConfiguration: + @markers.aws.validated + @pytest.mark.parametrize("tct_template", BASE_TEMPLATE_BINDINGS, ids=IDS_BASE_TEMPLATE_BINDINGS) + @pytest.mark.parametrize( + "inspection_level", [InspectionLevel.INFO, InspectionLevel.DEBUG, InspectionLevel.TRACE] + ) + def test_map_state_failure_count( + self, + aws_client, + aws_client_no_sync_prefix, + create_state_machine_iam_role, + sfn_snapshot, + inspection_level, + tct_template, + ): + sfn_snapshot.add_transformer(sfn_snapshot.transform.resource_name()) + + sfn_role_arn = create_state_machine_iam_role(aws_client) + template = TST.load_sfn_template(tct_template) + definition = json.dumps(template) + + below_tolerated_failure = aws_client_no_sync_prefix.stepfunctions.test_state( + definition=definition, + roleArn=sfn_role_arn, + input=DEFAULT_INPUT, + stateConfiguration={"mapIterationFailureCount": 0}, + inspectionLevel=inspection_level, + mock={"result": json.dumps([1, 1, 1])}, + ) + sfn_snapshot.match("below_tolerated_failure", below_tolerated_failure) + + exceeds_tolerated_failure = aws_client_no_sync_prefix.stepfunctions.test_state( + definition=definition, + roleArn=sfn_role_arn, + input=DEFAULT_INPUT, + stateConfiguration={"mapIterationFailureCount": 2}, + inspectionLevel=inspection_level, + mock={"result": json.dumps([0, 0, 1])}, + ) + sfn_snapshot.match("exceeds_tolerated_failure", exceeds_tolerated_failure) + + @markers.aws.validated + @pytest.mark.parametrize( + "inspection_level", [InspectionLevel.INFO, InspectionLevel.DEBUG, InspectionLevel.TRACE] + ) + def test_map_state_error_caused_by_state( + self, + aws_client, + aws_client_no_sync_prefix, + create_state_machine_iam_role, + sfn_snapshot, + inspection_level, + ): + test_input = [1, 1, 1] + + sfn_role_arn = create_state_machine_iam_role(aws_client) + template = TST.load_sfn_template(TST.BASE_MAP_STATE) + definition = json.dumps(template) + + test_case_response = aws_client_no_sync_prefix.stepfunctions.test_state( + definition=definition, + roleArn=sfn_role_arn, + input=json.dumps({"Values": test_input}), + stateConfiguration={ + "errorCausedByState": TEST_STATE_NAME, + }, + inspectionLevel=inspection_level, + mock={ + "errorOutput": {"error": "MockException", "cause": "Mock the cause of the error."} + }, + ) + + sfn_snapshot.match("test_case_response", test_case_response) + + @markers.aws.validated + @pytest.mark.parametrize("inspection_level", [InspectionLevel.DEBUG, InspectionLevel.TRACE]) + def test_state_configuration_retrier_retry_count( + self, + aws_client, + aws_client_no_sync_prefix, + create_state_machine_iam_role, + sfn_snapshot, + inspection_level, + ): + sfn_role_arn = create_state_machine_iam_role(aws_client) + template = TST.load_sfn_template(TST.BASE_TASK_STATE_RETRY) + definition = json.dumps(template) + + below_tolerated_retry_count_with_backoff = ( + aws_client_no_sync_prefix.stepfunctions.test_state( + definition=definition, + roleArn=sfn_role_arn, + input=DEFAULT_INPUT, + stateConfiguration={ + "retrierRetryCount": 4, + }, + inspectionLevel=inspection_level, + mock={ + "errorOutput": { + "error": "MockException", + "cause": "Mock the cause of the error.", + } + }, + ) + ) + + sfn_snapshot.match( + "below_tolerated_retry_count_with_backoff", below_tolerated_retry_count_with_backoff + ) + + exceeds_tolerated_retry_count = aws_client_no_sync_prefix.stepfunctions.test_state( + definition=definition, + roleArn=sfn_role_arn, + input=DEFAULT_INPUT, + stateConfiguration={ + "retrierRetryCount": 5, + }, + inspectionLevel=inspection_level, + mock={ + "errorOutput": {"error": "MockException", "cause": "Mock the cause of the error."} + }, + ) + + sfn_snapshot.match("exceeds_tolerated_retry_count", exceeds_tolerated_retry_count) + + @markers.aws.validated + @pytest.mark.parametrize( + "inspection_level", [InspectionLevel.INFO, InspectionLevel.DEBUG, InspectionLevel.TRACE] + ) + def test_state_configuration_map_iteration_failure_count_with_state_error( + self, + aws_client, + aws_client_no_sync_prefix, + create_state_machine_iam_role, + sfn_snapshot, + inspection_level, + ): + sfn_role_arn = create_state_machine_iam_role(aws_client) + + template = TST.load_sfn_template(TST.BASE_MAP_STATE) + definition = json.dumps(template) + + below_tolerated_failure = aws_client_no_sync_prefix.stepfunctions.test_state( + definition=definition, + roleArn=sfn_role_arn, + input=DEFAULT_INPUT, + stateConfiguration={ + "mapIterationFailureCount": 0, + "errorCausedByState": "TestState", + }, + inspectionLevel=inspection_level, + mock={"errorOutput": {"error": "MockException", "cause": "Mock the error cause."}}, + ) + sfn_snapshot.match("below_tolerated_failure", below_tolerated_failure) + + exceeds_tolerated_failure = aws_client_no_sync_prefix.stepfunctions.test_state( + definition=definition, + roleArn=sfn_role_arn, + input=DEFAULT_INPUT, + stateConfiguration={ + "mapIterationFailureCount": 2, + "errorCausedByState": "TestState", + }, + inspectionLevel=inspection_level, + mock={"errorOutput": {"error": "MockException", "cause": "Mock the error cause."}}, + ) + sfn_snapshot.match("exceeds_tolerated_failure", exceeds_tolerated_failure) + + @markers.aws.validated + @pytest.mark.parametrize( + "inspection_level", [InspectionLevel.INFO, InspectionLevel.DEBUG, InspectionLevel.TRACE] + ) + def test_state_machine_with_state_error( + self, + aws_client, + aws_client_no_sync_prefix, + create_state_machine_iam_role, + sfn_snapshot, + inspection_level, + ): + sfn_role_arn = create_state_machine_iam_role(aws_client) + + template = TSMT.load_sfn_template(TSMT.BASE_MAP_STATE_MACHINE) + definition = json.dumps(template) + + below_tolerated_failure = aws_client_no_sync_prefix.stepfunctions.test_state( + stateName="State0", + definition=definition, + roleArn=sfn_role_arn, + input=DEFAULT_INPUT, + stateConfiguration={ + "mapIterationFailureCount": 0, + "errorCausedByState": "HandleItem", + }, + inspectionLevel=inspection_level, + mock={"errorOutput": {"error": "MockException", "cause": "Mock the error cause."}}, + ) + sfn_snapshot.match("below_tolerated_failure", below_tolerated_failure) + + exceeds_tolerated_failure = aws_client_no_sync_prefix.stepfunctions.test_state( + stateName="State0", + definition=definition, + roleArn=sfn_role_arn, + input=DEFAULT_INPUT, + stateConfiguration={ + "mapIterationFailureCount": 2, + "errorCausedByState": "HandleItem", + }, + inspectionLevel=inspection_level, + mock={"errorOutput": {"error": "MockException", "cause": "Mock the error cause."}}, + ) + sfn_snapshot.match("exceeds_tolerated_failure", exceeds_tolerated_failure) + + @markers.aws.validated + @pytest.mark.parametrize( + "inspection_level", [InspectionLevel.INFO, InspectionLevel.DEBUG, InspectionLevel.TRACE] + ) + def test_state_machine_configuration_map_iteration_item_reader( + self, + aws_client, + aws_client_no_sync_prefix, + create_state_machine_iam_role, + sfn_snapshot, + inspection_level, + ): + sfn_role_arn = create_state_machine_iam_role(aws_client) + exec_input = json.dumps({"Bucket": "test-bucket", "Key": "test-key"}) + + template = TSMT.load_sfn_template(TSMT.MAP_ITEM_READER_STATE_MACHINE) + definition = json.dumps(template) + test_case_response = aws_client_no_sync_prefix.stepfunctions.test_state( + stateName="State0", + definition=definition, + roleArn=sfn_role_arn, + input=exec_input, + stateConfiguration={ + "mapItemReaderData": json.dumps([1, 2, 3]), + }, + inspectionLevel=inspection_level, + mock={"result": json.dumps([1, 4, 9])}, + ) + sfn_snapshot.match("test_case_response", test_case_response) + + @markers.aws.validated + @pytest.mark.parametrize( + "inspection_level", [InspectionLevel.INFO, InspectionLevel.DEBUG, InspectionLevel.TRACE] + ) + def test_state_machine_configuration_item_reader_with_error( + self, + aws_client, + aws_client_no_sync_prefix, + create_state_machine_iam_role, + sfn_snapshot, + inspection_level, + ): + sfn_role_arn = create_state_machine_iam_role(aws_client) + exec_input = json.dumps({"Bucket": "test-bucket", "Key": "test-key"}) + + template = TSMT.load_sfn_template(TSMT.MAP_ITEM_READER_STATE_MACHINE) + definition = json.dumps(template) + below_tolerated_failure = aws_client_no_sync_prefix.stepfunctions.test_state( + stateName="State0", + definition=definition, + roleArn=sfn_role_arn, + input=exec_input, + stateConfiguration={ + "mapIterationFailureCount": 0, + "errorCausedByState": "HandleItem", + "mapItemReaderData": json.dumps([1, 2, 3]), + }, + inspectionLevel=inspection_level, + mock={"errorOutput": {"error": "MockException", "cause": "Mock the error cause."}}, + ) + sfn_snapshot.match("below_tolerated_failure", below_tolerated_failure) + + exceeds_tolerated_failure = aws_client_no_sync_prefix.stepfunctions.test_state( + stateName="State0", + definition=definition, + roleArn=sfn_role_arn, + input=exec_input, + stateConfiguration={ + "mapIterationFailureCount": 2, + "errorCausedByState": "HandleItem", + "mapItemReaderData": json.dumps([1, 2, 3]), + }, + inspectionLevel=inspection_level, + mock={"errorOutput": {"error": "MockException", "cause": "Mock the error cause."}}, + ) + sfn_snapshot.match("exceeds_tolerated_failure", exceeds_tolerated_failure) diff --git a/tests/aws/services/stepfunctions/v2/test_state/test_state_configuration.snapshot.json b/tests/aws/services/stepfunctions/v2/test_state/test_state_configuration.snapshot.json new file mode 100644 index 0000000000000..e671c9d9b73cb --- /dev/null +++ b/tests/aws/services/stepfunctions/v2/test_state/test_state_configuration.snapshot.json @@ -0,0 +1,1395 @@ +{ + "tests/aws/services/stepfunctions/v2/test_state/test_state_configuration.py::TestStateConfiguration::test_map_state_error_caused_by_state[INFO]": { + "recorded-date": "13-11-2025, 17:07:52", + "recorded-content": { + "test_case_response": { + "cause": "Mock the cause of the error.", + "error": "MockException", + "status": "FAILED", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_state_configuration.py::TestStateConfiguration::test_map_state_error_caused_by_state[DEBUG]": { + "recorded-date": "13-11-2025, 17:08:07", + "recorded-content": { + "test_case_response": { + "cause": "Mock the cause of the error.", + "error": "MockException", + "inspectionData": { + "input": { + "Values": [ + 1, + 1, + 1 + ] + }, + "maxConcurrency": 0 + }, + "status": "FAILED", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_state_configuration.py::TestStateConfiguration::test_map_state_error_caused_by_state[TRACE]": { + "recorded-date": "13-11-2025, 17:08:21", + "recorded-content": { + "test_case_response": { + "cause": "Mock the cause of the error.", + "error": "MockException", + "inspectionData": { + "input": { + "Values": [ + 1, + 1, + 1 + ] + }, + "maxConcurrency": 0 + }, + "status": "FAILED", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_state_configuration.py::TestStateConfiguration::test_state_configuration_map_iteration_failure_count_with_state_error[INFO]": { + "recorded-date": "13-11-2025, 17:08:37", + "recorded-content": { + "below_tolerated_failure": { + "cause": "Mock the error cause.", + "error": "MockException", + "status": "FAILED", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "exceeds_tolerated_failure": { + "cause": "Mock the error cause.", + "error": "MockException", + "status": "FAILED", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_state_configuration.py::TestStateConfiguration::test_state_configuration_map_iteration_failure_count_with_state_error[DEBUG]": { + "recorded-date": "13-11-2025, 17:08:51", + "recorded-content": { + "below_tolerated_failure": { + "cause": "Mock the error cause.", + "error": "MockException", + "inspectionData": { + "input": { + "Values": [ + "first", + "second", + "third" + ] + }, + "maxConcurrency": 0 + }, + "status": "FAILED", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "exceeds_tolerated_failure": { + "cause": "Mock the error cause.", + "error": "MockException", + "inspectionData": { + "input": { + "Values": [ + "first", + "second", + "third" + ] + }, + "maxConcurrency": 0 + }, + "status": "FAILED", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_state_configuration.py::TestStateConfiguration::test_state_configuration_map_iteration_failure_count_with_state_error[TRACE]": { + "recorded-date": "13-11-2025, 17:09:07", + "recorded-content": { + "below_tolerated_failure": { + "cause": "Mock the error cause.", + "error": "MockException", + "inspectionData": { + "input": { + "Values": [ + "first", + "second", + "third" + ] + }, + "maxConcurrency": 0 + }, + "status": "FAILED", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "exceeds_tolerated_failure": { + "cause": "Mock the error cause.", + "error": "MockException", + "inspectionData": { + "input": { + "Values": [ + "first", + "second", + "third" + ] + }, + "maxConcurrency": 0 + }, + "status": "FAILED", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_state_configuration.py::TestStateConfiguration::test_state_machine_with_state_error[INFO]": { + "recorded-date": "13-11-2025, 17:09:27", + "recorded-content": { + "below_tolerated_failure": { + "cause": "Mock the error cause.", + "error": "MockException", + "status": "FAILED", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "exceeds_tolerated_failure": { + "cause": "Mock the error cause.", + "error": "MockException", + "status": "FAILED", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_state_configuration.py::TestStateConfiguration::test_state_machine_with_state_error[DEBUG]": { + "recorded-date": "13-11-2025, 17:09:43", + "recorded-content": { + "below_tolerated_failure": { + "cause": "Mock the error cause.", + "error": "MockException", + "inspectionData": { + "afterInputPath": { + "Values": [ + "first", + "second", + "third" + ] + }, + "afterItemsPath": "[\"first\", \"second\", \"third\"]", + "input": { + "Values": [ + "first", + "second", + "third" + ] + }, + "maxConcurrency": 0, + "toleratedFailureCount": 2 + }, + "status": "FAILED", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "exceeds_tolerated_failure": { + "cause": "Mock the error cause.", + "error": "MockException", + "inspectionData": { + "afterInputPath": { + "Values": [ + "first", + "second", + "third" + ] + }, + "afterItemsPath": "[\"first\", \"second\", \"third\"]", + "input": { + "Values": [ + "first", + "second", + "third" + ] + }, + "maxConcurrency": 0, + "toleratedFailureCount": 2 + }, + "status": "FAILED", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_state_configuration.py::TestStateConfiguration::test_state_machine_with_state_error[TRACE]": { + "recorded-date": "13-11-2025, 17:09:57", + "recorded-content": { + "below_tolerated_failure": { + "cause": "Mock the error cause.", + "error": "MockException", + "inspectionData": { + "afterInputPath": { + "Values": [ + "first", + "second", + "third" + ] + }, + "afterItemsPath": "[\"first\", \"second\", \"third\"]", + "input": { + "Values": [ + "first", + "second", + "third" + ] + }, + "maxConcurrency": 0, + "toleratedFailureCount": 2 + }, + "status": "FAILED", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "exceeds_tolerated_failure": { + "cause": "Mock the error cause.", + "error": "MockException", + "inspectionData": { + "afterInputPath": { + "Values": [ + "first", + "second", + "third" + ] + }, + "afterItemsPath": "[\"first\", \"second\", \"third\"]", + "input": { + "Values": [ + "first", + "second", + "third" + ] + }, + "maxConcurrency": 0, + "toleratedFailureCount": 2 + }, + "status": "FAILED", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_state_configuration.py::TestStateConfiguration::test_state_machine_configuration_map_iteration_item_reader[INFO]": { + "recorded-date": "13-11-2025, 17:59:50", + "recorded-content": { + "test_case_response": { + "output": "[1, 4, 9]", + "status": "SUCCEEDED", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_state_configuration.py::TestStateConfiguration::test_state_machine_configuration_map_iteration_item_reader[DEBUG]": { + "recorded-date": "13-11-2025, 18:00:05", + "recorded-content": { + "test_case_response": { + "inspectionData": { + "input": { + "Bucket": "test-bucket", + "Key": "test-key" + }, + "maxConcurrency": 1 + }, + "output": "[1, 4, 9]", + "status": "SUCCEEDED", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_state_configuration.py::TestStateConfiguration::test_state_machine_configuration_map_iteration_item_reader[TRACE]": { + "recorded-date": "13-11-2025, 18:00:20", + "recorded-content": { + "test_case_response": { + "inspectionData": { + "input": { + "Bucket": "test-bucket", + "Key": "test-key" + }, + "maxConcurrency": 1 + }, + "output": "[1, 4, 9]", + "status": "SUCCEEDED", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_state_configuration.py::TestStateConfiguration::test_map_state_failure_count[INFO-BASE_MAP_STATE]": { + "recorded-date": "13-11-2025, 18:01:00", + "recorded-content": { + "below_tolerated_failure": { + "output": { + "input": { + "Values": [ + "first", + "second", + "third" + ] + }, + "context": { + "Execution": { + "Id": "arn::states::111111111111:express::", + "Input": { + "Values": [ + "first", + "second", + "third" + ] + }, + "Name": "", + "RoleArn": "arn::iam::111111111111:role/", + "StartTime": "date" + }, + "StateMachine": { + "Id": "arn::states::111111111111:stateMachine:", + "Name": "" + }, + "State": { + "Name": "StateName", + "EnteredTime": "date", + "RetryCount": 0 + } + }, + "result": [ + 1, + 1, + 1 + ] + }, + "status": "SUCCEEDED", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "exceeds_tolerated_failure": { + "output": { + "input": { + "Values": [ + "first", + "second", + "third" + ] + }, + "context": { + "Execution": { + "Id": "arn::states::111111111111:express::", + "Input": { + "Values": [ + "first", + "second", + "third" + ] + }, + "Name": "", + "RoleArn": "arn::iam::111111111111:role/", + "StartTime": "date" + }, + "StateMachine": { + "Id": "arn::states::111111111111:stateMachine:", + "Name": "" + }, + "State": { + "Name": "StateName", + "EnteredTime": "date", + "RetryCount": 0 + } + }, + "result": [ + 0, + 0, + 1 + ] + }, + "status": "SUCCEEDED", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_state_configuration.py::TestStateConfiguration::test_map_state_failure_count[INFO-BASE_MAP_STATE_CATCH]": { + "recorded-date": "13-11-2025, 18:01:16", + "recorded-content": { + "below_tolerated_failure": { + "output": "[1, 1, 1]", + "status": "SUCCEEDED", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "exceeds_tolerated_failure": { + "cause": "The specified tolerated failure threshold was exceeded", + "error": "States.ExceedToleratedFailureThreshold", + "nextState": "HandleThreshold", + "output": { + "input": { + "Values": [ + "first", + "second", + "third" + ] + }, + "context": { + "Execution": { + "Id": "arn::states::111111111111:express::", + "Input": { + "Values": [ + "first", + "second", + "third" + ] + }, + "Name": "", + "RoleArn": "arn::iam::111111111111:role/", + "StartTime": "date" + }, + "StateMachine": { + "Id": "arn::states::111111111111:stateMachine:", + "Name": "" + }, + "State": { + "Name": "StateName", + "EnteredTime": "date", + "RetryCount": 0 + } + }, + "errorOutput": { + "Error": "States.ExceedToleratedFailureThreshold", + "Cause": "The specified tolerated failure threshold was exceeded" + } + }, + "status": "CAUGHT_ERROR", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_state_configuration.py::TestStateConfiguration::test_map_state_failure_count[INFO-BASE_MAP_STATE_RETRY]": { + "recorded-date": "13-11-2025, 18:01:31", + "recorded-content": { + "below_tolerated_failure": { + "output": "[1, 1, 1]", + "status": "SUCCEEDED", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "exceeds_tolerated_failure": { + "cause": "The specified tolerated failure threshold was exceeded", + "error": "States.ExceedToleratedFailureThreshold", + "status": "RETRIABLE", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_state_configuration.py::TestStateConfiguration::test_map_state_failure_count[INFO-MAP_TASK_STATE]": { + "recorded-date": "13-11-2025, 18:07:46", + "recorded-content": { + "below_tolerated_failure": { + "output": { + "result": [ + "pass", + "pass", + "pass" + ], + "successCount": 3, + "failedCount": 0 + }, + "status": "SUCCEEDED", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "exceeds_tolerated_failure": { + "cause": "The specified tolerated failure threshold was exceeded", + "error": "States.ExceedToleratedFailureThreshold", + "status": "RETRIABLE", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_state_configuration.py::TestStateConfiguration::test_map_state_failure_count[DEBUG-BASE_MAP_STATE]": { + "recorded-date": "18-11-2025, 11:30:45", + "recorded-content": { + "below_tolerated_failure": { + "inspectionData": { + "input": { + "Values": [ + "first", + "second", + "third" + ] + }, + "maxConcurrency": 0 + }, + "output": { + "input": { + "Values": [ + "first", + "second", + "third" + ] + }, + "context": { + "Execution": { + "Id": "arn::states::111111111111:express::", + "Input": { + "Values": [ + "first", + "second", + "third" + ] + }, + "Name": "", + "RoleArn": "arn::iam::111111111111:role/", + "StartTime": "date" + }, + "StateMachine": { + "Id": "arn::states::111111111111:stateMachine:", + "Name": "" + }, + "State": { + "Name": "StateName", + "EnteredTime": "date", + "RetryCount": 0 + } + }, + "result": [ + 1, + 1, + 1 + ] + }, + "status": "SUCCEEDED", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "exceeds_tolerated_failure": { + "inspectionData": { + "input": { + "Values": [ + "first", + "second", + "third" + ] + }, + "maxConcurrency": 0 + }, + "output": { + "input": { + "Values": [ + "first", + "second", + "third" + ] + }, + "context": { + "Execution": { + "Id": "arn::states::111111111111:express::", + "Input": { + "Values": [ + "first", + "second", + "third" + ] + }, + "Name": "", + "RoleArn": "arn::iam::111111111111:role/", + "StartTime": "date" + }, + "StateMachine": { + "Id": "arn::states::111111111111:stateMachine:", + "Name": "" + }, + "State": { + "Name": "StateName", + "EnteredTime": "date", + "RetryCount": 0 + } + }, + "result": [ + 0, + 0, + 1 + ] + }, + "status": "SUCCEEDED", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_state_configuration.py::TestStateConfiguration::test_map_state_failure_count[DEBUG-BASE_MAP_STATE_CATCH]": { + "recorded-date": "13-11-2025, 18:02:22", + "recorded-content": { + "below_tolerated_failure": { + "inspectionData": { + "input": { + "Values": [ + "first", + "second", + "third" + ] + }, + "maxConcurrency": 0, + "toleratedFailureCount": 1 + }, + "output": "[1, 1, 1]", + "status": "SUCCEEDED", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "exceeds_tolerated_failure": { + "cause": "The specified tolerated failure threshold was exceeded", + "error": "States.ExceedToleratedFailureThreshold", + "inspectionData": { + "errorDetails": { + "catchIndex": 1 + }, + "input": { + "Values": [ + "first", + "second", + "third" + ] + }, + "maxConcurrency": 0, + "toleratedFailureCount": 1 + }, + "nextState": "HandleThreshold", + "output": { + "input": { + "Values": [ + "first", + "second", + "third" + ] + }, + "context": { + "Execution": { + "Id": "arn::states::111111111111:express::", + "Input": { + "Values": [ + "first", + "second", + "third" + ] + }, + "Name": "", + "RoleArn": "arn::iam::111111111111:role/", + "StartTime": "date" + }, + "StateMachine": { + "Id": "arn::states::111111111111:stateMachine:", + "Name": "" + }, + "State": { + "Name": "StateName", + "EnteredTime": "date", + "RetryCount": 0 + } + }, + "errorOutput": { + "Error": "States.ExceedToleratedFailureThreshold", + "Cause": "The specified tolerated failure threshold was exceeded" + } + }, + "status": "CAUGHT_ERROR", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_state_configuration.py::TestStateConfiguration::test_map_state_failure_count[DEBUG-BASE_MAP_STATE_RETRY]": { + "recorded-date": "13-11-2025, 18:02:38", + "recorded-content": { + "below_tolerated_failure": { + "inspectionData": { + "input": { + "Values": [ + "first", + "second", + "third" + ] + }, + "maxConcurrency": 0, + "toleratedFailureCount": 1 + }, + "output": "[1, 1, 1]", + "status": "SUCCEEDED", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "exceeds_tolerated_failure": { + "cause": "The specified tolerated failure threshold was exceeded", + "error": "States.ExceedToleratedFailureThreshold", + "inspectionData": { + "errorDetails": { + "retryBackoffIntervalSeconds": 1, + "retryIndex": 1 + }, + "input": { + "Values": [ + "first", + "second", + "third" + ] + }, + "maxConcurrency": 0, + "toleratedFailureCount": 1 + }, + "status": "RETRIABLE", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_state_configuration.py::TestStateConfiguration::test_map_state_failure_count[DEBUG-MAP_TASK_STATE]": { + "recorded-date": "13-11-2025, 18:07:18", + "recorded-content": { + "below_tolerated_failure": { + "inspectionData": { + "input": { + "Values": [ + "first", + "second", + "third" + ] + }, + "maxConcurrency": 0, + "toleratedFailureCount": 1 + }, + "output": { + "result": [ + "pass", + "pass", + "pass" + ], + "successCount": 3, + "failedCount": 0 + }, + "status": "SUCCEEDED", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "exceeds_tolerated_failure": { + "cause": "The specified tolerated failure threshold was exceeded", + "error": "States.ExceedToleratedFailureThreshold", + "inspectionData": { + "errorDetails": { + "retryBackoffIntervalSeconds": 1, + "retryIndex": 1 + }, + "input": { + "Values": [ + "first", + "second", + "third" + ] + }, + "maxConcurrency": 0, + "toleratedFailureCount": 1 + }, + "status": "RETRIABLE", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_state_configuration.py::TestStateConfiguration::test_map_state_failure_count[TRACE-BASE_MAP_STATE]": { + "recorded-date": "13-11-2025, 18:03:08", + "recorded-content": { + "below_tolerated_failure": { + "inspectionData": { + "input": { + "Values": [ + "first", + "second", + "third" + ] + }, + "maxConcurrency": 0 + }, + "output": { + "input": { + "Values": [ + "first", + "second", + "third" + ] + }, + "context": { + "Execution": { + "Id": "arn::states::111111111111:express::", + "Input": { + "Values": [ + "first", + "second", + "third" + ] + }, + "Name": "", + "RoleArn": "arn::iam::111111111111:role/", + "StartTime": "date" + }, + "StateMachine": { + "Id": "arn::states::111111111111:stateMachine:", + "Name": "" + }, + "State": { + "Name": "StateName", + "EnteredTime": "date", + "RetryCount": 0 + } + }, + "result": [ + 1, + 1, + 1 + ] + }, + "status": "SUCCEEDED", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "exceeds_tolerated_failure": { + "inspectionData": { + "input": { + "Values": [ + "first", + "second", + "third" + ] + }, + "maxConcurrency": 0 + }, + "output": { + "input": { + "Values": [ + "first", + "second", + "third" + ] + }, + "context": { + "Execution": { + "Id": "arn::states::111111111111:express::", + "Input": { + "Values": [ + "first", + "second", + "third" + ] + }, + "Name": "", + "RoleArn": "arn::iam::111111111111:role/", + "StartTime": "date" + }, + "StateMachine": { + "Id": "arn::states::111111111111:stateMachine:", + "Name": "" + }, + "State": { + "Name": "StateName", + "EnteredTime": "date", + "RetryCount": 0 + } + }, + "result": [ + 0, + 0, + 1 + ] + }, + "status": "SUCCEEDED", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_state_configuration.py::TestStateConfiguration::test_map_state_failure_count[TRACE-BASE_MAP_STATE_CATCH]": { + "recorded-date": "13-11-2025, 18:03:23", + "recorded-content": { + "below_tolerated_failure": { + "inspectionData": { + "input": { + "Values": [ + "first", + "second", + "third" + ] + }, + "maxConcurrency": 0, + "toleratedFailureCount": 1 + }, + "output": "[1, 1, 1]", + "status": "SUCCEEDED", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "exceeds_tolerated_failure": { + "cause": "The specified tolerated failure threshold was exceeded", + "error": "States.ExceedToleratedFailureThreshold", + "inspectionData": { + "errorDetails": { + "catchIndex": 1 + }, + "input": { + "Values": [ + "first", + "second", + "third" + ] + }, + "maxConcurrency": 0, + "toleratedFailureCount": 1 + }, + "nextState": "HandleThreshold", + "output": { + "input": { + "Values": [ + "first", + "second", + "third" + ] + }, + "context": { + "Execution": { + "Id": "arn::states::111111111111:express::", + "Input": { + "Values": [ + "first", + "second", + "third" + ] + }, + "Name": "", + "RoleArn": "arn::iam::111111111111:role/", + "StartTime": "date" + }, + "StateMachine": { + "Id": "arn::states::111111111111:stateMachine:", + "Name": "" + }, + "State": { + "Name": "StateName", + "EnteredTime": "date", + "RetryCount": 0 + } + }, + "errorOutput": { + "Error": "States.ExceedToleratedFailureThreshold", + "Cause": "The specified tolerated failure threshold was exceeded" + } + }, + "status": "CAUGHT_ERROR", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_state_configuration.py::TestStateConfiguration::test_map_state_failure_count[TRACE-BASE_MAP_STATE_RETRY]": { + "recorded-date": "13-11-2025, 18:03:38", + "recorded-content": { + "below_tolerated_failure": { + "inspectionData": { + "input": { + "Values": [ + "first", + "second", + "third" + ] + }, + "maxConcurrency": 0, + "toleratedFailureCount": 1 + }, + "output": "[1, 1, 1]", + "status": "SUCCEEDED", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "exceeds_tolerated_failure": { + "cause": "The specified tolerated failure threshold was exceeded", + "error": "States.ExceedToleratedFailureThreshold", + "inspectionData": { + "errorDetails": { + "retryBackoffIntervalSeconds": 1, + "retryIndex": 1 + }, + "input": { + "Values": [ + "first", + "second", + "third" + ] + }, + "maxConcurrency": 0, + "toleratedFailureCount": 1 + }, + "status": "RETRIABLE", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_state_configuration.py::TestStateConfiguration::test_map_state_failure_count[TRACE-MAP_TASK_STATE]": { + "recorded-date": "13-11-2025, 18:06:47", + "recorded-content": { + "below_tolerated_failure": { + "inspectionData": { + "input": { + "Values": [ + "first", + "second", + "third" + ] + }, + "maxConcurrency": 0, + "toleratedFailureCount": 1 + }, + "output": { + "result": [ + "pass", + "pass", + "pass" + ], + "successCount": 3, + "failedCount": 0 + }, + "status": "SUCCEEDED", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "exceeds_tolerated_failure": { + "cause": "The specified tolerated failure threshold was exceeded", + "error": "States.ExceedToleratedFailureThreshold", + "inspectionData": { + "errorDetails": { + "retryBackoffIntervalSeconds": 1, + "retryIndex": 1 + }, + "input": { + "Values": [ + "first", + "second", + "third" + ] + }, + "maxConcurrency": 0, + "toleratedFailureCount": 1 + }, + "status": "RETRIABLE", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_state_configuration.py::TestStateConfiguration::test_state_machine_configuration_item_reader_with_error[INFO]": { + "recorded-date": "14-11-2025, 11:13:46", + "recorded-content": { + "below_tolerated_failure": { + "cause": "Mock the error cause.", + "error": "MockException", + "status": "FAILED", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "exceeds_tolerated_failure": { + "cause": "Mock the error cause.", + "error": "MockException", + "status": "FAILED", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_state_configuration.py::TestStateConfiguration::test_state_machine_configuration_item_reader_with_error[DEBUG]": { + "recorded-date": "14-11-2025, 11:14:02", + "recorded-content": { + "below_tolerated_failure": { + "cause": "Mock the error cause.", + "error": "MockException", + "inspectionData": { + "input": { + "Bucket": "test-bucket", + "Key": "test-key" + }, + "maxConcurrency": 1 + }, + "status": "FAILED", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "exceeds_tolerated_failure": { + "cause": "Mock the error cause.", + "error": "MockException", + "inspectionData": { + "input": { + "Bucket": "test-bucket", + "Key": "test-key" + }, + "maxConcurrency": 1 + }, + "status": "FAILED", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_state_configuration.py::TestStateConfiguration::test_state_machine_configuration_item_reader_with_error[TRACE]": { + "recorded-date": "14-11-2025, 11:14:18", + "recorded-content": { + "below_tolerated_failure": { + "cause": "Mock the error cause.", + "error": "MockException", + "inspectionData": { + "input": { + "Bucket": "test-bucket", + "Key": "test-key" + }, + "maxConcurrency": 1 + }, + "status": "FAILED", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "exceeds_tolerated_failure": { + "cause": "Mock the error cause.", + "error": "MockException", + "inspectionData": { + "input": { + "Bucket": "test-bucket", + "Key": "test-key" + }, + "maxConcurrency": 1 + }, + "status": "FAILED", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_state_configuration.py::TestStateConfiguration::test_state_configuration_retrier_retry_count[TRACE]": { + "recorded-date": "22-11-2025, 17:13:28", + "recorded-content": { + "below_tolerated_retry_count_with_backoff": { + "cause": "Mock the cause of the error.", + "error": "MockException", + "inspectionData": { + "afterArguments": { + "FunctionName": "foo", + "Payload": "bar" + }, + "errorDetails": { + "retryBackoffIntervalSeconds": 16, + "retryIndex": 0 + }, + "input": { + "Values": [ + "first", + "second", + "third" + ] + } + }, + "status": "RETRIABLE", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "exceeds_tolerated_retry_count": { + "cause": "Mock the cause of the error.", + "error": "MockException", + "inspectionData": { + "afterArguments": { + "FunctionName": "foo", + "Payload": "bar" + }, + "errorDetails": { + "retryIndex": 0 + }, + "input": { + "Values": [ + "first", + "second", + "third" + ] + } + }, + "status": "FAILED", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_state_configuration.py::TestStateConfiguration::test_state_configuration_retrier_retry_count[DEBUG]": { + "recorded-date": "22-11-2025, 17:13:15", + "recorded-content": { + "below_tolerated_retry_count_with_backoff": { + "cause": "Mock the cause of the error.", + "error": "MockException", + "inspectionData": { + "afterArguments": { + "FunctionName": "foo", + "Payload": "bar" + }, + "errorDetails": { + "retryBackoffIntervalSeconds": 16, + "retryIndex": 0 + }, + "input": { + "Values": [ + "first", + "second", + "third" + ] + } + }, + "status": "RETRIABLE", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "exceeds_tolerated_retry_count": { + "cause": "Mock the cause of the error.", + "error": "MockException", + "inspectionData": { + "afterArguments": { + "FunctionName": "foo", + "Payload": "bar" + }, + "errorDetails": { + "retryIndex": 0 + }, + "input": { + "Values": [ + "first", + "second", + "third" + ] + } + }, + "status": "FAILED", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + } +} diff --git a/tests/aws/services/stepfunctions/v2/test_state/test_state_configuration.validation.json b/tests/aws/services/stepfunctions/v2/test_state/test_state_configuration.validation.json new file mode 100644 index 0000000000000..98b079ae98aa6 --- /dev/null +++ b/tests/aws/services/stepfunctions/v2/test_state/test_state_configuration.validation.json @@ -0,0 +1,236 @@ +{ + "tests/aws/services/stepfunctions/v2/test_state/test_state_configuration.py::TestStateConfiguration::test_map_state_error_caused_by_state[DEBUG]": { + "last_validated_date": "2025-11-13T17:08:09+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 12.93, + "teardown": 1.67, + "total": 14.6 + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_state_configuration.py::TestStateConfiguration::test_map_state_error_caused_by_state[INFO]": { + "last_validated_date": "2025-11-13T17:07:54+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 13.3, + "teardown": 1.91, + "total": 15.21 + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_state_configuration.py::TestStateConfiguration::test_map_state_error_caused_by_state[TRACE]": { + "last_validated_date": "2025-11-13T17:08:23+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 12.77, + "teardown": 1.96, + "total": 14.73 + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_state_configuration.py::TestStateConfiguration::test_map_state_failure_count[DEBUG-BASE_MAP_STATE]": { + "last_validated_date": "2025-11-18T11:40:56+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 13.05, + "teardown": 1.82, + "total": 14.87 + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_state_configuration.py::TestStateConfiguration::test_map_state_failure_count[DEBUG-BASE_MAP_STATE_CATCH]": { + "last_validated_date": "2025-11-18T11:41:11+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 13.67, + "teardown": 1.7, + "total": 15.37 + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_state_configuration.py::TestStateConfiguration::test_map_state_failure_count[DEBUG-BASE_MAP_STATE_RETRY]": { + "last_validated_date": "2025-11-18T11:41:26+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 12.8, + "teardown": 1.78, + "total": 14.58 + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_state_configuration.py::TestStateConfiguration::test_map_state_failure_count[DEBUG-MAP_TASK_STATE]": { + "last_validated_date": "2025-11-18T11:41:41+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 13.48, + "teardown": 1.66, + "total": 15.14 + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_state_configuration.py::TestStateConfiguration::test_map_state_failure_count[DEBUG]": { + "last_validated_date": "2025-11-13T17:07:23+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 13.18, + "teardown": 1.72, + "total": 14.9 + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_state_configuration.py::TestStateConfiguration::test_map_state_failure_count[INFO-BASE_MAP_STATE]": { + "last_validated_date": "2025-11-18T11:39:50+00:00", + "durations_in_seconds": { + "setup": 1.44, + "call": 16.26, + "teardown": 1.95, + "total": 19.65 + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_state_configuration.py::TestStateConfiguration::test_map_state_failure_count[INFO-BASE_MAP_STATE_CATCH]": { + "last_validated_date": "2025-11-18T11:40:05+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 12.81, + "teardown": 2.06, + "total": 14.87 + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_state_configuration.py::TestStateConfiguration::test_map_state_failure_count[INFO-BASE_MAP_STATE_RETRY]": { + "last_validated_date": "2025-11-18T11:40:21+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 13.96, + "teardown": 1.66, + "total": 15.62 + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_state_configuration.py::TestStateConfiguration::test_map_state_failure_count[INFO-MAP_TASK_STATE]": { + "last_validated_date": "2025-11-18T11:40:41+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 18.16, + "teardown": 1.65, + "total": 19.81 + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_state_configuration.py::TestStateConfiguration::test_map_state_failure_count[INFO]": { + "last_validated_date": "2025-11-13T17:07:09+00:00", + "durations_in_seconds": { + "setup": 1.08, + "call": 15.54, + "teardown": 1.76, + "total": 18.38 + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_state_configuration.py::TestStateConfiguration::test_map_state_failure_count[TRACE-BASE_MAP_STATE]": { + "last_validated_date": "2025-11-18T11:41:56+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 13.27, + "teardown": 1.77, + "total": 15.04 + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_state_configuration.py::TestStateConfiguration::test_map_state_failure_count[TRACE-BASE_MAP_STATE_CATCH]": { + "last_validated_date": "2025-11-18T11:42:11+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 13.39, + "teardown": 1.78, + "total": 15.17 + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_state_configuration.py::TestStateConfiguration::test_map_state_failure_count[TRACE-BASE_MAP_STATE_RETRY]": { + "last_validated_date": "2025-11-18T11:42:26+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 13.37, + "teardown": 1.61, + "total": 14.98 + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_state_configuration.py::TestStateConfiguration::test_map_state_failure_count[TRACE-MAP_TASK_STATE]": { + "last_validated_date": "2025-11-18T11:42:42+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 14.14, + "teardown": 2.11, + "total": 16.25 + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_state_configuration.py::TestStateConfiguration::test_map_state_failure_count[TRACE]": { + "last_validated_date": "2025-11-13T17:07:39+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 13.2, + "teardown": 2.1, + "total": 15.3 + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_state_configuration.py::TestStateConfiguration::test_state_configuration_retrier_retry_count[DEBUG]": { + "last_validated_date": "2025-11-22T17:13:16+00:00", + "durations_in_seconds": { + "setup": 0.59, + "call": 13.49, + "teardown": 1.03, + "total": 15.11 + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_state_configuration.py::TestStateConfiguration::test_state_configuration_retrier_retry_count[TRACE]": { + "last_validated_date": "2025-11-22T17:13:29+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 11.95, + "teardown": 1.09, + "total": 13.04 + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_state_configuration.py::TestStateConfiguration::test_state_machine_configuration_item_reader_with_error[DEBUG]": { + "last_validated_date": "2025-11-14T11:14:04+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 14.13, + "teardown": 1.75, + "total": 15.88 + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_state_configuration.py::TestStateConfiguration::test_state_machine_configuration_item_reader_with_error[INFO]": { + "last_validated_date": "2025-11-14T11:13:48+00:00", + "durations_in_seconds": { + "setup": 1.16, + "call": 16.23, + "teardown": 1.76, + "total": 19.15 + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_state_configuration.py::TestStateConfiguration::test_state_machine_configuration_item_reader_with_error[TRACE]": { + "last_validated_date": "2025-11-14T11:14:20+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 14.42, + "teardown": 1.86, + "total": 16.28 + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_state_configuration.py::TestStateConfiguration::test_state_machine_configuration_map_iteration_item_reader[DEBUG]": { + "last_validated_date": "2025-11-13T18:00:07+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 13.76, + "teardown": 1.7, + "total": 15.46 + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_state_configuration.py::TestStateConfiguration::test_state_machine_configuration_map_iteration_item_reader[INFO]": { + "last_validated_date": "2025-11-13T17:59:52+00:00", + "durations_in_seconds": { + "setup": 1.15, + "call": 21.21, + "teardown": 1.77, + "total": 24.13 + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_state_configuration.py::TestStateConfiguration::test_state_machine_configuration_map_iteration_item_reader[TRACE]": { + "last_validated_date": "2025-11-13T18:00:22+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 12.78, + "teardown": 1.64, + "total": 14.42 + } + } +} diff --git a/tests/aws/services/stepfunctions/v2/test_state/test_state_context_object.py b/tests/aws/services/stepfunctions/v2/test_state/test_state_context_object.py new file mode 100644 index 0000000000000..8498ccaea94dc --- /dev/null +++ b/tests/aws/services/stepfunctions/v2/test_state/test_state_context_object.py @@ -0,0 +1,299 @@ +import json +from datetime import datetime +from typing import Final + +import pytest +from botocore.exceptions import ClientError + +from localstack.aws.api.stepfunctions import InspectionLevel +from localstack.testing.aws.util import is_aws_cloud +from localstack.testing.pytest import markers +from tests.aws.services.stepfunctions.templates.context_object.context_object_templates import ( + ContextObjectTemplates, +) +from tests.aws.services.stepfunctions.templates.test_state.test_state_templates import ( + TestStateTemplate as TST, +) + +TEST_STATE_NAME: Final[str] = "TestState" + +_CONTEXT_OBJECT_FULL: Final[dict] = { + "Execution": { + "Id": "arn:aws:states:::execution:MyStateMachine:execution-name-12345", + "Input": { + "input-value": 0, + "message": "test data", + "values": ["charizard", "pikachu", "bulbasaur"], + }, + "Name": "execution-name-12345", + "RoleArn": "arn:aws:iam:::role/StepFunctionsRole", + "StartTime": "2025-01-15T10:30:00.000Z", + }, + "State": { + "EnteredTime": "2025-01-15T10:30:01.500Z", + "Name": "MyTaskState", + "RetryCount": 0, + }, + "StateMachine": { + "Id": "arn:aws:states:::stateMachine:MyStateMachine", + "Name": "MyStateMachine", + }, + # Context object contains 'Task' when state is not a Task state with a '.sync' or '.waitForTaskToken' service integration pattern + # "Task": { + # "Token": "AAAAKgAAAAIAAAAAAAAAAZGexGPEB9DwXS+Bz/bGmUq4hN8v7X3LKnKj0p1qJ7qL4d5kF2gH3iJ4jK5lM6nN7oO8pP9qQ0rR1sS2tT3uU4vV5wW6xX7yY8zZ9aA0bB1cC2dD3eE4fF5gG6hH7iI8jJ9kK0lL1mM2nN3oO4pP5qQ6rR7sS8tT9uU0vV1wW2xX3yY4zZ5" + # }, + # Invalid Context object provided: 'Map' field is not supported when mocking a Context object + # "Map": { + # "Item": {"Index": 2, "Value": {"id": "item-3", "name": "Third Item", "quantity": 15}} + # }, +} + +CONTEXT_OBJECT_FULL: Final[str] = json.dumps(_CONTEXT_OBJECT_FULL) + +TASK_CONTEXT_OBJECT_FULL: Final[str] = json.dumps( + _CONTEXT_OBJECT_FULL | {"Task": {"Token": "abcd123"}} +) + +BASE_CONTEXT_OBJECT_BINDINGS: list[str] = ["$$", "$$.Execution.Input", "$$.Execution.Input.values"] + +IDS_BASE_CONTEXT_OBJECT_BINDINGS: list[str] = ["ALL", "EXECUTION_INPUT", "EXECUTION_INPUT_VALUES"] + + +class TestStateContextObject: + @markers.aws.validated + @pytest.mark.parametrize( + "context_object_literal", BASE_CONTEXT_OBJECT_BINDINGS, ids=IDS_BASE_CONTEXT_OBJECT_BINDINGS + ) + def test_state_task_context_object( + self, + aws_client_no_sync_prefix, + sfn_snapshot, + context_object_literal, + ): + state_machine_template = ContextObjectTemplates.load_sfn_template( + ContextObjectTemplates.CONTEXT_OBJECT_RESULT_PATH + ) + + state_template = state_machine_template["States"][TEST_STATE_NAME] + + definition = json.dumps(state_template) + definition = definition.replace( + ContextObjectTemplates.CONTEXT_OBJECT_LITERAL_PLACEHOLDER, context_object_literal + ) + + exec_input = json.dumps( + {"FunctionName": "lambda_function_name", "Payload": {"input-value": 0}} + ) + mocked_result = json.dumps({"pokemon": ["charizard", "pikachu", "bulbasaur"]}) + + test_case_response = aws_client_no_sync_prefix.stepfunctions.test_state( + definition=definition, + input=exec_input, + inspectionLevel=InspectionLevel.TRACE, + context=CONTEXT_OBJECT_FULL, + mock={"result": mocked_result}, + ) + sfn_snapshot.match("test_case_response", test_case_response) + + @markers.aws.validated + def test_state_wait_task_context_object( + self, + aws_client_no_sync_prefix, + account_id, + region_name, + sfn_snapshot, + ): + state_template = TST.load_sfn_template( + TST.IO_SQS_SERVICE_TASK_WAIT, + ) + + sqs_queue_url = f"https://sqs.{region_name}.amazonaws.com/{account_id}/test-queue" + state_template["Parameters"]["QueueUrl"] = sqs_queue_url + + definition = json.dumps(state_template) + mocked_result = json.dumps({"pokemon": ["charizard", "pikachu", "bulbasaur"]}) + + test_case_response = aws_client_no_sync_prefix.stepfunctions.test_state( + definition=definition, + inspectionLevel=InspectionLevel.TRACE, + context=TASK_CONTEXT_OBJECT_FULL, + mock={"result": mocked_result}, + ) + sfn_snapshot.match("test_case_response", test_case_response) + + @markers.aws.validated + @pytest.mark.parametrize( + "context_object_literal", + BASE_CONTEXT_OBJECT_BINDINGS, + ids=IDS_BASE_CONTEXT_OBJECT_BINDINGS, + ) + @pytest.mark.skipif(not is_aws_cloud(), reason="Error messages are different") + def test_state_map_context_object( + self, + aws_client_no_sync_prefix, + sfn_snapshot, + context_object_literal, + ): + state_machine_template = ContextObjectTemplates.load_sfn_template( + ContextObjectTemplates.CONTEXT_OBJECT_ITEMS_PATH + ) + + state_template = state_machine_template["States"][TEST_STATE_NAME] + + definition = json.dumps(state_template) + definition = definition.replace( + ContextObjectTemplates.CONTEXT_OBJECT_LITERAL_PLACEHOLDER, context_object_literal + ) + + exec_input = json.dumps(["fire", "electricity", "grass"]) + mocked_result = json.dumps(["CHARIZARD", "PIKACHU", "BULBASAUR"]) + + test_case_response = aws_client_no_sync_prefix.stepfunctions.test_state( + definition=definition, + input=exec_input, + inspectionLevel=InspectionLevel.TRACE, + context=CONTEXT_OBJECT_FULL, + mock={"result": mocked_result}, + ) + sfn_snapshot.match("test_case_response", test_case_response) + + @markers.aws.validated + @pytest.mark.parametrize( + "state_template,context_template", + [ + (ContextObjectTemplates.CONTEXT_OBJECT_RESULT_PATH, TASK_CONTEXT_OBJECT_FULL), + (ContextObjectTemplates.CONTEXT_OBJECT_INPUT_PATH, CONTEXT_OBJECT_FULL), + ], + ids=["TOKEN_TASK_NOT_SYNC", "INVALID_STATE_PASS"], + ) + @pytest.mark.skipif(condition=not is_aws_cloud(), reason="Failure cases not yet handled.") + def test_state_context_object_invalid_states( + self, + aws_client_no_sync_prefix, + sfn_snapshot, + state_template, + context_template, + ): + state_machine_template = ContextObjectTemplates.load_sfn_template(state_template) + + state_template = state_machine_template["States"][TEST_STATE_NAME] + + definition = json.dumps(state_template) + definition = definition.replace( + ContextObjectTemplates.CONTEXT_OBJECT_LITERAL_PLACEHOLDER, "$$" + ) + + exec_input = json.dumps(["fire", "electricity", "grass"]) + mocked_result = json.dumps({"pokemon": ["CHARIZARD", "PIKACHU", "BULBASAUR"]}) + + with pytest.raises(ClientError) as exc: + aws_client_no_sync_prefix.stepfunctions.test_state( + definition=definition, + input=exec_input, + inspectionLevel=InspectionLevel.TRACE, + context=context_template, + mock={"result": mocked_result}, + ) + sfn_snapshot.match( + "exception", {"exception_typename": exc.typename, "exception_value": exc.value} + ) + + @markers.aws.validated + @pytest.mark.parametrize( + "context_template", + [ + {"Execution": {"Id": 1}}, + {"Map": {}}, + {"Execution": {"pokemon": "squirtle"}}, + {"Pokedex": {}}, + ], + ids=[ + "INVALID_EXECUTION_ID_TYPE", + "INVALID_MAP", + "INVALID_EXECUTION_FIELD", + "INVALID_FIELD", + ], + ) + def test_state_context_object_validation_failures( + self, + aws_client_no_sync_prefix, + sfn_snapshot, + context_template, + ): + context_object = json.dumps(context_template) + + state_template = TST.load_sfn_template( + TST.BASE_SFN_START_EXECUTION_TASK_STATE, + ) + definition = json.dumps(state_template) + + exec_input = json.dumps( + {"stateMachineArn": "arn", "targetInput": None, "name": "exec_name"} + ) + + result = {"ExecutionArn": "exec_arn", "StartDate": datetime.now().isoformat()} + mocked_result = json.dumps(result) + + with pytest.raises(ClientError) as exc: + aws_client_no_sync_prefix.stepfunctions.test_state( + definition=definition, + input=exec_input, + inspectionLevel=InspectionLevel.TRACE, + context=context_object, + mock={"result": mocked_result}, + ) + + sfn_snapshot.match( + "exception", {"exception_typename": exc.typename, "exception_value": exc.value} + ) + + @markers.aws.validated + @pytest.mark.parametrize( + "context_template", + [ + {"Execution": {}, "State": {}, "StateMachine": {}}, + pytest.param( + {}, + marks=pytest.mark.skipif( + not is_aws_cloud(), reason="Empty context case is not properly accounted for." + ), + ), + ], + ids=[ + "EMPTY_OBJECTS", + "EMPTY", + ], + ) + def test_state_context_object_edge_cases( + self, + aws_client_no_sync_prefix, + sfn_snapshot, + context_template, + ): + context_object = json.dumps(context_template) + + state_machine_template = ContextObjectTemplates.load_sfn_template( + ContextObjectTemplates.CONTEXT_OBJECT_RESULT_PATH + ) + + state_template = state_machine_template["States"][TEST_STATE_NAME] + + definition = json.dumps(state_template) + definition = definition.replace( + ContextObjectTemplates.CONTEXT_OBJECT_LITERAL_PLACEHOLDER, "$$" + ) + + exec_input = json.dumps( + {"FunctionName": "lambda_function_name", "Payload": {"input-value": 0}} + ) + + mocked_result = json.dumps({"pokemon": "pikachu"}) + + test_case_response = aws_client_no_sync_prefix.stepfunctions.test_state( + definition=definition, + input=exec_input, + inspectionLevel=InspectionLevel.TRACE, + context=context_object, + mock={"result": mocked_result}, + ) + sfn_snapshot.match("test_case_response", test_case_response) diff --git a/tests/aws/services/stepfunctions/v2/test_state/test_state_context_object.snapshot.json b/tests/aws/services/stepfunctions/v2/test_state/test_state_context_object.snapshot.json new file mode 100644 index 0000000000000..4c77205196992 --- /dev/null +++ b/tests/aws/services/stepfunctions/v2/test_state/test_state_context_object.snapshot.json @@ -0,0 +1,630 @@ +{ + "tests/aws/services/stepfunctions/v2/test_state/test_state_context_object.py::TestStateContextObject::test_state_task_context_object[ALL]": { + "recorded-date": "03-12-2025, 18:51:48", + "recorded-content": { + "test_case_response": { + "inspectionData": { + "afterInputPath": { + "FunctionName": "lambda_function_name", + "Payload": { + "input-value": 0 + } + }, + "afterParameters": { + "Payload": { + "Input": { + "FunctionName": "lambda_function_name", + "Payload": { + "input-value": 0 + } + } + }, + "FunctionName": "lambda_function_name" + }, + "afterResultPath": { + "ContextObjectValue": { + "Execution": { + "Id": "arn::states:::execution:MyStateMachine:execution-name-12345", + "Input": { + "input-value": 0, + "message": "test data", + "values": [ + "charizard", + "pikachu", + "bulbasaur" + ] + }, + "Name": "execution-name-12345", + "RoleArn": "arn::iam:::role/StepFunctionsRole", + "StartTime": "date" + }, + "State": { + "EnteredTime": "date", + "Name": "MyTaskState", + "RetryCount": 0 + }, + "StateMachine": { + "Id": "arn::states:::stateMachine:MyStateMachine", + "Name": "MyStateMachine" + } + }, + "LambdaOutput": { + "pokemon": [ + "charizard", + "pikachu", + "bulbasaur" + ] + } + }, + "afterResultSelector": { + "ContextObjectValue": { + "Execution": { + "Id": "arn::states:::execution:MyStateMachine:execution-name-12345", + "Input": { + "input-value": 0, + "message": "test data", + "values": [ + "charizard", + "pikachu", + "bulbasaur" + ] + }, + "Name": "execution-name-12345", + "RoleArn": "arn::iam:::role/StepFunctionsRole", + "StartTime": "date" + }, + "State": { + "EnteredTime": "date", + "Name": "MyTaskState", + "RetryCount": 0 + }, + "StateMachine": { + "Id": "arn::states:::stateMachine:MyStateMachine", + "Name": "MyStateMachine" + } + }, + "LambdaOutput": { + "pokemon": [ + "charizard", + "pikachu", + "bulbasaur" + ] + } + }, + "input": { + "FunctionName": "lambda_function_name", + "Payload": { + "input-value": 0 + } + }, + "result": { + "pokemon": [ + "charizard", + "pikachu", + "bulbasaur" + ] + } + }, + "output": { + "ContextObjectValue": { + "Execution": { + "Id": "arn::states:::execution:MyStateMachine:execution-name-12345", + "Input": { + "input-value": 0, + "message": "test data", + "values": [ + "charizard", + "pikachu", + "bulbasaur" + ] + }, + "Name": "execution-name-12345", + "RoleArn": "arn::iam:::role/StepFunctionsRole", + "StartTime": "date" + }, + "State": { + "EnteredTime": "date", + "Name": "MyTaskState", + "RetryCount": 0 + }, + "StateMachine": { + "Id": "arn::states:::stateMachine:MyStateMachine", + "Name": "MyStateMachine" + } + }, + "LambdaOutput": { + "pokemon": [ + "charizard", + "pikachu", + "bulbasaur" + ] + } + }, + "status": "SUCCEEDED", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_state_context_object.py::TestStateContextObject::test_state_task_context_object[EXECUTION_INPUT]": { + "recorded-date": "03-12-2025, 18:51:48", + "recorded-content": { + "test_case_response": { + "inspectionData": { + "afterInputPath": { + "FunctionName": "lambda_function_name", + "Payload": { + "input-value": 0 + } + }, + "afterParameters": { + "Payload": { + "Input": { + "FunctionName": "lambda_function_name", + "Payload": { + "input-value": 0 + } + } + }, + "FunctionName": "lambda_function_name" + }, + "afterResultPath": { + "ContextObjectValue": { + "input-value": 0, + "message": "test data", + "values": [ + "charizard", + "pikachu", + "bulbasaur" + ] + }, + "LambdaOutput": { + "pokemon": [ + "charizard", + "pikachu", + "bulbasaur" + ] + } + }, + "afterResultSelector": { + "ContextObjectValue": { + "input-value": 0, + "message": "test data", + "values": [ + "charizard", + "pikachu", + "bulbasaur" + ] + }, + "LambdaOutput": { + "pokemon": [ + "charizard", + "pikachu", + "bulbasaur" + ] + } + }, + "input": { + "FunctionName": "lambda_function_name", + "Payload": { + "input-value": 0 + } + }, + "result": { + "pokemon": [ + "charizard", + "pikachu", + "bulbasaur" + ] + } + }, + "output": { + "ContextObjectValue": { + "input-value": 0, + "message": "test data", + "values": [ + "charizard", + "pikachu", + "bulbasaur" + ] + }, + "LambdaOutput": { + "pokemon": [ + "charizard", + "pikachu", + "bulbasaur" + ] + } + }, + "status": "SUCCEEDED", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_state_context_object.py::TestStateContextObject::test_state_task_context_object[EXECUTION_INPUT_VALUES]": { + "recorded-date": "03-12-2025, 18:51:49", + "recorded-content": { + "test_case_response": { + "inspectionData": { + "afterInputPath": { + "FunctionName": "lambda_function_name", + "Payload": { + "input-value": 0 + } + }, + "afterParameters": { + "Payload": { + "Input": { + "FunctionName": "lambda_function_name", + "Payload": { + "input-value": 0 + } + } + }, + "FunctionName": "lambda_function_name" + }, + "afterResultPath": { + "ContextObjectValue": [ + "charizard", + "pikachu", + "bulbasaur" + ], + "LambdaOutput": { + "pokemon": [ + "charizard", + "pikachu", + "bulbasaur" + ] + } + }, + "afterResultSelector": { + "ContextObjectValue": [ + "charizard", + "pikachu", + "bulbasaur" + ], + "LambdaOutput": { + "pokemon": [ + "charizard", + "pikachu", + "bulbasaur" + ] + } + }, + "input": { + "FunctionName": "lambda_function_name", + "Payload": { + "input-value": 0 + } + }, + "result": { + "pokemon": [ + "charizard", + "pikachu", + "bulbasaur" + ] + } + }, + "output": { + "ContextObjectValue": [ + "charizard", + "pikachu", + "bulbasaur" + ], + "LambdaOutput": { + "pokemon": [ + "charizard", + "pikachu", + "bulbasaur" + ] + } + }, + "status": "SUCCEEDED", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_state_context_object.py::TestStateContextObject::test_state_wait_task_context_object": { + "recorded-date": "09-12-2025, 11:42:20", + "recorded-content": { + "test_case_response": { + "inspectionData": { + "afterInputPath": {}, + "afterParameters": { + "QueueUrl": "https://sqs..amazonaws.com/111111111111/test-queue", + "MessageBody": { + "Message": "Hello from Step Functions!", + "TaskToken": "abcd123" + } + }, + "afterResultPath": { + "SQS": { + "pokemon": [ + "charizard", + "pikachu", + "bulbasaur" + ] + } + }, + "afterResultSelector": { + "pokemon": [ + "charizard", + "pikachu", + "bulbasaur" + ] + }, + "input": {}, + "result": { + "pokemon": [ + "charizard", + "pikachu", + "bulbasaur" + ] + } + }, + "nextState": "NEXT_STATE", + "output": { + "SQS": { + "pokemon": [ + "charizard", + "pikachu", + "bulbasaur" + ] + } + }, + "status": "SUCCEEDED", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_state_context_object.py::TestStateContextObject::test_state_map_context_object[ALL]": { + "recorded-date": "03-12-2025, 18:51:49", + "recorded-content": { + "test_case_response": { + "cause": "Reference path \"$\" must point to array.", + "error": "States.Runtime", + "inspectionData": { + "afterInputPath": "[\"fire\", \"electricity\", \"grass\"]", + "input": "[\"fire\", \"electricity\", \"grass\"]" + }, + "status": "FAILED", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_state_context_object.py::TestStateContextObject::test_state_map_context_object[EXECUTION_INPUT]": { + "recorded-date": "03-12-2025, 18:51:49", + "recorded-content": { + "test_case_response": { + "cause": "Reference path \"$.Execution.Input\" must point to array.", + "error": "States.Runtime", + "inspectionData": { + "afterInputPath": "[\"fire\", \"electricity\", \"grass\"]", + "input": "[\"fire\", \"electricity\", \"grass\"]" + }, + "status": "FAILED", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_state_context_object.py::TestStateContextObject::test_state_map_context_object[EXECUTION_INPUT_VALUES]": { + "recorded-date": "03-12-2025, 18:51:49", + "recorded-content": { + "test_case_response": { + "inspectionData": { + "afterInputPath": "[\"fire\", \"electricity\", \"grass\"]", + "afterItemsPath": "[\"charizard\", \"pikachu\", \"bulbasaur\"]", + "afterResultPath": "[\"CHARIZARD\", \"PIKACHU\", \"BULBASAUR\"]", + "afterResultSelector": "[\"CHARIZARD\", \"PIKACHU\", \"BULBASAUR\"]", + "input": "[\"fire\", \"electricity\", \"grass\"]", + "maxConcurrency": 1 + }, + "output": "[\"CHARIZARD\", \"PIKACHU\", \"BULBASAUR\"]", + "status": "SUCCEEDED", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_state_context_object.py::TestStateContextObject::test_state_context_object_invalid_states[TOKEN_TASK_NOT_SYNC]": { + "recorded-date": "03-12-2025, 18:51:50", + "recorded-content": { + "exception": { + "exception_typename": "ValidationException", + "exception_value": "An error occurred (ValidationException) when calling the TestState operation: Invalid Context object provided: Context object contains 'Task' when state is not a Task state with a '.sync' or '.waitForTaskToken' service integration pattern" + } + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_state_context_object.py::TestStateContextObject::test_state_context_object_invalid_states[INVALID_STATE_PASS]": { + "recorded-date": "03-12-2025, 18:51:50", + "recorded-content": { + "exception": { + "exception_typename": "ValidationException", + "exception_value": "An error occurred (ValidationException) when calling the TestState operation: State type 'Pass' is not supported when a mock is specified" + } + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_state_context_object.py::TestStateContextObject::test_state_context_object_validation_failures[INVALID_EXECUTION_ID_TYPE]": { + "recorded-date": "03-12-2025, 18:51:50", + "recorded-content": { + "exception": { + "exception_typename": "ValidationException", + "exception_value": "An error occurred (ValidationException) when calling the TestState operation: Invalid Context object provided: Execution.Id must be a string" + } + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_state_context_object.py::TestStateContextObject::test_state_context_object_validation_failures[INVALID_MAP]": { + "recorded-date": "03-12-2025, 18:51:50", + "recorded-content": { + "exception": { + "exception_typename": "ValidationException", + "exception_value": "An error occurred (ValidationException) when calling the TestState operation: Invalid Context object provided: 'Map' field is not supported when mocking a Context object" + } + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_state_context_object.py::TestStateContextObject::test_state_context_object_validation_failures[INVALID_EXECUTION_FIELD]": { + "recorded-date": "03-12-2025, 18:51:51", + "recorded-content": { + "exception": { + "exception_typename": "ValidationException", + "exception_value": "An error occurred (ValidationException) when calling the TestState operation: Invalid Context object provided: Field 'pokemon' is not allowed" + } + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_state_context_object.py::TestStateContextObject::test_state_context_object_validation_failures[INVALID_FIELD]": { + "recorded-date": "03-12-2025, 18:51:51", + "recorded-content": { + "exception": { + "exception_typename": "ValidationException", + "exception_value": "An error occurred (ValidationException) when calling the TestState operation: Invalid Context object provided: Field 'Pokedex' is not allowed" + } + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_state_context_object.py::TestStateContextObject::test_state_context_object_edge_cases[EMPTY_OBJECTS]": { + "recorded-date": "03-12-2025, 18:51:51", + "recorded-content": { + "test_case_response": { + "inspectionData": { + "afterInputPath": { + "FunctionName": "lambda_function_name", + "Payload": { + "input-value": 0 + } + }, + "afterParameters": { + "Payload": { + "Input": { + "FunctionName": "lambda_function_name", + "Payload": { + "input-value": 0 + } + } + }, + "FunctionName": "lambda_function_name" + }, + "afterResultPath": { + "ContextObjectValue": { + "Execution": {}, + "State": {}, + "StateMachine": {} + }, + "LambdaOutput": { + "pokemon": "pikachu" + } + }, + "afterResultSelector": { + "ContextObjectValue": { + "Execution": {}, + "State": {}, + "StateMachine": {} + }, + "LambdaOutput": { + "pokemon": "pikachu" + } + }, + "input": { + "FunctionName": "lambda_function_name", + "Payload": { + "input-value": 0 + } + }, + "result": { + "pokemon": "pikachu" + } + }, + "output": { + "ContextObjectValue": { + "Execution": {}, + "State": {}, + "StateMachine": {} + }, + "LambdaOutput": { + "pokemon": "pikachu" + } + }, + "status": "SUCCEEDED", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_state_context_object.py::TestStateContextObject::test_state_context_object_edge_cases[EMPTY]": { + "recorded-date": "03-12-2025, 18:51:51", + "recorded-content": { + "test_case_response": { + "inspectionData": { + "afterInputPath": { + "FunctionName": "lambda_function_name", + "Payload": { + "input-value": 0 + } + }, + "afterParameters": { + "Payload": { + "Input": { + "FunctionName": "lambda_function_name", + "Payload": { + "input-value": 0 + } + } + }, + "FunctionName": "lambda_function_name" + }, + "afterResultPath": { + "ContextObjectValue": {}, + "LambdaOutput": { + "pokemon": "pikachu" + } + }, + "afterResultSelector": { + "ContextObjectValue": {}, + "LambdaOutput": { + "pokemon": "pikachu" + } + }, + "input": { + "FunctionName": "lambda_function_name", + "Payload": { + "input-value": 0 + } + }, + "result": { + "pokemon": "pikachu" + } + }, + "output": { + "ContextObjectValue": {}, + "LambdaOutput": { + "pokemon": "pikachu" + } + }, + "status": "SUCCEEDED", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + } +} diff --git a/tests/aws/services/stepfunctions/v2/test_state/test_state_context_object.validation.json b/tests/aws/services/stepfunctions/v2/test_state/test_state_context_object.validation.json new file mode 100644 index 0000000000000..d3aea0013582c --- /dev/null +++ b/tests/aws/services/stepfunctions/v2/test_state/test_state_context_object.validation.json @@ -0,0 +1,137 @@ +{ + "tests/aws/services/stepfunctions/v2/test_state/test_state_context_object.py::TestStateContextObject::test_state_context_object_edge_cases[EMPTY]": { + "last_validated_date": "2025-12-03T18:51:51+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.22, + "teardown": 0.0, + "total": 0.22 + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_state_context_object.py::TestStateContextObject::test_state_context_object_edge_cases[EMPTY_OBJECTS]": { + "last_validated_date": "2025-12-03T18:51:51+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.22, + "teardown": 0.0, + "total": 0.22 + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_state_context_object.py::TestStateContextObject::test_state_context_object_invalid_states[INVALID_STATE_PASS]": { + "last_validated_date": "2025-12-03T18:51:50+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.22, + "teardown": 0.0, + "total": 0.22 + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_state_context_object.py::TestStateContextObject::test_state_context_object_invalid_states[TOKEN_TASK_NOT_SYNC]": { + "last_validated_date": "2025-12-03T18:51:50+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.2, + "teardown": 0.0, + "total": 0.2 + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_state_context_object.py::TestStateContextObject::test_state_context_object_validation_failures[INVALID_EXECUTION_FIELD]": { + "last_validated_date": "2025-12-03T18:51:51+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.21, + "teardown": 0.0, + "total": 0.21 + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_state_context_object.py::TestStateContextObject::test_state_context_object_validation_failures[INVALID_EXECUTION_ID_TYPE]": { + "last_validated_date": "2025-12-03T18:51:50+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.2, + "teardown": 0.0, + "total": 0.2 + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_state_context_object.py::TestStateContextObject::test_state_context_object_validation_failures[INVALID_FIELD]": { + "last_validated_date": "2025-12-03T18:51:51+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.24, + "teardown": 0.0, + "total": 0.24 + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_state_context_object.py::TestStateContextObject::test_state_context_object_validation_failures[INVALID_MAP]": { + "last_validated_date": "2025-12-03T18:51:50+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.19, + "teardown": 0.0, + "total": 0.19 + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_state_context_object.py::TestStateContextObject::test_state_map_context_object[ALL]": { + "last_validated_date": "2025-12-03T18:51:49+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.23, + "teardown": 0.0, + "total": 0.23 + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_state_context_object.py::TestStateContextObject::test_state_map_context_object[EXECUTION_INPUT]": { + "last_validated_date": "2025-12-03T18:51:49+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.22, + "teardown": 0.0, + "total": 0.22 + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_state_context_object.py::TestStateContextObject::test_state_map_context_object[EXECUTION_INPUT_VALUES]": { + "last_validated_date": "2025-12-03T18:51:49+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.21, + "teardown": 0.0, + "total": 0.21 + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_state_context_object.py::TestStateContextObject::test_state_task_context_object[ALL]": { + "last_validated_date": "2025-12-03T18:51:48+00:00", + "durations_in_seconds": { + "setup": 0.52, + "call": 0.67, + "teardown": 0.0, + "total": 1.19 + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_state_context_object.py::TestStateContextObject::test_state_task_context_object[EXECUTION_INPUT]": { + "last_validated_date": "2025-12-03T18:51:48+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.22, + "teardown": 0.0, + "total": 0.22 + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_state_context_object.py::TestStateContextObject::test_state_task_context_object[EXECUTION_INPUT_VALUES]": { + "last_validated_date": "2025-12-03T18:51:49+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.21, + "teardown": 0.0, + "total": 0.21 + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_state_context_object.py::TestStateContextObject::test_state_wait_task_context_object": { + "last_validated_date": "2025-12-09T11:42:20+00:00", + "durations_in_seconds": { + "setup": 0.48, + "call": 0.62, + "teardown": 0.0, + "total": 1.1 + } + } +} diff --git a/tests/aws/services/stepfunctions/v2/test_state/test_state_mock_validation.py b/tests/aws/services/stepfunctions/v2/test_state/test_state_mock_validation.py new file mode 100644 index 0000000000000..88d6741579695 --- /dev/null +++ b/tests/aws/services/stepfunctions/v2/test_state/test_state_mock_validation.py @@ -0,0 +1,241 @@ +import json + +import pytest + +from localstack.aws.api.stepfunctions import InspectionLevel +from localstack.testing.pytest import markers +from tests.aws.services.stepfunctions.templates.test_state.test_state_templates import ( + TestStateTemplate as TST, +) + + +class TestStateMockValidation: + STATES_NOT_ACCEPTING_MOCKS = [ + pytest.param(TST.BASE_PASS_STATE, id="PassState"), + pytest.param(TST.BASE_FAIL_STATE, id="FailState"), + pytest.param(TST.BASE_SUCCEED_STATE, id="SucceedState"), + # TODO choice + ] + MOCK_VARIANTS = [ + pytest.param({"result": json.dumps({"mock": "the unmockable"})}, id="mock_result"), + pytest.param({"errorOutput": {"error": "Error", "cause": "Cause"}}, id="mock_error_output"), + ] + + @markers.aws.validated + @pytest.mark.parametrize("definition_template", STATES_NOT_ACCEPTING_MOCKS) + @pytest.mark.parametrize("mock", MOCK_VARIANTS) + def test_state_type_does_not_accept_mock( + self, + aws_client_no_sync_prefix, + sfn_snapshot, + definition_template, + mock, + ): + template = TST.load_sfn_template(definition_template) + definition = json.dumps(template) + + with pytest.raises(Exception) as e: + aws_client_no_sync_prefix.stepfunctions.test_state( + definition=definition, + inspectionLevel=InspectionLevel.TRACE, + mock=mock, + ) + sfn_snapshot.match("validation_exception", e.value.response) + + STATES_REQUIRING_MOCKS = [ + pytest.param(TST.BASE_MAP_STATE, id="MapState"), + pytest.param(TST.MAP_TASK_STATE, id="MapTaskState"), + pytest.param(TST.BASE_PARALLEL_STATE, id="ParallelState"), + ] + + @markers.aws.validated + @pytest.mark.parametrize("definition_template", STATES_REQUIRING_MOCKS) + def test_state_type_requires_mock( + self, + aws_client_no_sync_prefix, + sfn_snapshot, + definition_template, + ): + template = TST.load_sfn_template(definition_template) + definition = json.dumps(template) + + with pytest.raises(Exception) as e: + aws_client_no_sync_prefix.stepfunctions.test_state( + definition=definition, + inspectionLevel=InspectionLevel.TRACE, + ) + sfn_snapshot.match("validation_exception", e.value.response) + + @markers.aws.validated + def test_both_mock_result_and_mock_error_output_are_set( + self, + aws_client_no_sync_prefix, + sfn_snapshot, + ): + template = TST.load_sfn_template(TST.BASE_LAMBDA_SERVICE_TASK_STATE) + definition = json.dumps(template) + mock = { + "result": json.dumps({"mock": "response"}), + "errorOutput": {"error": "Error", "cause": "Cause"}, + } + + with pytest.raises(Exception) as e: + aws_client_no_sync_prefix.stepfunctions.test_state( + definition=definition, + inspectionLevel=InspectionLevel.TRACE, + mock=mock, + ) + sfn_snapshot.match("validation_exception", e.value.response) + + @markers.aws.validated + def test_reveal_secrets_is_true_and_mock_result_is_set( + self, + aws_client_no_sync_prefix, + sfn_snapshot, + ): + template = TST.load_sfn_template(TST.BASE_LAMBDA_SERVICE_TASK_STATE) + definition = json.dumps(template) + mock = {"result": json.dumps({"mock": "response"})} + with pytest.raises(Exception) as e: + aws_client_no_sync_prefix.stepfunctions.test_state( + definition=definition, + inspectionLevel=InspectionLevel.TRACE, + mock=mock, + revealSecrets=True, + ) + sfn_snapshot.match("validation_exception", e.value.response) + + @markers.aws.validated + def test_mock_result_is_not_array_on_map_state_without_result_writer( + self, + aws_client_no_sync_prefix, + sfn_snapshot, + ): + template = TST.load_sfn_template(TST.BASE_MAP_STATE) + definition = json.dumps(template) + mock = {"result": json.dumps({"mock": "array is expected but object is provided instead"})} + with pytest.raises(Exception) as e: + aws_client_no_sync_prefix.stepfunctions.test_state( + definition=definition, + inspectionLevel=InspectionLevel.TRACE, + mock=mock, + ) + sfn_snapshot.match("validation_exception", e.value.response) + + @markers.aws.validated + def test_mock_result_is_not_object_on_map_state_with_result_writer( + self, + aws_client_no_sync_prefix, + sfn_snapshot, + ): + template = TST.load_sfn_template(TST.BASE_MAP_STATE_WITH_RESULT_WRITER) + definition = json.dumps(template) + mock = {"result": json.dumps(["object is expected but array is provided instead"])} + with pytest.raises(Exception) as e: + aws_client_no_sync_prefix.stepfunctions.test_state( + definition=definition, + inspectionLevel=InspectionLevel.TRACE, + mock=mock, + ) + sfn_snapshot.match("validation_exception", e.value.response) + + @markers.aws.validated + def test_mock_result_is_not_array_on_parallel_state( + self, + aws_client_no_sync_prefix, + sfn_snapshot, + ): + template = TST.load_sfn_template(TST.BASE_PARALLEL_STATE) + definition = json.dumps(template) + mock = {"result": json.dumps({"mock": "array is expected but object is provided instead"})} + with pytest.raises(Exception) as e: + aws_client_no_sync_prefix.stepfunctions.test_state( + definition=definition, + inspectionLevel=InspectionLevel.TRACE, + mock=mock, + ) + sfn_snapshot.match("validation_exception", e.value.response) + + @markers.aws.validated + def test_mock_result_array_size_mismatch_on_parallel_state( + self, + aws_client_no_sync_prefix, + sfn_snapshot, + ): + template = TST.load_sfn_template(TST.BASE_PARALLEL_STATE) + definition = json.dumps(template) + mock = {"result": json.dumps([{"branch1": "result"}])} + with pytest.raises(Exception) as e: + aws_client_no_sync_prefix.stepfunctions.test_state( + definition=definition, + inspectionLevel=InspectionLevel.TRACE, + mock=mock, + ) + sfn_snapshot.match("validation_exception", e.value.response) + + @markers.snapshot.skip_snapshot_verify(paths=["$..Error.Message", "$..message"]) + # ANTLR parser message has different wording but the same meaning as AWS response. Not investing time now to convert to the exact same wording - relying on error code for test. + # TODO match wording and hide implementation details (ANTLR) + @markers.aws.validated + def test_parallel_state_empty_branches( + self, + aws_client_no_sync_prefix, + sfn_snapshot, + ): + definition = json.dumps( + { + "Type": "Parallel", + "Branches": [], + "End": True, + } + ) + mock = {"result": json.dumps([])} + with pytest.raises(Exception) as e: + aws_client_no_sync_prefix.stepfunctions.test_state( + definition=definition, + inspectionLevel=InspectionLevel.TRACE, + mock=mock, + ) + sfn_snapshot.match("validation_exception", e.value.response) + + @markers.aws.validated + def test_map_iteration_failure_count_without_mock( + self, + aws_client, + aws_client_no_sync_prefix, + create_state_machine_iam_role, + sfn_snapshot, + ): + sfn_role_arn = create_state_machine_iam_role(aws_client) + template = TST.load_sfn_template(TST.BASE_MAP_STATE) + definition = json.dumps(template) + + with pytest.raises(aws_client.stepfunctions.exceptions.ValidationException) as e: + aws_client_no_sync_prefix.stepfunctions.test_state( + definition=definition, + roleArn=sfn_role_arn, + stateConfiguration={"mapIterationFailureCount": 0}, + ) + sfn_snapshot.match("validation_exception", e.value.response) + + @markers.aws.validated + def test_map_iteration_failure_count_exceeds_mock_result_items( + self, + aws_client, + aws_client_no_sync_prefix, + create_state_machine_iam_role, + sfn_snapshot, + ): + sfn_role_arn = create_state_machine_iam_role(aws_client) + template = TST.load_sfn_template(TST.BASE_MAP_STATE) + definition = json.dumps(template) + + with pytest.raises(aws_client.stepfunctions.exceptions.ValidationException) as e: + aws_client_no_sync_prefix.stepfunctions.test_state( + definition=definition, + roleArn=sfn_role_arn, + input=json.dumps({"Values": [1, 1, 1]}), + stateConfiguration={"mapIterationFailureCount": 4}, + mock={"result": json.dumps([1, 1, 1])}, + ) + sfn_snapshot.match("validation_exception", e.value.response) diff --git a/tests/aws/services/stepfunctions/v2/test_state/test_state_mock_validation.snapshot.json b/tests/aws/services/stepfunctions/v2/test_state/test_state_mock_validation.snapshot.json new file mode 100644 index 0000000000000..a27d32bbcf7b8 --- /dev/null +++ b/tests/aws/services/stepfunctions/v2/test_state/test_state_mock_validation.snapshot.json @@ -0,0 +1,290 @@ +{ + "tests/aws/services/stepfunctions/v2/test_state/test_state_mock_validation.py::TestStateMockValidation::test_state_type_does_not_accept_mock[mock_result-PassState]": { + "recorded-date": "10-12-2025, 00:28:08", + "recorded-content": { + "validation_exception": { + "Error": { + "Code": "ValidationException", + "Message": "State type 'Pass' is not supported when a mock is specified" + }, + "message": "State type 'Pass' is not supported when a mock is specified", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + } + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_state_mock_validation.py::TestStateMockValidation::test_state_type_does_not_accept_mock[mock_result-FailState]": { + "recorded-date": "10-12-2025, 00:28:09", + "recorded-content": { + "validation_exception": { + "Error": { + "Code": "ValidationException", + "Message": "State type 'Fail' is not supported when a mock is specified" + }, + "message": "State type 'Fail' is not supported when a mock is specified", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + } + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_state_mock_validation.py::TestStateMockValidation::test_state_type_does_not_accept_mock[mock_result-SucceedState]": { + "recorded-date": "10-12-2025, 00:28:09", + "recorded-content": { + "validation_exception": { + "Error": { + "Code": "ValidationException", + "Message": "State type 'Succeed' is not supported when a mock is specified" + }, + "message": "State type 'Succeed' is not supported when a mock is specified", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + } + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_state_mock_validation.py::TestStateMockValidation::test_state_type_does_not_accept_mock[mock_error_output-PassState]": { + "recorded-date": "10-12-2025, 00:28:09", + "recorded-content": { + "validation_exception": { + "Error": { + "Code": "ValidationException", + "Message": "State type 'Pass' is not supported when a mock is specified" + }, + "message": "State type 'Pass' is not supported when a mock is specified", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + } + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_state_mock_validation.py::TestStateMockValidation::test_state_type_does_not_accept_mock[mock_error_output-FailState]": { + "recorded-date": "10-12-2025, 00:28:09", + "recorded-content": { + "validation_exception": { + "Error": { + "Code": "ValidationException", + "Message": "State type 'Fail' is not supported when a mock is specified" + }, + "message": "State type 'Fail' is not supported when a mock is specified", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + } + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_state_mock_validation.py::TestStateMockValidation::test_state_type_does_not_accept_mock[mock_error_output-SucceedState]": { + "recorded-date": "10-12-2025, 00:28:09", + "recorded-content": { + "validation_exception": { + "Error": { + "Code": "ValidationException", + "Message": "State type 'Succeed' is not supported when a mock is specified" + }, + "message": "State type 'Succeed' is not supported when a mock is specified", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + } + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_state_mock_validation.py::TestStateMockValidation::test_state_type_requires_mock[MapState]": { + "recorded-date": "10-12-2025, 00:28:10", + "recorded-content": { + "validation_exception": { + "Error": { + "Code": "InvalidDefinition", + "Message": "TestState API does not support Map or Parallel states. Supported state types include: [Task, Wait, Pass, Succeed, Fail, Choice]" + }, + "message": "TestState API does not support Map or Parallel states. Supported state types include: [Task, Wait, Pass, Succeed, Fail, Choice]", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + } + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_state_mock_validation.py::TestStateMockValidation::test_state_type_requires_mock[MapTaskState]": { + "recorded-date": "10-12-2025, 00:28:10", + "recorded-content": { + "validation_exception": { + "Error": { + "Code": "InvalidDefinition", + "Message": "TestState API does not support Map or Parallel states. Supported state types include: [Task, Wait, Pass, Succeed, Fail, Choice]" + }, + "message": "TestState API does not support Map or Parallel states. Supported state types include: [Task, Wait, Pass, Succeed, Fail, Choice]", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + } + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_state_mock_validation.py::TestStateMockValidation::test_both_mock_result_and_mock_error_output_are_set": { + "recorded-date": "10-12-2025, 00:28:10", + "recorded-content": { + "validation_exception": { + "Error": { + "Code": "ValidationException", + "Message": "A test mock should have only one of the following fields: [result, errorOutput]." + }, + "message": "A test mock should have only one of the following fields: [result, errorOutput].", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + } + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_state_mock_validation.py::TestStateMockValidation::test_reveal_secrets_is_true_and_mock_result_is_set": { + "recorded-date": "10-12-2025, 00:28:10", + "recorded-content": { + "validation_exception": { + "Error": { + "Code": "ValidationException", + "Message": "TestState does not support RevealSecrets when a mock is specified." + }, + "message": "TestState does not support RevealSecrets when a mock is specified.", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + } + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_state_mock_validation.py::TestStateMockValidation::test_mock_result_is_not_array_on_map_state_without_result_writer": { + "recorded-date": "10-12-2025, 00:28:10", + "recorded-content": { + "validation_exception": { + "Error": { + "Code": "ValidationException", + "Message": "Mocked result must be an array." + }, + "message": "Mocked result must be an array.", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + } + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_state_mock_validation.py::TestStateMockValidation::test_mock_result_is_not_object_on_map_state_with_result_writer": { + "recorded-date": "10-12-2025, 00:28:11", + "recorded-content": { + "validation_exception": { + "Error": { + "Code": "ValidationException", + "Message": "Mocked result must be a JSON object." + }, + "message": "Mocked result must be a JSON object.", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + } + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_state_mock_validation.py::TestStateMockValidation::test_state_type_requires_mock[ParallelState]": { + "recorded-date": "24-02-2026, 22:49:05", + "recorded-content": { + "validation_exception": { + "Error": { + "Code": "InvalidDefinition", + "Message": "TestState API does not support Map or Parallel states. Supported state types include: [Task, Wait, Pass, Succeed, Fail, Choice]" + }, + "message": "TestState API does not support Map or Parallel states. Supported state types include: [Task, Wait, Pass, Succeed, Fail, Choice]", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + } + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_state_mock_validation.py::TestStateMockValidation::test_mock_result_is_not_array_on_parallel_state": { + "recorded-date": "24-02-2026, 22:49:05", + "recorded-content": { + "validation_exception": { + "Error": { + "Code": "ValidationException", + "Message": "Mocked result must be an array." + }, + "message": "Mocked result must be an array.", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + } + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_state_mock_validation.py::TestStateMockValidation::test_mock_result_array_size_mismatch_on_parallel_state": { + "recorded-date": "24-02-2026, 22:49:05", + "recorded-content": { + "validation_exception": { + "Error": { + "Code": "ValidationException", + "Message": "Mocked result must contain the same number of items as number of Parallel branches." + }, + "message": "Mocked result must contain the same number of items as number of Parallel branches.", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + } + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_state_mock_validation.py::TestStateMockValidation::test_parallel_state_empty_branches": { + "recorded-date": "24-02-2026, 22:49:05", + "recorded-content": { + "validation_exception": { + "Error": { + "Code": "InvalidDefinition", + "Message": "Invalid State Machine Definition: 'SCHEMA_VALIDATION_FAILED: Value cannot be empty at /States/StateName/Branches'" + }, + "message": "Invalid State Machine Definition: 'SCHEMA_VALIDATION_FAILED: Value cannot be empty at /States/StateName/Branches'", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + } + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_state_mock_validation.py::TestStateMockValidation::test_map_iteration_failure_count_without_mock": { + "recorded-date": "01-03-2026, 22:59:26", + "recorded-content": { + "validation_exception": { + "Error": { + "Code": "ValidationException", + "Message": "TestState does not support MapIterationFailureCount when a mock is not specified." + }, + "message": "TestState does not support MapIterationFailureCount when a mock is not specified.", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + } + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_state_mock_validation.py::TestStateMockValidation::test_map_iteration_failure_count_exceeds_mock_result_items": { + "recorded-date": "02-03-2026, 00:17:09", + "recorded-content": { + "validation_exception": { + "Error": { + "Code": "ValidationException", + "Message": "Map iteration failure count must be less than or equal to the number of Map iterations" + }, + "message": "Map iteration failure count must be less than or equal to the number of Map iterations", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + } + } + } +} diff --git a/tests/aws/services/stepfunctions/v2/test_state/test_state_mock_validation.validation.json b/tests/aws/services/stepfunctions/v2/test_state/test_state_mock_validation.validation.json new file mode 100644 index 0000000000000..97414144be834 --- /dev/null +++ b/tests/aws/services/stepfunctions/v2/test_state/test_state_mock_validation.validation.json @@ -0,0 +1,164 @@ +{ + "tests/aws/services/stepfunctions/v2/test_state/test_state_mock_validation.py::TestStateMockValidation::test_both_mock_result_and_mock_error_output_are_set": { + "last_validated_date": "2026-02-27T10:02:37+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.2, + "teardown": 0.0, + "total": 0.2 + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_state_mock_validation.py::TestStateMockValidation::test_map_iteration_failure_count_exceeds_mock_result_items": { + "last_validated_date": "2026-03-02T00:17:10+00:00", + "durations_in_seconds": { + "setup": 0.5, + "call": 13.04, + "teardown": 0.97, + "total": 14.51 + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_state_mock_validation.py::TestStateMockValidation::test_map_iteration_failure_count_without_mock": { + "last_validated_date": "2026-03-01T22:59:27+00:00", + "durations_in_seconds": { + "setup": 0.57, + "call": 14.18, + "teardown": 1.06, + "total": 15.81 + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_state_mock_validation.py::TestStateMockValidation::test_mock_result_array_size_mismatch_on_parallel_state": { + "last_validated_date": "2026-02-27T10:02:38+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.21, + "teardown": 0.0, + "total": 0.21 + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_state_mock_validation.py::TestStateMockValidation::test_mock_result_is_not_array_on_map_state_without_result_writer": { + "last_validated_date": "2026-02-27T10:02:37+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.19, + "teardown": 0.0, + "total": 0.19 + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_state_mock_validation.py::TestStateMockValidation::test_mock_result_is_not_array_on_parallel_state": { + "last_validated_date": "2026-02-27T10:02:38+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.19, + "teardown": 0.0, + "total": 0.19 + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_state_mock_validation.py::TestStateMockValidation::test_mock_result_is_not_object_on_map_state_with_result_writer": { + "last_validated_date": "2026-02-27T10:02:37+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.27, + "teardown": 0.0, + "total": 0.27 + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_state_mock_validation.py::TestStateMockValidation::test_parallel_state_empty_branches": { + "last_validated_date": "2026-02-27T10:02:38+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.19, + "teardown": 0.0, + "total": 0.19 + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_state_mock_validation.py::TestStateMockValidation::test_reveal_secrets_is_true_and_mock_result_is_set": { + "last_validated_date": "2026-02-27T10:02:37+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.19, + "teardown": 0.0, + "total": 0.19 + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_state_mock_validation.py::TestStateMockValidation::test_state_type_does_not_accept_mock[mock_error_output-FailState]": { + "last_validated_date": "2026-02-27T10:02:36+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.2, + "teardown": 0.0, + "total": 0.2 + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_state_mock_validation.py::TestStateMockValidation::test_state_type_does_not_accept_mock[mock_error_output-PassState]": { + "last_validated_date": "2026-02-27T10:02:36+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.21, + "teardown": 0.0, + "total": 0.21 + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_state_mock_validation.py::TestStateMockValidation::test_state_type_does_not_accept_mock[mock_error_output-SucceedState]": { + "last_validated_date": "2026-02-27T10:02:36+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.22, + "teardown": 0.0, + "total": 0.22 + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_state_mock_validation.py::TestStateMockValidation::test_state_type_does_not_accept_mock[mock_result-FailState]": { + "last_validated_date": "2026-02-27T10:02:35+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.21, + "teardown": 0.0, + "total": 0.21 + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_state_mock_validation.py::TestStateMockValidation::test_state_type_does_not_accept_mock[mock_result-PassState]": { + "last_validated_date": "2026-02-27T10:02:35+00:00", + "durations_in_seconds": { + "setup": 0.66, + "call": 0.71, + "teardown": 0.0, + "total": 1.37 + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_state_mock_validation.py::TestStateMockValidation::test_state_type_does_not_accept_mock[mock_result-SucceedState]": { + "last_validated_date": "2026-02-27T10:02:35+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.2, + "teardown": 0.0, + "total": 0.2 + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_state_mock_validation.py::TestStateMockValidation::test_state_type_requires_mock[MapState]": { + "last_validated_date": "2026-02-27T10:02:36+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.19, + "teardown": 0.0, + "total": 0.19 + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_state_mock_validation.py::TestStateMockValidation::test_state_type_requires_mock[MapTaskState]": { + "last_validated_date": "2026-02-27T10:02:36+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.19, + "teardown": 0.0, + "total": 0.19 + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_state_mock_validation.py::TestStateMockValidation::test_state_type_requires_mock[ParallelState]": { + "last_validated_date": "2026-02-27T10:02:37+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.19, + "teardown": 0.0, + "total": 0.19 + } + } +} diff --git a/tests/aws/services/stepfunctions/v2/test_state/test_test_state_machine_scenarios.py b/tests/aws/services/stepfunctions/v2/test_state/test_test_state_machine_scenarios.py new file mode 100644 index 0000000000000..305fbf7821939 --- /dev/null +++ b/tests/aws/services/stepfunctions/v2/test_state/test_test_state_machine_scenarios.py @@ -0,0 +1,132 @@ +import json +from typing import Final + +import pytest + +from localstack.aws.api.stepfunctions import InspectionLevel +from localstack.testing.pytest import markers +from tests.aws.services.stepfunctions.templates.test_state.test_state_templates import ( + TestStateMachineTemplate as TSMT, +) + +TEST_STATE_NAME: Final[str] = "State0" + +HELLO_WORLD_INPUT = json.dumps({"Value": "HelloWorld"}) + +BASE_TEMPLATE_INPUT_BINDINGS: list[tuple[str, str, str]] = [ + (TSMT.BASE_PASS_STATE_MACHINE, "State0", HELLO_WORLD_INPUT), + (TSMT.BASE_FAIL_STATE_MACHINE, "State0", HELLO_WORLD_INPUT), + (TSMT.BASE_MAP_STATE_MACHINE, "HandleItem", HELLO_WORLD_INPUT), +] + +IDS_BASE_TEMPLATE_INPUT_BINDINGS: list[str] = [ + "BASE_PASS_STATE_MACHINE", + "BASE_FAIL_STATE_MACHINE", + "BASE_MAP_STATE_MACHINE", +] + + +class TestStateMachineScenarios: + @markers.aws.validated + @pytest.mark.parametrize( + "tct_template,state_name,execution_input", + BASE_TEMPLATE_INPUT_BINDINGS, + ids=IDS_BASE_TEMPLATE_INPUT_BINDINGS, + ) + @pytest.mark.parametrize( + "inspection_level", [InspectionLevel.INFO, InspectionLevel.DEBUG, InspectionLevel.TRACE] + ) + def test_base_state_name( + self, + aws_client_no_sync_prefix, + sfn_snapshot, + tct_template, + state_name, + execution_input, + inspection_level, + ): + template = TSMT.load_sfn_template(tct_template) + definition = json.dumps(template) + + test_case_response = aws_client_no_sync_prefix.stepfunctions.test_state( + stateName=state_name, + definition=definition, + input=execution_input, + inspectionLevel=inspection_level, + ) + sfn_snapshot.match("test_case_response", test_case_response) + + @markers.aws.validated + @pytest.mark.parametrize("state_name", ["State0", "State1"]) + @pytest.mark.parametrize( + "inspection_level", [InspectionLevel.INFO, InspectionLevel.DEBUG, InspectionLevel.TRACE] + ) + def test_base_state_name_multi_state( + self, + aws_client_no_sync_prefix, + sfn_snapshot, + state_name, + inspection_level, + ): + template = TSMT.load_sfn_template(TSMT.BASE_MULTI_STATE_MACHINE) + definition = json.dumps(template) + + test_case_response = aws_client_no_sync_prefix.stepfunctions.test_state( + stateName=state_name, + definition=definition, + input=HELLO_WORLD_INPUT, + inspectionLevel=inspection_level, + ) + sfn_snapshot.match("test_case_response", test_case_response) + + @markers.aws.validated + @pytest.mark.parametrize( + "state_name", + ["dne", '"invalid"', ""], + ids=["dne", "invalid", "empty"], + ) + def test_base_state_name_validation_failures( + self, + aws_client_no_sync_prefix, + sfn_snapshot, + state_name, + ): + template = TSMT.load_sfn_template(TSMT.BASE_PASS_STATE_MACHINE) + definition = json.dumps(template) + + with pytest.raises(Exception) as ex: + aws_client_no_sync_prefix.stepfunctions.test_state( + stateName=state_name, + definition=definition, + input=HELLO_WORLD_INPUT, + inspectionLevel=InspectionLevel.INFO, + ) + + sfn_snapshot.match( + "exception", {"exception_typename": ex.typename, "exception_value": ex.value} + ) + + @markers.aws.validated + @markers.snapshot.skip_snapshot_verify(paths=["$..Error.Message", "$..message"]) + # ANTLR parser message has different wording but the same meaning as AWS response. Not investing time now to convert to the exact same wording - relying on error code for test. + # TODO match wording and hide implementation details (ANTLR) + # expected: + # /Error/Message "Invalid State Machine Definition: 'SCHEMA_VALIDATION_FAILED: The field 'Type' should have one of these values: [Task, Wait, Pass, Succeed, Fail, Choice, Parallel, Map] at /States/ExistingButInvalidState/Type'" + # actual: + # 'ASLParserException line 1:170, at "TypeThatDoesNotExist", mismatched input \'"TypeThatDoesNotExist"\' expecting {\'"Task"\', \'"Choice"\', \'"Fail"\', \'"Succeed"\', \'"Pass"\', \'"Wait"\', \'"Parallel"\', \'"Map"\'}' + def test_state_name_invalid_state_definition( + self, + aws_client_no_sync_prefix, + sfn_snapshot, + ): + template = TSMT.load_sfn_template(TSMT.BASE_INVALID_STATE_DEFINITION) + definition = json.dumps(template) + + with pytest.raises(Exception) as e: + aws_client_no_sync_prefix.stepfunctions.test_state( + stateName="ExistingButInvalidState", + definition=definition, + input=HELLO_WORLD_INPUT, + inspectionLevel=InspectionLevel.INFO, + ) + sfn_snapshot.match("validation_exception", e.value.response) diff --git a/tests/aws/services/stepfunctions/v2/test_state/test_test_state_machine_scenarios.snapshot.json b/tests/aws/services/stepfunctions/v2/test_state/test_test_state_machine_scenarios.snapshot.json new file mode 100644 index 0000000000000..ab77a405eefc6 --- /dev/null +++ b/tests/aws/services/stepfunctions/v2/test_state/test_test_state_machine_scenarios.snapshot.json @@ -0,0 +1,365 @@ +{ + "tests/aws/services/stepfunctions/v2/test_state/test_test_state_machine_scenarios.py::TestStateMachineScenarios::test_base_state_name[INFO-BASE_PASS_STATE_MACHINE]": { + "recorded-date": "03-12-2025, 00:48:38", + "recorded-content": { + "test_case_response": { + "output": { + "Value": "HelloWorld" + }, + "status": "SUCCEEDED", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_test_state_machine_scenarios.py::TestStateMachineScenarios::test_base_state_name[INFO-BASE_FAIL_STATE_MACHINE]": { + "recorded-date": "03-12-2025, 00:48:38", + "recorded-content": { + "test_case_response": { + "cause": "This state machines raises a 'SomeFailure' failure.", + "error": "SomeFailure", + "status": "FAILED", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_test_state_machine_scenarios.py::TestStateMachineScenarios::test_base_state_name[DEBUG-BASE_PASS_STATE_MACHINE]": { + "recorded-date": "03-12-2025, 00:48:39", + "recorded-content": { + "test_case_response": { + "inspectionData": { + "afterInputPath": { + "Value": "HelloWorld" + }, + "afterParameters": { + "Value": "HelloWorld" + }, + "afterResultPath": { + "Value": "HelloWorld" + }, + "afterResultSelector": { + "Value": "HelloWorld" + }, + "input": { + "Value": "HelloWorld" + } + }, + "output": { + "Value": "HelloWorld" + }, + "status": "SUCCEEDED", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_test_state_machine_scenarios.py::TestStateMachineScenarios::test_base_state_name[DEBUG-BASE_FAIL_STATE_MACHINE]": { + "recorded-date": "03-12-2025, 00:48:39", + "recorded-content": { + "test_case_response": { + "cause": "This state machines raises a 'SomeFailure' failure.", + "error": "SomeFailure", + "inspectionData": { + "input": { + "Value": "HelloWorld" + } + }, + "status": "FAILED", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_test_state_machine_scenarios.py::TestStateMachineScenarios::test_base_state_name[TRACE-BASE_PASS_STATE_MACHINE]": { + "recorded-date": "03-12-2025, 00:48:39", + "recorded-content": { + "test_case_response": { + "inspectionData": { + "afterInputPath": { + "Value": "HelloWorld" + }, + "afterParameters": { + "Value": "HelloWorld" + }, + "afterResultPath": { + "Value": "HelloWorld" + }, + "afterResultSelector": { + "Value": "HelloWorld" + }, + "input": { + "Value": "HelloWorld" + } + }, + "output": { + "Value": "HelloWorld" + }, + "status": "SUCCEEDED", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_test_state_machine_scenarios.py::TestStateMachineScenarios::test_base_state_name[TRACE-BASE_FAIL_STATE_MACHINE]": { + "recorded-date": "03-12-2025, 00:48:40", + "recorded-content": { + "test_case_response": { + "cause": "This state machines raises a 'SomeFailure' failure.", + "error": "SomeFailure", + "inspectionData": { + "input": { + "Value": "HelloWorld" + } + }, + "status": "FAILED", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_test_state_machine_scenarios.py::TestStateMachineScenarios::test_base_state_name_multi_state[INFO-State0]": { + "recorded-date": "03-12-2025, 00:48:40", + "recorded-content": { + "test_case_response": { + "nextState": "State1", + "output": { + "Value": "HelloWorld" + }, + "status": "SUCCEEDED", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_test_state_machine_scenarios.py::TestStateMachineScenarios::test_base_state_name_multi_state[INFO-State1]": { + "recorded-date": "03-12-2025, 00:48:40", + "recorded-content": { + "test_case_response": { + "cause": "This state machines raises a 'SomeFailure' failure.", + "error": "SomeFailure", + "status": "FAILED", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_test_state_machine_scenarios.py::TestStateMachineScenarios::test_base_state_name_multi_state[DEBUG-State0]": { + "recorded-date": "03-12-2025, 00:48:40", + "recorded-content": { + "test_case_response": { + "inspectionData": { + "input": { + "Value": "HelloWorld" + } + }, + "nextState": "State1", + "output": { + "Value": "HelloWorld" + }, + "status": "SUCCEEDED", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_test_state_machine_scenarios.py::TestStateMachineScenarios::test_base_state_name_multi_state[DEBUG-State1]": { + "recorded-date": "03-12-2025, 00:48:41", + "recorded-content": { + "test_case_response": { + "cause": "This state machines raises a 'SomeFailure' failure.", + "error": "SomeFailure", + "inspectionData": { + "input": { + "Value": "HelloWorld" + } + }, + "status": "FAILED", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_test_state_machine_scenarios.py::TestStateMachineScenarios::test_base_state_name_multi_state[TRACE-State0]": { + "recorded-date": "03-12-2025, 00:48:41", + "recorded-content": { + "test_case_response": { + "inspectionData": { + "input": { + "Value": "HelloWorld" + } + }, + "nextState": "State1", + "output": { + "Value": "HelloWorld" + }, + "status": "SUCCEEDED", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_test_state_machine_scenarios.py::TestStateMachineScenarios::test_base_state_name_multi_state[TRACE-State1]": { + "recorded-date": "03-12-2025, 00:48:41", + "recorded-content": { + "test_case_response": { + "cause": "This state machines raises a 'SomeFailure' failure.", + "error": "SomeFailure", + "inspectionData": { + "input": { + "Value": "HelloWorld" + } + }, + "status": "FAILED", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_test_state_machine_scenarios.py::TestStateMachineScenarios::test_base_state_name_validation_failures[dne]": { + "recorded-date": "03-12-2025, 00:48:41", + "recorded-content": { + "exception": { + "exception_typename": "ValidationException", + "exception_value": "An error occurred (ValidationException) when calling the TestState operation: State not found in definition" + } + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_test_state_machine_scenarios.py::TestStateMachineScenarios::test_base_state_name_validation_failures[invalid]": { + "recorded-date": "03-12-2025, 00:48:42", + "recorded-content": { + "exception": { + "exception_typename": "ValidationException", + "exception_value": "An error occurred (ValidationException) when calling the TestState operation: State not found in definition" + } + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_test_state_machine_scenarios.py::TestStateMachineScenarios::test_base_state_name_validation_failures[empty]": { + "recorded-date": "03-12-2025, 00:48:42", + "recorded-content": { + "exception": { + "exception_typename": "ParamValidationError", + "exception_value": "Parameter validation failed:\nInvalid length for parameter stateName, value: 0, valid min length: 1" + } + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_test_state_machine_scenarios.py::TestStateMachineScenarios::test_base_state_name[INFO-BASE_MAP_STATE_MACHINE]": { + "recorded-date": "03-12-2025, 00:48:39", + "recorded-content": { + "test_case_response": { + "output": { + "Value": "HelloWorld" + }, + "status": "SUCCEEDED", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_test_state_machine_scenarios.py::TestStateMachineScenarios::test_base_state_name[DEBUG-BASE_MAP_STATE_MACHINE]": { + "recorded-date": "03-12-2025, 00:48:39", + "recorded-content": { + "test_case_response": { + "inspectionData": { + "afterInputPath": { + "Value": "HelloWorld" + }, + "afterParameters": { + "Value": "HelloWorld" + }, + "afterResultPath": { + "Value": "HelloWorld" + }, + "afterResultSelector": { + "Value": "HelloWorld" + }, + "input": { + "Value": "HelloWorld" + } + }, + "output": { + "Value": "HelloWorld" + }, + "status": "SUCCEEDED", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_test_state_machine_scenarios.py::TestStateMachineScenarios::test_base_state_name[TRACE-BASE_MAP_STATE_MACHINE]": { + "recorded-date": "03-12-2025, 00:48:40", + "recorded-content": { + "test_case_response": { + "inspectionData": { + "afterInputPath": { + "Value": "HelloWorld" + }, + "afterParameters": { + "Value": "HelloWorld" + }, + "afterResultPath": { + "Value": "HelloWorld" + }, + "afterResultSelector": { + "Value": "HelloWorld" + }, + "input": { + "Value": "HelloWorld" + } + }, + "output": { + "Value": "HelloWorld" + }, + "status": "SUCCEEDED", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_test_state_machine_scenarios.py::TestStateMachineScenarios::test_state_name_invalid_state_definition": { + "recorded-date": "04-12-2025, 12:16:39", + "recorded-content": { + "validation_exception": { + "Error": { + "Code": "InvalidDefinition", + "Message": "Invalid State Machine Definition: 'SCHEMA_VALIDATION_FAILED: The field 'Type' should have one of these values: [Task, Wait, Pass, Succeed, Fail, Choice, Parallel, Map] at /States/ExistingButInvalidState/Type'" + }, + "message": "Invalid State Machine Definition: 'SCHEMA_VALIDATION_FAILED: The field 'Type' should have one of these values: [Task, Wait, Pass, Succeed, Fail, Choice, Parallel, Map] at /States/ExistingButInvalidState/Type'", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + } + } + } +} diff --git a/tests/aws/services/stepfunctions/v2/test_state/test_test_state_machine_scenarios.validation.json b/tests/aws/services/stepfunctions/v2/test_state/test_test_state_machine_scenarios.validation.json new file mode 100644 index 0000000000000..122acaa70d2a6 --- /dev/null +++ b/tests/aws/services/stepfunctions/v2/test_state/test_test_state_machine_scenarios.validation.json @@ -0,0 +1,173 @@ +{ + "tests/aws/services/stepfunctions/v2/test_state/test_test_state_machine_scenarios.py::TestStateMachineScenarios::test_base_state_name[DEBUG-BASE_FAIL_STATE_MACHINE]": { + "last_validated_date": "2025-12-03T00:48:39+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.19, + "teardown": 0.0, + "total": 0.19 + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_test_state_machine_scenarios.py::TestStateMachineScenarios::test_base_state_name[DEBUG-BASE_MAP_STATE_MACHINE]": { + "last_validated_date": "2025-12-03T00:48:39+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.18, + "teardown": 0.0, + "total": 0.18 + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_test_state_machine_scenarios.py::TestStateMachineScenarios::test_base_state_name[DEBUG-BASE_PASS_STATE_MACHINE]": { + "last_validated_date": "2025-12-03T00:48:39+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.19, + "teardown": 0.0, + "total": 0.19 + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_test_state_machine_scenarios.py::TestStateMachineScenarios::test_base_state_name[INFO-BASE_FAIL_STATE_MACHINE]": { + "last_validated_date": "2025-12-03T00:48:38+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.21, + "teardown": 0.0, + "total": 0.21 + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_test_state_machine_scenarios.py::TestStateMachineScenarios::test_base_state_name[INFO-BASE_MAP_STATE_MACHINE]": { + "last_validated_date": "2025-12-03T00:48:39+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.21, + "teardown": 0.0, + "total": 0.21 + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_test_state_machine_scenarios.py::TestStateMachineScenarios::test_base_state_name[INFO-BASE_PASS_STATE_MACHINE]": { + "last_validated_date": "2025-12-03T00:48:38+00:00", + "durations_in_seconds": { + "setup": 0.5, + "call": 0.6, + "teardown": 0.0, + "total": 1.1 + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_test_state_machine_scenarios.py::TestStateMachineScenarios::test_base_state_name[TRACE-BASE_FAIL_STATE_MACHINE]": { + "last_validated_date": "2025-12-03T00:48:40+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.19, + "teardown": 0.0, + "total": 0.19 + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_test_state_machine_scenarios.py::TestStateMachineScenarios::test_base_state_name[TRACE-BASE_MAP_STATE_MACHINE]": { + "last_validated_date": "2025-12-03T00:48:40+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.2, + "teardown": 0.0, + "total": 0.2 + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_test_state_machine_scenarios.py::TestStateMachineScenarios::test_base_state_name[TRACE-BASE_PASS_STATE_MACHINE]": { + "last_validated_date": "2025-12-03T00:48:39+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.18, + "teardown": 0.0, + "total": 0.18 + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_test_state_machine_scenarios.py::TestStateMachineScenarios::test_base_state_name_multi_state[DEBUG-State0]": { + "last_validated_date": "2025-12-03T00:48:40+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.2, + "teardown": 0.0, + "total": 0.2 + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_test_state_machine_scenarios.py::TestStateMachineScenarios::test_base_state_name_multi_state[DEBUG-State1]": { + "last_validated_date": "2025-12-03T00:48:41+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.27, + "teardown": 0.0, + "total": 0.27 + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_test_state_machine_scenarios.py::TestStateMachineScenarios::test_base_state_name_multi_state[INFO-State0]": { + "last_validated_date": "2025-12-03T00:48:40+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.19, + "teardown": 0.0, + "total": 0.19 + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_test_state_machine_scenarios.py::TestStateMachineScenarios::test_base_state_name_multi_state[INFO-State1]": { + "last_validated_date": "2025-12-03T00:48:40+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.21, + "teardown": 0.0, + "total": 0.21 + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_test_state_machine_scenarios.py::TestStateMachineScenarios::test_base_state_name_multi_state[TRACE-State0]": { + "last_validated_date": "2025-12-03T00:48:41+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.21, + "teardown": 0.0, + "total": 0.21 + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_test_state_machine_scenarios.py::TestStateMachineScenarios::test_base_state_name_multi_state[TRACE-State1]": { + "last_validated_date": "2025-12-03T00:48:41+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.18, + "teardown": 0.0, + "total": 0.18 + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_test_state_machine_scenarios.py::TestStateMachineScenarios::test_base_state_name_validation_failures[dne]": { + "last_validated_date": "2025-12-03T00:48:41+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.2, + "teardown": 0.0, + "total": 0.2 + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_test_state_machine_scenarios.py::TestStateMachineScenarios::test_base_state_name_validation_failures[empty]": { + "last_validated_date": "2025-12-03T00:48:42+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.06, + "teardown": 0.0, + "total": 0.06 + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_test_state_machine_scenarios.py::TestStateMachineScenarios::test_base_state_name_validation_failures[invalid]": { + "last_validated_date": "2025-12-03T00:48:42+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.59, + "teardown": 0.0, + "total": 0.59 + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_test_state_machine_scenarios.py::TestStateMachineScenarios::test_state_name_invalid_state_definition": { + "last_validated_date": "2025-12-04T12:16:39+00:00", + "durations_in_seconds": { + "setup": 0.55, + "call": 0.67, + "teardown": 0.0, + "total": 1.22 + } + } +} diff --git a/tests/aws/services/stepfunctions/v2/test_state/test_test_state_mock_scenarios.py b/tests/aws/services/stepfunctions/v2/test_state/test_test_state_mock_scenarios.py new file mode 100644 index 0000000000000..2bde8b14988aa --- /dev/null +++ b/tests/aws/services/stepfunctions/v2/test_state/test_test_state_mock_scenarios.py @@ -0,0 +1,280 @@ +import json +from datetime import datetime + +import pytest +from localstack_snapshot.snapshots.transformer import JsonpathTransformer, RegexTransformer + +from localstack.aws.api.stepfunctions import InspectionLevel +from localstack.testing.pytest import markers +from localstack.utils.aws import arns +from localstack.utils.strings import long_uid, md5, short_uid +from tests.aws.services.stepfunctions.templates.test_state.test_state_templates import ( + TestStateTemplate as TST, +) + + +class TestStateMockScenarios: + @markers.aws.validated + def test_base_lambda_service_task_mock_is_not_json_string( + self, + aws_client, + aws_client_no_sync_prefix, + sfn_snapshot, + ): + function_name = f"lambda_func_{short_uid()}" + sfn_snapshot.add_transformer(RegexTransformer(function_name, "")) + + template = TST.load_sfn_template(TST.BASE_LAMBDA_SERVICE_TASK_STATE) + definition = json.dumps(template) + exec_input = json.dumps({"FunctionName": function_name, "Payload": None}) + mock = { + "result": "not JSON string", + "fieldValidationMode": "NONE", # the result must be a valid JSON string even if field validation mode is NONE + } + + with pytest.raises(aws_client.stepfunctions.exceptions.ValidationException) as e: + aws_client_no_sync_prefix.stepfunctions.test_state( + definition=definition, + input=exec_input, + inspectionLevel=InspectionLevel.INFO, + mock=mock, + ) + sfn_snapshot.match("validation-exception", e.value.response) + + @markers.aws.validated + def test_base_lambda_service_task_mock_success( + self, + aws_client_no_sync_prefix, + sfn_snapshot, + ): + function_name = f"lambda_func_{short_uid()}" + sfn_snapshot.add_transformer(RegexTransformer(function_name, "")) + + template = TST.load_sfn_template(TST.BASE_LAMBDA_SERVICE_TASK_STATE) + definition = json.dumps(template) + exec_input = json.dumps({"FunctionName": function_name, "Payload": None}) + result = { + # Lambda API spec requires response payload to be a string. + # However, when not mocked, optimized lambda task output is a JSON. + # TODO Clarify whether such transformation is supposed to happen in TestState call as well or there is a caveat. + "Payload": "function output", + "SdkHttpMetadata": {"HttpStatusCode": 200}, + } + mock = {"result": json.dumps(result)} + + test_case_response = aws_client_no_sync_prefix.stepfunctions.test_state( + definition=definition, + input=exec_input, + inspectionLevel=InspectionLevel.INFO, + mock=mock, + ) + sfn_snapshot.match("test_case_response", test_case_response) + + DYNAMODB_TEMPLATES = [ + pytest.param(TST.BASE_DYNAMODB_SERVICE_TASK_STATE, id="base"), + pytest.param(TST.IO_DYNAMODB_SERVICE_TASK_STATE, id="io"), + pytest.param(TST.IO_OUTPUT_PATH_DYNAMODB_SERVICE_TASK_STATE, id="io_output_path"), + ] + + @markers.aws.validated + @pytest.mark.parametrize("template_path", DYNAMODB_TEMPLATES) + def test_io_dynamodb_service_task_mock_success( + self, + aws_client_no_sync_prefix, + sfn_snapshot, + template_path, + ): + table_name = f"sfn_test_table_{short_uid()}" + sfn_snapshot.add_transformer(RegexTransformer(table_name, "")) + + template = TST.load_sfn_template(template_path) + definition = json.dumps(template) + exec_input = json.dumps( + { + "TableName": table_name, + "Item": {"data": {"S": "HelloWorld"}, "id": {"S": "id1"}}, + } + ) + result = {"SdkHttpMetadata": {"HttpStatusCode": 200}} + mock = {"result": json.dumps(result)} + + test_case_response = aws_client_no_sync_prefix.stepfunctions.test_state( + definition=definition, + input=exec_input, + inspectionLevel=InspectionLevel.INFO, + mock=mock, + ) + sfn_snapshot.match("test_case_response", test_case_response) + + @markers.aws.validated + def test_put_events_mock_success( + self, + aws_client_no_sync_prefix, + sfn_snapshot, + ): + template = TST.load_sfn_template(TST.BASE_EVENTS_PUT_EVENTS_TASK_STATE) + definition = json.dumps(template) + + entries = [ + { + "Detail": "detail", + "DetailType": "detail_type", + "Source": "source", + }, + ] + exec_input = json.dumps({"Entries": entries}) + + result = {"Entries": [{"EventId": long_uid()}]} + mock = {"result": json.dumps(result)} + + test_case_response = aws_client_no_sync_prefix.stepfunctions.test_state( + definition=definition, + input=exec_input, + inspectionLevel=InspectionLevel.INFO, + mock=mock, + ) + sfn_snapshot.match("test_case_response", test_case_response) + + @markers.aws.validated + def test_send_sqs_message_success( + self, + aws_client_no_sync_prefix, + sfn_snapshot, + ): + template = TST.load_sfn_template(TST.BASE_SQS_SEND_MESSAGE_TASK_STATE) + definition = json.dumps(template) + + message_body = "message_body" + md5_of_message_body = md5(message_body) + sfn_snapshot.add_transformer(RegexTransformer(md5_of_message_body, "")) + + exec_input = json.dumps({"QueueUrl": "queue_url", "MessageBody": message_body}) + result = {"MD5OfMessageBody": md5_of_message_body, "MessageId": long_uid()} + mock = {"result": json.dumps(result)} + + test_case_response = aws_client_no_sync_prefix.stepfunctions.test_state( + definition=definition, + input=exec_input, + inspectionLevel=InspectionLevel.INFO, + mock=mock, + ) + sfn_snapshot.match("test_case_response", test_case_response) + + INSPECTION_LEVELS = [ + pytest.param(InspectionLevel.INFO, id="INFO"), + pytest.param(InspectionLevel.DEBUG, id="DEBUG"), + pytest.param(InspectionLevel.TRACE, id="TRACE"), + ] + + @markers.aws.validated + @pytest.mark.parametrize("inspection_level", INSPECTION_LEVELS) + def test_base_parallel_state_mock_success( + self, + aws_client_no_sync_prefix, + sfn_snapshot, + inspection_level, + ): + template = TST.load_sfn_template(TST.BASE_PARALLEL_STATE) + definition = json.dumps(template) + exec_input = json.dumps({"key": "value"}) + mock_result = [{"branch1": "result"}, {"branch2": "result"}] + mock = {"result": json.dumps(mock_result)} + + test_case_response = aws_client_no_sync_prefix.stepfunctions.test_state( + definition=definition, + input=exec_input, + inspectionLevel=inspection_level, + mock=mock, + ) + sfn_snapshot.match("test_case_response", test_case_response) + + @markers.aws.validated + @pytest.mark.parametrize("inspection_level", INSPECTION_LEVELS) + def test_io_parallel_state_mock_success( + self, + aws_client_no_sync_prefix, + sfn_snapshot, + inspection_level, + ): + template = TST.load_sfn_template(TST.IO_PARALLEL_STATE) + definition = json.dumps(template) + exec_input = json.dumps({"parallelInput": {"data": "input_value"}}) + mock_result = [{"branch1": "result"}, {"branch2": "result"}] + mock = {"result": json.dumps(mock_result)} + + test_case_response = aws_client_no_sync_prefix.stepfunctions.test_state( + definition=definition, + input=exec_input, + inspectionLevel=inspection_level, + mock=mock, + ) + sfn_snapshot.match("test_case_response", test_case_response) + + @markers.aws.validated + @pytest.mark.parametrize("inspection_level", INSPECTION_LEVELS) + def test_io_jsonata_parallel_state_mock_success( + self, + aws_client_no_sync_prefix, + sfn_snapshot, + inspection_level, + ): + template = TST.load_sfn_template(TST.IO_JSONATA_PARALLEL_STATE) + definition = json.dumps(template) + exec_input = json.dumps({"parallelInput": {"data": "input_value"}}) + mock_result = [{"branch1": "result"}, {"branch2": "result"}] + mock = {"result": json.dumps(mock_result)} + + test_case_response = aws_client_no_sync_prefix.stepfunctions.test_state( + definition=definition, + input=exec_input, + inspectionLevel=inspection_level, + mock=mock, + ) + sfn_snapshot.match("test_case_response", test_case_response) + + @markers.aws.validated + def test_sfn_start_execution_success( + self, + aws_client_no_sync_prefix, + account_id, + region_name, + sfn_snapshot, + ): + sfn_snapshot.add_transformer( + JsonpathTransformer( + jsonpath="$..output..StartDate", + replacement="start-date", + replace_reference=False, + ) + ) + + template = TST.load_sfn_template(TST.BASE_SFN_START_EXECUTION_TASK_STATE) + definition = json.dumps(template) + + target_state_machine_arn = arns.stepfunctions_state_machine_arn( + name="TargetStateMachine", account_id=account_id, region_name=region_name + ) + + target_execution_name = "TestStartTarget" + target_execution_arn = arns.stepfunctions_standard_execution_arn( + target_state_machine_arn, target_execution_name + ) + + exec_input = json.dumps( + { + "stateMachineArn": target_state_machine_arn, + "targetInput": None, + "name": target_execution_name, + } + ) + + result = {"ExecutionArn": target_execution_arn, "StartDate": datetime.now().isoformat()} + mock = {"result": json.dumps(result)} + + test_case_response = aws_client_no_sync_prefix.stepfunctions.test_state( + definition=definition, + input=exec_input, + inspectionLevel=InspectionLevel.INFO, + mock=mock, + ) + sfn_snapshot.match("test_case_response", test_case_response) diff --git a/tests/aws/services/stepfunctions/v2/test_state/test_test_state_mock_scenarios.snapshot.json b/tests/aws/services/stepfunctions/v2/test_state/test_test_state_mock_scenarios.snapshot.json new file mode 100644 index 0000000000000..64904254aa59c --- /dev/null +++ b/tests/aws/services/stepfunctions/v2/test_state/test_test_state_mock_scenarios.snapshot.json @@ -0,0 +1,410 @@ +{ + "tests/aws/services/stepfunctions/v2/test_state/test_test_state_mock_scenarios.py::TestStateMockScenarios::test_base_lambda_service_task_mock_success": { + "recorded-date": "03-12-2025, 00:34:13", + "recorded-content": { + "test_case_response": { + "output": { + "Payload": "function output", + "SdkHttpMetadata": { + "HttpStatusCode": 200 + } + }, + "status": "SUCCEEDED", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_test_state_mock_scenarios.py::TestStateMockScenarios::test_io_dynamodb_service_task_mock_success[base]": { + "recorded-date": "03-12-2025, 00:34:14", + "recorded-content": { + "test_case_response": { + "output": { + "SdkHttpMetadata": { + "HttpStatusCode": 200 + } + }, + "status": "SUCCEEDED", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_test_state_mock_scenarios.py::TestStateMockScenarios::test_io_dynamodb_service_task_mock_success[io]": { + "recorded-date": "03-12-2025, 00:34:14", + "recorded-content": { + "test_case_response": { + "output": { + "TableName": "", + "Item": { + "data": { + "S": "HelloWorld" + }, + "id": { + "S": "id1" + } + }, + "putItemOutput": { + "SdkHttpMetadata": { + "HttpStatusCode": 200 + } + } + }, + "status": "SUCCEEDED", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_test_state_mock_scenarios.py::TestStateMockScenarios::test_io_dynamodb_service_task_mock_success[io_output_path]": { + "recorded-date": "03-12-2025, 00:34:14", + "recorded-content": { + "test_case_response": { + "output": { + "SdkHttpMetadata": { + "HttpStatusCode": 200 + } + }, + "status": "SUCCEEDED", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_test_state_mock_scenarios.py::TestStateMockScenarios::test_put_events_mock_success": { + "recorded-date": "03-12-2025, 00:34:14", + "recorded-content": { + "test_case_response": { + "output": { + "Entries": [ + { + "EventId": "" + } + ] + }, + "status": "SUCCEEDED", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_test_state_mock_scenarios.py::TestStateMockScenarios::test_send_sqs_message_success": { + "recorded-date": "03-12-2025, 00:34:14", + "recorded-content": { + "test_case_response": { + "output": { + "MD5OfMessageBody": "", + "MessageId": "" + }, + "status": "SUCCEEDED", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_test_state_mock_scenarios.py::TestStateMockScenarios::test_sfn_start_execution_success": { + "recorded-date": "03-12-2025, 00:34:15", + "recorded-content": { + "test_case_response": { + "output": { + "targetExecutionResult": { + "ExecutionArn": "arn::states::111111111111:execution:TargetStateMachine:TestStartTarget", + "StartDate": "start-date" + } + }, + "status": "SUCCEEDED", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_test_state_mock_scenarios.py::TestStateMockScenarios::test_base_lambda_service_task_mock_is_not_json_string": { + "recorded-date": "03-12-2025, 00:34:13", + "recorded-content": { + "validation-exception": { + "Error": { + "Code": "ValidationException", + "Message": "Mocked result must be valid JSON" + }, + "message": "Mocked result must be valid JSON", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + } + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_test_state_mock_scenarios.py::TestStateMockScenarios::test_base_parallel_state_mock_success[INFO]": { + "recorded-date": "24-02-2026, 22:49:12", + "recorded-content": { + "test_case_response": { + "output": "[{\"branch1\": \"result\"}, {\"branch2\": \"result\"}]", + "status": "SUCCEEDED", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_test_state_mock_scenarios.py::TestStateMockScenarios::test_base_parallel_state_mock_success[DEBUG]": { + "recorded-date": "24-02-2026, 22:49:12", + "recorded-content": { + "test_case_response": { + "inspectionData": { + "afterResultPath": "[{\"branch1\": \"result\"}, {\"branch2\": \"result\"}]", + "afterResultSelector": "[{\"branch1\": \"result\"}, {\"branch2\": \"result\"}]", + "input": { + "key": "value" + } + }, + "output": "[{\"branch1\": \"result\"}, {\"branch2\": \"result\"}]", + "status": "SUCCEEDED", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_test_state_mock_scenarios.py::TestStateMockScenarios::test_base_parallel_state_mock_success[TRACE]": { + "recorded-date": "24-02-2026, 22:49:12", + "recorded-content": { + "test_case_response": { + "inspectionData": { + "afterResultPath": "[{\"branch1\": \"result\"}, {\"branch2\": \"result\"}]", + "afterResultSelector": "[{\"branch1\": \"result\"}, {\"branch2\": \"result\"}]", + "input": { + "key": "value" + } + }, + "output": "[{\"branch1\": \"result\"}, {\"branch2\": \"result\"}]", + "status": "SUCCEEDED", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_test_state_mock_scenarios.py::TestStateMockScenarios::test_io_parallel_state_mock_success[INFO]": { + "recorded-date": "24-02-2026, 22:49:12", + "recorded-content": { + "test_case_response": { + "output": { + "parallelInput": { + "data": "input_value" + }, + "parallelResult": [ + { + "branch1": "result" + }, + { + "branch2": "result" + } + ] + }, + "status": "SUCCEEDED", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_test_state_mock_scenarios.py::TestStateMockScenarios::test_io_parallel_state_mock_success[DEBUG]": { + "recorded-date": "24-02-2026, 22:49:13", + "recorded-content": { + "test_case_response": { + "inspectionData": { + "afterResultPath": { + "parallelInput": { + "data": "input_value" + }, + "parallelResult": [ + { + "branch1": "result" + }, + { + "branch2": "result" + } + ] + }, + "afterResultSelector": "[{\"branch1\": \"result\"}, {\"branch2\": \"result\"}]", + "input": { + "parallelInput": { + "data": "input_value" + } + } + }, + "output": { + "parallelInput": { + "data": "input_value" + }, + "parallelResult": [ + { + "branch1": "result" + }, + { + "branch2": "result" + } + ] + }, + "status": "SUCCEEDED", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_test_state_mock_scenarios.py::TestStateMockScenarios::test_io_parallel_state_mock_success[TRACE]": { + "recorded-date": "24-02-2026, 22:49:13", + "recorded-content": { + "test_case_response": { + "inspectionData": { + "afterResultPath": { + "parallelInput": { + "data": "input_value" + }, + "parallelResult": [ + { + "branch1": "result" + }, + { + "branch2": "result" + } + ] + }, + "afterResultSelector": "[{\"branch1\": \"result\"}, {\"branch2\": \"result\"}]", + "input": { + "parallelInput": { + "data": "input_value" + } + } + }, + "output": { + "parallelInput": { + "data": "input_value" + }, + "parallelResult": [ + { + "branch1": "result" + }, + { + "branch2": "result" + } + ] + }, + "status": "SUCCEEDED", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_test_state_mock_scenarios.py::TestStateMockScenarios::test_io_jsonata_parallel_state_mock_success[INFO]": { + "recorded-date": "27-02-2026, 09:29:56", + "recorded-content": { + "test_case_response": { + "output": { + "parallelInput": { + "data": "input_value" + }, + "parallelResult": [ + { + "branch1": "result" + }, + { + "branch2": "result" + } + ] + }, + "status": "SUCCEEDED", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_test_state_mock_scenarios.py::TestStateMockScenarios::test_io_jsonata_parallel_state_mock_success[DEBUG]": { + "recorded-date": "27-02-2026, 09:29:57", + "recorded-content": { + "test_case_response": { + "inspectionData": { + "input": { + "parallelInput": { + "data": "input_value" + } + } + }, + "output": { + "parallelInput": { + "data": "input_value" + }, + "parallelResult": [ + { + "branch1": "result" + }, + { + "branch2": "result" + } + ] + }, + "status": "SUCCEEDED", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_test_state_mock_scenarios.py::TestStateMockScenarios::test_io_jsonata_parallel_state_mock_success[TRACE]": { + "recorded-date": "27-02-2026, 09:29:57", + "recorded-content": { + "test_case_response": { + "inspectionData": { + "input": { + "parallelInput": { + "data": "input_value" + } + } + }, + "output": { + "parallelInput": { + "data": "input_value" + }, + "parallelResult": [ + { + "branch1": "result" + }, + { + "branch2": "result" + } + ] + }, + "status": "SUCCEEDED", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + } +} diff --git a/tests/aws/services/stepfunctions/v2/test_state/test_test_state_mock_scenarios.validation.json b/tests/aws/services/stepfunctions/v2/test_state/test_test_state_mock_scenarios.validation.json new file mode 100644 index 0000000000000..507740201862c --- /dev/null +++ b/tests/aws/services/stepfunctions/v2/test_state/test_test_state_mock_scenarios.validation.json @@ -0,0 +1,155 @@ +{ + "tests/aws/services/stepfunctions/v2/test_state/test_test_state_mock_scenarios.py::TestStateMockScenarios::test_base_lambda_service_task_mock_is_not_json_string": { + "last_validated_date": "2026-02-27T10:03:22+00:00", + "durations_in_seconds": { + "setup": 0.52, + "call": 0.62, + "teardown": 0.0, + "total": 1.14 + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_test_state_mock_scenarios.py::TestStateMockScenarios::test_base_lambda_service_task_mock_success": { + "last_validated_date": "2026-02-27T10:03:22+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.21, + "teardown": 0.0, + "total": 0.21 + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_test_state_mock_scenarios.py::TestStateMockScenarios::test_base_parallel_state_mock_success[DEBUG]": { + "last_validated_date": "2026-02-27T10:03:23+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.19, + "teardown": 0.0, + "total": 0.19 + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_test_state_mock_scenarios.py::TestStateMockScenarios::test_base_parallel_state_mock_success[INFO]": { + "last_validated_date": "2026-02-27T10:03:23+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.2, + "teardown": 0.0, + "total": 0.2 + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_test_state_mock_scenarios.py::TestStateMockScenarios::test_base_parallel_state_mock_success[TRACE]": { + "last_validated_date": "2026-02-27T10:03:24+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.35, + "teardown": 0.0, + "total": 0.35 + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_test_state_mock_scenarios.py::TestStateMockScenarios::test_io_dynamodb_service_task_mock_success[base]": { + "last_validated_date": "2026-02-27T10:03:22+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.21, + "teardown": 0.0, + "total": 0.21 + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_test_state_mock_scenarios.py::TestStateMockScenarios::test_io_dynamodb_service_task_mock_success[io]": { + "last_validated_date": "2026-02-27T10:03:22+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.2, + "teardown": 0.0, + "total": 0.2 + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_test_state_mock_scenarios.py::TestStateMockScenarios::test_io_dynamodb_service_task_mock_success[io_output_path]": { + "last_validated_date": "2026-02-27T10:03:23+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.21, + "teardown": 0.0, + "total": 0.21 + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_test_state_mock_scenarios.py::TestStateMockScenarios::test_io_jsonata_parallel_state_mock_success[DEBUG]": { + "last_validated_date": "2026-02-27T10:03:25+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.2, + "teardown": 0.0, + "total": 0.2 + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_test_state_mock_scenarios.py::TestStateMockScenarios::test_io_jsonata_parallel_state_mock_success[INFO]": { + "last_validated_date": "2026-02-27T10:03:25+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.19, + "teardown": 0.0, + "total": 0.19 + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_test_state_mock_scenarios.py::TestStateMockScenarios::test_io_jsonata_parallel_state_mock_success[TRACE]": { + "last_validated_date": "2026-02-27T10:03:25+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.19, + "teardown": 0.0, + "total": 0.19 + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_test_state_mock_scenarios.py::TestStateMockScenarios::test_io_parallel_state_mock_success[DEBUG]": { + "last_validated_date": "2026-02-27T10:03:24+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.25, + "teardown": 0.0, + "total": 0.25 + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_test_state_mock_scenarios.py::TestStateMockScenarios::test_io_parallel_state_mock_success[INFO]": { + "last_validated_date": "2026-02-27T10:03:24+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.2, + "teardown": 0.0, + "total": 0.2 + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_test_state_mock_scenarios.py::TestStateMockScenarios::test_io_parallel_state_mock_success[TRACE]": { + "last_validated_date": "2026-02-27T10:03:24+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.2, + "teardown": 0.0, + "total": 0.2 + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_test_state_mock_scenarios.py::TestStateMockScenarios::test_put_events_mock_success": { + "last_validated_date": "2026-02-27T10:03:23+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.19, + "teardown": 0.0, + "total": 0.19 + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_test_state_mock_scenarios.py::TestStateMockScenarios::test_send_sqs_message_success": { + "last_validated_date": "2026-02-27T10:03:23+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.21, + "teardown": 0.0, + "total": 0.21 + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_test_state_mock_scenarios.py::TestStateMockScenarios::test_sfn_start_execution_success": { + "last_validated_date": "2026-02-27T10:03:25+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.21, + "teardown": 0.0, + "total": 0.21 + } + } +} diff --git a/tests/aws/services/stepfunctions/v2/test_state/test_test_state_scenarios.py b/tests/aws/services/stepfunctions/v2/test_state/test_test_state_scenarios.py index facf99bd57c7a..bfd51262ebeed 100644 --- a/tests/aws/services/stepfunctions/v2/test_state/test_test_state_scenarios.py +++ b/tests/aws/services/stepfunctions/v2/test_state/test_test_state_scenarios.py @@ -7,9 +7,18 @@ from localstack.aws.api.stepfunctions import InspectionLevel from localstack.testing.pytest import markers from localstack.utils.strings import short_uid +from tests.aws.services.stepfunctions.templates.evaluatejsonata.evaluate_jsonata_templates import ( + EvaluateJsonataTemplate as EJT, +) +from tests.aws.services.stepfunctions.templates.outputdecl.output_templates import ( + OutputTemplates as OT, +) from tests.aws.services.stepfunctions.templates.services.services_templates import ( ServicesTemplates as ST, ) +from tests.aws.services.stepfunctions.templates.test_state.test_state_templates import ( + TestStateMachineTemplate as TSMT, +) from tests.aws.services.stepfunctions.templates.test_state.test_state_templates import ( TestStateTemplate as TST, ) @@ -22,6 +31,7 @@ } ) BASE_CHOICE_STATE_INPUT = json.dumps({"type": "Private", "value": 22}) +BASE_MAP_STATE_INPUT = json.dumps({"Values": [1, 2, 3]}) BASE_TEMPLATE_INPUT_BINDINGS: list[tuple[str, str]] = [ (TST.BASE_PASS_STATE, HELLO_WORLD_INPUT), @@ -83,17 +93,6 @@ def test_base_inspection_level_info( sfn_snapshot.match("test_case_response", test_case_response) @markers.aws.validated - @markers.snapshot.skip_snapshot_verify( - paths=[ - # Unknown generalisable behaviour by AWS leads to the outputting of undeclared and - # unsupported state modifiers. Such as ResultSelector, which is neither defined in - # this Pass state, nor supported by Pass states. - "$..inspectionData.afterInputPath", - "$..inspectionData.afterParameters", - "$..inspectionData.afterResultPath", - "$..inspectionData.afterResultSelector", - ] - ) @pytest.mark.parametrize( "tct_template,execution_input", BASE_TEMPLATE_INPUT_BINDINGS, @@ -123,17 +122,6 @@ def test_base_inspection_level_debug( sfn_snapshot.match("test_case_response", test_case_response) @markers.aws.validated - @markers.snapshot.skip_snapshot_verify( - paths=[ - # Unknown generalisable behaviour by AWS leads to the outputting of undeclared and - # unsupported state modifiers. Such as ResultSelector, which is neither defined in - # this Pass state, nor supported by Pass states. - "$..inspectionData.afterInputPath", - "$..inspectionData.afterParameters", - "$..inspectionData.afterResultPath", - "$..inspectionData.afterResultSelector", - ] - ) @pytest.mark.parametrize( "tct_template,execution_input", BASE_TEMPLATE_INPUT_BINDINGS, @@ -163,16 +151,6 @@ def test_base_inspection_level_trace( sfn_snapshot.match("test_case_response", test_case_response) @markers.aws.validated - @markers.snapshot.skip_snapshot_verify( - paths=[ - # Unknown generalisable behaviour by AWS leads to the outputting of undeclared and - # unsupported state modifiers. - "$..inspectionData.afterInputPath", - "$..inspectionData.afterParameters", - "$..inspectionData.afterResultPath", - "$..inspectionData.afterResultSelector", - ] - ) @pytest.mark.parametrize( "inspection_level", [InspectionLevel.INFO, InspectionLevel.DEBUG, InspectionLevel.TRACE] ) @@ -209,14 +187,6 @@ def test_base_lambda_task_state( sfn_snapshot.match("test_case_response", test_case_response) @markers.aws.validated - @markers.snapshot.skip_snapshot_verify( - paths=[ - # Unknown generalisable behaviour by AWS leads to the outputting of undeclared state modifiers. - "$..inspectionData.afterInputPath", - "$..inspectionData.afterResultPath", - "$..inspectionData.afterResultSelector", - ] - ) @pytest.mark.parametrize( "inspection_level", [InspectionLevel.INFO, InspectionLevel.DEBUG, InspectionLevel.TRACE] ) @@ -250,3 +220,248 @@ def test_base_lambda_service_task_state( inspectionLevel=inspection_level, ) sfn_snapshot.match("test_case_response", test_case_response) + + @markers.aws.validated + def test_base_lambda_service_task_state_no_role_arn_validation( + self, + aws_client_no_sync_prefix, + sfn_snapshot, + ): + function_name = f"lambda_func_{short_uid()}" + sfn_snapshot.add_transformer(RegexTransformer(function_name, "")) + + template = TST.load_sfn_template(TST.BASE_LAMBDA_SERVICE_TASK_STATE) + definition = json.dumps(template) + exec_input = json.dumps({"FunctionName": function_name, "Payload": None}) + + with pytest.raises(Exception) as e: + aws_client_no_sync_prefix.stepfunctions.test_state( + definition=definition, + input=exec_input, + inspectionLevel=InspectionLevel.TRACE, + ) + sfn_snapshot.match("validation_exception", e.value.response) + + @markers.aws.validated + @pytest.mark.parametrize( + "inspection_level", [InspectionLevel.INFO, InspectionLevel.DEBUG, InspectionLevel.TRACE] + ) + @pytest.mark.parametrize( + "expression_dict", + [ + {"MaxConcurrency": EJT.JSONATA_NUMBER_EXPRESSION}, + {"ToleratedFailurePercentage": EJT.JSONATA_NUMBER_EXPRESSION}, + {"ToleratedFailureCount": EJT.JSONATA_NUMBER_EXPRESSION}, + ], + ids=[ + "MAX_CONCURRENCY", + "TOLERATED_FAILURE_PERCENTAGE", + "TOLERATED_FAILURE_COUNT", + ], + ) + def test_base_map_state_inspect( + self, + aws_client, + aws_client_no_sync_prefix, + create_state_machine_iam_role, + sfn_snapshot, + expression_dict, + inspection_level, + ): + sfn_snapshot.add_transformer(sfn_snapshot.transform.resource_name()) + + sfn_role_arn = create_state_machine_iam_role(aws_client) + template = TST.load_sfn_template(TST.BASE_MAP_STATE) + template.update(expression_dict) + + definition = json.dumps(template) + + test_case_response = aws_client_no_sync_prefix.stepfunctions.test_state( + definition=definition, + roleArn=sfn_role_arn, + input=BASE_MAP_STATE_INPUT, + inspectionLevel=inspection_level, + mock={"result": json.dumps([1, 1, 1])}, + ) + sfn_snapshot.match("test_case_response", test_case_response) + + @markers.aws.validated + @pytest.mark.parametrize( + "inspection_level", [InspectionLevel.INFO, InspectionLevel.DEBUG, InspectionLevel.TRACE] + ) + def test_state_task_catch_error( + self, + aws_client, + aws_client_no_sync_prefix, + create_state_machine_iam_role, + sfn_snapshot, + inspection_level, + ): + sfn_snapshot.add_transformer(sfn_snapshot.transform.resource_name()) + + sfn_role_arn = create_state_machine_iam_role(aws_client) + template = TST.load_sfn_template(TST.BASE_TASK_STATE_CATCH) + definition = json.dumps(template) + + catch_mock_exception_response = aws_client_no_sync_prefix.stepfunctions.test_state( + definition=definition, + roleArn=sfn_role_arn, + input=HELLO_WORLD_INPUT, + inspectionLevel=inspection_level, + mock={ + "errorOutput": {"error": "MockException", "cause": "Mock the cause of the error."} + }, + ) + + sfn_snapshot.match("test_catch_mock_exception_response", catch_mock_exception_response) + + catch_task_failed_response = aws_client_no_sync_prefix.stepfunctions.test_state( + definition=definition, + roleArn=sfn_role_arn, + input=HELLO_WORLD_INPUT, + inspectionLevel=inspection_level, + mock={"errorOutput": {"error": "States.TaskFailed", "cause": "The task failed."}}, + ) + + sfn_snapshot.match("catch_task_failed_response", catch_task_failed_response) + + @markers.aws.validated + def test_localstack_blogpost_scenario( + self, + aws_client, + aws_client_no_sync_prefix, + sfn_snapshot, + region_name, + ): + template = TSMT.load_sfn_template(TSMT.LOCALSTACK_BLOGPOST_SCENARIO_STATE_MACHINE) + template["States"]["Ask for Approval"]["Arguments"]["ApiEndpoint"] = ( + f"example.execute-api.{region_name}.amazonaws.com" + ) + definition = json.dumps(template) + + # Step 1 - Testing the Approval Required state + # 1.1 Approval Required state correctly approves small purchases + + small_purchase_input = json.dumps({"cost": 9}) + + small_purchase_approval_required_response = ( + aws_client_no_sync_prefix.stepfunctions.test_state( + definition=definition, + input=small_purchase_input, + stateName="Approval Required", + inspectionLevel=InspectionLevel.TRACE, + ) + ) + sfn_snapshot.match( + "small_purchase_approval_required_response", small_purchase_approval_required_response + ) + + # 1.2 Approval Required state correctly sends large purchases to the approval ask process + + large_purchase_input = json.dumps({"cost": 10}) + + large_purchase_approval_required_response = ( + aws_client_no_sync_prefix.stepfunctions.test_state( + definition=definition, + input=large_purchase_input, + stateName="Approval Required", + inspectionLevel=InspectionLevel.TRACE, + ) + ) + sfn_snapshot.match( + "large_purchase_approval_required_response", large_purchase_approval_required_response + ) + + # Step 2 - Testing the Approval Ask state + # Approval Ask state correctly approves large purchases + + large_purchase_input = json.dumps({"cost": 10}) + + large_purchase_ask_for_approval_response = ( + aws_client_no_sync_prefix.stepfunctions.test_state( + definition=definition, + input=large_purchase_input, + stateName="Ask for Approval", + mock={"result": '{"approval": true }'}, + inspectionLevel=InspectionLevel.TRACE, + ) + ) + sfn_snapshot.match( + "large_purchase_ask_for_approval_response", large_purchase_ask_for_approval_response + ) + + # Step 3 - Testing the Check Approval state + # 3.1 Approval granted + + check_approval_granted_input = json.dumps( + {"approval": True, "approval_code": "2387462", "approved_by": "Mary"} + ) + + check_approval_granted_response = aws_client_no_sync_prefix.stepfunctions.test_state( + definition=definition, + input=check_approval_granted_input, + stateName="Check Approval", + inspectionLevel=InspectionLevel.TRACE, + ) + sfn_snapshot.match("check_approval_granted_response", check_approval_granted_response) + + # 3.2 Approval denied + + check_approval_denied_input = json.dumps({"approval": False}) + + check_approval_denied_response = aws_client_no_sync_prefix.stepfunctions.test_state( + definition=definition, + input=check_approval_denied_input, + stateName="Check Approval", + inspectionLevel=InspectionLevel.TRACE, + ) + sfn_snapshot.match("check_approval_denied_response", check_approval_denied_response) + + TEMPLATES_VARIABLES = [ + pytest.param( + ( + OT.BASE_EXPR, + { + "var_input_value": "test_value", + "var_constant_1": 10, + }, + ), + id="base_expressions", + ), + pytest.param((OT.BASE_LITERALS, {}), id="empty_variables"), + ] + + @pytest.mark.parametrize("templates_variables", TEMPLATES_VARIABLES) + @markers.aws.validated + @markers.snapshot.skip_snapshot_verify( + paths=[ + "$..RoleArn", # needed until optional roleArn is introduced for test state, see comment in provider implementation. + "$..output.ja_states_context.State.Name", # currently, test state returns "StateName" as a state name in AWS. We return actual state name. Adding to skip as not worth a special condition in the code + ] + ) + def test_state_with_variables( + self, + aws_client_no_sync_prefix, + sfn_snapshot, + templates_variables, + ): + sfn_snapshot.add_transformer( + sfn_snapshot.transform.key_value("RoleArn", "role-arn", reference_replacement=False) + ) # roleArn is null in AWS but is not null in LocalStack, see comment in provider implementation. If this transformer is not added then roleArn is picked up as another resource name in LocalStack, causing resource placeholders mismatch, e.g. where is expected. + sfn_snapshot.add_transformer(sfn_snapshot.transform.resource_name()) + template_path, variables_raw = templates_variables + template = OT.load_sfn_template(template_path) + + definition = json.dumps(template) + + exec_input = json.dumps({"input_values": [1, 2, 3]}) + variables = json.dumps(variables_raw) + + test_case_response = aws_client_no_sync_prefix.stepfunctions.test_state( + definition=definition, + stateName="State0", + input=exec_input, + variables=variables, + inspectionLevel=InspectionLevel.TRACE, + ) + sfn_snapshot.match("test_case_response", test_case_response) diff --git a/tests/aws/services/stepfunctions/v2/test_state/test_test_state_scenarios.snapshot.json b/tests/aws/services/stepfunctions/v2/test_state/test_test_state_scenarios.snapshot.json index 1e11cdcc339f2..a70b54e455d41 100644 --- a/tests/aws/services/stepfunctions/v2/test_state/test_test_state_scenarios.snapshot.json +++ b/tests/aws/services/stepfunctions/v2/test_state/test_test_state_scenarios.snapshot.json @@ -1,6 +1,6 @@ { "tests/aws/services/stepfunctions/v2/test_state/test_test_state_scenarios.py::TestStateCaseScenarios::test_base_inspection_level_info[BASE_PASS_STATE]": { - "recorded-date": "12-04-2024, 20:45:35", + "recorded-date": "14-11-2025, 16:38:49", "recorded-content": { "test_case_response": { "output": { @@ -15,7 +15,7 @@ } }, "tests/aws/services/stepfunctions/v2/test_state/test_test_state_scenarios.py::TestStateCaseScenarios::test_base_inspection_level_info[BASE_RESULT_PASS_STATE]": { - "recorded-date": "12-04-2024, 20:45:49", + "recorded-date": "14-11-2025, 16:39:04", "recorded-content": { "test_case_response": { "output": { @@ -30,7 +30,7 @@ } }, "tests/aws/services/stepfunctions/v2/test_state/test_test_state_scenarios.py::TestStateCaseScenarios::test_base_inspection_level_info[IO_PASS_STATE]": { - "recorded-date": "12-04-2024, 20:46:03", + "recorded-date": "14-11-2025, 16:39:19", "recorded-content": { "test_case_response": { "output": { @@ -55,7 +55,7 @@ } }, "tests/aws/services/stepfunctions/v2/test_state/test_test_state_scenarios.py::TestStateCaseScenarios::test_base_inspection_level_info[IO_RESULT_PASS_STATE]": { - "recorded-date": "12-04-2024, 20:46:15", + "recorded-date": "14-11-2025, 16:39:34", "recorded-content": { "test_case_response": { "output": { @@ -79,7 +79,7 @@ } }, "tests/aws/services/stepfunctions/v2/test_state/test_test_state_scenarios.py::TestStateCaseScenarios::test_base_inspection_level_info[BASE_FAIL_STATE]": { - "recorded-date": "12-04-2024, 20:46:28", + "recorded-date": "14-11-2025, 16:39:49", "recorded-content": { "test_case_response": { "cause": "This state machines raises a 'SomeFailure' failure.", @@ -93,7 +93,7 @@ } }, "tests/aws/services/stepfunctions/v2/test_state/test_test_state_scenarios.py::TestStateCaseScenarios::test_base_inspection_level_info[BASE_SUCCEED_STATE]": { - "recorded-date": "12-04-2024, 20:46:41", + "recorded-date": "14-11-2025, 16:40:09", "recorded-content": { "test_case_response": { "output": { @@ -108,7 +108,7 @@ } }, "tests/aws/services/stepfunctions/v2/test_state/test_test_state_scenarios.py::TestStateCaseScenarios::test_base_inspection_level_info[BASE_CHOICE_STATE]": { - "recorded-date": "12-04-2024, 20:46:53", + "recorded-date": "14-11-2025, 16:40:25", "recorded-content": { "test_case_response": { "nextState": "ValueInTwenties", @@ -125,7 +125,7 @@ } }, "tests/aws/services/stepfunctions/v2/test_state/test_test_state_scenarios.py::TestStateCaseScenarios::test_base_inspection_level_debug[BASE_PASS_STATE]": { - "recorded-date": "12-04-2024, 20:47:06", + "recorded-date": "14-11-2025, 16:40:40", "recorded-content": { "test_case_response": { "inspectionData": { @@ -157,7 +157,7 @@ } }, "tests/aws/services/stepfunctions/v2/test_state/test_test_state_scenarios.py::TestStateCaseScenarios::test_base_inspection_level_debug[BASE_RESULT_PASS_STATE]": { - "recorded-date": "12-04-2024, 20:47:19", + "recorded-date": "14-11-2025, 16:40:54", "recorded-content": { "test_case_response": { "inspectionData": { @@ -186,7 +186,7 @@ } }, "tests/aws/services/stepfunctions/v2/test_state/test_test_state_scenarios.py::TestStateCaseScenarios::test_base_inspection_level_debug[IO_PASS_STATE]": { - "recorded-date": "12-04-2024, 20:47:31", + "recorded-date": "14-11-2025, 16:41:09", "recorded-content": { "test_case_response": { "inspectionData": { @@ -247,7 +247,7 @@ } }, "tests/aws/services/stepfunctions/v2/test_state/test_test_state_scenarios.py::TestStateCaseScenarios::test_base_inspection_level_debug[IO_RESULT_PASS_STATE]": { - "recorded-date": "12-04-2024, 20:47:44", + "recorded-date": "14-11-2025, 16:41:23", "recorded-content": { "test_case_response": { "inspectionData": { @@ -300,7 +300,7 @@ } }, "tests/aws/services/stepfunctions/v2/test_state/test_test_state_scenarios.py::TestStateCaseScenarios::test_base_inspection_level_debug[BASE_FAIL_STATE]": { - "recorded-date": "12-04-2024, 20:47:56", + "recorded-date": "14-11-2025, 16:41:38", "recorded-content": { "test_case_response": { "cause": "This state machines raises a 'SomeFailure' failure.", @@ -322,7 +322,7 @@ } }, "tests/aws/services/stepfunctions/v2/test_state/test_test_state_scenarios.py::TestStateCaseScenarios::test_base_inspection_level_debug[BASE_SUCCEED_STATE]": { - "recorded-date": "12-04-2024, 20:48:10", + "recorded-date": "14-11-2025, 16:41:59", "recorded-content": { "test_case_response": { "inspectionData": { @@ -345,7 +345,7 @@ } }, "tests/aws/services/stepfunctions/v2/test_state/test_test_state_scenarios.py::TestStateCaseScenarios::test_base_inspection_level_debug[BASE_CHOICE_STATE]": { - "recorded-date": "12-04-2024, 20:48:24", + "recorded-date": "14-11-2025, 16:42:14", "recorded-content": { "test_case_response": { "inspectionData": { @@ -372,7 +372,7 @@ } }, "tests/aws/services/stepfunctions/v2/test_state/test_test_state_scenarios.py::TestStateCaseScenarios::test_base_inspection_level_trace[BASE_PASS_STATE]": { - "recorded-date": "12-04-2024, 20:48:37", + "recorded-date": "14-11-2025, 16:42:30", "recorded-content": { "test_case_response": { "inspectionData": { @@ -404,7 +404,7 @@ } }, "tests/aws/services/stepfunctions/v2/test_state/test_test_state_scenarios.py::TestStateCaseScenarios::test_base_inspection_level_trace[BASE_RESULT_PASS_STATE]": { - "recorded-date": "12-04-2024, 20:48:50", + "recorded-date": "14-11-2025, 16:42:45", "recorded-content": { "test_case_response": { "inspectionData": { @@ -433,7 +433,7 @@ } }, "tests/aws/services/stepfunctions/v2/test_state/test_test_state_scenarios.py::TestStateCaseScenarios::test_base_inspection_level_trace[IO_PASS_STATE]": { - "recorded-date": "12-04-2024, 20:49:03", + "recorded-date": "14-11-2025, 16:43:00", "recorded-content": { "test_case_response": { "inspectionData": { @@ -494,7 +494,7 @@ } }, "tests/aws/services/stepfunctions/v2/test_state/test_test_state_scenarios.py::TestStateCaseScenarios::test_base_inspection_level_trace[IO_RESULT_PASS_STATE]": { - "recorded-date": "12-04-2024, 20:49:22", + "recorded-date": "14-11-2025, 16:43:16", "recorded-content": { "test_case_response": { "inspectionData": { @@ -547,7 +547,7 @@ } }, "tests/aws/services/stepfunctions/v2/test_state/test_test_state_scenarios.py::TestStateCaseScenarios::test_base_inspection_level_trace[BASE_FAIL_STATE]": { - "recorded-date": "12-04-2024, 20:49:31", + "recorded-date": "14-11-2025, 16:43:31", "recorded-content": { "test_case_response": { "cause": "This state machines raises a 'SomeFailure' failure.", @@ -569,7 +569,7 @@ } }, "tests/aws/services/stepfunctions/v2/test_state/test_test_state_scenarios.py::TestStateCaseScenarios::test_base_inspection_level_trace[BASE_SUCCEED_STATE]": { - "recorded-date": "12-04-2024, 20:49:44", + "recorded-date": "14-11-2025, 16:43:45", "recorded-content": { "test_case_response": { "inspectionData": { @@ -592,7 +592,7 @@ } }, "tests/aws/services/stepfunctions/v2/test_state/test_test_state_scenarios.py::TestStateCaseScenarios::test_base_inspection_level_trace[BASE_CHOICE_STATE]": { - "recorded-date": "12-04-2024, 20:49:57", + "recorded-date": "14-11-2025, 16:44:00", "recorded-content": { "test_case_response": { "inspectionData": { @@ -619,7 +619,7 @@ } }, "tests/aws/services/stepfunctions/v2/test_state/test_test_state_scenarios.py::TestStateCaseScenarios::test_base_lambda_task_state[INFO]": { - "recorded-date": "12-04-2024, 20:50:22", + "recorded-date": "14-11-2025, 16:44:29", "recorded-content": { "test_case_response": { "output": "\"HelloWorld!\"", @@ -632,7 +632,7 @@ } }, "tests/aws/services/stepfunctions/v2/test_state/test_test_state_scenarios.py::TestStateCaseScenarios::test_base_lambda_task_state[DEBUG]": { - "recorded-date": "12-04-2024, 20:50:37", + "recorded-date": "14-11-2025, 16:44:48", "recorded-content": { "test_case_response": { "inspectionData": { @@ -659,7 +659,7 @@ } }, "tests/aws/services/stepfunctions/v2/test_state/test_test_state_scenarios.py::TestStateCaseScenarios::test_base_lambda_task_state[TRACE]": { - "recorded-date": "12-04-2024, 20:50:52", + "recorded-date": "14-11-2025, 16:45:08", "recorded-content": { "test_case_response": { "inspectionData": { @@ -686,7 +686,7 @@ } }, "tests/aws/services/stepfunctions/v2/test_state/test_test_state_scenarios.py::TestStateCaseScenarios::test_base_lambda_service_task_state[INFO]": { - "recorded-date": "12-04-2024, 20:51:07", + "recorded-date": "14-11-2025, 16:45:27", "recorded-content": { "test_case_response": { "output": { @@ -703,9 +703,7 @@ "Connection": [ "keep-alive" ], - "x-amzn-RequestId": [ - "" - ], + "x-amzn-RequestId": "x-amzn-RequestId", "Content-Length": [ "2" ], @@ -722,13 +720,13 @@ "Date": "date", "X-Amz-Executed-Version": "$LATEST", "x-amzn-Remapped-Content-Length": "0", - "x-amzn-RequestId": "", + "x-amzn-RequestId": "x-amzn-RequestId", "X-Amzn-Trace-Id": "X-Amzn-Trace-Id" }, "HttpStatusCode": 200 }, "SdkResponseMetadata": { - "RequestId": "" + "RequestId": "RequestId" }, "StatusCode": 200 }, @@ -741,7 +739,7 @@ } }, "tests/aws/services/stepfunctions/v2/test_state/test_test_state_scenarios.py::TestStateCaseScenarios::test_base_lambda_service_task_state[DEBUG]": { - "recorded-date": "12-04-2024, 20:51:22", + "recorded-date": "14-11-2025, 16:45:46", "recorded-content": { "test_case_response": { "inspectionData": { @@ -767,9 +765,7 @@ "Connection": [ "keep-alive" ], - "x-amzn-RequestId": [ - "" - ], + "x-amzn-RequestId": "x-amzn-RequestId", "Content-Length": [ "2" ], @@ -786,13 +782,13 @@ "Date": "date", "X-Amz-Executed-Version": "$LATEST", "x-amzn-Remapped-Content-Length": "0", - "x-amzn-RequestId": "", + "x-amzn-RequestId": "x-amzn-RequestId", "X-Amzn-Trace-Id": "X-Amzn-Trace-Id" }, "HttpStatusCode": 200 }, "SdkResponseMetadata": { - "RequestId": "" + "RequestId": "RequestId" }, "StatusCode": 200 }, @@ -810,9 +806,7 @@ "Connection": [ "keep-alive" ], - "x-amzn-RequestId": [ - "" - ], + "x-amzn-RequestId": "x-amzn-RequestId", "Content-Length": [ "2" ], @@ -829,13 +823,13 @@ "Date": "date", "X-Amz-Executed-Version": "$LATEST", "x-amzn-Remapped-Content-Length": "0", - "x-amzn-RequestId": "", + "x-amzn-RequestId": "x-amzn-RequestId", "X-Amzn-Trace-Id": "X-Amzn-Trace-Id" }, "HttpStatusCode": 200 }, "SdkResponseMetadata": { - "RequestId": "" + "RequestId": "RequestId" }, "StatusCode": 200 }, @@ -857,9 +851,7 @@ "Connection": [ "keep-alive" ], - "x-amzn-RequestId": [ - "" - ], + "x-amzn-RequestId": "x-amzn-RequestId", "Content-Length": [ "2" ], @@ -876,13 +868,13 @@ "Date": "date", "X-Amz-Executed-Version": "$LATEST", "x-amzn-Remapped-Content-Length": "0", - "x-amzn-RequestId": "", + "x-amzn-RequestId": "x-amzn-RequestId", "X-Amzn-Trace-Id": "X-Amzn-Trace-Id" }, "HttpStatusCode": 200 }, "SdkResponseMetadata": { - "RequestId": "" + "RequestId": "RequestId" }, "StatusCode": 200 } @@ -901,9 +893,7 @@ "Connection": [ "keep-alive" ], - "x-amzn-RequestId": [ - "" - ], + "x-amzn-RequestId": "x-amzn-RequestId", "Content-Length": [ "2" ], @@ -920,13 +910,13 @@ "Date": "date", "X-Amz-Executed-Version": "$LATEST", "x-amzn-Remapped-Content-Length": "0", - "x-amzn-RequestId": "", + "x-amzn-RequestId": "x-amzn-RequestId", "X-Amzn-Trace-Id": "X-Amzn-Trace-Id" }, "HttpStatusCode": 200 }, "SdkResponseMetadata": { - "RequestId": "" + "RequestId": "RequestId" }, "StatusCode": 200 }, @@ -939,7 +929,7 @@ } }, "tests/aws/services/stepfunctions/v2/test_state/test_test_state_scenarios.py::TestStateCaseScenarios::test_base_lambda_service_task_state[TRACE]": { - "recorded-date": "12-04-2024, 20:51:37", + "recorded-date": "14-11-2025, 16:46:06", "recorded-content": { "test_case_response": { "inspectionData": { @@ -965,9 +955,7 @@ "Connection": [ "keep-alive" ], - "x-amzn-RequestId": [ - "" - ], + "x-amzn-RequestId": "x-amzn-RequestId", "Content-Length": [ "2" ], @@ -984,13 +972,13 @@ "Date": "date", "X-Amz-Executed-Version": "$LATEST", "x-amzn-Remapped-Content-Length": "0", - "x-amzn-RequestId": "", + "x-amzn-RequestId": "x-amzn-RequestId", "X-Amzn-Trace-Id": "X-Amzn-Trace-Id" }, "HttpStatusCode": 200 }, "SdkResponseMetadata": { - "RequestId": "" + "RequestId": "RequestId" }, "StatusCode": 200 }, @@ -1008,9 +996,7 @@ "Connection": [ "keep-alive" ], - "x-amzn-RequestId": [ - "" - ], + "x-amzn-RequestId": "x-amzn-RequestId", "Content-Length": [ "2" ], @@ -1027,13 +1013,13 @@ "Date": "date", "X-Amz-Executed-Version": "$LATEST", "x-amzn-Remapped-Content-Length": "0", - "x-amzn-RequestId": "", + "x-amzn-RequestId": "x-amzn-RequestId", "X-Amzn-Trace-Id": "X-Amzn-Trace-Id" }, "HttpStatusCode": 200 }, "SdkResponseMetadata": { - "RequestId": "" + "RequestId": "RequestId" }, "StatusCode": 200 }, @@ -1055,9 +1041,7 @@ "Connection": [ "keep-alive" ], - "x-amzn-RequestId": [ - "" - ], + "x-amzn-RequestId": "x-amzn-RequestId", "Content-Length": [ "2" ], @@ -1074,13 +1058,13 @@ "Date": "date", "X-Amz-Executed-Version": "$LATEST", "x-amzn-Remapped-Content-Length": "0", - "x-amzn-RequestId": "", + "x-amzn-RequestId": "x-amzn-RequestId", "X-Amzn-Trace-Id": "X-Amzn-Trace-Id" }, "HttpStatusCode": 200 }, "SdkResponseMetadata": { - "RequestId": "" + "RequestId": "RequestId" }, "StatusCode": 200 } @@ -1099,9 +1083,7 @@ "Connection": [ "keep-alive" ], - "x-amzn-RequestId": [ - "" - ], + "x-amzn-RequestId": "x-amzn-RequestId", "Content-Length": [ "2" ], @@ -1118,13 +1100,13 @@ "Date": "date", "X-Amz-Executed-Version": "$LATEST", "x-amzn-Remapped-Content-Length": "0", - "x-amzn-RequestId": "", + "x-amzn-RequestId": "x-amzn-RequestId", "X-Amzn-Trace-Id": "X-Amzn-Trace-Id" }, "HttpStatusCode": 200 }, "SdkResponseMetadata": { - "RequestId": "" + "RequestId": "RequestId" }, "StatusCode": 200 }, @@ -1135,5 +1117,1258 @@ } } } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_test_state_scenarios.py::TestStateCaseScenarios::test_base_map_state_inspect_trace[MAX_CONCURRENCY]": { + "recorded-date": "12-11-2025, 15:25:18", + "recorded-content": { + "test_case_response": { + "inspectionData": { + "input": { + "Values": [ + 1, + 2, + 3 + ] + }, + "maxConcurrency": 1 + }, + "output": { + "input": { + "Values": [ + 1, + 2, + 3 + ] + }, + "context": { + "Execution": { + "Id": "arn::states::111111111111:express::", + "Input": { + "Values": [ + 1, + 2, + 3 + ] + }, + "Name": "", + "RoleArn": "arn::iam::111111111111:role/", + "StartTime": "date" + }, + "StateMachine": { + "Id": "arn::states::111111111111:stateMachine:", + "Name": "" + }, + "State": { + "Name": "StateName", + "EnteredTime": "date", + "RetryCount": 0 + } + }, + "result": [ + 1, + 1, + 1 + ] + }, + "status": "SUCCEEDED", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_test_state_scenarios.py::TestStateCaseScenarios::test_base_map_state_inspect_trace[TOLERATED_FAILURE_PERCENTAGE]": { + "recorded-date": "12-11-2025, 14:19:49", + "recorded-content": { + "test_case_response": { + "inspectionData": { + "input": { + "Values": [ + 1, + 2, + 3 + ] + }, + "maxConcurrency": 0, + "toleratedFailurePercentage": 1.0 + }, + "output": { + "input": { + "Values": [ + 1, + 2, + 3 + ] + }, + "context": { + "Execution": { + "Id": "arn::states::111111111111:express::", + "Input": { + "Values": [ + 1, + 2, + 3 + ] + }, + "Name": "", + "RoleArn": "arn::iam::111111111111:role/", + "StartTime": "date" + }, + "StateMachine": { + "Id": "arn::states::111111111111:stateMachine:", + "Name": "" + }, + "State": { + "Name": "StateName", + "EnteredTime": "date", + "RetryCount": 0 + } + }, + "result": [ + 1, + 1, + 1 + ] + }, + "status": "SUCCEEDED", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_test_state_scenarios.py::TestStateCaseScenarios::test_base_map_state_inspect_trace[TOLERATED_FAILURE_COUNT]": { + "recorded-date": "12-11-2025, 14:20:04", + "recorded-content": { + "test_case_response": { + "inspectionData": { + "input": { + "Values": [ + 1, + 2, + 3 + ] + }, + "maxConcurrency": 0, + "toleratedFailureCount": 1 + }, + "output": { + "input": { + "Values": [ + 1, + 2, + 3 + ] + }, + "context": { + "Execution": { + "Id": "arn::states::111111111111:express::", + "Input": { + "Values": [ + 1, + 2, + 3 + ] + }, + "Name": "", + "RoleArn": "arn::iam::111111111111:role/", + "StartTime": "date" + }, + "StateMachine": { + "Id": "arn::states::111111111111:stateMachine:", + "Name": "" + }, + "State": { + "Name": "StateName", + "EnteredTime": "date", + "RetryCount": 0 + } + }, + "result": [ + 1, + 1, + 1 + ] + }, + "status": "SUCCEEDED", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_test_state_scenarios.py::TestStateCaseScenarios::test_base_inspection_level_info[BASE_MAP_STATE]": { + "recorded-date": "13-11-2025, 11:02:39", + "recorded-content": {} + }, + "tests/aws/services/stepfunctions/v2/test_state/test_test_state_scenarios.py::TestStateCaseScenarios::test_base_map_state_inspect[MAX_CONCURRENCY-INFO]": { + "recorded-date": "14-11-2025, 16:46:24", + "recorded-content": { + "test_case_response": { + "output": { + "input": { + "Values": [ + 1, + 2, + 3 + ] + }, + "context": { + "Execution": { + "Id": "arn::states::111111111111:express::", + "Input": { + "Values": [ + 1, + 2, + 3 + ] + }, + "Name": "", + "RoleArn": "arn::iam::111111111111:role/", + "StartTime": "date" + }, + "StateMachine": { + "Id": "arn::states::111111111111:stateMachine:", + "Name": "" + }, + "State": { + "Name": "StateName", + "EnteredTime": "date", + "RetryCount": 0 + } + }, + "result": [ + 1, + 1, + 1 + ] + }, + "status": "SUCCEEDED", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_test_state_scenarios.py::TestStateCaseScenarios::test_base_map_state_inspect[MAX_CONCURRENCY-DEBUG]": { + "recorded-date": "14-11-2025, 16:46:39", + "recorded-content": { + "test_case_response": { + "inspectionData": { + "input": { + "Values": [ + 1, + 2, + 3 + ] + }, + "maxConcurrency": 1 + }, + "output": { + "input": { + "Values": [ + 1, + 2, + 3 + ] + }, + "context": { + "Execution": { + "Id": "arn::states::111111111111:express::", + "Input": { + "Values": [ + 1, + 2, + 3 + ] + }, + "Name": "", + "RoleArn": "arn::iam::111111111111:role/", + "StartTime": "date" + }, + "StateMachine": { + "Id": "arn::states::111111111111:stateMachine:", + "Name": "" + }, + "State": { + "Name": "StateName", + "EnteredTime": "date", + "RetryCount": 0 + } + }, + "result": [ + 1, + 1, + 1 + ] + }, + "status": "SUCCEEDED", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_test_state_scenarios.py::TestStateCaseScenarios::test_base_map_state_inspect[MAX_CONCURRENCY-TRACE]": { + "recorded-date": "14-11-2025, 16:46:54", + "recorded-content": { + "test_case_response": { + "inspectionData": { + "input": { + "Values": [ + 1, + 2, + 3 + ] + }, + "maxConcurrency": 1 + }, + "output": { + "input": { + "Values": [ + 1, + 2, + 3 + ] + }, + "context": { + "Execution": { + "Id": "arn::states::111111111111:express::", + "Input": { + "Values": [ + 1, + 2, + 3 + ] + }, + "Name": "", + "RoleArn": "arn::iam::111111111111:role/", + "StartTime": "date" + }, + "StateMachine": { + "Id": "arn::states::111111111111:stateMachine:", + "Name": "" + }, + "State": { + "Name": "StateName", + "EnteredTime": "date", + "RetryCount": 0 + } + }, + "result": [ + 1, + 1, + 1 + ] + }, + "status": "SUCCEEDED", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_test_state_scenarios.py::TestStateCaseScenarios::test_base_map_state_inspect[TOLERATED_FAILURE_PERCENTAGE-INFO]": { + "recorded-date": "14-11-2025, 16:47:08", + "recorded-content": { + "test_case_response": { + "output": { + "input": { + "Values": [ + 1, + 2, + 3 + ] + }, + "context": { + "Execution": { + "Id": "arn::states::111111111111:express::", + "Input": { + "Values": [ + 1, + 2, + 3 + ] + }, + "Name": "", + "RoleArn": "arn::iam::111111111111:role/", + "StartTime": "date" + }, + "StateMachine": { + "Id": "arn::states::111111111111:stateMachine:", + "Name": "" + }, + "State": { + "Name": "StateName", + "EnteredTime": "date", + "RetryCount": 0 + } + }, + "result": [ + 1, + 1, + 1 + ] + }, + "status": "SUCCEEDED", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_test_state_scenarios.py::TestStateCaseScenarios::test_base_map_state_inspect[TOLERATED_FAILURE_PERCENTAGE-DEBUG]": { + "recorded-date": "14-11-2025, 16:47:23", + "recorded-content": { + "test_case_response": { + "inspectionData": { + "input": { + "Values": [ + 1, + 2, + 3 + ] + }, + "maxConcurrency": 0, + "toleratedFailurePercentage": 1.0 + }, + "output": { + "input": { + "Values": [ + 1, + 2, + 3 + ] + }, + "context": { + "Execution": { + "Id": "arn::states::111111111111:express::", + "Input": { + "Values": [ + 1, + 2, + 3 + ] + }, + "Name": "", + "RoleArn": "arn::iam::111111111111:role/", + "StartTime": "date" + }, + "StateMachine": { + "Id": "arn::states::111111111111:stateMachine:", + "Name": "" + }, + "State": { + "Name": "StateName", + "EnteredTime": "date", + "RetryCount": 0 + } + }, + "result": [ + 1, + 1, + 1 + ] + }, + "status": "SUCCEEDED", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_test_state_scenarios.py::TestStateCaseScenarios::test_base_map_state_inspect[TOLERATED_FAILURE_PERCENTAGE-TRACE]": { + "recorded-date": "14-11-2025, 16:47:38", + "recorded-content": { + "test_case_response": { + "inspectionData": { + "input": { + "Values": [ + 1, + 2, + 3 + ] + }, + "maxConcurrency": 0, + "toleratedFailurePercentage": 1.0 + }, + "output": { + "input": { + "Values": [ + 1, + 2, + 3 + ] + }, + "context": { + "Execution": { + "Id": "arn::states::111111111111:express::", + "Input": { + "Values": [ + 1, + 2, + 3 + ] + }, + "Name": "", + "RoleArn": "arn::iam::111111111111:role/", + "StartTime": "date" + }, + "StateMachine": { + "Id": "arn::states::111111111111:stateMachine:", + "Name": "" + }, + "State": { + "Name": "StateName", + "EnteredTime": "date", + "RetryCount": 0 + } + }, + "result": [ + 1, + 1, + 1 + ] + }, + "status": "SUCCEEDED", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_test_state_scenarios.py::TestStateCaseScenarios::test_base_map_state_inspect[TOLERATED_FAILURE_COUNT-INFO]": { + "recorded-date": "14-11-2025, 16:47:54", + "recorded-content": { + "test_case_response": { + "output": { + "input": { + "Values": [ + 1, + 2, + 3 + ] + }, + "context": { + "Execution": { + "Id": "arn::states::111111111111:express::", + "Input": { + "Values": [ + 1, + 2, + 3 + ] + }, + "Name": "", + "RoleArn": "arn::iam::111111111111:role/", + "StartTime": "date" + }, + "StateMachine": { + "Id": "arn::states::111111111111:stateMachine:", + "Name": "" + }, + "State": { + "Name": "StateName", + "EnteredTime": "date", + "RetryCount": 0 + } + }, + "result": [ + 1, + 1, + 1 + ] + }, + "status": "SUCCEEDED", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_test_state_scenarios.py::TestStateCaseScenarios::test_base_map_state_inspect[TOLERATED_FAILURE_COUNT-DEBUG]": { + "recorded-date": "14-11-2025, 16:48:09", + "recorded-content": { + "test_case_response": { + "inspectionData": { + "input": { + "Values": [ + 1, + 2, + 3 + ] + }, + "maxConcurrency": 0, + "toleratedFailureCount": 1 + }, + "output": { + "input": { + "Values": [ + 1, + 2, + 3 + ] + }, + "context": { + "Execution": { + "Id": "arn::states::111111111111:express::", + "Input": { + "Values": [ + 1, + 2, + 3 + ] + }, + "Name": "", + "RoleArn": "arn::iam::111111111111:role/", + "StartTime": "date" + }, + "StateMachine": { + "Id": "arn::states::111111111111:stateMachine:", + "Name": "" + }, + "State": { + "Name": "StateName", + "EnteredTime": "date", + "RetryCount": 0 + } + }, + "result": [ + 1, + 1, + 1 + ] + }, + "status": "SUCCEEDED", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_test_state_scenarios.py::TestStateCaseScenarios::test_base_map_state_inspect[TOLERATED_FAILURE_COUNT-TRACE]": { + "recorded-date": "14-11-2025, 16:48:24", + "recorded-content": { + "test_case_response": { + "inspectionData": { + "input": { + "Values": [ + 1, + 2, + 3 + ] + }, + "maxConcurrency": 0, + "toleratedFailureCount": 1 + }, + "output": { + "input": { + "Values": [ + 1, + 2, + 3 + ] + }, + "context": { + "Execution": { + "Id": "arn::states::111111111111:express::", + "Input": { + "Values": [ + 1, + 2, + 3 + ] + }, + "Name": "", + "RoleArn": "arn::iam::111111111111:role/", + "StartTime": "date" + }, + "StateMachine": { + "Id": "arn::states::111111111111:stateMachine:", + "Name": "" + }, + "State": { + "Name": "StateName", + "EnteredTime": "date", + "RetryCount": 0 + } + }, + "result": [ + 1, + 1, + 1 + ] + }, + "status": "SUCCEEDED", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_test_state_scenarios.py::TestStateCaseScenarios::test_state_task_catch_error[INFO]": { + "recorded-date": "21-11-2025, 13:59:35", + "recorded-content": { + "test_catch_mock_exception_response": { + "cause": "Mock the cause of the error.", + "error": "MockException", + "nextState": "HandleMockError", + "output": { + "input": { + "Value": "HelloWorld" + }, + "context": { + "Execution": { + "Id": "arn::states::111111111111:express::", + "Input": { + "Value": "HelloWorld" + }, + "Name": "", + "RoleArn": "arn::iam::111111111111:role/", + "StartTime": "date" + }, + "StateMachine": { + "Id": "arn::states::111111111111:stateMachine:", + "Name": "" + }, + "State": { + "Name": "StateName", + "EnteredTime": "date", + "RetryCount": 0 + } + }, + "errorOutput": { + "Error": "MockException", + "Cause": "Mock the cause of the error." + } + }, + "status": "CAUGHT_ERROR", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "catch_task_failed_response": { + "cause": "The task failed.", + "error": "States.TaskFailed", + "nextState": "HandleThreshold", + "output": { + "input": { + "Value": "HelloWorld" + }, + "context": { + "Execution": { + "Id": "arn::states::111111111111:express::", + "Input": { + "Value": "HelloWorld" + }, + "Name": "", + "RoleArn": "arn::iam::111111111111:role/", + "StartTime": "date" + }, + "StateMachine": { + "Id": "arn::states::111111111111:stateMachine:", + "Name": "" + }, + "State": { + "Name": "StateName", + "EnteredTime": "date", + "RetryCount": 0 + } + }, + "errorOutput": { + "Error": "States.TaskFailed", + "Cause": "The task failed." + } + }, + "status": "CAUGHT_ERROR", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_test_state_scenarios.py::TestStateCaseScenarios::test_state_task_catch_error[DEBUG]": { + "recorded-date": "21-11-2025, 13:59:50", + "recorded-content": { + "test_catch_mock_exception_response": { + "cause": "Mock the cause of the error.", + "error": "MockException", + "inspectionData": { + "afterArguments": { + "FunctionName": "foo", + "Payload": "bar" + }, + "errorDetails": { + "catchIndex": 0 + }, + "input": { + "Value": "HelloWorld" + } + }, + "nextState": "HandleMockError", + "output": { + "input": { + "Value": "HelloWorld" + }, + "context": { + "Execution": { + "Id": "arn::states::111111111111:express::", + "Input": { + "Value": "HelloWorld" + }, + "Name": "", + "RoleArn": "arn::iam::111111111111:role/", + "StartTime": "date" + }, + "StateMachine": { + "Id": "arn::states::111111111111:stateMachine:", + "Name": "" + }, + "State": { + "Name": "StateName", + "EnteredTime": "date", + "RetryCount": 0 + } + }, + "errorOutput": { + "Error": "MockException", + "Cause": "Mock the cause of the error." + } + }, + "status": "CAUGHT_ERROR", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "catch_task_failed_response": { + "cause": "The task failed.", + "error": "States.TaskFailed", + "inspectionData": { + "afterArguments": { + "FunctionName": "foo", + "Payload": "bar" + }, + "errorDetails": { + "catchIndex": 1 + }, + "input": { + "Value": "HelloWorld" + } + }, + "nextState": "HandleThreshold", + "output": { + "input": { + "Value": "HelloWorld" + }, + "context": { + "Execution": { + "Id": "arn::states::111111111111:express::", + "Input": { + "Value": "HelloWorld" + }, + "Name": "", + "RoleArn": "arn::iam::111111111111:role/", + "StartTime": "date" + }, + "StateMachine": { + "Id": "arn::states::111111111111:stateMachine:", + "Name": "" + }, + "State": { + "Name": "StateName", + "EnteredTime": "date", + "RetryCount": 0 + } + }, + "errorOutput": { + "Error": "States.TaskFailed", + "Cause": "The task failed." + } + }, + "status": "CAUGHT_ERROR", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_test_state_scenarios.py::TestStateCaseScenarios::test_state_task_catch_error[TRACE]": { + "recorded-date": "21-11-2025, 14:00:05", + "recorded-content": { + "test_catch_mock_exception_response": { + "cause": "Mock the cause of the error.", + "error": "MockException", + "inspectionData": { + "afterArguments": { + "FunctionName": "foo", + "Payload": "bar" + }, + "errorDetails": { + "catchIndex": 0 + }, + "input": { + "Value": "HelloWorld" + } + }, + "nextState": "HandleMockError", + "output": { + "input": { + "Value": "HelloWorld" + }, + "context": { + "Execution": { + "Id": "arn::states::111111111111:express::", + "Input": { + "Value": "HelloWorld" + }, + "Name": "", + "RoleArn": "arn::iam::111111111111:role/", + "StartTime": "date" + }, + "StateMachine": { + "Id": "arn::states::111111111111:stateMachine:", + "Name": "" + }, + "State": { + "Name": "StateName", + "EnteredTime": "date", + "RetryCount": 0 + } + }, + "errorOutput": { + "Error": "MockException", + "Cause": "Mock the cause of the error." + } + }, + "status": "CAUGHT_ERROR", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "catch_task_failed_response": { + "cause": "The task failed.", + "error": "States.TaskFailed", + "inspectionData": { + "afterArguments": { + "FunctionName": "foo", + "Payload": "bar" + }, + "errorDetails": { + "catchIndex": 1 + }, + "input": { + "Value": "HelloWorld" + } + }, + "nextState": "HandleThreshold", + "output": { + "input": { + "Value": "HelloWorld" + }, + "context": { + "Execution": { + "Id": "arn::states::111111111111:express::", + "Input": { + "Value": "HelloWorld" + }, + "Name": "", + "RoleArn": "arn::iam::111111111111:role/", + "StartTime": "date" + }, + "StateMachine": { + "Id": "arn::states::111111111111:stateMachine:", + "Name": "" + }, + "State": { + "Name": "StateName", + "EnteredTime": "date", + "RetryCount": 0 + } + }, + "errorOutput": { + "Error": "States.TaskFailed", + "Cause": "The task failed." + } + }, + "status": "CAUGHT_ERROR", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_test_state_scenarios.py::TestStateCaseScenarios::test_localstack_blogpost_scenario": { + "recorded-date": "02-12-2025, 23:11:05", + "recorded-content": { + "small_purchase_approval_required_response": { + "inspectionData": { + "input": { + "cost": 9 + } + }, + "nextState": "Purchase Approved", + "output": { + "cost": 9 + }, + "status": "SUCCEEDED", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "large_purchase_approval_required_response": { + "inspectionData": { + "input": { + "cost": 10 + } + }, + "nextState": "Ask for Approval", + "output": { + "cost": 10 + }, + "status": "SUCCEEDED", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "large_purchase_ask_for_approval_response": { + "inspectionData": { + "afterArguments": { + "Method": "POST", + "ApiEndpoint": "example.execute-api..amazonaws.com", + "Path": "/approval", + "RequestBody": { + "cost": 10, + "dept_id": "12345678" + }, + "AuthType": "NO_AUTH" + }, + "input": { + "cost": 10 + }, + "result": { + "approval": true + } + }, + "nextState": "Check Approval", + "output": { + "approval": true, + "approval_code": "2387462", + "approved_by": "Mary" + }, + "status": "SUCCEEDED", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "check_approval_granted_response": { + "inspectionData": { + "input": { + "approval": true, + "approval_code": "2387462", + "approved_by": "Mary" + } + }, + "nextState": "Purchase Approved", + "output": { + "approval": true, + "approval_code": "2387462", + "approved_by": "Mary" + }, + "status": "SUCCEEDED", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + }, + "check_approval_denied_response": { + "inspectionData": { + "input": { + "approval": false + } + }, + "nextState": "Not Approved", + "output": { + "approval": false + }, + "status": "SUCCEEDED", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_test_state_scenarios.py::TestStateCaseScenarios::test_base_lambda_service_task_state_no_role_arn_validation": { + "recorded-date": "03-12-2025, 00:38:08", + "recorded-content": { + "validation_exception": { + "Error": { + "Code": "ValidationException", + "Message": "RoleArn must be specified when testing a Task state" + }, + "message": "RoleArn must be specified when testing a Task state", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 400 + } + } + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_test_state_scenarios.py::TestStateCaseScenarios::test_state_with_variables[base_expressions]": { + "recorded-date": "24-02-2026, 11:15:19", + "recorded-content": { + "test_case_response": { + "inspectionData": { + "input": { + "input_values": [ + 1, + 2, + 3 + ] + }, + "variables": { + "var_input_value": "test_value", + "var_constant_1": 10 + } + }, + "output": { + "ja_states_context": { + "Execution": { + "Id": "arn::states::111111111111:express::", + "Input": { + "input_values": [ + 1, + 2, + 3 + ] + }, + "Name": "", + "RoleArn": null, + "StartTime": "date" + }, + "StateMachine": { + "Id": "arn::states::111111111111:stateMachine:", + "Name": "" + }, + "State": { + "Name": "StateName", + "EnteredTime": "date" + } + }, + "ja_states_input": { + "input_values": [ + 1, + 2, + 3 + ] + }, + "ja_var_access": "test_value", + "ja_expr": 16 + }, + "status": "SUCCEEDED", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_test_state_scenarios.py::TestStateCaseScenarios::test_state_with_variables[empty_variables]": { + "recorded-date": "24-02-2026, 11:15:19", + "recorded-content": { + "test_case_response": { + "inspectionData": { + "input": { + "input_values": [ + 1, + 2, + 3 + ] + } + }, + "output": { + "constant_null": null, + "constant_int": 0, + "constant_float": 0.1, + "constant_bool": true, + "constant_str": "constant string", + "constant_not_jsonata": " {% states.input %} ", + "constant_varpath_states": "$states.input", + "constant_varpath": "$no.such.var.path", + "constant_jp_input": "$", + "constant_jp_input.$": "$", + "constant_jp_input_path": "$.input_value", + "constant_jp_context": "$$", + "constant_if": "States.Format('Format:{}', 101)", + "constant_lst_empty": [], + "constant_lst": [ + null, + 0, + 0.1, + true, + [], + { + "constant": 0 + }, + " {% states.input %} ", + "$states.input", + "$no.such.var.path" + ], + "constant_obj_empty": {}, + "constant_obj": { + "in_obj_constant_null": null, + "in_obj_constant_int": 0, + "in_obj_constant_float": 0.1, + "in_obj_constant_bool": true, + "in_obj_constant_str": "constant string", + "in_obj_constant_not_jsonata": " {% states.input %} ", + "in_obj_constant_lst_empty": [], + "in_obj_constant_lst": [ + null, + 0, + 0.1, + true, + [], + { + "constant": 0 + }, + " {% states.input %} ", + "$states.input", + "$no.such.var.path" + ], + "in_obj_constant_obj_empty": {}, + "in_obj_constant_obj": { + "constant": 0 + } + } + }, + "status": "SUCCEEDED", + "ResponseMetadata": { + "HTTPHeaders": {}, + "HTTPStatusCode": 200 + } + } + } } } diff --git a/tests/aws/services/stepfunctions/v2/test_state/test_test_state_scenarios.validation.json b/tests/aws/services/stepfunctions/v2/test_state/test_test_state_scenarios.validation.json index 6ee1aeac5b542..682e0e35d2d66 100644 --- a/tests/aws/services/stepfunctions/v2/test_state/test_test_state_scenarios.validation.json +++ b/tests/aws/services/stepfunctions/v2/test_state/test_test_state_scenarios.validation.json @@ -1,83 +1,416 @@ { "tests/aws/services/stepfunctions/v2/test_state/test_test_state_scenarios.py::TestStateCaseScenarios::test_base_inspection_level_debug[BASE_CHOICE_STATE]": { - "last_validated_date": "2024-04-12T20:48:24+00:00" + "last_validated_date": "2025-11-14T16:42:16+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 13.57, + "teardown": 1.66, + "total": 15.23 + } }, "tests/aws/services/stepfunctions/v2/test_state/test_test_state_scenarios.py::TestStateCaseScenarios::test_base_inspection_level_debug[BASE_FAIL_STATE]": { - "last_validated_date": "2024-04-12T20:47:56+00:00" + "last_validated_date": "2025-11-14T16:41:40+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 13.65, + "teardown": 1.75, + "total": 15.4 + } }, "tests/aws/services/stepfunctions/v2/test_state/test_test_state_scenarios.py::TestStateCaseScenarios::test_base_inspection_level_debug[BASE_PASS_STATE]": { - "last_validated_date": "2024-04-12T20:47:06+00:00" + "last_validated_date": "2025-11-14T16:40:41+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 13.21, + "teardown": 1.79, + "total": 15.0 + } }, "tests/aws/services/stepfunctions/v2/test_state/test_test_state_scenarios.py::TestStateCaseScenarios::test_base_inspection_level_debug[BASE_RESULT_PASS_STATE]": { - "last_validated_date": "2024-04-12T20:47:19+00:00" + "last_validated_date": "2025-11-14T16:40:56+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 12.84, + "teardown": 1.78, + "total": 14.62 + } }, "tests/aws/services/stepfunctions/v2/test_state/test_test_state_scenarios.py::TestStateCaseScenarios::test_base_inspection_level_debug[BASE_SUCCEED_STATE]": { - "last_validated_date": "2024-04-12T20:48:10+00:00" + "last_validated_date": "2025-11-14T16:42:00+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 18.47, + "teardown": 1.74, + "total": 20.21 + } }, "tests/aws/services/stepfunctions/v2/test_state/test_test_state_scenarios.py::TestStateCaseScenarios::test_base_inspection_level_debug[IO_PASS_STATE]": { - "last_validated_date": "2024-04-12T20:47:31+00:00" + "last_validated_date": "2025-11-14T16:41:10+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 12.56, + "teardown": 1.65, + "total": 14.21 + } }, "tests/aws/services/stepfunctions/v2/test_state/test_test_state_scenarios.py::TestStateCaseScenarios::test_base_inspection_level_debug[IO_RESULT_PASS_STATE]": { - "last_validated_date": "2024-04-12T20:47:44+00:00" + "last_validated_date": "2025-11-14T16:41:25+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 12.87, + "teardown": 1.64, + "total": 14.51 + } }, "tests/aws/services/stepfunctions/v2/test_state/test_test_state_scenarios.py::TestStateCaseScenarios::test_base_inspection_level_info[BASE_CHOICE_STATE]": { - "last_validated_date": "2024-04-12T20:46:53+00:00" + "last_validated_date": "2025-11-14T16:40:26+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 13.61, + "teardown": 1.77, + "total": 15.38 + } }, "tests/aws/services/stepfunctions/v2/test_state/test_test_state_scenarios.py::TestStateCaseScenarios::test_base_inspection_level_info[BASE_FAIL_STATE]": { - "last_validated_date": "2024-04-12T20:46:28+00:00" + "last_validated_date": "2025-11-14T16:39:51+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 12.73, + "teardown": 1.81, + "total": 14.54 + } }, "tests/aws/services/stepfunctions/v2/test_state/test_test_state_scenarios.py::TestStateCaseScenarios::test_base_inspection_level_info[BASE_PASS_STATE]": { - "last_validated_date": "2024-04-12T20:45:35+00:00" + "last_validated_date": "2025-11-14T16:38:51+00:00", + "durations_in_seconds": { + "setup": 1.16, + "call": 15.38, + "teardown": 1.95, + "total": 18.49 + } }, "tests/aws/services/stepfunctions/v2/test_state/test_test_state_scenarios.py::TestStateCaseScenarios::test_base_inspection_level_info[BASE_RESULT_PASS_STATE]": { - "last_validated_date": "2024-04-12T20:45:49+00:00" + "last_validated_date": "2025-11-14T16:39:06+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 12.83, + "teardown": 1.75, + "total": 14.58 + } }, "tests/aws/services/stepfunctions/v2/test_state/test_test_state_scenarios.py::TestStateCaseScenarios::test_base_inspection_level_info[BASE_SUCCEED_STATE]": { - "last_validated_date": "2024-04-12T20:46:41+00:00" + "last_validated_date": "2025-11-14T16:40:11+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 18.15, + "teardown": 2.27, + "total": 20.42 + } }, "tests/aws/services/stepfunctions/v2/test_state/test_test_state_scenarios.py::TestStateCaseScenarios::test_base_inspection_level_info[IO_PASS_STATE]": { - "last_validated_date": "2024-04-12T20:46:03+00:00" + "last_validated_date": "2025-11-14T16:39:21+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 12.93, + "teardown": 1.85, + "total": 14.78 + } }, "tests/aws/services/stepfunctions/v2/test_state/test_test_state_scenarios.py::TestStateCaseScenarios::test_base_inspection_level_info[IO_RESULT_PASS_STATE]": { - "last_validated_date": "2024-04-12T20:46:15+00:00" + "last_validated_date": "2025-11-14T16:39:36+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 13.77, + "teardown": 1.7, + "total": 15.47 + } }, "tests/aws/services/stepfunctions/v2/test_state/test_test_state_scenarios.py::TestStateCaseScenarios::test_base_inspection_level_trace[BASE_CHOICE_STATE]": { - "last_validated_date": "2024-04-12T20:49:57+00:00" + "last_validated_date": "2025-11-14T16:44:02+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 12.71, + "teardown": 1.82, + "total": 14.53 + } }, "tests/aws/services/stepfunctions/v2/test_state/test_test_state_scenarios.py::TestStateCaseScenarios::test_base_inspection_level_trace[BASE_FAIL_STATE]": { - "last_validated_date": "2024-04-12T20:49:31+00:00" + "last_validated_date": "2025-11-14T16:43:33+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 12.87, + "teardown": 1.78, + "total": 14.65 + } }, "tests/aws/services/stepfunctions/v2/test_state/test_test_state_scenarios.py::TestStateCaseScenarios::test_base_inspection_level_trace[BASE_PASS_STATE]": { - "last_validated_date": "2024-04-12T20:48:37+00:00" + "last_validated_date": "2025-11-14T16:42:32+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 14.77, + "teardown": 1.86, + "total": 16.63 + } }, "tests/aws/services/stepfunctions/v2/test_state/test_test_state_scenarios.py::TestStateCaseScenarios::test_base_inspection_level_trace[BASE_RESULT_PASS_STATE]": { - "last_validated_date": "2024-04-12T20:48:50+00:00" + "last_validated_date": "2025-11-14T16:42:47+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 12.98, + "teardown": 1.84, + "total": 14.82 + } }, "tests/aws/services/stepfunctions/v2/test_state/test_test_state_scenarios.py::TestStateCaseScenarios::test_base_inspection_level_trace[BASE_SUCCEED_STATE]": { - "last_validated_date": "2024-04-12T20:49:44+00:00" + "last_validated_date": "2025-11-14T16:43:47+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 12.54, + "teardown": 1.69, + "total": 14.23 + } }, "tests/aws/services/stepfunctions/v2/test_state/test_test_state_scenarios.py::TestStateCaseScenarios::test_base_inspection_level_trace[IO_PASS_STATE]": { - "last_validated_date": "2024-04-12T20:49:03+00:00" + "last_validated_date": "2025-11-14T16:43:03+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 12.84, + "teardown": 2.72, + "total": 15.56 + } }, "tests/aws/services/stepfunctions/v2/test_state/test_test_state_scenarios.py::TestStateCaseScenarios::test_base_inspection_level_trace[IO_RESULT_PASS_STATE]": { - "last_validated_date": "2024-04-12T20:49:22+00:00" + "last_validated_date": "2025-11-14T16:43:18+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 13.82, + "teardown": 1.76, + "total": 15.58 + } }, "tests/aws/services/stepfunctions/v2/test_state/test_test_state_scenarios.py::TestStateCaseScenarios::test_base_lambda_service_task_state[DEBUG]": { - "last_validated_date": "2024-04-12T20:51:22+00:00" + "last_validated_date": "2025-11-14T16:45:49+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 15.84, + "teardown": 3.3, + "total": 19.14 + } }, "tests/aws/services/stepfunctions/v2/test_state/test_test_state_scenarios.py::TestStateCaseScenarios::test_base_lambda_service_task_state[INFO]": { - "last_validated_date": "2024-04-12T20:51:07+00:00" + "last_validated_date": "2025-11-14T16:45:30+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 15.59, + "teardown": 3.28, + "total": 18.87 + } }, "tests/aws/services/stepfunctions/v2/test_state/test_test_state_scenarios.py::TestStateCaseScenarios::test_base_lambda_service_task_state[TRACE]": { - "last_validated_date": "2024-04-12T20:51:37+00:00" + "last_validated_date": "2025-11-14T16:46:10+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 16.65, + "teardown": 3.49, + "total": 20.14 + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_test_state_scenarios.py::TestStateCaseScenarios::test_base_lambda_service_task_state_no_role_arn_validation": { + "last_validated_date": "2025-12-03T00:38:08+00:00", + "durations_in_seconds": { + "setup": 0.53, + "call": 0.67, + "teardown": 0.0, + "total": 1.2 + } }, "tests/aws/services/stepfunctions/v2/test_state/test_test_state_scenarios.py::TestStateCaseScenarios::test_base_lambda_task_state[DEBUG]": { - "last_validated_date": "2024-04-12T20:50:37+00:00" + "last_validated_date": "2025-11-14T16:44:51+00:00", + "durations_in_seconds": { + "setup": 0.01, + "call": 15.42, + "teardown": 3.14, + "total": 18.57 + } }, "tests/aws/services/stepfunctions/v2/test_state/test_test_state_scenarios.py::TestStateCaseScenarios::test_base_lambda_task_state[INFO]": { - "last_validated_date": "2024-04-12T20:50:22+00:00" + "last_validated_date": "2025-11-14T16:44:33+00:00", + "durations_in_seconds": { + "setup": 11.62, + "call": 16.2, + "teardown": 3.41, + "total": 31.23 + } }, "tests/aws/services/stepfunctions/v2/test_state/test_test_state_scenarios.py::TestStateCaseScenarios::test_base_lambda_task_state[TRACE]": { - "last_validated_date": "2024-04-12T20:50:52+00:00" + "last_validated_date": "2025-11-14T16:45:11+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 16.93, + "teardown": 3.07, + "total": 20.0 + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_test_state_scenarios.py::TestStateCaseScenarios::test_base_map_state_inspect[MAX_CONCURRENCY-DEBUG]": { + "last_validated_date": "2025-11-14T16:46:41+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 12.75, + "teardown": 1.87, + "total": 14.62 + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_test_state_scenarios.py::TestStateCaseScenarios::test_base_map_state_inspect[MAX_CONCURRENCY-INFO]": { + "last_validated_date": "2025-11-14T16:46:26+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 14.44, + "teardown": 1.86, + "total": 16.3 + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_test_state_scenarios.py::TestStateCaseScenarios::test_base_map_state_inspect[MAX_CONCURRENCY-TRACE]": { + "last_validated_date": "2025-11-14T16:46:55+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 12.99, + "teardown": 1.9, + "total": 14.89 + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_test_state_scenarios.py::TestStateCaseScenarios::test_base_map_state_inspect[TOLERATED_FAILURE_COUNT-DEBUG]": { + "last_validated_date": "2025-11-14T16:48:11+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 13.69, + "teardown": 1.65, + "total": 15.34 + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_test_state_scenarios.py::TestStateCaseScenarios::test_base_map_state_inspect[TOLERATED_FAILURE_COUNT-INFO]": { + "last_validated_date": "2025-11-14T16:47:56+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 12.98, + "teardown": 2.01, + "total": 14.99 + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_test_state_scenarios.py::TestStateCaseScenarios::test_base_map_state_inspect[TOLERATED_FAILURE_COUNT-TRACE]": { + "last_validated_date": "2025-11-14T16:48:26+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 12.64, + "teardown": 2.6, + "total": 15.24 + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_test_state_scenarios.py::TestStateCaseScenarios::test_base_map_state_inspect[TOLERATED_FAILURE_PERCENTAGE-DEBUG]": { + "last_validated_date": "2025-11-14T16:47:24+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 12.76, + "teardown": 1.79, + "total": 14.55 + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_test_state_scenarios.py::TestStateCaseScenarios::test_base_map_state_inspect[TOLERATED_FAILURE_PERCENTAGE-INFO]": { + "last_validated_date": "2025-11-14T16:47:10+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 12.72, + "teardown": 1.77, + "total": 14.49 + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_test_state_scenarios.py::TestStateCaseScenarios::test_base_map_state_inspect[TOLERATED_FAILURE_PERCENTAGE-TRACE]": { + "last_validated_date": "2025-11-14T16:47:41+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 13.78, + "teardown": 2.43, + "total": 16.21 + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_test_state_scenarios.py::TestStateCaseScenarios::test_base_map_state_inspect_trace[MAX_CONCURRENCY]": { + "last_validated_date": "2025-11-12T15:25:20+00:00", + "durations_in_seconds": { + "setup": 1.65, + "call": 15.24, + "teardown": 1.84, + "total": 18.73 + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_test_state_scenarios.py::TestStateCaseScenarios::test_base_map_state_inspect_trace[TOLERATED_FAILURE_COUNT]": { + "last_validated_date": "2025-11-12T14:20:06+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 12.61, + "teardown": 1.86, + "total": 14.47 + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_test_state_scenarios.py::TestStateCaseScenarios::test_base_map_state_inspect_trace[TOLERATED_FAILURE_PERCENTAGE]": { + "last_validated_date": "2025-11-12T14:19:51+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 12.68, + "teardown": 1.81, + "total": 14.49 + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_test_state_scenarios.py::TestStateCaseScenarios::test_localstack_blogpost_scenario": { + "last_validated_date": "2025-12-02T23:11:05+00:00", + "durations_in_seconds": { + "setup": 0.55, + "call": 1.26, + "teardown": 0.0, + "total": 1.81 + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_test_state_scenarios.py::TestStateCaseScenarios::test_state_task_catch_error[DEBUG]": { + "last_validated_date": "2025-11-21T13:59:51+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 12.82, + "teardown": 1.67, + "total": 14.49 + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_test_state_scenarios.py::TestStateCaseScenarios::test_state_task_catch_error[INFO]": { + "last_validated_date": "2025-11-21T13:59:37+00:00", + "durations_in_seconds": { + "setup": 1.32, + "call": 16.93, + "teardown": 1.76, + "total": 20.01 + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_test_state_scenarios.py::TestStateCaseScenarios::test_state_task_catch_error[TRACE]": { + "last_validated_date": "2025-11-21T14:00:06+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 13.14, + "teardown": 1.77, + "total": 14.91 + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_test_state_scenarios.py::TestStateCaseScenarios::test_state_with_variables[base_expressions]": { + "last_validated_date": "2026-02-24T11:15:19+00:00", + "durations_in_seconds": { + "setup": 0.49, + "call": 0.63, + "teardown": 0.0, + "total": 1.12 + } + }, + "tests/aws/services/stepfunctions/v2/test_state/test_test_state_scenarios.py::TestStateCaseScenarios::test_state_with_variables[empty_variables]": { + "last_validated_date": "2026-02-24T11:15:19+00:00", + "durations_in_seconds": { + "setup": 0.0, + "call": 0.22, + "teardown": 0.0, + "total": 0.22 + } } } diff --git a/tests/aws/services/transcribe/test_transcribe.py b/tests/aws/services/transcribe/test_transcribe.py index e3235ade6ce8b..689b4ad7fe011 100644 --- a/tests/aws/services/transcribe/test_transcribe.py +++ b/tests/aws/services/transcribe/test_transcribe.py @@ -14,6 +14,7 @@ from localstack.packages.ffmpeg import ffmpeg_package from localstack.services.transcribe.packages import vosk_package from localstack.services.transcribe.provider import LANGUAGE_MODELS, TranscribeProvider +from localstack.testing import config as test_config from localstack.testing.aws.util import is_aws_cloud from localstack.testing.pytest import markers from localstack.utils.files import new_tmp_file @@ -97,6 +98,10 @@ def transcribe_snapshot_transformer(snapshot): class TestTranscribe: @pytest.fixture(scope="class", autouse=True) def pre_install_dependencies(self): + if is_aws_cloud() or test_config.TEST_SKIP_LOCALSTACK_START: + # we don't install the dependencies if LocalStack is not running in process + return + if not ffmpeg_installed.is_set() or not vosk_installed.is_set(): install_async() @@ -111,7 +116,6 @@ def pre_install_dependencies(self): LOG.info("Spent %s seconds downloading transcribe dependencies", int(time.time() - start)) assert not installation_errored.is_set(), "installation of transcribe dependencies failed" - yield @staticmethod def _wait_transcription_job( @@ -442,6 +446,7 @@ def test_transcribe_error_speaker_labels(self, transcribe_create_job, aws_client transcribe_create_job(audio_file=file_path, params=settings) snapshot.match("err_speaker_labels_diarization", e.value) + @markers.requires_in_process # test relies on the installation of ffmpeg @markers.aws.validated @markers.snapshot.skip_snapshot_verify( paths=[ @@ -455,7 +460,7 @@ def test_transcribe_error_invalid_length(self, transcribe_create_job, aws_client media_file = os.path.join(tempfile.gettempdir(), "audio_4h.mp3") run( - f"{ffmpeg_bin} -f lavfi -i anullsrc=r=44100:cl=mono -t 14400 -q:a 9 -acodec libmp3lame {media_file}" + f"{ffmpeg_bin} -f lavfi -i anullsrc=r=44100:cl=mono -t 14401 -q:a 9 -acodec libmp3lame {media_file}" ) job_name = transcribe_create_job(audio_file=media_file) diff --git a/tests/aws/templates/apigateway-mock-cors-deployment.json b/tests/aws/templates/apigateway-mock-cors-deployment.json new file mode 100644 index 0000000000000..a3b19161143d3 --- /dev/null +++ b/tests/aws/templates/apigateway-mock-cors-deployment.json @@ -0,0 +1,86 @@ +{ + "AWSTemplateFormatVersion": "2010-09-09", + "Resources": { + "Api": { + "Type": "AWS::ApiGateway::RestApi", + "Properties": { + "Name": "cors-test-api" + } + }, + "MethodGet": { + "Type": "AWS::ApiGateway::Method", + "Properties": { + "RestApiId": { "Ref": "Api" }, + "ResourceId": { "Fn::GetAtt": ["Api", "RootResourceId"] }, + "HttpMethod": "GET", + "AuthorizationType": "NONE", + "Integration": { + "Type": "MOCK", + "RequestTemplates": { + "application/json": "{\"statusCode\":200}" + }, + "IntegrationResponses": [ + { + "StatusCode": "200", + "ResponseTemplates": { + "application/json": "{\"msg\":\"{{ response_msg }}\"}" + } + } + ] + }, + "MethodResponses": [{ "StatusCode": "200" }] + } + }, + "MethodOptions": { + "Type": "AWS::ApiGateway::Method", + "Properties": { + "RestApiId": { "Ref": "Api" }, + "ResourceId": { "Fn::GetAtt": ["Api", "RootResourceId"] }, + "HttpMethod": "OPTIONS", + "AuthorizationType": "NONE", + "Integration": { + "Type": "MOCK", + "RequestTemplates": { + "application/json": "{\"statusCode\":200}" + }, + "IntegrationResponses": [ + { + "StatusCode": "200", + "ResponseParameters": { + "method.response.header.Access-Control-Allow-Headers": "'Content-Type'", + "method.response.header.Access-Control-Allow-Methods": "'GET,OPTIONS'", + "method.response.header.Access-Control-Allow-Origin": "'*'" + }, + "ResponseTemplates": { + "application/json": "{\"statusCode\":200}" + } + } + ] + }, + "MethodResponses": [ + { + "StatusCode": "200", + "ResponseParameters": { + "method.response.header.Access-Control-Allow-Headers": false, + "method.response.header.Access-Control-Allow-Methods": false, + "method.response.header.Access-Control-Allow-Origin": false + } + } + ] + } + }, + "{{ deployment_logical_id }}": { + "Type": "AWS::ApiGateway::Deployment", + "DependsOn": ["MethodGet", "MethodOptions"], + "Properties": { + "RestApiId": { "Ref": "Api" }, + "StageName": "local" + } + } + }, + "Outputs": { + "ApiId": { + "Value": { "Ref": "Api" } + } + } +} diff --git a/tests/aws/templates/apigateway_basepath_mapping.yaml b/tests/aws/templates/apigateway_basepath_mapping.yaml new file mode 100644 index 0000000000000..38027b982b404 --- /dev/null +++ b/tests/aws/templates/apigateway_basepath_mapping.yaml @@ -0,0 +1,57 @@ +Parameters: + CertificateArn: + Type: String + + DomainName: + Type: String +Resources: + MyRestApi: + Type: AWS::ApiGateway::RestApi + Properties: + Name: test-api + MyMethod: + Type: AWS::ApiGateway::Method + Properties: + RestApiId: + Ref: MyRestApi + ResourceId: + Fn::GetAtt: + - MyRestApi + - RootResourceId + HttpMethod: GET + AuthorizationType: NONE + Integration: + Type: MOCK + RequestTemplates: + application/json: '{"statusCode": 200}' + MethodResponses: + - StatusCode: 200 + MyDeployment: + Type: AWS::ApiGateway::Deployment + Properties: + RestApiId: + Ref: MyRestApi + DependsOn: + - MyMethod + MyStage: + Type: AWS::ApiGateway::Stage + Properties: + RestApiId: + Ref: MyRestApi + DeploymentId: + Ref: MyDeployment + StageName: prod + MyDomainName: + Type: AWS::ApiGateway::DomainName + Properties: + DomainName: !Ref DomainName + CertificateArn: !Ref CertificateArn + MyBasePathMapping: + Type: AWS::ApiGateway::BasePathMapping + Properties: + DomainName: + Ref: MyDomainName + RestApiId: + Ref: MyRestApi + Stage: + Ref: MyStage diff --git a/tests/aws/templates/apigateway_stage_access_log_settings.yaml b/tests/aws/templates/apigateway_stage_access_log_settings.yaml new file mode 100644 index 0000000000000..19d99f3134b69 --- /dev/null +++ b/tests/aws/templates/apigateway_stage_access_log_settings.yaml @@ -0,0 +1,52 @@ +Parameters: + RestApiName: + Type: String + +Resources: + RestApi: + Type: AWS::ApiGateway::RestApi + Properties: + Name: !Ref RestApiName + + MockMethod: + Type: 'AWS::ApiGateway::Method' + Properties: + RestApiId: !Ref RestApi + ResourceId: !GetAtt + - RestApi + - RootResourceId + HttpMethod: POST + AuthorizationType: NONE + Integration: + Type: MOCK + + ApiDeployment: + Type: AWS::ApiGateway::Deployment + Properties: + RestApiId: + Ref: RestApi + Description: "basic deployment" + DependsOn: + - MockMethod + + TestStage: + Type: AWS::ApiGateway::Stage + Properties: + StageName: test + RestApiId: !Ref RestApi + DeploymentId: !Ref ApiDeployment + Description: "test stage description" + AccessLogSetting: + DestinationArn: !GetAtt MyLogGroup.Arn + Format: $context.extendedRequestId $context.identity.sourceIp $context.identity.caller $context.identity.user [$context.requestTime] "$context.httpMethod $context.resourcePath $context.protocol" $context.status $context.responseLength $context.requestId + MyLogGroup: + Type: AWS::Logs::LogGroup + Properties: + LogGroupName: !Join + - '-' + - - !Ref RestApi + - access-logs + +Outputs: + RestApiId: + Value: !GetAtt RestApi.RestApiId diff --git a/tests/aws/templates/cfn_parameter_list_subnet_id_type.yaml b/tests/aws/templates/cfn_parameter_list_subnet_id_type.yaml new file mode 100644 index 0000000000000..eebeb6b947c96 --- /dev/null +++ b/tests/aws/templates/cfn_parameter_list_subnet_id_type.yaml @@ -0,0 +1,12 @@ +Parameters: + ParamsList: + Type: List +Resources: + MyParam: + Type: AWS::SSM::Parameter + Properties: + Type: String + Value: !Join ["|", !Ref ParamsList] +Outputs: + ParamValue: + Value: !GetAtt MyParam.Value diff --git a/tests/aws/templates/conditions/conditional-resource-getatt-delete.yaml b/tests/aws/templates/conditions/conditional-resource-getatt-delete.yaml new file mode 100644 index 0000000000000..7d8081ba6fef8 --- /dev/null +++ b/tests/aws/templates/conditions/conditional-resource-getatt-delete.yaml @@ -0,0 +1,43 @@ +AWSTemplateFormatVersion: '2010-09-09' + +Parameters: + EnableQueue: + Type: String + Default: 'false' + AllowedValues: ['true', 'false'] + +Conditions: + CreateQueue: !Equals [!Ref EnableQueue, 'true'] + +Resources: + MyTable: + Type: AWS::DynamoDB::Table + Properties: + TableName: !Sub '${AWS::StackName}-table' + BillingMode: PAY_PER_REQUEST + AttributeDefinitions: + - AttributeName: PK + AttributeType: S + KeySchema: + - AttributeName: PK + KeyType: HASH + + MyQueue: + Type: AWS::SQS::Queue + Condition: CreateQueue + + MyAlarm: + Type: AWS::CloudWatch::Alarm + Condition: CreateQueue + Properties: + AlarmName: !Sub '${AWS::StackName}-alarm' + MetricName: ApproximateNumberOfMessagesVisible + Namespace: AWS/SQS + Statistic: Sum + Period: 300 + EvaluationPeriods: 1 + Threshold: 100 + ComparisonOperator: GreaterThanThreshold + Dimensions: + - Name: QueueName + Value: !GetAtt MyQueue.QueueName diff --git a/tests/aws/templates/deletion_policy.yaml b/tests/aws/templates/deletion_policy.yaml new file mode 100644 index 0000000000000..6de133bcd5fdc --- /dev/null +++ b/tests/aws/templates/deletion_policy.yaml @@ -0,0 +1,26 @@ +AWSTemplateFormatVersion: '2010-09-09' +Description: Minimal DynamoDB Conditional DeletionPolicy Example + +Parameters: + ParameterValue: + Type: String + EnvType: + Type: String + Default: dev + AllowedValues: [dev, prod] + Description: Environment name. Use 'prod' to trigger Retain policy. + +Conditions: + IsPermanentEnvironment: !Equals [!Ref EnvType, prod] + +Resources: + MyParameter: + Type: AWS::SSM::Parameter + DeletionPolicy: !If [IsPermanentEnvironment, Retain, Delete] + Properties: + Type: String + Value: !Ref ParameterValue + +Outputs: + ParameterName: + Value: !Ref MyParameter \ No newline at end of file diff --git a/tests/aws/templates/getatt_validation.yml b/tests/aws/templates/getatt_validation.yml new file mode 100644 index 0000000000000..fb82b2ad47b7e --- /dev/null +++ b/tests/aws/templates/getatt_validation.yml @@ -0,0 +1,10 @@ +Parameters: + MyParameterValue: + Type: String + +Resources: + MyParameter: + Type: AWS::SSM::Parameter + Properties: + Type: String + Value: !Select [ 0, !Split [ "-", !GetAtt [ !Ref MyParameterValue ] ] ] diff --git a/tests/aws/templates/getatt_validation2.yml b/tests/aws/templates/getatt_validation2.yml new file mode 100644 index 0000000000000..e1a8b61a22d07 --- /dev/null +++ b/tests/aws/templates/getatt_validation2.yml @@ -0,0 +1,18 @@ +Parameters: + MyParameterValue: + Type: String + +Resources: + MyParameter1: + Type: AWS::SSM::Parameter + Properties: + Type: String + Value: foo + + MyParameter2: + Type: AWS::SSM::Parameter + Properties: + Type: String + Value: + Fn::GetAtt: + - MyParameter1 diff --git a/tests/aws/templates/logs_group.yml b/tests/aws/templates/logs_group.yml index b0aaa510dcfae..0a0f5c1f5ac07 100644 --- a/tests/aws/templates/logs_group.yml +++ b/tests/aws/templates/logs_group.yml @@ -1,11 +1,16 @@ +Parameters: + LogGroupName: + Type: String + Default: AWS::NoValue + Resources: logGroup68A52FBE: Type: AWS::Logs::LogGroup Properties: + LogGroupName: !Ref LogGroupName RetentionInDays: 731 Outputs: LogGroupNameOutput: Value: Ref: logGroup68A52FBE - diff --git a/tests/aws/templates/references_to_conditions.yml b/tests/aws/templates/references_to_conditions.yml new file mode 100644 index 0000000000000..01bed33232515 --- /dev/null +++ b/tests/aws/templates/references_to_conditions.yml @@ -0,0 +1,39 @@ +Parameters: + Toggle: + Type: String + + ParameterValue: + Type: String + +Conditions: + ShouldDeploy: + Fn::Equals: + - !Ref Toggle + - "yes" + +Resources: + BaseParameter: + # We need a single resource to deploy + Type: AWS::SSM::Parameter + Properties: + Type: String + Value: !Ref ParameterValue + + ConditionalParameter: + Type: AWS::SSM::Parameter + Condition: ShouldDeploy + Properties: + Type: String + Value: !Ref ParameterValue + + AnotherResource: + Type: AWS::SSM::Parameter + Condition: ShouldDeploy + Properties: + Type: String + Value: !GetAtt ConditionalParameter.Value + +Outputs: + ConditionalParameterValue: + Condition: ShouldDeploy + Value: !GetAtt ConditionalParameter.Value diff --git a/tests/aws/templates/route53_hostedzoneid_weighted_template.yaml b/tests/aws/templates/route53_hostedzoneid_weighted_template.yaml new file mode 100644 index 0000000000000..03f6e1a7c5b3e --- /dev/null +++ b/tests/aws/templates/route53_hostedzoneid_weighted_template.yaml @@ -0,0 +1,60 @@ +Parameters: + Name: + Type: String + HostedZoneId: + Type: String + BucketRegionOneHost: + Type: String + BucketRegionOneHostedZoneId: + Type: String + BucketRegionTwoHost: + Type: String + BucketRegionTwoHostedZoneId: + Type: String + WeightBucketOne: + Type: Number + Default: 255 + WeightBucketTwo: + Type: Number + Default: 0 + BucketOneSetIdentifier: + Type: String + Default: region-1 + BucketTwoSetIdentifier: + Type: String + Default: region-2 + +Resources: + ApiWeightedRecordSetOne: + Type: AWS::Route53::RecordSet + Properties: + HostedZoneId: !Ref HostedZoneId + Name: !Ref Name + Type: A + SetIdentifier: !Ref BucketOneSetIdentifier + Weight: !Ref WeightBucketOne + AliasTarget: + DNSName: !Ref BucketRegionOneHost + HostedZoneId: !Ref BucketRegionOneHostedZoneId + EvaluateTargetHealth: false + + ApiWeightedRecordSetTwo: + Type: AWS::Route53::RecordSet + Properties: + HostedZoneId: !Ref HostedZoneId + Name: !Ref Name + Type: A + SetIdentifier: !Ref BucketTwoSetIdentifier + Weight: !Ref WeightBucketTwo + AliasTarget: + DNSName: !Ref BucketRegionTwoHost + HostedZoneId: !Ref BucketRegionTwoHostedZoneId + EvaluateTargetHealth: false + +Outputs: + RecordSetOneId: + Value: + Ref: ApiWeightedRecordSetOne + RecordSetTwoId: + Value: + Ref: ApiWeightedRecordSetTwo diff --git a/tests/aws/templates/sqs_fifo_autogenerate_name.yaml b/tests/aws/templates/sqs_fifo_autogenerate_name.yaml deleted file mode 100644 index 62e85cf2aa551..0000000000000 --- a/tests/aws/templates/sqs_fifo_autogenerate_name.yaml +++ /dev/null @@ -1,22 +0,0 @@ -Parameters: - IsFifo: - Type: String - -Conditions: - IsFifo: !Equals [ !Ref IsFifo, "true"] - -Resources: - FooQueueA2A23E59: - Type: AWS::SQS::Queue - Properties: - ContentBasedDeduplication: !If [ IsFifo, "true", !Ref AWS::NoValue ] - FifoQueue: !If [ IsFifo, "true", !Ref AWS::NoValue ] - VisibilityTimeout: 300 - UpdateReplacePolicy: Delete - DeletionPolicy: Delete -Outputs: - FooQueueName: - Value: - Fn::GetAtt: - - FooQueueA2A23E59 - - QueueName diff --git a/tests/aws/templates/sqs_fifo_queue.yml b/tests/aws/templates/sqs_fifo_queue.yml deleted file mode 100644 index 6d1077a421c4c..0000000000000 --- a/tests/aws/templates/sqs_fifo_queue.yml +++ /dev/null @@ -1,18 +0,0 @@ -AWSTemplateFormatVersion: 2010-09-09 -Parameters: - QueueName: - Type: String - Default: "test-queue" - Description: "Name of the SQS queue" -Resources: - FifoQueue: - Type: 'AWS::SQS::Queue' - Properties: - QueueName: !Sub "${QueueName}.fifo" - ContentBasedDeduplication: "false" - FifoQueue: "true" - -Outputs: - QueueURL: - Value: !GetAtt FifoQueue.QueueName - Description: "URL of the SQS queue" diff --git a/tests/aws/templates/sqs_queue_update_1.yaml b/tests/aws/templates/sqs_queue_update_1.yaml new file mode 100644 index 0000000000000..63c8f35db036a --- /dev/null +++ b/tests/aws/templates/sqs_queue_update_1.yaml @@ -0,0 +1,11 @@ +Resources: + StandardQueue: + Type: 'AWS::SQS::Queue' + +Outputs: + QueueUrl: + Description: 'URL of the SQS Standard Queue' + Value: !Ref StandardQueue + QueueArn: + Description: 'ARN of the SQS Standard Queue' + Value: !GetAtt StandardQueue.Arn \ No newline at end of file diff --git a/tests/aws/templates/sqs_queue_update_2.yaml b/tests/aws/templates/sqs_queue_update_2.yaml new file mode 100644 index 0000000000000..be3c3b69929f4 --- /dev/null +++ b/tests/aws/templates/sqs_queue_update_2.yaml @@ -0,0 +1,16 @@ +Resources: + StandardQueue: + Type: 'AWS::SQS::Queue' + Properties: + VisibilityTimeout: 30 + MaximumMessageSize: 4321 + MessageRetentionPeriod: 17539 + ReceiveMessageWaitTimeSeconds: 17 + +Outputs: + QueueUrl: + Description: 'URL of the SQS Standard Queue' + Value: !Ref StandardQueue + QueueArn: + Description: 'ARN of the SQS Standard Queue' + Value: !GetAtt StandardQueue.Arn \ No newline at end of file diff --git a/tests/aws/templates/sqs_queue_update_no_change.yml b/tests/aws/templates/sqs_queue_update_no_change.yml deleted file mode 100644 index dad49efefd6fb..0000000000000 --- a/tests/aws/templates/sqs_queue_update_no_change.yml +++ /dev/null @@ -1,29 +0,0 @@ -Parameters: - AddBucket: - Type: String - AllowedValues: - - "true" - - "false" - - BucketName: - Type: String - -Conditions: - ShouldDeployBucket: !Equals ["true", !Ref AddBucket] - -Resources: - Queue: - Type: AWS::SQS::Queue - - Bucket: - Type: AWS::S3::Bucket - Condition: ShouldDeployBucket - Properties: - BucketName: !Ref BucketName - -Outputs: - QueueUrl: - Value: !Ref Queue - - QueueArn: - Value: !GetAtt Queue.Arn diff --git a/tests/aws/templates/sqs_with_queuepolicy_updated.yaml b/tests/aws/templates/sqs_with_queuepolicy_updated.yaml deleted file mode 100644 index 17818bddc3fd2..0000000000000 --- a/tests/aws/templates/sqs_with_queuepolicy_updated.yaml +++ /dev/null @@ -1,25 +0,0 @@ -Resources: - Queue4A7E3555: - Type: AWS::SQS::Queue - QueuePolicy25439813: - Type: AWS::SQS::QueuePolicy - Properties: - PolicyDocument: - Statement: - - Action: - - sqs:SendMessage - - sqs:GetQueueAttributes - - sqs:GetQueueUrl - Effect: Deny - Principal: "*" - Resource: - Fn::GetAtt: - - Queue4A7E3555 - - Arn - Version: "2012-10-17" - Queues: - - Ref: Queue4A7E3555 -Outputs: - QueueUrlOutput: - Value: - Ref: Queue4A7E3555 diff --git a/tests/aws/templates/update_retain_policy.yaml b/tests/aws/templates/update_retain_policy.yaml new file mode 100644 index 0000000000000..ffd7d60bbf040 --- /dev/null +++ b/tests/aws/templates/update_retain_policy.yaml @@ -0,0 +1,18 @@ +Parameters: + ParameterValue: + Type: String + + ParameterName: + Type: String + + PolicyType: + Type: String + +Resources: + MyParameter: + Type: AWS::SSM::Parameter + Properties: + Name: !Ref ParameterName + Type: String + Value: !Ref ParameterValue + UpdateReplacePolicy: !Ref PolicyType \ No newline at end of file diff --git a/tests/aws/test_error_injection.py b/tests/aws/test_error_injection.py index c01fde6f76187..9edd72cd1449f 100644 --- a/tests/aws/test_error_injection.py +++ b/tests/aws/test_error_injection.py @@ -11,6 +11,7 @@ class TestErrorInjection: + @markers.requires_in_process @markers.aws.only_localstack def test_kinesis_error_injection( self, monkeypatch, wait_for_stream_ready, aws_client, aws_client_factory @@ -34,6 +35,7 @@ def test_kinesis_error_injection( finally: aws_client.kinesis.delete_stream(StreamName=stream_name) + @markers.requires_in_process @markers.aws.only_localstack def test_dynamodb_error_injection(self, monkeypatch, aws_client, dynamodb_create_table): table_name = dynamodb_create_table()["TableDescription"]["TableName"] @@ -51,6 +53,7 @@ def test_dynamodb_error_injection(self, monkeypatch, aws_client, dynamodb_create ) exc.match("ProvisionedThroughputExceededException") + @markers.requires_in_process @markers.aws.only_localstack def test_dynamodb_read_error_injection(self, monkeypatch, aws_client, dynamodb_create_table): table_name = dynamodb_create_table()["TableDescription"]["TableName"] @@ -68,6 +71,7 @@ def test_dynamodb_read_error_injection(self, monkeypatch, aws_client, dynamodb_c ) exc.match("ProvisionedThroughputExceededException") + @markers.requires_in_process @markers.aws.only_localstack def test_dynamodb_write_error_injection(self, monkeypatch, aws_client, dynamodb_create_table): table_name = dynamodb_create_table()["TableDescription"]["TableName"] diff --git a/tests/aws/test_integration.py b/tests/aws/test_integration.py index cf8e929672c33..171183df4d9fa 100644 --- a/tests/aws/test_integration.py +++ b/tests/aws/test_integration.py @@ -208,6 +208,7 @@ def _assert_objects_created(): # clean up aws_client.firehose.delete_delivery_stream(DeliveryStreamName=stream_name) + @pytest.mark.skip(reason="flaky") @markers.aws.unknown def test_lambda_streams_batch_and_transactions( self, diff --git a/tests/aws/test_network_configuration.py b/tests/aws/test_network_configuration.py index de6a7dcdbdd3b..71d4bf2706915 100644 --- a/tests/aws/test_network_configuration.py +++ b/tests/aws/test_network_configuration.py @@ -27,6 +27,7 @@ class TestOpenSearch: OpenSearch does not respect any customisations and just returns a domain with localhost.localstack.cloud in. """ + @markers.requires_in_process @markers.aws.only_localstack def test_default_strategy( self, opensearch_create_domain, assert_host_customisation, aws_client @@ -60,6 +61,7 @@ def test_port_strategy( assert_host_customisation(endpoint) + @markers.requires_in_process @markers.aws.only_localstack def test_path_strategy( self, @@ -81,6 +83,7 @@ def test_path_strategy( class TestS3: @markers.aws.only_localstack + @markers.requires_in_process def test_non_us_east_1_location( self, s3_empty_bucket, cleanups, assert_host_customisation, aws_client_factory ): @@ -101,6 +104,7 @@ def cleanup(): assert_host_customisation(res["Location"]) + @markers.requires_in_process @markers.aws.only_localstack def test_multipart_upload(self, s3_bucket, assert_host_customisation, aws_client): key_name = f"key-{short_uid()}" @@ -119,6 +123,7 @@ def test_multipart_upload(self, s3_bucket, assert_host_customisation, aws_client assert_host_customisation(res["Location"]) + @markers.requires_in_process @markers.aws.only_localstack def test_201_response(self, s3_bucket, assert_host_customisation, aws_client): key_name = f"key-{short_uid()}" @@ -150,6 +155,7 @@ class TestSQS: * LOCALSTACK_HOST """ + @markers.requires_in_process @markers.aws.only_localstack def test_off_strategy_without_external_port( self, monkeypatch, sqs_create_queue, assert_host_customisation @@ -162,6 +168,7 @@ def test_off_strategy_without_external_port( assert_host_customisation(queue_url) assert queue_name in queue_url + @markers.requires_in_process @markers.aws.only_localstack def test_off_strategy_with_external_port( self, monkeypatch, sqs_create_queue, assert_host_customisation @@ -181,6 +188,7 @@ def test_off_strategy_with_external_port( assert queue_name in queue_url assert f":{external_port}" in queue_url + @markers.requires_in_process @markers.aws.only_localstack @pytest.mark.parametrize("strategy", ["standard", "domain"]) def test_domain_based_strategies( @@ -194,6 +202,7 @@ def test_domain_based_strategies( assert_host_customisation(queue_url) assert queue_name in queue_url + @markers.requires_in_process @markers.aws.only_localstack def test_path_strategy(self, monkeypatch, sqs_create_queue, assert_host_customisation): monkeypatch.setattr(config, "SQS_ENDPOINT_STRATEGY", "path") @@ -206,6 +215,7 @@ def test_path_strategy(self, monkeypatch, sqs_create_queue, assert_host_customis class TestLambda: + @markers.requires_in_process @markers.aws.only_localstack def test_function_url(self, assert_host_customisation, create_lambda_function, aws_client): function_name = f"function-{short_uid()}" @@ -226,6 +236,7 @@ def test_function_url(self, assert_host_customisation, create_lambda_function, a assert_host_customisation(function_url) + @markers.requires_in_process @pytest.mark.skip(reason="Not implemented for new provider (was tested for old provider)") @markers.aws.only_localstack def test_http_api_for_function_url( diff --git a/tests/bootstrap/cdk_templates/LocalStackHostBootstrap/ClusterStack.json b/tests/bootstrap/cdk_templates/LocalStackHostBootstrap/ClusterStack.json index b3d13d04488aa..34917a1af679b 100644 --- a/tests/bootstrap/cdk_templates/LocalStackHostBootstrap/ClusterStack.json +++ b/tests/bootstrap/cdk_templates/LocalStackHostBootstrap/ClusterStack.json @@ -27,7 +27,7 @@ "EncryptionAtRestOptions": { "Enabled": false }, - "EngineVersion": "OpenSearch_2.3", + "EngineVersion": "OpenSearch_2.19", "LogPublishingOptions": {}, "NodeToNodeEncryptionOptions": { "Enabled": false diff --git a/tests/bootstrap/test_cosmetic_configuration.py b/tests/bootstrap/test_cosmetic_configuration.py index ebdc7aee17337..aab3afd9006e8 100644 --- a/tests/bootstrap/test_cosmetic_configuration.py +++ b/tests/bootstrap/test_cosmetic_configuration.py @@ -46,14 +46,14 @@ def chosen_localstack_host() -> str: # these fixtures have been copied from the pre-existing fixtures @pytest.fixture(scope="class") -def class_container_factory() -> Generator[ContainerFactory, None, None]: +def class_container_factory() -> Generator[ContainerFactory]: factory = ContainerFactory() yield factory factory.remove_all_containers() @pytest.fixture(scope="class") -def class_stream_container_logs() -> Generator[LogStreamFactory, None, None]: +def class_stream_container_logs() -> Generator[LogStreamFactory]: factory = LogStreamFactory() yield factory factory.close() @@ -155,7 +155,7 @@ def infrastructure( stack, "Domain", domain_name=domain_name, - version=cdk.aws_opensearchservice.EngineVersion.OPENSEARCH_2_3, + version=cdk.aws_opensearchservice.EngineVersion.OPENSEARCH_2_19, ) cdk.CfnOutput(stack, "DomainEndpoint", value=domain.domain_endpoint) diff --git a/tests/cli/__init__.py b/tests/cli/__init__.py deleted file mode 100644 index 4c3a166dbd7a6..0000000000000 --- a/tests/cli/__init__.py +++ /dev/null @@ -1,2 +0,0 @@ -"""Bootstrapping is the process of starting localstack. This is not always testable in the regular integration test -environment. This is what this module is for.""" diff --git a/tests/cli/conftest.py b/tests/cli/conftest.py deleted file mode 100644 index 0579c8a9122cb..0000000000000 --- a/tests/cli/conftest.py +++ /dev/null @@ -1,10 +0,0 @@ -import pytest - -from localstack import config - - -@pytest.fixture(autouse=True) -def _setup_cli_environment(monkeypatch): - # normally we are setting LOCALSTACK_CLI in localstack/cli/main.py, which is not actually run in the tests - monkeypatch.setenv("LOCALSTACK_CLI", "1") - monkeypatch.setattr(config, "dirs", config.Directories.for_cli()) diff --git a/tests/cli/test_cli.py b/tests/cli/test_cli.py deleted file mode 100644 index 6177d381ec7ba..0000000000000 --- a/tests/cli/test_cli.py +++ /dev/null @@ -1,340 +0,0 @@ -import json -import logging -import os.path - -import pytest -import requests -from click.testing import CliRunner - -import localstack.utils.container_utils.docker_cmd_client -from localstack import config, constants -from localstack.cli.localstack import localstack as cli -from localstack.config import Directories, in_docker -from localstack.constants import MODULE_MAIN_PATH -from localstack.utils import bootstrap -from localstack.utils.bootstrap import in_ci -from localstack.utils.common import poll_condition -from localstack.utils.container_utils.container_client import ContainerClient, NoSuchImage -from localstack.utils.files import mkdir -from localstack.utils.net import get_free_udp_port -from localstack.utils.run import run, to_str - -LOG = logging.getLogger(__name__) - - -@pytest.fixture -def runner(): - return CliRunner() - - -def container_exists(client: ContainerClient, container_name: str) -> bool: - try: - container_id = client.get_container_id(container_name) - return True if container_id else False - except Exception: - return False - - -@pytest.fixture(autouse=True) -def container_client(): - client = localstack.utils.container_utils.docker_cmd_client.CmdDockerClient() - - yield client - - try: - client.stop_container(config.MAIN_CONTAINER_NAME, timeout=5) - except Exception: - pass - - # wait until container has been removed - assert poll_condition( - lambda: not container_exists(client, config.MAIN_CONTAINER_NAME), timeout=20 - ) - - -@pytest.fixture -def backup_and_remove_image(monkeypatch, container_client: ContainerClient): - """ - To test whether the image is pulled correctly, we must remove the image. - However we do not want to do this and remove the current image, so "back it - up" - i.e. tag it with another tag, and restore it afterwards. - """ - - source_image_name = f"{constants.DOCKER_IMAGE_NAME}:latest" - tagged_image_name = f"{constants.DOCKER_IMAGE_NAME}:backup" - container_client.tag_image(source_image_name, tagged_image_name) - container_client.remove_image(source_image_name, force=True) - monkeypatch.setenv("IMAGE_NAME", source_image_name) - - yield - - container_client.tag_image(tagged_image_name, source_image_name) - - -@pytest.fixture -def create_container(container_client: ContainerClient): - """Creates (but does not start) a docker container with the name 'localstack-main'""" - container_client.create_container(image_name="localstack/localstack", name="localstack-main") - yield - container_client.remove_container("localstack-main", force=True) - - -@pytest.mark.skipif(condition=in_docker(), reason="cannot run CLI tests in docker") -class TestCliContainerLifecycle: - def test_start_wait_stop(self, runner, container_client): - result = runner.invoke(cli, ["start", "-d"]) - assert result.exit_code == 0 - assert "starting LocalStack" in result.output - - result = runner.invoke(cli, ["wait", "-t", "60"]) - assert result.exit_code == 0 - - assert container_client.is_container_running(config.MAIN_CONTAINER_NAME), ( - "container name was not running after wait" - ) - - # Note: if `LOCALSTACK_HOST` is set to a domain that does not resolve to `127.0.0.1` then - # this test will fail - health = requests.get(config.external_service_url() + "/_localstack/health") - assert health.ok, f"health request did not return OK: {health.text}" - - result = runner.invoke(cli, ["stop"]) - assert result.exit_code == 0 - - with pytest.raises(requests.ConnectionError): - requests.get(config.external_service_url() + "/_localstack/health") - - @pytest.mark.usefixtures("backup_and_remove_image") - def test_pulling_image_message(self, runner, container_client: ContainerClient): - image_name_and_tag = f"{constants.DOCKER_IMAGE_NAME}:latest" - with pytest.raises(NoSuchImage): - container_client.inspect_image(image_name_and_tag, pull=False) - - result = runner.invoke(cli, ["start", "-d"]) - - assert result.exit_code == 0, result.output - - # we cannot check for "Pulling container image" which would be more accurate - # since it is printed in a temporary status line and may not be present in - # the output if the docker pull is fast enough, but we can check for the - # presence of another message which is present when pulling the image. - assert "download complete" in result.output - - def test_start_already_existing(self, runner, container_client, create_container): - # normal start - result = runner.invoke(cli, ["start"]) - assert container_exists(container_client, config.MAIN_CONTAINER_NAME) - assert result.exit_code == 1 - assert "Error" in result.output - assert "already exists" in result.output - - # detached start - result = runner.invoke(cli, ["start", "-d"]) - assert container_exists(container_client, config.MAIN_CONTAINER_NAME) - assert result.exit_code == 1 - assert "Error" in result.output - assert "already exists" in result.output - - def test_start_already_running(self, runner, container_client): - runner.invoke(cli, ["start", "-d"]) - runner.invoke(cli, ["wait", "-t", "180"]) - - # normal start - # - non-idempotent: non-zero exit code + error log if the container is already running - result = runner.invoke(cli, ["start"]) - assert container_exists(container_client, config.MAIN_CONTAINER_NAME) - assert result.exit_code == 1 - assert "Error" in result.output - assert "is already running" in result.output - - # detached start - # - idempotent - zero exit code + no error log if the container is already running - result = runner.invoke(cli, ["start", "-d"]) - assert container_exists(container_client, config.MAIN_CONTAINER_NAME) - assert result.exit_code == 0 - assert "Error" not in result.output - assert "is already running" in result.output - - def test_wait_timeout_raises_exception(self, runner, container_client): - # assume a wait without start fails - result = runner.invoke(cli, ["wait", "-t", "0.5"]) - assert result.exit_code != 0 - - def test_logs(self, runner, container_client): - result = runner.invoke(cli, ["logs"]) - assert result.exit_code != 0 - - runner.invoke(cli, ["start", "-d"]) - runner.invoke(cli, ["wait", "-t", "60"]) - - result = runner.invoke(cli, ["logs", "--tail", "20"]) - assert constants.READY_MARKER_OUTPUT in result.output.splitlines() - - def test_restart(self, runner, container_client): - result = runner.invoke(cli, ["restart"]) - assert result.exit_code != 0 - - runner.invoke(cli, ["start", "-d"]) - runner.invoke(cli, ["wait", "-t", "60"]) - - result = runner.invoke(cli, ["restart"]) - assert result.exit_code == 0 - assert "restarted" in result.output - - def test_status_services(self, runner): - result = runner.invoke(cli, ["status", "services"]) - assert result.exit_code != 0 - assert "could not connect to LocalStack health endpoint" in result.output - - runner.invoke(cli, ["start", "-d"]) - runner.invoke(cli, ["wait", "-t", "60"]) - - result = runner.invoke(cli, ["status", "services"]) - - # just a smoke test - assert "dynamodb" in result.output - for line in result.output.splitlines(): - if "dynamodb" in line: - assert "available" in line - - def test_custom_docker_flags(self, runner, tmp_path, monkeypatch, container_client): - volume = tmp_path / "volume" - volume.mkdir() - - monkeypatch.setattr(config, "DOCKER_FLAGS", f"-p 42069 -v {volume}:{volume}") - - runner.invoke(cli, ["start", "-d"]) - runner.invoke(cli, ["wait", "-t", "60"]) - - inspect = container_client.inspect_container(config.MAIN_CONTAINER_NAME) - assert "42069/tcp" in inspect["HostConfig"]["PortBindings"] - assert f"{volume}:{volume}" in inspect["HostConfig"]["Binds"] - - def test_volume_dir_mounted_correctly(self, runner, tmp_path, monkeypatch, container_client): - volume_dir = tmp_path / "volume" - - # set different directories and make sure they are mounted correctly - monkeypatch.setenv("LOCALSTACK_VOLUME_DIR", str(volume_dir)) - monkeypatch.setattr(config, "VOLUME_DIR", str(volume_dir)) - - runner.invoke(cli, ["start", "-d"]) - runner.invoke(cli, ["wait", "-t", "60"]) - - # check that mounts were created correctly - inspect = container_client.inspect_container(config.MAIN_CONTAINER_NAME) - binds = inspect["HostConfig"]["Binds"] - assert f"{volume_dir}:{constants.DEFAULT_VOLUME_DIR}" in binds - - def test_container_starts_non_root(self, runner, monkeypatch, container_client): - user = "localstack" - monkeypatch.setattr(config, "DOCKER_FLAGS", f"--user={user}") - - if in_ci() and os.path.exists("/home/runner"): - volume_dir = "/home/runner/.cache/localstack/volume/" - mkdir(volume_dir) - run(["sudo", "chmod", "-R", "777", volume_dir]) - - runner.invoke(cli, ["start", "-d"]) - runner.invoke(cli, ["wait", "-t", "60"]) - - cmd = ["awslocal", "stepfunctions", "list-state-machines"] - output = container_client.exec_in_container(config.MAIN_CONTAINER_NAME, cmd) - result = json.loads(output[0]) - assert "stateMachines" in result - - output = container_client.exec_in_container(config.MAIN_CONTAINER_NAME, ["ps", "-fu", user]) - assert "localstack-supervisor" in to_str(output[0]) - - def test_start_cli_within_container(self, runner, container_client, tmp_path): - output = container_client.run_container( - # CAVEAT: Updates to the Docker image are not immediately reflected when using the latest image from - # DockerHub in the CI. Re-build the Docker image locally through - # `IMAGE_NAME="localstack/localstack" ./bin/docker-helper.sh build` for local testing. - "localstack/localstack", - remove=True, - entrypoint="", - command=["bin/localstack", "start", "-d"], - volumes=[ - ("/var/run/docker.sock", "/var/run/docker.sock"), - (MODULE_MAIN_PATH, "/opt/code/localstack/localstack"), - ], - env_vars={"LOCALSTACK_VOLUME_DIR": f"{tmp_path}/ls-volume"}, - ) - stdout = to_str(output[0]) - assert "starting LocalStack" in stdout - assert "detaching" in stdout - - # assert that container is running - runner.invoke(cli, ["wait", "-t", "60"]) - - -@pytest.mark.skipif(condition=in_docker(), reason="cannot run CLI tests in docker") -class TestDNSServer: - def test_dns_port_published_with_flag(self, runner, container_client, monkeypatch): - port = get_free_udp_port() - monkeypatch.setenv("DEBUG", "1") - monkeypatch.setenv("DNS_PORT", str(port)) - monkeypatch.setattr(config, "DNS_PORT", port) - - runner.invoke(cli, ["start", "-d", "--host-dns"]) - runner.invoke(cli, ["wait", "-t", "60"]) - - inspect = container_client.inspect_container(config.MAIN_CONTAINER_NAME) - assert f"{port}/udp" in inspect["HostConfig"]["PortBindings"] - - def test_dns_port_not_published_by_default(self, runner, container_client, monkeypatch): - monkeypatch.setenv("DEBUG", "1") - - runner.invoke(cli, ["start", "-d"]) - runner.invoke(cli, ["wait", "-t", "60"]) - - inspect = container_client.inspect_container(config.MAIN_CONTAINER_NAME) - assert "53/udp" not in inspect["HostConfig"]["PortBindings"] - - -class TestHooks: - def test_prepare_host_hook_called_with_correct_dirs(self, runner, monkeypatch): - """ - Assert that the prepare_host(..) hook is called with the appropriate dirs layout (e.g., cache - dir writeable). Required, for example, for API key activation and local key caching. - """ - - # simulate that we're running in Docker - monkeypatch.setattr(config, "is_in_docker", True) - - result_configs = [] - - def _prepare_host(*args, **kwargs): - # store the configs that will be passed to prepare_host hooks (Docker status, infra process, dirs layout) - result_configs.append((config.is_in_docker, None, config.dirs)) - - # patch the prepare_host function which calls the hooks - monkeypatch.setattr(bootstrap, "prepare_host", _prepare_host) - - def noop(*args, **kwargs): - pass - - # patch start_infra_in_docker to be a no-op (we don't actually want to start the container for this test) - assert bootstrap.start_infra_in_docker - monkeypatch.setattr(bootstrap, "start_infra_in_docker", noop) - - # run the 'start' command, which should call the prepare_host hooks - runner.invoke(cli, ["start"]) - - # assert that result configs are as expected - assert len(result_configs) == 1 - dirs: Directories - in_docker, is_infra_process, dirs = result_configs[0] - assert in_docker is False - # cache dir should exist and be writeable - assert os.path.exists(dirs.cache) - assert os.access(dirs.cache, os.W_OK) - - -class TestImports: - """Simple tests to assert that certain code paths can be imported from the CLI""" - - def test_import_venv(self): - from localstack.utils.venv import VirtualEnvironment - - assert VirtualEnvironment diff --git a/tests/unit/test_dns_server.py b/tests/integration/dns/test_dns_server.py similarity index 95% rename from tests/unit/test_dns_server.py rename to tests/integration/dns/test_dns_server.py index c64f9ff5538be..479d4aefe5f09 100644 --- a/tests/unit/test_dns_server.py +++ b/tests/integration/dns/test_dns_server.py @@ -20,6 +20,14 @@ class TestDNSServer: + """ + End to end tests of our DNS server implementation. + These tests use the `example.org` and `example.com` domains for testing, and also tests the fallback to the public DNS + Changes in the upstream name resolution of those domains might lead to test failures. + + TODO we should investigate creating our own test domain with a fixed behavior to avoid potential test failures + """ + @pytest.fixture def dns_server(self): dns_port = get_free_udp_port() @@ -176,11 +184,12 @@ def test_dns_server_soa_record_suffix_matching(self, dns_server, query_dns): assert "something.org." in answer.to_text() assert "noc.something.org." in answer.to_text() + @pytest.mark.skip(reason="failing as of 2025-12-17") def test_dns_server_subdomain_of_route(self, dns_server, query_dns): """Test querying a subdomain of a record entry without a wildcard""" # add ipv4 host - dns_server.add_host("example.org", TargetRecord("127.0.0.1", RecordType.A)) - answer = query_dns("nonexistent.example.org", "A") + dns_server.add_host("example.com", TargetRecord("127.0.0.1", RecordType.A)) + answer = query_dns("nonexistent.example.com", "A") assert not answer.answer # should still have authority section # TODO uncomment once it is clear why in CI the authority section is missing @@ -301,19 +310,19 @@ def test_dns_server_alias_lifecycle(self, dns_server, query_dns): """Test adding and deleting aliases""" dns_server.add_host("example.org", TargetRecord("122.122.122.122", RecordType.A)) dns_server.add_alias( - source_name="foo.something.org", + source_name="foo.example.org", record_type=RecordType.A, target=AliasTarget(target="example.org"), ) - answer = query_dns("foo.something.org", "A") + answer = query_dns("foo.example.org", "A") assert answer.answer assert "122.122.122.122" in answer.to_text() # delete alias and try again dns_server.delete_alias( - source_name="foo.something.org", record_type=RecordType.A, target=AliasTarget(target="") + source_name="foo.example.org", record_type=RecordType.A, target=AliasTarget(target="") ) - answer = query_dns("foo.something.org", "A") + answer = query_dns("foo.example.org", "A") assert not answer.answer # check if add_host is still available @@ -420,7 +429,7 @@ def test_delete_operations_of_nonexistent_entries(self, dns_server): with pytest.raises(ValueError): dns_server.delete_alias( - source_name="foo.something.org", + source_name="foo.example.org", record_type=RecordType.A, target=AliasTarget(target=""), ) diff --git a/tests/integration/docker_utils/test_docker.py b/tests/integration/docker_utils/test_docker.py index 668f7843bd291..45a754a87e682 100644 --- a/tests/integration/docker_utils/test_docker.py +++ b/tests/integration/docker_utils/test_docker.py @@ -20,6 +20,7 @@ from localstack.utils.container_utils.container_client import ( AccessDenied, ContainerClient, + ContainerConfiguration, ContainerException, DockerContainerStats, DockerContainerStatus, @@ -43,7 +44,12 @@ reserve_available_container_port, reserve_container_port, ) -from localstack.utils.net import Port, PortNotAvailableException, get_free_tcp_port +from localstack.utils.net import ( + Port, + PortNotAvailableException, + get_addressable_container_host, + get_free_tcp_port, +) from localstack.utils.strings import to_bytes from localstack.utils.sync import retry from localstack.utils.threads import FuncThread @@ -128,6 +134,84 @@ def _create_network(network_name: str): LOG.debug("Error while cleaning up network %s: %s", network, e) +@pytest.fixture +def authenticated_registry(docker_client: ContainerClient, create_container): + """ + Creates and starts an authenticated Docker registry for testing. + Returns a dict with registry details: port, username, password, auth_config, and cleanup function. + """ + registry_port = get_free_tcp_port() + registry_name = _random_container_name() + + username = "testuser" + password = "testpass" + # precomputed_hash = bcrypt.hashpw(password.encode(), bcrypt.gensalt()) + precomputed_hash = b"$2b$12$aR8RRkqWtpy.lZetR15tT.PjDmTsRX7p3fHNbOe0bPDV4xArNTVZG" + htpasswd_content = f"{username}:".encode() + precomputed_hash + b"\n" + + # Create and start registry container + ports = PortMappings() + ports.add(registry_port, 5000) + + htpasswd_content_str = htpasswd_content.decode("utf-8").strip() + registry_container = create_container( + "registry:2", + name=registry_name, + ports=ports, + env_vars={ + "REGISTRY_AUTH": "htpasswd", + "REGISTRY_AUTH_HTPASSWD_PATH": "/auth/htpasswd", + "REGISTRY_AUTH_HTPASSWD_REALM": "Registry Realm", + "REGISTRY_HTTP_SECRET": "localstack-registry-secret", + }, + command=[ + "sh", + "-c", + f"mkdir -p /auth && echo '{htpasswd_content_str}' > /auth/htpasswd && exec /entrypoint.sh /etc/docker/registry/config.yml", + ], + ) + docker_client.start_container(registry_container.container_id) + + registry_host = get_addressable_container_host() + + def _check_registry_auth(): + import requests + + s = requests.Session() + s.trust_env = False + url = f"http://{registry_host}:{registry_port}/v2/" + response = s.get( + url, + auth=(username, password), + timeout=2, + ) + if response.status_code == 200: + LOG.info("Registry authentication ready at %s", url) + return + raise Exception(f"Registry auth check returned status {response.status_code}") + + retry(_check_registry_auth, retries=20, sleep=0.5) + + yield { + "port": registry_port, + "host": registry_host, # For health checks from test container + "docker_host": "localhost", # For Docker daemon to push/pull (always localhost, Docker treats it as insecure) + "name": registry_name, + "container_id": registry_container.container_id, + "auth_config": { + "username": username, + "password": password, + }, + } + + # Cleanup + try: + docker_client.stop_container(registry_name) + docker_client.remove_container(registry_name) + except Exception: + LOG.warning("Failed to clean up registry container: %s", registry_name, exc_info=True) + + class TestDockerClient: def test_get_system_info(self, docker_client: ContainerClient): info = docker_client.get_system_info() @@ -1275,6 +1359,136 @@ def test_push_invalid_registry(self, docker_client: ContainerClient): finally: docker_client.remove_image(image_name) + @markers.skip_offline + def test_authenticated_pull_with_invalid_credentials( + self, docker_client: ContainerClient, authenticated_registry + ): + docker_host = authenticated_registry["docker_host"] + port = authenticated_registry["port"] + test_image = f"{docker_host}:{port}/test-image-{short_uid()}:latest" + + # Try to pull without credentials + with pytest.raises((NoSuchImage, ContainerException)): + docker_client.pull_image(test_image) + + wrong_auth = { + "username": authenticated_registry["auth_config"]["username"], + "password": "wrongpassword", + } + with pytest.raises(ContainerException): + docker_client.pull_image(test_image, auth_config=wrong_auth) + + @markers.skip_offline + def test_authenticated_push_and_pull( + self, docker_client: ContainerClient, authenticated_registry + ): + registry_port = authenticated_registry["port"] + docker_host = authenticated_registry["docker_host"] + auth_config = authenticated_registry["auth_config"] + test_image = f"{docker_host}:{registry_port}/test-hello-{short_uid()}:latest" + + try: + _pull_image_if_not_exists(docker_client, "hello-world") + docker_client.tag_image("hello-world", test_image) + + docker_client.push_image(test_image, auth_config=auth_config) + docker_client.remove_image(test_image) + + docker_client.pull_image(test_image, auth_config=auth_config) + + # Verify exists + image_info = docker_client.inspect_image(test_image, pull=False) + assert test_image in image_info.get("RepoTags", []) + + finally: + try: + docker_client.remove_image(test_image) + except Exception: + pass + + @markers.skip_offline + def test_authenticated_push_without_credentials_raises_error( + self, docker_client: ContainerClient, authenticated_registry + ): + registry_port = authenticated_registry["port"] + docker_host = authenticated_registry["docker_host"] + test_image = f"{docker_host}:{registry_port}/test-hello-{short_uid()}:latest" + + _pull_image_if_not_exists(docker_client, "hello-world") + docker_client.tag_image("hello-world", test_image) + + try: + with pytest.raises(AccessDenied): + docker_client.push_image(test_image) + + finally: + try: + docker_client.remove_image(test_image) + except Exception: + pass + + @markers.skip_offline + @pytest.mark.parametrize( + "method,use_config", + [ + ("create", False), + ("run", False), + ("create", True), + ("run", True), + ], + ids=[ + "create_container", + "run_container", + "create_container_from_config", + "run_container_from_config", + ], + ) + def test_container_operations_with_auth_config( + self, docker_client: ContainerClient, authenticated_registry, method: str, use_config: bool + ): + registry_port = authenticated_registry["port"] + docker_host = authenticated_registry["docker_host"] + auth_config = authenticated_registry["auth_config"] + test_image = f"{docker_host}:{registry_port}/test-hello-{short_uid()}:latest" + + try: + _pull_image_if_not_exists(docker_client, "hello-world") + docker_client.tag_image("hello-world", test_image) + docker_client.push_image(test_image, auth_config=auth_config) + docker_client.remove_image(test_image) + + # Execute the appropriate method + if use_config: + container_config = ContainerConfiguration( + image_name=test_image, + auth_config=auth_config, + ) + if method == "create": + container = docker_client.create_container_from_config(container_config) + output, _ = docker_client.start_container(container, attach=True) + else: # method == "run" + output, _ = docker_client.run_container_from_config(container_config) + else: + if method == "create": + container = docker_client.create_container( + image_name=test_image, + auth_config=auth_config, + ) + output, _ = docker_client.start_container(container, attach=True) + else: # method == "run" + output, _ = docker_client.run_container( + image_name=test_image, + auth_config=auth_config, + ) + + assert "hello" in output.decode(config.DEFAULT_ENCODING) + + finally: + try: + docker_client.remove_image(test_image) + except Exception: + pass + @markers.skip_offline def test_tag_image(self, docker_client: ContainerClient): if _is_podman_test() and isinstance(docker_client, SdkDockerClient): @@ -2187,6 +2401,35 @@ def test_get_container_stats(self, docker_client, create_container): assert 0.0 <= stats["MemPerc"] <= 100.0 +class TestDockerCgroupLimits: + def test_run_container_with_memory_limit(self, docker_client, create_container): + container = create_container( + "alpine", + command=[ + "sh", + "-c", + "if [ -e /sys/fs/cgroup/cgroup.controllers ]; then cat /sys/fs/cgroup/memory.max; else cat /sys/fs/cgroup/memory/memory.limit_in_bytes; fi", + ], + mem_limit="128m", + ) + stdout, _ = docker_client.start_container(container.container_id, attach=True) + assert "134217728" in stdout.decode("utf-8") + + def test_run_container_with_cpu_shares(self, docker_client, create_container): + container = create_container( + "alpine", + command=[ + "sh", + "-c", + "if [ -e /sys/fs/cgroup/cgroup.controllers ]; then cat /sys/fs/cgroup/cpu.weight; else cat /sys/fs/cgroup/cpu,cpuacct/cpu.shares; fi", + ], + cpu_shares=256, + ) + stdout, _ = docker_client.start_container(container.container_id, attach=True) + stdout = stdout.decode("utf-8") + assert "35" in stdout or "256" in stdout + + def _pull_image_if_not_exists(docker_client: ContainerClient, image_name: str): if image_name not in docker_client.get_docker_image_names(): docker_client.pull_image(image_name) diff --git a/tests/integration/test_catalog.py b/tests/integration/test_catalog.py new file mode 100644 index 0000000000000..4717dfc04647c --- /dev/null +++ b/tests/integration/test_catalog.py @@ -0,0 +1,212 @@ +import json + +import pytest +from botocore.exceptions import WaiterError + +from localstack import config +from localstack.services.cloudformation.engine.v2 import ( + change_set_resource_support_checker as support_checker_module, +) +from localstack.services.cloudformation.engine.v2.change_set_resource_support_checker import ( + ChangeSetResourceSupportChecker, +) +from localstack.testing.pytest import markers +from localstack.utils.catalog.catalog import ( + AwsServicesSupportStatus, + CatalogPlugin, + CfnResourceSupportStatus, +) +from localstack.utils.catalog.common import ( + AwsServicesSupportInLatest, + AwsServiceSupportAtRuntime, + CloudFormationResourcesSupportAtRuntime, + CloudFormationResourcesSupportInLatest, +) +from localstack.utils.strings import short_uid + +UNSUPPORTED_RESOURCE_CASES = [ + ( + "AWS::TestService::UnsupportedLatest", + CloudFormationResourcesSupportInLatest.NOT_SUPPORTED, + "testservice", + ), + ( + "AWS::RuntimeService::NotImplemented", + CloudFormationResourcesSupportAtRuntime.NOT_IMPLEMENTED, + "runtimeservice", + ), + ( + "AWS::LicenseRuntime::RequiresUpgrade", + AwsServiceSupportAtRuntime.AVAILABLE_WITH_LICENSE_UPGRADE, + "licenseruntime", + ), + ( + "AWS::RuntimeService::Missing", + AwsServiceSupportAtRuntime.NOT_IMPLEMENTED, + "runtimeservice", + ), + ( + "AWS::LatestService::RequiresUpgrade", + AwsServicesSupportInLatest.SUPPORTED_WITH_LICENSE_UPGRADE, + "latestservice", + ), + ( + "AWS::LatestService::NotSupported", + AwsServicesSupportInLatest.NOT_SUPPORTED, + "latestservice", + ), +] + + +class _TestingCatalogPlugin(CatalogPlugin): + name = "testing-catalog" + + def __init__(self): + self._unsupported_resources = { + resource: status for resource, status, _ in UNSUPPORTED_RESOURCE_CASES + } + + def get_aws_service_status( + self, service_name: str, operation_name: str | None = None + ) -> AwsServicesSupportStatus | None: + return AwsServicesSupportInLatest.SUPPORTED + + def get_cloudformation_resource_status( + self, resource_name: str, service_name: str, is_pro_resource: bool = False + ) -> CfnResourceSupportStatus | AwsServicesSupportInLatest | None: + return self._unsupported_resources.get( + resource_name, CloudFormationResourcesSupportAtRuntime.AVAILABLE + ) + + +@pytest.fixture +def testing_catalog(monkeypatch): + plugin = _TestingCatalogPlugin() + monkeypatch.setattr(support_checker_module, "get_aws_catalog", lambda: plugin) + return plugin + + +@markers.aws.only_localstack +def test_ignore_unsupported_resources_toggle(testing_catalog, aws_client, monkeypatch, cleanups): + unsupported_resource = "AWS::LatestService::NotSupported" + + # template with one supported and one unsupported resource + bucket_name = f"cfn-toggle-{short_uid()}" + template_body = json.dumps( + { + "Resources": { + "SupportedBucket": { + "Type": "AWS::S3::Bucket", + "Properties": {"BucketName": bucket_name}, + }, + "Unsupported": {"Type": unsupported_resource}, + }, + } + ) + + # 1) ignore lists empty -> change set should fail + monkeypatch.setattr(config, "CFN_IGNORE_UNSUPPORTED_RESOURCE_TYPES", False) + monkeypatch.setattr(config, "CFN_IGNORE_UNSUPPORTED_TYPE_CREATE", []) + stack_name_fail = f"stack-fail-{short_uid()}" + change_set_name_fail = f"cs-{short_uid()}" + response = aws_client.cloudformation.create_change_set( + StackName=stack_name_fail, + ChangeSetName=change_set_name_fail, + TemplateBody=template_body, + ChangeSetType="CREATE", + ) + cs_id_fail, stack_id_fail = response["Id"], response["StackId"] + + waiter = aws_client.cloudformation.get_waiter("change_set_create_complete") + with pytest.raises(WaiterError) as exc_info: + waiter.wait( + ChangeSetName=cs_id_fail, + ) + + assert exc_info.value.last_response["Status"] == "FAILED" + status_reason = exc_info.value.last_response["StatusReason"] + assert ChangeSetResourceSupportChecker.TITLE_MESSAGE in status_reason + assert unsupported_resource in status_reason + cleanups.append(lambda: aws_client.cloudformation.delete_change_set(ChangeSetName=cs_id_fail)) + cleanups.append(lambda: aws_client.cloudformation.delete_stack(StackName=stack_id_fail)) + + # 2) add unsupported resource to create ignore list -> deployment succeeds and bucket is present + monkeypatch.setattr(config, "CFN_IGNORE_UNSUPPORTED_TYPE_CREATE", [unsupported_resource]) + stack_name_ok = f"stack-ok-{short_uid()}" + change_set_name_ok = f"cs-{short_uid()}" + response = aws_client.cloudformation.create_change_set( + StackName=stack_name_ok, + ChangeSetName=change_set_name_ok, + TemplateBody=template_body, + ChangeSetType="CREATE", + ) + cs_id_ok, stack_id_ok = response["Id"], response["StackId"] + + waiter.wait( + ChangeSetName=cs_id_ok, + ) + aws_client.cloudformation.execute_change_set(ChangeSetName=cs_id_ok) + aws_client.cloudformation.get_waiter("stack_create_complete").wait( + StackName=stack_name_ok, + ) + + buckets = aws_client.s3.list_buckets()["Buckets"] + assert any(b["Name"] == bucket_name for b in buckets) + + cleanups.append(lambda: aws_client.cloudformation.delete_stack(StackName=stack_id_ok)) + + +@markers.aws.only_localstack +@pytest.mark.parametrize( + "unsupported_resource, expected_service", + [(resource, expected_service) for resource, _, expected_service in UNSUPPORTED_RESOURCE_CASES], +) +def test_catalog_reports_unsupported_resources_in_stack_status( + testing_catalog, aws_client, unsupported_resource, expected_service, monkeypatch, cleanups +): + monkeypatch.setattr(config, "CFN_IGNORE_UNSUPPORTED_RESOURCE_TYPES", False) + template_body = json.dumps( + { + "Resources": {"Unsupported": {"Type": unsupported_resource}}, + } + ) + + stack_name = f"stack-{short_uid()}" + change_set_name = f"change-set-{short_uid()}" + + response = aws_client.cloudformation.create_change_set( + StackName=stack_name, + ChangeSetName=change_set_name, + TemplateBody=template_body, + Capabilities=["CAPABILITY_AUTO_EXPAND", "CAPABILITY_IAM", "CAPABILITY_NAMED_IAM"], + ChangeSetType="CREATE", + ) + + change_set_id = response["Id"] + stack_id = response["StackId"] + + waiter = aws_client.cloudformation.get_waiter("change_set_create_complete") + with pytest.raises(WaiterError) as exc_info: + waiter.wait( + ChangeSetName=change_set_id, + ) + assert exc_info.value.last_response["Status"] == "FAILED" + status_reason = exc_info.value.last_response["StatusReason"] + assert ChangeSetResourceSupportChecker.TITLE_MESSAGE in status_reason + assert unsupported_resource in status_reason + + with pytest.raises(WaiterError) as exc_info: + aws_client.cloudformation.get_waiter("stack_create_complete").wait( + StackName=stack_id, + ) + + stack_description = exc_info.value.last_response["Stacks"][0] + stack_status_reason = stack_description.get("StackStatusReason", "") + assert ChangeSetResourceSupportChecker.TITLE_MESSAGE in stack_status_reason + assert unsupported_resource in stack_status_reason + assert expected_service in stack_status_reason.lower() + + cleanups.append( + lambda: aws_client.cloudformation.delete_change_set(ChangeSetName=change_set_id) + ) + cleanups.append(lambda: aws_client.cloudformation.delete_stack(StackName=stack_id)) diff --git a/tests/unit/aws/handlers/test_service.py b/tests/unit/aws/handlers/test_service.py index ee8c9c3127b37..22dd95e9f94eb 100644 --- a/tests/unit/aws/handlers/test_service.py +++ b/tests/unit/aws/handlers/test_service.py @@ -1,4 +1,8 @@ +from collections.abc import Iterable + import pytest +from moto.core.exceptions import RESTError, ServiceException +from moto.ec2.exceptions import EC2_ERROR_RESPONSE from localstack.aws.api import CommonServiceException, RequestContext from localstack.aws.chain import HandlerChain @@ -6,6 +10,7 @@ from localstack.aws.handlers.service import ServiceExceptionSerializer, ServiceResponseParser from localstack.aws.protocol.serializer import create_serializer from localstack.http import Request, Response +from localstack.utils.catalog.common import AwsServiceSupportAtRuntime @pytest.fixture @@ -146,21 +151,45 @@ def test_invalid_exception_does_nothing(self, service_response_handler_chain): class TestServiceExceptionSerializer: @pytest.mark.parametrize( - "message, output", + "catalog_status, expected_message", [ - ("", "not available in your current license plan or has not yet been emulated"), - ("Ups!", "Ups!"), + ( + AwsServiceSupportAtRuntime.AVAILABLE_WITH_LICENSE_UPGRADE, + "is not included within your LocalStack license", + ), + ( + None, + "The API for service opensearch is either not included in your current license plan or has not yet been emulated by LocalStack.", + ), ], ) - def test_not_implemented_error(self, message, output): + def test_not_implemented_error_uses_catalog_when_message_is_empty( + self, catalog_status, expected_message, aws_catalog_mock + ): + catalog = aws_catalog_mock("localstack.aws.handlers.service.get_aws_catalog") + catalog.get_aws_service_status.return_value = catalog_status + context = create_aws_request_context( + "opensearch", "DescribeDomain", "rest-json", {"DomainName": "foobar"} + ) + not_implemented_exception = NotImplementedError("") + + ServiceExceptionSerializer().create_exception_response(not_implemented_exception, context) + + assert expected_message in context.service_exception.message + assert context.service_exception.code == "InternalFailure" + assert not context.service_exception.sender_fault + assert context.service_exception.status_code == 501 + + def test_not_implemented_error_with_custom_message(self): context = create_aws_request_context( "opensearch", "DescribeDomain", "rest-json", {"DomainName": "foobar"} ) - not_implemented_exception = NotImplementedError(message) + custom_message = "Ups!" + not_implemented_exception = NotImplementedError(custom_message) ServiceExceptionSerializer().create_exception_response(not_implemented_exception, context) - assert output in context.service_exception.message + assert context.service_exception.message == custom_message assert context.service_exception.code == "InternalFailure" assert not context.service_exception.sender_fault assert context.service_exception.status_code == 501 @@ -198,3 +227,69 @@ def capture_original_exception_handler( assert err_context.service_exception.__traceback__ assert err_context.service_exception.__traceback__ == raised_exception.__traceback__ assert err_context.service_exception.status_code == 500 + + def test_moto_service_exception_is_translated(self, service_response_handler_chain): + # Redefine exception here but use the right base exc. This is to improve tolerance against Moto refactors. + class MessageRejectedError(ServiceException): + code = "MessageRejected" + + # Ensure ServiceExceptions are translated + context = create_aws_request_context( + "ses", + "SendRawEmail", + "query", + { + "Destinations": ["invalid@example.com"], + "RawMessage": { + "Data": b"From: origin@example.com\nTo: destination@example.com\nSubject: sub\n\nbody\n\n" + }, + }, + ) + msg = "Did not have authority to send email" + moto_exception = MessageRejectedError(msg) + + ServiceExceptionSerializer().create_exception_response(moto_exception, context) + + assert msg in context.service_exception.message + assert context.service_exception.code == "MessageRejected" + assert not context.service_exception.sender_fault + assert context.service_exception.status_code == 400 + + def test_moto_rest_error_is_translated(self, service_response_handler_chain): + # Redefine exception here but use the right base exc. This is to improve tolerance against Moto refactors. + class InvalidKeyPairNameError(RESTError): + code = 400 + request_id_tag_name = "RequestID" + extended_templates = {"custom_response": EC2_ERROR_RESPONSE} + env = RESTError.extended_environment(extended_templates) + + def __init__(self, key: Iterable[str]): + super().__init__( + "InvalidKeyPair.NotFound", + f"The keypair '{key}' does not exist.", + template="custom_response", + ) + + # Ensure RESTErrors are translated + context = create_aws_request_context( + "ec2", + "RunInstances", + "ec2", + { + "ImageId": "ami-deadc0de", + "InstanceType": "t3.nano", + "KeyName": "some-key-pair", + "MaxCount": 1, + "MinCount": 1, + }, + ) + moto_exception = InvalidKeyPairNameError({"some-key-pair"}) + + ServiceExceptionSerializer().create_exception_response(moto_exception, context) + + assert ( + "The keypair '{'some-key-pair'}' does not exist." in context.service_exception.message + ) + assert context.service_exception.code == "InvalidKeyPair.NotFound" + assert not context.service_exception.sender_fault + assert context.service_exception.status_code == 400 diff --git a/tests/unit/aws/protocol/test_parser.py b/tests/unit/aws/protocol/test_parser.py index 78a5297a3bbb4..4b686dc636e8c 100644 --- a/tests/unit/aws/protocol/test_parser.py +++ b/tests/unit/aws/protocol/test_parser.py @@ -910,9 +910,9 @@ def test_ec2_parser_ec2_with_botocore(): def test_restjson_parser_path_params_with_slashes(): _botocore_parser_integration_test( - service="qldb", + service="appconfig", action="ListTagsForResource", - ResourceArn="arn:aws:qldb:eu-central-1:000000000000:ledger/c-c67c827a", + ResourceArn="arn:aws:appconfig:us-east-1:000000000000:application/application-1/environment/env-1", ) @@ -1452,7 +1452,6 @@ def test_restxml_ignores_get_body(): def test_smithy_rpc_v2_cbor(): # we are using a service that LocalStack does not implement yet because it implements `smithy-rpc-v2-cbor` # we can replace this service by CloudWatch once it has support in Botocore - # TODO: test timestamp parsing # example taken from: # https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/arc-region-switch/client/create_plan.html @@ -1525,6 +1524,24 @@ def test_smithy_rpc_v2_cbor(): ) +def test_rpc_v2_cbor_timestamp_parsing(): + # This is a real request from the Java SDK v2 + # It does not encode Timestamps like Botocore: it encodes them as Double of Length 8 (botocore uses Integer) + request = HttpRequest( + method="POST", + path="/v1/service/GraniteServiceVersion20100801/operation/PutMetricData", + body=b"\xbfiNamespacelSITE/TRAFFICjMetricData\x81\xbfjMetricNamemPAGES_VISITEDjDimensions\x81\xbfdNamelUNIQUE_PAGESeValuedURLS\xffiTimestamp\xc1\xfbA\xdaP\xaf+\x88\xa3\xd7eValue\xfb?\xf3\xbfg\xf4\xdb\xdf\x8fdUnitdNone\xff\xff", + ) + parser = create_parser(load_service("cloudwatch"), protocol="smithy-rpc-v2-cbor") + parsed_operation_model, parsed_request = parser.parse(request) + timestamp = parsed_request["MetricData"][0]["Timestamp"] + assert isinstance(timestamp, datetime) + assert timestamp.microsecond == 135000 + assert timestamp.second == 38 + assert timestamp.minute == 22 + assert timestamp.tzinfo == UTC + + @pytest.mark.parametrize("protocol", ("json", "smithy-rpc-v2-cbor")) def test_protocol_selection(protocol): # we are using a service that LocalStack does not implement yet because it implements `smithy-rpc-v2-cbor` diff --git a/tests/unit/aws/protocol/test_serializer.py b/tests/unit/aws/protocol/test_serializer.py index 5deb13d118c3b..6821796927b25 100644 --- a/tests/unit/aws/protocol/test_serializer.py +++ b/tests/unit/aws/protocol/test_serializer.py @@ -97,8 +97,11 @@ def _botocore_serializer_integration_test( # Use the parser from botocore to parse the serialized response response_parser = create_parser(service_protocol) + # Properly use HeadersDict from botocore to properly parse headers + response_dict = serialized_response.to_readonly_response_dict() + response_dict["headers"] = HeadersDict(response_dict.get("headers", {})) parsed_response = response_parser.parse( - serialized_response.to_readonly_response_dict(), + response_dict, service.operation_model(action).output_shape, ) diff --git a/tests/unit/aws/test_connect.py b/tests/unit/aws/test_connect.py index 85962c4b41964..447f37be471d1 100644 --- a/tests/unit/aws/test_connect.py +++ b/tests/unit/aws/test_connect.py @@ -198,22 +198,18 @@ def test_external_aws_client_credentials_loaded_from_env_if_set_to_none( "iam", "iot", "iot_data", - "iotanalytics", "iotwireless", "kafka", "kinesis", "kms", "lakeformation", "logs", - "mediastore", "mq", "mwaa", "neptune", "opensearch", "organizations", "pi", - "qldb", - "qldb_session", "rds", "rds_data", "redshift", diff --git a/tests/unit/aws/test_service_router.py b/tests/unit/aws/test_service_router.py index 2b82a579b18bf..5dece947a4782 100644 --- a/tests/unit/aws/test_service_router.py +++ b/tests/unit/aws/test_service_router.py @@ -101,6 +101,9 @@ def _collect_operations() -> tuple[ServiceModel, OperationModel]: "sagemaker-edge", "sagemaker-featurestore-runtime", "sagemaker-metrics", + "signin", + "signer", # `signer` has conflicts with `signer-data` `GetRevocationStatus` + "signer-data", "sms-voice", "sso", "sso-oidc", diff --git a/tests/unit/aws/test_skeleton.py b/tests/unit/aws/test_skeleton.py index d61099b839868..8c4ebba8b793a 100644 --- a/tests/unit/aws/test_skeleton.py +++ b/tests/unit/aws/test_skeleton.py @@ -14,6 +14,7 @@ from localstack.aws.skeleton import DispatchTable, ServiceRequestDispatcher, Skeleton from localstack.aws.spec import load_service from localstack.http import Request +from localstack.utils.catalog.common import AwsServiceSupportAtRuntime """ Stripped down version of the SQS API generated by the Scaffold. """ @@ -196,23 +197,28 @@ def test_skeleton_e2e_sqs_send_message(): @pytest.mark.parametrize( - "api_class, oracle_message", + "api_class, service_support_status, oracle_message", [ ( TestSqsApiNotImplemented(), + AwsServiceSupportAtRuntime.NOT_IMPLEMENTED, ( - "The API action 'SendMessage' for service 'sqs' is either not available " - "in your current license plan or has not yet been emulated by LocalStack. " - "Please refer to https://docs.localstack.cloud/references/coverage/coverage_sqs for more information." + "Sorry, the SendMessage operation on the sqs service is not currently supported by LocalStack." ), ), ( TestSqsApiNotImplementedWithMessage(), + AwsServiceSupportAtRuntime.NOT_IMPLEMENTED, "We will implement it soon, that's a promise!", ), ], ) -def test_skeleton_e2e_sqs_send_message_not_implemented(api_class, oracle_message): +def test_skeleton_e2e_sqs_send_message_not_implemented( + api_class, service_support_status, oracle_message, aws_catalog_mock +): + catalog = aws_catalog_mock("localstack.aws.skeleton.get_aws_catalog") + catalog.get_aws_service_status.return_value = service_support_status + sqs_service = load_service("sqs-query") skeleton = Skeleton(sqs_service, api_class) request = Request( @@ -287,7 +293,9 @@ def delete_queue(_context: RequestContext, _request: ServiceRequest): } -def test_dispatch_missing_method_returns_internal_failure(): +def test_dispatch_missing_method_returns_internal_failure(aws_catalog_mock): + catalog = aws_catalog_mock("localstack.aws.skeleton.get_aws_catalog") + catalog.get_aws_service_status.return_value = AwsServiceSupportAtRuntime.NOT_IMPLEMENTED table: DispatchTable = {} sqs_service = load_service("sqs-query") @@ -316,9 +324,7 @@ def test_dispatch_missing_method_returns_internal_failure(): assert parsed_response["Error"] == { "Code": "InternalFailure", "Message": ( - "The API action 'DeleteQueue' for service 'sqs' is either not available in your " - "current license plan or has not yet been emulated by LocalStack. " - "Please refer to https://docs.localstack.cloud/references/coverage/coverage_sqs for more information." + "Sorry, the DeleteQueue operation on the sqs service is not currently supported by LocalStack." ), } diff --git a/tests/unit/cli/test_cli.py b/tests/unit/cli/test_cli.py deleted file mode 100644 index 0313ded90f218..0000000000000 --- a/tests/unit/cli/test_cli.py +++ /dev/null @@ -1,336 +0,0 @@ -import json -import logging -import sys -import threading -from queue import Queue - -import click -import pytest -from click.testing import CliRunner - -import localstack.constants -import localstack.utils.analytics.cli -from localstack import config -from localstack.cli.localstack import create_with_plugins, is_frozen_bundle -from localstack.cli.localstack import localstack as cli -from localstack.config import HostAndPort -from localstack.constants import VERSION -from localstack.http import Request -from localstack.utils.common import is_command_available -from localstack.utils.container_utils.container_client import ContainerException, DockerNotAvailable - -cli: click.Group - - -@pytest.fixture -def runner(): - return CliRunner() - - -@pytest.mark.parametrize( - "exception,expected_message", - [ - (KeyboardInterrupt(), "Aborted!"), - (DockerNotAvailable(), "Docker could not be found on the system"), - (ContainerException("example message"), "example message"), - (click.ClickException("example message"), "example message"), - (click.exceptions.Exit(code=1), ""), - ], -) -def test_error_handling(runner: CliRunner, monkeypatch, exception, expected_message): - """Test different globally handled exceptions, their status code, and error message.""" - - def mock_call(*args, **kwargs): - raise exception - - from localstack.utils import bootstrap - - monkeypatch.setattr(bootstrap, "start_infra_locally", mock_call) - result = runner.invoke(cli, ["start", "--host"]) - assert result.exit_code == 1 - assert expected_message in result.output - - -def test_error_handling_help(runner): - """Make sure the help command is not interpreted as an error (Exit exception is raised).""" - result = runner.invoke(cli, ["-h"]) - assert result.exit_code == 0 - assert "Usage: localstack" in result.output - - -def test_create_with_plugins(runner): - localstack_cli = create_with_plugins() - result = runner.invoke(localstack_cli.group, ["--version"]) - assert result.exit_code == 0 - assert result.output.strip() == f"LocalStack CLI {VERSION}" - - -def test_version(runner): - result = runner.invoke(cli, ["--version"]) - assert result.exit_code == 0 - assert result.output.strip() == f"LocalStack CLI {VERSION}" - - -def test_status_services_error(runner): - result = runner.invoke(cli, ["status", "services"]) - assert result.exit_code == 1 - assert "Error" in result.output - - -@pytest.mark.parametrize("command", ["ssh", "stop"]) -def test_container_not_runnin_error(runner, command): - result = runner.invoke(cli, [command]) - assert result.exit_code == 1 - assert "Error" in result.output - assert "Expected a running LocalStack container" in result.output - - -def test_start_docker_is_default(runner, monkeypatch): - from localstack.utils import bootstrap - - called = threading.Event() - - def mock_call(*args, **kwargs): - called.set() - - monkeypatch.setattr(bootstrap, "start_infra_in_docker", mock_call) - runner.invoke(cli, ["start"]) - assert called.is_set() - - -def test_start_host(runner, monkeypatch): - from localstack.utils import bootstrap - - called = threading.Event() - - def mock_call(*args, **kwargs): - called.set() - - monkeypatch.setattr(bootstrap, "start_infra_locally", mock_call) - runner.invoke(cli, ["start", "--host"]) - assert called.is_set() - - -def test_status_services(runner, httpserver, monkeypatch): - # configure LOCALSTACK_HOST because the services endpoint makes a request against the - # external URL of LocalStack, which may be different to the edge port - monkeypatch.setattr( - config, - "LOCALSTACK_HOST", - HostAndPort( - host="localhost.localstack.cloud", - port=httpserver.port, - ), - ) - - services = {"dynamodb": "starting", "s3": "running"} - httpserver.expect_request("/_localstack/health", method="GET").respond_with_json( - {"services": services} - ) - - result = runner.invoke(cli, ["status", "services"]) - - assert result.exit_code == 0, result - - assert "dynamodb" in result.output - assert "s3" in result.output - - for line in result.output.splitlines(): - if "dynamodb" in line: - assert "starting" in line - assert "running" not in line - if "s3" in line: - assert "running" in line - assert "starting" not in line - - -def test_validate_config(runner, monkeypatch, tmp_path): - if not is_command_available("docker-compose"): - pytest.skip("config validation needs the docker-compose command") - - file = tmp_path / "docker-compose.yml" - file.touch() - - file.write_text( - """version: "3.3" -services: - localstack: - container_name: "${LOCALSTACK_DOCKER_NAME-localstack-main}" - image: localstack/localstack - network_mode: bridge - ports: - - "127.0.0.1:53:53" - - "127.0.0.1:53:53/udp" - - "127.0.0.1:443:443" - - "127.0.0.1:4566:4566" - - "127.0.0.1:4571:4571" - environment: - - SERVICES=${SERVICES- } - - DEBUG=${DEBUG- } - - DATA_DIR=${DATA_DIR- } - - LOCALSTACK_AUTH_TOKEN=${LOCALSTACK_AUTH_TOKEN- } - - KINESIS_ERROR_PROBABILITY=${KINESIS_ERROR_PROBABILITY- } - - DOCKER_HOST=unix:///var/run/docker.sock - volumes: - - "${TMPDIR:-/tmp/localstack}:/tmp/localstack" - - "/var/run/docker.sock:/var/run/docker.sock" -""" - ) - - result = runner.invoke(cli, ["config", "validate", "--file", str(file)]) - - assert result.exit_code == 0 - assert "config valid" in result.output - - -def test_validate_config_syntax_error(runner, monkeypatch, tmp_path): - if not is_command_available("docker-compose"): - pytest.skip("config validation needs the docker-compose command") - - file = tmp_path / "docker-compose.yml" - file.touch() - - file.write_text("foobar.---\n") - - result = runner.invoke(cli, ["config", "validate", "--file", str(file)]) - - assert result.exit_code == 1 - assert "Error" in result.output - - -@pytest.mark.parametrize( - "cli_input,expected_cmd,expected_params", - [ - ("stop", "localstack stop", []), - ("config show", "localstack config show", ["format_"]), - ("--debug config show --format plain", "localstack config show", ["format_"]), - ], -) -def test_publish_analytics_event_on_command_invocation( - cli_input, expected_cmd, expected_params, runner, monkeypatch, caplog, httpserver -): - # must suppress pytest logging due to weird issue with click https://github.com/pytest-dev/pytest/issues/3344 - caplog.set_level(logging.CRITICAL) - monkeypatch.setattr(localstack.utils.analytics.cli, "ANALYTICS_API_RESPONSE_TIMEOUT_SECS", 3) - request_data = Queue() - input = cli_input.split(" ") - - def _handler(_request: Request): - request_data.put(_request.data) - - httpserver.expect_request("").respond_with_handler(_handler) - monkeypatch.setattr(localstack.constants, "ANALYTICS_API", httpserver.url_for("/")) - runner.invoke(cli, input) - request_payload = request_data.get(timeout=5) - - assert request_data.qsize() == 0 - payload = json.loads(request_payload) - events = payload["events"] - assert len(events) == 1 - event = events[0] - metadata = event["metadata"] - assert "client_time" in metadata - assert "session_id" in metadata - assert event["name"] == "cli_cmd" - assert event["payload"]["cmd"] == expected_cmd - assert event["payload"]["params"] == expected_params - - -@pytest.mark.parametrize( - "cli_input", - [ - "invalid", - "status services", - "config show --format invalid", - ], -) -def test_do_not_publish_analytics_event_on_invalid_command_invocation( - cli_input, runner, monkeypatch, caplog, httpserver -): - # must suppress pytest logging due to weird issue with click https://github.com/pytest-dev/pytest/issues/3344 - caplog.set_level(logging.CRITICAL) - monkeypatch.setattr(localstack.utils.analytics.cli, "ANALYTICS_API_RESPONSE_TIMEOUT_SECS", 3) - request_data = [] - input = cli_input.split(" ") - - def _handler(_request: Request): - request_data.append(_request.data) - - httpserver.expect_request("").respond_with_handler(_handler) - monkeypatch.setenv("ANALYTICS_API", httpserver.url_for("/")) - runner.invoke(cli, input) - assert len(request_data) == 0, ( - "analytics API should not be invoked when an invalid command is supplied" - ) - - -def test_disable_publish_analytics_event_on_command_invocation( - runner, monkeypatch, caplog, httpserver -): - # must suppress pytest logging due to weird issue with click https://github.com/pytest-dev/pytest/issues/3344 - caplog.set_level(logging.CRITICAL) - monkeypatch.setattr(localstack.utils.analytics.cli, "ANALYTICS_API_RESPONSE_TIMEOUT_SECS", 3) - monkeypatch.setattr(localstack.config, "DISABLE_EVENTS", True) - request_data = [] - - def _handler(_request: Request): - request_data.append(_request.data) - - httpserver.expect_request("").respond_with_handler(_handler) - monkeypatch.setenv("ANALYTICS_API", httpserver.url_for("/")) - runner.invoke(cli, ["config", "show"]) - assert len(request_data) == 0, "analytics API should not be invoked when DISABLE_EVENTS is set" - - -def test_timeout_publishing_command_invocation(runner, monkeypatch, caplog, httpserver): - # must suppress pytest logging due to weird issue with click https://github.com/pytest-dev/pytest/issues/3344 - caplog.set_level(logging.CRITICAL) - monkeypatch.setattr( - # simulate slow API call by turning timeout way down - localstack.utils.analytics.cli, - "ANALYTICS_API_RESPONSE_TIMEOUT_SECS", - 0.001, - ) - request_data = [] - - def _handler(_request: Request): - request_data.append(_request.data) - - httpserver.expect_request("").respond_with_handler(_handler) - monkeypatch.setenv("ANALYTICS_API", httpserver.url_for("/")) - runner.invoke(cli, ["config", "show"]) - assert len(request_data) == 0, ( - "analytics event publisher process should time out if request is taking too long" - ) - - -def test_is_frozen(monkeypatch): - # mimic a frozen pyinstaller binary according to https://pyinstaller.org/en/stable/runtime-information.html - monkeypatch.setattr(sys, "frozen", True, raising=False) - monkeypatch.setattr(sys, "_MEIPASS", "/absolute/path/to/bundle/folder", raising=False) - assert is_frozen_bundle() - - -def test_not_is_frozen(monkeypatch): - # mimic running from source - monkeypatch.delattr(sys, "frozen", raising=False) - assert not is_frozen_bundle() - monkeypatch.setattr(sys, "frozen", True, raising=False) - monkeypatch.delattr(sys, "_MEIPASS", raising=False) - assert not is_frozen_bundle() - - -@pytest.mark.parametrize("shell", ["bash", "zsh", "fish"]) -def test_completion(monkeypatch, runner, shell: str): - test_binary_name = "testbinaryname" - monkeypatch.setattr(localstack.config, "DISABLE_EVENTS", True) - monkeypatch.setattr(sys, "argv", [test_binary_name]) - result = runner.invoke(cli, ["completion", shell]) - assert result.exit_code == 0 - assert f"_{test_binary_name.upper()}_COMPLETE={shell}_complete" in result.output - - -def test_completion_unknown_shell(monkeypatch, runner): - monkeypatch.setattr(localstack.config, "DISABLE_EVENTS", True) - result = runner.invoke(cli, ["completion", "unknown_shell"]) - assert result.exit_code != 0 diff --git a/tests/unit/cli/test_profiles.py b/tests/unit/cli/test_profiles.py deleted file mode 100644 index c48fd4b9e739d..0000000000000 --- a/tests/unit/cli/test_profiles.py +++ /dev/null @@ -1,148 +0,0 @@ -import os -import sys - -from localstack.cli.profiles import set_and_remove_profile_from_sys_argv - - -def profile_test(monkeypatch, input_args, expected_profile, expected_argv): - monkeypatch.setattr(sys, "argv", input_args) - monkeypatch.setenv("CONFIG_PROFILE", "") - set_and_remove_profile_from_sys_argv() - assert os.environ["CONFIG_PROFILE"] == expected_profile - assert sys.argv == expected_argv - - -def test_profiles_equals_notation(monkeypatch): - profile_test( - monkeypatch, - input_args=["--profile=non-existing-test-profile"], - expected_profile="non-existing-test-profile", - expected_argv=[], - ) - - -def test_profiles_separate_args_notation(monkeypatch): - profile_test( - monkeypatch, - input_args=["--profile", "non-existing-test-profile"], - expected_profile="non-existing-test-profile", - expected_argv=[], - ) - - -def test_p_equals_notation(monkeypatch): - profile_test( - monkeypatch, - input_args=["-p=non-existing-test-profile"], - expected_profile="non-existing-test-profile", - expected_argv=["-p=non-existing-test-profile"], - ) - - -def test_p_separate_args_notation(monkeypatch): - profile_test( - monkeypatch, - input_args=["-p", "non-existing-test-profile"], - expected_profile="non-existing-test-profile", - expected_argv=["-p", "non-existing-test-profile"], - ) - - -def test_profiles_args_before_and_after(monkeypatch): - profile_test( - monkeypatch, - input_args=["cli", "-D", "--profile=non-existing-test-profile", "start"], - expected_profile="non-existing-test-profile", - expected_argv=["cli", "-D", "start"], - ) - - -def test_profiles_args_before_and_after_separate(monkeypatch): - profile_test( - monkeypatch, - input_args=["cli", "-D", "--profile", "non-existing-test-profile", "start"], - expected_profile="non-existing-test-profile", - expected_argv=["cli", "-D", "start"], - ) - - -def test_p_args_before_and_after_separate(monkeypatch): - profile_test( - monkeypatch, - input_args=["cli", "-D", "-p", "non-existing-test-profile", "start"], - expected_profile="non-existing-test-profile", - expected_argv=["cli", "-D", "-p", "non-existing-test-profile", "start"], - ) - - -def test_profiles_args_multiple(monkeypatch): - profile_test( - monkeypatch, - input_args=[ - "cli", - "--profile", - "non-existing-test-profile", - "start", - "--profile", - "another-profile", - ], - expected_profile="another-profile", - expected_argv=["cli", "start"], - ) - - -def test_p_args_multiple(monkeypatch): - profile_test( - monkeypatch, - input_args=[ - "cli", - "-p", - "non-existing-test-profile", - "start", - "-p", - "another-profile", - ], - expected_profile="non-existing-test-profile", - expected_argv=[ - "cli", - "-p", - "non-existing-test-profile", - "start", - "-p", - "another-profile", - ], - ) - - -def test_p_and_profile_args(monkeypatch): - profile_test( - monkeypatch, - input_args=[ - "cli", - "-p", - "non-existing-test-profile", - "start", - "--profile", - "the_profile", - "-p", - "another-profile", - ], - expected_profile="the_profile", - expected_argv=[ - "cli", - "-p", - "non-existing-test-profile", - "start", - "-p", - "another-profile", - ], - ) - - -def test_trailing_p_argument(monkeypatch): - profile_test( - monkeypatch, - input_args=["cli", "start", "-p"], - expected_profile="", - expected_argv=["cli", "start", "-p"], - ) diff --git a/tests/unit/services/cloudformation/test_deploy_ui.py b/tests/unit/services/cloudformation/test_deploy_ui.py deleted file mode 100644 index d5db5387bc579..0000000000000 --- a/tests/unit/services/cloudformation/test_deploy_ui.py +++ /dev/null @@ -1,12 +0,0 @@ -from rolo import Request - -from localstack.services.cloudformation.deploy_ui import CloudFormationUi - - -class TestCloudFormationUiResource: - def test_get(self): - resource = CloudFormationUi() - response = resource.on_get(Request("GET", "/", body=b"None")) - assert response.status == "200 OK" - assert "" in response.get_data(as_text=True), "deploy UI did not render HTML" - assert "text/html" in response.headers.get("content-type", "") diff --git a/tests/unit/services/cloudformation/test_provider_utils.py b/tests/unit/services/cloudformation/test_provider_utils.py index 78ee6b73727d6..dad72ee3534de 100644 --- a/tests/unit/services/cloudformation/test_provider_utils.py +++ b/tests/unit/services/cloudformation/test_provider_utils.py @@ -200,3 +200,17 @@ def test_lower_camelcase_to_pascalcase_skip_keys(self): original_dict, skip_keys={"Configuration"} ) assert converted_dict == target_dict + + def test_resource_tags_to_remove_or_update(self): + previous = [ + {"Key": "k1", "Value": "v1"}, + {"Key": "k2", "Value": "v2"}, + {"Key": "k3", "Value": "v3"}, + {"Key": "k4", "Value": "v4"}, + ] + desired = [{"Key": "k2", "Value": "v2-updated"}, {"Key": "k3", "Value": "v3"}] + + to_remove, to_update = utils.resource_tags_to_remove_or_update(previous, desired) + + assert sorted(to_remove) == ["k1", "k4"] + assert to_update == {"k2": "v2-updated", "k3": "v3"} diff --git a/tests/unit/services/s3/test_s3.py b/tests/unit/services/s3/test_s3.py index 313fc03add170..adac05fd12298 100644 --- a/tests/unit/services/s3/test_s3.py +++ b/tests/unit/services/s3/test_s3.py @@ -18,6 +18,11 @@ from localstack.services.s3.codec import AwsChunkedDecoder from localstack.services.s3.constants import S3_CHUNK_SIZE from localstack.services.s3.exceptions import MalformedXML +from localstack.services.s3.headers import ( + decode_header_rfc2047, + encode_header_rfc2047, + replace_non_iso_8859_1_characters, +) from localstack.services.s3.models import S3Multipart, S3Object, S3Part from localstack.services.s3.storage.ephemeral import EphemeralS3ObjectStore from localstack.services.s3.validation import validate_canned_acl @@ -369,6 +374,31 @@ def test_parse_post_object_tagging_xml_exception(self): def test_get_bucket_and_key_from_s3_uri(self, s3_uri, bucket, object_key): assert s3_utils.get_bucket_and_key_from_s3_uri(s3_uri) == (bucket, object_key) + @pytest.mark.parametrize( + "lower_case, header_name", + [ + ("test-header", "Test-Header"), + ("test-response-header", "Test-Response-Header"), + ("testHeader", "Testheader"), + ], + ) + def test_capitalized_snake_case(self, lower_case, header_name): + assert s3_utils.capitalize_header_name_from_snake_case(lower_case) == header_name + + @pytest.mark.parametrize( + "param_name, header_name", + [ + ("ResponseContentType", "response-content-type"), + ("ResponseContentLanguage", "response-content-language"), + ("ResponseExpires", "response-expires"), + ("ResponseCacheControl", "response-cache-control"), + ("ResponseContentDisposition", "response-content-disposition"), + ("ResponseContentEncoding", "response-content-encoding"), + ], + ) + def test_header_name_from_pascal_case(self, param_name, header_name): + assert s3_utils.header_name_from_capitalized_param(param_name) == header_name + class TestS3PresignedUrl: """ @@ -726,3 +756,98 @@ def test_version_id_ordering(self): for index, version_id in enumerate(version_ids[1:]): previous_version = version_ids[index] assert s3_utils.is_version_older_than_other(previous_version, version_id) + + +class TestS3HeaderEncoding: + @pytest.mark.parametrize( + "header, expected", + [ + ("ÄMÄZÕÑ S3", "=?UTF-8?Q?=C3=84M=C3=84Z=C3=95=C3=91_S3?="), + ( + "test_—_file%E2%80%94_é_2.pdf", + "=?UTF-8?Q?test=5F=E2=80=94=5Ffile%E2%80%94=5F=C3=A9=5F2.pdf?=", + ), + ( + "test_—_file%E2%80%94_é_2👑.pdf", + "=?UTF-8?Q?test=5F=E2=80=94=5Ffile%E2%80%94=5F=C3=A9=5F2=F0=9F=91=91.pdf?=", + ), + ( + "! \"#$%&'()*+,-./0123456789:;<>'?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\t", + "! \"#$%&'()*+,-./0123456789:;<>'?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\t", + ), + ("\x00\x01\x02\x03\x04", "=?UTF-8?B?AAECAwQ=?="), + ], + ) + def test_encode_header_rfc_2047(self, header, expected): + assert encode_header_rfc2047(header) == expected + + @pytest.mark.parametrize( + "header, expected", + [ + ( + "=?UTF-8?Q?=C3=84M=C3=84Z=C3=95=C3=91_S3?=", + "ÄMÄZÕÑ S3", + ), + ( + "=?UTF-8?Q?test=5F=E2=80=94=5Ffile%E2%80%94=5F=C3=A9=5F2.pdf?=", + "test_—_file%E2%80%94_é_2.pdf", + ), + ( + "=?UTF-8?Q?test=5F=E2=80=94=5Ffile%E2%80%94=5F=C3=A9=5F2=F0=9F=91=91.pdf?=", + "test_—_file%E2%80%94_é_2👑.pdf", + ), + ( + "! \"#$%&'()*+,-./0123456789:;<>'?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\t", + "! \"#$%&'()*+,-./0123456789:;<>'?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\t", + ), + ( + "=?UTF-8?B?AAECAwQ=?=", + "\x00\x01\x02\x03\x04", + ), + # broken B64 + ( + "=?UTF-8?B?=GGG?=", + "���", + ), + ], + ) + def test_decode_header_rfc2047(self, header, expected): + assert decode_header_rfc2047(header) == expected + + @pytest.mark.parametrize( + "header, expected", + [ + ("non-ascii-%E2%80%94_—_é_", "non-ascii-%E2%80%94_ _é_"), + ('filename="test_—_file%E2%80%94_é_2.pdf"', 'filename="test_ _file%E2%80%94_é_2.pdf"'), + ( + 'filename="test_—_file%E2%80%94_é_2.pdf"', + 'filename="test_ _file%E2%80%94_é_2.pdf"', + ), + ("", ""), + ], + ) + def test_sanitize_for_latin_1_header(self, header, expected): + assert replace_non_iso_8859_1_characters(header) == expected + + +class TestS3ContinuationToken: + @pytest.mark.parametrize( + "key", + [ + "file%2Fname", + "test@key/", + "test%123", + "test%percent", + "test key/", + "test key//", + "test%123/", + "a/%F0%9F%98%80/", + "date=2026-01-01/", + "date=2026-02-01/", + "date=2026-03-01/", + "date=2026-05-01/", + ], + ) + def test_continuation_token_is_consistent(self, key): + encoded_key = s3_utils.encode_continuation_token(key) + assert s3_utils.decode_continuation_token(encoded_key) == key diff --git a/tests/unit/services/sns/test_sns.py b/tests/unit/services/sns/test_sns.py index 545ea6d39c1ed..e842065a4b52e 100644 --- a/tests/unit/services/sns/test_sns.py +++ b/tests/unit/services/sns/test_sns.py @@ -13,11 +13,11 @@ from localstack.services.sns.provider import ( encode_subscription_token_with_region, get_region_from_subscription_token, - is_raw_message_delivery, ) from localstack.services.sns.publisher import ( compute_canonical_string, create_sns_message_body, + is_raw_message_delivery, ) from localstack.utils.time import timestamp_millis diff --git a/tests/unit/services/stepfunctions/test_jsonata_variable_references.py b/tests/unit/services/stepfunctions/test_jsonata_variable_references.py new file mode 100644 index 0000000000000..e991443853800 --- /dev/null +++ b/tests/unit/services/stepfunctions/test_jsonata_variable_references.py @@ -0,0 +1,84 @@ +"""Unit tests for JSONata variable reference extraction. + +Regression tests for https://github.com/localstack/localstack/issues/13579 +""" + +import pytest + +from localstack.services.stepfunctions.asl.jsonata.jsonata import ( + IllegalJSONataVariableReference, + extract_jsonata_variable_references, +) + + +class TestExtractJsonataVariableReferences: + def test_simple_variable(self): + refs = extract_jsonata_variable_references("$states.input.foo") + assert refs == {"$states.input.foo"} + + def test_multiple_variables(self): + refs = extract_jsonata_variable_references("$states.input.part1 + $states.input.part2") + assert refs == {"$states.input.part1", "$states.input.part2"} + + def test_variables_inside_array_literal(self): + """Regression test for #13579: $merge with dynamic args returns {}.""" + refs = extract_jsonata_variable_references( + "$merge([$states.input.part1, $states.input.part2])" + ) + assert refs == {"$merge", "$states.input.part1", "$states.input.part2"} + + def test_variables_inside_nested_brackets(self): + refs = extract_jsonata_variable_references("$append([$a, $b], [$c])") + assert refs == {"$append", "$a", "$b", "$c"} + + def test_variable_with_bracket_field_access(self): + """String literals inside brackets should be skipped by branch 2.""" + refs = extract_jsonata_variable_references('$states.input["field-name"]') + assert refs == {"$states.input"} + + def test_variable_inside_string_literal_ignored(self): + refs = extract_jsonata_variable_references('"$notavar"') + assert refs == set() + + def test_variable_inside_single_quote_string_ignored(self): + refs = extract_jsonata_variable_references("'$notavar'") + assert refs == set() + + def test_variable_inside_regex_literal_ignored(self): + refs = extract_jsonata_variable_references("/\\$pattern/i") + assert refs == set() + + def test_empty_expression(self): + refs = extract_jsonata_variable_references("") + assert refs == set() + + def test_no_variables(self): + refs = extract_jsonata_variable_references("1 + 2") + assert refs == set() + + def test_lone_dollar_ignored(self): + """Bare $ is the JSONata context variable (e.g. in filter predicates + like [$ = 1]) — it should not be extracted as a variable reference.""" + refs = extract_jsonata_variable_references("$") + assert refs == set() + + def test_double_dollar_raises(self): + """$$ is the JSONata root input reference — it is captured by the regex + but rejected as an illegal variable reference.""" + with pytest.raises(IllegalJSONataVariableReference): + extract_jsonata_variable_references("$$") + + def test_filter_expression_with_variable(self): + refs = extract_jsonata_variable_references("$data[$type]") + assert refs == {"$data", "$type"} + + def test_filter_predicate_with_context_variable(self): + """Filter predicates using bare $ (context variable) should not cause + errors or be extracted. Regression test for MAP_TASK_STATE expressions + like $count($states.result[$ = 1]).""" + refs = extract_jsonata_variable_references("$count($states.result[$ = 1])") + assert refs == {"$count", "$states.result"} + + def test_filter_predicate_bare_dollar_equals_zero(self): + refs = extract_jsonata_variable_references("$states.result[$ = 0]") + assert refs == {"$states.result"} diff --git a/tests/unit/test_common.py b/tests/unit/test_common.py index e0e93b4be7669..6ed89d8cc4e60 100644 --- a/tests/unit/test_common.py +++ b/tests/unit/test_common.py @@ -2,7 +2,6 @@ import io import itertools import os -import threading import time import zipfile from datetime import UTC, date, datetime, timedelta @@ -95,8 +94,20 @@ def test_now_utc(self): test = datetime.now(UTC).timestamp() assert test == pytest.approx(env, 1) - def test_is_number(self): - assert common.is_number(5) + @pytest.mark.parametrize( + "value,is_number", + [ + (5, True), + (-12.1, True), + (2e15, True), + ("test", False), + (False, False), + (True, False), + (None, False), + ], + ) + def test_is_number(self, value, is_number): + assert common.is_number(value) == is_number def test_is_ip_address(self): assert common.is_ip_address("10.0.0.1") @@ -351,24 +362,6 @@ def test_format_number(self): assert fn(-12.521, decimals=4) == "-12.521" assert fn(-1.2234354123e3, decimals=4) == "-1223.4354" - def test_cleanup_threads_and_processes_calls_shutdown_hooks(self): - # TODO: move all run/concurrency related tests into separate class - - started = threading.Event() - done = threading.Event() - - def run_method(*args, **kwargs): - started.set() - func_thread = kwargs["_thread"] - # thread waits until it is stopped - func_thread._stop_event.wait() - done.set() - - common.start_thread(run_method) - assert started.wait(timeout=2) - common.cleanup_threads_and_processes() - assert done.wait(timeout=2) - def test_proxy_map(self): old_http_proxy = config.OUTBOUND_HTTP_PROXY old_https_proxy = config.OUTBOUND_HTTPS_PROXY @@ -534,6 +527,15 @@ def test_save_load_file(tmp_path): assert content + more_content == load_file(file_name) +def test_load_file_strict(tmp_path): + file_name = tmp_path / short_uid() + assert not os.path.isfile(file_name) + + assert load_file(file_name) is None + with pytest.raises(FileNotFoundError): + load_file(file_name, strict=True) + + def test_save_load_file_with_permissions(tmp_path): file_name = tmp_path / (f"special_permissions_{short_uid()}") content = f"some_content_{short_uid()}" diff --git a/tests/unit/test_dockerclient.py b/tests/unit/test_dockerclient.py index 146d86db33854..7e18bcd1af1c0 100644 --- a/tests/unit/test_dockerclient.py +++ b/tests/unit/test_dockerclient.py @@ -13,6 +13,7 @@ PortMappings, Ulimit, Util, + get_registry_from_image_name, ) from localstack.utils.container_utils.docker_cmd_client import CmdDockerClient @@ -388,3 +389,64 @@ def test_adjacent_port_to_many_to_one(self): } result = port_mappings.to_dict() assert result == expected_result + + +class TestGetRegistryFromImageName: + """Tests for the get_registry_from_image_name utility function.""" + + @pytest.mark.parametrize( + "image_name,expected", + [ + # Docker Hub images (no explicit registry) + ("nginx", "docker.io"), + ("nginx:latest", "docker.io"), + ("localstack/localstack", "docker.io"), + ("localstack/localstack:latest", "docker.io"), + # Images with explicit registry + ("private-registry.com/localstack/localstack", "private-registry.com"), + ("private-registry.com/localstack", "private-registry.com"), + ("registry.example.com/my-image:v1.0", "registry.example.com"), + # Localhost registries + ("localhost:5000/myimage", "localhost:5000"), + ("localhost/myimage", "localhost"), + # Docker Hub with explicit domain + ("docker.io/nginx", "docker.io"), + ("docker.io/nginx:latest", "docker.io"), + # AWS ECR + ( + "123456789.dkr.ecr.us-east-1.amazonaws.com/my-repo", + "123456789.dkr.ecr.us-east-1.amazonaws.com", + ), + ( + "123456789.dkr.ecr.us-east-1.amazonaws.com/my-repo:tag", + "123456789.dkr.ecr.us-east-1.amazonaws.com", + ), + # Google Container Registry + ("gcr.io/my-project/my-image", "gcr.io"), + ("gcr.io/my-project/my-image:latest", "gcr.io"), + # Registry with port + ("registry.example.com:5000/image", "registry.example.com:5000"), + ("registry.example.com:443/image:tag", "registry.example.com:443"), + # LocalStack ECR + ( + "000000000000.dkr.ecr.us-east-1.localhost.localstack.cloud:4566/repo", + "000000000000.dkr.ecr.us-east-1.localhost.localstack.cloud:4566", + ), + ], + ) + def test_extract_registry_from_various_image_formats(self, image_name, expected): + """Test extracting registry from various Docker image name formats.""" + assert get_registry_from_image_name(image_name) == expected + + @pytest.mark.parametrize( + "prefix,image_name,expected", + [ + ("my-mirror.example.com", "nginx:latest", "my-mirror.example.com"), + ("my-mirror.example.com", "docker.io/nginx:latest", "my-mirror.example.com"), + ("my-mirror.example.com", "registry.example.com/image", "my-mirror.example.com"), + ("harbor.example.com", "localhost:5000/myimage", "harbor.example.com"), + ], + ) + def test_with_docker_global_image_prefix(self, image_name, expected, prefix, monkeypatch): + monkeypatch.setattr(config, "DOCKER_GLOBAL_IMAGE_PREFIX", prefix) + assert get_registry_from_image_name(image_name) == expected diff --git a/tests/unit/test_moto.py b/tests/unit/test_moto.py index af650cdcffcb9..10ab416d54ead 100644 --- a/tests/unit/test_moto.py +++ b/tests/unit/test_moto.py @@ -1,8 +1,6 @@ import pytest -from moto.core.exceptions import ServiceException -from localstack.aws.api import CommonServiceException -from localstack.services.moto import ServiceExceptionTranslator, get_dispatcher +from localstack.services.moto import get_dispatcher def test_get_dispatcher_for_path_with_optional_slashes(): @@ -13,22 +11,3 @@ def test_get_dispatcher_for_path_with_optional_slashes(): def test_get_dispatcher_for_non_existing_path_raises_not_implemented(): with pytest.raises(NotImplementedError): get_dispatcher("route53", "/non-existing") - - -def test_service_exception_translator_context_manager(): - class WeirdException(ServiceException): - code = "WeirdErrorCode" - - # Ensure Moto ServiceExceptions are translated to ASF CommonServiceException - with pytest.raises(CommonServiceException) as exc: - with ServiceExceptionTranslator(): - raise WeirdException() - assert exc.value.code == "WeirdErrorCode" - - # Ensure other exceptions are not affected - with pytest.raises(RuntimeError): - raise RuntimeError() - - with pytest.raises(RuntimeError): - with ServiceExceptionTranslator(): - raise RuntimeError() diff --git a/tests/unit/test_tagging.py b/tests/unit/test_tagging.py index 876fa15753485..fc0870cbd84f9 100644 --- a/tests/unit/test_tagging.py +++ b/tests/unit/test_tagging.py @@ -1,6 +1,7 @@ import pytest -from localstack.utils.tagging import TaggingService +from localstack.utils.strings import short_uid +from localstack.utils.tagging import TaggingService, Tags class TestTaggingService: @@ -45,3 +46,62 @@ def test_field_name_override(self, tagging_service): assert svc.list_tags_for_resource("arn") == { "Tags": [{"keY": "my", "valuE": "congratulations"}] } + + +@pytest.fixture +def mock_arn(): + return f"arn-{short_uid()}" + + +@pytest.fixture +def tags_collection(): + return Tags() + + +class TestTagsCollection: + def test_update_tags(self, tags_collection, mock_arn): + # Ensure the tags which existed / didn't exist before are updated accordingly. + tags_collection.update_tags(mock_arn, {"Environment": "Production", "Foo": "Bar"}) + tags = tags_collection.get_tags(mock_arn) + assert "Foo" in tags + assert tags["Foo"] == "Bar" + assert tags["Environment"] == "Production" + + def test_get_tags(self, tags_collection, mock_arn): + non_existent_resource_tags = tags_collection.get_tags("bad-arn") + assert len(non_existent_resource_tags) == 0 + + def test_delete_tags(self, tags_collection, mock_arn): + tags_collection.update_tags(mock_arn, {"Foo": "Bar"}) + + # Test deleting the same key twice even when it's not in the tag mapping. This should not raise. + for _ in range(2): + tags_collection.delete_tags(mock_arn, ["Environment"]) + tags = tags_collection.get_tags(mock_arn) + assert "Foo" in tags + assert len(tags) == 1 + + tags_collection.delete_tags(mock_arn, ["Foo"]) + tags = tags_collection.get_tags(mock_arn) + assert len(tags) == 0 + + # This operation shouldn't raise if the ARN is not in the tagging store. + non_existent_arn = f"non-existent-{short_uid()}" + tags_collection.delete_tags(non_existent_arn, ["Foo"]) + tags = tags_collection.get_tags(non_existent_arn) + assert len(tags) == 0 + + def test_delete_all_tags(self, tags_collection, mock_arn): + tags_collection.update_tags(mock_arn, {"Foo": "Bar", "Environment": "Testing"}) + tags = tags_collection.get_tags(mock_arn) + assert len(tags) == 2 + + tags_collection.delete_all_tags(mock_arn) + updated_tags = tags_collection.get_tags(mock_arn) + assert len(updated_tags) == 0 + + # Delete all tags should not raise if the ARN is not in the store + non_existent_arn = f"non-existent-{short_uid()}" + tags_collection.delete_all_tags(non_existent_arn) + tags = tags_collection.get_tags(non_existent_arn) + assert len(tags) == 0 diff --git a/tests/unit/utils/analytics/test_publisher.py b/tests/unit/utils/analytics/test_publisher.py index 4c24ebdaf14af..d7f3bde593c9f 100644 --- a/tests/unit/utils/analytics/test_publisher.py +++ b/tests/unit/utils/analytics/test_publisher.py @@ -1,6 +1,4 @@ import datetime -import threading -from queue import Queue import pytest @@ -8,7 +6,6 @@ from localstack.utils.analytics.client import AnalyticsClient from localstack.utils.analytics.events import Event, EventMetadata from localstack.utils.analytics.metadata import get_session_id -from localstack.utils.analytics.publisher import Publisher, PublisherBuffer from localstack.utils.sync import retry @@ -20,76 +17,6 @@ def new_event(payload=None) -> Event: ) -class TestPublisherBuffer: - def test_basic(self): - calls = Queue() - - class QueuePublisher(Publisher): - def publish(self, _events: list[Event]): - calls.put(_events) - - buffer = PublisherBuffer(QueuePublisher(), flush_size=2, flush_interval=1000) - - t = threading.Thread(target=buffer.run) - t.start() - - try: - e1 = new_event() - e2 = new_event() - e3 = new_event() - - buffer.handle(e1) - buffer.handle(e2) - - c1 = calls.get(timeout=2) - assert len(c1) == 2 - - buffer.handle(e3) # should flush after close despite flush_size = 2 - finally: - buffer.close() - - c2 = calls.get(timeout=2) - assert len(c2) == 1 - - assert c1[0] == e1 - assert c1[1] == e2 - assert c2[0] == e3 - - t.join(10) - - def test_interval(self): - calls = Queue() - - class QueuePublisher(Publisher): - def publish(self, _events: list[Event]): - calls.put(_events) - - buffer = PublisherBuffer(QueuePublisher(), flush_size=10, flush_interval=1) - - t = threading.Thread(target=buffer.run) - t.start() - - try: - e1 = new_event() - e2 = new_event() - e3 = new_event() - e4 = new_event() - - buffer.handle(e1) - buffer.handle(e2) - c1 = calls.get(timeout=2) - - buffer.handle(e3) - buffer.handle(e4) - c2 = calls.get(timeout=2) - finally: - buffer.close() - - assert len(c1) == 2 - assert len(c2) == 2 - t.join(10) - - class TestGlobalAnalyticsBus: def test(self, httpserver): httpserver.expect_request("/v0/session").respond_with_json({"track_events": True}) diff --git a/tests/unit/utils/aws/test_arns.py b/tests/unit/utils/aws/test_arns.py new file mode 100644 index 0000000000000..17c0c4409e718 --- /dev/null +++ b/tests/unit/utils/aws/test_arns.py @@ -0,0 +1,19 @@ +from localstack.utils.aws import arns + + +def test_arn_creation_with_colon_names(): + region_name = "us-east-1" + account_id = "123456789012" + name = "noColons" + name_colon = "col:on" + pattern = "arn:%s::%s:%s:thing/%s" + + assert ( + arns._resource_arn(name, pattern, account_id, region_name) + == f"arn:aws::{region_name}:{account_id}:thing/{name}" + ) + assert arns._resource_arn(name_colon, pattern, account_id, region_name) == name_colon + assert ( + arns._resource_arn(name_colon, pattern, account_id, region_name, True) + == f"arn:aws::{region_name:}:{account_id}:thing/{name_colon}" + ) diff --git a/tests/unit/utils/catalog/__init__.py b/tests/unit/utils/catalog/__init__.py new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/tests/unit/utils/catalog/conftest.py b/tests/unit/utils/catalog/conftest.py new file mode 100644 index 0000000000000..738e9b1214211 --- /dev/null +++ b/tests/unit/utils/catalog/conftest.py @@ -0,0 +1,38 @@ +from localstack.utils.catalog.common import AwsRemoteCatalog, LocalStackMetadata + +CATALOG = AwsRemoteCatalog( + schema_version="v1", + localstack=LocalStackMetadata(version="4.7"), + services={ + "athena": { + "pro": { + "provider": "athena:pro", + "operations": ["StartQueryExecution", "GetQueryExecution"], + "plans": ["ultimate", "enterprise"], + } + }, + "s3": { + "community": { + "provider": "s3:default", + "operations": ["CreateBucket"], + "plans": ["free", "base", "ultimate", "enterprise"], + }, + "pro": { + "provider": "s3:pro", + "operations": ["SelectObjectContent"], + "plans": ["base", "ultimate", "enterprise"], + }, + }, + "kms": { + "community": { + "provider": "kms:default", + "operations": ["ListKeys"], + "plans": ["free", "base", "ultimate", "enterprise"], + } + }, + }, + cloudformation_resources={ + "community": {"AWS::S3::Bucket": {"methods": ["Create", "Delete"]}}, + "pro": {"AWS::Athena::CapacitiesReservation": {"methods": ["Create", "Update", "Delete"]}}, + }, +) diff --git a/tests/unit/utils/test_catalog.py b/tests/unit/utils/catalog/test_catalog.py similarity index 52% rename from tests/unit/utils/test_catalog.py rename to tests/unit/utils/catalog/test_catalog.py index 974cd01920820..44fdc59410d6a 100644 --- a/tests/unit/utils/test_catalog.py +++ b/tests/unit/utils/catalog/test_catalog.py @@ -4,10 +4,13 @@ from localstack.utils.catalog.catalog_loader import RemoteCatalogLoader from localstack.utils.catalog.common import ( AwsRemoteCatalog, + AwsServiceCatalog, AwsServiceOperationsSupportInLatest, AwsServicesSupportInLatest, + CloudFormationResource, CloudFormationResourcesSupportAtRuntime, CloudFormationResourcesSupportInLatest, + LocalstackEmulatorType, LocalStackMetadata, ) @@ -25,41 +28,48 @@ def get_remote_catalog(self) -> AwsRemoteCatalog: localstack=LocalStackMetadata(version="4.7"), services={ "athena": { - "pro": { - "provider": "athena:pro", - "operations": ["StartQueryExecution", "GetQueryExecution"], - "plans": ["ultimate", "enterprise"], - } + "pro": AwsServiceCatalog( + provider="athena:pro", + operations=["StartQueryExecution", "GetQueryExecution"], + plans=["ultimate", "enterprise"], + ) }, "s3": { - "community": { - "provider": "s3:default", - "operations": ["CreateBucket"], - "plans": ["free", "base", "ultimate", "enterprise"], - }, - "pro": { - "provider": "s3:pro", - "operations": ["SelectObjectContent"], - "plans": ["base", "ultimate", "enterprise"], - }, + "community": AwsServiceCatalog( + provider="s3:default", + operations=["CreateBucket"], + plans=["free", "base", "ultimate", "enterprise"], + ), + "pro": AwsServiceCatalog( + provider="s3:pro", + operations=["SelectObjectContent"], + plans=["base", "ultimate", "enterprise"], + ), }, "kms": { - "community": { - "provider": "kms:default", - "operations": ["ListKeys"], - "plans": ["free", "base", "ultimate", "enterprise"], - } + "community": AwsServiceCatalog( + provider="kms:default", + operations=["ListKeys"], + plans=["free", "base", "ultimate", "enterprise"], + ) }, }, cloudformation_resources={ - "community": {"AWS::S3::Bucket": {"methods": ["Create", "Delete"]}}, - "pro": {"AWS::Athena::CapacitiesReservation": {"methods": ["Create", "Update", "Delete"]}}, + "community": { + "AWS::S3::Bucket": CloudFormationResource(methods=["Create", "Delete"]), + "AWS::KMS::Key": CloudFormationResource(methods=["Create", "Delete"]), + }, + "pro": { + "AWS::Athena::CapacitiesReservation": CloudFormationResource( + methods=["Create", "Update", "Delete"] + ), + }, }, ) @pytest.fixture(scope="class", autouse=True) -def aws_catalog(): +def aws_catalog_with_static_data(): return AwsCatalogRemoteStatePlugin(FakeCatalogLoader(CATALOG)) @@ -72,8 +82,8 @@ class TestAwsCatalog: ("nonexistent", AwsServicesSupportInLatest.NOT_SUPPORTED), ], ) - def test_get_service_status(self, aws_catalog, service_name, expected_status): - result = aws_catalog.get_aws_service_status(service_name) + def test_get_service_status(self, aws_catalog_with_static_data, service_name, expected_status): + result = aws_catalog_with_static_data.get_aws_service_status(service_name) assert result == expected_status @pytest.mark.parametrize( @@ -89,21 +99,22 @@ def test_get_service_status(self, aws_catalog, service_name, expected_status): ], ) def test_get_service_status_with_operation( - self, aws_catalog, service_name, operation_name, expected_status + self, aws_catalog_with_static_data, service_name, operation_name, expected_status ): - result = aws_catalog.get_aws_service_status(service_name, operation_name) + result = aws_catalog_with_static_data.get_aws_service_status(service_name, operation_name) assert result == expected_status - def test_get_service_status_with_only_one_emulator_type(self, aws_catalog): - result = aws_catalog.get_aws_service_status("athena") + def test_get_service_status_with_only_one_emulator_type(self, aws_catalog_with_static_data): + result = aws_catalog_with_static_data.get_aws_service_status("athena") assert result == AwsServicesSupportInLatest.SUPPORTED_WITH_LICENSE_UPGRADE - def test_get_service_status_with_empty_operation(self, aws_catalog): + def test_get_service_status_with_empty_operation(self, aws_catalog_with_static_data): assert ( - aws_catalog.get_aws_service_status("s3", None) == AwsServicesSupportInLatest.SUPPORTED + aws_catalog_with_static_data.get_aws_service_status("s3", None) + == AwsServicesSupportInLatest.SUPPORTED ) assert ( - aws_catalog.get_aws_service_status("s3", "") + aws_catalog_with_static_data.get_aws_service_status("s3", "") == AwsServiceOperationsSupportInLatest.SUPPORTED ) @@ -125,7 +136,20 @@ def test_get_service_status_with_empty_operation(self, aws_catalog): ], ) def test_get_cfn_resource_status( - self, aws_catalog, resource_name, service_name, expected_status + self, aws_catalog_with_static_data, resource_name, service_name, expected_status ): - result = aws_catalog.get_cloudformation_resource_status(resource_name, service_name) + result = aws_catalog_with_static_data.get_cloudformation_resource_status( + resource_name, service_name + ) assert result == expected_status + + def test_build_cfn_catalog_resources(self, aws_catalog_with_static_data): + community_resources = aws_catalog_with_static_data.cfn_resources_in_latest[ + LocalstackEmulatorType.COMMUNITY + ] + assert set(community_resources) == {"AWS::S3::Bucket", "AWS::KMS::Key"} + + pro_resources = aws_catalog_with_static_data.cfn_resources_in_latest[ + LocalstackEmulatorType.PRO + ] + assert set(pro_resources) == {"AWS::Athena::CapacitiesReservation"} diff --git a/tests/unit/utils/catalog/test_catalog_loader.py b/tests/unit/utils/catalog/test_catalog_loader.py new file mode 100644 index 0000000000000..4648a5e7b0df3 --- /dev/null +++ b/tests/unit/utils/catalog/test_catalog_loader.py @@ -0,0 +1,42 @@ +import json + +import pydantic +import pytest + +from localstack.utils.catalog.catalog_loader import AwsCatalogLoaderException, RemoteCatalogLoader +from localstack.utils.catalog.common import AwsRemoteCatalog +from localstack.utils.json import FileMappedDocument +from tests.unit.utils.catalog.conftest import CATALOG + + +class TestCatalogLoader: + def test_parse_valid_catalog(self): + catalog_loader = RemoteCatalogLoader() + assert catalog_loader._parse_catalog(CATALOG.json().encode()) == CATALOG + + def test_parse_catalog_with_missing_key(self): + catalog_loader = RemoteCatalogLoader() + catalog = CATALOG.dict() + catalog.pop("localstack") + with pytest.raises(pydantic.ValidationError): + catalog_loader._parse_catalog(json.dumps(catalog).encode()) + + def test_parse_catalog_with_invalid_json(self): + with pytest.raises(AwsCatalogLoaderException, match="Could not de-serialize json catalog"): + RemoteCatalogLoader()._parse_catalog(b'{"invalid": json content') + + def test_save_catalog_to_cache(self, tmp_path): + path = tmp_path / "test_catalog.json" + catalog_doc = FileMappedDocument(path) + catalog_loader = RemoteCatalogLoader() + catalog_doc.update( + CATALOG.model_dump() | {"localstack": {"version": "v1.1"}, "key1": "value1"} + ) + + assert "key1" in catalog_doc + assert catalog_doc["localstack"]["version"] == "v1.1" + + catalog_loader._save_catalog_to_cache(catalog_doc, CATALOG) + + catalog_doc.load() + assert AwsRemoteCatalog(**catalog_doc) == CATALOG diff --git a/tests/unit/utils/test_batch_policy.py b/tests/unit/utils/test_batching.py similarity index 77% rename from tests/unit/utils/test_batch_policy.py rename to tests/unit/utils/test_batching.py index e93fd594ded1d..5b3fc1ddfdcaa 100644 --- a/tests/unit/utils/test_batch_policy.py +++ b/tests/unit/utils/test_batching.py @@ -1,8 +1,10 @@ +import threading import time +from queue import Queue import pytest -from localstack.utils.batch_policy import Batcher +from localstack.utils.batching import AsyncBatcher, Batcher class SimpleItem: @@ -25,7 +27,7 @@ def test_add_single_item(self): assert result == ["item1", "item2"] assert batcher.get_current_size() == 0 - def test_add_multple_items(self): + def test_add_multiple_items(self): batcher = Batcher(max_count=3) assert not batcher.add(["item1", "item2"]) @@ -188,3 +190,71 @@ def test_deep_copy(self): batch = batcher.flush() assert batch[0]["key"] == "value" + + +class TestAsyncBatcher: + def test_basic(self): + calls = Queue() + + def collect(_batch: list): + calls.put(_batch) + + buffer = AsyncBatcher(collect, max_batch_size=2, max_flush_interval=1000) + + t = threading.Thread(target=buffer.run) + t.start() + + try: + e1 = "e1" + e2 = "e2" + e3 = "e3" + + buffer.add(e1) + buffer.add(e2) + + c1 = calls.get(timeout=2) + assert len(c1) == 2 + + buffer.add(e3) # should flush after close despite flush_size = 2 + finally: + buffer.close() + + c2 = calls.get(timeout=2) + assert len(c2) == 1 + + assert c1[0] == e1 + assert c1[1] == e2 + assert c2[0] == e3 + + t.join(10) + + def test_interval(self): + calls = Queue() + + def collect(_batch: list): + calls.put(_batch) + + buffer = AsyncBatcher(collect, max_batch_size=10, max_flush_interval=1) + + t = threading.Thread(target=buffer.run) + t.start() + + try: + e1 = "e1" + e2 = "e2" + e3 = "e3" + e4 = "e4" + + buffer.add(e1) + buffer.add(e2) + c1 = calls.get(timeout=2) + + buffer.add(e3) + buffer.add(e4) + c2 = calls.get(timeout=2) + finally: + buffer.close() + + assert len(c1) == 2 + assert len(c2) == 2 + t.join(10) diff --git a/tests/unit/utils/test_coverage_docs.py b/tests/unit/utils/test_coverage_docs.py deleted file mode 100644 index b21442736295a..0000000000000 --- a/tests/unit/utils/test_coverage_docs.py +++ /dev/null @@ -1,19 +0,0 @@ -from localstack.utils.coverage_docs import get_coverage_link_for_service - - -def test_coverage_link_for_existing_service(): - coverage_link = get_coverage_link_for_service("s3", "random_action") - assert coverage_link == ( - "The API action 'random_action' for service 's3' is either not available in your current " - "license plan or has not yet been emulated by LocalStack. " - "Please refer to https://docs.localstack.cloud/references/coverage/coverage_s3 for more information." - ) - - -def test_coverage_link_for_non_existing_service(): - coverage_link = get_coverage_link_for_service("dummy_service", "random_action") - assert coverage_link == ( - "The API for service 'dummy_service' is either not included in your current license plan or " - "has not yet been emulated by LocalStack. " - "Please refer to https://docs.localstack.cloud/references/coverage for more details." - ) diff --git a/tests/unit/utils/test_event_matcher.py b/tests/unit/utils/test_event_matcher.py index 436aa1b7c15be..88a2a13759206 100644 --- a/tests/unit/utils/test_event_matcher.py +++ b/tests/unit/utils/test_event_matcher.py @@ -2,7 +2,6 @@ import pytest -from localstack import config from localstack.aws.api.events import InvalidEventPatternException from localstack.utils.event_matcher import matches_event @@ -19,46 +18,16 @@ EVENT_STR = json.dumps(EVENT_DICT) -@pytest.fixture -def event_rule_engine(monkeypatch): - """Fixture to control EVENT_RULE_ENGINE config""" - - def _set_engine(engine: str): - monkeypatch.setattr(config, "EVENT_RULE_ENGINE", engine) - - return _set_engine - - -@pytest.mark.skip(reason="jpype conflict") -def test_matches_event_with_java_engine_strings(event_rule_engine): - """Test Java engine with string inputs (EventBridge case)""" - event_rule_engine("java") +def test_matches_event_strings(): assert matches_event(EVENT_PATTERN_STR, EVENT_STR) -@pytest.mark.skip(reason="jpype conflict") -def test_matches_event_with_java_engine_dicts(event_rule_engine): - """Test Java engine with dict inputs (ESM/Pipes case)""" - event_rule_engine("java") - assert matches_event(EVENT_PATTERN_DICT, EVENT_DICT) - - -def test_matches_event_with_python_engine_strings(event_rule_engine): - """Test Python engine with string inputs""" - event_rule_engine("python") - assert matches_event(EVENT_PATTERN_STR, EVENT_STR) - - -def test_matches_event_with_python_engine_dicts(event_rule_engine): - """Test Python engine with dict inputs""" - event_rule_engine("python") +def test_matches_event_dicts(): assert matches_event(EVENT_PATTERN_DICT, EVENT_STR) -@pytest.mark.skip(reason="jpype conflict") -def test_matches_event_mixed_inputs(event_rule_engine): +def test_matches_event_mixed_inputs(): """Test with mixed string/dict inputs""" - event_rule_engine("java") assert matches_event(EVENT_PATTERN_STR, EVENT_DICT) assert matches_event(EVENT_PATTERN_DICT, EVENT_STR) @@ -69,20 +38,9 @@ def test_matches_event_non_matching_pattern(): assert not matches_event(non_matching_pattern, EVENT_DICT) -@pytest.mark.parametrize("engine", ("python", "java")) -def test_matches_event_invalid_json(event_rule_engine, engine): +def test_matches_event_invalid_json(): """Test with invalid JSON strings""" - - if engine == "java": - # this lets the exception bubble up to the provider, when AWS returns a proper exception, it should be fixed - exception_type = json.JSONDecodeError - # do not re-enable this test, enabling jpype here will break StepFunctions - pytest.skip("jpype conflict") - else: - exception_type = InvalidEventPatternException - - event_rule_engine(engine) - with pytest.raises(exception_type): + with pytest.raises(InvalidEventPatternException): matches_event("{invalid-json}", EVENT_STR) diff --git a/tests/unit/utils/test_json.py b/tests/unit/utils/test_json.py index 7680ab7793b61..4e2ed844e086c 100644 --- a/tests/unit/utils/test_json.py +++ b/tests/unit/utils/test_json.py @@ -1,9 +1,27 @@ import json -from localstack.utils.json import BytesEncoder +from localstack.utils.json import BytesEncoder, assign_to_path def test_json_encoder(): payload = {"foo": b"foobar"} result = json.dumps(payload, cls=BytesEncoder) assert result == '{"foo": "Zm9vYmFy"}' + + +def test_assign_to_path_single_path(): + target = {} + assign_to_path(target, "a", "bar") + assert target == {"a": "bar"} + + +def test_assign_multi_nested_path(): + target = {} + assign_to_path(target, "a.b.foo", "bar") + assert target == {"a": {"b": {"foo": "bar"}}} + + +def test_assign_to_path_mixed_delimiters(): + target = {} + assign_to_path(target, "a.b/c", "d", delimiter="/") + assert target == {"a.b": {"c": "d"}} diff --git a/tests/unit/utils/test_sync.py b/tests/unit/utils/test_sync.py index a1cda2ed38d1d..0eda2486f7784 100644 --- a/tests/unit/utils/test_sync.py +++ b/tests/unit/utils/test_sync.py @@ -1,6 +1,8 @@ import threading -from localstack.utils.sync import SynchronizedDefaultDict +import pytest + +from localstack.utils.sync import Once, SynchronizedDefaultDict, once_func def test_synchronized_defaultdict(): @@ -17,3 +19,166 @@ def test_synchronized_defaultdict(): with d["a"]: assert isinstance(d["a"], type(threading.RLock())) + + +class TestOnce: + def test_executes_only_once(self): + once = Once() + + res = [] + + def fn(): + res.append(1) + + assert once.do(fn) is None + assert once.do(fn) is None + assert len(res) == 1 + + def test_exception_propagates(self): + once = Once() + + res = [] + + def error_fn(): + res.append(1) + raise ValueError("oops") + + # Only the first call raises an exception + with pytest.raises(ValueError, match="oops"): + once.do(error_fn) + + once.do(error_fn) # No exception raised + + assert len(res) == 1 + + def test_different_functions(self): + once = Once() + + res = [] + fn_1 = lambda: res.append(1) # noqa + fn_2 = lambda: res.append(2) # noqa + + # Only the first call to Once is run + once.do(fn_1) + once.do(fn_2) + + assert len(res) == 1 + assert res[0] == 1 + + +class TestOnceDecorator: + def test_executes_only_once(self): + counter = [] + + @once_func + def increment(): + counter.append(1) + return sum(counter) + + result1 = increment() + result2 = increment() + result3 = increment() + + assert len(counter) == 1 + assert result1 == 1 + assert result2 == 1 + assert result3 == 1 + + def test_with_arguments(self): + calls = [] + + @once_func + def add(a, b): + calls.append((a, b)) + return a + b + + result1 = add(2, 3) + result2 = add(5, 7) + result3 = add(1, 1) + + assert len(calls) == 1 + assert calls[0] == (2, 3) + assert result1 == 5 + assert result2 == 5 + assert result3 == 5 + + def test_exception_reraises(self): + call_count = [] + + @once_func + def failing_function(): + call_count.append(1) + raise ValueError("Something went wrong") + + with pytest.raises(ValueError, match="Something went wrong"): + failing_function() + + with pytest.raises(ValueError, match="Something went wrong"): + failing_function() + + with pytest.raises(ValueError, match="Something went wrong"): + failing_function() + + assert len(call_count) == 1 + + def test_none_return_value(self): + calls = [] + + @once_func + def returns_none(): + calls.append(1) + return None + + result1 = returns_none() + result2 = returns_none() + + assert len(calls) == 1 + assert result1 is None + assert result2 is None + + def test_preserves_function_metadata(self): + @once_func + def documented_function(): + """This is a docstring.""" + return 42 + + assert documented_function.__name__ == "documented_function" + assert documented_function.__doc__ == "This is a docstring." + + def test_multiple_decorated_functions(self): + counter1 = [] + counter2 = [] + + @once_func + def function1(): + counter1.append(1) + return "func1" + + @once_func + def function2(): + counter2.append(1) + return "func2" + + assert function1() == "func1" + assert function1() == "func1" + assert function2() == "func2" + assert function2() == "func2" + + assert len(counter1) == 1 + assert len(counter2) == 1 + + def test_with_kwargs(self): + calls = [] + + @once_func + def with_kwargs(a, b=10, **kwargs): + calls.append((a, b, kwargs)) + return "result" + + result1 = with_kwargs(1, b=20, extra="data") + result2 = with_kwargs(5) + + assert len(calls) == 1 + assert calls[0] == (1, 20, {"extra": "data"}) + assert result1 == "result" + assert result2 == "result" diff --git a/tests/unit/utils/test_tags.py b/tests/unit/utils/test_tags.py new file mode 100644 index 0000000000000..dcde947e97258 --- /dev/null +++ b/tests/unit/utils/test_tags.py @@ -0,0 +1,18 @@ +from localstack.utils import tagging + + +def test_convert_tag_list_to_dictionary(): + tags_list = [{"Key": "key", "Value": "value"}] + assert tagging.tag_list_to_map(tags_list) == {"key": "value"} + tags_list = [{"key": "key", "value": "value"}] + assert tagging.tag_list_to_map(tags_list, key_field="key", value_field="value") == { + "key": "value" + } + + +def test_convert_tag_dictionary_to_list(): + tags_dict = {"key": "value"} + assert tagging.tag_map_to_list(tags_dict) == [{"Key": "key", "Value": "value"}] + assert tagging.tag_map_to_list(tags_dict, key_field="key", value_field="value") == [ + {"key": "key", "value": "value"} + ] diff --git a/tests/unit/utils/test_threads.py b/tests/unit/utils/test_threads.py new file mode 100644 index 0000000000000..5ea39264ff771 --- /dev/null +++ b/tests/unit/utils/test_threads.py @@ -0,0 +1,62 @@ +import threading + +from localstack.utils.threads import ( + TMP_THREADS, + FuncThread, + cleanup_threads_and_processes, + start_thread, + start_worker_thread, +) + + +class TestThreads: + class TestStartThread: + def test_start_thread_returns_a_func_thread(self): + def examplefunc(*args): + pass + + thread = start_thread(examplefunc) + + assert isinstance(thread, FuncThread) + assert thread.name.startswith("examplefunc-") + assert thread in TMP_THREADS + + def test_start_thread_with_custom_name(self): + thread = start_thread(lambda: None, name="somefunc") + + assert thread.name.startswith("somefunc-") + + class TestStartWorkerThread: + def test_start_worker_thread_returns_a_func_thread(self): + thread = start_worker_thread(lambda: None) + + assert isinstance(thread, FuncThread) + assert thread.name.startswith("start_worker_thread-") + assert thread not in TMP_THREADS + + def test_start_worker_thread_with_custom_name(self): + thread = start_worker_thread(lambda: None, name="somefunc") + assert thread.name.startswith("somefunc-") + + def test_cleanup_threads_and_processes_calls_shutdown_hooks(self): + started = threading.Event() + done = threading.Event() + + # Note: we're extending FuncThread here to make sure we have access to `_stop_event` + # Regular users would use `start_thread` instead + class ThreadTest(FuncThread): + def __init__(self) -> None: + super().__init__(self.run_method) + + def run_method(self, *args): + started.set() + # thread waits until it is stopped + self._stop_event.wait() + done.set() + + test_thread = ThreadTest() + TMP_THREADS.append(test_thread) + test_thread.start() + assert started.wait(timeout=2) + cleanup_threads_and_processes() + assert done.wait(timeout=2)